On 05/03/2013 02:07 PM, Osier Yang wrote:
From: Han Cheng <hanc.fnst(a)cn.fujitsu.com>
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
Might be nice to include this mapping in the code comments especially
for those looking for this type of information some day that may not
think to look in a git commit log...
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst(a)cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang(a)redhat.com>
---
v3 - v4:
* Remove checking for "bug == 0"
* Split "bootindex" and "readonly" support into another patch
v2.5 - v3:
* Add support for all other controllers, but not only virtio-scsi
* Add checking for "bus == 0"
* Add checking for "target == 0" && "unit <= 7" for scsi
host device
which is on "lsilogic" controller.
* Integrate xml2argv test from 10/10 of v2.5 into this patch
---
src/qemu/qemu_command.c | 132 ++++++++++++++++++++-
src/qemu/qemu_command.h | 6 +
.../qemuxml2argv-hostdev-scsi-lsi.args | 9 ++
.../qemuxml2argv-hostdev-scsi-lsi.xml | 35 ++++++
.../qemuxml2argv-hostdev-scsi-virtio-scsi.args | 9 ++
...l => qemuxml2argv-hostdev-scsi-virtio-scsi.xml} | 0
tests/qemuxml2argvtest.c | 9 ++
tests/qemuxml2xmltest.c | 3 +-
8 files changed, 199 insertions(+), 4 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-scsi.args
rename tests/qemuxml2argvdata/{qemuxml2argv-hostdev-scsi.xml =>
qemuxml2argv-hostdev-scsi-virtio-scsi.xml} (100%)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 575dce1..df896aa 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 <linux/capability.h>
#endif
@@ -745,7 +746,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;
}
@@ -4673,7 +4683,96 @@ qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev)
return ret;
}
+char *
+qemuBuildSCSIHostdevDrvStr(virDomainHostdevDefPtr dev,
+ virQEMUCapsPtr qemuCaps ATTRIBUTE_UNUSED)
+{
+ 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);
+ virBufferAsprintf(&buf, ",id=%s-%s",
+ virDomainDeviceAddressTypeToString(dev->info->type),
+ dev->info->alias);
+
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ goto error;
+ }
+
VIR_FREE(sg);
No comments on remainder. I assume the test config is good - at least
it's there!
ACK
John
+ 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;
+ }
+ }
+
+ virBufferAsprintf(&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 */
@@ -7927,10 +8026,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) {
@@ -8039,6 +8139,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 a706942..9e4975d 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 0000000..06f7938
--- /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 0000000..98c469c
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi.xml
@@ -0,0 +1,35 @@
+<domain type='qemu'>
+ <name>QEMUGuest2</name>
+ <uuid>c7a5fdbd-edaf-9466-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219100</memory>
+ <currentMemory unit='KiB'>219100</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/QEMUGuest2'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0'
target='0' unit='0'/>
+ </disk>
+ <controller type='scsi' index='0'/>
+ <controller type='usb' index='0'/>
+ <controller type='ide'
index='0'/>72ae3d932c0119a3e0f8a9175b8e46977cae046a
+ <controller type='pci' index='0' model='pci-root'/>
+ <hostdev mode='subsystem' type='scsi' managed='yes'>
+ <source>
+ <adapter name='scsi_host0'/>
+ <address bus='0' target='0' unit='0'/>
+ </source>
+ <address type='drive' controller='0' bus='0'
target='0' unit='7'/>
+ </hostdev>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
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 0000000..b92afc7
--- /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 1286273..abe04b3 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -974,6 +974,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 1ca1f7e..08c3eeb 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);