1/* 2 * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 * 32 */ 33 34#if HAVE_CONFIG_H 35# include <config.h> 36#endif /* HAVE_CONFIG_H */ 37 38#include <sys/poll.h> 39#include <unistd.h> 40#include <string.h> 41#include <errno.h> 42#include <sys/types.h> 43#include <sys/stat.h> 44#include <fcntl.h> 45#include <sys/ioctl.h> 46#include <netinet/in.h> 47#include <dirent.h> 48#include <stdlib.h> 49#include <ctype.h> 50 51#include "umad.h" 52 53#define IB_OPENIB_OUI (0x001405) 54 55#ifdef HAVE_VALGRIND_MEMCHECK_H 56 57# include <valgrind/memcheck.h> 58 59# ifndef VALGRIND_MAKE_MEM_DEFINED 60# warning "Valgrind support requested, but VALGRIND_MAKE_MEM_DEFINED not available" 61# endif 62 63#endif /* HAVE_VALGRIND_MEMCHECK_H */ 64 65#ifndef VALGRIND_MAKE_MEM_DEFINED 66# define VALGRIND_MAKE_MEM_DEFINED(addr,len) 67#endif 68 69typedef struct ib_user_mad_reg_req { 70 uint32_t id; 71 uint32_t method_mask[4]; 72 uint8_t qpn; 73 uint8_t mgmt_class; 74 uint8_t mgmt_class_version; 75 uint8_t oui[3]; 76 uint8_t rmpp_version; 77} ib_user_mad_reg_req_t; 78 79#define TRACE if (umaddebug) IBWARN 80#define DEBUG if (umaddebug) IBWARN 81 82int umaddebug = 0; 83 84#define UMAD_DEV_FILE_SZ 256 85 86static char *def_ca_name = "mthca0"; 87static int def_ca_port = 1; 88 89static unsigned abi_version; 90static unsigned new_user_mad_api; 91 92/************************************* 93 * Port 94 */ 95static int 96find_cached_ca(char *ca_name, umad_ca_t *ca) 97{ 98 return 0; /* caching not implemented yet */ 99} 100 101static int 102put_ca(umad_ca_t *ca) 103{ 104 return 0; /* caching not implemented yet */ 105} 106 107static int 108release_port(umad_port_t *port) 109{ 110 free(port->pkeys); 111 port->pkeys = NULL; 112 port->pkeys_size = 0; 113 return 0; 114} 115 116static int check_for_digit_name(const struct dirent *dent) 117{ 118 const char *p = dent->d_name; 119 while (*p && isdigit(*p)) 120 p++; 121 return *p ? 0 : 1; 122} 123 124static int 125get_port(char *ca_name, char *dir, int portnum, umad_port_t *port) 126{ 127 char port_dir[256]; 128 uint8_t gid[16]; 129 struct dirent **namelist = NULL; 130 int i, len, ret = 0; 131 132 strncpy(port->ca_name, ca_name, sizeof port->ca_name - 1); 133 port->portnum = portnum; 134 port->pkeys = NULL; 135 136 len = snprintf(port_dir, sizeof(port_dir), "%s/%d", dir, portnum); 137 if (len < 0 || len > sizeof(port_dir)) 138 goto clean; 139 140 if (sys_read_uint(port_dir, SYS_PORT_LMC, &port->lmc) < 0) 141 goto clean; 142 if (sys_read_uint(port_dir, SYS_PORT_SMLID, &port->sm_lid) < 0) 143 goto clean; 144 if (sys_read_uint(port_dir, SYS_PORT_SMSL, &port->sm_sl) < 0) 145 goto clean; 146 if (sys_read_uint(port_dir, SYS_PORT_LID, &port->base_lid) < 0) 147 goto clean; 148 if (sys_read_uint(port_dir, SYS_PORT_STATE, &port->state) < 0) 149 goto clean; 150 if (sys_read_uint(port_dir, SYS_PORT_PHY_STATE, &port->phys_state) < 0) 151 goto clean; 152 if (sys_read_uint(port_dir, SYS_PORT_RATE, &port->rate) < 0) 153 goto clean; 154 if (sys_read_uint64(port_dir, SYS_PORT_CAPMASK, &port->capmask) < 0) 155 goto clean; 156 157 port->capmask = htonl(port->capmask); 158 159 if (sys_read_gid(port_dir, SYS_PORT_GID, gid) < 0) 160 goto clean; 161 162 memcpy(&port->gid_prefix, gid, sizeof port->gid_prefix); 163 memcpy(&port->port_guid, gid + 8, sizeof port->port_guid); 164 165 snprintf(port_dir + len, sizeof(port_dir) - len, "/pkeys"); 166 ret = sys_scandir(port_dir, &namelist, check_for_digit_name, NULL); 167 if (ret <= 0) { 168 IBWARN("no pkeys found for %s:%u (at dir %s)...", 169 port->ca_name, port->portnum, port_dir); 170 goto clean; 171 } 172 port->pkeys = calloc(ret, sizeof(port->pkeys[0])); 173 if (!port->pkeys) { 174 IBWARN("get_port: calloc failed: %s", strerror(errno)); 175 goto clean; 176 } 177 for (i = 0; i < ret ; i++) { 178 unsigned idx, val; 179 idx = strtoul(namelist[i]->d_name, NULL, 0); 180 sys_read_uint(port_dir, namelist[i]->d_name, &val); 181 port->pkeys[idx] = val; 182 free(namelist[i]); 183 } 184 port->pkeys_size = ret; 185 free(namelist); 186 namelist = NULL; 187 port_dir[len] = '\0'; 188 189 /* FIXME: handle gids */ 190 191 return 0; 192 193clean: 194 if (namelist) { 195 for (i = 0; i < ret ; i++) 196 free(namelist[i]); 197 free(namelist); 198 } 199 if (port->pkeys) 200 free(port->pkeys); 201 return -EIO; 202} 203 204static int 205release_ca(umad_ca_t *ca) 206{ 207 int i; 208 209 for (i = 0; i <= ca->numports; i++) { 210 if (!ca->ports[i]) 211 continue; 212 release_port(ca->ports[i]); 213 free(ca->ports[i]); 214 ca->ports[i] = 0; 215 } 216 return 0; 217} 218 219/* 220 * if *port > 0, check ca[port] state. Otherwise set *port to 221 * the first port that is active, and if such is not found, to 222 * the first port that is link up and if none are linkup, then 223 * the first port that is not disabled. Otherwise return -1. 224 */ 225static int 226resolve_ca_port(char *ca_name, int *port) 227{ 228 umad_ca_t ca; 229 int active = -1, up = -1; 230 int i; 231 232 TRACE("checking ca '%s'", ca_name); 233 234 if (umad_get_ca(ca_name, &ca) < 0) 235 return -1; 236 237 if (ca.node_type == 2) { 238 *port = 0; /* switch sma port 0 */ 239 return 1; 240 } 241 242 if (*port > 0) { /* check only the port the user wants */ 243 if (*port > ca.numports) 244 return -1; 245 if (!ca.ports[*port]) 246 return -1; 247 if (ca.ports[*port]->state == 4) 248 return 1; 249 if (ca.ports[*port]->phys_state != 3) 250 return 0; 251 return -1; 252 } 253 254 for (i = 0; i <= ca.numports; i++) { 255 DEBUG("checking port %d", i); 256 if (!ca.ports[i]) 257 continue; 258 if (up < 0 && ca.ports[i]->phys_state == 5) 259 up = *port = i; 260 if (ca.ports[i]->state == 4) { 261 active = *port = i; 262 DEBUG("found active port %d", i); 263 break; 264 } 265 } 266 267 if (active == -1 && up == -1) { /* no active or linkup port found */ 268 for (i = 0; i <= ca.numports; i++) { 269 DEBUG("checking port %d", i); 270 if (!ca.ports[i]) 271 continue; 272 if (ca.ports[i]->phys_state != 3) { 273 up = *port = i; 274 break; 275 } 276 } 277 } 278 279 release_ca(&ca); 280 281 if (active >= 0) 282 return 1; 283 if (up >= 0) 284 return 0; 285 return -1; 286} 287 288static char * 289resolve_ca_name(char *ca_name, int *best_port) 290{ 291 static char names[UMAD_MAX_DEVICES][UMAD_CA_NAME_LEN]; 292 int phys_found = -1, port_found = 0, port, port_type; 293 int caidx, n; 294 295 if (ca_name && (!best_port || *best_port)) 296 return ca_name; 297 298 if (ca_name) { 299 if (resolve_ca_port(ca_name, best_port) < 0) 300 return 0; 301 return ca_name; 302 } 303 304 /* Get the list of CA names */ 305 if ((n = umad_get_cas_names((void *)names, 20)) < 0) 306 return 0; 307 308 /* Find the first existing CA with an active port */ 309 for (caidx = 0; caidx < n; caidx++) { 310 TRACE("checking ca '%s'", names[caidx]); 311 312 port = best_port ? *best_port : 0; 313 if ((port_type = resolve_ca_port(names[caidx], &port)) < 0) 314 continue; 315 316 DEBUG("found ca %s with port %d type %d", 317 names[caidx], port, port_type); 318 319 if (port_type > 0) { 320 if (best_port) 321 *best_port = port; 322 DEBUG("found ca %s with active port %d", 323 names[caidx], port); 324 return (char *)(names + caidx); 325 } 326 327 if (phys_found == -1) { 328 phys_found = caidx; 329 port_found = port; 330 } 331 } 332 333 DEBUG("phys found %d on %s port %d", 334 phys_found, phys_found >=0 ? names[phys_found] : 0, port_found); 335 if (phys_found >= 0) { 336 if (best_port) 337 *best_port = port_found; 338 return names[phys_found]; 339 } 340 341 if (best_port) 342 *best_port = def_ca_port; 343 return def_ca_name; 344} 345 346static int 347get_ca(char *ca_name, umad_ca_t *ca) 348{ 349#ifdef __linux__ 350 DIR *dir; 351#endif 352 char dir_name[256]; 353 struct dirent **namelist; 354 int r, i, ret; 355 int portnum; 356 357 strncpy(ca->ca_name, ca_name, sizeof ca->ca_name); 358 359 snprintf(dir_name, sizeof(dir_name), "%s/%s", SYS_INFINIBAND, 360 ca->ca_name); 361 362 if ((r = sys_read_uint(dir_name, SYS_NODE_TYPE, &ca->node_type)) < 0) 363 return r; 364 if (sys_read_string(dir_name, SYS_CA_FW_VERS, ca->fw_ver, 365 sizeof ca->fw_ver) < 0) 366 ca->fw_ver[0] = '\0'; 367 if (sys_read_string(dir_name, SYS_CA_HW_VERS, ca->hw_ver, 368 sizeof ca->hw_ver) < 0) 369 ca->hw_ver[0] = '\0'; 370 if ((r = sys_read_string(dir_name, SYS_CA_TYPE, ca->ca_type, 371 sizeof ca->ca_type)) < 0) 372 ca->ca_type[0] = '\0'; 373 if ((r = sys_read_guid(dir_name, SYS_CA_NODE_GUID, &ca->node_guid)) < 0) 374 return r; 375 if ((r = sys_read_guid(dir_name, SYS_CA_SYS_GUID, &ca->system_guid)) < 0) 376 return r; 377 378 snprintf(dir_name, sizeof(dir_name), "%s/%s/%s", 379 SYS_INFINIBAND, ca->ca_name, SYS_CA_PORTS_DIR); 380 381#ifdef __linux__ 382 if (!(dir = opendir(dir_name))) 383 return -ENOENT; 384#endif 385 386 if ((r = sys_scandir(dir_name, &namelist, 0, alphasort)) < 0) { 387 ret = errno < 0 ? errno : -EIO; 388 goto error; 389 } 390 391 ret = 0; 392 ca->numports = 0; 393 memset(ca->ports, 0, sizeof ca->ports); 394 for (i = 0; i < r; i++) { 395 portnum = 0; 396 if (!strcmp(".", namelist[i]->d_name) || 397 !strcmp("..", namelist[i]->d_name)) 398 continue; 399 if (strcmp("0", namelist[i]->d_name) && 400 ((portnum = atoi(namelist[i]->d_name)) <= 0 || 401 portnum >= UMAD_CA_MAX_PORTS)) { 402 ret = -EIO; 403 goto clean; 404 } 405 if (!(ca->ports[portnum] = calloc(1, sizeof(*ca->ports[portnum])))) { 406 ret = -ENOMEM; 407 goto clean; 408 } 409 if (get_port(ca_name, dir_name, portnum, ca->ports[portnum]) < 0) { 410 free(ca->ports[portnum]); 411 ca->ports[portnum] = NULL; 412 ret = -EIO; 413 goto clean; 414 } 415 if (ca->numports < portnum) 416 ca->numports = portnum; 417 } 418 419 for (i = 0; i < r; i++) 420 free(namelist[i]); 421 free(namelist); 422 423#ifdef __linux__ 424 closedir(dir); 425#endif 426 put_ca(ca); 427 return 0; 428 429clean: 430 for (i = 0; i < r; i++) 431 free(namelist[i]); 432 free(namelist); 433error: 434#ifdef __linux__ 435 closedir(dir); 436#endif 437 release_ca(ca); 438 439 return ret; 440} 441 442static int 443umad_id_to_dev(int umad_id, char *dev, unsigned *port) 444{ 445 char path[256]; 446 int r; 447 448 snprintf(path, sizeof(path), SYS_INFINIBAND_MAD "/umad%d", umad_id); 449 450 if ((r = sys_read_string(path, SYS_IB_MAD_DEV, dev, UMAD_CA_NAME_LEN)) < 0) 451 return r; 452 453 if ((r = sys_read_uint(path, SYS_IB_MAD_PORT, port)) < 0) 454 return r; 455 456 return 0; 457} 458 459static int 460dev_to_umad_id(char *dev, unsigned port) 461{ 462 char umad_dev[UMAD_CA_NAME_LEN]; 463 unsigned umad_port; 464 int id; 465 466 for (id = 0; id < UMAD_MAX_PORTS; id++) { 467 if (umad_id_to_dev(id, umad_dev, &umad_port) < 0) 468 continue; 469 if (strncmp(dev, umad_dev, UMAD_CA_NAME_LEN)) 470 continue; 471 if (port != umad_port) 472 continue; 473 474 DEBUG("mapped %s %d to %d", dev, port, id); 475 return id; 476 } 477 478 return -1; /* not found */ 479} 480 481/******************************* 482 * Public interface 483 */ 484 485int 486umad_init(void) 487{ 488 TRACE("umad_init"); 489 if (sys_read_uint(IB_UMAD_ABI_DIR, IB_UMAD_ABI_FILE, &abi_version) < 0) { 490 IBWARN("can't read ABI version from %s/%s (%m): is ib_umad module loaded?", 491 IB_UMAD_ABI_DIR, IB_UMAD_ABI_FILE); 492 return -1; 493 } 494 if (abi_version < IB_UMAD_ABI_VERSION) { 495 IBWARN("wrong ABI version: %s/%s is %d but library minimal ABI is %d", 496 IB_UMAD_ABI_DIR, IB_UMAD_ABI_FILE, abi_version, IB_UMAD_ABI_VERSION); 497 return -1; 498 } 499 return 0; 500} 501 502int 503umad_done(void) 504{ 505 TRACE("umad_done"); 506 /* FIXME - verify that all ports are closed */ 507 return 0; 508} 509 510static unsigned is_ib_type(char *ca_name) 511{ 512 char dir_name[256]; 513 unsigned type; 514 515 snprintf(dir_name, sizeof(dir_name), "%s/%s", SYS_INFINIBAND, ca_name); 516 517 if (sys_read_uint(dir_name, SYS_NODE_TYPE, &type) < 0) 518 return 0; 519 520 return type >= 1 && type <= 3 ? 1 : 0; 521} 522 523int 524umad_get_cas_names(char cas[][UMAD_CA_NAME_LEN], int max) 525{ 526 struct dirent **namelist; 527 int n, i, j = 0; 528 529 TRACE("max %d", max); 530 531 n = sys_scandir(SYS_INFINIBAND, &namelist, NULL, alphasort); 532 if (n > 0) { 533 for (i = 0; i < n; i++) { 534 if (strcmp(namelist[i]->d_name, ".") && 535 strcmp(namelist[i]->d_name, "..")) { 536 if (j < max && is_ib_type(namelist[i]->d_name)) 537 strncpy(cas[j++], namelist[i]->d_name, 538 UMAD_CA_NAME_LEN); 539 } 540 free(namelist[i]); 541 } 542 DEBUG("return %d cas", j); 543 } else { 544 /* Is this still needed ? */ 545 strncpy((char *)cas, def_ca_name, UMAD_CA_NAME_LEN); 546 DEBUG("return 1 ca"); 547 j = 1; 548 } 549 if (n >= 0) 550 free(namelist); 551 return j; 552} 553 554int 555umad_get_ca_portguids(char *ca_name, uint64_t *portguids, int max) 556{ 557 umad_ca_t ca; 558 int ports = 0, i; 559 560 TRACE("ca name %s max port guids %d", ca_name, max); 561 if (!(ca_name = resolve_ca_name(ca_name, 0))) 562 return -ENODEV; 563 564 if (umad_get_ca(ca_name, &ca) < 0) 565 return -1; 566 567 if (portguids) { 568 if (ca.numports + 1 > max) { 569 release_ca(&ca); 570 return -ENOMEM; 571 } 572 573 for (i = 0; i <= ca.numports; i++) 574 portguids[ports++] = ca.ports[i] ? ca.ports[i]->port_guid : 0; 575 } 576 577 release_ca(&ca); 578 DEBUG("%s: %d ports", ca_name, ports); 579 580 return ports; 581} 582 583int 584umad_get_issm_path(char *ca_name, int portnum, char path[], int max) 585{ 586 int umad_id; 587 588 TRACE("ca %s port %d", ca_name, portnum); 589 590 if (!(ca_name = resolve_ca_name(ca_name, &portnum))) 591 return -ENODEV; 592 593 if ((umad_id = dev_to_umad_id(ca_name, portnum)) < 0) 594 return -EINVAL; 595 596 snprintf(path, max, "%s/issm%u", UMAD_DEV_DIR , umad_id); 597 598 return 0; 599} 600 601int 602umad_open_port(char *ca_name, int portnum) 603{ 604 char dev_file[UMAD_DEV_FILE_SZ]; 605 int umad_id, fd; 606 607 TRACE("ca %s port %d", ca_name, portnum); 608 609 if (!(ca_name = resolve_ca_name(ca_name, &portnum))) 610 return -ENODEV; 611 612 DEBUG("opening %s port %d", ca_name, portnum); 613 614 if ((umad_id = dev_to_umad_id(ca_name, portnum)) < 0) 615 return -EINVAL; 616 617 snprintf(dev_file, sizeof(dev_file), "%s/umad%d", 618 UMAD_DEV_DIR , umad_id); 619 620 if ((fd = open(dev_file, O_RDWR|O_NONBLOCK)) < 0) { 621 DEBUG("open %s failed: %s", dev_file, strerror(errno)); 622 return -EIO; 623 } 624 625 if (abi_version > 5 || !ioctl(fd, IB_USER_MAD_ENABLE_PKEY, NULL)) 626 new_user_mad_api = 1; 627 else 628 new_user_mad_api = 0; 629 630 DEBUG("opened %s fd %d portid %d", dev_file, fd, umad_id); 631 return fd; 632} 633 634int 635umad_get_ca(char *ca_name, umad_ca_t *ca) 636{ 637 int r; 638 639 TRACE("ca_name %s", ca_name); 640 if (!(ca_name = resolve_ca_name(ca_name, 0))) 641 return -ENODEV; 642 643 if (find_cached_ca(ca_name, ca) > 0) 644 return 0; 645 646 if ((r = get_ca(ca_name, ca)) < 0) 647 return r; 648 649 DEBUG("opened %s", ca_name); 650 return 0; 651} 652 653int 654umad_release_ca(umad_ca_t *ca) 655{ 656 int r; 657 658 TRACE("ca_name %s", ca->ca_name); 659 if (!ca) 660 return -ENODEV; 661 662 if ((r = release_ca(ca)) < 0) 663 return r; 664 665 DEBUG("releasing %s", ca->ca_name); 666 return 0; 667} 668 669int 670umad_get_port(char *ca_name, int portnum, umad_port_t *port) 671{ 672 char dir_name[256]; 673 674 TRACE("ca_name %s portnum %d", ca_name, portnum); 675 676 if (!(ca_name = resolve_ca_name(ca_name, &portnum))) 677 return -ENODEV; 678 679 snprintf(dir_name, sizeof(dir_name), "%s/%s/%s", 680 SYS_INFINIBAND, ca_name, SYS_CA_PORTS_DIR); 681 682 return get_port(ca_name, dir_name, portnum, port); 683} 684 685int 686umad_release_port(umad_port_t *port) 687{ 688 int r; 689 690 TRACE("port %s:%d", port->ca_name, port->portnum); 691 if (!port) 692 return -ENODEV; 693 694 if ((r = release_port(port)) < 0) 695 return r; 696 697 DEBUG("releasing %s:%d", port->ca_name, port->portnum); 698 return 0; 699} 700 701int 702umad_close_port(int fd) 703{ 704 close(fd); 705 DEBUG("closed fd %d", fd); 706 return 0; 707} 708 709void * 710umad_get_mad(void *umad) 711{ 712 return new_user_mad_api ? ((struct ib_user_mad *)umad)->data : 713 (void *)&((struct ib_user_mad *)umad)->addr.pkey_index; 714} 715 716size_t 717umad_size(void) 718{ 719 return new_user_mad_api ? sizeof (struct ib_user_mad) : 720 sizeof(struct ib_user_mad) - 8; 721} 722 723int 724umad_set_grh(void *umad, void *mad_addr) 725{ 726 struct ib_user_mad *mad = umad; 727 struct ib_mad_addr *addr = mad_addr; 728 729 if (mad_addr) { 730 mad->addr.grh_present = 1; 731 memcpy(mad->addr.gid, addr->gid, 16); 732 mad->addr.flow_label = htonl(addr->flow_label); 733 mad->addr.hop_limit = addr->hop_limit; 734 mad->addr.traffic_class = addr->traffic_class; 735 } else 736 mad->addr.grh_present = 0; 737 return 0; 738} 739 740int 741umad_set_pkey(void *umad, int pkey_index) 742{ 743 struct ib_user_mad *mad = umad; 744 745 if (new_user_mad_api) 746 mad->addr.pkey_index = pkey_index; 747 748 return 0; 749} 750 751int 752umad_get_pkey(void *umad) 753{ 754 struct ib_user_mad *mad = umad; 755 756 if (new_user_mad_api) 757 return mad->addr.pkey_index; 758 759 return 0; 760} 761 762int 763umad_set_addr(void *umad, int dlid, int dqp, int sl, int qkey) 764{ 765 struct ib_user_mad *mad = umad; 766 767 TRACE("umad %p dlid %d dqp %d sl %d, qkey %x", 768 umad, dlid, dqp, sl, qkey); 769 mad->addr.qpn = htonl(dqp); 770 mad->addr.lid = htons(dlid); 771 mad->addr.qkey = htonl(qkey); 772 mad->addr.sl = sl; 773 774 return 0; 775} 776 777int 778umad_set_addr_net(void *umad, int dlid, int dqp, int sl, int qkey) 779{ 780 struct ib_user_mad *mad = umad; 781 782 TRACE("umad %p dlid %d dqp %d sl %d qkey %x", 783 umad, ntohs(dlid), ntohl(dqp), sl, ntohl(qkey)); 784 mad->addr.qpn = dqp; 785 mad->addr.lid = dlid; 786 mad->addr.qkey = qkey; 787 mad->addr.sl = sl; 788 789 return 0; 790} 791 792int 793umad_send(int fd, int agentid, void *umad, int length, 794 int timeout_ms, int retries) 795{ 796 struct ib_user_mad *mad = umad; 797 int n; 798 799 TRACE("fd %d agentid %d umad %p timeout %u", 800 fd, agentid, umad, timeout_ms); 801 errno = 0; 802 803 mad->timeout_ms = timeout_ms; 804 mad->retries = retries; 805 mad->agent_id = agentid; 806 807 if (umaddebug > 1) 808 umad_dump(mad); 809 810 n = write(fd, mad, length + umad_size()); 811 if (n == length + umad_size()) 812 return 0; 813 814 DEBUG("write returned %d != sizeof umad %zu + length %d (%m)", 815 n, umad_size(), length); 816 if (!errno) 817 errno = EIO; 818 return -EIO; 819} 820 821static int 822dev_poll(int fd, int timeout_ms) 823{ 824 struct pollfd ufds; 825 int n; 826 827 ufds.fd = fd; 828 ufds.events = POLLIN; 829 830 if ((n = poll(&ufds, 1, timeout_ms)) == 1) 831 return 0; 832 833 if (n == 0) 834 return -ETIMEDOUT; 835 836 return -EIO; 837} 838 839int 840umad_recv(int fd, void *umad, int *length, int timeout_ms) 841{ 842 struct ib_user_mad *mad = umad; 843 int n; 844 845 errno = 0; 846 TRACE("fd %d umad %p timeout %u", fd, umad, timeout_ms); 847 848 if (!umad || !length) { 849 errno = EINVAL; 850 return -EINVAL; 851 } 852 853 if (timeout_ms && (n = dev_poll(fd, timeout_ms)) < 0) { 854 if (!errno) 855 errno = -n; 856 return n; 857 } 858 859 n = read(fd, umad, umad_size() + *length); 860 861 VALGRIND_MAKE_MEM_DEFINED(umad, umad_size() + *length); 862 863 if ((n >= 0) && (n <= umad_size() + *length)) { 864 DEBUG("mad received by agent %d length %d", mad->agent_id, n); 865 if (n > umad_size()) 866 *length = n - umad_size(); 867 else 868 *length = 0; 869 return mad->agent_id; 870 } 871 872 if (n == -EWOULDBLOCK) { 873 if (!errno) 874 errno = EWOULDBLOCK; 875 return n; 876 } 877 878 DEBUG("read returned %zu > sizeof umad %zu + length %d (%m)", 879 mad->length - umad_size(), umad_size(), *length); 880 881 *length = mad->length - umad_size(); 882 if (!errno) 883 errno = EIO; 884 return -errno; 885} 886 887int 888umad_poll(int fd, int timeout_ms) 889{ 890 TRACE("fd %d timeout %u", fd, timeout_ms); 891 return dev_poll(fd, timeout_ms); 892} 893 894int 895umad_get_fd(int fd) 896{ 897 TRACE("fd %d", fd); 898 return fd; 899} 900 901int 902umad_register_oui(int fd, int mgmt_class, uint8_t rmpp_version, 903 uint8_t oui[3], long method_mask[]) 904{ 905 struct ib_user_mad_reg_req req; 906 907 TRACE("fd %d mgmt_class %u rmpp_version %d oui 0x%x%x%x method_mask %p", 908 fd, mgmt_class, (int)rmpp_version, (int)oui[0], (int)oui[1], 909 (int)oui[2], method_mask); 910 911 if (mgmt_class < 0x30 || mgmt_class > 0x4f) { 912 DEBUG("mgmt class %d not in vendor range 2", mgmt_class); 913 return -EINVAL; 914 } 915 916 req.qpn = 1; 917 req.mgmt_class = mgmt_class; 918 req.mgmt_class_version = 1; 919 memcpy(req.oui, oui, sizeof req.oui); 920 req.rmpp_version = rmpp_version; 921 922 if (method_mask) 923 memcpy(req.method_mask, method_mask, sizeof req.method_mask); 924 else 925 memset(req.method_mask, 0, sizeof req.method_mask); 926 927 VALGRIND_MAKE_MEM_DEFINED(&req, sizeof req); 928 929 if (!ioctl(fd, IB_USER_MAD_REGISTER_AGENT, (void *)&req)) { 930 DEBUG("fd %d registered to use agent %d qp %d class 0x%x oui %p", 931 fd, req.id, req.qpn, req.mgmt_class, oui); 932 return req.id; /* return agentid */ 933 } 934 935 DEBUG("fd %d registering qp %d class 0x%x version %d oui %p failed: %m", 936 fd, req.qpn, req.mgmt_class, req.mgmt_class_version, oui); 937 return -EPERM; 938} 939 940int 941umad_register(int fd, int mgmt_class, int mgmt_version, 942 uint8_t rmpp_version, long method_mask[]) 943{ 944 struct ib_user_mad_reg_req req; 945 uint32_t oui = htonl(IB_OPENIB_OUI); 946 int qp; 947 948 TRACE("fd %d mgmt_class %u mgmt_version %u rmpp_version %d method_mask %p", 949 fd, mgmt_class, mgmt_version, rmpp_version, method_mask); 950 951 req.qpn = qp = (mgmt_class == 0x1 || mgmt_class == 0x81) ? 0 : 1; 952 req.mgmt_class = mgmt_class; 953 req.mgmt_class_version = mgmt_version; 954 req.rmpp_version = rmpp_version; 955 956 if (method_mask) 957 memcpy(req.method_mask, method_mask, sizeof req.method_mask); 958 else 959 memset(req.method_mask, 0, sizeof req.method_mask); 960 961 memcpy(&req.oui, (char *)&oui + 1, sizeof req.oui); 962 963 VALGRIND_MAKE_MEM_DEFINED(&req, sizeof req); 964 965 if (!ioctl(fd, IB_USER_MAD_REGISTER_AGENT, (void *)&req)) { 966 DEBUG("fd %d registered to use agent %d qp %d", 967 fd, req.id, qp); 968 return req.id; /* return agentid */ 969 } 970 971 DEBUG("fd %d registering qp %d class 0x%x version %d failed: %m", 972 fd, qp, mgmt_class, mgmt_version); 973 return -EPERM; 974} 975 976int 977umad_unregister(int fd, int agentid) 978{ 979 TRACE("fd %d unregistering agent %d", fd, agentid); 980 return ioctl(fd, IB_USER_MAD_UNREGISTER_AGENT, &agentid); 981} 982 983int 984umad_status(void *umad) 985{ 986 struct ib_user_mad *mad = umad; 987 988 return mad->status; 989} 990 991ib_mad_addr_t * 992umad_get_mad_addr(void *umad) 993{ 994 struct ib_user_mad *mad = umad; 995 996 return &mad->addr; 997} 998 999int 1000umad_debug(int level) 1001{ 1002 if (level >= 0) 1003 umaddebug = level; 1004 return umaddebug; 1005} 1006 1007void 1008umad_addr_dump(ib_mad_addr_t *addr) 1009{ 1010#define HEX(x) ((x) < 10 ? '0' + (x) : 'a' + ((x) -10)) 1011 char gid_str[64]; 1012 int i; 1013 1014 for (i = 0; i < sizeof addr->gid; i++) { 1015 gid_str[i*2] = HEX(addr->gid[i] >> 4); 1016 gid_str[i*2+1] = HEX(addr->gid[i] & 0xf); 1017 } 1018 gid_str[i*2] = 0; 1019 IBWARN("qpn %d qkey 0x%x lid 0x%x sl %d\n" 1020 "grh_present %d gid_index %d hop_limit %d traffic_class %d flow_label 0x%x pkey_index 0x%x\n" 1021 "Gid 0x%s", 1022 ntohl(addr->qpn), ntohl(addr->qkey), ntohs(addr->lid), addr->sl, 1023 addr->grh_present, (int)addr->gid_index, (int)addr->hop_limit, 1024 (int)addr->traffic_class, addr->flow_label, addr->pkey_index, 1025 gid_str); 1026} 1027 1028void 1029umad_dump(void *umad) 1030{ 1031 struct ib_user_mad * mad = umad; 1032 1033 IBWARN("agent id %d status %x timeout %d", 1034 mad->agent_id, mad->status, mad->timeout_ms); 1035 umad_addr_dump(&mad->addr); 1036} 1037