[libvirt] [PATCH 3/8] util: Convert virStoragePoolSourceAdapter to virStorageAdapter

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


Introduce src/util/virstoragedevice.{c,h}. Rather than have virstoragefile
be a repository for more things - create a new module to share the adapter
definitions between the storage pool and eventually the domain. The devices
will need device address functions (no need to pollute more code for that).

Move the virStoragePoolSourceAdapter from storage_conf into the new
module and parcel out the the structure a bit more into 'fchost' and
'scsi_host' specific pieces creating virStoragePoolSourceAdapterSCSIHost
and virStoragePoolSourceAdapterFCHost structures for easier access.

Modify code in the various places which formerly used the pool structure
to use the new model. This includes some changes that will use the Ptr
rather than just the struct (try to shorten the number of times one
has to type adapter.data.fchost or adapter.data.scsi_host as well as
[pool->]def->source.adapter.

Signed-off-by: John Ferlan <jferlan at redhat.com>
---
 po/POTFILES.in                     |   1 +
 src/Makefile.am                    |   1 +
 src/conf/storage_conf.c            | 338 ++++++++-----------------------------
 src/conf/storage_conf.h            |  35 +---
 src/libvirt_private.syms           |  16 +-
 src/libxl/libxl_conf.c             |   1 +
 src/phyp/phyp_driver.c             |   3 +-
 src/storage/storage_backend_scsi.c | 131 +++++++-------
 src/test/test_driver.c             |   4 +-
 src/util/virscsihost.c             |  28 +--
 src/util/virscsihost.h             |   8 +-
 src/util/virstoragedevice.c        | 292 ++++++++++++++++++++++++++++++++
 src/util/virstoragedevice.h        |  89 ++++++++++
 13 files changed, 548 insertions(+), 399 deletions(-)
 create mode 100644 src/util/virstoragedevice.c
 create mode 100644 src/util/virstoragedevice.h

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 9f66697..fe07d16 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -248,6 +248,7 @@ src/util/virsecret.c
 src/util/virsexpr.c
 src/util/virsocketaddr.c
 src/util/virstorageencryption.c
+src/util/virstoragedevice.c
 src/util/virstoragefile.c
 src/util/virstring.c
 src/util/virsysinfo.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 46ca272..d14b376 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -171,6 +171,7 @@ UTIL_SOURCES =							\
 		util/virsexpr.c util/virsexpr.h			\
 		util/virsocketaddr.h util/virsocketaddr.c	\
 		util/virstorageencryption.c util/virstorageencryption.h \
+		util/virstoragedevice.c util/virstoragedevice.h	\
 		util/virstoragefile.c util/virstoragefile.h	\
 		util/virstring.h util/virstring.c		\
 		util/virsysinfo.c util/virsysinfo.h		\
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index 0e9a51f..c68e827 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -100,10 +100,6 @@ VIR_ENUM_IMPL(virStoragePartedFs,
               "ext2", "ext2",
               "extended")
 
-VIR_ENUM_IMPL(virStoragePoolSourceAdapter,
-              VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST,
-              "default", "scsi_host", "fc_host")
-
 typedef const char *(*virStorageVolFormatToString)(int format);
 typedef int (*virStorageVolFormatFromString)(const char *format);
 
@@ -342,21 +338,6 @@ virStorageVolDefFree(virStorageVolDefPtr def)
     VIR_FREE(def);
 }
 
-static void
-virStoragePoolSourceAdapterClear(virStoragePoolSourceAdapterPtr adapter)
-{
-    if (adapter->type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
-        VIR_FREE(adapter->data.fchost.wwnn);
-        VIR_FREE(adapter->data.fchost.wwpn);
-        VIR_FREE(adapter->data.fchost.parent);
-        VIR_FREE(adapter->data.fchost.parent_wwnn);
-        VIR_FREE(adapter->data.fchost.parent_wwpn);
-        VIR_FREE(adapter->data.fchost.parent_fabric_wwn);
-    } else if (adapter->type ==
-               VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
-        VIR_FREE(adapter->data.scsi_host.name);
-    }
-}
 
 void
 virStoragePoolSourceDeviceClear(virStoragePoolSourceDevicePtr dev)
@@ -382,7 +363,7 @@ virStoragePoolSourceClear(virStoragePoolSourcePtr source)
     VIR_FREE(source->devices);
     VIR_FREE(source->dir);
     VIR_FREE(source->name);
-    virStoragePoolSourceAdapterClear(&source->adapter);
+    virStorageAdapterClear(&source->adapter);
     VIR_FREE(source->initiator.iqn);
     virStorageAuthDefFree(source->auth);
     VIR_FREE(source->vendor);
@@ -462,6 +443,7 @@ virStoragePoolObjRemove(virStoragePoolObjListPtr pools,
     }
 }
 
+
 static int
 virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
                              virStoragePoolSourcePtr source,
@@ -470,14 +452,13 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
 {
     int ret = -1;
     xmlNodePtr relnode, authnode, *nodeset = NULL;
+    xmlNodePtr adapternode;
     int nsource;
     size_t i;
     virStoragePoolOptionsPtr options;
     virStorageAuthDefPtr authdef = NULL;
     char *name = NULL;
     char *port = NULL;
-    char *adapter_type = NULL;
-    char *managed = NULL;
     int n;
 
     relnode = ctxt->node;
@@ -583,109 +564,9 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
         VIR_STRDUP(source->dir, "/") < 0)
         goto cleanup;
 
-    if ((adapter_type = virXPathString("string(./adapter/@type)", ctxt))) {
-        if ((source->adapter.type =
-             virStoragePoolSourceAdapterTypeFromString(adapter_type)) <= 0) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                           _("Unknown pool adapter type '%s'"),
-                           adapter_type);
+    if ((adapternode = virXPathNode("./adapter", ctxt))) {
+        if (virStorageAdapterParseXML(&source->adapter, adapternode, ctxt) < 0)
             goto cleanup;
-        }
-
-        if (source->adapter.type ==
-            VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
-            source->adapter.data.fchost.parent =
-                virXPathString("string(./adapter/@parent)", ctxt);
-            managed = virXPathString("string(./adapter/@managed)", ctxt);
-            if (managed) {
-                source->adapter.data.fchost.managed =
-                    virTristateBoolTypeFromString(managed);
-                if (source->adapter.data.fchost.managed < 0) {
-                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                   _("unknown fc_host managed setting '%s'"),
-                                   managed);
-                    goto cleanup;
-                }
-            }
-
-            source->adapter.data.fchost.parent_wwnn =
-                virXPathString("string(./adapter/@parent_wwnn)", ctxt);
-            source->adapter.data.fchost.parent_wwpn =
-                virXPathString("string(./adapter/@parent_wwpn)", ctxt);
-            source->adapter.data.fchost.parent_fabric_wwn =
-                virXPathString("string(./adapter/@parent_fabric_wwn)", ctxt);
-
-            source->adapter.data.fchost.wwpn =
-                virXPathString("string(./adapter/@wwpn)", ctxt);
-            source->adapter.data.fchost.wwnn =
-                virXPathString("string(./adapter/@wwnn)", ctxt);
-        } else if (source->adapter.type ==
-                   VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
-
-            source->adapter.data.scsi_host.name =
-                virXPathString("string(./adapter/@name)", ctxt);
-            if (virXPathNode("./adapter/parentaddr", ctxt)) {
-                xmlNodePtr addrnode = virXPathNode("./adapter/parentaddr/address",
-                                                   ctxt);
-                virPCIDeviceAddressPtr addr =
-                    &source->adapter.data.scsi_host.parentaddr;
-
-                if (!addrnode) {
-                    virReportError(VIR_ERR_XML_ERROR, "%s",
-                                   _("Missing scsi_host PCI address element"));
-                    goto cleanup;
-                }
-                source->adapter.data.scsi_host.has_parent = true;
-                if (virPCIDeviceAddressParseXML(addrnode, addr) < 0)
-                    goto cleanup;
-                if ((virXPathInt("string(./adapter/parentaddr/@unique_id)",
-                                 ctxt,
-                                 &source->adapter.data.scsi_host.unique_id) < 0) ||
-                    (source->adapter.data.scsi_host.unique_id < 0)) {
-                    virReportError(VIR_ERR_XML_ERROR, "%s",
-                                   _("Missing or invalid scsi adapter "
-                                     "'unique_id' value"));
-                    goto cleanup;
-                }
-            }
-        }
-    } else {
-        char *wwnn = NULL;
-        char *wwpn = NULL;
-        char *parent = NULL;
-
-        /* "type" was not specified in the XML, so we must verify that
-         * "wwnn", "wwpn", "parent", or "parentaddr" are also not in the
-         * XML. If any are found, then we cannot just use "name" alone".
-         */
-        wwnn = virXPathString("string(./adapter/@wwnn)", ctxt);
-        wwpn = virXPathString("string(./adapter/@wwpn)", ctxt);
-        parent = virXPathString("string(./adapter/@parent)", ctxt);
-
-        if (wwnn || wwpn || parent) {
-            VIR_FREE(wwnn);
-            VIR_FREE(wwpn);
-            VIR_FREE(parent);
-            virReportError(VIR_ERR_XML_ERROR, "%s",
-                           _("Use of 'wwnn', 'wwpn', and 'parent' attributes "
-                             "requires use of the adapter 'type'"));
-            goto cleanup;
-        }
-
-        if (virXPathNode("./adapter/parentaddr", ctxt)) {
-            virReportError(VIR_ERR_XML_ERROR, "%s",
-                           _("Use of 'parent' element requires use "
-                             "of the adapter 'type'"));
-            goto cleanup;
-        }
-
-        /* To keep back-compat, 'type' is not required to specify
-         * for scsi_host adapter.
-         */
-        if ((source->adapter.data.scsi_host.name =
-             virXPathString("string(./adapter/@name)", ctxt)))
-            source->adapter.type =
-                VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST;
     }
 
     if ((authnode = virXPathNode("./auth", ctxt))) {
@@ -711,8 +592,6 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
 
     VIR_FREE(port);
     VIR_FREE(nodeset);
-    VIR_FREE(adapter_type);
-    VIR_FREE(managed);
     virStorageAuthDefFree(authdef);
     return ret;
 }
@@ -928,37 +807,8 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt)
             goto error;
         }
 
-        if (ret->source.adapter.type ==
-            VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
-            if (!ret->source.adapter.data.fchost.wwnn ||
-                !ret->source.adapter.data.fchost.wwpn) {
-                virReportError(VIR_ERR_XML_ERROR, "%s",
-                               _("'wwnn' and 'wwpn' must be specified for adapter "
-                                 "type 'fchost'"));
-                goto error;
-            }
-
-            if (!virValidateWWN(ret->source.adapter.data.fchost.wwnn) ||
-                !virValidateWWN(ret->source.adapter.data.fchost.wwpn))
-                goto error;
-        } else if (ret->source.adapter.type ==
-                   VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
-            if (!ret->source.adapter.data.scsi_host.name &&
-                !ret->source.adapter.data.scsi_host.has_parent) {
-                virReportError(VIR_ERR_XML_ERROR, "%s",
-                               _("Either 'name' or 'parent' must be specified "
-                                 "for the 'scsi_host' adapter"));
-                goto error;
-            }
-
-            if (ret->source.adapter.data.scsi_host.name &&
-                ret->source.adapter.data.scsi_host.has_parent) {
-                virReportError(VIR_ERR_XML_ERROR, "%s",
-                               _("Both 'name' and 'parent' cannot be specified "
-                                 "for the 'scsi_host' adapter"));
-                goto error;
-            }
-        }
+        if (virStorageAdapterParseValidate(&ret->source.adapter) < 0)
+            goto error;
     }
 
     /* If DEVICE is the only source type, then its required */
@@ -1112,49 +962,10 @@ virStoragePoolSourceFormat(virBufferPtr buf,
     if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR)
         virBufferEscapeString(buf, "<dir path='%s'/>\n", src->dir);
 
-    if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER)) {
-        if (src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST ||
-            src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST)
-            virBufferAsprintf(buf, "<adapter type='%s'",
-                              virStoragePoolSourceAdapterTypeToString(src->adapter.type));
-
-        if (src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
-            virBufferEscapeString(buf, " parent='%s'",
-                                  src->adapter.data.fchost.parent);
-            if (src->adapter.data.fchost.managed)
-                virBufferAsprintf(buf, " managed='%s'",
-                                  virTristateBoolTypeToString(src->adapter.data.fchost.managed));
-            virBufferEscapeString(buf, " parent_wwnn='%s'",
-                                  src->adapter.data.fchost.parent_wwnn);
-            virBufferEscapeString(buf, " parent_wwpn='%s'",
-                                  src->adapter.data.fchost.parent_wwpn);
-            virBufferEscapeString(buf, " parent_fabric_wwn='%s'",
-                                  src->adapter.data.fchost.parent_fabric_wwn);
-
-            virBufferAsprintf(buf, " wwnn='%s' wwpn='%s'/>\n",
-                              src->adapter.data.fchost.wwnn,
-                              src->adapter.data.fchost.wwpn);
-        } else if (src->adapter.type ==
-                   VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
-            if (src->adapter.data.scsi_host.name) {
-                virBufferAsprintf(buf, " name='%s'/>\n",
-                                  src->adapter.data.scsi_host.name);
-            } else {
-                virPCIDeviceAddress addr;
-                virBufferAddLit(buf, ">\n");
-                virBufferAdjustIndent(buf, 2);
-                virBufferAsprintf(buf, "<parentaddr unique_id='%d'>\n",
-                                  src->adapter.data.scsi_host.unique_id);
-                virBufferAdjustIndent(buf, 2);
-                addr = src->adapter.data.scsi_host.parentaddr;
-                ignore_value(virPCIDeviceAddressFormat(buf, addr, false));
-                virBufferAdjustIndent(buf, -2);
-                virBufferAddLit(buf, "</parentaddr>\n");
-                virBufferAdjustIndent(buf, -2);
-                virBufferAddLit(buf, "</adapter>\n");
-            }
-        }
-    }
+    if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) &&
+        (src->adapter.type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST ||
+         src->adapter.type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST))
+        virStorageAdapterFormat(buf, &src->adapter);
 
     if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME)
         virBufferEscapeString(buf, "<name>%s</name>\n", src->name);
@@ -2279,27 +2090,20 @@ virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools,
 
 
 static int
-getSCSIHostNumber(virStoragePoolSourceAdapter adapter,
+getSCSIHostNumber(virStorageAdapterSCSIHostPtr scsi_host,
                   unsigned int *hostnum)
 {
     int ret = -1;
     unsigned int num;
     char *name = NULL;
 
-    if (adapter.data.scsi_host.has_parent) {
-        virPCIDeviceAddress addr = adapter.data.scsi_host.parentaddr;
-        unsigned int unique_id = adapter.data.scsi_host.unique_id;
-
-        if (!(name = virSCSIHostGetNameByParentaddr(addr.domain,
-                                                    addr.bus,
-                                                    addr.slot,
-                                                    addr.function,
-                                                    unique_id)))
+    if (scsi_host->has_parent) {
+        if (!(name = virSCSIHostGetNameByParentaddr(scsi_host)))
             goto cleanup;
         if (virSCSIHostGetNumber(name, &num) < 0)
             goto cleanup;
     } else {
-        if (virSCSIHostGetNumber(adapter.data.scsi_host.name, &num) < 0)
+        if (virSCSIHostGetNumber(scsi_host->name, &num) < 0)
             goto cleanup;
     }
 
@@ -2330,7 +2134,7 @@ virStorageIsSameHostnum(const char *name,
  * matchFCHostToSCSIHost:
  *
  * @conn: Connection pointer
- * @fc_adapter: fc_host adapter (either def or pool->def)
+ * @fchost: fc_host adapter ptr (either def or pool->def)
  * @scsi_hostnum: Already determined "scsi_pool" hostnum
  *
  * Returns true/false whether there is a match between the incoming
@@ -2338,7 +2142,7 @@ virStorageIsSameHostnum(const char *name,
  */
 static bool
 matchFCHostToSCSIHost(virConnectPtr conn,
-                      virStoragePoolSourceAdapter fc_adapter,
+                      virStorageAdapterFCHostPtr fchost,
                       unsigned int scsi_hostnum)
 {
     char *name = NULL;
@@ -2348,16 +2152,14 @@ matchFCHostToSCSIHost(virConnectPtr conn,
     /* If we have a parent defined, get its hostnum, and compare to the
      * scsi_hostnum. If they are the same, then we have a match
      */
-    if (fc_adapter.data.fchost.parent &&
-        virStorageIsSameHostnum(fc_adapter.data.fchost.parent, scsi_hostnum))
+    if (fchost->parent &&
+        virStorageIsSameHostnum(fchost->parent, scsi_hostnum))
         return true;
 
-    /* If we find an fc_adapter name, then either libvirt created a vHBA
+    /* If we find an fc adapter name, then either libvirt created a vHBA
      * for this fc_host or a 'virsh nodedev-create' generated a vHBA.
      */
-    if ((name = virVHBAGetHostByWWN(NULL, fc_adapter.data.fchost.wwnn,
-                                    fc_adapter.data.fchost.wwpn))) {
-
+    if ((name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) {
         /* Get the scsi_hostN for the vHBA in order to see if it
          * matches our scsi_hostnum
          */
@@ -2372,7 +2174,7 @@ matchFCHostToSCSIHost(virConnectPtr conn,
          * If the parent fc_hostnum is the same as the scsi_hostnum, we
          * have a match.
          */
-        if (conn && !fc_adapter.data.fchost.parent) {
+        if (conn && !fchost->parent) {
             if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0) {
                 VIR_FREE(name);
                 return false;
@@ -2404,25 +2206,21 @@ matchFCHostToSCSIHost(virConnectPtr conn,
     return false;
 }
 
+
 static bool
-matchSCSIAdapterParent(virStoragePoolObjPtr pool,
-                       virStoragePoolDefPtr def)
+matchSCSIAdapterParent(virStorageAdapterSCSIHostPtr pool_scsi_host,
+                       virStorageAdapterSCSIHostPtr def_scsi_host)
 {
-    virPCIDeviceAddressPtr pooladdr =
-        &pool->def->source.adapter.data.scsi_host.parentaddr;
-    virPCIDeviceAddressPtr defaddr =
-        &def->source.adapter.data.scsi_host.parentaddr;
-    int pool_unique_id =
-        pool->def->source.adapter.data.scsi_host.unique_id;
-    int def_unique_id =
-        def->source.adapter.data.scsi_host.unique_id;
+    virPCIDeviceAddressPtr pooladdr = &pool_scsi_host->parentaddr;
+    virPCIDeviceAddressPtr defaddr = &def_scsi_host->parentaddr;
+
     if (pooladdr->domain == defaddr->domain &&
         pooladdr->bus == defaddr->bus &&
         pooladdr->slot == defaddr->slot &&
         pooladdr->function == defaddr->function &&
-        pool_unique_id == def_unique_id) {
+        pool_scsi_host->unique_id == def_scsi_host->unique_id)
         return true;
-    }
+
     return false;
 }
 
@@ -2465,6 +2263,8 @@ virStoragePoolSourceFindDuplicate(virConnectPtr conn,
     int ret = 1;
     virStoragePoolObjPtr pool = NULL;
     virStoragePoolObjPtr matchpool = NULL;
+    virStorageAdapterPtr pool_adapter;
+    virStorageAdapterPtr def_adapter;
 
     /* Check the pool list for duplicate underlying storage */
     for (i = 0; i < pools->count; i++) {
@@ -2500,62 +2300,70 @@ virStoragePoolSourceFindDuplicate(virConnectPtr conn,
             break;
 
         case VIR_STORAGE_POOL_SCSI:
-            if (pool->def->source.adapter.type ==
-                VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST &&
-                def->source.adapter.type ==
-                VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
-                if (STREQ(pool->def->source.adapter.data.fchost.wwnn,
-                          def->source.adapter.data.fchost.wwnn) &&
-                    STREQ(pool->def->source.adapter.data.fchost.wwpn,
-                          def->source.adapter.data.fchost.wwpn))
+            pool_adapter = &pool->def->source.adapter;
+            def_adapter = &def->source.adapter;
+            if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST &&
+                def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST) {
+                virStorageAdapterFCHostPtr pool_fchost =
+                    &pool_adapter->data.fchost;
+                virStorageAdapterFCHostPtr def_fchost =
+                    &def_adapter->data.fchost;
+                if (STREQ(pool_fchost->wwnn, def_fchost->wwnn) &&
+                    STREQ(pool_fchost->wwpn, def_fchost->wwpn))
                     matchpool = pool;
-            } else if (pool->def->source.adapter.type ==
-                       VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST &&
-                       def->source.adapter.type ==
-                       VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
+            } else if (pool_adapter->type ==
+                       VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST &&
+                       def_adapter->type ==
+                       VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST) {
+                virStorageAdapterSCSIHostPtr pool_scsi_host =
+                    &pool_adapter->data.scsi_host;
+                virStorageAdapterSCSIHostPtr def_scsi_host =
+                    &def_adapter->data.scsi_host;
                 unsigned int pool_hostnum, def_hostnum;
 
-                if (pool->def->source.adapter.data.scsi_host.has_parent &&
-                    def->source.adapter.data.scsi_host.has_parent &&
-                    matchSCSIAdapterParent(pool, def)) {
+                if (pool_scsi_host->has_parent &&
+                    def_scsi_host->has_parent &&
+                    matchSCSIAdapterParent(pool_scsi_host, def_scsi_host)) {
                     matchpool = pool;
                     break;
                 }
 
-                if (getSCSIHostNumber(pool->def->source.adapter,
-                                      &pool_hostnum) < 0 ||
-                    getSCSIHostNumber(def->source.adapter, &def_hostnum) < 0)
+                if (getSCSIHostNumber(pool_scsi_host, &pool_hostnum) < 0 ||
+                    getSCSIHostNumber(def_scsi_host, &def_hostnum) < 0)
                     break;
                 if (pool_hostnum == def_hostnum)
                     matchpool = pool;
-            } else if (pool->def->source.adapter.type ==
-                       VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST &&
-                       def->source.adapter.type ==
-                       VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
+            } else if (pool_adapter->type ==
+                       VIR_STORAGE_ADAPTER_TYPE_FC_HOST &&
+                       def_adapter->type ==
+                       VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST) {
+                virStorageAdapterFCHostPtr pool_fchost =
+                    &pool_adapter->data.fchost;
+                virStorageAdapterSCSIHostPtr def_scsi_host =
+                    &def_adapter->data.scsi_host;
                 unsigned int scsi_hostnum;
 
                 /* Get the scsi_hostN for the scsi_host source adapter def */
-                if (getSCSIHostNumber(def->source.adapter,
-                                      &scsi_hostnum) < 0)
+                if (getSCSIHostNumber(def_scsi_host, &scsi_hostnum) < 0)
                     break;
 
-                if (matchFCHostToSCSIHost(conn, pool->def->source.adapter,
-                                          scsi_hostnum)) {
+                if (matchFCHostToSCSIHost(conn, pool_fchost, scsi_hostnum)) {
                     matchpool = pool;
                     break;
                 }
 
-            } else if (pool->def->source.adapter.type ==
-                       VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST &&
-                       def->source.adapter.type ==
-                       VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
+            } else if (pool_adapter->type ==
+                       VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST &&
+                       def_adapter->type ==
+                       VIR_STORAGE_ADAPTER_TYPE_FC_HOST) {
+                virStorageAdapterSCSIHostPtr pool_scsi_host =
+                    &pool_adapter->data.scsi_host;
                 unsigned int scsi_hostnum;
 
-                if (getSCSIHostNumber(pool->def->source.adapter,
-                                      &scsi_hostnum) < 0)
+                if (getSCSIHostNumber(pool_scsi_host, &scsi_hostnum) < 0)
                     break;
 
-                if (matchFCHostToSCSIHost(conn, def->source.adapter,
+                if (matchFCHostToSCSIHost(conn, &def_adapter->data.fchost,
                                           scsi_hostnum)) {
                     matchpool = pool;
                     break;
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h
index 1723afc..67813b0 100644
--- a/src/conf/storage_conf.h
+++ b/src/conf/storage_conf.h
@@ -26,6 +26,7 @@
 
 # include "internal.h"
 # include "virstorageencryption.h"
+# include "virstoragedevice.h"
 # include "virstoragefile.h"
 # include "virbitmap.h"
 # include "virthread.h"
@@ -170,38 +171,6 @@ struct _virStoragePoolSourceDevice {
     } geometry;
 };
 
-typedef enum {
-    VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_DEFAULT = 0,
-    VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST,
-    VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST,
-
-    VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST,
-} virStoragePoolSourceAdapterType;
-VIR_ENUM_DECL(virStoragePoolSourceAdapter)
-
-typedef struct _virStoragePoolSourceAdapter virStoragePoolSourceAdapter;
-typedef virStoragePoolSourceAdapter *virStoragePoolSourceAdapterPtr;
-struct _virStoragePoolSourceAdapter {
-    int type; /* virStoragePoolSourceAdapterType */
-
-    union {
-        struct {
-            char *name;
-            virPCIDeviceAddress parentaddr; /* host address */
-            int unique_id;
-            bool has_parent;
-        } scsi_host;
-        struct {
-            char *parent;
-            char *parent_wwnn;
-            char *parent_wwpn;
-            char *parent_fabric_wwn;
-            char *wwnn;
-            char *wwpn;
-            int managed;        /* enum virTristateSwitch */
-        } fchost;
-    } data;
-};
 
 typedef struct _virStoragePoolSource virStoragePoolSource;
 typedef virStoragePoolSource *virStoragePoolSourcePtr;
@@ -218,7 +187,7 @@ struct _virStoragePoolSource {
     char *dir;
 
     /* Or an adapter */
-    virStoragePoolSourceAdapter adapter;
+    virStorageAdapter adapter;
 
     /* Or a name */
     char *name;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index e6ccd69..b88e700 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -902,8 +902,6 @@ virStoragePoolObjSaveDef;
 virStoragePoolObjUnlock;
 virStoragePoolSaveConfig;
 virStoragePoolSaveState;
-virStoragePoolSourceAdapterTypeFromString;
-virStoragePoolSourceAdapterTypeToString;
 virStoragePoolSourceClear;
 virStoragePoolSourceDeviceClear;
 virStoragePoolSourceFindDuplicate;
@@ -2435,6 +2433,20 @@ virSocketAddrSetIPv6Addr;
 virSocketAddrSetIPv6AddrNetOrder;
 virSocketAddrSetPort;
 
+
+# util/virstoragedevice.h
+virStorageAdapterClear;
+virStorageAdapterFormat;
+virStorageAdapterParseValidate;
+virStorageAdapterParseXML;
+virStorageAdapterTypeFromString;
+virStorageAdapterTypeToString;
+virStorageAdapterVHBAClear;
+virStorageAdapterVHBAFormat;
+virStorageAdapterVHBAParseValidate;
+virStorageAdapterVHBAParseXML;
+
+
 # util/virstorageencryption.h
 virStorageEncryptionFormat;
 virStorageEncryptionFree;
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c
index 4bab651..d32456c 100644
--- a/src/libxl/libxl_conf.c
+++ b/src/libxl/libxl_conf.c
@@ -46,6 +46,7 @@
 #include "libxl_conf.h"
 #include "libxl_utils.h"
 #include "virstoragefile.h"
+#include "virstoragedevice.h"
 #include "secret_util.h"
 
 
diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c
index 7a5df3f..39fa026 100644
--- a/src/phyp/phyp_driver.c
+++ b/src/phyp/phyp_driver.c
@@ -2467,8 +2467,7 @@ phypBuildStoragePool(virConnectPtr conn, virStoragePoolDefPtr def)
     int exit_status = 0;
     virBuffer buf = VIR_BUFFER_INITIALIZER;
 
-    if (source.adapter.type !=
-        VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
+    if (source.adapter.type != VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST) {
         virReportError(VIR_ERR_XML_ERROR, "%s",
                        _("Only 'scsi_host' adapter is supported"));
         goto cleanup;
diff --git a/src/storage/storage_backend_scsi.c b/src/storage/storage_backend_scsi.c
index cd05741..afc3c89 100644
--- a/src/storage/storage_backend_scsi.c
+++ b/src/storage/storage_backend_scsi.c
@@ -176,33 +176,30 @@ virStoragePoolFCRefreshThread(void *opaque)
 }
 
 static char *
-getAdapterName(virStoragePoolSourceAdapter adapter)
+getAdapterName(virStorageAdapterPtr adapter)
 {
     char *name = NULL;
     char *parentaddr = NULL;
+    virStorageAdapterSCSIHostPtr scsi_host;
+    virStorageAdapterFCHostPtr fchost;
 
-    if (adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
-        if (adapter.data.scsi_host.has_parent) {
-            virPCIDeviceAddress addr = adapter.data.scsi_host.parentaddr;
-            unsigned int unique_id = adapter.data.scsi_host.unique_id;
+    if (adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST) {
+        scsi_host = &adapter->data.scsi_host;
 
-            if (!(name = virSCSIHostGetNameByParentaddr(addr.domain,
-                                                        addr.bus,
-                                                        addr.slot,
-                                                        addr.function,
-                                                        unique_id)))
+        if (scsi_host->has_parent) {
+            if (!(name = virSCSIHostGetNameByParentaddr(scsi_host)))
                 goto cleanup;
         } else {
-            ignore_value(VIR_STRDUP(name, adapter.data.scsi_host.name));
+            ignore_value(VIR_STRDUP(name, scsi_host->name));
         }
-    } else if (adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
-        if (!(name = virVHBAGetHostByWWN(NULL,
-                                         adapter.data.fchost.wwnn,
-                                         adapter.data.fchost.wwpn))) {
+    }
+
+    if (adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST) {
+        fchost = &adapter->data.fchost;
+        if (!(name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) {
             virReportError(VIR_ERR_XML_ERROR,
                            _("Failed to find SCSI host with wwnn='%s', "
-                             "wwpn='%s'"), adapter.data.fchost.wwnn,
-                           adapter.data.fchost.wwpn);
+                             "wwpn='%s'"), fchost->wwnn, fchost->wwpn);
         }
     }
 
@@ -254,10 +251,10 @@ checkParent(virConnectPtr conn,
 
 static int
 createVport(virConnectPtr conn,
-            virStoragePoolObjPtr pool)
+            virStoragePoolDefPtr def,
+            const char *configFile,
+            virStorageAdapterFCHostPtr fchost)
 {
-    const char *configFile = pool->configFile;
-    virStoragePoolSourceAdapterPtr adapter = &pool->def->source.adapter;
     unsigned int parent_host;
     char *name = NULL;
     char *parent_hoststr = NULL;
@@ -266,45 +263,37 @@ createVport(virConnectPtr conn,
     virThread thread;
     int ret = -1;
 
-    if (adapter->type != VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST)
-        return 0;
-
     VIR_DEBUG("conn=%p, configFile='%s' parent='%s', wwnn='%s' wwpn='%s'",
-              conn, NULLSTR(configFile), NULLSTR(adapter->data.fchost.parent),
-              adapter->data.fchost.wwnn, adapter->data.fchost.wwpn);
+              conn, NULLSTR(configFile), NULLSTR(fchost->parent),
+              fchost->wwnn, fchost->wwpn);
 
     /* If we find an existing HBA/vHBA within the fc_host sysfs
      * using the wwnn/wwpn, then a nodedev is already created for
      * this pool and we don't have to create the vHBA
      */
-    if ((name = virVHBAGetHostByWWN(NULL, adapter->data.fchost.wwnn,
-                                    adapter->data.fchost.wwpn))) {
+    if ((name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) {
         /* If a parent was provided, let's make sure the 'name' we've
          * retrieved has the same parent
          */
-        if (adapter->data.fchost.parent &&
-            checkParent(conn, name, adapter->data.fchost.parent))
+        if (fchost->parent && checkParent(conn, name, fchost->parent))
             ret = 0;
 
         goto cleanup;
     }
 
-    if (adapter->data.fchost.parent) {
-        if (VIR_STRDUP(parent_hoststr, adapter->data.fchost.parent) < 0)
+    if (fchost->parent) {
+        if (VIR_STRDUP(parent_hoststr, fchost->parent) < 0)
             goto cleanup;
-    } else if (adapter->data.fchost.parent_wwnn &&
-               adapter->data.fchost.parent_wwpn) {
-        if (!(parent_hoststr =
-              virVHBAGetHostByWWN(NULL, adapter->data.fchost.parent_wwnn,
-                                  adapter->data.fchost.parent_wwpn))) {
+    } else if (fchost->parent_wwnn && fchost->parent_wwpn) {
+        if (!(parent_hoststr = virVHBAGetHostByWWN(NULL, fchost->parent_wwnn,
+                                                   fchost->parent_wwpn))) {
             virReportError(VIR_ERR_XML_ERROR, "%s",
                            _("cannot find parent using provided wwnn/wwpn"));
             goto cleanup;
         }
-    } else if (adapter->data.fchost.parent_fabric_wwn) {
+    } else if (fchost->parent_fabric_wwn) {
         if (!(parent_hoststr =
-              virVHBAGetHostByFabricWWN(NULL,
-                                        adapter->data.fchost.parent_fabric_wwn))) {
+              virVHBAGetHostByFabricWWN(NULL, fchost->parent_fabric_wwn))) {
             virReportError(VIR_ERR_XML_ERROR, "%s",
                            _("cannot find parent using provided fabric_wwn"));
             goto cleanup;
@@ -323,8 +312,8 @@ createVport(virConnectPtr conn,
         goto cleanup;
 
     /* NOTE:
-     * We do not save the parent_hoststr in adapter->data.fchost.parent
-     * since we could be writing out the 'def' to the saved XML config.
+     * We do not save the parent_hoststr in fchost->parent since
+     * we could be writing out the 'def' to the saved XML config.
      * If we wrote out the name in the XML, then future starts would
      * always use the same parent rather than finding the "best available"
      * parent. Besides we have a way to determine the parent based on
@@ -342,16 +331,16 @@ createVport(virConnectPtr conn,
      * restart, we need to save the persistent configuration. So if not
      * already defined as YES, then force the issue.
      */
-    if (adapter->data.fchost.managed != VIR_TRISTATE_BOOL_YES) {
-        adapter->data.fchost.managed = VIR_TRISTATE_BOOL_YES;
+    if (fchost->managed != VIR_TRISTATE_BOOL_YES) {
+        fchost->managed = VIR_TRISTATE_BOOL_YES;
         if (configFile) {
-            if (virStoragePoolSaveConfig(configFile, pool->def) < 0)
+            if (virStoragePoolSaveConfig(configFile, def) < 0)
                 goto cleanup;
         }
     }
 
-    if (virVHBAManageVport(parent_host, adapter->data.fchost.wwpn,
-                           adapter->data.fchost.wwnn, VPORT_CREATE) < 0)
+    if (virVHBAManageVport(parent_host, fchost->wwpn, fchost->wwnn,
+                           VPORT_CREATE) < 0)
         goto cleanup;
 
     virFileWaitForDevices();
@@ -361,10 +350,9 @@ createVport(virConnectPtr conn,
      * retry logic set to true. If the thread isn't created, then no big
      * deal since it's still possible to refresh the pool later.
      */
-    if ((name = virVHBAGetHostByWWN(NULL, adapter->data.fchost.wwnn,
-                                    adapter->data.fchost.wwpn))) {
+    if ((name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) {
         if (VIR_ALLOC(cbdata) == 0) {
-            memcpy(cbdata->pool_uuid, pool->def->uuid, VIR_UUID_BUFLEN);
+            memcpy(cbdata->pool_uuid, def->uuid, VIR_UUID_BUFLEN);
             VIR_STEAL_PTR(cbdata->fchost_name, name);
 
             if (virThreadCreate(&thread, false, virStoragePoolFCRefreshThread,
@@ -384,9 +372,10 @@ createVport(virConnectPtr conn,
     return ret;
 }
 
+
 static int
 deleteVport(virConnectPtr conn,
-            virStoragePoolSourceAdapter adapter)
+            virStorageAdapterFCHostPtr fchost)
 {
     unsigned int parent_host;
     char *name = NULL;
@@ -394,25 +383,19 @@ deleteVport(virConnectPtr conn,
     char *vhba_parent = NULL;
     int ret = -1;
 
-    if (adapter.type != VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST)
-        return 0;
-
     VIR_DEBUG("conn=%p parent='%s', managed='%d' wwnn='%s' wwpn='%s'",
-              conn, NULLSTR(adapter.data.fchost.parent),
-              adapter.data.fchost.managed,
-              adapter.data.fchost.wwnn,
-              adapter.data.fchost.wwpn);
+              conn, NULLSTR(fchost->parent), fchost->managed,
+              fchost->wwnn, fchost->wwpn);
 
     /* If we're not managing the deletion of the vHBA, then just return */
-    if (adapter.data.fchost.managed != VIR_TRISTATE_BOOL_YES)
+    if (fchost->managed != VIR_TRISTATE_BOOL_YES)
         return 0;
 
     /* Find our vHBA by searching the fc_host sysfs tree for our wwnn/wwpn */
-    if (!(name = virVHBAGetHostByWWN(NULL, adapter.data.fchost.wwnn,
-                                     adapter.data.fchost.wwpn))) {
+    if (!(name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Failed to find fc_host for wwnn='%s' and wwpn='%s'"),
-                       adapter.data.fchost.wwnn, adapter.data.fchost.wwpn);
+                       fchost->wwnn, fchost->wwpn);
         goto cleanup;
     }
 
@@ -420,8 +403,8 @@ deleteVport(virConnectPtr conn,
      * get the parent_host value; otherwise, we have to determine
      * the parent scsi_host which we did not save at startup time
      */
-    if (adapter.data.fchost.parent) {
-        if (virSCSIHostGetNumber(adapter.data.fchost.parent, &parent_host) < 0)
+    if (fchost->parent) {
+        if (virSCSIHostGetNumber(fchost->parent, &parent_host) < 0)
             goto cleanup;
     } else {
         if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0)
@@ -434,8 +417,8 @@ deleteVport(virConnectPtr conn,
             goto cleanup;
     }
 
-    if (virVHBAManageVport(parent_host, adapter.data.fchost.wwpn,
-                           adapter.data.fchost.wwnn, VPORT_DELETE) < 0)
+    if (virVHBAManageVport(parent_host, fchost->wwpn, fchost->wwnn,
+                           VPORT_DELETE) < 0)
         goto cleanup;
 
     ret = 0;
@@ -458,13 +441,13 @@ virStorageBackendSCSICheckPool(virStoragePoolObjPtr pool,
 
     *isActive = false;
 
-    if (!(name = getAdapterName(pool->def->source.adapter))) {
+    if (!(name = getAdapterName(&pool->def->source.adapter))) {
         /* It's normal for the pool with "fc_host" type source
          * adapter fails to get the adapter name, since the vHBA
          * the adapter based on might be not created yet.
          */
         if (pool->def->source.adapter.type ==
-            VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
+            VIR_STORAGE_ADAPTER_TYPE_FC_HOST) {
             virResetLastError();
             return 0;
         } else {
@@ -498,7 +481,7 @@ virStorageBackendSCSIRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
 
     pool->def->allocation = pool->def->capacity = pool->def->available = 0;
 
-    if (!(name = getAdapterName(pool->def->source.adapter)))
+    if (!(name = getAdapterName(&pool->def->source.adapter)))
         return -1;
 
     if (virSCSIHostGetNumber(name, &host) < 0)
@@ -522,15 +505,21 @@ static int
 virStorageBackendSCSIStartPool(virConnectPtr conn,
                                virStoragePoolObjPtr pool)
 {
-    return createVport(conn, pool);
+    if (pool->def->source.adapter.type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST)
+        return createVport(conn, pool->def, pool->configFile,
+                           &pool->def->source.adapter.data.fchost);
+
+    return 0;
 }
 
 static int
 virStorageBackendSCSIStopPool(virConnectPtr conn,
                               virStoragePoolObjPtr pool)
 {
-    virStoragePoolSourceAdapter adapter = pool->def->source.adapter;
-    return deleteVport(conn, adapter);
+    if (pool->def->source.adapter.type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST)
+        return deleteVport(conn, &pool->def->source.adapter.data.fchost);
+
+    return 0;
 }
 
 virStorageBackend virStorageBackendSCSI = {
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index 4dff0f1..5733a20 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -4422,7 +4422,7 @@ testStoragePoolCreateXML(virConnectPtr conn,
     def = NULL;
 
     if (pool->def->source.adapter.type ==
-        VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
+        VIR_STORAGE_ADAPTER_TYPE_FC_HOST) {
         /* In the real code, we'd call virVHBAManageVport followed by
          * find_new_device, but we cannot do that here since we're not
          * mocking udev. The mock routine will copy an existing vHBA and
@@ -4645,7 +4645,7 @@ testStoragePoolDestroy(virStoragePoolPtr pool)
     privpool->active = 0;
 
     if (privpool->def->source.adapter.type ==
-        VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
+        VIR_STORAGE_ADAPTER_TYPE_FC_HOST) {
         if (testDestroyVport(privconn,
                              privpool->def->source.adapter.data.fchost.wwnn,
                              privpool->def->source.adapter.data.fchost.wwpn) < 0)
diff --git a/src/util/virscsihost.c b/src/util/virscsihost.c
index eea0474..dffc958 100644
--- a/src/util/virscsihost.c
+++ b/src/util/virscsihost.c
@@ -218,36 +218,30 @@ virSCSIHostGetNumber(const char *adapter_name,
 }
 
 /* virSCSIHostGetNameByParentaddr:
- * @domain: The domain from the scsi_host parentaddr
- * @bus: The bus from the scsi_host parentaddr
- * @slot: The slot from the scsi_host parentaddr
- * @function: The function from the scsi_host parentaddr
- * @unique_id: The unique id value for parentaddr
+ * @scsi_host: The scsi_host adapter pointer.
  *
  * Generate a parentaddr and find the scsi_host host# for
- * the provided parentaddr PCI address fields.
+ * the provided scsi_host.
  *
  * Returns the "host#" string which must be free'd by
  * the caller or NULL on error
  */
 char *
-virSCSIHostGetNameByParentaddr(unsigned int domain,
-                               unsigned int bus,
-                               unsigned int slot,
-                               unsigned int function,
-                               unsigned int unique_id)
+virSCSIHostGetNameByParentaddr(virStorageAdapterSCSIHostPtr scsi_host)
 {
+    virPCIDeviceAddressPtr addr = &scsi_host->parentaddr;
     char *name = NULL;
     char *parentaddr = NULL;
 
     if (virAsprintf(&parentaddr, "%04x:%02x:%02x.%01x",
-                    domain, bus, slot, function) < 0)
+                    addr->domain, addr->bus, addr->slot, addr->function) < 0)
         goto cleanup;
-    if (!(name = virSCSIHostFindByPCI(NULL, parentaddr, unique_id))) {
+    if (!(name = virSCSIHostFindByPCI(NULL, parentaddr,
+                                      scsi_host->unique_id))) {
         virReportError(VIR_ERR_XML_ERROR,
                        _("Failed to find scsi_host using PCI '%s' "
                          "and unique_id='%u'"),
-                       parentaddr, unique_id);
+                       parentaddr, scsi_host->unique_id);
         goto cleanup;
     }
 
@@ -284,11 +278,7 @@ virSCSIHostGetNumber(const char *adapter_name ATTRIBUTE_UNUSED,
 }
 
 char *
-virSCSIHostGetNameByParentaddr(unsigned int domain ATTRIBUTE_UNUSED,
-                               unsigned int bus ATTRIBUTE_UNUSED,
-                               unsigned int slot ATTRIBUTE_UNUSED,
-                               unsigned int function ATTRIBUTE_UNUSED,
-                               unsigned int unique_id ATTRIBUTE_UNUSED)
+virSCSIHostGetNameByParentaddr(virStorageAdapterSCSIHostPtr scsi_host)
 {
     virReportSystemError(ENOSYS, "%s", _("Not supported on this platform"));
     return NULL;
diff --git a/src/util/virscsihost.h b/src/util/virscsihost.h
index c35ccb9..e0eddaf 100644
--- a/src/util/virscsihost.h
+++ b/src/util/virscsihost.h
@@ -21,6 +21,8 @@
 
 # include "internal.h"
 
+# include "virstoragedevice.h"
+
 int virSCSIHostGetUniqueId(const char *sysfs_prefix, int host);
 
 char *virSCSIHostFindByPCI(const char *sysfs_prefix,
@@ -31,10 +33,6 @@ int virSCSIHostGetNumber(const char *adapter_name,
                          unsigned int *result)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 
-char *virSCSIHostGetNameByParentaddr(unsigned int domain,
-                                     unsigned int bus,
-                                     unsigned int slot,
-                                     unsigned int function,
-                                     unsigned int unique_id);
+char *virSCSIHostGetNameByParentaddr(virStorageAdapterSCSIHostPtr scsi_host);
 
 #endif /* __VIR_SCSI_HOST_H__ */
diff --git a/src/util/virstoragedevice.c b/src/util/virstoragedevice.c
new file mode 100644
index 0000000..0d9db34
--- /dev/null
+++ b/src/util/virstoragedevice.c
@@ -0,0 +1,292 @@
+/*
+ * virstoragedevice.c: utility functions to share storage device mgmt
+ *                     between storage pools and domains
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "device_conf.h"
+
+#include "viralloc.h"
+#include "virerror.h"
+#include "virlog.h"
+#include "virstoragedevice.h"
+#include "virstring.h"
+#include "virutil.h"
+#include "virxml.h"
+
+#define VIR_FROM_THIS VIR_FROM_STORAGE
+
+VIR_LOG_INIT("util.virstoragedevice");
+
+VIR_ENUM_IMPL(virStorageAdapter,
+              VIR_STORAGE_ADAPTER_TYPE_LAST,
+              "default", "scsi_host", "fc_host")
+
+
+int
+virStorageAdapterVHBAParseXML(xmlNodePtr node,
+                              virStorageAdapterFCHostPtr fchost)
+{
+    char *managed = NULL;
+
+    fchost->parent = virXMLPropString(node, "parent");
+
+    if ((managed = virXMLPropString(node, "managed"))) {
+        if ((fchost->managed =
+             virTristateBoolTypeFromString(managed)) < 0) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("unknown fc_host managed setting '%s'"),
+                           managed);
+            VIR_FREE(managed);
+            return -1;
+        }
+    }
+
+    fchost->parent_wwnn = virXMLPropString(node, "parent_wwnn");
+    fchost->parent_wwpn = virXMLPropString(node, "parent_wwpn");
+    fchost->parent_fabric_wwn = virXMLPropString(node, "parent_fabric_wwn");
+    fchost->wwpn = virXMLPropString(node, "wwpn");
+    fchost->wwnn = virXMLPropString(node, "wwnn");
+
+    VIR_FREE(managed);
+    return 0;
+}
+
+
+int
+virStorageAdapterParseXML(virStorageAdapterPtr adapter,
+                          xmlNodePtr node,
+                          xmlXPathContextPtr ctxt)
+{
+    int ret = -1;
+    xmlNodePtr relnode = ctxt->node;
+    char *adapter_type = NULL;
+    virStorageAdapterSCSIHostPtr scsi_host;
+
+    ctxt->node = node;
+
+    if ((adapter_type = virXMLPropString(node, "type"))) {
+        if ((adapter->type =
+             virStorageAdapterTypeFromString(adapter_type)) <= 0) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("Unknown pool adapter type '%s'"),
+                           adapter_type);
+            goto cleanup;
+        }
+
+        if (adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST) {
+            if (virStorageAdapterVHBAParseXML(node, &adapter->data.fchost) < 0)
+                goto cleanup;
+        }
+
+        if (adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST) {
+            scsi_host = &adapter->data.scsi_host;
+
+            scsi_host->name = virXMLPropString(node, "name");
+            if (virXPathNode("./parentaddr", ctxt)) {
+                xmlNodePtr addrnode = virXPathNode("./parentaddr/address",
+                                                   ctxt);
+                virPCIDeviceAddressPtr addr = &scsi_host->parentaddr;
+                if (!addrnode) {
+                    virReportError(VIR_ERR_XML_ERROR, "%s",
+                                   _("Missing scsi_host PCI address element"));
+                    goto cleanup;
+                }
+                scsi_host->has_parent = true;
+                if (virPCIDeviceAddressParseXML(addrnode, addr) < 0)
+                    goto cleanup;
+                if ((virXPathInt("string(./parentaddr/@unique_id)",
+                                 ctxt,
+                                 &scsi_host->unique_id) < 0) ||
+                    (scsi_host->unique_id < 0)) {
+                    virReportError(VIR_ERR_XML_ERROR, "%s",
+                                   _("Missing or invalid scsi adapter "
+                                     "'unique_id' value"));
+                    goto cleanup;
+                }
+            }
+        }
+    } else {
+        char *wwnn = virXMLPropString(node, "wwnn");
+        char *wwpn = virXMLPropString(node, "wwpn");
+        char *parent = virXMLPropString(node, "parent");
+
+        /* "type" was not specified in the XML, so we must verify that
+         * "wwnn", "wwpn", "parent", or "parentaddr" are also not in the
+         * XML. If any are found, then we cannot just use "name" alone".
+         */
+        if (wwnn || wwpn || parent) {
+            VIR_FREE(wwnn);
+            VIR_FREE(wwpn);
+            VIR_FREE(parent);
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("Use of 'wwnn', 'wwpn', and 'parent' attributes "
+                             "requires use of the adapter 'type'"));
+            goto cleanup;
+        }
+
+        if (virXPathNode("./parentaddr", ctxt)) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("Use of 'parent' element requires use "
+                             "of the adapter 'type'"));
+            goto cleanup;
+        }
+
+        /* To keep back-compat, 'type' is not required to specify
+         * for scsi_host adapter.
+         */
+        if ((adapter->data.scsi_host.name = virXMLPropString(node, "name")))
+            adapter->type = VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST;
+    }
+
+    ret = 0;
+
+ cleanup:
+    ctxt->node = relnode;
+    VIR_FREE(adapter_type);
+    return ret;
+}
+
+
+void
+virStorageAdapterVHBAFormat(virBufferPtr buf,
+                            virStorageAdapterFCHostPtr fchost)
+{
+    virBufferEscapeString(buf, " parent='%s'", fchost->parent);
+    virBufferEscapeString(buf, " parent_wwnn='%s'", fchost->parent_wwnn);
+    virBufferEscapeString(buf, " parent_wwpn='%s'", fchost->parent_wwpn);
+    virBufferEscapeString(buf, " parent_fabric_wwn='%s'",
+                          fchost->parent_fabric_wwn);
+    if (fchost->managed != VIR_TRISTATE_BOOL_ABSENT)
+        virBufferAsprintf(buf, " managed='%s'",
+                          virTristateBoolTypeToString(fchost->managed));
+
+    virBufferAsprintf(buf, " wwnn='%s' wwpn='%s'/>\n",
+                      fchost->wwnn, fchost->wwpn);
+}
+
+
+void
+virStorageAdapterFormat(virBufferPtr buf,
+                        virStorageAdapterPtr adapter)
+{
+    virBufferAsprintf(buf, "<adapter type='%s'",
+                          virStorageAdapterTypeToString(adapter->type));
+
+    if (adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST)
+        virStorageAdapterVHBAFormat(buf, &adapter->data.fchost);
+
+    if (adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST) {
+        virStorageAdapterSCSIHostPtr scsi_host = &adapter->data.scsi_host;
+
+        if (scsi_host->name) {
+            virBufferAsprintf(buf, " name='%s'/>\n", scsi_host->name);
+        } else {
+            virPCIDeviceAddress addr;
+            virBufferAddLit(buf, ">\n");
+            virBufferAdjustIndent(buf, 2);
+            virBufferAsprintf(buf, "<parentaddr unique_id='%d'>\n",
+                              scsi_host->unique_id);
+            virBufferAdjustIndent(buf, 2);
+            addr = scsi_host->parentaddr;
+            ignore_value(virPCIDeviceAddressFormat(buf, addr, false));
+            virBufferAdjustIndent(buf, -2);
+            virBufferAddLit(buf, "</parentaddr>\n");
+            virBufferAdjustIndent(buf, -2);
+            virBufferAddLit(buf, "</adapter>\n");
+        }
+    }
+}
+
+
+void
+virStorageAdapterVHBAClear(virStorageAdapterFCHostPtr fchost)
+{
+    VIR_FREE(fchost->parent);
+    VIR_FREE(fchost->parent_wwnn);
+    VIR_FREE(fchost->parent_wwpn);
+    VIR_FREE(fchost->parent_fabric_wwn);
+    VIR_FREE(fchost->wwnn);
+    VIR_FREE(fchost->wwpn);
+}
+
+
+void
+virStorageAdapterClear(virStorageAdapterPtr adapter)
+{
+    if (adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST)
+        virStorageAdapterVHBAClear(&adapter->data.fchost);
+
+    if (adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST)
+        VIR_FREE(adapter->data.scsi_host.name);
+}
+
+
+int
+virStorageAdapterVHBAParseValidate(virStorageAdapterFCHostPtr fchost)
+{
+    if (!fchost->wwnn || !fchost->wwpn) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("'wwnn' and 'wwpn' must be specified for "
+                         "a VHBA adapter"));
+        return -1;
+    }
+
+    if (!virValidateWWN(fchost->wwnn) || !virValidateWWN(fchost->wwpn))
+        return -1;
+
+    if (fchost->parent_wwnn && !virValidateWWN(fchost->parent_wwnn))
+        return -1;
+
+    if (fchost->parent_wwpn && !virValidateWWN(fchost->parent_wwpn))
+        return -1;
+
+    if (fchost->parent_fabric_wwn &&
+        !virValidateWWN(fchost->parent_fabric_wwn))
+        return -1;
+
+    return 0;
+}
+
+
+int
+virStorageAdapterParseValidate(virStorageAdapterPtr adapter)
+{
+    if (adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST)
+        return virStorageAdapterVHBAParseValidate(&adapter->data.fchost);
+
+    if (adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST) {
+        virStorageAdapterSCSIHostPtr scsi_host = &adapter->data.scsi_host;
+
+        if (!scsi_host->name && !scsi_host->has_parent) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("Either 'name' or 'parent' must be specified "
+                             "for the 'scsi_host' adapter"));
+            return -1;
+        }
+
+        if (scsi_host->name && scsi_host->has_parent) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("Both 'name' and 'parent' cannot be specified "
+                             "for the 'scsi_host' adapter"));
+            return -1;
+        }
+    }
+
+    return 0;
+}
diff --git a/src/util/virstoragedevice.h b/src/util/virstoragedevice.h
new file mode 100644
index 0000000..c8459c7
--- /dev/null
+++ b/src/util/virstoragedevice.h
@@ -0,0 +1,89 @@
+/*
+ * virstoragedevice.h: utility functions to share storage device mgmt
+ *                     between storage pools and domains
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __VIR_STORAGE_DEVICE_H__
+# define __VIR_STORAGE_DEVICE_H__
+
+# include "virpci.h"
+# include "virxml.h"
+
+
+typedef enum {
+    VIR_STORAGE_ADAPTER_TYPE_DEFAULT = 0,
+    VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST,
+    VIR_STORAGE_ADAPTER_TYPE_FC_HOST,
+
+    VIR_STORAGE_ADAPTER_TYPE_LAST,
+} virStorageAdapterType;
+VIR_ENUM_DECL(virStorageAdapter)
+
+typedef struct _virStorageAdapterSCSIHost virStorageAdapterSCSIHost;
+typedef virStorageAdapterSCSIHost *virStorageAdapterSCSIHostPtr;
+struct _virStorageAdapterSCSIHost {
+    char *name;
+    virPCIDeviceAddress parentaddr; /* host address */
+    int unique_id;
+    bool has_parent;
+};
+
+typedef struct _virStorageAdapterFCHost virStorageAdapterFCHost;
+typedef virStorageAdapterFCHost *virStorageAdapterFCHostPtr;
+struct _virStorageAdapterFCHost {
+    char *parent;
+    char *parent_wwnn;
+    char *parent_wwpn;
+    char *parent_fabric_wwn;
+    char *wwnn;
+    char *wwpn;
+    int managed;        /* enum virTristateSwitch */
+};
+
+typedef struct _virStorageAdapter virStorageAdapter;
+typedef virStorageAdapter *virStorageAdapterPtr;
+struct _virStorageAdapter {
+    int type; /* virStorageAdapterType */
+
+    union {
+        virStorageAdapterSCSIHost scsi_host;
+        virStorageAdapterFCHost fchost;
+    } data;
+};
+
+
+int virStorageAdapterVHBAParseXML(xmlNodePtr node,
+                                  virStorageAdapterFCHostPtr fchost);
+
+int virStorageAdapterParseXML(virStorageAdapterPtr adapter,
+                              xmlNodePtr node,
+                              xmlXPathContextPtr ctxt);
+
+void virStorageAdapterVHBAFormat(virBufferPtr buf,
+                                 virStorageAdapterFCHostPtr fchost);
+
+void virStorageAdapterFormat(virBufferPtr buf, virStorageAdapterPtr adapter);
+
+void virStorageAdapterVHBAClear(virStorageAdapterFCHostPtr fchost);
+
+void virStorageAdapterClear(virStorageAdapterPtr adapter);
+
+int virStorageAdapterVHBAParseValidate(virStorageAdapterFCHostPtr fchost);
+
+int virStorageAdapterParseValidate(virStorageAdapterPtr adapter);
+
+#endif /* __VIR_STORAGE_DEVICE_H__ */
-- 
2.9.3




More information about the libvir-list mailing list