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 <[email protected]>
---
 Makefile.am         |   7 +-
 configure.ac        |   3 +
 fcoe-utils.spec.in  |   2 +-
 include/sysfs_hba.h |  64 +++++++++
 lib/sysfs_hba.c     | 388 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 460 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..825127a
--- /dev/null
+++ b/lib/sysfs_hba.c
@@ -0,0 +1,388 @@
+/*
+ * 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, '.');
+               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\n", 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

_______________________________________________
fcoe-devel mailing list
[email protected]
http://lists.open-fcoe.org/mailman/listinfo/fcoe-devel

Reply via email to