]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ofed/management/libibumad/src/umad.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ofed / management / libibumad / src / umad.c
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
96 find_cached_ca(char *ca_name, umad_ca_t *ca)
97 {
98         return 0;       /* caching not implemented yet */
99 }
100
101 static int
102 put_ca(umad_ca_t *ca)
103 {
104         return 0;       /* caching not implemented yet */
105 }
106
107 static int
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
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
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
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
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 *
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
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
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
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
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
503 umad_done(void)
504 {
505         TRACE("umad_done");
506         /* FIXME - verify that all ports are closed */
507         return 0;
508 }
509
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
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
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
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
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
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
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
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
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
702 umad_close_port(int fd)
703 {
704         close(fd);
705         DEBUG("closed fd %d", fd);
706         return 0;
707 }
708
709 void *
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
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
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
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
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
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
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
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
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
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
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
895 umad_get_fd(int fd)
896 {
897         TRACE("fd %d", fd);
898         return fd;
899 }
900
901 int
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
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
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
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 *
992 umad_get_mad_addr(void *umad)
993 {
994         struct ib_user_mad *mad = umad;
995
996         return &mad->addr;
997 }
998
999 int
1000 umad_debug(int level)
1001 {
1002         if (level >= 0)
1003                 umaddebug = level;
1004         return umaddebug;
1005 }
1006
1007 void
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
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 }