Rather than relaying requests across multiple levels, I'm just skipping the intermediate layers after the LUN has been parsed, and letting the device know the bus which ultimately knows how to process the request.
Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- hw/esp.c | 6 +++--- hw/lsi53c895a.c | 8 ++++---- hw/scsi-bus.c | 15 +++++++++------ hw/scsi-disk.c | 6 +++--- hw/scsi-generic.c | 5 +++-- hw/scsi.h | 21 ++++++++++++++++----- hw/spapr_vscsi.c | 6 +++--- hw/usb-msd.c | 6 +++--- 8 files changed, 44 insertions(+), 29 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index 6d3f5d2..e47dfec 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -190,7 +190,7 @@ static void esp_dma_enable(void *opaque, int irq, int level) static void esp_request_cancelled(SCSIRequest *req) { - ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent); + ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->initiator); if (req == s->current_req) { scsi_req_unref(s->current_req); @@ -244,7 +244,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) DPRINTF("do_busid_cmd: busid 0x%x\n", busid); lun = busid & 7; - s->current_req = scsi_req_new(s->current_dev, 0, lun); + s->current_req = scsi_req_new(s->current_dev, &s->busdev.qdev, 0, lun); datalen = scsi_req_enqueue(s->current_req, buf); s->ti_size = datalen; if (datalen != 0) { @@ -397,7 +397,7 @@ static void esp_do_dma(ESPState *s) static void esp_command_complete(SCSIRequest *req, uint32_t status) { - ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent); + ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->initiator); DPRINTF("SCSI Command complete\n"); if (s->ti_size != 0) { diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 83084b6..96b19f9 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -660,7 +660,7 @@ static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag) static void lsi_request_cancelled(SCSIRequest *req) { - LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent); + LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->initiator); lsi_request *p; if (s->current && req == s->current->req) { @@ -715,7 +715,7 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t len) /* Callback to indicate that the SCSI layer has completed a command. */ static void lsi_command_complete(SCSIRequest *req, uint32_t status) { - LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent); + LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->initiator); int out; out = (s->sstat1 & PHASE_MASK) == PHASE_DO; @@ -789,8 +789,8 @@ static void lsi_do_command(LSIState *s) assert(s->current == NULL); s->current = qemu_mallocz(sizeof(lsi_request)); s->current->tag = s->select_tag; - s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun); - + s->current->req = scsi_req_new(dev, &s->dev.qdev, s->current->tag, + s->current_lun); n = scsi_req_enqueue(s->current->req, buf); if (n) { if (n > 0) { diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 3b80541..24e91bf 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -143,14 +143,16 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus) return res; } -SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun) +SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, DeviceState *initiator, + uint32_t tag, uint32_t lun) { SCSIRequest *req; req = qemu_mallocz(size); req->refcount = 1; - req->bus = scsi_bus_from_device(d); + req->bus = scsi_bus_from_device(d, initiator); req->dev = d; + req->initiator = initiator; req->tag = tag; req->lun = lun; req->status = -1; @@ -158,9 +160,10 @@ SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t l return req; } -SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun) +SCSIRequest *scsi_req_new(SCSIDevice *d, DeviceState *initiator, + uint32_t tag, uint32_t lun) { - return d->info->alloc_req(d, tag, lun); + return d->info->alloc_req(d, initiator, tag, lun); } uint8_t *scsi_req_get_buf(SCSIRequest *req) @@ -724,8 +727,8 @@ void scsi_device_purge_requests(SCSIDevice *sdev) static char *scsibus_get_fw_dev_path(DeviceState *dev) { - SCSIDevice *d = (SCSIDevice*)dev; - SCSIBus *bus = scsi_bus_from_device(d); + SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev); + SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus); char path[100]; int i; diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 76c1748..87e5ac8 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -80,14 +80,14 @@ struct SCSIDiskState static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type); static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf); -static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, - uint32_t lun) +static SCSIRequest *scsi_new_request(SCSIDevice *d, DeviceState *initiator, + uint32_t tag, uint32_t lun) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); SCSIRequest *req; SCSIDiskReq *r; - req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun); + req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, initiator, tag, lun); r = DO_UPCAST(SCSIDiskReq, req, req); r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE); return req; diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index b67e154..94aca18 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -96,11 +96,12 @@ static int scsi_get_sense(SCSIRequest *req, uint8_t *outbuf, int len) return size; } -static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun) +static SCSIRequest *scsi_new_request(SCSIDevice *d, DeviceState *initiator, + uint32_t tag, uint32_t lun) { SCSIRequest *req; - req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun); + req = scsi_req_alloc(sizeof(SCSIGenericReq), d, initiator, tag, lun); return req; } diff --git a/hw/scsi.h b/hw/scsi.h index 4ba1801..fa3ca9b 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -35,6 +35,7 @@ typedef struct SCSISense { struct SCSIRequest { SCSIBus *bus; + DeviceState *initiator; SCSIDevice *dev; uint32_t refcount; uint32_t tag; @@ -73,7 +74,8 @@ struct SCSIDeviceInfo { int (*init)(SCSIDevice *dev); void (*destroy)(SCSIDevice *s); void (*reset)(SCSIDevice *s); - SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun); + SCSIRequest *(*alloc_req)(SCSIDevice *s, DeviceState *initiator, + uint32_t tag, uint32_t lun); void (*free_req)(SCSIRequest *req); int32_t (*send_command)(SCSIRequest *req, uint8_t *buf); void (*read_data)(SCSIRequest *req); @@ -103,9 +105,16 @@ void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev, const SCSIBusOps *ops); void scsi_qdev_register(SCSIDeviceInfo *info); -static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d) +static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d, DeviceState *initiator) { - return DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus); + SCSIBus *bus; + DeviceState *dev; + dev = &d->qdev; + do { + bus = DO_UPCAST(SCSIBus, qbus, dev->parent_bus); + dev = bus->qbus.parent; + } while (dev != initiator); + return bus; } SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, @@ -145,8 +154,10 @@ int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed); int scsi_sense_valid(SCSISense sense); SCSIDevice *scsi_decode_lun(SCSIBus *sbus, uint64_t sam_lun, int *lun); -SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun); -SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun); +SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, DeviceState *initiator, + uint32_t tag, uint32_t lun); +SCSIRequest *scsi_req_new(SCSIDevice *d, DeviceState *initiator, uint32_t tag, + uint32_t lun); int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf); void scsi_req_free(SCSIRequest *req); SCSIRequest *scsi_req_ref(SCSIRequest *req); diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 038b9e4..5b5fa87 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -475,7 +475,7 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req) /* Callback to indicate that the SCSI layer has completed a transfer. */ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) { - VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); + VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->initiator); vscsi_req *req = vscsi_find_req(s, sreq); uint8_t *buf; int rc = 0; @@ -561,7 +561,7 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status) static void vscsi_request_cancelled(SCSIRequest *sreq) { - VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); + VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->initiator); vscsi_req *req = vscsi_find_req(s, sreq); vscsi_put_req(s, req); @@ -649,7 +649,7 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) } req->lun = lun; - req->sreq = scsi_req_new(sdev, req->qtag, lun); + req->sreq = scsi_req_new(sdev, &s->vdev.qdev, req->qtag, lun); n = scsi_req_enqueue(req->sreq, srp->cmd.cdb); dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n", diff --git a/hw/usb-msd.c b/hw/usb-msd.c index c59797b..195089c 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -212,7 +212,7 @@ static void usb_msd_send_status(MSDState *s, USBPacket *p) static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len) { - MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); + MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->initiator); USBPacket *p = s->packet; if (req->tag != s->tag) { @@ -275,7 +275,7 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status) static void usb_msd_request_cancelled(SCSIRequest *req) { - MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); + MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->initiator); if (req == s->req) { scsi_req_unref(s->req); @@ -386,7 +386,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) s->tag, cbw.flags, cbw.cmd_len, s->data_len); s->residue = 0; s->scsi_len = 0; - s->req = scsi_req_new(s->scsi_dev, s->tag, 0); + s->req = scsi_req_new(s->scsi_dev, &s->dev.qdev, s->tag, 0); scsi_req_enqueue(s->req, cbw.cmd); /* ??? Should check that USB and SCSI data transfer directions match. */ -- 1.7.4.4