diff options
Diffstat (limited to 'hw/scsi')
-rw-r--r-- | hw/scsi/esp-pci.c | 1 | ||||
-rw-r--r-- | hw/scsi/lsi53c895a.c | 10 | ||||
-rw-r--r-- | hw/scsi/megasas.c | 3 | ||||
-rw-r--r-- | hw/scsi/scsi-bus.c | 74 | ||||
-rw-r--r-- | hw/scsi/scsi-disk.c | 52 | ||||
-rw-r--r-- | hw/scsi/scsi-generic.c | 7 | ||||
-rw-r--r-- | hw/scsi/virtio-scsi.c | 25 | ||||
-rw-r--r-- | hw/scsi/vmw_pvscsi.c | 3 |
8 files changed, 123 insertions, 52 deletions
diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c index 9971bbf92d..82795e68b8 100644 --- a/hw/scsi/esp-pci.c +++ b/hw/scsi/esp-pci.c @@ -378,7 +378,6 @@ static void esp_pci_scsi_uninit(PCIDevice *d) PCIESPState *pci = PCI_ESP(d); qemu_free_irq(pci->esp.irq); - memory_region_destroy(&pci->io); } static void esp_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 786d8483ec..513ea47e8a 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -2072,15 +2072,6 @@ static const VMStateDescription vmstate_lsi_scsi = { } }; -static void lsi_scsi_uninit(PCIDevice *d) -{ - LSIState *s = LSI53C895A(d); - - memory_region_destroy(&s->mmio_io); - memory_region_destroy(&s->ram_io); - memory_region_destroy(&s->io_io); -} - static const struct SCSIBusInfo lsi_scsi_info = { .tcq = true, .max_target = LSI_MAX_DEVS, @@ -2134,7 +2125,6 @@ static void lsi_class_init(ObjectClass *klass, void *data) PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); k->init = lsi_scsi_init; - k->exit = lsi_scsi_uninit; k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC; k->device_id = PCI_DEVICE_ID_LSI_53C895A; k->class_id = PCI_CLASS_STORAGE_SCSI; diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index c68a873f18..eedc9922a7 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -2129,9 +2129,6 @@ static void megasas_scsi_uninit(PCIDevice *d) if (megasas_use_msi(s)) { msi_uninit(d); } - memory_region_destroy(&s->mmio_io); - memory_region_destroy(&s->port_io); - memory_region_destroy(&s->queue_io); } static const struct SCSIBusInfo megasas_scsi_info = { diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 4341754253..6f4462b483 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -9,7 +9,6 @@ static char *scsibus_get_dev_path(DeviceState *dev); static char *scsibus_get_fw_dev_path(DeviceState *dev); -static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf); static void scsi_req_dequeue(SCSIRequest *req); static uint8_t *scsi_target_alloc_buf(SCSIRequest *req, size_t len); static void scsi_target_free_buf(SCSIRequest *req); @@ -54,6 +53,20 @@ static void scsi_device_destroy(SCSIDevice *s) } } +int scsi_bus_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf, + void *hba_private) +{ + SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus); + int rc; + + assert(cmd->len == 0); + rc = scsi_req_parse_cdb(dev, cmd, buf); + if (bus->info->parse_cdb) { + rc = bus->info->parse_cdb(dev, cmd, buf, hba_private); + } + return rc; +} + static SCSIRequest *scsi_device_alloc_req(SCSIDevice *s, uint32_t tag, uint32_t lun, uint8_t *buf, void *hba_private) { @@ -561,13 +574,44 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, uint8_t *buf, void *hba_private) { SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus); + const SCSIReqOps *ops; + SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(d); SCSIRequest *req; - SCSICommand cmd; + SCSICommand cmd = { .len = 0 }; + int ret; + + if ((d->unit_attention.key == UNIT_ATTENTION || + bus->unit_attention.key == UNIT_ATTENTION) && + (buf[0] != INQUIRY && + buf[0] != REPORT_LUNS && + buf[0] != GET_CONFIGURATION && + buf[0] != GET_EVENT_STATUS_NOTIFICATION && + + /* + * If we already have a pending unit attention condition, + * report this one before triggering another one. + */ + !(buf[0] == REQUEST_SENSE && d->sense_is_ua))) { + ops = &reqops_unit_attention; + } else if (lun != d->lun || + buf[0] == REPORT_LUNS || + (buf[0] == REQUEST_SENSE && d->sense_len)) { + ops = &reqops_target_command; + } else { + ops = NULL; + } + + if (ops != NULL || !sc->parse_cdb) { + ret = scsi_req_parse_cdb(d, &cmd, buf); + } else { + ret = sc->parse_cdb(d, &cmd, buf, hba_private); + } - if (scsi_req_parse(&cmd, d, buf) != 0) { + if (ret != 0) { trace_scsi_req_parse_bad(d->id, lun, tag, buf[0]); req = scsi_req_alloc(&reqops_invalid_opcode, d, tag, lun, hba_private); } else { + assert(cmd.len != 0); trace_scsi_req_parsed(d->id, lun, tag, buf[0], cmd.mode, cmd.xfer); if (cmd.lba != -1) { @@ -577,25 +621,8 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, if (cmd.xfer > INT32_MAX) { req = scsi_req_alloc(&reqops_invalid_field, d, tag, lun, hba_private); - } else if ((d->unit_attention.key == UNIT_ATTENTION || - bus->unit_attention.key == UNIT_ATTENTION) && - (buf[0] != INQUIRY && - buf[0] != REPORT_LUNS && - buf[0] != GET_CONFIGURATION && - buf[0] != GET_EVENT_STATUS_NOTIFICATION && - - /* - * If we already have a pending unit attention condition, - * report this one before triggering another one. - */ - !(buf[0] == REQUEST_SENSE && d->sense_is_ua))) { - req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun, - hba_private); - } else if (lun != d->lun || - buf[0] == REPORT_LUNS || - (buf[0] == REQUEST_SENSE && d->sense_len)) { - req = scsi_req_alloc(&reqops_target_command, d, tag, lun, - hba_private); + } else if (ops) { + req = scsi_req_alloc(ops, d, tag, lun, hba_private); } else { req = scsi_device_alloc_req(d, tag, lun, buf, hba_private); } @@ -1182,10 +1209,11 @@ static uint64_t scsi_cmd_lba(SCSICommand *cmd) return lba; } -static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) +int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf) { int rc; + cmd->lba = -1; switch (buf[0] >> 5) { case 0: cmd->len = 6; diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index d47ecd6ab4..d55521dcf6 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2501,12 +2501,8 @@ static int scsi_block_initfn(SCSIDevice *dev) return scsi_initfn(&s->qdev); } -static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, - uint32_t lun, uint8_t *buf, - void *hba_private) +static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf) { - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); - switch (buf[0]) { case READ_6: case READ_10: @@ -2523,9 +2519,9 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, case WRITE_VERIFY_12: case WRITE_VERIFY_16: /* If we are not using O_DIRECT, we might read stale data from the - * host cache if writes were made using other commands than these - * ones (such as WRITE SAME or EXTENDED COPY, etc.). So, without - * O_DIRECT everything must go through SG_IO. + * host cache if writes were made using other commands than these + * ones (such as WRITE SAME or EXTENDED COPY, etc.). So, without + * O_DIRECT everything must go through SG_IO. */ if (!(bdrv_get_flags(s->qdev.conf.bs) & BDRV_O_NOCACHE)) { break; @@ -2542,14 +2538,45 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, * just make scsi-block operate the same as scsi-generic for them. */ if (s->qdev.type != TYPE_ROM) { - return scsi_req_alloc(&scsi_disk_dma_reqops, &s->qdev, tag, lun, - hba_private); + return false; } + break; + + default: + break; + } + + return true; +} + + +static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, + uint32_t lun, uint8_t *buf, + void *hba_private) +{ + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); + + if (scsi_block_is_passthrough(s, buf)) { + return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun, + hba_private); + } else { + return scsi_req_alloc(&scsi_disk_dma_reqops, &s->qdev, tag, lun, + hba_private); } +} + +static int scsi_block_parse_cdb(SCSIDevice *d, SCSICommand *cmd, + uint8_t *buf, void *hba_private) +{ + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); - return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun, - hba_private); + if (scsi_block_is_passthrough(s, buf)) { + return scsi_bus_parse_cdb(&s->qdev, cmd, buf, hba_private); + } else { + return scsi_req_parse_cdb(&s->qdev, cmd, buf); + } } + #endif #define DEFINE_SCSI_DISK_PROPERTIES() \ @@ -2658,6 +2685,7 @@ static void scsi_block_class_initfn(ObjectClass *klass, void *data) sc->init = scsi_block_initfn; sc->destroy = scsi_destroy; sc->alloc_req = scsi_block_new_request; + sc->parse_cdb = scsi_block_parse_cdb; dc->fw_name = "disk"; dc->desc = "SCSI block device passthrough"; dc->reset = scsi_disk_reset; diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 3733d2c36c..0b2ff90b90 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -490,6 +490,12 @@ static Property scsi_generic_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, + uint8_t *buf, void *hba_private) +{ + return scsi_bus_parse_cdb(dev, cmd, buf, hba_private); +} + static void scsi_generic_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -498,6 +504,7 @@ static void scsi_generic_class_initfn(ObjectClass *klass, void *data) sc->init = scsi_generic_initfn; sc->destroy = scsi_destroy; sc->alloc_req = scsi_new_request; + sc->parse_cdb = scsi_generic_parse_cdb; dc->fw_name = "disk"; dc->desc = "pass through generic scsi device (/dev/sg*)"; dc->reset = scsi_generic_reset; diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 0eb069ae9b..2dd92552e0 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -406,6 +406,30 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, virtio_scsi_complete_cmd_req(req); } +static int virtio_scsi_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, + uint8_t *buf, void *hba_private) +{ + VirtIOSCSIReq *req = hba_private; + + if (cmd->len == 0) { + cmd->len = MIN(VIRTIO_SCSI_CDB_SIZE, SCSI_CMD_BUF_SIZE); + memcpy(cmd->buf, buf, cmd->len); + } + + /* Extract the direction and mode directly from the request, for + * host device passthrough. + */ + cmd->xfer = req->qsgl.size; + if (cmd->xfer == 0) { + cmd->mode = SCSI_XFER_NONE; + } else if (iov_size(req->elem.in_sg, req->elem.in_num) > req->resp_size) { + cmd->mode = SCSI_XFER_FROM_DEV; + } else { + cmd->mode = SCSI_XFER_TO_DEV; + } + return 0; +} + static QEMUSGList *virtio_scsi_get_sg_list(SCSIRequest *r) { VirtIOSCSIReq *req = r->hba_private; @@ -658,6 +682,7 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = { .change = virtio_scsi_change, .hotplug = virtio_scsi_hotplug, .hot_unplug = virtio_scsi_hot_unplug, + .parse_cdb = virtio_scsi_parse_cdb, .get_sg_list = virtio_scsi_get_sg_list, .save_request = virtio_scsi_save_request, .load_request = virtio_scsi_load_request, diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index f9ed926bd1..5734d19789 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -1087,7 +1087,6 @@ pvscsi_init(PCIDevice *pci_dev) s->completion_worker = qemu_bh_new(pvscsi_process_completion_queue, s); if (!s->completion_worker) { pvscsi_cleanup_msi(s); - memory_region_destroy(&s->io_space); return -ENOMEM; } @@ -1107,8 +1106,6 @@ pvscsi_uninit(PCIDevice *pci_dev) qemu_bh_delete(s->completion_worker); pvscsi_cleanup_msi(s); - - memory_region_destroy(&s->io_space); } static void |