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
69 typedef 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
82 int umaddebug = 0;
83
84 #define UMAD_DEV_FILE_SZ 256
85
86 static char *def_ca_name = "mthca0";
87 static int def_ca_port = 1;
88
89 static unsigned abi_version;
90 static unsigned new_user_mad_api;
91
92 /*************************************
93 * Port
94 */
95 static int
find_cached_ca(char * ca_name,umad_ca_t * ca)96 find_cached_ca(char *ca_name, umad_ca_t *ca)
97 {
98 return 0; /* caching not implemented yet */
99 }
100
101 static int
put_ca(umad_ca_t * ca)102 put_ca(umad_ca_t *ca)
103 {
104 return 0; /* caching not implemented yet */
105 }
106
107 static int
release_port(umad_port_t * port)108 release_port(umad_port_t *port)
109 {
110 free(port->pkeys);
111 port->pkeys = NULL;
112 port->pkeys_size = 0;
113 return 0;
114 }
115
check_for_digit_name(const struct dirent * dent)116 static 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
124 static int
get_port(char * ca_name,char * dir,int portnum,umad_port_t * port)125 get_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
193 clean:
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
204 static int
release_ca(umad_ca_t * ca)205 release_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 */
225 static int
resolve_ca_port(char * ca_name,int * port)226 resolve_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
288 static char *
resolve_ca_name(char * ca_name,int * best_port)289 resolve_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
346 static int
get_ca(char * ca_name,umad_ca_t * ca)347 get_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
429 clean:
430 for (i = 0; i < r; i++)
431 free(namelist[i]);
432 free(namelist);
433 error:
434 #ifdef __linux__
435 closedir(dir);
436 #endif
437 release_ca(ca);
438
439 return ret;
440 }
441
442 static int
umad_id_to_dev(int umad_id,char * dev,unsigned * port)443 umad_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
459 static int
dev_to_umad_id(char * dev,unsigned port)460 dev_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
485 int
umad_init(void)486 umad_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
502 int
umad_done(void)503 umad_done(void)
504 {
505 TRACE("umad_done");
506 /* FIXME - verify that all ports are closed */
507 return 0;
508 }
509
is_ib_type(char * ca_name)510 static 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
523 int
umad_get_cas_names(char cas[][UMAD_CA_NAME_LEN],int max)524 umad_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
554 int
umad_get_ca_portguids(char * ca_name,uint64_t * portguids,int max)555 umad_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
583 int
umad_get_issm_path(char * ca_name,int portnum,char path[],int max)584 umad_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
601 int
umad_open_port(char * ca_name,int portnum)602 umad_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
634 int
umad_get_ca(char * ca_name,umad_ca_t * ca)635 umad_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
653 int
umad_release_ca(umad_ca_t * ca)654 umad_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
669 int
umad_get_port(char * ca_name,int portnum,umad_port_t * port)670 umad_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
685 int
umad_release_port(umad_port_t * port)686 umad_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
701 int
umad_close_port(int fd)702 umad_close_port(int fd)
703 {
704 close(fd);
705 DEBUG("closed fd %d", fd);
706 return 0;
707 }
708
709 void *
umad_get_mad(void * umad)710 umad_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
716 size_t
umad_size(void)717 umad_size(void)
718 {
719 return new_user_mad_api ? sizeof (struct ib_user_mad) :
720 sizeof(struct ib_user_mad) - 8;
721 }
722
723 int
umad_set_grh(void * umad,void * mad_addr)724 umad_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
740 int
umad_set_pkey(void * umad,int pkey_index)741 umad_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
751 int
umad_get_pkey(void * umad)752 umad_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
762 int
umad_set_addr(void * umad,int dlid,int dqp,int sl,int qkey)763 umad_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
777 int
umad_set_addr_net(void * umad,int dlid,int dqp,int sl,int qkey)778 umad_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
792 int
umad_send(int fd,int agentid,void * umad,int length,int timeout_ms,int retries)793 umad_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
821 static int
dev_poll(int fd,int timeout_ms)822 dev_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
839 int
umad_recv(int fd,void * umad,int * length,int timeout_ms)840 umad_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
887 int
umad_poll(int fd,int timeout_ms)888 umad_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
894 int
umad_get_fd(int fd)895 umad_get_fd(int fd)
896 {
897 TRACE("fd %d", fd);
898 return fd;
899 }
900
901 int
umad_register_oui(int fd,int mgmt_class,uint8_t rmpp_version,uint8_t oui[3],long method_mask[])902 umad_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
940 int
umad_register(int fd,int mgmt_class,int mgmt_version,uint8_t rmpp_version,long method_mask[])941 umad_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
976 int
umad_unregister(int fd,int agentid)977 umad_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
983 int
umad_status(void * umad)984 umad_status(void *umad)
985 {
986 struct ib_user_mad *mad = umad;
987
988 return mad->status;
989 }
990
991 ib_mad_addr_t *
umad_get_mad_addr(void * umad)992 umad_get_mad_addr(void *umad)
993 {
994 struct ib_user_mad *mad = umad;
995
996 return &mad->addr;
997 }
998
999 int
umad_debug(int level)1000 umad_debug(int level)
1001 {
1002 if (level >= 0)
1003 umaddebug = level;
1004 return umaddebug;
1005 }
1006
1007 void
umad_addr_dump(ib_mad_addr_t * addr)1008 umad_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
1028 void
umad_dump(void * umad)1029 umad_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