Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 311363 Details for
Bug 415403
app-emulation/qemu-kvm-1.0.1: Reintroduce scsi support through virtio-scsi
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
RedHat's virtio-scsi patch
qemu_virtio-scsi_support.patch (text/plain), 54.65 KB, created by
Richard Yao (RETIRED)
on 2012-05-10 17:12:13 UTC
(
hide
)
Description:
RedHat's virtio-scsi patch
Filename:
MIME Type:
Creator:
Richard Yao (RETIRED)
Created:
2012-05-10 17:12:13 UTC
Size:
54.65 KB
patch
obsolete
>diff -ruNp qemu-kvm-1.0/default-configs/pci.mak qemu-kvm-1.0.virtio-scsi/default-configs/pci.mak >--- qemu-kvm-1.0/default-configs/pci.mak 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/default-configs/pci.mak 2012-02-07 14:44:53.424905251 -0600 >@@ -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 -ruNp qemu-kvm-1.0/default-configs/s390x-softmmu.mak qemu-kvm-1.0.virtio-scsi/default-configs/s390x-softmmu.mak >--- qemu-kvm-1.0/default-configs/s390x-softmmu.mak 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/default-configs/s390x-softmmu.mak 2012-02-07 14:44:53.424905251 -0600 >@@ -1 +1,2 @@ > CONFIG_VIRTIO=y >+CONFIG_VIRTIO_SCSI=y >diff -ruNp qemu-kvm-1.0/dma.h qemu-kvm-1.0.virtio-scsi/dma.h >--- qemu-kvm-1.0/dma.h 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/dma.h 2012-02-07 14:44:53.425905267 -0600 >@@ -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); >@@ -58,4 +58,10 @@ BlockDriverAIOCB *dma_bdrv_read(BlockDri > 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); >+ >+void dma_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, >+ QEMUSGList *sg, enum BlockAcctType type); >+ > #endif >diff -ruNp qemu-kvm-1.0/dma-helpers.c qemu-kvm-1.0.virtio-scsi/dma-helpers.c >--- qemu-kvm-1.0/dma-helpers.c 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/dma-helpers.c 2012-02-07 14:44:53.424905251 -0600 >@@ -196,3 +196,39 @@ BlockDriverAIOCB *dma_bdrv_write(BlockDr > { > 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); >+} >+ >+void dma_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, >+ QEMUSGList *sg, enum BlockAcctType type) >+{ >+ bdrv_acct_start(bs, cookie, sg->size, type); >+} >diff -ruNp qemu-kvm-1.0/hw/esp.c qemu-kvm-1.0.virtio-scsi/hw/esp.c >--- qemu-kvm-1.0/hw/esp.c 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/esp.c 2012-02-07 14:44:53.425905267 -0600 >@@ -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 -ruNp qemu-kvm-1.0/hw/ide/ahci.c qemu-kvm-1.0.virtio-scsi/hw/ide/ahci.c >--- qemu-kvm-1.0/hw/ide/ahci.c 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/ide/ahci.c 2012-02-07 14:44:53.426905283 -0600 >@@ -425,55 +425,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; >@@ -794,9 +745,8 @@ static void process_ncq_command(AHCIStat > 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 +758,8 @@ static void process_ncq_command(AHCIStat > 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); >@@ -1015,12 +964,12 @@ static int ahci_start_transfer(IDEDMA *d > 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 */ >@@ -1059,14 +1008,9 @@ static int ahci_dma_prepare_buf(IDEDMA * > { > 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; >@@ -1084,9 +1028,9 @@ static int ahci_dma_rw_buf(IDEDMA *dma, > } > > 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 */ >diff -ruNp qemu-kvm-1.0/hw/lsi53c895a.c qemu-kvm-1.0.virtio-scsi/hw/lsi53c895a.c >--- qemu-kvm-1.0/hw/lsi53c895a.c 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/lsi53c895a.c 2012-02-07 14:44:53.427905299 -0600 >@@ -699,7 +699,7 @@ static int lsi_queue_req(LSIState *s, SC > } > > /* 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 -ruNp qemu-kvm-1.0/hw/pci.h qemu-kvm-1.0.virtio-scsi/hw/pci.h >--- qemu-kvm-1.0/hw/pci.h 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/pci.h 2012-02-07 14:44:53.427905299 -0600 >@@ -76,6 +76,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 -ruNp qemu-kvm-1.0/hw/s390-virtio-bus.c qemu-kvm-1.0.virtio-scsi/hw/s390-virtio-bus.c >--- qemu-kvm-1.0/hw/s390-virtio-bus.c 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/s390-virtio-bus.c 2012-02-07 14:44:53.428905315 -0600 >@@ -158,6 +158,18 @@ static int s390_virtio_serial_init(VirtI > 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_ > }, > }; > >+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 -ruNp qemu-kvm-1.0/hw/s390-virtio-bus.h qemu-kvm-1.0.virtio-scsi/hw/s390-virtio-bus.h >--- qemu-kvm-1.0/hw/s390-virtio-bus.h 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/s390-virtio-bus.h 2012-02-07 14:44:53.428905315 -0600 >@@ -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 -ruNp qemu-kvm-1.0/hw/scsi-bus.c qemu-kvm-1.0.virtio-scsi/hw/scsi-bus.c >--- qemu-kvm-1.0/hw/scsi-bus.c 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/scsi-bus.c 2012-02-07 14:44:53.428905315 -0600 >@@ -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); >@@ -50,6 +51,7 @@ static void scsi_dma_restart_bh(void *op > scsi_req_continue(req); > break; > case SCSI_XFER_NONE: >+ assert(!req->sg); > scsi_req_dequeue(req); > scsi_req_enqueue(req); > break; >@@ -512,6 +514,8 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, > } > > 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]); >@@ -624,15 +628,25 @@ void scsi_req_build_sense(SCSIRequest *r > 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) { >+ req->sg = req->bus->info->get_sg_list(req); >+ } else { >+ req->sg = NULL; >+ } > 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); >@@ -1254,12 +1268,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); >- } else { >- trace_scsi_req_data(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); >+ 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) >@@ -1318,7 +1352,7 @@ void scsi_req_complete(SCSIRequest *req, > > 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); > } > >@@ -1393,3 +1427,100 @@ SCSIDevice *scsi_device_find(SCSIBus *bu > } > 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() >+ } >+}; >diff -ruNp qemu-kvm-1.0/hw/scsi-disk.c qemu-kvm-1.0.virtio-scsi/hw/scsi-disk.c >--- qemu-kvm-1.0/hw/scsi-disk.c 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/scsi-disk.c 2012-02-07 14:44:53.429905331 -0600 >@@ -38,6 +38,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , > #include "sysemu.h" > #include "blockdev.h" > #include "block_int.h" >+#include "dma.h" > > #ifdef __linux > #include <scsi/sg.h> >@@ -110,12 +111,12 @@ static void scsi_cancel_io(SCSIRequest * > 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); >@@ -123,6 +124,56 @@ static uint32_t scsi_init_iovec(SCSIDisk > 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; >+ 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 +264,17 @@ static void scsi_read_data(SCSIRequest * > 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, 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); >+ } > if (r->req.aiocb == NULL) { > scsi_read_complete(r, -EIO); > } >@@ -290,7 +348,7 @@ static void scsi_write_complete(void * o > 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); > } >@@ -318,21 +376,29 @@ static void scsi_write_data(SCSIRequest > 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); >- if (r->req.aiocb == NULL) { >- scsi_write_complete(r, -ENOMEM); >- } >- } else { >- /* Called for the first time. Ask the driver to send us more data. */ >- scsi_write_complete(r, 0); >+ } >+ if (r->req.aiocb == NULL) { >+ scsi_write_complete(r, -ENOMEM); > } > } > >@@ -1601,6 +1667,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, >@@ -1729,6 +1797,22 @@ static SCSIRequest *scsi_block_new_reque > DEFINE_PROP_STRING("ver", SCSIDiskState, version), \ > DEFINE_PROP_STRING("serial", SCSIDiskState, serial) > >+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 SCSIDeviceInfo scsi_disk_info[] = { > { > .qdev.name = "scsi-hd", >@@ -1736,6 +1820,7 @@ static SCSIDeviceInfo scsi_disk_info[] = > .qdev.desc = "virtual SCSI disk", > .qdev.size = sizeof(SCSIDiskState), > .qdev.reset = scsi_disk_reset, >+ .qdev.vmsd = &vmstate_scsi_disk_state, > .init = scsi_hd_initfn, > .destroy = scsi_destroy, > .alloc_req = scsi_new_request, >@@ -1751,6 +1836,7 @@ static SCSIDeviceInfo scsi_disk_info[] = > .qdev.desc = "virtual SCSI CD-ROM", > .qdev.size = sizeof(SCSIDiskState), > .qdev.reset = scsi_disk_reset, >+ .qdev.vmsd = &vmstate_scsi_disk_state, > .init = scsi_cd_initfn, > .destroy = scsi_destroy, > .alloc_req = scsi_new_request, >@@ -1766,6 +1852,7 @@ static SCSIDeviceInfo scsi_disk_info[] = > .qdev.desc = "SCSI block device passthrough", > .qdev.size = sizeof(SCSIDiskState), > .qdev.reset = scsi_disk_reset, >+ .qdev.vmsd = &vmstate_scsi_disk_state, > .init = scsi_block_initfn, > .destroy = scsi_destroy, > .alloc_req = scsi_block_new_request, >@@ -1780,6 +1867,7 @@ static SCSIDeviceInfo scsi_disk_info[] = > .qdev.desc = "virtual SCSI disk or CD-ROM (legacy)", > .qdev.size = sizeof(SCSIDiskState), > .qdev.reset = scsi_disk_reset, >+ .qdev.vmsd = &vmstate_scsi_disk_state, > .init = scsi_disk_initfn, > .destroy = scsi_destroy, > .alloc_req = scsi_new_request, >diff -ruNp qemu-kvm-1.0/hw/scsi-generic.c qemu-kvm-1.0.virtio-scsi/hw/scsi-generic.c >--- qemu-kvm-1.0/hw/scsi-generic.c 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/scsi-generic.c 2012-02-07 14:44:53.430905347 -0600 >@@ -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); >@@ -450,6 +472,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, >@@ -467,6 +491,7 @@ static SCSIDeviceInfo scsi_generic_info > .qdev.desc = "pass through generic scsi device (/dev/sg*)", > .qdev.size = sizeof(SCSIDevice), > .qdev.reset = scsi_generic_reset, >+ .qdev.vmsd = &vmstate_scsi_device, > .init = scsi_generic_initfn, > .destroy = scsi_destroy, > .alloc_req = scsi_new_request, >diff -ruNp qemu-kvm-1.0/hw/scsi.h qemu-kvm-1.0.virtio-scsi/hw/scsi.h >--- qemu-kvm-1.0/hw/scsi.h 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/scsi.h 2012-02-07 14:44:53.430905347 -0600 >@@ -47,8 +47,11 @@ struct SCSIRequest { > uint32_t tag; > uint32_t lun; > uint32_t status; >+ 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; >@@ -78,6 +81,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); >@@ -91,6 +104,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); > }; > > typedef int (*scsi_qdev_initfn)(SCSIDevice *dev); >@@ -107,8 +123,12 @@ 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); >+ QEMUSGList *(*get_sg_list)(SCSIRequest *req); >+ >+ void (*save_request)(QEMUFile *f, SCSIRequest *req); >+ void *(*load_request)(QEMUFile *f, SCSIRequest *req); > }; > > struct SCSIBus { >diff -ruNp qemu-kvm-1.0/hw/spapr_vscsi.c qemu-kvm-1.0.virtio-scsi/hw/spapr_vscsi.c >--- qemu-kvm-1.0/hw/spapr_vscsi.c 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/spapr_vscsi.c 2012-02-07 14:44:53.430905347 -0600 >@@ -494,7 +494,7 @@ static void vscsi_transfer_data(SCSIRequ > } > > /* 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 -ruNp qemu-kvm-1.0/hw/usb-msd.c qemu-kvm-1.0.virtio-scsi/hw/usb-msd.c >--- qemu-kvm-1.0/hw/usb-msd.c 2012-02-07 14:44:04.881123501 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/usb-msd.c 2012-02-07 14:44:53.431905363 -0600 >@@ -223,7 +223,7 @@ static void usb_msd_transfer_data(SCSIRe > } > } > >-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; >diff -ruNp qemu-kvm-1.0/hw/virtio.h qemu-kvm-1.0.virtio-scsi/hw/virtio.h >--- qemu-kvm-1.0/hw/virtio.h 2011-12-04 04:38:06.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/virtio.h 2012-02-07 14:44:53.433905395 -0600 >@@ -199,6 +199,8 @@ VirtIODevice *virtio_net_init(DeviceStat > 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, \ >diff -ruNp qemu-kvm-1.0/hw/virtio-pci.c qemu-kvm-1.0.virtio-scsi/hw/virtio-pci.c >--- qemu-kvm-1.0/hw/virtio-pci.c 2012-02-07 14:44:04.850123002 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/virtio-pci.c 2012-02-07 14:44:53.432905379 -0600 >@@ -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" >@@ -855,6 +856,32 @@ static int virtio_balloon_exit_pci(PCIDe > 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", >@@ -940,6 +967,21 @@ static PCIDeviceInfo virtio_info[] = { > }, > .qdev.reset = virtio_pci_reset, > },{ >+ .qdev.name = "virtio-scsi-pci", >+ .qdev.alias = "virtio-scsi", >+ .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 -ruNp qemu-kvm-1.0/hw/virtio-pci.h qemu-kvm-1.0.virtio-scsi/hw/virtio-pci.h >--- qemu-kvm-1.0/hw/virtio-pci.h 2012-02-07 14:44:04.850123002 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/virtio-pci.h 2012-02-07 14:44:53.432905379 -0600 >@@ -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 -ruNp qemu-kvm-1.0/hw/virtio-scsi.c qemu-kvm-1.0.virtio-scsi/hw/virtio-scsi.c >--- qemu-kvm-1.0/hw/virtio-scsi.c 1969-12-31 18:00:00.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/virtio-scsi.c 2012-02-07 14:44:53.432905379 -0600 >@@ -0,0 +1,607 @@ >+/* >+ * 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; >+ >+ SCSIBus bus; >+ VirtQueue *ctrl_vq; >+ VirtQueue *event_vq; >+ VirtQueue *cmd_vq; >+ uint32_t sense_size; >+ uint32_t cdb_size; >+ bool resetting; >+} 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 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; >+ 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_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); >+ 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; >+ } >+ >+ return; >+ >+fail: >+ req->resp.tmf->response = VIRTIO_SCSI_S_BAD_TARGET; >+} >+ >+static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) >+{ >+ 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(); >+ 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); >+ } >+} >+ >+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; >+ } 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 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; >+ } >+ 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); >+} >+ >+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) >+{ >+ 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(); >+ } >+ >+ 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; >+ } >+ >+ 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); >+ } >+ } >+} >+ >+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; >+} >+ >+/* 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, >+ .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, >+ .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), >+ 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); >+ >+ scsi_bus_new(&s->bus, dev, &virtio_scsi_scsi_info); >+ if (!dev->hotplugged) { >+ scsi_bus_legacy_handle_cmdline(&s->bus); >+ } >+ >+ register_savevm(dev, "virtio-scsi", virtio_scsi_id++, 1, >+ virtio_scsi_save, virtio_scsi_load, s); >+ >+ return &s->vdev; >+} >+ >+void virtio_scsi_exit(VirtIODevice *vdev) >+{ >+ virtio_cleanup(vdev); >+} >diff -ruNp qemu-kvm-1.0/hw/virtio-scsi.h qemu-kvm-1.0.virtio-scsi/hw/virtio-scsi.h >--- qemu-kvm-1.0/hw/virtio-scsi.h 1969-12-31 18:00:00.000000000 -0600 >+++ qemu-kvm-1.0.virtio-scsi/hw/virtio-scsi.h 2012-02-07 14:44:53.432905379 -0600 >@@ -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 -ruNp qemu-kvm-1.0/Makefile.target qemu-kvm-1.0.virtio-scsi/Makefile.target >--- qemu-kvm-1.0/Makefile.target 2012-02-07 14:44:04.965124855 -0600 >+++ qemu-kvm-1.0.virtio-scsi/Makefile.target 2012-02-07 14:44:53.126900450 -0600 >@@ -205,6 +205,7 @@ obj-y = arch_init.o cpus.o monitor.o mac > obj-$(CONFIG_NO_PCI) += pci-stub.o > obj-$(CONFIG_PCI) += pci.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
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 415403
: 311363