diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2011-07-28 18:02:13 +0200 |
---|---|---|
committer | Kevin Wolf <kwolf@redhat.com> | 2011-10-28 19:25:51 +0200 |
commit | f48a7a6e35bb6d50573cfb42f13878c593fb6c0c (patch) | |
tree | 7f867312c0062f25c182f0660ed92aafdc69ef4a /hw/scsi-bus.c | |
parent | d8bb00d6d72eba317f78501434fc37db4968fa31 (diff) | |
download | qemu-f48a7a6e35bb6d50573cfb42f13878c593fb6c0c.zip qemu-f48a7a6e35bb6d50573cfb42f13878c593fb6c0c.tar.gz qemu-f48a7a6e35bb6d50573cfb42f13878c593fb6c0c.tar.bz2 |
scsi: remove devs array from SCSIBus
Change the devs array into a linked list, and add a scsi_device_find
function to navigate the children list instead. This lets the SCSI
bus use more complex addressing, and HBAs can talk to the correct device
when there are multiple LUNs per target.
scsi_device_find may return another LUN on the same target if none is
found that matches exactly.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'hw/scsi-bus.c')
-rw-r--r-- | hw/scsi-bus.c | 53 |
1 files changed, 30 insertions, 23 deletions
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index d9d4e18..7104e98 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; } |