</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>
</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>
<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>
"scsi_generic",
"drm",
"mdev_types",
- "mdev")
+ "mdev",
+ "ccw")
VIR_ENUM_IMPL(virNodeDevNetCap, VIR_NODE_DEV_CAP_NET_LAST,
"80203",
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:
}
+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,
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:
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;
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;
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 {
virNodeDevCapSCSIGeneric sg;
virNodeDevCapDRM drm;
virNodeDevCapMdev mdev;
+ virNodeDevCapCCW ccw_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;
}
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)
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;
*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);
}
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:
--- /dev/null
+<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>
--- /dev/null
+<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>
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;
}
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;
}