This provides the infrastructure for simple devices to pick LUNs. Of course, this will not do anything until there is a device that can report the existence of those LUNs.
Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- hw/esp.c | 4 +++- hw/lsi53c895a.c | 2 +- hw/scsi-bus.c | 14 ++++++++++++++ hw/scsi.h | 3 +++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index 5a33c67..e5bab76 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -239,12 +239,14 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf) static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) { + SCSIDevice *dev; int32_t datalen; int lun; DPRINTF("do_busid_cmd: busid 0x%x\n", busid); lun = busid & 7; - s->current_req = scsi_req_new(s->current_dev, 0, lun); + dev = scsi_find_lun(s->current_dev, lun, buf); + s->current_req = scsi_req_new(dev, 0, lun); datalen = scsi_req_enqueue(s->current_req, buf); s->ti_size = datalen; if (datalen != 0) { diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index f291283..c549955 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -780,7 +780,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_find_lun(s->bus.devs[id], s->current_lun, buf); if (!dev) { lsi_bad_selection(s, id); return; diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 70b1092..4d46831 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -719,6 +719,20 @@ static char *scsibus_get_fw_dev_path(DeviceState *dev) return strdup(path); } +/* Simplified walk of the SCSI bus hierarchy, for devices that only support + one bus and only flat-space LUNs (typically 3-bit ones!). */ +SCSIDevice *scsi_find_lun(SCSIDevice *sdev, int lun, uint8_t *cdb) +{ + SCSIBus *sbus = sdev->children; + if (!sbus || + (lun == 0 && cdb[1] == REPORT_LUNS) || + lun >= sbus->ndev || sbus->devs[lun] == NULL) { + return sdev; + } else { + return sbus->devs[lun]; + } +} + /* Decode the bus and level parts of a LUN, as defined in the SCSI architecture model. If false is returned, the LUN could not be parsed. If true is return, "*bus" and "*target" identify the next two steps in the diff --git a/hw/scsi.h b/hw/scsi.h index aa75b82..438dd89 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -58,6 +58,7 @@ struct SCSIDevice uint32_t id; BlockConf conf; SCSIDeviceInfo *info; + SCSIBus *children; QTAILQ_HEAD(, SCSIRequest) requests; int blocksize; int type; @@ -143,7 +144,9 @@ extern const struct SCSISense sense_code_LUN_FAILURE; 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); +SCSIDevice *scsi_find_lun(SCSIDevice *sdev, int lun, uint8_t *cdb); 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); -- 1.7.4.4