hw/ppc/spapr: Fix boot path of usb-host storage devices

When passing through an USB storage device to a pseries guest, it
is currently not possible to automatically boot from the device
if the "bootindex" property has been specified, too (e.g. when using
"-device nec-usb-xhci -device usb-host,hostbus=1,hostaddr=2,bootindex=0"
at the command line). The problem is that QEMU builds a device tree path
like "/pci@800000020000000/usb@0/usb-host@1" and passes it to SLOF
in the /chosen/qemu,boot-list property. SLOF, however, probes the
USB device, recognizes that it is a storage device and thus changes
its name to "storage", and additionally adds a child node for the
SCSI LUN, so the correct boot path in SLOF is something like
"/pci@800000020000000/usb@0/storage@1/disk@101000000000000" instead.
So when we detect an USB mass storage device with SCSI interface,
we've got to adjust the firmware boot-device path properly that
SLOF can automatically boot from the device.

Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1354177
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
Thomas Huth 2016-12-14 22:44:17 +01:00 committed by David Gibson
parent e122090df3
commit b99260ebbb
4 changed files with 48 additions and 0 deletions

View file

@ -1707,6 +1707,35 @@ static void usb_host_auto_check(void *unused)
timer_mod(usb_auto_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 2000);
}
/**
* Check whether USB host device has a USB mass storage SCSI interface
*/
bool usb_host_dev_is_scsi_storage(USBDevice *ud)
{
USBHostDevice *uhd = USB_HOST_DEVICE(ud);
struct libusb_config_descriptor *conf;
const struct libusb_interface_descriptor *intf;
bool is_scsi_storage = false;
int i;
if (!uhd || libusb_get_active_config_descriptor(uhd->dev, &conf) != 0) {
return false;
}
for (i = 0; i < conf->bNumInterfaces; i++) {
intf = &conf->interface[i].altsetting[ud->altsetting[i]];
if (intf->bInterfaceClass == LIBUSB_CLASS_MASS_STORAGE &&
intf->bInterfaceSubClass == 6) { /* 6 means SCSI */
is_scsi_storage = true;
break;
}
}
libusb_free_config_descriptor(conf);
return is_scsi_storage;
}
void hmp_info_usbhost(Monitor *mon, const QDict *qdict)
{
libusb_device **devs = NULL;