File 0009-fcoe-utils-Add-sysfs_hba-to-to-fcoemon_utils.patch of Package fcoe-utils

From 883bf545d51aa3ce0cb712b44db19e3fcc0714f9 Mon Sep 17 00:00:00 2001
From: Johannes Thumshirn <jthumshirn@suse.de>
Date: Thu, 30 Jul 2015 15:06:15 +0200
Subject: [PATCH] fcoe-utils: Add sysfs_hba to to fcoemon_utils

Add sysfs_hba to to fcoemon_utils. This is the 1st part of obsoleting
libHBAAPI2 and libhbalinux2 for fcoe-utils.

Signed-off-by: Johannes Thumshirn <jthumshirn@suse.de>
---
 Makefile.am         |   7 +-
 configure.ac        |   3 +
 fcoe-utils.spec.in  |   2 +-
 include/sysfs_hba.h |  64 +++++++++
 lib/sysfs_hba.c     | 390 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 462 insertions(+), 4 deletions(-)
 create mode 100644 include/sysfs_hba.h
 create mode 100644 lib/sysfs_hba.c

diff --git a/Makefile.am b/Makefile.am
index c6599ef..59c197d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,7 +9,7 @@ AM_CFLAGS = -Wall -Wformat=2 -Werror -Wmissing-prototypes -Wstrict-prototypes
 
 ## rules for building fcoeadm
 fcoeadm_SOURCES = fcoeadm.c fcoeadm_display.c
-fcoeadm_LDADD = lib/libutil.a libopenfcoe.a $(HBAAPI_LIBS)
+fcoeadm_LDADD = lib/libutil.a libopenfcoe.a $(PCIACCESS_LIBS) $(HBAAPI_LIBS)
 fcoeadm_CFLAGS = $(AM_CFLAGS) $(HBAAPI_CFLAGS)
 
 ## rules for building fcoemon
@@ -29,7 +29,8 @@ fipvlan_LDADD = lib/libutil.a
 AUTOMAKE_OPTIONS=subdir-objects
 noinst_LIBRARIES = lib/libutil.a libopenfcoe.a
 lib_libutil_a_SOURCES = lib/fcoe_utils.c lib/sa_log.c lib/sa_select.c \
-	lib/sa_timer.c lib/sa_other.c lib/fip.c lib/rtnetlink.c lib/sa_sys.c
+	lib/sa_timer.c lib/sa_other.c lib/fip.c lib/rtnetlink.c lib/sa_sys.c \
+	lib/sysfs_hba.c
 libopenfcoe_a_SOURCES = libopenfcoe.c
 
 ## header files that need to be distributed
@@ -38,7 +39,7 @@ noinst_HEADERS = fcoeadm_display.h fcoe_clif.h fcoemon.h \
 	include/fc_types.h include/fip.h include/net_types.h include/rtnetlink.h \
 	include/libopenfcoe.h include/scsi_netlink_fc.h include/scsi_netlink.h \
 	include/strarr.h include/fc_ns.h include/fc_gs.h include/fc_els.h include/scsi_bsg_fc.h \
-	include/linux/rtnetlink.h include/linux/types.h include/linux/dcbnl.h
+	include/sysfs_hba.h include/linux/rtnetlink.h include/linux/types.h include/linux/dcbnl.h
 
 ## install configuration file in $(prefix)/etc/fcoe
 fcoe_configdir = ${sysconfdir}/fcoe
diff --git a/configure.ac b/configure.ac
index ef0ffb1..5bafef3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,6 +17,9 @@ AC_SUBST([LLDPAD_CFLAGS])
 PKG_CHECK_MODULES([LIBHBALINUX], [libhbalinux >= 1.0.17])
 AC_SUBST([LIBHBALINUX_CFLAGS])
 
+PKG_CHECK_MODULES([PCIACCESS], [pciaccess])
+AC_SUBST([PCIACCESS_LIBS])
+
 PKG_PROG_PKG_CONFIG
 AC_ARG_WITH([systemdsystemunitdir],
         AS_HELP_STRING([--with-systemdsystemunitdir=DIR],
diff --git a/fcoe-utils.spec.in b/fcoe-utils.spec.in
index d45b84b..dff3fbd 100644
--- a/fcoe-utils.spec.in
+++ b/fcoe-utils.spec.in
@@ -9,7 +9,7 @@ URL:            http://www.open-fcoe.org
 Source0:        http://www.open-fcoe.org/openfc/%{name}-%{version}.tar.gz
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
-BuildRequires:  libHBAAPI-devel lldpad-devel
+BuildRequires:  libHBAAPI-devel lldpad-devel libpciaccess0
 Requires:       lldpad
 Requires(post):   chkconfig
 Requires(preun):  chkconfig initscripts
diff --git a/include/sysfs_hba.h b/include/sysfs_hba.h
new file mode 100644
index 0000000..1e62477
--- /dev/null
+++ b/include/sysfs_hba.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright(c) 2015 SUSE GmbH. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#ifndef _SYSFS_HBA_H
+#define _SYSFS_HBA_H
+
+#include <stdint.h>
+
+
+#define HBA_PORTSPEED_4GBIT		0x0008  /* 4 GBit/sec */
+#define HBA_PORTSPEED_8GBIT		0x0010  /* 8 GBit/sec */
+#define HBA_PORTSPEED_16GBIT		0x0020  /* 16 GBit/sec */
+#define HBA_PORTSPEED_32GBIT		0x0040  /* 32 GBit/sec */
+#define HBA_PORTSPEED_20GBIT		0x0080  /* 20 GBit/sec */
+#define HBA_PORTSPEED_40GBIT		0x0100  /* 40 GBit/sec */
+#define HBA_PORTSPEED_NOT_NEGOTIATED	(1 << 15) /* Speed not established */
+
+struct port_attributes {
+	char device_name[256];
+	char symbolic_name[256];
+	char node_name[256];
+	char port_name[256];
+	char fabric_name[256];
+	char speed[256];
+	char supported_speeds[256];
+	char maxframe_size[256];
+	char port_id[256];
+	char port_state[256];
+};
+
+struct hba_info {
+	char manufacturer[64];
+	char serial_number[64];
+	char model_description[256];
+	char hardware_version[256];
+	char driver_name[256];
+	char driver_version[256];
+	uint32_t nports;
+};
+
+
+int get_number_of_adapters(void);
+struct hba_info *get_hbainfo_by_pcidev(const char *pcidev);
+struct port_attributes *get_port_attribs(const char *host);
+char *get_pci_dev_from_netdev(const char *netdev);
+char *get_host_from_netdev(const char *netdev);
+
+#endif /* _SYSFS_HBA_H */
diff --git a/lib/sysfs_hba.c b/lib/sysfs_hba.c
new file mode 100644
index 0000000..e7f3e0b
--- /dev/null
+++ b/lib/sysfs_hba.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright(c) 2015 SUSE GmbH. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#define _GNU_SOURCE
+
+#include <linux/pci_regs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <pciaccess.h>
+
+#include "sysfs_hba.h"
+#include "fcoemon_utils.h"
+
+#define SYSFS_HOST_DIR	"/sys/class/fc_host"
+#define SYSFS_NET_DIR	"/sys/class/net"
+
+static void get_device_serial_number(struct pci_device *dev,
+				     struct hba_info *info)
+{
+	uint32_t pcie_cap_header;
+	uint32_t dword_high = 0;
+	uint32_t dword_low = 0;
+	uint16_t pcie_cap_id;
+	pciaddr_t offset;
+	uint16_t status;
+	uint8_t cap_ptr;
+	int rc;
+
+	snprintf(info->serial_number, sizeof(info->serial_number), "Unknown");
+
+	rc = pci_device_cfg_read_u16(dev, &status, PCI_STATUS);
+	if (rc) {
+		fprintf(stderr, "Failed reading PCI status register\n");
+		return;
+	}
+
+	if (!(status & PCI_STATUS_CAP_LIST)) {
+		fprintf(stderr, "PCI capabilities are not supported\n");
+		return;
+	}
+
+	rc = pci_device_cfg_read_u8(dev, &cap_ptr,  PCI_CAPABILITY_LIST);
+	if (rc) {
+		fprintf(stderr, "Failed reading PCI Capability List Register\n");
+		return;
+	}
+
+	offset = cap_ptr;
+
+	while (offset) {
+		uint8_t next_cap;
+		uint8_t cap_id;
+
+		rc = pci_device_cfg_read_u8(dev, &cap_id, offset + PCI_CAP_LIST_ID);
+		if (rc) {
+			fprintf(stderr, "Failed reading capability ID at 0x%"PRIx64"\n",
+				offset + PCI_CAP_LIST_ID);
+			return;
+		}
+
+		if (cap_id != PCI_CAP_ID_EXP) {
+			rc = pci_device_cfg_read_u8(dev, &next_cap,
+						offset + PCI_CAP_LIST_NEXT);
+			if (rc) {
+				fprintf(stderr, "Failed reading next capability ID at 0x%"PRIx64"\n",
+				offset + PCI_CAP_LIST_NEXT);
+				return;
+			}
+
+			offset = (pciaddr_t) next_cap;
+			continue;
+		}
+
+		offset = 0x100;
+		do {
+			rc = pci_device_cfg_read_u32(dev, &pcie_cap_header, offset);
+			if (rc) {
+				fprintf(stderr, "Failed reading PCIe config header\n");
+				return;
+			}
+
+			pcie_cap_id = pcie_cap_header & 0xffff;
+
+			if (pcie_cap_id != PCI_EXT_CAP_ID_DSN) {
+				offset = (pciaddr_t) pcie_cap_header >> 20;
+				continue;
+			}
+
+			(void) pci_device_cfg_read_u32(dev, &dword_low, offset + 4);
+			(void) pci_device_cfg_read_u32(dev, &dword_high, offset + 8);
+			snprintf(info->serial_number, sizeof(info->serial_number),
+				"%02X%02X%02X%02X%02X%02X\n",
+				dword_high >> 24, (dword_high >> 16) & 0xff,
+				(dword_high >> 8) & 0xff, (dword_low >> 16) & 0xff,
+				(dword_low >> 8) & 0xff, dword_low & 0xff);
+			break;
+		} while (offset);
+
+		break;
+	}
+}
+
+static void get_pci_device_info(struct pci_device *dev, struct hba_info *info)
+{
+	char *unknown = "unknown";
+	const char *vname;
+	const char *dname;
+	uint8_t revision;
+
+	vname = pci_device_get_vendor_name(dev);
+	if (!vname)
+		vname = unknown;
+
+	strncpy(info->manufacturer, vname, sizeof(info->manufacturer));
+
+	dname = pci_device_get_device_name(dev);
+	if (!dname)
+		dname = unknown;
+
+	strncpy(info->model_description, dname,
+		sizeof(info->model_description));
+
+	pci_device_cfg_read_u8(dev, &revision, PCI_REVISION_ID);
+	snprintf(info->hardware_version, sizeof(info->hardware_version),
+		"%02x", revision);
+
+	info->nports = 1;
+
+	get_device_serial_number(dev, info);
+}
+
+static void get_module_info(const char *pcidev, struct hba_info *info)
+{
+	char buf[1024];
+	char *path;
+	int err;
+
+	strncpy(info->driver_name, "Unknown", sizeof(info->driver_name));
+	strncpy(info->driver_version, "Unknown", sizeof(info->driver_version));
+
+	err = asprintf(&path, "/sys/bus/pci/devices/%s/driver/module", pcidev);
+	if (err == -1)
+		return;
+
+	sa_sys_read_line(path, "version",
+			 info->driver_version, sizeof(info->driver_version));
+
+	err = readlink(path, buf, sizeof(buf) - 1);
+	free(path);
+	if (err == -1)
+		return;
+
+	buf[err] = '\0';
+
+	if (strstr(buf, "module"))
+		strncpy(info->driver_name,
+			strstr(buf, "module") + strlen("module") + 1,
+			sizeof(info->driver_name));
+
+	return;
+}
+
+struct hba_info *get_hbainfo_by_pcidev(const char *pcidev)
+{
+	struct pci_device_iterator *iterator;
+	struct pci_slot_match match;
+	struct pci_device *dev;
+	struct hba_info *info;
+	int rc;
+
+	rc = pci_system_init();
+	if (rc)
+		return NULL;
+
+	info = calloc(1, sizeof(struct hba_info));
+	if (!info)
+		return NULL;
+
+	sscanf(pcidev, "%x:%x:%x.%x", &match.domain, &match.bus, &match.dev, &match.func);
+
+	iterator = pci_slot_match_iterator_create(&match);
+	if (!iterator) {
+		free(info);
+		return NULL;
+	}
+
+	for (;;) {
+		dev = pci_device_next(iterator);
+		if (!dev)
+			break;
+		get_pci_device_info(dev, info);
+		get_module_info(pcidev, info);
+	}
+
+	free(iterator);
+	pci_system_cleanup();
+
+	return info;
+}
+
+struct port_attributes *get_port_attribs(const char *host)
+{
+	struct port_attributes *pa;
+	char *path;
+	int err;
+
+	err = asprintf(&path, "%s/%s", SYSFS_HOST_DIR, host);
+	if (err == -1)
+		return NULL;
+
+	pa = calloc(1, sizeof(*pa));
+	if (!pa)
+		goto free_path;
+
+	strncpy(pa->device_name, host, sizeof(pa->device_name));
+
+	sa_sys_read_line(path, "symbolic_name", pa->symbolic_name, sizeof(pa->symbolic_name));
+	sa_sys_read_line(path, "node_name", pa->node_name, sizeof(pa->node_name));
+	sa_sys_read_line(path, "port_name", pa->port_name, sizeof(pa->port_name));
+	sa_sys_read_line(path, "fabric_name", pa->fabric_name, sizeof(pa->fabric_name));
+	sa_sys_read_line(path, "speed", pa->speed, sizeof(pa->speed));
+	sa_sys_read_line(path, "supported_speeds", pa->supported_speeds, sizeof(pa->supported_speeds));
+	sa_sys_read_line(path, "maxframe_size", pa->maxframe_size, sizeof(pa->maxframe_size));
+	sa_sys_read_line(path, "port_id", pa->port_id, sizeof(pa->port_id));
+	sa_sys_read_line(path, "port_state", pa->port_state, sizeof(pa->port_state));
+
+free_path:
+	free(path);
+
+	return pa;
+}
+
+char *get_pci_dev_from_netdev(const char *netdev)
+{
+	char buf[1024];
+	char *pcidev;
+	char *path;
+	char *cp;
+	int func;
+	int dom;
+	int bus;
+	int dev;
+	int ret;
+
+	ret = asprintf(&path, "%s/%s/device", SYSFS_NET_DIR, netdev);
+	if (ret == -1)
+		return NULL;
+
+	ret = readlink(path, buf, sizeof(buf) - 1);
+	free(path);
+	if (ret == -1) {
+		char realdev[256];
+		char *subif;
+		size_t len;
+
+		subif = strchr(netdev, '.');
+		if (subif == NULL)
+			return NULL;
+		len = strlen(netdev) - strlen(subif);
+		strncpy(realdev, netdev, len);
+		if (realdev[len] != '\0')
+			realdev[len] = '\0';
+
+		ret = asprintf(&path, "%s/%s/lower_%s", SYSFS_NET_DIR,
+			       netdev, realdev);
+		if (ret == -1)
+			return NULL;
+
+		ret = readlink(path, buf, sizeof(buf) -1 );
+		free(path);
+
+		if (ret == -1)
+			return NULL;
+	}
+
+	do {
+		cp = strrchr(buf, '/');
+		if (!cp)
+			break;
+
+		ret = sscanf(cp + 1, "%x:%x:%x.%x", &dom, &bus, &dev, &func);
+		if (ret == 4)
+			break;
+
+		*cp = '\0';
+	} while(cp && cp > buf);
+
+	ret = asprintf(&pcidev, "%04x:%02x:%02x.%x", dom, bus, dev, func);
+	if (ret == -1)
+		return NULL;
+
+	return pcidev;
+}
+
+char *get_host_from_netdev(const char *netdev)
+{
+	struct dirent *dp;
+	char *host = NULL;
+	char *path = NULL;
+	DIR *dir;
+	int ret;
+
+	ret = asprintf(&path, "%s/%s/ctlr_0/", SYSFS_NET_DIR, netdev);
+	if(ret == -1)
+		return NULL;
+
+	dir = opendir(path);
+	free(path);
+	path = NULL;
+
+	if (!dir)
+		return NULL;
+
+	for (dp = readdir(dir); dp != NULL; dp = readdir(dir)) {
+		if (dp->d_name[0] == '.' && dp->d_name[1] == '\0') continue;
+		if (dp->d_name[1] == '.' && dp->d_name[2] == '\0') continue;
+
+		host = strstr(dp->d_name, "host");
+		if (host) {
+			struct stat sb;
+
+			ret = asprintf(&path, "%s/%s/ctlr_0/%s/fc_host/%s",
+				SYSFS_NET_DIR, netdev, host, host);
+			if (ret == -1)
+				goto out_closedir;
+
+			ret = stat(path, &sb);
+			free(path);
+			path = NULL;
+
+			if (ret == -1)
+				host = NULL;
+			break;
+
+		}
+	}
+
+out_closedir:
+	closedir(dir);
+
+	return host ? strdup(host) : NULL;
+}
+
+int get_number_of_adapters(void)
+{
+	struct dirent *dp;
+	int num = 0;
+	DIR *dir;
+
+	dir = opendir(SYSFS_HOST_DIR);
+	if (!dir)
+		return errno;
+
+	for (dp = readdir(dir); dp != NULL; dp = readdir(dir)) {
+		if (dp->d_name[0] == '.' && dp->d_name[1] == '\0') continue;
+		if (dp->d_name[1] == '.' && dp->d_name[2] == '\0') continue;
+
+		if (strstr(dp->d_name, "host"))
+			num++;
+
+	}
+
+	closedir(dir);
+
+	return num;
+}
-- 
2.5.0

openSUSE Build Service is sponsored by