[ofw] [PATCH] ib-diags: update to latest version

Hefty, Sean sean.hefty at intel.com
Wed Jun 2 12:52:08 PDT 2010


Update to git commit 4a55423059e76ccba95aed36dd256510082b1e27

Direct update - all needed changes submitted back to linux
maintainer.

Signed-off-by: Sean Hefty <sean.hefty at intel.com>
---
Index: tools/infiniband-diags/include/ibdiag_common.h
===================================================================
--- tools/infiniband-diags/include/ibdiag_common.h      (revision 2812)
+++ tools/infiniband-diags/include/ibdiag_common.h      (working copy)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2006-2007 The Regents of the University of California.
- * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -50,10 +50,10 @@

 #undef DEBUG
 #define DEBUG(fmt, ...) do { \
-       if (ibdebug || ibverbose) IBWARN(fmt, ## __VA_ARGS__); \
+       if (ibdebug) IBDEBUG(fmt, ## __VA_ARGS__); \
 } while (0)
 #define VERBOSE(fmt, ...) do { \
-       if (ibdebug || ibverbose > 1) IBWARN(fmt, ## __VA_ARGS__); \
+       if (ibverbose) IBVERBOSE(fmt, ## __VA_ARGS__); \
 } while (0)
 #define IBERROR(fmt, ...) iberror(__FUNCTION__, fmt, ## __VA_ARGS__)

Index: tools/infiniband-diags/src/ibaddr.c
===================================================================
--- tools/infiniband-diags/src/ibaddr.c (revision 2812)
+++ tools/infiniband-diags/src/ibaddr.c (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
Index: tools/infiniband-diags/src/ibdiag_common.c
===================================================================
--- tools/infiniband-diags/src/ibdiag_common.c  (revision 2812)
+++ tools/infiniband-diags/src/ibdiag_common.c  (working copy)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2006-2007 The Regents of the University of California.
- * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -147,7 +147,7 @@
                break;
        case 'V':
                fprintf(stderr, "%s %s\n", prog_name, get_build_version());
-               exit(2);
+               exit(0);
        case 'e':
                madrpc_show_errors(1);
                break;
Index: tools/infiniband-diags/src/iblinkinfo.c
===================================================================
--- tools/infiniband-diags/src/iblinkinfo.c     (revision 2812)
+++ tools/infiniband-diags/src/iblinkinfo.c     (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
  * Copyright (c) 2008 Lawrence Livermore National Lab.  All rights reserved.
  *
@@ -55,12 +55,12 @@

 static char *node_name_map_file = NULL;
 static nn_map_t *node_name_map = NULL;
+static char *load_cache_file = NULL;

 static uint64_t guid = 0;
 static char *guid_str = NULL;
 static char *dr_path = NULL;
 static int all = 0;
-static int hops = 0;

 static int down_links_only = 0;
 static int line_mode = 0;
@@ -69,13 +69,10 @@

 static unsigned int get_max(unsigned int num)
 {
-       unsigned int v = num;   // 32-bit word to find the log base 2 of
-       unsigned r = 0;         // r will be lg(v)
+       unsigned r = 0;         // r will be lg(num)

-       while (v >>= 1)         // unroll for more speed...
-       {
+       while (num >>= 1)       // unroll for more speed...
                r++;
-       }

        return (1 << r);
 }
@@ -90,26 +87,24 @@
                                     & mad_get_field(port->remoteport->info, 0,
                                                     IB_PORT_LINK_WIDTH_SUPPORTED_F));
        if ((max_width & mad_get_field(port->info, 0,
-                                      IB_PORT_LINK_WIDTH_ACTIVE_F)) == 0) {
+                                      IB_PORT_LINK_WIDTH_ACTIVE_F)) == 0)
                // we are not at the max supported width
                // print what we could be at.
                snprintf(width_msg, msg_size, "Could be %s",
                         mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F,
                                      buf, 64, &max_width));
-       }

        max_speed = get_max(mad_get_field(port->info, 0,
                                          IB_PORT_LINK_SPEED_SUPPORTED_F)
                            & mad_get_field(port->remoteport->info, 0,
                                            IB_PORT_LINK_SPEED_SUPPORTED_F));
        if ((max_speed & mad_get_field(port->info, 0,
-                                      IB_PORT_LINK_SPEED_ACTIVE_F)) == 0) {
+                                      IB_PORT_LINK_SPEED_ACTIVE_F)) == 0)
                // we are not at the max supported speed
                // print what we could be at.
                snprintf(speed_msg, msg_size, "Could be %s",
                         mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F,
                                      buf, 64, &max_speed));
-       }
 }

 void print_port(ibnd_node_t * node, ibnd_port_t * port)
@@ -138,20 +133,34 @@
        width_msg[0] = '\0';
        speed_msg[0] = '\0';

-       n = snprintf(link_str, 256, "(%3s %s %6s/%8s)",
+       /* C14-24.2.1 states that a down port allows for invalid data to be
+        * returned for all PortInfo components except PortState and
+        * PortPhysicalState */
+       if (istate != IB_LINK_DOWN) {
+               n = snprintf(link_str, 256, "(%3s %9s %6s/%8s)",
                     mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, width, 64,
                                  &iwidth),
                     mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, speed, 64,
-                                 &ispeed), mad_dump_val(IB_PORT_STATE_F, state,
-                                                        64, &istate),
+                                 &ispeed),
+                    mad_dump_val(IB_PORT_STATE_F, state, 64, &istate),
                     mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64,
                                  &iphystate));
+       } else {
+               n = snprintf(link_str, 256, "(              %6s/%8s)",
+                    mad_dump_val(IB_PORT_STATE_F, state, 64, &istate),
+                    mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64,
+                                 &iphystate));
+       }

-       if (add_sw_settings)
-               snprintf(link_str + n, 256 - n, " (HOQ:%d VL_Stall:%d)",
-                        mad_get_field(port->info, 0, IB_PORT_HOQ_LIFE_F),
-                        mad_get_field(port->info, 0,
-                                      IB_PORT_VL_STALL_COUNT_F));
+       /* again default values due to C14-24.2.1 */
+       if (add_sw_settings && istate != IB_LINK_DOWN) {
+               snprintf(link_str + n, 256 - n,
+                       " (HOQ:%d VL_Stall:%d)",
+                       mad_get_field(port->info, 0,
+                               IB_PORT_HOQ_LIFE_F),
+                       mad_get_field(port->info, 0,
+                               IB_PORT_VL_STALL_COUNT_F));
+       }

        if (port->remoteport) {
                char *remap =
@@ -231,10 +240,14 @@

 static int process_opt(void *context, int ch, char *optarg)
 {
+       struct ibnd_config *cfg = context;
        switch (ch) {
        case 1:
                node_name_map_file = strdup(optarg);
                break;
+       case 2:
+               load_cache_file = strdup(optarg);
+               break;
        case 'S':
                guid_str = optarg;
                guid = (uint64_t) strtoull(guid_str, 0, 0);
@@ -246,7 +259,7 @@
                all = 1;
                break;
        case 'n':
-               hops = (int)strtol(optarg, NULL, 0);
+               cfg->max_hops = strtoul(optarg, NULL, 0);
                break;
        case 'd':
                down_links_only = 1;
@@ -262,6 +275,9 @@
                break;
        case 'R':               /* nop */
                break;
+       case 'o':
+               cfg->max_smps = strtoul(optarg, NULL, 0);
+               break;
        default:
                return -1;
        }
@@ -271,6 +287,7 @@

 int main(int argc, char **argv)
 {
+       struct ibnd_config config = { 0 };
        int rc = 0;
        int resolved = -1;
        ibnd_fabric_t *fabric = NULL;
@@ -296,21 +313,23 @@
                 "print additional switch settings (PktLifeTime, HoqLife, VLStallCount)"},
                {"portguids", 'g', 0, NULL,
                 "print port guids instead of node guids"},
+               {"load-cache", 2, 1, "<file>",
+                "filename of ibnetdiscover cache to load"},
+               {"outstanding_smps", 'o', 1, NULL,
+                "specify the number of outstanding SMP's which should be "
+                "issued during the scan"},
                {"GNDN", 'R', 0, NULL,
                 "(This option is obsolete and does nothing)"},
                {0}
        };
        char usage_args[] = "";

-       ibdiag_process_opts(argc, argv, NULL, "SDandlpgRGL", opts, process_opt,
-                           usage_args, NULL);
+       ibdiag_process_opts(argc, argv, &config, "SDandlpgRGL", opts,
+                           process_opt, usage_args, NULL);

        argc -= optind;
        argv += optind;

-       if (ibverbose)
-               ibnd_debug(1);
-
        ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3);
        if (!ibmad_port) {
                fprintf(stderr, "Failed to open %s port %d", ibd_ca,
@@ -318,11 +337,18 @@
                exit(1);
        }

-       if (ibd_timeout)
+       if (ibd_timeout) {
                mad_rpc_set_timeout(ibmad_port, ibd_timeout);
+               config.timeout_ms = ibd_timeout;
+       }

        node_name_map = open_node_name_map(node_name_map_file);

+       if (dr_path && load_cache_file) {
+               fprintf(stderr, "Cannot specify cache and direct route path\n");
+               exit(1);
+       }
+
        if (dr_path) {
                /* only scan part of the fabric */
                if ((resolved =
@@ -339,19 +365,25 @@
                               guid_str);
        }

-       if (resolved >= 0)
-               if ((fabric = ibnd_discover_fabric(ibmad_port, &port_id,
-                                                  hops)) == NULL)
-                       IBWARN
-                           ("Single node discover failed; attempting full scan\n");
+       if (load_cache_file) {
+               if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL) {
+                       fprintf(stderr, "loading cached fabric failed\n");
+                       exit(1);
+               }
+       } else {
+               if (resolved >= 0 &&
+                   !(fabric =
+                     ibnd_discover_fabric(ibd_ca, ibd_ca_port, &port_id, &config)))
+                       IBWARN("Single node discover failed;"
+                              " attempting full scan\n");

-       if (!fabric)
-               if ((fabric =
-                    ibnd_discover_fabric(ibmad_port, NULL, -1)) == NULL) {
+               if (!fabric &&
+                   !(fabric = ibnd_discover_fabric(ibd_ca, ibd_ca_port, NULL, &config))) {
                        fprintf(stderr, "discover failed\n");
                        rc = 1;
                        goto close_port;
                }
+       }

        if (!all && guid_str) {
                ibnd_node_t *sw = ibnd_find_node_guid(fabric, guid);
Index: tools/infiniband-diags/src/ibnetdiscover.c
===================================================================
--- tools/infiniband-diags/src/ibnetdiscover.c  (revision 2812)
+++ tools/infiniband-diags/src/ibnetdiscover.c  (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
  * Copyright (c) 2008 Lawrence Livermore National Lab.  All rights reserved.
  *
@@ -34,7 +34,7 @@
  */

 #if HAVE_CONFIG_H
-#  include <config.h>
+#include <config.h>
 #endif                         /* HAVE_CONFIG_H */

 #define _GNU_SOURCE
@@ -57,12 +57,24 @@
 #define LIST_SWITCH_NODE (1 << IB_NODE_SWITCH)
 #define LIST_ROUTER_NODE (1 << IB_NODE_ROUTER)

-struct ibmad_port *srcport;
+#define DIFF_FLAG_SWITCH           0x01
+#define DIFF_FLAG_CA               0x02
+#define DIFF_FLAG_ROUTER           0x04
+#define DIFF_FLAG_PORT_CONNECTION  0x08
+#define DIFF_FLAG_LID              0x10
+#define DIFF_FLAG_NODE_DESCRIPTION 0x20

+#define DIFF_FLAG_DEFAULT (DIFF_FLAG_SWITCH | DIFF_FLAG_CA | DIFF_FLAG_ROUTER \
+                          | DIFF_FLAG_PORT_CONNECTION)
+
 static FILE *f;

 static char *node_name_map_file = NULL;
 static nn_map_t *node_name_map = NULL;
+static char *cache_file = NULL;
+static char *load_cache_file = NULL;
+static char *diff_cache_file = NULL;
+static unsigned diffcheck_flags = DIFF_FLAG_DEFAULT;

 static int report_max_hops = 0;

@@ -181,16 +193,18 @@
                ibnd_iter_nodes_type(fabric, list_node, IB_NODE_ROUTER, NULL);
 }

-void out_ids(ibnd_node_t * node, int group, char *chname)
+void out_ids(ibnd_node_t * node, int group, char *chname, char *out_prefix)
 {
        uint64_t sysimgguid =
            mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F);

-       fprintf(f, "\nvendid=0x%x\ndevid=0x%x\n",
-               mad_get_field(node->info, 0, IB_NODE_VENDORID_F),
+       fprintf(f, "\n%svendid=0x%x\n", out_prefix ? out_prefix : "",
+               mad_get_field(node->info, 0, IB_NODE_VENDORID_F));
+       fprintf(f, "%sdevid=0x%x\n", out_prefix ? out_prefix : "",
                mad_get_field(node->info, 0, IB_NODE_DEVID_F));
        if (sysimgguid)
-               fprintf(f, "sysimgguid=0x%" PRIx64, sysimgguid);
+               fprintf(f, "%ssysimgguid=0x%" PRIx64,
+                       out_prefix ? out_prefix : "", sysimgguid);
        if (group && node->chassis && node->chassis->chassisnum) {
                fprintf(f, "\t\t# Chassis %d", node->chassis->chassisnum);
                if (chname)
@@ -215,14 +229,29 @@
        return guid;
 }

-void out_switch(ibnd_node_t * node, int group, char *chname)
+void out_switch_detail(ibnd_node_t * node, char *sw_prefix)
 {
+       char *nodename = NULL;
+
+       nodename = remap_node_name(node_name_map, node->guid, node->nodedesc);
+
+       fprintf(f, "%sSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d",
+               sw_prefix ? sw_prefix : "", node->numports, node_name(node),
+               nodename, node->smaenhsp0 ? "enhanced" : "base",
+               node->smalid, node->smalmc);
+
+       free(nodename);
+}
+
+void out_switch(ibnd_node_t * node, int group, char *chname, char *id_prefix,
+               char *sw_prefix)
+{
        char *str;
        char str2[256];
-       char *nodename = NULL;

-       out_ids(node, group, chname);
-       fprintf(f, "switchguid=0x%" PRIx64, node->guid);
+       out_ids(node, group, chname, id_prefix);
+       fprintf(f, "%sswitchguid=0x%" PRIx64,
+               id_prefix ? id_prefix : "", node->guid);
        fprintf(f, "(%" PRIx64 ")",
                mad_get_field64(node->info, 0, IB_NODE_PORT_GUID_F));
        if (group) {
@@ -234,42 +263,54 @@
                if (str)
                        fprintf(f, "%s", str);
        }
+       fprintf(f, "\n");

-       nodename = remap_node_name(node_name_map, node->guid, node->nodedesc);
+       out_switch_detail(node, sw_prefix);
+       fprintf(f, "\n");
+}

-       fprintf(f, "\nSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d\n",
-               node->numports, node_name(node), nodename,
-               node->smaenhsp0 ? "enhanced" : "base",
-               node->smalid, node->smalmc);
+void out_ca_detail(ibnd_node_t * node, char *ca_prefix)
+{
+       char *node_type;

-       free(nodename);
+       switch (node->type) {
+       case IB_NODE_CA:
+               node_type = "Ca";
+               break;
+       case IB_NODE_ROUTER:
+               node_type = "Rt";
+               break;
+       default:
+               node_type = "???";
+               break;
+       }
+
+       fprintf(f, "%s%s\t%d %s\t\t# \"%s\"", ca_prefix ? ca_prefix : "",
+               node_type, node->numports, node_name(node),
+               clean_nodedesc(node->nodedesc));
 }

-void out_ca(ibnd_node_t * node, int group, char *chname)
+void out_ca(ibnd_node_t * node, int group, char *chname, char *id_prefix,
+           char *ca_prefix)
 {
        char *node_type;
-       char *node_type2;

-       out_ids(node, group, chname);
+       out_ids(node, group, chname, id_prefix);
        switch (node->type) {
        case IB_NODE_CA:
                node_type = "ca";
-               node_type2 = "Ca";
                break;
        case IB_NODE_ROUTER:
                node_type = "rt";
-               node_type2 = "Rt";
                break;
        default:
                node_type = "???";
-               node_type2 = "???";
                break;
        }

-       fprintf(f, "%sguid=0x%" PRIx64 "\n", node_type, node->guid);
-       fprintf(f, "%s\t%d %s\t\t# \"%s\"",
-               node_type2, node->numports, node_name(node),
-               clean_nodedesc(node->nodedesc));
+       fprintf(f, "%s%sguid=0x%" PRIx64 "\n",
+               id_prefix ? id_prefix : "", node_type, node->guid);
+       out_ca_detail(node, ca_prefix);
        if (group && ibnd_is_xsigo_hca(node->guid))
                fprintf(f, " (scp)");
        fprintf(f, "\n");
@@ -289,7 +330,7 @@
        return (NULL);
 }

-void out_switch_port(ibnd_port_t * port, int group)
+void out_switch_port(ibnd_port_t * port, int group, char *out_prefix)
 {
        char *ext_port_str = NULL;
        char *rem_nodename = NULL;
@@ -300,7 +341,7 @@

        DEBUG("port %p:%d remoteport %p\n", port, port->portnum,
              port->remoteport);
-       fprintf(f, "[%d]", port->portnum);
+       fprintf(f, "%s[%d]", out_prefix ? out_prefix : "", port->portnum);

        ext_port_str = out_ext_port(port, group);
        if (ext_port_str)
@@ -332,7 +373,7 @@
        free(rem_nodename);
 }

-void out_ca_port(ibnd_port_t * port, int group)
+void out_ca_port(ibnd_port_t * port, int group, char *out_prefix)
 {
        char *str = NULL;
        char *rem_nodename = NULL;
@@ -341,7 +382,7 @@
        uint32_t ispeed = mad_get_field(port->info, 0,
                                        IB_PORT_LINK_SPEED_ACTIVE_F);

-       fprintf(f, "[%d]", port->portnum);
+       fprintf(f, "%s[%d]", out_prefix ? out_prefix : "", port->portnum);
        if (port->node->type != IB_NODE_SWITCH)
                fprintf(f, "(%" PRIx64 ") ", port->guid);
        fprintf(f, "\t%s[%d]",
@@ -384,11 +425,11 @@
            && node->chassis->chassisnum)
                return;

-       out_switch(node, data->group, NULL);
+       out_switch(node, data->group, NULL, NULL, NULL);
        for (p = 1; p <= node->numports; p++) {
                port = node->ports[p];
                if (port && port->remoteport)
-                       out_switch_port(port, data->group);
+                       out_switch_port(port, data->group, NULL);
        }
 }

@@ -402,12 +443,12 @@
        /* Now, skip chassis based CAs */
        if (data->group && node->chassis && node->chassis->chassisnum)
                return;
-       out_ca(node, data->group, NULL);
+       out_ca(node, data->group, NULL, NULL, NULL);

        for (p = 1; p <= node->numports; p++) {
                port = node->ports[p];
                if (port && port->remoteport)
-                       out_ca_port(port, data->group);
+                       out_ca_port(port, data->group, NULL);
        }
 }

@@ -421,11 +462,11 @@
        /* Now, skip chassis based RTs */
        if (data->group && node->chassis && node->chassis->chassisnum)
                return;
-       out_ca(node, data->group, NULL);
+       out_ca(node, data->group, NULL, NULL, NULL);
        for (p = 1; p <= node->numports; p++) {
                port = node->ports[p];
                if (port && port->remoteport)
-                       out_ca_port(port, data->group);
+                       out_ca_port(port, data->group, NULL);
        }
 }

@@ -441,8 +482,9 @@

        fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t));
        if (report_max_hops)
-               fprintf(f, "# Reported max hops discovered: %d\n",
-                       fabric->maxhops_discovered);
+               fprintf(f, "# Reported max hops discovered: %u\n"
+                       "# Total MADs used: %u\n",
+                       fabric->maxhops_discovered, fabric->total_mads_used);
        fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n",
                fabric->from_node->guid,
                mad_get_field64(fabric->from_node->info, 0,
@@ -459,19 +501,15 @@
                        if (!ch->chassisnum)
                                continue;
                        chguid = out_chassis(fabric, ch->chassisnum);
-
                        chname = NULL;
-/**
- * Will this work for Xsigo?
- */
                        if (ibnd_is_xsigo_guid(chguid)) {
                                for (node = ch->nodes; node;
                                     node = node->next_chassis_node) {
                                        if (ibnd_is_xsigo_hca(node->guid)) {
                                                chname = node->nodedesc;
                                                fprintf(f, "Hostname: %s\n",
-                                                       clean_nodedesc(node->
-                                                                      nodedesc));
+                                                       clean_nodedesc
+                                                       (node->nodedesc));
                                        }
                                }
                        }
@@ -480,7 +518,7 @@
                        for (n = 1; n <= SPINES_MAX_NUM; n++) {
                                if (ch->spinenode[n]) {
                                        out_switch(ch->spinenode[n], group,
-                                                  chname);
+                                                  chname, NULL, NULL);
                                        for (p = 1;
                                             p <= ch->spinenode[n]->numports;
                                             p++) {
@@ -488,7 +526,8 @@
                                                    ch->spinenode[n]->ports[p];
                                                if (port && port->remoteport)
                                                        out_switch_port(port,
-                                                                       group);
+                                                                       group,
+                                                                       NULL);
                                        }
                                }
                        }
@@ -496,7 +535,7 @@
                        for (n = 1; n <= LINES_MAX_NUM; n++) {
                                if (ch->linenode[n]) {
                                        out_switch(ch->linenode[n], group,
-                                                  chname);
+                                                  chname, NULL, NULL);
                                        for (p = 1;
                                             p <= ch->linenode[n]->numports;
                                             p++) {
@@ -504,7 +543,8 @@
                                                    ch->linenode[n]->ports[p];
                                                if (port && port->remoteport)
                                                        out_switch_port(port,
-                                                                       group);
+                                                                       group,
+                                                                       NULL);
                                        }
                                }
                        }
@@ -513,12 +553,14 @@
                        for (node = ch->nodes; node;
                             node = node->next_chassis_node) {
                                if (node->type == IB_NODE_SWITCH) {
-                                       out_switch(node, group, chname);
+                                       out_switch(node, group, chname, NULL,
+                                                  NULL);
                                        for (p = 1; p <= node->numports; p++) {
                                                port = node->ports[p];
                                                if (port && port->remoteport)
                                                        out_switch_port(port,
-                                                                       group);
+                                                                       group,
+                                                                       NULL);
                                        }
                                }

@@ -528,12 +570,12 @@
                        for (node = ch->nodes; node;
                             node = node->next_chassis_node) {
                                if (node->type == IB_NODE_CA) {
-                                       out_ca(node, group, chname);
+                                       out_ca(node, group, chname, NULL, NULL);
                                        for (p = 1; p <= node->numports; p++) {
                                                port = node->ports[p];
                                                if (port && port->remoteport)
-                                                       out_ca_port(port,
-                                                                   group);
+                                                       out_ca_port(port, group,
+                                                                   NULL);
                                        }
                                }
                        }
@@ -543,8 +585,8 @@
        } else {                /* !group */
                iter_user_data.group = group;
                iter_user_data.skip_chassis_nodes = 0;
-               ibnd_iter_nodes_type(fabric, switch_iter_func,
-                                    IB_NODE_SWITCH, &iter_user_data);
+               ibnd_iter_nodes_type(fabric, switch_iter_func, IB_NODE_SWITCH,
+                                    &iter_user_data);
        }

        chname = NULL;
@@ -554,8 +596,8 @@

                fprintf(f, "\nNon-Chassis Nodes\n");

-               ibnd_iter_nodes_type(fabric, switch_iter_func,
-                                    IB_NODE_SWITCH, &iter_user_data);
+               ibnd_iter_nodes_type(fabric, switch_iter_func, IB_NODE_SWITCH,
+                                    &iter_user_data);
        }

        iter_user_data.group = group;
@@ -608,16 +650,250 @@
        }
 }

+struct iter_diff_data {
+       uint32_t diff_flags;
+       ibnd_fabric_t *fabric1;
+       ibnd_fabric_t *fabric2;
+       char *fabric1_prefix;
+       char *fabric2_prefix;
+       void (*out_header) (ibnd_node_t *, int, char *, char *, char *);
+       void (*out_header_detail) (ibnd_node_t *, char *);
+       void (*out_port) (ibnd_port_t *, int, char *);
+};
+
+static void diff_iter_out_header(ibnd_node_t * node,
+                                struct iter_diff_data *data,
+                                int *out_header_flag)
+{
+       if (!(*out_header_flag)) {
+               (*data->out_header) (node, 0, NULL, NULL, NULL);
+               (*out_header_flag)++;
+       }
+}
+
+static void diff_ports(ibnd_node_t * fabric1_node, ibnd_node_t * fabric2_node,
+                      int *out_header_flag, struct iter_diff_data *data)
+{
+       ibnd_port_t *fabric1_port;
+       ibnd_port_t *fabric2_port;
+       int p;
+
+       for (p = 1; p <= fabric1_node->numports; p++) {
+               int fabric1_out = 0, fabric2_out = 0;
+
+               fabric1_port = fabric1_node->ports[p];
+               fabric2_port = fabric2_node->ports[p];
+
+               if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION) {
+                       if ((fabric1_port && !fabric2_port)
+                           || ((fabric1_port && fabric2_port)
+                               && (fabric1_port->remoteport
+                                   && !fabric2_port->remoteport)))
+                               fabric1_out++;
+                       else if ((!fabric1_port && fabric2_port)
+                                || ((fabric1_port && fabric2_port)
+                                    && (!fabric1_port->remoteport
+                                        && fabric2_port->remoteport)))
+                               fabric2_out++;
+                       else if ((fabric1_port && fabric2_port)
+                                && ((fabric1_port->guid != fabric2_port->guid)
+                                    ||
+                                    ((fabric1_port->remoteport
+                                      && fabric2_port->remoteport)
+                                     && (fabric1_port->remoteport->guid !=
+                                         fabric2_port->remoteport->guid)))) {
+                               fabric1_out++;
+                               fabric2_out++;
+                       }
+               }
+
+               if ((data->diff_flags & DIFF_FLAG_LID)
+                   && fabric1_port && fabric2_port
+                   && fabric1_port->base_lid != fabric2_port->base_lid) {
+                       fabric1_out++;
+                       fabric2_out++;
+               }
+
+               if (fabric1_out) {
+                       diff_iter_out_header(fabric1_node, data,
+                                            out_header_flag);
+                       (*data->out_port) (fabric1_port, 0,
+                                          data->fabric1_prefix);
+               }
+               if (fabric2_out) {
+                       diff_iter_out_header(fabric1_node, data,
+                                            out_header_flag);
+                       (*data->out_port) (fabric2_port, 0,
+                                          data->fabric2_prefix);
+               }
+       }
+}
+
+static void diff_iter_func(ibnd_node_t * fabric1_node, void *iter_user_data)
+{
+       struct iter_diff_data *data = iter_user_data;
+       ibnd_node_t *fabric2_node;
+       ibnd_port_t *fabric1_port;
+       int p;
+
+       DEBUG("DEBUG: fabric1_node %p\n", fabric1_node);
+
+       fabric2_node = ibnd_find_node_guid(data->fabric2, fabric1_node->guid);
+       if (!fabric2_node) {
+               (*data->out_header) (fabric1_node, 0, NULL,
+                                    data->fabric1_prefix,
+                                    data->fabric1_prefix);
+               for (p = 1; p <= fabric1_node->numports; p++) {
+                       fabric1_port = fabric1_node->ports[p];
+                       if (fabric1_port && fabric1_port->remoteport)
+                               (*data->out_port) (fabric1_port, 0,
+                                                  data->fabric1_prefix);
+               }
+       } else if (data->diff_flags &
+                  (DIFF_FLAG_PORT_CONNECTION | DIFF_FLAG_LID
+                   | DIFF_FLAG_NODE_DESCRIPTION)) {
+               int out_header_flag = 0;
+
+               if ((data->diff_flags & DIFF_FLAG_LID
+                    && fabric1_node->smalid != fabric2_node->smalid) ||
+                   (data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION
+                    && memcmp(fabric1_node->nodedesc, fabric2_node->nodedesc,
+                              IB_SMP_DATA_SIZE))) {
+                       (*data->out_header) (fabric1_node, 0, NULL, NULL,
+                                            data->fabric1_prefix);
+                       (*data->out_header_detail) (fabric2_node,
+                                                   data->fabric2_prefix);
+                       fprintf(f, "\n");
+                       out_header_flag++;
+               }
+
+               if (fabric1_node->numports != fabric2_node->numports) {
+                       diff_iter_out_header(fabric1_node, data,
+                                            &out_header_flag);
+                       fprintf(f, "%snumports = %d\n", data->fabric1_prefix,
+                               fabric1_node->numports);
+                       fprintf(f, "%snumports = %d\n", data->fabric2_prefix,
+                               fabric2_node->numports);
+                       return;
+               }
+
+               if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION
+                   || data->diff_flags & DIFF_FLAG_LID)
+                       diff_ports(fabric1_node, fabric2_node, &out_header_flag,
+                                  data);
+       }
+}
+
+static int diff_common(ibnd_fabric_t * orig_fabric, ibnd_fabric_t * new_fabric,
+                      int node_type, uint32_t diff_flags,
+                      void (*out_header) (ibnd_node_t *, int, char *, char *,
+                                          char *),
+                      void (*out_header_detail) (ibnd_node_t *, char *),
+                      void (*out_port) (ibnd_port_t *, int, char *))
+{
+       struct iter_diff_data iter_diff_data;
+
+       iter_diff_data.diff_flags = diff_flags;
+       iter_diff_data.fabric1 = orig_fabric;
+       iter_diff_data.fabric2 = new_fabric;
+       iter_diff_data.fabric1_prefix = "< ";
+       iter_diff_data.fabric2_prefix = "> ";
+       iter_diff_data.out_header = out_header;
+       iter_diff_data.out_header_detail = out_header_detail;
+       iter_diff_data.out_port = out_port;
+       ibnd_iter_nodes_type(orig_fabric, diff_iter_func, node_type,
+                            &iter_diff_data);
+
+       /* Do opposite diff to find existence of node types
+        * in new_fabric but not in orig_fabric.
+        *
+        * In this diff, we don't need to check port connections,
+        * lids, or node descriptions since it has already been
+        * done (i.e. checks are only done when guid exists on both
+        * orig and new).
+        */
+       iter_diff_data.diff_flags = diff_flags & ~DIFF_FLAG_PORT_CONNECTION;
+       iter_diff_data.diff_flags &= ~DIFF_FLAG_LID;
+       iter_diff_data.diff_flags &= ~DIFF_FLAG_NODE_DESCRIPTION;
+       iter_diff_data.fabric1 = new_fabric;
+       iter_diff_data.fabric2 = orig_fabric;
+       iter_diff_data.fabric1_prefix = "> ";
+       iter_diff_data.fabric2_prefix = "< ";
+       iter_diff_data.out_header = out_header;
+       iter_diff_data.out_header_detail = out_header_detail;
+       iter_diff_data.out_port = out_port;
+       ibnd_iter_nodes_type(new_fabric, diff_iter_func, node_type,
+                            &iter_diff_data);
+
+       return 0;
+}
+
+int diff(ibnd_fabric_t * orig_fabric, ibnd_fabric_t * new_fabric)
+{
+       if (diffcheck_flags & DIFF_FLAG_SWITCH)
+               diff_common(orig_fabric, new_fabric, IB_NODE_SWITCH,
+                           diffcheck_flags, out_switch, out_switch_detail,
+                           out_switch_port);
+
+       if (diffcheck_flags & DIFF_FLAG_CA)
+               diff_common(orig_fabric, new_fabric, IB_NODE_CA,
+                           diffcheck_flags, out_ca, out_ca_detail,
+                           out_ca_port);
+
+       if (diffcheck_flags & DIFF_FLAG_ROUTER)
+               diff_common(orig_fabric, new_fabric, IB_NODE_ROUTER,
+                           diffcheck_flags, out_ca, out_ca_detail,
+                           out_ca_port);
+
+       return 0;
+}
+
 static int list, group, ports_report;

 static int process_opt(void *context, int ch, char *optarg)
 {
+       struct ibnd_config *cfg = context;
+       char *p;
+
        switch (ch) {
        case 1:
                node_name_map_file = strdup(optarg);
                break;
+       case 2:
+               cache_file = strdup(optarg);
+               break;
+       case 3:
+               load_cache_file = strdup(optarg);
+               break;
+       case 4:
+               diff_cache_file = strdup(optarg);
+               break;
+       case 5:
+               diffcheck_flags = 0;
+               p = strtok(optarg, ",");
+               while (p) {
+                       if (!strcasecmp(p, "sw"))
+                               diffcheck_flags |= DIFF_FLAG_SWITCH;
+                       else if (!strcasecmp(p, "ca"))
+                               diffcheck_flags |= DIFF_FLAG_CA;
+                       else if (!strcasecmp(p, "router"))
+                               diffcheck_flags |= DIFF_FLAG_ROUTER;
+                       else if (!strcasecmp(p, "port"))
+                               diffcheck_flags |= DIFF_FLAG_PORT_CONNECTION;
+                       else if (!strcasecmp(p, "lid"))
+                               diffcheck_flags |= DIFF_FLAG_LID;
+                       else if (!strcasecmp(p, "nodedesc"))
+                               diffcheck_flags |= DIFF_FLAG_NODE_DESCRIPTION;
+                       else {
+                               fprintf(stderr, "invalid diff check key: %s\n",
+                                       p);
+                               return -1;
+                       }
+                       p = strtok(NULL, ",");
+               }
+               break;
        case 's':
-               ibnd_show_progress(1);
+               cfg->show_progress = 1;
                break;
        case 'l':
                list = LIST_CA_NODE | LIST_SWITCH_NODE | LIST_ROUTER_NODE;
@@ -640,6 +916,9 @@
        case 'm':
                report_max_hops = 1;
                break;
+       case 'o':
+               cfg->max_smps = strtoul(optarg, NULL, 0);
+               break;
        default:
                return -1;
        }
@@ -649,11 +928,10 @@

 int main(int argc, char **argv)
 {
+       struct ibnd_config config = { 0 };
        ibnd_fabric_t *fabric = NULL;
+       ibnd_fabric_t *diff_fabric = NULL;

-       struct ibmad_port *ibmad_port;
-       int mgmt_classes[2] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS };
-
        const struct ibdiag_opt opts[] = {
                {"show", 's', 0, NULL, "show more information"},
                {"list", 'l', 0, NULL, "list of connected nodes"},
@@ -662,14 +940,25 @@
                {"Switch_list", 'S', 0, NULL, "list of connected switches"},
                {"Router_list", 'R', 0, NULL, "list of connected routers"},
                {"node-name-map", 1, 1, "<file>", "node name map file"},
+               {"cache", 2, 1, "<file>",
+                "filename to cache ibnetdiscover data to"},
+               {"load-cache", 3, 1, "<file>",
+                "filename of ibnetdiscover cache to load"},
+               {"diff", 4, 1, "<file>",
+                "filename of ibnetdiscover cache to diff"},
+               {"diffcheck", 5, 1, "<key(s)>",
+                "specify checks to execute for --diff"},
                {"ports", 'p', 0, NULL, "obtain a ports report"},
                {"max_hops", 'm', 0, NULL,
                 "report max hops discovered by the library"},
+               {"outstanding_smps", 'o', 1, NULL,
+                "specify the number of outstanding SMP's which should be "
+                "issued during the scan"},
                {0}
        };
        char usage_args[] = "[topology-file]";

-       ibdiag_process_opts(argc, argv, NULL, "sGDL", opts, process_opt,
+       ibdiag_process_opts(argc, argv, &config, "sGDL", opts, process_opt,
                            usage_args, NULL);

        f = stdout;
@@ -677,33 +966,43 @@
        argc -= optind;
        argv += optind;

-       if (ibverbose)
-               ibnd_debug(1);
-
-       ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 2);
-       if (!ibmad_port)
-               IBERROR("Failed to open %s port %d", ibd_ca, ibd_ca_port);
-
        if (ibd_timeout)
-               mad_rpc_set_timeout(ibmad_port, ibd_timeout);
+               config.timeout_ms = ibd_timeout;

        if (argc && !(f = fopen(argv[0], "w")))
                IBERROR("can't open file %s for writing", argv[0]);

        node_name_map = open_node_name_map(node_name_map_file);

-       if ((fabric = ibnd_discover_fabric(ibmad_port, NULL, -1)) == NULL)
-               IBERROR("discover failed\n");
+       if (diff_cache_file &&
+           !(diff_fabric = ibnd_load_fabric(diff_cache_file, 0)))
+               IBERROR("loading cached fabric for diff failed\n");

+       if (load_cache_file) {
+               if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL)
+                       IBERROR("loading cached fabric failed\n");
+       } else {
+               if ((fabric =
+                    ibnd_discover_fabric(ibd_ca, ibd_ca_port, NULL, &config)) == NULL)
+                       IBERROR("discover failed\n");
+       }
+
        if (ports_report)
                ibnd_iter_nodes(fabric, dump_ports_report, NULL);
        else if (list)
                list_nodes(fabric, list);
+       else if (diff_fabric)
+               diff(diff_fabric, fabric);
        else
                dump_topology(group, fabric);

+       if (cache_file)
+               if (ibnd_cache_fabric(fabric, cache_file, 0) < 0)
+                       IBERROR("caching ibnetdiscover data failed\n");
+
        ibnd_destroy_fabric(fabric);
+       if (diff_fabric)
+               ibnd_destroy_fabric(diff_fabric);
        close_node_name_map(node_name_map);
-       mad_rpc_close_port(ibmad_port);
        exit(0);
 }
Index: tools/infiniband-diags/src/ibping.c
===================================================================
--- tools/infiniband-diags/src/ibping.c (revision 2812)
+++ tools/infiniband-diags/src/ibping.c (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
Index: tools/infiniband-diags/src/ibportstate.c
===================================================================
--- tools/infiniband-diags/src/ibportstate.c    (revision 2812)
+++ tools/infiniband-diags/src/ibportstate.c    (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -46,93 +46,133 @@

 #include "ibdiag_common.h"

+enum port_ops {
+       QUERY,
+       ENABLE,
+       RESET,
+       DISABLE,
+       SPEED,
+       WIDTH,
+       DOWN,
+       ARM,
+       ACTIVE,
+       VLS,
+       MTU,
+       LID,
+       SMLID,
+       LMC,
+};
+
 struct ibmad_port *srcport;
+int speed = 0; /* no state change */
+int width = 0; /* no state change */
+int lid;
+int smlid;
+int lmc;
+int mtu;
+int vls = 0; /* no state change */

+struct {
+       const char *name;
+       int *val;
+       int set;
+} port_args[] = {
+       {"query", NULL, 0},     /* QUERY */
+       {"enable", NULL, 0},    /* ENABLE */
+       {"reset", NULL, 0},     /* RESET */
+       {"disable", NULL, 0},   /* DISABLE */
+       {"speed", &speed, 0},   /* SPEED */
+       {"width", &width, 0},   /* WIDTH */
+       {"down", NULL, 0},      /* DOWN */
+       {"arm", NULL, 0},       /* ARM */
+       {"active", NULL, 0},    /* ACTIVE */
+       {"vls", &vls, 0},       /* VLS */
+       {"mtu", &mtu, 0},       /* MTU */
+       {"lid", &lid, 0},       /* LID */
+       {"smlid", &smlid, 0},   /* SMLID */
+       {"lmc", &lmc, 0},       /* LMC */
+};
+
+#define NPORT_ARGS (sizeof(port_args) / sizeof(port_args[0]))
+
 /*******************************************/

+/*
+ * Return 1 if port is a switch, else zero.
+ */
 static int get_node_info(ib_portid_t * dest, uint8_t * data)
 {
        int node_type;

        if (!smp_query_via(data, dest, IB_ATTR_NODE_INFO, 0, 0, srcport))
-               return -1;
+               IBERROR("smp query nodeinfo failed");

        node_type = mad_get_field(data, 0, IB_NODE_TYPE_F);
        if (node_type == IB_NODE_SWITCH)        /* Switch NodeType ? */
+               return 1;
+       else
                return 0;
-       else
-               return 1;
 }

-static int get_port_info(ib_portid_t * dest, uint8_t * data, int portnum,
-                        int port_op)
+static void get_port_info(ib_portid_t * dest, uint8_t * data, int portnum)
 {
+       if (!smp_query_via(data, dest, IB_ATTR_PORT_INFO, portnum, 0, srcport))
+               IBERROR("smp query portinfo failed");
+}
+
+static void show_port_info(ib_portid_t * dest, uint8_t * data, int portnum)
+{
        char buf[2048];
        char val[64];

-       if (!smp_query_via(data, dest, IB_ATTR_PORT_INFO, portnum, 0, srcport))
-               return -1;
+       mad_dump_portstates(buf, sizeof buf, data, sizeof data);
+       mad_decode_field(data, IB_PORT_LID_F, val);
+       mad_dump_field(IB_PORT_LID_F, buf + strlen(buf),
+                      sizeof buf - strlen(buf), val);
+       sprintf(buf + strlen(buf), "%s", "\n");
+       mad_decode_field(data, IB_PORT_SMLID_F, val);
+       mad_dump_field(IB_PORT_SMLID_F, buf + strlen(buf),
+                      sizeof buf - strlen(buf), val);
+       sprintf(buf + strlen(buf), "%s", "\n");
+       mad_decode_field(data, IB_PORT_LMC_F, val);
+       mad_dump_field(IB_PORT_LMC_F, buf + strlen(buf),
+                      sizeof buf - strlen(buf), val);
+       sprintf(buf + strlen(buf), "%s", "\n");
+       mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, val);
+       mad_dump_field(IB_PORT_LINK_WIDTH_SUPPORTED_F, buf + strlen(buf),
+                      sizeof buf - strlen(buf), val);
+       sprintf(buf + strlen(buf), "%s", "\n");
+       mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, val);
+       mad_dump_field(IB_PORT_LINK_WIDTH_ENABLED_F, buf + strlen(buf),
+                      sizeof buf - strlen(buf), val);
+       sprintf(buf + strlen(buf), "%s", "\n");
+       mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, val);
+       mad_dump_field(IB_PORT_LINK_WIDTH_ACTIVE_F, buf + strlen(buf),
+                      sizeof buf - strlen(buf), val);
+       sprintf(buf + strlen(buf), "%s", "\n");
+       mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, val);
+       mad_dump_field(IB_PORT_LINK_SPEED_SUPPORTED_F, buf + strlen(buf),
+                      sizeof buf - strlen(buf), val);
+       sprintf(buf + strlen(buf), "%s", "\n");
+       mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val);
+       mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf + strlen(buf),
+                      sizeof buf - strlen(buf), val);
+       sprintf(buf + strlen(buf), "%s", "\n");
+       mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, val);
+       mad_dump_field(IB_PORT_LINK_SPEED_ACTIVE_F, buf + strlen(buf),
+                      sizeof buf - strlen(buf), val);
+       sprintf(buf + strlen(buf), "%s", "\n");

-       if (port_op != 4) {
-               mad_dump_portstates(buf, sizeof buf, data, sizeof data);
-               mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, val);
-               mad_dump_field(IB_PORT_LINK_WIDTH_SUPPORTED_F,
-                              buf + strlen(buf), sizeof buf - strlen(buf),
-                              val);
-               sprintf(buf + strlen(buf), "%s", "\n");
-               mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, val);
-               mad_dump_field(IB_PORT_LINK_WIDTH_ENABLED_F, buf + strlen(buf),
-                              sizeof buf - strlen(buf), val);
-               sprintf(buf + strlen(buf), "%s", "\n");
-               mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, val);
-               mad_dump_field(IB_PORT_LINK_WIDTH_ACTIVE_F, buf + strlen(buf),
-                              sizeof buf - strlen(buf), val);
-               sprintf(buf + strlen(buf), "%s", "\n");
-               mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, val);
-               mad_dump_field(IB_PORT_LINK_SPEED_SUPPORTED_F,
-                              buf + strlen(buf), sizeof buf - strlen(buf),
-                              val);
-               sprintf(buf + strlen(buf), "%s", "\n");
-               mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val);
-               mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf + strlen(buf),
-                              sizeof buf - strlen(buf), val);
-               sprintf(buf + strlen(buf), "%s", "\n");
-               mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, val);
-               mad_dump_field(IB_PORT_LINK_SPEED_ACTIVE_F, buf + strlen(buf),
-                              sizeof buf - strlen(buf), val);
-               sprintf(buf + strlen(buf), "%s", "\n");
-       } else {
-               mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val);
-               mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf, sizeof buf,
-                              val);
-               sprintf(buf + strlen(buf), "%s", "\n");
-       }
-
        printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf);
-       return 0;
 }

-static int set_port_info(ib_portid_t * dest, uint8_t * data, int portnum,
-                        int port_op)
+static void set_port_info(ib_portid_t * dest, uint8_t * data, int portnum)
 {
-       char buf[2048];
-       char val[64];
-
        if (!smp_set_via(data, dest, IB_ATTR_PORT_INFO, portnum, 0, srcport))
-               return -1;
+               IBERROR("smp set portinfo failed");

-       if (port_op != 4)
-               mad_dump_portstates(buf, sizeof buf, data, sizeof data);
-       else {
-               mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val);
-               mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf, sizeof buf,
-                              val);
-               sprintf(buf + strlen(buf), "%s", "\n");
-       }
-
        printf("\nAfter PortInfo set:\n");
-       printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf);
-       return 0;
+       show_port_info(dest, data, portnum);
 }

 static int get_link_width(int lwe, int lws)
@@ -201,22 +241,23 @@
        int mgmt_classes[3] =
            { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS };
        ib_portid_t portid = { 0 };
-       int err;
-       int port_op = 0;        /* default to query */
-       int speed = 15;
-       int is_switch = 1;
+       int port_op = -1;
+       int is_switch;
        int state, physstate, lwe, lws, lwa, lse, lss, lsa;
        int peerlocalportnum, peerlwe, peerlws, peerlwa, peerlse, peerlss,
            peerlsa;
-       int width = 255, peerwidth, peerspeed;
+       int peerwidth, peerspeed;
        uint8_t data[IB_SMP_DATA_SIZE];
        ib_portid_t peerportid = { 0 };
        int portnum = 0;
        ib_portid_t selfportid = { 0 };
        int selfport = 0;
-
+       int changed = 0;
+       int i;
+       long val;
        char usage_args[] = "<dest dr_path|lid|guid> <portnum> [<op>]\n"
-           "\nSupported ops: enable, disable, reset, speed, width, query";
+           "\nSupported ops: enable, disable, reset, speed, width, query,\n"
+           "\tdown, arm, active, vls, mtu, lid, smlid, lmc\n";
        const char *usage_examples[] = {
                "3 1 disable\t\t\t# by lid",
                "-G 0x2C9000100D051 1 enable\t# by guid",
@@ -224,6 +265,7 @@
                "3 1 reset\t\t\t# by lid",
                "3 1 speed 1\t\t\t# by lid",
                "3 1 width 1\t\t\t# by lid",
+               "-D 0 1 lid 0x1234 arm\t\t# by direct route",
                NULL
        };

@@ -247,78 +289,129 @@
        if (argc > 1)
                portnum = strtol(argv[1], 0, 0);

-       /* First, make sure it is a switch port if it is a "set" */
-       if (argc >= 3) {
-               if (!strcmp(argv[2], "enable"))
-                       port_op = 1;
-               else if (!strcmp(argv[2], "disable"))
-                       port_op = 2;
-               else if (!strcmp(argv[2], "reset"))
-                       port_op = 3;
-               else if (!strcmp(argv[2], "speed")) {
-                       if (argc < 4)
-                               IBERROR
-                                   ("speed requires an additional parameter");
-                       port_op = 4;
-                       /* Parse speed value */
-                       speed = strtoul(argv[3], 0, 0);
-                       if (speed > 15)
-                               IBERROR("invalid speed value %d", speed);
-               } else if (!strcmp(argv[2], "width")) {
-                       if (argc < 4)
-                               IBERROR
-                                   ("width requires an additional parameter");
-                       port_op = 5;
-                       /* Parse width value */
-                       width = strtoul(argv[3], 0, 0);
-                       if (width > 15 && width != 255)
-                               IBERROR("invalid width value %d", width);
+       for (i = 2; i < argc; i++) {
+               int j;
+
+               for (j = 0; j < NPORT_ARGS; j++) {
+                       if (strcmp(argv[i], port_args[j].name))
+                               continue;
+                       port_args[j].set = 1;
+                       if (!port_args[j].val) {
+                               if (port_op >= 0)
+                                       IBERROR("%s only one of: ",
+                                               "query, enable, disable, "
+                                               "reset, down, arm, active, "
+                                               "can be specified",
+                                               port_args[j].name);
+                               port_op = j;
+                               break;
+                       }
+                       if (++i >= argc)
+                               IBERROR("%s requires an additional parameter",
+                                       port_args[j].name);
+                       val = strtol(argv[i], 0, 0);
+                       switch (j) {
+                       case SPEED:
+                               if (val < 0 || val > 15)
+                                       IBERROR("invalid speed value %ld", val);
+                               break;
+                       case WIDTH:
+                               if (val < 0 || (val > 15 && val != 255))
+                                       IBERROR("invalid width value %ld", val);
+                               break;
+                       case VLS:
+                               if (val <= 0 || val > 5)
+                                       IBERROR("invalid vls value %ld", val);
+                               break;
+                       case MTU:
+                               if (val <= 0 || val > 5)
+                                       IBERROR("invalid mtu value %ld", val);
+                               break;
+                       case LID:
+                               if (val <= 0 || val >= 0xC000)
+                                       IBERROR("invalid lid value 0x%lx", val);
+                               break;
+                       case SMLID:
+                               if (val <= 0 || val >= 0xC000)
+                                       IBERROR("invalid smlid value 0x%lx",
+                                               val);
+                               break;
+                       case LMC:
+                               if (val < 0 || val > 7)
+                                       IBERROR("invalid lmc value %ld", val);
+                       }
+                       *port_args[j].val = (int)val;
+                       changed = 1;
+                       break;
                }
+               if (j == NPORT_ARGS)
+                       IBERROR("invalid operation: %s", argv[i]);
        }
+       if (port_op < 0)
+               port_op = QUERY;

-       err = get_node_info(&portid, data);
-       if (err < 0)
-               IBERROR("smp query nodeinfo failed");
-       if (err) {              /* not switch */
-               if (port_op == 0)       /* query op */
-                       is_switch = 0;
-               else if (port_op == 2)  /* disable */
-                       IBERROR("Node type not switch - disable not allowed");
-       }
+       is_switch = get_node_info(&portid, data);

-       if (port_op)
-               printf("Initial PortInfo:\n");
+       if (port_op != QUERY || changed)
+               printf("Initial %s PortInfo:\n", is_switch ? "Switch" : "CA");
        else
-               printf("PortInfo:\n");
-       err = get_port_info(&portid, data, portnum, port_op);
-       if (err < 0)
-               IBERROR("smp query portinfo failed");
+               printf("%s PortInfo:\n", is_switch ? "Switch" : "CA");
+       get_port_info(&portid, data, portnum);
+       show_port_info(&portid, data, portnum);

-       /* Only if one of the "set" options is chosen */
-       if (port_op) {
-               if ((port_op == 1) || (port_op == 3)) { /* Enable or Reset port */
-                       mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 2);        /* Polling */
-                       mad_set_field(data, 0, IB_PORT_STATE_F, 0);     /* No Change */
-               } else if (port_op == 2) {      /* Disable port */
+       if (port_op != QUERY || changed) {
+               /*
+                * If we aren't setting the LID and the LID is the default,
+                * the SMA command will fail due to an invalid LID.
+                * Set it to something unlikely but valid.
+                */
+               val = mad_get_field(data, 0, IB_PORT_LID_F);
+               if (!port_args[LID].set && (!val || val == 0xFFFF))
+                       mad_set_field(data, 0, IB_PORT_LID_F, 0x1234);
+               val = mad_get_field(data, 0, IB_PORT_SMLID_F);
+               if (!port_args[SMLID].set && (!val || val == 0xFFFF))
+                       mad_set_field(data, 0, IB_PORT_SMLID_F, 0x1234);
+               mad_set_field(data, 0, IB_PORT_STATE_F, 0);     /* NOP */
+               mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 0);        /* NOP */
+
+               switch (port_op) {
+               case ENABLE:
+               case RESET:
+                       /* Polling */
+                       mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 2);
+                       break;
+               case DISABLE:
                        printf("Disable may be irreversible\n");
-                       mad_set_field(data, 0, IB_PORT_STATE_F, 1);     /* Down */
-                       mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 3);        /* Disabled */
-               } else if (port_op == 4) {      /* Set speed */
-                       mad_set_field(data, 0, IB_PORT_LINK_SPEED_ENABLED_F,
-                                     speed);
-                       mad_set_field(data, 0, IB_PORT_STATE_F, 0);
-                       mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 0);
-               } else if (port_op == 5) {      /* Set width */
-                       mad_set_field(data, 0, IB_PORT_LINK_WIDTH_ENABLED_F,
-                                     width);
-                       mad_set_field(data, 0, IB_PORT_STATE_F, 0);
-                       mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 0);
+                       mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 3);
+                       break;
+               case DOWN:
+                       mad_set_field(data, 0, IB_PORT_STATE_F, 1);
+                       break;
+               case ARM:
+                       mad_set_field(data, 0, IB_PORT_STATE_F, 3);
+                       break;
+               case ACTIVE:
+                       mad_set_field(data, 0, IB_PORT_STATE_F, 4);
+                       break;
                }

-               err = set_port_info(&portid, data, portnum, port_op);
-               if (err < 0)
-                       IBERROR("smp set portinfo failed");
-               /* query op - only compare peer port if switch port, exclude SP0 */
+               /* always set enabled speed/width - defaults to NOP */
+               mad_set_field(data, 0, IB_PORT_LINK_SPEED_ENABLED_F, speed);
+               mad_set_field(data, 0, IB_PORT_LINK_WIDTH_ENABLED_F, width);
+
+               if (port_args[VLS].set)
+                       mad_set_field(data, 0, IB_PORT_OPER_VLS_F, vls);
+               if (port_args[MTU].set)
+                       mad_set_field(data, 0, IB_PORT_NEIGHBOR_MTU_F, mtu);
+               if (port_args[LID].set)
+                       mad_set_field(data, 0, IB_PORT_LID_F, lid);
+               if (port_args[SMLID].set)
+                       mad_set_field(data, 0, IB_PORT_SMLID_F, smlid);
+               if (port_args[LMC].set)
+                       mad_set_field(data, 0, IB_PORT_LMC_F, lmc);
+
+               set_port_info(&portid, data, portnum);
+
        } else if (is_switch && portnum) {
                /* Now, make sure PortState is Active */
                /* Or is PortPhysicalState LinkUp sufficient ? */
@@ -351,20 +444,15 @@
                        peerportid.drpath.drdlid = 0xffff;

                        /* Get peer port NodeInfo to obtain peer port number */
-                       err = get_node_info(&peerportid, data);
-                       if (err < 0)
-                               IBERROR("smp query nodeinfo failed");
+                       get_node_info(&peerportid, data);

                        mad_decode_field(data, IB_NODE_LOCAL_PORT_F,
                                         &peerlocalportnum);

                        printf("Peer PortInfo:\n");
                        /* Get peer port characteristics */
-                       err =
-                           get_port_info(&peerportid, data, peerlocalportnum,
-                                         port_op);
-                       if (err < 0)
-                               IBERROR("smp query peer portinfo failed");
+                       get_port_info(&peerportid, data, peerlocalportnum);
+                       show_port_info(&peerportid, data, peerlocalportnum);

                        mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F,
                                         &peerlwe);
Index: tools/infiniband-diags/src/ibqueryerrors.c
===================================================================
--- tools/infiniband-diags/src/ibqueryerrors.c  (revision 2812)
+++ tools/infiniband-diags/src/ibqueryerrors.c  (working copy)
@@ -1,7 +1,8 @@
 /*
- * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
  * Copyright (c) 2008 Lawrence Livermore National Lab.  All rights reserved.
+ * Copyright (c) 2009 HNR Consulting.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -57,29 +58,30 @@
 struct ibmad_port *ibmad_port;
 static char *node_name_map_file = NULL;
 static nn_map_t *node_name_map = NULL;
+static char *load_cache_file = NULL;
+
 int data_counters = 0;
 int port_config = 0;
 uint64_t node_guid = 0;
 char *node_guid_str = NULL;
+#define SUP_MAX 64
 int sup_total = 0;
-enum MAD_FIELDS *suppressed_fields = NULL;
+enum MAD_FIELDS suppressed_fields[SUP_MAX];
 char *dr_path = NULL;
 uint8_t node_type_to_print = 0;
+unsigned clear_errors = 0, clear_counts = 0, details = 0;

 #define PRINT_SWITCH 0x1
 #define PRINT_CA     0x2
 #define PRINT_ROUTER 0x4
-#define PRINT_ALL 0xFF /* all nodes default flag */
+#define PRINT_ALL 0xFF         /* all nodes default flag */

 static unsigned int get_max(unsigned int num)
 {
-       unsigned int v = num;   // 32-bit word to find the log base 2 of
-       unsigned r = 0;         // r will be lg(v)
+       unsigned r = 0;         // r will be lg(num)

-       while (v >>= 1)         // unroll for more speed...
-       {
+       while (num >>= 1)       // unroll for more speed...
                r++;
-       }

        return (1 << r);
 }
@@ -95,29 +97,27 @@
                                     & mad_get_field(port->remoteport->info, 0,
                                                     IB_PORT_LINK_WIDTH_SUPPORTED_F));
        if ((max_width & mad_get_field(port->info, 0,
-                                      IB_PORT_LINK_WIDTH_ACTIVE_F)) == 0) {
+                                      IB_PORT_LINK_WIDTH_ACTIVE_F)) == 0)
                // we are not at the max supported width
                // print what we could be at.
                snprintf(width_msg, msg_size, "Could be %s",
                         mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F,
                                      buf, 64, &max_width));
-       }

        max_speed = get_max(mad_get_field(port->info, 0,
                                          IB_PORT_LINK_SPEED_SUPPORTED_F)
                            & mad_get_field(port->remoteport->info, 0,
                                            IB_PORT_LINK_SPEED_SUPPORTED_F));
        if ((max_speed & mad_get_field(port->info, 0,
-                                      IB_PORT_LINK_SPEED_ACTIVE_F)) == 0) {
+                                      IB_PORT_LINK_SPEED_ACTIVE_F)) == 0)
                // we are not at the max supported speed
                // print what we could be at.
                snprintf(speed_msg, msg_size, "Could be %s",
                         mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F,
                                      buf, 64, &max_speed));
-       }
 }

-static void print_port_config(ibnd_node_t * node, int portnum)
+static void print_port_config(char *node_name, ibnd_node_t * node, int portnum)
 {
        char width[64], speed[64], state[64], physstate[64];
        char remote_str[256];
@@ -142,16 +142,23 @@
        width_msg[0] = '\0';
        speed_msg[0] = '\0';

-       snprintf(link_str, 256, "(%3s %s %6s/%8s)",
-                mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, width, 64, &iwidth),
-                mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, speed, 64, &ispeed),
-                mad_dump_val(IB_PORT_STATE_F, state, 64, &istate),
-                mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64, &iphystate));
+       /* C14-24.2.1 states that a down port allows for invalid data to be
+        * returned for all PortInfo components except PortState and
+        * PortPhysicalState */
+       if (istate != IB_LINK_DOWN) {
+               snprintf(link_str, 256, "(%3s %9s %6s/%8s)",
+                        mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, width, 64, &iwidth),
+                        mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, speed, 64, &ispeed),
+                        mad_dump_val(IB_PORT_STATE_F, state, 64, &istate),
+                        mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64, &iphystate));
+       } else {
+               snprintf(link_str, 256, "(              %6s/%8s)",
+                        mad_dump_val(IB_PORT_STATE_F, state, 64, &istate),
+                        mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64, &iphystate));
+       }

        if (port->remoteport) {
-               char *remap =
-                   remap_node_name(node_name_map, port->remoteport->node->guid,
-                                   port->remoteport->node->nodedesc);
+               char *rem_node_name = NULL;

                if (port->remoteport->ext_portnum)
                        snprintf(ext_port_str, 256, "%d",
@@ -161,14 +168,20 @@

                get_msg(width_msg, speed_msg, 256, port);

+               rem_node_name = remap_node_name(node_name_map,
+                                               port->remoteport->node->guid,
+                                               port->remoteport->node->
+                                               nodedesc);
+
                snprintf(remote_str, 256,
                         "0x%016" PRIx64 " %6d %4d[%2s] \"%s\" (%s %s)\n",
                         port->remoteport->node->guid,
                         port->remoteport->base_lid ? port->remoteport->
                         base_lid : port->remoteport->node->smalid,
-                        port->remoteport->portnum, ext_port_str, remap,
+                        port->remoteport->portnum, ext_port_str, rem_node_name,
                         width_msg, speed_msg);
-               free(remap);
+
+               free(rem_node_name);
        } else
                snprintf(remote_str, 256, "           [  ] \"\" ( )\n");

@@ -189,50 +202,95 @@
 static int suppress(enum MAD_FIELDS field)
 {
        int i = 0;
-       if (suppressed_fields)
-               for (i = 0; i < sup_total; i++) {
-                       if (field == suppressed_fields[i])
-                               return (1);
-               }
-       return (0);
+       for (i = 0; i < sup_total; i++)
+               if (field == suppressed_fields[i])
+                       return 1;
+       return 0;
 }

 static void report_suppressed(void)
 {
        int i = 0;
-       if (suppressed_fields) {
-               printf("Suppressing:");
-               for (i = 0; i < sup_total; i++) {
-                       printf(" %s", mad_field_name(suppressed_fields[i]));
-               }
-               printf("\n");
+       printf("Suppressing:");
+       for (i = 0; i < sup_total; i++)
+               printf(" %s", mad_field_name(suppressed_fields[i]));
+       printf("\n");
+}
+
+static int query_and_dump(char *buf, size_t size, ib_portid_t * portid,
+                         ibnd_node_t * node, char *node_name, int portnum,
+                         const char *attr_name, uint16_t attr_id,
+                         int start_field, int end_field)
+{
+       uint8_t pc[1024];
+       uint32_t val = 0;
+       int i, n;
+
+       memset(pc, 0, sizeof(pc));
+
+       if (!pma_query_via(pc, portid, portnum, ibd_timeout, attr_id,
+                          ibmad_port)) {
+               IBWARN("%s query failed on %s, %s port %d", attr_name,
+                      node_name, portid2str(portid), portnum);
+               return 0;
        }
+
+       for (n = 0, i = start_field; i < end_field; i++) {
+               mad_decode_field(pc, i, (void *)&val);
+               if (val)
+                       n += snprintf(buf + n, size - n, " [%s == %u]",
+                                     mad_field_name(i), val);
+       }
+
+       return n;
 }

-static void print_results(ibnd_node_t * node, uint8_t * pc, int portnum,
+static void print_results(ib_portid_t * portid, char *node_name,
+                         ibnd_node_t * node, uint8_t * pc, int portnum,
                          int *header_printed)
 {
        char buf[1024];
        char *str = buf;
        uint32_t val = 0;
-       int n = 0;
-       int i = 0;
+       int i, n;

        for (n = 0, i = IB_PC_ERR_SYM_F; i <= IB_PC_VL15_DROPPED_F; i++) {
                if (suppress(i))
                        continue;

+               /* this is not a counter, skip it */
+               if (i == IB_PC_COUNTER_SELECT2_F)
+                       continue;
+
                mad_decode_field(pc, i, (void *)&val);
                if (val)
-                       n += snprintf(str + n, 1024 - n, " [%s == %d]",
+                       n += snprintf(str + n, 1024 - n, " [%s == %u]",
                                      mad_field_name(i), val);
+
+               /* If there are PortXmitDiscards, get details (if supported) */
+               if (i == IB_PC_XMT_DISCARDS_F && details && val) {
+                       n += query_and_dump(str + n, sizeof(buf) - n, portid,
+                                           node, node_name, portnum,
+                                           "PortXmitDiscardDetails",
+                                           IB_GSI_PORT_XMIT_DISCARD_DETAILS,
+                                           IB_PC_RCV_LOCAL_PHY_ERR_F,
+                                           IB_PC_RCV_ERR_LAST_F);
+                       /* If there are PortRcvErrors, get details (if supported) */
+               } else if (i == IB_PC_ERR_RCV_F && details && val) {
+                       n += query_and_dump(str + n, sizeof(buf) - n, portid,
+                                           node, node_name, portnum,
+                                           "PortRcvErrorDetails",
+                                           IB_GSI_PORT_RCV_ERROR_DETAILS,
+                                           IB_PC_XMT_INACT_DISC_F,
+                                           IB_PC_XMT_DISC_LAST_F);
+               }
        }

        if (!suppress(IB_PC_XMT_WAIT_F)) {
                mad_decode_field(pc, IB_PC_XMT_WAIT_F, (void *)&val);
                if (val)
-                       n += snprintf(str + n, 1024 - n, " [%s == %d]",
-                                     mad_field_name(i), val);
+                       n += snprintf(str + n, 1024 - n, " [%s == %u]",
+                                     mad_field_name(IB_PC_XMT_WAIT_F), val);
        }

        /* if we found errors. */
@@ -243,65 +301,97 @@
                                mad_decode_field(pc, i, (void *)&val64);
                                if (val64)
                                        n += snprintf(str + n, 1024 - n,
-                                                     " [%s == %" PRId64 "]",
+                                                     " [%s == %" PRIu64 "]",
                                                      mad_field_name(i), val64);
                        }

                if (!*header_printed) {
-                       char *nodename =
-                           remap_node_name(node_name_map, node->guid,
-                                           node->nodedesc);
                        printf("Errors for 0x%" PRIx64 " \"%s\"\n", node->guid,
-                              nodename);
+                              node_name);
                        *header_printed = 1;
-                       free(nodename);
                }

                printf("   GUID 0x%" PRIx64 " port %d:%s\n", node->guid,
                       portnum, str);
                if (port_config)
-                       print_port_config(node, portnum);
+                       print_port_config(node_name, node, portnum);
        }
 }

-static void print_port(ibnd_node_t * node, int portnum, int *header_printed)
+static int query_cap_mask(ib_portid_t * portid, char *node_name, int portnum,
+                         uint16_t * cap_mask)
 {
        uint8_t pc[1024];
-       uint16_t cap_mask;
-       ib_portid_t portid = { 0 };
-       char *nodename =
-           remap_node_name(node_name_map, node->guid, node->nodedesc);
+       uint16_t rc_cap_mask;

-       if (node->type == IB_NODE_SWITCH)
-               ib_portid_set(&portid, node->smalid, 0, 0);
-       else
-               ib_portid_set(&portid, node->ports[portnum]->base_lid, 0, 0);
-
        /* PerfMgt ClassPortInfo is a required attribute */
-       if (!pma_query_via(pc, &portid, portnum, ibd_timeout, CLASS_PORT_INFO,
+       if (!pma_query_via(pc, portid, portnum, ibd_timeout, CLASS_PORT_INFO,
                           ibmad_port)) {
                IBWARN("classportinfo query failed on %s, %s port %d",
-                      nodename, portid2str(&portid), portnum);
-               goto cleanup;
+                      node_name, portid2str(portid), portnum);
+               return -1;
        }
+
        /* ClassPortInfo should be supported as part of libibmad */
-       memcpy(&cap_mask, pc + 2, sizeof(cap_mask));    /* CapabilityMask */
+       memcpy(&rc_cap_mask, pc + 2, sizeof(rc_cap_mask));      /* CapabilityMask */

-       if (!pma_query_via(pc, &portid, portnum, ibd_timeout,
+       *cap_mask = ntohs(rc_cap_mask);
+       return 0;
+}
+
+static void print_port(ib_portid_t * portid, uint16_t cap_mask, char *node_name,
+                      ibnd_node_t * node, int portnum, int *header_printed)
+{
+       uint8_t pc[1024];
+
+       memset(pc, 0, 1024);
+
+       if (!pma_query_via(pc, portid, portnum, ibd_timeout,
                           IB_GSI_PORT_COUNTERS, ibmad_port)) {
-               IBWARN("IB_GSI_PORT_COUNTERS query failed on %s, %s port %d\n",
-                      nodename, portid2str(&portid), portnum);
-               goto cleanup;
+               IBWARN("IB_GSI_PORT_COUNTERS query failed on %s, %s port %d",
+                      node_name, portid2str(portid), portnum);
+               return;
        }
        if (!(cap_mask & 0x1000)) {
-               /* if PortCounters:PortXmitWait not suppported clear this counter */
+               /* if PortCounters:PortXmitWait not supported clear this counter */
                uint32_t foo = 0;
                mad_encode_field(pc, IB_PC_XMT_WAIT_F, &foo);
        }
-       print_results(node, pc, portnum, header_printed);
+       print_results(portid, node_name, node, pc, portnum, header_printed);
+}

-cleanup:
-       free(nodename);
+static void clear_port(ib_portid_t * portid, uint16_t cap_mask,
+                      char *node_name, int port)
+{
+       uint8_t pc[1024];
+       /* bits defined in Table 228 PortCounters CounterSelect and
+        * CounterSelect2
+        */
+       uint32_t mask = 0;
+
+       if (!clear_errors && !clear_counts)
+               return;
+
+       if (clear_errors) {
+               mask |= 0xFFF;
+               if (cap_mask & 0x1000)
+                       mask |= 0x10000;
+       }
+       if (clear_counts)
+               mask |= 0xF000;
+
+       if (!performance_reset_via(pc, portid, port, mask, ibd_timeout,
+                                  IB_GSI_PORT_COUNTERS, ibmad_port))
+               IBERROR("Failed to reset errors %s port %d", node_name, port);
+
+       if (details && clear_errors) {
+               performance_reset_via(pc, portid, port, 0xf, ibd_timeout,
+                                     IB_GSI_PORT_XMIT_DISCARD_DETAILS,
+                                     ibmad_port);
+               performance_reset_via(pc, portid, port, 0x3f, ibd_timeout,
+                                     IB_GSI_PORT_RCV_ERROR_DETAILS,
+                                     ibmad_port);
+       }
 }

 void print_node(ibnd_node_t * node, void *user_data)
@@ -310,6 +400,10 @@
        int p = 0;
        int startport = 1;
        int type = 0;
+       int all_port_sup = 0;
+       ib_portid_t portid = { 0 };
+       uint16_t cap_mask = 0;
+       char *node_name = NULL;

        switch (node->type) {
        case IB_NODE_SWITCH:
@@ -329,18 +423,44 @@
        if (node->type == IB_NODE_SWITCH && node->smaenhsp0)
                startport = 0;

+       node_name = remap_node_name(node_name_map, node->guid, node->nodedesc);
+
        for (p = startport; p <= node->numports; p++) {
                if (node->ports[p]) {
-                       print_port(node, p, &header_printed);
+                       if (node->type == IB_NODE_SWITCH)
+                               ib_portid_set(&portid, node->smalid, 0, 0);
+                       else
+                               ib_portid_set(&portid, node->ports[p]->base_lid,
+                                             0, 0);
+
+                       if (query_cap_mask(&portid, node_name, p, &cap_mask) <
+                           0)
+                               continue;
+
+                       if (cap_mask & 0x100)
+                               all_port_sup = 1;
+
+                       print_port(&portid, cap_mask, node_name, node, p,
+                                  &header_printed);
+                       if (!all_port_sup)
+                               clear_port(&portid, cap_mask, node_name, p);
                }
        }
+
+       if (all_port_sup)
+               clear_port(&portid, cap_mask, node_name, 0xFF);
+
+       free(node_name);
 }

 static void add_suppressed(enum MAD_FIELDS field)
 {
-       suppressed_fields = realloc(suppressed_fields, sizeof(enum MAD_FIELDS));
-       suppressed_fields[sup_total] = field;
-       sup_total++;
+       if (sup_total >= SUP_MAX) {
+               IBWARN("Maximum (%d) fields have been suppressed; skipping %s",
+                      sup_total, mad_field_name(field));
+               return;
+       }
+       suppressed_fields[sup_total++] = field;
 }

 static void calculate_suppressed_fields(char *str)
@@ -351,11 +471,9 @@

        val = strtok_r(tmp, ",", &lasts);
        while (val) {
-               for (f = IB_PC_FIRST_F; f <= IB_PC_LAST_F; f++) {
-                       if (strcmp(val, mad_field_name(f)) == 0) {
+               for (f = IB_PC_FIRST_F; f <= IB_PC_LAST_F; f++)
+                       if (strcmp(val, mad_field_name(f)) == 0)
                                add_suppressed(f);
-                       }
-               }
                val = strtok_r(NULL, ",", &lasts);
        }

@@ -364,6 +482,7 @@

 static int process_opt(void *context, int ch, char *optarg)
 {
+       struct ibnd_config *cfg = context;
        switch (ch) {
        case 's':
                calculate_suppressed_fields(optarg);
@@ -387,6 +506,12 @@
        case 5:
                node_type_to_print |= PRINT_ROUTER;
                break;
+       case 6:
+               details = 1;
+               break;
+       case 7:
+               load_cache_file = strdup(optarg);
+               break;
        case 'G':
        case 'S':
                node_guid_str = optarg;
@@ -400,6 +525,15 @@
                break;
        case 'R':               /* nop */
                break;
+       case 'k':
+               clear_errors = 1;
+               break;
+       case 'K':
+               clear_counts = 1;
+               break;
+       case 'o':
+               cfg->max_smps = strtoul(optarg, NULL, 0);
+               break;
        default:
                return -1;
        }
@@ -409,6 +543,7 @@

 int main(int argc, char **argv)
 {
+       struct ibnd_config config = { 0 };
        int resolved = -1;
        ib_portid_t portid = { 0 };
        int rc = 0;
@@ -437,11 +572,22 @@
                {"switch", 3, 0, NULL, "print data for switches only"},
                {"ca", 4, 0, NULL, "print data for CA's only"},
                {"router", 5, 0, NULL, "print data for routers only"},
+               {"details", 6, 0, NULL, "include transmit discard details"},
+               {"clear-errors", 'k', 0, NULL,
+                "Clear error counters after read"},
+               {"clear-counts", 'K', 0, NULL,
+                "Clear data counters after read"},
+               {"load-cache", 7, 1, "<file>",
+                "filename of ibnetdiscover cache to load"},
+               {"outstanding_smps", 'o', 1, NULL,
+                "specify the number of outstanding SMP's which should be "
+                "issued during the scan"},
                {0}
        };
        char usage_args[] = "";

-       ibdiag_process_opts(argc, argv, NULL, "scnSrRDGL", opts, process_opt,
+       memset(suppressed_fields, 0, sizeof suppressed_fields);
+       ibdiag_process_opts(argc, argv, &config, "scnSrRDGL", opts, process_opt,
                            usage_args, NULL);

        argc -= optind;
@@ -450,47 +596,59 @@
        if (!node_type_to_print)
                node_type_to_print = PRINT_ALL;

-       if (ibverbose)
-               ibnd_debug(1);
-
        ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 4);
        if (!ibmad_port)
                IBERROR("Failed to open port; %s:%d\n", ibd_ca, ibd_ca_port);

-       if (ibd_timeout)
+       if (ibd_timeout) {
                mad_rpc_set_timeout(ibmad_port, ibd_timeout);
+               config.timeout_ms = ibd_timeout;
+       }

        node_name_map = open_node_name_map(node_name_map_file);

+       if (dr_path && load_cache_file) {
+               fprintf(stderr, "Cannot specify cache and direct route path\n");
+               exit(1);
+       }
+
        /* limit the scan the fabric around the target */
        if (dr_path) {
                if ((resolved =
                     ib_resolve_portid_str_via(&portid, dr_path, IB_DEST_DRPATH,
                                               NULL, ibmad_port)) < 0)
-                       IBWARN("Failed to resolve %s; attempting full scan\n",
+                       IBWARN("Failed to resolve %s; attempting full scan",
                               dr_path);
        } else if (node_guid_str) {
                if ((resolved =
                     ib_resolve_portid_str_via(&portid, node_guid_str,
                                               IB_DEST_GUID, ibd_sm_id,
                                               ibmad_port)) < 0)
-                       IBWARN("Failed to resolve %s; attempting full scan\n",
+                       IBWARN("Failed to resolve %s; attempting full scan",
                               node_guid_str);
        }

-       if (resolved >= 0)
-               if ((fabric = ibnd_discover_fabric(ibmad_port, &portid,
-                                                  0)) == NULL)
-                       IBWARN
-                           ("Single node discover failed; attempting full scan\n");
+       if (load_cache_file) {
+               if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL) {
+                       fprintf(stderr, "loading cached fabric failed\n");
+                       exit(1);
+               }
+       } else {
+               if (resolved >= 0 &&
+                   !(fabric = ibnd_discover_fabric(ibd_ca, ibd_ca_port,
+                                                   &portid, &config)))
+                       IBWARN("Single node discover failed;"
+                              " attempting full scan");

-       if (!fabric)            /* do a full scan */
-               if ((fabric =
-                    ibnd_discover_fabric(ibmad_port, NULL, -1)) == NULL) {
+               if (!fabric && !(fabric = ibnd_discover_fabric(ibd_ca,
+                                                              ibd_ca_port,
+                                                              NULL,
+                                                              &config))) {
                        fprintf(stderr, "discover failed\n");
                        rc = 1;
                        goto close_port;
                }
+       }

        report_suppressed();

@@ -506,8 +664,10 @@
                uint8_t ni[IB_SMP_DATA_SIZE];

                if (!smp_query_via(ni, &portid, IB_ATTR_NODE_INFO, 0,
-                                  ibd_timeout, ibmad_port))
-                       return -1;
+                                  ibd_timeout, ibmad_port)) {
+                       rc = -1;
+                       goto destroy_fabric;
+               }
                mad_decode_field(ni, IB_NODE_GUID_F, &(node_guid));

                node = ibnd_find_node_guid(fabric, node_guid);
@@ -518,6 +678,7 @@
        } else
                ibnd_iter_nodes(fabric, print_node, NULL);

+destroy_fabric:
        ibnd_destroy_fabric(fabric);

 close_port:
Index: tools/infiniband-diags/src/ibqueryerrors/SOURCES
===================================================================
--- tools/infiniband-diags/src/ibqueryerrors/SOURCES    (revision 2812)
+++ tools/infiniband-diags/src/ibqueryerrors/SOURCES    (working copy)
@@ -20,6 +20,7 @@

 TARGETLIBS = \
        $(SDK_LIB_PATH)\kernel32.lib    \
+       $(SDK_LIB_PATH)\ws2_32.lib              \
 !if $(FREEBUILD)
        $(TARGETPATH)\*\complib.lib             \
        $(TARGETPATH)\*\libibmad.lib    \
Index: tools/infiniband-diags/src/ibroute.c
===================================================================
--- tools/infiniband-diags/src/ibroute.c        (revision 2812)
+++ tools/infiniband-diags/src/ibroute.c        (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  * Copyright (c) 2009 Mellanox Technologies LTD.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -142,7 +142,7 @@
        uint64_t nodeguid;
        uint32_t mod;
        unsigned block, i, j, e, nports, cap, chunks, startblock, lastblock,
-                top;
+           top;
        int n = 0;

        if ((s = check_switch(portid, &nports, &nodeguid, sw, nd)))
Index: tools/infiniband-diags/src/ibsendtrap.c
===================================================================
--- tools/infiniband-diags/src/ibsendtrap.c     (revision 2812)
+++ tools/infiniband-diags/src/ibsendtrap.c     (working copy)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2008 Lawrence Livermore National Security
- * Copyright (c) 2009 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2008-2009 Voltaire Inc.  All rights reserved.
  * Copyright (c) 2009 HNR Consulting.  All rights reserved.
  *
  * Produced at Lawrence Livermore National Laboratory.
@@ -73,6 +73,15 @@
        return cap_mask;
 }

+static void build_trap145(ib_mad_notice_attr_t * n, ib_portid_t * port)
+{
+       n->generic_type = 0x80 | IB_NOTICE_TYPE_INFO;
+       n->g_or_v.generic.prod_type_lsb = cl_hton16(get_node_type(port));
+       n->g_or_v.generic.trap_num = cl_hton16(145);
+       n->issuer_lid = cl_hton16((uint16_t) port->lid);
+       n->data_details.ntc_145.new_sys_guid = cl_hton64(0x1234567812345678);
+}
+
 static void build_trap144_local(ib_mad_notice_attr_t * n, ib_portid_t * port)
 {
        n->generic_type = 0x80 | IB_NOTICE_TYPE_INFO;
@@ -149,6 +158,7 @@
        {"node_desc_change", build_trap144_nodedesc},
        {"link_speed_enabled_change", build_trap144_linkspeed},
        {"local_link_integrity", build_trap129},
+       {"sys_image_guid_change", build_trap145},
        {NULL, NULL}
 };

Index: tools/infiniband-diags/src/ibstat.c
===================================================================
--- tools/infiniband-diags/src/ibstat.c (revision 2812)
+++ tools/infiniband-diags/src/ibstat.c (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -124,6 +124,7 @@
        printf("%sCapability mask: 0x%08x\n", pre, ntohl(port->capmask));
        printf("%sPort GUID: 0x%016llx\n", pre,
               (long long unsigned)ntohll(port->port_guid));
+       printf("%sLink layer: %s\n", pre, port->link_layer);
        return 0;
 }

@@ -142,9 +143,8 @@
                if (portnum > ca.numports || !ca.ports[portnum]) {
                        IBWARN("%s: '%s' has no port number %d - max (%d)",
                               ((unsigned)ca.node_type <=
-                               IB_NODE_MAX ? node_type_str[ca.
-                                                           node_type] : "???"),
-                              ca_name, portnum, ca.numports);
+                               IB_NODE_MAX ? node_type_str[ca.node_type] :
+                               "???"), ca_name, portnum, ca.numports);
                        return -1;
                }
                printf("%s: '%s'\n",
Index: tools/infiniband-diags/src/ibsysstat.c
===================================================================
--- tools/infiniband-diags/src/ibsysstat.c      (revision 2812)
+++ tools/infiniband-diags/src/ibsysstat.c      (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
Index: tools/infiniband-diags/src/ibtracert.c
===================================================================
--- tools/infiniband-diags/src/ibtracert.c      (revision 2812)
+++ tools/infiniband-diags/src/ibtracert.c      (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  * Copyright (c) 2009 HNR Consulting.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -659,17 +659,15 @@
                        printf("[%d] -> %s {0x%016" PRIx64 "}[%d]\n",
                               node->ports->remoteport->portnum,
                               (node->type <=
-                               IB_NODE_MAX ? node_type_str[node->
-                                                           type] : "???"),
-                              node->nodeguid, node->upport);
+                               IB_NODE_MAX ? node_type_str[node->type] :
+                               "???"), node->nodeguid, node->upport);
                else
                        printf("[%d] -> %s 0x%" PRIx64 "[%d] lid %u \"%s\"\n",
                               node->ports->remoteport->portnum,
                               (node->type <=
-                               IB_NODE_MAX ? node_type_str[node->
-                                                           type] : "???"),
-                              node->nodeguid, node->upport, node->ports->lid,
-                              nodename);
+                               IB_NODE_MAX ? node_type_str[node->type] :
+                               "???"), node->nodeguid, node->upport,
+                              node->ports->lid, nodename);
        }

        if (node->dist < 0)
Index: tools/infiniband-diags/src/mcm_rereg_test.c
===================================================================
--- tools/infiniband-diags/src/mcm_rereg_test.c (revision 2812)
+++ tools/infiniband-diags/src/mcm_rereg_test.c (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2006-2009 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
Index: tools/infiniband-diags/src/perfquery.c
===================================================================
--- tools/infiniband-diags/src/perfquery.c      (revision 2812)
+++ tools/infiniband-diags/src/perfquery.c      (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
  * Copyright (c) 2009 HNR Consulting.  All rights reserved.
  *
@@ -293,8 +293,8 @@
                        IBERROR("perfquery");
                if (!(cap_mask & 0x1000)) {
                        /* if PortCounters:PortXmitWait not supported clear this counter */
-                       IBWARN
-                           ("PortXmitWait not indicated so ignore this counter");
+                       VERBOSE("PortXmitWait not indicated"
+                               " so ignore this counter");
                        perf_count.xmtwait = 0;
                        mad_encode_field(pc, IB_PC_XMT_WAIT_F,
                                         &perf_count.xmtwait);
@@ -302,7 +302,10 @@
                if (aggregate)
                        aggregate_perfcounters();
                else
-                       mad_dump_perfcounters(buf, sizeof buf, pc, sizeof pc);
+                       mad_dump_fields(buf, sizeof buf, pc, sizeof pc,
+                                                       IB_PC_FIRST_F,
+                                                       (cap_mask & 0x1000)?IB_PC_LAST_F:(IB_PC_RCV_PKTS_F+1));
+
        } else {
                if (!(cap_mask & 0x200))        /* 1.2 errata: bit 9 is extended counter support */
                        IBWARN
@@ -344,56 +347,70 @@
 }

 static int reset, reset_only, all_ports, loop_ports, port, extended, xmt_sl,
-    rcv_sl;
+    rcv_sl, xmt_disc, rcv_err, smpl_ctl;

-void xmt_sl_query(ib_portid_t * portid, int port, int mask)
+static void common_func(ib_portid_t * portid, int port_num, int mask,
+                       unsigned query, unsigned reset,
+                       const char *name, uint16_t attr,
+                       void dump_func(char *, int, void *, int))
 {
        char buf[1024];

-       if (reset_only) {
-               if (!performance_reset_via(pc, portid, port, mask, ibd_timeout,
-                                          IB_GSI_PORT_XMIT_DATA_SL, srcport))
-                       IBERROR("perfslreset");
-               return;
+       if (query) {
+               if (!pma_query_via(pc, portid, port_num, ibd_timeout, attr,
+                                  srcport))
+                       IBERROR("cannot query %s", name);
+
+               dump_func(buf, sizeof(buf), pc, sizeof(pc));
+
+               printf("# %s counters: %s port %d\n%s", name,
+                      portid2str(portid), port_num, buf);
        }

-       if (!pma_query_via(pc, portid, port, ibd_timeout,
-                          IB_GSI_PORT_XMIT_DATA_SL, srcport))
-               IBERROR("perfslquery");
+       if (reset && !performance_reset_via(pc, portid, port, mask, ibd_timeout,
+                                           attr, srcport))
+               IBERROR("cannot reset %s", name);
+}

-       mad_dump_perfcounters_xmt_sl(buf, sizeof buf, pc, sizeof pc);
-       printf("# PortXmitDataSL counters: %s port %d\n%s", portid2str(portid),
-              port, buf);
+static void xmt_sl_query(ib_portid_t * portid, int port, int mask)
+{
+       common_func(portid, port, mask, !reset_only, (reset_only || reset),
+                   "PortXmitDataSL", IB_GSI_PORT_XMIT_DATA_SL,
+                   mad_dump_perfcounters_xmt_sl);
+}

-       if (reset)
-               if (!performance_reset_via(pc, portid, port, mask, ibd_timeout,
-                                          IB_GSI_PORT_XMIT_DATA_SL, srcport))
-                       IBERROR("perfslreset");
+static void rcv_sl_query(ib_portid_t * portid, int port, int mask)
+{
+       common_func(portid, port, mask, !reset_only, (reset_only || reset),
+                   "PortRcvDataSL", IB_GSI_PORT_RCV_DATA_SL,
+                   mad_dump_perfcounters_rcv_sl);
 }

-void rcv_sl_query(ib_portid_t * portid, int port, int mask)
+static void xmt_disc_query(ib_portid_t * portid, int port, int mask)
 {
+       common_func(portid, port, mask, !reset_only, (reset_only || reset),
+                   "PortXmitDiscardDetails", IB_GSI_PORT_XMIT_DISCARD_DETAILS,
+                   mad_dump_perfcounters_xmt_disc);
+}
+
+static void rcv_err_query(ib_portid_t * portid, int port, int mask)
+{
+       common_func(portid, port, mask, !reset_only, (reset_only || reset),
+                   "PortRcvErrorDetails", IB_GSI_PORT_RCV_ERROR_DETAILS,
+                   mad_dump_perfcounters_rcv_err);
+}
+
+void dump_portsamples_control(ib_portid_t * portid, int port)
+{
        char buf[1024];

-       if (reset_only) {
-               if (!performance_reset_via(pc, portid, port, mask, ibd_timeout,
-                                          IB_GSI_PORT_RCV_DATA_SL, srcport))
-                       IBERROR("perfslreset");
-               return;
-       }
-
        if (!pma_query_via(pc, portid, port, ibd_timeout,
-                          IB_GSI_PORT_RCV_DATA_SL, srcport))
-               IBERROR("perfslquery");
+                          IB_GSI_PORT_SAMPLES_CONTROL, srcport))
+               IBERROR("sampctlquery");

-       mad_dump_perfcounters_rcv_sl(buf, sizeof buf, pc, sizeof pc);
-       printf("# PortRcvDataSL counters: %s port %d\n%s", portid2str(portid),
+       mad_dump_portsamples_control(buf, sizeof buf, pc, sizeof pc);
+       printf("# PortSamplesControl: %s port %d\n%s", portid2str(portid),
               port, buf);
-
-       if (reset)
-               if (!performance_reset_via(pc, portid, port, mask, ibd_timeout,
-                                          IB_GSI_PORT_RCV_DATA_SL, srcport))
-                       IBERROR("perfslreset");
 }

 static int process_opt(void *context, int ch, char *optarg)
@@ -408,6 +425,15 @@
        case 'S':
                rcv_sl = 1;
                break;
+       case 'D':
+               xmt_disc = 1;
+               break;
+       case 'E':
+               rcv_err = 1;
+               break;
+       case 'c':
+               smpl_ctl = 1;
+               break;
        case 'a':
                all_ports++;
                port = ALL_PORTS;
@@ -446,6 +472,9 @@
                {"extended", 'x', 0, NULL, "show extended port counters"},
                {"xmtsl", 'X', 0, NULL, "show Xmt SL port counters"},
                {"rcvsl", 'S', 0, NULL, "show Rcv SL port counters"},
+               {"xmtdisc", 'D', 0, NULL, "show Xmt Discard Details"},
+               {"rcverr", 'E', 0, NULL, "show Rcv Error Details"},
+               {"smplctl", 'c', 0, NULL, "show samples control"},
                {"all_ports", 'a', 0, NULL, "show aggregated counters"},
                {"loop_ports", 'l', 0, NULL, "iterate through each port"},
                {"reset_after_read", 'r', 0, NULL, "reset counters after read"},
@@ -516,6 +545,21 @@
                goto done;
        }

+       if (xmt_disc) {
+               xmt_disc_query(&portid, port, mask);
+               goto done;
+       }
+
+       if (rcv_err) {
+               rcv_err_query(&portid, port, mask);
+               goto done;
+       }
+
+       if (smpl_ctl) {
+               dump_portsamples_control(&portid, port);
+               goto done;
+       }
+
        if (all_ports_loop || (loop_ports && (all_ports || port == ALL_PORTS))) {
                if (smp_query_via(data, &portid, IB_ATTR_NODE_INFO, 0, 0,
                                  srcport) < 0)
Index: tools/infiniband-diags/src/saquery.c
===================================================================
--- tools/infiniband-diags/src/saquery.c        (revision 2812)
+++ tools/infiniband-diags/src/saquery.c        (working copy)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2006,2007 The Regents of the University of California.
- * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
  * Copyright (c) 2009 HNR Consulting. All rights reserved.
@@ -124,6 +124,45 @@
 uint64_t requested_guid = 0;
 int requested_guid_flag = 0;

+#define SA_ERR_UNKNOWN IB_SA_MAD_STATUS_PRIO_SUGGESTED
+
+const char *ib_sa_error_str[] = {
+       "SA_NO_ERROR",
+       "SA_ERR_NO_RESOURCES",
+       "SA_ERR_REQ_INVALID",
+       "SA_ERR_NO_RECORDS",
+       "SA_ERR_TOO_MANY_RECORDS",
+       "SA_ERR_REQ_INVALID_GID",
+       "SA_ERR_REQ_INSUFFICIENT_COMPONENTS",
+       "SA_ERR_REQ_DENIED",
+       "SA_ERR_STATUS_PRIO_SUGGESTED",
+       "SA_ERR_UNKNOWN"
+};
+
+static inline const char *ib_sa_err_str(IN uint8_t status)
+{
+       if (status > SA_ERR_UNKNOWN)
+               status = SA_ERR_UNKNOWN;
+       return (ib_sa_error_str[status]);
+}
+
+static inline void report_err(int status)
+{
+       int st = status & 0xff;
+       char sm_err_str[64] = { 0 };
+       char sa_err_str[64] = { 0 };
+
+       if (st)
+               sprintf(sm_err_str, " SM(%s)", ib_get_err_str(st));
+
+       st = status >> 8;
+       if (st)
+               sprintf(sa_err_str, " SA(%s)", ib_sa_err_str((uint8_t) st));
+
+       fprintf(stderr, "ERROR: Query result returned 0x%04x, %s%s\n",
+               status, sm_err_str, sa_err_str);
+}
+
 static int sa_query(struct bind_handle *h, uint8_t method,
                    uint16_t attr, uint32_t mod, uint64_t comp_mask,
                    uint64_t sm_key, void *data)
@@ -240,14 +279,14 @@
               "\t\tbase_version............0x%X\n"
               "\t\tclass_version...........0x%X\n"
               "\t\tnode_type...............%s\n"
-              "\t\tnum_ports...............0x%X\n"
+              "\t\tnum_ports...............%u\n"
               "\t\tsys_guid................0x%016" PRIx64 "\n"
               "\t\tnode_guid...............0x%016" PRIx64 "\n"
               "\t\tport_guid...............0x%016" PRIx64 "\n"
               "\t\tpartition_cap...........0x%X\n"
               "\t\tdevice_id...............0x%X\n"
               "\t\trevision................0x%X\n"
-              "\t\tport_num................0x%X\n"
+              "\t\tport_num................%u\n"
               "\t\tvendor_id...............0x%X\n"
               "\t\tNodeDescription.........%s\n",
               cl_ntoh16(nr->lid), cl_ntoh16(nr->resv),
@@ -300,8 +339,8 @@
               "\t\tservice_id..............0x%016" PRIx64 "\n"
               "\t\tdgid....................%s\n"
               "\t\tsgid....................%s\n"
-              "\t\tdlid....................0x%X\n"
-              "\t\tslid....................0x%X\n"
+              "\t\tdlid....................%u\n"
+              "\t\tslid....................%u\n"
               "\t\thop_flow_raw............0x%X\n"
               "\t\ttclass..................0x%X\n"
               "\t\tnum_path_revers.........0x%X\n"
@@ -312,8 +351,7 @@
               "\t\trate....................0x%X\n"
               "\t\tpkt_life................0x%X\n"
               "\t\tpreference..............0x%X\n"
-              "\t\tresv2...................0x%X\n"
-              "\t\tresv3...................0x%X\n",
+              "\t\tresv2...................0x%02X%02X%02X%02X%02X%02X\n",
               cl_ntoh64(p_pr->service_id),
               inet_ntop(AF_INET6, p_pr->dgid.raw, gid_str, sizeof gid_str),
               inet_ntop(AF_INET6, p_pr->sgid.raw, gid_str2, sizeof gid_str2),
@@ -322,7 +360,8 @@
               cl_ntoh16(p_pr->pkey), ib_path_rec_qos_class(p_pr),
               ib_path_rec_sl(p_pr), p_pr->mtu, p_pr->rate, p_pr->pkt_life,
               p_pr->preference,
-              *(uint32_t *) & p_pr->resv2, *((uint16_t *) & p_pr->resv2 + 2));
+              p_pr->resv2[0], p_pr->resv2[1], p_pr->resv2[2],
+              p_pr->resv2[3], p_pr->resv2[4], p_pr->resv2[5]);
 }

 static void dump_class_port_info(void *data)
@@ -368,9 +407,9 @@

        printf("PortInfoRecord dump:\n"
               "\t\tEndPortLid..............%u\n"
-              "\t\tPortNum.................0x%X\n"
-              "\t\tbase_lid................0x%X\n"
-              "\t\tmaster_sm_base_lid......0x%X\n"
+              "\t\tPortNum.................%u\n"
+              "\t\tbase_lid................%u\n"
+              "\t\tmaster_sm_base_lid......%u\n"
               "\t\tcapability_mask.........0x%X\n",
               cl_ntoh16(p_pir->lid), p_pir->port_num,
               cl_ntoh16(p_pi->base_lid), cl_ntoh16(p_pi->master_sm_base_lid),
@@ -388,7 +427,7 @@
        printf("PortInfoRecord dump:\n"
               "\tRID:\n"
               "\t\tEndPortLid..............%u\n"
-              "\t\tPortNum.................0x%x\n"
+              "\t\tPortNum.................%u\n"
               "\t\tReserved................0x%x\n"
               "\tPortInfo dump:\n\t\t%s",
               cl_ntoh16(pir->lid), pir->port_num, pir->resv, buf2);
@@ -581,8 +620,8 @@
        uint32_t qpn;
        uint8_t resp_time_val;

-       ib_inform_info_get_qpn_resp_time(p_iir->inform_info.g_or_v.generic.
-                                        qpn_resp_time_val, &qpn,
+       ib_inform_info_get_qpn_resp_time(p_iir->inform_info.g_or_v.
+                                        generic.qpn_resp_time_val, &qpn,
                                         &resp_time_val);
        if (p_iir->inform_info.is_generic)
                printf("InformInfoRecord dump:\n"
@@ -591,8 +630,8 @@
                       "\t\tSubscriberEnum..........0x%X\n"
                       "\t\tInformInfo dump:\n"
                       "\t\tgid.....................%s\n"
-                      "\t\tlid_range_begin.........0x%X\n"
-                      "\t\tlid_range_end...........0x%X\n"
+                      "\t\tlid_range_begin.........%u\n"
+                      "\t\tlid_range_end...........%u\n"
                       "\t\tis_generic..............0x%X\n"
                       "\t\tsubscribe...............0x%X\n"
                       "\t\ttrap_type...............0x%X\n"
@@ -621,8 +660,8 @@
                       "\t\tSubscriberEnum..........0x%X\n"
                       "\t\tInformInfo dump:\n"
                       "\t\tgid.....................%s\n"
-                      "\t\tlid_range_begin.........0x%X\n"
-                      "\t\tlid_range_end...........0x%X\n"
+                      "\t\tlid_range_begin.........%u\n"
+                      "\t\tlid_range_end...........%u\n"
                       "\t\tis_generic..............0x%X\n"
                       "\t\tsubscribe...............0x%X\n"
                       "\t\ttrap_type...............0x%X\n"
@@ -794,8 +833,7 @@
        }

        if (result.status != IB_SUCCESS) {
-               fprintf(stderr, "Query result returned: %s\n",
-                       ib_get_err_str(result.status));
+               report_err(result.status);
                return result.status;
        }

@@ -985,8 +1023,8 @@
                        if (!requested_name ||
                            (strncmp(requested_name,
                                     (char *)node_record->node_desc.description,
-                                    sizeof(node_record->node_desc.
-                                           description)) == 0)) {
+                                    sizeof(node_record->
+                                           node_desc.description)) == 0)) {
                                print_node_record(node_record);
                                if (node_print_desc == UNIQUE_LID_ONLY) {
                                        return_mad();
@@ -1009,8 +1047,7 @@
                return ret;
        }
        if (result.status != IB_SUCCESS) {
-               fprintf(stderr, "ERROR: Query result returned: %s\n",
-                       ib_get_err_str(result.status));
+               report_err(result.status);
                return (result.status);
        }
        dump_results(&result, dump_class_port_info);
Index: tools/infiniband-diags/src/sminfo.c
===================================================================
--- tools/infiniband-diags/src/sminfo.c (revision 2812)
+++ tools/infiniband-diags/src/sminfo.c (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
Index: tools/infiniband-diags/src/smpdump.c
===================================================================
--- tools/infiniband-diags/src/smpdump.c        (revision 2812)
+++ tools/infiniband-diags/src/smpdump.c        (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
Index: tools/infiniband-diags/src/smpquery.c
===================================================================
--- tools/infiniband-diags/src/smpquery.c       (revision 2812)
+++ tools/infiniband-diags/src/smpquery.c       (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
Index: tools/infiniband-diags/src/vendstat.c
===================================================================
--- tools/infiniband-diags/src/vendstat.c       (revision 2812)
+++ tools/infiniband-diags/src/vendstat.c       (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -97,14 +97,12 @@
 } is3_general_info_t;

 typedef struct {
-       uint32_t address;
-       uint32_t data;
-       uint32_t mask;
-} is3_record_t;
-
-typedef struct {
        uint8_t reserved[8];
-       is3_record_t record[18];
+       struct is3_record {
+               uint32_t address;
+               uint32_t data;
+               uint32_t mask;
+       } record[18];
 } is3_config_space_t;

 #define COUNTER_GROUPS_NUM 2
@@ -127,23 +125,61 @@
        is4_group_select_t group_selects[COUNTER_GROUPS_NUM];
 } is4_config_counter_groups_t;

-void counter_groups_info(ib_portid_t * portid, int port)
+static int do_vendor(ib_portid_t *portid, struct ibmad_port *srcport,
+                    uint8_t class, uint8_t method, uint16_t attr_id,
+                    uint32_t attr_mod, void *data)
 {
-       char buf[1024];
        ib_vendor_call_t call;
-       is4_counter_group_info_t *cg_info;
-       int i, num_cg;

        memset(&call, 0, sizeof(call));
-       call.mgmt_class = IB_MLX_VENDOR_CLASS;
-       call.method = IB_MAD_METHOD_GET;
+       call.mgmt_class = class;
+       call.method = method;
        call.timeout = ibd_timeout;
-       call.attrid = IB_MLX_IS4_COUNTER_GROUP_INFO;
-       call.mod = port;
+       call.attrid = attr_id;
+       call.mod = attr_mod;

+       if (!ib_vendor_call_via(data, portid, &call, srcport))
+               IBERROR("vendstat: method %u, attribute %u", method, attr_id);
+
+       return 0;
+}
+
+static void do_config_space_records(ib_portid_t *portid, unsigned set,
+                                   is3_config_space_t *cs, unsigned records)
+{
+       unsigned i;
+
+       if (records > 18)
+               records = 18;
+       for (i = 0; i < records; i++) {
+               cs->record[i].address = htonl(cs->record[i].address);
+               cs->record[i].data = htonl(cs->record[i].data);
+               cs->record[i].mask = htonl(cs->record[i].mask);
+       }
+
+       if (do_vendor(portid, srcport, IB_MLX_VENDOR_CLASS,
+                     set ? IB_MAD_METHOD_SET : IB_MAD_METHOD_GET,
+                     IB_MLX_IS3_CONFIG_SPACE_ACCESS, 2 << 22 | records << 16,
+                     cs))
+               IBERROR("cannot %s config space records", set ? "set" : "get");
+
+       for (i = 0; i < records; i++) {
+               printf("Config space record at 0x%x: 0x%x\n",
+                      ntohl(cs->record[i].address),
+                      ntohl(cs->record[i].data & cs->record[i].mask));
+       }
+}
+
+static void counter_groups_info(ib_portid_t * portid, int port)
+{
+       char buf[1024];
+       is4_counter_group_info_t *cg_info;
+       int i, num_cg;
+
        /* Counter Group Info */
        memset(&buf, 0, sizeof(buf));
-       if (!ib_vendor_call_via(&buf, portid, &call, srcport))
+       if (do_vendor(portid, srcport, IB_MLX_VENDOR_CLASS, IB_MAD_METHOD_GET,
+                     IB_MLX_IS4_COUNTER_GROUP_INFO, port, buf))
                IBERROR("counter group info query");

        cg_info = (is4_counter_group_info_t *) & buf;
@@ -166,20 +202,12 @@

 static int cg0, cg1;

-void config_counter_groups(ib_portid_t * portid, int port)
+static void config_counter_groups(ib_portid_t * portid, int port)
 {
        char buf[1024];
-       ib_vendor_call_t call;
        is4_config_counter_groups_t *cg_config;

-       memset(&call, 0, sizeof(call));
-       call.mgmt_class = IB_MLX_VENDOR_CLASS;
-       call.attrid = IB_MLX_IS4_CONFIG_COUNTER_GROUP;
-       call.timeout = ibd_timeout;
-       call.mod = port;
        /* configure counter groups for groups 0 and 1 */
-       call.method = IB_MAD_METHOD_SET;
-
        memset(&buf, 0, sizeof(buf));
        cg_config = (is4_config_counter_groups_t *) & buf;

@@ -188,19 +216,23 @@
        cg_config->group_selects[0].group_select = (uint8_t) cg0;
        cg_config->group_selects[1].group_select = (uint8_t) cg1;

-       if (!ib_vendor_call_via(&buf, portid, &call, srcport))
+       if (do_vendor(portid, srcport, IB_MLX_VENDOR_CLASS, IB_MAD_METHOD_SET,
+                     IB_MLX_IS4_CONFIG_COUNTER_GROUP, port, buf))
                IBERROR("config counter group set");

        /* get config counter groups */
        memset(&buf, 0, sizeof(buf));
-       call.method = IB_MAD_METHOD_GET;

-       if (!ib_vendor_call_via(&buf, portid, &call, srcport))
+       if (do_vendor(portid, srcport, IB_MLX_VENDOR_CLASS, IB_MAD_METHOD_GET,
+                     IB_MLX_IS4_CONFIG_COUNTER_GROUP, port, buf))
                IBERROR("config counter group query");
 }

 static int general_info, xmit_wait, counter_group_info, config_counter_group;
+static is3_config_space_t write_cs, read_cs;
+static unsigned write_cs_records, read_cs_records;

+
 static int process_opt(void *context, int ch, char *optarg)
 {
        int ret;
@@ -220,6 +252,31 @@
                if (ret != 2)
                        return -1;
                break;
+       case 'R':
+               if (read_cs_records >= 18)
+                       break;
+               ret = sscanf(optarg, "%x,%x",
+                            &read_cs.record[read_cs_records].address,
+                            &read_cs.record[read_cs_records].mask);
+               if (ret < 1)
+                       return -1;
+               else if (ret == 1)
+                       read_cs.record[read_cs_records].mask = 0xffffffff;
+               read_cs_records++;
+               break;
+       case 'W':
+               if (write_cs_records >= 18)
+                       break;
+               ret = sscanf(optarg, "%x,%x,%x",
+                            &write_cs.record[write_cs_records].address,
+                            &write_cs.record[write_cs_records].data,
+                            &write_cs.record[write_cs_records].mask);
+               if (ret < 2)
+                       return -1;
+               else if (ret == 2)
+                       write_cs.record[write_cs_records].mask = 0xffffffff;
+               write_cs_records++;
+               break;
        default:
                return -1;
        }
@@ -234,22 +291,21 @@
        ib_portid_t portid = { 0 };
        int port = 0;
        char buf[1024];
-       ib_vendor_call_t call;
        is3_general_info_t *gi;
-       is3_config_space_t *cs;
-       int i;

        const struct ibdiag_opt opts[] = {
-               {"N", 'N', 0, NULL, "show IS3 general information"},
+               {"N", 'N', 0, NULL, "show IS3 or IS4 general information"},
                {"w", 'w', 0, NULL, "show IS3 port xmit wait counters"},
                {"i", 'i', 0, NULL, "show IS4 counter group info"},
                {"c", 'c', 1, "<num,num>", "configure IS4 counter groups"},
+               {"Read", 'R', 1, "<addr,mask>", "Read configuration space record at addr"},
+               {"Write", 'W', 1, "<addr,val,mask>", "Write configuration space record at addr"},
                {0}
        };

        char usage_args[] = "<lid|guid> [port]";
        const char *usage_examples[] = {
-               "-N 6\t\t# read IS3 general information",
+               "-N 6\t\t# read IS3 or IS4 general information",
                "-w 6\t\t# read IS3 port xmit wait counters",
                "-i 6 12\t# read IS4 port 12 counter group info",
                "-c 0,1 6 12\t# configure IS4 port 12 counter groups for PortXmitDataSL",
@@ -289,6 +345,16 @@
                exit(0);
        }

+       if (read_cs_records || write_cs_records) {
+               if (read_cs_records)
+                       do_config_space_records(&portid, 0, &read_cs,
+                                               read_cs_records);
+               if (write_cs_records)
+                       do_config_space_records(&portid, 1, &write_cs,
+                                               write_cs_records);
+               exit(0);
+       }
+
        /* These are Mellanox specific vendor MADs */
        /* but vendors change the VendorId so how know for sure ? */
        /* Only General Info and Port Xmit Wait Counters */
@@ -299,25 +365,19 @@
        /* Would need a list of these and it might not be complete */
        /* so for right now, punt on this */

-       memset(&call, 0, sizeof(call));
-       call.mgmt_class = IB_MLX_VENDOR_CLASS;
-       call.method = IB_MAD_METHOD_GET;
-       call.timeout = ibd_timeout;
-
+       /* vendor ClassPortInfo is required attribute if class supported */
        memset(&buf, 0, sizeof(buf));
-       /* vendor ClassPortInfo is required attribute if class supported */
-       call.attrid = CLASS_PORT_INFO;
-       if (!ib_vendor_call_via(&buf, &portid, &call, srcport))
+       if (do_vendor(&portid, srcport, IB_MLX_VENDOR_CLASS, IB_MAD_METHOD_GET,
+                     CLASS_PORT_INFO, 0, buf))
                IBERROR("classportinfo query");

        memset(&buf, 0, sizeof(buf));
-       call.attrid = IB_MLX_IS3_GENERAL_INFO;
-       if (!ib_vendor_call_via(&buf, &portid, &call, srcport))
-               IBERROR("vendstat");
        gi = (is3_general_info_t *) & buf;
+       if (do_vendor(&portid, srcport, IB_MLX_VENDOR_CLASS, IB_MAD_METHOD_GET,
+                     IB_MLX_IS3_GENERAL_INFO, 0, gi))

        if (general_info) {
-               /* dump IS3 general info here */
+               /* dump IS3 or IS4 general info here */
                printf("hw_dev_rev:  0x%04x\n", ntohs(gi->hw_info.hw_revision));
                printf("hw_dev_id:   0x%04x\n", ntohs(gi->hw_info.device_id));
                printf("hw_uptime:   0x%08x\n", ntohl(gi->hw_info.uptime));
@@ -336,20 +396,22 @@
        }

        if (xmit_wait) {
+               is3_config_space_t *cs;
+               unsigned i;
+
                if (ntohs(gi->hw_info.device_id) != IS3_DEVICE_ID)
                        IBERROR("Unsupported device ID 0x%x",
                                ntohs(gi->hw_info.device_id));

                memset(&buf, 0, sizeof(buf));
-               call.attrid = IB_MLX_IS3_CONFIG_SPACE_ACCESS;
-               /* Limit of 18 accesses per MAD ? */
-               call.mod = 2 << 22 | 16 << 16;  /* 16 records */
                /* Set record addresses for each port */
                cs = (is3_config_space_t *) & buf;
                for (i = 0; i < 16; i++)
                        cs->record[i].address =
                            htonl(IB_MLX_IS3_PORT_XMIT_WAIT + ((i + 1) << 12));
-               if (!ib_vendor_call_via(&buf, &portid, &call, srcport))
+               if (do_vendor(&portid, srcport, IB_MLX_VENDOR_CLASS,
+                             IB_MAD_METHOD_GET, IB_MLX_IS3_CONFIG_SPACE_ACCESS,
+                             2 << 22 | 16 << 16, cs))
                        IBERROR("vendstat");

                for (i = 0; i < 16; i++)
@@ -358,14 +420,14 @@

                /* Last 8 ports is another query */
                memset(&buf, 0, sizeof(buf));
-               call.attrid = IB_MLX_IS3_CONFIG_SPACE_ACCESS;
-               call.mod = 2 << 22 | 8 << 16;   /* 8 records */
                /* Set record addresses for each port */
                cs = (is3_config_space_t *) & buf;
                for (i = 0; i < 8; i++)
                        cs->record[i].address =
                            htonl(IB_MLX_IS3_PORT_XMIT_WAIT + ((i + 17) << 12));
-               if (!ib_vendor_call_via(&buf, &portid, &call, srcport))
+               if (do_vendor(&portid, srcport, IB_MLX_VENDOR_CLASS,
+                             IB_MAD_METHOD_GET, IB_MLX_IS3_CONFIG_SPACE_ACCESS,
+                             2 << 22 | 8 << 16, cs))
                        IBERROR("vendstat");

                for (i = 0; i < 8; i++)





More information about the ofw mailing list