static struct verbs_device *mlx5_driver_init(const char *uverbs_sys_path, int abi_version) { char value[8]; struct mlx5_device *dev; unsigned vendor, device; int i; if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor", value, sizeof value) < 0) return NULL; sscanf(value, "%i", &vendor); if (ibv_read_sysfs_file(uverbs_sys_path, "device/device", value, sizeof value) < 0) return NULL; sscanf(value, "%i", &device); for (i = 0; i < sizeof hca_table / sizeof hca_table[0]; ++i) if (vendor == hca_table[i].vendor && device == hca_table[i].device) goto found; return NULL; found: if (abi_version < MLX5_UVERBS_MIN_ABI_VERSION || abi_version > MLX5_UVERBS_MAX_ABI_VERSION) { fprintf(stderr, PFX "Fatal: ABI version %d of %s is not supported " "(min supported %d, max supported %d)\n", abi_version, uverbs_sys_path, MLX5_UVERBS_MIN_ABI_VERSION, MLX5_UVERBS_MAX_ABI_VERSION); return NULL; } dev = malloc(sizeof *dev); if (!dev) { fprintf(stderr, PFX "Fatal: couldn't allocate device for %s\n", uverbs_sys_path); return NULL; } dev->page_size = sysconf(_SC_PAGESIZE); dev->devid.id = device; dev->driver_abi_ver = abi_version; dev->verbs_dev.sz = sizeof(dev->verbs_dev); dev->verbs_dev.size_of_context = sizeof(struct mlx5_context) - sizeof(struct ibv_context); /* * mlx5_init_context will initialize provider calls */ dev->verbs_dev.init_context = mlx5_alloc_context; dev->verbs_dev.uninit_context = mlx5_free_context; return &dev->verbs_dev; }
static int check_abi_version(void) { char value[8]; if ((ibv_read_sysfs_file(ibv_get_sysfs_path(), "class/misc/rdma_cm/abi_version", value, sizeof value) < 0) && (ibv_read_sysfs_file(ibv_get_sysfs_path(), "class/infiniband_ucma/abi_version", value, sizeof value) < 0)) { /* * Older version of Linux do not have class/misc. To support * backports, assume the most recent version of the ABI. If * we're wrong, we'll simply fail later when calling the ABI. */ fprintf(stderr, "librdmacm: couldn't read ABI version.\n"); fprintf(stderr, "librdmacm: assuming: %d\n", abi_ver); return 0; } abi_ver = strtol(value, NULL, 10); if (abi_ver < RDMA_USER_CM_MIN_ABI_VERSION || abi_ver > RDMA_USER_CM_MAX_ABI_VERSION) { fprintf(stderr, "librdmacm: kernel ABI version %d " "doesn't match library version %d.\n", abi_ver, RDMA_USER_CM_MAX_ABI_VERSION); return -1; } return 0; }
static struct ibv_device *mlx4_driver_init(const char *uverbs_sys_path, int abi_version) { char value[8]; struct mlx4_device *dev; unsigned vendor, device; int i; if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor", value, sizeof value) < 0) return NULL; sscanf(value, "%i", &vendor); if (ibv_read_sysfs_file(uverbs_sys_path, "device/device", value, sizeof value) < 0) return NULL; sscanf(value, "%i", &device); for (i = 0; i < sizeof hca_table / sizeof hca_table[0]; ++i) if (vendor == hca_table[i].vendor && device == hca_table[i].device) goto found; return NULL; found: if (abi_version < MLX4_UVERBS_MIN_ABI_VERSION || abi_version > MLX4_UVERBS_MAX_ABI_VERSION) { fprintf(stderr, PFX "Fatal: ABI version %d of %s is not supported " "(min supported %d, max supported %d)\n", abi_version, uverbs_sys_path, MLX4_UVERBS_MIN_ABI_VERSION, MLX4_UVERBS_MAX_ABI_VERSION); return NULL; } dev = malloc(sizeof *dev); if (!dev) { fprintf(stderr, PFX "Fatal: couldn't allocate device for %s\n", uverbs_sys_path); return NULL; } dev->ibv_dev.ops = mlx4_dev_ops; dev->page_size = sysconf(_SC_PAGESIZE); return &dev->ibv_dev; }
static struct ibv_device *fake_driver_init(const char *uverbs_sys_path, int abi_version) { char value[8]; int vendor; /* This function should only be invoked for /sys/class/infiniband/usnic_X devices, but double check just to be absolutely sure: read the vendor ID and ensure that it is Cisco. */ if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor", value, sizeof(value)) < 0) { return NULL; } if (sscanf(value, "%i", &vendor) != 1) { return NULL; } if (vendor == PCI_VENDOR_ID_CISCO) { return &fake_dev; } /* We didn't find a device that we want to support */ return NULL; }
/* * Export the old libsysfs sysfs_class_device-based driver entry point * if libibverbs does not export an ibv_register_driver() function. */ struct ibv_device *openib_driver_init(struct sysfs_class_device *sysdev) { int abi_ver = 0; char value[8]; if (ibv_read_sysfs_file(sysdev->path, "abi_version", value, sizeof value) > 0) abi_ver = strtol(value, NULL, 10); return mthca_driver_init(sysdev->path, abi_ver); }
int __ibv_query_pkey(struct ibv_context *context, uint8_t port_num, int index, uint16_t *pkey) { char name[24]; char attr[8]; uint16_t val; snprintf(name, sizeof name, "ports/%d/pkeys/%d", port_num, index); if (ibv_read_sysfs_file(context->device->ibdev_path, name, attr, sizeof attr) < 0) return -1; if (sscanf(attr, "%hx", &val) != 1) return -1; *pkey = htons(val); return 0; }
uint64_t __ibv_get_device_guid(struct ibv_device *device) { char attr[24]; uint64_t guid = 0; uint16_t parts[4]; int i; if (ibv_read_sysfs_file(device->ibdev_path, "node_guid", attr, sizeof attr) < 0) return 0; if (sscanf(attr, "%hx:%hx:%hx:%hx", parts, parts + 1, parts + 2, parts + 3) != 4) return 0; for (i = 0; i < 4; ++i) guid = (guid << 16) | parts[i]; return htonll(guid); }
static struct ibv_device *try_driver(struct ibv_driver *driver, struct ibv_sysfs_dev *sysfs_dev) { struct ibv_device *dev; char value[8]; dev = driver->init_func(sysfs_dev->sysfs_path, sysfs_dev->abi_ver); if (!dev) return NULL; if (ibv_read_sysfs_file(sysfs_dev->ibdev_path, "node_type", value, sizeof value) < 0) { fprintf(stderr, PFX "Warning: no node_type attr under %s.\n", sysfs_dev->ibdev_path); dev->node_type = IBV_NODE_UNKNOWN; } else { dev->node_type = strtol(value, NULL, 10); if (dev->node_type < IBV_NODE_CA || dev->node_type > IBV_NODE_RNIC) dev->node_type = IBV_NODE_UNKNOWN; } switch (dev->node_type) { case IBV_NODE_CA: case IBV_NODE_SWITCH: case IBV_NODE_ROUTER: dev->transport_type = IBV_TRANSPORT_IB; break; case IBV_NODE_RNIC: dev->transport_type = IBV_TRANSPORT_IWARP; break; default: dev->transport_type = IBV_TRANSPORT_UNKNOWN; break; } strcpy(dev->dev_name, sysfs_dev->sysfs_name); strcpy(dev->dev_path, sysfs_dev->sysfs_path); strcpy(dev->name, sysfs_dev->ibdev_name); strcpy(dev->ibdev_path, sysfs_dev->ibdev_path); return dev; }
static int check_abi_version(const char *path) { char value[8]; if (ibv_read_sysfs_file(path, "class/infiniband_verbs/abi_version", value, sizeof value) < 0) { return ENOSYS; } abi_ver = strtol(value, NULL, 10); if (abi_ver < IB_USER_VERBS_MIN_ABI_VERSION || abi_ver > IB_USER_VERBS_MAX_ABI_VERSION) { fprintf(stderr, PFX "Fatal: kernel ABI version %d " "doesn't match library version %d.\n", abi_ver, IB_USER_VERBS_MAX_ABI_VERSION); return ENOSYS; } return 0; }
int __ibv_query_gid(struct ibv_context *context, uint8_t port_num, int index, union ibv_gid *gid) { char name[24]; char attr[41]; uint16_t val; int i; snprintf(name, sizeof name, "ports/%d/gids/%d", port_num, index); if (ibv_read_sysfs_file(context->device->ibdev_path, name, attr, sizeof attr) < 0) return -1; for (i = 0; i < 8; ++i) { if (sscanf(attr + i * 5, "%hx", &val) != 1) return -1; gid->raw[i * 2 ] = val >> 8; gid->raw[i * 2 + 1] = val & 0xff; } return 0; }
static int find_sysfs_devs(void) { char class_path[IBV_SYSFS_PATH_MAX]; DIR *class_dir; struct dirent *dent; struct ibv_sysfs_dev *sysfs_dev = NULL; char value[8]; int ret = 0; snprintf(class_path, sizeof class_path, "%s/class/infiniband_verbs", ibv_get_sysfs_path()); class_dir = opendir(class_path); if (!class_dir) return ENOSYS; while ((dent = readdir(class_dir))) { struct stat buf; if (dent->d_name[0] == '.') continue; if (!sysfs_dev) sysfs_dev = malloc(sizeof *sysfs_dev); if (!sysfs_dev) { ret = ENOMEM; goto out; } snprintf(sysfs_dev->sysfs_path, sizeof sysfs_dev->sysfs_path, "%s/%s", class_path, dent->d_name); if (stat(sysfs_dev->sysfs_path, &buf)) { fprintf(stderr, PFX "Warning: couldn't stat '%s'.\n", sysfs_dev->sysfs_path); continue; } if (!S_ISDIR(buf.st_mode)) continue; snprintf(sysfs_dev->sysfs_name, sizeof sysfs_dev->sysfs_name, "%s", dent->d_name); if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "ibdev", sysfs_dev->ibdev_name, sizeof sysfs_dev->ibdev_name) < 0) { fprintf(stderr, PFX "Warning: no ibdev class attr for '%s'.\n", dent->d_name); continue; } snprintf(sysfs_dev->ibdev_path, sizeof sysfs_dev->ibdev_path, "%s/class/infiniband/%s", ibv_get_sysfs_path(), sysfs_dev->ibdev_name); sysfs_dev->next = sysfs_dev_list; sysfs_dev->have_driver = 0; if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "abi_version", value, sizeof value) > 0) sysfs_dev->abi_ver = strtol(value, NULL, 10); else sysfs_dev->abi_ver = 0; sysfs_dev_list = sysfs_dev; sysfs_dev = NULL; } out: if (sysfs_dev) free(sysfs_dev); closedir(class_dir); return ret; }
static int __ibv_exp_query_gid_attr(struct ibv_context *context, uint8_t port_num, unsigned int index, struct ibv_exp_gid_attr *attr) { char *dir_path; char name[32]; char buff[41]; DIR *dir; if (attr->comp_mask & ~(IBV_EXP_QUERY_GID_ATTR_RESERVED - 1)) return ENOTSUP; if (attr->comp_mask & IBV_EXP_QUERY_GID_ATTR_TYPE) { snprintf(name, sizeof(name), "ports/%d/gid_attrs/types/%d", port_num, index); if (ibv_read_sysfs_file(context->device->ibdev_path, name, buff, sizeof(buff)) <= 0) { if (errno == EINVAL) { /* In IB, this file doesn't exist and we return * -EINVAL. */ attr->type = IBV_EXP_IB_ROCE_V1_GID_TYPE; goto query_gid; } if (asprintf(&dir_path, "%s/%s", context->device->ibdev_path, "ports/1/gid_attrs/") < 0) return ENOMEM; dir = opendir(dir_path); free(dir_path); if (!dir) { if (errno == ENOENT) /* Assuming that if gid_attrs doesn't * exist, we have an old kernel and all * GIDs are IB/RoCE v1 */ attr->type = IBV_EXP_IB_ROCE_V1_GID_TYPE; else return errno; } else { closedir(dir); return EINVAL; } } else { if (!strcmp(buff, "IB/RoCE V1")) attr->type = IBV_EXP_IB_ROCE_V1_GID_TYPE; else if (!strcmp(buff, "RoCE V2")) attr->type = IBV_EXP_ROCE_V2_GID_TYPE; else if (!strcmp(buff, "RoCE V1.5")) attr->type = IBV_EXP_ROCE_V1_5_GID_TYPE; else return EINVAL; } } query_gid: if (attr->comp_mask & IBV_EXP_QUERY_GID_ATTR_GID) { if (ibv_query_gid(context, port_num, index, &attr->gid)) return ENOENT; } return 0; }