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>
This commit is contained in:
parent
d8bb00d6d7
commit
f48a7a6e35
8
hw/esp.c
8
hw/esp.c
@ -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) {
|
||||
|
@ -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,14 +1680,10 @@ 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;
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -37,30 +37,31 @@ 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) {
|
||||
error_report("bad scsi device id: %d", dev->id);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
assert(i != bus->info->ndev);
|
||||
|
||||
snprintf(path, sizeof(path), "%s@%x", qdev_fw_name(dev), i);
|
||||
snprintf(path, sizeof(path), "%s@%d:%d:%d", qdev_fw_name(dev),
|
||||
0, d->id, d->lun);
|
||||
|
||||
return strdup(path);
|
||||
}
|
||||
|
||||
SCSIDevice *scsi_device_find(SCSIBus *bus, int id, int lun)
|
||||
{
|
||||
DeviceState *qdev;
|
||||
SCSIDevice *target_dev = NULL;
|
||||
|
||||
QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) {
|
||||
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
|
||||
|
||||
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
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user