infiniband-diags: initial port of linux ib diags
authorshefty <shefty@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Fri, 23 Jan 2009 21:56:35 +0000 (21:56 +0000)
committershefty <shefty@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Fri, 23 Jan 2009 21:56:35 +0000 (21:56 +0000)
Signed-off-by: Sean Hefty <sean.hefty@intel.com>
git-svn-id: svn://openib.tc.cornell.edu/gen1/trunk@1870 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

32 files changed:
tools/infiniband_diags/dirs [new file with mode: 0644]
tools/infiniband_diags/include/grouping.h [new file with mode: 0644]
tools/infiniband_diags/include/ibdiag_common.h [new file with mode: 0644]
tools/infiniband_diags/include/ibdiag_version.h [new file with mode: 0644]
tools/infiniband_diags/include/ibnetdiscover.h [new file with mode: 0644]
tools/infiniband_diags/src/dirs [new file with mode: 0644]
tools/infiniband_diags/src/grouping.c [new file with mode: 0644]
tools/infiniband_diags/src/ibaddr.c [new file with mode: 0644]
tools/infiniband_diags/src/ibaddr/SOURCES [new file with mode: 0644]
tools/infiniband_diags/src/ibdiag_common.c [new file with mode: 0644]
tools/infiniband_diags/src/ibnetdiscover.c [new file with mode: 0644]
tools/infiniband_diags/src/ibnetdiscover/SOURCES [new file with mode: 0644]
tools/infiniband_diags/src/ibping.c [new file with mode: 0644]
tools/infiniband_diags/src/ibping/SOURCES [new file with mode: 0644]
tools/infiniband_diags/src/ibportstate.c [new file with mode: 0644]
tools/infiniband_diags/src/ibroute.c [new file with mode: 0644]
tools/infiniband_diags/src/ibsendtrap.c [new file with mode: 0644]
tools/infiniband_diags/src/ibstat.c [new file with mode: 0644]
tools/infiniband_diags/src/ibstat/SOURCES [new file with mode: 0644]
tools/infiniband_diags/src/ibsysstat.c [new file with mode: 0644]
tools/infiniband_diags/src/ibtracert.c [new file with mode: 0644]
tools/infiniband_diags/src/mcm_rereg_test.c [new file with mode: 0644]
tools/infiniband_diags/src/perfquery.c [new file with mode: 0644]
tools/infiniband_diags/src/perfquery/SOURCES [new file with mode: 0644]
tools/infiniband_diags/src/saquery.c [new file with mode: 0644]
tools/infiniband_diags/src/saquery/SOURCES [new file with mode: 0644]
tools/infiniband_diags/src/sminfo.c [new file with mode: 0644]
tools/infiniband_diags/src/sminfo/SOURCES [new file with mode: 0644]
tools/infiniband_diags/src/smpdump.c [new file with mode: 0644]
tools/infiniband_diags/src/smpquery.c [new file with mode: 0644]
tools/infiniband_diags/src/vendstat.c [new file with mode: 0644]
tools/infiniband_diags/src/vendstat/SOURCES [new file with mode: 0644]

diff --git a/tools/infiniband_diags/dirs b/tools/infiniband_diags/dirs
new file mode 100644 (file)
index 0000000..039a6ee
--- /dev/null
@@ -0,0 +1,2 @@
+DIRS = \\r
+       src
\ No newline at end of file
diff --git a/tools/infiniband_diags/include/grouping.h b/tools/infiniband_diags/include/grouping.h
new file mode 100644 (file)
index 0000000..1044f3a
--- /dev/null
@@ -0,0 +1,112 @@
+/*\r
+ * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.\r
+ * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+#ifndef _GROUPING_H_\r
+#define _GROUPING_H_\r
+\r
+/*========================================================*/\r
+/*               FABRIC SCANNER SPECIFIC DATA             */\r
+/*========================================================*/\r
+\r
+#define SPINES_MAX_NUM 12\r
+#define LINES_MAX_NUM 36\r
+\r
+typedef struct ChassisList ChassisList;\r
+typedef struct AllChassisList AllChassisList;\r
+\r
+struct ChassisList {\r
+       ChassisList *next;\r
+       uint64_t chassisguid;\r
+       int chassisnum;\r
+       int chassistype;\r
+       int nodecount;          /* used for grouping by SystemImageGUID */\r
+       Node *spinenode[SPINES_MAX_NUM + 1];\r
+       Node *linenode[LINES_MAX_NUM + 1];\r
+};\r
+\r
+struct AllChassisList {\r
+       ChassisList *first;\r
+       ChassisList *current;\r
+       ChassisList *last;\r
+};\r
+\r
+/*========================================================*/\r
+/*                CHASSIS RECOGNITION SPECIFIC DATA       */\r
+/*========================================================*/\r
+\r
+/* Device IDs */\r
+#define VTR_DEVID_IB_FC_ROUTER         0x5a00\r
+#define VTR_DEVID_IB_IP_ROUTER         0x5a01\r
+#define VTR_DEVID_ISR9600_SPINE                0x5a02\r
+#define VTR_DEVID_ISR9600_LEAF         0x5a03\r
+#define VTR_DEVID_HCA1                 0x5a04\r
+#define VTR_DEVID_HCA2                 0x5a44\r
+#define VTR_DEVID_HCA3                 0x6278\r
+#define VTR_DEVID_SW_6IB4              0x5a05\r
+#define VTR_DEVID_ISR9024              0x5a06\r
+#define VTR_DEVID_ISR9288              0x5a07\r
+#define VTR_DEVID_SLB24                        0x5a09\r
+#define VTR_DEVID_SFB12                        0x5a08\r
+#define VTR_DEVID_SFB4                 0x5a0b\r
+#define VTR_DEVID_ISR9024_12           0x5a0c\r
+#define VTR_DEVID_SLB8                 0x5a0d\r
+#define VTR_DEVID_RLX_SWITCH_BLADE     0x5a20\r
+#define VTR_DEVID_ISR9024_DDR          0x5a31\r
+#define VTR_DEVID_SFB12_DDR            0x5a32\r
+#define VTR_DEVID_SFB4_DDR             0x5a33\r
+#define VTR_DEVID_SLB24_DDR            0x5a34\r
+#define VTR_DEVID_SFB2012              0x5a37\r
+#define VTR_DEVID_SLB2024              0x5a38\r
+#define VTR_DEVID_ISR2012              0x5a39\r
+#define VTR_DEVID_SFB2004              0x5a40\r
+#define VTR_DEVID_ISR2004              0x5a41\r
+\r
+enum ChassisType { UNRESOLVED_CT, ISR9288_CT, ISR9096_CT, ISR2012_CT, ISR2004_CT };\r
+enum ChassisSlot { UNRESOLVED_CS, LINE_CS, SPINE_CS, SRBD_CS };\r
+\r
+/*========================================================*/\r
+/*                External interface                      */\r
+/*========================================================*/\r
+\r
+ChassisList *group_nodes();\r
+char *portmapstring(Port *port);\r
+char *get_chassis_type(unsigned char chassistype);\r
+char *get_chassis_slot(unsigned char chassisslot);\r
+uint64_t get_chassis_guid(unsigned char chassisnum);\r
+\r
+int is_xsigo_guid(uint64_t guid);\r
+int is_xsigo_tca(uint64_t guid);\r
+int is_xsigo_hca(uint64_t guid);\r
+\r
+#endif /* _GROUPING_H_ */\r
diff --git a/tools/infiniband_diags/include/ibdiag_common.h b/tools/infiniband_diags/include/ibdiag_common.h
new file mode 100644 (file)
index 0000000..1ed5758
--- /dev/null
@@ -0,0 +1,65 @@
+/*\r
+ * Copyright (c) 2006-2007 The Regents of the University of California.\r
+ * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+#ifndef _IBDIAG_COMMON_H_\r
+#define _IBDIAG_COMMON_H_\r
+\r
+#include <stdio.h>\r
+\r
+#if !defined( __cplusplus )\r
+#define inline __inline\r
+#endif\r
+\r
+extern char *argv0;\r
+extern int   ibdebug;\r
+\r
+/*========================================================*/\r
+/*                External interface                      */\r
+/*========================================================*/\r
+\r
+void  iberror(const char *fn, char *msg, ...);\r
+\r
+#undef DEBUG\r
+#define        DEBUG   if (ibdebug || verbose) IBWARN\r
+#define        VERBOSE if (ibdebug || verbose > 1) IBWARN\r
+#define IBERROR(fmt, ...) iberror(__FUNCTION__, fmt, ## __VA_ARGS__)\r
+\r
+#include <ibdiag_version.h>\r
+\r
+static inline const char* get_build_version(void) \r
+{ \r
+       return "BUILD VERSION: " IBDIAG_VERSION " Build date: " __DATE__ " " __TIME__ ;\r
+}\r
+\r
+#endif /* _IBDIAG_COMMON_H_ */\r
diff --git a/tools/infiniband_diags/include/ibdiag_version.h b/tools/infiniband_diags/include/ibdiag_version.h
new file mode 100644 (file)
index 0000000..790385f
--- /dev/null
@@ -0,0 +1,39 @@
+/*\r
+ * Copyright (c) 2008 Voltaire Inc.  All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+#ifndef _IBDIAG_VERSION_H_\r
+#define _IBDIAG_VERSION_H_\r
+\r
+#define IBDIAG_VERSION "1.4.2"\r
+\r
+#endif /* _IBDIAG_VERSION_H_ */\r
diff --git a/tools/infiniband_diags/include/ibnetdiscover.h b/tools/infiniband_diags/include/ibnetdiscover.h
new file mode 100644 (file)
index 0000000..c52cad5
--- /dev/null
@@ -0,0 +1,107 @@
+/*\r
+ * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.\r
+ * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+#ifndef _IBNETDISCOVER_H_\r
+#define _IBNETDISCOVER_H_\r
+\r
+#define MAXHOPS                63\r
+\r
+#define CA_NODE                1\r
+#define SWITCH_NODE    2\r
+#define ROUTER_NODE    3\r
+\r
+#define LIST_CA_NODE    (1 << CA_NODE)\r
+#define LIST_SWITCH_NODE (1 << SWITCH_NODE)\r
+#define LIST_ROUTER_NODE (1 << ROUTER_NODE)\r
+\r
+/* Vendor IDs (for chassis based systems) */\r
+#define VTR_VENDOR_ID                  0x8f1   /* Voltaire */\r
+#define TS_VENDOR_ID                   0x5ad   /* Cisco */\r
+#define SS_VENDOR_ID                   0x66a   /* InfiniCon */\r
+#define XS_VENDOR_ID                   0x1397  /* Xsigo */\r
+\r
+\r
+typedef struct Port Port;\r
+typedef struct Node Node;\r
+typedef struct ChassisRecord ChassisRecord;\r
+\r
+struct ChassisRecord {\r
+       ChassisRecord *next;\r
+\r
+       unsigned char chassisnum;\r
+       unsigned char anafanum;\r
+       unsigned char slotnum;\r
+       unsigned char chassistype;\r
+       unsigned char chassisslot;\r
+};\r
+\r
+struct Port {\r
+       Port *next;\r
+       uint64_t portguid;\r
+       int portnum;\r
+       int lid;\r
+       int lmc;\r
+       int state;\r
+       int physstate;\r
+       int linkwidth;\r
+       int linkspeed;\r
+\r
+       Node *node;\r
+       Port *remoteport;               /* null if SMA */\r
+};\r
+\r
+struct Node {\r
+       Node *htnext;\r
+       Node *dnext;\r
+       Port *ports;\r
+       ib_portid_t path;\r
+       int type;\r
+       int dist;\r
+       int numports;\r
+       int localport;\r
+       int smalid;\r
+       int smalmc;\r
+       int smaenhsp0;\r
+       uint32_t devid;\r
+       uint32_t vendid;\r
+       uint64_t sysimgguid;\r
+       uint64_t nodeguid;\r
+       uint64_t portguid;\r
+       char nodedesc[64];\r
+       uint8_t nodeinfo[64];\r
+\r
+       ChassisRecord *chrecord;\r
+};\r
+\r
+#endif /* _IBNETDISCOVER_H_ */\r
diff --git a/tools/infiniband_diags/src/dirs b/tools/infiniband_diags/src/dirs
new file mode 100644 (file)
index 0000000..23d2382
--- /dev/null
@@ -0,0 +1,13 @@
+DIRS =                 \\r
+       sminfo          \\r
+       ibstat          \\r
+       perfquery       \\r
+       vendstat        \\r
+       ibaddr\r
+       \r
+       \r
+       \r
+       \r
+       \r
+       \r
+               
\ No newline at end of file
diff --git a/tools/infiniband_diags/src/grouping.c b/tools/infiniband_diags/src/grouping.c
new file mode 100644 (file)
index 0000000..93b6f09
--- /dev/null
@@ -0,0 +1,793 @@
+/*\r
+ * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.\r
+ * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+/*========================================================*/\r
+/*               FABRIC SCANNER SPECIFIC DATA             */\r
+/*========================================================*/\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif /* HAVE_CONFIG_H */\r
+\r
+#include <stdlib.h>\r
+\r
+#if defined(_WIN32) || defined(_WIN64)\r
+#include <windows.h>\r
+#include <winsock2.h>\r
+#include "..\ibdiag_common.c"\r
+#else\r
+#include <stdint.h>\r
+#include <inttypes.h>\r
+#endif\r
+\r
+#include <infiniband/common.h>\r
+#include <infiniband/mad.h>\r
+\r
+#include "ibnetdiscover.h"\r
+#include "grouping.h"\r
+\r
+#define OUT_BUFFER_SIZE 16\r
+\r
+\r
+extern Node *nodesdist[MAXHOPS+1];     /* last is CA list */\r
+extern Node *mynode;\r
+extern Port *myport;\r
+extern int maxhops_discovered;\r
+\r
+AllChassisList mylist;\r
+\r
+char *ChassisTypeStr[5] = { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004" };\r
+char *ChassisSlotStr[4] = { "", "Line", "Spine", "SRBD" };\r
+\r
+\r
+char *get_chassis_type(unsigned char chassistype)\r
+{\r
+       if (chassistype == UNRESOLVED_CT || chassistype > ISR2004_CT)\r
+               return NULL;\r
+       return ChassisTypeStr[chassistype];\r
+}\r
+\r
+char *get_chassis_slot(unsigned char chassisslot)\r
+{\r
+       if (chassisslot == UNRESOLVED_CS || chassisslot > SRBD_CS)\r
+               return NULL;\r
+       return ChassisSlotStr[chassisslot];\r
+}\r
+\r
+static struct ChassisList *find_chassisnum(unsigned char chassisnum)\r
+{\r
+       ChassisList *current;\r
+\r
+       for (current = mylist.first; current; current = current->next) {\r
+               if (current->chassisnum == chassisnum)\r
+                       return current;\r
+       }\r
+\r
+       return NULL;\r
+}\r
+\r
+static uint64_t topspin_chassisguid(uint64_t guid)\r
+{\r
+       /* Byte 3 in system image GUID is chassis type, and */\r
+       /* Byte 4 is location ID (slot) so just mask off byte 4 */\r
+       return guid & 0xffffffff00ffffffULL;\r
+}\r
+\r
+int is_xsigo_guid(uint64_t guid)\r
+{\r
+       if ((guid & 0xffffff0000000000ULL) == 0x0013970000000000ULL)\r
+               return 1;\r
+       else\r
+               return 0;\r
+}\r
+\r
+static int is_xsigo_leafone(uint64_t guid)\r
+{\r
+       if ((guid & 0xffffffffff000000ULL) == 0x0013970102000000ULL)\r
+               return 1;\r
+       else\r
+               return 0;\r
+}\r
+\r
+int is_xsigo_hca(uint64_t guid)\r
+{\r
+       /* NodeType 2 is HCA */\r
+       if ((guid & 0xffffffff00000000ULL) == 0x0013970200000000ULL)\r
+               return 1;\r
+       else\r
+               return 0;\r
+}\r
+\r
+int is_xsigo_tca(uint64_t guid)\r
+{\r
+       /* NodeType 3 is TCA */\r
+       if ((guid & 0xffffffff00000000ULL) == 0x0013970300000000ULL)\r
+               return 1;\r
+       else\r
+               return 0;\r
+}\r
+\r
+static int is_xsigo_ca(uint64_t guid)\r
+{\r
+       if (is_xsigo_hca(guid) || is_xsigo_tca(guid))\r
+               return 1;\r
+       else\r
+               return 0;\r
+}\r
+\r
+static int is_xsigo_switch(uint64_t guid)\r
+{\r
+       if ((guid & 0xffffffff00000000ULL) == 0x0013970100000000ULL)\r
+               return 1;\r
+       else\r
+               return 0;\r
+}\r
+\r
+static uint64_t xsigo_chassisguid(Node *node)\r
+{\r
+       if (!is_xsigo_ca(node->sysimgguid)) {\r
+               /* Byte 3 is NodeType and byte 4 is PortType */\r
+               /* If NodeType is 1 (switch), PortType is masked */\r
+               if (is_xsigo_switch(node->sysimgguid))\r
+                       return node->sysimgguid & 0xffffffff00ffffffULL;\r
+               else\r
+                       return node->sysimgguid;\r
+       } else {\r
+               /* Is there a peer port ? */\r
+               if (!node->ports->remoteport)\r
+                       return node->sysimgguid;\r
+\r
+               /* If peer port is Leaf 1, use its chassis GUID */\r
+               if (is_xsigo_leafone(node->ports->remoteport->node->sysimgguid))\r
+                       return node->ports->remoteport->node->sysimgguid &\r
+                              0xffffffff00ffffffULL;\r
+               else\r
+                       return node->sysimgguid;\r
+       }\r
+}\r
+\r
+static uint64_t get_chassisguid(Node *node)\r
+{\r
+       if (node->vendid == TS_VENDOR_ID || node->vendid == SS_VENDOR_ID)\r
+               return topspin_chassisguid(node->sysimgguid);\r
+       else if (node->vendid == XS_VENDOR_ID || is_xsigo_guid(node->sysimgguid))\r
+               return xsigo_chassisguid(node);\r
+       else\r
+               return node->sysimgguid;\r
+}\r
+\r
+static struct ChassisList *find_chassisguid(Node *node)\r
+{\r
+       ChassisList *current;\r
+       uint64_t chguid;\r
+\r
+       chguid = get_chassisguid(node);\r
+       for (current = mylist.first; current; current = current->next) {\r
+               if (current->chassisguid == chguid)\r
+                       return current;\r
+       }\r
+\r
+       return NULL;\r
+}\r
+\r
+uint64_t get_chassis_guid(unsigned char chassisnum)\r
+{\r
+       ChassisList *chassis;\r
+\r
+       chassis = find_chassisnum(chassisnum);\r
+       if (chassis)\r
+               return chassis->chassisguid;\r
+       else\r
+               return 0;\r
+}\r
+\r
+static int is_router(Node *node)\r
+{\r
+       return (node->devid == VTR_DEVID_IB_FC_ROUTER ||\r
+               node->devid == VTR_DEVID_IB_IP_ROUTER);\r
+}\r
+\r
+static int is_spine_9096(Node *node)\r
+{\r
+       return (node->devid == VTR_DEVID_SFB4 ||\r
+               node->devid == VTR_DEVID_SFB4_DDR);\r
+}\r
+\r
+static int is_spine_9288(Node *node)\r
+{\r
+       return (node->devid == VTR_DEVID_SFB12 ||\r
+               node->devid == VTR_DEVID_SFB12_DDR);\r
+}\r
+\r
+static int is_spine_2004(Node *node)\r
+{\r
+       return (node->devid == VTR_DEVID_SFB2004);\r
+}\r
+\r
+static int is_spine_2012(Node *node)\r
+{\r
+       return (node->devid == VTR_DEVID_SFB2012);\r
+}\r
+\r
+static int is_spine(Node *node)\r
+{\r
+       return (is_spine_9096(node) || is_spine_9288(node) ||\r
+               is_spine_2004(node) || is_spine_2012(node));\r
+}\r
+\r
+static int is_line_24(Node *node)\r
+{\r
+       return (node->devid == VTR_DEVID_SLB24 ||\r
+               node->devid == VTR_DEVID_SLB24_DDR);\r
+}\r
+\r
+static int is_line_8(Node *node)\r
+{\r
+       return (node->devid == VTR_DEVID_SLB8);\r
+}\r
+\r
+static int is_line_2024(Node *node)\r
+{\r
+       return (node->devid == VTR_DEVID_SLB2024);\r
+}\r
+\r
+static int is_line(Node *node)\r
+{\r
+       return (is_line_24(node) || is_line_8(node) || is_line_2024(node));\r
+}\r
+\r
+int is_chassis_switch(Node *node)\r
+{\r
+    return (is_spine(node) || is_line(node));\r
+}\r
+\r
+/* these structs help find Line (Anafa) slot number while using spine portnum */\r
+int line_slot_2_sfb4[25]        = { 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4 };\r
+int anafa_line_slot_2_sfb4[25]  = { 0, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2 };\r
+int line_slot_2_sfb12[25]       = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10, 10, 11, 11, 12, 12 };\r
+int anafa_line_slot_2_sfb12[25] = { 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 };\r
+\r
+/* IPR FCR modules connectivity while using sFB4 port as reference */\r
+int ipr_slot_2_sfb4_port[25]    = { 0, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1 };\r
+\r
+/* these structs help find Spine (Anafa) slot number while using spine portnum */\r
+int spine12_slot_2_slb[25]      = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };\r
+int anafa_spine12_slot_2_slb[25]= { 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };\r
+int spine4_slot_2_slb[25]       = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };\r
+int anafa_spine4_slot_2_slb[25] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };\r
+/*     reference                     { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; */\r
+\r
+static void get_sfb_slot(Node *node, Port *lineport)\r
+{\r
+       ChassisRecord *ch = node->chrecord;\r
+\r
+       ch->chassisslot = SPINE_CS;\r
+       if (is_spine_9096(node)) {\r
+               ch->chassistype = ISR9096_CT;\r
+               ch->slotnum = spine4_slot_2_slb[lineport->portnum];\r
+               ch->anafanum = anafa_spine4_slot_2_slb[lineport->portnum];\r
+       } else if (is_spine_9288(node)) {\r
+               ch->chassistype = ISR9288_CT;\r
+               ch->slotnum = spine12_slot_2_slb[lineport->portnum];\r
+               ch->anafanum = anafa_spine12_slot_2_slb[lineport->portnum];\r
+       } else if (is_spine_2012(node)) {\r
+               ch->chassistype = ISR2012_CT;\r
+               ch->slotnum = spine12_slot_2_slb[lineport->portnum];\r
+               ch->anafanum = anafa_spine12_slot_2_slb[lineport->portnum];\r
+       } else if (is_spine_2004(node)) {\r
+               ch->chassistype = ISR2004_CT;\r
+               ch->slotnum = spine4_slot_2_slb[lineport->portnum];\r
+               ch->anafanum = anafa_spine4_slot_2_slb[lineport->portnum];\r
+       } else {\r
+               IBPANIC("Unexpected node found: guid 0x%016" PRIx64, node->nodeguid);\r
+       }\r
+}\r
+\r
+static void get_router_slot(Node *node, Port *spineport)\r
+{\r
+       ChassisRecord *ch = node->chrecord;\r
+       int guessnum = 0;\r
+\r
+       if (!ch) {\r
+               if (!(node->chrecord = calloc(1, sizeof(ChassisRecord))))\r
+                       IBPANIC("out of mem");\r
+               ch = node->chrecord;\r
+       }\r
+\r
+       ch->chassisslot = SRBD_CS;\r
+       if (is_spine_9096(spineport->node)) {\r
+               ch->chassistype = ISR9096_CT;\r
+               ch->slotnum = line_slot_2_sfb4[spineport->portnum];\r
+               ch->anafanum = ipr_slot_2_sfb4_port[spineport->portnum];\r
+       } else if (is_spine_9288(spineport->node)) {\r
+               ch->chassistype = ISR9288_CT;\r
+               ch->slotnum = line_slot_2_sfb12[spineport->portnum];\r
+               /* this is a smart guess based on nodeguids order on sFB-12 module */\r
+               guessnum = spineport->node->nodeguid % 4;\r
+               /* module 1 <--> remote anafa 3 */\r
+               /* module 2 <--> remote anafa 2 */\r
+               /* module 3 <--> remote anafa 1 */\r
+               ch->anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2));\r
+       } else if (is_spine_2012(spineport->node)) {\r
+               ch->chassistype = ISR2012_CT;\r
+               ch->slotnum = line_slot_2_sfb12[spineport->portnum];\r
+               /* this is a smart guess based on nodeguids order on sFB-12 module */\r
+               guessnum = spineport->node->nodeguid % 4;\r
+               // module 1 <--> remote anafa 3\r
+               // module 2 <--> remote anafa 2\r
+               // module 3 <--> remote anafa 1\r
+               ch->anafanum = (guessnum == 3? 1 : (guessnum == 1 ? 3 : 2));\r
+       } else if (is_spine_2004(spineport->node)) {\r
+               ch->chassistype = ISR2004_CT;\r
+               ch->slotnum = line_slot_2_sfb4[spineport->portnum];\r
+               ch->anafanum = ipr_slot_2_sfb4_port[spineport->portnum];\r
+       } else {\r
+               IBPANIC("Unexpected node found: guid 0x%016" PRIx64, spineport->node->nodeguid);\r
+       }\r
+}\r
+\r
+static void get_slb_slot(ChassisRecord *ch, Port *spineport)\r
+{\r
+       ch->chassisslot = LINE_CS;\r
+       if (is_spine_9096(spineport->node)) {\r
+               ch->chassistype = ISR9096_CT;\r
+               ch->slotnum = line_slot_2_sfb4[spineport->portnum];\r
+               ch->anafanum = anafa_line_slot_2_sfb4[spineport->portnum];\r
+       } else if (is_spine_9288(spineport->node)) {\r
+               ch->chassistype = ISR9288_CT;\r
+               ch->slotnum = line_slot_2_sfb12[spineport->portnum];\r
+               ch->anafanum = anafa_line_slot_2_sfb12[spineport->portnum];\r
+       } else if (is_spine_2012(spineport->node)) {\r
+               ch->chassistype = ISR2012_CT;\r
+               ch->slotnum = line_slot_2_sfb12[spineport->portnum];\r
+               ch->anafanum = anafa_line_slot_2_sfb12[spineport->portnum];\r
+       } else if (is_spine_2004(spineport->node)) {\r
+               ch->chassistype = ISR2004_CT;\r
+               ch->slotnum = line_slot_2_sfb4[spineport->portnum];\r
+               ch->anafanum = anafa_line_slot_2_sfb4[spineport->portnum];\r
+       } else {\r
+               IBPANIC("Unexpected node found: guid 0x%016" PRIx64, spineport->node->nodeguid);\r
+       }\r
+}\r
+\r
+/*\r
+       This function called for every Voltaire node in fabric\r
+       It could be optimized so, but time overhead is very small\r
+       and its only diag.util\r
+*/\r
+static void fill_chassis_record(Node *node)\r
+{\r
+       Port *port;\r
+       Node *remnode = 0;\r
+       ChassisRecord *ch = 0;\r
+\r
+       if (node->chrecord) /* somehow this node has already been passed */\r
+               return;\r
+\r
+       if (!(node->chrecord = calloc(1, sizeof(ChassisRecord))))\r
+               IBPANIC("out of mem");\r
+\r
+       ch = node->chrecord;\r
+\r
+       /* node is router only in case of using unique lid */\r
+       /* (which is lid of chassis router port) */\r
+       /* in such case node->ports is actually a requested port... */\r
+       if (is_router(node) && is_spine(node->ports->remoteport->node))\r
+               get_router_slot(node, node->ports->remoteport);\r
+       else if (is_spine(node)) {\r
+               for (port = node->ports; port; port = port->next) {\r
+                       if (!port->remoteport)\r
+                               continue;\r
+                       remnode = port->remoteport->node;\r
+                       if (remnode->type != SWITCH_NODE) {\r
+                               if (!remnode->chrecord)\r
+                                       get_router_slot(remnode, port);\r
+                               continue;\r
+                       }\r
+                       if (!ch->chassistype)\r
+                               /* we assume here that remoteport belongs to line */\r
+                               get_sfb_slot(node, port->remoteport);\r
+\r
+                               /* we could break here, but need to find if more routers connected */\r
+               }\r
+\r
+       } else if (is_line(node)) {\r
+               for (port = node->ports; port; port = port->next) {\r
+                       if (port->portnum > 12)\r
+                               continue;\r
+                       if (!port->remoteport)\r
+                               continue;\r
+                       /* we assume here that remoteport belongs to spine */\r
+                       get_slb_slot(ch, port->remoteport);\r
+                       break;\r
+               }\r
+       }\r
+\r
+       return;\r
+}\r
+\r
+static int get_line_index(Node *node)\r
+{\r
+       int retval = 3 * (node->chrecord->slotnum - 1) + node->chrecord->anafanum;\r
+\r
+       if (retval > LINES_MAX_NUM || retval < 1)\r
+               IBPANIC("Internal error");\r
+       return retval;\r
+}\r
+\r
+static int get_spine_index(Node *node)\r
+{\r
+       int retval;\r
+\r
+       if (is_spine_9288(node) || is_spine_2012(node))\r
+               retval = 3 * (node->chrecord->slotnum - 1) + node->chrecord->anafanum;\r
+       else\r
+               retval = node->chrecord->slotnum;\r
+\r
+       if (retval > SPINES_MAX_NUM || retval < 1)\r
+               IBPANIC("Internal error");\r
+       return retval;\r
+}\r
+\r
+static void insert_line_router(Node *node, ChassisList *chassislist)\r
+{\r
+       int i = get_line_index(node);\r
+\r
+       if (chassislist->linenode[i])\r
+               return;         /* already filled slot */\r
+\r
+       chassislist->linenode[i] = node;\r
+       node->chrecord->chassisnum = chassislist->chassisnum;\r
+}\r
+\r
+static void insert_spine(Node *node, ChassisList *chassislist)\r
+{\r
+       int i = get_spine_index(node);\r
+\r
+       if (chassislist->spinenode[i])\r
+               return;         /* already filled slot */\r
+\r
+       chassislist->spinenode[i] = node;\r
+       node->chrecord->chassisnum = chassislist->chassisnum;\r
+}\r
+\r
+static void pass_on_lines_catch_spines(ChassisList *chassislist)\r
+{\r
+       Node *node, *remnode;\r
+       Port *port;\r
+       int i;\r
+\r
+       for (i = 1; i <= LINES_MAX_NUM; i++) {\r
+               node = chassislist->linenode[i];\r
+\r
+               if (!(node && is_line(node)))\r
+                       continue;       /* empty slot or router */\r
+\r
+               for (port = node->ports; port; port = port->next) {\r
+                       if (port->portnum > 12)\r
+                               continue;\r
+\r
+                       if (!port->remoteport)\r
+                               continue;\r
+                       remnode = port->remoteport->node;\r
+\r
+                       if (!remnode->chrecord)\r
+                               continue;       /* some error - spine not initialized ? FIXME */\r
+                       insert_spine(remnode, chassislist);\r
+               }\r
+       }\r
+}\r
+\r
+static void pass_on_spines_catch_lines(ChassisList *chassislist)\r
+{\r
+       Node *node, *remnode;\r
+       Port *port;\r
+       int i;\r
+\r
+       for (i = 1; i <= SPINES_MAX_NUM; i++) {\r
+               node = chassislist->spinenode[i];\r
+               if (!node)\r
+                       continue;       /* empty slot */\r
+               for (port = node->ports; port; port = port->next) {\r
+                       if (!port->remoteport)\r
+                               continue;\r
+                       remnode = port->remoteport->node;\r
+\r
+                       if (!remnode->chrecord)\r
+                               continue;       /* some error - line/router not initialized ? FIXME */\r
+                       insert_line_router(remnode, chassislist);\r
+               }\r
+       }\r
+}\r
+\r
+/*\r
+       Stupid interpolation algorithm...\r
+       But nothing to do - have to be compliant with VoltaireSM/NMS\r
+*/\r
+static void pass_on_spines_interpolate_chguid(ChassisList *chassislist)\r
+{\r
+       Node *node;\r
+       int i;\r
+\r
+       for (i = 1; i <= SPINES_MAX_NUM; i++) {\r
+               node = chassislist->spinenode[i];\r
+               if (!node)\r
+                       continue;       /* skip the empty slots */\r
+\r
+               /* take first guid minus one to be consistent with SM */\r
+               chassislist->chassisguid = node->nodeguid - 1;\r
+               break;\r
+       }\r
+}\r
+\r
+/*\r
+       This function fills chassislist structure with all nodes\r
+       in that chassis\r
+       chassislist structure = structure of one standalone chassis\r
+*/\r
+static void build_chassis(Node *node, ChassisList *chassislist)\r
+{\r
+       Node *remnode = 0;\r
+       Port *port = 0;\r
+\r
+       /* we get here with node = chassis_spine */\r
+       chassislist->chassistype = node->chrecord->chassistype;\r
+       insert_spine(node, chassislist);\r
+\r
+       /* loop: pass on all ports of node */\r
+       for (port = node->ports; port; port = port->next) {\r
+               if (!port->remoteport)\r
+                       continue;\r
+               remnode = port->remoteport->node;\r
+\r
+               if (!remnode->chrecord)\r
+                       continue; /* some error - line or router not initialized ? FIXME */\r
+\r
+               insert_line_router(remnode, chassislist);\r
+       }\r
+\r
+       pass_on_lines_catch_spines(chassislist);\r
+       /* this pass needed for to catch routers, since routers connected only */\r
+       /* to spines in slot 1 or 4 and we could miss them first time */\r
+       pass_on_spines_catch_lines(chassislist);\r
+\r
+       /* additional 2 passes needed for to overcome a problem of pure "in-chassis" */\r
+       /* connectivity - extra pass to ensure that all related chips/modules */\r
+       /* inserted into the chassislist */\r
+       pass_on_lines_catch_spines(chassislist);\r
+       pass_on_spines_catch_lines(chassislist);\r
+       pass_on_spines_interpolate_chguid(chassislist);\r
+}\r
+\r
+/*========================================================*/\r
+/*                INTERNAL TO EXTERNAL PORT MAPPING       */\r
+/*========================================================*/\r
+\r
+/*\r
+Description : On ISR9288/9096 external ports indexing\r
+              is not matching the internal ( anafa ) port\r
+              indexes. Use this MAP to translate the data you get from\r
+              the OpenIB diagnostics (smpquery, ibroute, ibtracert, etc.)\r
+\r
+\r
+Module : sLB-24\r
+                anafa 1             anafa 2\r
+ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24\r
+int port | 22 23 24 18 17 16 | 22 23 24 18 17 16\r
+ext port | 1  2  3  4  5  6  | 7  8  9  10 11 12\r
+int port | 19 20 21 15 14 13 | 19 20 21 15 14 13\r
+------------------------------------------------\r
+\r
+Module : sLB-8\r
+                anafa 1             anafa 2\r
+ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24\r
+int port | 24 23 22 18 17 16 | 24 23 22 18 17 16\r
+ext port | 1  2  3  4  5  6  | 7  8  9  10 11 12\r
+int port | 21 20 19 15 14 13 | 21 20 19 15 14 13\r
+\r
+----------->\r
+                anafa 1             anafa 2\r
+ext port | -  -  5  -  -  6  | -  -  7  -  -  8\r
+int port | 24 23 22 18 17 16 | 24 23 22 18 17 16\r
+ext port | -  -  1  -  -  2  | -  -  3  -  -  4\r
+int port | 21 20 19 15 14 13 | 21 20 19 15 14 13\r
+------------------------------------------------\r
+\r
+Module : sLB-2024\r
+\r
+ext port | 13 14 15 16 17 18 19 20 21 22 23 24\r
+A1 int port| 13 14 15 16 17 18 19 20 21 22 23 24\r
+ext port | 1 2 3 4 5 6 7 8 9 10 11 12\r
+A2 int port| 13 14 15 16 17 18 19 20 21 22 23 24\r
+---------------------------------------------------\r
+\r
+*/\r
+\r
+int int2ext_map_slb24[2][25] = {\r
+                                       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 5, 4, 18, 17, 16, 1, 2, 3, 13, 14, 15 },\r
+                                       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 11, 10, 24, 23, 22, 7, 8, 9, 19, 20, 21 }\r
+                               };\r
+int int2ext_map_slb8[2][25] = {\r
+                                       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 6, 6, 6, 1, 1, 1, 5, 5, 5 },\r
+                                       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 8, 8, 8, 3, 3, 3, 7, 7, 7 }\r
+                               };\r
+int int2ext_map_slb2024[2][25] = {\r
+                                       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 },\r
+                                       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }\r
+                               };\r
+/*     reference                       { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; */\r
+\r
+/*\r
+       This function relevant only for line modules/chips\r
+       Returns string with external port index\r
+*/\r
+char *portmapstring(Port *port)\r
+{\r
+       static char mapping[OUT_BUFFER_SIZE];\r
+       ChassisRecord *ch = port->node->chrecord;\r
+       int portnum = port->portnum;\r
+       int chipnum = 0;\r
+       int pindex = 0;\r
+       Node *node = port->node;\r
+\r
+       if (!ch || !is_line(node) || (portnum < 13 || portnum > 24))\r
+               return NULL;\r
+\r
+       if (ch->anafanum < 1 || ch->anafanum > 2)\r
+               return NULL;\r
+\r
+       memset(mapping, 0, sizeof(mapping));\r
+\r
+       chipnum = ch->anafanum - 1;\r
+\r
+       if (is_line_24(node))\r
+               pindex = int2ext_map_slb24[chipnum][portnum];\r
+       else if (is_line_2024(node))\r
+               pindex = int2ext_map_slb2024[chipnum][portnum];\r
+       else\r
+               pindex = int2ext_map_slb8[chipnum][portnum];\r
+\r
+       sprintf(mapping, "[ext %d]", pindex);\r
+\r
+       return mapping;\r
+}\r
+\r
+static void add_chassislist()\r
+{\r
+       if (!(mylist.current = calloc(1, sizeof(ChassisList))))\r
+               IBPANIC("out of mem");\r
+\r
+       if (mylist.first == NULL) {\r
+               mylist.first = mylist.current;\r
+               mylist.last = mylist.current;\r
+       } else {\r
+               mylist.last->next = mylist.current;\r
+               mylist.current->next = NULL;\r
+               mylist.last = mylist.current;\r
+       }\r
+}\r
+\r
+/*\r
+       Main grouping function\r
+       Algorithm:\r
+       1. pass on every Voltaire node\r
+       2. catch spine chip for every Voltaire node\r
+               2.1 build/interpolate chassis around this chip\r
+               2.2 go to 1.\r
+       3. pass on non Voltaire nodes (SystemImageGUID based grouping)\r
+       4. now group non Voltaire nodes by SystemImageGUID\r
+*/\r
+ChassisList *group_nodes()\r
+{\r
+       Node *node;\r
+       int dist;\r
+       int chassisnum = 0;\r
+       struct ChassisList *chassis;\r
+\r
+       mylist.first = NULL;\r
+       mylist.current = NULL;\r
+       mylist.last = NULL;\r
+\r
+       /* first pass on switches and build for every Voltaire node */\r
+       /* an appropriate chassis record (slotnum and position) */\r
+       /* according to internal connectivity */\r
+       /* not very efficient but clear code so... */\r
+       for (dist = 0; dist <= maxhops_discovered; dist++) {\r
+               for (node = nodesdist[dist]; node; node = node->dnext) {\r
+                       if (node->vendid == VTR_VENDOR_ID)\r
+                               fill_chassis_record(node);\r
+               }\r
+       }\r
+\r
+       /* separate every Voltaire chassis from each other and build linked list of them */\r
+       /* algorithm: catch spine and find all surrounding nodes */\r
+       for (dist = 0; dist <= maxhops_discovered; dist++) {\r
+               for (node = nodesdist[dist]; node; node = node->dnext) {\r
+                       if (node->vendid != VTR_VENDOR_ID)\r
+                               continue;\r
+                       if (!node->chrecord || node->chrecord->chassisnum || !is_spine(node))\r
+                               continue;\r
+                       add_chassislist();\r
+                       mylist.current->chassisnum = ++chassisnum;\r
+                       build_chassis(node, mylist.current);\r
+               }\r
+       }\r
+\r
+       /* now make pass on nodes for chassis which are not Voltaire */\r
+       /* grouped by common SystemImageGUID */\r
+       for (dist = 0; dist <= maxhops_discovered; dist++) {\r
+               for (node = nodesdist[dist]; node; node = node->dnext) {\r
+                       if (node->vendid == VTR_VENDOR_ID)\r
+                               continue;\r
+                       if (node->sysimgguid) {\r
+                               chassis = find_chassisguid(node);\r
+                               if (chassis)\r
+                                       chassis->nodecount++;\r
+                               else {\r
+                                       /* Possible new chassis */\r
+                                       add_chassislist();\r
+                                       mylist.current->chassisguid = get_chassisguid(node);\r
+                                       mylist.current->nodecount = 1;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       /* now, make another pass to see which nodes are part of chassis */\r
+       /* (defined as chassis->nodecount > 1) */\r
+       for (dist = 0; dist <= MAXHOPS; ) {\r
+               for (node = nodesdist[dist]; node; node = node->dnext) {\r
+                       if (node->vendid == VTR_VENDOR_ID)\r
+                               continue;\r
+                       if (node->sysimgguid) {\r
+                               chassis = find_chassisguid(node);\r
+                               if (chassis && chassis->nodecount > 1) {\r
+                                       if (!chassis->chassisnum)\r
+                                               chassis->chassisnum = ++chassisnum;\r
+                                       if (!node->chrecord) {\r
+                                               if (!(node->chrecord = calloc(1, sizeof(ChassisRecord))))\r
+                                                       IBPANIC("out of mem");\r
+                                               node->chrecord->chassisnum = chassis->chassisnum;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               if (dist == maxhops_discovered)\r
+                       dist = MAXHOPS; /* skip to CAs */\r
+               else\r
+                       dist++;\r
+       }\r
+\r
+       return (mylist.first);\r
+}\r
diff --git a/tools/infiniband_diags/src/ibaddr.c b/tools/infiniband_diags/src/ibaddr.c
new file mode 100644 (file)
index 0000000..65e0308
--- /dev/null
@@ -0,0 +1,221 @@
+/*\r
+ * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif /* HAVE_CONFIG_H */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#if defined(_WIN32) \r
+#include <windows.h>\r
+#include <winsock2.h>\r
+#include <ws2tcpip.h> \r
+#include "..\..\..\..\etc\user\getopt.c"\r
+#else\r
+#include <unistd.h>\r
+#include <stdarg.h>\r
+#include <getopt.h>\r
+#include <arpa/inet.h>\r
+#endif\r
+\r
+#include <infiniband/umad.h>\r
+#include <infiniband/mad.h>\r
+\r
+#include "ibdiag_common.h"\r
+\r
+char *argv0 = "ibaddr";\r
+\r
+static int\r
+ib_resolve_addr(ib_portid_t *portid, int portnum, int show_lid, int show_gid)\r
+{\r
+       char   gid_str[INET6_ADDRSTRLEN];\r
+       uint8_t portinfo[64];\r
+       uint8_t nodeinfo[64];\r
+       uint64_t guid, prefix;\r
+       ibmad_gid_t gid;\r
+       int lmc;\r
+\r
+       if (!smp_query(nodeinfo, portid, IB_ATTR_NODE_INFO, 0, 0))\r
+               return -1;\r
+\r
+       if (!smp_query(portinfo, portid, IB_ATTR_PORT_INFO, portnum, 0))\r
+               return -1;\r
+\r
+       mad_decode_field(portinfo, IB_PORT_LID_F, &portid->lid);\r
+       mad_decode_field(portinfo, IB_PORT_GID_PREFIX_F, &prefix);\r
+       mad_decode_field(portinfo, IB_PORT_LMC_F, &lmc);\r
+       mad_decode_field(nodeinfo, IB_NODE_PORT_GUID_F, &guid);\r
+\r
+       mad_encode_field(gid, IB_GID_PREFIX_F, &prefix);\r
+       mad_encode_field(gid, IB_GID_GUID_F, &guid);\r
+\r
+       if (show_gid) {\r
+               printf("GID %s ", inet_ntop(AF_INET6, gid, gid_str,\r
+                       sizeof gid_str));\r
+       }\r
+\r
+       if (show_lid > 0)\r
+               printf("LID start 0x%x end 0x%x", portid->lid, portid->lid + (1 << lmc) - 1);\r
+       else if (show_lid < 0)\r
+               printf("LID start %d end %d", portid->lid, portid->lid + (1 << lmc) - 1);\r
+       printf("\n");\r
+       return 0;\r
+}\r
+\r
+static void\r
+usage(void)\r
+{\r
+       char *basename;\r
+\r
+       if (!(basename = strrchr(argv0, '/')))\r
+               basename = argv0;\r
+       else\r
+               basename++;\r
+\r
+       fprintf(stderr, "Usage: %s [-d(ebug) -D(irect) -G(uid) -l(id_show) -g(id_show) -s(m_port) sm_lid -C ca_name -P ca_port "\r
+                       "-t(imeout) timeout_ms -V(ersion) -h(elp)] [<lid|dr_path|guid>]\n",\r
+                       basename);\r
+       fprintf(stderr, "\tExamples:\n");\r
+       fprintf(stderr, "\t\t%s\t\t\t# local port's address\n", basename);\r
+       fprintf(stderr, "\t\t%s 32\t\t# show lid range and gid of lid 32\n", basename);\r
+       fprintf(stderr, "\t\t%s -G 0x8f1040023\t# same but using guid address\n", basename);\r
+       fprintf(stderr, "\t\t%s -l 32\t\t# show lid range only\n", basename);\r
+       fprintf(stderr, "\t\t%s -L 32\t\t# show decimal lid range only\n", basename);\r
+       fprintf(stderr, "\t\t%s -g 32\t\t# show gid address only\n", basename);\r
+       exit(-1);\r
+}\r
+\r
+int __cdecl\r
+main(int argc, char **argv)\r
+{\r
+       int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS};\r
+       ib_portid_t *sm_id = 0, sm_portid = {0};\r
+       ib_portid_t portid = {0};\r
+       extern int ibdebug;\r
+       int dest_type = IB_DEST_LID;\r
+       int timeout = 0;        /* use default */\r
+       int show_lid = 0, show_gid = 0;\r
+       int port = 0;\r
+       char *ca = 0;\r
+       int ca_port = 0;\r
+\r
+       static char str_opts[] = "C:P:t:s:dDGglLVhu";\r
+       static struct option long_opts[] = {\r
+               { "C", 1, 0, 'C'},\r
+               { "P", 1, 0, 'P'},\r
+               { "debug", 0, 0, 'd'},\r
+               { "Direct", 0, 0, 'D'},\r
+               { "Guid", 0, 0, 'G'},\r
+               { "gid_show", 0, 0, 'g'},\r
+               { "lid_show", 0, 0, 'l'},\r
+               { "Lid_show", 0, 0, 'L'},\r
+               { "timeout", 1, 0, 't'},\r
+               { "sm_port", 1, 0, 's'},\r
+               { "Version", 0, 0, 'V'},\r
+               { "help", 0, 0, 'h'},\r
+               { "usage", 0, 0, 'u'},\r
+               { 0 }\r
+       };\r
+\r
+       argv0 = argv[0];\r
+\r
+       while (1) {\r
+               int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);\r
+               if ( ch == -1 )\r
+                       break;\r
+               switch(ch) {\r
+               case 'C':\r
+                       ca = optarg;\r
+                       break;\r
+               case 'P':\r
+                       ca_port = strtoul(optarg, 0, 0);\r
+                       break;\r
+               case 'd':\r
+                       ibdebug++;\r
+                       break;\r
+               case 'D':\r
+                       dest_type = IB_DEST_DRPATH;\r
+                       break;\r
+               case 'g':\r
+                       show_gid++;\r
+                       break;\r
+               case 'G':\r
+                       dest_type = IB_DEST_GUID;\r
+                       break;\r
+               case 'l':\r
+                       show_lid++;\r
+                       break;\r
+               case 'L':\r
+                       show_lid = -100;\r
+                       break;\r
+               case 's':\r
+                       if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0)\r
+                               IBERROR("can't resolve SM destination port %s", optarg);\r
+                       sm_id = &sm_portid;\r
+                       break;\r
+               case 't':\r
+                       timeout = strtoul(optarg, 0, 0);\r
+                       madrpc_set_timeout(timeout);\r
+                       break;\r
+               case 'V':\r
+                       fprintf(stderr, "%s %s\n", argv0, get_build_version() );\r
+                       exit(-1);\r
+               default:\r
+                       usage();\r
+                       break;\r
+               }\r
+       }\r
+       argc -= optind;\r
+       argv += optind;\r
+\r
+       if (argc > 1)\r
+               port = strtoul(argv[1], 0, 0);\r
+\r
+       if (!show_lid && !show_gid)\r
+               show_lid = show_gid = 1;\r
+\r
+       madrpc_init(ca, ca_port, mgmt_classes, 3);\r
+\r
+       if (argc) {\r
+               if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0)\r
+                       IBERROR("can't resolve destination port %s", argv[0]);\r
+       } else {\r
+               if (ib_resolve_self(&portid, &port, 0) < 0)\r
+                       IBERROR("can't resolve self port %s", argv[0]);\r
+       }\r
+\r
+       if (ib_resolve_addr(&portid, port, show_lid, show_gid) < 0)\r
+               IBERROR("can't resolve requested address");\r
+       exit(0);\r
+}\r
diff --git a/tools/infiniband_diags/src/ibaddr/SOURCES b/tools/infiniband_diags/src/ibaddr/SOURCES
new file mode 100644 (file)
index 0000000..cbaf51c
--- /dev/null
@@ -0,0 +1,30 @@
+TARGETNAME = ibaddr\r
+TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR)\r
+TARGETTYPE = PROGRAM\r
+\r
+UMTYPE = console\r
+UMENTRY = main\r
+\r
+USE_MSVCRT = 1\r
+USE_STL = 1\r
+USE_NATIVE_EH = 1\r
+USE_IOSTREAM = 1\r
+\r
+SOURCES = ..\ibaddr.c ..\ibdiag_common.c\r
+       \r
+INCLUDES = ..;..\..\include;..\..\..\..\ulp\libibmad\include;..\..\..\..\ulp\libibumad\include;..\..\..\..\inc;..\..\..\..\inc\user;\r
+\r
+TARGETLIBS =   \\r
+       $(SDK_LIB_PATH)\kernel32.lib    \\r
+       $(SDK_LIB_PATH)\advapi32.lib    \\r
+       $(SDK_LIB_PATH)\user32.lib      \\r
+       $(SDK_LIB_PATH)\ole32.lib       \\r
+       $(SDK_LIB_PATH)\ws2_32.lib      \\r
+!if $(FREEBUILD)\r
+       $(TARGETPATH)\*\libibmad.lib    \\r
+       $(TARGETPATH)\*\libibumad.lib   \r
+!else\r
+       $(TARGETPATH)\*\libibmadd.lib   \\r
+       $(TARGETPATH)\*\libibumadd.lib  \r
+!endif\r
+\r
diff --git a/tools/infiniband_diags/src/ibdiag_common.c b/tools/infiniband_diags/src/ibdiag_common.c
new file mode 100644 (file)
index 0000000..a78e4e1
--- /dev/null
@@ -0,0 +1,86 @@
+/*\r
+ * Copyright (c) 2006-2007 The Regents of the University of California.\r
+ * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+/**\r
+ * Define common functions which can be included in the various C based diags.\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+#if defined(_WIN32) || defined(_WIN64)\r
+#include <windows.h>\r
+#include <winsock2.h>\r
+#include <ws2tcpip.h>\r
+#if !defined(getpid)\r
+    #define getpid GetCurrentProcessId\r
+#endif\r
+#else\r
+#define _GNU_SOURCE\r
+#include <errno.h>\r
+#include <string.h>\r
+#include <stdarg.h>\r
+#include <sys/types.h>\r
+#include <unistd.h>\r
+#include <ctype.h>\r
+#include <config.h>\r
+#endif\r
+\r
+#include "ibdiag_common.h"\r
+\r
+int ibdebug;\r
+\r
+void\r
+iberror(const char *fn, char *msg, ...)\r
+{\r
+       char buf[512], *s;\r
+       va_list va;\r
+       int n;\r
+\r
+       va_start(va, msg);\r
+       n = vsprintf(buf, msg, va);\r
+       va_end(va);\r
+       buf[n] = 0;\r
+\r
+       if ((s = strrchr(argv0, '/')))\r
+               argv0 = s + 1;\r
+\r
+       if (ibdebug)\r
+               printf("%s: iberror: [pid %d] %s: failed: %s\n", argv0, getpid(), fn, buf);\r
+       else\r
+               printf("%s: iberror: failed: %s\n", argv0, buf);\r
+\r
+       exit(-1);\r
+}\r
+\r
diff --git a/tools/infiniband_diags/src/ibnetdiscover.c b/tools/infiniband_diags/src/ibnetdiscover.c
new file mode 100644 (file)
index 0000000..faf89ec
--- /dev/null
@@ -0,0 +1,1051 @@
+/*\r
+ * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.\r
+ * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif /* HAVE_CONFIG_H */\r
+\r
+#define _GNU_SOURCE\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <unistd.h>\r
+#include <stdarg.h>\r
+#include <time.h>\r
+#include <string.h>\r
+#include <getopt.h>\r
+#include <errno.h>\r
+#include <inttypes.h>\r
+\r
+#include <infiniband/common.h>\r
+#include <infiniband/umad.h>\r
+#include <infiniband/mad.h>\r
+#include <infiniband/complib/cl_nodenamemap.h>\r
+\r
+#include "ibnetdiscover.h"\r
+#include "grouping.h"\r
+#include "ibdiag_common.h"\r
+\r
+static char *node_type_str[] = {\r
+       "???",\r
+       "ca",\r
+       "switch",\r
+       "router",\r
+       "iwarp rnic"\r
+};\r
+\r
+static char *linkwidth_str[] = {\r
+       "??",\r
+       "1x",\r
+       "4x",\r
+       "??",\r
+       "8x",\r
+       "??",\r
+       "??",\r
+       "??",\r
+       "12x"\r
+};\r
+\r
+static char *linkspeed_str[] = {\r
+       "???",\r
+       "SDR",\r
+       "DDR",\r
+       "???",\r
+       "QDR"\r
+};\r
+\r
+static int timeout = 2000;             /* ms */\r
+static int dumplevel = 0;\r
+static int verbose;\r
+static FILE *f;\r
+\r
+char *argv0 = "ibnetdiscover";\r
+\r
+static char *node_name_map_file = NULL;\r
+static nn_map_t *node_name_map = NULL;\r
+\r
+Node *nodesdist[MAXHOPS+1];     /* last is Ca list */\r
+Node *mynode;\r
+int maxhops_discovered = 0;\r
+\r
+struct ChassisList *chassis = NULL;\r
+\r
+static char *\r
+get_linkwidth_str(int linkwidth)\r
+{\r
+       if (linkwidth > 8)\r
+               return linkwidth_str[0];\r
+       else\r
+               return linkwidth_str[linkwidth];\r
+}\r
+\r
+static char *\r
+get_linkspeed_str(int linkspeed)\r
+{\r
+       if (linkspeed > 4)\r
+               return linkspeed_str[0];\r
+       else\r
+               return linkspeed_str[linkspeed];\r
+}\r
+\r
+static inline const char*\r
+node_type_str2(Node *node)\r
+{\r
+       switch(node->type) {\r
+       case SWITCH_NODE: return "SW";\r
+       case CA_NODE:     return "CA";\r
+       case ROUTER_NODE: return "RT";\r
+       }\r
+       return "??";\r
+}\r
+\r
+void\r
+decode_port_info(void *pi, Port *port)\r
+{\r
+       mad_decode_field(pi, IB_PORT_LID_F, &port->lid);\r
+       mad_decode_field(pi, IB_PORT_LMC_F, &port->lmc);\r
+       mad_decode_field(pi, IB_PORT_STATE_F, &port->state);\r
+       mad_decode_field(pi, IB_PORT_PHYS_STATE_F, &port->physstate);\r
+       mad_decode_field(pi, IB_PORT_LINK_WIDTH_ACTIVE_F, &port->linkwidth);\r
+       mad_decode_field(pi, IB_PORT_LINK_SPEED_ACTIVE_F, &port->linkspeed);\r
+}\r
+\r
+\r
+int\r
+get_port(Port *port, int portnum, ib_portid_t *portid)\r
+{\r
+       char portinfo[64];\r
+       void *pi = portinfo;\r
+\r
+       port->portnum = portnum;\r
+\r
+       if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, portnum, timeout))\r
+               return -1;\r
+       decode_port_info(pi, port);\r
+\r
+       DEBUG("portid %s portnum %d: lid %d state %d physstate %d %s %s",\r
+               portid2str(portid), portnum, port->lid, port->state, port->physstate, get_linkwidth_str(port->linkwidth), get_linkspeed_str(port->linkspeed));\r
+       return 1;\r
+}\r
+/*\r
+ * Returns 0 if non switch node is found, 1 if switch is found, -1 if error.\r
+ */\r
+int\r
+get_node(Node *node, Port *port, ib_portid_t *portid)\r
+{\r
+       char portinfo[64];\r
+       char switchinfo[64];\r
+       void *pi = portinfo, *ni = node->nodeinfo, *nd = node->nodedesc;\r
+       void *si = switchinfo;\r
+\r
+       if (!smp_query(ni, portid, IB_ATTR_NODE_INFO, 0, timeout))\r
+               return -1;\r
+\r
+       mad_decode_field(ni, IB_NODE_GUID_F, &node->nodeguid);\r
+       mad_decode_field(ni, IB_NODE_TYPE_F, &node->type);\r
+       mad_decode_field(ni, IB_NODE_NPORTS_F, &node->numports);\r
+       mad_decode_field(ni, IB_NODE_DEVID_F, &node->devid);\r
+       mad_decode_field(ni, IB_NODE_VENDORID_F, &node->vendid);\r
+       mad_decode_field(ni, IB_NODE_SYSTEM_GUID_F, &node->sysimgguid);\r
+       mad_decode_field(ni, IB_NODE_PORT_GUID_F, &node->portguid);\r
+       mad_decode_field(ni, IB_NODE_LOCAL_PORT_F, &node->localport);\r
+       port->portnum = node->localport;\r
+       port->portguid = node->portguid;\r
+\r
+       if (!smp_query(nd, portid, IB_ATTR_NODE_DESC, 0, timeout))\r
+               return -1;\r
+\r
+       if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, 0, timeout))\r
+               return -1;\r
+       decode_port_info(pi, port);\r
+\r
+       if (node->type != SWITCH_NODE)\r
+               return 0;\r
+\r
+       node->smalid = port->lid;\r
+       node->smalmc = port->lmc;\r
+\r
+       /* after we have the sma information find out the real PortInfo for this port */\r
+       if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, node->localport, timeout))\r
+               return -1;\r
+       decode_port_info(pi, port);\r
+\r
+        if (!smp_query(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout))\r
+                node->smaenhsp0 = 0;   /* assume base SP0 */\r
+       else\r
+               mad_decode_field(si, IB_SW_ENHANCED_PORT0_F, &node->smaenhsp0);\r
+\r
+       DEBUG("portid %s: got switch node %" PRIx64 " '%s'",\r
+             portid2str(portid), node->nodeguid, node->nodedesc);\r
+       return 1;\r
+}\r
+\r
+static int\r
+extend_dpath(ib_dr_path_t *path, int nextport)\r
+{\r
+       if (path->cnt+2 >= sizeof(path->p))\r
+               return -1;\r
+       ++path->cnt;\r
+       if (path->cnt > maxhops_discovered)\r
+               maxhops_discovered = path->cnt;\r
+       path->p[path->cnt] = nextport;\r
+       return path->cnt;\r
+}\r
+\r
+static void\r
+dump_endnode(ib_portid_t *path, char *prompt, Node *node, Port *port)\r
+{\r
+       if (!dumplevel)\r
+               return;\r
+\r
+       fprintf(f, "%s -> %s %s {%016" PRIx64 "} portnum %d lid %d-%d\"%s\"\n",\r
+               portid2str(path), prompt,\r
+               (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"),\r
+               node->nodeguid, node->type == SWITCH_NODE ? 0 : port->portnum,\r
+               port->lid, port->lid + (1 << port->lmc) - 1,\r
+               clean_nodedesc(node->nodedesc));\r
+}\r
+\r
+#define HASHGUID(guid)         ((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103)))\r
+#define HTSZ 137\r
+\r
+static Node *nodestbl[HTSZ];\r
+\r
+static Node *\r
+find_node(Node *new)\r
+{\r
+       int hash = HASHGUID(new->nodeguid) % HTSZ;\r
+       Node *node;\r
+\r
+       for (node = nodestbl[hash]; node; node = node->htnext)\r
+               if (node->nodeguid == new->nodeguid)\r
+                       return node;\r
+\r
+       return NULL;\r
+}\r
+\r
+static Node *\r
+create_node(Node *temp, ib_portid_t *path, int dist)\r
+{\r
+       Node *node;\r
+       int hash = HASHGUID(temp->nodeguid) % HTSZ;\r
+\r
+       node = malloc(sizeof(*node));\r
+       if (!node)\r
+               return NULL;\r
+\r
+       memcpy(node, temp, sizeof(*node));\r
+       node->dist = dist;\r
+       node->path = *path;\r
+\r
+       node->htnext = nodestbl[hash];\r
+       nodestbl[hash] = node;\r
+\r
+       if (node->type != SWITCH_NODE)\r
+               dist = MAXHOPS;         /* special Ca list */\r
+\r
+       node->dnext = nodesdist[dist];\r
+       nodesdist[dist] = node;\r
+\r
+       return node;\r
+}\r
+\r
+static Port *\r
+find_port(Node *node, Port *port)\r
+{\r
+       Port *old;\r
+\r
+       for (old = node->ports; old; old = old->next)\r
+               if (old->portnum == port->portnum)\r
+                       return old;\r
+\r
+       return NULL;\r
+}\r
+\r
+static Port *\r
+create_port(Node *node, Port *temp)\r
+{\r
+       Port *port;\r
+\r
+       port = malloc(sizeof(*port));\r
+       if (!port)\r
+               return NULL;\r
+\r
+       memcpy(port, temp, sizeof(*port));\r
+       port->node = node;\r
+       port->next = node->ports;\r
+       node->ports = port;\r
+\r
+       return port;\r
+}\r
+\r
+static void\r
+link_ports(Node *node, Port *port, Node *remotenode, Port *remoteport)\r
+{\r
+       DEBUG("linking: 0x%" PRIx64 " %p->%p:%u and 0x%" PRIx64 " %p->%p:%u",\r
+               node->nodeguid, node, port, port->portnum,\r
+               remotenode->nodeguid, remotenode, remoteport, remoteport->portnum);\r
+       if (port->remoteport)\r
+               port->remoteport->remoteport = NULL;\r
+       if (remoteport->remoteport)\r
+               remoteport->remoteport->remoteport = NULL;\r
+       port->remoteport = remoteport;\r
+       remoteport->remoteport = port;\r
+}\r
+\r
+static int\r
+handle_port(Node *node, Port *port, ib_portid_t *path, int portnum, int dist)\r
+{\r
+       Node node_buf;\r
+       Port port_buf;\r
+       Node *remotenode, *oldnode;\r
+       Port *remoteport, *oldport;\r
+\r
+       memset(&node_buf, 0, sizeof(node_buf));\r
+       memset(&port_buf, 0, sizeof(port_buf));\r
+\r
+       DEBUG("handle node %p port %p:%d dist %d", node, port, portnum, dist);\r
+       if (port->physstate != 5)       /* LinkUp */\r
+               return -1;\r
+\r
+       if (extend_dpath(&path->drpath, portnum) < 0)\r
+               return -1;\r
+\r
+       if (get_node(&node_buf, &port_buf, path) < 0) {\r
+               IBWARN("NodeInfo on %s failed, skipping port",\r
+                       portid2str(path));\r
+               path->drpath.cnt--;     /* restore path */\r
+               return -1;\r
+       }\r
+\r
+       oldnode = find_node(&node_buf);\r
+       if (oldnode)\r
+               remotenode = oldnode;\r
+       else if (!(remotenode = create_node(&node_buf, path, dist + 1)))\r
+               IBERROR("no memory");\r
+\r
+       oldport = find_port(remotenode, &port_buf);\r
+       if (oldport) {\r
+               remoteport = oldport;\r
+               if (node != remotenode || port != remoteport)\r
+                       IBWARN("port moving...");\r
+       } else if (!(remoteport = create_port(remotenode, &port_buf)))\r
+               IBERROR("no memory");\r
+\r
+       dump_endnode(path, oldnode ? "known remote" : "new remote",\r
+                    remotenode, remoteport);\r
+\r
+       link_ports(node, port, remotenode, remoteport);\r
+\r
+       path->drpath.cnt--;     /* restore path */\r
+       return 0;\r
+}\r
+\r
+/*\r
+ * Return 1 if found, 0 if not, -1 on errors.\r
+ */\r
+static int\r
+discover(ib_portid_t *from)\r
+{\r
+       Node node_buf;\r
+       Port port_buf;\r
+       Node *node;\r
+       Port *port;\r
+       int i;\r
+       int dist = 0;\r
+       ib_portid_t *path;\r
+\r
+       DEBUG("from %s", portid2str(from));\r
+\r
+       memset(&node_buf, 0, sizeof(node_buf));\r
+       memset(&port_buf, 0, sizeof(port_buf));\r
+\r
+       if (get_node(&node_buf, &port_buf, from) < 0) {\r
+               IBWARN("can't reach node %s", portid2str(from));\r
+               return -1;\r
+       }\r
+\r
+       node = create_node(&node_buf, from, 0);\r
+       if (!node)\r
+               IBERROR("out of memory");\r
+\r
+       mynode = node;\r
+\r
+       port = create_port(node, &port_buf);\r
+       if (!port)\r
+               IBERROR("out of memory");\r
+\r
+       if (node->type != SWITCH_NODE &&\r
+           handle_port(node, port, from, node->localport, 0) < 0)\r
+               return 0;\r
+\r
+       for (dist = 0; dist < MAXHOPS; dist++) {\r
+\r
+               for (node = nodesdist[dist]; node; node = node->dnext) {\r
+\r
+                       path = &node->path;\r
+\r
+                       DEBUG("dist %d node %p", dist, node);\r
+                       dump_endnode(path, "processing", node, port);\r
+\r
+                       for (i = 1; i <= node->numports; i++) {\r
+                               if (i == node->localport)\r
+                                       continue;\r
+\r
+                               if (get_port(&port_buf, i, path) < 0) {\r
+                                       IBWARN("can't reach node %s port %d", portid2str(path), i);\r
+                                       continue;\r
+                               }\r
+\r
+                               port = find_port(node, &port_buf);\r
+                               if (port)\r
+                                       continue;\r
+\r
+                               port = create_port(node, &port_buf);\r
+                               if (!port)\r
+                                       IBERROR("out of memory");\r
+\r
+                               /* If switch, set port GUID to node GUID */\r
+                               if (node->type == SWITCH_NODE)\r
+                                       port->portguid = node->portguid;\r
+\r
+                               handle_port(node, port, path, i, dist);\r
+                       }\r
+               }\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+char *\r
+node_name(Node *node)\r
+{\r
+       static char buf[256];\r
+\r
+       switch(node->type) {\r
+       case SWITCH_NODE:\r
+               sprintf(buf, "\"%s", "S");\r
+               break;\r
+       case CA_NODE:\r
+               sprintf(buf, "\"%s", "H");\r
+               break;\r
+       case ROUTER_NODE:\r
+               sprintf(buf, "\"%s", "R");\r
+               break;\r
+       default:\r
+               sprintf(buf, "\"%s", "?");\r
+               break;\r
+       }\r
+       sprintf(buf+2, "-%016" PRIx64 "\"", node->nodeguid);\r
+\r
+       return buf;\r
+}\r
+\r
+void\r
+list_node(Node *node)\r
+{\r
+       char *node_type;\r
+       char *nodename = remap_node_name(node_name_map, node->nodeguid,\r
+                                             node->nodedesc);\r
+\r
+       switch(node->type) {\r
+       case SWITCH_NODE:\r
+               node_type = "Switch";\r
+               break;\r
+       case CA_NODE:\r
+               node_type = "Ca";\r
+               break;\r
+       case ROUTER_NODE:\r
+               node_type = "Router";\r
+               break;\r
+       default:\r
+               node_type = "???";\r
+               break;\r
+       }\r
+       fprintf(f, "%s\t : 0x%016" PRIx64 " ports %d devid 0x%x vendid 0x%x \"%s\"\n",\r
+               node_type,\r
+               node->nodeguid, node->numports, node->devid, node->vendid,\r
+               nodename);\r
+\r
+       free(nodename);\r
+}\r
+\r
+void\r
+out_ids(Node *node, int group, char *chname)\r
+{\r
+       fprintf(f, "\nvendid=0x%x\ndevid=0x%x\n", node->vendid, node->devid);\r
+       if (node->sysimgguid)\r
+               fprintf(f, "sysimgguid=0x%" PRIx64, node->sysimgguid);\r
+       if (group\r
+           && node->chrecord && node->chrecord->chassisnum) {\r
+               fprintf(f, "\t\t# Chassis %d", node->chrecord->chassisnum);\r
+               if (chname)\r
+                       fprintf(f, " (%s)", chname);\r
+               if (is_xsigo_tca(node->nodeguid) && node->ports->remoteport)\r
+                       fprintf(f, " slot %d", node->ports->remoteport->portnum);\r
+       }\r
+       fprintf(f, "\n");\r
+}\r
+\r
+uint64_t\r
+out_chassis(int chassisnum)\r
+{\r
+       uint64_t guid;\r
+\r
+       fprintf(f, "\nChassis %d", chassisnum);\r
+       guid = get_chassis_guid(chassisnum);\r
+       if (guid)\r
+               fprintf(f, " (guid 0x%" PRIx64 ")", guid);\r
+       fprintf(f, "\n");\r
+       return guid;\r
+}\r
+\r
+void\r
+out_switch(Node *node, int group, char *chname)\r
+{\r
+       char *str;\r
+       char *nodename = NULL;\r
+\r
+       out_ids(node, group, chname);\r
+       fprintf(f, "switchguid=0x%" PRIx64, node->nodeguid);\r
+       fprintf(f, "(%" PRIx64 ")", node->portguid);\r
+       /* Currently, only if Voltaire chassis */\r
+       if (group\r
+           && node->chrecord && node->chrecord->chassisnum\r
+           && node->vendid == VTR_VENDOR_ID) {\r
+               str = get_chassis_type(node->chrecord->chassistype);\r
+               if (str)\r
+                       fprintf(f, "%s ", str);\r
+               str = get_chassis_slot(node->chrecord->chassisslot);\r
+               if (str)\r
+                       fprintf(f, "%s ", str);\r
+               fprintf(f, "%d Chip %d", node->chrecord->slotnum, node->chrecord->anafanum);\r
+       }\r
+\r
+       nodename = remap_node_name(node_name_map, node->nodeguid,\r
+                               node->nodedesc);\r
+\r
+       fprintf(f, "\nSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d\n",\r
+               node->numports, node_name(node),\r
+               nodename,\r
+               node->smaenhsp0 ? "enhanced" : "base",\r
+               node->smalid, node->smalmc);\r
+\r
+       free(nodename);\r
+}\r
+\r
+void\r
+out_ca(Node *node, int group, char *chname)\r
+{\r
+       char *node_type;\r
+       char *node_type2;\r
+       char *nodename = remap_node_name(node_name_map, node->nodeguid,\r
+                                             node->nodedesc);\r
+\r
+       out_ids(node, group, chname);\r
+       switch(node->type) {\r
+       case CA_NODE:\r
+               node_type = "ca";\r
+               node_type2 = "Ca";\r
+               break;\r
+       case ROUTER_NODE:\r
+               node_type = "rt";\r
+               node_type2 = "Rt";\r
+               break;\r
+       default:\r
+               node_type = "???";\r
+               node_type2 = "???";\r
+               break;\r
+       }\r
+\r
+       fprintf(f, "%sguid=0x%" PRIx64 "\n", node_type, node->nodeguid);\r
+       fprintf(f, "%s\t%d %s\t\t# \"%s\"",\r
+               node_type2, node->numports, node_name(node),\r
+               nodename);\r
+       if (group && is_xsigo_hca(node->nodeguid))\r
+               fprintf(f, " (scp)");\r
+       fprintf(f, "\n");\r
+\r
+       free(nodename);\r
+}\r
+\r
+static char *\r
+out_ext_port(Port *port, int group)\r
+{\r
+       char *str = NULL;\r
+\r
+       /* Currently, only if Voltaire chassis */\r
+       if (group\r
+           && port->node->chrecord && port->node->vendid == VTR_VENDOR_ID)\r
+               str = portmapstring(port);\r
+\r
+       return (str);\r
+}\r
+\r
+void\r
+out_switch_port(Port *port, int group)\r
+{\r
+       char *ext_port_str = NULL;\r
+       char *rem_nodename = NULL;\r
+\r
+       DEBUG("port %p:%d remoteport %p", port, port->portnum, port->remoteport);\r
+       fprintf(f, "[%d]", port->portnum);\r
+\r
+       ext_port_str = out_ext_port(port, group);\r
+       if (ext_port_str)\r
+               fprintf(f, "%s", ext_port_str);\r
+\r
+       rem_nodename = remap_node_name(node_name_map,\r
+                               port->remoteport->node->nodeguid,\r
+                               port->remoteport->node->nodedesc);\r
+\r
+       ext_port_str = out_ext_port(port->remoteport, group);\r
+       fprintf(f, "\t%s[%d]%s",\r
+               node_name(port->remoteport->node),\r
+               port->remoteport->portnum,\r
+               ext_port_str ? ext_port_str : "");\r
+       if (port->remoteport->node->type != SWITCH_NODE)\r
+               fprintf(f, "(%" PRIx64 ") ", port->remoteport->portguid);\r
+       fprintf(f, "\t\t# \"%s\" lid %d %s%s",\r
+               rem_nodename,\r
+               port->remoteport->node->type == SWITCH_NODE ? port->remoteport->node->smalid : port->remoteport->lid,\r
+               get_linkwidth_str(port->linkwidth),\r
+               get_linkspeed_str(port->linkspeed));\r
+\r
+       if (is_xsigo_tca(port->remoteport->portguid))\r
+               fprintf(f, " slot %d", port->portnum);\r
+       else if (is_xsigo_hca(port->remoteport->portguid))\r
+               fprintf(f, " (scp)");\r
+       fprintf(f, "\n");\r
+\r
+       free(rem_nodename);\r
+}\r
+\r
+void\r
+out_ca_port(Port *port, int group)\r
+{\r
+       char *str = NULL;\r
+       char *rem_nodename = NULL;\r
+\r
+       fprintf(f, "[%d]", port->portnum);\r
+       if (port->node->type != SWITCH_NODE)\r
+               fprintf(f, "(%" PRIx64 ") ", port->portguid);\r
+       fprintf(f, "\t%s[%d]",\r
+               node_name(port->remoteport->node),\r
+               port->remoteport->portnum);\r
+       str = out_ext_port(port->remoteport, group);\r
+       if (str)\r
+               fprintf(f, "%s", str);\r
+       if (port->remoteport->node->type != SWITCH_NODE)\r
+               fprintf(f, " (%" PRIx64 ") ", port->remoteport->portguid);\r
+\r
+       rem_nodename = remap_node_name(node_name_map,\r
+                               port->remoteport->node->nodeguid,\r
+                               port->remoteport->node->nodedesc);\r
+\r
+       fprintf(f, "\t\t# lid %d lmc %d \"%s\" lid %d %s%s\n",\r
+               port->lid, port->lmc, rem_nodename,\r
+               port->remoteport->node->type == SWITCH_NODE ? port->remoteport->node->smalid : port->remoteport->lid,\r
+               get_linkwidth_str(port->linkwidth),\r
+               get_linkspeed_str(port->linkspeed));\r
+\r
+       free(rem_nodename);\r
+}\r
+\r
+int\r
+dump_topology(int listtype, int group)\r
+{\r
+       Node *node;\r
+       Port *port;\r
+       int i = 0, dist = 0;\r
+       time_t t = time(0);\r
+       uint64_t chguid;\r
+       char *chname = NULL;\r
+\r
+       if (!listtype) {\r
+               fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t));\r
+               fprintf(f, "# Max of %d hops discovered\n", maxhops_discovered);\r
+               fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n", mynode->nodeguid, mynode->portguid);\r
+       }\r
+\r
+       /* Make pass on switches */\r
+       if (group && !listtype) {\r
+               ChassisList *ch = NULL;\r
+\r
+               /* Chassis based switches first */\r
+               for (ch = chassis; ch; ch = ch->next) {\r
+                       int n = 0;\r
+\r
+                       if (!ch->chassisnum)\r
+                               continue;\r
+                       chguid = out_chassis(ch->chassisnum);\r
+                       if (chname)\r
+                               free(chname);\r
+                       chname = NULL;\r
+                       if (is_xsigo_guid(chguid)) {\r
+                               for (node = nodesdist[MAXHOPS]; node; node = node->dnext) {\r
+                                       if (!node->chrecord ||\r
+                                           !node->chrecord->chassisnum)\r
+                                               continue;\r
+\r
+                                       if (node->chrecord->chassisnum != ch->chassisnum)\r
+                                               continue;\r
+\r
+                                       if (is_xsigo_hca(node->nodeguid)) {\r
+                                               chname = remap_node_name(node_name_map,\r
+                                                               node->nodeguid,\r
+                                                               node->nodedesc);\r
+                                               fprintf(f, "Hostname: %s\n", chname);\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       fprintf(f, "\n# Spine Nodes");\r
+                       for (n = 1; n <= (SPINES_MAX_NUM+1); n++) {\r
+                               if (ch->spinenode[n]) {\r
+                                       out_switch(ch->spinenode[n], group, chname);\r
+                                       for (port = ch->spinenode[n]->ports; port; port = port->next, i++)\r
+                                               if (port->remoteport)\r
+                                                       out_switch_port(port, group);\r
+                               }\r
+                       }\r
+                       fprintf(f, "\n# Line Nodes");\r
+                       for (n = 1; n <= (LINES_MAX_NUM+1); n++) {\r
+                               if (ch->linenode[n]) {\r
+                                       out_switch(ch->linenode[n], group, chname);\r
+                                       for (port = ch->linenode[n]->ports; port; port = port->next, i++)\r
+                                               if (port->remoteport)\r
+                                                       out_switch_port(port, group);\r
+                               }\r
+                       }\r
+\r
+                       fprintf(f, "\n# Chassis Switches");\r
+                       for (dist = 0; dist <= maxhops_discovered; dist++) {\r
+\r
+                               for (node = nodesdist[dist]; node; node = node->dnext) {\r
+\r
+                                       /* Non Voltaire chassis */\r
+                                       if (node->vendid == VTR_VENDOR_ID)\r
+                                               continue;\r
+                                       if (!node->chrecord ||\r
+                                           !node->chrecord->chassisnum)\r
+                                               continue;\r
+\r
+                                       if (node->chrecord->chassisnum != ch->chassisnum)\r
+                                               continue;\r
+\r
+                                       out_switch(node, group, chname);\r
+                                       for (port = node->ports; port; port = port->next, i++)\r
+                                               if (port->remoteport)\r
+                                                       out_switch_port(port, group);\r
+\r
+                               }\r
+\r
+                       }\r
+\r
+                       fprintf(f, "\n# Chassis CAs");\r
+                       for (node = nodesdist[MAXHOPS]; node; node = node->dnext) {\r
+                               if (!node->chrecord ||\r
+                                   !node->chrecord->chassisnum)\r
+                                       continue;\r
+\r
+                               if (node->chrecord->chassisnum != ch->chassisnum)\r
+                                       continue;\r
+\r
+                               out_ca(node, group, chname);\r
+                               for (port = node->ports; port; port = port->next, i++)\r
+                                       if (port->remoteport)\r
+                                               out_ca_port(port, group);\r
+\r
+                       }\r
+\r
+               }\r
+\r
+       } else {\r
+               for (dist = 0; dist <= maxhops_discovered; dist++) {\r
+\r
+                       for (node = nodesdist[dist]; node; node = node->dnext) {\r
+\r
+                               DEBUG("SWITCH: dist %d node %p", dist, node);\r
+                               if (!listtype)\r
+                                       out_switch(node, group, chname);\r
+                               else {\r
+                                       if (listtype & LIST_SWITCH_NODE)\r
+                                               list_node(node);\r
+                                       continue;\r
+                               }\r
+\r
+                               for (port = node->ports; port; port = port->next, i++)\r
+                                       if (port->remoteport)\r
+                                               out_switch_port(port, group);\r
+                       }\r
+               }\r
+       }\r
+\r
+       if (chname)\r
+               free(chname);\r
+       chname = NULL;\r
+       if (group && !listtype) {\r
+\r
+               fprintf(f, "\nNon-Chassis Nodes\n");\r
+\r
+               for (dist = 0; dist <= maxhops_discovered; dist++) {\r
+\r
+                       for (node = nodesdist[dist]; node; node = node->dnext) {\r
+\r
+                               DEBUG("SWITCH: dist %d node %p", dist, node);\r
+                               /* Now, skip chassis based switches */\r
+                               if (node->chrecord &&\r
+                                   node->chrecord->chassisnum)\r
+                                       continue;\r
+                               out_switch(node, group, chname);\r
+\r
+                               for (port = node->ports; port; port = port->next, i++)\r
+                                       if (port->remoteport)\r
+                                               out_switch_port(port, group);\r
+                       }\r
+\r
+               }\r
+\r
+       }\r
+\r
+       /* Make pass on CAs */\r
+       for (node = nodesdist[MAXHOPS]; node; node = node->dnext) {\r
+\r
+               DEBUG("CA: dist %d node %p", dist, node);\r
+               if (!listtype) {\r
+                       /* Now, skip chassis based CAs */\r
+                       if (group && node->chrecord &&\r
+                           node->chrecord->chassisnum)\r
+                               continue;\r
+                       out_ca(node, group, chname);\r
+               } else {\r
+                       if (((listtype & LIST_CA_NODE) && (node->type == CA_NODE)) ||\r
+                           ((listtype & LIST_ROUTER_NODE) && (node->type == ROUTER_NODE)))\r
+                               list_node(node);\r
+                       continue;\r
+               }\r
+\r
+               for (port = node->ports; port; port = port->next, i++)\r
+                       if (port->remoteport)\r
+                               out_ca_port(port, group);\r
+       }\r
+\r
+       if (chname)\r
+               free(chname);\r
+\r
+       return i;\r
+}\r
+\r
+void dump_ports_report ()\r
+{\r
+       int b, n = 0, p;\r
+       Node *node;\r
+       Port *port;\r
+\r
+       // If switch and LID == 0, search of other switch ports with\r
+       // valid LID and assign it to all ports of that switch\r
+       for (b = 0; b <= MAXHOPS; b++)\r
+               for (node = nodesdist[b]; node; node = node->dnext)\r
+                       if (node->type == SWITCH_NODE) {\r
+                               int swlid = 0;\r
+                               for (p = 0, port = node->ports;\r
+                                    p < node->numports && port && !swlid;\r
+                                    port = port->next)\r
+                                       if (port->lid != 0)\r
+                                               swlid = port->lid;\r
+                               for (p = 0, port = node->ports;\r
+                                    p < node->numports && port;\r
+                                    port = port->next)\r
+                                       port->lid = swlid;\r
+                       }\r
+\r
+       for (b = 0; b <= MAXHOPS; b++)\r
+               for (node = nodesdist[b]; node; node = node->dnext) {\r
+                       for (p = 0, port = node->ports;\r
+                            p < node->numports && port;\r
+                            p++, port = port->next) {\r
+                               fprintf(stdout,\r
+                                       "%2s %5d %2d 0x%016" PRIx64 " %s %s",\r
+                                       node_type_str2(port->node), port->lid,\r
+                                       port->portnum,\r
+                                       port->portguid,\r
+                                       get_linkwidth_str(port->linkwidth),\r
+                                       get_linkspeed_str(port->linkspeed));\r
+                               if (port->remoteport)\r
+                                       fprintf(stdout,\r
+                                               " - %2s %5d %2d 0x%016" PRIx64\r
+                                               " ( '%s' - '%s' )\n",\r
+                                               node_type_str2(port->remoteport->node),\r
+                                               port->remoteport->lid,\r
+                                               port->remoteport->portnum,\r
+                                               port->remoteport->portguid,\r
+                                               port->node->nodedesc,\r
+                                               port->remoteport->node->nodedesc);\r
+                               else\r
+                                       fprintf(stdout, "%36s'%s'\n", "",\r
+                                               port->node->nodedesc);\r
+                       }\r
+                       n++;\r
+               }\r
+}\r
+\r
+void\r
+usage(void)\r
+{\r
+       fprintf(stderr, "Usage: %s [-d(ebug)] -e(rr_show) -v(erbose) -s(how) -l(ist) -g(rouping) -H(ca_list) -S(witch_list) -R(outer_list) -V(ersion) -C ca_name -P ca_port "\r
+                       "-t(imeout) timeout_ms --node-name-map node-name-map] -p(orts) [<topology-file>]\n",\r
+                       argv0);\r
+       fprintf(stderr, "       --node-name-map <node-name-map> specify a node name map file\n");\r
+       exit(-1);\r
+}\r
+\r
+int\r
+main(int argc, char **argv)\r
+{\r
+       int mgmt_classes[2] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS};\r
+       ib_portid_t my_portid = {0};\r
+       int udebug = 0, list = 0;\r
+       char *ca = 0;\r
+       int ca_port = 0;\r
+       int group = 0;\r
+       int ports_report = 0;\r
+\r
+       static char const str_opts[] = "C:P:t:devslgHSRpVhu";\r
+       static const struct option long_opts[] = {\r
+               { "C", 1, 0, 'C'},\r
+               { "P", 1, 0, 'P'},\r
+               { "debug", 0, 0, 'd'},\r
+               { "err_show", 0, 0, 'e'},\r
+               { "verbose", 0, 0, 'v'},\r
+               { "show", 0, 0, 's'},\r
+               { "list", 0, 0, 'l'},\r
+               { "grouping", 0, 0, 'g'},\r
+               { "Hca_list", 0, 0, 'H'},\r
+               { "Switch_list", 0, 0, 'S'},\r
+               { "Router_list", 0, 0, 'R'},\r
+               { "timeout", 1, 0, 't'},\r
+               { "node-name-map", 1, 0, 1},\r
+               { "ports", 0, 0, 'p'},\r
+               { "Version", 0, 0, 'V'},\r
+               { "help", 0, 0, 'h'},\r
+               { "usage", 0, 0, 'u'},\r
+               { }\r
+       };\r
+\r
+       f = stdout;\r
+\r
+       argv0 = argv[0];\r
+\r
+       while (1) {\r
+               int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);\r
+               if ( ch == -1 )\r
+                       break;\r
+               switch(ch) {\r
+               case 1:\r
+                       node_name_map_file = strdup(optarg);\r
+                       break;\r
+               case 'C':\r
+                       ca = optarg;\r
+                       break;\r
+               case 'P':\r
+                       ca_port = strtoul(optarg, 0, 0);\r
+                       break;\r
+               case 'd':\r
+                       ibdebug++;\r
+                       madrpc_show_errors(1);\r
+                       umad_debug(udebug);\r
+                       udebug++;\r
+                       break;\r
+               case 't':\r
+                       timeout = strtoul(optarg, 0, 0);\r
+                       break;\r
+               case 'v':\r
+                       verbose++;\r
+                       dumplevel++;\r
+                       break;\r
+               case 's':\r
+                       dumplevel = 1;\r
+                       break;\r
+               case 'e':\r
+                       madrpc_show_errors(1);\r
+                       break;\r
+               case 'l':\r
+                       list = LIST_CA_NODE | LIST_SWITCH_NODE | LIST_ROUTER_NODE;\r
+                       break;\r
+               case 'g':\r
+                       group = 1;\r
+                       break;\r
+               case 'S':\r
+                       list = LIST_SWITCH_NODE;\r
+                       break;\r
+               case 'H':\r
+                       list = LIST_CA_NODE;\r
+                       break;\r
+               case 'R':\r
+                       list = LIST_ROUTER_NODE;\r
+                       break;\r
+               case 'V':\r
+                       fprintf(stderr, "%s %s\n", argv0, get_build_version() );\r
+                       exit(-1);\r
+               case 'p':\r
+                       ports_report = 1;\r
+                       break;\r
+               default:\r
+                       usage();\r
+                       break;\r
+               }\r
+       }\r
+       argc -= optind;\r
+       argv += optind;\r
+\r
+       if (argc && !(f = fopen(argv[0], "w")))\r
+               IBERROR("can't open file %s for writing", argv[0]);\r
+\r
+       madrpc_init(ca, ca_port, mgmt_classes, 2);\r
+       node_name_map = open_node_name_map(node_name_map_file);\r
+\r
+       if (discover(&my_portid) < 0)\r
+               IBERROR("discover");\r
+\r
+       if (group)\r
+               chassis = group_nodes();\r
+\r
+       if (ports_report)\r
+               dump_ports_report();\r
+       else\r
+               dump_topology(list, group);\r
+\r
+       close_node_name_map(node_name_map);\r
+       exit(0);\r
+}\r
diff --git a/tools/infiniband_diags/src/ibnetdiscover/SOURCES b/tools/infiniband_diags/src/ibnetdiscover/SOURCES
new file mode 100644 (file)
index 0000000..849db8e
--- /dev/null
@@ -0,0 +1,30 @@
+TARGETNAME = ibnetdiscover\r
+TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR)\r
+TARGETTYPE = PROGRAM\r
+\r
+UMTYPE = console\r
+UMENTRY = main\r
+\r
+USE_MSVCRT = 1\r
+USE_STL = 1\r
+USE_NATIVE_EH = 1\r
+USE_IOSTREAM = 1\r
+\r
+SOURCES = ..\ibnetdiscover.c ..\ibdiag_common.c\r
+       \r
+INCLUDES = ..;..\..\include;..\..\..\..\ulp\libibmad\include;..\..\..\..\ulp\libibumad\include;..\..\..\..\inc;..\..\..\..\inc\user;\r
+\r
+TARGETLIBS =   \\r
+       $(SDK_LIB_PATH)\kernel32.lib    \\r
+       $(SDK_LIB_PATH)\advapi32.lib    \\r
+       $(SDK_LIB_PATH)\user32.lib      \\r
+       $(SDK_LIB_PATH)\ole32.lib       \\r
+       $(SDK_LIB_PATH)\ws2_32.lib      \\r
+!if $(FREEBUILD)\r
+       $(TARGETPATH)\*\libibmad.lib    \\r
+       $(TARGETPATH)\*\libibumad.lib   \r
+!else\r
+       $(TARGETPATH)\*\libibmadd.lib   \\r
+       $(TARGETPATH)\*\libibumadd.lib  \r
+!endif\r
+\r
diff --git a/tools/infiniband_diags/src/ibping.c b/tools/infiniband_diags/src/ibping.c
new file mode 100644 (file)
index 0000000..767436b
--- /dev/null
@@ -0,0 +1,338 @@
+/*\r
+ * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif /* HAVE_CONFIG_H */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+#if defined(_WIN32) \r
+#include <windows.h>\r
+#include <winsock2.h>\r
+#include <ws2tcpip.h> \r
+#include "..\..\..\..\etc\user\getopt.c"\r
+#else\r
+#include <unistd.h>\r
+#include <stdarg.h>\r
+#include <time.h>\r
+#include <string.h>\r
+#include <signal.h>\r
+#include <getopt.h>\r
+#endif\r
+\r
+#include <infiniband/umad.h>\r
+#include <infiniband/mad.h>\r
+\r
+#include "ibdiag_common.h"\r
+\r
+#undef DEBUG\r
+#define        DEBUG   if (verbose) IBWARN\r
+\r
+static int dest_type = IB_DEST_LID;\r
+static int verbose;\r
+static char host_and_domain[IB_VENDOR_RANGE2_DATA_SIZE];\r
+static char last_host[IB_VENDOR_RANGE2_DATA_SIZE];\r
+\r
+char *argv0 = "ibping";\r
+\r
+static void\r
+get_host_and_domain(char *data, int sz)\r
+{\r
+       char *s = data;\r
+       int n;\r
+\r
+       if (gethostname(s, sz) < 0)\r
+               snprintf(s, sz, "?hostname?");\r
+\r
+       s[sz-1] = 0;\r
+       if ((n = strlen(s)) >= sz)\r
+               return;\r
+       s[n] = '.';\r
+       s += n + 1;\r
+       sz -= n + 1;\r
+\r
+       if (getdomainname(s, sz) < 0)\r
+               snprintf(s, sz, "?domainname?");\r
+       if (strlen(s) == 0)\r
+               s[-1] = 0;      /* no domain */\r
+}\r
+\r
+static char *\r
+ibping_serv(void)\r
+{\r
+       void *umad;\r
+       void *mad;\r
+       char *data;\r
+\r
+       DEBUG("starting to serve...");\r
+\r
+       while ((umad = mad_receive(0, -1))) {\r
+\r
+               mad = umad_get_mad(umad);\r
+               data = (char *)mad + IB_VENDOR_RANGE2_DATA_OFFS;\r
+\r
+               memcpy(data, host_and_domain, IB_VENDOR_RANGE2_DATA_SIZE);\r
+\r
+               DEBUG("Pong: %s", data);\r
+\r
+               if (mad_respond(umad, 0, 0) < 0)\r
+                       DEBUG("respond failed");\r
+\r
+               mad_free(umad);\r
+       }\r
+\r
+       DEBUG("server out");\r
+       return 0;\r
+}\r
+\r
+static uint64_t\r
+ibping(ib_portid_t *portid, int quiet)\r
+{\r
+       char data[IB_VENDOR_RANGE2_DATA_SIZE] = {0};\r
+       ib_vendor_call_t call;\r
+       uint64_t start, rtt;\r
+\r
+       DEBUG("Ping..");\r
+\r
+       start = getcurrenttime();\r
+\r
+       call.method = IB_MAD_METHOD_GET;\r
+       call.mgmt_class = IB_VENDOR_OPENIB_PING_CLASS;\r
+       call.attrid = 0;\r
+       call.mod = 0;\r
+       call.oui = IB_OPENIB_OUI;\r
+       call.timeout = 0;\r
+       memset(&call.rmpp, 0, sizeof call.rmpp);\r
+\r
+       if (!ib_vendor_call(data, portid, &call))\r
+               return ~0llu;\r
+\r
+       rtt = getcurrenttime() - start;\r
+\r
+       if (!last_host[0])\r
+               memcpy(last_host, data, sizeof last_host);\r
+\r
+       if (!quiet)\r
+               printf("Pong from %s (%s): time %" PRIu64 ".%03" PRIu64 " ms\n",\r
+                       data, portid2str(portid), rtt/1000, rtt%1000);\r
+\r
+       return rtt;\r
+}\r
+\r
+static void\r
+usage(void)\r
+{\r
+       char *basename;\r
+\r
+       if (!(basename = strrchr(argv0, '/')))\r
+               basename = argv0;\r
+       else\r
+               basename++;\r
+\r
+       fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port "\r
+                       "-t(imeout) timeout_ms -c ping_count -f(lood) -o oui -S(erver)] <dest lid|guid>\n",\r
+                       basename);\r
+       exit(-1);\r
+}\r
+\r
+static uint64_t minrtt = ~0ull, maxrtt, total_rtt;\r
+static uint64_t start, total_time, replied, lost, ntrans;\r
+static ib_portid_t portid = {0};\r
+\r
+void\r
+report(int sig)\r
+{\r
+       total_time = getcurrenttime() - start;\r
+\r
+       DEBUG("out due signal %d", sig);\r
+\r
+       printf("\n--- %s (%s) ibping statistics ---\n", last_host, portid2str(&portid));\r
+       printf("%" PRIu64 " packets transmitted, %" PRIu64 " received, %" PRIu64 "%% packet loss, time %" PRIu64 " ms\n",\r
+               ntrans, replied,\r
+               (lost != 0) ?  lost * 100 / ntrans : 0, total_time / 1000);\r
+       printf("rtt min/avg/max = %" PRIu64 ".%03" PRIu64 "/%" PRIu64 ".%03" PRIu64 "/%" PRIu64 ".%03" PRIu64 " ms\n",\r
+               minrtt == ~0ull ? 0 : minrtt/1000,\r
+               minrtt == ~0ull ? 0 : minrtt%1000,\r
+               replied ? total_rtt/replied/1000 : 0,\r
+               replied ? (total_rtt/replied)%1000 : 0,\r
+               maxrtt/1000, maxrtt%1000);\r
+\r
+       exit(0);\r
+}\r
+\r
+int\r
+main(int argc, char **argv)\r
+{\r
+       int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS};\r
+       int ping_class = IB_VENDOR_OPENIB_PING_CLASS;\r
+       ib_portid_t *sm_id = 0, sm_portid = {0};\r
+       int timeout = 0, udebug = 0, server = 0, flood = 0;\r
+       int oui = IB_OPENIB_OUI;\r
+       uint64_t rtt;\r
+       uint count = ~0;\r
+       extern int ibdebug;\r
+       char *err;\r
+       char *ca = 0;\r
+       int ca_port = 0;\r
+\r
+       static char str_opts[] = "C:P:t:s:c:o:devGfSVhu";\r
+       static struct option long_opts[] = {\r
+               { "C", 1, 0, 'C'},\r
+               { "P", 1, 0, 'P'},\r
+               { "debug", 0, 0, 'd'},\r
+               { "err_show", 0, 0, 'e'},\r
+               { "verbose", 0, 0, 'v'},\r
+               { "Guid", 0, 0, 'G'},\r
+               { "s", 1, 0, 's'},\r
+               { "timeout", 1, 0, 't'},\r
+               { "c", 1, 0, 'c'},\r
+               { "flood", 0, 0, 'f'},\r
+               { "o", 1, 0, 'o'},\r
+               { "Server", 0, 0, 'S'},\r
+               { "Version", 0, 0, 'V'},\r
+               { "help", 0, 0, 'h'},\r
+               { "usage", 0, 0, 'u'},\r
+               { 0 }\r
+       };\r
+\r
+       argv0 = argv[0];\r
+\r
+       while (1) {\r
+               int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);\r
+               if ( ch == -1 )\r
+                       break;\r
+               switch(ch) {\r
+               case 'C':\r
+                       ca = optarg;\r
+                       break;\r
+               case 'P':\r
+                       ca_port = strtoul(optarg, 0, 0);\r
+                       break;\r
+               case 'c':\r
+                       count = strtoul(optarg, 0, 0);\r
+                       break;\r
+               case 'd':\r
+                       ibdebug++;\r
+                       madrpc_show_errors(1);\r
+                       umad_debug(udebug);\r
+                       udebug++;\r
+                       break;\r
+               case 'e':\r
+                       madrpc_show_errors(1);\r
+                       break;\r
+               case 'f':\r
+                       flood++;\r
+                       break;\r
+               case 'G':\r
+                       dest_type = IB_DEST_GUID;\r
+                       break;\r
+               case 'o':\r
+                       oui = strtoul(optarg, 0, 0);\r
+                       break;\r
+               case 's':\r
+                       if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0)\r
+                               IBERROR("can't resolve SM destination port %s", optarg);\r
+                       sm_id = &sm_portid;\r
+                       break;\r
+               case 'S':\r
+                       server++;\r
+                       break;\r
+               case 't':\r
+                       timeout = strtoul(optarg, 0, 0);\r
+                       madrpc_set_timeout(timeout);\r
+                       break;\r
+               case 'v':\r
+                       verbose++;\r
+                       break;\r
+               case 'V':\r
+                       fprintf(stderr, "%s %s\n", argv0, get_build_version() );\r
+                       exit(-1);\r
+               default:\r
+                       usage();\r
+                       break;\r
+               }\r
+       }\r
+       argc -= optind;\r
+       argv += optind;\r
+\r
+       if (!argc && !server)\r
+               usage();\r
+\r
+       madrpc_init(ca, ca_port, mgmt_classes, 3);\r
+\r
+       if (server) {\r
+               if (mad_register_server(ping_class, 0, 0, oui) < 0)\r
+                       IBERROR("can't serve class %d on this port", ping_class);\r
+\r
+               get_host_and_domain(host_and_domain, sizeof host_and_domain);\r
+\r
+               if ((err = ibping_serv()))\r
+                       IBERROR("ibping to %s: %s", portid2str(&portid), err);\r
+               exit(0);\r
+       }\r
+\r
+       if (mad_register_client(ping_class, 0) < 0)\r
+               IBERROR("can't register ping class %d on this port", ping_class);\r
+\r
+       if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0)\r
+               IBERROR("can't resolve destination port %s", argv[0]);\r
+\r
+       signal(SIGINT, report);\r
+       signal(SIGTERM, report);\r
+\r
+       start = getcurrenttime();\r
+\r
+       while (count-- > 0) {\r
+               ntrans++;\r
+               if ((rtt = ibping(&portid, flood)) == ~0ull) {\r
+                       DEBUG("ibping to %s failed", portid2str(&portid));\r
+                       lost++;\r
+               } else {\r
+                       if (rtt < minrtt)\r
+                               minrtt = rtt;\r
+                       if (rtt > maxrtt)\r
+                               maxrtt = rtt;\r
+                       total_rtt += rtt;\r
+                       replied++;\r
+               }\r
+\r
+               if (!flood)\r
+                       sleep(1);\r
+       }\r
+\r
+       report(0);\r
+\r
+       exit(-1);\r
+}\r
diff --git a/tools/infiniband_diags/src/ibping/SOURCES b/tools/infiniband_diags/src/ibping/SOURCES
new file mode 100644 (file)
index 0000000..0d9d896
--- /dev/null
@@ -0,0 +1,30 @@
+TARGETNAME = ibping\r
+TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR)\r
+TARGETTYPE = PROGRAM\r
+\r
+UMTYPE = console\r
+UMENTRY = main\r
+\r
+USE_MSVCRT = 1\r
+USE_STL = 1\r
+USE_NATIVE_EH = 1\r
+USE_IOSTREAM = 1\r
+\r
+SOURCES = ..\ibping.c ..\ibdiag_common.c\r
+       \r
+INCLUDES = ..;..\..\include;..\..\..\..\ulp\libibmad\include;..\..\..\..\ulp\libibumad\include;..\..\..\..\inc;..\..\..\..\inc\user;\r
+\r
+TARGETLIBS =   \\r
+       $(SDK_LIB_PATH)\kernel32.lib    \\r
+       $(SDK_LIB_PATH)\advapi32.lib    \\r
+       $(SDK_LIB_PATH)\user32.lib      \\r
+       $(SDK_LIB_PATH)\ole32.lib       \\r
+       $(SDK_LIB_PATH)\ws2_32.lib      \\r
+!if $(FREEBUILD)\r
+       $(TARGETPATH)\*\libibmad.lib    \\r
+       $(TARGETPATH)\*\libibumad.lib   \r
+!else\r
+       $(TARGETPATH)\*\libibmadd.lib   \\r
+       $(TARGETPATH)\*\libibumadd.lib  \r
+!endif\r
+\r
diff --git a/tools/infiniband_diags/src/ibportstate.c b/tools/infiniband_diags/src/ibportstate.c
new file mode 100644 (file)
index 0000000..07d7a01
--- /dev/null
@@ -0,0 +1,448 @@
+/*\r
+ * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif /* HAVE_CONFIG_H */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <unistd.h>\r
+#include <stdarg.h>\r
+#include <time.h>\r
+#include <string.h>\r
+#include <getopt.h>\r
+\r
+#include <infiniband/common.h>\r
+#include <infiniband/umad.h>\r
+#include <infiniband/mad.h>\r
+\r
+#include "ibdiag_common.h"\r
+\r
+#undef DEBUG\r
+#define        DEBUG   if (verbose>1) IBWARN\r
+\r
+static int dest_type = IB_DEST_LID;\r
+static int verbose;\r
+\r
+char *argv0 = "ibportstate";\r
+\r
+/*******************************************/\r
+\r
+static int\r
+get_node_info(ib_portid_t *dest, uint8_t *data)\r
+{\r
+       int node_type;\r
+\r
+       if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0))\r
+               return -1;\r
+\r
+       node_type = mad_get_field(data, 0, IB_NODE_TYPE_F);\r
+       if (node_type == IB_NODE_SWITCH)        /* Switch NodeType ? */\r
+               return 0;\r
+       else\r
+               return 1;\r
+}\r
+\r
+static int\r
+get_port_info(ib_portid_t *dest, uint8_t *data, int portnum, int port_op)\r
+{\r
+       char buf[2048];\r
+       char val[64];\r
+\r
+       if (!smp_query(data, dest, IB_ATTR_PORT_INFO, portnum, 0))\r
+               return -1;\r
+\r
+       if (port_op != 4) {\r
+               mad_dump_portstates(buf, sizeof buf, data, sizeof data);\r
+               mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, val);\r
+               mad_dump_field(IB_PORT_LINK_WIDTH_SUPPORTED_F, buf + strlen(buf), sizeof buf - strlen(buf), val);\r
+               sprintf(buf+strlen(buf), "%s", "\n");\r
+               mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, val);\r
+               mad_dump_field(IB_PORT_LINK_WIDTH_ENABLED_F, buf + strlen(buf), sizeof buf - strlen(buf), val);\r
+               sprintf(buf+strlen(buf), "%s", "\n");\r
+               mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, val);\r
+               mad_dump_field(IB_PORT_LINK_WIDTH_ACTIVE_F, buf + strlen(buf), sizeof buf - strlen(buf), val);\r
+               sprintf(buf+strlen(buf), "%s", "\n");\r
+               mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, val);\r
+               mad_dump_field(IB_PORT_LINK_SPEED_SUPPORTED_F, buf + strlen(buf), sizeof buf - strlen(buf), val);\r
+               sprintf(buf+strlen(buf), "%s", "\n");\r
+               mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val);\r
+               mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf + strlen(buf), sizeof buf - strlen(buf), val);\r
+               sprintf(buf+strlen(buf), "%s", "\n");\r
+               mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, val);\r
+               mad_dump_field(IB_PORT_LINK_SPEED_ACTIVE_F, buf + strlen(buf), sizeof buf - strlen(buf), val);\r
+               sprintf(buf+strlen(buf), "%s", "\n");\r
+       } else {\r
+               mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val);\r
+               mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf, sizeof buf, val);\r
+               sprintf(buf+strlen(buf), "%s", "\n");\r
+       }\r
+\r
+       printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf);\r
+       return 0;\r
+}\r
+\r
+static int\r
+set_port_info(ib_portid_t *dest, uint8_t *data, int portnum, int port_op)\r
+{\r
+       char buf[2048];\r
+       char val[64];\r
+\r
+       if (!smp_set(data, dest, IB_ATTR_PORT_INFO, portnum, 0))\r
+               return -1;\r
+\r
+       if (port_op != 4)\r
+               mad_dump_portstates(buf, sizeof buf, data, sizeof data);\r
+       else {\r
+               mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val);\r
+               mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf, sizeof buf, val);\r
+               sprintf(buf+strlen(buf), "%s", "\n");\r
+       }\r
+\r
+       printf("\nAfter PortInfo set:\n");\r
+       printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf);\r
+       return 0;\r
+}\r
+\r
+static int\r
+get_link_width(int lwe, int lws)\r
+{\r
+       if (lwe == 255)\r
+               return lws;\r
+       else\r
+               return lwe;\r
+}\r
+\r
+static int\r
+get_link_speed(int lse, int lss)\r
+{\r
+       if (lse == 15)\r
+               return lss;\r
+       else\r
+               return lse;\r
+}\r
+\r
+static void\r
+validate_width(int width, int peerwidth, int lwa)\r
+{\r
+       if ((width & 0x8) && (peerwidth & 0x8)) {\r
+               if (lwa != 8)\r
+                       IBWARN("Peer ports operating at active width %d rather than 8 (12x)", lwa);\r
+       } else {\r
+               if ((width & 0x4) && (peerwidth & 0x4)) {\r
+                       if (lwa != 4)\r
+                               IBWARN("Peer ports operating at active width %d rather than 4 (8x)", lwa);\r
+               } else {\r
+                       if ((width & 0x2) && (peerwidth & 0x2)) {\r
+                               if (lwa != 2)\r
+                                       IBWARN("Peer ports operating at active width %d rather than 2 (4x)", lwa);\r
+                       } else {\r
+                               if ((width & 0x1) && (peerwidth & 0x1)) {\r
+                                       if (lwa != 1)\r
+                                               IBWARN("Peer ports operating at active width %d rather than 1 (1x)", lwa);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+static void\r
+validate_speed(int speed, int peerspeed, int lsa)\r
+{\r
+       if ((speed & 0x4) && (peerspeed & 0x4)) {\r
+               if (lsa != 4)\r
+                       IBWARN("Peer ports operating at active speed %d rather than  4 (10.0 Gbps)", lsa);\r
+       } else {\r
+               if ((speed & 0x2) && (peerspeed & 0x2)) {\r
+                       if (lsa != 2)\r
+                               IBWARN("Peer ports operating at active speed %d rather than 2 (5.0 Gbps)", lsa);\r
+               } else {\r
+                       if ((speed & 0x1) && (peerspeed & 0x1)) {\r
+                               if (lsa != 1)\r
+                                       IBWARN("Peer ports operating at active speed %d rather than 1 (2.5 Gbps)", lsa);\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+void\r
+usage(void)\r
+{\r
+       char *basename;\r
+\r
+       if (!(basename = strrchr(argv0, '/')))\r
+               basename = argv0;\r
+       else\r
+               basename++;\r
+\r
+       fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -D(irect) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port "\r
+                       "-t(imeout) timeout_ms] <dest dr_path|lid|guid> <portnum> [<op>]\n",\r
+                       basename);\r
+       fprintf(stderr, "\tsupported ops: enable, disable, reset, speed, query\n");\r
+       fprintf(stderr, "\n\texamples:\n");\r
+       fprintf(stderr, "\t\t%s 3 1 disable\t\t\t# by lid\n", basename);\r
+       fprintf(stderr, "\t\t%s -G 0x2C9000100D051 1 enable\t# by guid\n", basename);\r
+       fprintf(stderr, "\t\t%s -D 0 1\t\t\t# (query) by direct route\n", basename);\r
+       fprintf(stderr, "\t\t%s 3 1 reset\t\t\t# by lid\n", basename);\r
+       fprintf(stderr, "\t\t%s 3 1 speed 1\t\t\t# by lid\n", basename);\r
+       exit(-1);\r
+}\r
+\r
+int\r
+main(int argc, char **argv)\r
+{\r
+       int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS};\r
+       ib_portid_t portid = {0};\r
+       ib_portid_t *sm_id = 0, sm_portid = {0};\r
+       extern int ibdebug;\r
+       int err;\r
+       int timeout = 0, udebug = 0;\r
+       char *ca = 0;\r
+       int ca_port = 0;\r
+       int port_op = 0;        /* default to query */\r
+       int speed = 15;\r
+       int is_switch = 1;\r
+       int state, physstate, lwe, lws, lwa, lse, lss, lsa;\r
+       int peerlocalportnum, peerlwe, peerlws, peerlwa, peerlse, peerlss, peerlsa;\r
+       int width, peerwidth, peerspeed;\r
+       uint8_t data[IB_SMP_DATA_SIZE];\r
+       ib_portid_t peerportid = {0};\r
+       int portnum = 0;\r
+       ib_portid_t selfportid = {0};\r
+       int selfport = 0;\r
+\r
+       static char const str_opts[] = "C:P:t:s:devDGVhu";\r
+       static const struct option long_opts[] = {\r
+               { "C", 1, 0, 'C'},\r
+               { "P", 1, 0, 'P'},\r
+               { "debug", 0, 0, 'd'},\r
+               { "err_show", 0, 0, 'e'},\r
+               { "verbose", 0, 0, 'v'},\r
+               { "Direct", 0, 0, 'D'},\r
+               { "Guid", 0, 0, 'G'},\r
+               { "timeout", 1, 0, 't'},\r
+               { "s", 1, 0, 's'},\r
+               { "Version", 0, 0, 'V'},\r
+               { "help", 0, 0, 'h'},\r
+               { "usage", 0, 0, 'u'},\r
+               { }\r
+       };\r
+\r
+       argv0 = argv[0];\r
+\r
+       while (1) {\r
+               int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);\r
+               if ( ch == -1 )\r
+                       break;\r
+               switch(ch) {\r
+               case 'd':\r
+                       ibdebug++;\r
+                       madrpc_show_errors(1);\r
+                       umad_debug(udebug);\r
+                       udebug++;\r
+                       break;\r
+               case 'e':\r
+                       madrpc_show_errors(1);\r
+                       break;\r
+               case 'D':\r
+                       dest_type = IB_DEST_DRPATH;\r
+                       break;\r
+               case 'G':\r
+                       dest_type = IB_DEST_GUID;\r
+                       break;\r
+               case 'C':\r
+                       ca = optarg;\r
+                       break;\r
+               case 'P':\r
+                       ca_port = strtoul(optarg, 0, 0);\r
+                       break;\r
+               case 's':\r
+                       if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0)\r
+                               IBERROR("can't resolve SM destination port %s", optarg);\r
+                       sm_id = &sm_portid;\r
+                       break;\r
+               case 't':\r
+                       timeout = strtoul(optarg, 0, 0);\r
+                       madrpc_set_timeout(timeout);\r
+                       break;\r
+               case 'v':\r
+                       verbose++;\r
+                       break;\r
+               case 'V':\r
+                       fprintf(stderr, "%s %s\n", argv0, get_build_version() );\r
+                       exit(-1);\r
+               default:\r
+                       usage();\r
+                       break;\r
+               }\r
+       }\r
+       argc -= optind;\r
+       argv += optind;\r
+\r
+       if (argc < 2)\r
+               usage();\r
+\r
+       madrpc_init(ca, ca_port, mgmt_classes, 3);\r
+\r
+       if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0)\r
+               IBERROR("can't resolve destination port %s", argv[0]);\r
+\r
+       /* First, make sure it is a switch port if it is a "set" */\r
+       if (argc >= 3) {\r
+               if (!strcmp(argv[2], "enable"))\r
+                       port_op = 1;\r
+               else if (!strcmp(argv[2], "disable"))\r
+                       port_op = 2;\r
+               else if (!strcmp(argv[2], "reset"))\r
+                       port_op = 3;\r
+               else if (!strcmp(argv[2], "speed")) {\r
+                       if (argc < 4)\r
+                               IBERROR("speed requires an additional parameter");\r
+                       port_op = 4;\r
+                       /* Parse speed value */\r
+                       speed = strtoul(argv[3], 0, 0);\r
+                       if (speed > 15)\r
+                               IBERROR("invalid speed value %d", speed);\r
+               }\r
+       }\r
+\r
+       err = get_node_info(&portid, data);\r
+       if (err < 0)\r
+               IBERROR("smp query nodeinfo failed");\r
+       if (err) {              /* not switch */\r
+               if (port_op == 0)       /* query op */\r
+                       is_switch = 0;\r
+               else if (port_op != 4)  /* other than speed op */\r
+                       IBERROR("smp query nodeinfo: Node type not switch");\r
+       }\r
+\r
+       if (argc-1 > 0)\r
+               portnum = strtol(argv[1], 0, 0);\r
+\r
+       if (port_op)\r
+               printf("Initial PortInfo:\n");\r
+       else\r
+               printf("PortInfo:\n");\r
+       err = get_port_info(&portid, data, portnum, port_op);\r
+       if (err < 0)\r
+               IBERROR("smp query portinfo failed");\r
+\r
+       /* Only if one of the "set" options is chosen */\r
+       if (port_op) {\r
+               if (port_op == 1)               /* Enable port */\r
+                       mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 2);        /* Polling */\r
+               else if ((port_op == 2) || (port_op == 3)) { /* Disable port */\r
+                       mad_set_field(data, 0, IB_PORT_STATE_F, 1);             /* Down */\r
+                       mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 3);        /* Disabled */\r
+               } else if (port_op == 4) {      /* Set speed */\r
+                       mad_set_field(data, 0, IB_PORT_LINK_SPEED_ENABLED_F, speed);\r
+                       mad_set_field(data, 0, IB_PORT_STATE_F, 0);\r
+                       mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 0);\r
+               }\r
+\r
+               err = set_port_info(&portid, data, portnum, port_op);\r
+               if (err < 0)\r
+                       IBERROR("smp set portinfo failed");\r
+\r
+               if (port_op == 3) {     /* Reset port - so also enable */\r
+                       mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 2);        /* Polling */\r
+                       err = set_port_info(&portid, data, portnum, port_op);\r
+                       if (err < 0)\r
+                               IBERROR("smp set portinfo failed");\r
+               }\r
+       } else {        /* query op */\r
+               /* only compare peer port if switch port */\r
+               if (is_switch) {\r
+                       /* First, exclude SP0 */\r
+                       if (portnum) {\r
+                               /* Now, make sure PortState is Active */\r
+                               /* Or is PortPhysicalState LinkUp sufficient ? */\r
+                               mad_decode_field(data, IB_PORT_STATE_F, &state);\r
+                               mad_decode_field(data, IB_PORT_PHYS_STATE_F, &physstate);\r
+                               if (state == 4) {       /* Active */\r
+                                       mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, &lwe );\r
+                                       mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, &lws);\r
+                                       mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, &lwa);\r
+                                       mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, &lss);\r
+                                       mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, &lsa);\r
+                                       mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, &lse);\r
+\r
+                                       /* Setup portid for peer port */\r
+                                       memcpy(&peerportid, &portid, sizeof(peerportid));\r
+                                       peerportid.drpath.cnt = 1;\r
+                                       peerportid.drpath.p[1] = portnum;\r
+\r
+                                       /* Set DrSLID to local lid */\r
+                                       if (ib_resolve_self(&selfportid, &selfport, 0) < 0)\r
+                                               IBERROR("could not resolve self");\r
+                                       peerportid.drpath.drslid = selfportid.lid;\r
+                                       peerportid.drpath.drdlid = 0xffff;\r
+\r
+                                       /* Get peer port NodeInfo to obtain peer port number */\r
+                                       err = get_node_info(&peerportid, data);\r
+                                       if (err < 0)\r
+                                               IBERROR("smp query nodeinfo failed");\r
+\r
+                                       mad_decode_field(data, IB_NODE_LOCAL_PORT_F, &peerlocalportnum);\r
+\r
+                                       printf("Peer PortInfo:\n");\r
+                                       /* Get peer port characteristics */\r
+                                       err = get_port_info(&peerportid, data, peerlocalportnum, port_op);\r
+                                       if (err < 0)\r
+                                               IBERROR("smp query peer portinfofailed");\r
+\r
+                                       mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, &peerlwe );\r
+                                       mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, &peerlws);\r
+                                       mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, &peerlwa);\r
+                                       mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, &peerlss);\r
+                                       mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, &peerlsa);\r
+                                       mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, &peerlse);\r
+\r
+                                       /* Now validate peer port characteristics */\r
+                                       /* Examine Link Width */\r
+                                       width = get_link_width(lwe, lws);\r
+                                       peerwidth = get_link_width(peerlwe, peerlws);\r
+                                       validate_width(width, peerwidth, lwa);\r
+\r
+                                       /* Examine Link Speed */\r
+                                       speed = get_link_speed(lse, lss);\r
+                                       peerspeed = get_link_speed(peerlse, peerlss);\r
+                                       validate_speed(speed, peerspeed, lsa);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       exit(0);\r
+}\r
diff --git a/tools/infiniband_diags/src/ibroute.c b/tools/infiniband_diags/src/ibroute.c
new file mode 100644 (file)
index 0000000..83e2142
--- /dev/null
@@ -0,0 +1,495 @@
+/*\r
+ * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif /* HAVE_CONFIG_H */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <unistd.h>\r
+#include <stdarg.h>\r
+#include <time.h>\r
+#include <string.h>\r
+#include <inttypes.h>\r
+#include <getopt.h>\r
+#include <netinet/in.h>\r
+#include <ctype.h>\r
+\r
+#include <infiniband/common.h>\r
+#include <infiniband/umad.h>\r
+#include <infiniband/mad.h>\r
+#include <infiniband/complib/cl_nodenamemap.h>\r
+\r
+#include "ibdiag_common.h"\r
+\r
+static int dest_type = IB_DEST_LID;\r
+static int brief;\r
+static int verbose;\r
+static int dump_all;\r
+\r
+char *argv0 = "ibroute";\r
+\r
+/*******************************************/\r
+\r
+char *\r
+check_switch(ib_portid_t *portid, int *nports, uint64_t *guid,\r
+            uint8_t *sw, char *nd)\r
+{\r
+       uint8_t ni[IB_SMP_DATA_SIZE] = {0};\r
+       int type;\r
+\r
+       DEBUG("checking node type");\r
+       if (!smp_query(ni, portid, IB_ATTR_NODE_INFO, 0, 0)) {\r
+               xdump(stderr, "nodeinfo\n", ni, sizeof ni);\r
+               return "node info failed: valid addr?";\r
+       }\r
+\r
+       if (!smp_query(nd, portid, IB_ATTR_NODE_DESC, 0, 0))\r
+               return "node desc failed";\r
+\r
+       mad_decode_field(ni, IB_NODE_TYPE_F, &type);\r
+       if (type != IB_NODE_SWITCH)\r
+               return "not a switch";\r
+\r
+       DEBUG("Gathering information about switch");\r
+       mad_decode_field(ni, IB_NODE_NPORTS_F, nports);\r
+       mad_decode_field(ni, IB_NODE_GUID_F, guid);\r
+\r
+       if (!smp_query(sw, portid, IB_ATTR_SWITCH_INFO, 0, 0))\r
+               return "switch info failed: is a switch node?";\r
+\r
+       return 0;\r
+}\r
+\r
+#define IB_MLIDS_IN_BLOCK      (IB_SMP_DATA_SIZE/2)\r
+\r
+int\r
+dump_mlid(char *str, int strlen, int mlid, int nports,\r
+         uint16_t mft[16][IB_MLIDS_IN_BLOCK])\r
+{\r
+       uint16_t mask;\r
+       int i, chunk, bit;\r
+       int nonzero = 0;\r
+\r
+       if (brief) {\r
+               int n = 0, chunks = ALIGN(nports + 1, 16) / 16;\r
+               for (i = 0; i < chunks; i++) {\r
+                       mask = ntohs(mft[i][mlid%IB_MLIDS_IN_BLOCK]);\r
+                       if (mask)\r
+                               nonzero++;\r
+                       n += snprintf(str + n, strlen - n, "%04hx", mask);\r
+                       if (n >= strlen) {\r
+                               n = strlen;\r
+                               break;\r
+                       }\r
+               }\r
+               if (!nonzero && !dump_all) {\r
+                       str[0] = 0;\r
+                       return 0;\r
+               }\r
+               return n;\r
+       }\r
+       for (i = 0; i <= nports; i++) {\r
+               chunk = i / 16;\r
+               bit = i % 16;\r
+\r
+               mask = ntohs(mft[chunk][mlid%IB_MLIDS_IN_BLOCK]);\r
+               if (mask)\r
+                       nonzero++;\r
+               str[i*2] = (mask & (1 << bit)) ? 'x' : ' ';\r
+               str[i*2+1] = ' ';\r
+       }\r
+       if (!nonzero && !dump_all) {\r
+               str[0] = 0;\r
+               return 0;\r
+       }\r
+       str[i*2] = 0;\r
+       return i * 2;\r
+}\r
+\r
+uint16_t mft[16][IB_MLIDS_IN_BLOCK];\r
+\r
+char *\r
+dump_multicast_tables(ib_portid_t *portid, int startlid, int endlid)\r
+{\r
+       char nd[IB_SMP_DATA_SIZE] = {0};\r
+       uint8_t sw[IB_SMP_DATA_SIZE] = {0};\r
+       char str[512];\r
+       char *s;\r
+       uint64_t nodeguid;\r
+       uint32_t mod;\r
+       int block, i, j, e, nports, cap, chunks;\r
+       int n = 0, startblock, lastblock;\r
+\r
+       if ((s = check_switch(portid, &nports, &nodeguid, sw, nd)))\r
+               return s;\r
+\r
+       mad_decode_field(sw, IB_SW_MCAST_FDB_CAP_F, &cap);\r
+\r
+       if (!endlid || endlid > IB_MIN_MCAST_LID + cap - 1)\r
+               endlid = IB_MIN_MCAST_LID + cap - 1;\r
+\r
+       if (!startlid)\r
+               startlid = IB_MIN_MCAST_LID;\r
+\r
+       if (startlid < IB_MIN_MCAST_LID) {\r
+               IBWARN("illegal start mlid %x, set to %x", startlid, IB_MIN_MCAST_LID);\r
+               startlid = IB_MIN_MCAST_LID;\r
+       }\r
+\r
+       if (endlid > IB_MAX_MCAST_LID) {\r
+               IBWARN("illegal end mlid %x, truncate to %x", endlid, IB_MAX_MCAST_LID);\r
+               endlid = IB_MAX_MCAST_LID;\r
+       }\r
+\r
+       printf("Multicast mlids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64 " (%s):\n",\r
+               startlid, endlid, portid2str(portid), nodeguid, clean_nodedesc(nd));\r
+\r
+       if (brief)\r
+               printf(" MLid       Port Mask\n");\r
+       else {\r
+               if (nports > 9) {\r
+                       for (i = 0, s = str; i <= nports; i++) {\r
+                               *s++ = (i%10) ? ' ' : '0' + i/10;\r
+                               *s++ = ' ';\r
+                       }\r
+                       *s = 0;\r
+                       printf("            %s\n", str);\r
+               }\r
+               for (i = 0, s = str; i <= nports; i++)\r
+                       s += sprintf(s, "%d ", i%10);\r
+               printf("     Ports: %s\n", str);\r
+               printf(" MLid\n");\r
+       }\r
+       if (verbose)\r
+               printf("Switch muticast mlids capability is 0x%d\n", cap);\r
+\r
+       chunks = ALIGN(nports + 1, 16) / 16;\r
+\r
+       startblock = startlid / IB_MLIDS_IN_BLOCK;\r
+       lastblock = endlid / IB_MLIDS_IN_BLOCK;\r
+       for (block = startblock; block <= lastblock; block++) {\r
+               for (j = 0; j < chunks; j++) {\r
+                       mod = (block - IB_MIN_MCAST_LID/IB_MLIDS_IN_BLOCK) | (j << 28);\r
+\r
+                       DEBUG("reading block %x chunk %d mod %x", block, j, mod);\r
+                       if (!smp_query(mft + j, portid, IB_ATTR_MULTICASTFORWTBL, mod, 0))\r
+                               return "multicast forwarding table get failed";\r
+               }\r
+\r
+               i = block * IB_MLIDS_IN_BLOCK;\r
+               e = i + IB_MLIDS_IN_BLOCK;\r
+               if (i < startlid)\r
+                       i = startlid;\r
+               if (e > endlid + 1)\r
+                       e = endlid + 1;\r
+\r
+               for (; i < e; i++) {\r
+                       if (dump_mlid(str, sizeof str, i, nports, mft) == 0)\r
+                               continue;\r
+                       printf("0x%04x      %s\n", i, str);\r
+                       n++;\r
+               }\r
+       }\r
+\r
+       printf("%d %smlids dumped \n", n, dump_all ? "" : "valid ");\r
+       return 0;\r
+}\r
+\r
+int\r
+dump_lid(char *str, int strlen, int lid, int valid)\r
+{\r
+       char nd[IB_SMP_DATA_SIZE] = {0};\r
+       uint8_t ni[IB_SMP_DATA_SIZE] = {0};\r
+       uint8_t pi[IB_SMP_DATA_SIZE] = {0};\r
+       ib_portid_t lidport = {0};\r
+       static int last_port_lid, base_port_lid;\r
+       char ntype[50], sguid[30], desc[64];\r
+       static uint64_t portguid;\r
+       int baselid, lmc, type;\r
+\r
+       if (brief) {\r
+               str[0] = 0;\r
+               return 0;\r
+       }\r
+\r
+       if (lid <= last_port_lid) {\r
+               if (!valid)\r
+                       return snprintf(str, strlen, ": (path #%d - illegal port)",\r
+                                       lid - base_port_lid);\r
+               else if (!portguid)\r
+                       return snprintf(str, strlen,\r
+                                       ": (path #%d out of %d)",\r
+                                       lid - base_port_lid + 1,\r
+                                       last_port_lid - base_port_lid + 1);\r
+               else {\r
+                       return snprintf(str, strlen,\r
+                                       ": (path #%d out of %d: portguid %s)",\r
+                                       lid - base_port_lid + 1,\r
+                                       last_port_lid - base_port_lid + 1,\r
+                                       mad_dump_val(IB_NODE_PORT_GUID_F, sguid, sizeof sguid, &portguid));\r
+               }\r
+       }\r
+\r
+       if (!valid)\r
+               return snprintf(str, strlen, ": (illegal port)");\r
+\r
+       portguid = 0;\r
+       lidport.lid = lid;\r
+\r
+       if (!smp_query(nd, &lidport, IB_ATTR_NODE_DESC, 0, 100) ||\r
+           !smp_query(pi, &lidport, IB_ATTR_PORT_INFO, 0, 100) ||\r
+           !smp_query(ni, &lidport, IB_ATTR_NODE_INFO, 0, 100))\r
+               return snprintf(str, strlen, ": (unknown node and type)");\r
+\r
+       mad_decode_field(ni, IB_NODE_PORT_GUID_F, &portguid);\r
+       mad_decode_field(ni, IB_NODE_TYPE_F, &type);\r
+\r
+       mad_decode_field(pi, IB_PORT_LID_F, &baselid);\r
+       mad_decode_field(pi, IB_PORT_LMC_F, &lmc);\r
+\r
+       if (lmc > 0) {\r
+               base_port_lid = baselid;\r
+               last_port_lid = baselid + (1 << lmc) - 1;\r
+       }\r
+\r
+       return snprintf(str, strlen, ": (%s portguid %s: %s)",\r
+               mad_dump_val(IB_NODE_TYPE_F, ntype, sizeof ntype, &type),\r
+               mad_dump_val(IB_NODE_PORT_GUID_F, sguid, sizeof sguid, &portguid),\r
+               mad_dump_val(IB_NODE_DESC_F, desc, sizeof desc, clean_nodedesc(nd)));\r
+}\r
+\r
+char *\r
+dump_unicast_tables(ib_portid_t *portid, int startlid, int endlid)\r
+{\r
+       char lft[IB_SMP_DATA_SIZE];\r
+       char nd[IB_SMP_DATA_SIZE];\r
+       uint8_t sw[IB_SMP_DATA_SIZE];\r
+       char str[200], *s;\r
+       uint64_t nodeguid;\r
+       int block, i, e, nports, top;\r
+       int n = 0, startblock, endblock;\r
+\r
+       if ((s = check_switch(portid, &nports, &nodeguid, sw, nd)))\r
+               return s;\r
+\r
+       mad_decode_field(sw, IB_SW_LINEAR_FDB_TOP_F, &top);\r
+\r
+       if (!endlid || endlid > top)\r
+               endlid = top;\r
+\r
+       if (endlid > IB_MAX_UCAST_LID) {\r
+               IBWARN("ilegal lft top %d, truncate to %d", endlid, IB_MAX_UCAST_LID);\r
+               endlid = IB_MAX_UCAST_LID;\r
+       }\r
+\r
+       printf("Unicast lids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64 " (%s):\n",\r
+               startlid, endlid, portid2str(portid), nodeguid, clean_nodedesc(nd));\r
+\r
+       DEBUG("Switch top is 0x%x\n", top);\r
+\r
+       printf("  Lid  Out   Destination\n");\r
+       printf("       Port     Info \n");\r
+       startblock = startlid / IB_SMP_DATA_SIZE;\r
+       endblock = ALIGN(endlid, IB_SMP_DATA_SIZE) / IB_SMP_DATA_SIZE;\r
+       for (block = startblock; block <= endblock; block++) {\r
+               DEBUG("reading block %d", block);\r
+               if (!smp_query(lft, portid, IB_ATTR_LINEARFORWTBL, block, 0))\r
+                       return "linear forwarding table get failed";\r
+               i = block * IB_SMP_DATA_SIZE;\r
+               e = i + IB_SMP_DATA_SIZE;\r
+               if (i < startlid)\r
+                       i = startlid;\r
+               if (e > endlid + 1)\r
+                       e = endlid + 1;\r
+\r
+               for (;i < e; i++) {\r
+                       unsigned outport = lft[i % IB_SMP_DATA_SIZE];\r
+                       unsigned valid = (outport <= nports);\r
+\r
+                       if (!valid && !dump_all)\r
+                               continue;\r
+                       dump_lid(str, sizeof str, i, valid);\r
+                       printf("0x%04x %03u %s\n", i, outport & 0xff, str);\r
+                       n++;\r
+               }\r
+       }\r
+\r
+       printf("%d %slids dumped \n", n, dump_all ? "" : "valid ");\r
+       return 0;\r
+}\r
+\r
+void\r
+usage(void)\r
+{\r
+       char *basename;\r
+\r
+       if (!(basename = strrchr(argv0, '/')))\r
+               basename = argv0;\r
+       else\r
+               basename++;\r
+\r
+       fprintf(stderr, "Usage: %s [-d(ebug)] -a(ll) -n(o_dests) -v(erbose) -D(irect) -G(uid) -M(ulticast) -s smlid -V(ersion) -C ca_name -P ca_port "\r
+                       "-t(imeout) timeout_ms] [<dest dr_path|lid|guid> [<startlid> [<endlid>]]]\n",\r
+                       basename);\r
+       fprintf(stderr, "\n\tUnicast examples:\n");\r
+       fprintf(stderr, "\t\t%s 4\t# dump all lids with valid out ports of switch with lid 4\n", basename);\r
+       fprintf(stderr, "\t\t%s -a 4\t# same, but dump all lids, even with invalid out ports\n", basename);\r
+       fprintf(stderr, "\t\t%s -n 4\t# simple dump format - no destination resolving\n", basename);\r
+       fprintf(stderr, "\t\t%s 4 10\t# dump lids starting from 10\n", basename);\r
+       fprintf(stderr, "\t\t%s 4 0x10 0x20\t# dump lid range\n", basename);\r
+       fprintf(stderr, "\t\t%s -G 0x08f1040023\t# resolve switch by GUID\n", basename);\r
+       fprintf(stderr, "\t\t%s -D 0,1\t# resolve switch by direct path\n", basename);\r
+\r
+       fprintf(stderr, "\n\tMulticast examples:\n");\r
+       fprintf(stderr, "\t\t%s -M 4\t# dump all non empty mlids of switch with lid 4\n", basename);\r
+       fprintf(stderr, "\t\t%s -M 4 0xc010 0xc020\t# same, but with range\n", basename);\r
+       fprintf(stderr, "\t\t%s -M -n 4\t# simple dump format\n", basename);\r
+       exit(-1);\r
+}\r
+\r
+int\r
+main(int argc, char **argv)\r
+{\r
+       int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS};\r
+       ib_portid_t portid = {0};\r
+       ib_portid_t *sm_id = 0, sm_portid = {0};\r
+       int timeout;\r
+       int multicast = 0, startlid = 0, endlid = 0;\r
+       char *err;\r
+       char *ca = 0;\r
+       int ca_port = 0;\r
+\r
+       static char const str_opts[] = "C:P:t:s:danvDGMVhu";\r
+       static const struct option long_opts[] = {\r
+               { "C", 1, 0, 'C'},\r
+               { "P", 1, 0, 'P'},\r
+               { "debug", 0, 0, 'd'},\r
+               { "all", 0, 0, 'a'},\r
+               { "no_dests", 0, 0, 'n'},\r
+               { "verbose", 0, 0, 'v'},\r
+               { "Direct", 0, 0, 'D'},\r
+               { "Guid", 0, 0, 'G'},\r
+               { "Multicast", 0, 0, 'M'},\r
+               { "timeout", 1, 0, 't'},\r
+               { "s", 1, 0, 's'},\r
+               { "Version", 0, 0, 'V'},\r
+               { "help", 0, 0, 'h'},\r
+               { "usage", 0, 0, 'u'},\r
+               { }\r
+       };\r
+\r
+       argv0 = argv[0];\r
+\r
+       while (1) {\r
+               int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);\r
+               if ( ch == -1 )\r
+                       break;\r
+               switch(ch) {\r
+               case 'C':\r
+                       ca = optarg;\r
+                       break;\r
+               case 'P':\r
+                       ca_port = strtoul(optarg, 0, 0);\r
+                       break;\r
+               case 'a':\r
+                       dump_all++;\r
+                       break;\r
+               case 'd':\r
+                       ibdebug++;\r
+                       break;\r
+               case 'D':\r
+                       dest_type = IB_DEST_DRPATH;\r
+                       break;\r
+               case 'G':\r
+                       dest_type = IB_DEST_GUID;\r
+                       break;\r
+               case 'M':\r
+                       multicast++;\r
+                       break;\r
+               case 'n':\r
+                       brief++;\r
+                       break;\r
+               case 's':\r
+                       if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0)\r
+                               IBERROR("can't resolve SM destination port %s", optarg);\r
+                       sm_id = &sm_portid;\r
+                       break;\r
+               case 't':\r
+                       timeout = strtoul(optarg, 0, 0);\r
+                       madrpc_set_timeout(timeout);\r
+                       break;\r
+               case 'v':\r
+                       madrpc_show_errors(1);\r
+                       verbose++;\r
+                       break;\r
+               case 'V':\r
+                       fprintf(stderr, "%s %s\n", argv0, get_build_version() );\r
+                       exit(-1);\r
+               default:\r
+                       usage();\r
+                       break;\r
+               }\r
+       }\r
+       argc -= optind;\r
+       argv += optind;\r
+\r
+       if (!argc)\r
+               usage();\r
+\r
+       if (argc > 1)\r
+               startlid = strtoul(argv[1], 0, 0);\r
+       if (argc > 2)\r
+               endlid = strtoul(argv[2], 0, 0);\r
+\r
+       madrpc_init(ca, ca_port, mgmt_classes, 3);\r
+\r
+       if (!argc) {\r
+               if (ib_resolve_self(&portid, 0, 0) < 0)\r
+                       IBERROR("can't resolve self addr");\r
+       } else {\r
+               if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0)\r
+                       IBERROR("can't resolve destination port %s", argv[1]);\r
+       }\r
+\r
+       if (multicast)\r
+               err = dump_multicast_tables(&portid, startlid, endlid);\r
+       else\r
+               err = dump_unicast_tables(&portid, startlid, endlid);\r
+\r
+       if (err)\r
+               IBERROR("dump tables: %s", err);\r
+\r
+       exit(0);\r
+}\r
diff --git a/tools/infiniband_diags/src/ibsendtrap.c b/tools/infiniband_diags/src/ibsendtrap.c
new file mode 100644 (file)
index 0000000..47db29a
--- /dev/null
@@ -0,0 +1,176 @@
+/*\r
+ * Copyright (c) 2008 Lawrence Livermore National Security\r
+ *\r
+ * Produced at Lawrence Livermore National Laboratory.\r
+ * Written by Ira Weiny <weiny2@llnl.gov>.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <unistd.h>\r
+#include <string.h>\r
+\r
+#define _GNU_SOURCE\r
+#include <getopt.h>\r
+\r
+#include <infiniband/mad.h>\r
+#include <infiniband/iba/ib_types.h>\r
+\r
+#include "ibdiag_common.h"\r
+\r
+char *argv0 = "";\r
+\r
+static int send_144_node_desc_update(void)\r
+{\r
+       ib_portid_t sm_port;\r
+       ib_portid_t selfportid;\r
+       int selfport;\r
+       ib_rpc_t trap_rpc;\r
+       ib_mad_notice_attr_t notice;\r
+\r
+       if (ib_resolve_self(&selfportid, &selfport, NULL))\r
+               IBERROR("can't resolve self");\r
+\r
+       if (ib_resolve_smlid(&sm_port, 0))\r
+               IBERROR("can't resolve SM destination port");\r
+\r
+       memset(&trap_rpc, 0, sizeof(trap_rpc));\r
+       trap_rpc.mgtclass = IB_SMI_CLASS;\r
+       trap_rpc.method = IB_MAD_METHOD_TRAP;\r
+       trap_rpc.trid = mad_trid();\r
+       trap_rpc.attr.id = NOTICE;\r
+       trap_rpc.datasz = IB_SMP_DATA_SIZE;\r
+       trap_rpc.dataoffs = IB_SMP_DATA_OFFS;\r
+\r
+       memset(&notice, 0, sizeof(notice));\r
+       notice.generic_type = 0x80 | IB_NOTICE_TYPE_INFO;\r
+       notice.g_or_v.generic.prod_type_lsb = cl_hton16(IB_NODE_TYPE_CA);\r
+       notice.g_or_v.generic.trap_num = cl_hton16(144);\r
+       notice.issuer_lid = cl_hton16(selfportid.lid);\r
+       notice.data_details.ntc_144.lid = cl_hton16(selfportid.lid);\r
+       notice.data_details.ntc_144.local_changes =\r
+           TRAP_144_MASK_OTHER_LOCAL_CHANGES;\r
+       notice.data_details.ntc_144.change_flgs =\r
+           TRAP_144_MASK_NODE_DESCRIPTION_CHANGE;\r
+\r
+       return (mad_send(&trap_rpc, &sm_port, NULL, &notice));\r
+}\r
+\r
+typedef struct _trap_def {\r
+       char *trap_name;\r
+       int (*send_func) (void);\r
+} trap_def_t;\r
+\r
+trap_def_t traps[2] = {\r
+       {"node_desc_change", send_144_node_desc_update},\r
+       {NULL, NULL}\r
+};\r
+\r
+static void usage(void)\r
+{\r
+       int i;\r
+\r
+       fprintf(stderr, "Usage: %s [-hV]"\r
+               " [-C <ca_name>] [-P <ca_port>] [<trap_name>]\n", argv0);\r
+       fprintf(stderr, "   -V print version\n");\r
+       fprintf(stderr, "   <trap_name> can be one of the following\n");\r
+       for (i = 0; traps[i].trap_name; i++) {\r
+               fprintf(stderr, "      %s\n", traps[i].trap_name);\r
+       }\r
+       fprintf(stderr, "   default behavior is to send \"%s\"\n",\r
+               traps[0].trap_name);\r
+\r
+       exit(-1);\r
+}\r
+\r
+int send_trap(char *trap_name)\r
+{\r
+       int i;\r
+\r
+       for (i = 0; traps[i].trap_name; i++) {\r
+               if (strcmp(traps[i].trap_name, trap_name) == 0) {\r
+                       return (traps[i].send_func());\r
+               }\r
+       }\r
+       usage();\r
+       exit(1);\r
+}\r
+\r
+int main(int argc, char **argv)\r
+{\r
+       int mgmt_classes[2] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS };\r
+       int ch = 0;\r
+       char *trap_name = NULL;\r
+       char *ca = NULL;\r
+       int ca_port = 0;\r
+\r
+       static char const str_opts[] = "hVP:C:";\r
+       static const struct option long_opts[] = {\r
+               {"Version", 0, 0, 'V'},\r
+               {"P", 1, 0, 'P'},\r
+               {"C", 1, 0, 'C'},\r
+               {"help", 0, 0, 'h'},\r
+               {}\r
+       };\r
+\r
+       argv0 = argv[0];\r
+\r
+       while ((ch = getopt_long(argc, argv, str_opts, long_opts, NULL)) != -1) {\r
+               switch (ch) {\r
+               case 'V':\r
+                       fprintf(stderr, "%s %s\n", argv0, get_build_version());\r
+                       exit(-1);\r
+               case 'C':\r
+                       ca = optarg;\r
+                       break;\r
+               case 'P':\r
+                       ca_port = strtoul(optarg, NULL, 0);\r
+                       break;\r
+               case 'h':\r
+               default:\r
+                       usage();\r
+               }\r
+       }\r
+       argc -= optind;\r
+       argv += optind;\r
+\r
+       if (!argv[0]) {\r
+               trap_name = traps[0].trap_name;\r
+       } else {\r
+               trap_name = argv[0];\r
+       }\r
+\r
+       madrpc_show_errors(1);\r
+       madrpc_init(ca, ca_port, mgmt_classes, 2);\r
+\r
+       return (send_trap(trap_name));\r
+}\r
diff --git a/tools/infiniband_diags/src/ibstat.c b/tools/infiniband_diags/src/ibstat.c
new file mode 100644 (file)
index 0000000..8825277
--- /dev/null
@@ -0,0 +1,297 @@
+/*\r
+ * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+#if !defined(_WIN32) \r
+#define _GNU_SOURCE\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif /* HAVE_CONFIG_H */\r
+\r
+#include <inttypes.h>\r
+#include <string.h>\r
+#include <errno.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <unistd.h>\r
+#include <stdarg.h>\r
+#include <sys/types.h>\r
+#include <sys/stat.h>\r
+#include <fcntl.h>\r
+#include <sys/ioctl.h>\r
+#include <unistd.h>\r
+#include <string.h>\r
+#include <getopt.h>\r
+#include <endian.h>\r
+#include <byteswap.h>\r
+#include <sys/poll.h>\r
+#include <syslog.h>\r
+#include <netinet/in.h>\r
+#else\r
+#include "..\..\..\..\etc\user\getopt.c"\r
+#endif\r
+\r
+#include <infiniband/umad.h>\r
+#include <infiniband/mad.h>\r
+#include <ibdiag_common.h>\r
+\r
+static int debug;\r
+\r
+char *argv0 = "ibstat";\r
+\r
+static char *node_type_str[] = {\r
+       "???",\r
+       "CA",\r
+       "Switch",\r
+       "Router",\r
+       "iWARP RNIC"\r
+};\r
+\r
+static void\r
+ca_dump(umad_ca_t *ca)\r
+{\r
+       if (!ca->node_type)\r
+               return;\r
+       printf("%s '%s'\n", ((unsigned int)ca->node_type <= IB_NODE_MAX ? node_type_str[ca->node_type] : "???"), ca->ca_name);\r
+       printf("\t%s type: %s\n", ((unsigned int)ca->node_type <= IB_NODE_MAX ? node_type_str[ca->node_type] : "???"),ca->ca_type);\r
+       printf("\tNumber of ports: %d\n", ca->numports);\r
+       printf("\tFirmware version: %s\n", ca->fw_ver);\r
+       printf("\tHardware version: %s\n", ca->hw_ver);\r
+       printf("\tNode GUID: 0x%016"PRIx64"\n", ntohll(ca->node_guid));\r
+       printf("\tSystem image GUID: 0x%016"PRIx64"\n", ntohll(ca->system_guid));\r
+}\r
+\r
+static char *port_state_str[] = {\r
+       "???",\r
+       "Down",\r
+       "Initializing",\r
+       "Armed",\r
+       "Active"\r
+};\r
+\r
+static char *port_phy_state_str[] = {\r
+       "No state change",\r
+       "Sleep",\r
+       "Polling",\r
+       "Disabled",\r
+       "PortConfigurationTraining",\r
+       "LinkUp",\r
+       "LinkErrorRecovery",\r
+       "PhyTest"\r
+};\r
+\r
+static int\r
+port_dump(umad_port_t *port, int alone)\r
+{\r
+       char *pre = "";\r
+       char *hdrpre = "";\r
+\r
+       if (!port)\r
+               return -1;\r
+\r
+       if (!alone) {\r
+               pre = "         ";\r
+               hdrpre = "      ";\r
+       }\r
+\r
+       printf("%sPort %d:\n", hdrpre, port->portnum);\r
+       printf("%sState: %s\n", pre, (unsigned int)port->state <= 4 ? port_state_str[port->state] : "???");\r
+       printf("%sPhysical state: %s\n", pre, (unsigned int)port->state <= 7 ? port_phy_state_str[port->phys_state] : "???");\r
+       printf("%sRate: %d\n", pre, port->rate);\r
+       printf("%sBase lid: %d\n", pre, port->base_lid);\r
+       printf("%sLMC: %d\n", pre, port->lmc);\r
+       printf("%sSM lid: %d\n", pre, port->sm_lid);\r
+       printf("%sCapability mask: 0x%08x\n", pre, (unsigned int)ntohll(port->capmask));\r
+       printf("%sPort GUID: 0x%016"PRIx64"\n", pre, (long long unsigned)ntohll(port->port_guid));\r
+       return 0;\r
+}\r
+\r
+static int\r
+ca_stat(char *ca_name, int portnum, int no_ports)\r
+{\r
+       umad_ca_t ca;\r
+       int r;\r
+\r
+       if ((r = umad_get_ca(ca_name, &ca)) < 0)\r
+               return r;\r
+\r
+       if (!ca.node_type)\r
+               return 0;\r
+\r
+       if (!no_ports && portnum >= 0) {\r
+               if (portnum > ca.numports || !ca.ports[portnum]) {\r
+                       IBWARN("%s: '%s' has no port number %d - max (%d)",\r
+                               ((unsigned int)ca.node_type <= IB_NODE_MAX ? node_type_str[ca.node_type] : "???"),\r
+                               ca_name, portnum, ca.numports);\r
+                       return -1;\r
+               }\r
+               printf("%s: '%s'\n", ((unsigned int)ca.node_type <= IB_NODE_MAX ? node_type_str[ca.node_type] : "???"), ca.ca_name);\r
+               port_dump(ca.ports[portnum], 1);\r
+               return 0;\r
+       }\r
+\r
+       /* print ca header */\r
+       ca_dump(&ca);\r
+\r
+       if (no_ports)\r
+               return 0;\r
+\r
+       for (portnum = 0; portnum < ca.numports; portnum++)\r
+               port_dump(ca.ports[portnum], 0);\r
+\r
+       return 0;\r
+}\r
+\r
+static int\r
+ports_list(char names[][UMAD_CA_NAME_LEN], int n)\r
+{\r
+       uint64_t guids[64];\r
+       int found, ports, i;\r
+\r
+       for (i = 0, found = 0; i < n && found < 64; i++) {\r
+               if ((ports = umad_get_ca_portguids(names[i], guids + found, 64 - found)) < 0)\r
+                       return -1;\r
+               found += ports;\r
+       }\r
+\r
+       for (i = 0; i < found; i++)\r
+               if (guids[i])\r
+                       printf("0x%016"PRIx64"\n", (long long unsigned)ntohll(guids[i]));\r
+       return found;\r
+}\r
+\r
+void\r
+usage(void)\r
+{\r
+       fprintf(stderr, "Usage: %s [-d(ebug) -l(ist_of_cas) -s(hort) -p(ort_list) -V(ersion)] <ca_name> [portnum]\n", argv0);\r
+       fprintf(stderr, "\tExamples:\n");\r
+       fprintf(stderr, "\t\t%s -l        # list all IB devices\n", argv0);\r
+       fprintf(stderr, "\t\t%s mthca0 2 # stat port 2 of 'mthca0'\n", argv0);\r
+       exit(-1);\r
+}\r
+\r
+int __cdecl\r
+main(int argc, char *argv[])\r
+{\r
+       char names[20][UMAD_CA_NAME_LEN];\r
+       int dev_port = -1;\r
+       int list_only = 0, short_format = 0, list_ports = 0;\r
+       int n, i;\r
+\r
+       static char str_opts[] = "dlspVhu";\r
+       static struct option long_opts[] = {\r
+               { "debug", 0, 0, 'd'},\r
+               { "list_of_cas", 0, 0, 'l'},\r
+               { "short", 0, 0, 's'},\r
+               { "port_list", 0, 0, 'p'},\r
+               { "Version", 0, 0, 'V'},\r
+               { "help", 0, 0, 'h'},\r
+               { "usage", 0, 0, 'u'},\r
+               { 0 }\r
+       };\r
+\r
+       argv0 = argv[0];\r
+\r
+       while (1) {\r
+               int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);\r
+               if ( ch == -1 )\r
+                       break;\r
+               switch(ch) {\r
+               case 'd':\r
+                       debug++;\r
+                       break;\r
+               case 'l':\r
+                       list_only++;\r
+                       break;\r
+               case 's':\r
+                       short_format++;\r
+                       break;\r
+               case 'p':\r
+                       list_ports++;\r
+                       break;\r
+               case 'V':\r
+                       fprintf(stderr, "%s %s\n", argv0, get_build_version() );\r
+                       exit(-1);\r
+               default:\r
+                       usage();\r
+                       break;\r
+               }\r
+       }\r
+       argc -= optind;\r
+       argv += optind;\r
+\r
+       if (argc > 1)\r
+               dev_port = strtol(argv[1], 0, 0);\r
+\r
+       if (umad_init() < 0)\r
+               IBPANIC("can't init UMAD library");\r
+\r
+       if ((n = umad_get_cas_names((void *)names, UMAD_CA_NAME_LEN)) < 0)\r
+               IBPANIC("can't list IB device names");\r
+\r
+       if (argc) {\r
+               for (i = 0; i < n; i++)\r
+                       if (!strncmp(names[i], argv[0], sizeof names[i]))\r
+                               break;\r
+               if (i >= n)\r
+                       IBPANIC("'%s' IB device can't be found", argv[0]);\r
+\r
+               strncpy(names[i], argv[0], sizeof names[i]);\r
+               n = 1;\r
+       }\r
+\r
+       if (list_ports) {\r
+               if (ports_list(names, n) < 0)\r
+                       IBPANIC("can't list ports");\r
+               return 0;\r
+       }\r
+\r
+       if (!list_only && argc) {\r
+               if (ca_stat(argv[0], dev_port, short_format) < 0)\r
+                       IBPANIC("stat of IB device '%s' failed", argv[0]);\r
+               return 0;\r
+       }\r
+\r
+       for (i = 0; i < n; i++) {\r
+               if (list_only)\r
+                       printf("%s\n", names[i]);\r
+               else\r
+                       if (ca_stat(names[i], -1, short_format) < 0)\r
+                               IBPANIC("stat of IB device '%s' failed", names[i]);\r
+       }\r
+\r
+       return 0;\r
+}\r
diff --git a/tools/infiniband_diags/src/ibstat/SOURCES b/tools/infiniband_diags/src/ibstat/SOURCES
new file mode 100644 (file)
index 0000000..4fc625f
--- /dev/null
@@ -0,0 +1,32 @@
+TARGETNAME = ibstat\r
+TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR)\r
+TARGETTYPE = PROGRAM\r
+\r
+UMTYPE = console\r
+UMENTRY = main\r
+\r
+USE_MSVCRT = 1\r
+USE_STL = 1\r
+USE_NATIVE_EH = 1\r
+USE_IOSTREAM = 1\r
+\r
+SOURCES = ..\ibstat.c ..\ibdiag_common.c\r
+       \r
+INCLUDES = ..;..\..\include;..\..\..\..\ulp\libibmad\include;..\..\..\..\ulp\libibumad\include;..\..\..\..\inc;..\..\..\..\inc\user;\r
+\r
+TARGETLIBS =   \\r
+       $(SDK_LIB_PATH)\kernel32.lib    \\r
+       $(SDK_LIB_PATH)\advapi32.lib    \\r
+       $(SDK_LIB_PATH)\user32.lib      \\r
+       $(SDK_LIB_PATH)\ole32.lib       \\r
+       $(SDK_LIB_PATH)\ws2_32.lib      \\r
+!if $(FREEBUILD)\r
+       $(TARGETPATH)\*\complib.lib     \\r
+       $(TARGETPATH)\*\libibmad.lib    \\r
+       $(TARGETPATH)\*\libibumad.lib   \r
+!else\r
+       $(TARGETPATH)\*\complibd.lib    \\r
+       $(TARGETPATH)\*\libibmadd.lib   \\r
+       $(TARGETPATH)\*\libibumadd.lib  \r
+!endif\r
+\r
diff --git a/tools/infiniband_diags/src/ibsysstat.c b/tools/infiniband_diags/src/ibsysstat.c
new file mode 100644 (file)
index 0000000..63e450c
--- /dev/null
@@ -0,0 +1,354 @@
+/*\r
+ * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif /* HAVE_CONFIG_H */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <unistd.h>\r
+#include <stdarg.h>\r
+#include <time.h>\r
+#include <string.h>\r
+#include <getopt.h>\r
+\r
+#include <infiniband/common.h>\r
+#include <infiniband/umad.h>\r
+#include <infiniband/mad.h>\r
+\r
+#include "ibdiag_common.h"\r
+\r
+#undef DEBUG\r
+#define        DEBUG   if (verbose) IBWARN\r
+\r
+static int dest_type = IB_DEST_LID;\r
+static int verbose;\r
+\r
+#define MAX_CPUS 8\r
+\r
+enum ib_sysstat_attr_t {\r
+       IB_PING_ATTR = 0x10,\r
+       IB_HOSTINFO_ATTR = 0x11,\r
+       IB_CPUINFO_ATTR = 0x12,\r
+};\r
+\r
+typedef struct cpu_info {\r
+       char *model;\r
+       char *mhz;\r
+} cpu_info;\r
+\r
+static cpu_info cpus[MAX_CPUS];\r
+static int host_ncpu;\r
+\r
+char *argv0 = "ibsysstat";\r
+\r
+static void\r
+mk_reply(int attr, void *data, int sz)\r
+{\r
+       char *s = data;\r
+       int n, i;\r
+\r
+       switch (attr) {\r
+       case IB_PING_ATTR:\r
+               break;          /* nothing to do here, just reply */\r
+       case IB_HOSTINFO_ATTR:\r
+               if (gethostname(s, sz) < 0)\r
+                       snprintf(s, sz, "?hostname?");\r
+               s[sz-1] = 0;\r
+               if ((n = strlen(s)) >= sz)\r
+                       break;\r
+               s[n] = '.';\r
+               s += n+1;\r
+               sz -= n+1;\r
+               if (getdomainname(s, sz) < 0)\r
+                       snprintf(s, sz, "?domainname?");\r
+               if (strlen(s) == 0)\r
+                       s[-1] = 0;      /* no domain */\r
+               break;\r
+       case IB_CPUINFO_ATTR:\r
+               for (i = 0; i < host_ncpu && sz > 0; i++) {\r
+                       n = snprintf(s, sz, "cpu %d: model %s MHZ %s\n",\r
+                                    i, cpus[i].model, cpus[i].mhz);\r
+                       if (n >= sz) {\r
+                               IBWARN("cpuinfo truncated");\r
+                               break;\r
+                       }\r
+                       sz -= n;\r
+                       s += n;\r
+               }\r
+               break;\r
+       default:\r
+               DEBUG("unknown attr %d", attr);\r
+       }\r
+}\r
+\r
+static char *\r
+ibsystat_serv(void)\r
+{\r
+       void *umad;\r
+       void *mad;\r
+       int attr, mod;\r
+\r
+       DEBUG("starting to serve...");\r
+\r
+       while ((umad = mad_receive(0, -1))) {\r
+\r
+               mad = umad_get_mad(umad);\r
+\r
+               attr = mad_get_field(mad, 0, IB_MAD_ATTRID_F);\r
+               mod = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F);\r
+\r
+               DEBUG("got packet: attr 0x%x mod 0x%x", attr, mod);\r
+\r
+               mk_reply(attr, (char *)mad + IB_VENDOR_RANGE2_DATA_OFFS, IB_VENDOR_RANGE2_DATA_SIZE);\r
+\r
+               if (mad_respond(umad, 0, 0) < 0)\r
+                       DEBUG("respond failed");\r
+\r
+               mad_free(umad);\r
+       }\r
+\r
+       DEBUG("server out");\r
+       return 0;\r
+}\r
+\r
+static int\r
+match_attr(char *str)\r
+{\r
+       if (!strcmp(str, "ping"))\r
+               return IB_PING_ATTR;\r
+       if (!strcmp(str, "host"))\r
+               return IB_HOSTINFO_ATTR;\r
+       if (!strcmp(str, "cpu"))\r
+               return IB_CPUINFO_ATTR;\r
+       return -1;\r
+}\r
+\r
+static char *\r
+ibsystat(ib_portid_t *portid, int attr)\r
+{\r
+       char data[IB_VENDOR_RANGE2_DATA_SIZE] = {0};\r
+       ib_vendor_call_t call;\r
+\r
+       DEBUG("Sysstat ping..");\r
+\r
+       call.method = IB_MAD_METHOD_GET;\r
+       call.mgmt_class = IB_VENDOR_OPENIB_SYSSTAT_CLASS;\r
+       call.attrid = attr;\r
+       call.mod = 0;\r
+       call.oui = IB_OPENIB_OUI;\r
+       call.timeout = 0;\r
+       memset(&call.rmpp, 0, sizeof call.rmpp);\r
+\r
+       if (!ib_vendor_call(data, portid, &call))\r
+               return "vendor call failed";\r
+\r
+       DEBUG("Got sysstat pong..");\r
+       if (attr != IB_PING_ATTR)\r
+               puts(data);\r
+       else\r
+               printf("sysstat ping succeeded\n");\r
+       return 0;\r
+}\r
+\r
+int\r
+build_cpuinfo(void)\r
+{\r
+       char line[1024] = {0}, *s, *e;\r
+       FILE *f;\r
+       int ncpu = 0;\r
+\r
+       if (!(f = fopen("/proc/cpuinfo", "r"))) {\r
+               IBWARN("couldn't open /proc/cpuinfo");\r
+               return 0;\r
+       }\r
+\r
+       while (fgets(line, sizeof(line) - 1, f)) {\r
+               if (!strncmp(line, "processor\t", 10)) {\r
+                       ncpu++;\r
+                       if (ncpu > MAX_CPUS)\r
+                               return MAX_CPUS;\r
+                       continue;\r
+               }\r
+\r
+               if (!ncpu || !(s = strchr(line, ':')))\r
+                       continue;\r
+\r
+               if ((e = strchr(s, '\n')))\r
+                       *e = 0;\r
+               if (!strncmp(line, "model name\t", 11))\r
+                       cpus[ncpu-1].model = strdup(s+1);\r
+               else if (!strncmp(line, "cpu MHz\t", 8))\r
+                       cpus[ncpu-1].mhz = strdup(s+1);\r
+       }\r
+\r
+       fclose(f);\r
+\r
+       DEBUG("ncpu %d", ncpu);\r
+\r
+       return ncpu;\r
+}\r
+\r
+static void\r
+usage(void)\r
+{\r
+       char *basename;\r
+\r
+       if (!(basename = strrchr(argv0, '/')))\r
+               basename = argv0;\r
+       else\r
+               basename++;\r
+\r
+       fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port "\r
+                       "-t(imeout) timeout_ms -o oui -S(erver)] <dest lid|guid> [<op>]\n",\r
+                       basename);\r
+       exit(-1);\r
+}\r
+\r
+int\r
+main(int argc, char **argv)\r
+{\r
+       int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS};\r
+       int sysstat_class = IB_VENDOR_OPENIB_SYSSTAT_CLASS;\r
+       ib_portid_t portid = {0};\r
+       ib_portid_t *sm_id = 0, sm_portid = {0};\r
+       int timeout = 0, udebug = 0, server = 0;\r
+       int oui = IB_OPENIB_OUI, attr = IB_PING_ATTR;\r
+       extern int ibdebug;\r
+       char *err;\r
+       char *ca = 0;\r
+       int ca_port = 0;\r
+\r
+       static char const str_opts[] = "C:P:t:s:o:devGSVhu";\r
+       static const struct option long_opts[] = {\r
+               { "C", 1, 0, 'C'},\r
+               { "P", 1, 0, 'P'},\r
+               { "debug", 0, 0, 'd'},\r
+               { "err_show", 0, 0, 'e'},\r
+               { "verbose", 0, 0, 'v'},\r
+               { "Guid", 0, 0, 'G'},\r
+               { "timeout", 1, 0, 't'},\r
+               { "s", 1, 0, 's'},\r
+               { "o", 1, 0, 'o'},\r
+               { "Server", 0, 0, 'S'},\r
+               { "Version", 0, 0, 'V'},\r
+               { "help", 0, 0, 'h'},\r
+               { "usage", 0, 0, 'u'},\r
+               { }\r
+       };\r
+\r
+       argv0 = argv[0];\r
+\r
+       while (1) {\r
+               int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);\r
+               if ( ch == -1 )\r
+                       break;\r
+               switch(ch) {\r
+               case 'C':\r
+                       ca = optarg;\r
+                       break;\r
+               case 'P':\r
+                       ca_port = strtoul(optarg, 0, 0);\r
+                       break;\r
+               case 'd':\r
+                       ibdebug++;\r
+                       madrpc_show_errors(1);\r
+                       umad_debug(udebug);\r
+                       udebug++;\r
+                       break;\r
+               case 'e':\r
+                       madrpc_show_errors(1);\r
+                       break;\r
+               case 'G':\r
+                       dest_type = IB_DEST_GUID;\r
+                       break;\r
+               case 'o':\r
+                       oui = strtoul(optarg, 0, 0);\r
+                       break;\r
+               case 's':\r
+                       if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0)\r
+                               IBERROR("can't resolve SM destination port %s", optarg);\r
+                       sm_id = &sm_portid;\r
+                       break;\r
+               case 'S':\r
+                       server++;\r
+                       break;\r
+               case 't':\r
+                       timeout = strtoul(optarg, 0, 0);\r
+                       madrpc_set_timeout(timeout);\r
+                       break;\r
+               case 'v':\r
+                       verbose++;\r
+                       break;\r
+               case 'V':\r
+                       fprintf(stderr, "%s %s\n", argv0, get_build_version() );\r
+                       exit(-1);\r
+               default:\r
+                       usage();\r
+                       break;\r
+               }\r
+       }\r
+       argc -= optind;\r
+       argv += optind;\r
+\r
+       if (!argc && !server)\r
+               usage();\r
+\r
+       if (argc > 1 && (attr = match_attr(argv[1])) < 0)\r
+               usage();\r
+\r
+       madrpc_init(ca, ca_port, mgmt_classes, 3);\r
+\r
+       if (server) {\r
+               if (mad_register_server(sysstat_class, 0, 0, oui) < 0)\r
+                       IBERROR("can't serve class %d", sysstat_class);\r
+\r
+               host_ncpu = build_cpuinfo();\r
+\r
+               if ((err = ibsystat_serv()))\r
+                       IBERROR("ibssystat to %s: %s", portid2str(&portid), err);\r
+               exit(0);\r
+       }\r
+\r
+       if (mad_register_client(sysstat_class, 0) < 0)\r
+               IBERROR("can't register to sysstat class %d", sysstat_class);\r
+\r
+       if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0)\r
+               IBERROR("can't resolve destination port %s", argv[0]);\r
+\r
+       if ((err = ibsystat(&portid, attr)))\r
+               IBERROR("ibsystat to %s: %s", portid2str(&portid), err);\r
+\r
+       exit(0);\r
+}\r
diff --git a/tools/infiniband_diags/src/ibtracert.c b/tools/infiniband_diags/src/ibtracert.c
new file mode 100644 (file)
index 0000000..724ac80
--- /dev/null
@@ -0,0 +1,865 @@
+/*\r
+ * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif /* HAVE_CONFIG_H */\r
+\r
+#define _GNU_SOURCE\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <unistd.h>\r
+#include <stdarg.h>\r
+#include <ctype.h>\r
+#include <getopt.h>\r
+#include <netinet/in.h>\r
+#include <inttypes.h>\r
+#include <errno.h>\r
+\r
+#include <infiniband/common.h>\r
+#include <infiniband/umad.h>\r
+#include <infiniband/mad.h>\r
+#include <infiniband/complib/cl_nodenamemap.h>\r
+\r
+#include "ibdiag_common.h"\r
+\r
+#define MAXHOPS        63\r
+\r
+static char *node_type_str[] = {\r
+       "???",\r
+       "ca",\r
+       "switch",\r
+       "router",\r
+       "iwarp rnic"\r
+};\r
+\r
+static int timeout = 0;                /* ms */\r
+static int verbose;\r
+static int force;\r
+static FILE *f;\r
+\r
+char *argv0 = "ibtracert";\r
+\r
+static char *node_name_map_file = NULL;\r
+static nn_map_t *node_name_map = NULL;\r
+\r
+typedef struct Port Port;\r
+typedef struct Switch Switch;\r
+typedef struct Node Node;\r
+\r
+struct Port {\r
+       Port *next;\r
+       Port *remoteport;\r
+       uint64_t portguid;\r
+       int portnum;\r
+       int lid;\r
+       int lmc;\r
+       int state;\r
+       int physstate;\r
+       char portinfo[64];\r
+};\r
+\r
+struct Switch {\r
+       int linearcap;\r
+       int mccap;\r
+       int linearFDBtop;\r
+       int fdb_base;\r
+       int8_t fdb[64];\r
+       char switchinfo[64];\r
+};\r
+\r
+struct Node {\r
+       Node *htnext;\r
+       Node *dnext;\r
+       Port *ports;\r
+       ib_portid_t path;\r
+       int type;\r
+       int dist;\r
+       int numports;\r
+       int upport;\r
+       Node *upnode;\r
+       uint64_t nodeguid;      /* also portguid */\r
+       char nodedesc[64];\r
+       char nodeinfo[64];\r
+};\r
+\r
+Node *nodesdist[MAXHOPS];\r
+uint64_t target_portguid;\r
+\r
+static int\r
+get_node(Node *node, Port *port, ib_portid_t *portid)\r
+{\r
+       void *pi = port->portinfo, *ni = node->nodeinfo, *nd = node->nodedesc;\r
+       char *s, *e;\r
+\r
+       if (!smp_query(ni, portid, IB_ATTR_NODE_INFO, 0, timeout))\r
+               return -1;\r
+\r
+       if (!smp_query(nd, portid, IB_ATTR_NODE_DESC, 0, timeout))\r
+               return -1;\r
+\r
+       for (s = nd, e = s + 64; s < e; s++) {\r
+               if (!*s)\r
+                       break;\r
+               if (!isprint(*s))\r
+                       *s = ' ';\r
+       }\r
+\r
+       if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, 0, timeout))\r
+               return -1;\r
+\r
+       mad_decode_field(ni, IB_NODE_GUID_F, &node->nodeguid);\r
+       mad_decode_field(ni, IB_NODE_TYPE_F, &node->type);\r
+       mad_decode_field(ni, IB_NODE_NPORTS_F, &node->numports);\r
+\r
+       mad_decode_field(ni, IB_NODE_PORT_GUID_F, &port->portguid);\r
+       mad_decode_field(ni, IB_NODE_LOCAL_PORT_F, &port->portnum);\r
+       mad_decode_field(pi, IB_PORT_LID_F, &port->lid);\r
+       mad_decode_field(pi, IB_PORT_LMC_F, &port->lmc);\r
+       mad_decode_field(pi, IB_PORT_STATE_F, &port->state);\r
+\r
+       DEBUG("portid %s: got node %" PRIx64 " '%s'", portid2str(portid), node->nodeguid, node->nodedesc);\r
+       return 0;\r
+}\r
+\r
+static int\r
+switch_lookup(Switch *sw, ib_portid_t *portid, int lid)\r
+{\r
+       void *si = sw->switchinfo, *fdb = sw->fdb;\r
+\r
+       if (!smp_query(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout))\r
+               return -1;\r
+\r
+       mad_decode_field(si, IB_SW_LINEAR_FDB_CAP_F, &sw->linearcap);\r
+       mad_decode_field(si, IB_SW_LINEAR_FDB_TOP_F, &sw->linearFDBtop);\r
+\r
+       if (lid > sw->linearcap && lid > sw->linearFDBtop)\r
+               return -1;\r
+\r
+       if (!smp_query(fdb, portid, IB_ATTR_LINEARFORWTBL, lid / 64, timeout))\r
+               return -1;\r
+\r
+       DEBUG("portid %s: forward lid %d to port %d",\r
+               portid2str(portid), lid, sw->fdb[lid % 64]);\r
+       return sw->fdb[lid % 64];\r
+}\r
+\r
+static int\r
+sameport(Port *a, Port *b)\r
+{\r
+       return a->portguid == b->portguid || (force && a->lid == b->lid);\r
+}\r
+\r
+static int\r
+extend_dpath(ib_dr_path_t *path, int nextport)\r
+{\r
+       if (path->cnt+2 >= sizeof(path->p))\r
+               return -1;\r
+       ++path->cnt;\r
+       path->p[path->cnt] = nextport;\r
+       return path->cnt;\r
+}\r
+\r
+static void\r
+dump_endnode(int dump, char *prompt, Node *node, Port *port)\r
+{\r
+       char *nodename = NULL;\r
+\r
+       if (!dump)\r
+               return;\r
+       if (dump == 1) {\r
+               fprintf(f, "%s {0x%016" PRIx64 "}[%d]\n",\r
+                       prompt, node->nodeguid,\r
+                       node->type == IB_NODE_SWITCH ? 0 : port->portnum);\r
+               return;\r
+       }\r
+\r
+       nodename = remap_node_name(node_name_map, node->nodeguid, node->nodedesc);\r
+\r
+       fprintf(f, "%s %s {0x%016" PRIx64 "} portnum %d lid %u-%u \"%s\"\n",\r
+               prompt,\r
+               (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"),\r
+               node->nodeguid, node->type == IB_NODE_SWITCH ? 0 : port->portnum,\r
+               port->lid, port->lid + (1 << port->lmc) - 1,\r
+               nodename);\r
+\r
+       free(nodename);\r
+}\r
+\r
+static void\r
+dump_route(int dump, Node *node, int outport, Port *port)\r
+{\r
+       char *nodename = NULL;\r
+\r
+       if (!dump && !verbose)\r
+               return;\r
+\r
+       nodename = remap_node_name(node_name_map, node->nodeguid, node->nodedesc);\r
+\r
+       if (dump == 1)\r
+               fprintf(f, "[%d] -> {0x%016" PRIx64 "}[%d]\n",\r
+                       outport, port->portguid, port->portnum);\r
+       else\r
+               fprintf(f, "[%d] -> %s port {0x%016" PRIx64 "}[%d] lid %u-%u \"%s\"\n",\r
+                       outport,\r
+                       (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"),\r
+                       port->portguid, port->portnum,\r
+                       port->lid, port->lid + (1 << port->lmc) - 1,\r
+                       nodename);\r
+\r
+       free(nodename);\r
+}\r
+\r
+static int\r
+find_route(ib_portid_t *from, ib_portid_t *to, int dump)\r
+{\r
+       Node *node, fromnode, tonode, nextnode;\r
+       Port *port, fromport, toport, nextport;\r
+       Switch sw;\r
+       int maxhops = MAXHOPS;\r
+       int portnum, outport;\r
+\r
+       DEBUG("from %s", portid2str(from));\r
+\r
+       if (get_node(&fromnode, &fromport, from) < 0 ||\r
+           get_node(&tonode, &toport, to) < 0) {\r
+               IBWARN("can't reach to/from ports");\r
+               if (!force)\r
+                       return -1;\r
+               if (to->lid > 0)\r
+                       toport.lid = to->lid;\r
+               IBWARN("Force: look for lid %d", to->lid);\r
+       }\r
+\r
+       node = &fromnode;\r
+       port = &fromport;\r
+       portnum = port->portnum;\r
+\r
+       dump_endnode(dump, "From", node, port);\r
+\r
+       while (maxhops--) {\r
+               if (port->state != 4)\r
+                       goto badport;\r
+\r
+               if (sameport(port, &toport))\r
+                       break;  /* found */\r
+\r
+               outport = portnum;\r
+               if (node->type == IB_NODE_SWITCH) {\r
+                       DEBUG("switch node");\r
+                       if ((outport = switch_lookup(&sw, from, to->lid)) < 0 ||\r
+                           outport > node->numports)\r
+                               goto badtbl;\r
+\r
+                       if (extend_dpath(&from->drpath, outport) < 0)\r
+                               goto badpath;\r
+\r
+                       if (get_node(&nextnode, &nextport, from) < 0) {\r
+                               IBWARN("can't reach port at %s", portid2str(from));\r
+                               return -1;\r
+                       }\r
+                       if (outport == 0) {\r
+                               if (!sameport(&nextport, &toport))\r
+                                       goto badtbl;\r
+                               else\r
+                                       break;  /* found SMA port */\r
+                       }\r
+               } else if ((node->type == IB_NODE_CA) ||\r
+                          (node->type == IB_NODE_ROUTER)) {\r
+                       int ca_src = 0;\r
+\r
+                       DEBUG("ca or router node");\r
+                       if (!sameport(port, &fromport)) {\r
+                               IBWARN("can't continue: reached CA or router port %" PRIx64 ", lid %d",\r
+                                       port->portguid, port->lid);\r
+                               return -1;\r
+                       }\r
+                       /* we are at CA or router "from" - go one hop back to (hopefully) a switch */\r
+                       if (from->drpath.cnt > 0) {\r
+                               DEBUG("ca or router node - return back 1 hop");\r
+                               from->drpath.cnt--;\r
+                       } else {\r
+                               ca_src = 1;\r
+                               if (portnum && extend_dpath(&from->drpath, portnum) < 0)\r
+                                       goto badpath;\r
+                       }\r
+                       if (get_node(&nextnode, &nextport, from) < 0) {\r
+                               IBWARN("can't reach port at %s", portid2str(from));\r
+                               return -1;\r
+                       }\r
+                       /* fix port num to be seen from the CA or router side */\r
+                       if (!ca_src)\r
+                               nextport.portnum = from->drpath.p[from->drpath.cnt+1];\r
+               }\r
+               port = &nextport;\r
+               if (port->state != 4)\r
+                       goto badoutport;\r
+               node = &nextnode;\r
+               portnum = port->portnum;\r
+               dump_route(dump, node, outport, port);\r
+       }\r
+\r
+       if (maxhops <= 0) {\r
+               IBWARN("no route found after %d hops", MAXHOPS);\r
+               return -1;\r
+       }\r
+       dump_endnode(dump, "To", node, port);\r
+       return 0;\r
+\r
+badport:\r
+       IBWARN("Bad port state found: node \"%s\" port %d state %d",\r
+               clean_nodedesc(node->nodedesc), portnum, port->state);\r
+       return -1;\r
+badoutport:\r
+       IBWARN("Bad out port state found: node \"%s\" outport %d state %d",\r
+               clean_nodedesc(node->nodedesc), outport, port->state);\r
+       return -1;\r
+badtbl:\r
+       IBWARN("Bad forwarding table entry found at: node \"%s\" lid entry %d is %d (top %d)",\r
+               clean_nodedesc(node->nodedesc), to->lid, outport, sw.linearFDBtop);\r
+       return -1;\r
+badpath:\r
+       IBWARN("Direct path too long!");\r
+       return -1;\r
+}\r
+\r
+\r
+/**************************\r
+ * MC span part\r
+ */\r
+\r
+#define HASHGUID(guid)         ((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103)))\r
+#define HTSZ 137\r
+\r
+static int\r
+insert_node(Node *new)\r
+{\r
+       static Node *nodestbl[HTSZ];\r
+       int hash = HASHGUID(new->nodeguid) % HTSZ;\r
+       Node *node ;\r
+\r
+       for (node = nodestbl[hash]; node; node = node->htnext)\r
+               if (node->nodeguid == new->nodeguid) {\r
+                       DEBUG("node %" PRIx64 " already exists", new->nodeguid);\r
+                       return -1;\r
+               }\r
+\r
+       new->htnext = nodestbl[hash];\r
+       nodestbl[hash] = new;\r
+\r
+       return 0;\r
+}\r
+\r
+static int\r
+get_port(Port *port, int portnum, ib_portid_t *portid)\r
+{\r
+       char portinfo[64];\r
+       void *pi = portinfo;\r
+\r
+       port->portnum = portnum;\r
+\r
+       if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, portnum, timeout))\r
+               return -1;\r
+\r
+       mad_decode_field(pi, IB_PORT_LID_F, &port->lid);\r
+       mad_decode_field(pi, IB_PORT_LMC_F, &port->lmc);\r
+       mad_decode_field(pi, IB_PORT_STATE_F, &port->state);\r
+       mad_decode_field(pi, IB_PORT_PHYS_STATE_F, &port->physstate);\r
+\r
+       VERBOSE("portid %s portnum %d: lid %d state %d physstate %d",\r
+               portid2str(portid), portnum, port->lid, port->state, port->physstate);\r
+       return 1;\r
+}\r
+\r
+static void\r
+link_port(Port *port, Node *node)\r
+{\r
+       port->next = node->ports;\r
+       node->ports = port;\r
+}\r
+\r
+static int\r
+new_node(Node *node, Port *port, ib_portid_t *path, int dist)\r
+{\r
+       if (port->portguid == target_portguid) {\r
+               node->dist = -1;                /* tag as target */\r
+               link_port(port, node);\r
+               dump_endnode(verbose, "found target", node, port);\r
+               return 1;       /* found; */\r
+       }\r
+\r
+       /* BFS search start with my self */\r
+       if (insert_node(node) < 0)\r
+               return -1;      /* known switch */\r
+\r
+       VERBOSE("insert dist %d node %p port %d lid %d", dist, node, port->portnum, port->lid);\r
+\r
+       link_port(port, node);\r
+\r
+       node->dist = dist;\r
+       node->path = *path;\r
+       node->dnext = nodesdist[dist];\r
+       nodesdist[dist] = node;\r
+\r
+       return 0;\r
+}\r
+\r
+static int\r
+switch_mclookup(Node *node, ib_portid_t *portid, int mlid, char *map)\r
+{\r
+       Switch sw;\r
+       char mdb[64];\r
+       void *si = sw.switchinfo;\r
+       uint16_t *msets = (uint16_t *)mdb;\r
+       int maxsets, block, i, set;\r
+\r
+       memset(map, 0, 256);\r
+\r
+       if (!smp_query(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout))\r
+               return -1;\r
+\r
+       mlid -= 0xc000;\r
+\r
+       mad_decode_field(si, IB_SW_MCAST_FDB_CAP_F, &sw.mccap);\r
+\r
+       if (mlid > sw.mccap)\r
+               return -1;\r
+\r
+       block = mlid / 32;\r
+       maxsets = (node->numports + 15) / 16;           /* round up */\r
+\r
+       for (set = 0; set < maxsets; set++) {\r
+               if (!smp_query(mdb, portid, IB_ATTR_MULTICASTFORWTBL,\r
+                   block | (set << 28), timeout))\r
+                       return -1;\r
+\r
+               for (i = 0; i < 16; i++, map++) {\r
+                       uint16_t mask = ntohs(msets[mlid % 32]);\r
+                       if (mask & (1 << i))\r
+                               *map = 1;\r
+                       else\r
+                               continue;\r
+                       VERBOSE("Switch guid 0x%" PRIx64 ": mlid 0x%x is forwarded to port %d",\r
+                               node->nodeguid, mlid + 0xc000, i + set * 16);\r
+               }\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+/*\r
+ * Return 1 if found, 0 if not, -1 on errors.\r
+ */\r
+static Node *\r
+find_mcpath(ib_portid_t *from, int mlid)\r
+{\r
+       Node *node, *remotenode;\r
+       Port *port, *remoteport;\r
+       char map[256];\r
+       int r, i;\r
+       int dist = 0, leafport = 0;\r
+       ib_portid_t *path;\r
+\r
+       DEBUG("from %s", portid2str(from));\r
+\r
+       if (!(node = calloc(1, sizeof(Node))))\r
+               IBERROR("out of memory");\r
+\r
+       if (!(port = calloc(1, sizeof(Port))))\r
+               IBERROR("out of memory");\r
+\r
+       if (get_node(node, port, from) < 0) {\r
+               IBWARN("can't reach node %s", portid2str(from));\r
+               return 0;\r
+       }\r
+\r
+       node->upnode = 0;               /* root */\r
+       if ((r = new_node(node, port, from, 0)) > 0) {\r
+               if (node->type != IB_NODE_SWITCH) {\r
+                       IBWARN("ibtracert from CA to CA is unsupported");\r
+                       return 0;       /* ibtracert from host to itself is unsupported */\r
+               }\r
+\r
+               if (switch_mclookup(node, from, mlid, map) < 0 ||\r
+                   !map[0])\r
+                       return 0;\r
+               return node;\r
+       }\r
+\r
+       for (dist = 0; dist < MAXHOPS; dist++) {\r
+\r
+               for (node = nodesdist[dist]; node; node = node->dnext) {\r
+\r
+                       path = &node->path;\r
+\r
+                       VERBOSE("dist %d node %p", dist, node);\r
+                       dump_endnode(verbose, "processing", node, node->ports);\r
+\r
+                       memset(map, 0, sizeof(map));\r
+\r
+                       if (node->type != IB_NODE_SWITCH) {\r
+                               if (dist)\r
+                                       continue;\r
+                               leafport = path->drpath.p[path->drpath.cnt];\r
+                               map[port->portnum] = 1;\r
+                               node->upport = 0;       /* starting here */\r
+                               DEBUG("Starting from CA 0x%" PRIx64 " lid %d port %d (leafport %d)",\r
+                                       node->nodeguid, port->lid, port->portnum, leafport);\r
+                       } else {        /* switch */\r
+\r
+                               /* if starting from a leaf port fix up port (up port) */\r
+                               if (dist == 1 && leafport)\r
+                                       node->upport = leafport;\r
+\r
+                               if (switch_mclookup(node, path, mlid, map) < 0) {\r
+                                       IBWARN("skipping bad Switch 0x%" PRIx64 "",\r
+                                               node->nodeguid);\r
+                                       continue;\r
+                               }\r
+                       }\r
+\r
+                       for (i = 1; i <= node->numports; i++) {\r
+                               if (!map[i] || i == node->upport)\r
+                                       continue;\r
+\r
+                               if (dist == 0 && leafport) {\r
+                                       if (from->drpath.cnt > 0)\r
+                                               path->drpath.cnt--;\r
+                               } else {\r
+                                       if (!(port = calloc(1, sizeof(Port))))\r
+                                               IBERROR("out of memory");\r
+\r
+                                       if (get_port(port, i, path) < 0) {\r
+                                               IBWARN("can't reach node %s port %d", portid2str(path), i);\r
+                                               return 0;\r
+                                       }\r
+\r
+                                       if (port->physstate != 5) {     /* LinkUP */\r
+                                               free(port);\r
+                                               continue;\r
+                                       }\r
+\r
+#if 0\r
+                                       link_port(port, node);\r
+#endif\r
+\r
+                                       if (extend_dpath(&path->drpath, i) < 0)\r
+                                               return 0;\r
+                               }\r
+\r
+                               if (!(remotenode = calloc(1, sizeof(Node))))\r
+                                       IBERROR("out of memory");\r
+\r
+                               if (!(remoteport = calloc(1, sizeof(Port))))\r
+                                       IBERROR("out of memory");\r
+\r
+                               if (get_node(remotenode, remoteport, path) < 0) {\r
+                                       IBWARN("NodeInfo on %s port %d failed, skipping port",\r
+                                               portid2str(path), i);\r
+                                       path->drpath.cnt--;     /* restore path */\r
+                                       free(remotenode);\r
+                                       free(remoteport);\r
+                                       continue;\r
+                               }\r
+\r
+                               remotenode->upnode = node;\r
+                               remotenode->upport = remoteport->portnum;\r
+                               remoteport->remoteport = port;\r
+\r
+                               if ((r = new_node(remotenode, remoteport, path, dist+1)) > 0)\r
+                                       return remotenode;\r
+\r
+                               if (r == 0)\r
+                                       dump_endnode(verbose, "new remote",\r
+                                               remotenode, remoteport);\r
+                               else if (remotenode->type == IB_NODE_SWITCH)\r
+                                       dump_endnode(2, "ERR: circle discovered at",\r
+                                               remotenode, remoteport);\r
+\r
+                               path->drpath.cnt--;     /* restore path */\r
+                       }\r
+               }\r
+       }\r
+\r
+       return 0;               /* not found */\r
+}\r
+\r
+static uint64_t\r
+find_target_portguid(ib_portid_t *to)\r
+{\r
+       Node tonode;\r
+       Port toport;\r
+\r
+       if (get_node(&tonode, &toport, to) < 0) {\r
+               IBWARN("can't find to port\n");\r
+               return -1;\r
+       }\r
+\r
+       return toport.portguid;\r
+}\r
+\r
+static void\r
+dump_mcpath(Node *node, int dumplevel)\r
+{\r
+       char *nodename = NULL;\r
+\r
+       if (node->upnode)\r
+               dump_mcpath(node->upnode, dumplevel);\r
+\r
+       nodename = remap_node_name(node_name_map, node->nodeguid, node->nodedesc);\r
+\r
+       if (!node->dist) {\r
+               printf("From %s 0x%" PRIx64 " port %d lid %u-%u \"%s\"\n",\r
+                       (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"),\r
+                       node->nodeguid, node->ports->portnum, node->ports->lid,\r
+                       node->ports->lid + (1 << node->ports->lmc) - 1,\r
+                       nodename);\r
+               goto free_name;\r
+       }\r
+\r
+       if (node->dist) {\r
+               if (dumplevel == 1)\r
+                       printf("[%d] -> %s {0x%016" PRIx64 "}[%d]\n",\r
+                               node->ports->remoteport->portnum,\r
+                               (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"),\r
+                               node->nodeguid, node->upport);\r
+               else\r
+                       printf("[%d] -> %s 0x%" PRIx64 "[%d] lid %u \"%s\"\n",\r
+                               node->ports->remoteport->portnum,\r
+                               (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"),\r
+                               node->nodeguid, node->upport,\r
+                               node->ports->lid, nodename);\r
+       }\r
+\r
+       if (node->dist < 0)\r
+       /* target node */\r
+               printf("To %s 0x%" PRIx64 " port %d lid %u-%u \"%s\"\n",\r
+                       (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"),\r
+                       node->nodeguid, node->ports->portnum, node->ports->lid,\r
+                       node->ports->lid + (1 << node->ports->lmc) - 1,\r
+                       nodename);\r
+\r
+free_name:\r
+       free(nodename);\r
+}\r
+\r
+static int resolve_lid(ib_portid_t  *portid, const void *srcport)\r
+{\r
+       uint8_t portinfo[64];\r
+       uint16_t lid;\r
+\r
+       if (!smp_query_via(portinfo, portid, IB_ATTR_PORT_INFO, 0, 0, srcport))\r
+               return -1;\r
+       mad_decode_field(portinfo, IB_PORT_LID_F, &lid);\r
+\r
+       ib_portid_set(portid, lid, 0, 0);\r
+\r
+       return 0;\r
+}\r
+\r
+static void\r
+usage(void)\r
+{\r
+       char *basename;\r
+\r
+       if (!(basename = strrchr(argv0, '/')))\r
+               basename = argv0;\r
+       else\r
+               basename++;\r
+\r
+       fprintf(stderr, "Usage: %s [-d(ebug) -v(erbose) -D(irect) -G(uids) -n(o_info) -C ca_name -P ca_port "\r
+                       "-s smlid -t(imeout) timeout_ms -m mlid --node-name-map node-name-map ] <src-addr> <dest-addr>\n",\r
+                       basename);\r
+       fprintf(stderr, "\n\tUnicast examples:\n");\r
+       fprintf(stderr, "\t\t%s 4 16\t\t\t# show path between lids 4 and 16\n", basename);\r
+       fprintf(stderr, "\t\t%s -n 4 16\t\t# same, but using simple output format\n", basename);\r
+       fprintf(stderr, "\t\t%s -G 0x8f1040396522d 0x002c9000100d051\t# use guid addresses\n", basename);\r
+\r
+       fprintf(stderr, "\n\tMulticast example:\n");\r
+       fprintf(stderr, "\t\t%s -m 0xc000 4 16\t# show multicast path of mlid 0xc000 between lids 4 and 16\n", basename);\r
+       exit(-1);\r
+}\r
+\r
+int\r
+main(int argc, char **argv)\r
+{\r
+       int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS};\r
+       ib_portid_t my_portid = {0};\r
+       ib_portid_t src_portid = {0};\r
+       ib_portid_t dest_portid = {0};\r
+       ib_portid_t *sm_id = 0, sm_portid = {0};\r
+       int dumplevel = 2, dest_type = IB_DEST_LID, multicast = 0, mlid = 0;\r
+       Node *endnode;\r
+       int udebug = 0;\r
+       char *ca = 0;\r
+       int ca_port = 0;\r
+\r
+       static char const str_opts[] = "C:P:t:s:m:dvfDGnVhu";\r
+       static const struct option long_opts[] = {\r
+               { "C", 1, 0, 'C'},\r
+               { "P", 1, 0, 'P'},\r
+               { "debug", 0, 0, 'd'},\r
+               { "verbose", 0, 0, 'v'},\r
+               { "force", 0, 0, 'f'},\r
+               { "Direct", 0, 0, 'D'},\r
+               { "Guids", 0, 0, 'G'},\r
+               { "no_info", 0, 0, 'n'},\r
+               { "timeout", 1, 0, 't'},\r
+               { "s", 1, 0, 's'},\r
+               { "m", 1, 0, 'm'},\r
+               { "Version", 0, 0, 'V'},\r
+               { "help", 0, 0, 'h'},\r
+               { "usage", 0, 0, 'u'},\r
+               { "node-name-map", 1, 0, 1},\r
+               { }\r
+       };\r
+\r
+       argv0 = argv[0];\r
+\r
+       f = stdout;\r
+\r
+       while (1) {\r
+               int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);\r
+               if ( ch == -1 )\r
+                       break;\r
+               switch(ch) {\r
+               case 1:\r
+                       node_name_map_file = strdup(optarg);\r
+                       break;\r
+               case 'C':\r
+                       ca = optarg;\r
+                       break;\r
+               case 'P':\r
+                       ca_port = strtoul(optarg, 0, 0);\r
+                       break;\r
+               case 'd':\r
+                       ibdebug++;\r
+                       madrpc_show_errors(1);\r
+                       umad_debug(udebug);\r
+                       udebug++;\r
+                       break;\r
+               case 'D':\r
+                       dest_type = IB_DEST_DRPATH;\r
+                       break;\r
+               case 'G':\r
+                       dest_type = IB_DEST_GUID;\r
+                       break;\r
+               case 'm':\r
+                       multicast++;\r
+                       mlid = strtoul(optarg, 0, 0);\r
+                       break;\r
+               case 'f':\r
+                       force++;\r
+                       break;\r
+               case 'n':\r
+                       dumplevel = 1;\r
+                       break;\r
+               case 's':\r
+                       if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0)\r
+                               IBERROR("can't resolve SM destination port %s", optarg);\r
+                       sm_id = &sm_portid;\r
+                       break;\r
+               case 't':\r
+                       timeout = strtoul(optarg, 0, 0);\r
+                       madrpc_set_timeout(timeout);\r
+                       break;\r
+               case 'v':\r
+                       madrpc_show_errors(1);\r
+                       verbose++;\r
+                       break;\r
+               case 'V':\r
+                       fprintf(stderr, "%s %s\n", argv0, get_build_version() );\r
+                       exit(-1);\r
+               default:\r
+                       usage();\r
+                       break;\r
+               }\r
+       }\r
+       argc -= optind;\r
+       argv += optind;\r
+\r
+       if (argc < 2)\r
+               usage();\r
+\r
+       madrpc_init(ca, ca_port, mgmt_classes, 3);\r
+       node_name_map = open_node_name_map(node_name_map_file);\r
+\r
+       if (ib_resolve_portid_str(&src_portid, argv[0], dest_type, sm_id) < 0)\r
+               IBERROR("can't resolve source port %s", argv[0]);\r
+\r
+       if (ib_resolve_portid_str(&dest_portid, argv[1], dest_type, sm_id) < 0)\r
+               IBERROR("can't resolve destination port %s", argv[1]);\r
+\r
+       if (dest_type == IB_DEST_DRPATH) {\r
+               if (resolve_lid(&src_portid, NULL) < 0)\r
+                       IBERROR("cannot resolve lid for port \'%s\'",\r
+                               portid2str(&src_portid));\r
+               if (resolve_lid(&dest_portid, NULL) < 0)\r
+                       IBERROR("cannot resolve lid for port \'%s\'",\r
+                               portid2str(&dest_portid));\r
+       }\r
+\r
+       if (dest_portid.lid == 0 || src_portid.lid == 0) {\r
+               IBWARN("bad src/dest lid");\r
+               usage();\r
+       }\r
+\r
+       if (dest_type != IB_DEST_DRPATH) {\r
+               /* first find a direct path to the src port */\r
+               if (find_route(&my_portid, &src_portid, 0) < 0)\r
+                       IBERROR("can't find a route to the src port");\r
+\r
+               src_portid = my_portid;\r
+       }\r
+\r
+       if (!multicast) {\r
+               if (find_route(&src_portid, &dest_portid, dumplevel) < 0)\r
+                       IBERROR("can't find a route from src to dest");\r
+               exit(0);\r
+       } else {\r
+               if (mlid < 0xc000)\r
+                       IBWARN("invalid MLID; must be 0xc000 or larger");\r
+       }\r
+\r
+       if (!(target_portguid = find_target_portguid(&dest_portid)))\r
+               IBERROR("can't reach target lid %d", dest_portid.lid);\r
+\r
+       if (!(endnode = find_mcpath(&src_portid, mlid)))\r
+               IBERROR("can't find a multicast route from src to dest");\r
+\r
+       /* dump multicast path */\r
+       dump_mcpath(endnode, dumplevel);\r
+\r
+       close_node_name_map(node_name_map);\r
+       exit(0);\r
+}\r
diff --git a/tools/infiniband_diags/src/mcm_rereg_test.c b/tools/infiniband_diags/src/mcm_rereg_test.c
new file mode 100644 (file)
index 0000000..1eb62ec
--- /dev/null
@@ -0,0 +1,489 @@
+/*\r
+ * Copyright (c) 2006 Voltaire, Inc. All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <errno.h>\r
+#include <inttypes.h>\r
+\r
+#include <infiniband/umad.h>\r
+#include <infiniband/mad.h>\r
+\r
+#define info(fmt, arg...) fprintf(stderr, "INFO: " fmt, ##arg )\r
+#define err(fmt, arg...) fprintf(stderr, "ERR: " fmt, ##arg )\r
+#ifdef NOISY_DEBUG\r
+#define dbg(fmt, arg...) fprintf(stderr, "DBG: " fmt, ##arg )\r
+#else\r
+#define dbg(fmt, arg...)\r
+#endif\r
+\r
+#define TMO 100\r
+\r
+/* Multicast Member Record Component Masks */\r
+#define IB_MCR_COMPMASK_MGID        (1ULL<<0)\r
+#define IB_MCR_COMPMASK_PORT_GID    (1ULL<<1)\r
+#define IB_MCR_COMPMASK_QKEY        (1ULL<<2)\r
+#define IB_MCR_COMPMASK_MLID        (1ULL<<3)\r
+#define IB_MCR_COMPMASK_MTU_SEL     (1ULL<<4)\r
+#define IB_MCR_COMPMASK_MTU         (1ULL<<5)\r
+#define IB_MCR_COMPMASK_TCLASS      (1ULL<<6)\r
+#define IB_MCR_COMPMASK_PKEY        (1ULL<<7)\r
+#define IB_MCR_COMPMASK_RATE_SEL    (1ULL<<8)\r
+#define IB_MCR_COMPMASK_RATE        (1ULL<<9)\r
+#define IB_MCR_COMPMASK_LIFE_SEL    (1ULL<<10)\r
+#define IB_MCR_COMPMASK_LIFE        (1ULL<<11)\r
+#define IB_MCR_COMPMASK_SL          (1ULL<<12)\r
+#define IB_MCR_COMPMASK_FLOW        (1ULL<<13)\r
+#define IB_MCR_COMPMASK_HOP         (1ULL<<14)\r
+#define IB_MCR_COMPMASK_SCOPE       (1ULL<<15)\r
+#define IB_MCR_COMPMASK_JOIN_STATE  (1ULL<<16)\r
+#define IB_MCR_COMPMASK_PROXY       (1ULL<<17)\r
+\r
+static ibmad_gid_t mgid_ipoib = {\r
+       0xff, 0x12, 0x40, 0x1b, 0xff, 0xff, 0x00, 0x00,\r
+       0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff\r
+};\r
+\r
+uint64_t build_mcm_rec(uint8_t *data, ibmad_gid_t mgid, ibmad_gid_t port_gid)\r
+{\r
+       memset(data, 0, IB_SA_DATA_SIZE);\r
+       mad_set_array(data, 0, IB_SA_MCM_MGID_F, mgid);\r
+       mad_set_array(data, 0, IB_SA_MCM_PORTGID_F, port_gid);\r
+       mad_set_field(data, 0, IB_SA_MCM_JOIN_STATE_F, 1);\r
+\r
+       return IB_MCR_COMPMASK_MGID|IB_MCR_COMPMASK_PORT_GID|\r
+               IB_MCR_COMPMASK_JOIN_STATE;\r
+}\r
+\r
+static void build_mcm_rec_umad(void *umad, ib_portid_t *dport, int method,\r
+                              uint64_t comp_mask, uint8_t *data)\r
+{\r
+       ib_rpc_t rpc;\r
+\r
+       memset(&rpc, 0, sizeof(rpc));\r
+       rpc.mgtclass = IB_SA_CLASS;\r
+       rpc.method = method;\r
+       rpc.attr.id = IB_SA_ATTR_MCRECORD;\r
+       rpc.attr.mod = 0; // ???\r
+       rpc.mask = comp_mask;\r
+       rpc.datasz = IB_SA_DATA_SIZE;\r
+       rpc.dataoffs = IB_SA_DATA_OFFS;\r
+\r
+       mad_build_pkt(umad, &rpc, dport, NULL, data);\r
+}\r
+\r
+static int rereg_send(int port, int agent, ib_portid_t *dport,\r
+                     uint8_t *umad, int len, int method, ibmad_gid_t port_gid)\r
+{\r
+       uint8_t data[IB_SA_DATA_SIZE];\r
+       uint64_t comp_mask;\r
+\r
+       comp_mask = build_mcm_rec(data, mgid_ipoib, port_gid);\r
+\r
+       build_mcm_rec_umad(umad, dport, method, comp_mask, data);\r
+       if(umad_send(port, agent, umad, len, TMO, 0) < 0) {\r
+               err("umad_send leave failed: %s\n", strerror(errno));\r
+               return -1;\r
+       }\r
+       dbg("umad_send %d: tid = 0x%016" PRIx64 "\n", method,\r
+           mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F));\r
+\r
+       return 0;\r
+}\r
+\r
+static int rereg_port_gid(int port, int agent, ib_portid_t *dport,\r
+                         uint8_t *umad, int len, ibmad_gid_t port_gid)\r
+{\r
+       uint8_t data[IB_SA_DATA_SIZE];\r
+       uint64_t comp_mask;\r
+\r
+       comp_mask = build_mcm_rec(data, mgid_ipoib, port_gid);\r
+\r
+       build_mcm_rec_umad(umad, dport, IB_MAD_METHOD_DELETE,\r
+                          comp_mask, data);\r
+       if(umad_send(port, agent, umad, len, TMO, 0) < 0) {\r
+               err("umad_send leave failed: %s\n", strerror(errno));\r
+               return -1;\r
+       }\r
+       dbg("umad_send leave: tid = 0x%016" PRIx64 "\n",\r
+           mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F));\r
+\r
+       build_mcm_rec_umad(umad, dport, IB_MAD_METHOD_SET,\r
+                          comp_mask, data);\r
+       if(umad_send(port, agent, umad, len, TMO, 0) < 0) {\r
+               err("umad_send join failed: %s\n", strerror(errno));\r
+               return -1;\r
+       }\r
+       dbg("umad_send join: tid = 0x%016" PRIx64 "\n",\r
+           mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F));\r
+\r
+       return 0;\r
+}\r
+\r
+struct guid_trid {\r
+       ibmad_gid_t gid;\r
+       uint64_t guid;\r
+       uint64_t trid;\r
+};\r
+\r
+static int rereg_send_all(int port, int agent, ib_portid_t *dport,\r
+                         struct guid_trid *list, unsigned cnt)\r
+{\r
+       uint8_t *umad;\r
+       int len = umad_size() + 256;\r
+       int i, ret;\r
+\r
+       info("rereg_send_all... cnt = %u\n", cnt);\r
+\r
+       umad = calloc(1, len);\r
+       if (!umad) {\r
+               err("cannot alloc mem for umad: %s\n", strerror(errno));\r
+               return -1;\r
+       }\r
+\r
+       for (i = 0; i < cnt; i++) {\r
+               ret = rereg_port_gid(port, agent, dport, umad, len, list[i].gid);\r
+               if (ret < 0) {\r
+                       err("rereg_send_all: rereg_port_gid 0x%016" PRIx64\r
+                           " failed\n", list[i].guid);\r
+                       continue;\r
+               }\r
+               list[i].trid = mad_get_field64(umad_get_mad(umad), 0,\r
+                                              IB_MAD_TRID_F);\r
+       }\r
+\r
+       info("rereg_send_all: sent %u requests\n", cnt*2);\r
+\r
+       free(umad);\r
+\r
+       return 0;\r
+}\r
+\r
+#if 0\r
+static int rereg_mcm_rec_send(int port, int agent, ib_portid_t *dport, int cnt)\r
+{\r
+       ib_portid_t portid;\r
+       ibmad_gid_t port_gid;\r
+       uint8_t *umad;\r
+       int len, ret = 0;\r
+\r
+       ib_resolve_self(&portid, NULL, &port_gid);\r
+\r
+       len = umad_size() + 256;\r
+       umad = calloc(1, len);\r
+       if (!umad) {\r
+               err("cannot alloc mem for umad: %s\n", strerror(errno));\r
+               return -1;\r
+       }\r
+\r
+       while(cnt--) {\r
+               if (!rereg_port_gid(port, agent, dport, umad, len, port_gid))\r
+                       ret += 2;\r
+       }\r
+\r
+       free(umad);\r
+\r
+       return ret;\r
+}\r
+#endif\r
+\r
+static int rereg_recv(int port, int agent, ib_portid_t *dport,\r
+                     uint8_t *umad, int length, int tmo)\r
+{\r
+       int ret, retry = 0;\r
+       int len = length;\r
+\r
+       while((ret = umad_recv(port, umad, &len, tmo)) < 0 &&\r
+             errno == ETIMEDOUT) {\r
+               if (retry++ > 3)\r
+                       return 0;\r
+       }\r
+       if (ret < 0) {\r
+               err("umad_recv %d failed: %s\n", ret, strerror(errno));\r
+               return -1;\r
+       }\r
+       dbg("umad_recv (retries %d), tid = 0x%016" PRIx64 ": len = %d, status = %d\n",\r
+           retry,\r
+           mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F),\r
+           len, umad_status(umad));\r
+\r
+       return 1;\r
+}\r
+\r
+static int rereg_recv_all(int port, int agent, ib_portid_t *dport,\r
+                         struct guid_trid *list, unsigned cnt)\r
+{\r
+       uint8_t *umad, *mad;\r
+       int len = umad_size() + 256;\r
+       uint64_t trid;\r
+       unsigned n, method, status;\r
+       int i;\r
+\r
+       info("rereg_recv_all...\n");\r
+\r
+       umad = calloc(1, len);\r
+       if (!umad) {\r
+               err("cannot alloc mem for umad: %s\n", strerror(errno));\r
+               return -1;\r
+       }\r
+\r
+       n = 0;\r
+       while (rereg_recv(port, agent, dport, umad, len, TMO) > 0) {\r
+               dbg("rereg_recv_all: done %d\n", n);\r
+               n++;\r
+               mad = umad_get_mad(umad);\r
+\r
+               method = mad_get_field(mad, 0, IB_MAD_METHOD_F);\r
+               status = mad_get_field(mad, 0, IB_MAD_STATUS_F);\r
+\r
+               if (status)\r
+                       dbg("MAD status %x, method %x\n", status, method);\r
+\r
+               if (status &&\r
+                   (method&0x7f) == (IB_MAD_METHOD_GET_RESPONSE&0x7f)) {\r
+                       trid = mad_get_field64(mad, 0, IB_MAD_TRID_F);\r
+                       for (i = 0; i < cnt; i++)\r
+                               if (trid == list[i].trid)\r
+                                       break;\r
+                       if (i == cnt) {\r
+                               err("cannot find trid 0x%016" PRIx64 "\n",\r
+                                   trid);\r
+                               continue;\r
+                       }\r
+                       info("guid 0x%016" PRIx64 ": method = %x status = %x. Resending\n",\r
+                            ntohll(list[i].guid), method, status);\r
+                       rereg_port_gid(port, agent, dport, umad, len,\r
+                                      list[i].gid);\r
+                       list[i].trid = mad_get_field64(umad_get_mad(umad), 0,\r
+                                                      IB_MAD_TRID_F);\r
+               }\r
+       }\r
+\r
+       info("rereg_recv_all: got %u responses\n", n);\r
+\r
+       free(umad);\r
+       return 0;\r
+}\r
+\r
+static int rereg_query_all(int port, int agent, ib_portid_t *dport,\r
+                          struct guid_trid *list, unsigned cnt)\r
+{\r
+       uint8_t *umad, *mad;\r
+       int len = umad_size() + 256;\r
+       unsigned method, status;\r
+       int i, ret;\r
+\r
+       info("rereg_query_all...\n");\r
+\r
+       umad = calloc(1, len);\r
+       if (!umad) {\r
+               err("cannot alloc mem for umad: %s\n", strerror(errno));\r
+               return -1;\r
+       }\r
+\r
+       for ( i = 0; i < cnt; i++ ) {\r
+               ret = rereg_send(port, agent, dport, umad, len,\r
+                                IB_MAD_METHOD_GET, list[i].gid);\r
+               if (ret < 0) {\r
+                       err("query_all: rereg_send failed.\n");\r
+                       continue;\r
+               }\r
+\r
+               ret = rereg_recv(port, agent, dport, umad, len, TMO);\r
+               if (ret < 0) {\r
+                       err("query_all: rereg_recv failed.\n");\r
+                       continue;\r
+               }\r
+\r
+               mad = umad_get_mad(umad);\r
+\r
+               method = mad_get_field(mad, 0, IB_MAD_METHOD_F);\r
+               status = mad_get_field(mad, 0, IB_MAD_STATUS_F);\r
+\r
+               if (status)\r
+                       info("guid 0x%016" PRIx64 ": status %x, method %x\n",\r
+                            ntohll(list[i].guid), status, method);\r
+       }\r
+\r
+       info("rereg_query_all: %u queried.\n", cnt);\r
+\r
+       free(umad);\r
+       return 0;\r
+}\r
+\r
+#if 0\r
+static int rereg_mcm_rec_recv(int port, int agent, int cnt)\r
+{\r
+       uint8_t *umad, *mad;\r
+       int len = umad_size() + 256;\r
+       int i;\r
+\r
+       umad = calloc(1, len);\r
+       if (!umad) {\r
+               err("cannot alloc mem for umad: %s\n", strerror(errno));\r
+               return -1;\r
+       }\r
+\r
+       for ( i = 0; i < cnt; i++ ) {\r
+               int retry;\r
+               retry = 0;\r
+               while (umad_recv(port, umad, &len, TMO) < 0 &&\r
+                      errno == ETIMEDOUT)\r
+                       if (retry++ > 3) {\r
+                               err("umad_recv %d failed: %s\n",\r
+                                   i, strerror(errno));\r
+                               free(umad);\r
+                               return -1;\r
+                       }\r
+               dbg("umad_recv %d (retries %d), tid = 0x%016" PRIx64 ": len = %d, status = %d\n",\r
+                   i, retry,\r
+                   mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F),\r
+                   len, umad_status(umad));\r
+               mad = umad_get_mad(umad);\r
+       }\r
+\r
+       free(umad);\r
+       return 0;\r
+}\r
+#endif\r
+\r
+#define MAX_CLIENTS 50\r
+\r
+static int rereg_and_test_port(char *guid_file, int port, int agent, ib_portid_t *dport, int timeout)\r
+{\r
+       char line[256];\r
+       FILE *f;\r
+       ibmad_gid_t port_gid;\r
+       uint64_t prefix = htonll(0xfe80000000000000llu);\r
+       uint64_t guid = htonll(0x0002c90200223825llu);\r
+       struct guid_trid *list;\r
+       int i = 0;\r
+\r
+       list = calloc(MAX_CLIENTS, sizeof(*list));\r
+       if (!list) {\r
+               err("cannot alloc mem for guid/trid list: %s\n", strerror(errno));\r
+               return -1;\r
+       }\r
+\r
+       f = fopen(guid_file, "r");\r
+       if (!f) {\r
+               err("cannot open %s: %s\n", guid_file, strerror(errno));\r
+               return -1;\r
+       }\r
+\r
+       while (fgets(line, sizeof(line), f)) {\r
+               guid = strtoull(line, NULL, 0);\r
+               guid = htonll(guid);\r
+               memcpy(&port_gid[0], &prefix, 8);\r
+               memcpy(&port_gid[8], &guid, 8);\r
+\r
+               list[i].guid = guid;\r
+               memcpy(list[i].gid, port_gid, sizeof(list[i].gid));\r
+               list[i].trid = 0;\r
+               if (++i >= MAX_CLIENTS)\r
+                       break;\r
+       }\r
+       fclose(f);\r
+\r
+       rereg_send_all(port, agent, dport, list, i);\r
+       rereg_recv_all(port, agent, dport, list, i);\r
+\r
+       rereg_query_all(port, agent, dport, list, i);\r
+\r
+       free(list);\r
+       return 0;\r
+}\r
+\r
+int main(int argc, char **argv)\r
+{\r
+       char *guid_file = "port_guids.list";\r
+       int mgmt_classes[2] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS};\r
+       ib_portid_t dport_id;\r
+       int port, agent;\r
+       uint8_t *umad, *mad;\r
+       int len;\r
+\r
+       if (argc > 1)\r
+               guid_file = argv[1];\r
+\r
+       madrpc_init(NULL, 0, mgmt_classes, 2);\r
+\r
+#if 1\r
+       ib_resolve_smlid(&dport_id, TMO);\r
+#else\r
+       memset(&dport_id, 0, sizeof(dport_id));\r
+       dport_id.lid = 1;\r
+#endif\r
+       dport_id.qp = 1;\r
+       if (!dport_id.qkey)\r
+               dport_id.qkey = IB_DEFAULT_QP1_QKEY;\r
+\r
+\r
+       len = umad_size() + 256;\r
+       umad = calloc(1, len);\r
+       if (!umad) {\r
+               err("cannot alloc mem for umad: %s\n", strerror(errno));\r
+               return -1;\r
+       }\r
+\r
+#if 1\r
+       port = madrpc_portid();\r
+#else\r
+       ret = umad_init();\r
+\r
+       port = umad_open_port(NULL, 0);\r
+       if (port < 0) {\r
+               err("umad_open_port failed: %s\n", strerror(errno));\r
+               return port;\r
+       }\r
+#endif\r
+\r
+       agent = umad_register(port, IB_SA_CLASS, 2, 0, NULL);\r
+\r
+#if 0\r
+       int cnt;\r
+       cnt = rereg_mcm_rec_send(port, agent, &dport_id, cnt);\r
+\r
+       rereg_recv_all(port, agent, &dport_id);\r
+#else\r
+       rereg_and_test_port(guid_file, port, agent, &dport_id, TMO);\r
+#endif\r
+       mad = umad_get_mad(umad);\r
+\r
+       free(umad);\r
+       umad_unregister(port, agent);\r
+       umad_close_port(port);\r
+       umad_done();\r
+\r
+       return 0;\r
+}\r
diff --git a/tools/infiniband_diags/src/perfquery.c b/tools/infiniband_diags/src/perfquery.c
new file mode 100644 (file)
index 0000000..641e03a
--- /dev/null
@@ -0,0 +1,518 @@
+/*\r
+ * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.\r
+ * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+#if defined(_WIN32) \r
+#include <windows.h>\r
+#include <winsock2.h>\r
+#include "..\..\..\..\etc\user\getopt.c"\r
+#else\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif /* HAVE_CONFIG_H */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <unistd.h>\r
+#include <stdarg.h>\r
+#include <getopt.h>\r
+#include <netinet/in.h>\r
+#endif\r
+\r
+#include <infiniband/umad.h>\r
+#include <infiniband/mad.h>\r
+\r
+#include "ibdiag_common.h"\r
+\r
+struct perf_count {\r
+       uint32_t portselect;\r
+       uint32_t counterselect;\r
+       uint32_t symbolerrors;\r
+       uint32_t linkrecovers;\r
+       uint32_t linkdowned;\r
+       uint32_t rcverrors;\r
+       uint32_t rcvremotephyerrors;\r
+       uint32_t rcvswrelayerrors;\r
+       uint32_t xmtdiscards;\r
+       uint32_t xmtconstrainterrors;\r
+       uint32_t rcvconstrainterrors;\r
+       uint32_t linkintegrityerrors;\r
+       uint32_t excbufoverrunerrors;\r
+       uint32_t vl15dropped;\r
+       uint32_t xmtdata;\r
+       uint32_t rcvdata;\r
+       uint32_t xmtpkts;\r
+       uint32_t rcvpkts;\r
+};\r
+\r
+struct perf_count_ext {\r
+       uint32_t portselect;\r
+       uint32_t counterselect;\r
+       uint64_t portxmitdata;\r
+       uint64_t portrcvdata;\r
+       uint64_t portxmitpkts;\r
+       uint64_t portrcvpkts;\r
+       uint64_t portunicastxmitpkts;\r
+       uint64_t portunicastrcvpkts;\r
+       uint64_t portmulticastxmitpkits;\r
+       uint64_t portmulticastrcvpkts;\r
+};\r
+\r
+static uint8_t pc[1024];\r
+\r
+struct perf_count perf_count = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};\r
+struct perf_count_ext perf_count_ext = {0,0,0,0,0,0,0,0,0,0};\r
+\r
+char *argv0 = "perfquery";\r
+\r
+#define ALL_PORTS 0xFF\r
+\r
+static void\r
+usage(void)\r
+{\r
+       char *basename;\r
+\r
+       if (!(basename = strrchr(argv0, '/')))\r
+               basename = argv0;\r
+       else\r
+               basename++;\r
+\r
+       fprintf(stderr, "Usage: %s [-d(ebug) -G(uid) -a(ll_ports) -l(oop_ports) -r(eset_after_read) -C ca_name -P ca_port "\r
+                       "-R(eset_only) -t(imeout) timeout_ms -V(ersion) -h(elp)] [<lid|guid> [[port] [reset_mask]]]\n",\r
+                       basename);\r
+       fprintf(stderr, "\tExamples:\n");\r
+       fprintf(stderr, "\t\t%s\t\t# read local port's performance counters\n", basename);\r
+       fprintf(stderr, "\t\t%s 32 1\t\t# read performance counters from lid 32, port 1\n", basename);\r
+       fprintf(stderr, "\t\t%s -e 32 1\t# read extended performance counters from lid 32, port 1\n", basename);\r
+       fprintf(stderr, "\t\t%s -a 32\t\t# read performance counters from lid 32, all ports\n", basename);\r
+       fprintf(stderr, "\t\t%s -r 32 1\t# read performance counters and reset\n", basename);\r
+       fprintf(stderr, "\t\t%s -e -r 32 1\t# read extended performance counters and reset\n", basename);\r
+       fprintf(stderr, "\t\t%s -R 0x20 1\t# reset performance counters of port 1 only\n", basename);\r
+       fprintf(stderr, "\t\t%s -e -R 0x20 1\t# reset extended performance counters of port 1 only\n", basename);\r
+       fprintf(stderr, "\t\t%s -R -a 32\t# reset performance counters of all ports\n", basename);\r
+       fprintf(stderr, "\t\t%s -R 32 2 0x0fff\t# reset only error counters of port 2\n", basename);\r
+       fprintf(stderr, "\t\t%s -R 32 2 0xf000\t# reset only non-error counters of port 2\n", basename);\r
+       exit(-1);\r
+}\r
+\r
+/* Notes: IB semantics is to cap counters if count has exceeded limits.\r
+ * Therefore we must check for overflows and cap the counters if necessary.\r
+ *\r
+ * mad_decode_field and mad_encode_field assume 32 bit integers passed in\r
+ * for fields < 32 bits in length.\r
+ */\r
+\r
+static void aggregate_4bit(uint32_t *dest, uint32_t val)\r
+{\r
+       if ((((*dest) + val) < (*dest))\r
+           || ((*dest) + val) > 0xf)\r
+               (*dest) = 0xf;\r
+       else\r
+               (*dest) = (*dest) + val;\r
+}\r
+\r
+static void aggregate_8bit(uint32_t *dest, uint32_t val)\r
+{\r
+       if ((((*dest) + val) < (*dest))\r
+           || ((*dest) + val) > 0xff)\r
+               (*dest) = 0xff;\r
+       else\r
+               (*dest) = (*dest) + val;\r
+}\r
+\r
+static void aggregate_16bit(uint32_t *dest, uint32_t val)\r
+{\r
+       if ((((*dest) + val) < (*dest))\r
+           || ((*dest) + val) > 0xffff)\r
+               (*dest) = 0xffff;\r
+       else\r
+               (*dest) = (*dest) + val;\r
+}\r
+\r
+static void aggregate_32bit(uint32_t *dest, uint32_t val)\r
+{\r
+       if (((*dest) + val) < (*dest))\r
+               (*dest) = 0xffffffff;\r
+       else\r
+               (*dest) = (*dest) + val;\r
+}\r
+\r
+static void aggregate_64bit(uint64_t *dest, uint64_t val)\r
+{\r
+       if (((*dest) + val) < (*dest))\r
+               (*dest) = 0xffffffffffffffffULL;\r
+       else\r
+               (*dest) = (*dest) + val;\r
+}\r
+\r
+static void aggregate_perfcounters(void)\r
+{\r
+       uint32_t val;\r
+\r
+       mad_decode_field(pc, IB_PC_PORT_SELECT_F, &val);\r
+       perf_count.portselect = val;\r
+        mad_decode_field(pc, IB_PC_COUNTER_SELECT_F, &val);\r
+       perf_count.counterselect = val;\r
+        mad_decode_field(pc, IB_PC_ERR_SYM_F, &val);\r
+       aggregate_16bit(&perf_count.symbolerrors, val);\r
+        mad_decode_field(pc, IB_PC_LINK_RECOVERS_F, &val);\r
+       aggregate_8bit(&perf_count.linkrecovers, val);\r
+        mad_decode_field(pc, IB_PC_LINK_DOWNED_F, &val);\r
+       aggregate_8bit(&perf_count.linkdowned, val);\r
+        mad_decode_field(pc, IB_PC_ERR_RCV_F, &val);\r
+       aggregate_16bit(&perf_count.rcverrors, val);\r
+        mad_decode_field(pc, IB_PC_ERR_PHYSRCV_F, &val);\r
+       aggregate_16bit(&perf_count.rcvremotephyerrors, val);\r
+        mad_decode_field(pc, IB_PC_ERR_SWITCH_REL_F, &val);\r
+       aggregate_16bit(&perf_count.rcvswrelayerrors, val);\r
+        mad_decode_field(pc, IB_PC_XMT_DISCARDS_F, &val);\r
+       aggregate_16bit(&perf_count.xmtdiscards, val);\r
+        mad_decode_field(pc, IB_PC_ERR_XMTCONSTR_F, &val);\r
+       aggregate_8bit(&perf_count.xmtconstrainterrors, val);\r
+        mad_decode_field(pc, IB_PC_ERR_RCVCONSTR_F, &val);\r
+       aggregate_8bit(&perf_count.rcvconstrainterrors, val);\r
+        mad_decode_field(pc, IB_PC_ERR_LOCALINTEG_F, &val);\r
+       aggregate_4bit(&perf_count.linkintegrityerrors, val);\r
+        mad_decode_field(pc, IB_PC_ERR_EXCESS_OVR_F, &val);\r
+       aggregate_4bit(&perf_count.excbufoverrunerrors, val);\r
+        mad_decode_field(pc, IB_PC_VL15_DROPPED_F, &val);\r
+       aggregate_16bit(&perf_count.vl15dropped, val);\r
+        mad_decode_field(pc, IB_PC_XMT_BYTES_F, &val);\r
+       aggregate_32bit(&perf_count.xmtdata, val);\r
+        mad_decode_field(pc, IB_PC_RCV_BYTES_F, &val);\r
+       aggregate_32bit(&perf_count.rcvdata, val);\r
+        mad_decode_field(pc, IB_PC_XMT_PKTS_F, &val);\r
+       aggregate_32bit(&perf_count.xmtpkts, val);\r
+        mad_decode_field(pc, IB_PC_RCV_PKTS_F, &val);\r
+       aggregate_32bit(&perf_count.rcvpkts, val);\r
+}\r
+\r
+static void output_aggregate_perfcounters(ib_portid_t *portid)\r
+{\r
+       char buf[1024];\r
+       uint32_t val = ALL_PORTS;\r
+\r
+       /* set port_select to 255 to emulate AllPortSelect */\r
+       mad_encode_field(pc, IB_PC_PORT_SELECT_F, &val);\r
+       mad_encode_field(pc, IB_PC_COUNTER_SELECT_F, &perf_count.counterselect);\r
+       mad_encode_field(pc, IB_PC_ERR_SYM_F, &perf_count.symbolerrors);\r
+       mad_encode_field(pc, IB_PC_LINK_RECOVERS_F, &perf_count.linkrecovers);\r
+       mad_encode_field(pc, IB_PC_LINK_DOWNED_F, &perf_count.linkdowned);\r
+       mad_encode_field(pc, IB_PC_ERR_RCV_F, &perf_count.rcverrors);\r
+       mad_encode_field(pc, IB_PC_ERR_PHYSRCV_F, &perf_count.rcvremotephyerrors);\r
+       mad_encode_field(pc, IB_PC_ERR_SWITCH_REL_F, &perf_count.rcvswrelayerrors);\r
+       mad_encode_field(pc, IB_PC_XMT_DISCARDS_F, &perf_count.xmtdiscards);\r
+       mad_encode_field(pc, IB_PC_ERR_XMTCONSTR_F, &perf_count.xmtconstrainterrors);\r
+       mad_encode_field(pc, IB_PC_ERR_RCVCONSTR_F, &perf_count.rcvconstrainterrors);\r
+       mad_encode_field(pc, IB_PC_ERR_LOCALINTEG_F, &perf_count.linkintegrityerrors);\r
+       mad_encode_field(pc, IB_PC_ERR_EXCESS_OVR_F, &perf_count.excbufoverrunerrors);\r
+       mad_encode_field(pc, IB_PC_VL15_DROPPED_F, &perf_count.vl15dropped);\r
+       mad_encode_field(pc, IB_PC_XMT_BYTES_F, &perf_count.xmtdata);\r
+       mad_encode_field(pc, IB_PC_RCV_BYTES_F, &perf_count.rcvdata);\r
+       mad_encode_field(pc, IB_PC_XMT_PKTS_F, &perf_count.xmtpkts);\r
+       mad_encode_field(pc, IB_PC_RCV_PKTS_F, &perf_count.rcvpkts);\r
+\r
+       mad_dump_perfcounters(buf, sizeof buf, pc, sizeof pc);\r
+\r
+       printf("# Port counters: %s port %d\n%s", portid2str(portid), ALL_PORTS, buf);\r
+}\r
+\r
+static void aggregate_perfcounters_ext(void)\r
+{\r
+       uint32_t val;\r
+       uint64_t val64;\r
+\r
+       mad_decode_field(pc, IB_PC_EXT_PORT_SELECT_F, &val);\r
+       perf_count_ext.portselect = val;\r
+       mad_decode_field(pc, IB_PC_EXT_COUNTER_SELECT_F, &val);\r
+       perf_count_ext.counterselect = val;\r
+       mad_decode_field(pc, IB_PC_EXT_XMT_BYTES_F, &val64);\r
+       aggregate_64bit(&perf_count_ext.portxmitdata, val64);\r
+       mad_decode_field(pc, IB_PC_EXT_RCV_BYTES_F, &val64);\r
+       aggregate_64bit(&perf_count_ext.portrcvdata, val64);\r
+       mad_decode_field(pc, IB_PC_EXT_XMT_PKTS_F, &val64);\r
+       aggregate_64bit(&perf_count_ext.portxmitpkts, val64);\r
+       mad_decode_field(pc, IB_PC_EXT_RCV_PKTS_F, &val64);\r
+       aggregate_64bit(&perf_count_ext.portrcvpkts, val64);\r
+       mad_decode_field(pc, IB_PC_EXT_XMT_UPKTS_F, &val64);\r
+       aggregate_64bit(&perf_count_ext.portunicastxmitpkts, val64);\r
+       mad_decode_field(pc, IB_PC_EXT_RCV_UPKTS_F, &val64);\r
+       aggregate_64bit(&perf_count_ext.portunicastrcvpkts, val64);\r
+       mad_decode_field(pc, IB_PC_EXT_XMT_MPKTS_F, &val64);\r
+       aggregate_64bit(&perf_count_ext.portmulticastxmitpkits, val64);\r
+       mad_decode_field(pc, IB_PC_EXT_RCV_MPKTS_F, &val64);\r
+       aggregate_64bit(&perf_count_ext.portmulticastrcvpkts, val64);\r
+}\r
+\r
+static void output_aggregate_perfcounters_ext(ib_portid_t *portid)\r
+{\r
+       char buf[1024];\r
+       uint32_t val = ALL_PORTS;\r
+\r
+        /* set port_select to 255 to emulate AllPortSelect */\r
+        mad_encode_field(pc, IB_PC_EXT_PORT_SELECT_F, &val);\r
+       mad_encode_field(pc, IB_PC_EXT_COUNTER_SELECT_F, &perf_count_ext.counterselect);\r
+       mad_encode_field(pc, IB_PC_EXT_XMT_BYTES_F, &perf_count_ext.portxmitdata);\r
+       mad_encode_field(pc, IB_PC_EXT_RCV_BYTES_F, &perf_count_ext.portrcvdata);\r
+       mad_encode_field(pc, IB_PC_EXT_XMT_PKTS_F, &perf_count_ext.portxmitpkts);\r
+       mad_encode_field(pc, IB_PC_EXT_RCV_PKTS_F, &perf_count_ext.portrcvpkts);\r
+       mad_encode_field(pc, IB_PC_EXT_XMT_UPKTS_F, &perf_count_ext.portunicastxmitpkts);\r
+       mad_encode_field(pc, IB_PC_EXT_RCV_UPKTS_F, &perf_count_ext.portunicastrcvpkts);\r
+       mad_encode_field(pc, IB_PC_EXT_XMT_MPKTS_F, &perf_count_ext.portmulticastxmitpkits);\r
+       mad_encode_field(pc, IB_PC_EXT_RCV_MPKTS_F, &perf_count_ext.portmulticastrcvpkts);\r
+\r
+       mad_dump_perfcounters_ext(buf, sizeof buf, pc, sizeof pc);\r
+\r
+       printf("# Port counters: %s port %d\n%s", portid2str(portid), ALL_PORTS, buf);\r
+}\r
+\r
+static void dump_perfcounters(int extended, int timeout, uint16_t cap_mask, ib_portid_t *portid,\r
+                             int port, int aggregate)\r
+{\r
+       char buf[1024];\r
+\r
+       if (extended != 1) {\r
+               if (!port_performance_query(pc, portid, port, timeout))\r
+                       IBERROR("perfquery");\r
+               if (aggregate)\r
+                       aggregate_perfcounters();\r
+               else\r
+                       mad_dump_perfcounters(buf, sizeof buf, pc, sizeof pc);\r
+       } else {\r
+               if (!(cap_mask & 0x200)) /* 1.2 errata: bit 9 is extended counter support */\r
+                       IBWARN("PerfMgt ClassPortInfo 0x%x extended counters not indicated\n", cap_mask);\r
+\r
+               if (!port_performance_ext_query(pc, portid, port, timeout))\r
+                       IBERROR("perfextquery");\r
+               if (aggregate)\r
+                       aggregate_perfcounters_ext();\r
+               else\r
+                       mad_dump_perfcounters_ext(buf, sizeof buf, pc, sizeof pc);\r
+       }\r
+\r
+       if (!aggregate)\r
+               printf("# Port counters: %s port %d\n%s", portid2str(portid), port, buf);\r
+}\r
+\r
+static void reset_counters(int extended, int timeout, int mask, ib_portid_t *portid, int port)\r
+{\r
+       if (extended != 1) {\r
+               if (!port_performance_reset(pc, portid, port, mask, timeout))\r
+                       IBERROR("perf reset");\r
+       } else {\r
+               if (!port_performance_ext_reset(pc, portid, port, mask, timeout))\r
+                       IBERROR("perf ext reset");\r
+       }\r
+}\r
+\r
+int __cdecl\r
+main(int argc, char **argv)\r
+{\r
+       int mgmt_classes[4] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS, IB_PERFORMANCE_CLASS};\r
+       ib_portid_t *sm_id = 0, sm_portid = {0};\r
+       ib_portid_t portid = {0};\r
+       extern int ibdebug;\r
+       int dest_type = IB_DEST_LID;\r
+       int timeout = 0;        /* use default */\r
+       int mask = 0xffff, all_ports = 0;\r
+       int reset = 0, reset_only = 0;\r
+       int port = 0;\r
+       int udebug = 0;\r
+       char *ca = 0;\r
+       int ca_port = 0;\r
+       int extended = 0;\r
+       uint16_t cap_mask;\r
+       int all_ports_loop = 0;\r
+       int loop_ports = 0;\r
+       int node_type, num_ports = 0;\r
+       uint8_t data[IB_SMP_DATA_SIZE];\r
+       int start_port = 1;\r
+       int enhancedport0;\r
+       int i;\r
+\r
+       static char str_opts[] = "C:P:s:t:dGealrRVhu";\r
+       static struct option long_opts[] = {\r
+               { "C", 1, 0, 'C'},\r
+               { "P", 1, 0, 'P'},\r
+               { "debug", 0, 0, 'd'},\r
+               { "Guid", 0, 0, 'G'},\r
+               { "extended", 0, 0, 'e'},\r
+               { "all_ports", 0, 0, 'a'},\r
+               { "loop_ports", 0, 0, 'l'},\r
+               { "reset_after_read", 0, 0, 'r'},\r
+               { "Reset_only", 0, 0, 'R'},\r
+               { "sm_portid", 1, 0, 's'},\r
+               { "timeout", 1, 0, 't'},\r
+               { "Version", 0, 0, 'V'},\r
+               { "help", 0, 0, 'h'},\r
+               { "usage", 0, 0, 'u'},\r
+               { 0 }\r
+       };\r
+\r
+       argv0 = argv[0];\r
+\r
+       while (1) {\r
+               int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);\r
+               if ( ch == -1 )\r
+                       break;\r
+               switch(ch) {\r
+               case 'C':\r
+                       ca = optarg;\r
+                       break;\r
+               case 'P':\r
+                       ca_port = strtoul(optarg, 0, 0);\r
+                       break;\r
+               case 'e':\r
+                       extended = 1;\r
+                       break;\r
+               case 'a':\r
+                       all_ports++;\r
+                       port = ALL_PORTS;\r
+                       break;\r
+               case 'l':\r
+                       loop_ports++;\r
+                       break;\r
+               case 'd':\r
+                       ibdebug++;\r
+                       madrpc_show_errors(1);\r
+                       umad_debug(udebug);\r
+                       udebug++;\r
+                       break;\r
+               case 'G':\r
+                       dest_type = IB_DEST_GUID;\r
+                       break;\r
+               case 's':\r
+                       if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0)\r
+                               IBERROR("can't resolve SM destination port %s", optarg);\r
+                       sm_id = &sm_portid;\r
+                       break;\r
+               case 'r':\r
+                       reset++;\r
+                       break;\r
+               case 'R':\r
+                       reset_only++;\r
+                       break;\r
+               case 't':\r
+                       timeout = strtoul(optarg, 0, 0);\r
+                       madrpc_set_timeout(timeout);\r
+                       break;\r
+               case 'V':\r
+                       fprintf(stderr, "%s %s\n", argv0, get_build_version() );\r
+                       exit(-1);\r
+               default:\r
+                       usage();\r
+                       break;\r
+               }\r
+       }\r
+       argc -= optind;\r
+       argv += optind;\r
+\r
+       if (argc > 1)\r
+               port = strtoul(argv[1], 0, 0);\r
+       if (argc > 2)\r
+               mask = strtoul(argv[2], 0, 0);\r
+\r
+       madrpc_init(ca, ca_port, mgmt_classes, 4);\r
+\r
+       if (argc) {\r
+               if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0)\r
+                       IBERROR("can't resolve destination port %s", argv[0]);\r
+       } else {\r
+               if (ib_resolve_self(&portid, &port, 0) < 0)\r
+                       IBERROR("can't resolve self port %s", argv[0]);\r
+       }\r
+\r
+       /* PerfMgt ClassPortInfo is a required attribute */\r
+       if (!perf_classportinfo_query(pc, &portid, port, timeout))\r
+               IBERROR("classportinfo query");\r
+       /* ClassPortInfo should be supported as part of libibmad */\r
+       memcpy(&cap_mask, pc+2, sizeof(cap_mask));      /* CapabilityMask */\r
+       cap_mask = ntohs(cap_mask);\r
+       if (!(cap_mask & 0x100)) { /* bit 8 is AllPortSelect */\r
+    &nbs