For scsi-generic, the command line will be like: -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 The relationship between the libvirt address attrs and the qdev properties are(channel should always be 0): bus=scsi<controller>.0 scsi-id=<target> lun=<unit> Signed-off-by: Han Cheng <hanc.fnst@xxxxxxxxxxxxxx> --- src/qemu/qemu_command.c | 130 +++++++++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_command.h | 6 ++ 2 files changed, 133 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index e0c53be..ea1f5e0 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -659,7 +659,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; } @@ -4416,6 +4425,87 @@ qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev) return ret; } +char * +qemuBuildSCSIHostdevDrvStr(virDomainHostdevDefPtr dev, virQEMUCapsPtr qemuCaps) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + char *sg = NULL; + + if (!(sg = virSCSIDeviceGetDevStr(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); + VIR_FREE(sg); + virBufferAsprintf(&buf, ",id=%s-%s", + virDomainDeviceAddressTypeToString(dev->info->type), + dev->info->alias); + if (dev->readonly && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_READONLY)) + virBufferAsprintf(&buf, ",readonly=on"); + if (virBufferError(&buf)) { + virReportOOMError(); + goto error; + } + + return virBufferContentAndReset(&buf); + +error: + virBufferFreeAndReset(&buf); + return NULL; +} + + +char * +qemuBuildSCSIHostdevDevStr(virDomainDefPtr def, virDomainHostdevDefPtr dev, + virQEMUCapsPtr qemuCaps) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + int controllerModel = -1; + + controllerModel = + virDomainDeviceFindControllerModel(def, dev->info, + VIR_DOMAIN_CONTROLLER_TYPE_SCSI); + if (qemuSetScsiControllerModel(def, qemuCaps, &controllerModel) < 0) + goto error; + /* TODO: deal with lsi or ibm controller */ + if (controllerModel == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI) { + virBufferAsprintf(&buf, "scsi-generic"); + if (dev->info->addr.drive.bus != 0) { + virReportError(VIR_ERR_XML_ERROR, + "%s", _("SCSI controller only supports 1 bus")); + goto error; + } + /* TODO: deal with early version qemu which does not support bus... */ + virBufferAsprintf(&buf, + ",bus=scsi%d.0,channel=0,scsi-id=%d,lun=%d", + dev->info->addr.drive.controller, + 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 (dev->info->bootIndex) + virBufferAsprintf(&buf, ",bootindex=%d", dev->info->bootIndex); + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unsupport controller model '%s'"), + virDomainControllerModelSCSITypeToString(controllerModel)); + goto error; + } + 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 @@ -7489,10 +7579,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 && @@ -7509,6 +7600,39 @@ qemuBuildCommandLine(virConnectPtr conn, " supported with this version of qemu")); goto error; } + if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI && + !virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_GENERIC_BOOTINDEX)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("booting from assigned SCSI devices is not" + " supported with this version of qemu")); + 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_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; } } diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 1789c20..fcf9892 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -139,6 +139,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, -- 1.7.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list