1/* 2 * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 * 32 */ 33 34#if HAVE_CONFIG_H 35# include <config.h> 36#endif /* HAVE_CONFIG_H */ 37 38#include <stdio.h> 39#include <stdlib.h> 40#include <unistd.h> 41#include <stdarg.h> 42#include <time.h> 43#include <string.h> 44#include <getopt.h> 45 46#include <infiniband/common.h> 47#include <infiniband/umad.h> 48#include <infiniband/mad.h> 49 50#include "ibdiag_common.h" 51 52#undef DEBUG 53#define DEBUG if (verbose>1) IBWARN 54 55static int dest_type = IB_DEST_LID; 56static int verbose; 57 58char *argv0 = "ibportstate"; 59 60/*******************************************/ 61 62static int 63get_node_info(ib_portid_t *dest, uint8_t *data) 64{ 65 int node_type; 66 67 if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) 68 return -1; 69 70 node_type = mad_get_field(data, 0, IB_NODE_TYPE_F); 71 if (node_type == IB_NODE_SWITCH) /* Switch NodeType ? */ 72 return 0; 73 else 74 return 1; 75} 76 77static int 78get_port_info(ib_portid_t *dest, uint8_t *data, int portnum, int port_op) 79{ 80 char buf[2048]; 81 char val[64]; 82 83 if (!smp_query(data, dest, IB_ATTR_PORT_INFO, portnum, 0)) 84 return -1; 85 86 if (port_op != 4) { 87 mad_dump_portstates(buf, sizeof buf, data, sizeof data); 88 mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, val); 89 mad_dump_field(IB_PORT_LINK_WIDTH_SUPPORTED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); 90 sprintf(buf+strlen(buf), "%s", "\n"); 91 mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, val); 92 mad_dump_field(IB_PORT_LINK_WIDTH_ENABLED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); 93 sprintf(buf+strlen(buf), "%s", "\n"); 94 mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, val); 95 mad_dump_field(IB_PORT_LINK_WIDTH_ACTIVE_F, buf + strlen(buf), sizeof buf - strlen(buf), val); 96 sprintf(buf+strlen(buf), "%s", "\n"); 97 mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, val); 98 mad_dump_field(IB_PORT_LINK_SPEED_SUPPORTED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); 99 sprintf(buf+strlen(buf), "%s", "\n"); 100 mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val); 101 mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); 102 sprintf(buf+strlen(buf), "%s", "\n"); 103 mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, val); 104 mad_dump_field(IB_PORT_LINK_SPEED_ACTIVE_F, buf + strlen(buf), sizeof buf - strlen(buf), val); 105 sprintf(buf+strlen(buf), "%s", "\n"); 106 } else { 107 mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val); 108 mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf, sizeof buf, val); 109 sprintf(buf+strlen(buf), "%s", "\n"); 110 } 111 112 printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf); 113 return 0; 114} 115 116static int 117set_port_info(ib_portid_t *dest, uint8_t *data, int portnum, int port_op) 118{ 119 char buf[2048]; 120 char val[64]; 121 122 if (!smp_set(data, dest, IB_ATTR_PORT_INFO, portnum, 0)) 123 return -1; 124 125 if (port_op != 4) 126 mad_dump_portstates(buf, sizeof buf, data, sizeof data); 127 else { 128 mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val); 129 mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf, sizeof buf, val); 130 sprintf(buf+strlen(buf), "%s", "\n"); 131 } 132 133 printf("\nAfter PortInfo set:\n"); 134 printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf); 135 return 0; 136} 137 138static int 139get_link_width(int lwe, int lws) 140{ 141 if (lwe == 255) 142 return lws; 143 else 144 return lwe; 145} 146 147static int 148get_link_speed(int lse, int lss) 149{ 150 if (lse == 15) 151 return lss; 152 else 153 return lse; 154} 155 156static void 157validate_width(int width, int peerwidth, int lwa) 158{ 159 if ((width & 0x8) && (peerwidth & 0x8)) { 160 if (lwa != 8) 161 IBWARN("Peer ports operating at active width %d rather than 8 (12x)", lwa); 162 } else { 163 if ((width & 0x4) && (peerwidth & 0x4)) { 164 if (lwa != 4) 165 IBWARN("Peer ports operating at active width %d rather than 4 (8x)", lwa); 166 } else { 167 if ((width & 0x2) && (peerwidth & 0x2)) { 168 if (lwa != 2) 169 IBWARN("Peer ports operating at active width %d rather than 2 (4x)", lwa); 170 } else { 171 if ((width & 0x1) && (peerwidth & 0x1)) { 172 if (lwa != 1) 173 IBWARN("Peer ports operating at active width %d rather than 1 (1x)", lwa); 174 } 175 } 176 } 177 } 178} 179 180static void 181validate_speed(int speed, int peerspeed, int lsa) 182{ 183 if ((speed & 0x4) && (peerspeed & 0x4)) { 184 if (lsa != 4) 185 IBWARN("Peer ports operating at active speed %d rather than 4 (10.0 Gbps)", lsa); 186 } else { 187 if ((speed & 0x2) && (peerspeed & 0x2)) { 188 if (lsa != 2) 189 IBWARN("Peer ports operating at active speed %d rather than 2 (5.0 Gbps)", lsa); 190 } else { 191 if ((speed & 0x1) && (peerspeed & 0x1)) { 192 if (lsa != 1) 193 IBWARN("Peer ports operating at active speed %d rather than 1 (2.5 Gbps)", lsa); 194 } 195 } 196 } 197} 198 199void 200usage(void) 201{ 202 char *basename; 203 204 if (!(basename = strrchr(argv0, '/'))) 205 basename = argv0; 206 else 207 basename++; 208 209 fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -D(irect) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port " 210 "-t(imeout) timeout_ms] <dest dr_path|lid|guid> <portnum> [<op>]\n", 211 basename); 212 fprintf(stderr, "\tsupported ops: enable, disable, reset, speed, query\n"); 213 fprintf(stderr, "\n\texamples:\n"); 214 fprintf(stderr, "\t\t%s 3 1 disable\t\t\t# by lid\n", basename); 215 fprintf(stderr, "\t\t%s -G 0x2C9000100D051 1 enable\t# by guid\n", basename); 216 fprintf(stderr, "\t\t%s -D 0 1\t\t\t# (query) by direct route\n", basename); 217 fprintf(stderr, "\t\t%s 3 1 reset\t\t\t# by lid\n", basename); 218 fprintf(stderr, "\t\t%s 3 1 speed 1\t\t\t# by lid\n", basename); 219 exit(-1); 220} 221 222int 223main(int argc, char **argv) 224{ 225 int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; 226 ib_portid_t portid = {0}; 227 ib_portid_t *sm_id = 0, sm_portid = {0}; 228 extern int ibdebug; 229 int err; 230 int timeout = 0, udebug = 0; 231 char *ca = 0; 232 int ca_port = 0; 233 int port_op = 0; /* default to query */ 234 int speed = 15; 235 int is_switch = 1; 236 int state, physstate, lwe, lws, lwa, lse, lss, lsa; 237 int peerlocalportnum, peerlwe, peerlws, peerlwa, peerlse, peerlss, peerlsa; 238 int width, peerwidth, peerspeed; 239 uint8_t data[IB_SMP_DATA_SIZE]; 240 ib_portid_t peerportid = {0}; 241 int portnum = 0; 242 ib_portid_t selfportid = {0}; 243 int selfport = 0; 244 245 static char const str_opts[] = "C:P:t:s:devDGVhu"; 246 static const struct option long_opts[] = { 247 { "C", 1, 0, 'C'}, 248 { "P", 1, 0, 'P'}, 249 { "debug", 0, 0, 'd'}, 250 { "err_show", 0, 0, 'e'}, 251 { "verbose", 0, 0, 'v'}, 252 { "Direct", 0, 0, 'D'}, 253 { "Guid", 0, 0, 'G'}, 254 { "timeout", 1, 0, 't'}, 255 { "s", 1, 0, 's'}, 256 { "Version", 0, 0, 'V'}, 257 { "help", 0, 0, 'h'}, 258 { "usage", 0, 0, 'u'}, 259 { } 260 }; 261 262 argv0 = argv[0]; 263 264 while (1) { 265 int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); 266 if ( ch == -1 ) 267 break; 268 switch(ch) { 269 case 'd': 270 ibdebug++; 271 madrpc_show_errors(1); 272 umad_debug(udebug); 273 udebug++; 274 break; 275 case 'e': 276 madrpc_show_errors(1); 277 break; 278 case 'D': 279 dest_type = IB_DEST_DRPATH; 280 break; 281 case 'G': 282 dest_type = IB_DEST_GUID; 283 break; 284 case 'C': 285 ca = optarg; 286 break; 287 case 'P': 288 ca_port = strtoul(optarg, 0, 0); 289 break; 290 case 's': 291 if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) 292 IBERROR("can't resolve SM destination port %s", optarg); 293 sm_id = &sm_portid; 294 break; 295 case 't': 296 timeout = strtoul(optarg, 0, 0); 297 madrpc_set_timeout(timeout); 298 break; 299 case 'v': 300 verbose++; 301 break; 302 case 'V': 303 fprintf(stderr, "%s %s\n", argv0, get_build_version() ); 304 exit(-1); 305 default: 306 usage(); 307 break; 308 } 309 } 310 argc -= optind; 311 argv += optind; 312 313 if (argc < 2) 314 usage(); 315 316 madrpc_init(ca, ca_port, mgmt_classes, 3); 317 318 if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) 319 IBERROR("can't resolve destination port %s", argv[0]); 320 321 /* First, make sure it is a switch port if it is a "set" */ 322 if (argc >= 3) { 323 if (!strcmp(argv[2], "enable")) 324 port_op = 1; 325 else if (!strcmp(argv[2], "disable")) 326 port_op = 2; 327 else if (!strcmp(argv[2], "reset")) 328 port_op = 3; 329 else if (!strcmp(argv[2], "speed")) { 330 if (argc < 4) 331 IBERROR("speed requires an additional parameter"); 332 port_op = 4; 333 /* Parse speed value */ 334 speed = strtoul(argv[3], 0, 0); 335 if (speed > 15) 336 IBERROR("invalid speed value %d", speed); 337 } 338 } 339 340 err = get_node_info(&portid, data); 341 if (err < 0) 342 IBERROR("smp query nodeinfo failed"); 343 if (err) { /* not switch */ 344 if (port_op == 0) /* query op */ 345 is_switch = 0; 346 else if (port_op != 4) /* other than speed op */ 347 IBERROR("smp query nodeinfo: Node type not switch"); 348 } 349 350 if (argc-1 > 0) 351 portnum = strtol(argv[1], 0, 0); 352 353 if (port_op) 354 printf("Initial PortInfo:\n"); 355 else 356 printf("PortInfo:\n"); 357 err = get_port_info(&portid, data, portnum, port_op); 358 if (err < 0) 359 IBERROR("smp query portinfo failed"); 360 361 /* Only if one of the "set" options is chosen */ 362 if (port_op) { 363 if (port_op == 1) /* Enable port */ 364 mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 2); /* Polling */ 365 else if ((port_op == 2) || (port_op == 3)) { /* Disable port */ 366 mad_set_field(data, 0, IB_PORT_STATE_F, 1); /* Down */ 367 mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 3); /* Disabled */ 368 } else if (port_op == 4) { /* Set speed */ 369 mad_set_field(data, 0, IB_PORT_LINK_SPEED_ENABLED_F, speed); 370 mad_set_field(data, 0, IB_PORT_STATE_F, 0); 371 mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 0); 372 } 373 374 err = set_port_info(&portid, data, portnum, port_op); 375 if (err < 0) 376 IBERROR("smp set portinfo failed"); 377 378 if (port_op == 3) { /* Reset port - so also enable */ 379 mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 2); /* Polling */ 380 err = set_port_info(&portid, data, portnum, port_op); 381 if (err < 0) 382 IBERROR("smp set portinfo failed"); 383 } 384 } else { /* query op */ 385 /* only compare peer port if switch port */ 386 if (is_switch) { 387 /* First, exclude SP0 */ 388 if (portnum) { 389 /* Now, make sure PortState is Active */ 390 /* Or is PortPhysicalState LinkUp sufficient ? */ 391 mad_decode_field(data, IB_PORT_STATE_F, &state); 392 mad_decode_field(data, IB_PORT_PHYS_STATE_F, &physstate); 393 if (state == 4) { /* Active */ 394 mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, &lwe ); 395 mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, &lws); 396 mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, &lwa); 397 mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, &lss); 398 mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, &lsa); 399 mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, &lse); 400 401 /* Setup portid for peer port */ 402 memcpy(&peerportid, &portid, sizeof(peerportid)); 403 peerportid.drpath.cnt = 1; 404 peerportid.drpath.p[1] = portnum; 405 406 /* Set DrSLID to local lid */ 407 if (ib_resolve_self(&selfportid, &selfport, 0) < 0) 408 IBERROR("could not resolve self"); 409 peerportid.drpath.drslid = selfportid.lid; 410 peerportid.drpath.drdlid = 0xffff; 411 412 /* Get peer port NodeInfo to obtain peer port number */ 413 err = get_node_info(&peerportid, data); 414 if (err < 0) 415 IBERROR("smp query nodeinfo failed"); 416 417 mad_decode_field(data, IB_NODE_LOCAL_PORT_F, &peerlocalportnum); 418 419 printf("Peer PortInfo:\n"); 420 /* Get peer port characteristics */ 421 err = get_port_info(&peerportid, data, peerlocalportnum, port_op); 422 if (err < 0) 423 IBERROR("smp query peer portinfofailed"); 424 425 mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, &peerlwe ); 426 mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, &peerlws); 427 mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, &peerlwa); 428 mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, &peerlss); 429 mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, &peerlsa); 430 mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, &peerlse); 431 432 /* Now validate peer port characteristics */ 433 /* Examine Link Width */ 434 width = get_link_width(lwe, lws); 435 peerwidth = get_link_width(peerlwe, peerlws); 436 validate_width(width, peerwidth, lwa); 437 438 /* Examine Link Speed */ 439 speed = get_link_speed(lse, lss); 440 peerspeed = get_link_speed(peerlse, peerlss); 441 validate_speed(speed, peerspeed, lsa); 442 } 443 } 444 } 445 } 446 447 exit(0); 448} 449