ib-mgmt: update to 518083dc46963eb5fb48855acbe2b351ce7361f8
[mirror/winof/.git] / tools / infiniband-diags / src / ibqueryerrors.c
1 /*
2  * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
3  * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
4  * Copyright (c) 2008 Lawrence Livermore National Lab.  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 #define _GNU_SOURCE
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <stdarg.h>
45 #include <time.h>
46 #include <string.h>
47 #include <getopt.h>
48 #include <errno.h>
49 #include <inttypes.h>
50
51 #include <complib/cl_nodenamemap.h>
52 #include <infiniband/ibnetdisc.h>
53 #include <infiniband/mad.h>
54
55 #include "ibdiag_common.h"
56
57 struct ibmad_port *ibmad_port;
58 static char *node_name_map_file = NULL;
59 static nn_map_t *node_name_map = NULL;
60 int data_counters = 0;
61 int port_config = 0;
62 uint64_t switch_guid = 0;
63 char *switch_guid_str = NULL;
64 int sup_total = 0;
65 enum MAD_FIELDS *suppressed_fields = NULL;
66 char *dr_path = NULL;
67 int all_nodes = 0;
68
69 static unsigned int
70 get_max(unsigned int num)
71 {
72         unsigned int v = num; // 32-bit word to find the log base 2 of
73         unsigned r = 0; // r will be lg(v)
74
75         while (v >>= 1) // unroll for more speed...
76         {
77                 r++;
78         }
79
80         return (1 << r);
81 }
82
83 static void
84 get_msg(char *width_msg, char *speed_msg, int msg_size, ibnd_port_t *port)
85 {
86         char buf[64];
87         uint32_t max_speed = 0;
88
89         uint32_t max_width = get_max(mad_get_field(port->info, 0,
90                                         IB_PORT_LINK_WIDTH_SUPPORTED_F)
91                                 & mad_get_field(port->remoteport->info, 0,
92                                         IB_PORT_LINK_WIDTH_SUPPORTED_F));
93         if ((max_width & mad_get_field(port->info, 0,
94                                 IB_PORT_LINK_WIDTH_ACTIVE_F)) == 0) {
95                 // we are not at the max supported width
96                 // print what we could be at.
97                 snprintf(width_msg, msg_size, "Could be %s",
98                         mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F,
99                                 buf, 64, &max_width));
100         }
101
102         max_speed = get_max(mad_get_field(port->info, 0,
103                                         IB_PORT_LINK_SPEED_SUPPORTED_F)
104                                 & mad_get_field(port->remoteport->info, 0,
105                                         IB_PORT_LINK_SPEED_SUPPORTED_F));
106         if ((max_speed & mad_get_field(port->info, 0,
107                                 IB_PORT_LINK_SPEED_ACTIVE_F)) == 0) {
108                 // we are not at the max supported speed
109                 // print what we could be at.
110                 snprintf(speed_msg, msg_size, "Could be %s",
111                         mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F,
112                                 buf, 64, &max_speed));
113         }
114 }
115
116 static void
117 print_port_config(ibnd_node_t *node, int portnum)
118 {
119         char width[64], speed[64], state[64], physstate[64];
120         char remote_str[256];
121         char link_str[256];
122         char width_msg[256];
123         char speed_msg[256];
124         char ext_port_str[256];
125         int iwidth, ispeed, istate, iphystate;
126
127         ibnd_port_t *port = node->ports[portnum];
128
129         if (!port)
130                 return;
131
132         iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F);
133         ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F);
134         istate = mad_get_field(port->info, 0, IB_PORT_STATE_F);
135         iphystate = mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F);
136
137         remote_str[0] = '\0';
138         link_str[0] = '\0';
139         width_msg[0] = '\0';
140         speed_msg[0] = '\0';
141
142         snprintf(link_str, 256, "(%3s %s %6s/%8s)",
143                 mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, width, 64, &iwidth),
144                 mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, speed, 64, &ispeed),
145                 mad_dump_val(IB_PORT_STATE_F, state, 64, &istate),
146                 mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64, &iphystate));
147
148         if (port->remoteport) {
149                 char *remap = remap_node_name(node_name_map, port->remoteport->node->guid,
150                                 port->remoteport->node->nodedesc);
151
152                 if (port->remoteport->ext_portnum)
153                         snprintf(ext_port_str, 256, "%d", port->remoteport->ext_portnum);
154                 else
155                         ext_port_str[0] = '\0';
156
157                 get_msg(width_msg, speed_msg, 256, port);
158
159                 snprintf(remote_str, 256,
160                         "0x%016"PRIx64" %6d %4d[%2s] \"%s\" (%s %s)\n",
161                         port->remoteport->node->guid,
162                         port->remoteport->base_lid ?  port->remoteport->base_lid :
163                                 port->remoteport->node->smalid,
164                         port->remoteport->portnum,
165                         ext_port_str,
166                         remap,
167                         width_msg,
168                         speed_msg);
169                 free(remap);
170         } else
171                 snprintf(remote_str, 256, "           [  ] \"\" ( )\n");
172
173         if (port->ext_portnum)
174                 snprintf(ext_port_str, 256, "%d", port->ext_portnum);
175         else
176                 ext_port_str[0] = '\0';
177
178         if (node->type == IB_NODE_SWITCH)
179                 printf("       Link info: %6d", node->smalid);
180         else
181                 printf("       Link info: %6d", port->base_lid);
182
183         printf("%4d[%2s] ==%s==>  %s",
184                 port->portnum, ext_port_str, link_str, remote_str);
185 }
186
187 static int
188 suppress(enum MAD_FIELDS field)
189 {
190         int i = 0;
191         if (suppressed_fields)
192                 for (i = 0; i < sup_total; i++) {
193                         if (field == suppressed_fields[i])
194                                 return (1);
195                 }
196         return (0);
197 }
198
199 static void
200 report_suppressed(void)
201 {
202         int i = 0;
203         if (suppressed_fields) {
204                 printf("Suppressing:");
205                 for (i = 0; i < sup_total; i++) {
206                         printf(" %s", mad_field_name(suppressed_fields[i]));
207                 }
208                 printf("\n");
209         }
210 }
211
212 static void
213 print_results(ibnd_node_t *node, uint8_t *pc, int portnum, int *header_printed)
214 {
215         char buf[1024];
216         char *str = buf;
217         uint32_t val = 0;
218         int n = 0;
219         int i = 0;
220
221         for (n = 0, i = IB_PC_ERR_SYM_F; i <= IB_PC_VL15_DROPPED_F; i++) {
222                 if (suppress(i))
223                         continue;
224
225                 mad_decode_field(pc, i, (void *)&val);
226                 if (val)
227                         n += snprintf(str+n, 1024-n, " [%s == %d]",
228                                 mad_field_name(i), val);
229         }
230
231         if (!suppress(IB_PC_XMT_WAIT_F)) {
232                 mad_decode_field(pc, IB_PC_XMT_WAIT_F, (void *)&val);
233                 if (val)
234                         n += snprintf(str+n, 1024-n, " [%s == %d]", mad_field_name(i), val);
235         }
236
237         /* if we found errors. */
238         if (n != 0) {
239                 if (data_counters)
240                         for (i = IB_PC_XMT_BYTES_F; i <= IB_PC_RCV_PKTS_F; i++) {
241                                 uint64_t val64 = 0;
242                                 mad_decode_field(pc, i, (void *)&val64);
243                                 if (val64)
244                                         n += snprintf(str+n, 1024-n, " [%s == %"PRId64"]",
245                                                 mad_field_name(i), val64);
246                         }
247
248                 if (!*header_printed) {
249                         char *nodename = remap_node_name(node_name_map, node->guid, node->nodedesc);
250                         printf("Errors for 0x%" PRIx64 " \"%s\"\n", node->guid, nodename);
251                         *header_printed = 1;
252                         free(nodename);
253                 }
254
255                 printf("   GUID 0x%" PRIx64 " port %d:%s\n", node->guid, portnum, str);
256                 if (port_config)
257                         print_port_config(node, portnum);
258         }
259 }
260
261 static void
262 print_port(ibnd_node_t *node, int portnum, int *header_printed)
263 {
264         uint8_t pc[1024];
265         uint16_t cap_mask;
266         ib_portid_t portid = {0};
267         char *nodename = remap_node_name(node_name_map, node->guid, node->nodedesc);
268
269         if (node->type == IB_NODE_SWITCH)
270                 ib_portid_set(&portid, node->smalid, 0, 0);
271         else
272                 ib_portid_set(&portid, node->ports[portnum]->base_lid, 0, 0);
273
274         /* PerfMgt ClassPortInfo is a required attribute */
275         if (!pma_query_via(pc, &portid, portnum, ibd_timeout, CLASS_PORT_INFO,
276                            ibmad_port)) {
277                 IBWARN("classportinfo query failed on %s, %s port %d",
278                         nodename, portid2str(&portid), portnum);
279                 goto cleanup;
280         }
281         /* ClassPortInfo should be supported as part of libibmad */
282         memcpy(&cap_mask, pc + 2, sizeof(cap_mask));    /* CapabilityMask */
283
284         if (!pma_query_via(pc, &portid, portnum, ibd_timeout,
285                                 IB_GSI_PORT_COUNTERS,
286                                 ibmad_port)) {
287                 IBWARN("IB_GSI_PORT_COUNTERS query failed on %s, %s port %d\n",
288                         nodename, portid2str(&portid), portnum);
289                 goto cleanup;
290         }
291         if (!(cap_mask & 0x1000)) {
292                 /* if PortCounters:PortXmitWait not suppported clear this counter */
293                 uint32_t foo = 0;
294                 mad_encode_field(pc, IB_PC_XMT_WAIT_F, &foo);
295         }
296         print_results(node, pc, portnum, header_printed);
297
298 cleanup:
299         free(nodename);
300 }
301
302 void
303 print_node(ibnd_node_t *node, void *user_data)
304 {
305         int header_printed = 0;
306         int p = 0;
307         int startport = 1;
308
309         if (!all_nodes && node->type != IB_NODE_SWITCH)
310                 return;
311
312         if (node->type == IB_NODE_SWITCH && node->smaenhsp0)
313                 startport = 0;
314
315         for (p = startport; p <= node->numports; p++) {
316                 if (node->ports[p]) {
317                         print_port(node, p, &header_printed);
318                 }
319         }
320 }
321
322 static void
323 add_suppressed(enum MAD_FIELDS field)
324 {
325         suppressed_fields = realloc(suppressed_fields, sizeof(enum MAD_FIELDS));
326         suppressed_fields[sup_total] = field;
327         sup_total++;
328 }
329
330 static void
331 calculate_suppressed_fields(char *str)
332 {
333         enum MAD_FIELDS f;
334         char *val, *lasts = NULL;
335         char *tmp = strdup(str);
336
337         val = strtok_r(tmp, ",", &lasts);
338         while (val) {
339                 for (f = IB_PC_FIRST_F; f <= IB_PC_LAST_F; f++) {
340                         if (strcmp(val, mad_field_name(f)) == 0) {
341                                 add_suppressed(f);
342                         }
343                 }
344                 val = strtok_r(NULL, ",", &lasts);
345         }
346
347         free(tmp);
348 }
349
350 static int process_opt(void *context, int ch, char *optarg)
351 {
352         switch (ch) {
353         case 's':
354                 calculate_suppressed_fields(optarg);
355                 break;
356         case 'c':
357                 /* Right now this is the only "common" error */
358                 add_suppressed(IB_PC_ERR_SWITCH_REL_F);
359                 break;
360         case 1:
361                 node_name_map_file = strdup(optarg);
362                 break;
363         case 2:
364                 data_counters++;
365                 break;
366         case 3:
367                 all_nodes++;
368                 break;
369         case 'S':
370                 switch_guid_str = optarg;
371                 switch_guid = strtoull(optarg, 0, 0);
372                 break;
373         case 'D':
374                 dr_path = strdup(optarg);
375                 break;
376         case 'r':
377                 port_config++;
378                 break;
379         case 'R': /* nop */
380                 break;
381         default:
382                 return -1;
383         }
384
385         return 0;
386 }
387
388 int
389 main(int argc, char **argv)
390 {
391         int rc = 0;
392         ibnd_fabric_t *fabric = NULL;
393
394         int mgmt_classes[4] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS, IB_PERFORMANCE_CLASS};
395
396         const struct ibdiag_opt opts[] = {
397                 { "suppress", 's', 1, "<err1,err2,...>", "suppress errors listed" },
398                 { "suppress-common", 'c', 0, NULL, "suppress some of the common counters" },
399                 { "node-name-map", 1, 1, "<file>", "node name map file" },
400                 { "switch", 'S', 1, "<switch_guid>", "query only <switch_guid> (hex format)"},
401                 { "Direct", 'D', 1, "<dr_path>", "query only switch specified by <dr_path>"},
402                 { "report-port", 'r', 0, NULL, "report port configuration information"},
403                 { "GNDN", 'R', 0, NULL, "(This option is obsolete and does nothing)"},
404                 { "data", 2, 0, NULL, "include the data counters in the output"},
405                 { "all", 3, 0, NULL, "output all nodes (not just switches)"},
406                 { 0 }
407         };
408         char usage_args[] = "";
409
410         ibdiag_process_opts(argc, argv, "sDLG", "snSrR", opts, process_opt,
411                             usage_args, NULL);
412
413         argc -= optind;
414         argv += optind;
415
416         if (ibverbose)
417                 ibnd_debug(1);
418
419         ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 4);
420         if (!ibmad_port)
421                 IBERROR("Failed to open port; %s:%d\n", ibd_ca, ibd_ca_port);
422
423         node_name_map = open_node_name_map(node_name_map_file);
424
425         if (switch_guid) {
426                 /* limit the scan the fabric around the target */
427                 ib_portid_t portid = {0};
428
429                 if (ib_resolve_portid_str_via(&portid, switch_guid_str, IB_DEST_GUID,
430                                         ibd_sm_id, ibmad_port) >= 0) {
431                         if ((fabric = ibnd_discover_fabric(ibmad_port, ibd_timeout, &portid, 1)) == NULL)
432                                 IBWARN("Single node discover failed; attempting full scan\n");
433                 } else
434                         IBWARN("Failed to resolve %s; attempting full scan\n", switch_guid_str);
435         }
436
437         if (!fabric) /* do a full scan */
438                 if ((fabric = ibnd_discover_fabric(ibmad_port, ibd_timeout, NULL, -1)) == NULL) {
439                         fprintf(stderr, "discover failed\n");
440                         rc = 1;
441                         goto close_port;
442                 }
443
444         report_suppressed();
445
446         if (switch_guid) {
447                 ibnd_node_t *node = ibnd_find_node_guid(fabric, switch_guid);
448                 print_node(node, NULL);
449         } else if (dr_path) {
450                 ibnd_node_t *node = ibnd_find_node_dr(fabric, dr_path);
451                 print_node(node, NULL);
452         } else
453                 ibnd_iter_nodes(fabric, print_node, NULL);
454
455         ibnd_destroy_fabric(fabric);
456
457 close_port:
458         mad_rpc_close_port(ibmad_port);
459         close_node_name_map(node_name_map);
460         exit(rc);
461 }