qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/11] virtio-scsi device model
@ 2011-12-06 11:01 Paolo Bonzini
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 01/11] qiov: prevent double free or use-after-free Paolo Bonzini
                   ` (11 more replies)
  0 siblings, 12 replies; 15+ messages in thread
From: Paolo Bonzini @ 2011-12-06 11:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha

Given that the discussion on the spec has converged, here is finally
the virtio-scsi device model.

The first patch is an (already posted) bug fix.  The next 6 patches
add scatter/gather support to the SCSI layer; the final 4 add the
device---first a stub, and then progressively more features.

Paolo Bonzini (9):
  qiov: prevent double free or use-after-free
  dma-helpers: make QEMUSGList target independent
  dma-helpers: add dma_buf_read and dma_buf_write
  dma-helpers: add accounting wrappers
  scsi: pass residual amount to command_complete
  scsi: add scatter/gather functionality
  scsi-disk: enable scatter/gather functionality
  virtio-scsi: add basic SCSI bus operation
  virtio-scsi: process control queue requests

Stefan Hajnoczi (2):
  virtio-scsi: Add virtio-scsi stub device
  virtio-scsi: Add basic request processing infrastructure

 Makefile.target                   |    1 +
 cutils.c                          |    3 +
 default-configs/pci.mak           |    1 +
 default-configs/s390x-softmmu.mak |    1 +
 dma-helpers.c                     |   36 +++
 dma.h                             |   20 +-
 hw/esp.c                          |    5 +-
 hw/ide/ahci.c                     |   10 +-
 hw/lsi53c895a.c                   |    4 +-
 hw/pci.h                          |    1 +
 hw/s390-virtio-bus.c              |   24 ++
 hw/s390-virtio-bus.h              |    2 +
 hw/scsi-bus.c                     |   35 ++-
 hw/scsi-disk.c                    |   63 ++++-
 hw/scsi.h                         |    7 +-
 hw/spapr_vscsi.c                  |    4 +-
 hw/usb-msd.c                      |    4 +-
 hw/virtio-pci.c                   |   41 +++
 hw/virtio-pci.h                   |    2 +
 hw/virtio-scsi.c                  |  553 +++++++++++++++++++++++++++++++++++++
 hw/virtio-scsi.h                  |   36 +++
 hw/virtio.h                       |    3 +
 22 files changed, 815 insertions(+), 41 deletions(-)
 create mode 100644 hw/virtio-scsi.c
 create mode 100644 hw/virtio-scsi.h

-- 
1.7.7.1

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 01/11] qiov: prevent double free or use-after-free
  2011-12-06 11:01 [Qemu-devel] [PATCH 00/11] virtio-scsi device model Paolo Bonzini
@ 2011-12-06 11:01 ` Paolo Bonzini
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 02/11] dma-helpers: make QEMUSGList target independent Paolo Bonzini
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Paolo Bonzini @ 2011-12-06 11:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha

qemu_iovec_destroy does not clear the QEMUIOVector fully, and the data
could thus be used after free or freed again.  This can be observed with
virtio-scsi, because canceling DMA requests can happen more easily with
SCSI (due to task management functions) than with other backends.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 cutils.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/cutils.c b/cutils.c
index 6db6304..24b3fe3 100644
--- a/cutils.c
+++ b/cutils.c
@@ -217,7 +217,10 @@ void qemu_iovec_destroy(QEMUIOVector *qiov)
 {
     assert(qiov->nalloc != -1);
 
+    qemu_iovec_reset(qiov);
     g_free(qiov->iov);
+    qiov->nalloc = 0;
+    qiov->iov = NULL;
 }
 
 void qemu_iovec_reset(QEMUIOVector *qiov)
-- 
1.7.7.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 02/11] dma-helpers: make QEMUSGList target independent
  2011-12-06 11:01 [Qemu-devel] [PATCH 00/11] virtio-scsi device model Paolo Bonzini
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 01/11] qiov: prevent double free or use-after-free Paolo Bonzini
@ 2011-12-06 11:01 ` Paolo Bonzini
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 03/11] dma-helpers: add dma_buf_read and dma_buf_write Paolo Bonzini
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Paolo Bonzini @ 2011-12-06 11:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha

This lets scsi-* observe the overall s/g list and pass it to the DMA
helpers.

size_t can potentially be smaller than dma_addr_t.  However, the overall
size of a S/G list can actually be bigger than dma_addr_t because (for
writes) you could reuse the same buffer multiple times.  So there is
no difference in practice.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 dma.h |   14 +++++++-------
 1 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/dma.h b/dma.h
index a13209d..d50019b 100644
--- a/dma.h
+++ b/dma.h
@@ -17,6 +17,13 @@
 
 typedef struct ScatterGatherEntry ScatterGatherEntry;
 
+struct QEMUSGList {
+    ScatterGatherEntry *sg;
+    int nsg;
+    int nalloc;
+    size_t size;
+};
+
 #if defined(TARGET_PHYS_ADDR_BITS)
 typedef target_phys_addr_t dma_addr_t;
 
@@ -32,13 +39,6 @@ struct ScatterGatherEntry {
     dma_addr_t len;
 };
 
-struct QEMUSGList {
-    ScatterGatherEntry *sg;
-    int nsg;
-    int nalloc;
-    dma_addr_t size;
-};
-
 void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint);
 void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len);
 void qemu_sglist_destroy(QEMUSGList *qsg);
-- 
1.7.7.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 03/11] dma-helpers: add dma_buf_read and dma_buf_write
  2011-12-06 11:01 [Qemu-devel] [PATCH 00/11] virtio-scsi device model Paolo Bonzini
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 01/11] qiov: prevent double free or use-after-free Paolo Bonzini
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 02/11] dma-helpers: make QEMUSGList target independent Paolo Bonzini
@ 2011-12-06 11:01 ` Paolo Bonzini
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 04/11] dma-helpers: add accounting wrappers Paolo Bonzini
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Paolo Bonzini @ 2011-12-06 11:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha

These helpers do a full transfer from an in-memory buffer to target
memory, with support for scatter/gather lists.  It will be used to
store the reply of an emulated command into a QEMUSGList provided by
the adapter.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 dma-helpers.c |   30 ++++++++++++++++++++++++++++++
 dma.h         |    3 +++
 2 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/dma-helpers.c b/dma-helpers.c
index f08cdb5..f53a51f 100644
--- a/dma-helpers.c
+++ b/dma-helpers.c
@@ -204,3 +204,33 @@ BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
 {
     return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, true);
 }
+
+
+static uint64_t dma_buf_rw(uint8_t *ptr, int32_t len, QEMUSGList *sg, bool to_dev)
+{
+    uint64_t resid;
+    int sg_cur_index;
+
+    resid = sg->size;
+    sg_cur_index = 0;
+    len = MIN(len, resid);
+    while (len > 0) {
+        ScatterGatherEntry entry = sg->sg[sg_cur_index++];
+        cpu_physical_memory_rw(entry.base, ptr, MIN(len, entry.len), !to_dev);
+        ptr += entry.len;
+        len -= entry.len;
+        resid -= entry.len;
+    }
+
+    return resid;
+}
+
+uint64_t dma_buf_read(uint8_t *ptr, int32_t len, QEMUSGList *sg)
+{
+    return dma_buf_rw(ptr, len, sg, 0);
+}
+
+uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg)
+{
+    return dma_buf_rw(ptr, len, sg, 1);
+}
diff --git a/dma.h b/dma.h
index d50019b..346ac4f 100644
--- a/dma.h
+++ b/dma.h
@@ -58,4 +58,7 @@ BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
 BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
                                  QEMUSGList *sg, uint64_t sector,
                                  BlockDriverCompletionFunc *cb, void *opaque);
+uint64_t dma_buf_read(uint8_t *ptr, int32_t len, QEMUSGList *sg);
+uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg);
+
 #endif
-- 
1.7.7.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 04/11] dma-helpers: add accounting wrappers
  2011-12-06 11:01 [Qemu-devel] [PATCH 00/11] virtio-scsi device model Paolo Bonzini
                   ` (2 preceding siblings ...)
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 03/11] dma-helpers: add dma_buf_read and dma_buf_write Paolo Bonzini
@ 2011-12-06 11:01 ` Paolo Bonzini
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 05/11] scsi: pass residual amount to command_complete Paolo Bonzini
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Paolo Bonzini @ 2011-12-06 11:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha

The length of the transfer is already in the sglist, so add a wrapper
that fetches it.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 dma-helpers.c |    6 ++++++
 dma.h         |    3 +++
 hw/ide/ahci.c |   10 ++++------
 3 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/dma-helpers.c b/dma-helpers.c
index f53a51f..a773489 100644
--- a/dma-helpers.c
+++ b/dma-helpers.c
@@ -234,3 +234,9 @@ uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg)
 {
     return dma_buf_rw(ptr, len, sg, 1);
 }
+
+void dma_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie,
+                    QEMUSGList *sg, enum BlockAcctType type)
+{
+    bdrv_acct_start(bs, cookie, sg->size, type);
+}
diff --git a/dma.h b/dma.h
index 346ac4f..20e86d2 100644
--- a/dma.h
+++ b/dma.h
@@ -61,4 +61,7 @@ BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
 uint64_t dma_buf_read(uint8_t *ptr, int32_t len, QEMUSGList *sg);
 uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg);
 
+void dma_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie,
+                    QEMUSGList *sg, enum BlockAcctType type);
+
 #endif
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 0af201d..28f32cc 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -794,9 +794,8 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
             DPRINTF(port, "tag %d aio read %"PRId64"\n",
                     ncq_tfs->tag, ncq_tfs->lba);
 
-            bdrv_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct,
-                            (ncq_tfs->sector_count-1) * BDRV_SECTOR_SIZE,
-                            BDRV_ACCT_READ);
+            dma_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct,
+                           &ncq_tfs->sglist, BDRV_ACCT_READ);
             ncq_tfs->aiocb = dma_bdrv_read(ncq_tfs->drive->port.ifs[0].bs,
                                            &ncq_tfs->sglist, ncq_tfs->lba,
                                            ncq_cb, ncq_tfs);
@@ -808,9 +807,8 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
             DPRINTF(port, "tag %d aio write %"PRId64"\n",
                     ncq_tfs->tag, ncq_tfs->lba);
 
-            bdrv_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct,
-                            (ncq_tfs->sector_count-1) * BDRV_SECTOR_SIZE,
-                            BDRV_ACCT_WRITE);
+            dma_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct,
+                           &ncq_tfs->sglist, BDRV_ACCT_WRITE);
             ncq_tfs->aiocb = dma_bdrv_write(ncq_tfs->drive->port.ifs[0].bs,
                                             &ncq_tfs->sglist, ncq_tfs->lba,
                                             ncq_cb, ncq_tfs);
-- 
1.7.7.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 05/11] scsi: pass residual amount to command_complete
  2011-12-06 11:01 [Qemu-devel] [PATCH 00/11] virtio-scsi device model Paolo Bonzini
                   ` (3 preceding siblings ...)
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 04/11] dma-helpers: add accounting wrappers Paolo Bonzini
@ 2011-12-06 11:01 ` Paolo Bonzini
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 06/11] scsi: add scatter/gather functionality Paolo Bonzini
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Paolo Bonzini @ 2011-12-06 11:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha

With the upcoming sglist support, HBAs will not see any transfer_data
call and will not have a way to detect short transfers.  So pass the
residual amount of data upon command completion.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/esp.c         |    3 ++-
 hw/lsi53c895a.c  |    2 +-
 hw/scsi-bus.c    |   12 ++++++++----
 hw/scsi.h        |    3 ++-
 hw/spapr_vscsi.c |    2 +-
 hw/usb-msd.c     |    2 +-
 6 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/hw/esp.c b/hw/esp.c
index b698a43..8516db5 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -389,7 +389,8 @@ static void esp_do_dma(ESPState *s)
     esp_dma_done(s);
 }
 
-static void esp_command_complete(SCSIRequest *req, uint32_t status)
+static void esp_command_complete(SCSIRequest *req, uint32_t status,
+                                 int32_t resid)
 {
     ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent);
 
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index fcc27d7..c53760b 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -699,7 +699,7 @@ static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
 }
 
  /* Callback to indicate that the SCSI layer has completed a command.  */
-static void lsi_command_complete(SCSIRequest *req, uint32_t status)
+static void lsi_command_complete(SCSIRequest *req, uint32_t status, int32_t resid)
 {
     LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
     int out;
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 64e709e..aa811f4 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -512,6 +512,8 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
     }
 
     req->cmd = cmd;
+    req->resid = req->cmd.xfer;
+
     switch (buf[0]) {
     case INQUIRY:
         trace_scsi_inquiry(d->id, lun, tag, cmd.buf[1], cmd.buf[2]);
@@ -1256,10 +1258,12 @@ void scsi_req_data(SCSIRequest *req, int len)
 {
     if (req->io_canceled) {
         trace_scsi_req_data_canceled(req->dev->id, req->lun, req->tag, len);
-    } else {
-        trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
-        req->bus->info->transfer_data(req, len);
+        return;
     }
+    trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
+    assert(req->cmd.mode != SCSI_XFER_NONE);
+    req->resid -= len;
+    req->bus->info->transfer_data(req, len);
 }
 
 void scsi_req_print(SCSIRequest *req)
@@ -1318,7 +1322,7 @@ void scsi_req_complete(SCSIRequest *req, int status)
 
     scsi_req_ref(req);
     scsi_req_dequeue(req);
-    req->bus->info->complete(req, req->status);
+    req->bus->info->complete(req, req->status, req->resid);
     scsi_req_unref(req);
 }
 
diff --git a/hw/scsi.h b/hw/scsi.h
index ab6e952..27ca087 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -47,6 +47,7 @@ struct SCSIRequest {
     uint32_t          tag;
     uint32_t          lun;
     uint32_t          status;
+    size_t            resid;
     SCSICommand       cmd;
     BlockDriverAIOCB  *aiocb;
     uint8_t sense[SCSI_SENSE_BUF_SIZE];
@@ -107,7 +108,7 @@ struct SCSIBusInfo {
     int tcq;
     int max_channel, max_target, max_lun;
     void (*transfer_data)(SCSIRequest *req, uint32_t arg);
-    void (*complete)(SCSIRequest *req, uint32_t arg);
+    void (*complete)(SCSIRequest *req, uint32_t arg, int32_t len);
     void (*cancel)(SCSIRequest *req);
 };
 
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 00e2d2d..c28bba9 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -494,7 +494,7 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
 }
 
 /* Callback to indicate that the SCSI layer has completed a transfer.  */
-static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status)
+static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, int32_t resid)
 {
     VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
     vscsi_req *req = sreq->hba_private;
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 4c06950..1c7bc82 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -223,7 +223,7 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
     }
 }
 
-static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
+static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, int32_t resid)
 {
     MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
     USBPacket *p = s->packet;
-- 
1.7.7.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 06/11] scsi: add scatter/gather functionality
  2011-12-06 11:01 [Qemu-devel] [PATCH 00/11] virtio-scsi device model Paolo Bonzini
                   ` (4 preceding siblings ...)
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 05/11] scsi: pass residual amount to command_complete Paolo Bonzini
@ 2011-12-06 11:01 ` Paolo Bonzini
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 07/11] scsi-disk: enable " Paolo Bonzini
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Paolo Bonzini @ 2011-12-06 11:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha

Scatter/gather functionality uses the newly added DMA helpers.  The
device can choose between doing DMA itself, or calling scsi_req_data
as usual.  In the latter case, scsi_req_data will use the buffer-based
DMA helpers to copy piecewise to/from the destination area(s).

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/esp.c         |    2 +-
 hw/lsi53c895a.c  |    2 +-
 hw/scsi-bus.c    |   28 ++++++++++++++++++++++++----
 hw/scsi.h        |    4 +++-
 hw/spapr_vscsi.c |    2 +-
 hw/usb-msd.c     |    2 +-
 6 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/hw/esp.c b/hw/esp.c
index 8516db5..e72e8ba 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -239,7 +239,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
     lun = busid & 7;
     current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun);
     s->current_req = scsi_req_new(current_lun, 0, lun, buf, NULL);
-    datalen = scsi_req_enqueue(s->current_req);
+    datalen = scsi_req_enqueue(s->current_req, NULL);
     s->ti_size = datalen;
     if (datalen != 0) {
         s->rregs[ESP_RSTAT] = STAT_TC;
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index c53760b..55533af 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -778,7 +778,7 @@ static void lsi_do_command(LSIState *s)
     s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun, buf,
                                    s->current);
 
-    n = scsi_req_enqueue(s->current->req);
+    n = scsi_req_enqueue(s->current->req, NULL);
     if (n) {
         if (n > 0) {
             lsi_set_phase(s, PHASE_DI);
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index aa811f4..b42c3b1 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -5,6 +5,7 @@
 #include "qdev.h"
 #include "blockdev.h"
 #include "trace.h"
+#include "dma.h"
 
 static char *scsibus_get_fw_dev_path(DeviceState *dev);
 static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
@@ -51,7 +52,7 @@ static void scsi_dma_restart_bh(void *opaque)
                 break;
             case SCSI_XFER_NONE:
                 scsi_req_dequeue(req);
-                scsi_req_enqueue(req);
+                scsi_req_enqueue(req, NULL);
                 break;
             }
         }
@@ -626,7 +627,7 @@ void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
     req->sense_len = 18;
 }
 
-int32_t scsi_req_enqueue(SCSIRequest *req)
+int32_t scsi_req_enqueue(SCSIRequest *req, QEMUSGList *sg)
 {
     int32_t rc;
 
@@ -634,6 +635,7 @@ int32_t scsi_req_enqueue(SCSIRequest *req)
     scsi_req_ref(req);
     req->enqueued = true;
     QTAILQ_INSERT_TAIL(&req->dev->requests, req, next);
+    req->sg = sg;
 
     scsi_req_ref(req);
     rc = req->ops->send_command(req, req->cmd.buf);
@@ -1256,14 +1258,32 @@ void scsi_req_continue(SCSIRequest *req)
    Once it completes, calling scsi_req_continue will restart I/O.  */
 void scsi_req_data(SCSIRequest *req, int len)
 {
+    uint8_t *buf;
     if (req->io_canceled) {
         trace_scsi_req_data_canceled(req->dev->id, req->lun, req->tag, len);
         return;
     }
     trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
     assert(req->cmd.mode != SCSI_XFER_NONE);
-    req->resid -= len;
-    req->bus->info->transfer_data(req, len);
+    if (!req->sg) {
+        req->resid -= len;
+        req->bus->info->transfer_data(req, len);
+        return;
+    }
+
+    /* If the device calls scsi_req_data and the HBA specified a
+     * scatter/gather list, the transfer has to happen in a single
+     * step.  */
+    assert(!req->dma_started);
+    req->dma_started = true;
+
+    buf = scsi_req_get_buf(req);
+    if (req->cmd.mode == SCSI_XFER_FROM_DEV) {
+        req->resid = dma_buf_read(buf, len, req->sg);
+    } else {
+        req->resid = dma_buf_write(buf, len, req->sg);
+    }
+    scsi_req_continue(req);
 }
 
 void scsi_req_print(SCSIRequest *req)
diff --git a/hw/scsi.h b/hw/scsi.h
index 27ca087..8d84c8f 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -50,6 +50,8 @@ struct SCSIRequest {
     size_t            resid;
     SCSICommand       cmd;
     BlockDriverAIOCB  *aiocb;
+    QEMUSGList        *sg;
+    bool              dma_started;
     uint8_t sense[SCSI_SENSE_BUF_SIZE];
     uint32_t sense_len;
     bool enqueued;
@@ -187,7 +189,7 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
                             uint32_t tag, uint32_t lun, void *hba_private);
 SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
                           uint8_t *buf, void *hba_private);
-int32_t scsi_req_enqueue(SCSIRequest *req);
+int32_t scsi_req_enqueue(SCSIRequest *req, QEMUSGList *qsg);
 void scsi_req_free(SCSIRequest *req);
 SCSIRequest *scsi_req_ref(SCSIRequest *req);
 void scsi_req_unref(SCSIRequest *req);
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index c28bba9..fe4ca65 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -624,7 +624,7 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
 
     req->lun = lun;
     req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, req);
-    n = scsi_req_enqueue(req->sreq);
+    n = scsi_req_enqueue(req->sreq, NULL);
 
     dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n",
             req->qtag, srp->cmd.cdb[0], id, lun, n);
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 1c7bc82..68a9f53 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -377,7 +377,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
             s->residue = 0;
             s->scsi_len = 0;
             s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL);
-            scsi_req_enqueue(s->req);
+            scsi_req_enqueue(s->req, NULL);
             if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) {
                 scsi_req_continue(s->req);
             }
-- 
1.7.7.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 07/11] scsi-disk: enable scatter/gather functionality
  2011-12-06 11:01 [Qemu-devel] [PATCH 00/11] virtio-scsi device model Paolo Bonzini
                   ` (5 preceding siblings ...)
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 06/11] scsi: add scatter/gather functionality Paolo Bonzini
@ 2011-12-06 11:01 ` Paolo Bonzini
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 08/11] virtio-scsi: Add virtio-scsi stub device Paolo Bonzini
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Paolo Bonzini @ 2011-12-06 11:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/scsi-disk.c |   63 ++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 50 insertions(+), 13 deletions(-)

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 505accd..1640d2d 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -38,6 +38,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 #include "sysemu.h"
 #include "blockdev.h"
 #include "block_int.h"
+#include "dma.h"
 
 #ifdef __linux
 #include <scsi/sg.h>
@@ -123,6 +124,27 @@ static uint32_t scsi_init_iovec(SCSIDiskReq *r)
     return r->qiov.size / 512;
 }
 
+static void scsi_dma_complete(void *opaque, int ret)
+{
+    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+    bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+
+    if (ret) {
+        if (scsi_handle_rw_error(r, -ret)) {
+            goto done;
+        }
+    }
+
+    r->sector += r->sector_count;
+    r->sector_count = 0;
+    scsi_req_complete(&r->req, GOOD);
+
+done:
+    scsi_req_unref(&r->req);
+}
+
 static void scsi_read_complete(void * opaque, int ret)
 {
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
@@ -213,10 +235,17 @@ static void scsi_read_data(SCSIRequest *req)
         return;
     }
 
-    n = scsi_init_iovec(r);
-    bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
-    r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n,
-                              scsi_read_complete, r);
+    if (r->req.sg) {
+        dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ);
+        r->req.resid -= r->req.sg->size;
+        r->req.aiocb = dma_bdrv_read(s->qdev.conf.bs, r->req.sg, r->sector,
+                                     scsi_dma_complete, r);
+    } else {
+        n = scsi_init_iovec(r);
+        bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+        r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n,
+                                      scsi_read_complete, r);
+    }
 }
 
 /*
@@ -315,18 +344,26 @@ static void scsi_write_data(SCSIRequest *req)
         return;
     }
 
-    n = r->qiov.size / 512;
-    if (n) {
-        if (s->tray_open) {
-            scsi_write_complete(r, -ENOMEDIUM);
-            return;
-        }
+    if (!r->req.sg && !r->qiov.size) {
+        /* Called for the first time.  Ask the driver to send us more data.  */
+        scsi_write_complete(r, 0);
+        return;
+    }
+    if (s->tray_open) {
+        scsi_write_complete(r, -ENOMEDIUM);
+        return;
+    }
+
+    if (r->req.sg) {
+        dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_WRITE);
+        r->req.resid -= r->req.sg->size;
+        r->req.aiocb = dma_bdrv_write(s->qdev.conf.bs, r->req.sg, r->sector,
+                                      scsi_dma_complete, r);
+    } else {
+        n = r->qiov.size / 512;
         bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
         r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, r->sector, &r->qiov, n,
                                        scsi_write_complete, r);
-    } else {
-        /* Called for the first time.  Ask the driver to send us more data.  */
-        scsi_write_complete(r, 0);
     }
 }
 
-- 
1.7.7.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 08/11] virtio-scsi: Add virtio-scsi stub device
  2011-12-06 11:01 [Qemu-devel] [PATCH 00/11] virtio-scsi device model Paolo Bonzini
                   ` (6 preceding siblings ...)
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 07/11] scsi-disk: enable " Paolo Bonzini
@ 2011-12-06 11:01 ` Paolo Bonzini
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 09/11] virtio-scsi: Add basic request processing infrastructure Paolo Bonzini
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Paolo Bonzini @ 2011-12-06 11:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha

From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>

Add a useless virtio SCSI HBA device:

  qemu -device virtio-scsi-pci

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 Makefile.target                   |    1 +
 default-configs/pci.mak           |    1 +
 default-configs/s390x-softmmu.mak |    1 +
 hw/pci.h                          |    1 +
 hw/s390-virtio-bus.c              |   24 ++++
 hw/s390-virtio-bus.h              |    2 +
 hw/virtio-pci.c                   |   41 +++++++
 hw/virtio-pci.h                   |    2 +
 hw/virtio-scsi.c                  |  227 +++++++++++++++++++++++++++++++++++++
 hw/virtio-scsi.h                  |   36 ++++++
 hw/virtio.h                       |    3 +
 11 files changed, 339 insertions(+), 0 deletions(-)
 create mode 100644 hw/virtio-scsi.c
 create mode 100644 hw/virtio-scsi.h

diff --git a/Makefile.target b/Makefile.target
index a111521..f3bc562 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -199,6 +199,7 @@ obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o ioport.o
 # need to fix this properly
 obj-$(CONFIG_NO_PCI) += pci-stub.o
 obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
+obj-$(CONFIG_VIRTIO_SCSI) += virtio-scsi.o
 obj-y += vhost_net.o
 obj-$(CONFIG_VHOST_NET) += vhost.o
 obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index 22bd350..9c8edd4 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -1,5 +1,6 @@
 CONFIG_PCI=y
 CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_SCSI=y
 CONFIG_VIRTIO=y
 CONFIG_USB_UHCI=y
 CONFIG_USB_OHCI=y
diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak
index 3005729..e588803 100644
--- a/default-configs/s390x-softmmu.mak
+++ b/default-configs/s390x-softmmu.mak
@@ -1 +1,2 @@
 CONFIG_VIRTIO=y
+CONFIG_VIRTIO_SCSI=y
diff --git a/hw/pci.h b/hw/pci.h
index 625e717..767bcd4 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -75,6 +75,7 @@
 #define PCI_DEVICE_ID_VIRTIO_BLOCK       0x1001
 #define PCI_DEVICE_ID_VIRTIO_BALLOON     0x1002
 #define PCI_DEVICE_ID_VIRTIO_CONSOLE     0x1003
+#define PCI_DEVICE_ID_VIRTIO_SCSI        0x1004
 
 #define FMT_PCIBUS                      PRIx64
 
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index c4b9a99..2da52c2 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -158,6 +158,18 @@ static int s390_virtio_serial_init(VirtIOS390Device *dev)
     return r;
 }
 
+static int s390_virtio_scsi_init(VirtIOS390Device *dev)
+{
+    VirtIODevice *vdev;
+
+    vdev = virtio_scsi_init((DeviceState *)dev, &dev->scsi);
+    if (!vdev) {
+        return -1;
+    }
+
+    return s390_virtio_device_init(dev, vdev);
+}
+
 static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq)
 {
     ram_addr_t token_off;
@@ -370,6 +382,17 @@ static VirtIOS390DeviceInfo s390_virtio_serial = {
     },
 };
 
+static VirtIOS390DeviceInfo s390_virtio_scsi = {
+    .init = s390_virtio_scsi_init,
+    .qdev.name = "virtio-scsi-s390",
+    .qdev.alias = "virtio-scsi",
+    .qdev.size = sizeof(VirtIOS390Device),
+    .qdev.props = (Property[]) {
+        DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOS390Device, host_features, scsi),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
 static int s390_virtio_busdev_init(DeviceState *dev, DeviceInfo *info)
 {
     VirtIOS390DeviceInfo *_info = (VirtIOS390DeviceInfo *)info;
@@ -392,6 +415,7 @@ static void s390_virtio_register(void)
     s390_virtio_bus_register_withprop(&s390_virtio_serial);
     s390_virtio_bus_register_withprop(&s390_virtio_blk);
     s390_virtio_bus_register_withprop(&s390_virtio_net);
+    s390_virtio_bus_register_withprop(&s390_virtio_scsi);
 }
 device_init(s390_virtio_register);
 
diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h
index f1bece7..a840936 100644
--- a/hw/s390-virtio-bus.h
+++ b/hw/s390-virtio-bus.h
@@ -19,6 +19,7 @@
 
 #include "virtio-net.h"
 #include "virtio-serial.h"
+#include "virtio-scsi.h"
 
 #define VIRTIO_DEV_OFFS_TYPE		0	/* 8 bits */
 #define VIRTIO_DEV_OFFS_NUM_VQ		1	/* 8 bits */
@@ -47,6 +48,7 @@ typedef struct VirtIOS390Device {
     uint32_t host_features;
     virtio_serial_conf serial;
     virtio_net_conf net;
+    VirtIOSCSIConf scsi;
 } VirtIOS390Device;
 
 typedef struct VirtIOS390Bus {
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 64c6a94..5ba018f 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -19,6 +19,7 @@
 #include "virtio-blk.h"
 #include "virtio-net.h"
 #include "virtio-serial.h"
+#include "virtio-scsi.h"
 #include "pci.h"
 #include "qemu-error.h"
 #include "msix.h"
@@ -779,6 +780,32 @@ static int virtio_balloon_exit_pci(PCIDevice *pci_dev)
     return virtio_exit_pci(pci_dev);
 }
 
+static int virtio_scsi_init_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
+
+    vdev = virtio_scsi_init(&pci_dev->qdev, &proxy->scsi);
+    if (!vdev) {
+        return -EINVAL;
+    }
+
+    vdev->nvectors = proxy->nvectors;
+    virtio_init_pci(proxy, vdev);
+
+    /* make the actual value visible */
+    proxy->nvectors = vdev->nvectors;
+    return 0;
+}
+
+static int virtio_scsi_exit_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    virtio_scsi_exit(proxy->vdev);
+    return virtio_exit_pci(pci_dev);
+}
+
 static PCIDeviceInfo virtio_info[] = {
     {
         .qdev.name = "virtio-blk-pci",
@@ -864,6 +891,20 @@ static PCIDeviceInfo virtio_info[] = {
         },
         .qdev.reset = virtio_pci_reset,
     },{
+        .qdev.name = "virtio-scsi-pci",
+        .qdev.size = sizeof(VirtIOPCIProxy),
+        .init      = virtio_scsi_init_pci,
+        .exit      = virtio_scsi_exit_pci,
+        .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+        .device_id = PCI_DEVICE_ID_VIRTIO_SCSI,
+        .class_id  = PCI_CLASS_STORAGE_SCSI,
+        .revision  = 0x00,
+        .qdev.props = (Property[]) {
+            DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+            DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOPCIProxy, host_features, scsi),
+            DEFINE_PROP_END_OF_LIST(),
+        },
+    }, {
         /* end of list */
     }
 };
diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h
index f8404de..20523af 100644
--- a/hw/virtio-pci.h
+++ b/hw/virtio-pci.h
@@ -17,6 +17,7 @@
 
 #include "virtio-net.h"
 #include "virtio-serial.h"
+#include "virtio-scsi.h"
 
 /* Performance improves when virtqueue kick processing is decoupled from the
  * vcpu thread using ioeventfd for some devices. */
@@ -40,6 +41,7 @@ typedef struct {
 #endif
     virtio_serial_conf serial;
     virtio_net_conf net;
+    VirtIOSCSIConf scsi;
     bool ioeventfd_disabled;
     bool ioeventfd_started;
 } VirtIOPCIProxy;
diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
new file mode 100644
index 0000000..a807a28
--- /dev/null
+++ b/hw/virtio-scsi.c
@@ -0,0 +1,227 @@
+/*
+ * Virtio SCSI HBA
+ *
+ * Copyright IBM, Corp. 2010
+ * Copyright Red Hat, Inc. 2011
+ *
+ * Authors:
+ *   Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
+ *   Paolo Bonzini      <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "virtio-scsi.h"
+#include <hw/scsi.h>
+#include <hw/scsi-defs.h>
+
+#define VIRTIO_SCSI_VQ_SIZE     128
+#define VIRTIO_SCSI_CDB_SIZE    32
+#define VIRTIO_SCSI_SENSE_SIZE  96
+#define VIRTIO_SCSI_MAX_CHANNEL 0
+#define VIRTIO_SCSI_MAX_TARGET  255
+#define VIRTIO_SCSI_MAX_LUN     16383
+
+/* Response codes */
+#define VIRTIO_SCSI_S_OK                       0
+#define VIRTIO_SCSI_S_UNDERRUN                 1
+#define VIRTIO_SCSI_S_ABORTED                  2
+#define VIRTIO_SCSI_S_BAD_TARGET               3
+#define VIRTIO_SCSI_S_RESET                    4
+#define VIRTIO_SCSI_S_BUSY                     5
+#define VIRTIO_SCSI_S_TRANSPORT_FAILURE        6
+#define VIRTIO_SCSI_S_TARGET_FAILURE           7
+#define VIRTIO_SCSI_S_NEXUS_FAILURE            8
+#define VIRTIO_SCSI_S_FAILURE                  9
+#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED       10
+#define VIRTIO_SCSI_S_FUNCTION_REJECTED        11
+#define VIRTIO_SCSI_S_INCORRECT_LUN            12
+
+/* Controlq type codes.  */
+#define VIRTIO_SCSI_T_TMF                      0
+#define VIRTIO_SCSI_T_AN_QUERY                 1
+#define VIRTIO_SCSI_T_AN_SUBSCRIBE             2
+
+/* Valid TMF subtypes.  */
+#define VIRTIO_SCSI_T_TMF_ABORT_TASK           0
+#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET       1
+#define VIRTIO_SCSI_T_TMF_CLEAR_ACA            2
+#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET       3
+#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET      4
+#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET   5
+#define VIRTIO_SCSI_T_TMF_QUERY_TASK           6
+#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET       7
+
+/* Events.  */
+#define VIRTIO_SCSI_T_EVENTS_MISSED            0x80000000
+#define VIRTIO_SCSI_T_NO_EVENT                 0
+#define VIRTIO_SCSI_T_TRANSPORT_RESET          1
+#define VIRTIO_SCSI_T_ASYNC_NOTIFY             2
+
+/* SCSI command request, followed by data-out */
+typedef struct {
+    uint8_t lun[8];              /* Logical Unit Number */
+    uint64_t tag;                /* Command identifier */
+    uint8_t task_attr;           /* Task attribute */
+    uint8_t prio;
+    uint8_t crn;
+    uint8_t cdb[];
+} QEMU_PACKED VirtIOSCSICmdReq;
+
+/* Response, followed by sense data and data-in */
+typedef struct {
+    uint32_t sense_len;          /* Sense data length */
+    uint32_t resid;              /* Residual bytes in data buffer */
+    uint16_t status_qualifier;   /* Status qualifier */
+    uint8_t status;              /* Command completion status */
+    uint8_t response;            /* Response values */
+    uint8_t sense[];
+} QEMU_PACKED VirtIOSCSICmdResp;
+
+/* Task Management Request */
+typedef struct {
+    uint32_t type;
+    uint32_t subtype;
+    uint8_t lun[8];
+    uint64_t tag;
+} QEMU_PACKED VirtIOSCSICtrlTMFReq;
+
+typedef struct {
+    uint8_t response;
+} QEMU_PACKED VirtIOSCSICtrlTMFResp;
+
+/* Asynchronous notification query/subscription */
+typedef struct {
+    uint32_t type;
+    uint8_t lun[8];
+    uint32_t event_requested;
+} QEMU_PACKED VirtIOSCSICtrlANReq;
+
+typedef struct {
+    uint32_t event_actual;
+    uint8_t response;
+} QEMU_PACKED VirtIOSCSICtrlANResp;
+
+typedef struct {
+    uint32_t event;
+    uint8_t lun[8];
+    uint32_t reason;
+} QEMU_PACKED VirtIOSCSIEvent;
+
+typedef struct {
+    uint32_t num_queues;
+    uint32_t seg_max;
+    uint32_t max_sectors;
+    uint32_t cmd_per_lun;
+    uint32_t event_info_size;
+    uint32_t sense_size;
+    uint32_t cdb_size;
+    uint16_t max_channel;
+    uint16_t max_target;
+    uint32_t max_lun;
+} QEMU_PACKED VirtIOSCSIConfig;
+
+typedef struct {
+    VirtIODevice vdev;
+    DeviceState *qdev;
+    VirtIOSCSIConf *conf;
+
+    VirtQueue *ctrl_vq;
+    VirtQueue *event_vq;
+    VirtQueue *cmd_vq;
+    uint32_t sense_size;
+    uint32_t cdb_size;
+} VirtIOSCSI;
+
+static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
+{
+    /* TODO */
+}
+
+static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
+{
+    /* TODO */
+}
+
+static void virtio_scsi_get_config(VirtIODevice *vdev,
+                                   uint8_t *config)
+{
+    VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
+    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
+
+    stl_raw(&scsiconf->num_queues, s->conf->num_queues);
+    stl_raw(&scsiconf->seg_max, 128 - 2);
+    stl_raw(&scsiconf->max_sectors, s->conf->max_sectors);
+    stl_raw(&scsiconf->cmd_per_lun, s->conf->cmd_per_lun);
+    stl_raw(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
+    stl_raw(&scsiconf->sense_size, s->sense_size);
+    stl_raw(&scsiconf->cdb_size, s->cdb_size);
+    stl_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
+    stl_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
+    stl_raw(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
+}
+
+static void virtio_scsi_set_config(VirtIODevice *vdev,
+                                   const uint8_t *config)
+{
+    VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
+    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
+
+    if ((uint32_t) ldl_raw(&scsiconf->sense_size) >= 65536 ||
+        (uint32_t) ldl_raw(&scsiconf->cdb_size) >= 256) {
+        error_report("bad data written to virtio-scsi configuration space");
+        exit(1);
+    }
+
+    s->sense_size = ldl_raw(&scsiconf->sense_size);
+    s->cdb_size = ldl_raw(&scsiconf->cdb_size);
+}
+
+static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
+                                         uint32_t requested_features)
+{
+    return requested_features;
+}
+
+static void virtio_scsi_reset(VirtIODevice *vdev)
+{
+    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
+
+    s->sense_size = VIRTIO_SCSI_SENSE_SIZE;
+    s->cdb_size = VIRTIO_SCSI_CDB_SIZE;
+}
+
+VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf)
+{
+    VirtIOSCSI *s;
+
+    s = (VirtIOSCSI *)virtio_common_init("virtio-scsi", VIRTIO_ID_SCSI,
+                                         sizeof(VirtIOSCSIConfig),
+                                         sizeof(VirtIOSCSI));
+
+    s->qdev = dev;
+    s->conf = proxyconf;
+
+    s->vdev.get_config = virtio_scsi_get_config;
+    s->vdev.set_config = virtio_scsi_set_config;
+    s->vdev.get_features = virtio_scsi_get_features;
+    s->vdev.reset = virtio_scsi_reset;
+
+    s->ctrl_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
+                                   virtio_scsi_handle_ctrl);
+    s->event_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
+                                   NULL);
+    s->cmd_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
+                                   virtio_scsi_handle_cmd);
+
+    /* TODO savevm */
+
+    return &s->vdev;
+}
+
+void virtio_scsi_exit(VirtIODevice *vdev)
+{
+    virtio_cleanup(vdev);
+}
diff --git a/hw/virtio-scsi.h b/hw/virtio-scsi.h
new file mode 100644
index 0000000..72928ab
--- /dev/null
+++ b/hw/virtio-scsi.h
@@ -0,0 +1,36 @@
+/*
+ * Virtio SCSI HBA
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _QEMU_VIRTIO_SCSI_H
+#define _QEMU_VIRTIO_SCSI_H
+
+#include "virtio.h"
+#include "net.h"
+#include "pci.h"
+
+/* The ID for virtio_scsi */
+#define VIRTIO_ID_SCSI  7
+
+struct VirtIOSCSIConf {
+    uint32_t num_queues;
+    uint32_t max_sectors;
+    uint32_t cmd_per_lun;
+};
+
+#define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _features_field, _conf_field) \
+    DEFINE_VIRTIO_COMMON_FEATURES(_state, _features_field), \
+    DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1), \
+    DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 0xFFFF), \
+    DEFINE_PROP_UINT32("cmd_per_lun", _state, _conf_field.cmd_per_lun, 128)
+
+#endif /* _QEMU_VIRTIO_SCSI_H */
diff --git a/hw/virtio.h b/hw/virtio.h
index 25f5564..400c092 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -199,6 +199,8 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
 typedef struct virtio_serial_conf virtio_serial_conf;
 VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial);
 VirtIODevice *virtio_balloon_init(DeviceState *dev);
+typedef struct VirtIOSCSIConf VirtIOSCSIConf;
+VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf);
 #ifdef CONFIG_LINUX
 VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf);
 #endif
@@ -208,6 +210,7 @@ void virtio_net_exit(VirtIODevice *vdev);
 void virtio_blk_exit(VirtIODevice *vdev);
 void virtio_serial_exit(VirtIODevice *vdev);
 void virtio_balloon_exit(VirtIODevice *vdev);
+void virtio_scsi_exit(VirtIODevice *vdev);
 
 #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
 	DEFINE_PROP_BIT("indirect_desc", _state, _field, \
-- 
1.7.7.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 09/11] virtio-scsi: Add basic request processing infrastructure
  2011-12-06 11:01 [Qemu-devel] [PATCH 00/11] virtio-scsi device model Paolo Bonzini
                   ` (7 preceding siblings ...)
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 08/11] virtio-scsi: Add virtio-scsi stub device Paolo Bonzini
@ 2011-12-06 11:01 ` Paolo Bonzini
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 10/11] virtio-scsi: add basic SCSI bus operation Paolo Bonzini
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Paolo Bonzini @ 2011-12-06 11:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha

From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/virtio-scsi.c |  142 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 140 insertions(+), 2 deletions(-)

diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index a807a28..c86e15e 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -135,14 +135,152 @@ typedef struct {
     uint32_t cdb_size;
 } VirtIOSCSI;
 
+typedef struct VirtIOSCSIReq {
+    VirtIOSCSI *dev;
+    VirtQueue *vq;
+    VirtQueueElement elem;
+    QEMUSGList qsgl;
+    SCSIRequest *sreq;
+    union {
+        char                  *buf;
+        VirtIOSCSICmdReq      *cmd;
+        VirtIOSCSICtrlTMFReq  *tmf;
+        VirtIOSCSICtrlANReq   *an;
+    } req;
+    union {
+        char                  *buf;
+        VirtIOSCSICmdResp     *cmd;
+        VirtIOSCSICtrlTMFResp *tmf;
+        VirtIOSCSICtrlANResp  *an;
+        VirtIOSCSIEvent       *event;
+    } resp;
+} VirtIOSCSIReq;
+
+static void virtio_scsi_complete_req(VirtIOSCSIReq *req)
+{
+    VirtIOSCSI *s = req->dev;
+    VirtQueue *vq = req->vq;
+    virtqueue_push(vq, &req->elem, req->qsgl.size + req->elem.in_sg[0].iov_len);
+    qemu_sglist_destroy(&req->qsgl);
+    if (req->sreq) {
+        req->sreq->hba_private = NULL;
+        scsi_req_unref(req->sreq);
+    }
+    g_free(req);
+    virtio_notify(&s->vdev, vq);
+}
+
+static void virtio_scsi_bad_req(void)
+{
+    error_report("wrong size for virtio-scsi headers");
+    exit(1);
+}
+
+static void qemu_sgl_init_external(QEMUSGList *qsgl, struct iovec *sg,
+                                   target_phys_addr_t *addr, int num)
+{
+    memset(qsgl, 0, sizeof(*qsgl));
+    while (num--) {
+        qemu_sglist_add(qsgl, *(addr++), (sg++)->iov_len);
+    }
+}
+
+static void virtio_scsi_parse_req(VirtIOSCSI *s, VirtQueue *vq,
+                                  VirtIOSCSIReq *req)
+{
+    assert(req->elem.out_num && req->elem.in_num);
+    req->vq = vq;
+    req->dev = s;
+    req->sreq = NULL;
+    req->req.buf = req->elem.out_sg[0].iov_base;
+    req->resp.buf = req->elem.in_sg[0].iov_base;
+
+    if (req->elem.out_num > 1) {
+        qemu_sgl_init_external(&req->qsgl, &req->elem.out_sg[1],
+                               &req->elem.out_addr[1],
+                               req->elem.out_num - 1);
+    } else {
+        qemu_sgl_init_external(&req->qsgl, &req->elem.in_sg[1],
+                               &req->elem.in_addr[1],
+                               req->elem.in_num - 1);
+    }
+}
+
+static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
+{
+    VirtIOSCSIReq *req;
+    req = g_malloc(sizeof(*req));
+    if (!virtqueue_pop(vq, &req->elem)) {
+        g_free(req);
+        return NULL;
+    }
+
+    virtio_scsi_parse_req(s, vq, req);
+    return req;
+}
+
+static void virtio_scsi_fail_ctrl_req(VirtIOSCSIReq *req)
+{
+    if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) {
+        req->resp.tmf->response = VIRTIO_SCSI_S_FAILURE;
+    } else {
+        req->resp.an->response = VIRTIO_SCSI_S_FAILURE;
+    }
+
+    virtio_scsi_complete_req(req);
+}
+
 static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
 {
-    /* TODO */
+    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
+    VirtIOSCSIReq *req;
+
+    while ((req = virtio_scsi_pop_req(s, vq))) {
+        virtio_scsi_fail_ctrl_req(req);
+    }
+}
+
+static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req)
+{
+    req->resp.cmd->response = VIRTIO_SCSI_S_FAILURE;
+    virtio_scsi_complete_req(req);
 }
 
 static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
 {
-    /* TODO */
+    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
+    VirtIOSCSIReq *req;
+
+    while ((req = virtio_scsi_pop_req(s, vq))) {
+        int out_size, in_size;
+        if (req->elem.out_num < 1 || req->elem.in_num < 1) {
+            virtio_scsi_bad_req();
+        }
+
+        out_size = req->elem.out_sg[0].iov_len;
+        in_size = req->elem.in_sg[0].iov_len;
+        if (out_size < sizeof(VirtIOSCSICmdReq) + s->cdb_size ||
+            in_size < sizeof(VirtIOSCSICmdResp) + s->sense_size) {
+            virtio_scsi_bad_req();
+        }
+
+        if (req->elem.out_num > 1 && req->elem.in_num > 1) {
+            virtio_scsi_fail_cmd_req(req);
+            continue;
+        }
+
+        req->resp.cmd->resid = 0;
+        req->resp.cmd->status_qualifier = 0;
+        req->resp.cmd->status = CHECK_CONDITION;
+        req->resp.cmd->sense_len = 4;
+        req->resp.cmd->sense[0] = 0xf0; /* Fixed format current sense */
+        req->resp.cmd->sense[1] = ILLEGAL_REQUEST;
+        req->resp.cmd->sense[2] = 0x20;
+        req->resp.cmd->sense[3] = 0x00;
+        req->resp.cmd->response = VIRTIO_SCSI_S_OK;
+
+        virtio_scsi_complete_req(req);
+    }
 }
 
 static void virtio_scsi_get_config(VirtIODevice *vdev,
-- 
1.7.7.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 10/11] virtio-scsi: add basic SCSI bus operation
  2011-12-06 11:01 [Qemu-devel] [PATCH 00/11] virtio-scsi device model Paolo Bonzini
                   ` (8 preceding siblings ...)
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 09/11] virtio-scsi: Add basic request processing infrastructure Paolo Bonzini
@ 2011-12-06 11:01 ` Paolo Bonzini
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 11/11] virtio-scsi: process control queue requests Paolo Bonzini
  2012-01-12  5:17 ` [Qemu-devel] [PATCH 00/11] virtio-scsi device model Hu Tao
  11 siblings, 0 replies; 15+ messages in thread
From: Paolo Bonzini @ 2011-12-06 11:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/virtio-scsi.c |  101 +++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 89 insertions(+), 11 deletions(-)

diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index c86e15e..dbb4003 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -128,6 +128,7 @@ typedef struct {
     DeviceState *qdev;
     VirtIOSCSIConf *conf;
 
+    SCSIBus bus;
     VirtQueue *ctrl_vq;
     VirtQueue *event_vq;
     VirtQueue *cmd_vq;
@@ -156,6 +157,22 @@ typedef struct VirtIOSCSIReq {
     } resp;
 } VirtIOSCSIReq;
 
+static inline int virtio_scsi_get_lun(uint8_t *lun)
+{
+    return ((lun[2] << 8) | lun[3]) & 0x3FFF;
+}
+
+static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun)
+{
+    if (lun[0] != 1) {
+        return NULL;
+    }
+    if (lun[2] != 0 && !(lun[2] >= 0x40 && lun[2] < 0x80)) {
+        return NULL;
+    }
+    return scsi_device_find(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun));
+}
+
 static void virtio_scsi_complete_req(VirtIOSCSIReq *req)
 {
     VirtIOSCSI *s = req->dev;
@@ -240,6 +257,36 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
     }
 }
 
+static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
+                                         int32_t resid)
+{
+    VirtIOSCSIReq *req = r->hba_private;
+
+    req->resp.cmd->response = VIRTIO_SCSI_S_OK;
+    req->resp.cmd->status = status;
+    if (req->resp.cmd->status == GOOD) {
+        req->resp.cmd->resid = resid;
+        if (resid) {
+            req->resp.cmd->response = VIRTIO_SCSI_S_UNDERRUN;
+        }
+    } else {
+       req->resp.cmd->resid = 0;
+       scsi_req_get_sense(r, req->resp.cmd->sense, VIRTIO_SCSI_SENSE_SIZE);
+    }
+    virtio_scsi_complete_req(req);
+}
+
+static void virtio_scsi_request_cancelled(SCSIRequest *r)
+{
+    VirtIOSCSIReq *req = r->hba_private;
+
+    if (!req) {
+        return;
+    }
+    req->resp.cmd->response = VIRTIO_SCSI_S_ABORTED;
+    virtio_scsi_complete_req(req);
+}
+
 static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req)
 {
     req->resp.cmd->response = VIRTIO_SCSI_S_FAILURE;
@@ -250,8 +297,10 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
 {
     VirtIOSCSI *s = (VirtIOSCSI *)vdev;
     VirtIOSCSIReq *req;
+    int n;
 
     while ((req = virtio_scsi_pop_req(s, vq))) {
+        SCSIDevice *d;
         int out_size, in_size;
         if (req->elem.out_num < 1 || req->elem.in_num < 1) {
             virtio_scsi_bad_req();
@@ -265,18 +314,32 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
             virtio_scsi_fail_cmd_req(req);
             continue;
         }
+
+        d = virtio_scsi_device_find(s, req->req.cmd->lun);
+        if (!d) {
+            req->resp.cmd->response = VIRTIO_SCSI_S_BAD_TARGET;
+            virtio_scsi_complete_req(req);
+            continue;
+        }
+        req->sreq = scsi_req_new(d, req->req.cmd->tag,
+                                 virtio_scsi_get_lun(req->req.cmd->lun),
+                                 req->req.cmd->cdb, req);
+
+        if (req->sreq->cmd.mode != SCSI_XFER_NONE) {
+            int req_mode =
+                (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV);
+
+            if (req->sreq->cmd.mode != req_mode) {
+                virtio_scsi_fail_cmd_req(req);
+                scsi_req_cancel(req->sreq);
+                continue;
+            }
+        }
 
-        req->resp.cmd->resid = 0;
-        req->resp.cmd->status_qualifier = 0;
-        req->resp.cmd->status = CHECK_CONDITION;
-        req->resp.cmd->sense_len = 4;
-        req->resp.cmd->sense[0] = 0xf0; /* Fixed format current sense */
-        req->resp.cmd->sense[1] = ILLEGAL_REQUEST;
-        req->resp.cmd->sense[2] = 0x20;
-        req->resp.cmd->sense[3] = 0x00;
-        req->resp.cmd->response = VIRTIO_SCSI_S_OK;
-
-        virtio_scsi_complete_req(req);
+        n = scsi_req_enqueue(req->sreq, &req->qsgl);
+        if (n) {
+            scsi_req_continue(req->sreq);
+        }
     }
 }
 
@@ -331,6 +394,16 @@ static void virtio_scsi_reset(VirtIODevice *vdev)
     s->cdb_size = VIRTIO_SCSI_CDB_SIZE;
 }
 
+static struct SCSIBusInfo virtio_scsi_scsi_info = {
+    .tcq = true,
+    .max_channel = VIRTIO_SCSI_MAX_CHANNEL,
+    .max_target = VIRTIO_SCSI_MAX_TARGET,
+    .max_lun = VIRTIO_SCSI_MAX_LUN,
+
+    .complete = virtio_scsi_command_complete,
+    .cancel = virtio_scsi_request_cancelled,
+};
+
 VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf)
 {
     VirtIOSCSI *s;
@@ -355,6 +428,11 @@ VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf)
     s->cmd_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
                                    virtio_scsi_handle_cmd);
 
+    scsi_bus_new(&s->bus, dev, &virtio_scsi_scsi_info);
+    if (!dev->hotplugged) {
+        scsi_bus_legacy_handle_cmdline(&s->bus);
+    }
+
     /* TODO savevm */
 
     return &s->vdev;
-- 
1.7.7.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 11/11] virtio-scsi: process control queue requests
  2011-12-06 11:01 [Qemu-devel] [PATCH 00/11] virtio-scsi device model Paolo Bonzini
                   ` (9 preceding siblings ...)
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 10/11] virtio-scsi: add basic SCSI bus operation Paolo Bonzini
@ 2011-12-06 11:01 ` Paolo Bonzini
  2012-01-12  5:17 ` [Qemu-devel] [PATCH 00/11] virtio-scsi device model Hu Tao
  11 siblings, 0 replies; 15+ messages in thread
From: Paolo Bonzini @ 2011-12-06 11:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/virtio-scsi.c |  128 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 120 insertions(+), 8 deletions(-)

diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index dbb4003..601a646 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -134,6 +134,7 @@ typedef struct {
     VirtQueue *cmd_vq;
     uint32_t sense_size;
     uint32_t cdb_size;
+    bool resetting;
 } VirtIOSCSI;
 
 typedef struct VirtIOSCSIReq {
@@ -236,15 +237,98 @@ static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
     return req;
 }
 
-static void virtio_scsi_fail_ctrl_req(VirtIOSCSIReq *req)
+static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
 {
-    if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) {
-        req->resp.tmf->response = VIRTIO_SCSI_S_FAILURE;
-    } else {
-        req->resp.an->response = VIRTIO_SCSI_S_FAILURE;
+    SCSIDevice *d = virtio_scsi_device_find(s, req->req.cmd->lun);
+    SCSIRequest *r, *next;
+    DeviceState *qdev;
+    int target;
+
+    switch (req->req.tmf->subtype) {
+    case VIRTIO_SCSI_T_TMF_ABORT_TASK:
+    case VIRTIO_SCSI_T_TMF_QUERY_TASK:
+        d = virtio_scsi_device_find(s, req->req.cmd->lun);
+        if (!d) {
+            goto fail;
+        }
+        if (d->lun != virtio_scsi_get_lun(req->req.cmd->lun)) {
+            req->resp.tmf->response = VIRTIO_SCSI_S_INCORRECT_LUN;
+            break;
+        }
+        QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
+            if (r->tag == req->req.cmd->tag) {
+                break;
+            }
+        }
+        if (r && r->hba_private) {
+            if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_ABORT_TASK) {
+                scsi_req_cancel(r);
+            }
+            req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
+        } else {
+            req->resp.tmf->response = VIRTIO_SCSI_S_OK;
+        }
+        break;
+
+    case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
+        d = virtio_scsi_device_find(s, req->req.cmd->lun);
+        if (!d) {
+            goto fail;
+        }
+        if (d->lun == virtio_scsi_get_lun(req->req.cmd->lun)) {
+            s->resetting++;
+            qdev_reset_all(&d->qdev);
+            s->resetting--;
+        }
+        break;
+
+    case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
+    case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET:
+    case VIRTIO_SCSI_T_TMF_QUERY_TASK_SET:
+        d = virtio_scsi_device_find(s, req->req.cmd->lun);
+        if (!d) {
+            goto fail;
+        }
+        if (d->lun != virtio_scsi_get_lun(req->req.cmd->lun)) {
+            req->resp.tmf->response = VIRTIO_SCSI_S_INCORRECT_LUN;
+            break;
+        }
+        req->resp.tmf->response = VIRTIO_SCSI_S_OK;
+        QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
+            if (r->hba_private) {
+                if (req->req.tmf->subtype != VIRTIO_SCSI_T_TMF_QUERY_TASK) {
+                    scsi_req_cancel(r);
+                }
+                req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
+            }
+        }
+        break;
+
+    case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
+        target = req->req.cmd->lun[1];
+        s->resetting++;
+        QTAILQ_FOREACH(qdev, &s->bus.qbus.children, sibling) {
+             d = DO_UPCAST(SCSIDevice, qdev, qdev);
+             if (d->channel == 0 && d->id == target) {
+                qdev_reset_all(&d->qdev);
+             }
+        }
+        s->resetting--;
+        break;
+
+    case VIRTIO_SCSI_T_TMF_CLEAR_ACA:
+        req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
+        break;
+
+    default:
+        req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_REJECTED;
+        break;
     }
 
-    virtio_scsi_complete_req(req);
+    return;
+
+fail:
+    req->resp.tmf->response = VIRTIO_SCSI_S_BAD_TARGET;
 }
 
 static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
@@ -253,7 +334,31 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
     VirtIOSCSIReq *req;
 
     while ((req = virtio_scsi_pop_req(s, vq))) {
-        virtio_scsi_fail_ctrl_req(req);
+        int out_size, in_size;
+        if (req->elem.out_num < 1 || req->elem.in_num < 1) {
+            virtio_scsi_bad_req();
+            continue;
+        }
+
+        out_size = req->elem.out_sg[0].iov_len;
+        in_size = req->elem.in_sg[0].iov_len;
+        if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) {
+            if (out_size < sizeof(VirtIOSCSICtrlTMFReq) ||
+                in_size < sizeof(VirtIOSCSICtrlTMFResp)) {
+                virtio_scsi_bad_req();
+            }
+            virtio_scsi_do_tmf(s, req);
+
+        } else if (req->req.tmf->type == VIRTIO_SCSI_T_AN_QUERY ||
+                   req->req.tmf->type == VIRTIO_SCSI_T_AN_SUBSCRIBE) {
+            if (out_size < sizeof(VirtIOSCSICtrlANReq) ||
+                in_size < sizeof(VirtIOSCSICtrlANResp)) {
+                virtio_scsi_bad_req();
+            }
+            req->resp.an->event_actual = 0;
+            req->resp.an->response = VIRTIO_SCSI_S_OK;
+        }
+        virtio_scsi_complete_req(req);
     }
 }
 
@@ -283,7 +388,11 @@ static void virtio_scsi_request_cancelled(SCSIRequest *r)
     if (!req) {
         return;
     }
-    req->resp.cmd->response = VIRTIO_SCSI_S_ABORTED;
+    if (req->dev->resetting) {
+        req->resp.cmd->response = VIRTIO_SCSI_S_RESET;
+    } else {
+        req->resp.cmd->response = VIRTIO_SCSI_S_ABORTED;
+    }
     virtio_scsi_complete_req(req);
 }
 
-- 
1.7.7.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 00/11] virtio-scsi device model
  2011-12-06 11:01 [Qemu-devel] [PATCH 00/11] virtio-scsi device model Paolo Bonzini
                   ` (10 preceding siblings ...)
  2011-12-06 11:01 ` [Qemu-devel] [PATCH 11/11] virtio-scsi: process control queue requests Paolo Bonzini
@ 2012-01-12  5:17 ` Hu Tao
  2012-01-12  9:47   ` Paolo Bonzini
  11 siblings, 1 reply; 15+ messages in thread
From: Hu Tao @ 2012-01-12  5:17 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, stefanha

Hi Paolo,

How to add a virtio-scsi device? What parameters should I specify
in qemu command line?

-- 
Thanks,
Hu Tao

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 00/11] virtio-scsi device model
  2012-01-12  5:17 ` [Qemu-devel] [PATCH 00/11] virtio-scsi device model Hu Tao
@ 2012-01-12  9:47   ` Paolo Bonzini
  2012-01-13  0:33     ` Hu Tao
  0 siblings, 1 reply; 15+ messages in thread
From: Paolo Bonzini @ 2012-01-12  9:47 UTC (permalink / raw)
  To: Hu Tao; +Cc: qemu-devel, stefanha

On 01/12/2012 06:17 AM, Hu Tao wrote:
> Hi Paolo,
>
> How to add a virtio-scsi device? What parameters should I specify
> in qemu command line?

Same as with other SCSI devices:

   -device virtio-scsi-pci

then for every disk

   -drive if=none,file=PATH,id=NAME
   -device scsi-hd,drive=NAME

(or scsi-cd for a CD-ROM drive).

Paolo

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 00/11] virtio-scsi device model
  2012-01-12  9:47   ` Paolo Bonzini
@ 2012-01-13  0:33     ` Hu Tao
  0 siblings, 0 replies; 15+ messages in thread
From: Hu Tao @ 2012-01-13  0:33 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, stefanha

On Thu, Jan 12, 2012 at 10:47:48AM +0100, Paolo Bonzini wrote:
> On 01/12/2012 06:17 AM, Hu Tao wrote:
> >Hi Paolo,
> >
> >How to add a virtio-scsi device? What parameters should I specify
> >in qemu command line?
> 
> Same as with other SCSI devices:
> 
>   -device virtio-scsi-pci
> 
> then for every disk
> 
>   -drive if=none,file=PATH,id=NAME
>   -device scsi-hd,drive=NAME
> 
> (or scsi-cd for a CD-ROM drive).

Thank you. I'll have a try.

-- 
Thanks,
Hu Tao

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2012-01-13  0:33 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-12-06 11:01 [Qemu-devel] [PATCH 00/11] virtio-scsi device model Paolo Bonzini
2011-12-06 11:01 ` [Qemu-devel] [PATCH 01/11] qiov: prevent double free or use-after-free Paolo Bonzini
2011-12-06 11:01 ` [Qemu-devel] [PATCH 02/11] dma-helpers: make QEMUSGList target independent Paolo Bonzini
2011-12-06 11:01 ` [Qemu-devel] [PATCH 03/11] dma-helpers: add dma_buf_read and dma_buf_write Paolo Bonzini
2011-12-06 11:01 ` [Qemu-devel] [PATCH 04/11] dma-helpers: add accounting wrappers Paolo Bonzini
2011-12-06 11:01 ` [Qemu-devel] [PATCH 05/11] scsi: pass residual amount to command_complete Paolo Bonzini
2011-12-06 11:01 ` [Qemu-devel] [PATCH 06/11] scsi: add scatter/gather functionality Paolo Bonzini
2011-12-06 11:01 ` [Qemu-devel] [PATCH 07/11] scsi-disk: enable " Paolo Bonzini
2011-12-06 11:01 ` [Qemu-devel] [PATCH 08/11] virtio-scsi: Add virtio-scsi stub device Paolo Bonzini
2011-12-06 11:01 ` [Qemu-devel] [PATCH 09/11] virtio-scsi: Add basic request processing infrastructure Paolo Bonzini
2011-12-06 11:01 ` [Qemu-devel] [PATCH 10/11] virtio-scsi: add basic SCSI bus operation Paolo Bonzini
2011-12-06 11:01 ` [Qemu-devel] [PATCH 11/11] virtio-scsi: process control queue requests Paolo Bonzini
2012-01-12  5:17 ` [Qemu-devel] [PATCH 00/11] virtio-scsi device model Hu Tao
2012-01-12  9:47   ` Paolo Bonzini
2012-01-13  0:33     ` Hu Tao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).