1 /*
2  * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
3  * Copyright (c) 2010,2011 Mellanox Technologies LTD.  All rights reserved.
4  * Copyright (c) 2011,2016 Oracle and/or its affiliates. All rights reserved.
5  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  *
34  */
35 
36 #if HAVE_CONFIG_H
37 #  include <config.h>
38 #endif				/* HAVE_CONFIG_H */
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include <string.h>
44 #include <getopt.h>
45 #include <errno.h>
46 
47 #include <infiniband/umad.h>
48 #include <infiniband/mad.h>
49 
50 #include "ibdiag_common.h"
51 
52 enum port_ops {
53 	QUERY,
54 	ENABLE,
55 	RESET,
56 	DISABLE,
57 	SPEED,
58 	ESPEED,
59 	FDR10SPEED,
60 	WIDTH,
61 	DOWN,
62 	ARM,
63 	ACTIVE,
64 	VLS,
65 	MTU,
66 	LID,
67 	SMLID,
68 	LMC,
69 	MKEY,
70 	MKEYLEASE,
71 	MKEYPROT,
72 	ON,
73 	OFF
74 };
75 
76 struct ibmad_port *srcport;
77 uint64_t speed = 0; /* no state change */
78 uint64_t espeed = 0; /* no state change */
79 uint64_t fdr10 = 0; /* no state change */
80 uint64_t width = 0; /* no state change */
81 uint64_t lid;
82 uint64_t smlid;
83 uint64_t lmc;
84 uint64_t mtu;
85 uint64_t vls = 0; /* no state change */
86 uint64_t mkey;
87 uint64_t mkeylease;
88 uint64_t mkeyprot;
89 
90 struct {
91 	const char *name;
92 	uint64_t *val;
93 	int set;
94 } port_args[] = {
95 	{"query", NULL, 0},	/* QUERY */
96 	{"enable", NULL, 0},	/* ENABLE */
97 	{"reset", NULL, 0},	/* RESET */
98 	{"disable", NULL, 0},	/* DISABLE */
99 	{"speed", &speed, 0},	/* SPEED */
100 	{"espeed", &espeed, 0},	/* EXTENDED SPEED */
101 	{"fdr10", &fdr10, 0},	/* FDR10 SPEED */
102 	{"width", &width, 0},	/* WIDTH */
103 	{"down", NULL, 0},	/* DOWN */
104 	{"arm", NULL, 0},	/* ARM */
105 	{"active", NULL, 0},	/* ACTIVE */
106 	{"vls", &vls, 0},	/* VLS */
107 	{"mtu", &mtu, 0},	/* MTU */
108 	{"lid", &lid, 0},	/* LID */
109 	{"smlid", &smlid, 0},	/* SMLID */
110 	{"lmc", &lmc, 0},	/* LMC */
111 	{"mkey", &mkey, 0},	/* MKEY */
112 	{"mkeylease", &mkeylease, 0},	/* MKEY LEASE */
113 	{"mkeyprot", &mkeyprot, 0},	/* MKEY PROTECT BITS */
114 	{"on", NULL, 0},	/* ON */
115 	{"off", NULL, 0},	/* OFF */
116 };
117 
118 #define NPORT_ARGS (sizeof(port_args) / sizeof(port_args[0]))
119 
120 /*******************************************/
121 
122 /*
123  * Return 1 if node is a switch, else zero.
124  */
125 static int get_node_info(ib_portid_t * dest, uint8_t * data)
126 {
127 	int node_type;
128 
129 	if (!smp_query_via(data, dest, IB_ATTR_NODE_INFO, 0, 0, srcport))
130 		IBEXIT("smp query nodeinfo failed");
131 
132 	node_type = mad_get_field(data, 0, IB_NODE_TYPE_F);
133 	if (node_type == IB_NODE_SWITCH)	/* Switch NodeType ? */
134 		return 1;
135 	else
136 		return 0;
137 }
138 
139 static int get_port_info(ib_portid_t * dest, uint8_t * data, int portnum,
140 			 int is_switch)
141 {
142 	uint8_t smp[IB_SMP_DATA_SIZE];
143 	uint8_t *info;
144 	int cap_mask;
145 
146 	if (is_switch) {
147 		if (!smp_query_via(smp, dest, IB_ATTR_PORT_INFO, 0, 0, srcport))
148 			IBEXIT("smp query port 0 portinfo failed");
149 		info = smp;
150 	} else
151 		info = data;
152 
153 	if (!smp_query_via(data, dest, IB_ATTR_PORT_INFO, portnum, 0, srcport))
154 		IBEXIT("smp query portinfo failed");
155 	cap_mask = mad_get_field(info, 0, IB_PORT_CAPMASK_F);
156 	return (cap_mask & CL_NTOH32(IB_PORT_CAP_HAS_EXT_SPEEDS));
157 }
158 
159 static void show_port_info(ib_portid_t * dest, uint8_t * data, int portnum,
160 			   int espeed_cap, int is_switch)
161 {
162 	char buf[2300];
163 	char val[64];
164 
165 	mad_dump_portstates(buf, sizeof buf, data, sizeof *data);
166 	mad_decode_field(data, IB_PORT_LID_F, val);
167 	mad_dump_field(IB_PORT_LID_F, buf + strlen(buf),
168 		       sizeof buf - strlen(buf), val);
169 	sprintf(buf + strlen(buf), "%s", "\n");
170 	mad_decode_field(data, IB_PORT_SMLID_F, val);
171 	mad_dump_field(IB_PORT_SMLID_F, buf + strlen(buf),
172 		       sizeof buf - strlen(buf), val);
173 	sprintf(buf + strlen(buf), "%s", "\n");
174 	mad_decode_field(data, IB_PORT_LMC_F, val);
175 	mad_dump_field(IB_PORT_LMC_F, buf + strlen(buf),
176 		       sizeof buf - strlen(buf), val);
177 	sprintf(buf + strlen(buf), "%s", "\n");
178 	mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, val);
179 	mad_dump_field(IB_PORT_LINK_WIDTH_SUPPORTED_F, buf + strlen(buf),
180 		       sizeof buf - strlen(buf), val);
181 	sprintf(buf + strlen(buf), "%s", "\n");
182 	mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, val);
183 	mad_dump_field(IB_PORT_LINK_WIDTH_ENABLED_F, buf + strlen(buf),
184 		       sizeof buf - strlen(buf), val);
185 	sprintf(buf + strlen(buf), "%s", "\n");
186 	mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, val);
187 	mad_dump_field(IB_PORT_LINK_WIDTH_ACTIVE_F, buf + strlen(buf),
188 		       sizeof buf - strlen(buf), val);
189 	sprintf(buf + strlen(buf), "%s", "\n");
190 	mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, val);
191 	mad_dump_field(IB_PORT_LINK_SPEED_SUPPORTED_F, buf + strlen(buf),
192 		       sizeof buf - strlen(buf), val);
193 	sprintf(buf + strlen(buf), "%s", "\n");
194 	mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val);
195 	mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf + strlen(buf),
196 		       sizeof buf - strlen(buf), val);
197 	sprintf(buf + strlen(buf), "%s", "\n");
198 	mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, val);
199 	mad_dump_field(IB_PORT_LINK_SPEED_ACTIVE_F, buf + strlen(buf),
200 		       sizeof buf - strlen(buf), val);
201 	sprintf(buf + strlen(buf), "%s", "\n");
202 	if (espeed_cap) {
203 		mad_decode_field(data, IB_PORT_LINK_SPEED_EXT_SUPPORTED_F, val);
204 		mad_dump_field(IB_PORT_LINK_SPEED_EXT_SUPPORTED_F,
205 			       buf + strlen(buf), sizeof buf - strlen(buf),
206 			       val);
207 		sprintf(buf + strlen(buf), "%s", "\n");
208 		mad_decode_field(data, IB_PORT_LINK_SPEED_EXT_ENABLED_F, val);
209 		mad_dump_field(IB_PORT_LINK_SPEED_EXT_ENABLED_F,
210 			       buf + strlen(buf), sizeof buf - strlen(buf),
211 			       val);
212 		sprintf(buf + strlen(buf), "%s", "\n");
213 		mad_decode_field(data, IB_PORT_LINK_SPEED_EXT_ACTIVE_F, val);
214 		mad_dump_field(IB_PORT_LINK_SPEED_EXT_ACTIVE_F,
215 			       buf + strlen(buf), sizeof buf - strlen(buf),
216 			       val);
217 		sprintf(buf + strlen(buf), "%s", "\n");
218 	}
219 	if (!is_switch || portnum == 0) {
220 		if (show_keys) {
221 			mad_decode_field(data, IB_PORT_MKEY_F, val);
222 			mad_dump_field(IB_PORT_MKEY_F, buf + strlen(buf),
223 				       sizeof buf - strlen(buf), val);
224 		} else
225 			snprint_field(buf+strlen(buf), sizeof(buf)-strlen(buf),
226 				      IB_PORT_MKEY_F, 32, NOT_DISPLAYED_STR);
227 		sprintf(buf+strlen(buf), "%s", "\n");
228 		mad_decode_field(data, IB_PORT_MKEY_LEASE_F, val);
229 		mad_dump_field(IB_PORT_MKEY_LEASE_F, buf + strlen(buf),
230 			       sizeof buf - strlen(buf), val);
231 		sprintf(buf+strlen(buf), "%s", "\n");
232 		mad_decode_field(data, IB_PORT_MKEY_PROT_BITS_F, val);
233 		mad_dump_field(IB_PORT_MKEY_PROT_BITS_F, buf + strlen(buf),
234 			       sizeof buf - strlen(buf), val);
235 		sprintf(buf+strlen(buf), "%s", "\n");
236 	}
237 
238 	printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf);
239 }
240 
241 static void set_port_info(ib_portid_t * dest, uint8_t * data, int portnum,
242 			  int espeed_cap, int is_switch)
243 {
244 	unsigned mod;
245 
246 	mod = portnum;
247 	if (espeed_cap)
248 		mod |= 1<<31;
249 	if (!smp_set_via(data, dest, IB_ATTR_PORT_INFO, mod, 0, srcport))
250 		IBEXIT("smp set portinfo failed");
251 
252 	printf("\nAfter PortInfo set:\n");
253 	show_port_info(dest, data, portnum, espeed_cap, is_switch);
254 }
255 
256 static void get_mlnx_ext_port_info(ib_portid_t * dest, uint8_t * data, int portnum)
257 {
258 	if (!smp_query_via(data, dest, IB_ATTR_MLNX_EXT_PORT_INFO,
259 			   portnum, 0, srcport))
260 		IBEXIT("smp query ext portinfo failed");
261 }
262 
263 static void show_mlnx_ext_port_info(ib_portid_t * dest, uint8_t * data, int portnum)
264 {
265 	char buf[256];
266 
267 	mad_dump_mlnx_ext_port_info(buf, sizeof buf, data, IB_SMP_DATA_SIZE);
268 
269 	printf("# MLNX ext Port info: %s port %d\n%s", portid2str(dest),
270 	       portnum, buf);
271 }
272 
273 static void set_mlnx_ext_port_info(ib_portid_t * dest, uint8_t * data, int portnum)
274 {
275 	if (!smp_set_via(data, dest, IB_ATTR_MLNX_EXT_PORT_INFO,
276 			 portnum, 0, srcport))
277 		IBEXIT("smp set MLNX ext portinfo failed");
278 
279 	printf("\nAfter MLNXExtendedPortInfo set:\n");
280 	show_mlnx_ext_port_info(dest, data, portnum);
281 }
282 
283 static int get_link_width(int lwe, int lws)
284 {
285 	if (lwe == 255)
286 		return lws;
287 	else
288 		return lwe;
289 }
290 
291 static int get_link_speed(int lse, int lss)
292 {
293 	if (lse == 15)
294 		return lss;
295 	else
296 		return lse;
297 }
298 
299 static int get_link_speed_ext(int lsee, int lses)
300 {
301 	if (lsee == 31)
302 		return lses;
303 	else
304 		return lsee;
305 }
306 
307 static void validate_width(int width, int peerwidth, int lwa)
308 {
309 	if ((width & peerwidth & 0x8)) {
310 		if (lwa != 8)
311 			IBWARN
312 			    ("Peer ports operating at active width %d rather than 8 (12x)",
313 			     lwa);
314 	} else if ((width & peerwidth & 0x4)) {
315 		if (lwa != 4)
316 			IBWARN
317 			    ("Peer ports operating at active width %d rather than 4 (8x)",
318 			     lwa);
319 	} else if ((width & peerwidth & 0x2)) {
320 		if (lwa != 2)
321 			IBWARN
322 			    ("Peer ports operating at active width %d rather than 2 (4x)",
323 			     lwa);
324 	} else if ((width & peerwidth & 0x10)) {
325 		if (lwa != 16)
326 			IBWARN
327 			    ("Peer ports operating at active width %d rather than 16 (2x)",
328 			      lwa);
329 	} else if ((width & peerwidth & 0x1)) {
330 		if (lwa != 1)
331 			IBWARN
332 			    ("Peer ports operating at active width %d rather than 1 (1x)",
333 			     lwa);
334 	}
335 }
336 
337 static void validate_speed(int speed, int peerspeed, int lsa)
338 {
339 	if ((speed & peerspeed & 0x4)) {
340 		if (lsa != 4)
341 			IBWARN
342 			    ("Peer ports operating at active speed %d rather than 4 (10.0 Gbps)",
343 			     lsa);
344 	} else if ((speed & peerspeed & 0x2)) {
345 		if (lsa != 2)
346 			IBWARN
347 			    ("Peer ports operating at active speed %d rather than 2 (5.0 Gbps)",
348 			     lsa);
349 	} else if ((speed & peerspeed & 0x1)) {
350 		if (lsa != 1)
351 			IBWARN
352 			    ("Peer ports operating at active speed %d rather than 1 (2.5 Gbps)",
353 			     lsa);
354 	}
355 }
356 
357 static void validate_extended_speed(int espeed, int peerespeed, int lsea)
358 {
359 	if ((espeed & peerespeed & 0x2)) {
360 		if (lsea != 2)
361 			IBWARN
362 			    ("Peer ports operating at active extended speed %d rather than 2 (25.78125 Gbps)",
363 			     lsea);
364 	} else if ((espeed & peerespeed & 0x1)) {
365 		if (lsea != 1)
366 			IBWARN
367 			    ("Peer ports operating at active extended speed %d rather than 1 (14.0625 Gbps)",
368 			     lsea);
369 	}
370 }
371 
372 int main(int argc, char **argv)
373 {
374 	int mgmt_classes[3] =
375 	    { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS };
376 	ib_portid_t portid = { 0 };
377 	int port_op = -1;
378 	int is_switch, is_peer_switch, espeed_cap, peer_espeed_cap;
379 	int state, physstate, lwe, lws, lwa, lse, lss, lsa, lsee, lses, lsea,
380 	    fdr10s, fdr10e, fdr10a;
381 	int peerlocalportnum, peerlwe, peerlws, peerlwa, peerlse, peerlss,
382 	    peerlsa, peerlsee, peerlses, peerlsea, peerfdr10s, peerfdr10e,
383 	    peerfdr10a;
384 	int peerwidth, peerspeed, peerespeed;
385 	uint8_t data[IB_SMP_DATA_SIZE] = { 0 };
386 	uint8_t data2[IB_SMP_DATA_SIZE] = { 0 };
387 	ib_portid_t peerportid = { 0 };
388 	int portnum = 0;
389 	ib_portid_t selfportid = { 0 };
390 	int selfport = 0;
391 	int changed = 0;
392 	int i;
393 	uint32_t vendorid, rem_vendorid;
394 	uint16_t devid, rem_devid;
395 	uint64_t val;
396 	char *endp;
397 	char usage_args[] = "<dest dr_path|lid|guid> <portnum> [<op>]\n"
398 	    "\nSupported ops: enable, disable, on, off, reset, speed, espeed, fdr10,\n"
399 	    "\twidth, query, down, arm, active, vls, mtu, lid, smlid, lmc,\n"
400 	    "\tmkey, mkeylease, mkeyprot\n";
401 	const char *usage_examples[] = {
402 		"3 1 disable\t\t\t# by lid",
403 		"-G 0x2C9000100D051 1 enable\t# by guid",
404 		"-D 0 1\t\t\t# (query) by direct route",
405 		"3 1 reset\t\t\t# by lid",
406 		"3 1 speed 1\t\t\t# by lid",
407 		"3 1 width 1\t\t\t# by lid",
408 		"-D 0 1 lid 0x1234 arm\t\t# by direct route",
409 		NULL
410 	};
411 
412 	ibdiag_process_opts(argc, argv, NULL, NULL, NULL, NULL,
413 			    usage_args, usage_examples);
414 
415 	argc -= optind;
416 	argv += optind;
417 
418 	if (argc < 2)
419 		ibdiag_show_usage();
420 
421 	srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3);
422 	if (!srcport)
423 		IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port);
424 
425 	smp_mkey_set(srcport, ibd_mkey);
426 
427 	if (resolve_portid_str(ibd_ca, ibd_ca_port, &portid, argv[0],
428 			       ibd_dest_type, ibd_sm_id, srcport) < 0)
429 		IBEXIT("can't resolve destination port %s", argv[0]);
430 
431 	if (argc > 1)
432 		portnum = strtol(argv[1], 0, 0);
433 
434 	for (i = 2; i < argc; i++) {
435 		int j;
436 
437 		for (j = 0; j < NPORT_ARGS; j++) {
438 			if (strcmp(argv[i], port_args[j].name))
439 				continue;
440 			port_args[j].set = 1;
441 			if (!port_args[j].val) {
442 				if (port_op >= 0)
443 					IBEXIT("%s only one of: ",
444 						"query, enable, disable, "
445 						"reset, down, arm, active, "
446 						"can be specified",
447 						port_args[j].name);
448 				port_op = j;
449 				break;
450 			}
451 			if (++i >= argc)
452 				IBEXIT("%s requires an additional parameter",
453 					port_args[j].name);
454 			val = strtoull(argv[i], 0, 0);
455 			switch (j) {
456 			case SPEED:
457 				if (val > 15)
458 					IBEXIT("invalid speed value %ld", val);
459 				break;
460 			case ESPEED:
461 				if (val > 31)
462 					IBEXIT("invalid extended speed value %ld", val);
463 				break;
464 			case FDR10SPEED:
465 				if (val > 1)
466 					IBEXIT("invalid fdr10 speed value %ld", val);
467 				break;
468 			case WIDTH:
469 				if ((val > 31 && val != 255))
470 					IBEXIT("invalid width value %ld", val);
471 				break;
472 			case VLS:
473 				if (val == 0 || val > 5)
474 					IBEXIT("invalid vls value %ld", val);
475 				break;
476 			case MTU:
477 				if (val == 0 || val > 5)
478 					IBEXIT("invalid mtu value %ld", val);
479 				break;
480 			case LID:
481 				if (val == 0 || val >= 0xC000)
482 					IBEXIT("invalid lid value 0x%lx", val);
483 				break;
484 			case SMLID:
485 				if (val == 0 || val >= 0xC000)
486 					IBEXIT("invalid smlid value 0x%lx",
487 						val);
488 				break;
489 			case LMC:
490 				if (val > 7)
491 					IBEXIT("invalid lmc value %ld", val);
492 				break;
493 			case MKEY:
494 				errno = 0;
495 				val = strtoull(argv[i], &endp, 0);
496 				if (errno || *endp != '\0') {
497 					errno = 0;
498 					val = strtoull(getpass("New M_Key: "),
499 						       &endp, 0);
500 					if (errno || *endp != '\0') {
501 						IBEXIT("Bad new M_Key\n");
502 					}
503 				}
504 				/* All 64-bit values are legal */
505 				break;
506 			case MKEYLEASE:
507 				if (val > 0xFFFF)
508 					IBEXIT("invalid mkey lease time %ld", val);
509 				break;
510 			case MKEYPROT:
511 				if (val > 3)
512 					IBEXIT("invalid mkey protection bit setting %ld", val);
513 			}
514 			*port_args[j].val = val;
515 			changed = 1;
516 			break;
517 		}
518 		if (j == NPORT_ARGS)
519 			IBEXIT("invalid operation: %s", argv[i]);
520 	}
521 	if (port_op < 0)
522 		port_op = QUERY;
523 
524 	is_switch = get_node_info(&portid, data);
525 	vendorid = (uint32_t) mad_get_field(data, 0, IB_NODE_VENDORID_F);
526 	devid = (uint16_t) mad_get_field(data, 0, IB_NODE_DEVID_F);
527 
528 	if ((port_args[MKEY].set || port_args[MKEYLEASE].set ||
529 	     port_args[MKEYPROT].set) && is_switch && portnum != 0)
530 		IBEXIT("Can't set M_Key fields on switch port != 0");
531 
532 	if (port_op != QUERY || changed)
533 		printf("Initial %s PortInfo:\n", is_switch ? "Switch" : "CA/RT");
534 	else
535 		printf("%s PortInfo:\n", is_switch ? "Switch" : "CA/RT");
536 	espeed_cap = get_port_info(&portid, data, portnum, is_switch);
537 	show_port_info(&portid, data, portnum, espeed_cap, is_switch);
538 	if (is_mlnx_ext_port_info_supported(vendorid, devid)) {
539 		get_mlnx_ext_port_info(&portid, data2, portnum);
540 		show_mlnx_ext_port_info(&portid, data2, portnum);
541 	}
542 
543 	if (port_op != QUERY || changed) {
544 		/*
545 		 * If we aren't setting the LID and the LID is the default,
546 		 * the SMA command will fail due to an invalid LID.
547 		 * Set it to something unlikely but valid.
548 		 */
549 		physstate = mad_get_field(data, 0, IB_PORT_PHYS_STATE_F);
550 
551 		val = mad_get_field(data, 0, IB_PORT_LID_F);
552 		if (!port_args[LID].set && (!val || val == 0xFFFF))
553 			mad_set_field(data, 0, IB_PORT_LID_F, 0x1234);
554 		val = mad_get_field(data, 0, IB_PORT_SMLID_F);
555 		if (!port_args[SMLID].set && (!val || val == 0xFFFF))
556 			mad_set_field(data, 0, IB_PORT_SMLID_F, 0x1234);
557 		mad_set_field(data, 0, IB_PORT_STATE_F, 0);	/* NOP */
558 		mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 0);	/* NOP */
559 
560 		switch (port_op) {
561 		case ON:
562 			/* Enable only if state is Disable */
563 			if(physstate != 3) {
564 				printf("Port is already in enable state\n");
565 				goto close_port;
566 			}
567 			/* FALLTHROUGH */
568 		case ENABLE:
569 		case RESET:
570 			/* Polling */
571 			mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 2);
572 			break;
573 		case OFF:
574 		case DISABLE:
575 			printf("Disable may be irreversible\n");
576 			mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 3);
577 			break;
578 		case DOWN:
579 			mad_set_field(data, 0, IB_PORT_STATE_F, 1);
580 			break;
581 		case ARM:
582 			mad_set_field(data, 0, IB_PORT_STATE_F, 3);
583 			break;
584 		case ACTIVE:
585 			mad_set_field(data, 0, IB_PORT_STATE_F, 4);
586 			break;
587 		}
588 
589 		/* always set enabled speeds/width - defaults to NOP */
590 		mad_set_field(data, 0, IB_PORT_LINK_SPEED_ENABLED_F, speed);
591 		mad_set_field(data, 0, IB_PORT_LINK_SPEED_EXT_ENABLED_F, espeed);
592 		mad_set_field(data, 0, IB_PORT_LINK_WIDTH_ENABLED_F, width);
593 
594 		if (port_args[VLS].set)
595 			mad_set_field(data, 0, IB_PORT_OPER_VLS_F, vls);
596 		if (port_args[MTU].set)
597 			mad_set_field(data, 0, IB_PORT_NEIGHBOR_MTU_F, mtu);
598 		if (port_args[LID].set)
599 			mad_set_field(data, 0, IB_PORT_LID_F, lid);
600 		if (port_args[SMLID].set)
601 			mad_set_field(data, 0, IB_PORT_SMLID_F, smlid);
602 		if (port_args[LMC].set)
603 			mad_set_field(data, 0, IB_PORT_LMC_F, lmc);
604 
605 		if (port_args[FDR10SPEED].set) {
606 			mad_set_field(data2, 0,
607 				      IB_MLNX_EXT_PORT_STATE_CHG_ENABLE_F,
608 				      FDR10);
609 			mad_set_field(data2, 0,
610 				      IB_MLNX_EXT_PORT_LINK_SPEED_ENABLED_F,
611 				      fdr10);
612 			set_mlnx_ext_port_info(&portid, data2, portnum);
613 		}
614 
615 		if (port_args[MKEY].set)
616 			mad_set_field64(data, 0, IB_PORT_MKEY_F, mkey);
617 		if (port_args[MKEYLEASE].set)
618 			mad_set_field(data, 0, IB_PORT_MKEY_LEASE_F,
619 				      mkeylease);
620 		if (port_args[MKEYPROT].set)
621 			mad_set_field(data, 0, IB_PORT_MKEY_PROT_BITS_F,
622 				      mkeyprot);
623 
624 		set_port_info(&portid, data, portnum, espeed_cap, is_switch);
625 
626 	} else if (is_switch && portnum) {
627 		/* Now, make sure PortState is Active */
628 		/* Or is PortPhysicalState LinkUp sufficient ? */
629 		mad_decode_field(data, IB_PORT_STATE_F, &state);
630 		mad_decode_field(data, IB_PORT_PHYS_STATE_F, &physstate);
631 		if (state == 4) {	/* Active */
632 			mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F,
633 					 &lwe);
634 			mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F,
635 					 &lws);
636 			mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F,
637 					 &lwa);
638 			mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F,
639 					 &lss);
640 			mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F,
641 					 &lsa);
642 			mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F,
643 					 &lse);
644 			mad_decode_field(data2,
645 					 IB_MLNX_EXT_PORT_LINK_SPEED_SUPPORTED_F,
646 					 &fdr10s);
647 			mad_decode_field(data2,
648 					 IB_MLNX_EXT_PORT_LINK_SPEED_ENABLED_F,
649 					 &fdr10e);
650 			mad_decode_field(data2,
651 					 IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F,
652 					 &fdr10a);
653 			if (espeed_cap) {
654 				mad_decode_field(data,
655 						 IB_PORT_LINK_SPEED_EXT_SUPPORTED_F,
656 						 &lses);
657 				mad_decode_field(data,
658 						 IB_PORT_LINK_SPEED_EXT_ACTIVE_F,
659 						 &lsea);
660 				mad_decode_field(data,
661 						 IB_PORT_LINK_SPEED_EXT_ENABLED_F,
662 						 &lsee);
663 			}
664 
665 			/* Setup portid for peer port */
666 			memcpy(&peerportid, &portid, sizeof(peerportid));
667 			if (portid.lid == 0) {
668 				peerportid.drpath.cnt++;
669 				if (peerportid.drpath.cnt == IB_SUBNET_PATH_HOPS_MAX) {
670 					IBEXIT("Too many hops");
671 				}
672 			} else {
673 				peerportid.drpath.cnt = 1;
674 
675 				/* Set DrSLID to local lid */
676 				if (resolve_self(ibd_ca, ibd_ca_port, &selfportid,
677 						         &selfport, 0) < 0)
678 					IBEXIT("could not resolve self");
679 				peerportid.drpath.drslid = (uint16_t) selfportid.lid;
680 				peerportid.drpath.drdlid = 0xffff;
681 			}
682 			peerportid.drpath.p[peerportid.drpath.cnt] = (uint8_t) portnum;
683 
684 			/* Get peer port NodeInfo to obtain peer port number */
685 			is_peer_switch = get_node_info(&peerportid, data);
686 			rem_vendorid = (uint32_t) mad_get_field(data, 0, IB_NODE_VENDORID_F);
687 			rem_devid = (uint16_t) mad_get_field(data, 0, IB_NODE_DEVID_F);
688 
689 			mad_decode_field(data, IB_NODE_LOCAL_PORT_F,
690 					 &peerlocalportnum);
691 
692 			printf("Peer PortInfo:\n");
693 			/* Get peer port characteristics */
694 			peer_espeed_cap = get_port_info(&peerportid, data,
695 							peerlocalportnum,
696 							is_peer_switch);
697 			if (is_mlnx_ext_port_info_supported(rem_vendorid, rem_devid))
698 				get_mlnx_ext_port_info(&peerportid, data2,
699 						       peerlocalportnum);
700 			show_port_info(&peerportid, data, peerlocalportnum,
701 				       peer_espeed_cap, is_peer_switch);
702 			if (is_mlnx_ext_port_info_supported(rem_vendorid, rem_devid))
703 				show_mlnx_ext_port_info(&peerportid, data2,
704 							peerlocalportnum);
705 
706 			mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F,
707 					 &peerlwe);
708 			mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F,
709 					 &peerlws);
710 			mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F,
711 					 &peerlwa);
712 			mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F,
713 					 &peerlss);
714 			mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F,
715 					 &peerlsa);
716 			mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F,
717 					 &peerlse);
718 			mad_decode_field(data2,
719 					 IB_MLNX_EXT_PORT_LINK_SPEED_SUPPORTED_F,
720 					 &peerfdr10s);
721 			mad_decode_field(data2,
722 					 IB_MLNX_EXT_PORT_LINK_SPEED_ENABLED_F,
723 					 &peerfdr10e);
724 			mad_decode_field(data2,
725 					 IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F,
726 					 &peerfdr10a);
727 			if (peer_espeed_cap) {
728 				mad_decode_field(data,
729 						 IB_PORT_LINK_SPEED_EXT_SUPPORTED_F,
730 						 &peerlses);
731 				mad_decode_field(data,
732 						 IB_PORT_LINK_SPEED_EXT_ACTIVE_F,
733 						 &peerlsea);
734 				mad_decode_field(data,
735 						 IB_PORT_LINK_SPEED_EXT_ENABLED_F,
736 						 &peerlsee);
737 			}
738 
739 			/* Now validate peer port characteristics */
740 			/* Examine Link Width */
741 			width = get_link_width(lwe, lws);
742 			peerwidth = get_link_width(peerlwe, peerlws);
743 			validate_width(width, peerwidth, lwa);
744 
745 			/* Examine Link Speeds */
746 			speed = get_link_speed(lse, lss);
747 			peerspeed = get_link_speed(peerlse, peerlss);
748 			validate_speed(speed, peerspeed, lsa);
749 
750 			if (espeed_cap && peer_espeed_cap) {
751 				espeed = get_link_speed_ext(lsee, lses);
752 				peerespeed = get_link_speed_ext(peerlsee,
753 								peerlses);
754 				validate_extended_speed(espeed, peerespeed,
755 							lsea);
756 			} else {
757 				if (fdr10e & FDR10 && peerfdr10e & FDR10) {
758 					if (!(fdr10a & FDR10))
759 						IBWARN("Peer ports operating at active speed %d rather than FDR10", lsa);
760 				}
761 			}
762 		}
763 	}
764 
765 close_port:
766 	mad_rpc_close_port(srcport);
767 	exit(0);
768 }
769