[libvirt] [PATCH 8/8] conf: Add vHBA controller definition to domain

John Ferlan jferlan at redhat.com
Mon Feb 20 13:18:19 UTC 2017


Add the parsing of a vHBA controller to a domain <controller> XML.
The concept of a vHBA is somewhere between a scsi_host <hostdev> and
<controller>, so rather than invent a new <vhba> type, use the
existing <controller> syntax and add an <adapter> element to mimic
the existing storage pool 'fc_host' <adapter> element.

The new element can be parsed, but is unusable. The syntax is:

    <adapter [parent='%s' |
              parent_wwnn='%s' parent_wwpn='%s' |
              parent_fabric_wwn='%s']
              wwnn='%s' wwpn='%s'/>

and is be a subelement of a <controller type='scsi' model='virtio-scsi'>
element. A vHBA is only supported for the virtio-scsi. The controller
will be used exclusively to pass through vHBA LUNs to the domain as they
are discovered or remove them from the domain as that's discovered.

Since this controller is a "virtual" device and no physical qemu -device
is created for it, add checks into various places that would place a disk
or hostdev LUN onto a controller to ensure the vHBA controller is not used.

For now modify the qemu_command and qemu_hotplug code to error out if
one of these is defined. Future patches will add support.

Signed-off-by: John Ferlan <jferlan at redhat.com>
---
 docs/schemas/basictypes.rng                        |  66 ++++----
 docs/schemas/domaincommon.rng                      |  12 +-
 src/conf/domain_audit.c                            |  32 ++++
 src/conf/domain_conf.c                             | 180 +++++++++++++++++++--
 src/conf/domain_conf.h                             |   2 +
 src/qemu/qemu_alias.c                              |   5 +
 src/qemu/qemu_command.c                            |   4 +
 src/qemu/qemu_hotplug.c                            |  16 ++
 .../qemuxml2argv-vhba-no-parent.xml                |  38 +++++
 .../qemuxml2argv-vhba-parent-fabric.xml            |  38 +++++
 .../qemuxml2argv-vhba-parent-name.xml              |  38 +++++
 .../qemuxml2argv-vhba-parent-wwns.xml              |  38 +++++
 .../qemuxml2xmlout-vhba-no-parent.xml              |  47 ++++++
 .../qemuxml2xmlout-vhba-parent-fabric.xml          |  47 ++++++
 .../qemuxml2xmlout-vhba-parent-name.xml            |  47 ++++++
 .../qemuxml2xmlout-vhba-parent-wwns.xml            |  47 ++++++
 tests/qemuxml2xmltest.c                            |   9 ++
 17 files changed, 624 insertions(+), 42 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-vhba-no-parent.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-vhba-parent-fabric.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-vhba-parent-name.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-vhba-parent-wwns.xml
 create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-no-parent.xml
 create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-parent-fabric.xml
 create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-parent-name.xml
 create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-parent-wwns.xml

diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
index cc560e6..6f050cd 100644
--- a/docs/schemas/basictypes.rng
+++ b/docs/schemas/basictypes.rng
@@ -417,43 +417,47 @@
           <attribute name='type'>
             <value>fc_host</value>
           </attribute>
-          <optional>
-            <attribute name='parent'>
-              <text/>
-            </attribute>
-          </optional>
-          <optional>
-            <attribute name='managed'>
-              <ref name="virYesNo"/>
-            </attribute>
-          </optional>
-          <optional>
-            <attribute name='parent_wwnn'>
-              <ref name='wwn'/>
-            </attribute>
-          </optional>
-          <optional>
-            <attribute name='parent_wwpn'>
-              <ref name='wwn'/>
-            </attribute>
-          </optional>
-          <optional>
-            <attribute name='parent_fabric_wwn'>
-              <ref name='wwn'/>
-            </attribute>
-          </optional>
-          <attribute name='wwnn'>
-            <ref name='wwn'/>
-          </attribute>
-          <attribute name='wwpn'>
-            <ref name='wwn'/>
-          </attribute>
+          <ref name='vhbaadapter'/>
         </group>
       </choice>
       <empty/>
     </element>
   </define>
 
+  <define name="vhbaadapter">
+    <optional>
+      <attribute name='parent'>
+        <text/>
+      </attribute>
+    </optional>
+    <optional>
+      <attribute name='managed'>
+        <ref name="virYesNo"/>
+      </attribute>
+    </optional>
+    <optional>
+      <attribute name='parent_wwnn'>
+        <ref name='wwn'/>
+      </attribute>
+    </optional>
+    <optional>
+      <attribute name='parent_wwpn'>
+        <ref name='wwn'/>
+      </attribute>
+    </optional>
+    <optional>
+      <attribute name='parent_fabric_wwn'>
+        <ref name='wwn'/>
+      </attribute>
+    </optional>
+    <attribute name='wwnn'>
+      <ref name='wwn'/>
+    </attribute>
+    <attribute name='wwpn'>
+      <ref name='wwn'/>
+    </attribute>
+  </define>
+
   <define name="isaaddress">
     <optional>
       <attribute name="iobase">
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index c5f1013..6738ee7 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -1826,7 +1826,8 @@
               </choice>
             </attribute>
           </group>
-          <!-- scsi has an optional attribute "model" -->
+          <!-- scsi has an optional attribute "model"
+               and optional subelement "adapter" -->
           <group>
             <attribute name="type">
               <value>scsi</value>
@@ -1845,6 +1846,9 @@
                 </choice>
               </attribute>
             </optional>
+            <optional>
+              <ref name="scsiadapter"/>
+            </optional>
           </group>
           <!-- usb has an optional attribute "model",
                and optional subelements "master" and "ports" -->
@@ -4841,6 +4845,12 @@
     </element>
   </define>
 
+  <define name="scsiadapter">
+    <element name='adapter'>
+      <ref name='vhbaadapter'/>
+    </element>
+  </define>
+
   <define name="usbmaster">
     <element name="master">
       <attribute name="startport">
diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c
index 2d9ff5e..fcd2c69 100644
--- a/src/conf/domain_audit.c
+++ b/src/conf/domain_audit.c
@@ -516,6 +516,32 @@ virDomainAuditHostdev(virDomainObjPtr vm, virDomainHostdevDefPtr hostdev,
 
 
 /**
+ * virDomainAuditVHBA:
+ * @vm: domain making a change in pass-through host device
+ * @vhba: device being attached or removed
+ * @reason: one of "start", "attach", or "detach"
+ * @success: true if the device passthrough operation succeeded
+ *
+ * Log an audit message about an attempted device passthrough change.
+ */
+static void
+virDomainAuditVHBA(virDomainObjPtr vm, virStorageAdapterFCHostPtr fchost,
+                   const char *reason, bool success)
+{
+    char *wwstr = NULL;
+
+    if (virAsprintfQuiet(&wwstr, "%s:%s", fchost->wwpn, fchost->wwnn) < 0) {
+        VIR_WARN("OOM while encoding audit message");
+        return;
+    }
+
+    virDomainAuditGenericDev(vm, "vhba", NULL, wwstr, reason, success);
+
+    VIR_FREE(wwstr);
+}
+
+
+/**
  * virDomainAuditRedirdev:
  * @vm: domain making a change in pass-through host device
  * @redirdev: device being attached or removed
@@ -864,6 +890,12 @@ virDomainAuditStart(virDomainObjPtr vm, const char *reason, bool success)
         virDomainAuditHostdev(vm, hostdev, "start", true);
     }
 
+    for (i = 0; i < vm->def->ncontrollers; i++) {
+        if (!vm->def->controllers[i]->fchost)
+            continue;
+        virDomainAuditVHBA(vm, vm->def->controllers[i]->fchost, "start", true);
+    }
+
     for (i = 0; i < vm->def->nredirdevs; i++) {
         virDomainRedirdevDefPtr redirdev = vm->def->redirdevs[i];
         virDomainAuditRedirdev(vm, redirdev, "start", true);
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index a56ea82..c993f57 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1789,16 +1789,22 @@ virDomainControllerDefNew(virDomainControllerType type)
 }
 
 
-void virDomainControllerDefFree(virDomainControllerDefPtr def)
+void
+virDomainControllerDefFree(virDomainControllerDefPtr def)
 {
     if (!def)
         return;
 
+    if (def->fchost) {
+        virStorageAdapterVHBAClear(def->fchost);
+        VIR_FREE(def->fchost);
+    }
     virDomainDeviceInfoClear(&def->info);
 
     VIR_FREE(def);
 }
 
+
 virDomainFSDefPtr
 virDomainFSDefNew(void)
 {
@@ -2379,6 +2385,7 @@ void virDomainHostdevDefFree(virDomainHostdevDefPtr def)
         VIR_FREE(def);
 }
 
+
 void virDomainHubDefFree(virDomainHubDefPtr def)
 {
     if (!def)
@@ -3338,6 +3345,7 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device)
     case VIR_DOMAIN_DEVICE_LEASE:
     case VIR_DOMAIN_DEVICE_GRAPHICS:
     case VIR_DOMAIN_DEVICE_IOMMU:
+
     case VIR_DOMAIN_DEVICE_LAST:
     case VIR_DOMAIN_DEVICE_NONE:
         break;
@@ -3653,7 +3661,6 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
     case VIR_DOMAIN_DEVICE_GRAPHICS:
     case VIR_DOMAIN_DEVICE_HUB:
     case VIR_DOMAIN_DEVICE_REDIRDEV:
-    case VIR_DOMAIN_DEVICE_NONE:
     case VIR_DOMAIN_DEVICE_SMARTCARD:
     case VIR_DOMAIN_DEVICE_CHR:
     case VIR_DOMAIN_DEVICE_MEMBALLOON:
@@ -3661,10 +3668,12 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
     case VIR_DOMAIN_DEVICE_SHMEM:
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
-    case VIR_DOMAIN_DEVICE_LAST:
     case VIR_DOMAIN_DEVICE_RNG:
     case VIR_DOMAIN_DEVICE_MEMORY:
     case VIR_DOMAIN_DEVICE_IOMMU:
+
+    case VIR_DOMAIN_DEVICE_NONE:
+    case VIR_DOMAIN_DEVICE_LAST:
         break;
     }
 #endif
@@ -4169,6 +4178,10 @@ virDomainHostdevAssignAddress(virDomainXMLOptionPtr xmlopt,
         if (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
             continue;
 
+        /* Do not allow assignment to the VHBA controller */
+        if (def->controllers[i]->fchost)
+            continue;
+
         controller++;
         ret = virDomainControllerSCSINextUnit(def, max_unit,
                                               def->controllers[i]->idx);
@@ -4197,6 +4210,24 @@ virDomainHostdevAssignAddress(virDomainXMLOptionPtr xmlopt,
 }
 
 
+/* Returns true if the passed in address info matches the controller address
+ * for a VHBA controller */
+static bool
+virDomainDriveAddressIsUsedByVHBA(const virDomainDef *def,
+                                  const virDomainDeviceDriveAddress *addr)
+{
+    size_t i;
+
+    for (i = 0; i < def->ncontrollers; i++) {
+        if (def->controllers[i]->fchost &&
+            def->controllers[i]->idx == addr->controller)
+            return true;
+    }
+
+    return false;
+}
+
+
 static int
 virDomainDeviceDefPostParseInternal(virDomainDeviceDefPtr dev,
                                     const virDomainDef *def,
@@ -4303,6 +4334,17 @@ virDomainDeviceDefPostParseInternal(virDomainDeviceDefPtr dev,
                                    addr->target, addr->unit);
                     return -1;
                 }
+
+                /* If the assignment was to a vHBA controller fail */
+                if (virDomainDriveAddressIsUsedByVHBA(def, addr)) {
+                    virReportError(VIR_ERR_XML_ERROR,
+                                   _("SCSI host address controller='%u' "
+                                     "bus='%u' target='%u' unit='%u' cannot "
+                                     "use a vHBA controller"),
+                                   addr->controller, addr->bus,
+                                   addr->target, addr->unit);
+                    return -1;
+                }
             }
         }
     }
@@ -4318,6 +4360,16 @@ virDomainDeviceDefPostParseInternal(virDomainDeviceDefPtr dev,
                            virDomainControllerModelSCSITypeToString(VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI));
             return -1;
         }
+
+        if (cdev->fchost && cdev->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
+            cdev->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("Invalid VHBA configuration, requires controller "
+                             "model '%s'"),
+                           virDomainControllerModelSCSITypeToString(VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI));
+            return -1;
+        }
+
     }
 
     return 0;
@@ -4736,7 +4788,8 @@ virDomainDiskAddressDiskBusCompatibility(virDomainDiskBus bus,
 
 
 static int
-virDomainDiskDefValidate(const virDomainDiskDef *disk)
+virDomainDiskDefValidate(const virDomainDef *def,
+                         const virDomainDiskDef *disk)
 {
     /* Validate LUN configuration */
     if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
@@ -4766,6 +4819,17 @@ virDomainDiskDefValidate(const virDomainDiskDef *disk)
         return -1;
     }
 
+    /* If the disk is assigned to a controller being used for vHBA then
+     * reject it.
+     */
+    if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE &&
+        virDomainDriveAddressIsUsedByVHBA(def, &disk->info.addr.drive)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("disk '%s' improperly configured cannot use a "
+                         "VHBA controller"), disk->dst);
+        return -1;
+    }
+
     return 0;
 }
 
@@ -4822,7 +4886,7 @@ virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev,
 {
     switch ((virDomainDeviceType) dev->type) {
     case VIR_DOMAIN_DEVICE_DISK:
-        return virDomainDiskDefValidate(dev->data.disk);
+        return virDomainDiskDefValidate(def, dev->data.disk);
 
     case VIR_DOMAIN_DEVICE_REDIRDEV:
         return virDomainRedirdevDefValidate(def, dev->data.redirdev);
@@ -4830,6 +4894,10 @@ virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev,
     case VIR_DOMAIN_DEVICE_NET:
         return virDomainNetDefValidate(dev->data.net);
 
+    case VIR_DOMAIN_DEVICE_CONTROLLER:
+        if (dev->data.controller->fchost)
+            return virStorageAdapterVHBAParseValidate(dev->data.controller->fchost);
+
     case VIR_DOMAIN_DEVICE_LEASE:
     case VIR_DOMAIN_DEVICE_FS:
     case VIR_DOMAIN_DEVICE_INPUT:
@@ -4837,7 +4905,6 @@ virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev,
     case VIR_DOMAIN_DEVICE_VIDEO:
     case VIR_DOMAIN_DEVICE_HOSTDEV:
     case VIR_DOMAIN_DEVICE_WATCHDOG:
-    case VIR_DOMAIN_DEVICE_CONTROLLER:
     case VIR_DOMAIN_DEVICE_GRAPHICS:
     case VIR_DOMAIN_DEVICE_HUB:
     case VIR_DOMAIN_DEVICE_SMARTCARD:
@@ -6757,7 +6824,16 @@ virDomainDiskDefAssignAddress(virDomainXMLOptionPtr xmlopt,
             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                            _("using disk target name '%s' conflicts with "
                              "SCSI host device address controller='%u' "
-                             "bus='%u' target='%u' unit='%u"),
+                             "bus='%u' target='%u' unit='%u'"),
+                           def->dst, controller, 0, 0, unit);
+            return -1;
+        }
+
+        if (virDomainDriveAddressIsUsedByVHBA(vmdef, &addr)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("using disk target name '%s' conflicts with "
+                             "VHBA controller='%u' bus='%u' target='%u' "
+                             "unit='%u'"),
                            def->dst, controller, 0, 0, unit);
             return -1;
         }
@@ -8572,6 +8648,20 @@ virDomainControllerModelTypeToString(virDomainControllerDefPtr def,
 }
 
 
+static int
+virDomainControllerVHBAParseXML(xmlNodePtr node,
+                                virDomainControllerDefPtr def)
+{
+    if (VIR_ALLOC(def->fchost) < 0)
+        return -1;
+
+    if (virStorageAdapterVHBAParseXML(node, def->fchost) < 0)
+        return -1;
+
+    return 0;
+}
+
+
 /* Parse the XML definition for a controller
  * @param node XML nodeset to parse for controller definition
  */
@@ -8669,6 +8759,9 @@ virDomainControllerDefParseXML(xmlNodePtr node,
                 port = virXMLPropString(cur, "port");
                 busNr = virXMLPropString(cur, "busNr");
                 processedTarget = true;
+            } else if (xmlStrEqual(cur->name, BAD_CAST "adapter")) {
+                if (virDomainControllerVHBAParseXML(cur, def) < 0)
+                    goto error;
             }
         }
         cur = cur->next;
@@ -18609,6 +18702,67 @@ virDomainControllerDefCheckABIStability(virDomainControllerDefPtr src,
         return false;
     }
 
+    if ((src->fchost && !dst->fchost) || (!src->fchost && dst->fchost)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Target controller VHBA presence does not match "
+                         "source"));
+        return false;
+    }
+
+    if (src->fchost) {
+        if (STRNEQ(src->fchost->wwnn, dst->fchost->wwnn)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("Target VHBA wwnn %s does not match source %s"),
+                           dst->fchost->wwnn, src->fchost->wwnn);
+            return false;
+        }
+
+        if (STRNEQ(src->fchost->wwpn, dst->fchost->wwpn)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("Target VHBA wwpn %s does not match source %s"),
+                           dst->fchost->wwpn, src->fchost->wwpn);
+            return false;
+        }
+
+        if (STRNEQ_NULLABLE(src->fchost->parent, dst->fchost->parent)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("Target VHBA parent %s does not match source %s"),
+                           NULLSTR(dst->fchost->parent),
+                           NULLSTR(src->fchost->parent));
+            return false;
+        }
+
+        if (STRNEQ_NULLABLE(src->fchost->parent_wwnn,
+                            dst->fchost->parent_wwnn)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("Target VHBA parent wwnn %s does not match "
+                             "source %s"),
+                           NULLSTR(dst->fchost->parent_wwnn),
+                           NULLSTR(src->fchost->parent_wwnn));
+            return false;
+        }
+
+        if (STRNEQ_NULLABLE(src->fchost->parent_wwpn,
+                            dst->fchost->parent_wwpn)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("Target VHBA parent wwpn %s does not match "
+                             "source %s"),
+                           NULLSTR(dst->fchost->parent_wwpn),
+                           NULLSTR(src->fchost->parent_wwpn));
+            return false;
+        }
+
+        if (STRNEQ_NULLABLE(src->fchost->parent_fabric_wwn,
+                            dst->fchost->parent_fabric_wwn)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("Target VHBA parent fabric wwn %s does not match "
+                             "source %s"),
+                           NULLSTR(dst->fchost->parent_fabric_wwn),
+                           NULLSTR(src->fchost->parent_fabric_wwn));
+            return false;
+        }
+    }
+
     if (src->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) {
         if (src->opts.vioserial.ports != dst->opts.vioserial.ports) {
             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -19875,18 +20029,19 @@ virDomainDefCheckABIStabilityFlags(virDomainDefPtr src,
     case VIR_DOMAIN_DEVICE_GRAPHICS:
     case VIR_DOMAIN_DEVICE_HUB:
     case VIR_DOMAIN_DEVICE_REDIRDEV:
-    case VIR_DOMAIN_DEVICE_NONE:
     case VIR_DOMAIN_DEVICE_SMARTCARD:
     case VIR_DOMAIN_DEVICE_CHR:
     case VIR_DOMAIN_DEVICE_MEMBALLOON:
     case VIR_DOMAIN_DEVICE_NVRAM:
-    case VIR_DOMAIN_DEVICE_LAST:
     case VIR_DOMAIN_DEVICE_RNG:
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_SHMEM:
     case VIR_DOMAIN_DEVICE_MEMORY:
     case VIR_DOMAIN_DEVICE_IOMMU:
+
+    case VIR_DOMAIN_DEVICE_NONE:
+    case VIR_DOMAIN_DEVICE_LAST:
         break;
     }
 #endif
@@ -20900,7 +21055,7 @@ virDomainControllerDefFormat(virBufferPtr buf,
 
     if (pciModel || pciTarget ||
         def->queues || def->cmd_per_lun || def->max_sectors || def->ioeventfd ||
-        def->iothread ||
+        def->iothread || def->fchost ||
         virDomainDeviceInfoNeedsFormat(&def->info, flags) || pcihole64) {
         virBufferAddLit(buf, ">\n");
         virBufferAdjustIndent(buf, 2);
@@ -20965,6 +21120,11 @@ virDomainControllerDefFormat(virBufferPtr buf,
             virBufferAddLit(buf, "/>\n");
         }
 
+        if (def->fchost) {
+            virBufferAddLit(buf, "<adapter");
+            virStorageAdapterVHBAFormat(buf, def->fchost);
+        }
+
         if (virDomainDeviceInfoNeedsFormat(&def->info, flags) &&
             virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
             return -1;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 7e1afa4..90ad556 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -48,6 +48,7 @@
 # include "virobject.h"
 # include "device_conf.h"
 # include "virbitmap.h"
+# include "virstoragedevice.h"
 # include "virstoragefile.h"
 # include "virseclabel.h"
 # include "virprocess.h"
@@ -795,6 +796,7 @@ struct _virDomainControllerDef {
         virDomainPCIControllerOpts pciopts;
         virDomainUSBControllerOpts usbopts;
     } opts;
+    virStorageAdapterFCHostPtr fchost;
     virDomainDeviceInfo info;
 };
 
diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c
index 8521a44..6dc9985 100644
--- a/src/qemu/qemu_alias.c
+++ b/src/qemu/qemu_alias.c
@@ -165,6 +165,11 @@ qemuAssignDeviceControllerAlias(virDomainDefPtr domainDef,
         /* first USB device is "usb", others are normal "usb%d" */
         if (controller->idx == 0)
             return VIR_STRDUP(controller->info.alias, "usb");
+    } else if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
+               controller->fchost) {
+        /* There is no need for an alias for a vHBA since we're not passing
+         * it through to QEMU */
+        return 0;
     }
     /* all other controllers use the default ${type}${index} naming
      * scheme for alias/id.
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index f4bcfd4..44c2c81 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3120,6 +3120,10 @@ qemuBuildControllerDevCommandLine(virCommandPtr cmd,
             if (cont->type != contOrder[j])
                 continue;
 
+            /* skip vHBA controller */
+            if (cont->fchost)
+                continue;
+
             /* skip USB controllers with type none.*/
             if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB &&
                 cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE) {
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 2f209f1..f7829da 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -481,6 +481,12 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
         return -1;
     }
 
+    if (controller->fchost) {
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                       _("hotplug not support for vHBA controller."));
+        return -1;
+    }
+
     /* default idx would normally be set by virDomainDefPostParse(),
      * which isn't called in the case of live attach of a single
      * device.
@@ -566,6 +572,10 @@ qemuDomainFindOrCreateSCSIDiskController(virQEMUDriverPtr driver,
         if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
             continue;
 
+        /* The VHBA controller has a singular purpose */
+        if (cont->fchost)
+            continue;
+
         if (cont->idx == controller)
             return cont;
     }
@@ -4597,6 +4607,12 @@ int qemuDomainDetachControllerDevice(virQEMUDriverPtr driver,
         goto cleanup;
     }
 
+    if (detach->fchost) {
+        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                       _("vHBA controller cannot be detached"));
+        goto cleanup;
+    }
+
     if (!virDomainDeviceAddressIsValid(&detach->info, detach->info.type)) {
         virReportError(VIR_ERR_OPERATION_FAILED,
                        _("device with invalid '%s' address cannot be detached"),
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-vhba-no-parent.xml b/tests/qemuxml2argvdata/qemuxml2argv-vhba-no-parent.xml
new file mode 100644
index 0000000..20ef29c
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-vhba-no-parent.xml
@@ -0,0 +1,38 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</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/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <disk type='file' device='disk'>
+      <source file='/tmp/scsidisk.img'/>
+      <target dev='sda' bus='scsi'/>
+      <address type='drive' controller='0' bus='0' target='4' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'/>
+    <controller type='scsi' index='0' model='virtio-scsi'/>
+    <controller type='scsi' index='1' model='virtio-scsi'>
+      <adapter wwnn='20000000c9831b4b' wwpn='10000000c9831b4b'/>
+    </controller>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='0' model='pci-root'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-vhba-parent-fabric.xml b/tests/qemuxml2argvdata/qemuxml2argv-vhba-parent-fabric.xml
new file mode 100644
index 0000000..b58f924
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-vhba-parent-fabric.xml
@@ -0,0 +1,38 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</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/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <disk type='file' device='disk'>
+      <source file='/tmp/scsidisk.img'/>
+      <target dev='sda' bus='scsi'/>
+      <address type='drive' controller='0' bus='0' target='4' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'/>
+    <controller type='scsi' index='0' model='virtio-scsi'/>
+    <controller type='scsi' index='1' model='virtio-scsi'>
+      <adapter parent_fabric_wwn='2000000043214321' wwnn='20000000c9831b4b' wwpn='10000000c9831b4b'/>
+    </controller>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='0' model='pci-root'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-vhba-parent-name.xml b/tests/qemuxml2argvdata/qemuxml2argv-vhba-parent-name.xml
new file mode 100644
index 0000000..539188c
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-vhba-parent-name.xml
@@ -0,0 +1,38 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</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/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <disk type='file' device='disk'>
+      <source file='/tmp/scsidisk.img'/>
+      <target dev='sda' bus='scsi'/>
+      <address type='drive' controller='0' bus='0' target='4' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'/>
+    <controller type='scsi' index='0' model='virtio-scsi'/>
+    <controller type='scsi' index='1' model='virtio-scsi'>
+      <adapter parent='scsi_host1' wwnn='20000000c9831b4b' wwpn='10000000c9831b4b'/>
+    </controller>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='0' model='pci-root'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-vhba-parent-wwns.xml b/tests/qemuxml2argvdata/qemuxml2argv-vhba-parent-wwns.xml
new file mode 100644
index 0000000..5ca1b80
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-vhba-parent-wwns.xml
@@ -0,0 +1,38 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</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/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <disk type='file' device='disk'>
+      <source file='/tmp/scsidisk.img'/>
+      <target dev='sda' bus='scsi'/>
+      <address type='drive' controller='0' bus='0' target='4' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'/>
+    <controller type='scsi' index='0' model='virtio-scsi'/>
+    <controller type='scsi' index='1' model='virtio-scsi'>
+      <adapter parent_wwnn='2000000012341234' parent_wwpn='1000000012341234' wwnn='20000000c9831b4b' wwpn='10000000c9831b4b'/>
+    </controller>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='0' model='pci-root'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-no-parent.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-no-parent.xml
new file mode 100644
index 0000000..9f5ad6b
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-no-parent.xml
@@ -0,0 +1,47 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</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/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <disk type='file' device='disk'>
+      <source file='/tmp/scsidisk.img'/>
+      <target dev='sda' bus='scsi'/>
+      <address type='drive' controller='0' bus='0' target='4' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </controller>
+    <controller type='scsi' index='0' model='virtio-scsi'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </controller>
+    <controller type='scsi' index='1' model='virtio-scsi'>
+      <adapter wwnn='20000000c9831b4b' wwpn='10000000c9831b4b'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+    </controller>
+    <controller type='usb' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='virtio'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+    </memballoon>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-parent-fabric.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-parent-fabric.xml
new file mode 100644
index 0000000..753fe78
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-parent-fabric.xml
@@ -0,0 +1,47 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</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/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <disk type='file' device='disk'>
+      <source file='/tmp/scsidisk.img'/>
+      <target dev='sda' bus='scsi'/>
+      <address type='drive' controller='0' bus='0' target='4' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </controller>
+    <controller type='scsi' index='0' model='virtio-scsi'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </controller>
+    <controller type='scsi' index='1' model='virtio-scsi'>
+      <adapter parent_fabric_wwn='2000000043214321' wwnn='20000000c9831b4b' wwpn='10000000c9831b4b'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+    </controller>
+    <controller type='usb' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='virtio'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+    </memballoon>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-parent-name.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-parent-name.xml
new file mode 100644
index 0000000..e7bce0a
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-parent-name.xml
@@ -0,0 +1,47 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</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/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <disk type='file' device='disk'>
+      <source file='/tmp/scsidisk.img'/>
+      <target dev='sda' bus='scsi'/>
+      <address type='drive' controller='0' bus='0' target='4' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </controller>
+    <controller type='scsi' index='0' model='virtio-scsi'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </controller>
+    <controller type='scsi' index='1' model='virtio-scsi'>
+      <adapter parent='scsi_host1' wwnn='20000000c9831b4b' wwpn='10000000c9831b4b'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+    </controller>
+    <controller type='usb' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='virtio'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+    </memballoon>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-parent-wwns.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-parent-wwns.xml
new file mode 100644
index 0000000..2842f08
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-vhba-parent-wwns.xml
@@ -0,0 +1,47 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</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/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <disk type='file' device='disk'>
+      <source file='/tmp/scsidisk.img'/>
+      <target dev='sda' bus='scsi'/>
+      <address type='drive' controller='0' bus='0' target='4' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </controller>
+    <controller type='scsi' index='0' model='virtio-scsi'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </controller>
+    <controller type='scsi' index='1' model='virtio-scsi'>
+      <adapter parent_wwnn='2000000012341234' parent_wwpn='1000000012341234' wwnn='20000000c9831b4b' wwpn='10000000c9831b4b'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+    </controller>
+    <controller type='usb' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='virtio'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+    </memballoon>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 0702f58..e810afd 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -638,6 +638,15 @@ mymain(void)
     DO_TEST("disk-source-pool", NONE);
     DO_TEST("disk-source-pool-mode", NONE);
 
+    DO_TEST("vhba-no-parent",
+            QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_VIRTIO_SCSI);
+    DO_TEST("vhba-parent-name",
+            QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_VIRTIO_SCSI);
+    DO_TEST("vhba-parent-wwns",
+            QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_VIRTIO_SCSI);
+    DO_TEST("vhba-parent-fabric",
+            QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_VIRTIO_SCSI);
+
     DO_TEST("disk-drive-discard", NONE);
     DO_TEST("disk-drive-detect-zeroes", NONE);
 
-- 
2.9.3




More information about the libvir-list mailing list