369N/A/*
6320N/A * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
369N/A *
369N/A * This software is available to you under a choice of one of two
369N/A * licenses. You may choose to be licensed under the terms of the GNU
369N/A * General Public License (GPL) Version 2, available from the file
369N/A * COPYING in the main directory of this source tree, or the
369N/A * OpenIB.org BSD license below:
369N/A *
369N/A * Redistribution and use in source and binary forms, with or
369N/A * without modification, are permitted provided that the following
369N/A * conditions are met:
369N/A *
369N/A * - Redistributions of source code must retain the above
369N/A * copyright notice, this list of conditions and the following
369N/A * disclaimer.
369N/A *
369N/A * - Redistributions in binary form must reproduce the above
369N/A * copyright notice, this list of conditions and the following
369N/A * disclaimer in the documentation and/or other materials
369N/A * provided with the distribution.
369N/A *
369N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
369N/A * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
369N/A * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
369N/A * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
369N/A * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
369N/A * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
369N/A * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
369N/A * SOFTWARE.
369N/A */
369N/A#if HAVE_CONFIG_H
369N/A#include <config.h>
369N/A#endif /* HAVE_CONFIG_H */
369N/A
369N/A/*
369N/A * OFED Solaris wrapper
369N/A */
369N/A#if defined(__SVR4) && defined(__sun)
369N/A
369N/A#include <stdarg.h>
369N/A#include <fcntl.h>
369N/A#include <unistd.h>
369N/A#include <sys/types.h>
369N/A#include <sys/processor.h>
369N/A#include <stdio.h>
369N/A#include <stdlib.h>
369N/A#include <strings.h>
369N/A#include <sys/param.h>
736N/A#include <sys/ib/clients/of/sol_uverbs/sol_uverbs_ioctl.h>
736N/A#include <sys/ib/clients/of/sol_umad/sol_umad_ioctl.h>
369N/A#include <alloca.h>
369N/A#include "../include/infiniband/arch.h"
369N/A#include "../include/infiniband/verbs.h"
2948N/A#include "../include/infiniband/kern-abi.h"
2948N/A#include "../include/infiniband/driver.h"
369N/A#include <errno.h>
369N/A#include <pthread.h>
369N/A#include <kstat.h>
369N/A
1998N/A#define min(a, b) ((a) < (b) ? (a) : (b))
1998N/A
369N/A/*
369N/A * duplicate ABI definitions for HCAs as the HCA abi headers are not
369N/A * installed in proto.
736N/A */
369N/A#define RDMA_USER_CM_MIN_ABI_VERSION 3 /* rdma_cma_abi.h */
369N/A#define RDMA_USER_CM_MAX_ABI_VERSION 4 /* rdma_cma_abi.h */
369N/A
4994N/A/*
4994N/A * Some useful definitions.
4994N/A */
369N/A#define HW_DRIVER_MAX_NAME_LEN 20
369N/A#define UVERBS_KERNEL_SYSFS_NAME_BASE "uverbs"
369N/A#define UMAD_KERNEL_SYSFS_NAME_BASE "umad"
369N/A#define IB_HCA_DEVPATH_PREFIX "/dev/infiniband/hca"
369N/A#define IB_OFS_DEVPATH_PREFIX "/dev/infiniband/ofs"
4994N/A#define IB_HCA_DEVPATH_SZ 64
4994N/A#define MAX_OFS_DEVPATH_LEN 64
369N/A
3679N/A#define MAX_HCAS (64*16)
3679N/A#define MAX_PORTS (MAX_HCAS*2)
3679N/A
369N/A/*
369N/A * sol_uverbs_drv_status is the status of what libibverbs knows
369N/A * about the status of sol_uverbs driver.
369N/A */
369N/A#define SOL_UVERBS_DRV_STATUS_UNKNOWN 0x0
369N/A#define SOL_UVERBS_DRV_STATUS_LOADED 0x1
369N/A#define SOL_UVERBS_DRV_STATUS_UNLOADED 0x02
369N/A
369N/Astatic kstat_ctl_t *kc = NULL; /* libkstat cookie */
369N/Astatic int sol_uverbs_drv_status = SOL_UVERBS_DRV_STATUS_UNKNOWN;
369N/Astatic int sol_uverbs_minor_dev = -1;
369N/A
369N/A/*
6320N/A * Override verbs abi version.
6320N/A * If the build system doesn't have the intended
6320N/A * header file then override with the intended abi version.
6320N/A * These changes can be deleted once the build system has
6320N/A * the correct header file.
4994N/A */
4994N/A#if (IB_USER_VERBS_SOLARIS_ABI_VERSION == 2)
4994N/A#undef IB_USER_VERBS_SOLARIS_ABI_VERSION
6320N/A#define IB_USER_VERBS_SOLARIS_ABI_VERSION 4
4994N/A
6320N/A#define UVERBS_PSID_STR_SZ 32
6320N/A#define UVERBS_IBDEV_NAME_SZ 64
6320N/A#define UVERBS_HCA_DRIVER_NAME_SZ 40
6320N/A#define UVERBS_DEVID_STR_SZ 16
6320N/A
6320N/Atypedef struct sol_uverbs_hca_info_v4_s {
6320N/A char uverbs_hca_psid_string[UVERBS_PSID_STR_SZ];
6320N/A uint8_t uverbs_hca_pad1[8];
6320N/A char uverbs_hca_ibdev_name[UVERBS_IBDEV_NAME_SZ];
6320N/A char uverbs_hca_driver_name[UVERBS_HCA_DRIVER_NAME_SZ];
4994N/A uint32_t uverbs_hca_driver_instance;
4994N/A uint32_t uverbs_hca_vendorid;
4994N/A uint16_t uverbs_hca_deviceid;
4994N/A uint16_t uverbs_hca_devidx;
4994N/A int32_t uverbs_hca_abi_version;
4994N/A uint64_t uverbs_hca_fw_ver;
4994N/A uint64_t uverbs_hca_node_guid;
4994N/A uint64_t uverbs_hca_node_external_guid;
4994N/A uint64_t uverbs_hca_sys_image_guid;
4994N/A uint32_t uverbs_hca_hw_version;
6320N/A uint8_t uverbs_hca_pad2[4];
6320N/A char uverbs_hca_devid_string[UVERBS_DEVID_STR_SZ];
6320N/A uint8_t uverbs_hca_pad3[24];
6320N/A} sol_uverbs_hca_info_v4_t;
6320N/A#define IB_USER_VERBS_V4_IN_V3
6320N/A#endif
4994N/A
6320N/A/*
6320N/A * Some useful definitions.
6320N/A */
4994N/A#define SIZEOF_UVERBS_INFO (sizeof (sol_uverbs_info_t))
6320N/A#ifdef IB_USER_VERBS_V4_IN_V3
6320N/A#define SIZEOF_HCA_INFO (sizeof (sol_uverbs_hca_info_v4_t))
6320N/A#else
4994N/A#define SIZEOF_HCA_INFO (sizeof (sol_uverbs_hca_info_t))
6320N/A#endif
4994N/A#define UVERBS_INFO(x) ((sol_uverbs_info_t *)x)
4994N/A
4994N/A/*
369N/A * check_path() prefixs
369N/A */
369N/Atypedef enum cp_prefix_e {
369N/A CP_SOL_UVERBS = 1,
369N/A CP_DEVICE = 2,
369N/A CP_D = 3,
369N/A CP_GIDS = 4,
369N/A CP_PKEYS = 5,
4994N/A CP_PORTS = 6,
4994N/A CP_UMAD = 7,
4994N/A CP_SLASH = 8,
4994N/A CP_SYS = 9,
4994N/A CP_CLASS = 10,
4994N/A CP_INFINIBAND_VERBS = 11,
4994N/A CP_INFINIBAND = 12,
4994N/A CP_INFINIBAND_MAD = 13,
4994N/A CP_MISC = 14,
4994N/A CP_RDMA_CM = 15
369N/A} cp_prefix_t;
369N/A
369N/A/*
369N/A * Some temporary cache code, until things are cleaned up as part of DR
369N/A * work. This will speed up the sysfs emulation.
369N/A */
369N/Atypedef struct ibdev_cache_info_s {
4994N/A boolean_t ibd_valid;
4994N/A uint_t ibd_hw_rev;
4994N/A uint_t ibd_abi_version;
4994N/A uint_t ibd_vendor_id;
4994N/A uint_t ibd_device_id;
4994N/A char ibd_hca_path[IB_HCA_DEVPATH_SZ];
4994N/A char ibd_node_guid_str[20];
4994N/A char ibd_node_guid_external_str[20];
4994N/A char ibd_sys_image_guid[20];
4994N/A char ibd_fw_ver[16];
6320N/A char ibd_name[UVERBS_IBDEV_NAME_SZ];
6320N/A char ibd_boardid_string[UVERBS_PSID_STR_SZ];
6320N/A char ibd_devid_string[UVERBS_DEVID_STR_SZ];
369N/A} ibdev_cache_info_t;
369N/A
4994N/A/* IB device info cache */
4994N/Astatic ibdev_cache_info_t ibdev_cache[MAX_HCAS];
369N/Astatic int uverbs_abi_version = -1;
369N/A
369N/Atypedef struct umad_cache_info_s {
369N/A uint_t umc_valid;
369N/A int umc_port;
369N/A char umc_ib_dev[16];
369N/A} umad_cache_info_t;
3679N/Astatic umad_cache_info_t umad_dev_cache[MAX_PORTS];
369N/Astatic int umad_abi_version = -1;
369N/A
369N/Apthread_once_t oneTimeInit = PTHREAD_ONCE_INIT;
369N/Astatic int umad_cache_cnt = 0;
369N/Astatic boolean_t initialized = B_FALSE;
369N/Astatic boolean_t umad_cache_initialized = B_FALSE;
369N/Astatic boolean_t ibdev_cache_initialized = B_FALSE;
369N/Astatic pthread_mutex_t umad_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
369N/Astatic pthread_mutex_t ibdev_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
369N/A
736N/Aint sol_ibv_query_gid(struct ibv_context *, uint8_t, int, union ibv_gid *);
736N/Aint sol_ibv_query_pkey(struct ibv_context *, uint8_t, int, uint16_t *);
369N/Avoid __attribute__((constructor))solaris_init(void);
369N/Avoid __attribute__((destructor))solaris_fini(void);
369N/A
2948N/Aint sol_ibv_query_device(struct ibv_device *device,
2948N/A struct ibv_device_attr *device_attr);
2948N/A
2948N/Aint sol_ibv_query_port(struct ibv_context *, uint8_t, struct ibv_port_attr *);
2948N/A
369N/Avoid
369N/Asolaris_init(void)
369N/A{
369N/A while ((kc = kstat_open()) == NULL) {
369N/A if (errno == EAGAIN)
369N/A (void) poll(NULL, 0, 200);
369N/A else
369N/A fprintf(stderr, "cannot open /dev/kstat: %s\n",
369N/A strerror(errno));
369N/A }
369N/A}
369N/A
369N/Avoid
369N/Asolaris_fini(void)
369N/A{
369N/A (void) kstat_close(kc);
369N/A}
369N/A
4994N/A#define isdigit(c) ((c) >= '0' && (c) <= '9')
4994N/A
4994N/A/*
4994N/A * Given a device name of the form <driver-prefix><instance>,
4994N/A * get the device number. Device name is of the form
4994N/A * for example:- mlx4_0, mlx4_2 etc. Function will return the device instance
4994N/A * extracted from the name.
4994N/A * for example:- mlx4_0 will return 0 and mlx4_2 will return 2.
4994N/A */
4994N/Astatic int
4994N/Aget_device_num(const char *device_name)
4994N/A{
4994N/A const char *temp;
4994N/A const char *end;
4994N/A const char *start = device_name;
4994N/A int len;
4994N/A int devnum;
4994N/A
4994N/A if (!start)
4994N/A return (-1);
4994N/A
4994N/A len = strlen(device_name);
4994N/A end = &device_name[len - 1];
4994N/A
4994N/A for (temp = end; temp >= start && isdigit(*temp); temp--)
4994N/A /* Null body */;
4994N/A
4994N/A /*
4994N/A * Check if the device number is invalid.
4994N/A */
4994N/A if (temp == end || temp < start)
4994N/A return (-1);
4994N/A
4994N/A devnum = atoi(temp + 1);
4994N/A if (devnum < 0 || devnum >= MAX_HCAS)
4994N/A return (-1);
4994N/A
4994N/A return (devnum);
4994N/A}
4994N/A
4994N/A/*
4994N/A * For usages where ibdev cache needs to be read based on the IB device
4994N/A * name instead of uverbs device name a simple compare against the cache
4994N/A * entries is used to retrieve the corresponding ibdev cache entry.
4994N/A */
4994N/Astatic ibdev_cache_info_t *
4994N/Aibdev_cache_read_by_devname(const char *devname)
4994N/A{
4994N/A int idx;
4994N/A ibdev_cache_info_t *cache = NULL;
4994N/A
4994N/A if (!devname)
4994N/A return (NULL);
4994N/A
4994N/A for (idx = 0; idx < MAX_HCAS; idx++) {
4994N/A cache = &ibdev_cache[idx];
4994N/A if (strcmp(cache->ibd_name, devname) == 0)
4994N/A break;
4994N/A }
4994N/A
4994N/A /*
4994N/A * If we failed to find an entry return NULL.
4994N/A */
4994N/A if (idx == MAX_HCAS)
4994N/A cache = NULL;
4994N/A
4994N/A return (cache);
4994N/A}
4994N/A
4994N/A/*
4994N/A * Helper function to update the ibdev cache entries with the values obtained
4994N/A * from the uverbs HCA info ioctl.
4994N/A */
4994N/Astatic int
4994N/Aibdev_cache_init()
4994N/A{
4994N/A ibdev_cache_info_t *info;
4994N/A int fd, i, hca_cnt;
4994N/A char uverbs_devpath[MAX_OFS_DEVPATH_LEN];
6320N/A sol_uverbs_info_t *uverbs_infop;
6320N/A#ifdef IB_USER_VERBS_V4_IN_V3
6320N/A sol_uverbs_hca_info_v4_t *hca_infop;
4994N/A#else
4994N/A sol_uverbs_hca_info_t *hca_infop;
6320N/A#endif
4994N/A char *buf;
4994N/A size_t bufsize;
4994N/A uint16_t major, minor, sub_minor;
4994N/A uint64_t raw_fw_ver;
4994N/A uint64_t guid;
4994N/A
4994N/A snprintf(uverbs_devpath, MAX_OFS_DEVPATH_LEN, "%s/%s%d",
4994N/A IB_OFS_DEVPATH_PREFIX, UVERBS_KERNEL_SYSFS_NAME_BASE,
4994N/A sol_uverbs_minor_dev);
4994N/A
4994N/A /*
4994N/A * using the first sol_uverbs minor node that can be opened to get
4994N/A * all the HCA information
4994N/A */
4994N/A if ((fd = open(uverbs_devpath, O_RDWR)) < 0) {
4994N/A fprintf(stderr, "sol_uverbs failed to open: %s\n",
4994N/A strerror(errno));
4994N/A return (-1);
4994N/A }
4994N/A
4994N/A bufsize = SIZEOF_UVERBS_INFO + (MAX_HCAS * SIZEOF_HCA_INFO);
4994N/A buf = malloc(bufsize);
4994N/A if (!buf) {
4994N/A fprintf(stderr, "ibdev_cache_update() failed to alloc\n");
4994N/A close(fd);
4994N/A return (-1);
4994N/A }
4994N/A memset(buf, 0, bufsize);
4994N/A
4994N/A uverbs_infop = UVERBS_INFO(buf);
4994N/A uverbs_infop->uverbs_hca_cnt = MAX_HCAS;
4994N/A
4994N/A if (ioctl(fd, UVERBS_IOCTL_GET_HCA_INFO, uverbs_infop) != 0) {
4994N/A fprintf(stderr, "sol_uverbs ioctl failed: %s\n",
4994N/A strerror(errno));
4994N/A
4994N/A goto error_exit1;
4994N/A }
4994N/A
4994N/A if (uverbs_infop->uverbs_solaris_abi_version !=
4994N/A IB_USER_VERBS_SOLARIS_ABI_VERSION) {
4994N/A fprintf(stderr, "sol_uverbs solaris_abi_version !="
4994N/A "IB_USER_VERBS_SOLARIS_ABI_VERSION : %d\n",
4994N/A uverbs_infop->uverbs_solaris_abi_version);
4994N/A goto error_exit1;
4994N/A }
4994N/A
4994N/A hca_cnt = uverbs_infop->uverbs_hca_cnt; /* hca count returned */
4994N/A hca_infop = uverbs_infop->uverbs_hca_info;
4994N/A
4994N/A if (hca_cnt > MAX_HCAS) {
4994N/A fprintf(stderr, "Number of HCAs returned exceeds max\n");
4994N/A goto error_exit1;
4994N/A }
4994N/A
4994N/A if (uverbs_abi_version == -1)
4994N/A uverbs_abi_version = uverbs_infop->uverbs_abi_version;
4994N/A
4994N/A for (i = 0; i < hca_cnt; i++, hca_infop++) {
4994N/A
4994N/A /*
4994N/A * Update the cache.
4994N/A */
4994N/A info = &ibdev_cache[hca_infop->uverbs_hca_devidx];
4994N/A
4994N/A (void) strncpy(info->ibd_name,
6320N/A hca_infop->uverbs_hca_ibdev_name, UVERBS_IBDEV_NAME_SZ);
4994N/A
4994N/A guid = hca_infop->uverbs_hca_node_guid;
4994N/A sprintf(info->ibd_node_guid_str, "%04x:%04x:%04x:%04x",
4994N/A (unsigned)(guid >> 48) & 0xffff,
4994N/A (unsigned)(guid >> 32) & 0xffff,
4994N/A (unsigned)(guid >> 16) & 0xffff,
4994N/A (unsigned)(guid >> 0) & 0xffff);
4994N/A
4994N/A guid = hca_infop->uverbs_hca_node_external_guid;
4994N/A sprintf(info->ibd_node_guid_external_str, "%04x:%04x:%04x:%04x",
4994N/A (unsigned)(guid >> 48) & 0xffff,
4994N/A (unsigned)(guid >> 32) & 0xffff,
4994N/A (unsigned)(guid >> 16) & 0xffff,
4994N/A (unsigned)(guid >> 0) & 0xffff);
4994N/A
4994N/A guid = hca_infop->uverbs_hca_sys_image_guid;
4994N/A sprintf(info->ibd_sys_image_guid, "%04x:%04x:%04x:%04x",
4994N/A (unsigned)(guid >> 48) & 0xffff,
4994N/A (unsigned)(guid >> 32) & 0xffff,
4994N/A (unsigned)(guid >> 16) & 0xffff,
4994N/A (unsigned)(guid >> 0) & 0xffff);
4994N/A
4994N/A raw_fw_ver = hca_infop->uverbs_hca_fw_ver;
4994N/A major = (raw_fw_ver >> 32) & 0xffff;
4994N/A minor = (raw_fw_ver >> 16) & 0xffff;
4994N/A sub_minor = raw_fw_ver & 0xffff;
4994N/A
4994N/A snprintf(info->ibd_fw_ver, sizeof (info->ibd_fw_ver),
4994N/A "%d.%d.%03d", major, minor, sub_minor);
4994N/A
4994N/A info->ibd_hw_rev = hca_infop->uverbs_hca_hw_version;
4994N/A info->ibd_vendor_id = hca_infop->uverbs_hca_vendorid;
4994N/A info->ibd_device_id = hca_infop->uverbs_hca_deviceid;
4994N/A info->ibd_abi_version = hca_infop->uverbs_hca_abi_version;
4994N/A
4994N/A snprintf(info->ibd_hca_path, sizeof (info->ibd_hca_path),
4994N/A "%s/%s%d", IB_HCA_DEVPATH_PREFIX,
4994N/A hca_infop->uverbs_hca_driver_name,
4994N/A hca_infop->uverbs_hca_driver_instance);
4994N/A
4994N/A strncpy(info->ibd_boardid_string,
6320N/A hca_infop->uverbs_hca_psid_string, UVERBS_PSID_STR_SZ);
4994N/A
4994N/A strncpy(info->ibd_devid_string,
6320N/A hca_infop->uverbs_hca_devid_string, UVERBS_DEVID_STR_SZ);
4994N/A
4994N/A info->ibd_valid = B_TRUE;
4994N/A }
4994N/A
4994N/A free(buf);
4994N/A close(fd);
4994N/A return (0);
4994N/A
4994N/Aerror_exit1:
4994N/A free(buf);
4994N/A close(fd);
4994N/A return (-1);
4994N/A}
4994N/A
369N/Astatic int
369N/Aumad_cache_add(uint_t dev_num, int port, char *ibdev)
369N/A{
3679N/A if ((dev_num >= MAX_PORTS) || (umad_cache_cnt >= MAX_PORTS)) {
369N/A fprintf(stderr, "dev %d: exceeds umad cache size\n", dev_num);
369N/A return (1);
369N/A }
369N/A
369N/A umad_dev_cache[dev_num].umc_port = port;
369N/A strcpy(umad_dev_cache[dev_num].umc_ib_dev, ibdev);
369N/A umad_dev_cache[dev_num].umc_valid = 1;
369N/A umad_cache_cnt++;
369N/A return (0);
369N/A}
369N/A
369N/Astatic int
369N/Aumad_cache_init()
369N/A{
369N/A int i, fd, minor;
369N/A int save_errno = 0;
369N/A int port_cnt, bufsize;
4994N/A char umad_devpath[MAX_OFS_DEVPATH_LEN], *buf;
369N/A sol_umad_ioctl_info_t *umad_infop;
369N/A sol_umad_ioctl_port_info_t *port_infop;
369N/A
3679N/A for (minor = 0; minor < MAX_PORTS; minor++) {
4994N/A snprintf(umad_devpath, MAX_OFS_DEVPATH_LEN, "%s/%s%d",
369N/A IB_OFS_DEVPATH_PREFIX, UMAD_KERNEL_SYSFS_NAME_BASE,
369N/A minor);
369N/A
369N/A if ((fd = open(umad_devpath, O_RDWR)) > 0)
369N/A break;
369N/A
369N/A if ((! save_errno) && (errno != ENOENT))
369N/A save_errno = errno;
369N/A }
369N/A
3679N/A if ((minor == MAX_PORTS) && (fd < 0)) {
369N/A if (! save_errno)
369N/A save_errno = errno;
369N/A fprintf(stderr, "failed to open sol_umad: %s\n",
369N/A strerror(save_errno));
4994N/A return (-1);
369N/A }
369N/A
736N/A bufsize = sizeof (sol_umad_ioctl_info_t) +
3679N/A (sizeof (sol_umad_ioctl_port_info_t) * MAX_PORTS);
736N/A
369N/A buf = malloc(bufsize);
369N/A memset(buf, 0, bufsize);
369N/A umad_infop = (sol_umad_ioctl_info_t *)buf;
3679N/A umad_infop->umad_port_cnt = MAX_PORTS;
369N/A
369N/A if (ioctl(fd, IB_USER_MAD_GET_PORT_INFO, umad_infop) != 0) {
369N/A fprintf(stderr, "sol_umad ioctl failed: %s\n",
369N/A strerror(errno));
736N/A
369N/A goto error_exit;
369N/A }
369N/A
369N/A if (umad_infop->umad_solaris_abi_version !=
369N/A IB_USER_MAD_SOLARIS_ABI_VERSION) {
369N/A fprintf(stderr, "sol_umad solaris_abi_version !="
369N/A "IB_USER_MAD_SOLARIS_ABI_VERSION : %d\n",
369N/A umad_infop->umad_solaris_abi_version);
369N/A goto error_exit;
369N/A }
369N/A
369N/A /*
369N/A * set port_cnt to the number of total ports for all HCAs returned
369N/A */
369N/A port_cnt = umad_infop->umad_port_cnt;
369N/A port_infop = umad_infop->umad_port_info;
369N/A
369N/A if (umad_abi_version == -1)
369N/A umad_abi_version = umad_infop->umad_abi_version;
369N/A
369N/A for (i = 0; i < port_cnt; i++, port_infop++) {
369N/A if (umad_cache_add(port_infop->umad_port_idx,
369N/A port_infop->umad_port_num,
369N/A port_infop->umad_port_ibdev_name)) {
369N/A fprintf(stderr, "failed to add dev %d to umad cache",
369N/A port_infop->umad_port_idx);
369N/A goto error_exit;
369N/A }
369N/A }
369N/A
369N/A free(buf);
369N/A close(fd);
4994N/A return (0);
369N/A
369N/Aerror_exit:
369N/A free(buf);
369N/A close(fd);
4994N/A return (-1);
369N/A}
369N/A
369N/Avoid
369N/Ainitialize(void)
369N/A{
369N/A int fd, minor;
4994N/A char uverbs_devpath[MAX_OFS_DEVPATH_LEN];
369N/A
369N/A /*
369N/A * find the first sol_uverbs minor node that can be opened successfully
369N/A * and set sol_uverbs_mino_dev to that minor no.
369N/A */
369N/A for (minor = 0; minor < MAX_HCAS; minor++) {
4994N/A snprintf(uverbs_devpath, MAX_OFS_DEVPATH_LEN, "%s/%s%d",
369N/A IB_OFS_DEVPATH_PREFIX, UVERBS_KERNEL_SYSFS_NAME_BASE,
369N/A minor);
369N/A
369N/A if ((fd = open(uverbs_devpath, O_RDWR)) < 0) {
369N/A continue;
369N/A } else {
369N/A sol_uverbs_drv_status = SOL_UVERBS_DRV_STATUS_LOADED;
369N/A sol_uverbs_minor_dev = minor;
369N/A close(fd);
369N/A break;
369N/A }
369N/A }
369N/A
369N/A /*
369N/A * All minor nodes failed to open, so set sol_uverbs_drv_status to
369N/A * SOL_UVERBS_DRV_STATUS_UNLOADED to reflect that
369N/A */
369N/A if (minor == MAX_HCAS && sol_uverbs_minor_dev == -1) {
369N/A sol_uverbs_drv_status = SOL_UVERBS_DRV_STATUS_UNLOADED;
369N/A return;
369N/A }
369N/A
4994N/A memset(&ibdev_cache, 0, (sizeof (ibdev_cache_info_t) * MAX_HCAS));
369N/A memset(&umad_dev_cache, 0,
3679N/A (sizeof (umad_cache_info_t) * MAX_PORTS));
369N/A
369N/A initialized = B_TRUE;
369N/A}
369N/A
369N/A/*
369N/A * Some sysfs emulation software
369N/A */
369N/A
4994N/A/*
4994N/A * Extract the HCA dev name from the path and remove it from the path.
4994N/A * Given a path extract the HCA dev name of the form <dev-prefix><dev-instance>
4994N/A * During parsing the device instance number is validated to make sure it is
4994N/A * within MAX_HCAS limit, the routine also skips over the duplicate slashes.
4994N/A */
4994N/Astatic int
4994N/Acheck_path_for_hca(char *path, char *device_name)
4994N/A{
4994N/A int pos = 0;
4994N/A int len;
4994N/A
4994N/A while ((path[pos] != '/') || (path[pos] == '\0'))
4994N/A pos++;
4994N/A
4994N/A if (path[pos] != '/')
4994N/A return (0);
4994N/A
4994N/A strncpy(device_name, path, (pos + 1));
4994N/A device_name[pos] = '\0';
4994N/A
4994N/A if (get_device_num(device_name) < 0)
4994N/A return (0);
4994N/A
4994N/A while (path[pos] == '/')
4994N/A pos++;
4994N/A
4994N/A len = strlen(path);
4994N/A memmove(path, &path[pos], (len - pos) + 1);
4994N/A return (1);
4994N/A}
369N/A
369N/A/*
369N/A * Check whether a path starts with prefix, and if it does, remove it
369N/A * from the string. The prefix can also contain one %d scan argument.
369N/A */
369N/Astatic int
369N/Acheck_path(char *path, cp_prefix_t prefix, unsigned int *arg)
369N/A{
369N/A int ret, pos = 0;
369N/A
369N/A switch (prefix) {
369N/A case CP_SOL_UVERBS:
369N/A ret = sscanf(path, "uverbs%d%n/", arg,
369N/A &pos);
369N/A break;
369N/A case CP_DEVICE:
369N/A ret = sscanf(path, "device%n/", &pos);
369N/A break;
369N/A case CP_D:
369N/A ret = sscanf(path, "%d%n/", arg, &pos);
369N/A break;
369N/A case CP_GIDS:
369N/A ret = sscanf(path, "gids%n/", &pos);
369N/A break;
369N/A case CP_PKEYS:
369N/A ret = sscanf(path, "pkeys%n/", &pos);
369N/A break;
369N/A case CP_PORTS:
369N/A ret = sscanf(path, "ports%n/", &pos);
369N/A break;
369N/A case CP_UMAD:
369N/A ret = sscanf(path, "umad%d%n/", arg, &pos);
369N/A break;
369N/A case CP_SLASH:
369N/A ret = sscanf(path, "%n/", &pos);
369N/A break;
369N/A case CP_SYS:
369N/A ret = sscanf(path, "sys%n/", &pos);
369N/A break;
369N/A case CP_CLASS:
369N/A ret = sscanf(path, "class%n/", &pos);
369N/A break;
369N/A case CP_INFINIBAND_VERBS:
369N/A ret = sscanf(path, "infiniband_verbs%n/", &pos);
369N/A break;
369N/A case CP_INFINIBAND:
369N/A ret = sscanf(path, "infiniband%n/", &pos);
369N/A break;
369N/A case CP_INFINIBAND_MAD:
369N/A ret = sscanf(path, "infiniband_mad%n/", &pos);
369N/A break;
369N/A case CP_MISC:
369N/A ret = sscanf(path, "misc%n/", &pos);
369N/A break;
369N/A case CP_RDMA_CM:
369N/A ret = sscanf(path, "rdma_cm%n/", &pos);
369N/A break;
369N/A default:
369N/A /* Unkown prefix */
369N/A return (0);
369N/A }
369N/A
369N/A if (path[pos] == '/') {
369N/A /* Some requests have several consecutive slashes. */
369N/A while (path[pos] == '/')
369N/A pos ++;
369N/A
369N/A memmove(path, &path[pos], strlen(path)-pos+1);
369N/A return (1);
369N/A }
369N/A
369N/A return (0);
369N/A}
369N/A
369N/Astatic ibdev_cache_info_t *
369N/Aget_device_info(const char *devname)
369N/A{
648N/A ibdev_cache_info_t *info = NULL;
369N/A
369N/A if (pthread_mutex_lock(&ibdev_cache_mutex) != 0) {
369N/A fprintf(stderr, "failed: to acquire ibdev_cache_mutex %s\n",
369N/A strerror(errno));
369N/A return (NULL);
369N/A }
369N/A
4994N/A if (ibdev_cache_initialized == B_FALSE) {
4994N/A if (ibdev_cache_init() != 0) {
369N/A (void) pthread_mutex_unlock(&ibdev_cache_mutex);
369N/A fprintf(stderr, "failed to init ibdev_cache\n");
369N/A return (NULL);
369N/A }
4994N/A ibdev_cache_initialized = B_TRUE;
369N/A }
369N/A (void) pthread_mutex_unlock(&ibdev_cache_mutex);
369N/A
4994N/A info = ibdev_cache_read_by_devname(devname);
369N/A
369N/A return (info);
369N/A}
369N/A
369N/A/*
369N/A * Get the IB user verbs port info attributes for the specified device/port.
369N/A * If the address of a gid pointer is passed for "gid_table", the memory
369N/A * will be allocated and the ports gid table and returned as well. The caller
369N/A * must free this memory on successful completion. If the address of a
369N/A * pkey pointer is passed for "pkey_table", the memory will be allocated
369N/A * and the ports pkey table returned as well. The caller must free this
369N/A * memory on successful completion.
369N/A */
369N/Astatic int
369N/Aget_port_info(const char *devname, uint8_t port_num,
369N/A struct ibv_port_attr *port_attr, union ibv_gid **gid_table,
369N/A uint16_t **pkey_table)
369N/A{
369N/A struct ibv_device **root_dev_list, **dev_list = NULL;
2948N/A struct ibv_context ctx;
369N/A union ibv_gid *gids = NULL;
369N/A uint16_t *pkeys = NULL;
369N/A int i, num_dev, rv, ret = 1;
4994N/A char uverbs_devpath[MAX_OFS_DEVPATH_LEN];
369N/A
369N/A root_dev_list = dev_list = ibv_get_device_list(&num_dev);
369N/A if (!dev_list) {
369N/A fprintf(stderr, "No HCA devices found\n");
369N/A goto error_exit1;
369N/A }
369N/A
369N/A for (i = 0; i < num_dev; i++, dev_list++) {
369N/A if (strcmp(ibv_get_device_name(*dev_list), devname) == 0) {
369N/A break;
369N/A }
369N/A }
369N/A
369N/A if (i == num_dev) {
369N/A fprintf(stderr, "failed to find %s\n", devname);
369N/A goto error_exit2;
369N/A }
369N/A
4994N/A snprintf(uverbs_devpath, MAX_OFS_DEVPATH_LEN, "%s/%s",
4994N/A IB_OFS_DEVPATH_PREFIX, (*dev_list)->dev_name);
2948N/A
2948N/A ctx.device = *dev_list;
2948N/A
2948N/A if ((ctx.cmd_fd = open(uverbs_devpath, O_RDWR)) < 0)
369N/A goto error_exit2;
369N/A
2948N/A if (sol_ibv_query_port(&ctx, port_num, port_attr)) {
369N/A fprintf(stderr, "failed to query dev %p, port %d\n",
2948N/A &ctx, port_num);
369N/A goto error_exit3;
369N/A }
369N/A
369N/A if (gid_table) {
369N/A *gid_table = NULL;
369N/A gids = malloc(sizeof (union ibv_gid) * port_attr->gid_tbl_len);
369N/A if (!gids)
369N/A goto error_exit3;
369N/A /*
736N/A * set high bit of port_num to get all gids in one shot.
369N/A */
369N/A port_num |= 0x80;
2948N/A rv = sol_ibv_query_gid(&ctx, port_num, port_attr->gid_tbl_len,
736N/A gids);
736N/A if (rv != 0)
736N/A goto error_exit4;
369N/A
369N/A *gid_table = gids;
369N/A gids = NULL;
369N/A }
369N/A
369N/A if (pkey_table) {
369N/A *pkey_table = NULL;
369N/A pkeys = malloc(sizeof (uint16_t) * port_attr->pkey_tbl_len);
369N/A if (!pkeys)
369N/A goto error_exit4;
369N/A
736N/A /*
736N/A * set high bit of port_num to get all pkeys in one shot.
736N/A */
369N/A port_num |= 0x80;
2948N/A rv = sol_ibv_query_pkey(&ctx, port_num, port_attr->pkey_tbl_len,
369N/A pkeys);
736N/A if (rv != 0)
736N/A goto error_exit5;
369N/A
369N/A *pkey_table = pkeys;
369N/A pkeys = NULL;
369N/A }
369N/A
369N/A ret = 0;
369N/A
369N/A /*
369N/A * clean up and Return
369N/A */
369N/Aerror_exit5:
369N/A if (pkeys)
369N/A free(pkeys);
369N/Aerror_exit4:
369N/A if (gids)
369N/A free(gids);
369N/Aerror_exit3:
2948N/A if (ctx.cmd_fd > 0)
2948N/A close(ctx.cmd_fd);
369N/Aerror_exit2:
369N/A if (root_dev_list)
369N/A ibv_free_device_list(root_dev_list);
369N/Aerror_exit1:
369N/A return (ret);
369N/A}
369N/A
369N/A/*
369N/A * In Solaris environments, the underlying hardware driver is opened to
369N/A * perform the memory mapping operations of kernel allocated memory
369N/A * into the users address space.
369N/A */
369N/Aint
369N/Aibv_open_mmap_driver(char *dev_name)
369N/A{
369N/A int fd;
369N/A#ifndef _LP64
369N/A int tmpfd;
369N/A#endif
4994N/A int indx;
369N/A
369N/A /*
736N/A * Map the user verbs device (uverbs) to the associated
4994N/A * hca device. ibdev_cache is indexed by uverbs device minor number
4994N/A * so extracting the index here to refer to the ibdev_cache value,
369N/A */
4994N/A indx = strtol(dev_name + strlen(UVERBS_KERNEL_SYSFS_NAME_BASE),
369N/A NULL, 0);
4994N/A if (indx >= MAX_HCAS) {
369N/A fprintf(stderr, "Invalid device %s\n", dev_name);
369N/A goto err_dev;
369N/A }
369N/A
4994N/A if (!ibdev_cache[indx].ibd_valid) {
369N/A fprintf(stderr, "Invalid Device %s\n", dev_name);
369N/A goto err_dev;
369N/A }
369N/A
4994N/A fd = open(ibdev_cache[indx].ibd_hca_path, O_RDWR);
369N/A if (fd < 0) {
369N/A goto err_dev;
369N/A }
369N/A
369N/A#ifndef _LP64
369N/A /*
369N/A * libc can't handle fd's greater than 255, in order to
369N/A * ensure that these values remain available make fd > 255.
369N/A * Note: not needed for LP64
369N/A */
369N/A tmpfd = fcntl(fd, F_DUPFD, 256);
369N/A if (tmpfd >= 0) {
369N/A (void) close(fd);
369N/A fd = tmpfd;
369N/A }
369N/A#endif /* _LP64 */
369N/A
369N/A if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
369N/A fprintf(stderr, "FD_CLOEXEC failed: %s\n", strerror(errno));
369N/A goto err_close;
369N/A }
369N/A return (fd);
369N/A
369N/Aerr_close:
369N/A close(fd);
369N/Aerr_dev:
369N/A return (-1);
369N/A}
369N/A
369N/Astatic int
369N/Ainfiniband_verbs(char *path, char *buf, size_t size)
369N/A{
369N/A unsigned int device_num;
369N/A int len = -1;
4994N/A ibdev_cache_info_t *info_p;
369N/A
4994N/A if (pthread_mutex_lock(&ibdev_cache_mutex) != 0) {
4994N/A fprintf(stderr, "failed: to acquire ibdev_cache_mutex %s\n",
369N/A strerror(errno));
369N/A goto exit;
369N/A }
369N/A
4994N/A if (ibdev_cache_initialized == B_FALSE) {
4994N/A if (ibdev_cache_init() == 0)
4994N/A ibdev_cache_initialized = B_TRUE;
909N/A else {
4994N/A (void) pthread_mutex_unlock(&ibdev_cache_mutex);
909N/A#ifdef DEBUG
4994N/A fprintf(stderr, "failed: to init ibdev cache %s\n",
909N/A strerror(errno));
909N/A#endif
369N/A goto exit;
909N/A }
369N/A }
4994N/A (void) pthread_mutex_unlock(&ibdev_cache_mutex);
369N/A
369N/A if (check_path(path, CP_SOL_UVERBS, &device_num)) {
369N/A
369N/A if (device_num >= MAX_HCAS) {
369N/A fprintf(stderr, "Invalid path%s\n", path);
369N/A goto exit;
369N/A }
369N/A
4994N/A if (!ibdev_cache[device_num].ibd_valid)
369N/A goto exit;
369N/A
4994N/A info_p = &ibdev_cache[device_num];
369N/A
369N/A if (check_path(path, CP_DEVICE, NULL)) {
369N/A /*
369N/A * Under Linux, this is a link to the PCI device entry
369N/A * in /sys/devices/pci...../....
369N/A */
369N/A if (strcmp(path, "vendor") == 0) {
369N/A len = 1 + sprintf(buf, "0x%x",
4994N/A info_p->ibd_vendor_id);
369N/A } else if (strcmp(path, "device") == 0) {
369N/A len = 1 + sprintf(buf, "0x%x",
4994N/A info_p->ibd_device_id);
369N/A }
369N/A } else if (strcmp(path, "ibdev") == 0) {
4994N/A len = 1 + sprintf(buf, "%s", info_p->ibd_name);
369N/A } else if (strcmp(path, "abi_version") == 0) {
4994N/A len = 1 + sprintf(buf, "%d", info_p->ibd_abi_version);
369N/A }
369N/A } else if (strcmp(path, "abi_version") == 0) {
369N/A
369N/A if (uverbs_abi_version == -1) {
369N/A fprintf(stderr, "UVerbs ABI Version invalid\n");
369N/A
369N/A goto exit;
369N/A }
369N/A
736N/A len = 1 + sprintf(buf, "%d", uverbs_abi_version);
369N/A } else {
369N/A fprintf(stderr, "Unsupported read: %s\n", path);
369N/A }
369N/Aexit:
369N/A return (len);
369N/A}
369N/A
369N/Astatic int
369N/Ainfiniband_ports(char *path, char *buf, size_t size, char *dev_name)
369N/A{
369N/A int len = -1;
369N/A unsigned int port_num;
369N/A unsigned int gid_num;
369N/A union ibv_gid *gids;
369N/A uint64_t subnet_prefix;
369N/A uint64_t interface_id;
369N/A uint16_t *pkeys;
369N/A unsigned int pkey_num;
369N/A struct ibv_port_attr port_attr;
369N/A float rate;
369N/A
369N/A if (!(check_path(path, CP_D, &port_num)))
369N/A goto exit;
369N/A
369N/A if (check_path(path, CP_GIDS, NULL)) {
369N/A if (get_port_info(dev_name, port_num, &port_attr, &gids, NULL))
369N/A goto exit;
369N/A
369N/A gid_num = atoi(path);
369N/A
369N/A if (gid_num < port_attr.gid_tbl_len) {
369N/A
369N/A subnet_prefix =
369N/A htonll(gids[gid_num].global.subnet_prefix);
369N/A interface_id =
369N/A htonll(gids[gid_num].global.interface_id);
369N/A len = 1 + sprintf(buf,
369N/A "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
369N/A (unsigned)(subnet_prefix >> 48) & 0xffff,
369N/A (unsigned)(subnet_prefix >> 32) & 0xffff,
369N/A (unsigned)(subnet_prefix >> 16) & 0xffff,
369N/A (unsigned)(subnet_prefix >> 0) & 0xffff,
369N/A (unsigned)(interface_id >> 48) & 0xffff,
369N/A (unsigned)(interface_id >> 32) & 0xffff,
369N/A (unsigned)(interface_id >> 16) & 0xffff,
369N/A (unsigned)(interface_id >> 0) & 0xffff);
369N/A }
369N/A if (gids)
369N/A free(gids);
369N/A
369N/A } else if (check_path(path, CP_PKEYS, NULL)) {
369N/A if (get_port_info(dev_name, port_num, &port_attr, NULL, &pkeys))
369N/A goto exit;
369N/A
369N/A pkey_num = atoi(path);
369N/A if (pkey_num < port_attr.pkey_tbl_len)
369N/A len = 1 + sprintf(buf, "0x%04x", pkeys[pkey_num]);
369N/A
369N/A if (pkeys)
369N/A free(pkeys);
369N/A } else {
369N/A
369N/A if (get_port_info(dev_name, port_num, &port_attr, NULL, NULL))
369N/A goto exit;
369N/A
369N/A if (strcmp(path, "lid_mask_count") == 0) {
369N/A len = 1 + sprintf(buf, "%d", port_attr.lmc);
369N/A } else if (strcmp(path, "sm_lid") == 0) {
369N/A len = 1 + sprintf(buf, "0x%x", port_attr.sm_lid);
369N/A } else if (strcmp(path, "sm_sl") == 0) {
369N/A len = 1 + sprintf(buf, "%d", port_attr.sm_sl);
369N/A } else if (strcmp(path, "lid") == 0) {
369N/A len = 1 + sprintf(buf, "0x%x", port_attr.lid);
369N/A } else if (strcmp(path, "state") == 0) {
369N/A switch (port_attr.state) {
369N/A case IBV_PORT_NOP:
369N/A len = 1 + sprintf(buf, "%d: NOP",
369N/A port_attr.state);
369N/A break;
369N/A case IBV_PORT_DOWN:
369N/A len = 1 + sprintf(buf, "%d: DOWN",
369N/A port_attr.state);
369N/A break;
369N/A case IBV_PORT_INIT:
369N/A len = 1 + sprintf(buf, "%d: INIT",
369N/A port_attr.state);
369N/A break;
369N/A case IBV_PORT_ARMED:
369N/A len = 1 + sprintf(buf, "%d: ARMED",
369N/A port_attr.state);
369N/A break;
369N/A case IBV_PORT_ACTIVE:
369N/A len = 1 + sprintf(buf, "%d: ACTIVE",
369N/A port_attr.state);
369N/A break;
369N/A case IBV_PORT_ACTIVE_DEFER:
369N/A len = 1 + sprintf(buf,
369N/A "%d: ACTIVE_DEFER",
369N/A port_attr.state);
369N/A break;
369N/A default:
369N/A len = 1 + sprintf(buf, "%d: INVALID",
369N/A port_attr.state);
369N/A break;
369N/A }
369N/A } else if (strcmp(path, "phys_state") == 0) {
369N/A switch (port_attr.phys_state) {
369N/A case 1:
369N/A len = 1 + sprintf(buf, "%d: Sleep",
369N/A port_attr.phys_state);
369N/A break;
369N/A case 2:
369N/A len = 1 + sprintf(buf, "%d: Polling",
369N/A port_attr.phys_state);
369N/A break;
369N/A case 3:
369N/A len = 1 + sprintf(buf, "%d: Disabled",
369N/A port_attr.phys_state);
369N/A break;
369N/A case 4:
369N/A len = 1 + sprintf(buf,
369N/A "%d: PortConfigurationTraining",
369N/A port_attr.phys_state);
369N/A break;
369N/A case 5:
369N/A len = 1 + sprintf(buf, "%d: LinkUp",
369N/A port_attr.phys_state);
369N/A break;
369N/A case 6:
369N/A len = 1 + sprintf(buf,
369N/A "%d: LinkErrorRecovery",
369N/A port_attr.phys_state);
369N/A break;
369N/A case 7:
369N/A len = 1 + sprintf(buf,
369N/A "%d: Phy Test",
369N/A port_attr.phys_state);
369N/A break;
369N/A default:
369N/A len = 1 + sprintf(buf, "%d: <unknown>",
369N/A port_attr.phys_state);
369N/A break;
369N/A }
369N/A } else if (strcmp(path, "rate") == 0) {
369N/A /* rate = speed * width */
369N/A switch (port_attr.active_speed) {
369N/A case 1:
369N/A rate = 2.5;
369N/A break;
369N/A case 2:
369N/A rate = 5;
369N/A break;
369N/A case 4:
4994N/A /* FALLTHROUGH */
4994N/A case 8:
369N/A rate = 10;
369N/A break;
4994N/A case 16:
4994N/A rate = 14.0625;
4994N/A break;
4994N/A case 32:
4994N/A rate = 25.78125;
4994N/A break;
369N/A default:
369N/A rate = 0;
369N/A }
369N/A switch (port_attr.active_width) {
369N/A case 1:
369N/A break;
369N/A case 2:
369N/A rate = 4 * rate;
369N/A break;
369N/A case 4:
369N/A rate = 8 * rate;
369N/A break;
369N/A case 8:
369N/A rate = 12 * rate;
369N/A break;
369N/A default:
369N/A rate = 0;
369N/A }
369N/A len = 1 + sprintf(buf, "%f", rate);
369N/A } else if (strcmp(path, "cap_mask") == 0) {
369N/A len = 1 + sprintf(buf, "0x%08x",
369N/A port_attr.port_cap_flags);
3679N/A } else if (strcmp(path, "link_layer") == 0) {
3679N/A switch (port_attr.link_layer) {
3679N/A case IBV_LINK_LAYER_UNSPECIFIED:
3679N/A case IBV_LINK_LAYER_INFINIBAND:
3679N/A len = 1 + sprintf(buf, "%s", "IB");
3679N/A break;
3679N/A case IBV_LINK_LAYER_ETHERNET:
3679N/A len =
3679N/A 1 + sprintf(buf, "%s", "Ethernet");
3679N/A break;
3679N/A default:
3679N/A len = 1 + sprintf(buf, "%s", "Unknown");
3679N/A }
369N/A }
369N/A }
369N/Aexit:
369N/A return (len);
369N/A}
369N/A
369N/Astatic int
369N/Ainfiniband(char *path, char *buf, size_t size)
369N/A{
369N/A int len = -1;
4994N/A char dev_name[MAXNAMELEN];
369N/A ibdev_cache_info_t *info;
369N/A
4994N/A memset(dev_name, 0, MAXNAMELEN);
369N/A
4994N/A if (!check_path_for_hca(path, dev_name))
369N/A goto exit;
369N/A
369N/A if (check_path(path, CP_PORTS, NULL)) {
369N/A len = infiniband_ports(path, buf, size, dev_name);
369N/A } else if (strcmp(path, "node_type") == 0) {
369N/A len = 1 + sprintf(buf, "%d", IBV_NODE_CA);
369N/A } else {
369N/A if (!(info = get_device_info(dev_name)))
369N/A goto exit;
369N/A
369N/A if (strcmp(path, "node_guid") == 0) {
369N/A len = 1 + sprintf(buf, "%s", info->ibd_node_guid_str);
909N/A } else if (strcmp(path, "node_guid_external") == 0) {
909N/A len = 1 + sprintf(buf, "%s",
909N/A info->ibd_node_guid_external_str);
369N/A } else if (strcmp(path, "sys_image_guid") == 0) {
369N/A len = 1 + sprintf(buf, "%s", info->ibd_sys_image_guid);
369N/A } else if (strcmp(path, "fw_ver") == 0) {
369N/A len = 1 + sprintf(buf, "%s", info->ibd_fw_ver);
369N/A } else if (strcmp(path, "hw_rev") == 0) {
369N/A len = 1 + sprintf(buf, "%d", info->ibd_hw_rev);
369N/A } else if (strcmp(path, "hca_type") == 0) {
4994N/A len = 1 + sprintf(buf, "%s", info->ibd_devid_string);
369N/A } else if (strcmp(path, "board_id") == 0) {
4994N/A len = 1 + sprintf(buf, "%s", info->ibd_boardid_string);
369N/A }
369N/A }
369N/Aexit:
369N/A return (len);
369N/A}
369N/A
369N/Astatic int
369N/Ainfiniband_mad(char *path, char *buf, size_t size)
369N/A{
369N/A int len = -1;
369N/A unsigned int dev_num;
369N/A
369N/A if (pthread_mutex_lock(&umad_cache_mutex) != 0) {
369N/A fprintf(stderr, "failed: to acquire umad_cache_mutex %s\n",
369N/A strerror(errno));
369N/A goto exit;
369N/A }
4994N/A if (umad_cache_initialized == B_FALSE) {
4994N/A if (umad_cache_init() == 0)
369N/A umad_cache_initialized = B_TRUE;
909N/A else {
909N/A (void) pthread_mutex_unlock(&umad_cache_mutex);
909N/A#ifdef DEBUG
909N/A fprintf(stderr, "failed: to init umad cache %s\n",
909N/A strerror(errno));
909N/A#endif
369N/A goto exit;
909N/A }
369N/A }
369N/A (void) pthread_mutex_unlock(&umad_cache_mutex);
369N/A
369N/A if (check_path(path, CP_UMAD, &dev_num)) {
3679N/A if (dev_num >= MAX_PORTS) {
369N/A fprintf(stderr, "Invalid Path: %s\n", path);
369N/A goto exit;
369N/A }
369N/A if (!umad_dev_cache[dev_num].umc_valid) {
369N/A goto exit;
369N/A }
369N/A if (strcmp(path, "ibdev") == 0) {
369N/A len = strlcpy(buf, umad_dev_cache[dev_num].umc_ib_dev,
369N/A size) + 1;
369N/A } else if (strcmp(path, "port") == 0) {
369N/A len = 1 + sprintf(buf, "%d",
369N/A umad_dev_cache[dev_num].umc_port);
369N/A }
369N/A } else if (strcmp(path, "abi_version") == 0) {
369N/A if (umad_abi_version == -1) {
369N/A fprintf(stderr, "UMAD ABI Version invalid\n");
369N/A goto exit;
369N/A }
369N/A len =
369N/A 1 + sprintf(buf, "%d", umad_abi_version);
369N/A }
369N/Aexit:
369N/A return (len);
369N/A}
369N/A
369N/A/*
369N/A * Return -1 on error, or the length of the data (buf) on success.
369N/A */
369N/Aint
369N/Asol_read_sysfs_file(char *path, char *buf, size_t size)
369N/A{
369N/A int len = -1;
369N/A
369N/A if (!initialized) {
369N/A if (pthread_once(&oneTimeInit, initialize)) {
369N/A fprintf(stderr, "failed to initialize: %s\n",
369N/A strerror(errno));
369N/A goto exit;
369N/A }
369N/A if (!initialized)
369N/A /*
369N/A * There was a problem in initialize()
369N/A */
369N/A goto exit;
369N/A }
369N/A
369N/A if (!check_path(path, CP_SLASH, NULL))
369N/A goto exit;
369N/A
369N/A if (!check_path(path, CP_SYS, NULL))
369N/A goto exit;
369N/A
369N/A if (!check_path(path, CP_CLASS, NULL))
369N/A goto exit;
369N/A
369N/A if (check_path(path, CP_INFINIBAND_VERBS, NULL)) {
369N/A len = infiniband_verbs(path, buf, size);
369N/A } else if (check_path(path, CP_INFINIBAND, NULL)) {
369N/A len = infiniband(path, buf, size);
369N/A } else if (check_path(path, CP_INFINIBAND_MAD, NULL)) {
369N/A len = infiniband_mad(path, buf, size);
369N/A } else if (check_path(path, CP_MISC, NULL)) {
369N/A if (check_path(path, CP_RDMA_CM, NULL)) {
369N/A if (strcmp(path, "abi_version") == 0) {
369N/A len = 1 + sprintf(buf, "%d",
369N/A RDMA_USER_CM_MAX_ABI_VERSION);
369N/A }
369N/A }
369N/A }
369N/Aexit:
369N/A return (len);
369N/A}
369N/A
369N/A
369N/Aint
736N/Asol_get_cpu_info(sol_cpu_info_t **info_p)
369N/A{
369N/A kstat_t *ksp;
369N/A kstat_named_t *knp;
736N/A uint_t ncpus = 0, i;
736N/A sol_cpu_info_t *info;
736N/A
736N/A ncpus = sysconf(_SC_NPROCESSORS_ONLN);
736N/A
736N/A if (ncpus <= 0)
736N/A return (0);
736N/A
736N/A if (!(*info_p = malloc(ncpus * sizeof (sol_cpu_info_t))))
736N/A return (-1);
736N/A
736N/A info = *info_p;
736N/A bzero((void *)info, ncpus * sizeof (sol_cpu_info_t));
736N/A
736N/A for (i = 0; i < ncpus; i++) {
736N/A if ((ksp = kstat_lookup(kc, "cpu_info", i, NULL)) == NULL) {
736N/A if (i >= ncpus)
736N/A goto err_exit;
736N/A else
736N/A continue;
736N/A }
736N/A
736N/A if ((kstat_read(kc, ksp, NULL) == -1)) {
736N/A if (i >= ncpus)
736N/A goto err_exit;
736N/A else
736N/A continue;
736N/A }
736N/A
736N/A if ((knp = (kstat_named_t *)kstat_data_lookup(ksp, "brand"))
736N/A == NULL) {
736N/A if (i >= ncpus)
736N/A goto err_exit;
736N/A else
736N/A continue;
736N/A }
736N/A
736N/A (void) strlcpy(info[i].cpu_name, knp->value.str.addr.ptr,
736N/A knp->value.str.len);
736N/A
736N/A if ((knp = (kstat_named_t *)kstat_data_lookup(ksp, "clock_MHz"))
736N/A == NULL) {
736N/A if (i >= ncpus)
736N/A goto err_exit;
736N/A else
736N/A continue;
736N/A }
736N/A
736N/A info[i].cpu_mhz = knp->value.ui64;
736N/A info[i].cpu_number = i;
736N/A }
736N/A return (ncpus);
736N/Aerr_exit:
736N/A free(info);
736N/A return (-1);
736N/A}
736N/A
736N/Aint
736N/Asol_get_cpu_stats(sol_cpu_stats_t *stats)
736N/A{
736N/A size_t i, nr_cpus;
736N/A kstat_t *ksp;
736N/A kstat_named_t *knp;
369N/A
4994N/A memset(stats, 0, sizeof (sol_cpu_stats_t));
736N/A nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
736N/A
736N/A /* Aggregate the value of all CPUs */
736N/A for (i = 0; i < nr_cpus; i++) {
736N/A /*
736N/A * In case of some cpu_id doesn't have kstat info.,
736N/A * skip it and continue if it isn't the last one.
736N/A */
736N/A if ((ksp = kstat_lookup(kc, "cpu", i, "sys")) == NULL) {
736N/A if (i >= nr_cpus)
736N/A return (-1);
736N/A else
736N/A continue;
736N/A }
736N/A
736N/A if (kstat_read(kc, ksp, NULL) == -1) {
736N/A if (i >= nr_cpus)
736N/A return (-1);
736N/A else
736N/A continue;
736N/A }
736N/A
736N/A if ((knp = (kstat_named_t *)
736N/A kstat_data_lookup(ksp, "cpu_ticks_user")) == NULL) {
736N/A if (i >= nr_cpus)
736N/A return (-1);
736N/A else
736N/A continue;
736N/A }
736N/A
736N/A stats->t_user += knp->value.ui64;
736N/A
736N/A if ((knp = (kstat_named_t *)
736N/A kstat_data_lookup(ksp, "cpu_ticks_kernel")) == NULL) {
736N/A if ((knp == NULL) && i >= nr_cpus)
736N/A return (-1);
736N/A else
736N/A continue;
736N/A }
736N/A stats->t_kernel += knp->value.ui64;
736N/A
736N/A if ((knp = (kstat_named_t *)
736N/A kstat_data_lookup(ksp, "cpu_ticks_idle")) == NULL) {
736N/A if (i >= nr_cpus)
736N/A return (-1);
736N/A else
736N/A continue;
736N/A }
736N/A stats->t_idle += knp->value.ui64;
736N/A
736N/A if ((knp = (kstat_named_t *)
736N/A kstat_data_lookup(ksp, "cpu_ticks_wait")) == NULL) {
736N/A if (i >= nr_cpus)
736N/A return (-1);
736N/A else
736N/A continue;
736N/A }
736N/A stats->t_iowait += knp->value.ui64;
736N/A
736N/A if ((knp = (kstat_named_t *)
736N/A kstat_data_lookup(ksp, "cpu_nsec_intr")) == NULL) {
736N/A if (i >= nr_cpus)
736N/A return (-1);
736N/A else
736N/A continue;
736N/A }
736N/A stats->t_intr += knp->value.ui64; /* This is in NSEC */
736N/A }
736N/A return (0);
736N/A}
736N/A
736N/Aint
736N/Asol_ibv_query_gid(struct ibv_context *context, uint8_t port_num, int index,
736N/A union ibv_gid *gid)
736N/A{
2948N/A int count, start;
2948N/A sol_uverbs_gid_t *uverbs_gidp;
736N/A
369N/A /*
736N/A * Not exported via sysfs, use ioctl.
369N/A */
736N/A if (!context || !gid || (index < 0) ||
736N/A ((port_num & 0x80) && (index == 0)))
369N/A return (-1);
369N/A
736N/A if (port_num & 0x80) {
736N/A start = 0;
736N/A count = index;
736N/A } else {
736N/A start = index;
736N/A count = 1;
736N/A }
736N/A
736N/A uverbs_gidp = (sol_uverbs_gid_t *)malloc(count *
736N/A sizeof (union ibv_gid) + sizeof (sol_uverbs_gid_t));
736N/A if (uverbs_gidp == NULL) {
736N/A return (-1);
736N/A }
736N/A
736N/A uverbs_gidp->uverbs_port_num = port_num & 0x7F;
736N/A uverbs_gidp->uverbs_gid_cnt = count;
736N/A uverbs_gidp->uverbs_gid_start_index = start;
736N/A
2948N/A if (ioctl(context->cmd_fd, UVERBS_IOCTL_GET_GIDS, uverbs_gidp) != 0) {
736N/A#ifdef DEBUG
736N/A fprintf(stderr, "UVERBS_IOCTL_GET_GIDS failed: %s\n",
736N/A strerror(errno));
736N/A#endif
736N/A goto gid_error_exit;
736N/A }
736N/A
736N/A if (uverbs_gidp->uverbs_solaris_abi_version !=
736N/A IB_USER_VERBS_SOLARIS_ABI_VERSION) {
736N/A#ifdef DEBUG
736N/A fprintf(stderr, "sol_uverbs solaris_abi_version != "
736N/A "IB_USER_VERBS_SOLARIS_ABI_VERSION : %d\n",
736N/A uverbs_gidp->uverbs_solaris_abi_version);
736N/A#endif
736N/A goto gid_error_exit;
736N/A }
736N/A memcpy(gid, uverbs_gidp->uverbs_gids, sizeof (union ibv_gid) * count);
736N/A free(uverbs_gidp);
736N/A return (0);
736N/A
736N/Agid_error_exit:
736N/A free(uverbs_gidp);
736N/A return (-1);
736N/A}
736N/A
736N/Aint
736N/Asol_ibv_query_pkey(struct ibv_context *context, uint8_t port_num,
736N/A int index, uint16_t *pkey)
736N/A{
2948N/A int count, start;
2948N/A sol_uverbs_pkey_t *uverbs_pkeyp;
736N/A
736N/A /*
736N/A * Not exported via sysfs, use ioctl.
736N/A */
736N/A if (!context || !pkey || (index < 0) ||
736N/A ((port_num & 0x80) && (index == 0)))
369N/A return (-1);
369N/A
2948N/A if (context->cmd_fd < 0)
736N/A return (-1);
736N/A
736N/A if (port_num & 0x80) {
736N/A start = 0;
736N/A count = index;
736N/A } else {
736N/A start = index;
736N/A count = 1;
736N/A }
736N/A
736N/A uverbs_pkeyp = (sol_uverbs_pkey_t *)malloc(count *
736N/A sizeof (uint16_t) + sizeof (sol_uverbs_pkey_t));
736N/A if (uverbs_pkeyp == NULL) {
736N/A return (-1);
736N/A }
736N/A
736N/A uverbs_pkeyp->uverbs_port_num = port_num & 0x7F;
736N/A uverbs_pkeyp->uverbs_pkey_cnt = count;
736N/A uverbs_pkeyp->uverbs_pkey_start_index = start;
369N/A
2948N/A if (ioctl(context->cmd_fd, UVERBS_IOCTL_GET_PKEYS, uverbs_pkeyp) != 0) {
736N/A#ifdef DEBUG
736N/A fprintf(stderr, "UVERBS_IOCTL_GET_PKEYS failed: %s\n",
736N/A strerror(errno));
736N/A#endif
736N/A goto pkey_error_exit;
736N/A }
369N/A
736N/A if (uverbs_pkeyp->uverbs_solaris_abi_version !=
736N/A IB_USER_VERBS_SOLARIS_ABI_VERSION) {
736N/A#ifdef DEBUG
736N/A fprintf(stderr, "sol_uverbs solaris_abi_version != "
736N/A "IB_USER_VERBS_SOLARIS_ABI_VERSION : %d\n",
736N/A uverbs_pkeyp->uverbs_solaris_abi_version);
736N/A#endif
736N/A goto pkey_error_exit;
736N/A }
736N/A memcpy(pkey, uverbs_pkeyp->uverbs_pkey, sizeof (uint16_t) * count);
736N/A free(uverbs_pkeyp);
369N/A return (0);
736N/A
736N/Apkey_error_exit:
736N/A free(uverbs_pkeyp);
736N/A return (-1);
369N/A}
2948N/A
2948N/Aint
2948N/Asol_ibv_query_device(struct ibv_device *device, struct ibv_device_attr *attr)
2948N/A{
2948N/A struct ibv_query_device cmd;
2948N/A struct ibv_context context;
4994N/A char uverbs_devpath[MAX_OFS_DEVPATH_LEN];
4994N/A int ret;
2948N/A uint64_t raw_fw_ver;
2948N/A unsigned major, minor, sub_minor;
2948N/A
2948N/A context.device = device;
2948N/A
2948N/A if (!device || !attr)
2948N/A return (-1);
2948N/A
4994N/A snprintf(uverbs_devpath, MAX_OFS_DEVPATH_LEN, "%s/%s",
4994N/A IB_OFS_DEVPATH_PREFIX, device->dev_name);
2948N/A
2948N/A if ((context.cmd_fd = open(uverbs_devpath, O_RDWR)) < 0)
2948N/A return (-1);
2948N/A
2948N/A ret = ibv_cmd_query_device(&context, attr, &raw_fw_ver, &cmd,
2948N/A sizeof (cmd));
2948N/A
2948N/A if (ret)
2948N/A return (ret);
2948N/A
2948N/A major = (raw_fw_ver >> 32) & 0xffff;
2948N/A minor = (raw_fw_ver >> 16) & 0xffff;
2948N/A sub_minor = raw_fw_ver & 0xffff;
2948N/A
2948N/A snprintf(attr->fw_ver, sizeof (attr->fw_ver),
2948N/A "%d.%d.%03d", major, minor, sub_minor);
2948N/A
2948N/A close(context.cmd_fd);
2948N/A return (0);
2948N/A}
2948N/A
2948N/Aint
2948N/Asol_ibv_query_port(struct ibv_context *context, uint8_t port,
2948N/A struct ibv_port_attr *attr)
2948N/A{
2948N/A struct ibv_query_port cmd;
2948N/A
2948N/A return (ibv_cmd_query_port(context, port, attr, &cmd, sizeof (cmd)));
2948N/A}
369N/A#endif