]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/infiniband-diags/src/ibdiag_common.c
Add liblutok a lightweight C++ API for lua.
[FreeBSD/FreeBSD.git] / contrib / ofed / infiniband-diags / src / ibdiag_common.c
1 /*
2  * Copyright (c) 2006-2007 The Regents of the University of California.
3  * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
4  * Copyright (c) 2002-2010 Mellanox Technologies LTD. All rights reserved.
5  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
6  * Copyright (c) 2009 HNR Consulting. All rights reserved.
7  * Copyright (c) 2011 Lawrence Livermore National Security. All rights reserved.
8  *
9  * This software is available to you under a choice of one of two
10  * licenses.  You may choose to be licensed under the terms of the GNU
11  * General Public License (GPL) Version 2, available from the file
12  * COPYING in the main directory of this source tree, or the
13  * OpenIB.org BSD license below:
14  *
15  *     Redistribution and use in source and binary forms, with or
16  *     without modification, are permitted provided that the following
17  *     conditions are met:
18  *
19  *      - Redistributions of source code must retain the above
20  *        copyright notice, this list of conditions and the following
21  *        disclaimer.
22  *
23  *      - Redistributions in binary form must reproduce the above
24  *        copyright notice, this list of conditions and the following
25  *        disclaimer in the documentation and/or other materials
26  *        provided with the distribution.
27  *
28  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
32  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
33  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35  * SOFTWARE.
36  *
37  */
38
39 /**
40  * Define common functions which can be included in the various C based diags.
41  */
42
43 #define _GNU_SOURCE
44 #include <stdio.h>
45 #include <errno.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <stdarg.h>
49 #include <sys/types.h>
50 #include <unistd.h>
51 #include <ctype.h>
52 #include <config.h>
53 #include <getopt.h>
54 #include <limits.h>
55 #include <sys/stat.h>
56 #include <stdarg.h>
57
58 #include <infiniband/umad.h>
59 #include <infiniband/mad.h>
60 #include <ibdiag_common.h>
61 #include <ibdiag_version.h>
62
63 int ibverbose;
64 enum MAD_DEST ibd_dest_type = IB_DEST_LID;
65 ib_portid_t *ibd_sm_id;
66 static ib_portid_t sm_portid = { 0 };
67
68 /* general config options */
69 #define IBDIAG_CONFIG_GENERAL IBDIAG_CONFIG_PATH"/ibdiag.conf"
70 char *ibd_ca = NULL;
71 int ibd_ca_port = 0;
72 int ibd_timeout = 0;
73 uint32_t ibd_ibnetdisc_flags = IBND_CONFIG_MLX_EPI;
74 uint64_t ibd_mkey;
75 uint64_t ibd_sakey = 0;
76 int show_keys = 0;
77 char *ibd_nd_format = NULL;
78
79 static const char *prog_name;
80 static const char *prog_args;
81 static const char **prog_examples;
82 static struct option *long_opts = NULL;
83 static const struct ibdiag_opt *opts_map[256];
84
85 static const char *get_build_version(void)
86 {
87         return "BUILD VERSION: " IBDIAG_VERSION;
88 }
89
90 static void pretty_print(int start, int width, const char *str)
91 {
92         int len = width - start;
93         const char *p, *e;
94
95         while (1) {
96                 while (isspace(*str))
97                         str++;
98                 p = str;
99                 do {
100                         e = p + 1;
101                         p = strchr(e, ' ');
102                 } while (p && p - str < len);
103                 if (!p) {
104                         fprintf(stderr, "%s", str);
105                         break;
106                 }
107                 if (e - str == 1)
108                         e = p;
109                 fprintf(stderr, "%.*s\n%*s", (int)(e - str), str, start, "");
110                 str = e;
111         }
112 }
113
114 static inline int val_str_true(const char *val_str)
115 {
116         return ((strncmp(val_str, "TRUE", strlen("TRUE")) == 0) ||
117                 (strncmp(val_str, "true", strlen("true")) == 0));
118 }
119
120 void read_ibdiag_config(const char *file)
121 {
122         char buf[1024];
123         FILE *config_fd = NULL;
124         char *p_prefix, *p_last;
125         char *name;
126         char *val_str;
127         struct stat statbuf;
128
129         /* silently ignore missing config file */
130         if (stat(file, &statbuf))
131                 return;
132
133         config_fd = fopen(file, "r");
134         if (!config_fd)
135                 return;
136
137         while (fgets(buf, sizeof buf, config_fd) != NULL) {
138                 p_prefix = strtok_r(buf, "\n", &p_last);
139                 if (!p_prefix)
140                         continue; /* ignore blank lines */
141
142                 if (*p_prefix == '#')
143                         continue; /* ignore comment lines */
144
145                 name = strtok_r(p_prefix, "=", &p_last);
146                 val_str = strtok_r(NULL, "\n", &p_last);
147
148                 if (strncmp(name, "CA", strlen("CA")) == 0) {
149                         free(ibd_ca);
150                         ibd_ca = strdup(val_str);
151                 } else if (strncmp(name, "Port", strlen("Port")) == 0) {
152                         ibd_ca_port = strtoul(val_str, NULL, 0);
153                 } else if (strncmp(name, "timeout", strlen("timeout")) == 0) {
154                         ibd_timeout = strtoul(val_str, NULL, 0);
155                 } else if (strncmp(name, "MLX_EPI", strlen("MLX_EPI")) == 0) {
156                         if (val_str_true(val_str)) {
157                                 ibd_ibnetdisc_flags |= IBND_CONFIG_MLX_EPI;
158                         } else {
159                                 ibd_ibnetdisc_flags &= ~IBND_CONFIG_MLX_EPI;
160                         }
161                 } else if (strncmp(name, "m_key", strlen("m_key")) == 0) {
162                         ibd_mkey = strtoull(val_str, 0, 0);
163                 } else if (strncmp(name, "sa_key",
164                                    strlen("sa_key")) == 0) {
165                         ibd_sakey = strtoull(val_str, 0, 0);
166                 } else if (strncmp(name, "nd_format",
167                                    strlen("nd_format")) == 0) {
168                         ibd_nd_format = strdup(val_str);
169                 }
170         }
171
172         fclose(config_fd);
173 }
174
175
176 void ibdiag_show_usage()
177 {
178         struct option *o = long_opts;
179         int n;
180
181         fprintf(stderr, "\nUsage: %s [options] %s\n\n", prog_name,
182                 prog_args ? prog_args : "");
183
184         if (long_opts[0].name)
185                 fprintf(stderr, "Options:\n");
186         for (o = long_opts; o->name; o++) {
187                 const struct ibdiag_opt *io = opts_map[o->val];
188                 n = fprintf(stderr, "  --%s", io->name);
189                 if (isprint(io->letter))
190                         n += fprintf(stderr, ", -%c", io->letter);
191                 if (io->has_arg)
192                         n += fprintf(stderr, " %s",
193                                      io->arg_tmpl ? io->arg_tmpl : "<val>");
194                 if (io->description && *io->description) {
195                         n += fprintf(stderr, "%*s  ", 24 - n > 0 ? 24 - n : 0,
196                                      "");
197                         pretty_print(n, 74, io->description);
198                 }
199                 fprintf(stderr, "\n");
200         }
201
202         if (prog_examples) {
203                 const char **p;
204                 fprintf(stderr, "\nExamples:\n");
205                 for (p = prog_examples; *p && **p; p++)
206                         fprintf(stderr, "  %s %s\n", prog_name, *p);
207         }
208
209         fprintf(stderr, "\n");
210
211         exit(2);
212 }
213
214 static int process_opt(int ch, char *optarg)
215 {
216         char *endp;
217         long val;
218
219         switch (ch) {
220         case 'z':
221                 read_ibdiag_config(optarg);
222                 break;
223         case 'h':
224                 ibdiag_show_usage();
225                 break;
226         case 'V':
227                 fprintf(stderr, "%s %s\n", prog_name, get_build_version());
228                 exit(0);
229         case 'e':
230                 madrpc_show_errors(1);
231                 break;
232         case 'v':
233                 ibverbose++;
234                 break;
235         case 'd':
236                 ibdebug++;
237                 madrpc_show_errors(1);
238                 umad_debug(ibdebug - 1);
239                 break;
240         case 'C':
241                 ibd_ca = optarg;
242                 break;
243         case 'P':
244                 ibd_ca_port = strtoul(optarg, 0, 0);
245                 if (ibd_ca_port < 0)
246                         IBEXIT("cannot resolve CA port %d", ibd_ca_port);
247                 break;
248         case 'D':
249                 ibd_dest_type = IB_DEST_DRPATH;
250                 break;
251         case 'L':
252                 ibd_dest_type = IB_DEST_LID;
253                 break;
254         case 'G':
255                 ibd_dest_type = IB_DEST_GUID;
256                 break;
257         case 't':
258                 errno = 0;
259                 val = strtol(optarg, &endp, 0);
260                 if (errno || (endp && *endp != '\0') || val <= 0 ||
261                     val > INT_MAX)
262                         IBEXIT("Invalid timeout \"%s\".  Timeout requires a "
263                                 "positive integer value < %d.", optarg, INT_MAX);
264                 else {
265                         madrpc_set_timeout((int)val);
266                         ibd_timeout = (int)val;
267                 }
268                 break;
269         case 's':
270                 /* srcport is not required when resolving via IB_DEST_LID */
271                 if (resolve_portid_str(ibd_ca, ibd_ca_port, &sm_portid, optarg,
272                                 IB_DEST_LID, 0, NULL) < 0)
273                         IBEXIT("cannot resolve SM destination port %s",
274                                 optarg);
275                 ibd_sm_id = &sm_portid;
276                 break;
277         case 'K':
278                 show_keys = 1;
279                 break;
280         case 'y':
281                 errno = 0;
282                 ibd_mkey = strtoull(optarg, &endp, 0);
283                 if (errno || *endp != '\0') {
284                         errno = 0;
285                         ibd_mkey = strtoull(getpass("M_Key: "), &endp, 0);
286                         if (errno || *endp != '\0') {
287                                 IBEXIT("Bad M_Key");
288                         }
289                 }
290                 break;
291         default:
292                 return -1;
293         }
294
295         return 0;
296 }
297
298 static const struct ibdiag_opt common_opts[] = {
299         {"config", 'z', 1, "<config>", "use config file, default: " IBDIAG_CONFIG_GENERAL},
300         {"Ca", 'C', 1, "<ca>", "Ca name to use"},
301         {"Port", 'P', 1, "<port>", "Ca port number to use"},
302         {"Direct", 'D', 0, NULL, "use Direct address argument"},
303         {"Lid", 'L', 0, NULL, "use LID address argument"},
304         {"Guid", 'G', 0, NULL, "use GUID address argument"},
305         {"timeout", 't', 1, "<ms>", "timeout in ms"},
306         {"sm_port", 's', 1, "<lid>", "SM port lid"},
307         {"show_keys", 'K', 0, NULL, "display security keys in output"},
308         {"m_key", 'y', 1, "<key>", "M_Key to use in request"},
309         {"errors", 'e', 0, NULL, "show send and receive errors"},
310         {"verbose", 'v', 0, NULL, "increase verbosity level"},
311         {"debug", 'd', 0, NULL, "raise debug level"},
312         {"help", 'h', 0, NULL, "help message"},
313         {"version", 'V', 0, NULL, "show version"},
314         {0}
315 };
316
317 static void make_opt(struct option *l, const struct ibdiag_opt *o,
318                      const struct ibdiag_opt *map[])
319 {
320         l->name = o->name;
321         l->has_arg = o->has_arg;
322         l->flag = NULL;
323         l->val = o->letter;
324         if (!map[l->val])
325                 map[l->val] = o;
326 }
327
328 static struct option *make_long_opts(const char *exclude_str,
329                                      const struct ibdiag_opt *custom_opts,
330                                      const struct ibdiag_opt *map[])
331 {
332         struct option *long_opts, *l;
333         const struct ibdiag_opt *o;
334         unsigned n = 0;
335
336         if (custom_opts)
337                 for (o = custom_opts; o->name; o++)
338                         n++;
339
340         long_opts = malloc((sizeof(common_opts) / sizeof(common_opts[0]) + n) *
341                            sizeof(*long_opts));
342         if (!long_opts)
343                 return NULL;
344
345         l = long_opts;
346
347         if (custom_opts)
348                 for (o = custom_opts; o->name; o++)
349                         make_opt(l++, o, map);
350
351         for (o = common_opts; o->name; o++) {
352                 if (exclude_str && strchr(exclude_str, o->letter))
353                         continue;
354                 make_opt(l++, o, map);
355         }
356
357         memset(l, 0, sizeof(*l));
358
359         return long_opts;
360 }
361
362 static void make_str_opts(const struct option *o, char *p, unsigned size)
363 {
364         unsigned i, n = 0;
365
366         for (n = 0; o->name && n + 2 + o->has_arg < size; o++) {
367                 p[n++] = (char)o->val;
368                 for (i = 0; i < (unsigned)o->has_arg; i++)
369                         p[n++] = ':';
370         }
371         p[n] = '\0';
372 }
373
374 int ibdiag_process_opts(int argc, char *const argv[], void *cxt,
375                         const char *exclude_common_str,
376                         const struct ibdiag_opt custom_opts[],
377                         int (*custom_handler) (void *cxt, int val,
378                                                char *optarg),
379                         const char *usage_args, const char *usage_examples[])
380 {
381         char str_opts[1024];
382         const struct ibdiag_opt *o;
383
384         prog_name = argv[0];
385         prog_args = usage_args;
386         prog_examples = usage_examples;
387
388         if (long_opts)
389                 free(long_opts);
390
391         long_opts = make_long_opts(exclude_common_str, custom_opts, opts_map);
392         if (!long_opts)
393                 return -1;
394
395         read_ibdiag_config(IBDIAG_CONFIG_GENERAL);
396
397         make_str_opts(long_opts, str_opts, sizeof(str_opts));
398
399         while (1) {
400                 int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);
401                 if (ch == -1)
402                         break;
403                 o = opts_map[ch];
404                 if (!o)
405                         ibdiag_show_usage();
406                 if (custom_handler) {
407                         if (custom_handler(cxt, ch, optarg) &&
408                             process_opt(ch, optarg))
409                                 ibdiag_show_usage();
410                 } else if (process_opt(ch, optarg))
411                         ibdiag_show_usage();
412         }
413
414         return 0;
415 }
416
417 void ibexit(const char *fn, char *msg, ...)
418 {
419         char buf[512];
420         va_list va;
421         int n;
422
423         va_start(va, msg);
424         n = vsprintf(buf, msg, va);
425         va_end(va);
426         buf[n] = 0;
427
428         if (ibdebug)
429                 printf("%s: iberror: [pid %d] %s: failed: %s\n",
430                        prog_name ? prog_name : "", getpid(), fn, buf);
431         else
432                 printf("%s: iberror: failed: %s\n",
433                        prog_name ? prog_name : "", buf);
434
435         exit(-1);
436 }
437
438 char *
439 conv_cnt_human_readable(uint64_t val64, float *val, int data)
440 {
441         uint64_t tmp = val64;
442         int ui = 0;
443         int div = 1;
444
445         tmp /= 1024;
446         while (tmp) {
447                 ui++;
448                 tmp /= 1024;
449                 div *= 1024;
450         }
451
452         *val = (float)(val64);
453         if (data) {
454                 *val *= 4;
455                 if (*val/div > 1024) {
456                         ui++;
457                         div *= 1024;
458                 }
459         }
460         *val /= div;
461
462         if (data) {
463                 switch (ui) {
464                         case 0:
465                                 return ("B");
466                         case 1:
467                                 return ("KB");
468                         case 2:
469                                 return ("MB");
470                         case 3:
471                                 return ("GB");
472                         case 4:
473                                 return ("TB");
474                         case 5:
475                                 return ("PB");
476                         case 6:
477                                 return ("EB");
478                         default:
479                                 return ("");
480                 }
481         } else {
482                 switch (ui) {
483                         case 0:
484                                 return ("");
485                         case 1:
486                                 return ("K");
487                         case 2:
488                                 return ("M");
489                         case 3:
490                                 return ("G");
491                         case 4:
492                                 return ("T");
493                         case 5:
494                                 return ("P");
495                         case 6:
496                                 return ("E");
497                         default:
498                                 return ("");
499                 }
500         }
501         return ("");
502 }
503
504 int is_port_info_extended_supported(ib_portid_t * dest, int port,
505                                     struct ibmad_port *srcport)
506 {
507         uint8_t data[IB_SMP_DATA_SIZE] = { 0 };
508         uint32_t cap_mask;
509         uint16_t cap_mask2;
510
511         if (!smp_query_via(data, dest, IB_ATTR_PORT_INFO, port, 0, srcport))
512                 IBEXIT("port info query failed");
513
514         mad_decode_field(data, IB_PORT_CAPMASK_F, &cap_mask);
515         if (cap_mask & CL_NTOH32(IB_PORT_CAP_HAS_CAP_MASK2)) {
516                 mad_decode_field(data, IB_PORT_CAPMASK2_F, &cap_mask2);
517                 if (!(cap_mask2 &
518                       CL_NTOH16(IB_PORT_CAP2_IS_PORT_INFO_EXT_SUPPORTED))) {
519                         IBWARN("port info capability mask2 = 0x%x doesn't"
520                                " indicate PortInfoExtended support", cap_mask2);
521                         return 0;
522                 }
523         } else {
524                 IBWARN("port info capability mask2 not supported");
525                 return 0;
526         }
527
528         return 1;
529 }
530
531 int is_mlnx_ext_port_info_supported(uint32_t vendorid,
532                                     uint16_t devid)
533 {
534         if (ibd_ibnetdisc_flags & IBND_CONFIG_MLX_EPI) {
535
536                 if ((devid >= 0xc738 && devid <= 0xc73b) || devid == 0xcb20 || devid == 0xcf08 ||
537                     ((vendorid == 0x119f) &&
538                      /* Bull SwitchX */
539                      (devid == 0x1b02 || devid == 0x1b50 ||
540                       /* Bull SwitchIB and SwitchIB2 */
541                       devid == 0x1ba0 ||
542                       (devid >= 0x1bd0 && devid <= 0x1bd5))))
543                         return 1;
544                 if ((devid >= 0x1003 && devid <= 0x1017) ||
545                     ((vendorid == 0x119f) &&
546                      /* Bull ConnectX3 */
547                      (devid == 0x1b33 || devid == 0x1b73 ||
548                       devid == 0x1b40 || devid == 0x1b41 ||
549                       devid == 0x1b60 || devid == 0x1b61 ||
550                       /* Bull ConnectIB */
551                       devid == 0x1b83 ||
552                       devid == 0x1b93 || devid == 0x1b94 ||
553                       /* Bull ConnectX4 */
554                       devid == 0x1bb4 || devid == 0x1bb5 ||
555                       devid == 0x1bc4)))
556                         return 1;
557         }
558
559         return 0;
560 }
561
562 /** =========================================================================
563  * Resolve the SM portid using the umad layer rather than using
564  * ib_resolve_smlid_via which requires a PortInfo query on the local port.
565  */
566 int resolve_sm_portid(char *ca_name, uint8_t portnum, ib_portid_t *sm_id)
567 {
568         umad_port_t port;
569         int rc;
570
571         if (!sm_id)
572                 return (-1);
573
574         if ((rc = umad_get_port(ca_name, portnum, &port)) < 0)
575                 return rc;
576
577         memset(sm_id, 0, sizeof(*sm_id));
578         sm_id->lid = port.sm_lid;
579         sm_id->sl = port.sm_sl;
580
581         umad_release_port(&port);
582
583         return 0;
584 }
585
586 /** =========================================================================
587  * Resolve local CA characteristics using the umad layer rather than using
588  * ib_resolve_self_via which requires SMP queries on the local port.
589  */
590 int resolve_self(char *ca_name, uint8_t ca_port, ib_portid_t *portid,
591                  int *portnum, ibmad_gid_t *gid)
592 {
593         umad_port_t port;
594         uint64_t prefix, guid;
595         int rc;
596
597         if (!(portid || portnum || gid))
598                 return (-1);
599
600         if ((rc = umad_get_port(ca_name, ca_port, &port)) < 0)
601                 return rc;
602
603         if (portid) {
604                 memset(portid, 0, sizeof(*portid));
605                 portid->lid = port.base_lid;
606                 portid->sl = port.sm_sl;
607         }
608         if (portnum)
609                 *portnum = port.portnum;
610         if (gid) {
611                 memset(gid, 0, sizeof(*gid));
612                 prefix = cl_ntoh64(port.gid_prefix);
613                 guid = cl_ntoh64(port.port_guid);
614                 mad_encode_field(*gid, IB_GID_PREFIX_F, &prefix);
615                 mad_encode_field(*gid, IB_GID_GUID_F, &guid);
616         }
617
618         umad_release_port(&port);
619
620         return 0;
621 }
622
623 int resolve_gid(char *ca_name, uint8_t ca_port, ib_portid_t * portid,
624                 ibmad_gid_t gid, ib_portid_t * sm_id,
625                 const struct ibmad_port *srcport)
626 {
627         ib_portid_t sm_portid;
628         char buf[IB_SA_DATA_SIZE] = { 0 };
629
630         if (!sm_id) {
631                 sm_id = &sm_portid;
632                 if (resolve_sm_portid(ca_name, ca_port, sm_id) < 0)
633                         return -1;
634         }
635
636         if ((portid->lid =
637              ib_path_query_via(srcport, gid, gid, sm_id, buf)) < 0)
638                 return -1;
639
640         return 0;
641 }
642
643 int resolve_guid(char *ca_name, uint8_t ca_port, ib_portid_t *portid,
644                  uint64_t *guid, ib_portid_t *sm_id,
645                  const struct ibmad_port *srcport)
646 {
647         ib_portid_t sm_portid;
648         uint8_t buf[IB_SA_DATA_SIZE] = { 0 };
649         uint64_t prefix;
650         ibmad_gid_t selfgid;
651
652         if (!sm_id) {
653                 sm_id = &sm_portid;
654                 if (resolve_sm_portid(ca_name, ca_port, sm_id) < 0)
655                         return -1;
656         }
657
658         if (resolve_self(ca_name, ca_port, NULL, NULL, &selfgid) < 0)
659                 return -1;
660
661         memcpy(&prefix, portid->gid, sizeof(prefix));
662         if (!prefix)
663                 mad_set_field64(portid->gid, 0, IB_GID_PREFIX_F,
664                                 IB_DEFAULT_SUBN_PREFIX);
665         if (guid)
666                 mad_set_field64(portid->gid, 0, IB_GID_GUID_F, *guid);
667
668         if ((portid->lid =
669              ib_path_query_via(srcport, selfgid, portid->gid, sm_id, buf)) < 0)
670                 return -1;
671
672         mad_decode_field(buf, IB_SA_PR_SL_F, &portid->sl);
673         return 0;
674 }
675
676 /*
677  * Callers of this function should ensure their ibmad_port has been opened with
678  * IB_SA_CLASS as this function may require the SA to resolve addresses.
679  */
680 int resolve_portid_str(char *ca_name, uint8_t ca_port, ib_portid_t * portid,
681                        char *addr_str, enum MAD_DEST dest_type,
682                        ib_portid_t *sm_id, const struct ibmad_port *srcport)
683 {
684         ibmad_gid_t gid;
685         uint64_t guid;
686         int lid;
687         char *routepath;
688         ib_portid_t selfportid = { 0 };
689         int selfport = 0;
690
691         memset(portid, 0, sizeof *portid);
692
693         switch (dest_type) {
694         case IB_DEST_LID:
695                 lid = strtol(addr_str, 0, 0);
696                 if (!IB_LID_VALID(lid))
697                         return -1;
698                 return ib_portid_set(portid, lid, 0, 0);
699
700         case IB_DEST_DRPATH:
701                 if (str2drpath(&portid->drpath, addr_str, 0, 0) < 0)
702                         return -1;
703                 return 0;
704
705         case IB_DEST_GUID:
706                 if (!(guid = strtoull(addr_str, 0, 0)))
707                         return -1;
708
709                 /* keep guid in portid? */
710                 return resolve_guid(ca_name, ca_port, portid, &guid, sm_id,
711                                     srcport);
712
713         case IB_DEST_DRSLID:
714                 lid = strtol(addr_str, &routepath, 0);
715                 routepath++;
716                 if (!IB_LID_VALID(lid))
717                         return -1;
718                 ib_portid_set(portid, lid, 0, 0);
719
720                 /* handle DR parsing and set DrSLID to local lid */
721                 if (resolve_self(ca_name, ca_port, &selfportid, &selfport,
722                                  NULL) < 0)
723                         return -1;
724                 if (str2drpath(&portid->drpath, routepath, selfportid.lid, 0) <
725                     0)
726                         return -1;
727                 return 0;
728
729         case IB_DEST_GID:
730                 if (inet_pton(AF_INET6, addr_str, &gid) <= 0)
731                         return -1;
732                 return resolve_gid(ca_name, ca_port, portid, gid, sm_id,
733                                    srcport);
734         default:
735                 IBWARN("bad dest_type %d", dest_type);
736         }
737
738         return -1;
739 }
740
741 static unsigned int get_max_width(unsigned int num)
742 {
743         unsigned r = 0;                 /* 1x */
744
745         if (num & 8)
746                 r = 3;                  /* 12x */
747         else {
748                 if (num & 4)
749                         r = 2;          /* 8x */
750                 else if (num & 2)
751                         r = 1;          /* 4x */
752                 else if (num & 0x10)
753                         r = 4;          /* 2x */
754         }
755
756         return (1 << r);
757 }
758
759 static unsigned int get_max(unsigned int num)
760 {
761         unsigned r = 0;         // r will be lg(num)
762
763         while (num >>= 1)       // unroll for more speed...
764                 r++;
765
766         return (1 << r);
767 }
768
769 void get_max_msg(char *width_msg, char *speed_msg, int msg_size, ibnd_port_t * port)
770 {
771         char buf[64];
772         uint32_t max_speed = 0;
773         uint32_t cap_mask, rem_cap_mask, fdr10;
774         uint8_t *info = NULL;
775
776         uint32_t max_width = get_max_width(mad_get_field(port->info, 0,
777                                                    IB_PORT_LINK_WIDTH_SUPPORTED_F)
778                                      & mad_get_field(port->remoteport->info, 0,
779                                                      IB_PORT_LINK_WIDTH_SUPPORTED_F));
780         if ((max_width & mad_get_field(port->info, 0,
781                                        IB_PORT_LINK_WIDTH_ACTIVE_F)) == 0)
782                 // we are not at the max supported width
783                 // print what we could be at.
784                 snprintf(width_msg, msg_size, "Could be %s",
785                          mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F,
786                                       buf, 64, &max_width));
787
788         if (port->node->type == IB_NODE_SWITCH) {
789                 if (port->node->ports[0])
790                         info = (uint8_t *)&port->node->ports[0]->info;
791         }
792         else
793                 info = (uint8_t *)&port->info;
794
795         if (info)
796                 cap_mask = mad_get_field(info, 0, IB_PORT_CAPMASK_F);
797         else
798                 cap_mask = 0;
799
800         info = NULL;
801         if (port->remoteport->node->type == IB_NODE_SWITCH) {
802                 if (port->remoteport->node->ports[0])
803                         info = (uint8_t *)&port->remoteport->node->ports[0]->info;
804         } else
805                 info = (uint8_t *)&port->remoteport->info;
806
807         if (info)
808                 rem_cap_mask = mad_get_field(info, 0, IB_PORT_CAPMASK_F);
809         else
810                 rem_cap_mask = 0;
811         if (cap_mask & CL_NTOH32(IB_PORT_CAP_HAS_EXT_SPEEDS) &&
812             rem_cap_mask & CL_NTOH32(IB_PORT_CAP_HAS_EXT_SPEEDS))
813                 goto check_ext_speed;
814 check_fdr10_supp:
815         fdr10 = (mad_get_field(port->ext_info, 0,
816                                IB_MLNX_EXT_PORT_LINK_SPEED_SUPPORTED_F) & FDR10)
817                 && (mad_get_field(port->remoteport->ext_info, 0,
818                                   IB_MLNX_EXT_PORT_LINK_SPEED_SUPPORTED_F) & FDR10);
819         if (fdr10)
820                 goto check_fdr10_active;
821
822         max_speed = get_max(mad_get_field(port->info, 0,
823                                           IB_PORT_LINK_SPEED_SUPPORTED_F)
824                             & mad_get_field(port->remoteport->info, 0,
825                                             IB_PORT_LINK_SPEED_SUPPORTED_F));
826         if ((max_speed & mad_get_field(port->info, 0,
827                                        IB_PORT_LINK_SPEED_ACTIVE_F)) == 0)
828                 // we are not at the max supported speed
829                 // print what we could be at.
830                 snprintf(speed_msg, msg_size, "Could be %s",
831                          mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F,
832                                       buf, 64, &max_speed));
833         return;
834
835 check_ext_speed:
836         if (mad_get_field(port->info, 0,
837                           IB_PORT_LINK_SPEED_EXT_SUPPORTED_F) == 0 ||
838             mad_get_field(port->remoteport->info, 0,
839                           IB_PORT_LINK_SPEED_EXT_SUPPORTED_F) == 0)
840                 goto check_fdr10_supp;
841         max_speed = get_max(mad_get_field(port->info, 0,
842                                           IB_PORT_LINK_SPEED_EXT_SUPPORTED_F)
843                             & mad_get_field(port->remoteport->info, 0,
844                                             IB_PORT_LINK_SPEED_EXT_SUPPORTED_F));
845         if ((max_speed & mad_get_field(port->info, 0,
846                                        IB_PORT_LINK_SPEED_EXT_ACTIVE_F)) == 0)
847                 // we are not at the max supported extended speed
848                 // print what we could be at.
849                 snprintf(speed_msg, msg_size, "Could be %s",
850                          mad_dump_val(IB_PORT_LINK_SPEED_EXT_ACTIVE_F,
851                                       buf, 64, &max_speed));
852         return;
853
854 check_fdr10_active:
855         if ((mad_get_field(port->ext_info, 0,
856                            IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F) & FDR10) == 0) {
857                 /* Special case QDR to try to avoid confusion with FDR10 */
858                 if (mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F) == 4)     /* QDR (10.0 Gbps) */
859                         snprintf(speed_msg, msg_size,
860                                  "Could be FDR10 (Found link at QDR but expected speed is FDR10)");
861                 else
862                         snprintf(speed_msg, msg_size, "Could be FDR10");
863         }
864 }
865
866 int vsnprint_field(char *buf, size_t n, enum MAD_FIELDS f, int spacing,
867                    const char *format, va_list va_args)
868 {
869         int len, i, ret;
870
871         len = strlen(mad_field_name(f));
872         if (len + 2 > n || spacing + 1 > n)
873                 return 0;
874
875         strncpy(buf, mad_field_name(f), n);
876         buf[len] = ':';
877         for (i = len+1; i < spacing+1; i++) {
878                 buf[i] = '.';
879         }
880
881         ret = vsnprintf(&buf[spacing+1], n - spacing, format, va_args);
882         if (ret >= n - spacing)
883                 buf[n] = '\0';
884
885         return ret + spacing;
886 }
887
888 int snprint_field(char *buf, size_t n, enum MAD_FIELDS f, int spacing,
889                   const char *format, ...)
890 {
891         va_list val;
892         int ret;
893
894         va_start(val, format);
895         ret = vsnprint_field(buf, n, f, spacing, format, val);
896         va_end(val);
897
898         return ret;
899 }
900
901 void dump_portinfo(void *pi, int tabs)
902 {
903         int field, i;
904         char val[64];
905         char buf[1024];
906
907         for (field = IB_PORT_FIRST_F; field < IB_PORT_LAST_F; field++) {
908                 for (i=0;i<tabs;i++)
909                         printf("\t");
910                 if (field == IB_PORT_MKEY_F && show_keys == 0) {
911                         snprint_field(buf, 1024, field, 32, NOT_DISPLAYED_STR);
912                 } else {
913                         mad_decode_field(pi, field, val);
914                         if (!mad_dump_field(field, buf, 1024, val))
915                                 return;
916                 }
917                 printf("%s\n", buf);
918         }
919
920         for (field = IB_PORT_CAPMASK2_F;
921              field < IB_PORT_LINK_SPEED_EXT_LAST_F; field++) {
922                 for (i=0;i<tabs;i++)
923                         printf("\t");
924                 mad_decode_field(pi, field, val);
925                 if (!mad_dump_field(field, buf, 1024, val))
926                         return;
927                 printf("%s\n", buf);
928         }
929 }
930
931 op_fn_t *match_op(const match_rec_t match_tbl[], char *name)
932 {
933         const match_rec_t *r;
934         for (r = match_tbl; r->name; r++)
935                 if (!strcasecmp(r->name, name) ||
936                     (r->alias && !strcasecmp(r->alias, name)))
937                         return r->fn;
938         return NULL;
939 }