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