]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
node_device: introduce new capability FC_RPORT
authorBjoern Walk <bwalk@linux.vnet.ibm.com>
Mon, 22 May 2017 06:38:25 +0000 (08:38 +0200)
committerJohn Ferlan <jferlan@redhat.com>
Fri, 26 May 2017 14:44:05 +0000 (10:44 -0400)
Similar to scsi_host and fc_host, there is a relation between a
scsi_target and its transport specific fc_remote_port. Let's expose this
relation and relevant information behind it.

An example for a virsh nodedev-dumpxml:

    virsh # nodedev-dumpxml scsi_target0_0_0
    <device>
      <name>scsi_target0_0_0</name>
      <path>/sys/devices/[...]/host0/rport-0:0-0/target0:0:0</path>
      <parent>scsi_host0</parent>
      <capability type='scsi_target'>
        <target>target0:0:0</target>
        <capability type='fc_remote_port'>
          <rport>rport-0:0-0</rport>
          <wwpn>0x9d73bc45f0e21a86</wwpn>
        </capability>
      </capability>
    </device>

Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com>
Signed-off-by: Bjoern Walk <bwalk@linux.vnet.ibm.com>
docs/schemas/nodedev.rng
src/conf/node_device_conf.c
src/conf/node_device_conf.h
src/node_device/node_device_driver.c
src/node_device/node_device_linux_sysfs.c
src/node_device/node_device_linux_sysfs.h
src/node_device/node_device_udev.c
tests/nodedevschemadata/scsi_target1_0_0.xml [new file with mode: 0644]
tests/nodedevxml2xmltest.c

index 87bfb0c2865c738ac7b72ca09d38b0d31c5eb8c3..5bcf3178778144a7de410dd82995cd40684ab32b 100644 (file)
     </optional>
   </define>
 
+  <define name='capsfcrport'>
+    <attribute name='type'>
+      <value>fc_remote_port</value>
+    </attribute>
+
+    <element name='rport'>
+      <text/>
+    </element>
+
+    <element name='wwpn'>
+      <ref name='wwn'/>
+    </element>
+  </define>
+
   <define name='capscsitarget'>
     <attribute name='type'>
       <value>scsi_target</value>
     <element name='target'>
       <text/>
     </element>
+
+    <optional>
+      <element name='capability'>
+        <ref name='capsfcrport'/>
+      </element>
+    </optional>
   </define>
 
   <define name='capscsi'>
index 22c06f86979b2624ef5d4758c1435f6f322aae5b..e5947e67b6d5be96c543735d88d437ba571fcf58 100644 (file)
@@ -563,6 +563,16 @@ virNodeDeviceDefFormat(const virNodeDeviceDef *def)
         case VIR_NODE_DEV_CAP_SCSI_TARGET:
             virBufferEscapeString(&buf, "<target>%s</target>\n",
                                   data->scsi_target.name);
+            if (data->scsi_target.flags & VIR_NODE_DEV_CAP_FLAG_FC_RPORT) {
+                virBufferAddLit(&buf, "<capability type='fc_remote_port'>\n");
+                virBufferAdjustIndent(&buf, 2);
+                virBufferAsprintf(&buf, "<rport>%s</rport>\n",
+                                  data->scsi_target.rport);
+                virBufferAsprintf(&buf, "<wwpn>%s</wwpn>\n",
+                                  data->scsi_target.wwpn);
+                virBufferAdjustIndent(&buf, -2);
+                virBufferAddLit(&buf, "</capability>\n");
+            }
             break;
         case VIR_NODE_DEV_CAP_SCSI:
             virNodeDeviceCapSCSIDefFormat(&buf, data);
@@ -932,8 +942,10 @@ virNodeDevCapSCSITargetParseXML(xmlXPathContextPtr ctxt,
                                 xmlNodePtr node,
                                 virNodeDevCapSCSITargetPtr scsi_target)
 {
-    xmlNodePtr orignode;
-    int ret = -1;
+    xmlNodePtr orignode, *nodes = NULL;
+    int ret = -1, n = 0;
+    size_t i;
+    char *type = NULL;
 
     orignode = ctxt->node;
     ctxt->node = node;
@@ -946,10 +958,60 @@ virNodeDevCapSCSITargetParseXML(xmlXPathContextPtr ctxt,
         goto out;
     }
 
+    if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
+        goto out;
+
+    for (i = 0; i < n; ++i) {
+        type = virXMLPropString(nodes[i], "type");
+
+        if (!type) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("missing type for SCSI target capability for '%s'"),
+                           def->name);
+            goto out;
+        }
+
+        if (STREQ(type, "fc_remote_port")) {
+            xmlNodePtr orignode2;
+
+            scsi_target->flags |= VIR_NODE_DEV_CAP_FLAG_FC_RPORT;
+
+            orignode2 = ctxt->node;
+            ctxt->node = nodes[i];
+
+            if (virNodeDevCapsDefParseString("string(./rport[1])",
+                                             ctxt,
+                                             &scsi_target->rport) < 0) {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("missing rport name for '%s'"), def->name);
+                goto out;
+            }
+
+            if (virNodeDevCapsDefParseString("string(./wwpn[1])",
+                                             ctxt, &scsi_target->wwpn) < 0) {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("missing wwpn identifier for '%s'"),
+                               def->name);
+                goto out;
+            }
+
+            ctxt->node = orignode2;
+        } else {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("unknown SCSI target capability type '%s' for '%s'"),
+                           type, def->name);
+            goto out;
+        }
+
+        VIR_FREE(type);
+    }
+
     ret = 0;
 
  out:
     ctxt->node = orignode;
+    VIR_FREE(type);
+    VIR_FREE(nodes);
     return ret;
 }
 
@@ -2132,6 +2194,8 @@ virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
         break;
     case VIR_NODE_DEV_CAP_SCSI_TARGET:
         VIR_FREE(data->scsi_target.name);
+        VIR_FREE(data->scsi_target.rport);
+        VIR_FREE(data->scsi_target.wwpn);
         break;
     case VIR_NODE_DEV_CAP_SCSI:
         VIR_FREE(data->scsi.type);
index 285841edc0c3b16d7fd222278c114363e7e2dc65..ca105a3d605144543630b22694f9f832bdc77436 100644 (file)
@@ -92,6 +92,10 @@ typedef enum {
     VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS                        = (1 << 1),
 } virNodeDevSCSIHostCapFlags;
 
+typedef enum {
+    VIR_NODE_DEV_CAP_FLAG_FC_RPORT                     = (1 << 0),
+} virNodeDevSCSITargetCapsFlags;
+
 typedef enum {
     VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION     = (1 << 0),
     VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION      = (1 << 1),
@@ -227,6 +231,9 @@ typedef struct _virNodeDevCapSCSITarget virNodeDevCapSCSITarget;
 typedef virNodeDevCapSCSITarget *virNodeDevCapSCSITargetPtr;
 struct _virNodeDevCapSCSITarget {
     char *name;
+    unsigned int flags; /* enum virNodeDevSCSITargetCapsFlags */
+    char *rport;
+    char *wwpn;
 };
 
 typedef struct _virNodeDevCapSCSI virNodeDevCapSCSI;
index 66faf2b4fcf96798b98794032fdb262ec9c0a425..10f8777b5158190dd630c69cc29e1a6b13e58ff5 100644 (file)
@@ -56,6 +56,10 @@ static int update_caps(virNodeDeviceObjPtr dev)
         case VIR_NODE_DEV_CAP_SCSI_HOST:
             nodeDeviceSysfsGetSCSIHostCaps(&cap->data.scsi_host);
             break;
+        case VIR_NODE_DEV_CAP_SCSI_TARGET:
+            nodeDeviceSysfsGetSCSITargetCaps(dev->def->sysfs_path,
+                                             &cap->data.scsi_target);
+            break;
         case VIR_NODE_DEV_CAP_NET:
             if (virNetDevGetLinkInfo(cap->data.net.ifname, &cap->data.net.lnk) < 0)
                 return -1;
@@ -76,7 +80,6 @@ static int update_caps(virNodeDeviceObjPtr dev)
         case VIR_NODE_DEV_CAP_SYSTEM:
         case VIR_NODE_DEV_CAP_USB_DEV:
         case VIR_NODE_DEV_CAP_USB_INTERFACE:
-        case VIR_NODE_DEV_CAP_SCSI_TARGET:
         case VIR_NODE_DEV_CAP_SCSI:
         case VIR_NODE_DEV_CAP_STORAGE:
         case VIR_NODE_DEV_CAP_FC_HOST:
index ecfe34d4197786b769f24051b8f4109796dab0ef..e02c384035c6964d52c8b64ff0faf3fc853555bb 100644 (file)
 #include <sys/stat.h>
 #include <stdlib.h>
 
+#include "dirname.h"
 #include "node_device_driver.h"
 #include "node_device_hal.h"
 #include "node_device_linux_sysfs.h"
 #include "virerror.h"
 #include "viralloc.h"
+#include "virfcp.h"
 #include "virlog.h"
 #include "virfile.h"
 #include "virscsihost.h"
@@ -125,6 +127,50 @@ nodeDeviceSysfsGetSCSIHostCaps(virNodeDevCapSCSIHostPtr scsi_host)
 }
 
 
+int
+nodeDeviceSysfsGetSCSITargetCaps(const char *sysfsPath,
+                                 virNodeDevCapSCSITargetPtr scsi_target)
+{
+    int ret = -1;
+    char *dir = NULL, *rport = NULL;
+
+    VIR_DEBUG("Checking if '%s' is an FC remote port", scsi_target->name);
+
+    /* /sys/devices/[...]/host0/rport-0:0-0/target0:0:0 -> rport-0:0-0 */
+    if (!(dir = mdir_name(sysfsPath)))
+        return -1;
+
+    if (VIR_STRDUP(rport, last_component(dir)) < 0)
+        goto cleanup;
+
+    if (!virFCIsCapableRport(rport))
+        goto cleanup;
+
+    VIR_FREE(scsi_target->rport);
+    VIR_STEAL_PTR(scsi_target->rport, rport);
+
+    if (virFCReadRportValue(scsi_target->rport, "port_name",
+                            &scsi_target->wwpn) < 0) {
+        VIR_WARN("Failed to read port_name for '%s'", scsi_target->rport);
+        goto cleanup;
+    }
+
+    scsi_target->flags |= VIR_NODE_DEV_CAP_FLAG_FC_RPORT;
+    ret = 0;
+
+ cleanup:
+    if (ret < 0) {
+        VIR_FREE(scsi_target->rport);
+        VIR_FREE(scsi_target->wwpn);
+        scsi_target->flags &= ~VIR_NODE_DEV_CAP_FLAG_FC_RPORT;
+    }
+    VIR_FREE(rport);
+    VIR_FREE(dir);
+
+    return ret;
+}
+
+
 static int
 nodeDeviceSysfsGetPCISRIOVCaps(const char *sysfsPath,
                                virNodeDevCapPCIDevPtr pci_dev)
@@ -231,6 +277,12 @@ nodeDeviceSysfsGetSCSIHostCaps(virNodeDevCapSCSIHostPtr scsi_host ATTRIBUTE_UNUS
     return -1;
 }
 
+int nodeDeviceSysfsGetSCSITargetCaps(const char *sysfsPath ATTRIBUTE_UNUSED,
+                                     virNodeDevCapSCSITargetPtr scsi_target ATTRIBUTE_UNUSED)
+{
+    return -1;
+}
+
 int
 nodeDeviceSysfsGetPCIRelatedDevCaps(const char *sysfsPath ATTRIBUTE_UNUSED,
                                     virNodeDevCapPCIDevPtr pci_dev ATTRIBUTE_UNUSED)
index 8deea6699879cc9725a5205a3f6abca1b92c6edf..12cfe6341e5de71e62c61fb360bf033307f60e1f 100644 (file)
@@ -26,6 +26,8 @@
 # include "node_device_conf.h"
 
 int nodeDeviceSysfsGetSCSIHostCaps(virNodeDevCapSCSIHostPtr scsi_host);
+int nodeDeviceSysfsGetSCSITargetCaps(const char *sysfsPath,
+                                     virNodeDevCapSCSITargetPtr scsi_target);
 int nodeDeviceSysfsGetPCIRelatedDevCaps(const char *sysfsPath,
                                         virNodeDevCapPCIDevPtr pci_dev);
 
index cc854b53802f293e7c050d4b1811b81a4c78981a..f100fd2e54e396b8b28add0ac0fbee8aa22ef77b 100644 (file)
@@ -697,7 +697,7 @@ static int udevProcessSCSIHost(struct udev_device *device ATTRIBUTE_UNUSED,
 }
 
 
-static int udevProcessSCSITarget(struct udev_device *device ATTRIBUTE_UNUSED,
+static int udevProcessSCSITarget(struct udev_device *device,
                                  virNodeDeviceDefPtr def)
 {
     const char *sysname = NULL;
@@ -708,6 +708,8 @@ static int udevProcessSCSITarget(struct udev_device *device ATTRIBUTE_UNUSED,
     if (VIR_STRDUP(scsi_target->name, sysname) < 0)
         return -1;
 
+    nodeDeviceSysfsGetSCSITargetCaps(def->sysfs_path, &def->caps->data.scsi_target);
+
     if (udevGenerateDeviceName(device, def, NULL) != 0)
         return -1;
 
diff --git a/tests/nodedevschemadata/scsi_target1_0_0.xml b/tests/nodedevschemadata/scsi_target1_0_0.xml
new file mode 100644 (file)
index 0000000..b783c54
--- /dev/null
@@ -0,0 +1,12 @@
+<device>
+  <name>scsi_target1_0_0</name>
+  <path>/sys/devices/css0/0.0.0000/0.0.0000/host1/rport-1:0-0/target1:0:0</path>
+  <parent>scsi_host0</parent>
+  <capability type='scsi_target'>
+    <target>target1:0:0</target>
+    <capability type='fc_remote_port'>
+      <rport>rport-1:0-0</rport>
+      <wwpn>0x9d73bc45f0e21a86</wwpn>
+    </capability>
+  </capability>
+</device>
index 805deef269511c06a1272c305a4e95f1d471c9bc..5d9f4724db4af18068216d716213b8e353dd0b42 100644 (file)
@@ -95,6 +95,7 @@ mymain(void)
     DO_TEST("pci_0000_00_02_0_header_type");
     DO_TEST("pci_0000_00_1c_0_header_type");
     DO_TEST("scsi_target0_0_0");
+    DO_TEST("scsi_target1_0_0");
     DO_TEST("pci_0000_02_10_7_sriov");
     DO_TEST("pci_0000_02_10_7_sriov_vfs");
     DO_TEST("pci_0000_02_10_7_sriov_zero_vfs_max_count");