]> xenbits.xensource.com Git - libvirt.git/commitdiff
conf: Generic XMLs for scsi hostdev
authorHan Cheng <hanc.fnst@cn.fujitsu.com>
Fri, 3 May 2013 18:07:20 +0000 (02:07 +0800)
committerOsier Yang <jyang@redhat.com>
Mon, 13 May 2013 10:23:50 +0000 (18:23 +0800)
An example of the scsi hostdev XML:

    <hostdev mode='subsystem' type='scsi'>
      <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>

Controller is implicitly added for scsi hostdev, though the scsi
controller's model defaults to "lsilogic", which might be not what
the user wants (same problem exists for virtio-scsi disk). It's
the existing problem, will be addressed later.

The device address must be specified manually. Later patch will let
libvirt generate it automatically.

This only introduces the generic XMLs for scsi hostdev, later patches
will add other elements, e.g. <readonly>, <shareable>.

Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
docs/formatdomain.html.in
docs/schemas/domaincommon.rng
src/conf/domain_audit.c
src/conf/domain_conf.c
src/conf/domain_conf.h
tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi.xml [new file with mode: 0644]
tests/qemuxml2xmltest.c

index 572d7eeecae1fdff9f2adf6725c4b96c36347fc3..27fd458fe5b9dec752d0003add8f22d902217e3b 100644 (file)
 
     <h4><a name="elementsHostDev">Host device assignment</a></h4>
 
-    <h5><a href="elementsHostDevSubsys">USB / PCI devices</a></h5>
+    <h5><a href="elementsHostDevSubsys">USB / PCI / SCSI devices</a></h5>
 
     <p>
-      USB and PCI devices attached to the host can be passed through
+      USB, PCI and SCSI devices attached to the host can be passed through
       to the guest using the <code>hostdev</code> element.
-      <span class="since">since after 0.4.4 for USB and 0.6.0 for PCI
-        (KVM only)</span>:
+      <span class="since">since after 0.4.4 for USB, 0.6.0 for PCI(KVM only)
+        and 1.0.6 for SCSI(KVM only)</span>:
     </p>
 
 <pre>
       &lt;rom bar='on' file='/etc/fake/boot.bin'/&gt;
     &lt;/hostdev&gt;
   &lt;/devices&gt;
+  ...</pre>
+
+    <p>or:</p>
+
+<pre>
+  ...
+  &lt;devices&gt;
+    &lt;hostdev mode='subsystem' type='scsi'&gt;
+      &lt;source&gt;
+        &lt;adapter name='scsi_host0'/&gt;
+        &lt;address type='scsi' bus='0' target='0' unit='0'/&gt;
+      &lt;/source&gt;
+      &lt;readonly/&gt;
+      &lt;address type='drive' controller='0' bus='0' target='0' unit='0'/&gt;
+    &lt;/hostdev&gt;
+  &lt;/devices&gt;
   ...</pre>
 
     <dl>
       <dt><code>hostdev</code></dt>
       <dd>The <code>hostdev</code> element is the main container for describing
         host devices. For usb device passthrough <code>mode</code> is always
-        "subsystem" and <code>type</code> is "usb" for a USB device and "pci"
-        for a PCI device. When <code>managed</code> is "yes" for a PCI
+        "subsystem" and <code>type</code> is "usb" for a USB device, "pci"
+        for a PCI device and "scsi" for a SCSI device. When
+        <code>managed</code> is "yes" for a PCI
         device, it is detached from the host before being passed on to
         the guest, and reattached to the host after the guest exits.
         If <code>managed</code> is omitted or "no", and for USB
         hot-plugging the device,
         and <code>virNodeDeviceReAttach</code> (or <code>virsh
         nodedev-reattach</code>) after hot-unplug or stopping the
-        guest.</dd>
+        guest. For SCSI device, user is responsible to make sure the device
+        is not used by host.</dd>
       <dt><code>source</code></dt>
       <dd>The source element describes the device as seen from the host.
       The USB device can either be addressed by vendor / product id using the
       <code>vendor</code> and <code>product</code> elements or by the device's
       address on the hosts using the <code>address</code> element. PCI devices
       on the other hand can only be described by their <code>address</code>.
+      SCSI devices are described by both the <code>adapter</code> and
+      <code>address</code> elements.
 
       <span class="since">Since 1.0.0</span>, the <code>source</code> element
       of USB devices may contain <code>startupPolicy</code> attribute which can
index 10596dc0c0102b92494ee92dc7d0ea00a7894ef9..6a4b77aa13715ba5e9293ab4b847bbaf2a121493 100644 (file)
     <choice>
       <ref name="hostdevsubsyspci"/>
       <ref name="hostdevsubsysusb"/>
+      <ref name="hostdevsubsysscsi"/>
     </choice>
   </define>
 
     </element>
   </define>
 
+  <define name="hostdevsubsysscsi">
+    <attribute name="type">
+      <value>scsi</value>
+    </attribute>
+    <element name="source">
+      <interleave>
+        <ref name="sourceinfoadapter"/>
+        <element name="address">
+          <ref name="scsiaddress"/>
+        </element>
+      </interleave>
+    </element>
+  </define>
+
   <define name="hostdevcapsstorage">
     <attribute name="type">
       <value>storage</value>
       </attribute>
     </element>
   </define>
+  <define name="scsiaddress">
+    <attribute name="bus">
+      <ref name="driveBus"/>
+    </attribute>
+    <attribute name="target">
+      <ref name="driveTarget"/>
+    </attribute>
+    <attribute name="unit">
+      <ref name="driveUnit"/>
+    </attribute>
+  </define>
   <define name="usbportaddress">
     <attribute name="bus">
       <ref name="usbAddr"/>
index 40910d679f0c2d8450393cbc1991f3f0d451c554..a6cefb2e859b870763d698ae11bf5d1dc231ba84 100644 (file)
@@ -399,6 +399,16 @@ virDomainAuditHostdev(virDomainObjPtr vm, virDomainHostdevDefPtr hostdev,
                 goto cleanup;
             }
             break;
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
+            if (virAsprintf(&address, "%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) {
+                VIR_WARN("OOM while encoding audit message");
+                goto cleanup;
+            }
+            break;
         default:
             VIR_WARN("Unexpected hostdev type while encoding audit message: %d",
                      hostdev->source.subsys.type);
index e0bd8aa47f6c490ea23ea1bd7d6fc57f601dce96..d20faa5eef8cf5464ee2d06fd5db40e84516d75b 100644 (file)
@@ -585,7 +585,8 @@ VIR_ENUM_IMPL(virDomainHostdevMode, VIR_DOMAIN_HOSTDEV_MODE_LAST,
 
 VIR_ENUM_IMPL(virDomainHostdevSubsys, VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST,
               "usb",
-              "pci")
+              "pci",
+              "scsi")
 
 VIR_ENUM_IMPL(virDomainHostdevSubsysPciBackend,
               VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST,
@@ -1634,7 +1635,8 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
     if (def->parent.type == VIR_DOMAIN_DEVICE_NONE)
         virDomainDeviceInfoFree(def->info);
 
-    if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) {
+    switch (def->mode) {
+    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
         switch (def->source.caps.type) {
         case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
             VIR_FREE(def->source.caps.u.storage.block);
@@ -1646,6 +1648,11 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
             VIR_FREE(def->source.caps.u.net.iface);
             break;
         }
+        break;
+    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
+        if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
+            VIR_FREE(def->source.subsys.u.scsi.adapter);
+        break;
     }
 }
 
@@ -3680,6 +3687,94 @@ out:
     return ret;
 }
 
+static int
+virDomainHostdevSubsysScsiDefParseXML(const xmlNodePtr node,
+                                      virDomainHostdevDefPtr def)
+{
+    int ret = -1;
+    bool got_address = false, got_adapter = false;
+    xmlNodePtr cur;
+    char *bus = NULL, *target = NULL, *unit = NULL;
+
+    cur = node->children;
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE) {
+            if (xmlStrEqual(cur->name, BAD_CAST "address")) {
+                if (got_address) {
+                    virReportError(VIR_ERR_XML_ERROR, "%s",
+                                   _("more than one source addresses is "
+                                     "specified for scsi hostdev"));
+                    goto cleanup;
+                }
+
+                if (!(bus = virXMLPropString(cur, "bus")) ||
+                    !(target = virXMLPropString(cur, "target")) ||
+                    !(unit = virXMLPropString(cur, "unit"))) {
+                    virReportError(VIR_ERR_XML_ERROR, "%s",
+                                   _("'bus', 'target', and 'unit' must be specified "
+                                     "for scsi hostdev source address"));
+                    goto cleanup;
+                }
+
+                if (virStrToLong_ui(bus, NULL, 0, &def->source.subsys.u.scsi.bus) < 0) {
+                    virReportError(VIR_ERR_INTERNAL_ERROR,
+                                   _("cannot parse bus '%s'"), bus);
+                    goto cleanup;
+                }
+
+                if (virStrToLong_ui(target, NULL, 0, &def->source.subsys.u.scsi.target) < 0) {
+                    virReportError(VIR_ERR_INTERNAL_ERROR,
+                                   _("cannot parse target '%s'"), target);
+                    goto cleanup;
+                }
+
+                if (virStrToLong_ui(unit, NULL, 0, &def->source.subsys.u.scsi.unit) < 0) {
+                    virReportError(VIR_ERR_INTERNAL_ERROR,
+                                   _("cannot parse unit '%s'"), unit);
+                    goto cleanup;
+                }
+
+                got_address = true;
+            } else if (xmlStrEqual(cur->name, BAD_CAST "adapter")) {
+                if (got_adapter) {
+                    virReportError(VIR_ERR_XML_ERROR, "%s",
+                                   _("more than one adapters is specified "
+                                     "for scsi hostdev source"));
+                    goto cleanup;
+                }
+                if (!(def->source.subsys.u.scsi.adapter =
+                      virXMLPropString(cur, "name"))) {
+                    virReportError(VIR_ERR_XML_ERROR, "%s",
+                                   _("'adapter' must be specified for scsi hostdev source"));
+                    goto cleanup;
+                }
+
+                got_adapter = true;
+            } else {
+                virReportError(VIR_ERR_XML_ERROR,
+                               _("unsupported element '%s' of scsi hostdev source"),
+                               cur->name);
+                goto cleanup;
+            }
+        }
+        cur = cur->next;
+    }
+
+    if (!got_address || !got_adapter) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("'adapter' and 'address' must be specified for scsi "
+                         "hostdev source"));
+        goto cleanup;
+    }
+
+    ret = 0;
+cleanup:
+    VIR_FREE(bus);
+    VIR_FREE(target);
+    VIR_FREE(unit);
+    return ret;
+}
+
 static int
 virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
                                   xmlXPathContextPtr ctxt,
@@ -3761,6 +3856,12 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
         if (virDomainHostdevSubsysUsbDefParseXML(sourcenode, def) < 0)
             goto error;
         break;
+
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
+        if (virDomainHostdevSubsysScsiDefParseXML(sourcenode, def) < 0)
+            goto error;
+        break;
+
     default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("address type='%s' not supported in hostdev interfaces"),
@@ -8623,6 +8724,13 @@ virDomainHostdevDefParseXML(const xmlNodePtr node,
                 goto error;
             }
             break;
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
+            if (def->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
+                virReportError(VIR_ERR_XML_ERROR, "%s",
+                               _("SCSI host devices must have address specified"));
+                goto error;
+            }
+            break;
         }
     }
 
@@ -9150,6 +9258,17 @@ virDomainHostdevMatchSubsysPCI(virDomainHostdevDefPtr a,
     return 0;
 }
 
+static int
+virDomainHostdevMatchSubsysSCSI(virDomainHostdevDefPtr a,
+                                virDomainHostdevDefPtr b)
+{
+    if (STREQ(a->source.subsys.u.scsi.adapter, b->source.subsys.u.scsi.adapter) &&
+        a->source.subsys.u.scsi.bus == b->source.subsys.u.scsi.bus &&
+        a->source.subsys.u.scsi.target == b->source.subsys.u.scsi.target &&
+        a->source.subsys.u.scsi.unit == b->source.subsys.u.scsi.unit)
+        return 1;
+    return 0;
+}
 
 static int
 virDomainHostdevMatchSubsys(virDomainHostdevDefPtr a,
@@ -9163,6 +9282,8 @@ virDomainHostdevMatchSubsys(virDomainHostdevDefPtr a,
         return virDomainHostdevMatchSubsysPCI(a, b);
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
         return virDomainHostdevMatchSubsysUSB(a, b);
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
+        return virDomainHostdevMatchSubsysSCSI(a, b);
     }
     return 0;
 }
@@ -12987,6 +13108,30 @@ virDomainDefMaybeAddSmartcardController(virDomainDefPtr def)
     return 0;
 }
 
+static int
+virDomainDefMaybeAddHostdevSCSIcontroller(virDomainDefPtr def)
+{
+    /* Look for any hostdev scsi dev */
+    int i;
+    int maxController = -1;
+    virDomainHostdevDefPtr hostdev;
+
+    for (i = 0; i < def->nhostdevs; i++) {
+        hostdev = def->hostdevs[i];
+        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
+            (int)hostdev->info->addr.drive.controller > maxController) {
+            maxController = hostdev->info->addr.drive.controller;
+        }
+    }
+
+    for (i = 0; i <= maxController; i++) {
+        if (virDomainDefMaybeAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_SCSI, i, -1) < 0)
+            return -1;
+    }
+
+    return 0;
+}
 
 /*
  * Based on the declared <address/> info for any devices,
@@ -13023,6 +13168,9 @@ virDomainDefAddImplicitControllers(virDomainDefPtr def)
     if (virDomainDefMaybeAddSmartcardController(def) < 0)
         return -1;
 
+    if (virDomainDefMaybeAddHostdevSCSIcontroller(def) < 0)
+        return -1;
+
     return 0;
 }
 
@@ -13928,6 +14076,15 @@ virDomainHostdevDefFormatSubsys(virBufferPtr buf,
             virBufferAddLit(buf, "</origstates>\n");
         }
         break;
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
+        virBufferAsprintf(buf, "<adapter name='%s'/>\n",
+                          def->source.subsys.u.scsi.adapter);
+        virBufferAsprintf(buf, "<address %sbus='%d' target='%d' unit='%d'/>\n",
+                          includeTypeInAddr ? "type='scsi' " : "",
+                          def->source.subsys.u.scsi.bus,
+                          def->source.subsys.u.scsi.target,
+                          def->source.subsys.u.scsi.unit);
+        break;
     default:
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unexpected hostdev type %d"),
index 21f7ce28da7583bef4ed5c9a011aa0757ebe6b5e..1efae699c3ca73539717601f90695723ad59c268 100644 (file)
@@ -384,6 +384,7 @@ enum virDomainHostdevMode {
 enum virDomainHostdevSubsysType {
     VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB,
     VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI,
+    VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI,
 
     VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST
 };
@@ -417,6 +418,12 @@ struct _virDomainHostdevSubsys {
             virDevicePCIAddress addr; /* host address */
             int backend; /* enum virDomainHostdevSubsysPciBackendType */
         } pci;
+        struct {
+            char *adapter;
+            unsigned bus;
+            unsigned target;
+            unsigned unit;
+        } scsi;
     } u;
 };
 
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi.xml b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-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>
index 64c1c83023d9bd8778ddd12ace861696b6526623..1ca1f7e0da5d2d9be351402c2a2551c51e46d13a 100644 (file)
@@ -285,6 +285,8 @@ mymain(void)
     DO_TEST_DIFFERENT("pci-autoadd-addr");
     DO_TEST_DIFFERENT("pci-autoadd-idx");
 
+    DO_TEST("hostdev-scsi");
+
     virObjectUnref(driver.caps);
     virObjectUnref(driver.xmlopt);