]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/infiniband-diags/src/ibqueryerrors.c
Merge compiler-rt trunk r366426, resolve conflicts, and add
[FreeBSD/FreeBSD.git] / contrib / ofed / infiniband-diags / src / ibqueryerrors.c
1 /*
2  * Copyright (c) 2004-2009 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  * Copyright (c) 2009 HNR Consulting.  All rights reserved.
6  * Copyright (c) 2010,2011 Mellanox Technologies LTD.  All rights reserved.
7  *
8  * This software is available to you under a choice of one of two
9  * licenses.  You may choose to be licensed under the terms of the GNU
10  * General Public License (GPL) Version 2, available from the file
11  * COPYING in the main directory of this source tree, or the
12  * OpenIB.org BSD license below:
13  *
14  *     Redistribution and use in source and binary forms, with or
15  *     without modification, are permitted provided that the following
16  *     conditions are met:
17  *
18  *      - Redistributions of source code must retain the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer.
21  *
22  *      - Redistributions in binary form must reproduce the above
23  *        copyright notice, this list of conditions and the following
24  *        disclaimer in the documentation and/or other materials
25  *        provided with the distribution.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
31  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34  * SOFTWARE.
35  *
36  */
37
38 #if HAVE_CONFIG_H
39 #  include <config.h>
40 #endif                          /* HAVE_CONFIG_H */
41
42 #define _GNU_SOURCE
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include <stdarg.h>
47 #include <time.h>
48 #include <string.h>
49 #include <getopt.h>
50 #include <errno.h>
51 #include <inttypes.h>
52
53 #include <complib/cl_nodenamemap.h>
54 #include <infiniband/ibnetdisc.h>
55 #include <infiniband/mad.h>
56
57 #include "ibdiag_common.h"
58 #include "ibdiag_sa.h"
59
60 struct ibmad_port *ibmad_port;
61 static char *node_name_map_file = NULL;
62 static nn_map_t *node_name_map = NULL;
63 static char *load_cache_file = NULL;
64 static uint16_t lid2sl_table[sizeof(uint8_t) * 1024 * 48] = { 0 };
65 static int obtain_sl = 1;
66
67 int data_counters = 0;
68 int data_counters_only = 0;
69 int port_config = 0;
70 uint64_t port_guid = 0;
71 char *port_guid_str = NULL;
72 #define SUP_MAX 64
73 int sup_total = 0;
74 enum MAD_FIELDS suppressed_fields[SUP_MAX];
75 char *dr_path = NULL;
76 uint8_t node_type_to_print = 0;
77 unsigned clear_errors = 0, clear_counts = 0, details = 0;
78
79 #define PRINT_SWITCH 0x1
80 #define PRINT_CA     0x2
81 #define PRINT_ROUTER 0x4
82 #define PRINT_ALL 0xFF          /* all nodes default flag */
83
84 #define DEFAULT_HALF_WORLD_PR_TIMEOUT (3000)
85
86 struct {
87         int nodes_checked;
88         int bad_nodes;
89         int ports_checked;
90         int bad_ports;
91         int pma_query_failures;
92 } summary = { 0 };
93
94 #define DEF_THRES_FILE IBDIAG_CONFIG_PATH"/error_thresholds"
95 static char *threshold_file = DEF_THRES_FILE;
96
97 /* define a "packet" with threshold values in it */
98 uint8_t thresholds[1204] = { 0 };
99 char * threshold_str = "";
100
101 static unsigned valid_gid(ib_gid_t * gid)
102 {
103         ib_gid_t zero_gid;
104         memset(&zero_gid, 0, sizeof zero_gid);
105         return memcmp(&zero_gid, gid, sizeof(*gid));
106 }
107
108 static void set_thres(char *name, uint32_t val)
109 {
110         int f;
111         int n;
112         char tmp[256];
113         for (f = IB_PC_FIRST_F; f <= IB_PC_LAST_F; f++) {
114                 if (strcmp(name, mad_field_name(f)) == 0) {
115                         mad_encode_field(thresholds, f, &val);
116                         snprintf(tmp, 255, "[%s = %u]", name, val);
117                         threshold_str = realloc(threshold_str,
118                                         strlen(threshold_str)+strlen(tmp)+1);
119                         if (!threshold_str) {
120                                 fprintf(stderr, "Failed to allocate memory: "
121                                         "%s\n", strerror(errno));
122                                 exit(1);
123                         }
124                         n = strlen(threshold_str);
125                         strcpy(threshold_str+n, tmp);
126                 }
127         }
128 }
129
130 static void set_thresholds(char *threshold_file)
131 {
132         char buf[1024];
133         int val = 0;
134         FILE *thresf = fopen(threshold_file, "r");
135         char *p_prefix, *p_last;
136         char *name;
137         char *val_str;
138         char str[64];
139
140         if (!thresf)
141                 return;
142
143         snprintf(str, 63, "Thresholds: ");
144         threshold_str = malloc(strlen(str)+1);
145         if (!threshold_str) {
146                 fprintf(stderr, "Failed to allocate memory: %s\n",
147                         strerror(errno));
148                 exit(1);
149         }
150         strcpy(threshold_str, str);
151         while (fgets(buf, sizeof buf, thresf) != NULL) {
152                 p_prefix = strtok_r(buf, "\n", &p_last);
153                 if (!p_prefix)
154                         continue; /* ignore blank lines */
155
156                 if (*p_prefix == '#')
157                         continue; /* ignore comment lines */
158
159                 name = strtok_r(p_prefix, "=", &p_last);
160                 val_str = strtok_r(NULL, "\n", &p_last);
161
162                 val = strtoul(val_str, NULL, 0);
163                 set_thres(name, val);
164         }
165
166         fclose(thresf);
167 }
168
169 static int exceeds_threshold(int field, unsigned val)
170 {
171         uint32_t thres = 0;
172         mad_decode_field(thresholds, field, &thres);
173         return (val > thres);
174 }
175
176 static void print_port_config(ibnd_node_t * node, int portnum)
177 {
178         char width[64], speed[64], state[64], physstate[64];
179         char remote_str[256];
180         char link_str[256];
181         char width_msg[256];
182         char speed_msg[256];
183         char ext_port_str[256];
184         int iwidth, ispeed, fdr10, espeed, istate, iphystate, cap_mask;
185         uint8_t *info;
186
187         ibnd_port_t *port = node->ports[portnum];
188
189         if (!port)
190                 return;
191
192         iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F);
193         ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F);
194         fdr10 = mad_get_field(port->ext_info, 0,
195                               IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F) & FDR10;
196
197         if (port->node->type == IB_NODE_SWITCH)
198                 info = (uint8_t *)&port->node->ports[0]->info;
199         else
200                 info = (uint8_t *)&port->info;
201         cap_mask = mad_get_field(info, 0, IB_PORT_CAPMASK_F);
202         if (cap_mask & CL_NTOH32(IB_PORT_CAP_HAS_EXT_SPEEDS))
203                 espeed = mad_get_field(port->info, 0,
204                                        IB_PORT_LINK_SPEED_EXT_ACTIVE_F);
205         else
206                 espeed = 0;
207         istate = mad_get_field(port->info, 0, IB_PORT_STATE_F);
208         iphystate = mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F);
209
210         remote_str[0] = '\0';
211         link_str[0] = '\0';
212         width_msg[0] = '\0';
213         speed_msg[0] = '\0';
214
215         /* C14-24.2.1 states that a down port allows for invalid data to be
216          * returned for all PortInfo components except PortState and
217          * PortPhysicalState */
218         if (istate != IB_LINK_DOWN) {
219                 if (!espeed) {
220                         if (fdr10)
221                                 sprintf(speed, "10.0 Gbps (FDR10)");
222                         else
223                                 mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, speed,
224                                              64, &ispeed);
225                 } else
226                         mad_dump_val(IB_PORT_LINK_SPEED_EXT_ACTIVE_F, speed,
227                              64, &espeed);
228
229                 snprintf(link_str, 256, "(%3s %18s %6s/%8s)",
230                          mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, width, 64, &iwidth),
231                          speed,
232                          mad_dump_val(IB_PORT_STATE_F, state, 64, &istate),
233                          mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64, &iphystate));
234         } else {
235                 snprintf(link_str, 256, "(              %6s/%8s)",
236                          mad_dump_val(IB_PORT_STATE_F, state, 64, &istate),
237                          mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64, &iphystate));
238         }
239
240         if (port->remoteport) {
241                 char *rem_node_name = NULL;
242
243                 if (port->remoteport->ext_portnum)
244                         snprintf(ext_port_str, 256, "%d",
245                                  port->remoteport->ext_portnum);
246                 else
247                         ext_port_str[0] = '\0';
248
249                 get_max_msg(width_msg, speed_msg, 256, port);
250
251                 rem_node_name = remap_node_name(node_name_map,
252                                                 port->remoteport->node->guid,
253                                                 port->remoteport->node->
254                                                 nodedesc);
255
256                 snprintf(remote_str, 256,
257                          "0x%016" PRIx64 " %6d %4d[%2s] \"%s\" (%s %s)\n",
258                          port->remoteport->guid,
259                          port->remoteport->base_lid ? port->remoteport->
260                          base_lid : port->remoteport->node->smalid,
261                          port->remoteport->portnum, ext_port_str, rem_node_name,
262                          width_msg, speed_msg);
263
264                 free(rem_node_name);
265         } else
266                 snprintf(remote_str, 256, "           [  ] \"\" ( )\n");
267
268         if (port->ext_portnum)
269                 snprintf(ext_port_str, 256, "%d", port->ext_portnum);
270         else
271                 ext_port_str[0] = '\0';
272
273         if (node->type == IB_NODE_SWITCH)
274                 printf("       Link info: %6d", node->smalid);
275         else
276                 printf("       Link info: %6d", port->base_lid);
277
278         printf("%4d[%2s] ==%s==>  %s",
279                port->portnum, ext_port_str, link_str, remote_str);
280 }
281
282 static int suppress(enum MAD_FIELDS field)
283 {
284         int i = 0;
285         for (i = 0; i < sup_total; i++)
286                 if (field == suppressed_fields[i])
287                         return 1;
288         return 0;
289 }
290
291 static void report_suppressed(void)
292 {
293         int i = 0;
294         printf("## Suppressed:");
295         for (i = 0; i < sup_total; i++)
296                 printf(" %s", mad_field_name(suppressed_fields[i]));
297         printf("\n");
298 }
299
300 static int print_summary(void)
301 {
302         printf("\n## Summary: %d nodes checked, %d bad nodes found\n",
303                 summary.nodes_checked, summary.bad_nodes);
304         printf("##          %d ports checked, %d ports have errors beyond threshold\n",
305                 summary.ports_checked, summary.bad_ports);
306         printf("## %s\n", threshold_str);
307         if (summary.pma_query_failures)
308                 printf("##          %d PMA query failures\n", summary.pma_query_failures);
309         report_suppressed();
310         return (summary.bad_ports);
311 }
312
313 static void insert_lid2sl_table(struct sa_query_result *r)
314 {
315     unsigned int i;
316     for (i = 0; i < r->result_cnt; i++) {
317             ib_path_rec_t *p_pr = (ib_path_rec_t *)sa_get_query_rec(r->p_result_madw, i);
318             lid2sl_table[cl_ntoh16(p_pr->dlid)] = ib_path_rec_sl(p_pr);
319     }
320 }
321
322 static int path_record_query(ib_gid_t sgid,uint64_t dguid)
323 {
324      ib_path_rec_t pr;
325      ib_net64_t comp_mask = 0;
326      uint8_t reversible = 0;
327      struct sa_handle * h;
328
329      if (!(h = sa_get_handle()))
330         return -1;
331
332      ibd_timeout = DEFAULT_HALF_WORLD_PR_TIMEOUT;
333      memset(&pr, 0, sizeof(pr));
334
335      CHECK_AND_SET_GID(sgid, pr.sgid, PR, SGID);
336      if(dguid) {
337              mad_encode_field(sgid.raw, IB_GID_GUID_F, &dguid);
338              CHECK_AND_SET_GID(sgid, pr.dgid, PR, DGID);
339      }
340
341      CHECK_AND_SET_VAL(1, 8, -1, pr.num_path, PR, NUMBPATH);/*to get only one PathRecord for each source and destination pair*/
342      CHECK_AND_SET_VAL(1, 8, -1, reversible, PR, REVERSIBLE);/*for a reversible path*/
343      pr.num_path |= reversible << 7;
344      struct sa_query_result result;
345      int ret = sa_query(h, IB_MAD_METHOD_GET_TABLE,
346                         (uint16_t)IB_SA_ATTR_PATHRECORD,0,cl_ntoh64(comp_mask),ibd_sakey,
347                         &pr, sizeof(pr), &result);
348      if (ret) {
349              sa_free_handle(h);
350              fprintf(stderr, "Query SA failed: %s; sa call path_query failed\n", strerror(ret));
351              return ret;
352      }
353      if (result.status != IB_SA_MAD_STATUS_SUCCESS) {
354              sa_report_err(result.status);
355              ret = EIO;
356              goto Exit;
357      }
358
359      insert_lid2sl_table(&result);
360 Exit:
361      sa_free_handle(h);
362      sa_free_result_mad(&result);
363      return ret;
364 }
365
366 static int query_and_dump(char *buf, size_t size, ib_portid_t * portid,
367                           char *node_name, int portnum,
368                           const char *attr_name, uint16_t attr_id,
369                           int start_field, int end_field)
370 {
371         uint8_t pc[1024];
372         uint32_t val = 0;
373         int i, n;
374
375         memset(pc, 0, sizeof(pc));
376
377         if (!pma_query_via(pc, portid, portnum, ibd_timeout, attr_id,
378                            ibmad_port)) {
379                 IBWARN("%s query failed on %s, %s port %d", attr_name,
380                        node_name, portid2str(portid), portnum);
381                 summary.pma_query_failures++;
382                 return 0;
383         }
384
385         for (n = 0, i = start_field; i < end_field; i++) {
386                 mad_decode_field(pc, i, (void *)&val);
387                 if (val)
388                         n += snprintf(buf + n, size - n, " [%s == %u]",
389                                       mad_field_name(i), val);
390         }
391
392         return n;
393 }
394
395
396 static int print_results(ib_portid_t * portid, char *node_name,
397                          ibnd_node_t * node, uint8_t * pc, int portnum,
398                          int *header_printed, uint8_t *pce, uint16_t cap_mask)
399 {
400         char buf[1024];
401         char *str = buf;
402         uint32_t val = 0;
403         int i, n;
404
405         for (n = 0, i = IB_PC_ERR_SYM_F; i <= IB_PC_VL15_DROPPED_F; i++) {
406                 if (suppress(i))
407                         continue;
408
409                 /* this is not a counter, skip it */
410                 if (i == IB_PC_COUNTER_SELECT2_F)
411                         continue;
412
413                 mad_decode_field(pc, i, (void *)&val);
414                 if (exceeds_threshold(i, val)) {
415                         n += snprintf(str + n, 1024 - n, " [%s == %u]",
416                                       mad_field_name(i), val);
417
418                         /* If there are PortXmitDiscards, get details (if supported) */
419                         if (i == IB_PC_XMT_DISCARDS_F && details) {
420                                 n += query_and_dump(str + n, sizeof(buf) - n, portid,
421                                                     node_name, portnum,
422                                                     "PortXmitDiscardDetails",
423                                                     IB_GSI_PORT_XMIT_DISCARD_DETAILS,
424                                                     IB_PC_RCV_LOCAL_PHY_ERR_F,
425                                                     IB_PC_RCV_ERR_LAST_F);
426                                 /* If there are PortRcvErrors, get details (if supported) */
427                         } else if (i == IB_PC_ERR_RCV_F && details) {
428                                 n += query_and_dump(str + n, sizeof(buf) - n, portid,
429                                                     node_name, portnum,
430                                                     "PortRcvErrorDetails",
431                                                     IB_GSI_PORT_RCV_ERROR_DETAILS,
432                                                     IB_PC_XMT_INACT_DISC_F,
433                                                     IB_PC_XMT_DISC_LAST_F);
434                         }
435                 }
436         }
437
438         if (!suppress(IB_PC_XMT_WAIT_F)) {
439                 mad_decode_field(pc, IB_PC_XMT_WAIT_F, (void *)&val);
440                 if (exceeds_threshold(IB_PC_XMT_WAIT_F, val))
441                         n += snprintf(str + n, 1024 - n, " [%s == %u]",
442                                       mad_field_name(IB_PC_XMT_WAIT_F), val);
443         }
444
445         /* if we found errors. */
446         if (n != 0) {
447                 if (data_counters) {
448                         uint8_t *pkt = pc;
449                         int start_field = IB_PC_XMT_BYTES_F;
450                         int end_field = IB_PC_RCV_PKTS_F;
451
452                         if (pce) {
453                                 pkt = pce;
454                                 start_field = IB_PC_EXT_XMT_BYTES_F;
455                                 if (cap_mask & IB_PM_EXT_WIDTH_SUPPORTED)
456                                         end_field = IB_PC_EXT_RCV_MPKTS_F;
457                                 else
458                                         end_field = IB_PC_EXT_RCV_PKTS_F;
459                         }
460
461                         for (i = start_field; i <= end_field; i++) {
462                                 uint64_t val64 = 0;
463                                 float val = 0;
464                                 char *unit = "";
465                                 mad_decode_field(pkt, i, (void *)&val64);
466                                 if (val64) {
467                                         int data = 0;
468                                         if (i == IB_PC_EXT_XMT_BYTES_F ||
469                                             i == IB_PC_EXT_RCV_BYTES_F ||
470                                             i == IB_PC_XMT_BYTES_F ||
471                                             i == IB_PC_RCV_BYTES_F)
472                                                 data = 1;
473                                         unit = conv_cnt_human_readable(val64,
474                                                                 &val, data);
475                                         n += snprintf(str + n, 1024 - n,
476                                                 " [%s == %" PRIu64
477                                                 " (%5.3f%s)]",
478                                                 mad_field_name(i), val64, val,
479                                                 unit);
480                                 }
481                         }
482                 }
483
484                 if (!*header_printed) {
485                         if (node->type == IB_NODE_SWITCH)
486                                 printf("Errors for 0x%" PRIx64 " \"%s\"\n",
487                                         node->ports[0]->guid, node_name);
488                         else
489                                 printf("Errors for \"%s\"\n", node_name);
490                         *header_printed = 1;
491                         summary.bad_nodes++;
492                 }
493
494                 if (portnum == 0xFF) {
495                         if (node->type == IB_NODE_SWITCH)
496                                 printf("   GUID 0x%" PRIx64 " port ALL:%s\n",
497                                        node->ports[0]->guid, str);
498                 } else {
499                         printf("   GUID 0x%" PRIx64 " port %d:%s\n",
500                                node->ports[portnum]->guid, portnum, str);
501                         if (port_config)
502                                 print_port_config(node, portnum);
503                         summary.bad_ports++;
504                 }
505         }
506         return (n);
507 }
508
509 static int query_cap_mask(ib_portid_t * portid, char *node_name, int portnum,
510                           uint16_t * cap_mask)
511 {
512         uint8_t pc[1024] = { 0 };
513         uint16_t rc_cap_mask;
514
515         portid->sl = lid2sl_table[portid->lid];
516
517         /* PerfMgt ClassPortInfo is a required attribute */
518         if (!pma_query_via(pc, portid, portnum, ibd_timeout, CLASS_PORT_INFO,
519                            ibmad_port)) {
520                 IBWARN("classportinfo query failed on %s, %s port %d",
521                        node_name, portid2str(portid), portnum);
522                 summary.pma_query_failures++;
523                 return -1;
524         }
525
526         /* ClassPortInfo should be supported as part of libibmad */
527         memcpy(&rc_cap_mask, pc + 2, sizeof(rc_cap_mask));      /* CapabilityMask */
528
529         *cap_mask = rc_cap_mask;
530         return 0;
531 }
532
533 static int print_data_cnts(ib_portid_t * portid, uint16_t cap_mask,
534                            char *node_name, ibnd_node_t * node, int portnum,
535                            int *header_printed)
536 {
537         uint8_t pc[1024];
538         int i;
539         int start_field = IB_PC_XMT_BYTES_F;
540         int end_field = IB_PC_RCV_PKTS_F;
541
542         memset(pc, 0, 1024);
543
544         portid->sl = lid2sl_table[portid->lid];
545
546         if (cap_mask & (IB_PM_EXT_WIDTH_SUPPORTED | IB_PM_EXT_WIDTH_NOIETF_SUP)) {
547                 if (!pma_query_via(pc, portid, portnum, ibd_timeout,
548                                    IB_GSI_PORT_COUNTERS_EXT, ibmad_port)) {
549                         IBWARN("IB_GSI_PORT_COUNTERS_EXT query failed on %s, %s port %d",
550                                node_name, portid2str(portid), portnum);
551                         summary.pma_query_failures++;
552                         return (1);
553                 }
554                 start_field = IB_PC_EXT_XMT_BYTES_F;
555                 if (cap_mask & IB_PM_EXT_WIDTH_SUPPORTED)
556                         end_field = IB_PC_EXT_RCV_MPKTS_F;
557                 else
558                         end_field = IB_PC_EXT_RCV_PKTS_F;
559         } else {
560                 if (!pma_query_via(pc, portid, portnum, ibd_timeout,
561                                    IB_GSI_PORT_COUNTERS, ibmad_port)) {
562                         IBWARN("IB_GSI_PORT_COUNTERS query failed on %s, %s port %d",
563                                node_name, portid2str(portid), portnum);
564                         summary.pma_query_failures++;
565                         return (1);
566                 }
567                 start_field = IB_PC_XMT_BYTES_F;
568                 end_field = IB_PC_RCV_PKTS_F;
569         }
570
571         if (!*header_printed) {
572                 printf("Data Counters for 0x%" PRIx64 " \"%s\"\n", node->guid,
573                        node_name);
574                 *header_printed = 1;
575         }
576
577         if (portnum == 0xFF)
578                 printf("   GUID 0x%" PRIx64 " port ALL:", node->guid);
579         else
580                 printf("   GUID 0x%" PRIx64 " port %d:",
581                        node->guid, portnum);
582
583         for (i = start_field; i <= end_field; i++) {
584                 uint64_t val64 = 0;
585                 float val = 0;
586                 char *unit = "";
587                 int data = 0;
588                 mad_decode_field(pc, i, (void *)&val64);
589                 if (i == IB_PC_EXT_XMT_BYTES_F || i == IB_PC_EXT_RCV_BYTES_F ||
590                     i == IB_PC_XMT_BYTES_F || i == IB_PC_RCV_BYTES_F)
591                         data = 1;
592                 unit = conv_cnt_human_readable(val64, &val, data);
593                 printf(" [%s == %" PRIu64 " (%5.3f%s)]", mad_field_name(i),
594                         val64, val, unit);
595         }
596         printf("\n");
597
598         if (portnum != 0xFF && port_config)
599                 print_port_config(node, portnum);
600
601         return (0);
602 }
603
604 static int print_errors(ib_portid_t * portid, uint16_t cap_mask,
605                         char *node_name, ibnd_node_t * node, int portnum,
606                         int *header_printed)
607 {
608         uint8_t pc[1024];
609         uint8_t pce[1024];
610         uint8_t *pc_ext = NULL;
611
612         memset(pc, 0, 1024);
613         memset(pce, 0, 1024);
614
615         portid->sl = lid2sl_table[portid->lid];
616
617         if (!pma_query_via(pc, portid, portnum, ibd_timeout,
618                            IB_GSI_PORT_COUNTERS, ibmad_port)) {
619                 IBWARN("IB_GSI_PORT_COUNTERS query failed on %s, %s port %d",
620                        node_name, portid2str(portid), portnum);
621                 summary.pma_query_failures++;
622                 return (0);
623         }
624
625         if (cap_mask & (IB_PM_EXT_WIDTH_SUPPORTED | IB_PM_EXT_WIDTH_NOIETF_SUP)) {
626                 if (!pma_query_via(pce, portid, portnum, ibd_timeout,
627                     IB_GSI_PORT_COUNTERS_EXT, ibmad_port)) {
628                         IBWARN("IB_GSI_PORT_COUNTERS_EXT query failed on %s, %s port %d",
629                                node_name, portid2str(portid), portnum);
630                         summary.pma_query_failures++;
631                         return (0);
632                 }
633                 pc_ext = pce;
634         }
635
636         if (!(cap_mask & IB_PM_PC_XMIT_WAIT_SUP)) {
637                 /* if PortCounters:PortXmitWait not supported clear this counter */
638                 uint32_t foo = 0;
639                 mad_encode_field(pc, IB_PC_XMT_WAIT_F, &foo);
640         }
641         return (print_results(portid, node_name, node, pc, portnum,
642                               header_printed, pc_ext, cap_mask));
643 }
644
645 uint8_t *reset_pc_ext(void *rcvbuf, ib_portid_t * dest,
646                       int port, unsigned mask, unsigned timeout,
647                       const struct ibmad_port * srcport)
648 {
649         ib_rpc_t rpc = { 0 };
650         int lid = dest->lid;
651
652         DEBUG("lid %u port %d mask 0x%x", lid, port, mask);
653
654         if (lid == -1) {
655                 IBWARN("only lid routed is supported");
656                 return NULL;
657         }
658
659         if (!mask)
660                 mask = ~0;
661
662         rpc.mgtclass = IB_PERFORMANCE_CLASS;
663         rpc.method = IB_MAD_METHOD_SET;
664         rpc.attr.id = IB_GSI_PORT_COUNTERS_EXT;
665
666         memset(rcvbuf, 0, IB_MAD_SIZE);
667
668         /* Same for attribute IDs */
669         mad_set_field(rcvbuf, 0, IB_PC_EXT_PORT_SELECT_F, port);
670         mad_set_field(rcvbuf, 0, IB_PC_EXT_COUNTER_SELECT_F, mask);
671         rpc.attr.mod = 0;
672         rpc.timeout = timeout;
673         rpc.datasz = IB_PC_DATA_SZ;
674         rpc.dataoffs = IB_PC_DATA_OFFS;
675         if (!dest->qp)
676                 dest->qp = 1;
677         if (!dest->qkey)
678                 dest->qkey = IB_DEFAULT_QP1_QKEY;
679
680         return mad_rpc(srcport, &rpc, dest, rcvbuf, rcvbuf);
681 }
682
683 static void clear_port(ib_portid_t * portid, uint16_t cap_mask,
684                        char *node_name, int port)
685 {
686         uint8_t pc[1024] = { 0 };
687         /* bits defined in Table 228 PortCounters CounterSelect and
688          * CounterSelect2
689          */
690         uint32_t mask = 0;
691
692         if (clear_errors) {
693                 mask |= 0xFFF;
694                 if (cap_mask & IB_PM_PC_XMIT_WAIT_SUP)
695                         mask |= 0x10000;
696         }
697         if (clear_counts)
698                 mask |= 0xF000;
699
700         if (mask)
701                 if (!performance_reset_via(pc, portid, port, mask, ibd_timeout,
702                                            IB_GSI_PORT_COUNTERS, ibmad_port))
703                         fprintf(stderr, "Failed to reset errors %s port %d\n", node_name,
704                                 port);
705
706         if (clear_errors && details) {
707                 memset(pc, 0, 1024);
708                 performance_reset_via(pc, portid, port, 0xf, ibd_timeout,
709                                       IB_GSI_PORT_XMIT_DISCARD_DETAILS,
710                                       ibmad_port);
711                 memset(pc, 0, 1024);
712                 performance_reset_via(pc, portid, port, 0x3f, ibd_timeout,
713                                       IB_GSI_PORT_RCV_ERROR_DETAILS,
714                                       ibmad_port);
715         }
716
717         if (clear_counts &&
718             (cap_mask &
719              (IB_PM_EXT_WIDTH_SUPPORTED | IB_PM_EXT_WIDTH_NOIETF_SUP))) {
720                 if (cap_mask & IB_PM_EXT_WIDTH_SUPPORTED)
721                         mask = 0xFF;
722                 else
723                         mask = 0x0F;
724
725                 if (!reset_pc_ext(pc, portid, port, mask, ibd_timeout,
726                     ibmad_port))
727                         fprintf(stderr, "Failed to reset extended data counters %s, "
728                                 "%s port %d\n", node_name, portid2str(portid),
729                                 port);
730         }
731 }
732
733 void print_node(ibnd_node_t * node, void *user_data)
734 {
735         int header_printed = 0;
736         int p = 0;
737         int startport = 1;
738         int type = 0;
739         int all_port_sup = 0;
740         ib_portid_t portid = { 0 };
741         uint16_t cap_mask = 0;
742         char *node_name = NULL;
743
744         switch (node->type) {
745         case IB_NODE_SWITCH:
746                 type = PRINT_SWITCH;
747                 break;
748         case IB_NODE_CA:
749                 type = PRINT_CA;
750                 break;
751         case IB_NODE_ROUTER:
752                 type = PRINT_ROUTER;
753                 break;
754         }
755
756         if ((type & node_type_to_print) == 0)
757                 return;
758
759         if (node->type == IB_NODE_SWITCH && node->smaenhsp0)
760                 startport = 0;
761
762         node_name = remap_node_name(node_name_map, node->guid, node->nodedesc);
763
764         if (node->type == IB_NODE_SWITCH) {
765                 ib_portid_set(&portid, node->smalid, 0, 0);
766                 p = 0;
767         } else {
768                 for (p = 1; p <= node->numports; p++) {
769                         if (node->ports[p]) {
770                                 ib_portid_set(&portid,
771                                               node->ports[p]->base_lid,
772                                               0, 0);
773                                 break;
774                         }
775                 }
776         }
777
778         if ((query_cap_mask(&portid, node_name, p, &cap_mask) == 0) &&
779             (cap_mask & IB_PM_ALL_PORT_SELECT))
780                 all_port_sup = 1;
781
782         if (data_counters_only) {
783                 for (p = startport; p <= node->numports; p++) {
784                         if (node->ports[p]) {
785                                 if (node->type == IB_NODE_SWITCH)
786                                         ib_portid_set(&portid, node->smalid, 0, 0);
787                                 else
788                                         ib_portid_set(&portid, node->ports[p]->base_lid,
789                                                       0, 0);
790
791                                 print_data_cnts(&portid, cap_mask, node_name, node, p,
792                                                 &header_printed);
793                                 summary.ports_checked++;
794                                 if (!all_port_sup)
795                                         clear_port(&portid, cap_mask, node_name, p);
796                         }
797                 }
798         } else {
799                 if (all_port_sup)
800                         if (!print_errors(&portid, cap_mask, node_name, node,
801                                           0xFF, &header_printed)) {
802                                 summary.ports_checked += node->numports;
803                                 goto clear;
804                         }
805
806                 for (p = startport; p <= node->numports; p++) {
807                         if (node->ports[p]) {
808                                 if (node->type == IB_NODE_SWITCH)
809                                         ib_portid_set(&portid, node->smalid, 0, 0);
810                                 else
811                                         ib_portid_set(&portid, node->ports[p]->base_lid,
812                                                       0, 0);
813
814                                 print_errors(&portid, cap_mask, node_name, node, p,
815                                              &header_printed);
816                                 summary.ports_checked++;
817                                 if (!all_port_sup)
818                                         clear_port(&portid, cap_mask, node_name, p);
819                         }
820                 }
821         }
822
823 clear:
824         summary.nodes_checked++;
825         if (all_port_sup)
826                 clear_port(&portid, cap_mask, node_name, 0xFF);
827
828         free(node_name);
829 }
830
831 static void add_suppressed(enum MAD_FIELDS field)
832 {
833         if (sup_total >= SUP_MAX) {
834                 IBWARN("Maximum (%d) fields have been suppressed; skipping %s",
835                        sup_total, mad_field_name(field));
836                 return;
837         }
838         suppressed_fields[sup_total++] = field;
839 }
840
841 static void calculate_suppressed_fields(char *str)
842 {
843         enum MAD_FIELDS f;
844         char *val, *lasts = NULL;
845         char *tmp = strdup(str);
846
847         val = strtok_r(tmp, ",", &lasts);
848         while (val) {
849                 for (f = IB_PC_FIRST_F; f <= IB_PC_LAST_F; f++)
850                         if (strcmp(val, mad_field_name(f)) == 0)
851                                 add_suppressed(f);
852                 val = strtok_r(NULL, ",", &lasts);
853         }
854
855         free(tmp);
856 }
857
858 static int process_opt(void *context, int ch, char *optarg)
859 {
860         struct ibnd_config *cfg = context;
861         switch (ch) {
862         case 's':
863                 calculate_suppressed_fields(optarg);
864                 break;
865         case 'c':
866                 /* Right now this is the only "common" error */
867                 add_suppressed(IB_PC_ERR_SWITCH_REL_F);
868                 break;
869         case 1:
870                 node_name_map_file = strdup(optarg);
871                 break;
872         case 2:
873                 data_counters++;
874                 break;
875         case 3:
876                 node_type_to_print |= PRINT_SWITCH;
877                 break;
878         case 4:
879                 node_type_to_print |= PRINT_CA;
880                 break;
881         case 5:
882                 node_type_to_print |= PRINT_ROUTER;
883                 break;
884         case 6:
885                 details = 1;
886                 break;
887         case 7:
888                 load_cache_file = strdup(optarg);
889                 break;
890         case 8:
891                 threshold_file = strdup(optarg);
892                 break;
893         case 9:
894                 data_counters_only = 1;
895                 break;
896         case 10:
897                 obtain_sl = 0;
898                 break;
899         case 'G':
900         case 'S':
901                 port_guid_str = optarg;
902                 port_guid = strtoull(optarg, 0, 0);
903                 break;
904         case 'D':
905                 dr_path = strdup(optarg);
906                 break;
907         case 'r':
908                 port_config++;
909                 break;
910         case 'R':               /* nop */
911                 break;
912         case 'k':
913                 clear_errors = 1;
914                 break;
915         case 'K':
916                 clear_counts = 1;
917                 break;
918         case 'o':
919                 cfg->max_smps = strtoul(optarg, NULL, 0);
920                 break;
921         default:
922                 return -1;
923         }
924
925         return 0;
926 }
927
928 int main(int argc, char **argv)
929 {
930         struct ibnd_config config = { 0 };
931         int resolved = -1;
932         ib_portid_t portid = { 0 };
933         ib_portid_t self_portid = { 0 };
934         int rc = 0;
935         ibnd_fabric_t *fabric = NULL;
936         ib_gid_t self_gid;
937         int port = 0;
938
939         int mgmt_classes[4] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS,
940                 IB_PERFORMANCE_CLASS
941         };
942
943         const struct ibdiag_opt opts[] = {
944                 {"suppress", 's', 1, "<err1,err2,...>",
945                  "suppress errors listed"},
946                 {"suppress-common", 'c', 0, NULL,
947                  "suppress some of the common counters"},
948                 {"node-name-map", 1, 1, "<file>", "node name map file"},
949                 {"port-guid", 'G', 1, "<port_guid>",
950                  "report the node containing the port specified by <port_guid>"},
951                 {"", 'S', 1, "<port_guid>",
952                  "Same as \"-G\" for backward compatibility"},
953                 {"Direct", 'D', 1, "<dr_path>",
954                  "report the node containing the port specified by <dr_path>"},
955                 {"skip-sl", 10, 0, NULL,"don't obtain SL to all destinations"},
956                 {"report-port", 'r', 0, NULL,
957                  "report port link information"},
958                 {"threshold-file", 8, 1, NULL,
959                  "specify an alternate threshold file, default: " DEF_THRES_FILE},
960                 {"GNDN", 'R', 0, NULL,
961                  "(This option is obsolete and does nothing)"},
962                 {"data", 2, 0, NULL, "include data counters for ports with errors"},
963                 {"switch", 3, 0, NULL, "print data for switches only"},
964                 {"ca", 4, 0, NULL, "print data for CA's only"},
965                 {"router", 5, 0, NULL, "print data for routers only"},
966                 {"details", 6, 0, NULL, "include transmit discard details"},
967                 {"counters", 9, 0, NULL, "print data counters only"},
968                 {"clear-errors", 'k', 0, NULL,
969                  "Clear error counters after read"},
970                 {"clear-counts", 'K', 0, NULL,
971                  "Clear data counters after read"},
972                 {"load-cache", 7, 1, "<file>",
973                  "filename of ibnetdiscover cache to load"},
974                 {"outstanding_smps", 'o', 1, NULL,
975                  "specify the number of outstanding SMP's which should be "
976                  "issued during the scan"},
977                 {0}
978         };
979         char usage_args[] = "";
980
981         memset(suppressed_fields, 0, sizeof suppressed_fields);
982         ibdiag_process_opts(argc, argv, &config, "cDGKLnRrSs", opts, process_opt,
983                             usage_args, NULL);
984
985         argc -= optind;
986         argv += optind;
987
988         if (!node_type_to_print)
989                 node_type_to_print = PRINT_ALL;
990
991         ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 4);
992         if (!ibmad_port)
993                 IBEXIT("Failed to open port; %s:%d\n", ibd_ca, ibd_ca_port);
994
995         smp_mkey_set(ibmad_port, ibd_mkey);
996
997         if (ibd_timeout) {
998                 mad_rpc_set_timeout(ibmad_port, ibd_timeout);
999                 config.timeout_ms = ibd_timeout;
1000         }
1001
1002         config.flags = ibd_ibnetdisc_flags;
1003         config.mkey = ibd_mkey;
1004
1005         if (dr_path && load_cache_file) {
1006                 mad_rpc_close_port(ibmad_port);
1007                 fprintf(stderr, "Cannot specify cache and direct route path\n");
1008                 exit(-1);
1009         }
1010
1011         if (resolve_self(ibd_ca, ibd_ca_port, &self_portid, &port, &self_gid.raw) < 0) {
1012                 mad_rpc_close_port(ibmad_port);
1013                 IBEXIT("can't resolve self port %s", argv[0]);
1014         }
1015
1016         node_name_map = open_node_name_map(node_name_map_file);
1017
1018         /* limit the scan the fabric around the target */
1019         if (dr_path) {
1020                 if ((resolved =
1021                      resolve_portid_str(ibd_ca, ibd_ca_port, &portid, dr_path,
1022                                         IB_DEST_DRPATH, NULL, ibmad_port)) < 0)
1023                         IBWARN("Failed to resolve %s; attempting full scan",
1024                                dr_path);
1025         } else if (port_guid_str) {
1026                 if ((resolved =
1027                      resolve_portid_str(ibd_ca, ibd_ca_port, &portid,
1028                                         port_guid_str, IB_DEST_GUID, ibd_sm_id,
1029                                                ibmad_port)) < 0)
1030                         IBWARN("Failed to resolve %s; attempting full scan",
1031                                port_guid_str);
1032                 if(obtain_sl)
1033                         lid2sl_table[portid.lid] = portid.sl;
1034         }
1035
1036         mad_rpc_close_port(ibmad_port);
1037
1038         if (load_cache_file) {
1039                 if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL) {
1040                         fprintf(stderr, "loading cached fabric failed\n");
1041                         rc = -1;
1042                         goto close_port;
1043                 }
1044         } else {
1045                 if (resolved >= 0) {
1046                         if (!config.max_hops)
1047                                 config.max_hops = 1;
1048                         if (!(fabric = ibnd_discover_fabric(ibd_ca, ibd_ca_port,
1049                                                     &portid, &config)))
1050                                 IBWARN("Single node discover failed;"
1051                                        " attempting full scan");
1052                 }
1053
1054                 if (!fabric && !(fabric = ibnd_discover_fabric(ibd_ca,
1055                                                                ibd_ca_port,
1056                                                                NULL,
1057                                                                &config))) {
1058                         fprintf(stderr, "discover failed\n");
1059                         rc = -1;
1060                         goto close_port;
1061                 }
1062         }
1063
1064         set_thresholds(threshold_file);
1065
1066         /* reopen the global ibmad_port */
1067         ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port,
1068                                        mgmt_classes, 4);
1069         if (!ibmad_port) {
1070                 ibnd_destroy_fabric(fabric);
1071                 close_node_name_map(node_name_map);
1072                 IBEXIT("Failed to reopen port: %s:%d\n",
1073                         ibd_ca, ibd_ca_port);
1074         }
1075
1076         smp_mkey_set(ibmad_port, ibd_mkey);
1077
1078         if (ibd_timeout)
1079                 mad_rpc_set_timeout(ibmad_port, ibd_timeout);
1080
1081         if (port_guid_str) {
1082                 ibnd_port_t *port = ibnd_find_port_guid(fabric, port_guid);
1083                 if (port)
1084                         print_node(port->node, NULL);
1085                 else
1086                         fprintf(stderr, "Failed to find node: %s\n",
1087                                 port_guid_str);
1088         } else if (dr_path) {
1089                 ibnd_port_t *port;
1090                 uint8_t ni[IB_SMP_DATA_SIZE] = { 0 };
1091                 if (!smp_query_via(ni, &portid, IB_ATTR_NODE_INFO, 0,
1092                            ibd_timeout, ibmad_port)) {
1093                                 fprintf(stderr, "Failed to query local Node Info\n");
1094                                 goto destroy_fabric;
1095                 }
1096
1097                 mad_decode_field(ni, IB_NODE_PORT_GUID_F, &(port_guid));
1098
1099                 port = ibnd_find_port_guid(fabric, port_guid);
1100                 if (port) {
1101                         if(obtain_sl)
1102                                 if(path_record_query(self_gid,port->guid))
1103                                         goto destroy_fabric;
1104                         print_node(port->node, NULL);
1105                 } else
1106                         fprintf(stderr, "Failed to find node: %s\n", dr_path);
1107         } else {
1108                 if(obtain_sl)
1109                         if(path_record_query(self_gid,0))
1110                                 goto destroy_fabric;
1111
1112                 ibnd_iter_nodes(fabric, print_node, NULL);
1113         }
1114
1115         rc = print_summary();
1116         if (rc)
1117                 rc = 1;
1118
1119 destroy_fabric:
1120         mad_rpc_close_port(ibmad_port);
1121         ibnd_destroy_fabric(fabric);
1122
1123 close_port:
1124         close_node_name_map(node_name_map);
1125         exit(rc);
1126 }