09861befa16ff02155090ceb7e9772fa86b7cd01
[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         int n = 0;
127
128         ibnd_port_t *port = node->ports[portnum];
129
130         if (!port)
131                 return;
132
133         iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F);
134         ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F);
135         istate = mad_get_field(port->info, 0, IB_PORT_STATE_F);
136         iphystate = mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F);
137
138         remote_str[0] = '\0';
139         link_str[0] = '\0';
140         width_msg[0] = '\0';
141         speed_msg[0] = '\0';
142
143         n = snprintf(link_str, 256, "(%3s %s %6s/%8s)",
144                 mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, width, 64, &iwidth),
145                 mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, speed, 64, &ispeed),
146                 mad_dump_val(IB_PORT_STATE_F, state, 64, &istate),
147                 mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64, &iphystate));
148
149         if (port->remoteport) {
150                 char *remap = remap_node_name(node_name_map, port->remoteport->node->guid,
151                                 port->remoteport->node->nodedesc);
152
153                 if (port->remoteport->ext_portnum)
154                         snprintf(ext_port_str, 256, "%d", port->remoteport->ext_portnum);
155                 else
156                         ext_port_str[0] = '\0';
157
158                 get_msg(width_msg, speed_msg, 256, port);
159
160                 snprintf(remote_str, 256,
161                         "0x%016"PRIx64" %6d %4d[%2s] \"%s\" (%s %s)\n",
162                         port->remoteport->node->guid,
163                         port->remoteport->base_lid ?  port->remoteport->base_lid :
164                                 port->remoteport->node->smalid,
165                         port->remoteport->portnum,
166                         ext_port_str,
167                         remap,
168                         width_msg,
169                         speed_msg);
170                 free(remap);
171         } else
172                 snprintf(remote_str, 256, "           [  ] \"\" ( )\n");
173
174         if (port->ext_portnum)
175                 snprintf(ext_port_str, 256, "%d", port->ext_portnum);
176         else
177                 ext_port_str[0] = '\0';
178
179         if (node->type == IB_NODE_SWITCH)
180                 printf("       %6d", node->smalid);
181         else
182                 printf("       %6d", port->base_lid);
183
184         printf("%4d[%2s] ==%s==>  %s",
185                 port->portnum, ext_port_str, link_str, remote_str);
186 }
187
188 static int
189 suppress(enum MAD_FIELDS field)
190 {
191         int i = 0;
192         if (suppressed_fields)
193                 for (i = 0; i < sup_total; i++) {
194                         if (field == suppressed_fields[i])
195                                 return (1);
196                 }
197         return (0);
198 }
199
200 static void
201 report_suppressed(void)
202 {
203         int i = 0;
204         if (suppressed_fields) {
205                 printf("Suppressing:");
206                 for (i = 0; i < sup_total; i++) {
207                         printf(" %s", mad_field_name(suppressed_fields[i]));
208                 }
209                 printf("\n");
210         }
211 }
212
213 static void
214 print_results(ibnd_node_t *node, uint8_t *pc, int portnum)
215 {
216         char buf[1024];
217         char *str = buf;
218         uint32_t val = 0;
219         int n = 0;
220         int i = 0;
221
222         for (n = 0, i = IB_PC_ERR_SYM_F; i <= IB_PC_VL15_DROPPED_F; i++) {
223                 if (suppress(i))
224                         continue;
225
226                 mad_decode_field(pc, i, (void *)&val);
227                 if (val)
228                         n += snprintf(str+n, 1024-n, " [%s == %d]",
229                                 mad_field_name(i), val);
230         }
231
232         if (!suppress(IB_PC_XMT_WAIT_F)) {
233                 mad_decode_field(pc, IB_PC_XMT_WAIT_F, (void *)&val);
234                 if (val)
235                         n += snprintf(str+n, 1024-n, " [%s == %d]", mad_field_name(i), val);
236         }
237
238         /* if we found errors. */
239         if (n != 0) {
240                 char *nodename = remap_node_name(node_name_map, node->guid, node->nodedesc);
241                 if (data_counters)
242                         for (i = IB_PC_XMT_BYTES_F; i <= IB_PC_RCV_PKTS_F; i++) {
243                                 uint64_t val64 = 0;
244                                 mad_decode_field(pc, i, (void *)&val64);
245                                 if (val64)
246                                         n += snprintf(str+n, 1024-n, " [%s == %"PRId64"]",
247                                                 mad_field_name(i), val64);
248                         }
249
250                 printf("Errors for 0x%" PRIx64 " \"%s\"\n", node->guid, nodename);
251                 printf("   GUID 0x%" PRIx64 " port %d:%s\n",
252                         node->guid, portnum, str);
253                 if (port_config)
254                         print_port_config(node, portnum);
255                 free(nodename);
256         }
257 }
258
259 static void
260 print_port(ibnd_node_t *node, int portnum)
261 {
262         uint8_t pc[1024];
263         uint16_t cap_mask;
264         ib_portid_t portid = {0};
265         char *nodename = remap_node_name(node_name_map, node->guid, node->nodedesc);
266
267         if (node->type == IB_NODE_SWITCH)
268                 ib_portid_set(&portid, node->smalid, 0, 0);
269         else
270                 ib_portid_set(&portid, node->ports[portnum]->base_lid, 0, 0);
271
272         /* PerfMgt ClassPortInfo is a required attribute */
273         if (!pma_query_via(pc, &portid, portnum, ibd_timeout, CLASS_PORT_INFO,
274                            ibmad_port)) {
275                 IBWARN("classportinfo query failed on %s, %s port %d",
276                         nodename, portid2str(&portid), portnum);
277                 goto cleanup;
278         }
279         /* ClassPortInfo should be supported as part of libibmad */
280         memcpy(&cap_mask, pc + 2, sizeof(cap_mask));    /* CapabilityMask */
281
282         if (!pma_query_via(pc, &portid, portnum, ibd_timeout,
283                                 IB_GSI_PORT_COUNTERS,
284                                 ibmad_port)) {
285                 IBWARN("IB_GSI_PORT_COUNTERS query failed on %s, %s port %d\n",
286                         nodename, portid2str(&portid), portnum);
287                 goto cleanup;
288         }
289         if (!(cap_mask & 0x1000)) {
290                 /* if PortCounters:PortXmitWait not suppported clear this counter */
291                 uint32_t foo = 0;
292                 mad_encode_field(pc, IB_PC_XMT_WAIT_F, &foo);
293         }
294         print_results(node, pc, portnum);
295
296 cleanup:
297         free(nodename);
298 }
299
300 void
301 print_node(ibnd_node_t *node, void *user_data)
302 {
303         int p = 0;
304         int startport = 1;
305
306         if (!all_nodes && node->type != IB_NODE_SWITCH)
307                 return;
308
309         if (node->type == IB_NODE_SWITCH && node->smaenhsp0)
310                 startport = 0;
311
312         for (p = startport; p <= node->numports; p++) {
313                 if (node->ports[p]) {
314                         print_port(node, p);
315                 }
316         }
317 }
318
319 static void
320 add_suppressed(enum MAD_FIELDS field)
321 {
322         suppressed_fields = realloc(suppressed_fields, sizeof(enum MAD_FIELDS));
323         suppressed_fields[sup_total] = field;
324         sup_total++;
325 }
326
327 static void
328 calculate_suppressed_fields(char *str)
329 {
330         enum MAD_FIELDS f;
331         char *val, *lasts = NULL;
332         char *tmp = strdup(str);
333
334         val = strtok_r(tmp, ",", &lasts);
335         while (val) {
336                 for (f = IB_PC_FIRST_F; f <= IB_PC_LAST_F; f++) {
337                         if (strcmp(val, mad_field_name(f)) == 0) {
338                                 add_suppressed(f);
339                         }
340                 }
341                 val = strtok_r(NULL, ",", &lasts);
342         }
343
344         free(tmp);
345 }
346
347 static int process_opt(void *context, int ch, char *optarg)
348 {
349         switch (ch) {
350         case 's':
351                 calculate_suppressed_fields(optarg);
352                 break;
353         case 'c':
354                 /* Right now this is the only "common" error */
355                 add_suppressed(IB_PC_ERR_SWITCH_REL_F);
356                 break;
357         case 1:
358                 node_name_map_file = strdup(optarg);
359                 break;
360         case 2:
361                 data_counters++;
362                 break;
363         case 3:
364                 all_nodes++;
365                 break;
366         case 'S':
367                 switch_guid_str = optarg;
368                 switch_guid = strtoull(optarg, 0, 0);
369                 break;
370         case 'D':
371                 dr_path = strdup(optarg);
372                 break;
373         case 'r':
374                 port_config++;
375                 break;
376         case 'R': /* nop */
377                 break;
378         default:
379                 return -1;
380         }
381
382         return 0;
383 }
384
385 int
386 main(int argc, char **argv)
387 {
388         int rc = 0;
389         ibnd_fabric_t *fabric = NULL;
390
391         int mgmt_classes[4] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS, IB_PERFORMANCE_CLASS};
392
393         const struct ibdiag_opt opts[] = {
394                 { "suppress", 's', 1, "<err1,err2,...>", "suppress errors listed" },
395                 { "suppress-common", 'c', 0, NULL, "suppress some of the common counters" },
396                 { "node-name-map", 1, 1, "<file>", "node name map file" },
397                 { "switch", 'S', 1, "<switch_guid>", "query only <switch_guid> (hex format)"},
398                 { "Direct", 'D', 1, "<dr_path>", "query only switch specified by <dr_path>"},
399                 { "report-port", 'r', 0, NULL, "report port configuration information"},
400                 { "GNDN", 'R', 0, NULL, "(This option is obsolete and does nothing)"},
401                 { "data", 2, 0, NULL, "include the data counters in the output"},
402                 { "all", 3, 0, NULL, "output all nodes (not just switches)"},
403                 { 0 }
404         };
405         char usage_args[] = "";
406
407         ibdiag_process_opts(argc, argv, "sDLG", "snSrR", opts, process_opt,
408                             usage_args, NULL);
409
410         argc -= optind;
411         argv += optind;
412
413         if (ibverbose)
414                 ibnd_debug(1);
415
416         ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 4);
417         if (!ibmad_port)
418                 IBERROR("Failed to open port; %s:%d\n", ibd_ca, ibd_ca_port);
419
420         node_name_map = open_node_name_map(node_name_map_file);
421
422         if (switch_guid) {
423                 /* limit the scan the fabric around the target */
424                 ib_portid_t portid = {0};
425
426                 if (ib_resolve_portid_str_via(&portid, switch_guid_str, IB_DEST_GUID,
427                                         ibd_sm_id, ibmad_port) < 0) {
428                         fprintf(stderr, "can't resolve destination port %s %p\n",
429                                 switch_guid_str, ibd_sm_id);
430                         rc = 1;
431                         goto close_port;
432                 }
433
434                 if ((fabric = ibnd_discover_fabric(ibmad_port, ibd_timeout, &portid, 1)) == NULL) {
435                         fprintf(stderr, "discover failed\n");
436                         rc = 1;
437                         goto close_port;
438                 }
439         } else {
440                 if ((fabric = ibnd_discover_fabric(ibmad_port, ibd_timeout, NULL, -1)) == NULL) {
441                         fprintf(stderr, "discover failed\n");
442                         rc = 1;
443                         goto close_port;
444                 }
445         }
446
447         report_suppressed();
448
449         if (switch_guid) {
450                 ibnd_node_t *node = ibnd_find_node_guid(fabric, switch_guid);
451                 print_node(node, NULL);
452         } else if (dr_path) {
453                 ibnd_node_t *node = ibnd_find_node_dr(fabric, dr_path);
454                 print_node(node, NULL);
455         } else
456                 ibnd_iter_nodes(fabric, print_node, NULL);
457
458         ibnd_destroy_fabric(fabric);
459
460 close_port:
461         mad_rpc_close_port(ibmad_port);
462         close_node_name_map(node_name_map);
463         exit(rc);
464 }