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