mirror of
https://github.com/qemu/qemu.git
synced 2024-11-25 20:03:37 +08:00
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:
parent
e122090df3
commit
b99260ebbb
@ -2198,6 +2198,19 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SLOF probes the USB devices, and if it recognizes that the device is a
|
||||
* storage device, it changes its name to "storage" instead of "usb-host",
|
||||
* and additionally adds a child node for the SCSI LUN, so the correct
|
||||
* boot path in SLOF is something like .../storage@1/disk@xxx" instead.
|
||||
*/
|
||||
if (strcmp("usb-host", qdev_fw_name(dev)) == 0) {
|
||||
USBDevice *usbdev = CAST(USBDevice, dev, TYPE_USB_DEVICE);
|
||||
if (usb_host_dev_is_scsi_storage(usbdev)) {
|
||||
return g_strdup_printf("storage@%s/disk", usbdev->port->path);
|
||||
}
|
||||
}
|
||||
|
||||
if (phb) {
|
||||
/* Replace "pci" with "pci@800000020000000" */
|
||||
return g_strdup_printf("pci@%"PRIX64, phb->buid);
|
||||
|
@ -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;
|
||||
|
@ -46,3 +46,8 @@ USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool usb_host_dev_is_scsi_storage(USBDevice *ud)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -471,6 +471,7 @@ void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
|
||||
/* usb-linux.c */
|
||||
USBDevice *usb_host_device_open(USBBus *bus, const char *devname);
|
||||
void hmp_info_usbhost(Monitor *mon, const QDict *qdict);
|
||||
bool usb_host_dev_is_scsi_storage(USBDevice *usbdev);
|
||||
|
||||
/* usb ports of the VM */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user