From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1JHiB7-00055E-1a for qemu-devel@nongnu.org; Wed, 23 Jan 2008 11:10:17 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1JHiB2-0004zr-Nn for qemu-devel@nongnu.org; Wed, 23 Jan 2008 11:10:16 -0500 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JHiB2-0004zb-Jl for qemu-devel@nongnu.org; Wed, 23 Jan 2008 11:10:12 -0500 Received: from ecfrec.frec.bull.fr ([129.183.4.8]) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1JHiB2-0005ho-60 for qemu-devel@nongnu.org; Wed, 23 Jan 2008 11:10:12 -0500 Received: from localhost (localhost [127.0.0.1]) by ecfrec.frec.bull.fr (Postfix) with ESMTP id 75F7E19D9C7 for ; Wed, 23 Jan 2008 17:09:57 +0100 (CET) Received: from ecfrec.frec.bull.fr ([127.0.0.1]) by localhost (ecfrec.frec.bull.fr [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 12862-07 for ; Wed, 23 Jan 2008 17:09:53 +0100 (CET) Received: from ecn002.frec.bull.fr (ecn002.frec.bull.fr [129.183.4.6]) by ecfrec.frec.bull.fr (Postfix) with ESMTP id DE98F19D9BB for ; Wed, 23 Jan 2008 17:09:24 +0100 (CET) In-Reply-To: <12011047743807@bull.net> Date: Wed, 23 Jan 2008 17:12:55 +0100 Message-Id: <12011047751421@bull.net> Mime-Version: 1.0 From: Laurent Vivier Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="iso-8859-1" Subject: [Qemu-devel] [PATCH 5/5] SCSI device DMA split Reply-To: Laurent Vivier , qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: qemu-devel@nongnu.org With some emulated SCSI devices, like usb-storage or ide-scsi, DMA transfers are limited to 64 kiB or 32 kiB. This patch allows to split a READ or WRITE into several READ or WRITE. Laurent --- block-sg.c | 1=20 hw/scsi-generic.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++= ++--- 2 files changed, 105 insertions(+), 6 deletions(-) Index: qemu/hw/scsi-generic.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- qemu.orig/hw/scsi-generic.c 2008-01-23 15:29:26.000000000 +0100 +++ qemu/hw/scsi-generic.c 2008-01-23 15:29:26.000000000 +0100 @@ -60,6 +60,8 @@ do { fprintf(stderr, "scsi-generic: " fm #define MAX_UINT ((unsigned int)-1) #endif =20 +#define MAX_CHUNK 65536 + typedef struct SCSIRequest { SGRequest sg; struct SCSIRequest *next; @@ -70,6 +72,8 @@ typedef struct SCSIRequest { uint8_t *buf; int buflen; int len; + int remaining; + int offset; } SCSIRequest; =20 struct SCSIDeviceState @@ -81,6 +85,7 @@ struct SCSIDeviceState void *card; int driver_status; uint8_t sensebuf[SCSI_SENSE_BUF_SIZE]; + int max_chunk; }; =20 /* Global pool of SCSIRequest structures. */ @@ -98,6 +103,7 @@ static SCSIRequest *scsi_new_request(SCS r->buf =3D NULL; r->buflen =3D 0; } + r->offset =3D 0; r->dev =3D s; r->tag =3D tag; memset(r->cmd, 0, sizeof(r->cmd)); @@ -186,23 +192,93 @@ static void scsi_cancel_io(SCSIDevice *d } } =20 +static void scsi_cmd_next(uint8_t *cmd, uint32_t inc) +{ + uint32_t addr; + switch (cmd[0] >> 5) { + case 0: + addr =3D cmd[3] | (cmd[2] << 8); + addr +=3D inc; + cmd[2] =3D addr >> 8; + cmd[3] =3D addr; + break; + case 1: + case 2: + case 4: + case 5: + addr =3D cmd[5] | ((cmd[4] << 8) | ((cmd[3] << 16) | (cmd[2] << 24= ))); + addr +=3D inc; + cmd[2] =3D addr >> 24; + cmd[3] =3D addr >> 16; + cmd[4] =3D addr >> 8; + cmd[5] =3D addr; + break; + } +} +static void scsi_set_length(uint8_t *cmd, uint32_t len) +{ + switch (cmd[0] >> 5) { + case 0: + cmd[4] =3D len; + break; + case 1: + case 2: + cmd[7] =3D (len >> 8); + cmd[8] =3D len; + break; + case 4: + cmd[10] =3D len >> 24; + cmd[11] =3D len >> 16; + cmd[12] =3D len >> 8; + cmd[13] =3D len; + break; + case 5: + cmd[6] =3D len >> 24; + cmd[7] =3D len >> 16; + cmd[8] =3D len >> 8; + cmd[9] =3D len; + break; + } +} + + static int execute_command(BlockDriverState *bdrv, SCSIRequest *r, int direction, BlockDriverCompletionFunc *complete) { + int ret; + SCSIDeviceState *s =3D r->dev; + + r->remaining =3D 0; +retry: + if (s->max_chunk && r->buflen > s->max_chunk) { + r->remaining =3D r->buflen - s->max_chunk; + scsi_set_length(r->cmd, s->max_chunk / s->blocksize); + r->buflen =3D s->max_chunk; + } memset(&r->sg, 0, sizeof(r->sg)); r->sg.io_header.interface_id =3D 'S'; + r->sg.io_header.dxferp =3D r->buf + r->offset; r->sg.io_header.dxfer_direction =3D direction; r->sg.io_header.cmd_len =3D r->cmdlen; - r->sg.io_header.mx_sb_len =3D sizeof(r->dev->sensebuf); r->sg.io_header.dxfer_len =3D r->buflen; - r->sg.io_header.dxferp =3D r->buf; + r->sg.io_header.mx_sb_len =3D sizeof(s->sensebuf); + r->sg.io_header.sbp =3D s->sensebuf; r->sg.io_header.cmdp =3D r->cmd; - r->sg.io_header.sbp =3D r->dev->sensebuf; r->sg.io_header.timeout =3D MAX_UINT; r->sg.io_header.flags |=3D SG_FLAG_DIRECT_IO; =20 - return bdrv_execute(bdrv, &r->sg, complete); + ret =3D bdrv_execute(bdrv, &r->sg, complete); + if (ret =3D=3D -1 && errno =3D=3D 12) { + if (!s->max_chunk) { + s->max_chunk =3D MAX_CHUNK; + goto retry; + } else if (s->max_chunk > s->blocksize) { + s->max_chunk >>=3D 1; + goto retry; + } + } + return ret; } =20 static void scsi_read_complete(void *request, int ret) @@ -216,7 +292,18 @@ static void scsi_read_complete(void *req scsi_command_complete(r, ret); return; } - len =3D r->sg.io_header.dxfer_len - r->sg.io_header.resid; + r->offset +=3D r->sg.io_header.dxfer_len - r->sg.io_header.resid; + if (r->remaining !=3D 0) { + scsi_cmd_next(r->cmd, r->buflen / s->blocksize); + scsi_set_length(r->cmd, r->remaining / s->blocksize); + r->buflen =3D r->remaining; + ret =3D execute_command(s->bdrv, r, SG_DXFER_FROM_DEV, + scsi_read_complete); + if (ret =3D=3D -1) + scsi_command_complete(r, -EINVAL); + return; + } + len =3D r->offset; DPRINTF("Data ready tag=3D0x%x len=3D%d\n", r->tag, len); =20 r->len =3D -1; @@ -263,12 +350,24 @@ static void scsi_read_data(SCSIDevice *d static void scsi_write_complete(void* request, int ret) { SCSIRequest* r =3D (SCSIRequest*)request; + SCSIDeviceState *s =3D r->dev; DPRINTF("scsi_write_complete() ret =3D %d\n", ret); if (ret) { DPRINTF("IO error\n"); scsi_command_complete(r, ret); return; } + r->offset +=3D r->sg.io_header.dxfer_len - r->sg.io_header.resid; + if (r->remaining !=3D 0) { + scsi_cmd_next(r->cmd, r->buflen / s->blocksize); + scsi_set_length(r->cmd, r->remaining / s->blocksize); + r->buflen =3D r->remaining; + ret =3D execute_command(s->bdrv, r, SG_DXFER_TO_DEV, + scsi_write_complete); + if (ret =3D=3D -1) + scsi_command_complete(r, -EINVAL); + return; + } =20 scsi_command_complete(r, ret); } @@ -591,6 +690,7 @@ SCSIDevice *scsi_generic_init(BlockDrive s->card =3D card; s->blocksize =3D get_blocksize(s->bdrv); s->driver_status =3D 0; + s->max_chunk =3D 0; memset(s->sensebuf, 0, sizeof(s->sensebuf)); /* removable media returns 0 if not present */ if (s->blocksize <=3D 0) Index: qemu/block-sg.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- qemu.orig/block-sg.c 2008-01-23 15:33:03.000000000 +0100 +++ qemu/block-sg.c 2008-01-23 15:33:28.000000000 +0100 @@ -151,7 +151,6 @@ int sg_execute(BlockDriverState *bs, voi =20 if (sg_write(bs, (const uint8_t *)&r->io_header, sizeof(r->io_header)) =3D=3D -1) { - BADF("execute_command: write failed ! (%d)\n", errno); return -1; } if (complete =3D=3D NULL) {