Patchwork [08/15] scsi-disk: Allocate iovec dynamically

login
register
mail settings
Submitter Hannes Reinecke
Date Nov. 24, 2010, 11:16 a.m.
Message ID <1290597370-21365-9-git-send-email-hare@suse.de>
Download mbox | patch
Permalink /patch/72841/
State New
Headers show

Comments

Hannes Reinecke - Nov. 24, 2010, 11:16 a.m.
Rather than have the iovec part of the structure with a fixed size
of '1' we should be allocating it dynamically. This will allow us
to pass in SGLs directly.

Signed-off-by: Hannes Reinecke <hare@suse.de>
---
 hw/scsi-disk.c |  102 +++++++++++++++++++++++++++++++++-----------------------
 1 files changed, 60 insertions(+), 42 deletions(-)

Patch

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index a71607e..deec825 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -37,6 +37,7 @@  do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 #include "scsi-defs.h"
 #include "sysemu.h"
 #include "blockdev.h"
+#include "iov.h"
 
 #define SCSI_DMA_BUF_SIZE    131072
 #define SCSI_MAX_INQUIRY_LEN 256
@@ -56,7 +57,10 @@  typedef struct SCSIDiskReq {
     /* Both sector and sector_count are in terms of qemu 512 byte blocks.  */
     uint64_t sector;
     uint32_t sector_count;
-    struct iovec iov;
+    uint8_t *iov_buf;
+    uint64_t iov_len;
+    struct iovec *iov;
+    int iov_num;
     QEMUIOVector qiov;
     uint32_t status;
 } SCSIDiskReq;
@@ -86,13 +90,19 @@  static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag,
 
     req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun);
     r = DO_UPCAST(SCSIDiskReq, req, req);
-    r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
+    r->iov_buf = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
+    r->iov = qemu_mallocz(sizeof(struct iovec));
+    r->iov[0].iov_base = r->iov_buf;
+    r->iov_num = 1;
     return r;
 }
 
 static void scsi_remove_request(SCSIDiskReq *r)
 {
-    qemu_vfree(r->iov.iov_base);
+    qemu_free(r->iov);
+    r->iov = NULL;
+    qemu_vfree(r->iov_buf);
+    r->iov_buf = NULL;
     scsi_req_free(&r->req);
 }
 
@@ -117,7 +127,7 @@  static void scsi_req_set_status(SCSIDiskReq *r, int status, SCSISense sense)
 /* Helper function for command completion.  */
 static void scsi_command_complete(SCSIDiskReq *r, int status, SCSISense sense)
 {
-    DPRINTF("Command complete tag=0x%x status=%d sense=%d/%d/%d\n",
+    DPRINTF("Command complete tag=0x%x status=%d sense=%02x/%02x/%02x\n",
             r->req.tag, status, sense.key, sense.asc, sense.ascq);
     scsi_req_set_status(r, status, sense);
     scsi_req_complete(&r->req);
@@ -142,7 +152,7 @@  static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
 static void scsi_read_complete(void * opaque, int ret)
 {
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
-    int n;
+    size_t iov_len = 0;
 
     r->req.aiocb = NULL;
 
@@ -151,13 +161,11 @@  static void scsi_read_complete(void * opaque, int ret)
             return;
         }
     }
+    iov_len = iov_size(r->iov, r->iov_num);
 
-    DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len);
+    DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, iov_len);
 
-    n = r->iov.iov_len / 512;
-    r->sector += n;
-    r->sector_count -= n;
-    r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
+    r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, iov_len);
 }
 
 
@@ -167,9 +175,10 @@  static void scsi_read_request(SCSIDiskReq *r)
     uint32_t n;
 
     if (r->sector_count == (uint32_t)-1) {
-        DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
+        DPRINTF("Read buf_len=%zd\n", r->iov[0].iov_len);
         r->sector_count = 0;
-        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
+        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag,
+                             r->iov[0].iov_len);
         return;
     }
     DPRINTF("Read sector_count=%d\n", r->sector_count);
@@ -179,15 +188,21 @@  static void scsi_read_request(SCSIDiskReq *r)
     }
 
     n = r->sector_count;
-    if (n > SCSI_DMA_BUF_SIZE / 512)
-        n = SCSI_DMA_BUF_SIZE / 512;
+    if (r->iov_buf) {
+        /* Reset iovec */
+        if (n > SCSI_DMA_BUF_SIZE / 512)
+            n = SCSI_DMA_BUF_SIZE / 512;
+        r->iov[0].iov_len = n * 512;
+    }
 
-    r->iov.iov_len = n * 512;
-    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+    qemu_iovec_init_external(&r->qiov, r->iov, r->iov_num);
     r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
                               scsi_read_complete, r);
     if (r->req.aiocb == NULL) {
         scsi_read_complete(r, -EIO);
+    } else {
+        r->sector += n;
+        r->sector_count -= n;
     }
 }
 
@@ -264,17 +279,20 @@  static void scsi_write_complete(void * opaque, int ret)
         }
     }
 
-    n = r->iov.iov_len / 512;
+    n = iov_size(r->iov, r->iov_num) / 512;
     r->sector += n;
     r->sector_count -= n;
     if (r->sector_count == 0) {
         scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
     } else {
         len = r->sector_count * 512;
-        if (len > SCSI_DMA_BUF_SIZE) {
-            len = SCSI_DMA_BUF_SIZE;
+        if (r->iov_buf) {
+            /* Reset iovec */
+            if (len > SCSI_DMA_BUF_SIZE) {
+                len = SCSI_DMA_BUF_SIZE;
+            }
+            r->iov[0].iov_len = len;
         }
-        r->iov.iov_len = len;
         DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, len);
         r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, len);
     }
@@ -285,9 +303,9 @@  static void scsi_write_request(SCSIDiskReq *r)
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
     uint32_t n;
 
-    n = r->iov.iov_len / 512;
+    n = iov_size(r->iov, r->iov_num) / 512;
     if (n) {
-        qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+        qemu_iovec_init_external(&r->qiov, r->iov, r->iov_num);
         r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
                                    scsi_write_complete, r);
         if (r->req.aiocb == NULL) {
@@ -352,7 +370,7 @@  static void scsi_dma_restart_bh(void *opaque)
                 scsi_write_request(r);
                 break;
             case SCSI_REQ_STATUS_RETRY_FLUSH:
-                ret = scsi_disk_emulate_command(r, r->iov.iov_base);
+                ret = scsi_disk_emulate_command(r, r->iov[0].iov_base);
                 if (ret == 0) {
                     scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
                 }
@@ -385,7 +403,7 @@  static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
         BADF("Bad buffer tag 0x%x\n", tag);
         return NULL;
     }
-    return (uint8_t *)r->iov.iov_base;
+    return r->iov_buf;
 }
 
 static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
@@ -1001,12 +1019,10 @@  static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
                                  uint8_t *buf, int lun)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
-    uint32_t len;
+    ssize_t len = 0;
     int is_write;
     uint8_t command;
-    uint8_t *outbuf;
     SCSIDiskReq *r;
-    int rc;
 
     command = buf[0];
     r = scsi_find_request(s, tag);
@@ -1017,7 +1033,6 @@  static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
     /* ??? Tags are not unique for different luns.  We only implement a
        single lun, so this should not matter.  */
     r = scsi_new_request(s, tag, lun);
-    outbuf = (uint8_t *)r->iov.iov_base;
     is_write = 0;
     DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
 
@@ -1065,23 +1080,25 @@  static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
     case REPORT_LUNS:
     case VERIFY:
     case REZERO_UNIT:
-        rc = scsi_disk_emulate_command(r, outbuf);
-        if (rc < 0) {
+        len = scsi_disk_emulate_command(r, r->iov[0].iov_base);
+        if (len < 0) {
             return 0;
         }
 
-        r->iov.iov_len = rc;
+        r->iov[0].iov_len = len;
         break;
     case READ_6:
     case READ_10:
     case READ_12:
     case READ_16:
-        len = r->req.cmd.xfer / d->blocksize;
-        DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);
-        if (r->req.cmd.lba > s->max_lba)
+        r->sector_count = r->req.cmd.xfer / d->blocksize * s->cluster_size;
+        DPRINTF("Read (sector %" PRId64 ", blocks %d)\n", r->req.cmd.lba,
+                r->sector_count);
+        if (r->req.cmd.lba > s->max_lba) {
+            r->sector_count = 0;
             goto illegal_lba;
+        }
         r->sector = r->req.cmd.lba * s->cluster_size;
-        r->sector_count = len * s->cluster_size;
         break;
     case WRITE_6:
     case WRITE_10:
@@ -1090,14 +1107,15 @@  static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
     case WRITE_VERIFY:
     case WRITE_VERIFY_12:
     case WRITE_VERIFY_16:
-        len = r->req.cmd.xfer / d->blocksize;
-        DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
+        r->sector_count = r->req.cmd.xfer / d->blocksize * s->cluster_size;
+        DPRINTF("Write %s(sector %" PRId64 ", blocks %d)\n",
                 (command & 0xe) == 0xe ? "And Verify " : "",
-                r->req.cmd.lba, len);
-        if (r->req.cmd.lba > s->max_lba)
+                r->req.cmd.lba, r->sector_count);
+        if (r->req.cmd.lba > s->max_lba) {
+            r->sector_count = 0;
             goto illegal_lba;
+        }
         r->sector = r->req.cmd.lba * s->cluster_size;
-        r->sector_count = len * s->cluster_size;
         is_write = 1;
         break;
     case MODE_SELECT:
@@ -1135,10 +1153,10 @@  static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
         scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LBA_OUT_OF_RANGE));
         return 0;
     }
-    if (r->sector_count == 0 && r->iov.iov_len == 0) {
+    if (r->sector_count == 0 && len == 0) {
         scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
     }
-    len = r->sector_count * 512 + r->iov.iov_len;
+    len += r->sector_count * 512;
     if (is_write) {
         return -len;
     } else {