--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/components/open-fabrics/libibverbs/solaris_compatibility.c Tue Jul 05 19:16:33 2011 -0700
@@ -0,0 +1,1633 @@
+/*
+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+/*
+ * OFED Solaris wrapper
+ */
+#if defined(__SVR4) && defined(__sun)
+
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/processor.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/param.h>
+#include <sys/ib/adapters/hermon/hermon_ioctl.h>
+#include <sys/ib/adapters/tavor/tavor_ioctl.h>
+
+#include <alloca.h>
+#include "../include/infiniband/arch.h"
+#include "../include/infiniband/verbs.h"
+#include <errno.h>
+#include <pthread.h>
+#include <kstat.h>
+
+/*
+ * The followings will be removed when sol_uverbs_ioctl.h and sol_umad_ioctl.h
+ * are delivered through ON.
+ */
+
+#define UVERBS_IOCTL ('v' << 8)
+
+#define IB_USER_VERBS_SOLARIS_ABI_VERSION 1
+
+typedef enum {
+ UVERBS_IOCTL_GET_HCA_INFO = UVERBS_IOCTL | 0x01
+} uverbs_ioctl_enum_t;
+
+typedef struct sol_uverbs_hca_info_s {
+ char uverbs_hca_psid_string[MAXNAMELEN];
+ char uverbs_hca_ibdev_name[MAXNAMELEN];
+ char uverbs_hca_driver_name[MAXNAMELEN];
+ uint32_t uverbs_hca_driver_instance;
+ uint32_t uverbs_hca_vendorid;
+ uint16_t uverbs_hca_deviceid;
+ uint8_t uverbs_hca_devidx;
+ uint8_t uverbs_hca_pad1[5];
+} sol_uverbs_hca_info_t;
+
+typedef struct sol_uverbs_info_s {
+ int32_t uverbs_abi_version;
+ int32_t uverbs_solaris_abi_version;
+ int16_t uverbs_hca_cnt;
+ int8_t uverbs_pad1[6]; /* Padding for alignment */
+ sol_uverbs_hca_info_t uverbs_hca_info[];
+} sol_uverbs_info_t;
+
+#define UMAD_IOCTL ('m' << 8)
+
+#define IB_USER_MAD_SOLARIS_ABI_VERSION 1
+
+typedef enum {
+ IB_USER_MAD_GET_PORT_INFO = UMAD_IOCTL | 0x01
+} umad_ioctl_enum_t;
+
+typedef struct sol_umad_ioctl_port_info_s {
+ char umad_port_ibdev_name[MAXNAMELEN];
+ uint32_t umad_port_num;
+ uint16_t umad_port_idx;
+ uint8_t umad_port_pad1[2];
+} sol_umad_ioctl_port_info_t;
+
+typedef struct sol_umad_ioctl_info_s {
+ int32_t umad_abi_version;
+ int32_t umad_solaris_abi_version;
+ int16_t umad_port_cnt;
+ int8_t umad_pad1[6]; /* alignment padding */
+ sol_umad_ioctl_port_info_t umad_port_info[];
+} sol_umad_ioctl_info_t;
+
+/* end of sol_uverbs_ioctl.h and sol_umad_ioctl.h contents */
+
+/*
+ * duplicate ABI definitions for HCAs as the HCA abi headers are not
+ * installed in proto.
+ */
+#define MTHCA_UVERBS_ABI_VERSION 1 /* mthca-abi.h */
+#define MLX4_UVERBS_MAX_ABI_VERSION 3 /* mlx4-abi.h */
+#define RDMA_USER_CM_MIN_ABI_VERSION 3 /* rdma_cma_abi.h */
+#define RDMA_USER_CM_MAX_ABI_VERSION 4 /* rdma_cma_abi.h */
+
+#define MLX4 0
+#define MTHCA 1
+#define MAX_HCAS 16
+#define MAX_HCA_PORTS 16
+#define HW_DRIVER_MAX_NAME_LEN 20
+#define UVERBS_KERNEL_SYSFS_NAME_BASE "uverbs"
+#define UMAD_KERNEL_SYSFS_NAME_BASE "umad"
+#define IB_HCA_DEVPATH_PREFIX "/dev/infiniband/hca"
+#define IB_OFS_DEVPATH_PREFIX "/dev/infiniband/ofs"
+#define CONNECTX_NAME "mlx4_"
+#define INFINIHOST_NAME "mthca"
+
+#define MELLANOX_VENDOR_ID 0x15b3
+#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44
+#define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282
+#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278
+#define PCI_DEVICE_ID_MELLANOX_HERMON_SDR 0x6340
+#define PCI_DEVICE_ID_MELLANOX_HERMON_DDR 0x634a
+#define PCI_DEVICE_ID_MELLANOX_HERMON_QDR 0x6354
+#define PCI_DEVICE_ID_MELLANOX_HERMON_DDR_PCIE2 0x6732
+#define PCI_DEVICE_ID_MELLANOX_HERMON_QDR_PCIE2 0x673c
+#define INFINIHOST_DEVICE_ID_2 0x5a45
+#define INFINIHOST_DEVICE_ID_4 0x6279
+
+/*
+ * sol_uverbs_drv_status is the status of what libibverbs knows
+ * about the status of sol_uverbs driver.
+ */
+#define SOL_UVERBS_DRV_STATUS_UNKNOWN 0x0
+#define SOL_UVERBS_DRV_STATUS_LOADED 0x1
+#define SOL_UVERBS_DRV_STATUS_UNLOADED 0x02
+
+static kstat_ctl_t *kc = NULL; /* libkstat cookie */
+static int sol_uverbs_drv_status = SOL_UVERBS_DRV_STATUS_UNKNOWN;
+static int sol_uverbs_minor_dev = -1;
+
+/*
+ * check_path() prefixs
+ */
+typedef enum cp_prefix_e {
+ CP_SOL_UVERBS = 1,
+ CP_DEVICE = 2,
+ CP_D = 3,
+ CP_GIDS = 4,
+ CP_PKEYS = 5,
+ CP_MTHCA = 6,
+ CP_MLX4 = 7,
+ CP_PORTS = 8,
+ CP_UMAD = 9,
+ CP_SLASH = 10,
+ CP_SYS = 11,
+ CP_CLASS = 12,
+ CP_INFINIBAND_VERBS = 13,
+ CP_INFINIBAND = 14,
+ CP_INFINIBAND_MAD = 15,
+ CP_MISC = 16,
+ CP_RDMA_CM = 17
+} cp_prefix_t;
+
+/*
+ * Some temporary cache code, until things are cleaned up as part of DR
+ * work. This will speed up the sysfs emulation.
+ */
+typedef struct ibdev_cache_info_s {
+ uint_t ibd_valid;
+ uint_t ibd_hw_rev;
+ char ibd_node_guid_str[20];
+ char ibd_sys_image_guid[20];
+ char ibd_fw_ver[16];
+ char ibd_name[8];
+ int ibd_boardid_index;
+} ibdev_cache_info_t;
+
+/* tavor and hermon - hence 2 */
+static ibdev_cache_info_t ibdev_cache[2][MAX_HCAS];
+
+typedef struct uverbs_cache_info_s {
+ uint_t uvc_valid;
+ uint_t uvc_ibdev_abi_version;
+ uint_t uvc_vendor_id;
+ uint_t uvc_device_id;
+ int uvc_hca_instance;
+ char uvc_ibdev_name[8];
+ char uvc_ibdev_hca_path[MAXPATHLEN];
+} uverbs_cache_info_t;
+static uverbs_cache_info_t uverbs_dev_cache[MAX_HCAS];
+static int uverbs_abi_version = -1;
+
+typedef struct umad_cache_info_s {
+ uint_t umc_valid;
+ int umc_port;
+ char umc_ib_dev[16];
+} umad_cache_info_t;
+static umad_cache_info_t umad_dev_cache[MAX_HCAS * MAX_HCA_PORTS];
+static int umad_abi_version = -1;
+
+/*
+ * Structure to hold the part number & PSID for an HCA card
+ * This is a sub-set of the file :
+ * /ws/onnv-clone/usr/src/cmd/fwflash/plugins/hdrs/MELLANOX.h
+ */
+typedef struct mlx_mdr_s {
+ char *mlx_pn;
+ char *mlx_psid;
+} mlx_mdr_t;
+
+/*
+ * Magic decoder ring for matching HCA hardware/firmware.
+ * Part Number / PSID / String ID
+ */
+mlx_mdr_t mlx_mdr[] = {
+ /* For failure case, use unknown as "board-id" */
+ { "unknown", "unknown" },
+
+ /* Part No PSID */
+ { "375-3605-01", "SUN0160000001" },
+ { "375-3382-01", "SUN0030000001" },
+ { "375-3481-01", "SUN0040000001" },
+ { "375-3418-01", "SUN0040000001" },
+ { "375-3259-01", "SUN0010000001" },
+ { "375-3259-03", "SUN0010000001" },
+ { "X1289A-Z", "SUN0010010001" },
+ { "375-3548-01", "SUN0060000001" },
+ { "375-3549-01", "SUN0070000001" },
+ { "375-3549-01", "SUN0070130001" },
+ { "375-3481-01", "SUN0050000001" },
+ { "375-3439-01", "SUN0051000001" },
+ { "375-3260-03", "SUN0020000001" },
+ { "375-3605-01", "SUN0160000002" },
+ { "375-3697-01", "SUN0160000002" },
+ { "375-3606-01", "SUN0150000001" },
+ { "375-3606-02", "SUN0150000009" },
+ { "375-3606-03", "SUN0150000009" },
+ { "375-3606-02", "SUN0170000009" },
+ { "375-3696-01", "SUN0170000009" },
+ { "375-3551-05", "SUN0080000001" },
+ { "MHEA28-XS", "MT_0250000001" },
+ { "MHEA28-XSC", "MT_0390110001" },
+ { "MHEA28-XT", "MT_0150000001" },
+ { "MHEA28-XTC", "MT_0370110001" },
+ { "MHGA28-XT", "MT_0150000002" },
+ { "MHGA28-XTC", "MT_0370110002" },
+ { "MHGA28-XTC", "MT_0370130002" },
+ { "MHGA28-XS", "MT_0250000002" },
+ { "MHGA28-XSC", "MT_0390110002" },
+ { "MHGA28-XSC", "MT_0390130002" },
+ { "MHEL-CF128", "MT_0190000001" },
+ { "MHEL-CF128-T", "MT_00A0000001" },
+ { "MTLP25208-CF128T", "MT_00A0000001" },
+ { "MHEL-CF128-TC", "MT_00A0010001" },
+ { "MHEL-CF128-TC", "MT_0140010001" },
+ { "MHEL-CF128-SC", "MT_0190010001" },
+ { "MHEA28-1TC", "MT_02F0110001" },
+ { "MHEA28-1SC", "MT_0330110001" },
+ { "MHGA28-1T", "MT_0200000001" },
+ { "MHGA28-1TC", "MT_02F0110002" },
+ { "MHGA28-1SC", "MT_0330110002" },
+ { "MHGA28-1S", "MT_0430000001" },
+ { "MHEL-CF256-T", "MT_00B0000001" },
+ { "MTLP25208-CF256T", "MT_00B0000001" },
+ { "MHEL-CF256-TC", "MT_00B0010001" },
+ { "MHEA28-2TC", "MT_0300110001" },
+ { "MHEA28-2SC", "MT_0340110001" },
+ { "MHGA28-2T", "MT_0210000001" },
+ { "MHGA28-2TC", "MT_0300110002" },
+ { "MHGA28-2SC", "MT_0340110002" },
+ { "MHEL-CF512-T", "MT_00C0000001" },
+ { "MTLP25208-CF512T", "MT_00C0000001" },
+ { "MHGA28-5T", "MT_0220000001" },
+ { "MHES14-XSC", "MT_0410110001" },
+ { "MHES14-XT", "MT_01F0000001" },
+ { "MHES14-XTC", "MT_03F0110001" },
+ { "MHES18-XS", "MT_0260000001" },
+ { "MHES18-XS", "MT_0260010001" },
+ { "MHES18-XSC", "MT_03D0110001" },
+ { "MHES18-XSC", "MT_03D0120001" },
+ { "MHES18-XSC", "MT_03D0130001" },
+ { "MHES18-XT", "MT_0230000002" },
+ { "MHES18-XT", "MT_0230010002" },
+ { "MHES18-XTC", "MT_03B0110001" },
+ { "MHES18-XTC", "MT_03B0120001" },
+ { "MHES18-XTC", "MT_03B0140001" },
+ { "MHGS18-XS", "MT_0260000002" },
+ { "MHGS18-XSC", "MT_03D0110002" },
+ { "MHGS18-XSC", "MT_03D0120002" },
+ { "MHGS18-XSC", "MT_03D0130002" },
+ { "MHGS18-XT", "MT_0230000001" },
+ { "MHGS18-XTC", "MT_03B0110002" },
+ { "MHGS18-XTC", "MT_03B0120002" },
+ { "MHGS18-XTC", "MT_03B0140002" },
+ { "MHXL-CF128", "MT_0180000001" },
+ { "MHXL-CF128-T", "MT_0030000001" },
+ { "MTLP23108-CF128T", "MT_0030000001" },
+ { "MHET2X-1SC", "MT_0280110001" },
+ { "MHET2X-1SC", "MT_0280120001" },
+ { "MHET2X-1TC", "MT_0270110001" },
+ { "MHET2X-1TC", "MT_0270120001" },
+ { "MHXL-CF256-T", "MT_0040000001" },
+ { "MHET2X-2SC", "MT_02D0110001" },
+ { "MHET2X-2SC", "MT_02D0120001" },
+ { "MHET2X-2TC", "MT_02B0110001" },
+ { "MHET2X-2TC", "MT_02B0120001" },
+ { "MHX-CE128-T", "MT_0000000001" },
+ { "MTPB23108-CE128", "MT_0000000001" },
+ { "MHX-CE256-T", "MT_0010000001" },
+ { "MTPB23108-CE256", "MT_0010000001" },
+ { "MHX-CE512-T", "MT_0050000001" },
+ { "MTPB23108-CE512", "MT_0050000001" },
+ { "MHEH28-XSC", "MT_04C0110001" },
+ { "MHEH28-XSC", "MT_04C0130005" },
+ { "MHEH28-XTC", "MT_04A0110001" },
+ { "MHEH28-XTC", "MT_04A0130005" },
+ { "MHGH28-XSC", "MT_04C0110002" },
+ { "MHGH28-XSC", "MT_04C0120002" },
+ { "MHGH28-XSC", "MT_04C0140005" },
+ { "MHGH28-XTC", "MT_04A0110002" },
+ { "MHGH28-XTC", "MT_04A0120002" },
+ { "MHGH28-XTC", "MT_04A0140005" },
+ { "MHGH29-XSC", "MT_0A60110002" },
+ { "MHGH29-XSC", "MT_0A60120005" },
+ { "MHGH29-XTC", "MT_0A50110002" },
+ { "MHGH29-XTC", "MT_0A50120005" },
+ { "MHJH29-XTC", "MT_04E0110003" },
+ { "MHJH29-XSC", "MT_0500120005" },
+ { "MHQH29-XTC", "MT_04E0120005" },
+ { "MHQH19-XTC", "MT_0C40110009" },
+ { "MHQH29-XTC", "MT_0BB0110003" },
+ { "MHQH29-XTC", "MT_0BB0120003" },
+ { "MHEH28B-XSR", "MT_0D10110001" },
+ { "MHEH28B-XTR", "MT_0D20110001" },
+ { "MHGH28B-XSR", "MT_0D10110002" },
+ { "MHGH28B-XTR", "MT_0D20110002" },
+ { "MHGH18B-XTR", "MT_0D30110002" },
+ { "MNEH28B-XSR", "MT_0D40110004" },
+ { "MNEH28B-XTR", "MT_0D50110004" },
+ { "MNEH29B-XSR", "MT_0D40110010" },
+ { "MNEH29B-XTR", "MT_0D50110010" },
+ { "MHGH29B-XSR", "MT_0D10110008" },
+ { "MHGH29B-XTR", "MT_0D20110008" },
+ { "MHJH29B-XSR", "MT_0D10110009" },
+ { "MHJH29B-XSR", "MT_0D10120009" },
+ { "MHJH29B-XTR", "MT_0D20110009" },
+ { "MHJH29B-XTR", "MT_0D20120009" },
+ { "MHGH19B-XSR", "MT_0D60110008" },
+ { "MHGH19B-XTR", "MT_0D30110008" },
+ { "MHJH19B-XTR", "MT_0D30110009" },
+ { "MHQH29B-XSR", "MT_0D70110009" },
+ { "MHQH29B-XTR", "MT_0D80110009" },
+ { "MHQH29B-XTR", "MT_0D80120009" },
+ { "MHQH29B-XTR", "MT_0D80130009" },
+ { "MHQH29B-XTR", "MT_0E30110009" },
+ { "MHRH29B-XSR", "MT_0D70110008" },
+ { "MHRH29B-XTR", "MT_0D80110008" },
+ { "MHQH19B-XTR", "MT_0D90110009" },
+ { "MHRH19B-XSR", "MT_0E40110009" },
+ { "MHRH19B-XTR", "MT_0D90110008" },
+ { "MNPH28C-XSR", "MT_0DA0110004" },
+ { "MNPH28C-XTR", "MT_0DB0110004" },
+ { "MNPH29C-XSR", "MT_0DA0110010" },
+ { "MNPH29C-XTR", "MT_0DB0110010" },
+ { "MNPH29C-XTR", "MT_0DB0120010" },
+ { "MNPH29C-XTR", "MT_0DB0130010" },
+ { "MNZH29-XSR", "MT_0DC0110009" },
+ { "MNZH29-XTR", "MT_0DD0110009" },
+ { "MNZH29-XTR", "MT_0DD0120009" },
+ { "MHQH19B-XNR", "MT_0DF0110009" },
+ { "MHQH19B-XNR", "MT_0DF0120009" },
+ { "MNQH19-XTR", "MT_0D80110017" },
+ { "MNQH19C-XTR", "MT_0E20110017" },
+ { "MHZH29B-XSR", "MT_0E80110009" },
+ { "MHZH29B-XTR", "MT_0E90110009" },
+ { "MHZH29B-XTR", "MT_0E90110009" },
+ { "MHQA19-XTR", "MT_0EA0110009" },
+ { "MHRA19-XTR", "MT_0EB0110008" },
+ { "MHQH29C-XTR", "MT_0EF0110009" },
+ { "MHQH29C-XSR", "MT_0F00110009" },
+ { "MHRH29C-XTR", "MT_0F10110008" },
+ { "MHRH29C-XSR", "MT_0F20110008" },
+ { "MHPH29D-XTR", "MT_0F30110010" },
+ { "MHPH29D-XSR", "MT_0F40110010" },
+ { "MNPA19-XTR", "MT_0F60110010" },
+ { "MNPA19-XSR", "MT_0F70110010" },
+
+ /* Ethernet cards */
+ { "MNEH28B-XTR", "MT_0D50110004" },
+ { "MNEH29B-XSR", "MT_0D40110010" },
+ { "MNEH29B-XTR", "MT_0D50110010" },
+ { "MNPH28C-XSR", "MT_0DA0110004" },
+ { "MNPH28C-XTR", "MT_0DB0110004" },
+ { "MNPH29C-XSR", "MT_0DA0110010" },
+ { "MNPH29C-XTR", "MT_0DB0110010" },
+ { "X6275 M2 10GbE", "X6275M2_10G" }
+};
+
+/* Get mlx_mdr[] array size */
+#define MLX_SZ_MLX_MDR sizeof (mlx_mdr)
+#define MLX_SZ_MLX_MDR_STRUCT sizeof (mlx_mdr[0])
+#define MLX_MAX_ID (MLX_SZ_MLX_MDR / MLX_SZ_MLX_MDR_STRUCT)
+
+pthread_once_t oneTimeInit = PTHREAD_ONCE_INIT;
+static int umad_cache_cnt = 0;
+static int ibdev_cache_cnt = 0;
+static int uverbs_cache_cnt = 0;
+static boolean_t initialized = B_FALSE;
+static boolean_t umad_cache_initialized = B_FALSE;
+static boolean_t ibdev_cache_initialized = B_FALSE;
+static boolean_t uverbs_cache_initialized = B_FALSE;
+static pthread_mutex_t umad_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t ibdev_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t uverbs_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void __attribute__((constructor))solaris_init(void);
+void __attribute__((destructor))solaris_fini(void);
+
+void
+solaris_init(void)
+{
+ while ((kc = kstat_open()) == NULL) {
+ if (errno == EAGAIN)
+ (void) poll(NULL, 0, 200);
+ else
+ fprintf(stderr, "cannot open /dev/kstat: %s\n",
+ strerror(errno));
+ }
+}
+
+void
+solaris_fini(void)
+{
+ (void) kstat_close(kc);
+}
+
+static int
+umad_cache_add(uint_t dev_num, int port, char *ibdev)
+{
+ if ((dev_num >= (MAX_HCAS * MAX_HCA_PORTS)) ||
+ (umad_cache_cnt >= (MAX_HCAS * MAX_HCA_PORTS))) {
+ fprintf(stderr, "dev %d: exceeds umad cache size\n", dev_num);
+ return (1);
+ }
+
+ umad_dev_cache[dev_num].umc_port = port;
+ strcpy(umad_dev_cache[dev_num].umc_ib_dev, ibdev);
+ umad_dev_cache[dev_num].umc_valid = 1;
+ umad_cache_cnt++;
+ return (0);
+}
+
+static int
+ibdev_cache_add(uint_t dev_num, ibdev_cache_info_t *info_p)
+{
+ if ((dev_num >= MAX_HCAS) || (ibdev_cache_cnt >= (MAX_HCAS * 2))) {
+ fprintf(stderr, "dev %d: exceeds hca cache size\n", dev_num);
+ return (1);
+ }
+
+ if (!(strncmp(info_p->ibd_name, "mlx4", 4))) {
+ memcpy(&(ibdev_cache[MLX4][dev_num]), info_p,
+ sizeof (ibdev_cache_info_t));
+ ibdev_cache[MLX4][dev_num].ibd_valid = 1;
+ } else {
+ memcpy(&(ibdev_cache[MTHCA][dev_num]), info_p,
+ sizeof (ibdev_cache_info_t));
+ ibdev_cache[MTHCA][dev_num].ibd_valid = 1;
+ }
+
+ ibdev_cache_cnt++;
+ return (0);
+}
+
+static int
+uverbs_cache_add(uint_t dev_num, uverbs_cache_info_t *info_p)
+{
+ if ((dev_num >= MAX_HCAS) || (uverbs_cache_cnt >= MAX_HCAS)) {
+ fprintf(stderr, "dev %d: exceeds uverbs cache size\n", dev_num);
+ return (1);
+ }
+
+ memcpy(&(uverbs_dev_cache[dev_num]), info_p,
+ sizeof (uverbs_cache_info_t));
+
+ uverbs_dev_cache[dev_num].uvc_valid = 1;
+ uverbs_cache_cnt++;
+ return (0);
+}
+
+static int
+ibdev_cache_init()
+{
+ ibdev_cache_info_t info;
+ struct ibv_device **root_dev_list, **dev_list = NULL;
+ struct ibv_context *ctx = NULL;
+ struct ibv_device_attr device_attr;
+ int i, num_dev, dev_num, ret = 1;
+ uint64_t guid;
+ const char *p, *ibdev;
+
+
+ root_dev_list = dev_list = ibv_get_device_list(&num_dev);
+ if (!dev_list) {
+ fprintf(stderr, "No HCA devices found");
+ goto error_exit1;
+ }
+
+ for (i = 0; i < num_dev; i++, dev_list++) {
+
+ if (!(ctx = ibv_open_device(*dev_list))) {
+ fprintf(stderr, "failed to open device %p\n",
+ *dev_list);
+ goto error_exit2;
+ }
+
+ if (ibv_query_device(ctx, &device_attr)) {
+ fprintf(stderr, "failed to query device %p\n", ctx);
+ goto error_exit3;
+ }
+
+ guid = ntohll(device_attr.node_guid);
+ sprintf(info.ibd_node_guid_str, "%04x:%04x:%04x:%04x",
+ (unsigned)(guid >> 48) & 0xffff,
+ (unsigned)(guid >> 32) & 0xffff,
+ (unsigned)(guid >> 16) & 0xffff,
+ (unsigned)(guid >> 0) & 0xffff);
+
+ guid = ntohll(device_attr.sys_image_guid);
+ sprintf(info.ibd_sys_image_guid, "%04x:%04x:%04x:%04x",
+ (unsigned)(guid >> 48) & 0xffff,
+ (unsigned)(guid >> 32) & 0xffff,
+ (unsigned)(guid >> 16) & 0xffff,
+ (unsigned)(guid >> 0) & 0xffff);
+
+ (void) strcpy(info.ibd_fw_ver, device_attr.fw_ver);
+ info.ibd_hw_rev = device_attr.hw_ver;
+
+ ibdev = ibv_get_device_name(*dev_list);
+ p = ibdev + (strlen(ibdev)-1);
+ dev_num = atoi(p);
+ (void) strcpy(info.ibd_name, ibdev);
+
+ info.ibd_boardid_index = -1;
+
+ if (ibdev_cache_add(dev_num, &info)) {
+ fprintf(stderr, "failed to add dev %d to ibdev cache\n",
+ dev_num);
+ goto error_exit3;
+ }
+ }
+
+ ret = 0;
+
+ /* clean up and Return */
+error_exit3:
+ if (ctx)
+ ibv_close_device(ctx);
+error_exit2:
+ if (root_dev_list)
+ ibv_free_device_list(root_dev_list);
+error_exit1:
+ return (ret);
+}
+
+static int
+uverbs_cache_init()
+{
+ uverbs_cache_info_t info;
+ int dev_num, fd, i, bufsize, hca_cnt;
+ char uverbs_devpath[MAXPATHLEN];
+ sol_uverbs_info_t *uverbs_infop;
+ sol_uverbs_hca_info_t *hca_infop;
+ char *buf;
+
+ snprintf(uverbs_devpath, MAXPATHLEN, "%s/%s%d",
+ IB_OFS_DEVPATH_PREFIX, UVERBS_KERNEL_SYSFS_NAME_BASE,
+ sol_uverbs_minor_dev);
+
+ /*
+ * using the first sol_uverbs minor node that can be opened to get
+ * all the HCA information
+ */
+ if ((fd = open(uverbs_devpath, O_RDWR)) < 0) {
+ fprintf(stderr, "sol_uverbs failed to open: %s\n",
+ strerror(errno));
+ goto error_exit1;
+ }
+
+ bufsize = sizeof(sol_uverbs_info_t) + sizeof(sol_uverbs_hca_info_t) *
+ MAX_HCAS;
+
+ buf = malloc(bufsize);
+ memset(buf, 0, bufsize);
+ uverbs_infop = (sol_uverbs_info_t *)buf;
+ uverbs_infop->uverbs_hca_cnt = MAX_HCAS;
+
+ if (ioctl(fd, UVERBS_IOCTL_GET_HCA_INFO, uverbs_infop) != 0) {
+ fprintf(stderr, "sol_uverbs ioctl failed: %s\n",
+ strerror(errno));
+
+ goto error_exit2;
+ }
+
+ if (uverbs_infop->uverbs_solaris_abi_version !=
+ IB_USER_VERBS_SOLARIS_ABI_VERSION) {
+ fprintf(stderr, "sol_uverbs solaris_abi_version !="
+ "IB_USER_VERBS_SOLARIS_ABI_VERSION : %d\n",
+ uverbs_infop->uverbs_solaris_abi_version);
+ goto error_exit2;
+ }
+
+ hca_cnt = uverbs_infop->uverbs_hca_cnt; /* hca count returned */
+ hca_infop = uverbs_infop->uverbs_hca_info;
+
+ if (uverbs_abi_version == -1)
+ uverbs_abi_version = uverbs_infop->uverbs_abi_version;
+
+ for (i = 0; i < hca_cnt; i++, hca_infop++) {
+ info.uvc_vendor_id = hca_infop->uverbs_hca_vendorid;
+ info.uvc_device_id = hca_infop->uverbs_hca_deviceid;
+ info.uvc_hca_instance =
+ hca_infop->uverbs_hca_driver_instance;
+
+ snprintf(info.uvc_ibdev_hca_path, sizeof (info.uvc_ibdev_hca_path),
+ "%s/%s%d", IB_HCA_DEVPATH_PREFIX,
+ hca_infop->uverbs_hca_driver_name,
+ hca_infop->uverbs_hca_driver_instance);
+
+ if (! strncmp(hca_infop->uverbs_hca_ibdev_name, "mlx4_", 5))
+ info.uvc_ibdev_abi_version =
+ MLX4_UVERBS_MAX_ABI_VERSION;
+ else
+ info.uvc_ibdev_abi_version = MTHCA_UVERBS_ABI_VERSION;
+
+ strcpy(info.uvc_ibdev_name, hca_infop->uverbs_hca_ibdev_name);
+
+ dev_num = hca_infop->uverbs_hca_devidx;
+ if (uverbs_cache_add(dev_num, &info)) {
+ fprintf(stderr, "failed to add dev %d to uverbs "
+ "cache\n", dev_num);
+ goto error_exit2;
+ }
+ }
+
+ free(buf);
+ close(fd);
+ return (1);
+
+error_exit2:
+ free(buf);
+ close(fd);
+
+error_exit1:
+ return(0);
+}
+
+static int
+umad_cache_init()
+{
+ int i, fd, minor;
+ int save_errno = 0;
+ int port_cnt, bufsize;
+ char umad_devpath[MAXPATHLEN], *buf;
+ sol_umad_ioctl_info_t *umad_infop;
+ sol_umad_ioctl_port_info_t *port_infop;
+
+ for (minor = 0; minor < MAX_HCAS * MAX_HCA_PORTS; minor++) {
+ snprintf(umad_devpath, MAXPATHLEN, "%s/%s%d",
+ IB_OFS_DEVPATH_PREFIX, UMAD_KERNEL_SYSFS_NAME_BASE,
+ minor);
+
+ if ((fd = open(umad_devpath, O_RDWR)) > 0)
+ break;
+
+ if ((! save_errno) && (errno != ENOENT))
+ save_errno = errno;
+ }
+
+ if ((minor == MAX_HCAS * MAX_HCA_PORTS) && (fd < 0)) {
+ if (! save_errno)
+ save_errno = errno;
+ fprintf(stderr, "failed to open sol_umad: %s\n",
+ strerror(save_errno));
+ return (0);
+ }
+
+ bufsize = sizeof(sol_umad_ioctl_info_t) +
+ (sizeof(sol_umad_ioctl_port_info_t) * MAX_HCAS * MAX_HCA_PORTS);
+
+ buf = malloc(bufsize);
+ memset(buf, 0, bufsize);
+ umad_infop = (sol_umad_ioctl_info_t *)buf;
+ umad_infop->umad_port_cnt = MAX_HCAS * MAX_HCA_PORTS;
+
+ if (ioctl(fd, IB_USER_MAD_GET_PORT_INFO, umad_infop) != 0) {
+ fprintf(stderr, "sol_umad ioctl failed: %s\n",
+ strerror(errno));
+
+ goto error_exit;
+ }
+
+ if (umad_infop->umad_solaris_abi_version !=
+ IB_USER_MAD_SOLARIS_ABI_VERSION) {
+ fprintf(stderr, "sol_umad solaris_abi_version !="
+ "IB_USER_MAD_SOLARIS_ABI_VERSION : %d\n",
+ umad_infop->umad_solaris_abi_version);
+ goto error_exit;
+ }
+
+ /*
+ * set port_cnt to the number of total ports for all HCAs returned
+ */
+ port_cnt = umad_infop->umad_port_cnt;
+ port_infop = umad_infop->umad_port_info;
+
+ if (umad_abi_version == -1)
+ umad_abi_version = umad_infop->umad_abi_version;
+
+ for (i = 0; i < port_cnt; i++, port_infop++) {
+ if (umad_cache_add(port_infop->umad_port_idx,
+ port_infop->umad_port_num,
+ port_infop->umad_port_ibdev_name)) {
+ fprintf(stderr, "failed to add dev %d to umad cache",
+ port_infop->umad_port_idx);
+ goto error_exit;
+ }
+ }
+
+ free(buf);
+ close(fd);
+ return (1);
+
+error_exit:
+ free(buf);
+ close(fd);
+ return (0);
+}
+
+void
+initialize(void)
+{
+ int fd, minor;
+ char uverbs_devpath[MAXPATHLEN];
+
+ /*
+ * find the first sol_uverbs minor node that can be opened successfully
+ * and set sol_uverbs_mino_dev to that minor no.
+ */
+ for (minor = 0; minor < MAX_HCAS; minor++) {
+ snprintf(uverbs_devpath, MAXPATHLEN, "%s/%s%d",
+ IB_OFS_DEVPATH_PREFIX, UVERBS_KERNEL_SYSFS_NAME_BASE,
+ minor);
+
+ if ((fd = open(uverbs_devpath, O_RDWR)) < 0) {
+ continue;
+ } else {
+ sol_uverbs_drv_status = SOL_UVERBS_DRV_STATUS_LOADED;
+ sol_uverbs_minor_dev = minor;
+ close(fd);
+ break;
+ }
+ }
+
+ /*
+ * All minor nodes failed to open, so set sol_uverbs_drv_status to
+ * SOL_UVERBS_DRV_STATUS_UNLOADED to reflect that
+ */
+ if (minor == MAX_HCAS && sol_uverbs_minor_dev == -1) {
+ sol_uverbs_drv_status = SOL_UVERBS_DRV_STATUS_UNLOADED;
+ return;
+ }
+
+ memset(&uverbs_dev_cache, 0, (sizeof (uverbs_cache_info_t) * MAX_HCAS));
+ memset(&ibdev_cache, 0, (sizeof (ibdev_cache_info_t) * MAX_HCAS * 2));
+ memset(&umad_dev_cache, 0,
+ (sizeof (umad_cache_info_t) * MAX_HCAS * MAX_HCA_PORTS));
+
+ initialized = B_TRUE;
+}
+
+/*
+ * Some sysfs emulation software
+ */
+
+
+/*
+ * Check whether a path starts with prefix, and if it does, remove it
+ * from the string. The prefix can also contain one %d scan argument.
+ */
+static int
+check_path(char *path, cp_prefix_t prefix, unsigned int *arg)
+{
+ int ret, pos = 0;
+
+ switch (prefix) {
+ case CP_SOL_UVERBS:
+ ret = sscanf(path, "uverbs%d%n/", arg,
+ &pos);
+ break;
+ case CP_DEVICE:
+ ret = sscanf(path, "device%n/", &pos);
+ break;
+ case CP_D:
+ ret = sscanf(path, "%d%n/", arg, &pos);
+ break;
+ case CP_GIDS:
+ ret = sscanf(path, "gids%n/", &pos);
+ break;
+ case CP_PKEYS:
+ ret = sscanf(path, "pkeys%n/", &pos);
+ break;
+ case CP_MTHCA:
+ ret = sscanf(path, "mthca%d%n/", arg, &pos);
+ break;
+ case CP_MLX4:
+ ret = sscanf(path, "mlx4_%d%n/", arg, &pos);
+ break;
+ case CP_PORTS:
+ ret = sscanf(path, "ports%n/", &pos);
+ break;
+ case CP_UMAD:
+ ret = sscanf(path, "umad%d%n/", arg, &pos);
+ break;
+ case CP_SLASH:
+ ret = sscanf(path, "%n/", &pos);
+ break;
+ case CP_SYS:
+ ret = sscanf(path, "sys%n/", &pos);
+ break;
+ case CP_CLASS:
+ ret = sscanf(path, "class%n/", &pos);
+ break;
+ case CP_INFINIBAND_VERBS:
+ ret = sscanf(path, "infiniband_verbs%n/", &pos);
+ break;
+ case CP_INFINIBAND:
+ ret = sscanf(path, "infiniband%n/", &pos);
+ break;
+ case CP_INFINIBAND_MAD:
+ ret = sscanf(path, "infiniband_mad%n/", &pos);
+ break;
+ case CP_MISC:
+ ret = sscanf(path, "misc%n/", &pos);
+ break;
+ case CP_RDMA_CM:
+ ret = sscanf(path, "rdma_cm%n/", &pos);
+ break;
+ default:
+ /* Unkown prefix */
+ return (0);
+ }
+
+ if (path[pos] == '/') {
+ /* Some requests have several consecutive slashes. */
+ while (path[pos] == '/')
+ pos ++;
+
+ memmove(path, &path[pos], strlen(path)-pos+1);
+ return (1);
+ }
+
+ return (0);
+}
+
+static ibdev_cache_info_t *
+get_device_info(const char *devname)
+{
+ ibdev_cache_info_t *info;
+ const char *p = devname;
+ int dev_num;
+
+ if (pthread_mutex_lock(&ibdev_cache_mutex) != 0) {
+ fprintf(stderr, "failed: to acquire ibdev_cache_mutex %s\n",
+ strerror(errno));
+ return (NULL);
+ }
+
+ if (!ibdev_cache_initialized) {
+ if (ibdev_cache_init()) {
+ (void) pthread_mutex_unlock(&ibdev_cache_mutex);
+ fprintf(stderr, "failed to init ibdev_cache\n");
+ return (NULL);
+ } else {
+ ibdev_cache_initialized = B_TRUE;
+ }
+ }
+ (void) pthread_mutex_unlock(&ibdev_cache_mutex);
+
+ p = p+(strlen(p)-1);
+ dev_num = atoi(p);
+
+ if (dev_num >= MAX_HCAS) {
+ fprintf(stderr, "Invalid device %s\n", devname);
+ return (NULL);
+ }
+
+ if (strncmp(devname, "mlx4", 4) == 0) {
+ if (ibdev_cache[MLX4][dev_num].ibd_valid)
+ info = &(ibdev_cache[MLX4][dev_num]);
+ else
+ info = NULL;
+ } else {
+ if (ibdev_cache[MTHCA][dev_num].ibd_valid)
+ info = &(ibdev_cache[MTHCA][dev_num]);
+ else
+ info = NULL;
+ }
+
+ return (info);
+}
+
+/*
+ * Get the IB user verbs port info attributes for the specified device/port.
+ * If the address of a gid pointer is passed for "gid_table", the memory
+ * will be allocated and the ports gid table and returned as well. The caller
+ * must free this memory on successful completion. If the address of a
+ * pkey pointer is passed for "pkey_table", the memory will be allocated
+ * and the ports pkey table returned as well. The caller must free this
+ * memory on successful completion.
+ */
+static int
+get_port_info(const char *devname, uint8_t port_num,
+ struct ibv_port_attr *port_attr, union ibv_gid **gid_table,
+ uint16_t **pkey_table)
+{
+ struct ibv_device **root_dev_list, **dev_list = NULL;
+ struct ibv_context *ctx = NULL;
+ union ibv_gid *gids = NULL;
+ uint16_t *pkeys = NULL;
+ int i, num_dev, rv, ret = 1;
+
+ root_dev_list = dev_list = ibv_get_device_list(&num_dev);
+ if (!dev_list) {
+ fprintf(stderr, "No HCA devices found\n");
+ goto error_exit1;
+ }
+
+ for (i = 0; i < num_dev; i++, dev_list++) {
+ if (strcmp(ibv_get_device_name(*dev_list), devname) == 0) {
+ break;
+ }
+ }
+
+ if (i == num_dev) {
+ fprintf(stderr, "failed to find %s\n", devname);
+ goto error_exit2;
+ }
+
+ if (!(ctx = ibv_open_device(*dev_list))) {
+ fprintf(stderr, "failed to open device %p\n", *dev_list);
+ goto error_exit2;
+ }
+
+ if (ibv_query_port(ctx, port_num, port_attr)) {
+ fprintf(stderr, "failed to query dev %p, port %d\n",
+ ctx, port_num);
+ goto error_exit3;
+ }
+
+ if (gid_table) {
+ *gid_table = NULL;
+ gids = malloc(sizeof (union ibv_gid) * port_attr->gid_tbl_len);
+ if (!gids)
+ goto error_exit3;
+ /*
+ * set high bit of port_num, and try get all gids in one go.
+ */
+ port_num |= 0x80;
+ rv = ibv_query_gid(ctx, port_num, port_attr->gid_tbl_len, gids);
+
+ if (rv != 0) {
+ /*
+ * Quering all gids didn't work try one at a time.
+ */
+ port_num &= 0x7f;
+
+ for (i = 0; i < port_attr->gid_tbl_len; i++) {
+ if (ibv_query_gid(ctx, port_num, i, &gids[i]))
+ goto error_exit4;
+ }
+ }
+ *gid_table = gids;
+ gids = NULL;
+ }
+
+ if (pkey_table) {
+ *pkey_table = NULL;
+ pkeys = malloc(sizeof (uint16_t) * port_attr->pkey_tbl_len);
+ if (!pkeys)
+ goto error_exit4;
+
+ port_num |= 0x80;
+
+ rv = ibv_query_pkey(ctx, port_num, port_attr->pkey_tbl_len,
+ pkeys);
+
+ if (rv != 0) {
+ /*
+ * Quering all gids didn't work try one at a time.
+ */
+ port_num &= 0x7f;
+
+ for (i = 0; i < port_attr->pkey_tbl_len; i++) {
+ if (ibv_query_pkey(ctx, port_num, i, &pkeys[i]))
+ goto error_exit5;
+ }
+ }
+ *pkey_table = pkeys;
+ pkeys = NULL;
+ }
+
+ ret = 0;
+
+ /*
+ * clean up and Return
+ */
+error_exit5:
+ if (pkeys)
+ free(pkeys);
+error_exit4:
+ if (gids)
+ free(gids);
+error_exit3:
+ if (ctx)
+ ibv_close_device(ctx);
+error_exit2:
+ if (root_dev_list)
+ ibv_free_device_list(root_dev_list);
+error_exit1:
+ return (ret);
+}
+
+/*
+ * In Solaris environments, the underlying hardware driver is opened to
+ * perform the memory mapping operations of kernel allocated memory
+ * into the users address space.
+ */
+int
+ibv_open_mmap_driver(char *dev_name)
+{
+ int fd;
+#ifndef _LP64
+ int tmpfd;
+#endif
+ int uverbs_indx;
+
+ /*
+ * Map the user verbs device (uverbs) to the associated
+ * hca device.
+ */
+ uverbs_indx = strtol(dev_name + strlen(UVERBS_KERNEL_SYSFS_NAME_BASE),
+ NULL, 0);
+ if (uverbs_indx >= MAX_HCAS) {
+ fprintf(stderr, "Invalid device %s\n", dev_name);
+ goto err_dev;
+ }
+
+ if (!uverbs_dev_cache[uverbs_indx].uvc_valid) {
+ fprintf(stderr, "Invalid Device %s\n", dev_name);
+ goto err_dev;
+ }
+
+ fd = open(uverbs_dev_cache[uverbs_indx].uvc_ibdev_hca_path, O_RDWR);
+ if (fd < 0) {
+ goto err_dev;
+ }
+
+#ifndef _LP64
+ /*
+ * libc can't handle fd's greater than 255, in order to
+ * ensure that these values remain available make fd > 255.
+ * Note: not needed for LP64
+ */
+ tmpfd = fcntl(fd, F_DUPFD, 256);
+ if (tmpfd >= 0) {
+ (void) close(fd);
+ fd = tmpfd;
+ }
+#endif /* _LP64 */
+
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
+ fprintf(stderr, "FD_CLOEXEC failed: %s\n", strerror(errno));
+ goto err_close;
+ }
+ return (fd);
+
+err_close:
+ close(fd);
+err_dev:
+ return (-1);
+}
+
+static int
+infiniband_verbs(char *path, char *buf, size_t size)
+{
+ unsigned int device_num;
+ int len = -1;
+ uverbs_cache_info_t *info_p;
+
+ if (pthread_mutex_lock(&uverbs_cache_mutex) != 0) {
+ fprintf(stderr, "failed: to acquire uverbs_cache_mutex %s\n",
+ strerror(errno));
+ goto exit;
+ }
+
+ if (!uverbs_cache_initialized) {
+ if (uverbs_cache_init())
+ uverbs_cache_initialized = B_TRUE;
+ else
+ goto exit;
+ }
+ (void) pthread_mutex_unlock(&uverbs_cache_mutex);
+
+ if (check_path(path, CP_SOL_UVERBS, &device_num)) {
+
+ if (device_num >= MAX_HCAS) {
+ fprintf(stderr, "Invalid path%s\n", path);
+ goto exit;
+ }
+
+ if (!uverbs_dev_cache[device_num].uvc_valid) {
+ goto exit;
+ }
+
+ info_p = &uverbs_dev_cache[device_num];
+
+ if (check_path(path, CP_DEVICE, NULL)) {
+ /*
+ * Under Linux, this is a link to the PCI device entry
+ * in /sys/devices/pci...../....
+ */
+ if (strcmp(path, "vendor") == 0) {
+ len = 1 + sprintf(buf, "0x%x",
+ info_p->uvc_vendor_id);
+ } else if (strcmp(path, "device") == 0) {
+ len = 1 + sprintf(buf, "0x%x",
+ info_p->uvc_device_id);
+ }
+ } else if (strcmp(path, "ibdev") == 0) {
+ len = 1 + sprintf(buf, "%s",
+ info_p->uvc_ibdev_name);
+ } else if (strcmp(path, "abi_version") == 0) {
+ len = 1 + sprintf(buf, "%d",
+ info_p->uvc_ibdev_abi_version);
+ }
+ } else if (strcmp(path, "abi_version") == 0) {
+
+ if (uverbs_abi_version == -1) {
+ fprintf(stderr, "UVerbs ABI Version invalid\n");
+
+ goto exit;
+ }
+
+ len = 1 + sprintf(buf, "%d", uverbs_abi_version);
+ } else {
+ fprintf(stderr, "Unsupported read: %s\n", path);
+ }
+exit:
+ return (len);
+}
+
+static int
+infiniband_ports(char *path, char *buf, size_t size, char *dev_name)
+{
+ int len = -1;
+ unsigned int port_num;
+ unsigned int gid_num;
+ union ibv_gid *gids;
+ uint64_t subnet_prefix;
+ uint64_t interface_id;
+ uint16_t *pkeys;
+ unsigned int pkey_num;
+ struct ibv_port_attr port_attr;
+ float rate;
+
+ if (!(check_path(path, CP_D, &port_num)))
+ goto exit;
+
+ if (check_path(path, CP_GIDS, NULL)) {
+ if (get_port_info(dev_name, port_num, &port_attr, &gids, NULL))
+ goto exit;
+
+ gid_num = atoi(path);
+
+ if (gid_num < port_attr.gid_tbl_len) {
+
+ subnet_prefix =
+ htonll(gids[gid_num].global.subnet_prefix);
+ interface_id =
+ htonll(gids[gid_num].global.interface_id);
+ len = 1 + sprintf(buf,
+ "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
+ (unsigned)(subnet_prefix >> 48) & 0xffff,
+ (unsigned)(subnet_prefix >> 32) & 0xffff,
+ (unsigned)(subnet_prefix >> 16) & 0xffff,
+ (unsigned)(subnet_prefix >> 0) & 0xffff,
+ (unsigned)(interface_id >> 48) & 0xffff,
+ (unsigned)(interface_id >> 32) & 0xffff,
+ (unsigned)(interface_id >> 16) & 0xffff,
+ (unsigned)(interface_id >> 0) & 0xffff);
+ }
+ if (gids)
+ free(gids);
+
+ } else if (check_path(path, CP_PKEYS, NULL)) {
+ if (get_port_info(dev_name, port_num, &port_attr, NULL, &pkeys))
+ goto exit;
+
+ pkey_num = atoi(path);
+ if (pkey_num < port_attr.pkey_tbl_len)
+ len = 1 + sprintf(buf, "0x%04x", pkeys[pkey_num]);
+
+ if (pkeys)
+ free(pkeys);
+ } else {
+
+ if (get_port_info(dev_name, port_num, &port_attr, NULL, NULL))
+ goto exit;
+
+ if (strcmp(path, "lid_mask_count") == 0) {
+ len = 1 + sprintf(buf, "%d", port_attr.lmc);
+ } else if (strcmp(path, "sm_lid") == 0) {
+ len = 1 + sprintf(buf, "0x%x", port_attr.sm_lid);
+ } else if (strcmp(path, "sm_sl") == 0) {
+ len = 1 + sprintf(buf, "%d", port_attr.sm_sl);
+ } else if (strcmp(path, "lid") == 0) {
+ len = 1 + sprintf(buf, "0x%x", port_attr.lid);
+ } else if (strcmp(path, "state") == 0) {
+ switch (port_attr.state) {
+ case IBV_PORT_NOP:
+ len = 1 + sprintf(buf, "%d: NOP",
+ port_attr.state);
+ break;
+ case IBV_PORT_DOWN:
+ len = 1 + sprintf(buf, "%d: DOWN",
+ port_attr.state);
+ break;
+ case IBV_PORT_INIT:
+ len = 1 + sprintf(buf, "%d: INIT",
+ port_attr.state);
+ break;
+ case IBV_PORT_ARMED:
+ len = 1 + sprintf(buf, "%d: ARMED",
+ port_attr.state);
+ break;
+ case IBV_PORT_ACTIVE:
+ len = 1 + sprintf(buf, "%d: ACTIVE",
+ port_attr.state);
+ break;
+ case IBV_PORT_ACTIVE_DEFER:
+ len = 1 + sprintf(buf,
+ "%d: ACTIVE_DEFER",
+ port_attr.state);
+ break;
+ default:
+ len = 1 + sprintf(buf, "%d: INVALID",
+ port_attr.state);
+ break;
+ }
+ } else if (strcmp(path, "phys_state") == 0) {
+ switch (port_attr.phys_state) {
+ case 1:
+ len = 1 + sprintf(buf, "%d: Sleep",
+ port_attr.phys_state);
+ break;
+ case 2:
+ len = 1 + sprintf(buf, "%d: Polling",
+ port_attr.phys_state);
+ break;
+ case 3:
+ len = 1 + sprintf(buf, "%d: Disabled",
+ port_attr.phys_state);
+ break;
+ case 4:
+ len = 1 + sprintf(buf,
+ "%d: PortConfigurationTraining",
+ port_attr.phys_state);
+ break;
+ case 5:
+ len = 1 + sprintf(buf, "%d: LinkUp",
+ port_attr.phys_state);
+ break;
+ case 6:
+ len = 1 + sprintf(buf,
+ "%d: LinkErrorRecovery",
+ port_attr.phys_state);
+ break;
+ case 7:
+ len = 1 + sprintf(buf,
+ "%d: Phy Test",
+ port_attr.phys_state);
+ break;
+ default:
+ len = 1 + sprintf(buf, "%d: <unknown>",
+ port_attr.phys_state);
+ break;
+ }
+ } else if (strcmp(path, "rate") == 0) {
+ /* rate = speed * width */
+ switch (port_attr.active_speed) {
+ case 1:
+ rate = 2.5;
+ break;
+ case 2:
+ rate = 5;
+ break;
+ case 4:
+ rate = 10;
+ break;
+ default:
+ rate = 0;
+ }
+ switch (port_attr.active_width) {
+ case 1:
+ break;
+ case 2:
+ rate = 4 * rate;
+ break;
+ case 4:
+ rate = 8 * rate;
+ break;
+ case 8:
+ rate = 12 * rate;
+ break;
+ default:
+ rate = 0;
+ }
+ len = 1 + sprintf(buf, "%f", rate);
+ } else if (strcmp(path, "cap_mask") == 0) {
+ len = 1 + sprintf(buf, "0x%08x",
+ port_attr.port_cap_flags);
+ }
+ }
+exit:
+ return (len);
+}
+
+
+/*
+ * This function passes the HW Part number string obtained from driver
+ * IOCTL. The memory for "hca_hwpn" argument has to be passed by the
+ * caller and has to be at least 64 bytes in size.
+ */
+static int
+get_hca_hwpn_str(char *ibd_name, int fd, char *hca_hwpn)
+{
+ hermon_flash_init_ioctl_t hermon_flash_info;
+ tavor_flash_init_ioctl_t tavor_flash_info;
+ int rc;
+
+ if (strncmp(ibd_name, "mthca", 5) == 0) {
+ if ((rc = ioctl(fd, TAVOR_IOCTL_FLASH_INIT,
+ &tavor_flash_info)) != 0)
+ return (rc);
+ strncpy(hca_hwpn, tavor_flash_info.tf_hwpn, 64);
+ } else {
+ if ((rc = ioctl(fd, HERMON_IOCTL_FLASH_INIT,
+ &hermon_flash_info)) != 0)
+ return (rc);
+ strncpy(hca_hwpn, hermon_flash_info.af_hwpn, 64);
+ }
+ return (0);
+}
+
+static void
+init_boardid_index(ibdev_cache_info_t *ibd_info)
+{
+ int i;
+ int fd;
+ char hca_hwpn[64];
+ char *hwpnp;
+
+
+ if (pthread_mutex_lock(&uverbs_cache_mutex) != 0) {
+ fprintf(stderr, "failed: to acquire "
+ "uverbs_cache_mutex %s\n",
+ strerror(errno));
+ goto boardid_err;
+ }
+ if (!uverbs_cache_initialized) {
+ uverbs_cache_init();
+ uverbs_cache_initialized = B_TRUE;
+ }
+ (void) pthread_mutex_unlock(&uverbs_cache_mutex);
+
+ for (i = 0; i < MAX_HCAS; i++) {
+ if (uverbs_dev_cache[i].uvc_valid &&
+ strcmp(uverbs_dev_cache[i].uvc_ibdev_name,
+ ibd_info->ibd_name) == 0) {
+ break;
+ }
+ }
+
+ if (i == MAX_HCAS) {
+ fprintf(stderr, "failed to find uverbs_dev for %s\n",
+ ibd_info->ibd_name);
+ goto boardid_err;
+ }
+
+ fd = open(uverbs_dev_cache[i].uvc_ibdev_hca_path, O_RDWR);
+ if (fd < 0) {
+ goto boardid_err;
+ }
+
+ if (get_hca_hwpn_str(ibd_info->ibd_name, fd, hca_hwpn)) {
+ close(fd);
+ goto boardid_err;
+ }
+ close(fd);
+ if ((hwpnp = strchr(hca_hwpn, ' ')) != NULL)
+ *hwpnp = '\0';
+
+ /*
+ * Find part number, set the boardid_index,
+ * Skip index 0, as it is for failure "unknown"
+ * case.
+ */
+ for (i = 1; i < MLX_MAX_ID; i++) {
+ if (strcmp((const char *)hca_hwpn,
+ mlx_mdr[i].mlx_pn) == 0) {
+
+ /* Set boardid_index */
+ ibd_info->ibd_boardid_index = i;
+ return;
+ }
+ }
+
+boardid_err:
+ /* Failure case, default to "unknown" */
+ ibd_info->ibd_boardid_index = 0;
+}
+
+static int
+infiniband(char *path, char *buf, size_t size)
+{
+ int len = -1;
+ unsigned int device_num;
+ char dev_name[10];
+ ibdev_cache_info_t *info;
+
+ memset(dev_name, 0, 10);
+
+ if (check_path(path, CP_MTHCA, &device_num)) {
+ sprintf(dev_name, "mthca%d", device_num);
+ } else if (check_path(path, CP_MLX4, &device_num)) {
+ sprintf(dev_name, "mlx4_%d", device_num);
+ } else {
+ goto exit;
+ }
+
+ if (check_path(path, CP_PORTS, NULL)) {
+ len = infiniband_ports(path, buf, size, dev_name);
+ } else if (strcmp(path, "node_type") == 0) {
+ len = 1 + sprintf(buf, "%d", IBV_NODE_CA);
+ } else {
+ if (!(info = get_device_info(dev_name)))
+ goto exit;
+
+ if (strcmp(path, "node_guid") == 0) {
+ len = 1 + sprintf(buf, "%s", info->ibd_node_guid_str);
+ } else if (strcmp(path, "sys_image_guid") == 0) {
+ len = 1 + sprintf(buf, "%s", info->ibd_sys_image_guid);
+ } else if (strcmp(path, "fw_ver") == 0) {
+ len = 1 + sprintf(buf, "%s", info->ibd_fw_ver);
+ } else if (strcmp(path, "hw_rev") == 0) {
+ len = 1 + sprintf(buf, "%d", info->ibd_hw_rev);
+ } else if (strcmp(path, "hca_type") == 0) {
+ if (!(strncmp(info->ibd_name, "mlx4", 4)))
+ len = 1 + sprintf(buf, "%d", 0);
+ else
+ len = 1 + sprintf(buf, "unavailable");
+ } else if (strcmp(path, "board_id") == 0) {
+ if (info->ibd_boardid_index == -1)
+ init_boardid_index(info);
+
+ len = 1 + sprintf(buf, "%s",
+ mlx_mdr[info->ibd_boardid_index].mlx_psid);
+ }
+ }
+exit:
+ return (len);
+}
+
+static int
+infiniband_mad(char *path, char *buf, size_t size)
+{
+ int len = -1;
+ unsigned int dev_num;
+
+ if (pthread_mutex_lock(&umad_cache_mutex) != 0) {
+ fprintf(stderr, "failed: to acquire umad_cache_mutex %s\n",
+ strerror(errno));
+ goto exit;
+ }
+ if (!umad_cache_initialized) {
+ if (umad_cache_init())
+ umad_cache_initialized = B_TRUE;
+ else
+ goto exit;
+ }
+ (void) pthread_mutex_unlock(&umad_cache_mutex);
+
+ if (check_path(path, CP_UMAD, &dev_num)) {
+ if (dev_num >= MAX_HCAS * MAX_HCA_PORTS) {
+ fprintf(stderr, "Invalid Path: %s\n", path);
+ goto exit;
+ }
+ if (!umad_dev_cache[dev_num].umc_valid) {
+ goto exit;
+ }
+ if (strcmp(path, "ibdev") == 0) {
+ len = strlcpy(buf, umad_dev_cache[dev_num].umc_ib_dev,
+ size) + 1;
+ } else if (strcmp(path, "port") == 0) {
+ len = 1 + sprintf(buf, "%d",
+ umad_dev_cache[dev_num].umc_port);
+ }
+ } else if (strcmp(path, "abi_version") == 0) {
+ if (umad_abi_version == -1) {
+ fprintf(stderr, "UMAD ABI Version invalid\n");
+ goto exit;
+ }
+ len =
+ 1 + sprintf(buf, "%d", umad_abi_version);
+ }
+exit:
+ return (len);
+}
+
+/*
+ * Return -1 on error, or the length of the data (buf) on success.
+ */
+int
+sol_read_sysfs_file(char *path, char *buf, size_t size)
+{
+ int len = -1;
+
+ if (!initialized) {
+ if (pthread_once(&oneTimeInit, initialize)) {
+ fprintf(stderr, "failed to initialize: %s\n",
+ strerror(errno));
+ goto exit;
+ }
+ if (!initialized)
+ /*
+ * There was a problem in initialize()
+ */
+ goto exit;
+ }
+
+ if (!check_path(path, CP_SLASH, NULL))
+ goto exit;
+
+ if (!check_path(path, CP_SYS, NULL))
+ goto exit;
+
+ if (!check_path(path, CP_CLASS, NULL))
+ goto exit;
+
+ if (check_path(path, CP_INFINIBAND_VERBS, NULL)) {
+ len = infiniband_verbs(path, buf, size);
+ } else if (check_path(path, CP_INFINIBAND, NULL)) {
+ len = infiniband(path, buf, size);
+ } else if (check_path(path, CP_INFINIBAND_MAD, NULL)) {
+ len = infiniband_mad(path, buf, size);
+ } else if (check_path(path, CP_MISC, NULL)) {
+ if (check_path(path, CP_RDMA_CM, NULL)) {
+ if (strcmp(path, "abi_version") == 0) {
+ len = 1 + sprintf(buf, "%d",
+ RDMA_USER_CM_MAX_ABI_VERSION);
+ }
+ }
+ }
+exit:
+ return (len);
+}
+
+
+int
+sol_get_cpu_info(sol_cpu_info_t *info)
+{
+ kstat_t *ksp;
+ kstat_named_t *knp;
+
+ /*
+ * We should check all CPUS, and make sure they
+ * are all the same or return an array of structs.
+ */
+ ksp = kstat_lookup(kc, "cpu_info", 0, NULL);
+ if (ksp == NULL)
+ return (-1);
+
+ if (kstat_read(kc, ksp, NULL) == -1)
+ return (-1);
+
+ knp = (kstat_named_t *)kstat_data_lookup(ksp, "brand");
+ if (knp == NULL)
+ return (-1);
+
+ (void) strlcpy(info->cpu_name, knp->value.str.addr.ptr,
+ knp->value.str.len);
+
+ knp = (kstat_named_t *)kstat_data_lookup(ksp, "clock_MHz");
+ if (knp == NULL)
+ return -1;
+
+ info->cpu_mhz = knp->value.ui64;
+ info->cpu_num = sysconf(_SC_NPROCESSORS_ONLN);
+ return (0);
+}
+#endif