From nobody Mon Feb 9 04:46:47 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=reject dis=none) header.from=linux.ibm.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1738689385742569.6245289019688; Tue, 4 Feb 2025 09:16:25 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 996) id 8DA7E17CE; Tue, 4 Feb 2025 12:16:24 -0500 (EST) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 358FD1DFF; Tue, 4 Feb 2025 12:12:12 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 996) id ED5FC1B66; Tue, 4 Feb 2025 12:11:52 -0500 (EST) Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 32AF51B57 for ; Tue, 4 Feb 2025 12:11:51 -0500 (EST) Received: from pps.filterd (m0353729.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 514GF5gk023629 for ; Tue, 4 Feb 2025 17:11:50 GMT Received: from ppma23.wdc07v.mail.ibm.com (5d.69.3da9.ip4.static.sl-reverse.com [169.61.105.93]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 44kcq7ucva-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 04 Feb 2025 17:11:49 +0000 (GMT) Received: from pps.filterd (ppma23.wdc07v.mail.ibm.com [127.0.0.1]) by ppma23.wdc07v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 514GhbSj006578 for ; Tue, 4 Feb 2025 17:11:48 GMT Received: from smtprelay05.fra02v.mail.ibm.com ([9.218.2.225]) by ppma23.wdc07v.mail.ibm.com (PPS) with ESMTPS id 44hyekcf5g-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 04 Feb 2025 17:11:48 +0000 Received: from smtpav04.fra02v.mail.ibm.com (smtpav04.fra02v.mail.ibm.com [10.20.54.103]) by smtprelay05.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 514HBigT42598746 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 4 Feb 2025 17:11:44 GMT Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id A0808200B8; Tue, 4 Feb 2025 17:11:44 +0000 (GMT) Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7ACED200B5; Tue, 4 Feb 2025 17:11:44 +0000 (GMT) Received: from fiuczyvm.. (unknown [9.152.222.247]) by smtpav04.fra02v.mail.ibm.com (Postfix) with ESMTP; Tue, 4 Feb 2025 17:11:44 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-1.4 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=W/W7kzErUfPlY1+s6 ZVKnEmgL0cVCkXaUIZKYQBQMNo=; b=WnptlCj4dMsbJ20mtrk1xqWDCA/3qxjt8 PJybXrcMUSl8KTrXbY4iiG85TcEs54nMoH3ZchrVdw8nC3a0EjX3D1x2ja/21zGU 7fLB9IzDnpNPG1HC6PTQCPwafjD+efnpnnoxe3fEbf8u82s7xy6DmZiW8q5iVye9 umX0gamIhgrtC8ObIZIsgjeBxnBDCB4ejtpb00s29JrXY2gzOmHv72/bgSuSZ+6p CpP569qGX09afdr6f65z9TFlJW7YFGtpiGRDlle4UiPOZChn3KeXX/fMZxff2yyi +O71bdpPtI/C1YrJEtau61mr1XUlFcdzidp2M8t4gXc5mQf70tzHA== From: Boris Fiuczynski To: devel@lists.libvirt.org Subject: [PATCH 6/8] nodedev: add ccwgroup node device support Date: Tue, 4 Feb 2025 18:11:41 +0100 Message-ID: <20250204171143.93141-7-fiuczy@linux.ibm.com> X-Mailer: git-send-email 2.48.0 In-Reply-To: <20250204171143.93141-1-fiuczy@linux.ibm.com> References: <20250204171143.93141-1-fiuczy@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: JiNlHekUGhVNJ3LCfKkklASOe0s8iTck X-Proofpoint-ORIG-GUID: JiNlHekUGhVNJ3LCfKkklASOe0s8iTck X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1057,Hydra:6.0.680,FMLib:17.12.68.34 definitions=2025-02-04_08,2025-02-04_01,2024-11-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxscore=0 phishscore=0 suspectscore=0 mlxlogscore=999 spamscore=0 priorityscore=1501 malwarescore=0 impostorscore=0 bulkscore=0 adultscore=0 clxscore=1015 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2501170000 definitions=main-2502040131 Content-Transfer-Encoding: quoted-printable Message-ID-Hash: 75M2WLPJ7SKAQFZ4KSJAS6U3UONE2H3V X-Message-ID-Hash: 75M2WLPJ7SKAQFZ4KSJAS6U3UONE2H3V X-MailFrom: fiuczy@linux.ibm.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header CC: Boris Fiuczynski X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1738689388682019100 Content-Type: text/plain; charset="utf-8" Add ccwgroup node device type supporting qeth generic driver. Signed-off-by: Boris Fiuczynski --- docs/manpages/virsh.rst | 6 +- include/libvirt/libvirt-nodedev.h | 1 + src/conf/node_device_conf.c | 212 ++++++++++++++++++ src/conf/node_device_conf.h | 29 ++- src/conf/schemas/nodedev.rng | 43 ++++ src/conf/virnodedeviceobj.c | 4 +- src/libvirt_private.syms | 2 + src/node_device/node_device_driver.c | 5 + src/node_device/node_device_udev.c | 41 ++++ src/util/virccw.c | 102 +++++++++ src/util/virccw.h | 22 ++ tests/nodedevschemadata/ccwgroup_0_0_bd00.xml | 20 ++ tests/nodedevxml2xmlout/ccwgroup_0_0_bd00.xml | 1 + tests/nodedevxml2xmltest.c | 1 + tools/virsh-nodedev.c | 3 + 15 files changed, 487 insertions(+), 5 deletions(-) create mode 100644 tests/nodedevschemadata/ccwgroup_0_0_bd00.xml create mode 120000 tests/nodedevxml2xmlout/ccwgroup_0_0_bd00.xml diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index 868b354b2f..5e5734dff1 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -5532,9 +5532,9 @@ List all of the devices available on the node that ar= e known by libvirt. separated by comma, e.g. --cap pci,scsi. Valid capability types include 'system', 'pci', 'usb_device', 'usb', 'net', 'scsi_host', 'scsi_target', 'scsi', 'storage', 'fc_host', 'vports', 'scsi_generic', 'drm', 'mdev', -'mdev_types', 'ccw', 'css', 'ap_card', 'ap_queue', 'ap_matrix'. By default, -only active devices are listed. *--inactive* is used to list only inactive -devices, and *--all* is used to list both active and inactive devices. +'mdev_types', 'ccw', 'ccwgroup', 'css', 'ap_card', 'ap_queue', 'ap_matrix'. +By default, only active devices are listed. *--inactive* is used to list o= nly +inactive devices, and *--all* is used to list both active and inactive dev= ices. *--persistent* is used to list only persistent devices, and *--transient* = is used to list only transient devices. Not providing *--persistent* or *--transient* will list all devices unless filtered otherwise. *--transien= t* diff --git a/include/libvirt/libvirt-nodedev.h b/include/libvirt/libvirt-no= dedev.h index ec26c7a5e1..79bee4fb04 100644 --- a/include/libvirt/libvirt-nodedev.h +++ b/include/libvirt/libvirt-nodedev.h @@ -90,6 +90,7 @@ typedef enum { VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_QUEUE =3D 1 << 19, /* s390 A= P Queue (Since: 7.0.0) */ VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_MATRIX =3D 1 << 20, /* s390 A= P Matrix (Since: 7.0.0) */ VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPD =3D 1 << 21, /* Device= with VPD (Since: 7.9.0) */ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_CCWGROUP_DEV =3D 1 << 22, /* s390 C= CWGROUP device (Since: 11.1.0) */ =20 VIR_CONNECT_LIST_NODE_DEVICES_PERSISTENT =3D 1 << 28, /* Persis= ted devices (Since: 10.1.0) */ VIR_CONNECT_LIST_NODE_DEVICES_TRANSIENT =3D 1 << 29, /* Transi= ent devices (Since: 10.1.0) */ diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index bfd81b1692..1649df09a1 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -71,6 +71,12 @@ VIR_ENUM_IMPL(virNodeDevCap, "ap_queue", "ap_matrix", "vpd", + "ccwgroup", +); + +VIR_ENUM_IMPL(virNodeDevCCWGroupCap, + VIR_NODE_DEV_CAP_CCWGROUP_LAST, + "qeth_generic", ); =20 VIR_ENUM_IMPL(virNodeDevNetCap, @@ -670,6 +676,53 @@ virNodeDeviceCapCCWStateTypeFormat(virBuffer *buf, } =20 =20 +static void +virNodeDeviceCapCCWGroupQethFormat(virBuffer *buf, + const virCCWGroupTypeQeth *qeth) +{ + virBufferAsprintf(buf, "%s\n", qeth->card_type); + virBufferAsprintf(buf, "%s\n", qeth->chpid); +} + + +static void +virNodeDeviceCapCCWGroupDefFormat(virBuffer *buf, + const virNodeDevCapData *data) +{ + virNodeDevCapCCWGroup ccwgroup_dev =3D data->ccwgroup_dev; + size_t i; + + virNodeDeviceCapCCWStateTypeFormat(buf, ccwgroup_dev.state); + virCCWDeviceAddressFormat(buf, ccwgroup_dev.address); + + if (ccwgroup_dev.members) { + virBufferAddLit(buf, "\n"); + virBufferAdjustIndent(buf, 2); + for (i =3D 0; i < ccwgroup_dev.nmembers; i++) { + virBufferEscapeString(buf, "", + ccwgroup_dev.members[i]->ref); + virBufferEscapeString(buf, "%s\n", + ccwgroup_dev.members[i]->device); + } + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); + } + + virBufferAsprintf(buf, "\n", + virNodeDevCCWGroupCapTypeToString(ccwgroup_dev.type)= ); + virBufferAdjustIndent(buf, 2); + switch (ccwgroup_dev.type) { + case VIR_NODE_DEV_CAP_CCWGROUP_QETH_GENERIC: + virNodeDeviceCapCCWGroupQethFormat(buf, &ccwgroup_dev.qeth); + break; + case VIR_NODE_DEV_CAP_CCWGROUP_LAST: + break; + } + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); +} + + char * virNodeDeviceDefFormat(const virNodeDeviceDef *def, unsigned int flags) { @@ -787,6 +840,9 @@ virNodeDeviceDefFormat(const virNodeDeviceDef *def, uns= igned int flags) data->mdev_parent.mdev_types, data->mdev_parent.nmdev_types); break; + case VIR_NODE_DEV_CAP_CCWGROUP_DEV: + virNodeDeviceCapCCWGroupDefFormat(&buf, data); + break; case VIR_NODE_DEV_CAP_FC_HOST: case VIR_NODE_DEV_CAP_VPORTS: case VIR_NODE_DEV_CAP_VPD: @@ -1303,6 +1359,107 @@ virNodeDevCapCSSParseXML(xmlXPathContextPtr ctxt, } =20 =20 +static int +virNodeDevCapCCWGroupQethParseXML(xmlXPathContextPtr ctxt, + xmlNodePtr node, + virCCWGroupTypeQeth *qeth) +{ + VIR_XPATH_NODE_AUTORESTORE(ctxt) + ctxt->node =3D node; + + qeth->card_type =3D virXPathString("string(./card_type[1])", ctxt); + qeth->chpid =3D virXPathString("string(./chpid[1])", ctxt); + + return 0; +} + + +static int +virNodeDevCapCCWGroupParseXML(xmlXPathContextPtr ctxt, + virNodeDeviceDef *def, + xmlNodePtr node, + virNodeDevCapCCWGroup *ccwgroup_dev) +{ + VIR_XPATH_NODE_AUTORESTORE(ctxt) + g_autofree virCCWGroupMemberType **members =3D NULL; + g_autofree virCCWDeviceAddress *address =3D NULL; + g_autofree xmlNodePtr *ccw_device_nodes =3D NULL; + xmlNodePtr cap_node =3D NULL; + g_autofree char *state =3D NULL; + size_t i =3D 0; + int n =3D 0; + + ctxt->node =3D node; + + /* state is optional */ + ccwgroup_dev->state =3D VIR_NODE_DEV_CCW_STATE_LAST; + if ((state =3D virXPathString("string(./state[1])", ctxt))) { + int val; + if ((val =3D virNodeDevCCWStateTypeFromString(state)) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unknown state '%1$s' for '%2$s'"), state, de= f->name); + return -1; + } + ccwgroup_dev->state =3D val; + } + + address =3D g_new0(virCCWDeviceAddress, 1); + + if (virNodeDevCCWDeviceAddressParseXML(ctxt, + node, + def->name, + address) < 0) + return -1; + + ccwgroup_dev->address =3D g_steal_pointer(&address); + + /* Parse ccw_devices in members */ + if ((n =3D virXPathNodeSet("./members/ccw_device", ctxt, &ccw_device_n= odes)) < 0) + return -1; + + ccwgroup_dev->members =3D g_new0(virCCWGroupMemberType *, n); + + for (i =3D 0; i < n; i++) { + g_autoptr(virCCWGroupMemberType) ccwMember =3D g_new0(virCCWGroupM= emberType, 1); + + if (!(ccwMember->ref =3D virXMLPropString(ccw_device_nodes[i], "re= f"))) { + virReportError(VIR_ERR_XML_ERROR, + _("Missing ref property on ccw_device in member= s for '%1$s'"), + def->name); + return -1; + } + if (!(ccwMember->device =3D virXMLNodeContentString(ccw_device_nod= es[i]))) { + virReportError(VIR_ERR_XML_ERROR, + _("Missing data in ccw_device with ref '%1$s' i= n members for '%2$s'"), + ccwMember->ref, def->name); + return -1; + } + + VIR_APPEND_ELEMENT(ccwgroup_dev->members, + ccwgroup_dev->nmembers, + ccwMember); + } + + /* Parse capability */ + cap_node =3D virXPathNode("./capability", ctxt); + if (cap_node && virXMLPropEnum(cap_node, "type", + virNodeDevCCWGroupCapTypeFromString, + VIR_XML_PROP_REQUIRED, &ccwgroup_dev->t= ype) < 0) + return -1; + + switch (ccwgroup_dev->type) { + case VIR_NODE_DEV_CAP_CCWGROUP_QETH_GENERIC: + if (virNodeDevCapCCWGroupQethParseXML(ctxt, cap_node, &ccwgroup_de= v->qeth) < 0) + return -1; + break; + case VIR_NODE_DEV_CAP_CCWGROUP_LAST: + break; + } + + return 0; +} + + static int virNodeDevCapAPAdapterParseXML(xmlXPathContextPtr ctxt, virNodeDeviceDef *def, @@ -2343,6 +2500,10 @@ virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt, ret =3D virNodeDevCapAPMatrixParseXML(ctxt, def, node, &caps->data.ap_matrix); break; + case VIR_NODE_DEV_CAP_CCWGROUP_DEV: + ret =3D virNodeDevCapCCWGroupParseXML(ctxt, def, node, + &caps->data.ccwgroup_dev); + break; case VIR_NODE_DEV_CAP_MDEV_TYPES: case VIR_NODE_DEV_CAP_FC_HOST: case VIR_NODE_DEV_CAP_VPORTS: @@ -2635,6 +2796,19 @@ virNodeDevCapsDefFree(virNodeDevCapsDef *caps) case VIR_NODE_DEV_CAP_CCW_DEV: g_free(data->ccw_dev.dev_addr); break; + case VIR_NODE_DEV_CAP_CCWGROUP_DEV: + g_free(data->ccwgroup_dev.address); + for (i =3D 0; i < data->ccwgroup_dev.nmembers; i++) + virCCWGroupMemberTypeFree(data->ccwgroup_dev.members[i]); + g_free(data->ccwgroup_dev.members); + switch (data->ccwgroup_dev.type) { + case VIR_NODE_DEV_CAP_CCWGROUP_QETH_GENERIC: + virCCWGroupTypeQethFree(&data->ccwgroup_dev.qeth); + break; + case VIR_NODE_DEV_CAP_CCWGROUP_LAST: + break; + } + break; case VIR_NODE_DEV_CAP_DRM: case VIR_NODE_DEV_CAP_FC_HOST: case VIR_NODE_DEV_CAP_VPORTS: @@ -2694,6 +2868,11 @@ virNodeDeviceUpdateCaps(virNodeDeviceDef *def) &cap->data.mdev_pare= nt) < 0) return -1; break; + case VIR_NODE_DEV_CAP_CCWGROUP_DEV: + if (virNodeDeviceGetCCWGroupDynamicCaps(def->sysfs_path, + &cap->data.ccwgroup_de= v) < 0) + return -1; + break; =20 /* all types that (supposedly) don't require any updates * relative to what's in the cache. @@ -3194,6 +3373,31 @@ virNodeDeviceGetMdevParentDynamicCaps(const char *sy= sfsPath, return 0; } =20 +/* virNodeDeviceGetCCWGroupDynamicCaps() get info that is stored in sysfs + * about devices related to this device, i.e. things that can change + * without this device itself changing. These must be refreshed + * anytime full XML of the device is requested, because they can + * change with no corresponding notification from the kernel/udev. + */ +int +virNodeDeviceGetCCWGroupDynamicCaps(const char *sysfsPath, + virNodeDevCapCCWGroup *ccwgroup) +{ + size_t i; + + for (i =3D 0; i < ccwgroup->nmembers; i++) + virCCWGroupMemberTypeFree(ccwgroup->members[i]); + VIR_FREE(ccwgroup->members); + ccwgroup->nmembers =3D 0; + + if (virCCWGroupDeviceGetMembers(sysfsPath, + &ccwgroup->members, + &ccwgroup->nmembers) < 0) + return -1; + + return 0; +} + =20 #else =20 @@ -3239,4 +3443,12 @@ virNodeDeviceGetMdevParentDynamicCaps(const char *sy= sfsPath G_GNUC_UNUSED, } =20 =20 +int +virNodeDeviceGetCCWGroupDynamicCaps(const char *sysfsPath G_GNUC_UNUSED, + virNodeDevCapCCWGroup *ccwgroup G_GNUC= _UNUSED) +{ + return -1; +} + + #endif /* __linux__ */ diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index ad2258e90d..d94670e074 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -71,10 +71,17 @@ typedef enum { VIR_NODE_DEV_CAP_AP_QUEUE, /* s390 AP Queue */ VIR_NODE_DEV_CAP_AP_MATRIX, /* s390 AP Matrix device */ VIR_NODE_DEV_CAP_VPD, /* Device provides VPD */ + VIR_NODE_DEV_CAP_CCWGROUP_DEV, /* s390 CCWGROUP device */ =20 VIR_NODE_DEV_CAP_LAST } virNodeDevCapType; =20 +typedef enum { + /* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */ + VIR_NODE_DEV_CAP_CCWGROUP_QETH_GENERIC, /* s390 CCWGROUP QETH gene= ric device */ + VIR_NODE_DEV_CAP_CCWGROUP_LAST +} virNodeDevCCWGroupCapType; + typedef enum { /* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */ VIR_NODE_DEV_CAP_NET_80203, /* 802.03 network device */ @@ -83,6 +90,7 @@ typedef enum { } virNodeDevNetCapType; =20 VIR_ENUM_DECL(virNodeDevCap); +VIR_ENUM_DECL(virNodeDevCCWGroupCap); VIR_ENUM_DECL(virNodeDevNetCap); =20 typedef enum { @@ -321,6 +329,19 @@ struct _virNodeDevCapMdevParent { char *address; }; =20 +typedef struct _virNodeDevCapCCWGroup virNodeDevCapCCWGroup; +struct _virNodeDevCapCCWGroup { + virNodeDevCCWStateType state; // online attribute + virCCWDeviceAddress *address; + virCCWGroupMemberType **members; + size_t nmembers; + + virNodeDevCCWGroupCapType type; + union { + virCCWGroupTypeQeth qeth; + }; +}; + typedef struct _virNodeDevCapData virNodeDevCapData; struct _virNodeDevCapData { virNodeDevCapType type; @@ -343,6 +364,7 @@ struct _virNodeDevCapData { virNodeDevCapAPQueue ap_queue; virNodeDevCapAPMatrix ap_matrix; virNodeDevCapMdevParent mdev_parent; + virNodeDevCapCCWGroup ccwgroup_dev; }; }; =20 @@ -434,7 +456,8 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNodeDevCapsDef, virNod= eDevCapsDefFree); VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_CARD | \ VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_QUEUE | \ VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_MATRIX | \ - VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPD) + VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPD | \ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_CCWGROUP_DEV) =20 #define VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_ACTIVE \ VIR_CONNECT_LIST_NODE_DEVICES_ACTIVE | \ @@ -472,6 +495,10 @@ int virNodeDeviceGetMdevParentDynamicCaps(const char *sysfsPath, virNodeDevCapMdevParent *mdev_parent= ); =20 +int +virNodeDeviceGetCCWGroupDynamicCaps(const char *sysfsPath, + virNodeDevCapCCWGroup *ccwgroup); + int virNodeDeviceUpdateCaps(virNodeDeviceDef *def); =20 diff --git a/src/conf/schemas/nodedev.rng b/src/conf/schemas/nodedev.rng index 42a0cdcfd9..ebcda30f1f 100644 --- a/src/conf/schemas/nodedev.rng +++ b/src/conf/schemas/nodedev.rng @@ -83,6 +83,7 @@ + @@ -669,6 +670,48 @@ =20 + + + qeth_generic + + + + + + + + + + ccwgroup + + + + + online + offline + + + + + + + + + + + + + + + + + + + + + + + ccw diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index d0a6eab42b..23984995c8 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -741,6 +741,7 @@ virNodeDeviceObjHasCap(const virNodeDeviceObj *obj, case VIR_NODE_DEV_CAP_AP_CARD: case VIR_NODE_DEV_CAP_AP_QUEUE: case VIR_NODE_DEV_CAP_VPD: + case VIR_NODE_DEV_CAP_CCWGROUP_DEV: case VIR_NODE_DEV_CAP_LAST: break; } @@ -899,7 +900,8 @@ virNodeDeviceObjMatch(virNodeDeviceObj *obj, MATCH_CAP(AP_CARD) || MATCH_CAP(AP_QUEUE) || MATCH_CAP(AP_MATRIX) || - MATCH_CAP(VPD))) + MATCH_CAP(VPD) || + MATCH_CAP(CCWGROUP_DEV))) return false; } =20 diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 406e6583a3..07e1e673f0 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -892,12 +892,14 @@ virNetDevIPRouteParseXML; virNodeDevCapsDefFree; virNodeDevCapTypeFromString; virNodeDevCapTypeToString; +virNodeDevCCWGroupCapTypeFromString; virNodeDeviceCapsListExport; virNodeDeviceDefFormat; virNodeDeviceDefFree; virNodeDeviceDefParse; virNodeDeviceDefParseXML; virNodeDeviceGetAPMatrixDynamicCaps; +virNodeDeviceGetCCWGroupDynamicCaps; virNodeDeviceGetCSSDynamicCaps; virNodeDeviceGetMdevParentDynamicCaps; virNodeDeviceGetPCIDynamicCaps; diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_de= vice_driver.c index 9898b1914a..d716561361 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -695,6 +695,10 @@ nodeDeviceObjFormatAddress(virNodeDeviceObj *obj) addr =3D g_strdup(caps->data.mdev_parent.address); break; =20 + case VIR_NODE_DEV_CAP_CCWGROUP_DEV: + addr =3D virCCWDeviceAddressAsString(caps->data.ccwgroup_dev.a= ddress); + break; + case VIR_NODE_DEV_CAP_SYSTEM: case VIR_NODE_DEV_CAP_USB_DEV: case VIR_NODE_DEV_CAP_USB_INTERFACE: @@ -2189,6 +2193,7 @@ int nodeDeviceDefValidate(virNodeDeviceDef *def, case VIR_NODE_DEV_CAP_AP_QUEUE: case VIR_NODE_DEV_CAP_AP_MATRIX: case VIR_NODE_DEV_CAP_VPD: + case VIR_NODE_DEV_CAP_CCWGROUP_DEV: case VIR_NODE_DEV_CAP_LAST: break; } diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_devi= ce_udev.c index 6b362625f7..a78f47b65a 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -1389,6 +1389,43 @@ udevProcessAPMatrix(struct udev_device *device, } =20 =20 +static int +udevProcessCCWGroup(struct udev_device *device, + virNodeDeviceDef *def) +{ + const char *devtype =3D udev_device_get_devtype(device); + virNodeDevCapData *data =3D &def->caps->data; + + data->ccwgroup_dev.address =3D virCCWDeviceAddressFromString(udev_devi= ce_get_sysname(device)); + + udevCCWGetState(device, &data->ccwgroup_dev.state); + + udevGenerateDeviceName(device, def, NULL); + + if ((data->ccwgroup_dev.type =3D virNodeDevCCWGroupCapTypeFromString(d= evtype)) < 0) + return -1; + + switch (data->ccwgroup_dev.type) { + case VIR_NODE_DEV_CAP_CCWGROUP_QETH_GENERIC: + { + virCCWGroupTypeQeth *qeth =3D &data->ccwgroup_dev.qeth; + /* process qeth device information */ + udevGetStringSysfsAttr(device, "card_type", &qeth->card_type); + udevGetStringSysfsAttr(device, "chpid", &qeth->chpid); + } + break; + case VIR_NODE_DEV_CAP_CCWGROUP_LAST: + return -1; + } + + if (virNodeDeviceGetCCWGroupDynamicCaps(def->sysfs_path, + &data->ccwgroup_dev) < 0) + return -1; + + return 0; +} + + static int udevGetDeviceNodes(struct udev_device *device, virNodeDeviceDef *def) @@ -1447,6 +1484,8 @@ udevGetDeviceType(struct udev_device *device, *type =3D VIR_NODE_DEV_CAP_AP_CARD; else if (STREQ(devtype, "ap_queue")) *type =3D VIR_NODE_DEV_CAP_AP_QUEUE; + else if (STREQ(devtype, "qeth_generic")) + *type =3D VIR_NODE_DEV_CAP_CCWGROUP_DEV; } else { /* PCI devices don't set the DEVTYPE property. */ if (udevHasDeviceProperty(device, "PCI_CLASS")) @@ -1534,6 +1573,8 @@ udevGetDeviceDetails(virNodeDeviceDriverState *driver= _state, return udevProcessAPMatrix(device, def); case VIR_NODE_DEV_CAP_MDEV_TYPES: return udevProcessMdevParent(device, def); + case VIR_NODE_DEV_CAP_CCWGROUP_DEV: + return udevProcessCCWGroup(device, def); case VIR_NODE_DEV_CAP_VPD: case VIR_NODE_DEV_CAP_SYSTEM: case VIR_NODE_DEV_CAP_FC_HOST: diff --git a/src/util/virccw.c b/src/util/virccw.c index c6be013e16..0873c61889 100644 --- a/src/util/virccw.c +++ b/src/util/virccw.c @@ -19,9 +19,15 @@ */ =20 #include + #include "virccw.h" + +#include + #include "virerror.h" +#include "virfile.h" #include "virstring.h" +#include "viralloc.h" =20 #define VIR_FROM_THIS VIR_FROM_NONE =20 @@ -101,3 +107,99 @@ virCCWDeviceAddressParseFromString(const char *address, =20 return 0; } + +void +virCCWGroupMemberTypeFree(virCCWGroupMemberType *member) +{ + if (!member) + return; + + VIR_FREE(member->ref); + VIR_FREE(member->device); + VIR_FREE(member); +} + +static char * +virCCWGroupDeviceDevNodeName(const char *nodedev_prefix, + const char *sysfs_path) +{ + g_autofree char *node_name =3D NULL; + size_t i; + + node_name =3D g_path_get_basename(sysfs_path); + + for (i =3D 0; i < strlen(node_name); i++) { + if (!(g_ascii_isalnum(*(node_name + i)))) + *(node_name + i) =3D '_'; + } + + return g_strdup_printf("%s_%s", nodedev_prefix, node_name); +} + +/** + * virCCWGroupDeviceGetMembers: + * @sysfs_path: sysfs path to a group device + * @members: Where to add the found group members + * @nmembers: Number of found group members + * + * The sysfs path is searched for links with a name prefix "cdev". + * These links point the ccw device sysfs entry which is a member + * of the ccw group. + * + * Returns: -1 on error (invalid sysfs_path or group has no members) + * 0 on success + */ +int +virCCWGroupDeviceGetMembers(const char *sysfs_path, + virCCWGroupMemberType ***members, + size_t *nmembers) +{ + virCCWGroupMemberType *member =3D NULL; + g_autofree char *ccwdevpath =3D NULL; + g_autoptr(DIR) dir =3D NULL; + struct dirent *entry; + int direrr; + + if (virDirOpenIfExists(&dir, sysfs_path) <=3D 0) + return -1; + + while ((direrr =3D virDirRead(dir, &entry, NULL)) > 0) { + if (g_str_has_prefix(entry->d_name, "cdev")) { + // found a cdev reference + g_autofree char *cdevpath =3D NULL; + cdevpath =3D g_build_filename(sysfs_path, entry->d_name, NULL); + + if (virFileIsLink(cdevpath) !=3D 1) + continue; + + if (virFileResolveLink(cdevpath, &ccwdevpath) < 0) + continue; + + if (!virFileExists(ccwdevpath)) + continue; + + member =3D g_new0(virCCWGroupMemberType, 1); + + member->ref =3D g_strdup(entry->d_name); + member->device =3D virCCWGroupDeviceDevNodeName("ccw", ccwdevp= ath); + + VIR_APPEND_ELEMENT(*members, *nmembers, member); + } + } + + /* Groups without a member must not exist */ + if (*nmembers =3D=3D 0) + return -1; + + return 0; +} + +void +virCCWGroupTypeQethFree(virCCWGroupTypeQeth *qeth) +{ + if (!qeth) + return; + + VIR_FREE(qeth->card_type); + VIR_FREE(qeth->chpid); +} diff --git a/src/util/virccw.h b/src/util/virccw.h index 80cc716811..a8c9fa83ef 100644 --- a/src/util/virccw.h +++ b/src/util/virccw.h @@ -35,6 +35,18 @@ struct _virCCWDeviceAddress { bool assigned; }; =20 +typedef struct _virCCWGroupMemberType virCCWGroupMemberType; +struct _virCCWGroupMemberType { + char *ref; /* cdev reference */ + char *device; +}; + +typedef struct _virCCWGroupTypeQeth virCCWGroupTypeQeth; +struct _virCCWGroupTypeQeth { + char *card_type; + char *chpid; +}; + bool virCCWDeviceAddressIsValid(virCCWDeviceAddress *addr); bool virCCWDeviceAddressEqual(virCCWDeviceAddress *addr1, virCCWDeviceAddress *addr2); @@ -50,3 +62,13 @@ int virCCWDeviceAddressParseFromString(const char *addre= ss, unsigned int *cssid, unsigned int *ssid, unsigned int *devno); + +void virCCWGroupMemberTypeFree(virCCWGroupMemberType *member); + +int virCCWGroupDeviceGetMembers(const char *sysfs_path, + virCCWGroupMemberType ***members, + size_t *nmembers); + +void virCCWGroupTypeQethFree(virCCWGroupTypeQeth *qeth); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCCWGroupMemberType, virCCWGroupMemberType= Free); diff --git a/tests/nodedevschemadata/ccwgroup_0_0_bd00.xml b/tests/nodedevs= chemadata/ccwgroup_0_0_bd00.xml new file mode 100644 index 0000000000..4e6e540cfc --- /dev/null +++ b/tests/nodedevschemadata/ccwgroup_0_0_bd00.xml @@ -0,0 +1,20 @@ + + ccwgroup_0_0_bd00 + /sys/devices/qeth/0.0.bd00 + computer + + online + 0x0 + 0x0 + 0xbd00 + + ccw_0_0_bd01 + ccw_0_0_bd02 + ccw_0_0_bd00 + + + OSD_10GIG + BD + + + diff --git a/tests/nodedevxml2xmlout/ccwgroup_0_0_bd00.xml b/tests/nodedevx= ml2xmlout/ccwgroup_0_0_bd00.xml new file mode 120000 index 0000000000..a2749e6685 --- /dev/null +++ b/tests/nodedevxml2xmlout/ccwgroup_0_0_bd00.xml @@ -0,0 +1 @@ +../nodedevschemadata/ccwgroup_0_0_bd00.xml \ No newline at end of file diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c index 814a817725..d4d87b3bdc 100644 --- a/tests/nodedevxml2xmltest.c +++ b/tests/nodedevxml2xmltest.c @@ -146,6 +146,7 @@ mymain(void) DO_TEST("mdev_3627463d_b7f0_4fea_b468_f1da537d301b"); DO_TEST_INACTIVE("mdev_3627463d_b7f0_4fea_b468_f1da537d301b"); DO_TEST("ccw_0_0_ffff"); + DO_TEST("ccwgroup_0_0_bd00"); DO_TEST("css_0_0_ffff"); DO_TEST("css_0_0_ffff_channel_dev_addr"); DO_TEST("css_0_0_fffe_mdev_types"); diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index 145faff3e7..3aae7285a9 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -501,6 +501,9 @@ cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd G= _GNUC_UNUSED) case VIR_NODE_DEV_CAP_AP_MATRIX: flags |=3D VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_MATRIX; break; + case VIR_NODE_DEV_CAP_CCWGROUP_DEV: + flags |=3D VIR_CONNECT_LIST_NODE_DEVICES_CAP_CCWGROUP_DEV; + break; case VIR_NODE_DEV_CAP_LAST: break; } --=20 2.47.0