diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/esp.c | 8 | ||||
-rw-r--r-- | hw/lsi53c895a.c | 22 | ||||
-rw-r--r-- | hw/qdev.h | 2 | ||||
-rw-r--r-- | hw/scsi-bus.c | 53 | ||||
-rw-r--r-- | hw/scsi.h | 3 | ||||
-rw-r--r-- | hw/spapr_vscsi.c | 14 |
6 files changed, 50 insertions, 52 deletions
@@ -217,7 +217,8 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf) s->async_len = 0; } - if (target >= ESP_MAX_DEVS || !s->bus.devs[target]) { + s->current_dev = scsi_device_find(&s->bus, target, 0); + if (!s->current_dev) { // No such drive s->rregs[ESP_RSTAT] = 0; s->rregs[ESP_RINTR] = INTR_DC; @@ -225,7 +226,6 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf) esp_raise_irq(s); return 0; } - s->current_dev = s->bus.devs[target]; return dmalen; } @@ -233,10 +233,12 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) { int32_t datalen; int lun; + SCSIDevice *current_lun; trace_esp_do_busid_cmd(busid); lun = busid & 7; - s->current_req = scsi_req_new(s->current_dev, 0, lun, buf, NULL); + current_lun = scsi_device_find(&s->bus, s->current_dev->id, lun); + s->current_req = scsi_req_new(current_lun, 0, lun, buf, NULL); datalen = scsi_req_enqueue(s->current_req); s->ti_size = datalen; if (datalen != 0) { diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 4eeb49632c..c15f167c84 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -531,7 +531,7 @@ static void lsi_bad_selection(LSIState *s, uint32_t id) /* Initiate a SCSI layer data transfer. */ static void lsi_do_dma(LSIState *s, int out) { - uint32_t count, id; + uint32_t count; target_phys_addr_t addr; SCSIDevice *dev; @@ -542,12 +542,8 @@ static void lsi_do_dma(LSIState *s, int out) return; } - id = (s->current->tag >> 8) & 0xf; - dev = s->bus.devs[id]; - if (!dev) { - lsi_bad_selection(s, id); - return; - } + dev = s->current->req->dev; + assert(dev); count = s->dbc; if (count > s->current->dma_len) @@ -771,7 +767,7 @@ static void lsi_do_command(LSIState *s) s->command_complete = 0; id = (s->select_tag >> 8) & 0xf; - dev = s->bus.devs[id]; + dev = scsi_device_find(&s->bus, id, s->current_lun); if (!dev) { lsi_bad_selection(s, id); return; @@ -1202,7 +1198,7 @@ again: } s->sstat0 |= LSI_SSTAT0_WOA; s->scntl1 &= ~LSI_SCNTL1_IARB; - if (id >= LSI_MAX_DEVS || !s->bus.devs[id]) { + if (!scsi_device_find(&s->bus, id, 0)) { lsi_bad_selection(s, id); break; } @@ -1684,13 +1680,9 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) if (val & LSI_SCNTL1_RST) { if (!(s->sstat0 & LSI_SSTAT0_RST)) { DeviceState *dev; - int id; - for (id = 0; id < LSI_MAX_DEVS; id++) { - if (s->bus.devs[id]) { - dev = &s->bus.devs[id]->qdev; - dev->info->reset(dev); - } + QTAILQ_FOREACH(dev, &s->bus.qbus.children, sibling) { + dev->info->reset(dev); } s->sstat0 |= LSI_SSTAT0_RST; lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0); @@ -73,7 +73,7 @@ struct BusState { const char *name; int allow_hotplug; int qdev_allocated; - QTAILQ_HEAD(, DeviceState) children; + QTAILQ_HEAD(ChildrenHead, DeviceState) children; QLIST_ENTRY(BusState) sibling; }; diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index d9d4e18d66..7104e98d59 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -37,12 +37,16 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base) SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base); SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus); + SCSIDevice *olddev; int rc = -1; if (dev->id == -1) { - for (dev->id = 0; dev->id < bus->info->ndev; dev->id++) { - if (bus->devs[dev->id] == NULL) + int id; + for (id = 0; id < bus->info->ndev; id++) { + if (!scsi_device_find(bus, id, 0)) { + dev->id = id; break; + } } } if (dev->id >= bus->info->ndev) { @@ -50,17 +54,14 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base) goto err; } - if (bus->devs[dev->id]) { - qdev_free(&bus->devs[dev->id]->qdev); + olddev = scsi_device_find(bus, dev->id, dev->lun); + if (olddev && dev->lun == olddev->lun) { + qdev_free(&olddev->qdev); } - bus->devs[dev->id] = dev; dev->info = info; QTAILQ_INIT(&dev->requests); rc = dev->info->init(dev); - if (rc != 0) { - bus->devs[dev->id] = NULL; - } err: return rc; @@ -69,13 +70,10 @@ err: static int scsi_qdev_exit(DeviceState *qdev) { SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); - SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus); - assert(bus->devs[dev->id] != NULL); - if (bus->devs[dev->id]->info->destroy) { - bus->devs[dev->id]->info->destroy(bus->devs[dev->id]); + if (dev->info->destroy) { + dev->info->destroy(dev); } - bus->devs[dev->id] = NULL; return 0; } @@ -1157,19 +1155,28 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense) static char *scsibus_get_fw_dev_path(DeviceState *dev) { SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev); - SCSIBus *bus = scsi_bus_from_device(d); char path[100]; - int i; - for (i = 0; i < bus->info->ndev; i++) { - if (bus->devs[i] == d) { - break; - } - } + snprintf(path, sizeof(path), "%s@%d:%d:%d", qdev_fw_name(dev), + 0, d->id, d->lun); - assert(i != bus->info->ndev); + return strdup(path); +} + +SCSIDevice *scsi_device_find(SCSIBus *bus, int id, int lun) +{ + DeviceState *qdev; + SCSIDevice *target_dev = NULL; - snprintf(path, sizeof(path), "%s@%x", qdev_fw_name(dev), i); + QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) { + SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); - return strdup(path); + if (dev->id == id) { + if (dev->lun == lun) { + return dev; + } + target_dev = dev; + } + } + return target_dev; } @@ -110,8 +110,6 @@ struct SCSIBus { SCSISense unit_attention; const SCSIBusInfo *info; - - SCSIDevice *devs[MAX_SCSI_DEVS]; }; void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info); @@ -195,5 +193,6 @@ void scsi_req_abort(SCSIRequest *req, int status); void scsi_req_cancel(SCSIRequest *req); void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense); int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed); +SCSIDevice *scsi_device_find(SCSIBus *bus, int target, int lun); #endif diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 33ae9b4963..ea3bb085db 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -129,11 +129,12 @@ static void vscsi_put_req(vscsi_req *req) req->active = 0; } -static void vscsi_decode_id_lun(uint64_t srp_lun, int *id, int *lun) +static SCSIDevice *vscsi_device_find(SCSIBus *bus, uint64_t srp_lun, int *lun) { /* XXX Figure that one out properly ! This is crackpot */ - *id = (srp_lun >> 56) & 0x7f; + int id = (srp_lun >> 56) & 0x7f; *lun = (srp_lun >> 48) & 0xff; + return scsi_device_find(bus, id, *lun); } static int vscsi_send_iu(VSCSIState *s, vscsi_req *req, @@ -582,14 +583,11 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) { union srp_iu *srp = &req->iu.srp; SCSIDevice *sdev; - int n, id, lun; + int n, lun; - vscsi_decode_id_lun(be64_to_cpu(srp->cmd.lun), &id, &lun); - - /* Qemu vs. linux issue with LUNs to be sorted out ... */ - sdev = (id < 8 && lun < 16) ? s->bus.devs[id] : NULL; + sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun); if (!sdev) { - dprintf("VSCSI: Command for id %d with no drive\n", id); + dprintf("VSCSI: Command for lun %08" PRIx64 " with no drive\n", be64_to_cpu(srp->cmd.lun)); if (srp->cmd.cdb[0] == INQUIRY) { vscsi_inquiry_no_target(s, req); } else { |