]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: Build qemu command line for scsi host device
authorHan Cheng <hanc.fnst@cn.fujitsu.com>
Fri, 3 May 2013 18:07:23 +0000 (02:07 +0800)
committerOsier Yang <jyang@redhat.com>
Mon, 13 May 2013 10:50:16 +0000 (18:50 +0800)
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

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@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
src/qemu/qemu_command.c
src/qemu/qemu_command.h
tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi.args [new file with mode: 0644]
tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi.xml [new file with mode: 0644]
tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-scsi.args [new file with mode: 0644]
tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-scsi.xml [new file with mode: 0644]
tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi.xml [deleted file]
tests/qemuxml2argvtest.c
tests/qemuxml2xmltest.c

index fe70133664c4d4d538856a84bf3be565f972ae14..ef44809efac186fca51551ea6684f818b5cdc1cc 100644 (file)
@@ -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
@@ -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 &
index e690dee0513aeee33037bd8d912d65c58f150d08..ba42bb9eccb2a3b222874180170332465b8bb3f5 100644 (file)
@@ -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 (file)
index 0000000..06f7938
--- /dev/null
@@ -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 (file)
index 0000000..98c469c
--- /dev/null
@@ -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'/>
+    <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 (file)
index 0000000..b92afc7
--- /dev/null
@@ -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-virtio-scsi.xml b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-scsi.xml
new file mode 100644 (file)
index 0000000..5a263e7
--- /dev/null
@@ -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' model='virtio-scsi'/>
+    <controller type='usb' index='0'/>
+    <controller type='ide' index='0'/>
+    <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='4' unit='8'/>
+    </hostdev>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi.xml b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi.xml
deleted file mode 100644 (file)
index 5a263e7..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<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' model='virtio-scsi'/>
-    <controller type='usb' index='0'/>
-    <controller type='ide' index='0'/>
-    <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='4' unit='8'/>
-    </hostdev>
-    <memballoon model='virtio'/>
-  </devices>
-</domain>
index bd1cc68cfa76cd0e52afd71c7bf59dc8db57d032..1f86723aa81b4c1106c2f30c70aba397c2964ebf 100644 (file)
@@ -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);
index 1ca1f7e0da5d2d9be351402c2a2551c51e46d13a..08c3eeb31be377a0e1508ec25b8eabd848f6822e 100644 (file)
@@ -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);