From bb2adfe93476d0c1de2305a0baefd3520329682b Mon Sep 17 00:00:00 2001 From: Bjoern Walk Date: Mon, 22 May 2017 08:38:25 +0200 Subject: [PATCH] node_device: introduce new capability FC_RPORT 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 scsi_target0_0_0 /sys/devices/[...]/host0/rport-0:0-0/target0:0:0 scsi_host0 target0:0:0 rport-0:0-0 0x9d73bc45f0e21a86 Reviewed-by: Boris Fiuczynski Signed-off-by: Bjoern Walk --- docs/schemas/nodedev.rng | 20 ++++++ src/conf/node_device_conf.c | 68 +++++++++++++++++++- src/conf/node_device_conf.h | 7 ++ src/node_device/node_device_driver.c | 5 +- src/node_device/node_device_linux_sysfs.c | 52 +++++++++++++++ src/node_device/node_device_linux_sysfs.h | 2 + src/node_device/node_device_udev.c | 4 +- tests/nodedevschemadata/scsi_target1_0_0.xml | 12 ++++ tests/nodedevxml2xmltest.c | 1 + 9 files changed, 167 insertions(+), 4 deletions(-) create mode 100644 tests/nodedevschemadata/scsi_target1_0_0.xml diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng index 87bfb0c286..5bcf317877 100644 --- a/docs/schemas/nodedev.rng +++ b/docs/schemas/nodedev.rng @@ -458,6 +458,20 @@ + + + fc_remote_port + + + + + + + + + + + scsi_target @@ -466,6 +480,12 @@ + + + + + + diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 22c06f8697..e5947e67b6 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -563,6 +563,16 @@ virNodeDeviceDefFormat(const virNodeDeviceDef *def) case VIR_NODE_DEV_CAP_SCSI_TARGET: virBufferEscapeString(&buf, "%s\n", data->scsi_target.name); + if (data->scsi_target.flags & VIR_NODE_DEV_CAP_FLAG_FC_RPORT) { + virBufferAddLit(&buf, "\n"); + virBufferAdjustIndent(&buf, 2); + virBufferAsprintf(&buf, "%s\n", + data->scsi_target.rport); + virBufferAsprintf(&buf, "%s\n", + data->scsi_target.wwpn); + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "\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); diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index 285841edc0..ca105a3d60 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -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; diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 66faf2b4fc..10f8777b51 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -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: diff --git a/src/node_device/node_device_linux_sysfs.c b/src/node_device/node_device_linux_sysfs.c index ecfe34d419..e02c384035 100644 --- a/src/node_device/node_device_linux_sysfs.c +++ b/src/node_device/node_device_linux_sysfs.c @@ -26,11 +26,13 @@ #include #include +#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) diff --git a/src/node_device/node_device_linux_sysfs.h b/src/node_device/node_device_linux_sysfs.h index 8deea66998..12cfe6341e 100644 --- a/src/node_device/node_device_linux_sysfs.h +++ b/src/node_device/node_device_linux_sysfs.h @@ -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); diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index cc854b5380..f100fd2e54 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -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 index 0000000000..b783c54fea --- /dev/null +++ b/tests/nodedevschemadata/scsi_target1_0_0.xml @@ -0,0 +1,12 @@ + + scsi_target1_0_0 + /sys/devices/css0/0.0.0000/0.0.0000/host1/rport-1:0-0/target1:0:0 + scsi_host0 + + target1:0:0 + + rport-1:0-0 + 0x9d73bc45f0e21a86 + + + diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c index 805deef269..5d9f4724db 100644 --- a/tests/nodedevxml2xmltest.c +++ b/tests/nodedevxml2xmltest.c @@ -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"); -- 2.47.2