This patch modifies scsi_read_data() and scsi_write_data()
to use asynchronous I/O whith SCSI Generic.

block-raw.s has been modified to define the number of bytes to
transfer instead of the number of blocks: if nb_sectors is less than zero
the nb_sectors is a number of bytes.
---
 block-raw.c       |    5 +
 hw/lsi53c895a.c   |    2 
 hw/scsi-generic.c |  198 ++++++++++++++++++++++++++++++++++--------------------
 3 files changed, 133 insertions(+), 72 deletions(-)

Index: qemu/block-raw.c
===================================================================
--- qemu.orig/block-raw.c       2007-11-28 13:12:02.000000000 +0100
+++ qemu/block-raw.c    2007-11-28 13:12:22.000000000 +0100
@@ -385,7 +385,10 @@ static RawAIOCB *raw_aio_setup(BlockDriv
     acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num;
     acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
     acb->aiocb.aio_buf = buf;
-    acb->aiocb.aio_nbytes = nb_sectors * 512;
+    if (nb_sectors < 0)
+        acb->aiocb.aio_nbytes = -nb_sectors;
+    else
+        acb->aiocb.aio_nbytes = nb_sectors * 512;
     acb->aiocb.aio_offset = sector_num * 512;
     acb->next = first_aio;
     first_aio = acb;
Index: qemu/hw/scsi-generic.c
===================================================================
--- qemu.orig/hw/scsi-generic.c 2007-11-28 13:12:12.000000000 +0100
+++ qemu/hw/scsi-generic.c      2007-11-28 13:13:13.000000000 +0100
@@ -53,6 +53,7 @@ do { fprintf(stderr, "scsi-generic: " fm
 #define SG_ERR_DRIVER_SENSE 0x08
 
 typedef struct SCSIRequest {
+    BlockDriverAIOCB *aiocb;
     struct SCSIRequest *next;
     SCSIDeviceState *dev;
     uint32_t tag;
@@ -61,8 +62,8 @@ typedef struct SCSIRequest {
     uint8_t *buf;
     int buflen;
     int len;
-    int driver_status;
     uint8_t sensebuf[SCSI_SENSE_BUF_SIZE];
+    sg_io_hdr_t io_header;
 } SCSIRequest;
 
 struct SCSIDeviceState
@@ -94,13 +95,16 @@ static SCSIRequest *scsi_new_request(SCS
     r->tag = tag;
     memset(r->cmd, 0, sizeof(r->cmd));
     memset(r->sensebuf, 0, sizeof(r->sensebuf));
+    memset(&r->io_header, 0, sizeof(r->io_header));
     r->cmdlen = 0;
     r->len = 0;
+    r->aiocb = NULL;
 
     /* link */
 
     r->next = s->requests;
     s->requests = r;
+    DPRINTF("scsi_new_request tag=0x%x\n", tag);
     return r;
 }
 
@@ -109,6 +113,7 @@ static void scsi_remove_request(SCSIRequ
     SCSIRequest *last;
     SCSIDeviceState *s = r->dev;
 
+    DPRINTF("scsi_remove_request tag=0x%x\n", r->tag);
     if (s->requests == r) {
         s->requests = r->next;
     } else {
@@ -138,16 +143,24 @@ static SCSIRequest *scsi_find_request(SC
 
 static int scsi_get_sense(SCSIRequest *r)
 {
-    if ((r->driver_status & SG_ERR_DRIVER_SENSE) == 0)
+    if ((r->io_header.driver_status & SG_ERR_DRIVER_SENSE) == 0)
         return NO_SENSE;
     return r->sensebuf[2] & 0x0f;
 }
 
 /* Helper function for command completion.  */
-static void scsi_command_complete(SCSIRequest *r, int sense)
+static void scsi_command_complete(void *opaque, int ret)
 {
+    SCSIRequest *r = (SCSIRequest *)opaque;
     SCSIDeviceState *s = r->dev;
     uint32_t tag;
+    int sense;
+
+    if (ret != 0)
+        sense = HARDWARE_ERROR;
+    else
+        sense = scsi_get_sense(r);
+
     DPRINTF("Command complete 0x%p tag=0x%x sense=%d\n", r, r->tag, sense);
     tag = r->tag;
     scsi_remove_request(r);
@@ -163,46 +176,70 @@ static void scsi_cancel_io(SCSIDevice *d
     DPRINTF("Cancel tag=0x%x\n", tag);
     r = scsi_find_request(s, tag);
     if (r) {
+        if (r->aiocb)
+            bdrv_aio_cancel(r->aiocb);
+        r->aiocb = NULL;
         scsi_remove_request(r);
     }
 }
 
-static int execute_command(BlockDriverState *bdrv, uint8_t *cmdbuf, int cmdlen,
-                           uint8_t *outbuf, uint32_t outlen,
-                           uint8_t *sensebuf, int senselen,
-                           int direction, int *len)
-{
-    sg_io_hdr_t io_header;
-    int ret;
-
-    memset(&io_header, 0, sizeof(io_header));
-    io_header.interface_id = 'S';
-    io_header.dxfer_direction = direction;
-    io_header.dxfer_len = outlen;
-    io_header.dxferp = outbuf;
-    io_header.cmdp = cmdbuf;
-    io_header.cmd_len = cmdlen;
-    io_header.mx_sb_len = senselen;
-    io_header.sbp = sensebuf;
-    io_header.timeout = 6000; /* XXX */
+static int execute_command(BlockDriverState *bdrv,
+                           SCSIRequest *r, int direction,
+                          BlockDriverCompletionFunc *complete)
+{
+    r->io_header.interface_id = 'S';
+    r->io_header.dxfer_direction = direction;
+    r->io_header.dxfer_len = r->buflen;
+    r->io_header.dxferp = r->buf;
+    r->io_header.cmdp = r->cmd;
+    r->io_header.cmd_len = r->cmdlen;
+    r->io_header.mx_sb_len = sizeof(r->sensebuf);
+    r->io_header.sbp = r->sensebuf;
+    r->io_header.timeout = 6000; /* XXX */
 
-    ret = bdrv_pwrite(bdrv, -1, &io_header, sizeof(io_header));
-    if (ret == -1) {
+    if (bdrv_pwrite(bdrv, -1, &r->io_header, sizeof(r->io_header)) == -1) {
         BADF("execute_command: write failed ! (%d)\n", errno);
         return -1;
     }
-    while ((ret = bdrv_pread(bdrv, -1, &io_header, sizeof(io_header))) == -1 &&
-           errno == EINTR);
+    if (complete == NULL) {
+        int ret;
+        r->aiocb = NULL;
+        while ((ret = bdrv_pread(bdrv, -1, &r->io_header,
+                                           sizeof(r->io_header))) == -1 &&
+                      errno == EINTR);
+        if (ret == -1) {
+            BADF("execute_command: read failed !\n");
+            return -1;
+        }
+        return 0;
+    }
 
-    if (ret == -1) {
+    r->aiocb = bdrv_aio_read(bdrv, 0, (uint8_t*)&r->io_header,
+                          -(int64_t)sizeof(r->io_header), complete, r);
+    if (r->aiocb == NULL) {
         BADF("execute_command: read failed !\n");
         return -1;
     }
 
-    if (len != NULL)
-        *len = io_header.dxfer_len - io_header.resid;
+    return 0;
+}
+
+static void scsi_read_complete(void * opaque, int ret)
+{
+    SCSIRequest *r = (SCSIRequest *)opaque;
+    SCSIDeviceState *s = r->dev;
+    int len;
 
-    return io_header.driver_status;
+    if (ret) {
+        DPRINTF("IO error\n");
+        scsi_command_complete(r, ret);
+        return;
+    }
+    len = r->io_header.dxfer_len - r->io_header.resid;
+    DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, len);
+
+    r->len = -1;
+    s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len);
 }
 
 /* Read more data from scsi device into buffer.  */
@@ -210,25 +247,40 @@ static void scsi_read_data(SCSIDevice *d
 {
     SCSIDeviceState *s = d->state;
     SCSIRequest *r;
-    int len;
+    int ret;
 
     DPRINTF("scsi_read_data 0x%x\n", tag);
     r = scsi_find_request(s, tag);
     if (!r) {
         BADF("Bad read tag 0x%x\n", tag);
         /* ??? This is the wrong error.  */
-        scsi_command_complete(r, HARDWARE_ERROR);
+        scsi_command_complete(r, -EINVAL);
         return;
     }
 
     if (r->len == -1) {
-        scsi_command_complete(r, scsi_get_sense(r));
+        scsi_command_complete(r, 0);
         return;
     }
 
-    len = r->len;
-    r->len = -1;
-    s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len);
+    ret = execute_command(s->bdrv, r, SG_DXFER_FROM_DEV, scsi_read_complete);
+    if (ret == -1) {
+        scsi_command_complete(r, -EINVAL);
+        return;
+    }
+}
+
+static void scsi_write_complete(void * opaque, int ret)
+{
+    SCSIRequest *r = (SCSIRequest *)opaque;
+
+    if (ret) {
+        DPRINTF("IO error\n");
+        scsi_command_complete(r, ret);
+        return;
+    }
+
+    scsi_command_complete(r, ret);
 }
 
 /* Write data to a scsi device.  Returns nonzero on failure.
@@ -244,7 +296,7 @@ static int scsi_write_data(SCSIDevice *d
     if (!r) {
         BADF("Bad write tag 0x%x\n", tag);
         /* ??? This is the wrong error.  */
-        scsi_command_complete(r, HARDWARE_ERROR);
+        scsi_command_complete(r, -EINVAL);
         return 0;
     }
 
@@ -254,15 +306,11 @@ static int scsi_write_data(SCSIDevice *d
         return 0;
     }
 
-    ret = execute_command(s->bdrv, r->cmd, r->cmdlen, r->buf, r->len,
-                          r->sensebuf, sizeof(r->sensebuf),
-                          SG_DXFER_TO_DEV, NULL);
+    ret = execute_command(s->bdrv, r, SG_DXFER_TO_DEV, scsi_write_complete);
     if (ret == -1) {
-        scsi_command_complete(r, HARDWARE_ERROR);
+        scsi_command_complete(r, -EINVAL);
         return 1;
     }
-    r->driver_status = ret;
-    scsi_command_complete(r, scsi_get_sense(r));
 
     return 0;
 }
@@ -416,19 +464,12 @@ static int32_t scsi_send_command(SCSIDev
     SCSIRequest *r;
     int ret;
 
-    r = scsi_find_request(s, tag);
-    if (r) {
-        BADF("Tag 0x%x already in use %p\n", tag, r);
-        scsi_cancel_io(d, tag);
-    }
-    r = scsi_new_request(s, tag);
-
     /* ??? Tags are not unique for different luns.  We only implement a
        single lun, so this should not matter.  */
 
     if (lun != s->lun || (cmd[1] >> 5) != s->lun) {
         DPRINTF("Unimplemented LUN %d\n", lun ? lun : cmd[1] >> 5);
-        scsi_command_complete(r, ILLEGAL_REQUEST);
+        s->completion(s->opaque, SCSI_REASON_DONE, tag, HARDWARE_ERROR);
         return 0;
     }
 
@@ -438,21 +479,28 @@ static int32_t scsi_send_command(SCSIDev
     }
 
     DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag,
-            command, len);
+            cmd[0], len);
+
+    r = scsi_find_request(s, tag);
+    if (r) {
+        BADF("Tag 0x%x already in use %p\n", tag, r);
+        scsi_cancel_io(d, tag);
+    }
+    r = scsi_new_request(s, tag);
 
     memcpy(r->cmd, cmd, cmdlen);
     r->cmdlen = cmdlen;
 
     if (len == 0) {
-        ret = execute_command(s->bdrv, r->cmd, r->cmdlen, NULL, 0,
-                              r->sensebuf, sizeof(r->sensebuf),
-                              SG_DXFER_NONE, NULL);
+        if (r->buf != NULL)
+            free(r->buf);
+        r->buflen = 0;
+        r->buf = NULL;
+        ret = execute_command(s->bdrv, r, SG_DXFER_NONE, NULL);
         if (ret == -1) {
-            scsi_command_complete(r, HARDWARE_ERROR);
+            scsi_command_complete(r, -EINVAL);
             return 0;
         }
-        r->driver_status = ret;
-
         scsi_command_complete(r, scsi_get_sense(r));
         return 0;
     }
@@ -471,16 +519,6 @@ static int32_t scsi_send_command(SCSIDev
         return -len;
     }
 
-    ret = execute_command(s->bdrv, r->cmd, r->cmdlen, r->buf, r->len,
-                          r->sensebuf, sizeof(r->sensebuf),
-                          SG_DXFER_FROM_DEV, &len);
-    if (ret == -1) {
-        scsi_command_complete(r, HARDWARE_ERROR);
-        return 0;
-    }
-    r->len = len;
-    r->driver_status = ret;
-
     return len;
 }
 
@@ -489,16 +527,34 @@ static int get_blocksize(BlockDriverStat
     uint8_t cmd[10];
     uint8_t buf[8];
     uint8_t sensebuf[8];
+    sg_io_hdr_t io_header;
     int ret;
 
     memset(cmd, sizeof(cmd), 0);
     memset(buf, sizeof(buf), 0);
     cmd[0] = READ_CAPACITY;
-    ret = execute_command(bdrv, cmd, sizeof(cmd), buf, sizeof(buf),
-                          sensebuf, sizeof(sensebuf),
-                          SG_DXFER_FROM_DEV, NULL);
-    if (ret < 0)
+
+    memset(&io_header, 0, sizeof(io_header));
+    io_header.interface_id = 'S';
+    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
+    io_header.dxfer_len = sizeof(buf);
+    io_header.dxferp = buf;
+    io_header.cmdp = cmd;
+    io_header.cmd_len = sizeof(cmd);
+    io_header.mx_sb_len = sizeof(sensebuf);
+    io_header.sbp = sensebuf;
+    io_header.timeout = 6000; /* XXX */
+
+    ret = bdrv_pwrite(bdrv, -1, &io_header, sizeof(io_header));
+    if (ret == -1)
+        return -1;
+
+    while ((ret = bdrv_pread(bdrv, -1, &io_header, sizeof(io_header))) == -1 &&
+           errno == EINTR);
+
+    if (ret == -1)
         return -1;
+
     return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
 }
 
Index: qemu/hw/lsi53c895a.c
===================================================================
--- qemu.orig/hw/lsi53c895a.c   2007-11-28 13:12:02.000000000 +0100
+++ qemu/hw/lsi53c895a.c        2007-11-28 13:12:22.000000000 +0100
@@ -1225,6 +1225,8 @@ static uint8_t lsi_reg_readb(LSIState *s
         return s->sdid;
     case 0x07: /* GPREG0 */
         return 0x7f;
+    case 0x08: /* Revision ID */
+        return 0x00;
     case 0xa: /* SSID */
         return s->ssid;
     case 0xb: /* SBCL */



Reply via email to