1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 3219820Sjeff * Copyright (c) 2006 Cisco Systems, Inc. All rights reserved. 4219820Sjeff * 5219820Sjeff * This software is available to you under a choice of one of two 6219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 7219820Sjeff * General Public License (GPL) Version 2, available from the file 8219820Sjeff * COPYING in the main directory of this source tree, or the 9219820Sjeff * OpenIB.org BSD license below: 10219820Sjeff * 11219820Sjeff * Redistribution and use in source and binary forms, with or 12219820Sjeff * without modification, are permitted provided that the following 13219820Sjeff * conditions are met: 14219820Sjeff * 15219820Sjeff * - Redistributions of source code must retain the above 16219820Sjeff * copyright notice, this list of conditions and the following 17219820Sjeff * disclaimer. 18219820Sjeff * 19219820Sjeff * - Redistributions in binary form must reproduce the above 20219820Sjeff * copyright notice, this list of conditions and the following 21219820Sjeff * disclaimer in the documentation and/or other materials 22219820Sjeff * provided with the distribution. 23219820Sjeff * 24219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31219820Sjeff * SOFTWARE. 32219820Sjeff */ 33219820Sjeff 34219820Sjeff#if HAVE_CONFIG_H 35219820Sjeff# include <config.h> 36219820Sjeff#endif /* HAVE_CONFIG_H */ 37219820Sjeff 38219820Sjeff#include <stdlib.h> 39219820Sjeff#include <string.h> 40219820Sjeff#include <glob.h> 41219820Sjeff#include <stdio.h> 42219820Sjeff#include <dlfcn.h> 43219820Sjeff#include <unistd.h> 44219820Sjeff#include <sys/stat.h> 45219820Sjeff#include <sys/types.h> 46219820Sjeff#include <sys/time.h> 47219820Sjeff#include <sys/resource.h> 48219820Sjeff#include <dirent.h> 49219820Sjeff#include <errno.h> 50219820Sjeff 51219820Sjeff#include "ibverbs.h" 52219820Sjeff 53219820SjeffHIDDEN int abi_ver; 54219820Sjeff 55219820Sjeffstruct ibv_sysfs_dev { 56219820Sjeff char sysfs_name[IBV_SYSFS_NAME_MAX]; 57219820Sjeff char ibdev_name[IBV_SYSFS_NAME_MAX]; 58219820Sjeff char sysfs_path[IBV_SYSFS_PATH_MAX]; 59219820Sjeff char ibdev_path[IBV_SYSFS_PATH_MAX]; 60219820Sjeff struct ibv_sysfs_dev *next; 61219820Sjeff int abi_ver; 62219820Sjeff int have_driver; 63219820Sjeff}; 64219820Sjeff 65219820Sjeffstruct ibv_driver_name { 66219820Sjeff char *name; 67219820Sjeff struct ibv_driver_name *next; 68219820Sjeff}; 69219820Sjeff 70219820Sjeffstruct ibv_driver { 71219820Sjeff const char *name; 72219820Sjeff ibv_driver_init_func init_func; 73219820Sjeff struct ibv_driver *next; 74219820Sjeff}; 75219820Sjeff 76219820Sjeffstatic struct ibv_sysfs_dev *sysfs_dev_list; 77219820Sjeffstatic struct ibv_driver_name *driver_name_list; 78219820Sjeffstatic struct ibv_driver *head_driver, *tail_driver; 79219820Sjeff 80219820Sjeffstatic int find_sysfs_devs(void) 81219820Sjeff{ 82219820Sjeff#ifdef __linux__ 83219820Sjeff char class_path[IBV_SYSFS_PATH_MAX]; 84219820Sjeff DIR *class_dir; 85219820Sjeff struct dirent *dent; 86219820Sjeff struct ibv_sysfs_dev *sysfs_dev = NULL; 87219820Sjeff char value[8]; 88219820Sjeff int ret = 0; 89219820Sjeff 90219820Sjeff snprintf(class_path, sizeof class_path, "%s/class/infiniband_verbs", 91219820Sjeff ibv_get_sysfs_path()); 92219820Sjeff 93219820Sjeff class_dir = opendir(class_path); 94219820Sjeff if (!class_dir) 95219820Sjeff return ENOSYS; 96219820Sjeff 97219820Sjeff while ((dent = readdir(class_dir))) { 98219820Sjeff struct stat buf; 99219820Sjeff 100219820Sjeff if (dent->d_name[0] == '.') 101219820Sjeff continue; 102219820Sjeff 103219820Sjeff if (!sysfs_dev) 104219820Sjeff sysfs_dev = malloc(sizeof *sysfs_dev); 105219820Sjeff if (!sysfs_dev) { 106219820Sjeff ret = ENOMEM; 107219820Sjeff goto out; 108219820Sjeff } 109219820Sjeff 110219820Sjeff snprintf(sysfs_dev->sysfs_path, sizeof sysfs_dev->sysfs_path, 111219820Sjeff "%s/%s", class_path, dent->d_name); 112219820Sjeff 113219820Sjeff if (stat(sysfs_dev->sysfs_path, &buf)) { 114219820Sjeff fprintf(stderr, PFX "Warning: couldn't stat '%s'.\n", 115219820Sjeff sysfs_dev->sysfs_path); 116219820Sjeff continue; 117219820Sjeff } 118219820Sjeff 119219820Sjeff if (!S_ISDIR(buf.st_mode)) 120219820Sjeff continue; 121219820Sjeff 122219820Sjeff snprintf(sysfs_dev->sysfs_name, sizeof sysfs_dev->sysfs_name, 123219820Sjeff "%s", dent->d_name); 124219820Sjeff 125219820Sjeff if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "ibdev", 126219820Sjeff sysfs_dev->ibdev_name, 127219820Sjeff sizeof sysfs_dev->ibdev_name) < 0) { 128219820Sjeff fprintf(stderr, PFX "Warning: no ibdev class attr for '%s'.\n", 129219820Sjeff dent->d_name); 130219820Sjeff continue; 131219820Sjeff } 132219820Sjeff 133219820Sjeff snprintf(sysfs_dev->ibdev_path, sizeof sysfs_dev->ibdev_path, 134219820Sjeff "%s/class/infiniband/%s", ibv_get_sysfs_path(), 135219820Sjeff sysfs_dev->ibdev_name); 136219820Sjeff 137219820Sjeff sysfs_dev->next = sysfs_dev_list; 138219820Sjeff sysfs_dev->have_driver = 0; 139219820Sjeff if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "abi_version", 140219820Sjeff value, sizeof value) > 0) 141219820Sjeff sysfs_dev->abi_ver = strtol(value, NULL, 10); 142219820Sjeff else 143219820Sjeff sysfs_dev->abi_ver = 0; 144219820Sjeff 145219820Sjeff sysfs_dev_list = sysfs_dev; 146219820Sjeff sysfs_dev = NULL; 147219820Sjeff } 148219820Sjeff 149219820Sjeff out: 150219820Sjeff if (sysfs_dev) 151219820Sjeff free(sysfs_dev); 152219820Sjeff 153219820Sjeff closedir(class_dir); 154219820Sjeff return ret; 155219820Sjeff#else 156219820Sjeff char class_path[IBV_SYSFS_PATH_MAX]; 157219820Sjeff struct ibv_sysfs_dev *sysfs_dev = NULL; 158219820Sjeff char value[8]; 159219820Sjeff int ret = 0; 160219820Sjeff int i; 161219820Sjeff 162219820Sjeff snprintf(class_path, sizeof class_path, "%s/class/infiniband_verbs", 163219820Sjeff ibv_get_sysfs_path()); 164219820Sjeff 165219820Sjeff for (i = 0; i < 256; i++) { 166219820Sjeff if (!sysfs_dev) 167219820Sjeff sysfs_dev = malloc(sizeof *sysfs_dev); 168219820Sjeff if (!sysfs_dev) { 169219820Sjeff ret = ENOMEM; 170219820Sjeff goto out; 171219820Sjeff } 172219820Sjeff 173219820Sjeff snprintf(sysfs_dev->sysfs_path, sizeof sysfs_dev->sysfs_path, 174219820Sjeff "%s/uverbs%d", class_path, i); 175219820Sjeff 176219820Sjeff snprintf(sysfs_dev->sysfs_name, sizeof sysfs_dev->sysfs_name, 177219820Sjeff "uverbs%d", i); 178219820Sjeff 179219820Sjeff if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "ibdev", 180219820Sjeff sysfs_dev->ibdev_name, 181219820Sjeff sizeof sysfs_dev->ibdev_name) < 0) 182219820Sjeff continue; 183219820Sjeff 184219820Sjeff snprintf(sysfs_dev->ibdev_path, sizeof sysfs_dev->ibdev_path, 185219820Sjeff "%s/class/infiniband/%s", ibv_get_sysfs_path(), 186219820Sjeff sysfs_dev->ibdev_name); 187219820Sjeff 188219820Sjeff sysfs_dev->next = sysfs_dev_list; 189219820Sjeff sysfs_dev->have_driver = 0; 190219820Sjeff if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "abi_version", 191219820Sjeff value, sizeof value) > 0) 192219820Sjeff sysfs_dev->abi_ver = strtol(value, NULL, 10); 193219820Sjeff else 194219820Sjeff sysfs_dev->abi_ver = 0; 195219820Sjeff 196219820Sjeff sysfs_dev_list = sysfs_dev; 197219820Sjeff sysfs_dev = NULL; 198219820Sjeff } 199219820Sjeff 200219820Sjeff out: 201219820Sjeff if (sysfs_dev) 202219820Sjeff free(sysfs_dev); 203219820Sjeff 204219820Sjeff return ret; 205219820Sjeff 206219820Sjeff#endif 207219820Sjeff} 208219820Sjeff 209219820Sjeffvoid ibv_register_driver(const char *name, ibv_driver_init_func init_func) 210219820Sjeff{ 211219820Sjeff struct ibv_driver *driver; 212219820Sjeff 213219820Sjeff driver = malloc(sizeof *driver); 214219820Sjeff if (!driver) { 215219820Sjeff fprintf(stderr, PFX "Warning: couldn't allocate driver for %s\n", name); 216219820Sjeff return; 217219820Sjeff } 218219820Sjeff 219219820Sjeff driver->name = name; 220219820Sjeff driver->init_func = init_func; 221219820Sjeff driver->next = NULL; 222219820Sjeff 223219820Sjeff if (tail_driver) 224219820Sjeff tail_driver->next = driver; 225219820Sjeff else 226219820Sjeff head_driver = driver; 227219820Sjeff tail_driver = driver; 228219820Sjeff} 229219820Sjeff 230219820Sjeffstatic void load_driver(const char *name) 231219820Sjeff{ 232219820Sjeff char *so_name; 233219820Sjeff void *dlhandle; 234219820Sjeff 235219820Sjeff#define __IBV_QUOTE(x) #x 236219820Sjeff#define IBV_QUOTE(x) __IBV_QUOTE(x) 237219820Sjeff 238219820Sjeff if (asprintf(&so_name, 239219820Sjeff name[0] == '/' ? 240219820Sjeff "%s-" IBV_QUOTE(IBV_DEVICE_LIBRARY_EXTENSION) ".so" : 241219820Sjeff "lib%s-" IBV_QUOTE(IBV_DEVICE_LIBRARY_EXTENSION) ".so", 242219820Sjeff name) < 0) { 243219820Sjeff fprintf(stderr, PFX "Warning: couldn't load driver '%s'.\n", 244219820Sjeff name); 245219820Sjeff return; 246219820Sjeff } 247219820Sjeff 248219820Sjeff dlhandle = dlopen(so_name, RTLD_NOW); 249219820Sjeff if (!dlhandle) { 250219820Sjeff fprintf(stderr, PFX "Warning: couldn't load driver '%s': %s\n", 251219820Sjeff name, dlerror()); 252219820Sjeff goto out; 253219820Sjeff } 254219820Sjeff 255219820Sjeffout: 256219820Sjeff free(so_name); 257219820Sjeff} 258219820Sjeff 259219820Sjeffstatic void load_drivers(void) 260219820Sjeff{ 261219820Sjeff struct ibv_driver_name *name, *next_name; 262219820Sjeff const char *env; 263219820Sjeff char *list, *env_name; 264219820Sjeff 265219820Sjeff /* 266219820Sjeff * Only use drivers passed in through the calling user's 267219820Sjeff * environment if we're not running setuid. 268219820Sjeff */ 269219820Sjeff if (getuid() == geteuid()) { 270219820Sjeff if ((env = getenv("RDMAV_DRIVERS"))) { 271219820Sjeff list = strdupa(env); 272219820Sjeff while ((env_name = strsep(&list, ":;"))) 273219820Sjeff load_driver(env_name); 274219820Sjeff } else if ((env = getenv("IBV_DRIVERS"))) { 275219820Sjeff list = strdupa(env); 276219820Sjeff while ((env_name = strsep(&list, ":;"))) 277219820Sjeff load_driver(env_name); 278219820Sjeff } 279219820Sjeff } 280219820Sjeff 281219820Sjeff for (name = driver_name_list, next_name = name ? name->next : NULL; 282219820Sjeff name; 283219820Sjeff name = next_name, next_name = name ? name->next : NULL) { 284219820Sjeff load_driver(name->name); 285219820Sjeff free(name->name); 286219820Sjeff free(name); 287219820Sjeff } 288219820Sjeff} 289219820Sjeff 290219820Sjeffstatic void read_config_file(const char *path) 291219820Sjeff{ 292219820Sjeff FILE *conf; 293219820Sjeff char *line = NULL; 294219820Sjeff char *config; 295219820Sjeff char *field; 296219820Sjeff size_t buflen = 0; 297219820Sjeff ssize_t len; 298219820Sjeff 299219820Sjeff conf = fopen(path, "r"); 300219820Sjeff if (!conf) { 301219820Sjeff fprintf(stderr, PFX "Warning: couldn't read config file %s.\n", 302219820Sjeff path); 303219820Sjeff return; 304219820Sjeff } 305219820Sjeff 306219820Sjeff while ((len = getline(&line, &buflen, conf)) != -1) { 307219820Sjeff config = line + strspn(line, "\t "); 308219820Sjeff if (config[0] == '\n' || config[0] == '#') 309219820Sjeff continue; 310219820Sjeff 311219820Sjeff field = strsep(&config, "\n\t "); 312219820Sjeff 313219820Sjeff if (strcmp(field, "driver") == 0) { 314219820Sjeff struct ibv_driver_name *driver_name; 315219820Sjeff 316219820Sjeff config += strspn(config, "\t "); 317219820Sjeff field = strsep(&config, "\n\t "); 318219820Sjeff 319219820Sjeff driver_name = malloc(sizeof *driver_name); 320219820Sjeff if (!driver_name) { 321219820Sjeff fprintf(stderr, PFX "Warning: couldn't allocate " 322219820Sjeff "driver name '%s'.\n", field); 323219820Sjeff continue; 324219820Sjeff } 325219820Sjeff 326219820Sjeff driver_name->name = strdup(field); 327219820Sjeff if (!driver_name->name) { 328219820Sjeff fprintf(stderr, PFX "Warning: couldn't allocate " 329219820Sjeff "driver name '%s'.\n", field); 330219820Sjeff free(driver_name); 331219820Sjeff continue; 332219820Sjeff } 333219820Sjeff 334219820Sjeff driver_name->next = driver_name_list; 335219820Sjeff driver_name_list = driver_name; 336219820Sjeff } else 337219820Sjeff fprintf(stderr, PFX "Warning: ignoring bad config directive " 338219820Sjeff "'%s' in file '%s'.\n", field, path); 339219820Sjeff } 340219820Sjeff 341219820Sjeff if (line) 342219820Sjeff free(line); 343219820Sjeff fclose(conf); 344219820Sjeff} 345219820Sjeff 346219820Sjeffstatic void read_config(void) 347219820Sjeff{ 348219820Sjeff DIR *conf_dir; 349219820Sjeff struct dirent *dent; 350219820Sjeff char *path; 351219820Sjeff 352219820Sjeff conf_dir = opendir(IBV_CONFIG_DIR); 353219820Sjeff if (!conf_dir) { 354219820Sjeff fprintf(stderr, PFX "Warning: couldn't open config directory '%s'.\n", 355219820Sjeff IBV_CONFIG_DIR); 356219820Sjeff return; 357219820Sjeff } 358219820Sjeff 359219820Sjeff while ((dent = readdir(conf_dir))) { 360219820Sjeff struct stat buf; 361219820Sjeff 362219820Sjeff if (asprintf(&path, "%s/%s", IBV_CONFIG_DIR, dent->d_name) < 0) { 363219820Sjeff fprintf(stderr, PFX "Warning: couldn't read config file %s/%s.\n", 364219820Sjeff IBV_CONFIG_DIR, dent->d_name); 365219820Sjeff return; 366219820Sjeff } 367219820Sjeff 368219820Sjeff if (stat(path, &buf)) { 369219820Sjeff fprintf(stderr, PFX "Warning: couldn't stat config file '%s'.\n", 370219820Sjeff path); 371219820Sjeff goto next; 372219820Sjeff } 373219820Sjeff 374219820Sjeff if (!S_ISREG(buf.st_mode)) 375219820Sjeff goto next; 376219820Sjeff 377219820Sjeff read_config_file(path); 378219820Sjeffnext: 379219820Sjeff free(path); 380219820Sjeff } 381219820Sjeff 382219820Sjeff closedir(conf_dir); 383219820Sjeff} 384219820Sjeff 385219820Sjeffstatic struct ibv_device *try_driver(struct ibv_driver *driver, 386219820Sjeff struct ibv_sysfs_dev *sysfs_dev) 387219820Sjeff{ 388219820Sjeff struct ibv_device *dev; 389219820Sjeff char value[8]; 390219820Sjeff 391219820Sjeff dev = driver->init_func(sysfs_dev->sysfs_path, sysfs_dev->abi_ver); 392219820Sjeff if (!dev) 393219820Sjeff return NULL; 394219820Sjeff 395219820Sjeff if (ibv_read_sysfs_file(sysfs_dev->ibdev_path, "node_type", value, sizeof value) < 0) { 396219820Sjeff fprintf(stderr, PFX "Warning: no node_type attr under %s.\n", 397219820Sjeff sysfs_dev->ibdev_path); 398219820Sjeff dev->node_type = IBV_NODE_UNKNOWN; 399219820Sjeff } else { 400219820Sjeff dev->node_type = strtol(value, NULL, 10); 401219820Sjeff if (dev->node_type < IBV_NODE_CA || dev->node_type > IBV_NODE_RNIC) 402219820Sjeff dev->node_type = IBV_NODE_UNKNOWN; 403219820Sjeff } 404219820Sjeffout: 405219820Sjeff 406219820Sjeff switch (dev->node_type) { 407219820Sjeff case IBV_NODE_CA: 408219820Sjeff case IBV_NODE_SWITCH: 409219820Sjeff case IBV_NODE_ROUTER: 410219820Sjeff dev->transport_type = IBV_TRANSPORT_IB; 411219820Sjeff break; 412219820Sjeff case IBV_NODE_RNIC: 413219820Sjeff dev->transport_type = IBV_TRANSPORT_IWARP; 414219820Sjeff break; 415219820Sjeff default: 416219820Sjeff dev->transport_type = IBV_TRANSPORT_UNKNOWN; 417219820Sjeff break; 418219820Sjeff } 419219820Sjeff 420219820Sjeff strcpy(dev->dev_name, sysfs_dev->sysfs_name); 421219820Sjeff strcpy(dev->dev_path, sysfs_dev->sysfs_path); 422219820Sjeff strcpy(dev->name, sysfs_dev->ibdev_name); 423219820Sjeff strcpy(dev->ibdev_path, sysfs_dev->ibdev_path); 424219820Sjeff 425219820Sjeff return dev; 426219820Sjeff} 427219820Sjeff 428219820Sjeffstatic struct ibv_device *try_drivers(struct ibv_sysfs_dev *sysfs_dev) 429219820Sjeff{ 430219820Sjeff struct ibv_driver *driver; 431219820Sjeff struct ibv_device *dev; 432219820Sjeff 433219820Sjeff for (driver = head_driver; driver; driver = driver->next) { 434219820Sjeff dev = try_driver(driver, sysfs_dev); 435219820Sjeff if (dev) 436219820Sjeff return dev; 437219820Sjeff } 438219820Sjeff 439219820Sjeff return NULL; 440219820Sjeff} 441219820Sjeff 442219820Sjeffstatic int check_abi_version(const char *path) 443219820Sjeff{ 444219820Sjeff char value[8]; 445219820Sjeff 446219820Sjeff if (ibv_read_sysfs_file(path, "class/infiniband_verbs/abi_version", 447219820Sjeff value, sizeof value) < 0) { 448219820Sjeff return ENOSYS; 449219820Sjeff } 450219820Sjeff 451219820Sjeff abi_ver = strtol(value, NULL, 10); 452219820Sjeff 453219820Sjeff if (abi_ver < IB_USER_VERBS_MIN_ABI_VERSION || 454219820Sjeff abi_ver > IB_USER_VERBS_MAX_ABI_VERSION) { 455219820Sjeff fprintf(stderr, PFX "Fatal: kernel ABI version %d " 456219820Sjeff "doesn't match library version %d.\n", 457219820Sjeff abi_ver, IB_USER_VERBS_MAX_ABI_VERSION); 458219820Sjeff return ENOSYS; 459219820Sjeff } 460219820Sjeff 461219820Sjeff return 0; 462219820Sjeff} 463219820Sjeff 464219820Sjeffstatic void check_memlock_limit(void) 465219820Sjeff{ 466219820Sjeff struct rlimit rlim; 467219820Sjeff 468219820Sjeff if (!geteuid()) 469219820Sjeff return; 470219820Sjeff 471219820Sjeff if (getrlimit(RLIMIT_MEMLOCK, &rlim)) { 472219820Sjeff fprintf(stderr, PFX "Warning: getrlimit(RLIMIT_MEMLOCK) failed."); 473219820Sjeff return; 474219820Sjeff } 475219820Sjeff 476219820Sjeff if (rlim.rlim_cur <= 32768) 477219820Sjeff fprintf(stderr, PFX "Warning: RLIMIT_MEMLOCK is %lu bytes.\n" 478219820Sjeff " This will severely limit memory registrations.\n", 479219820Sjeff rlim.rlim_cur); 480219820Sjeff} 481219820Sjeff 482219820Sjeffstatic void add_device(struct ibv_device *dev, 483219820Sjeff struct ibv_device ***dev_list, 484219820Sjeff int *num_devices, 485219820Sjeff int *list_size) 486219820Sjeff{ 487219820Sjeff struct ibv_device **new_list; 488219820Sjeff 489219820Sjeff if (*list_size <= *num_devices) { 490219820Sjeff *list_size = *list_size ? *list_size * 2 : 1; 491219820Sjeff new_list = realloc(*dev_list, *list_size * sizeof (struct ibv_device *)); 492219820Sjeff if (!new_list) 493219820Sjeff return; 494219820Sjeff *dev_list = new_list; 495219820Sjeff } 496219820Sjeff 497219820Sjeff (*dev_list)[(*num_devices)++] = dev; 498219820Sjeff} 499219820Sjeff 500219820SjeffHIDDEN int ibverbs_init(struct ibv_device ***list) 501219820Sjeff{ 502219820Sjeff const char *sysfs_path; 503219820Sjeff struct ibv_sysfs_dev *sysfs_dev, *next_dev; 504219820Sjeff struct ibv_device *device; 505219820Sjeff int num_devices = 0; 506219820Sjeff int list_size = 0; 507219820Sjeff int statically_linked = 0; 508219820Sjeff int no_driver = 0; 509219820Sjeff int ret; 510219820Sjeff 511219820Sjeff *list = NULL; 512219820Sjeff 513219820Sjeff if (getenv("RDMAV_FORK_SAFE") || getenv("IBV_FORK_SAFE")) 514219820Sjeff if (ibv_fork_init()) 515219820Sjeff fprintf(stderr, PFX "Warning: fork()-safety requested " 516219820Sjeff "but init failed\n"); 517219820Sjeff 518219820Sjeff sysfs_path = ibv_get_sysfs_path(); 519219820Sjeff if (!sysfs_path) 520219820Sjeff return -ENOSYS; 521219820Sjeff 522219820Sjeff ret = check_abi_version(sysfs_path); 523219820Sjeff if (ret) 524219820Sjeff return -ret; 525219820Sjeff 526219820Sjeff check_memlock_limit(); 527219820Sjeff 528219820Sjeff read_config(); 529219820Sjeff 530219820Sjeff ret = find_sysfs_devs(); 531219820Sjeff if (ret) 532219820Sjeff return -ret; 533219820Sjeff 534219820Sjeff for (sysfs_dev = sysfs_dev_list; sysfs_dev; sysfs_dev = sysfs_dev->next) { 535219820Sjeff device = try_drivers(sysfs_dev); 536219820Sjeff if (device) { 537219820Sjeff add_device(device, list, &num_devices, &list_size); 538219820Sjeff sysfs_dev->have_driver = 1; 539219820Sjeff } else 540219820Sjeff no_driver = 1; 541219820Sjeff } 542219820Sjeff 543219820Sjeff if (!no_driver) 544219820Sjeff goto out; 545219820Sjeff 546219820Sjeff /* 547219820Sjeff * Check if we can dlopen() ourselves. If this fails, 548219820Sjeff * libibverbs is probably statically linked into the 549219820Sjeff * executable, and we should just give up, since trying to 550219820Sjeff * dlopen() a driver module will fail spectacularly (loading a 551219820Sjeff * driver .so will bring in dynamic copies of libibverbs and 552219820Sjeff * libdl to go along with the static copies the executable 553219820Sjeff * has, which quickly leads to a crash. 554219820Sjeff */ 555219820Sjeff { 556219820Sjeff void *hand = dlopen(NULL, RTLD_NOW); 557219820Sjeff if (!hand) { 558219820Sjeff fprintf(stderr, PFX "Warning: dlopen(NULL) failed, " 559219820Sjeff "assuming static linking.\n"); 560219820Sjeff statically_linked = 1; 561219820Sjeff goto out; 562219820Sjeff } 563219820Sjeff dlclose(hand); 564219820Sjeff } 565219820Sjeff 566219820Sjeff load_drivers(); 567219820Sjeff 568219820Sjeff for (sysfs_dev = sysfs_dev_list; sysfs_dev; sysfs_dev = sysfs_dev->next) { 569219820Sjeff if (sysfs_dev->have_driver) 570219820Sjeff continue; 571219820Sjeff 572219820Sjeff device = try_drivers(sysfs_dev); 573219820Sjeff if (device) { 574219820Sjeff add_device(device, list, &num_devices, &list_size); 575219820Sjeff sysfs_dev->have_driver = 1; 576219820Sjeff } 577219820Sjeff } 578219820Sjeff 579219820Sjeffout: 580219820Sjeff for (sysfs_dev = sysfs_dev_list, 581219820Sjeff next_dev = sysfs_dev ? sysfs_dev->next : NULL; 582219820Sjeff sysfs_dev; 583219820Sjeff sysfs_dev = next_dev, next_dev = sysfs_dev ? sysfs_dev->next : NULL) { 584219820Sjeff if (!sysfs_dev->have_driver) { 585219820Sjeff fprintf(stderr, PFX "Warning: no userspace device-specific " 586219820Sjeff "driver found for %s\n", sysfs_dev->sysfs_path); 587219820Sjeff if (statically_linked) 588219820Sjeff fprintf(stderr, " When linking libibverbs statically, " 589219820Sjeff "driver must be statically linked too.\n"); 590219820Sjeff } 591219820Sjeff free(sysfs_dev); 592219820Sjeff } 593219820Sjeff 594219820Sjeff return num_devices; 595219820Sjeff} 596