]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
node_device: detect CCW devices
authorBjoern Walk <bwalk@linux.vnet.ibm.com>
Mon, 22 May 2017 06:38:22 +0000 (08:38 +0200)
committerJohn Ferlan <jferlan@redhat.com>
Fri, 26 May 2017 14:44:05 +0000 (10:44 -0400)
Make CCW devices available to the node_device driver. The devices are
already seen by udev so let's implement necessary code for detecting
them properly.

Topologically, CCW devices are similar to PCI devices, e.g.:

    +- ccw_0_0_1a2b
        |
        +- scsi_host0
            |
            +- scsi_target0_0_0
                |
                +- scsi_0_0_0_0

Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com>
Signed-off-by: Bjoern Walk <bwalk@linux.vnet.ibm.com>
docs/schemas/basictypes.rng
docs/schemas/domaincommon.rng
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_udev.c
tests/nodedevschemadata/ccw_0_0_10000-invalid.xml [new file with mode: 0644]
tests/nodedevschemadata/ccw_0_0_ffff.xml [new file with mode: 0644]
tests/nodedevxml2xmltest.c
tools/virsh-nodedev.c

index cc560e66f28e6e210552edabd0779fc8fda4787b..1ea667cdf6f3323ba889b768e9ea28e8929df94f 100644 (file)
     </data>
   </define>
 
+  <define name="ccwCssidRange">
+    <choice>
+      <data type="string">
+        <param name="pattern">0x[0-9a-eA-E][0-9a-fA-F]?</param>
+      </data>
+      <data type="string">
+        <param name="pattern">0x[fF][0-9a-eA-E]?</param>
+      </data>
+      <data type="int">
+        <param name="minInclusive">0</param>
+        <param name="maxInclusive">254</param>
+      </data>
+    </choice>
+  </define>
+  <define name="ccwSsidRange">
+    <data type="string">
+      <param name="pattern">(0x)?[0-3]</param>
+    </data>
+  </define>
+  <define name="ccwDevnoRange">
+    <choice>
+      <data type="string">
+        <param name="pattern">0x[0-9a-fA-F]{1,4}</param>
+      </data>
+      <data type="int">
+        <param name="minInclusive">0</param>
+        <param name="maxInclusive">65535</param>
+      </data>
+    </choice>
+  </define>
+
   <define name="cpuset">
     <data type="string">
       <param name="pattern">([0-9]+(-[0-9]+)?|\^[0-9]+)(,([0-9]+(-[0-9]+)?|\^[0-9]+))*</param>
index 144c28159611fac3c83fdb4226fa6b64ffb46b5f..4d9f8d1a25ab1372f025d6a75854db8f878fb61b 100644 (file)
     </element>
     <empty/>
   </define>
-  <define name="ccwCssidRange">
-    <choice>
-      <data type="string">
-        <param name="pattern">0x[0-9a-eA-E][0-9a-fA-F]?</param>
-      </data>
-      <data type="string">
-        <param name="pattern">0x[fF][0-9a-eA-E]?</param>
-      </data>
-      <data type="int">
-        <param name="minInclusive">0</param>
-        <param name="maxInclusive">254</param>
-      </data>
-    </choice>
-  </define>
-  <define name="ccwSsidRange">
-    <data type="string">
-      <param name="pattern">(0x)?[0-3]</param>
-    </data>
-  </define>
-  <define name="ccwDevnoRange">
-    <choice>
-      <data type="string">
-        <param name="pattern">0x[0-9a-fA-F]{1,4}</param>
-      </data>
-      <data type="int">
-        <param name="minInclusive">0</param>
-        <param name="maxInclusive">65535</param>
-      </data>
-    </choice>
-  </define>
   <define name="panic">
     <element name="panic">
       <optional>
index 924f73861b83d61e831d8065804e3cf1f12bf66d..87bfb0c2865c738ac7b72ca09d38b0d31c5eb8c3 100644 (file)
@@ -84,6 +84,7 @@
         <ref name="capstorage"/>
         <ref name="capdrm"/>
         <ref name="capmdev"/>
+        <ref name="capccwdev"/>
       </choice>
     </element>
   </define>
     </element>
   </define>
 
+  <define name='capccwdev'>
+    <attribute name='type'>
+      <value>ccw</value>
+    </attribute>
+    <element name='cssid'>
+      <ref name='ccwCssidRange'/>
+    </element>
+    <element name='ssid'>
+      <ref name='ccwSsidRange'/>
+    </element>
+    <element name='devno'>
+      <ref name='ccwDevnoRange'/>
+    </element>
+  </define>
+
   <define name='address'>
     <element name='address'>
       <attribute name='domain'><ref name='hexuint'/></attribute>
index 722a4a5a00b775e84c0a9d71f9848de9db460c16..22c06f86979b2624ef5d4758c1435f6f322aae5b 100644 (file)
@@ -62,7 +62,8 @@ VIR_ENUM_IMPL(virNodeDevCap, VIR_NODE_DEV_CAP_LAST,
               "scsi_generic",
               "drm",
               "mdev_types",
-              "mdev")
+              "mdev",
+              "ccw")
 
 VIR_ENUM_IMPL(virNodeDevNetCap, VIR_NODE_DEV_CAP_NET_LAST,
               "80203",
@@ -581,6 +582,14 @@ virNodeDeviceDefFormat(const virNodeDeviceDef *def)
             virBufferAsprintf(&buf, "<iommuGroup number='%u'/>\n",
                               data->mdev.iommuGroupNumber);
             break;
+        case VIR_NODE_DEV_CAP_CCW_DEV:
+            virBufferAsprintf(&buf, "<cssid>0x%x</cssid>\n",
+                              data->ccw_dev.cssid);
+            virBufferAsprintf(&buf, "<ssid>0x%x</ssid>\n",
+                              data->ccw_dev.ssid);
+            virBufferAsprintf(&buf, "<devno>0x%04x</devno>\n",
+                              data->ccw_dev.devno);
+            break;
         case VIR_NODE_DEV_CAP_MDEV_TYPES:
         case VIR_NODE_DEV_CAP_FC_HOST:
         case VIR_NODE_DEV_CAP_VPORTS:
@@ -717,6 +726,66 @@ virNodeDevCapDRMParseXML(xmlXPathContextPtr ctxt,
 }
 
 
+static int
+virNodeDevCapCCWParseXML(xmlXPathContextPtr ctxt,
+                         virNodeDeviceDefPtr def,
+                         xmlNodePtr node,
+                         virNodeDevCapCCWPtr ccw_dev)
+{
+    xmlNodePtr orignode;
+    int ret = -1;
+    char *cssid = NULL, *ssid = NULL, *devno = NULL;
+
+    orignode = ctxt->node;
+    ctxt->node = node;
+
+   if (!(cssid = virXPathString("string(./cssid[1])", ctxt))) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("missing cssid value for '%s'"), def->name);
+        goto out;
+    }
+
+    if (virStrToLong_uip(cssid, NULL, 0, &ccw_dev->cssid) < 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("invalid cssid value '%s' for '%s'"),
+                       cssid, def->name);
+        goto out;
+    }
+
+    if (!(ssid = virXPathString("string(./ssid[1])", ctxt))) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("missing ssid value for '%s'"), def->name);
+        goto out;
+    }
+
+    if (virStrToLong_uip(ssid, NULL, 0, &ccw_dev->ssid) < 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("invalid ssid value '%s' for '%s'"),
+                       cssid, def->name);
+        goto out;
+    }
+
+    if (!(devno = virXPathString("string(./devno[1])", ctxt))) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("missing devno value for '%s'"), def->name);
+        goto out;
+    }
+
+    if (virStrToLong_uip(devno, NULL, 16, &ccw_dev->devno) < 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("invalid devno value '%s' for '%s'"),
+                       devno, def->name);
+        goto out;
+    }
+
+    ret = 0;
+
+ out:
+    ctxt->node = orignode;
+    return ret;
+}
+
+
 static int
 virNodeDevCapStorageParseXML(xmlXPathContextPtr ctxt,
                              virNodeDeviceDefPtr def,
@@ -1754,6 +1823,9 @@ virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt,
     case VIR_NODE_DEV_CAP_MDEV:
         ret = virNodeDevCapMdevParseXML(ctxt, def, node, &caps->data.mdev);
         break;
+    case VIR_NODE_DEV_CAP_CCW_DEV:
+        ret = virNodeDevCapCCWParseXML(ctxt, def, node, &caps->data.ccw_dev);
+        break;
     case VIR_NODE_DEV_CAP_MDEV_TYPES:
     case VIR_NODE_DEV_CAP_FC_HOST:
     case VIR_NODE_DEV_CAP_VPORTS:
@@ -2083,6 +2155,7 @@ virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
     case VIR_NODE_DEV_CAP_DRM:
     case VIR_NODE_DEV_CAP_FC_HOST:
     case VIR_NODE_DEV_CAP_VPORTS:
+    case VIR_NODE_DEV_CAP_CCW_DEV:
     case VIR_NODE_DEV_CAP_LAST:
         /* This case is here to shutup the compiler */
         break;
index 5743f9d3e2d04e3f008aa9e6fe31361898433dc9..bf9d5fce56eda9f7406dee42916bebd26731b20e 100644 (file)
@@ -66,6 +66,7 @@ typedef enum {
     VIR_NODE_DEV_CAP_DRM,               /* DRM device */
     VIR_NODE_DEV_CAP_MDEV_TYPES,        /* Device capable of mediated devices */
     VIR_NODE_DEV_CAP_MDEV,              /* Mediated device */
+    VIR_NODE_DEV_CAP_CCW_DEV,           /* s390 CCW device */
 
     VIR_NODE_DEV_CAP_LAST
 } virNodeDevCapType;
@@ -267,6 +268,14 @@ struct _virNodeDevCapDRM {
     virNodeDevDRMType type;
 };
 
+typedef struct _virNodeDevCapCCW virNodeDevCapCCW;
+typedef virNodeDevCapCCW *virNodeDevCapCCWPtr;
+struct _virNodeDevCapCCW {
+    unsigned int cssid;
+    unsigned int ssid;
+    unsigned int devno;
+};
+
 typedef struct _virNodeDevCapData virNodeDevCapData;
 typedef virNodeDevCapData *virNodeDevCapDataPtr;
 struct _virNodeDevCapData {
@@ -284,6 +293,7 @@ struct _virNodeDevCapData {
         virNodeDevCapSCSIGeneric sg;
         virNodeDevCapDRM drm;
         virNodeDevCapMdev mdev;
+        virNodeDevCapCCW ccw_dev;
     };
 };
 
index dfce17ce7157b55d43bd734065b94d4b5797b7be..66faf2b4fcf96798b98794032fdb262ec9c0a425 100644 (file)
@@ -84,6 +84,7 @@ static int update_caps(virNodeDeviceObjPtr dev)
         case VIR_NODE_DEV_CAP_SCSI_GENERIC:
         case VIR_NODE_DEV_CAP_MDEV_TYPES:
         case VIR_NODE_DEV_CAP_MDEV:
+        case VIR_NODE_DEV_CAP_CCW_DEV:
         case VIR_NODE_DEV_CAP_LAST:
             break;
         }
index 4ecb0b18fefce0b1ab0d0414ffba37ea2ecafbf8..cc854b53802f293e7c050d4b1811b81a4c78981a 100644 (file)
@@ -1104,6 +1104,36 @@ udevProcessMediatedDevice(struct udev_device *dev,
     return ret;
 }
 
+
+static int
+udevProcessCCW(struct udev_device *device,
+               virNodeDeviceDefPtr def)
+{
+    int online;
+    char *p;
+    virNodeDevCapDataPtr data = &def->caps->data;
+
+    /* process only online devices to keep the list sane */
+    if (udevGetIntSysfsAttr(device, "online", &online, 0) < 0 || online != 1)
+        return -1;
+
+    if ((p = strrchr(def->sysfs_path, '/')) == NULL ||
+        virStrToLong_ui(p + 1, &p, 16, &data->ccw_dev.cssid) < 0 || p == NULL ||
+        virStrToLong_ui(p + 1, &p, 16, &data->ccw_dev.ssid) < 0 || p == NULL ||
+        virStrToLong_ui(p + 1, &p, 16, &data->ccw_dev.devno) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("failed to parse the CCW address from sysfs path: '%s'"),
+                       def->sysfs_path);
+        return -1;
+    }
+
+    if (udevGenerateDeviceName(device, def, NULL) != 0)
+        return -1;
+
+    return 0;
+}
+
+
 static int
 udevGetDeviceNodes(struct udev_device *device,
                    virNodeDeviceDefPtr def)
@@ -1172,8 +1202,8 @@ udevGetDeviceType(struct udev_device *device,
         if (udevHasDeviceProperty(device, "INTERFACE"))
             *type = VIR_NODE_DEV_CAP_NET;
 
-        /* Neither SCSI generic devices nor mediated devices set DEVTYPE
-         * property, therefore we need to rely on the SUBSYSTEM property */
+        /* The following devices do not set the DEVTYPE property, therefore
+         * we need to rely on the SUBSYSTEM property */
         if (udevGetStringProperty(device, "SUBSYSTEM", &subsystem) < 0)
             return -1;
 
@@ -1181,6 +1211,8 @@ udevGetDeviceType(struct udev_device *device,
             *type = VIR_NODE_DEV_CAP_SCSI_GENERIC;
         else if (STREQ_NULLABLE(subsystem, "mdev"))
             *type = VIR_NODE_DEV_CAP_MDEV;
+        else if (STREQ_NULLABLE(subsystem, "ccw"))
+            *type = VIR_NODE_DEV_CAP_CCW_DEV;
 
         VIR_FREE(subsystem);
     }
@@ -1222,6 +1254,8 @@ static int udevGetDeviceDetails(struct udev_device *device,
         return udevProcessDRMDevice(device, def);
     case VIR_NODE_DEV_CAP_MDEV:
         return udevProcessMediatedDevice(device, def);
+    case VIR_NODE_DEV_CAP_CCW_DEV:
+        return udevProcessCCW(device, def);
     case VIR_NODE_DEV_CAP_MDEV_TYPES:
     case VIR_NODE_DEV_CAP_SYSTEM:
     case VIR_NODE_DEV_CAP_FC_HOST:
diff --git a/tests/nodedevschemadata/ccw_0_0_10000-invalid.xml b/tests/nodedevschemadata/ccw_0_0_10000-invalid.xml
new file mode 100644 (file)
index 0000000..d840555
--- /dev/null
@@ -0,0 +1,10 @@
+<device>
+  <name>ccw_0_0_10000</name>
+  <path>/sys/devices/css0/0.0.0000/0.0.10000</path>
+  <parent>computer</parent>
+  <capability type='ccw'>
+    <cssid>0x0</cssid>
+    <ssid>0x0</ssid>
+    <devno>0x10000</devno>
+  </capability>
+</device>
diff --git a/tests/nodedevschemadata/ccw_0_0_ffff.xml b/tests/nodedevschemadata/ccw_0_0_ffff.xml
new file mode 100644 (file)
index 0000000..5ecd0b0
--- /dev/null
@@ -0,0 +1,10 @@
+<device>
+  <name>ccw_0_0_ffff</name>
+  <path>/sys/devices/css0/0.0.0000/0.0.ffff</path>
+  <parent>computer</parent>
+  <capability type='ccw'>
+    <cssid>0x0</cssid>
+    <ssid>0x0</ssid>
+    <devno>0xffff</devno>
+  </capability>
+</device>
index a2aad518d339d75532109c2c6963196c6a4f9b85..805deef269511c06a1272c305a4e95f1d471c9bc 100644 (file)
@@ -103,6 +103,7 @@ mymain(void)
     DO_TEST("drm_renderD129");
     DO_TEST("pci_0000_02_10_7_mdev_types");
     DO_TEST("mdev_3627463d_b7f0_4fea_b468_f1da537d301b");
+    DO_TEST("ccw_0_0_ffff");
 
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
index ad96dda1f9f9f74cfdbac92f7b205d6351718586..1822d3dce3954d1cde21ace580e6091ab6e27955 100644 (file)
@@ -460,6 +460,8 @@ cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
         case VIR_NODE_DEV_CAP_MDEV:
             flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_MDEV;
             break;
+        case VIR_NODE_DEV_CAP_CCW_DEV:
+            /* enable next patch */
         case VIR_NODE_DEV_CAP_LAST:
             break;
         }