[libvirt] [PATCH 0/6] add qemu usb-scsi controller support

This patchset tries to add usb-scsi model for SCSI controller. http://lists.gnu.org/archive/html/qemu-devel/2012-06/msg03382.html "usb-uas is a pure UAS (usb attached scsi) emulation. The emulation works like any other scsi hba emulation (eps, lsi, virtio, megasas, ...). It provides just the HBA where you can attach scsi devices as you like using '-device'. A single scsi target with up to 256 luns is supported. For now only usb 2.0 transport is supported." libvirt XML snip <devices> <controller type='usb' index='2' model='ehci'> </controller> <controller type='scsi' index='0' model='usb-scsi'> <address type='usb' bus='2' port='1'/> </controller> </devices> qemu commandline: qemu ${other_vm_args} \ -device usb-ehci,id=usb2,bus=pci.0,addr=0x8 \ -device usb-uas,id=scsi0,bus=usb2.0,port=1 When a scsi disk is attached to usb-scsi controller, the target id must 0(usb-scsi only provide one scsi target). The unit value must in range of 0~255 for its lun number. As for the guest, the kernel with CONFIG_USB_UAS=y is necessary to have it show up scsi disk attached to UAS. Fedora has the kernel driver disabled by default though. (thanks to Gerd Hoffmann's suggestion) I grabbed linux-3.7.1 version from kernel website. It works after compiling. Guannan Ren(6) [PATCH 1/6] conf: declare usb spec and port number enum for usb [PATCH 2/6] conf: store usb spec and nports info when parsing usb [PATCH 3/6] qemu: add usb-uas caps flag [PATCH 4/6] qemu: add usb scsi controller support [PATCH 5/6] qemu: add usb-scsi controller checking when building [PATCH 6/6] test: add qemuxml2argv disk-scsi-uas testcase docs/formatdomain.html.in | 25 +++++- docs/schemas/domaincommon.rng | 1 + src/conf/domain_conf.c | 213 ++++++++++++++++++++++++++++++++++++++------ src/conf/domain_conf.h | 25 +++++- src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 41 +++++++-- src/vmx/vmx.c | 3 +- tests/qemuhelptest.c | 6 +- tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-uas.args | 10 +++ tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-uas.xml | 34 +++++++ tests/qemuxml2argvtest.c | 3 + 12 files changed, 326 insertions(+), 38 deletions(-)

Currently, libvirt could not tell what usb specification a certain USB device is running on or what kind of usb spec a USB controller supports. For example, USB controller: piix3-usb-uhci, piix4-usb-uhci, ohci only support USB 1.1 usb-ehci and ich9-usb-ehci1 only support USB 2.0 ich9-usb-ehci1 + ich9-usb-uhci{1|2|3} supports both USB 1.1 and USB 2.0 nec-usb-xhci supports USB 1.1, 2.0, 3.0 USB device: Most of them only support USB 1.1 usb-tablet Supports USB 1.1 and 2.0(in qemu 1.3 & older 1.1 only) usb-uas is USB 2.0 or above device. usb-storage supports USB1.1, 2.0 and 3.0 The usb spec may change over time for USB device, for USB constrollers it is fixed(From Gerd Hoffmann). So this patch tries to record usb spec infomation and port number supported by usb constrollers. Based on these info, we can simply check whether a usb device goes with right controller. --- src/conf/domain_conf.c | 32 ++++++++++++++++---------------- src/conf/domain_conf.h | 24 +++++++++++++++++++++++- src/qemu/qemu_command.c | 8 ++++---- 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 6feded4..646baab 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -4507,30 +4507,30 @@ virDomainControllerDefParseXML(xmlNodePtr node, char *ports = virXMLPropString(node, "ports"); if (ports) { int r = virStrToLong_i(ports, NULL, 10, - &def->opts.vioserial.ports); - if (r != 0 || def->opts.vioserial.ports < 0) { + &def->data.vioserial.ports); + if (r != 0 || def->data.vioserial.ports < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid ports: %s"), ports); VIR_FREE(ports); goto error; } } else { - def->opts.vioserial.ports = -1; + def->data.vioserial.ports = -1; } VIR_FREE(ports); char *vectors = virXMLPropString(node, "vectors"); if (vectors) { int r = virStrToLong_i(vectors, NULL, 10, - &def->opts.vioserial.vectors); - if (r != 0 || def->opts.vioserial.vectors < 0) { + &def->data.vioserial.vectors); + if (r != 0 || def->data.vioserial.vectors < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid vectors: %s"), vectors); VIR_FREE(vectors); goto error; } } else { - def->opts.vioserial.vectors = -1; + def->data.vioserial.vectors = -1; } VIR_FREE(vectors); break; @@ -8818,8 +8818,8 @@ static int virDomainDefMaybeAddController(virDomainDefPtr def, cont->model = -1; if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) { - cont->opts.vioserial.ports = -1; - cont->opts.vioserial.vectors = -1; + cont->data.vioserial.ports = -1; + cont->data.vioserial.vectors = -1; } @@ -10895,17 +10895,17 @@ static bool virDomainControllerDefCheckABIStability(virDomainControllerDefPtr sr } if (src->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) { - if (src->opts.vioserial.ports != dst->opts.vioserial.ports) { + if (src->data.vioserial.ports != dst->data.vioserial.ports) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Target controller ports %d does not match source %d"), - dst->opts.vioserial.ports, src->opts.vioserial.ports); + dst->data.vioserial.ports, src->data.vioserial.ports); goto cleanup; } - if (src->opts.vioserial.vectors != dst->opts.vioserial.vectors) { + if (src->data.vioserial.vectors != dst->data.vioserial.vectors) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Target controller vectors %d does not match source %d"), - dst->opts.vioserial.vectors, src->opts.vioserial.vectors); + dst->data.vioserial.vectors, src->data.vioserial.vectors); goto cleanup; } } @@ -12497,13 +12497,13 @@ virDomainControllerDefFormat(virBufferPtr buf, switch (def->type) { case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL: - if (def->opts.vioserial.ports != -1) { + if (def->data.vioserial.ports != -1) { virBufferAsprintf(buf, " ports='%d'", - def->opts.vioserial.ports); + def->data.vioserial.ports); } - if (def->opts.vioserial.vectors != -1) { + if (def->data.vioserial.vectors != -1) { virBufferAsprintf(buf, " vectors='%d'", - def->opts.vioserial.vectors); + def->data.vioserial.vectors); } break; diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 2ac338c..67143a5 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -701,6 +701,27 @@ struct _virDomainVirtioSerialOpts { int vectors; /* -1 == undef */ }; +enum virDomainUSBSpec { + VIR_DOMAIN_USB_SPEC_NONE = 0, + VIR_DOMAIN_USB_SEPC_1_1 = 1 << 0, + VIR_DOMAIN_USB_SPEC_2_0 = 1 << 1, + VIR_DOMAIN_USB_SPEC_3_0 = 1 << 2, +}; + +enum virDomainUSBControllerPortNumber { + VIR_DOMAIN_USB_CONTROLLER_UHCI_PORTN_2 = 2, + VIR_DOMAIN_USB_CONTROLLER_OHCI_PORTN_3 = 3, + VIR_DOMAIN_USB_CONTROLLER_XHCI_PORTN_4 = 4, + VIR_DOMAIN_USB_CONTROLLER_EHCI_PORTN_6 = 6, +}; + +typedef struct _virDomainUSBControllerData virDomainUSBControllerData; +typedef virDomainUSBControllerData *virDomainUSBControllerDataPtr; +struct _virDomainUSBControllerData { + unsigned int spec; + size_t nports; +}; + /* Stores the virtual disk controller configuration */ struct _virDomainControllerDef { int type; @@ -708,7 +729,8 @@ struct _virDomainControllerDef { int model; /* -1 == undef */ union { virDomainVirtioSerialOpts vioserial; - } opts; + virDomainUSBControllerData usb; + } data; virDomainDeviceInfo info; }; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 981c692..71e69f3 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3083,13 +3083,13 @@ qemuBuildControllerDevStr(virDomainDefPtr domainDef, } virBufferAsprintf(&buf, ",id=" QEMU_VIRTIO_SERIAL_PREFIX "%d", def->idx); - if (def->opts.vioserial.ports != -1) { + if (def->data.vioserial.ports != -1) { virBufferAsprintf(&buf, ",max_ports=%d", - def->opts.vioserial.ports); + def->data.vioserial.ports); } - if (def->opts.vioserial.vectors != -1) { + if (def->data.vioserial.vectors != -1) { virBufferAsprintf(&buf, ",vectors=%d", - def->opts.vioserial.vectors); + def->data.vioserial.vectors); } break; -- 1.7.11.4

USB controller UHCI/OHCI model: VIR_DOMAIN_USB_SEPC_1_1 EHCI model: VIR_DOMAIN_USB_SPEC_2_0 XHCI model: VIR_DOMAIN_USB_SEPC_1_1| \ VIR_DOMAIN_USB_SPEC_2_0| \ VIR_DOMAIN_USB_SPEC_3_0 VIR_DOMAIN_USB_CONTROLLER_UHCI_PORTN_2 = 2 VIR_DOMAIN_USB_CONTROLLER_OHCI_PORTN_3 = 3 VIR_DOMAIN_USB_CONTROLLER_XHCI_PORTN_4 = 4 VIR_DOMAIN_USB_CONTROLLER_EHCI_PORTN_6 = 6 --- src/conf/domain_conf.c | 69 +++++++++++++++++++++++++++++++++++++++++++------ src/qemu/qemu_command.c | 8 ++++-- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 646baab..a0946cc 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -4445,11 +4445,67 @@ static int virDomainControllerModelTypeFromString(const virDomainControllerDefPtr def, const char *model) { - if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) - return virDomainControllerModelSCSITypeFromString(model); - else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) - return virDomainControllerModelUSBTypeFromString(model); + if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI && + (def->model = virDomainControllerModelSCSITypeFromString(model)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown SCSI controller model type '%s'"), model); + goto error; + } + + if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) { + virDomainUSBControllerDataPtr usbController = &def->data.usb; + + if ((def->model = virDomainControllerModelUSBTypeFromString(model)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown USB controller model type '%s'"), model); + goto error; + } + + switch (def->model) { + case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI: + case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI: + case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1: + case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2: + case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3: + case VIR_DOMAIN_CONTROLLER_MODEL_USB_VT82C686B_UHCI: + usbController->spec = VIR_DOMAIN_USB_SEPC_1_1; + usbController->nports = VIR_DOMAIN_USB_CONTROLLER_UHCI_PORTN_2; + break; + + case VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI: + usbController->spec = VIR_DOMAIN_USB_SEPC_1_1; + usbController->nports = VIR_DOMAIN_USB_CONTROLLER_OHCI_PORTN_3; + break; + + case VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI: + case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1: + usbController->spec = VIR_DOMAIN_USB_SPEC_2_0; + usbController->nports = VIR_DOMAIN_USB_CONTROLLER_EHCI_PORTN_6; + break; + + case VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI: + usbController->spec = VIR_DOMAIN_USB_SEPC_1_1 | + VIR_DOMAIN_USB_SPEC_2_0 | + VIR_DOMAIN_USB_SPEC_3_0; + usbController->nports = VIR_DOMAIN_USB_CONTROLLER_XHCI_PORTN_4; + break; + + case VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE: + usbController->spec = VIR_DOMAIN_USB_SPEC_NONE; + usbController->nports = 0; + break; + + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to determine USB Specification " + "supported by USB constroller mode %s"), + virDomainControllerModelUSBTypeToString(def->model)); + goto error; + }; + } + return 0; +error: return -1; } @@ -4490,11 +4546,8 @@ virDomainControllerDefParseXML(xmlNodePtr node, model = virXMLPropString(node, "model"); if (model) { - if ((def->model = virDomainControllerModelTypeFromString(def, model)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown model type '%s'"), model); + if (virDomainControllerModelTypeFromString(def, model) < 0) goto error; - } } else { def->model = -1; } diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 71e69f3..78276b5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3010,10 +3010,14 @@ qemuBuildUSBControllerDevStr(virDomainDefPtr domainDef, model = def->model; if (model == -1) { - if (domainDef->os.arch == VIR_ARCH_PPC64) + if (domainDef->os.arch == VIR_ARCH_PPC64) { model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI; - else + def->data.usb.nports = VIR_DOMAIN_USB_CONTROLLER_OHCI_PORTN_3; + } else { model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI; + def->data.usb.nports = VIR_DOMAIN_USB_CONTROLLER_UHCI_PORTN_2; + } + def->data.usb.spec = VIR_DOMAIN_USB_SEPC_1_1; } smodel = qemuControllerModelUSBTypeToString(model); -- 1.7.11.4

QEMU_CAPS_DEVICE_USB_UAS /* -device usb-uas */ --- docs/schemas/domaincommon.rng | 1 + src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemuhelptest.c | 6 ++++-- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 67ae864..423ff58 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1376,6 +1376,7 @@ <value>vmpvscsi</value> <value>ibmvscsi</value> <value>virtio-scsi</value> + <value>usb-scsi</value> <value>piix3-uhci</value> <value>piix4-uhci</value> <value>ehci</value> diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index b166dd6..87b22c2 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -203,6 +203,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "usb-serial", /* 125 */ "usb-net", + "usb-uas", ); @@ -1351,6 +1352,7 @@ struct qemuCapsStringFlags qemuCapsObjectTypes[] = { { "vmware-svga", QEMU_CAPS_DEVICE_VMWARE_SVGA }, { "usb-serial", QEMU_CAPS_DEVICE_USB_SERIAL}, { "usb-net", QEMU_CAPS_DEVICE_USB_NET}, + { "usb-uas", QEMU_CAPS_DEVICE_USB_UAS}, }; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 089fa30..4b1347f 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -165,6 +165,7 @@ enum qemuCapsFlags { QEMU_CAPS_SCLP_S390 = 124, /* -device sclp* */ QEMU_CAPS_DEVICE_USB_SERIAL = 125, /* -device usb-serial */ QEMU_CAPS_DEVICE_USB_NET = 126, /* -device usb-net */ + QEMU_CAPS_DEVICE_USB_UAS = 127, /* -device usb-uas */ QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c index 68efd9c..507f97e 100644 --- a/tests/qemuhelptest.c +++ b/tests/qemuhelptest.c @@ -910,7 +910,8 @@ mymain(void) QEMU_CAPS_DEVICE_VMWARE_SVGA, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, QEMU_CAPS_DEVICE_USB_SERIAL, - QEMU_CAPS_DEVICE_USB_NET); + QEMU_CAPS_DEVICE_USB_NET, + QEMU_CAPS_DEVICE_USB_UAS); DO_TEST("qemu-kvm-1.2.0", 1002000, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -1014,7 +1015,8 @@ mymain(void) QEMU_CAPS_DEVICE_VMWARE_SVGA, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, QEMU_CAPS_DEVICE_USB_SERIAL, - QEMU_CAPS_DEVICE_USB_NET); + QEMU_CAPS_DEVICE_USB_NET, + QEMU_CAPS_DEVICE_USB_UAS); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 1.7.11.4

UAS(usb attached scsi) works like other scsi HBA emulation (lsi, virtio). For now only usb2.0 transport is supported. It only provides one scsi target with up to 256 luns. For usb scsi controller, the <address> subelment become mandatory rather than optional. Because each of them needs a usb port on usb controller with usb2.0, when there are multiple usb-scsi controllers with some of them having <address> and some of them not having <address>, it is hard to validate address info or pick up a valid port for them that doesn't have <address> subelement automatically. libvirt XML snip <devices> <controller type='usb' index='2' model='ehci'> </controller> <controller type='scsi' index='0' model='usb-scsi'> <address type='usb' bus='2' port='1'/> </controller> </devices> qemu commandline: qemu ${other_vm_args} \ -device usb-ehci,id=usb2,bus=pci.0,addr=0x8 \ -device usb-uas,id=scsi0,bus=usb2.0,port=1 --- docs/formatdomain.html.in | 25 ++++++++++- src/conf/domain_conf.c | 112 ++++++++++++++++++++++++++++++++++++++++++++-- src/conf/domain_conf.h | 1 + src/qemu/qemu_command.c | 10 +++++ src/vmx/vmx.c | 3 +- 5 files changed, 146 insertions(+), 5 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index bb0b199..89dc766 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2055,7 +2055,30 @@ control how many devices can be connected through the controller. A "scsi" controller has an optional attribute <code>model</code>, which is one of "auto", "buslogic", - "ibmvscsi", "lsilogic", "lsias1068", "virtio-scsi" or "vmpvscsi". + "ibmvscsi", "lsilogic", "lsias1068", "virtio-scsi", "vmpvscsi", + "usb-scsi". usb-scsi <span class="since">(since 1.0.2)</span> is + a pure UAS (usb attached scsi) emulation which works like any other + scsi controller. It provides a single scsi target with up to 256 + luns. usb-scsi is a USB2.0 device, so it also needs a usb controller + (Described below) which supports usb 2.0 transport, like model "ehci", + "nec-xhci". The <code><address></code> + <a href="#elementsAddress">documented above</a> can be used for + usb-scsi scsi controller to attach to USB2.0 controller. Note that + the <code><address></code> is mandatory. + </p> + +<pre> + ... + <devices> + <controller type='usb' index='1' model='ehci'/> + <controller type='scsi' index='0' model='usb-scsi'> + <address type='usb' bus='1' port='1'/> + </controller> + ... + </devices> + ...</pre> + + <p> A "usb" controller has an optional attribute <code>model</code>, which is one of "piix3-uhci", "piix4-uhci", "ehci", "ich9-ehci1", "ich9-uhci1", "ich9-uhci2", "ich9-uhci3", diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a0946cc..8b4e7e6 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -278,7 +278,8 @@ VIR_ENUM_IMPL(virDomainControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAS "lsisas1068", "vmpvscsi", "ibmvscsi", - "virtio-scsi"); + "virtio-scsi", + "usb-scsi"); VIR_ENUM_IMPL(virDomainControllerModelUSB, VIR_DOMAIN_CONTROLLER_MODEL_USB_LAST, "piix3-uhci", @@ -4556,6 +4557,15 @@ virDomainControllerDefParseXML(xmlNodePtr node, goto error; switch (def->type) { + case VIR_DOMAIN_CONTROLLER_TYPE_SCSI: + if (def->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_USB_UAS && + def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("usb scsi model of scsi controller requires " + "<address> subelement with type 'usb'")); + goto error; + } + break; case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL: { char *ports = virXMLPropString(node, "ports"); if (ports) { @@ -4618,9 +4628,10 @@ virDomainControllerDefParseXML(xmlNodePtr node, if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO && def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390 && - def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { + def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI && + def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Controllers must use the 'pci' address type")); + _("Controllers have incorrect address type")); goto error; } @@ -8917,6 +8928,98 @@ cleanup: return ret; } +static int +virDomainSCSIControllerUASRequireUSB20(virDomainDefPtr def) +{ + size_t i, j; + size_t nuass = 0, nusbs = 0; + int ret = -1; + virDomainControllerDefPtr *uas = NULL, *usb = NULL; + virDomainControllerDefPtr temp; + + /* Filter out uas scsi controllers and usb controllers + * which support USB2.0 Spec. + */ + for (i = 0; i < def->ncontrollers; i++) { + temp = def->controllers[i]; + if (temp->type != VIR_DOMAIN_CONTROLLER_TYPE_USB && + temp->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) + continue; + + if (temp->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) { + if (temp->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_USB_UAS) + continue; + + if (VIR_REALLOC_N(uas, nuass + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + uas[nuass++] = temp; + } + + if (temp->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) { + if (temp->model < 0 || + !(temp->data.usb.spec & VIR_DOMAIN_USB_SPEC_2_0)) + continue; + + if (VIR_REALLOC_N(usb, nusbs + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + usb[nusbs++] = temp; + } + } + + if (!nuass) { + ret = 0; + goto cleanup; + } + + if (!nusbs) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("usb-scsi model of SCSI controller requires " + "at least one USB2.0 controller")); + goto cleanup; + } + + for (i = 0; i < nuass; i++) { + bool found = false; + if (uas[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("usb-scsi model of SCSI controller " + "doesn't have bus info")); + goto cleanup; + } + + for (j = 0; j < nusbs; j++) { + if (uas[i]->info.addr.usb.bus == usb[j]->idx) + found = true; + } + + if (!found) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("The address info of usb-scsi controller " + "does not refer to USB2.0 controller")); + goto cleanup; + } + } + ret = 0; + +cleanup: + VIR_FREE(uas); + VIR_FREE(usb); + return ret; +} + +static int +virDomainControllerCheckConsistency(virDomainDefPtr def) +{ + + if (virDomainSCSIControllerUASRequireUSB20(def) < 0) + return -1; + + return 0; +} static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, xmlDocPtr xml, @@ -9856,6 +9959,9 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, } VIR_FREE(nodes); + if (virDomainControllerCheckConsistency(def) < 0) + goto error; + if (def->virtType == VIR_DOMAIN_VIRT_QEMU || def->virtType == VIR_DOMAIN_VIRT_KQEMU || def->virtType == VIR_DOMAIN_VIRT_KVM) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 67143a5..9801dbf 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -674,6 +674,7 @@ enum virDomainControllerModelSCSI { VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI, + VIR_DOMAIN_CONTROLLER_MODEL_SCSI_USB_UAS, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST }; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 78276b5..d459be0 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -506,6 +506,13 @@ qemuSetScsiControllerModel(virDomainDefPtr def, return -1; } break; + case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_USB_UAS: + if (!qemuCapsGet(caps, QEMU_CAPS_DEVICE_USB_UAS)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("This QEMU doesn't support " + "usb-scsi controller")); + return -1; + } case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI: /*TODO: need checking work here if necessary */ break; @@ -3068,6 +3075,9 @@ qemuBuildControllerDevStr(virDomainDefPtr domainDef, case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI: virBufferAddLit(&buf, "spapr-vscsi"); break; + case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_USB_UAS: + virBufferAddLit(&buf, "usb-uas"); + break; default: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported controller model: %s"), diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index c604bd2..65efa2d 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -511,7 +511,8 @@ VIR_ENUM_IMPL(virVMXControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST, "lsisas1068", "pvscsi", "UNUSED ibmvscsi", - "UNUSED virtio-scsi"); + "UNUSED virtio-scsi", + "UNUSED usb-scsi"); -- 1.7.11.4

libvirt XML snip <devices> <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/var/lib/libvirt/images/seconddisk'/> <target dev='sdb' bus='scsi'/> <address type='drive' controller='0' bus='0' target='0' unit='1'/> </disk> <controller type='usb' index='2' model='ehci'> <controller type='scsi' index='0' model='usb-scsi'> <address type='usb' bus='2' port='1'/> </controller> </devices> When a scsi disk is attached to usb-scsi controller, the target id must 0(usb-scsi only provide one scsi target). The unit value must in range of 0~255 for its lun number. --- src/qemu/qemu_command.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index d459be0..dc86071 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -2767,6 +2767,21 @@ qemuBuildDriveDevStr(virDomainDefPtr def, virBufferAddLit(&opt, "scsi-block"); } + if (controllerModel == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_USB_UAS) { + if (disk->info.addr.drive.target != 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Disk target must be 0 for usb-scsi controller")); + goto error; + } + + if (disk->info.addr.drive.unit & ~0xff) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Disk unit must be less than 256 " + "for usb-scsi controller")); + goto error; + } + } + virBufferAsprintf(&opt, ",bus=scsi%d.0,channel=%d,scsi-id=%d,lun=%d", disk->info.addr.drive.controller, disk->info.addr.drive.bus, -- 1.7.11.4

--- .../qemuxml2argv-disk-scsi-uas.args | 10 +++++++ .../qemuxml2argv-disk-scsi-uas.xml | 34 ++++++++++++++++++++++ tests/qemuxml2argvtest.c | 3 ++ 3 files changed, 47 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-uas.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-uas.xml diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-uas.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-uas.args new file mode 100644 index 0000000..c2d2743 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-uas.args @@ -0,0 +1,10 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \ +/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults \ +-monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c \ +-device usb-ehci,id=usb,bus=pci.0,addr=0x3 \ +-device usb-uas,id=scsi0,bus=usb.0,port=1 \ +-drive file=/dev/HostVG/QEMUGuest1,if=none,id=drive-ide0-0-0 \ +-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \ +-drive file=/tmp/scsidisk.img,if=none,id=drive-scsi0-0-0-0 \ +-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-uas.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-uas.xml new file mode 100644 index 0000000..d285503 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-uas.xml @@ -0,0 +1,34 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <disk type='file' device='disk'> + <source file='/tmp/scsidisk.img'/> + <target dev='sda' bus='scsi'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0' model='ehci'/> + <controller type='ide' index='0'/> + <controller type='scsi' index='0' model='usb-scsi'> + <address type='usb' bus='0' port='1'/> + </controller> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 31ed116..ceab6b6 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -509,6 +509,9 @@ mymain(void) DO_TEST("disk-scsi-virtio-scsi", QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_VIRTIO_SCSI_PCI); + DO_TEST("disk-scsi-uas", + QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_USB_EHCI, QEMU_CAPS_DEVICE_USB_UAS); DO_TEST("disk-sata-device", QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_ICH9_AHCI); -- 1.7.11.4

On Mon, Jan 14, 2013 at 05:04:19PM +0800, Guannan Ren wrote:
This patchset tries to add usb-scsi model for SCSI controller. http://lists.gnu.org/archive/html/qemu-devel/2012-06/msg03382.html
"usb-uas is a pure UAS (usb attached scsi) emulation. The emulation works like any other scsi hba emulation (eps, lsi, virtio, megasas, ...). It provides just the HBA where you can attach scsi devices as you like using '-device'. A single scsi target with up to 256 luns is supported. For now only usb 2.0 transport is supported."
libvirt XML snip <devices> <controller type='usb' index='2' model='ehci'> </controller> <controller type='scsi' index='0' model='usb-scsi'>
Same objection as with the usb-net series - we need a more explicit name here. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 01/14/2013 06:33 PM, Daniel P. Berrange wrote:
On Mon, Jan 14, 2013 at 05:04:19PM +0800, Guannan Ren wrote:
This patchset tries to add usb-scsi model for SCSI controller. http://lists.gnu.org/archive/html/qemu-devel/2012-06/msg03382.html
"usb-uas is a pure UAS (usb attached scsi) emulation. The emulation works like any other scsi hba emulation (eps, lsi, virtio, megasas, ...). It provides just the HBA where you can attach scsi devices as you like using '-device'. A single scsi target with up to 256 luns is supported. For now only usb 2.0 transport is supported."
libvirt XML snip <devices> <controller type='usb' index='2' model='ehci'> </controller> <controller type='scsi' index='0' model='usb-scsi'> Same objection as with the usb-net series - we need a more explicit name here.
Daniel
I choose usb-scsi because of virtio-scsi, idVendor is QEMU. idProduct is "USB Attached SCSI HBA". I originally named it usb-uas. Is it okay? To be honest, it is hard to think of a better name. Any better name is welcome. :) Guannan

Hi,
I choose usb-scsi because of virtio-scsi, idVendor is QEMU. idProduct is "USB Attached SCSI HBA". I originally named it usb-uas. Is it okay?
usb-uas would be better IMHO. "UAS" stays for *U*SB *A*ttached *S*CSI. It isn't the only usb scsi host adapter, the other one is usb-storage. This one speaks the old BOT (*B*ulk *O*nly *T*transport) protocol. The qemu implementation supports a single target with a single lun only. For historical reasons it hides the fact that it is a scsi hba and doesn't let you attach a scsi-* device, instead it wants a drive and creates the scsi-disk by itself. cheers, Gerd

On 01/14/2013 05:04 PM, Guannan Ren wrote:
This patchset tries to add usb-scsi model for SCSI controller. http://lists.gnu.org/archive/html/qemu-devel/2012-06/msg03382.html
"usb-uas is a pure UAS (usb attached scsi) emulation. The emulation works like any other scsi hba emulation (eps, lsi, virtio, megasas, ...). It provides just the HBA where you can attach scsi devices as you like using '-device'. A single scsi target with up to 256 luns is supported. For now only usb 2.0 transport is supported."
libvirt XML snip <devices> <controller type='usb' index='2' model='ehci'> </controller> <controller type='scsi' index='0' model='usb-scsi'> <address type='usb' bus='2' port='1'/> </controller> </devices>
qemu commandline: qemu ${other_vm_args} \ -device usb-ehci,id=usb2,bus=pci.0,addr=0x8 \ -device usb-uas,id=scsi0,bus=usb2.0,port=1
When a scsi disk is attached to usb-scsi controller, the target id must 0(usb-scsi only provide one scsi target). The unit value must in range of 0~255 for its lun number.
As for the guest, the kernel with CONFIG_USB_UAS=y is necessary to have it show up scsi disk attached to UAS. Fedora has the kernel driver disabled by default though. (thanks to Gerd Hoffmann's suggestion) I grabbed linux-3.7.1 version from kernel website. It works after compiling.
There is no good chipset or vendor name for usb-uas virtual device. idVendor is QEMU. ( 46f4) idProduct is "USB Attached SCSI HBA" (0003) For the name of this scsi model in XML, any opinion is welcome. If no other opinion, the usb-uas will be chosen (usb-scsi in this patchset) I am going to send a v2 with this fix. Guannan
participants (3)
-
Daniel P. Berrange
-
Gerd Hoffmann
-
Guannan Ren