* [Qemu-devel] [PATCH v3 01/15] dma-helpers: make QEMUSGList target independent
2012-02-13 17:10 [Qemu-devel] [PATCH v3 00/15] SCSI s/g + SCSI migration + virtio-scsi Paolo Bonzini
@ 2012-02-13 17:10 ` Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 02/15] dma-helpers: add dma_buf_read and dma_buf_write Paolo Bonzini
` (13 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2012-02-13 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, christian.hoff, kvm
scsi-disk will manage scatter/gather list, but it does not create
single entries so it remains target-independent. Make QEMUSGList
available to it.
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.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH v3 02/15] dma-helpers: add dma_buf_read and dma_buf_write
2012-02-13 17:10 [Qemu-devel] [PATCH v3 00/15] SCSI s/g + SCSI migration + virtio-scsi Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 01/15] dma-helpers: make QEMUSGList target independent Paolo Bonzini
@ 2012-02-13 17:10 ` Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 03/15] dma-helpers: add accounting wrappers Paolo Bonzini
` (12 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2012-02-13 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, christian.hoff, kvm
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.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH v3 03/15] dma-helpers: add accounting wrappers
2012-02-13 17:10 [Qemu-devel] [PATCH v3 00/15] SCSI s/g + SCSI migration + virtio-scsi Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 01/15] dma-helpers: make QEMUSGList target independent Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 02/15] dma-helpers: add dma_buf_read and dma_buf_write Paolo Bonzini
@ 2012-02-13 17:10 ` Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 04/15] ahci: use new DMA helpers Paolo Bonzini
` (11 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2012-02-13 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, christian.hoff, kvm
The length of the transfer is already in the sglist, the wrapper simply
fetches it.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
dma-helpers.c | 6 ++++++
dma.h | 3 +++
2 files changed, 9 insertions(+), 0 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
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH v3 04/15] ahci: use new DMA helpers
2012-02-13 17:10 [Qemu-devel] [PATCH v3 00/15] SCSI s/g + SCSI migration + virtio-scsi Paolo Bonzini
` (2 preceding siblings ...)
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 03/15] dma-helpers: add accounting wrappers Paolo Bonzini
@ 2012-02-13 17:10 ` Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 05/15] scsi: pass residual amount to command_complete Paolo Bonzini
` (10 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2012-02-13 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, christian.hoff, kvm
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/ide/ahci.c | 82 +++++++++------------------------------------------------
1 files changed, 13 insertions(+), 69 deletions(-)
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index c87a6ca..25ed844 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -426,55 +426,6 @@ static void ahci_reg_init(AHCIState *s)
}
}
-static uint32_t read_from_sglist(uint8_t *buffer, uint32_t len,
- QEMUSGList *sglist)
-{
- uint32_t i = 0;
- uint32_t total = 0, once;
- ScatterGatherEntry *cur_prd;
- uint32_t sgcount;
-
- cur_prd = sglist->sg;
- sgcount = sglist->nsg;
- for (i = 0; len && sgcount; i++) {
- once = MIN(cur_prd->len, len);
- cpu_physical_memory_read(cur_prd->base, buffer, once);
- cur_prd++;
- sgcount--;
- len -= once;
- buffer += once;
- total += once;
- }
-
- return total;
-}
-
-static uint32_t write_to_sglist(uint8_t *buffer, uint32_t len,
- QEMUSGList *sglist)
-{
- uint32_t i = 0;
- uint32_t total = 0, once;
- ScatterGatherEntry *cur_prd;
- uint32_t sgcount;
-
- DPRINTF(-1, "total: 0x%x bytes\n", len);
-
- cur_prd = sglist->sg;
- sgcount = sglist->nsg;
- for (i = 0; len && sgcount; i++) {
- once = MIN(cur_prd->len, len);
- DPRINTF(-1, "write 0x%x bytes to 0x%lx\n", once, (long)cur_prd->base);
- cpu_physical_memory_write(cur_prd->base, buffer, once);
- cur_prd++;
- sgcount--;
- len -= once;
- buffer += once;
- total += once;
- }
-
- return total;
-}
-
static void check_cmd(AHCIState *s, int port)
{
AHCIPortRegs *pr = &s->dev[port].port_regs;
@@ -795,9 +746,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);
@@ -809,9 +759,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);
@@ -1016,12 +965,12 @@ static int ahci_start_transfer(IDEDMA *dma)
is_write ? "writ" : "read", size, is_atapi ? "atapi" : "ata",
has_sglist ? "" : "o");
- if (is_write && has_sglist && (s->data_ptr < s->data_end)) {
- read_from_sglist(s->data_ptr, size, &s->sg);
- }
-
- if (!is_write && has_sglist && (s->data_ptr < s->data_end)) {
- write_to_sglist(s->data_ptr, size, &s->sg);
+ if (has_sglist && size) {
+ if (is_write) {
+ dma_buf_write(s->data_ptr, size, &s->sg);
+ } else {
+ dma_buf_read(s->data_ptr, size, &s->sg);
+ }
}
/* update number of transferred bytes */
@@ -1060,14 +1009,9 @@ static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write)
{
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
IDEState *s = &ad->port.ifs[0];
- int i;
ahci_populate_sglist(ad, &s->sg);
-
- s->io_buffer_size = 0;
- for (i = 0; i < s->sg.nsg; i++) {
- s->io_buffer_size += s->sg.sg[i].len;
- }
+ s->io_buffer_size = s->sg.size;
DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
return s->io_buffer_size != 0;
@@ -1085,9 +1029,9 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
}
if (is_write) {
- write_to_sglist(p, l, &s->sg);
+ dma_buf_read(p, l, &s->sg);
} else {
- read_from_sglist(p, l, &s->sg);
+ dma_buf_write(p, l, &s->sg);
}
/* update number of transferred bytes */
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH v3 05/15] scsi: pass residual amount to command_complete
2012-02-13 17:10 [Qemu-devel] [PATCH v3 00/15] SCSI s/g + SCSI migration + virtio-scsi Paolo Bonzini
` (3 preceding siblings ...)
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 04/15] ahci: use new DMA helpers Paolo Bonzini
@ 2012-02-13 17:10 ` Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 06/15] scsi: add scatter/gather functionality Paolo Bonzini
` (9 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2012-02-13 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, christian.hoff, kvm
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>
---
v2->v3: fixed resid type (Stefan)
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 2f44386..991e091 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -390,7 +390,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,
+ size_t resid)
{
ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent);
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 9a7ffe3..e36fe35 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, size_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 0ee50a8..6a069f4 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -533,6 +533,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]);
@@ -1275,10 +1277,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)
@@ -1337,7 +1341,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 dc72b6f..e1c52d2 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -46,6 +46,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];
@@ -112,7 +113,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, size_t resid);
void (*cancel)(SCSIRequest *req);
};
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 9cfce19..d7123df 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, size_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 6153376..47b8b8e 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, size_t resid)
{
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
USBPacket *p = s->packet;
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH v3 06/15] scsi: add scatter/gather functionality
2012-02-13 17:10 [Qemu-devel] [PATCH v3 00/15] SCSI s/g + SCSI migration + virtio-scsi Paolo Bonzini
` (4 preceding siblings ...)
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 05/15] scsi: pass residual amount to command_complete Paolo Bonzini
@ 2012-02-13 17:10 ` Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 07/15] scsi-disk: enable " Paolo Bonzini
` (8 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2012-02-13 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, christian.hoff, kvm
Scatter/gather functionality uses the newly added DMA helpers. The
device can choose between doing DMA itself, or calling scsi_req_data
as usual, which will use the newly added DMA helpers to copy piecewise
to/from the destination area(s).
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi-bus.c | 28 ++++++++++++++++++++++++++--
hw/scsi.h | 3 +++
2 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 6a069f4..69cb3fc 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);
@@ -651,6 +652,11 @@ int32_t scsi_req_enqueue(SCSIRequest *req)
assert(!req->enqueued);
scsi_req_ref(req);
+ if (req->bus->info->get_sg_list) {
+ req->sg = req->bus->info->get_sg_list(req);
+ } else {
+ req->sg = NULL;
+ }
req->enqueued = true;
QTAILQ_INSERT_TAIL(&req->dev->requests, req, next);
@@ -1275,14 +1281,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 e1c52d2..811f61c 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -49,6 +49,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;
@@ -115,6 +117,7 @@ struct SCSIBusInfo {
void (*transfer_data)(SCSIRequest *req, uint32_t arg);
void (*complete)(SCSIRequest *req, uint32_t arg, size_t resid);
void (*cancel)(SCSIRequest *req);
+ QEMUSGList *(*get_sg_list)(SCSIRequest *req);
};
struct SCSIBus {
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH v3 07/15] scsi-disk: enable scatter/gather functionality
2012-02-13 17:10 [Qemu-devel] [PATCH v3 00/15] SCSI s/g + SCSI migration + virtio-scsi Paolo Bonzini
` (5 preceding siblings ...)
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 06/15] scsi: add scatter/gather functionality Paolo Bonzini
@ 2012-02-13 17:10 ` Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 08/15] scsi: add SCSIDevice vmstate definitions Paolo Bonzini
` (7 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2012-02-13 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, christian.hoff, kvm
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi-bus.c | 1 +
hw/scsi-disk.c | 63 ++++++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 51 insertions(+), 13 deletions(-)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 69cb3fc..817aa49 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -87,6 +87,7 @@ static void scsi_dma_restart_bh(void *opaque)
scsi_req_continue(req);
break;
case SCSI_XFER_NONE:
+ assert(!req->sg);
scsi_req_dequeue(req);
scsi_req_enqueue(req);
break;
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 399e51e..0e4d6ad 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.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH v3 08/15] scsi: add SCSIDevice vmstate definitions
2012-02-13 17:10 [Qemu-devel] [PATCH v3 00/15] SCSI s/g + SCSI migration + virtio-scsi Paolo Bonzini
` (6 preceding siblings ...)
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 07/15] scsi-disk: enable " Paolo Bonzini
@ 2012-02-13 17:10 ` Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 09/15] scsi-generic: add migration support Paolo Bonzini
` (6 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2012-02-13 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, christian.hoff, kvm
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi-bus.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
hw/scsi.h | 16 ++++++++
2 files changed, 120 insertions(+), 3 deletions(-)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 817aa49..15841d0 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -647,10 +647,8 @@ void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
req->sense_len = 18;
}
-int32_t scsi_req_enqueue(SCSIRequest *req)
+static void scsi_req_enqueue_internal(SCSIRequest *req)
{
- int32_t rc;
-
assert(!req->enqueued);
scsi_req_ref(req);
if (req->bus->info->get_sg_list) {
@@ -660,7 +658,14 @@ int32_t scsi_req_enqueue(SCSIRequest *req)
}
req->enqueued = true;
QTAILQ_INSERT_TAIL(&req->dev->requests, req, next);
+}
+int32_t scsi_req_enqueue(SCSIRequest *req)
+{
+ int32_t rc;
+
+ assert(!req->retry);
+ scsi_req_enqueue_internal(req);
scsi_req_ref(req);
rc = req->ops->send_command(req, req->cmd.buf);
scsi_req_unref(req);
@@ -1442,6 +1447,102 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
return target_dev;
}
+/* SCSI request list. For simplicity, pv points to the whole device */
+
+static void put_scsi_requests(QEMUFile *f, void *pv, size_t size)
+{
+ SCSIDevice *s = pv;
+ SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus);
+ SCSIRequest *req;
+
+ QTAILQ_FOREACH(req, &s->requests, next) {
+ assert(!req->io_canceled);
+ assert(req->status == -1);
+ assert(req->retry);
+ assert(req->enqueued);
+
+ qemu_put_sbyte(f, 1);
+ qemu_put_buffer(f, req->cmd.buf, sizeof(req->cmd.buf));
+ qemu_put_be32s(f, &req->tag);
+ qemu_put_be32s(f, &req->lun);
+ if (bus->info->save_request) {
+ bus->info->save_request(f, req);
+ }
+ if (req->ops->save_request) {
+ req->ops->save_request(f, req);
+ }
+ }
+ qemu_put_sbyte(f, 0);
+}
+
+static int get_scsi_requests(QEMUFile *f, void *pv, size_t size)
+{
+ SCSIDevice *s = pv;
+ SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus);
+
+ while (qemu_get_sbyte(f)) {
+ uint8_t buf[SCSI_CMD_BUF_SIZE];
+ uint32_t tag;
+ uint32_t lun;
+ SCSIRequest *req;
+
+ qemu_get_buffer(f, buf, sizeof(buf));
+ qemu_get_be32s(f, &tag);
+ qemu_get_be32s(f, &lun);
+ req = scsi_req_new(s, tag, lun, buf, NULL);
+ if (bus->info->load_request) {
+ req->hba_private = bus->info->load_request(f, req);
+ }
+ if (req->ops->load_request) {
+ req->ops->load_request(f, req);
+ }
+
+ /* Just restart it later. */
+ req->retry = true;
+ scsi_req_enqueue_internal(req);
+
+ /* At this point, the request will be kept alive by the reference
+ * added by scsi_req_enqueue_internal, so we can release our reference.
+ * The HBA of course will add its own reference in the load_request
+ * callback if it needs to hold on the SCSIRequest.
+ */
+ scsi_req_unref(req);
+ }
+
+ return 0;
+}
+
+const VMStateInfo vmstate_info_scsi_requests = {
+ .name = "scsi-requests",
+ .get = get_scsi_requests,
+ .put = put_scsi_requests,
+};
+
+const VMStateDescription vmstate_scsi_device = {
+ .name = "SCSIDevice",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(unit_attention.key, SCSIDevice),
+ VMSTATE_UINT8(unit_attention.asc, SCSIDevice),
+ VMSTATE_UINT8(unit_attention.ascq, SCSIDevice),
+ VMSTATE_BOOL(sense_is_ua, SCSIDevice),
+ VMSTATE_UINT8_ARRAY(sense, SCSIDevice, SCSI_SENSE_BUF_SIZE),
+ VMSTATE_UINT32(sense_len, SCSIDevice),
+ {
+ .name = "requests",
+ .version_id = 0,
+ .field_exists = NULL,
+ .size = 0, /* ouch */
+ .info = &vmstate_info_scsi_requests,
+ .flags = VMS_SINGLE,
+ .offset = 0,
+ },
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void scsi_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
diff --git a/hw/scsi.h b/hw/scsi.h
index 811f61c..c6624ca 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -96,6 +96,16 @@ struct SCSIDevice
uint64_t max_lba;
};
+extern const VMStateDescription vmstate_scsi_device;
+
+#define VMSTATE_SCSI_DEVICE(_field, _state) { \
+ .name = (stringify(_field)), \
+ .size = sizeof(SCSIDevice), \
+ .vmsd = &vmstate_scsi_device, \
+ .flags = VMS_STRUCT, \
+ .offset = vmstate_offset_value(_state, _field, SCSIDevice), \
+}
+
/* cdrom.c */
int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num);
@@ -109,6 +119,9 @@ struct SCSIReqOps {
void (*write_data)(SCSIRequest *req);
void (*cancel_io)(SCSIRequest *req);
uint8_t *(*get_buf)(SCSIRequest *req);
+
+ void (*save_request)(QEMUFile *f, SCSIRequest *req);
+ void (*load_request)(QEMUFile *f, SCSIRequest *req);
};
struct SCSIBusInfo {
@@ -118,6 +131,9 @@ struct SCSIBusInfo {
void (*complete)(SCSIRequest *req, uint32_t arg, size_t resid);
void (*cancel)(SCSIRequest *req);
QEMUSGList *(*get_sg_list)(SCSIRequest *req);
+
+ void (*save_request)(QEMUFile *f, SCSIRequest *req);
+ void *(*load_request)(QEMUFile *f, SCSIRequest *req);
};
struct SCSIBus {
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH v3 09/15] scsi-generic: add migration support
2012-02-13 17:10 [Qemu-devel] [PATCH v3 00/15] SCSI s/g + SCSI migration + virtio-scsi Paolo Bonzini
` (7 preceding siblings ...)
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 08/15] scsi: add SCSIDevice vmstate definitions Paolo Bonzini
@ 2012-02-13 17:10 ` Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 10/15] scsi-disk: " Paolo Bonzini
` (5 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2012-02-13 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, christian.hoff, kvm
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi-generic.c | 25 +++++++++++++++++++++++++
1 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 4859212..cd62922 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -59,6 +59,28 @@ typedef struct SCSIGenericReq {
sg_io_hdr_t io_header;
} SCSIGenericReq;
+static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req)
+{
+ SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+
+ qemu_put_sbe32s(f, &r->buflen);
+ if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+ assert(!r->req.sg);
+ qemu_put_buffer(f, r->buf, r->req.cmd.xfer);
+ }
+}
+
+static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req)
+{
+ SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+
+ qemu_get_sbe32s(f, &r->buflen);
+ if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+ assert(!r->req.sg);
+ qemu_get_buffer(f, r->buf, r->req.cmd.xfer);
+ }
+}
+
static void scsi_free_request(SCSIRequest *req)
{
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
@@ -446,6 +468,8 @@ const SCSIReqOps scsi_generic_req_ops = {
.write_data = scsi_write_data,
.cancel_io = scsi_cancel_io,
.get_buf = scsi_get_buf,
+ .load_request = scsi_generic_load_request,
+ .save_request = scsi_generic_save_request,
};
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
@@ -474,6 +498,7 @@ static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
dc->desc = "pass through generic scsi device (/dev/sg*)";
dc->reset = scsi_generic_reset;
dc->props = scsi_generic_properties;
+ dc->vmsd = &vmstate_scsi_device;
}
static TypeInfo scsi_generic_info = {
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH v3 10/15] scsi-disk: add migration support
2012-02-13 17:10 [Qemu-devel] [PATCH v3 00/15] SCSI s/g + SCSI migration + virtio-scsi Paolo Bonzini
` (8 preceding siblings ...)
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 09/15] scsi-generic: add migration support Paolo Bonzini
@ 2012-02-13 17:10 ` Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 11/15] virtio-scsi: Add virtio-scsi stub device Paolo Bonzini
` (4 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2012-02-13 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, christian.hoff, kvm
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi-disk.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 55 insertions(+), 4 deletions(-)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 0e4d6ad..4d7b4eb 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -111,12 +111,12 @@ static void scsi_cancel_io(SCSIRequest *req)
r->req.aiocb = NULL;
}
-static uint32_t scsi_init_iovec(SCSIDiskReq *r)
+static uint32_t scsi_init_iovec(SCSIDiskReq *r, size_t size)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
if (!r->iov.iov_base) {
- r->buflen = SCSI_DMA_BUF_SIZE;
+ r->buflen = size;
r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
}
r->iov.iov_len = MIN(r->sector_count * 512, r->buflen);
@@ -124,6 +124,35 @@ static uint32_t scsi_init_iovec(SCSIDiskReq *r)
return r->qiov.size / 512;
}
+static void scsi_disk_save_request(QEMUFile *f, SCSIRequest *req)
+{
+ SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+
+ qemu_put_be64s(f, &r->sector);
+ qemu_put_be32s(f, &r->sector_count);
+ qemu_put_be32s(f, &r->buflen);
+ if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+ qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len);
+ }
+}
+
+static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req)
+{
+ SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+
+ qemu_get_be64s(f, &r->sector);
+ qemu_get_be32s(f, &r->sector_count);
+ qemu_get_be32s(f, &r->buflen);
+ if (r->buflen) {
+ scsi_init_iovec(r, r->buflen);
+ if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+ qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len);
+ }
+ }
+
+ qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+}
+
static void scsi_dma_complete(void *opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
@@ -241,7 +270,7 @@ static void scsi_read_data(SCSIRequest *req)
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);
+ n = scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
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);
@@ -316,7 +345,7 @@ static void scsi_write_complete(void * opaque, int ret)
if (r->sector_count == 0) {
scsi_req_complete(&r->req, GOOD);
} else {
- scsi_init_iovec(r);
+ scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size);
scsi_req_data(&r->req, r->qiov.size);
}
@@ -1621,6 +1650,8 @@ static const SCSIReqOps scsi_disk_reqops = {
.write_data = scsi_write_data,
.cancel_io = scsi_cancel_io,
.get_buf = scsi_get_buf,
+ .load_request = scsi_disk_load_request,
+ .save_request = scsi_disk_save_request,
};
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
@@ -1755,6 +1786,22 @@ static Property scsi_hd_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static const VMStateDescription vmstate_scsi_disk_state = {
+ .name = "scsi-disk",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_SCSI_DEVICE(qdev, SCSIDiskState),
+ VMSTATE_BOOL(media_changed, SCSIDiskState),
+ VMSTATE_BOOL(media_event, SCSIDiskState),
+ VMSTATE_BOOL(eject_request, SCSIDiskState),
+ VMSTATE_BOOL(tray_open, SCSIDiskState),
+ VMSTATE_BOOL(tray_locked, SCSIDiskState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void scsi_hd_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1768,6 +1815,7 @@ static void scsi_hd_class_initfn(ObjectClass *klass, void *data)
dc->desc = "virtual SCSI disk";
dc->reset = scsi_disk_reset;
dc->props = scsi_hd_properties;
+ dc->vmsd = &vmstate_scsi_disk_state;
}
static TypeInfo scsi_hd_info = {
@@ -1795,6 +1843,7 @@ static void scsi_cd_class_initfn(ObjectClass *klass, void *data)
dc->desc = "virtual SCSI CD-ROM";
dc->reset = scsi_disk_reset;
dc->props = scsi_cd_properties;
+ dc->vmsd = &vmstate_scsi_disk_state;
}
static TypeInfo scsi_cd_info = {
@@ -1822,6 +1871,7 @@ static void scsi_block_class_initfn(ObjectClass *klass, void *data)
dc->desc = "SCSI block device passthrough";
dc->reset = scsi_disk_reset;
dc->props = scsi_block_properties;
+ dc->vmsd = &vmstate_scsi_disk_state;
}
static TypeInfo scsi_block_info = {
@@ -1851,6 +1901,7 @@ static void scsi_disk_class_initfn(ObjectClass *klass, void *data)
dc->desc = "virtual SCSI disk or CD-ROM (legacy)";
dc->reset = scsi_disk_reset;
dc->props = scsi_disk_properties;
+ dc->vmsd = &vmstate_scsi_disk_state;
}
static TypeInfo scsi_disk_info = {
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH v3 11/15] virtio-scsi: Add virtio-scsi stub device
2012-02-13 17:10 [Qemu-devel] [PATCH v3 00/15] SCSI s/g + SCSI migration + virtio-scsi Paolo Bonzini
` (9 preceding siblings ...)
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 10/15] scsi-disk: " Paolo Bonzini
@ 2012-02-13 17:10 ` Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 12/15] virtio-scsi: Add basic request processing infrastructure Paolo Bonzini
` (3 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2012-02-13 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, christian.hoff, Stefan Hajnoczi, kvm
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>
Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
v2->v3: changed virtio id
Makefile.target | 1 +
default-configs/pci.mak | 1 +
default-configs/s390x-softmmu.mak | 1 +
hw/pci.h | 1 +
hw/s390-virtio-bus.c | 34 ++++++
hw/s390-virtio-bus.h | 4 +-
hw/virtio-pci.c | 56 +++++++++
hw/virtio-pci.h | 2 +
hw/virtio-scsi.c | 228 +++++++++++++++++++++++++++++++++++++
hw/virtio-scsi.h | 36 ++++++
hw/virtio.h | 3 +
11 files changed, 366 insertions(+), 1 deletions(-)
create mode 100644 hw/virtio-scsi.c
create mode 100644 hw/virtio-scsi.h
diff --git a/Makefile.target b/Makefile.target
index 29fde6e..c8f61d6 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -200,6 +200,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 9d3e1db..21e4ccf 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 33b0b18..ff4c12d 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 49140f8..3515abc 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -169,6 +169,39 @@ 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 Property virtio_scsi_properties[] = {
+ DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOPCIProxy, host_features, scsi),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void s390_virtio_scsi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
+
+ k->init = s390_virtio_scsi_init;
+ dc->props = s390_virtio_scsi_properties;
+}
+
+static DeviceInfo virtio_scsi_info = {
+ .name = "virtio-scsi-s390",
+ .parent = TYPE_VIRTIO_S390_DEVICE,
+ .instance_size = sizeof(VirtIOS390Device),
+ .class_init = s390_virtio_scsi_class_init,
+};
+
static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq)
{
ram_addr_t token_off;
@@ -439,6 +472,7 @@ static void s390_virtio_register(void)
type_register_static(&s390_virtio_serial);
type_register_static(&s390_virtio_blk);
type_register_static(&s390_virtio_net);
+ type_register_static(&s390_virtio_scsi);
}
device_init(s390_virtio_register);
diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h
index b5e59b7..ef534b6 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 */
@@ -67,7 +68,8 @@ struct VirtIOS390Device {
uint32_t host_features;
virtio_serial_conf serial;
virtio_net_conf net;
-};
+ VirtIOSCSIConf scsi;
+} VirtIOS390Device;
typedef struct VirtIOS390Bus {
BusState bus;
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 93fff54..08e63a6 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -21,6 +21,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"
@@ -930,12 +931,67 @@ static TypeInfo virtio_balloon_info = {
.class_init = virtio_balloon_class_init,
};
+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 Property virtio_scsi_properties[] = {
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+ DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOPCIProxy, host_features, scsi),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_scsi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_scsi_init_pci;
+ k->exit = virtio_scsi_exit_pci;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_STORAGE_SCSI;
+ dc->reset = virtio_pci_reset;
+ dc->props = virtio_scsi_properties;
+}
+
+static TypeInfo virtio_scsi_info = {
+ .name = "virtio-scsi-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VirtIOPCIProxy),
+ .class_init = virtio_scsi_class_init,
+};
+
static void virtio_pci_register_devices(void)
{
type_register_static(&virtio_blk_info);
type_register_static(&virtio_net_info);
type_register_static(&virtio_serial_info);
type_register_static(&virtio_balloon_info);
+ type_register_static(&virtio_scsi_info);
}
device_init(virtio_pci_register_devices)
diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h
index 344c22b..e560428 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..7ebfba7
--- /dev/null
+++ b/hw/virtio-scsi.c
@@ -0,0 +1,228 @@
+/*
+ * 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_OVERRUN 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;
+
+ /* TODO set up vdev function pointers */
+ 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..4bc889d
--- /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 8
+
+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.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH v3 12/15] virtio-scsi: Add basic request processing infrastructure
2012-02-13 17:10 [Qemu-devel] [PATCH v3 00/15] SCSI s/g + SCSI migration + virtio-scsi Paolo Bonzini
` (10 preceding siblings ...)
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 11/15] virtio-scsi: Add virtio-scsi stub device Paolo Bonzini
@ 2012-02-13 17:10 ` Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 13/15] virtio-scsi: add basic SCSI bus operation Paolo Bonzini
` (2 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2012-02-13 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, christian.hoff, Stefan Hajnoczi, kvm
From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Reviewed-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 7ebfba7..b34c14f 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(VirtIOSCSI *s, 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(s, 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.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH v3 13/15] virtio-scsi: add basic SCSI bus operation
2012-02-13 17:10 [Qemu-devel] [PATCH v3 00/15] SCSI s/g + SCSI migration + virtio-scsi Paolo Bonzini
` (11 preceding siblings ...)
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 12/15] virtio-scsi: Add basic request processing infrastructure Paolo Bonzini
@ 2012-02-13 17:10 ` Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 14/15] virtio-scsi: process control queue requests Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 15/15] virtio-scsi: add migration support Paolo Bonzini
14 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2012-02-13 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, christian.hoff, kvm
Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
v2->v3: fixed sense length (Christian Hoff)
hw/virtio-scsi.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 97 insertions(+), 13 deletions(-)
diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index b34c14f..21264a1 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,7 +257,42 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
}
}
-static void virtio_scsi_fail_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req)
+static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
+ size_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;
+ } else {
+ req->resp.cmd->resid = 0;
+ req->resp.cmd->sense_len =
+ scsi_req_get_sense(r, req->resp.cmd->sense, VIRTIO_SCSI_SENSE_SIZE);
+ }
+ virtio_scsi_complete_req(req);
+}
+
+static QEMUSGList *virtio_scsi_get_sg_list(SCSIRequest *r)
+{
+ VirtIOSCSIReq *req = r->hba_private;
+
+ return &req->qsgl;
+}
+
+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;
virtio_scsi_complete_req(req);
@@ -250,8 +301,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,21 +318,36 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
}
if (req->elem.out_num > 1 && req->elem.in_num > 1) {
- virtio_scsi_fail_cmd_req(s, req);
+ 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);
+ 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 ||
+ req->sreq->cmd.xfer > req->qsgl.size) {
+ req->resp.cmd->response = VIRTIO_SCSI_S_OVERRUN;
+ virtio_scsi_complete_req(req);
+ continue;
+ }
+ }
+
+ n = scsi_req_enqueue(req->sreq);
+ if (n) {
+ scsi_req_continue(req->sreq);
+ }
}
}
@@ -331,6 +399,17 @@ 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,
+ .get_sg_list = virtio_scsi_get_sg_list,
+};
+
VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf)
{
VirtIOSCSI *s;
@@ -355,6 +434,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.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH v3 14/15] virtio-scsi: process control queue requests
2012-02-13 17:10 [Qemu-devel] [PATCH v3 00/15] SCSI s/g + SCSI migration + virtio-scsi Paolo Bonzini
` (12 preceding siblings ...)
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 13/15] virtio-scsi: add basic SCSI bus operation Paolo Bonzini
@ 2012-02-13 17:10 ` Paolo Bonzini
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 15/15] virtio-scsi: add migration support Paolo Bonzini
14 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2012-02-13 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, christian.hoff, kvm
Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/virtio-scsi.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 117 insertions(+), 8 deletions(-)
diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index 21264a1..7ad60ec 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,95 @@ 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:
+ 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);
}
}
@@ -287,7 +392,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.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH v3 15/15] virtio-scsi: add migration support
2012-02-13 17:10 [Qemu-devel] [PATCH v3 00/15] SCSI s/g + SCSI migration + virtio-scsi Paolo Bonzini
` (13 preceding siblings ...)
2012-02-13 17:10 ` [Qemu-devel] [PATCH v3 14/15] virtio-scsi: process control queue requests Paolo Bonzini
@ 2012-02-13 17:10 ` Paolo Bonzini
14 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2012-02-13 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, christian.hoff, kvm
Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/virtio-scsi.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 49 insertions(+), 1 deletions(-)
diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index 7ad60ec..f5cecfc 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -237,6 +237,34 @@ static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
return req;
}
+static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq)
+{
+ VirtIOSCSIReq *req = sreq->hba_private;
+
+ qemu_put_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
+}
+
+static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
+{
+ SCSIBus *bus = sreq->bus;
+ VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
+ VirtIOSCSIReq *req;
+
+ req = g_malloc(sizeof(*req));
+ qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
+ virtio_scsi_parse_req(s, s->cmd_vq, req);
+
+ scsi_req_ref(sreq);
+ req->sreq = sreq;
+ if (req->sreq->cmd.mode != SCSI_XFER_NONE) {
+ int req_mode =
+ (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV);
+
+ assert(req->sreq->cmd.mode == req_mode);
+ }
+ return req;
+}
+
static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
{
SCSIDevice *d = virtio_scsi_device_find(s, req->req.cmd->lun);
@@ -508,6 +536,22 @@ static void virtio_scsi_reset(VirtIODevice *vdev)
s->cdb_size = VIRTIO_SCSI_CDB_SIZE;
}
+/* The device does not have anything to save beyond the virtio data.
+ * Request data is saved with callbacks from SCSI devices.
+ */
+static void virtio_scsi_save(QEMUFile *f, void *opaque)
+{
+ VirtIOSCSI *s = opaque;
+ virtio_save(&s->vdev, f);
+}
+
+static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id)
+{
+ VirtIOSCSI *s = opaque;
+ virtio_load(&s->vdev, f);
+ return 0;
+}
+
static struct SCSIBusInfo virtio_scsi_scsi_info = {
.tcq = true,
.max_channel = VIRTIO_SCSI_MAX_CHANNEL,
@@ -517,11 +561,14 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = {
.complete = virtio_scsi_command_complete,
.cancel = virtio_scsi_request_cancelled,
.get_sg_list = virtio_scsi_get_sg_list,
+ .save_request = virtio_scsi_save_request,
+ .load_request = virtio_scsi_load_request,
};
VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf)
{
VirtIOSCSI *s;
+ static int virtio_scsi_id;
s = (VirtIOSCSI *)virtio_common_init("virtio-scsi", VIRTIO_ID_SCSI,
sizeof(VirtIOSCSIConfig),
@@ -548,7 +595,8 @@ VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf)
scsi_bus_legacy_handle_cmdline(&s->bus);
}
- /* TODO savevm */
+ register_savevm(dev, "virtio-scsi", virtio_scsi_id++, 1,
+ virtio_scsi_save, virtio_scsi_load, s);
return &s->vdev;
}
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread