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 }
940