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