diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index fe70133664..ef44809efa 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -48,6 +48,7 @@ #include "device_conf.h" #include "virstoragefile.h" #include "virtpm.h" +#include "virscsi.h" #if defined(__linux__) # include #endif @@ -797,7 +798,16 @@ qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr hostdev } } - if (virAsprintf(&hostdev->info->alias, "hostdev%d", idx) < 0) { + if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) { + if (virAsprintf(&hostdev->info->alias, "hostdev-%s-%d-%d-%d", + hostdev->source.subsys.u.scsi.adapter, + hostdev->source.subsys.u.scsi.bus, + hostdev->source.subsys.u.scsi.target, + hostdev->source.subsys.u.scsi.unit) < 0) { + virReportOOMError(); + return -1; + } + } else if (virAsprintf(&hostdev->info->alias, "hostdev%d", idx) < 0) { virReportOOMError(); return -1; } @@ -4725,7 +4735,97 @@ qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev) return ret; } +char * +qemuBuildSCSIHostdevDrvStr(virDomainHostdevDefPtr dev, + virQEMUCapsPtr qemuCaps ATTRIBUTE_UNUSED) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + char *sg = NULL; + if (!(sg = virSCSIDeviceGetSgName(dev->source.subsys.u.scsi.adapter, + dev->source.subsys.u.scsi.bus, + dev->source.subsys.u.scsi.target, + dev->source.subsys.u.scsi.unit))) { + goto error; + } + + virBufferAsprintf(&buf, "file=/dev/%s,if=none", sg); + virBufferAsprintf(&buf, ",id=%s-%s", + virDomainDeviceAddressTypeToString(dev->info->type), + dev->info->alias); + + if (virBufferError(&buf)) { + virReportOOMError(); + goto error; + } + + VIR_FREE(sg); + return virBufferContentAndReset(&buf); +error: + VIR_FREE(sg); + virBufferFreeAndReset(&buf); + return NULL; +} + +char * +qemuBuildSCSIHostdevDevStr(virDomainDefPtr def, + virDomainHostdevDefPtr dev, + virQEMUCapsPtr qemuCaps) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + int model = -1; + + model = virDomainDeviceFindControllerModel(def, dev->info, + VIR_DOMAIN_CONTROLLER_TYPE_SCSI); + + if (qemuSetScsiControllerModel(def, qemuCaps, &model) < 0) + goto error; + + if (model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC) { + if (dev->info->addr.drive.target != 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("target must be 0 for scsi host device " + "if its controller model is 'lsilogic'")); + goto error; + } + + if (dev->info->addr.drive.unit > 7) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("unit must be not more than 7 for scsi host " + "device if its controller model is 'lsilogic'")); + goto error; + } + } + + virBufferAddLit(&buf, "scsi-generic"); + + if (model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC) { + virBufferAsprintf(&buf, ",bus=scsi%d.%d,scsi-id=%d", + dev->info->addr.drive.controller, + dev->info->addr.drive.bus, + dev->info->addr.drive.unit); + } else { + virBufferAsprintf(&buf, ",bus=scsi%d.0,channel=%d,scsi-id=%d,lun=%d", + dev->info->addr.drive.controller, + dev->info->addr.drive.bus, + dev->info->addr.drive.target, + dev->info->addr.drive.unit); + } + + virBufferAsprintf(&buf, ",drive=%s-%s,id=%s", + virDomainDeviceAddressTypeToString(dev->info->type), + dev->info->alias, dev->info->alias); + + if (virBufferError(&buf)) { + virReportOOMError(); + goto error; + } + + return virBufferContentAndReset(&buf); +error: + virBufferFreeAndReset(&buf); + return NULL; +} /* This function outputs a -chardev command line option which describes only the * host side of the character device */ @@ -7939,10 +8039,11 @@ qemuBuildCommandLine(virConnectPtr conn, if (hostdev->info->bootIndex) { if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && - hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)) { + hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && + hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("booting from assigned devices is only " - "supported for PCI and USB devices")); + "supported for PCI, USB and SCSI devices")); goto error; } else { if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { @@ -8051,6 +8152,32 @@ qemuBuildCommandLine(virConnectPtr conn, goto error; } } + + /* SCSI */ + if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && + hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) { + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE) && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE) && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) { + char *drvstr; + + virCommandAddArg(cmd, "-drive"); + if (!(drvstr = qemuBuildSCSIHostdevDrvStr(hostdev, qemuCaps))) + goto error; + virCommandAddArg(cmd, drvstr); + VIR_FREE(drvstr); + + virCommandAddArg(cmd, "-device"); + if (!(devstr = qemuBuildSCSIHostdevDevStr(def, hostdev, qemuCaps))) + goto error; + virCommandAddArg(cmd, devstr); + VIR_FREE(devstr); + } else { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("SCSI passthrough is not supported by this version of qemu")); + goto error; + } + } } /* Migration is very annoying due to wildly varying syntax & diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index e690dee051..ba42bb9ecc 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -138,6 +138,12 @@ char * qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev); char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev, virQEMUCapsPtr qemuCaps); +char * qemuBuildSCSIHostdevDrvStr(virDomainHostdevDefPtr dev, + virQEMUCapsPtr qemuCaps); +char * qemuBuildSCSIHostdevDevStr(virDomainDefPtr def, + virDomainHostdevDefPtr dev, + virQEMUCapsPtr qemuCaps); + char * qemuBuildHubDevStr(virDomainHubDefPtr dev, virQEMUCapsPtr qemuCaps); char * qemuBuildRedirdevDevStr(virDomainDefPtr def, virDomainRedirdevDefPtr dev, diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi.args b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi.args new file mode 100644 index 0000000000..06f793818b --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi.args @@ -0,0 +1,9 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc \ +-m 214 -smp 1 -nographic -nodefaults -monitor \ +unix:/tmp/test-monitor,server,nowait -no-acpi -boot c \ +-device lsi,id=scsi0,bus=pci.0,addr=0x3 -usb \ +-drive file=/dev/HostVG/QEMUGuest2,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=/dev/sg0,if=none,id=drive-hostdev-scsi_host0-0-0-0 \ +-device scsi-generic,bus=scsi0.0,scsi-id=7,drive=drive-hostdev-scsi_host0-0-0-0,id=hostdev-scsi_host0-0-0-0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi.xml b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi.xml new file mode 100644 index 0000000000..98c469c8a9 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi.xml @@ -0,0 +1,35 @@ + + QEMUGuest2 + c7a5fdbd-edaf-9466-926a-d65c16db1809 + 219100 + 219100 + 1 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + +
+ + + + + + + + +
+ +
+ + + + diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-scsi.args b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-scsi.args new file mode 100644 index 0000000000..b92afc776c --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-scsi.args @@ -0,0 +1,9 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \ +pc -m 214 -smp 1 -nographic -nodefaults -monitor \ +unix:/tmp/test-monitor,server,nowait -no-acpi -boot c \ +-device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x3 -usb \ +-drive file=/dev/HostVG/QEMUGuest2,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=/dev/sg0,if=none,id=drive-hostdev-scsi_host0-0-0-0 \ +-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=4,lun=8,drive=drive-hostdev-scsi_host0-0-0-0,id=hostdev-scsi_host0-0-0-0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi.xml b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-scsi.xml similarity index 100% rename from tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi.xml rename to tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-scsi.xml diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index bd1cc68cfa..1f86723aa8 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -977,6 +977,15 @@ mymain(void) DO_TEST("pci-autoadd-addr", QEMU_CAPS_DEVICE, QEMU_CAPS_DEVICE_PCI_BRIDGE); DO_TEST("pci-autoadd-idx", QEMU_CAPS_DEVICE, QEMU_CAPS_DEVICE_PCI_BRIDGE); + DO_TEST("hostdev-scsi-lsi", QEMU_CAPS_DRIVE, + QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE, + QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_SCSI_LSI, + QEMU_CAPS_DEVICE_SCSI_GENERIC); + DO_TEST("hostdev-scsi-virtio-scsi", QEMU_CAPS_DRIVE, + QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE, + QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_DEVICE_SCSI_GENERIC); + virObjectUnref(driver.config); virObjectUnref(driver.caps); virObjectUnref(driver.xmlopt); diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 1ca1f7e0da..08c3eeb31b 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -285,7 +285,8 @@ mymain(void) DO_TEST_DIFFERENT("pci-autoadd-addr"); DO_TEST_DIFFERENT("pci-autoadd-idx"); - DO_TEST("hostdev-scsi"); + DO_TEST("hostdev-scsi-lsi"); + DO_TEST("hostdev-scsi-virtio-scsi"); virObjectUnref(driver.caps); virObjectUnref(driver.xmlopt);