1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff * 32219820Sjeff */ 33219820Sjeff 34219820Sjeff#if HAVE_CONFIG_H 35219820Sjeff# include <config.h> 36219820Sjeff#endif /* HAVE_CONFIG_H */ 37219820Sjeff 38219820Sjeff#include <sys/poll.h> 39219820Sjeff#include <unistd.h> 40219820Sjeff#include <string.h> 41219820Sjeff#include <errno.h> 42219820Sjeff#include <sys/types.h> 43219820Sjeff#include <sys/stat.h> 44219820Sjeff#include <fcntl.h> 45219820Sjeff#include <sys/ioctl.h> 46219820Sjeff#include <netinet/in.h> 47219820Sjeff#include <dirent.h> 48219820Sjeff#include <stdlib.h> 49219820Sjeff#include <ctype.h> 50219820Sjeff 51219820Sjeff#include "umad.h" 52219820Sjeff 53219820Sjeff#define IB_OPENIB_OUI (0x001405) 54219820Sjeff 55219820Sjeff#ifdef HAVE_VALGRIND_MEMCHECK_H 56219820Sjeff 57219820Sjeff# include <valgrind/memcheck.h> 58219820Sjeff 59219820Sjeff# ifndef VALGRIND_MAKE_MEM_DEFINED 60219820Sjeff# warning "Valgrind support requested, but VALGRIND_MAKE_MEM_DEFINED not available" 61219820Sjeff# endif 62219820Sjeff 63219820Sjeff#endif /* HAVE_VALGRIND_MEMCHECK_H */ 64219820Sjeff 65219820Sjeff#ifndef VALGRIND_MAKE_MEM_DEFINED 66219820Sjeff# define VALGRIND_MAKE_MEM_DEFINED(addr,len) 67219820Sjeff#endif 68219820Sjeff 69219820Sjefftypedef struct ib_user_mad_reg_req { 70219820Sjeff uint32_t id; 71219820Sjeff uint32_t method_mask[4]; 72219820Sjeff uint8_t qpn; 73219820Sjeff uint8_t mgmt_class; 74219820Sjeff uint8_t mgmt_class_version; 75219820Sjeff uint8_t oui[3]; 76219820Sjeff uint8_t rmpp_version; 77219820Sjeff} ib_user_mad_reg_req_t; 78219820Sjeff 79219820Sjeff#define TRACE if (umaddebug) IBWARN 80219820Sjeff#define DEBUG if (umaddebug) IBWARN 81219820Sjeff 82219820Sjeffint umaddebug = 0; 83219820Sjeff 84219820Sjeff#define UMAD_DEV_FILE_SZ 256 85219820Sjeff 86219820Sjeffstatic char *def_ca_name = "mthca0"; 87219820Sjeffstatic int def_ca_port = 1; 88219820Sjeff 89219820Sjeffstatic unsigned abi_version; 90219820Sjeffstatic unsigned new_user_mad_api; 91219820Sjeff 92219820Sjeff/************************************* 93219820Sjeff * Port 94219820Sjeff */ 95219820Sjeffstatic int 96219820Sjefffind_cached_ca(char *ca_name, umad_ca_t *ca) 97219820Sjeff{ 98219820Sjeff return 0; /* caching not implemented yet */ 99219820Sjeff} 100219820Sjeff 101219820Sjeffstatic int 102219820Sjeffput_ca(umad_ca_t *ca) 103219820Sjeff{ 104219820Sjeff return 0; /* caching not implemented yet */ 105219820Sjeff} 106219820Sjeff 107219820Sjeffstatic int 108219820Sjeffrelease_port(umad_port_t *port) 109219820Sjeff{ 110219820Sjeff free(port->pkeys); 111219820Sjeff port->pkeys = NULL; 112219820Sjeff port->pkeys_size = 0; 113219820Sjeff return 0; 114219820Sjeff} 115219820Sjeff 116219820Sjeffstatic int check_for_digit_name(const struct dirent *dent) 117219820Sjeff{ 118219820Sjeff const char *p = dent->d_name; 119219820Sjeff while (*p && isdigit(*p)) 120219820Sjeff p++; 121219820Sjeff return *p ? 0 : 1; 122219820Sjeff} 123219820Sjeff 124219820Sjeffstatic int 125219820Sjeffget_port(char *ca_name, char *dir, int portnum, umad_port_t *port) 126219820Sjeff{ 127219820Sjeff char port_dir[256]; 128219820Sjeff uint8_t gid[16]; 129219820Sjeff struct dirent **namelist = NULL; 130219820Sjeff int i, len, ret = 0; 131219820Sjeff 132219820Sjeff strncpy(port->ca_name, ca_name, sizeof port->ca_name - 1); 133219820Sjeff port->portnum = portnum; 134219820Sjeff port->pkeys = NULL; 135219820Sjeff 136219820Sjeff len = snprintf(port_dir, sizeof(port_dir), "%s/%d", dir, portnum); 137219820Sjeff if (len < 0 || len > sizeof(port_dir)) 138219820Sjeff goto clean; 139219820Sjeff 140219820Sjeff if (sys_read_uint(port_dir, SYS_PORT_LMC, &port->lmc) < 0) 141219820Sjeff goto clean; 142219820Sjeff if (sys_read_uint(port_dir, SYS_PORT_SMLID, &port->sm_lid) < 0) 143219820Sjeff goto clean; 144219820Sjeff if (sys_read_uint(port_dir, SYS_PORT_SMSL, &port->sm_sl) < 0) 145219820Sjeff goto clean; 146219820Sjeff if (sys_read_uint(port_dir, SYS_PORT_LID, &port->base_lid) < 0) 147219820Sjeff goto clean; 148219820Sjeff if (sys_read_uint(port_dir, SYS_PORT_STATE, &port->state) < 0) 149219820Sjeff goto clean; 150219820Sjeff if (sys_read_uint(port_dir, SYS_PORT_PHY_STATE, &port->phys_state) < 0) 151219820Sjeff goto clean; 152219820Sjeff if (sys_read_uint(port_dir, SYS_PORT_RATE, &port->rate) < 0) 153219820Sjeff goto clean; 154219820Sjeff if (sys_read_uint64(port_dir, SYS_PORT_CAPMASK, &port->capmask) < 0) 155219820Sjeff goto clean; 156219820Sjeff 157219820Sjeff port->capmask = htonl(port->capmask); 158219820Sjeff 159219820Sjeff if (sys_read_gid(port_dir, SYS_PORT_GID, gid) < 0) 160219820Sjeff goto clean; 161219820Sjeff 162219820Sjeff memcpy(&port->gid_prefix, gid, sizeof port->gid_prefix); 163219820Sjeff memcpy(&port->port_guid, gid + 8, sizeof port->port_guid); 164219820Sjeff 165219820Sjeff snprintf(port_dir + len, sizeof(port_dir) - len, "/pkeys"); 166219820Sjeff ret = sys_scandir(port_dir, &namelist, check_for_digit_name, NULL); 167219820Sjeff if (ret <= 0) { 168219820Sjeff IBWARN("no pkeys found for %s:%u (at dir %s)...", 169219820Sjeff port->ca_name, port->portnum, port_dir); 170219820Sjeff goto clean; 171219820Sjeff } 172219820Sjeff port->pkeys = calloc(ret, sizeof(port->pkeys[0])); 173219820Sjeff if (!port->pkeys) { 174219820Sjeff IBWARN("get_port: calloc failed: %s", strerror(errno)); 175219820Sjeff goto clean; 176219820Sjeff } 177219820Sjeff for (i = 0; i < ret ; i++) { 178219820Sjeff unsigned idx, val; 179219820Sjeff idx = strtoul(namelist[i]->d_name, NULL, 0); 180219820Sjeff sys_read_uint(port_dir, namelist[i]->d_name, &val); 181219820Sjeff port->pkeys[idx] = val; 182219820Sjeff free(namelist[i]); 183219820Sjeff } 184219820Sjeff port->pkeys_size = ret; 185219820Sjeff free(namelist); 186219820Sjeff namelist = NULL; 187219820Sjeff port_dir[len] = '\0'; 188219820Sjeff 189219820Sjeff /* FIXME: handle gids */ 190219820Sjeff 191219820Sjeff return 0; 192219820Sjeff 193219820Sjeffclean: 194219820Sjeff if (namelist) { 195219820Sjeff for (i = 0; i < ret ; i++) 196219820Sjeff free(namelist[i]); 197219820Sjeff free(namelist); 198219820Sjeff } 199219820Sjeff if (port->pkeys) 200219820Sjeff free(port->pkeys); 201219820Sjeff return -EIO; 202219820Sjeff} 203219820Sjeff 204219820Sjeffstatic int 205219820Sjeffrelease_ca(umad_ca_t *ca) 206219820Sjeff{ 207219820Sjeff int i; 208219820Sjeff 209219820Sjeff for (i = 0; i <= ca->numports; i++) { 210219820Sjeff if (!ca->ports[i]) 211219820Sjeff continue; 212219820Sjeff release_port(ca->ports[i]); 213219820Sjeff free(ca->ports[i]); 214219820Sjeff ca->ports[i] = 0; 215219820Sjeff } 216219820Sjeff return 0; 217219820Sjeff} 218219820Sjeff 219219820Sjeff/* 220219820Sjeff * if *port > 0, check ca[port] state. Otherwise set *port to 221219820Sjeff * the first port that is active, and if such is not found, to 222219820Sjeff * the first port that is link up and if none are linkup, then 223219820Sjeff * the first port that is not disabled. Otherwise return -1. 224219820Sjeff */ 225219820Sjeffstatic int 226219820Sjeffresolve_ca_port(char *ca_name, int *port) 227219820Sjeff{ 228219820Sjeff umad_ca_t ca; 229219820Sjeff int active = -1, up = -1; 230219820Sjeff int i; 231219820Sjeff 232219820Sjeff TRACE("checking ca '%s'", ca_name); 233219820Sjeff 234219820Sjeff if (umad_get_ca(ca_name, &ca) < 0) 235219820Sjeff return -1; 236219820Sjeff 237219820Sjeff if (ca.node_type == 2) { 238219820Sjeff *port = 0; /* switch sma port 0 */ 239219820Sjeff return 1; 240219820Sjeff } 241219820Sjeff 242219820Sjeff if (*port > 0) { /* check only the port the user wants */ 243219820Sjeff if (*port > ca.numports) 244219820Sjeff return -1; 245219820Sjeff if (!ca.ports[*port]) 246219820Sjeff return -1; 247219820Sjeff if (ca.ports[*port]->state == 4) 248219820Sjeff return 1; 249219820Sjeff if (ca.ports[*port]->phys_state != 3) 250219820Sjeff return 0; 251219820Sjeff return -1; 252219820Sjeff } 253219820Sjeff 254219820Sjeff for (i = 0; i <= ca.numports; i++) { 255219820Sjeff DEBUG("checking port %d", i); 256219820Sjeff if (!ca.ports[i]) 257219820Sjeff continue; 258219820Sjeff if (up < 0 && ca.ports[i]->phys_state == 5) 259219820Sjeff up = *port = i; 260219820Sjeff if (ca.ports[i]->state == 4) { 261219820Sjeff active = *port = i; 262219820Sjeff DEBUG("found active port %d", i); 263219820Sjeff break; 264219820Sjeff } 265219820Sjeff } 266219820Sjeff 267219820Sjeff if (active == -1 && up == -1) { /* no active or linkup port found */ 268219820Sjeff for (i = 0; i <= ca.numports; i++) { 269219820Sjeff DEBUG("checking port %d", i); 270219820Sjeff if (!ca.ports[i]) 271219820Sjeff continue; 272219820Sjeff if (ca.ports[i]->phys_state != 3) { 273219820Sjeff up = *port = i; 274219820Sjeff break; 275219820Sjeff } 276219820Sjeff } 277219820Sjeff } 278219820Sjeff 279219820Sjeff release_ca(&ca); 280219820Sjeff 281219820Sjeff if (active >= 0) 282219820Sjeff return 1; 283219820Sjeff if (up >= 0) 284219820Sjeff return 0; 285219820Sjeff return -1; 286219820Sjeff} 287219820Sjeff 288219820Sjeffstatic char * 289219820Sjeffresolve_ca_name(char *ca_name, int *best_port) 290219820Sjeff{ 291219820Sjeff static char names[UMAD_MAX_DEVICES][UMAD_CA_NAME_LEN]; 292219820Sjeff int phys_found = -1, port_found = 0, port, port_type; 293219820Sjeff int caidx, n; 294219820Sjeff 295219820Sjeff if (ca_name && (!best_port || *best_port)) 296219820Sjeff return ca_name; 297219820Sjeff 298219820Sjeff if (ca_name) { 299219820Sjeff if (resolve_ca_port(ca_name, best_port) < 0) 300219820Sjeff return 0; 301219820Sjeff return ca_name; 302219820Sjeff } 303219820Sjeff 304219820Sjeff /* Get the list of CA names */ 305219820Sjeff if ((n = umad_get_cas_names((void *)names, 20)) < 0) 306219820Sjeff return 0; 307219820Sjeff 308219820Sjeff /* Find the first existing CA with an active port */ 309219820Sjeff for (caidx = 0; caidx < n; caidx++) { 310219820Sjeff TRACE("checking ca '%s'", names[caidx]); 311219820Sjeff 312219820Sjeff port = best_port ? *best_port : 0; 313219820Sjeff if ((port_type = resolve_ca_port(names[caidx], &port)) < 0) 314219820Sjeff continue; 315219820Sjeff 316219820Sjeff DEBUG("found ca %s with port %d type %d", 317219820Sjeff names[caidx], port, port_type); 318219820Sjeff 319219820Sjeff if (port_type > 0) { 320219820Sjeff if (best_port) 321219820Sjeff *best_port = port; 322219820Sjeff DEBUG("found ca %s with active port %d", 323219820Sjeff names[caidx], port); 324219820Sjeff return (char *)(names + caidx); 325219820Sjeff } 326219820Sjeff 327219820Sjeff if (phys_found == -1) { 328219820Sjeff phys_found = caidx; 329219820Sjeff port_found = port; 330219820Sjeff } 331219820Sjeff } 332219820Sjeff 333219820Sjeff DEBUG("phys found %d on %s port %d", 334219820Sjeff phys_found, phys_found >=0 ? names[phys_found] : 0, port_found); 335219820Sjeff if (phys_found >= 0) { 336219820Sjeff if (best_port) 337219820Sjeff *best_port = port_found; 338219820Sjeff return names[phys_found]; 339219820Sjeff } 340219820Sjeff 341219820Sjeff if (best_port) 342219820Sjeff *best_port = def_ca_port; 343219820Sjeff return def_ca_name; 344219820Sjeff} 345219820Sjeff 346219820Sjeffstatic int 347219820Sjeffget_ca(char *ca_name, umad_ca_t *ca) 348219820Sjeff{ 349219820Sjeff#ifdef __linux__ 350219820Sjeff DIR *dir; 351219820Sjeff#endif 352219820Sjeff char dir_name[256]; 353219820Sjeff struct dirent **namelist; 354219820Sjeff int r, i, ret; 355219820Sjeff int portnum; 356219820Sjeff 357219820Sjeff strncpy(ca->ca_name, ca_name, sizeof ca->ca_name); 358219820Sjeff 359219820Sjeff snprintf(dir_name, sizeof(dir_name), "%s/%s", SYS_INFINIBAND, 360219820Sjeff ca->ca_name); 361219820Sjeff 362219820Sjeff if ((r = sys_read_uint(dir_name, SYS_NODE_TYPE, &ca->node_type)) < 0) 363219820Sjeff return r; 364219820Sjeff if (sys_read_string(dir_name, SYS_CA_FW_VERS, ca->fw_ver, 365219820Sjeff sizeof ca->fw_ver) < 0) 366219820Sjeff ca->fw_ver[0] = '\0'; 367219820Sjeff if (sys_read_string(dir_name, SYS_CA_HW_VERS, ca->hw_ver, 368219820Sjeff sizeof ca->hw_ver) < 0) 369219820Sjeff ca->hw_ver[0] = '\0'; 370219820Sjeff if ((r = sys_read_string(dir_name, SYS_CA_TYPE, ca->ca_type, 371219820Sjeff sizeof ca->ca_type)) < 0) 372219820Sjeff ca->ca_type[0] = '\0'; 373219820Sjeff if ((r = sys_read_guid(dir_name, SYS_CA_NODE_GUID, &ca->node_guid)) < 0) 374219820Sjeff return r; 375219820Sjeff if ((r = sys_read_guid(dir_name, SYS_CA_SYS_GUID, &ca->system_guid)) < 0) 376219820Sjeff return r; 377219820Sjeff 378219820Sjeff snprintf(dir_name, sizeof(dir_name), "%s/%s/%s", 379219820Sjeff SYS_INFINIBAND, ca->ca_name, SYS_CA_PORTS_DIR); 380219820Sjeff 381219820Sjeff#ifdef __linux__ 382219820Sjeff if (!(dir = opendir(dir_name))) 383219820Sjeff return -ENOENT; 384219820Sjeff#endif 385219820Sjeff 386219820Sjeff if ((r = sys_scandir(dir_name, &namelist, 0, alphasort)) < 0) { 387219820Sjeff ret = errno < 0 ? errno : -EIO; 388219820Sjeff goto error; 389219820Sjeff } 390219820Sjeff 391219820Sjeff ret = 0; 392219820Sjeff ca->numports = 0; 393219820Sjeff memset(ca->ports, 0, sizeof ca->ports); 394219820Sjeff for (i = 0; i < r; i++) { 395219820Sjeff portnum = 0; 396219820Sjeff if (!strcmp(".", namelist[i]->d_name) || 397219820Sjeff !strcmp("..", namelist[i]->d_name)) 398219820Sjeff continue; 399219820Sjeff if (strcmp("0", namelist[i]->d_name) && 400219820Sjeff ((portnum = atoi(namelist[i]->d_name)) <= 0 || 401219820Sjeff portnum >= UMAD_CA_MAX_PORTS)) { 402219820Sjeff ret = -EIO; 403219820Sjeff goto clean; 404219820Sjeff } 405219820Sjeff if (!(ca->ports[portnum] = calloc(1, sizeof(*ca->ports[portnum])))) { 406219820Sjeff ret = -ENOMEM; 407219820Sjeff goto clean; 408219820Sjeff } 409219820Sjeff if (get_port(ca_name, dir_name, portnum, ca->ports[portnum]) < 0) { 410219820Sjeff free(ca->ports[portnum]); 411219820Sjeff ca->ports[portnum] = NULL; 412219820Sjeff ret = -EIO; 413219820Sjeff goto clean; 414219820Sjeff } 415219820Sjeff if (ca->numports < portnum) 416219820Sjeff ca->numports = portnum; 417219820Sjeff } 418219820Sjeff 419219820Sjeff for (i = 0; i < r; i++) 420219820Sjeff free(namelist[i]); 421219820Sjeff free(namelist); 422219820Sjeff 423219820Sjeff#ifdef __linux__ 424219820Sjeff closedir(dir); 425219820Sjeff#endif 426219820Sjeff put_ca(ca); 427219820Sjeff return 0; 428219820Sjeff 429219820Sjeffclean: 430219820Sjeff for (i = 0; i < r; i++) 431219820Sjeff free(namelist[i]); 432219820Sjeff free(namelist); 433219820Sjefferror: 434219820Sjeff#ifdef __linux__ 435219820Sjeff closedir(dir); 436219820Sjeff#endif 437219820Sjeff release_ca(ca); 438219820Sjeff 439219820Sjeff return ret; 440219820Sjeff} 441219820Sjeff 442219820Sjeffstatic int 443219820Sjeffumad_id_to_dev(int umad_id, char *dev, unsigned *port) 444219820Sjeff{ 445219820Sjeff char path[256]; 446219820Sjeff int r; 447219820Sjeff 448219820Sjeff snprintf(path, sizeof(path), SYS_INFINIBAND_MAD "/umad%d", umad_id); 449219820Sjeff 450219820Sjeff if ((r = sys_read_string(path, SYS_IB_MAD_DEV, dev, UMAD_CA_NAME_LEN)) < 0) 451219820Sjeff return r; 452219820Sjeff 453219820Sjeff if ((r = sys_read_uint(path, SYS_IB_MAD_PORT, port)) < 0) 454219820Sjeff return r; 455219820Sjeff 456219820Sjeff return 0; 457219820Sjeff} 458219820Sjeff 459219820Sjeffstatic int 460219820Sjeffdev_to_umad_id(char *dev, unsigned port) 461219820Sjeff{ 462219820Sjeff char umad_dev[UMAD_CA_NAME_LEN]; 463219820Sjeff unsigned umad_port; 464219820Sjeff int id; 465219820Sjeff 466219820Sjeff for (id = 0; id < UMAD_MAX_PORTS; id++) { 467219820Sjeff if (umad_id_to_dev(id, umad_dev, &umad_port) < 0) 468219820Sjeff continue; 469219820Sjeff if (strncmp(dev, umad_dev, UMAD_CA_NAME_LEN)) 470219820Sjeff continue; 471219820Sjeff if (port != umad_port) 472219820Sjeff continue; 473219820Sjeff 474219820Sjeff DEBUG("mapped %s %d to %d", dev, port, id); 475219820Sjeff return id; 476219820Sjeff } 477219820Sjeff 478219820Sjeff return -1; /* not found */ 479219820Sjeff} 480219820Sjeff 481219820Sjeff/******************************* 482219820Sjeff * Public interface 483219820Sjeff */ 484219820Sjeff 485219820Sjeffint 486219820Sjeffumad_init(void) 487219820Sjeff{ 488219820Sjeff TRACE("umad_init"); 489219820Sjeff if (sys_read_uint(IB_UMAD_ABI_DIR, IB_UMAD_ABI_FILE, &abi_version) < 0) { 490219820Sjeff IBWARN("can't read ABI version from %s/%s (%m): is ib_umad module loaded?", 491219820Sjeff IB_UMAD_ABI_DIR, IB_UMAD_ABI_FILE); 492219820Sjeff return -1; 493219820Sjeff } 494219820Sjeff if (abi_version < IB_UMAD_ABI_VERSION) { 495219820Sjeff IBWARN("wrong ABI version: %s/%s is %d but library minimal ABI is %d", 496219820Sjeff IB_UMAD_ABI_DIR, IB_UMAD_ABI_FILE, abi_version, IB_UMAD_ABI_VERSION); 497219820Sjeff return -1; 498219820Sjeff } 499219820Sjeff return 0; 500219820Sjeff} 501219820Sjeff 502219820Sjeffint 503219820Sjeffumad_done(void) 504219820Sjeff{ 505219820Sjeff TRACE("umad_done"); 506219820Sjeff /* FIXME - verify that all ports are closed */ 507219820Sjeff return 0; 508219820Sjeff} 509219820Sjeff 510219820Sjeffstatic unsigned is_ib_type(char *ca_name) 511219820Sjeff{ 512219820Sjeff char dir_name[256]; 513219820Sjeff unsigned type; 514219820Sjeff 515219820Sjeff snprintf(dir_name, sizeof(dir_name), "%s/%s", SYS_INFINIBAND, ca_name); 516219820Sjeff 517219820Sjeff if (sys_read_uint(dir_name, SYS_NODE_TYPE, &type) < 0) 518219820Sjeff return 0; 519219820Sjeff 520219820Sjeff return type >= 1 && type <= 3 ? 1 : 0; 521219820Sjeff} 522219820Sjeff 523219820Sjeffint 524219820Sjeffumad_get_cas_names(char cas[][UMAD_CA_NAME_LEN], int max) 525219820Sjeff{ 526219820Sjeff struct dirent **namelist; 527219820Sjeff int n, i, j = 0; 528219820Sjeff 529219820Sjeff TRACE("max %d", max); 530219820Sjeff 531219820Sjeff n = sys_scandir(SYS_INFINIBAND, &namelist, NULL, alphasort); 532219820Sjeff if (n > 0) { 533219820Sjeff for (i = 0; i < n; i++) { 534219820Sjeff if (strcmp(namelist[i]->d_name, ".") && 535219820Sjeff strcmp(namelist[i]->d_name, "..")) { 536219820Sjeff if (j < max && is_ib_type(namelist[i]->d_name)) 537219820Sjeff strncpy(cas[j++], namelist[i]->d_name, 538219820Sjeff UMAD_CA_NAME_LEN); 539219820Sjeff } 540219820Sjeff free(namelist[i]); 541219820Sjeff } 542219820Sjeff DEBUG("return %d cas", j); 543219820Sjeff } else { 544219820Sjeff /* Is this still needed ? */ 545219820Sjeff strncpy((char *)cas, def_ca_name, UMAD_CA_NAME_LEN); 546219820Sjeff DEBUG("return 1 ca"); 547219820Sjeff j = 1; 548219820Sjeff } 549219820Sjeff if (n >= 0) 550219820Sjeff free(namelist); 551219820Sjeff return j; 552219820Sjeff} 553219820Sjeff 554219820Sjeffint 555219820Sjeffumad_get_ca_portguids(char *ca_name, uint64_t *portguids, int max) 556219820Sjeff{ 557219820Sjeff umad_ca_t ca; 558219820Sjeff int ports = 0, i; 559219820Sjeff 560219820Sjeff TRACE("ca name %s max port guids %d", ca_name, max); 561219820Sjeff if (!(ca_name = resolve_ca_name(ca_name, 0))) 562219820Sjeff return -ENODEV; 563219820Sjeff 564219820Sjeff if (umad_get_ca(ca_name, &ca) < 0) 565219820Sjeff return -1; 566219820Sjeff 567219820Sjeff if (portguids) { 568219820Sjeff if (ca.numports + 1 > max) { 569219820Sjeff release_ca(&ca); 570219820Sjeff return -ENOMEM; 571219820Sjeff } 572219820Sjeff 573219820Sjeff for (i = 0; i <= ca.numports; i++) 574219820Sjeff portguids[ports++] = ca.ports[i] ? ca.ports[i]->port_guid : 0; 575219820Sjeff } 576219820Sjeff 577219820Sjeff release_ca(&ca); 578219820Sjeff DEBUG("%s: %d ports", ca_name, ports); 579219820Sjeff 580219820Sjeff return ports; 581219820Sjeff} 582219820Sjeff 583219820Sjeffint 584219820Sjeffumad_get_issm_path(char *ca_name, int portnum, char path[], int max) 585219820Sjeff{ 586219820Sjeff int umad_id; 587219820Sjeff 588219820Sjeff TRACE("ca %s port %d", ca_name, portnum); 589219820Sjeff 590219820Sjeff if (!(ca_name = resolve_ca_name(ca_name, &portnum))) 591219820Sjeff return -ENODEV; 592219820Sjeff 593219820Sjeff if ((umad_id = dev_to_umad_id(ca_name, portnum)) < 0) 594219820Sjeff return -EINVAL; 595219820Sjeff 596219820Sjeff snprintf(path, max, "%s/issm%u", UMAD_DEV_DIR , umad_id); 597219820Sjeff 598219820Sjeff return 0; 599219820Sjeff} 600219820Sjeff 601219820Sjeffint 602219820Sjeffumad_open_port(char *ca_name, int portnum) 603219820Sjeff{ 604219820Sjeff char dev_file[UMAD_DEV_FILE_SZ]; 605219820Sjeff int umad_id, fd; 606219820Sjeff 607219820Sjeff TRACE("ca %s port %d", ca_name, portnum); 608219820Sjeff 609219820Sjeff if (!(ca_name = resolve_ca_name(ca_name, &portnum))) 610219820Sjeff return -ENODEV; 611219820Sjeff 612219820Sjeff DEBUG("opening %s port %d", ca_name, portnum); 613219820Sjeff 614219820Sjeff if ((umad_id = dev_to_umad_id(ca_name, portnum)) < 0) 615219820Sjeff return -EINVAL; 616219820Sjeff 617219820Sjeff snprintf(dev_file, sizeof(dev_file), "%s/umad%d", 618219820Sjeff UMAD_DEV_DIR , umad_id); 619219820Sjeff 620219820Sjeff if ((fd = open(dev_file, O_RDWR|O_NONBLOCK)) < 0) { 621219820Sjeff DEBUG("open %s failed: %s", dev_file, strerror(errno)); 622219820Sjeff return -EIO; 623219820Sjeff } 624219820Sjeff 625219820Sjeff if (abi_version > 5 || !ioctl(fd, IB_USER_MAD_ENABLE_PKEY, NULL)) 626219820Sjeff new_user_mad_api = 1; 627219820Sjeff else 628219820Sjeff new_user_mad_api = 0; 629219820Sjeff 630219820Sjeff DEBUG("opened %s fd %d portid %d", dev_file, fd, umad_id); 631219820Sjeff return fd; 632219820Sjeff} 633219820Sjeff 634219820Sjeffint 635219820Sjeffumad_get_ca(char *ca_name, umad_ca_t *ca) 636219820Sjeff{ 637219820Sjeff int r; 638219820Sjeff 639219820Sjeff TRACE("ca_name %s", ca_name); 640219820Sjeff if (!(ca_name = resolve_ca_name(ca_name, 0))) 641219820Sjeff return -ENODEV; 642219820Sjeff 643219820Sjeff if (find_cached_ca(ca_name, ca) > 0) 644219820Sjeff return 0; 645219820Sjeff 646219820Sjeff if ((r = get_ca(ca_name, ca)) < 0) 647219820Sjeff return r; 648219820Sjeff 649219820Sjeff DEBUG("opened %s", ca_name); 650219820Sjeff return 0; 651219820Sjeff} 652219820Sjeff 653219820Sjeffint 654219820Sjeffumad_release_ca(umad_ca_t *ca) 655219820Sjeff{ 656219820Sjeff int r; 657219820Sjeff 658219820Sjeff TRACE("ca_name %s", ca->ca_name); 659219820Sjeff if (!ca) 660219820Sjeff return -ENODEV; 661219820Sjeff 662219820Sjeff if ((r = release_ca(ca)) < 0) 663219820Sjeff return r; 664219820Sjeff 665219820Sjeff DEBUG("releasing %s", ca->ca_name); 666219820Sjeff return 0; 667219820Sjeff} 668219820Sjeff 669219820Sjeffint 670219820Sjeffumad_get_port(char *ca_name, int portnum, umad_port_t *port) 671219820Sjeff{ 672219820Sjeff char dir_name[256]; 673219820Sjeff 674219820Sjeff TRACE("ca_name %s portnum %d", ca_name, portnum); 675219820Sjeff 676219820Sjeff if (!(ca_name = resolve_ca_name(ca_name, &portnum))) 677219820Sjeff return -ENODEV; 678219820Sjeff 679219820Sjeff snprintf(dir_name, sizeof(dir_name), "%s/%s/%s", 680219820Sjeff SYS_INFINIBAND, ca_name, SYS_CA_PORTS_DIR); 681219820Sjeff 682219820Sjeff return get_port(ca_name, dir_name, portnum, port); 683219820Sjeff} 684219820Sjeff 685219820Sjeffint 686219820Sjeffumad_release_port(umad_port_t *port) 687219820Sjeff{ 688219820Sjeff int r; 689219820Sjeff 690219820Sjeff TRACE("port %s:%d", port->ca_name, port->portnum); 691219820Sjeff if (!port) 692219820Sjeff return -ENODEV; 693219820Sjeff 694219820Sjeff if ((r = release_port(port)) < 0) 695219820Sjeff return r; 696219820Sjeff 697219820Sjeff DEBUG("releasing %s:%d", port->ca_name, port->portnum); 698219820Sjeff return 0; 699219820Sjeff} 700219820Sjeff 701219820Sjeffint 702219820Sjeffumad_close_port(int fd) 703219820Sjeff{ 704219820Sjeff close(fd); 705219820Sjeff DEBUG("closed fd %d", fd); 706219820Sjeff return 0; 707219820Sjeff} 708219820Sjeff 709219820Sjeffvoid * 710219820Sjeffumad_get_mad(void *umad) 711219820Sjeff{ 712219820Sjeff return new_user_mad_api ? ((struct ib_user_mad *)umad)->data : 713219820Sjeff (void *)&((struct ib_user_mad *)umad)->addr.pkey_index; 714219820Sjeff} 715219820Sjeff 716219820Sjeffsize_t 717219820Sjeffumad_size(void) 718219820Sjeff{ 719219820Sjeff return new_user_mad_api ? sizeof (struct ib_user_mad) : 720219820Sjeff sizeof(struct ib_user_mad) - 8; 721219820Sjeff} 722219820Sjeff 723219820Sjeffint 724219820Sjeffumad_set_grh(void *umad, void *mad_addr) 725219820Sjeff{ 726219820Sjeff struct ib_user_mad *mad = umad; 727219820Sjeff struct ib_mad_addr *addr = mad_addr; 728219820Sjeff 729219820Sjeff if (mad_addr) { 730219820Sjeff mad->addr.grh_present = 1; 731219820Sjeff memcpy(mad->addr.gid, addr->gid, 16); 732219820Sjeff mad->addr.flow_label = htonl(addr->flow_label); 733219820Sjeff mad->addr.hop_limit = addr->hop_limit; 734219820Sjeff mad->addr.traffic_class = addr->traffic_class; 735219820Sjeff } else 736219820Sjeff mad->addr.grh_present = 0; 737219820Sjeff return 0; 738219820Sjeff} 739219820Sjeff 740219820Sjeffint 741219820Sjeffumad_set_pkey(void *umad, int pkey_index) 742219820Sjeff{ 743219820Sjeff struct ib_user_mad *mad = umad; 744219820Sjeff 745219820Sjeff if (new_user_mad_api) 746219820Sjeff mad->addr.pkey_index = pkey_index; 747219820Sjeff 748219820Sjeff return 0; 749219820Sjeff} 750219820Sjeff 751219820Sjeffint 752219820Sjeffumad_get_pkey(void *umad) 753219820Sjeff{ 754219820Sjeff struct ib_user_mad *mad = umad; 755219820Sjeff 756219820Sjeff if (new_user_mad_api) 757219820Sjeff return mad->addr.pkey_index; 758219820Sjeff 759219820Sjeff return 0; 760219820Sjeff} 761219820Sjeff 762219820Sjeffint 763219820Sjeffumad_set_addr(void *umad, int dlid, int dqp, int sl, int qkey) 764219820Sjeff{ 765219820Sjeff struct ib_user_mad *mad = umad; 766219820Sjeff 767219820Sjeff TRACE("umad %p dlid %d dqp %d sl %d, qkey %x", 768219820Sjeff umad, dlid, dqp, sl, qkey); 769219820Sjeff mad->addr.qpn = htonl(dqp); 770219820Sjeff mad->addr.lid = htons(dlid); 771219820Sjeff mad->addr.qkey = htonl(qkey); 772219820Sjeff mad->addr.sl = sl; 773219820Sjeff 774219820Sjeff return 0; 775219820Sjeff} 776219820Sjeff 777219820Sjeffint 778219820Sjeffumad_set_addr_net(void *umad, int dlid, int dqp, int sl, int qkey) 779219820Sjeff{ 780219820Sjeff struct ib_user_mad *mad = umad; 781219820Sjeff 782219820Sjeff TRACE("umad %p dlid %d dqp %d sl %d qkey %x", 783219820Sjeff umad, ntohs(dlid), ntohl(dqp), sl, ntohl(qkey)); 784219820Sjeff mad->addr.qpn = dqp; 785219820Sjeff mad->addr.lid = dlid; 786219820Sjeff mad->addr.qkey = qkey; 787219820Sjeff mad->addr.sl = sl; 788219820Sjeff 789219820Sjeff return 0; 790219820Sjeff} 791219820Sjeff 792219820Sjeffint 793219820Sjeffumad_send(int fd, int agentid, void *umad, int length, 794219820Sjeff int timeout_ms, int retries) 795219820Sjeff{ 796219820Sjeff struct ib_user_mad *mad = umad; 797219820Sjeff int n; 798219820Sjeff 799219820Sjeff TRACE("fd %d agentid %d umad %p timeout %u", 800219820Sjeff fd, agentid, umad, timeout_ms); 801219820Sjeff errno = 0; 802219820Sjeff 803219820Sjeff mad->timeout_ms = timeout_ms; 804219820Sjeff mad->retries = retries; 805219820Sjeff mad->agent_id = agentid; 806219820Sjeff 807219820Sjeff if (umaddebug > 1) 808219820Sjeff umad_dump(mad); 809219820Sjeff 810219820Sjeff n = write(fd, mad, length + umad_size()); 811219820Sjeff if (n == length + umad_size()) 812219820Sjeff return 0; 813219820Sjeff 814219820Sjeff DEBUG("write returned %d != sizeof umad %zu + length %d (%m)", 815219820Sjeff n, umad_size(), length); 816219820Sjeff if (!errno) 817219820Sjeff errno = EIO; 818219820Sjeff return -EIO; 819219820Sjeff} 820219820Sjeff 821219820Sjeffstatic int 822219820Sjeffdev_poll(int fd, int timeout_ms) 823219820Sjeff{ 824219820Sjeff struct pollfd ufds; 825219820Sjeff int n; 826219820Sjeff 827219820Sjeff ufds.fd = fd; 828219820Sjeff ufds.events = POLLIN; 829219820Sjeff 830219820Sjeff if ((n = poll(&ufds, 1, timeout_ms)) == 1) 831219820Sjeff return 0; 832219820Sjeff 833219820Sjeff if (n == 0) 834219820Sjeff return -ETIMEDOUT; 835219820Sjeff 836219820Sjeff return -EIO; 837219820Sjeff} 838219820Sjeff 839219820Sjeffint 840219820Sjeffumad_recv(int fd, void *umad, int *length, int timeout_ms) 841219820Sjeff{ 842219820Sjeff struct ib_user_mad *mad = umad; 843219820Sjeff int n; 844219820Sjeff 845219820Sjeff errno = 0; 846219820Sjeff TRACE("fd %d umad %p timeout %u", fd, umad, timeout_ms); 847219820Sjeff 848219820Sjeff if (!umad || !length) { 849219820Sjeff errno = EINVAL; 850219820Sjeff return -EINVAL; 851219820Sjeff } 852219820Sjeff 853219820Sjeff if (timeout_ms && (n = dev_poll(fd, timeout_ms)) < 0) { 854219820Sjeff if (!errno) 855219820Sjeff errno = -n; 856219820Sjeff return n; 857219820Sjeff } 858219820Sjeff 859219820Sjeff n = read(fd, umad, umad_size() + *length); 860219820Sjeff 861219820Sjeff VALGRIND_MAKE_MEM_DEFINED(umad, umad_size() + *length); 862219820Sjeff 863219820Sjeff if ((n >= 0) && (n <= umad_size() + *length)) { 864219820Sjeff DEBUG("mad received by agent %d length %d", mad->agent_id, n); 865219820Sjeff if (n > umad_size()) 866219820Sjeff *length = n - umad_size(); 867219820Sjeff else 868219820Sjeff *length = 0; 869219820Sjeff return mad->agent_id; 870219820Sjeff } 871219820Sjeff 872219820Sjeff if (n == -EWOULDBLOCK) { 873219820Sjeff if (!errno) 874219820Sjeff errno = EWOULDBLOCK; 875219820Sjeff return n; 876219820Sjeff } 877219820Sjeff 878219820Sjeff DEBUG("read returned %zu > sizeof umad %zu + length %d (%m)", 879219820Sjeff mad->length - umad_size(), umad_size(), *length); 880219820Sjeff 881219820Sjeff *length = mad->length - umad_size(); 882219820Sjeff if (!errno) 883219820Sjeff errno = EIO; 884219820Sjeff return -errno; 885219820Sjeff} 886219820Sjeff 887219820Sjeffint 888219820Sjeffumad_poll(int fd, int timeout_ms) 889219820Sjeff{ 890219820Sjeff TRACE("fd %d timeout %u", fd, timeout_ms); 891219820Sjeff return dev_poll(fd, timeout_ms); 892219820Sjeff} 893219820Sjeff 894219820Sjeffint 895219820Sjeffumad_get_fd(int fd) 896219820Sjeff{ 897219820Sjeff TRACE("fd %d", fd); 898219820Sjeff return fd; 899219820Sjeff} 900219820Sjeff 901219820Sjeffint 902219820Sjeffumad_register_oui(int fd, int mgmt_class, uint8_t rmpp_version, 903219820Sjeff uint8_t oui[3], long method_mask[]) 904219820Sjeff{ 905219820Sjeff struct ib_user_mad_reg_req req; 906219820Sjeff 907219820Sjeff TRACE("fd %d mgmt_class %u rmpp_version %d oui 0x%x%x%x method_mask %p", 908219820Sjeff fd, mgmt_class, (int)rmpp_version, (int)oui[0], (int)oui[1], 909219820Sjeff (int)oui[2], method_mask); 910219820Sjeff 911219820Sjeff if (mgmt_class < 0x30 || mgmt_class > 0x4f) { 912219820Sjeff DEBUG("mgmt class %d not in vendor range 2", mgmt_class); 913219820Sjeff return -EINVAL; 914219820Sjeff } 915219820Sjeff 916219820Sjeff req.qpn = 1; 917219820Sjeff req.mgmt_class = mgmt_class; 918219820Sjeff req.mgmt_class_version = 1; 919219820Sjeff memcpy(req.oui, oui, sizeof req.oui); 920219820Sjeff req.rmpp_version = rmpp_version; 921219820Sjeff 922219820Sjeff if (method_mask) 923219820Sjeff memcpy(req.method_mask, method_mask, sizeof req.method_mask); 924219820Sjeff else 925219820Sjeff memset(req.method_mask, 0, sizeof req.method_mask); 926219820Sjeff 927219820Sjeff VALGRIND_MAKE_MEM_DEFINED(&req, sizeof req); 928219820Sjeff 929219820Sjeff if (!ioctl(fd, IB_USER_MAD_REGISTER_AGENT, (void *)&req)) { 930219820Sjeff DEBUG("fd %d registered to use agent %d qp %d class 0x%x oui %p", 931219820Sjeff fd, req.id, req.qpn, req.mgmt_class, oui); 932219820Sjeff return req.id; /* return agentid */ 933219820Sjeff } 934219820Sjeff 935219820Sjeff DEBUG("fd %d registering qp %d class 0x%x version %d oui %p failed: %m", 936219820Sjeff fd, req.qpn, req.mgmt_class, req.mgmt_class_version, oui); 937219820Sjeff return -EPERM; 938219820Sjeff} 939219820Sjeff 940219820Sjeffint 941219820Sjeffumad_register(int fd, int mgmt_class, int mgmt_version, 942219820Sjeff uint8_t rmpp_version, long method_mask[]) 943219820Sjeff{ 944219820Sjeff struct ib_user_mad_reg_req req; 945219820Sjeff uint32_t oui = htonl(IB_OPENIB_OUI); 946219820Sjeff int qp; 947219820Sjeff 948219820Sjeff TRACE("fd %d mgmt_class %u mgmt_version %u rmpp_version %d method_mask %p", 949219820Sjeff fd, mgmt_class, mgmt_version, rmpp_version, method_mask); 950219820Sjeff 951219820Sjeff req.qpn = qp = (mgmt_class == 0x1 || mgmt_class == 0x81) ? 0 : 1; 952219820Sjeff req.mgmt_class = mgmt_class; 953219820Sjeff req.mgmt_class_version = mgmt_version; 954219820Sjeff req.rmpp_version = rmpp_version; 955219820Sjeff 956219820Sjeff if (method_mask) 957219820Sjeff memcpy(req.method_mask, method_mask, sizeof req.method_mask); 958219820Sjeff else 959219820Sjeff memset(req.method_mask, 0, sizeof req.method_mask); 960219820Sjeff 961219820Sjeff memcpy(&req.oui, (char *)&oui + 1, sizeof req.oui); 962219820Sjeff 963219820Sjeff VALGRIND_MAKE_MEM_DEFINED(&req, sizeof req); 964219820Sjeff 965219820Sjeff if (!ioctl(fd, IB_USER_MAD_REGISTER_AGENT, (void *)&req)) { 966219820Sjeff DEBUG("fd %d registered to use agent %d qp %d", 967219820Sjeff fd, req.id, qp); 968219820Sjeff return req.id; /* return agentid */ 969219820Sjeff } 970219820Sjeff 971219820Sjeff DEBUG("fd %d registering qp %d class 0x%x version %d failed: %m", 972219820Sjeff fd, qp, mgmt_class, mgmt_version); 973219820Sjeff return -EPERM; 974219820Sjeff} 975219820Sjeff 976219820Sjeffint 977219820Sjeffumad_unregister(int fd, int agentid) 978219820Sjeff{ 979219820Sjeff TRACE("fd %d unregistering agent %d", fd, agentid); 980219820Sjeff return ioctl(fd, IB_USER_MAD_UNREGISTER_AGENT, &agentid); 981219820Sjeff} 982219820Sjeff 983219820Sjeffint 984219820Sjeffumad_status(void *umad) 985219820Sjeff{ 986219820Sjeff struct ib_user_mad *mad = umad; 987219820Sjeff 988219820Sjeff return mad->status; 989219820Sjeff} 990219820Sjeff 991219820Sjeffib_mad_addr_t * 992219820Sjeffumad_get_mad_addr(void *umad) 993219820Sjeff{ 994219820Sjeff struct ib_user_mad *mad = umad; 995219820Sjeff 996219820Sjeff return &mad->addr; 997219820Sjeff} 998219820Sjeff 999219820Sjeffint 1000219820Sjeffumad_debug(int level) 1001219820Sjeff{ 1002219820Sjeff if (level >= 0) 1003219820Sjeff umaddebug = level; 1004219820Sjeff return umaddebug; 1005219820Sjeff} 1006219820Sjeff 1007219820Sjeffvoid 1008219820Sjeffumad_addr_dump(ib_mad_addr_t *addr) 1009219820Sjeff{ 1010219820Sjeff#define HEX(x) ((x) < 10 ? '0' + (x) : 'a' + ((x) -10)) 1011219820Sjeff char gid_str[64]; 1012219820Sjeff int i; 1013219820Sjeff 1014219820Sjeff for (i = 0; i < sizeof addr->gid; i++) { 1015219820Sjeff gid_str[i*2] = HEX(addr->gid[i] >> 4); 1016219820Sjeff gid_str[i*2+1] = HEX(addr->gid[i] & 0xf); 1017219820Sjeff } 1018219820Sjeff gid_str[i*2] = 0; 1019219820Sjeff IBWARN("qpn %d qkey 0x%x lid 0x%x sl %d\n" 1020219820Sjeff "grh_present %d gid_index %d hop_limit %d traffic_class %d flow_label 0x%x pkey_index 0x%x\n" 1021219820Sjeff "Gid 0x%s", 1022219820Sjeff ntohl(addr->qpn), ntohl(addr->qkey), ntohs(addr->lid), addr->sl, 1023219820Sjeff addr->grh_present, (int)addr->gid_index, (int)addr->hop_limit, 1024219820Sjeff (int)addr->traffic_class, addr->flow_label, addr->pkey_index, 1025219820Sjeff gid_str); 1026219820Sjeff} 1027219820Sjeff 1028219820Sjeffvoid 1029219820Sjeffumad_dump(void *umad) 1030219820Sjeff{ 1031219820Sjeff struct ib_user_mad * mad = umad; 1032219820Sjeff 1033219820Sjeff IBWARN("agent id %d status %x timeout %d", 1034219820Sjeff mad->agent_id, mad->status, mad->timeout_ms); 1035219820Sjeff umad_addr_dump(&mad->addr); 1036219820Sjeff} 1037