diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
index cc560e66f28e6e210552edabd0779fc8fda4787b..1ea667cdf6f3323ba889b768e9ea28e8929df94f 100644
--- a/docs/schemas/basictypes.rng
+++ b/docs/schemas/basictypes.rng
@@ -318,6 +318,37 @@
+
+
+
+ 0x[0-9a-eA-E][0-9a-fA-F]?
+
+
+ 0x[fF][0-9a-eA-E]?
+
+
+ 0
+ 254
+
+
+
+
+
+ (0x)?[0-3]
+
+
+
+
+
+ 0x[0-9a-fA-F]{1,4}
+
+
+ 0
+ 65535
+
+
+
+
([0-9]+(-[0-9]+)?|\^[0-9]+)(,([0-9]+(-[0-9]+)?|\^[0-9]+))*
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 144c28159611fac3c83fdb4226fa6b64ffb46b5f..4d9f8d1a25ab1372f025d6a75854db8f878fb61b 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -5775,36 +5775,6 @@
-
-
-
- 0x[0-9a-eA-E][0-9a-fA-F]?
-
-
- 0x[fF][0-9a-eA-E]?
-
-
- 0
- 254
-
-
-
-
-
- (0x)?[0-3]
-
-
-
-
-
- 0x[0-9a-fA-F]{1,4}
-
-
- 0
- 65535
-
-
-
diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng
index 924f73861b83d61e831d8065804e3cf1f12bf66d..87bfb0c2865c738ac7b72ca09d38b0d31c5eb8c3 100644
--- a/docs/schemas/nodedev.rng
+++ b/docs/schemas/nodedev.rng
@@ -84,6 +84,7 @@
+
@@ -597,6 +598,21 @@
+
+
+ ccw
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index 722a4a5a00b775e84c0a9d71f9848de9db460c16..22c06f86979b2624ef5d4758c1435f6f322aae5b 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -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, "\n",
data->mdev.iommuGroupNumber);
break;
+ case VIR_NODE_DEV_CAP_CCW_DEV:
+ virBufferAsprintf(&buf, "0x%x\n",
+ data->ccw_dev.cssid);
+ virBufferAsprintf(&buf, "0x%x\n",
+ data->ccw_dev.ssid);
+ virBufferAsprintf(&buf, "0x%04x\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;
diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h
index 5743f9d3e2d04e3f008aa9e6fe31361898433dc9..bf9d5fce56eda9f7406dee42916bebd26731b20e 100644
--- a/src/conf/node_device_conf.h
+++ b/src/conf/node_device_conf.h
@@ -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;
};
};
diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c
index dfce17ce7157b55d43bd734065b94d4b5797b7be..66faf2b4fcf96798b98794032fdb262ec9c0a425 100644
--- a/src/node_device/node_device_driver.c
+++ b/src/node_device/node_device_driver.c
@@ -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;
}
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
index 4ecb0b18fefce0b1ab0d0414ffba37ea2ecafbf8..cc854b53802f293e7c050d4b1811b81a4c78981a 100644
--- a/src/node_device/node_device_udev.c
+++ b/src/node_device/node_device_udev.c
@@ -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
index 0000000000000000000000000000000000000000..d840555c09b6f86efc27231df6bb2aca53d8e1bd
--- /dev/null
+++ b/tests/nodedevschemadata/ccw_0_0_10000-invalid.xml
@@ -0,0 +1,10 @@
+
+ ccw_0_0_10000
+ /sys/devices/css0/0.0.0000/0.0.10000
+ computer
+
+ 0x0
+ 0x0
+ 0x10000
+
+
diff --git a/tests/nodedevschemadata/ccw_0_0_ffff.xml b/tests/nodedevschemadata/ccw_0_0_ffff.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5ecd0b0aae57f82c058e6a565bb63403e0c5157d
--- /dev/null
+++ b/tests/nodedevschemadata/ccw_0_0_ffff.xml
@@ -0,0 +1,10 @@
+
+ ccw_0_0_ffff
+ /sys/devices/css0/0.0.0000/0.0.ffff
+ computer
+
+ 0x0
+ 0x0
+ 0xffff
+
+
diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c
index a2aad518d339d75532109c2c6963196c6a4f9b85..805deef269511c06a1272c305a4e95f1d471c9bc 100644
--- a/tests/nodedevxml2xmltest.c
+++ b/tests/nodedevxml2xmltest.c
@@ -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;
}
diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c
index ad96dda1f9f9f74cfdbac92f7b205d6351718586..1822d3dce3954d1cde21ace580e6091ab6e27955 100644
--- a/tools/virsh-nodedev.c
+++ b/tools/virsh-nodedev.c
@@ -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;
}