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