***SPAM*** Re: [ofa-general] [PATCH V2 1/3] Create a new library libibnetdisc

Al Chu chu11 at llnl.gov
Tue Dec 23 10:29:02 PST 2008


Hey Ira,

Tiny comment below:

On Thu, 2008-12-11 at 16:20 -0800, Ira Weiny wrote:
> >From d615162e547f3a2b2d1acd8c79c24ee691c96c95 Mon Sep 17 00:00:00 2001
> From: Ira Weiny <weiny2 at llnl.gov>
> Date: Wed, 26 Nov 2008 12:54:47 -0800
> Subject: [PATCH] Create a new library libibnetdisc
> 
> This encompasses the functionality of ibnetdiscover in a C library.  It returns
> a single "ibnd_fabric_t" object which represents the data found during the
> scan.  The NodeInfo, PortInfo, and SwitchInfo are preserved from the queries
> made on the fabric to be used by the calling function as they see fit.
> 
> This greatly benefits some diags like iblinkinfo.pl.  This diag in particular
> was re-written using this library in C and has shown an 85% speed up on a ~1000
> node cluster.
> 
> Previous iblinkinfo.pl
>    real    3m35.876s
>    user    0m13.210s
>    sys     1m1.046s
> 
> New iblinkinfotest
>    real    0m32.869s
>    user    0m0.067s
>    sys     0m0.140s
> 
> Signed-off-by: Ira Weiny <weiny2 at llnl.gov>
> ---
>  infiniband-diags/Makefile.am                       |    1 +
>  infiniband-diags/configure.in                      |   31 +-
>  infiniband-diags/libibnetdisc/Makefile.am          |   66 ++
>  .../libibnetdisc/include/infiniband/ibnetdisc.h    |  276 ++++++
>  infiniband-diags/libibnetdisc/libibnetdisc.ver     |    9 +
>  infiniband-diags/libibnetdisc/man/ibnd_debug.3     |    2 +
>  .../libibnetdisc/man/ibnd_destroy_fabric.3         |    2 +
>  .../libibnetdisc/man/ibnd_discover_fabric.3        |   49 ++
>  .../libibnetdisc/man/ibnd_find_node_dr.3           |    2 +
>  .../libibnetdisc/man/ibnd_find_node_guid.3         |   25 +
>  .../libibnetdisc/man/ibnd_iter_nodes.3             |   24 +
>  .../libibnetdisc/man/ibnd_iter_nodes_type.3        |    2 +
>  .../libibnetdisc/man/ibnd_linkspeed_str.3          |    2 +
>  .../libibnetdisc/man/ibnd_linkstate_str.3          |    2 +
>  .../libibnetdisc/man/ibnd_linkwidth_str.3          |   26 +
>  .../libibnetdisc/man/ibnd_node_type_str.3          |    2 +
>  .../libibnetdisc/man/ibnd_node_type_str_short.3    |    2 +
>  .../libibnetdisc/man/ibnd_physstate_str.3          |    2 +
>  .../libibnetdisc/man/ibnd_show_progress.3          |    2 +
>  .../libibnetdisc/man/ibnd_update_node.3            |   21 +
>  infiniband-diags/libibnetdisc/src/chassis.c        |  818 ++++++++++++++++++
>  infiniband-diags/libibnetdisc/src/chassis.h        |   85 ++
>  infiniband-diags/libibnetdisc/src/ibnetdisc.c      |  872 ++++++++++++++++++++
>  infiniband-diags/libibnetdisc/src/internal.h       |   82 ++
>  infiniband-diags/libibnetdisc/src/libibnetdisc.map |   27 +
>  .../libibnetdisc/test/iblinkinfotest.c             |  395 +++++++++
>  infiniband-diags/libibnetdisc/test/ibnetdisctest.c |  675 +++++++++++++++
>  infiniband-diags/libibnetdisc/test/testleaks.c     |  268 ++++++
>  28 files changed, 3769 insertions(+), 1 deletions(-)
>  create mode 100644 infiniband-diags/libibnetdisc/Makefile.am
>  create mode 100644 infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
>  create mode 100644 infiniband-diags/libibnetdisc/libibnetdisc.ver
>  create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_debug.3
>  create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_destroy_fabric.3
>  create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_discover_fabric.3
>  create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_find_node_dr.3
>  create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_find_node_guid.3
>  create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_iter_nodes.3
>  create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_iter_nodes_type.3
>  create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_linkspeed_str.3
>  create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_linkstate_str.3
>  create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_linkwidth_str.3
>  create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_node_type_str.3
>  create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_node_type_str_short.3
>  create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_physstate_str.3
>  create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_show_progress.3
>  create mode 100644 infiniband-diags/libibnetdisc/man/ibnd_update_node.3
>  create mode 100644 infiniband-diags/libibnetdisc/src/chassis.c
>  create mode 100644 infiniband-diags/libibnetdisc/src/chassis.h
>  create mode 100644 infiniband-diags/libibnetdisc/src/ibnetdisc.c
>  create mode 100644 infiniband-diags/libibnetdisc/src/internal.h
>  create mode 100644 infiniband-diags/libibnetdisc/src/libibnetdisc.map
>  create mode 100644 infiniband-diags/libibnetdisc/test/iblinkinfotest.c
>  create mode 100644 infiniband-diags/libibnetdisc/test/ibnetdisctest.c
>  create mode 100644 infiniband-diags/libibnetdisc/test/testleaks.c
> 
> diff --git a/infiniband-diags/Makefile.am b/infiniband-diags/Makefile.am
> index c22ba5e..8e8c3c1 100644
> --- a/infiniband-diags/Makefile.am
> +++ b/infiniband-diags/Makefile.am
> @@ -1,3 +1,4 @@
> +SUBDIRS = libibnetdisc
>  
>  INCLUDES = -I$(top_builddir)/include/ -I$(srcdir)/include -I$(includedir) -I$(includedir)/infiniband
>  
> diff --git a/infiniband-diags/configure.in b/infiniband-diags/configure.in
> index 5509fec..7c346e2 100644
> --- a/infiniband-diags/configure.in
> +++ b/infiniband-diags/configure.in
> @@ -145,6 +145,34 @@ IBSCRIPTPATH_TMP2="`echo $IBSCRIPTPATH_TMP1 | sed 's/^NONE/$ac_default_prefix/'`
>  IBSCRIPTPATH="`eval echo $IBSCRIPTPATH_TMP2`"
>  AC_SUBST(IBSCRIPTPATH)
>  
> +dnl Begin libibnetdisc stuff
> +AC_CHECK_HEADERS([stdint.h stdlib.h string.h syslog.h unistd.h])
> +AC_CHECK_FUNCS([strrchr strtoul strtoull])
> +
> +ibnetdisc_api_version=`grep LIBVERSION $srcdir/libibnetdisc/libibnetdisc.ver | sed 's/LIBVERSION=//'`
> +if test -z $ibnetdisc_api_version; then
> +   echo "FAILED to find $srcdir/libibnetdisc/libibnetdisc.ver"
> +   exit 1
> +fi
> +AC_SUBST(ibnetdisc_api_version)
> +AC_DEFINE_UNQUOTED(API_VERSION,
> +	["$ibnetdisc_api_version"],
> +	[The API version of this library])
> +
> +AC_MSG_CHECKING(for --enable-test-utils)
> +AC_ARG_ENABLE(test-utils,
> +[  --enable-test-utils build additional test utilities (default=no)],
> +[case "${enableval}" in
> +  yes) tutils=yes ;;
> +  no)  tutils=no ;;
> +  *) AC_MSG_ERROR(bad value ${enableval} for --enable-test-utils) ;;
> +esac],[tutils=no])
> +AM_CONDITIONAL(ENABLE_TEST_UTILS, test x$tutils = xyes)
> +AC_MSG_RESULT(${tutils=no})
> +
> +dnl End libibnetdisc stuff
> +
> +
>  AC_CONFIG_FILES([\
>          Makefile \
>          infiniband-diags.spec \
> @@ -165,6 +193,7 @@ AC_CONFIG_FILES([\
>          scripts/ibhosts \
>          scripts/ibnodes \
>          scripts/ibswitches \
> -	scripts/ibrouters
> +	scripts/ibrouters \
> +   libibnetdisc/Makefile
>  ])
>  AC_OUTPUT
> diff --git a/infiniband-diags/libibnetdisc/Makefile.am b/infiniband-diags/libibnetdisc/Makefile.am
> new file mode 100644
> index 0000000..7b478b1
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/Makefile.am
> @@ -0,0 +1,66 @@
> +
> +#SUBDIRS = .
> +
> +INCLUDES = -I$(srcdir)/include -I$(includedir) -I$(includedir)/infiniband
> +
> +lib_LTLIBRARIES = libibnetdisc.la
> +sbin_PROGRAMS =
> +
> +if ENABLE_TEST_UTILS
> +sbin_PROGRAMS += test/ibnetdisctest \
> +                 test/iblinkinfotest \
> +                 test/testleaks
> +endif
> +
> +DBGFLAGS = -g
> +
> +if HAVE_LD_VERSION_SCRIPT
> +libibnetdisc_version_script = -Wl,--version-script=$(srcdir)/src/libibnetdisc.map
> +else
> +libibnetdisc_version_script =
> +endif
> +
> +libibnetdisc_la_SOURCES = src/ibnetdisc.c src/chassis.c src/chassis.h
> +libibnetdisc_la_CFLAGS = -Wall $(DBGFLAGS)
> +libibnetdisc_la_LDFLAGS = -version-info $(ibnetdisc_api_version) \
> +	-export-dynamic $(libibnetdisc_version_script) \
> +	-losmcomp -libmad
> +libibnetdisc_la_DEPENDENCIES = $(srcdir)/src/libibnetdisc.map
> +
> +libibnetdiscincludedir = $(includedir)/infiniband
> +
> +test_ibnetdisctest_SOURCES = test/ibnetdisctest.c
> +test_ibnetdisctest_CFLAGS = -Wall $(DBGFLAGS)
> +test_ibnetdisctest_LDFLAGS = -Wl,--rpath -Wl,$(libdir) \
> +			-libcommon -libnetdisc
> +
> +test_iblinkinfotest_SOURCES = test/iblinkinfotest.c
> +test_iblinkinfotest_CFLAGS = -Wall $(DBGFLAGS)
> +test_iblinkinfotest_LDFLAGS = -Wl,--rpath -Wl,$(libdir) \
> +			-libcommon -libnetdisc
> +
> +test_testleaks_SOURCES = test/testleaks.c
> +test_testleaks_CFLAGS = -Wall $(DBGFLAGS)
> +test_testleaks_LDFLAGS = -Wl,--rpath -Wl,$(libdir) \
> +			-libcommon -libnetdisc
> +
> +libibnetdiscinclude_HEADERS = $(srcdir)/include/infiniband/ibnetdisc.h
> +
> +man_MANS = man/ibnd_debug.3 \
> +	man/ibnd_destroy_fabric.3 \
> +	man/ibnd_discover_fabric.3 \
> +	man/ibnd_find_node_dr.3 \
> +	man/ibnd_find_node_guid.3 \
> +	man/ibnd_iter_nodes.3 \
> +	man/ibnd_iter_nodes_type.3 \
> +	man/ibnd_linkspeed_str.3 \
> +	man/ibnd_linkstate_str.3 \
> +	man/ibnd_linkwidth_str.3 \
> +	man/ibnd_node_type_str.3 \
> +	man/ibnd_physstate_str.3 \
> +	man/ibnd_update_node.3 \
> +	man/ibnd_show_progress.3
> +
> +EXTRA_DIST = libibnetdisc.spec.in libibnetdisc.spec \
> +	$(srcdir)/src/libibnetdisc.map libibnetdisc.ver autogen.sh
> +
> diff --git a/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h b/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
> new file mode 100644
> index 0000000..cdee2bd
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
> @@ -0,0 +1,276 @@
> +/*
> + * Copyright (c) 2008 Lawrence Livermore National Lab.  All rights reserved.
> + *
> + * This software is available to you under a choice of one of two
> + * licenses.  You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + *     Redistribution and use in source and binary forms, with or
> + *     without modification, are permitted provided that the following
> + *     conditions are met:
> + *
> + *      - Redistributions of source code must retain the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer.
> + *
> + *      - Redistributions in binary form must reproduce the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer in the documentation and/or other materials
> + *        provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + *
> + */
> +
> +#ifndef _IBNETDISC_H_
> +#define _IBNETDISC_H_
> +
> +#include <stdio.h>
> +#include <infiniband/mad.h>
> +
> +#define MAXHOPS		63
> +
> +/* HASH table defines */
> +#define HASHGUID(guid) ((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103)))
> +#define HTSZ 137
> +
> +#define	IBND_DEBUG(str, args...) \
> +	if (ibdebug) printf("%s:%d; "str, __FILE__, __LINE__, ##args)
> +#define	IBND_ERROR(str, args...) \
> +	fprintf(stderr, "%s:%d; "str, __FILE__, __LINE__, ##args)

I believe the "args ..." and "##args" are only for gcc.  Not sure how
much this portability issue matters for OFED.  Personally, I always do
the:

#define MYDEBUG(x) printf x

MYDEBUG(("lala: %s", somestrvar));

trick.

Al

> +/** =========================================================================
> + * ENUM definitions
> + */
> +typedef enum {
> +	IBND_CA_NODE	= 1,
> +	IBND_SWITCH_NODE = 2,
> +	IBND_ROUTER_NODE = 3
> +} ibnd_node_type_t;
> +
> +typedef enum {
> +	IBND_LINK_DOWN = 1,
> +	IBND_LINK_INIT = 2,
> +	IBND_LINK_ARMED = 3,
> +	IBND_LINK_ACTIVE = 4
> +} ibnd_link_state_t;
> +
> +/** =========================================================================
> + * Node
> + */
> +typedef struct switch_info {
> +	int smaenhsp0;
> +} ibnd_switch_info_t;
> +
> +typedef struct node_info {
> +	int base_ver;
> +	int class_ver;
> +	int type;
> +	int numports;
> +	uint64_t sysimgguid;
> +	uint64_t nodeguid;
> +	uint64_t nodeportguid;
> +	uint16_t partition_cap;
> +	uint32_t devid;
> +	uint32_t revision;
> +	int localport;
> +	uint32_t vendid;
> +} ibnd_node_info_t;
> +
> +struct ib_fabric; /* forward declare */
> +struct chassis; /* forward declare */
> +struct port; /* forward declare */
> +
> +typedef struct node {
> +	struct node *next; /* all node list in fabric */
> +	struct ib_fabric *fabric; /* the fabric node belongs to */
> +
> +	ib_portid_t path_portid; /* path from "from_node" */
> +	int dist; /* num of hops from "from_node" */
> +	int smalid;
> +	int smalmc;
> +	ibnd_switch_info_t sw_info;
> +	ibnd_node_info_t info;
> +	char nodedesc[64];
> +	struct port **ports; /* in order array of port pointers */
> +				/* the size of this array is info.numports + 1 */
> +				/* items MAY BE NULL!  (ie 0 == switches only) */
> +
> +	/* chassis info */
> +	struct node *next_chassis_node; /* next node in ibnd_chassis_t->nodes */
> +	struct chassis *chassis; /* if != NULL the chassis this node belongs to */
> +	unsigned char ch_type;
> +	unsigned char ch_anafanum;
> +	unsigned char ch_slotnum;
> +	unsigned char ch_slot;
> +} ibnd_node_t;
> +
> +/** =========================================================================
> + * Port
> + */
> +typedef struct port_info {
> +	int lid;
> +	int smlid;
> +	int link_speed_supported;
> +	int link_speed_enabled;
> +	int link_speed_active;
> +	int link_state;
> +	int phys_state;
> +	int link_down_def_state;
> +	int mkey_prot_bits;
> +	int lmc;
> +	int neighbor_mtu;
> +	int smsl;
> +	int init_type;
> +	int vl_capability;
> +	int vl_high_limit;
> +	int vl_arb_high_cap;
> +	int vl_arb_low_cap;
> +	int init_reply;
> +	int mtu_cap;
> +	int vl_stall_count;
> +	int hoq_lifetime;
> +	int oper_vls;
> +	int partition_enforce_in;
> +	int partition_enforce_out;
> +	int filter_raw_in;
> +	int filter_raw_out;
> +	int mkey_violations;
> +	int pkey_violations;
> +	int qkey_violations;
> +	int guid_capabilities;
> +	int client_rereg;
> +	int subnet_timeout;
> +	int response_time_val;
> +	int local_phys_error;
> +	int overrun_error;
> +	int max_credit_hint;
> +	uint32_t link_round_trip;
> +	int local_port;
> +	int link_width_supported;
> +	int link_width_enabled;
> +	int link_width_active;
> +	int diag_code;
> +	int mkey_lease;
> +	uint32_t capability_mask;
> +	uint64_t mkey;
> +	uint64_t gid_prefix;
> +} ibnd_port_info_t;

> +typedef struct port {
> +	uint64_t guid;
> +	int portnum;
> +	int ext_portnum; /* optional if != 0 external port num */
> +	ibnd_node_t *node; /* node this port belongs to */
> +	ibnd_port_info_t info;
> +	struct port *remoteport; /* null if SMA, or does not exist */
> +} ibnd_port_t;
> +
> +
> +/** =========================================================================
> + * Chassis data
> + */
> +typedef struct chassis {
> +	struct chassis *next;
> +	uint64_t chassisguid;
> +	int chassisnum;
> +
> +	/* generic grouping by SystemImageGUID */
> +	int nodecount;
> +	ibnd_node_t *nodes;
> +
> +	/* specific to voltaire type nodes */
> +#define SPINES_MAX_NUM 12
> +#define LINES_MAX_NUM 36
> +	ibnd_node_t *spinenode[SPINES_MAX_NUM + 1];
> +	ibnd_node_t *linenode[LINES_MAX_NUM + 1];
> +} ibnd_chassis_t;
> +
> +/** =========================================================================
> + * Fabric
> + * Main fabric object which is returned and represents the data discovered
> + */
> +typedef struct ib_fabric {
> +	/* the node the discover was initiated from
> +	 * "from" parameter in ibnd_discover_fabric
> +	 * or by default the node you ar running on
> +	 */
> +	ibnd_node_t *from_node;
> +	/* NULL term list of all nodes in the fabric */
> +	ibnd_node_t *nodes;
> +	/* NULL terminated list of all chassis found in the fabric */
> +	ibnd_chassis_t *chassis;
> +	int maxhops_discovered;
> +} ibnd_fabric_t;
> +
> +
> +/** =========================================================================
> + * Initialization (fabric operations)
> + */
> +void           ibnd_debug(int i);
> +void           ibnd_show_progress(int i);
> +
> +ibnd_fabric_t *ibnd_discover_fabric(char *dev_name, int dev_port,
> +			int timeout_ms, ib_portid_t *from, int hops);
> +	/**
> +	 * dev_name: (required) local device name to use to access the fabric
> +	 * dev_port: (required) local device port to use to access the fabric
> +	 * timeout_ms: (required) gives the timeout for a _SINGLE_ query on
> +	 *             the fabric.  So if there are mutiple nodes not
> +	 *             responding this may result in a lengthy delay.
> +	 * from: (optional) specify the node to start scanning from.
> +	 *       If NULL start from the node we are running on.
> +	 * hops: (optional) Specify how much of the fabric to traverse.
> +	 *       negative value == scan entire fabric
> +	 */
> +void           ibnd_destroy_fabric(ibnd_fabric_t *fabric);
> +
> +/** =========================================================================
> + * Node operations
> + */
> +ibnd_node_t *ibnd_find_node_guid(ibnd_fabric_t *fabric, uint64_t guid);
> +ibnd_node_t *ibnd_find_node_dr(ibnd_fabric_t *fabric, char *dr_str);
> +ibnd_node_t *ibnd_update_node(ibnd_node_t *node);
> +
> +typedef void (*ibnd_iter_node_func_t)(ibnd_node_t *node, void *user_data);
> +void         ibnd_iter_nodes(ibnd_fabric_t *fabric,
> +				ibnd_iter_node_func_t func,
> +				void *user_data);
> +void         ibnd_iter_nodes_type(ibnd_fabric_t *fabric,
> +				ibnd_iter_node_func_t func,
> +				ibnd_node_type_t node_type,
> +				void *user_data);
> +
> +/** =========================================================================
> + * Str convert functions
> + */
> +char          *ibnd_linkwidth_str(int link_width);
> +char          *ibnd_linkstate_str(int link_state);
> +char          *ibnd_physstate_str(int phys_state);
> +const char    *ibnd_node_type_str(ibnd_node_t *node);
> +const char    *ibnd_node_type_str_short(ibnd_node_t *node);
> +char          *ibnd_linkspeed_str(int link_speed, int data_rate);
> +	/* if data_rate == 0 use "SDR", "DDR", etc. */
> +	/* if data_rate == 1 use "2.5 Gbps", "5.0 Gbps", etc. */
> +
> +/** =========================================================================
> + * Chassis queries
> + */
> +uint64_t  ibnd_get_chassis_guid(ibnd_fabric_t *fabric, unsigned char chassisnum);
> +char     *ibnd_get_chassis_type(ibnd_node_t *node);
> +char     *ibnd_get_chassis_slot_str(ibnd_node_t *node, char *str, size_t size);
> +
> +int       ibnd_is_xsigo_guid(uint64_t guid);
> +int       ibnd_is_xsigo_tca(uint64_t guid);
> +int       ibnd_is_xsigo_hca(uint64_t guid);
> +
> +#endif	/* _IBNETDISC_H_ */
> diff --git a/infiniband-diags/libibnetdisc/libibnetdisc.ver b/infiniband-diags/libibnetdisc/libibnetdisc.ver
> new file mode 100644
> index 0000000..a0a5f3c
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/libibnetdisc.ver
> @@ -0,0 +1,9 @@
> +# In this file we track the current API version
> +# of the IB net discover interface (and libraries)
> +# The version is built of the following
> +# tree numbers:
> +# API_REV:RUNNING_REV:AGE
> +# API_REV - advance on any added API
> +# RUNNING_REV - advance any change to the vendor files
> +# AGE - number of backward versions the API still supports
> +LIBVERSION=1:0:0
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_debug.3 b/infiniband-diags/libibnetdisc/man/ibnd_debug.3
> new file mode 100644
> index 0000000..a4076fc
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_debug.3
> @@ -0,0 +1,2 @@
> +.\".TH IBND_DEBUG 3  "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.so man3/ibnd_discover_fabric.3
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_destroy_fabric.3 b/infiniband-diags/libibnetdisc/man/ibnd_destroy_fabric.3
> new file mode 100644
> index 0000000..8fe20ae
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_destroy_fabric.3
> @@ -0,0 +1,2 @@
> +.\".TH IBND_DESTROY_FABRIC 3  "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.so man3/ibnd_discover_fabric.3
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_discover_fabric.3 b/infiniband-diags/libibnetdisc/man/ibnd_discover_fabric.3
> new file mode 100644
> index 0000000..44d8c65
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_discover_fabric.3
> @@ -0,0 +1,49 @@
> +.TH IBND_DISCOVER_FABRIC 3  "July 25, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.SH "NAME"
> +ibnd_discover_fabric, ibnd_destroy_fabric, ibnd_debug ibnd_show_progress \- initialize ibnetdiscover library.
> +.SH "SYNOPSIS"
> +.nf
> +.B #include <infiniband/ibnetdisc.h>
> +.sp
> +.BI "ibnd_fabric_t *ibnd_discover_fabric(char *dev_name, int dev_port, int timeout_ms, ib_portid_t *from, int hops)"
> +.BI "void ibnd_destroy_fabric(ibnd_fabric_t *fabric)"
> +.BI "void ibnd_debug(int i)"
> +.BI "void ibnd_show_progress(int i)"
> +
> +
> +.SH "DESCRIPTION"
> +.B ibnd_discover_fabric()
> +Discover the fabric connected to the port specified by dev_name and dev_port, using a timeout specified.  The "from" and "hops" parameters are optional and allow one to scan part of a fabric by specifying a node "from" and a number of hops away from that node to scan, "hops".  This gives the user a "sub-fabric" which is "centered" anywhere they chose.
> +
> +.B ibnd_destroy_fabric()
> +free all memory and resources associated with the fabric.
> +
> +.B ibnd_debug()
> +Set the debug level to be printed as library operations take place.
> +
> +.B ibnd_debug()
> +Indicate that the library should print debug output which shows it's progress
> +through the fabric.
> +
> +.SH "RETURN VALUE"
> +.B ibnd_discover_fabric()
> +return NULL on failure, otherwise a valid ibnd_fabric_t object.
> +
> +.B ibnd_destory_fabric(), ibnd_debug()
> +NONE
> +
> +.SH "EXAMPLES"
> +
> +.B Discover the entire fabric connected to device "mthca0", port 1.
> +
> +	ibnd_discover_fabric("mthca0", 1, 100, NULL, 0);
> +
> +.B Discover only a single node and those nodes connected to it.
> +
> +	str2drpath(&(port_id.drpath), from, 0, 0);
> +
> +	ibnd_discover_fabric("mthca0", 1, 100, &port_id, 1);
> +
> +.SH "AUTHORS"
> +.TP
> +Ira Weiny <weiny2 at llnl.gov>
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_find_node_dr.3 b/infiniband-diags/libibnetdisc/man/ibnd_find_node_dr.3
> new file mode 100644
> index 0000000..612e501
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_find_node_dr.3
> @@ -0,0 +1,2 @@
> +.\".TH IBND_FIND_NODE_DR 3  "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.so man3/ibnd_find_node_guid.3
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_find_node_guid.3 b/infiniband-diags/libibnetdisc/man/ibnd_find_node_guid.3
> new file mode 100644
> index 0000000..676b528
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_find_node_guid.3
> @@ -0,0 +1,25 @@
> +.TH IBND_FIND_NODE_GUID 3  "July 25, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.SH "NAME"
> +ibnd_find_node_guid, ibnd_find_node_dr \- given a fabric object find the node object within it which matches the guid or directed route specified.
> +
> +.SH "SYNOPSIS"
> +.nf
> +.B #include <infiniband/ibnetdisc.h>
> +.sp
> +.BI "ibnd_node_t *ibnd_find_node_guid(ibnd_fabric_t *fabric, uint64_t guid)"
> +.BI "ibnd_node_t *ibnd_find_node_dr(ibnd_fabric_t *fabric, char *dr_str)"
> +
> +.SH "DESCRIPTION"
> +.B ibnd_find_node_guid()
> +Given a fabric object and a guid, return the ibnd_node_t object with that node guid.
> +.B ibnd_find_node_dr()
> +Given a fabric object and a directed route, return the ibnd_node_t object with
> +that directed route.
> +
> +.SH "RETURN VALUE"
> +.B ibnd_find_node_guid(), ibnd_find_node_dr()
> +return NULL on failure, otherwise a valid ibnd_node_t object.
> +
> +.SH "AUTHORS"
> +.TP
> +Ira Weiny <weiny2 at llnl.gov>
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_iter_nodes.3 b/infiniband-diags/libibnetdisc/man/ibnd_iter_nodes.3
> new file mode 100644
> index 0000000..7199dfb
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_iter_nodes.3
> @@ -0,0 +1,24 @@
> +.TH IBND_ITER_NODES 3  "July 25, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.SH "NAME"
> +ibnd_iter_nodes, ibnd_iter_nodes_type \- given a fabric object and a function itterate over the nodes in the fabric.
> +
> +.SH "SYNOPSIS"
> +.nf
> +.B #include <infiniband/ibnetdisc.h>
> +.sp
> +.BI "void ibnd_iter_nodes(ibnd_fabric_t *fabric, ibnd_iter_func_t func, void *user_data)"
> +.BI "void ibnd_iter_nodes_type(ibnd_fabric_t *fabric, ibnd_iter_func_t func, ibnd_node_type_t type, void *user_data)"
> +
> +.SH "DESCRIPTION"
> +.B ibnd_iter_nodes()
> +Itterate through all the nodes in the fabric and call "func" on them.
> +.B ibnd_iter_nodes_type()
> +The same as ibnd_iter_nodes except to limit the iteration to the nodes with the specified type.
> +
> +.SH "RETURN VALUE"
> +.B ibnd_iter_nodes(), ibnd_iter_nodes_type()
> +NONE
> +
> +.SH "AUTHORS"
> +.TP
> +Ira Weiny <weiny2 at llnl.gov>
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_iter_nodes_type.3 b/infiniband-diags/libibnetdisc/man/ibnd_iter_nodes_type.3
> new file mode 100644
> index 0000000..878547c
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_iter_nodes_type.3
> @@ -0,0 +1,2 @@
> +.\".TH IBND_FIND_NODES_TYPE 3  "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.so man3/ibnd_find_nodes.3
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_linkspeed_str.3 b/infiniband-diags/libibnetdisc/man/ibnd_linkspeed_str.3
> new file mode 100644
> index 0000000..128cd3e
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_linkspeed_str.3
> @@ -0,0 +1,2 @@
> +.\".TH IBND_LINKSPEED_STR 3  "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.so man3/ibnd_linkwidth_str.3
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_linkstate_str.3 b/infiniband-diags/libibnetdisc/man/ibnd_linkstate_str.3
> new file mode 100644
> index 0000000..2fa9189
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_linkstate_str.3
> @@ -0,0 +1,2 @@
> +.\".TH IBND_LINKSTATE_STR 3  "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.so man3/ibnd_linkwidth_str.3
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_linkwidth_str.3 b/infiniband-diags/libibnetdisc/man/ibnd_linkwidth_str.3
> new file mode 100644
> index 0000000..2cd4f0a
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_linkwidth_str.3
> @@ -0,0 +1,26 @@
> +.TH IBND_LINKWIDTH_STR 3  "July 25, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.SH "NAME"
> +ibnd_linkwidth_str, ibnd_linkspeed_str, ibnd_linkstate_str, ibnd_physstate_str, ibnd_node_type_str \- prety string functions.
> +
> +.SH "SYNOPSIS"
> +.nf
> +.B #include <infiniband/ibnetdisc.h>
> +.sp
> +.BI
> +.BI "char          *ibnd_linkwidth_str(int link_width)"
> +.BI "char          *ibnd_linkspeed_str(int link_speed)"
> +.BI "char          *ibnd_linkstate_str(int link_state)"
> +.BI "char          *ibnd_physstate_str(int phys_state)"
> +.BI "const char    *ibnd_node_type_str(ibnd_node_t *node)"
> +.BI "const char    *ibnd_node_type_str_short(ibnd_node_t *node)"
> +
> +.SH "DESCRIPTION"
> +Return user readable strings for the values given.
> +
> +.BI "const char    *ibnd_node_type_str_short(ibnd_node_t *node)"
> +Returns a shorter abbreviated version of the string.
> +
> +
> +.SH "AUTHORS"
> +.TP
> +Ira Weiny <weiny2 at llnl.gov>
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_node_type_str.3 b/infiniband-diags/libibnetdisc/man/ibnd_node_type_str.3
> new file mode 100644
> index 0000000..77dbf07
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_node_type_str.3
> @@ -0,0 +1,2 @@
> +.\".TH IBND_NODE_TYPE_STR 3  "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.so man3/ibnd_linkwidth_str.3
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_node_type_str_short.3 b/infiniband-diags/libibnetdisc/man/ibnd_node_type_str_short.3
> new file mode 100644
> index 0000000..62feb6e
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_node_type_str_short.3
> @@ -0,0 +1,2 @@
> +.\".TH IBND_NODE_TYPE_STR_SHORT 3  "Aug 05, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.so man3/ibnd_linkwidth_str.3
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_physstate_str.3 b/infiniband-diags/libibnetdisc/man/ibnd_physstate_str.3
> new file mode 100644
> index 0000000..aeeaeb7
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_physstate_str.3
> @@ -0,0 +1,2 @@
> +.\".TH IBND_PHYSSTATE_STR 3  "Aug 04, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.so man3/ibnd_physstate_str.3
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_show_progress.3 b/infiniband-diags/libibnetdisc/man/ibnd_show_progress.3
> new file mode 100644
> index 0000000..280af31
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_show_progress.3
> @@ -0,0 +1,2 @@
> +.\".TH IBND_SHOW_PROGRESS 3  "Nov 26, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.so man3/ibnd_discover_fabric.3
> diff --git a/infiniband-diags/libibnetdisc/man/ibnd_update_node.3 b/infiniband-diags/libibnetdisc/man/ibnd_update_node.3
> new file mode 100644
> index 0000000..d3aa206
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/man/ibnd_update_node.3
> @@ -0,0 +1,21 @@
> +.TH IBND_UPDATE_NODE 3  "July 25, 2008" "OpenIB" "OpenIB Programmer's Manual"
> +.SH "NAME"
> +ibnd_update_node \- Update the node specified with new data from the fabric.
> +
> +.SH "SYNOPSIS"
> +.nf
> +.B #include <infiniband/ibnetdisc.h>
> +.sp
> +.BI "ibnd_node_t *ibnd_update_node(ibnd_node_t *node)"
> +
> +.SH "DESCRIPTION"
> +.B ibnd_update_node()
> +Update the node info, port info, and node description of the node specified.
> +
> +.SH "RETURN VALUE"
> +.B ibnd_update_node()
> +Return NULL on failure, otherwise a valid ibnd_node_t object which is part of the fabric object.
> +
> +.SH "AUTHORS"
> +.TP
> +Ira Weiny <weiny2 at llnl.gov>
> diff --git a/infiniband-diags/libibnetdisc/src/chassis.c b/infiniband-diags/libibnetdisc/src/chassis.c
> new file mode 100644
> index 0000000..41f325e
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/src/chassis.c
> @@ -0,0 +1,818 @@
> +/*
> + * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
> + * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
> + * Copyright (c) 2008 Lawrence Livermore National Lab.  All rights reserved.
> + *
> + * This software is available to you under a choice of one of two
> + * licenses.  You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + *     Redistribution and use in source and binary forms, with or
> + *     without modification, are permitted provided that the following
> + *     conditions are met:
> + *
> + *      - Redistributions of source code must retain the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer.
> + *
> + *      - Redistributions in binary form must reproduce the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer in the documentation and/or other materials
> + *        provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + *
> + */
> +
> +/*========================================================*/
> +/*               FABRIC SCANNER SPECIFIC DATA             */
> +/*========================================================*/
> +
> +#if HAVE_CONFIG_H
> +#  include <config.h>
> +#endif /* HAVE_CONFIG_H */
> +
> +#include <stdint.h>
> +#include <stdlib.h>
> +#include <inttypes.h>
> +
> +#include <infiniband/common.h>
> +#include <infiniband/mad.h>
> +
> +#include "internal.h"
> +#include "chassis.h"
> +
> +static char *ChassisTypeStr[5] = { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004" };
> +static char *ChassisSlotTypeStr[4] = { "", "Line", "Spine", "SRBD" };
> +
> +char *ibnd_get_chassis_type(ibnd_node_t *node)
> +{
> +	/* Currently, only if Voltaire chassis */
> +	if (node->info.vendid != VTR_VENDOR_ID)
> +		return (NULL);
> +	if (!node->chassis)
> +		return (NULL);
> +	if (node->ch_type == UNRESOLVED_CT
> +		|| node->ch_type > ISR2004_CT)
> +		return (NULL);
> +	return ChassisTypeStr[node->ch_type];
> +}
> +
> +char *ibnd_get_chassis_slot_str(ibnd_node_t *node, char *str, size_t size)
> +{
> +	/* Currently, only if Voltaire chassis */
> +	if (node->info.vendid != VTR_VENDOR_ID)
> +		return (NULL);
> +	if (!node->chassis)
> +		return (NULL);
> +	if (node->ch_slot == UNRESOLVED_CS
> +		|| node->ch_slot > SRBD_CS)
> +		return (NULL);
> +	if (!str)
> +		return (NULL);
> +	snprintf(str, size, "%s %d Chip %d",
> +			ChassisSlotTypeStr[node->ch_slot],
> +			node->ch_slotnum,
> +			node->ch_anafanum);
> +	return (str);
> +}
> +
> +static ibnd_chassis_t *find_chassisnum(struct ibnd_fabric *fabric, unsigned char chassisnum)
> +{
> +	ibnd_chassis_t *current;
> +
> +	for (current = fabric->first_chassis; current; current = current->next) {
> +		if (current->chassisnum == chassisnum)
> +			return current;
> +	}
> +
> +	return NULL;
> +}
> +
> +static uint64_t topspin_chassisguid(uint64_t guid)
> +{
> +	/* Byte 3 in system image GUID is chassis type, and */
> +	/* Byte 4 is location ID (slot) so just mask off byte 4 */
> +	return guid & 0xffffffff00ffffffULL;
> +}
> +
> +int ibnd_is_xsigo_guid(uint64_t guid)
> +{
> +	if ((guid & 0xffffff0000000000ULL) == 0x0013970000000000ULL)
> +		return 1;
> +	else
> +		return 0;
> +}
> +
> +static int is_xsigo_leafone(uint64_t guid)
> +{
> +	if ((guid & 0xffffffffff000000ULL) == 0x0013970102000000ULL)
> +		return 1;
> +	else
> +		return 0;
> +}
> +
> +int ibnd_is_xsigo_hca(uint64_t guid)
> +{
> +	/* NodeType 2 is HCA */
> +	if ((guid & 0xffffffff00000000ULL) == 0x0013970200000000ULL)
> +		return 1;
> +	else
> +		return 0;
> +}
> +
> +int ibnd_is_xsigo_tca(uint64_t guid)
> +{
> +	/* NodeType 3 is TCA */
> +	if ((guid & 0xffffffff00000000ULL) == 0x0013970300000000ULL)
> +		return 1;
> +	else
> +		return 0;
> +}
> +
> +static int is_xsigo_ca(uint64_t guid)
> +{
> +	if (ibnd_is_xsigo_hca(guid) || ibnd_is_xsigo_tca(guid))
> +		return 1;
> +	else
> +		return 0;
> +}
> +
> +static int is_xsigo_switch(uint64_t guid)
> +{
> +	if ((guid & 0xffffffff00000000ULL) == 0x0013970100000000ULL)
> +		return 1;
> +	else
> +		return 0;
> +}
> +
> +static uint64_t xsigo_chassisguid(ibnd_node_t *node)
> +{
> +	if (!is_xsigo_ca(node->info.sysimgguid)) {
> +		/* Byte 3 is NodeType and byte 4 is PortType */
> +		/* If NodeType is 1 (switch), PortType is masked */
> +		if (is_xsigo_switch(node->info.sysimgguid))
> +			return node->info.sysimgguid & 0xffffffff00ffffffULL;
> +		else
> +			return node->info.sysimgguid;
> +	} else {
> +		if (!node->ports || !node->ports[1])
> +			return (0);
> +
> +		/* Is there a peer port ? */
> +		if (!node->ports[1]->remoteport)
> +			return node->info.sysimgguid;
> +
> +		/* If peer port is Leaf 1, use its chassis GUID */
> +		if (is_xsigo_leafone(node->ports[1]->remoteport->node->info.sysimgguid))
> +			return node->ports[1]->remoteport->node->info.sysimgguid &
> +			       0xffffffff00ffffffULL;
> +		else
> +			return node->info.sysimgguid;
> +	}
> +}
> +
> +static uint64_t get_chassisguid(ibnd_node_t *node)
> +{
> +	if (node->info.vendid == TS_VENDOR_ID || node->info.vendid == SS_VENDOR_ID)
> +		return topspin_chassisguid(node->info.sysimgguid);
> +	else if (node->info.vendid == XS_VENDOR_ID || ibnd_is_xsigo_guid(node->info.sysimgguid))
> +		return xsigo_chassisguid(node);
> +	else
> +		return node->info.sysimgguid;
> +}
> +
> +static ibnd_chassis_t *find_chassisguid(ibnd_node_t *node)
> +{
> +	struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(node->fabric);
> +	ibnd_chassis_t *current;
> +	uint64_t chguid;
> +
> +	chguid = get_chassisguid(node);
> +	for (current = f->first_chassis; current; current = current->next) {
> +		if (current->chassisguid == chguid)
> +			return current;
> +	}
> +
> +	return NULL;
> +}
> +
> +uint64_t ibnd_get_chassis_guid(ibnd_fabric_t *fabric, unsigned char chassisnum)
> +{
> +	struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(fabric);
> +	ibnd_chassis_t *chassis;
> +
> +	chassis = find_chassisnum(f, chassisnum);
> +	if (chassis)
> +		return chassis->chassisguid;
> +	else
> +		return 0;
> +}
> +
> +static int is_router(struct ibnd_node *n)
> +{
> +	return (n->node.info.devid == VTR_DEVID_IB_FC_ROUTER ||
> +		n->node.info.devid == VTR_DEVID_IB_IP_ROUTER);
> +}
> +
> +static int is_spine_9096(struct ibnd_node *n)
> +{
> +	return (n->node.info.devid == VTR_DEVID_SFB4 ||
> +		n->node.info.devid == VTR_DEVID_SFB4_DDR);
> +}
> +
> +static int is_spine_9288(struct ibnd_node *n)
> +{
> +	return (n->node.info.devid == VTR_DEVID_SFB12 ||
> +		n->node.info.devid == VTR_DEVID_SFB12_DDR);
> +}
> +
> +static int is_spine_2004(struct ibnd_node *n)
> +{
> +	return (n->node.info.devid == VTR_DEVID_SFB2004);
> +}
> +
> +static int is_spine_2012(struct ibnd_node *n)
> +{
> +	return (n->node.info.devid == VTR_DEVID_SFB2012);
> +}
> +
> +static int is_spine(struct ibnd_node *n)
> +{
> +	return (is_spine_9096(n) || is_spine_9288(n) ||
> +		is_spine_2004(n) || is_spine_2012(n));
> +}
> +
> +static int is_line_24(struct ibnd_node *n)
> +{
> +	return (n->node.info.devid == VTR_DEVID_SLB24 ||
> +		n->node.info.devid == VTR_DEVID_SLB24_DDR ||
> +		n->node.info.devid == VTR_DEVID_SRB2004);
> +}
> +
> +static int is_line_8(struct ibnd_node *n)
> +{
> +	return (n->node.info.devid == VTR_DEVID_SLB8);
> +}
> +
> +static int is_line_2024(struct ibnd_node *n)
> +{
> +	return (n->node.info.devid == VTR_DEVID_SLB2024);
> +}
> +
> +static int is_line(struct ibnd_node *n)
> +{
> +	return (is_line_24(n) || is_line_8(n) || is_line_2024(n));
> +}
> +
> +int is_chassis_switch(struct ibnd_node *n)
> +{
> +    return (is_spine(n) || is_line(n));
> +}
> +
> +/* these structs help find Line (Anafa) slot number while using spine portnum */
> +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 };
> +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 };
> +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 };
> +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 };
> +
> +/* IPR FCR modules connectivity while using sFB4 port as reference */
> +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 };
> +
> +/* these structs help find Spine (Anafa) slot number while using spine portnum */
> +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 };
> +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 };
> +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 };
> +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 };
> +/*	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 }; */
> +
> +static void get_sfb_slot(struct ibnd_node *node, ibnd_port_t *lineport)
> +{
> +	ibnd_node_t *n = (ibnd_node_t *)node;
> +
> +	n->ch_slot = SPINE_CS;
> +	if (is_spine_9096(node)) {
> +		n->ch_type = ISR9096_CT;
> +		n->ch_slotnum = spine4_slot_2_slb[lineport->portnum];
> +		n->ch_anafanum = anafa_spine4_slot_2_slb[lineport->portnum];
> +	} else if (is_spine_9288(node)) {
> +		n->ch_type = ISR9288_CT;
> +		n->ch_slotnum = spine12_slot_2_slb[lineport->portnum];
> +		n->ch_anafanum = anafa_spine12_slot_2_slb[lineport->portnum];
> +	} else if (is_spine_2012(node)) {
> +		n->ch_type = ISR2012_CT;
> +		n->ch_slotnum = spine12_slot_2_slb[lineport->portnum];
> +		n->ch_anafanum = anafa_spine12_slot_2_slb[lineport->portnum];
> +	} else if (is_spine_2004(node)) {
> +		n->ch_type = ISR2004_CT;
> +		n->ch_slotnum = spine4_slot_2_slb[lineport->portnum];
> +		n->ch_anafanum = anafa_spine4_slot_2_slb[lineport->portnum];
> +	} else {
> +		IBPANIC("Unexpected node found: guid 0x%016" PRIx64,
> +		node->node.info.nodeguid);
> +	}
> +}
> +
> +static void get_router_slot(struct ibnd_node *node, ibnd_port_t *spineport)
> +{
> +	ibnd_node_t *n = (ibnd_node_t *)node;
> +	int guessnum = 0;
> +
> +	node->ch_found = 1;
> +
> +	n->ch_slot = SRBD_CS;
> +	if (is_spine_9096(CONV_NODE_INTERNAL(spineport->node))) {
> +		n->ch_type = ISR9096_CT;
> +		n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
> +		n->ch_anafanum = ipr_slot_2_sfb4_port[spineport->portnum];
> +	} else if (is_spine_9288(CONV_NODE_INTERNAL(spineport->node))) {
> +		n->ch_type = ISR9288_CT;
> +		n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
> +		/* this is a smart guess based on nodeguids order on sFB-12 module */
> +		guessnum = spineport->node->info.nodeguid % 4;
> +		/* module 1 <--> remote anafa 3 */
> +		/* module 2 <--> remote anafa 2 */
> +		/* module 3 <--> remote anafa 1 */
> +		n->ch_anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2));
> +	} else if (is_spine_2012(CONV_NODE_INTERNAL(spineport->node))) {
> +		n->ch_type = ISR2012_CT;
> +		n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
> +		/* this is a smart guess based on nodeguids order on sFB-12 module */
> +		guessnum = spineport->node->info.nodeguid % 4;
> +		// module 1 <--> remote anafa 3
> +		// module 2 <--> remote anafa 2
> +		// module 3 <--> remote anafa 1
> +		n->ch_anafanum = (guessnum == 3? 1 : (guessnum == 1 ? 3 : 2));
> +	} else if (is_spine_2004(CONV_NODE_INTERNAL(spineport->node))) {
> +		n->ch_type = ISR2004_CT;
> +		n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
> +		n->ch_anafanum = ipr_slot_2_sfb4_port[spineport->portnum];
> +	} else {
> +		IBPANIC("Unexpected node found: guid 0x%016" PRIx64,
> +		spineport->node->info.nodeguid);
> +	}
> +}
> +
> +static void get_slb_slot(ibnd_node_t *n, ibnd_port_t *spineport)
> +{
> +	n->ch_slot = LINE_CS;
> +	if (is_spine_9096(CONV_NODE_INTERNAL(spineport->node))) {
> +		n->ch_type = ISR9096_CT;
> +		n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
> +		n->ch_anafanum = anafa_line_slot_2_sfb4[spineport->portnum];
> +	} else if (is_spine_9288(CONV_NODE_INTERNAL(spineport->node))) {
> +		n->ch_type = ISR9288_CT;
> +		n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
> +		n->ch_anafanum = anafa_line_slot_2_sfb12[spineport->portnum];
> +	} else if (is_spine_2012(CONV_NODE_INTERNAL(spineport->node))) {
> +		n->ch_type = ISR2012_CT;
> +		n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
> +		n->ch_anafanum = anafa_line_slot_2_sfb12[spineport->portnum];
> +	} else if (is_spine_2004(CONV_NODE_INTERNAL(spineport->node))) {
> +		n->ch_type = ISR2004_CT;
> +		n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
> +		n->ch_anafanum = anafa_line_slot_2_sfb4[spineport->portnum];
> +	} else {
> +		IBPANIC("Unexpected node found: guid 0x%016" PRIx64,
> +		spineport->node->info.nodeguid);
> +	}
> +}
> +
> +/* forward declare this */
> +static void voltaire_portmap(ibnd_port_t *port);
> +/*
> +	This function called for every Voltaire node in fabric
> +	It could be optimized so, but time overhead is very small
> +	and its only diag.util
> +*/
> +static void fill_voltaire_chassis_record(struct ibnd_node *node)
> +{
> +	ibnd_node_t *n = (ibnd_node_t *)node;
> +	int p = 0;
> +	ibnd_port_t *port;
> +	struct ibnd_node *remnode = 0;
> +
> +	if (node->ch_found) /* somehow this node has already been passed */
> +		return;
> +	node->ch_found = 1;
> +
> +	/* node is router only in case of using unique lid */
> +	/* (which is lid of chassis router port) */
> +	/* in such case node->ports is actually a requested port... */
> +	if (is_router(node)) {
> +		/* find the remote node */
> +		for (p = 1; p <= node->node.info.numports; p++) {
> +			port = node->node.ports[p];
> +			if (port && is_spine(CONV_NODE_INTERNAL(port->remoteport->node)))
> +				get_router_slot(node, port->remoteport);
> +		}
> +	} else if (is_spine(node)) {
> +		for (p = 1; p <= node->node.info.numports; p++) {
> +			port = node->node.ports[p];
> +			if (!port || !port->remoteport)
> +				continue;
> +			remnode = CONV_NODE_INTERNAL(port->remoteport->node);
> +			if (remnode->node.info.type != IBND_SWITCH_NODE) {
> +				if (!remnode->ch_found)
> +					get_router_slot(remnode, port);
> +				continue;
> +			}
> +			if (!n->ch_type)
> +				/* we assume here that remoteport belongs to line */
> +				get_sfb_slot(node, port->remoteport);
> +
> +				/* we could break here, but need to find if more routers connected */
> +		}
> +
> +	} else if (is_line(node)) {
> +		for (p = 1; p <= node->node.info.numports; p++) {
> +			port = node->node.ports[p];
> +			if (!port || port->portnum > 12 || !port->remoteport)
> +				continue;
> +			/* we assume here that remoteport belongs to spine */
> +			get_slb_slot(n, port->remoteport);
> +			break;
> +		}
> +	}
> +
> +	/* for each port of this node, map external ports */
> +	for (p = 1; p <= node->node.info.numports; p++) {
> +		port = node->node.ports[p];
> +		if (!port)
> +			continue;
> +		voltaire_portmap(port);
> +	}
> +
> +	return;
> +}
> +
> +static int get_line_index(ibnd_node_t *node)
> +{
> +	int retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum;
> +
> +	if (retval > LINES_MAX_NUM || retval < 1)
> +		IBPANIC("Internal error");
> +	return retval;
> +}
> +
> +static int get_spine_index(ibnd_node_t *node)
> +{
> +	int retval;
> +
> +	if (is_spine_9288(CONV_NODE_INTERNAL(node)) || is_spine_2012(CONV_NODE_INTERNAL(node)))
> +		retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum;
> +	else
> +		retval = node->ch_slotnum;
> +
> +	if (retval > SPINES_MAX_NUM || retval < 1)
> +		IBPANIC("Internal error");
> +	return retval;
> +}
> +
> +static void insert_line_router(ibnd_node_t *node, ibnd_chassis_t *chassis)
> +{
> +	int i = get_line_index(node);
> +
> +	if (chassis->linenode[i])
> +		return;		/* already filled slot */
> +
> +	chassis->linenode[i] = node;
> +	node->chassis = chassis;
> +}
> +
> +static void insert_spine(ibnd_node_t *node, ibnd_chassis_t *chassis)
> +{
> +	int i = get_spine_index(node);
> +
> +	if (chassis->spinenode[i])
> +		return;		/* already filled slot */
> +
> +	chassis->spinenode[i] = node;
> +	node->chassis = chassis;
> +}
> +
> +static void pass_on_lines_catch_spines(ibnd_chassis_t *chassis)
> +{
> +	ibnd_node_t *node, *remnode;
> +	ibnd_port_t *port;
> +	int i, p;
> +
> +	for (i = 1; i <= LINES_MAX_NUM; i++) {
> +		node = chassis->linenode[i];
> +
> +		if (!(node && is_line(CONV_NODE_INTERNAL(node))))
> +			continue;	/* empty slot or router */
> +
> +		for (p = 1; p <= node->info.numports; p++) {
> +			port = node->ports[p];
> +			if (!port || port->portnum > 12 || !port->remoteport)
> +				continue;
> +
> +			remnode = port->remoteport->node;
> +
> +			if (!CONV_NODE_INTERNAL(remnode)->ch_found)
> +				continue;	/* some error - spine not initialized ? FIXME */
> +			insert_spine(remnode, chassis);
> +		}
> +	}
> +}
> +
> +static void pass_on_spines_catch_lines(ibnd_chassis_t *chassis)
> +{
> +	ibnd_node_t *node, *remnode;
> +	ibnd_port_t *port;
> +	int i, p;
> +
> +	for (i = 1; i <= SPINES_MAX_NUM; i++) {
> +		node = chassis->spinenode[i];
> +		if (!node)
> +			continue;	/* empty slot */
> +		for (p = 1; p <= node->info.numports; p++) {
> +			port = node->ports[p];
> +			if (!port || !port->remoteport)
> +				continue;
> +			remnode = port->remoteport->node;
> +
> +			if (!CONV_NODE_INTERNAL(remnode)->ch_found)
> +				continue;	/* some error - line/router not initialized ? FIXME */
> +			insert_line_router(remnode, chassis);
> +		}
> +	}
> +}
> +
> +/*
> +	Stupid interpolation algorithm...
> +	But nothing to do - have to be compliant with VoltaireSM/NMS
> +*/
> +static void pass_on_spines_interpolate_chguid(ibnd_chassis_t *chassis)
> +{
> +	ibnd_node_t *node;
> +	int i;
> +
> +	for (i = 1; i <= SPINES_MAX_NUM; i++) {
> +		node = chassis->spinenode[i];
> +		if (!node)
> +			continue;	/* skip the empty slots */
> +
> +		/* take first guid minus one to be consistent with SM */
> +		chassis->chassisguid = node->info.nodeguid - 1;
> +		break;
> +	}
> +}
> +
> +/*
> +	This function fills chassis structure with all nodes
> +	in that chassis
> +	chassis structure = structure of one standalone chassis
> +*/
> +static void build_chassis(struct ibnd_node *node, ibnd_chassis_t *chassis)
> +{
> +	int p = 0;
> +	struct ibnd_node *remnode = 0;
> +	ibnd_port_t *port = 0;
> +
> +	/* we get here with node = chassis_spine */
> +	insert_spine((ibnd_node_t *)node, chassis);
> +
> +	/* loop: pass on all ports of node */
> +	for (p = 1; p <= node->node.info.numports; p++ ) {
> +		port = node->node.ports[p];
> +		if (!port || !port->remoteport)
> +			continue;
> +		remnode = CONV_NODE_INTERNAL(port->remoteport->node);
> +
> +		if (!remnode->ch_found)
> +			continue; /* some error - line or router not initialized ? FIXME */
> +
> +		insert_line_router(&(remnode->node), chassis);
> +	}
> +
> +	pass_on_lines_catch_spines(chassis);
> +	/* this pass needed for to catch routers, since routers connected only */
> +	/* to spines in slot 1 or 4 and we could miss them first time */
> +	pass_on_spines_catch_lines(chassis);
> +
> +	/* additional 2 passes needed for to overcome a problem of pure "in-chassis" */
> +	/* connectivity - extra pass to ensure that all related chips/modules */
> +	/* inserted into the chassis */
> +	pass_on_lines_catch_spines(chassis);
> +	pass_on_spines_catch_lines(chassis);
> +	pass_on_spines_interpolate_chguid(chassis);
> +}
> +
> +/*========================================================*/
> +/*                INTERNAL TO EXTERNAL PORT MAPPING       */
> +/*========================================================*/
> +
> +/*
> +Description : On ISR9288/9096 external ports indexing
> +              is not matching the internal ( anafa ) port
> +              indexes. Use this MAP to translate the data you get from
> +              the OpenIB diagnostics (smpquery, ibroute, ibtracert, etc.)
> +
> +
> +Module : sLB-24
> +                anafa 1             anafa 2
> +ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24
> +int port | 22 23 24 18 17 16 | 22 23 24 18 17 16
> +ext port | 1  2  3  4  5  6  | 7  8  9  10 11 12
> +int port | 19 20 21 15 14 13 | 19 20 21 15 14 13
> +------------------------------------------------
> +
> +Module : sLB-8
> +                anafa 1             anafa 2
> +ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24
> +int port | 24 23 22 18 17 16 | 24 23 22 18 17 16
> +ext port | 1  2  3  4  5  6  | 7  8  9  10 11 12
> +int port | 21 20 19 15 14 13 | 21 20 19 15 14 13
> +
> +----------->
> +                anafa 1             anafa 2
> +ext port | -  -  5  -  -  6  | -  -  7  -  -  8
> +int port | 24 23 22 18 17 16 | 24 23 22 18 17 16
> +ext port | -  -  1  -  -  2  | -  -  3  -  -  4
> +int port | 21 20 19 15 14 13 | 21 20 19 15 14 13
> +------------------------------------------------
> +
> +Module : sLB-2024
> +
> +ext port | 13 14 15 16 17 18 19 20 21 22 23 24
> +A1 int port| 13 14 15 16 17 18 19 20 21 22 23 24
> +ext port | 1 2 3 4 5 6 7 8 9 10 11 12
> +A2 int port| 13 14 15 16 17 18 19 20 21 22 23 24
> +---------------------------------------------------
> +
> +*/
> +
> +int int2ext_map_slb24[2][25] = {
> +					{ 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 },
> +					{ 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 }
> +				};
> +int int2ext_map_slb8[2][25] = {
> +					{ 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 },
> +					{ 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 }
> +				};
> +int int2ext_map_slb2024[2][25] = {
> +					{ 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 },
> +					{ 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 }
> +				};
> +/*	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 }; */
> +
> +/* map internal ports to external ports if appropriate */
> +static void
> +voltaire_portmap(ibnd_port_t *port)
> +{
> +	struct ibnd_node *n = CONV_NODE_INTERNAL(port->node);
> +	int portnum = port->portnum;
> +	int chipnum = 0;
> +	ibnd_node_t *node = port->node;
> +
> +	if (!n->ch_found || !is_line(CONV_NODE_INTERNAL(node)) || (portnum < 13 || portnum > 24)) {
> +		port->ext_portnum = 0;
> +		return;
> +	}
> +
> +	if (port->node->ch_anafanum < 1 || port->node->ch_anafanum > 2) {
> +		port->ext_portnum = 0;
> +		return;
> +	}
> +
> +	chipnum = port->node->ch_anafanum - 1;
> +
> +	if (is_line_24(CONV_NODE_INTERNAL(node)))
> +		port->ext_portnum = int2ext_map_slb24[chipnum][portnum];
> +	else if (is_line_2024(CONV_NODE_INTERNAL(node)))
> +		port->ext_portnum = int2ext_map_slb2024[chipnum][portnum];
> +	else
> +		port->ext_portnum = int2ext_map_slb8[chipnum][portnum];
> +}
> +
> +static void add_chassis(struct ibnd_fabric *fabric)
> +{
> +	if (!(fabric->current_chassis = calloc(1, sizeof(ibnd_chassis_t))))
> +		IBPANIC("out of mem");
> +
> +	if (fabric->first_chassis == NULL) {
> +		fabric->first_chassis = fabric->current_chassis;
> +		fabric->last_chassis = fabric->current_chassis;
> +	} else {
> +		fabric->last_chassis->next = fabric->current_chassis;
> +		fabric->last_chassis = fabric->current_chassis;
> +	}
> +}
> +
> +static void
> +add_node_to_chassis(ibnd_chassis_t *chassis, ibnd_node_t *node)
> +{
> +	node->chassis = chassis;
> +	node->next_chassis_node = chassis->nodes;
> +	chassis->nodes = node;
> +}
> +
> +/*
> +	Main grouping function
> +	Algorithm:
> +	1. pass on every Voltaire node
> +	2. catch spine chip for every Voltaire node
> +		2.1 build/interpolate chassis around this chip
> +		2.2 go to 1.
> +	3. pass on non Voltaire nodes (SystemImageGUID based grouping)
> +	4. now group non Voltaire nodes by SystemImageGUID
> +	Returns:
> +	Pointer to the first chassis in a NULL terminated list of chassis in
> +	the fabric specified.
> +*/
> +ibnd_chassis_t *group_nodes(struct ibnd_fabric *fabric)
> +{
> +	struct ibnd_node *node;
> +	int dist;
> +	int chassisnum = 0;
> +	ibnd_chassis_t *chassis;
> +
> +	fabric->first_chassis = NULL;
> +	fabric->current_chassis = NULL;
> +
> +	/* first pass on switches and build for every Voltaire node */
> +	/* an appropriate chassis record (slotnum and position) */
> +	/* according to internal connectivity */
> +	/* not very efficient but clear code so... */
> +	for (dist = 0; dist <= fabric->fabric.maxhops_discovered; dist++) {
> +		for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
> +			if (node->node.info.vendid == VTR_VENDOR_ID)
> +				fill_voltaire_chassis_record(node);
> +		}
> +	}
> +
> +	/* separate every Voltaire chassis from each other and build linked list of them */
> +	/* algorithm: catch spine and find all surrounding nodes */
> +	for (dist = 0; dist <= fabric->fabric.maxhops_discovered; dist++) {
> +		for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
> +			if (node->node.info.vendid != VTR_VENDOR_ID)
> +				continue;
> +			//if (!node->node.chrecord || node->node.chrecord->chassisnum || !is_spine(node))
> +			if (!node->ch_found
> +					|| (node->node.chassis && node->node.chassis->chassisnum)
> +					|| !is_spine(node))
> +				continue;
> +			add_chassis(fabric);
> +			fabric->current_chassis->chassisnum = ++chassisnum;
> +			build_chassis(node, fabric->current_chassis);
> +		}
> +	}
> +
> +	/* now make pass on nodes for chassis which are not Voltaire */
> +	/* grouped by common SystemImageGUID */
> +	for (dist = 0; dist <= fabric->fabric.maxhops_discovered; dist++) {
> +		for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
> +			if (node->node.info.vendid == VTR_VENDOR_ID)
> +				continue;
> +			if (node->node.info.sysimgguid) {
> +				chassis = find_chassisguid((ibnd_node_t *)node);
> +				if (chassis)
> +					chassis->nodecount++;
> +				else {
> +					/* Possible new chassis */
> +					add_chassis(fabric);
> +					fabric->current_chassis->chassisguid =
> +							get_chassisguid((ibnd_node_t *)node);
> +					fabric->current_chassis->nodecount = 1;
> +				}
> +			}
> +		}
> +	}
> +
> +	/* now, make another pass to see which nodes are part of chassis */
> +	/* (defined as chassis->nodecount > 1) */
> +	for (dist = 0; dist <= MAXHOPS; ) {
> +		for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
> +			if (node->node.info.vendid == VTR_VENDOR_ID)
> +				continue;
> +			if (node->node.info.sysimgguid) {
> +				chassis = find_chassisguid((ibnd_node_t *)node);
> +				if (chassis && chassis->nodecount > 1) {
> +					if (!chassis->chassisnum)
> +						chassis->chassisnum = ++chassisnum;
> +					if (!node->ch_found) {
> +						node->ch_found = 1;
> +						add_node_to_chassis(chassis, (ibnd_node_t *)node);
> +					}
> +				}
> +			}
> +		}
> +		if (dist == fabric->fabric.maxhops_discovered)
> +			dist = MAXHOPS;	/* skip to CAs */
> +		else
> +			dist++;
> +	}
> +
> +	return (fabric->first_chassis);
> +}
> diff --git a/infiniband-diags/libibnetdisc/src/chassis.h b/infiniband-diags/libibnetdisc/src/chassis.h
> new file mode 100644
> index 0000000..16dad49
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/src/chassis.h
> @@ -0,0 +1,85 @@
> +/*
> + * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
> + * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
> + *
> + * This software is available to you under a choice of one of two
> + * licenses.  You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + *     Redistribution and use in source and binary forms, with or
> + *     without modification, are permitted provided that the following
> + *     conditions are met:
> + *
> + *      - Redistributions of source code must retain the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer.
> + *
> + *      - Redistributions in binary form must reproduce the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer in the documentation and/or other materials
> + *        provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + *
> + */
> +
> +#ifndef _CHASSIS_H_
> +#define _CHASSIS_H_
> +
> +#include <infiniband/ibnetdisc.h>
> +
> +#include "internal.h"
> +
> +/*========================================================*/
> +/*                CHASSIS RECOGNITION SPECIFIC DATA       */
> +/*========================================================*/
> +
> +/* Device IDs */
> +#define VTR_DEVID_IB_FC_ROUTER		0x5a00
> +#define VTR_DEVID_IB_IP_ROUTER		0x5a01
> +#define VTR_DEVID_ISR9600_SPINE		0x5a02
> +#define VTR_DEVID_ISR9600_LEAF		0x5a03
> +#define VTR_DEVID_HCA1			0x5a04
> +#define VTR_DEVID_HCA2			0x5a44
> +#define VTR_DEVID_HCA3			0x6278
> +#define VTR_DEVID_SW_6IB4		0x5a05
> +#define VTR_DEVID_ISR9024		0x5a06
> +#define VTR_DEVID_ISR9288		0x5a07
> +#define VTR_DEVID_SLB24			0x5a09
> +#define VTR_DEVID_SFB12			0x5a08
> +#define VTR_DEVID_SFB4			0x5a0b
> +#define VTR_DEVID_ISR9024_12		0x5a0c
> +#define VTR_DEVID_SLB8			0x5a0d
> +#define VTR_DEVID_RLX_SWITCH_BLADE	0x5a20
> +#define VTR_DEVID_ISR9024_DDR		0x5a31
> +#define VTR_DEVID_SFB12_DDR		0x5a32
> +#define VTR_DEVID_SFB4_DDR		0x5a33
> +#define VTR_DEVID_SLB24_DDR		0x5a34
> +#define VTR_DEVID_SFB2012		0x5a37
> +#define VTR_DEVID_SLB2024		0x5a38
> +#define VTR_DEVID_ISR2012		0x5a39
> +#define VTR_DEVID_SFB2004		0x5a40
> +#define VTR_DEVID_ISR2004		0x5a41
> +#define VTR_DEVID_SRB2004		0x5a42
> +
> +/* Vendor IDs (for chassis based systems) */
> +#define VTR_VENDOR_ID			0x8f1	/* Voltaire */
> +#define TS_VENDOR_ID			0x5ad	/* Cisco */
> +#define SS_VENDOR_ID			0x66a	/* InfiniCon */
> +#define XS_VENDOR_ID			0x1397	/* Xsigo */
> +
> +enum ibnd_chassis_type { UNRESOLVED_CT, ISR9288_CT, ISR9096_CT, ISR2012_CT, ISR2004_CT };
> +enum ibnd_chassis_slot_type { UNRESOLVED_CS, LINE_CS, SPINE_CS, SRBD_CS };
> +
> +ibnd_chassis_t *group_nodes(struct ibnd_fabric *fabric);
> +
> +#endif	/* _CHASSIS_H_ */
> diff --git a/infiniband-diags/libibnetdisc/src/ibnetdisc.c b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
> new file mode 100644
> index 0000000..64e4ece
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
> @@ -0,0 +1,872 @@
> +/*
> + * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
> + * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
> + * Copyright (c) 2008 Lawrence Livermore National Laboratory
> + *
> + * This software is available to you under a choice of one of two
> + * licenses.  You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + *     Redistribution and use in source and binary forms, with or
> + *     without modification, are permitted provided that the following
> + *     conditions are met:
> + *
> + *      - Redistributions of source code must retain the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer.
> + *
> + *      - Redistributions in binary form must reproduce the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer in the documentation and/or other materials
> + *        provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + *
> + */
> +
> +#if HAVE_CONFIG_H
> +#  include <config.h>
> +#endif /* HAVE_CONFIG_H */
> +
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <stdarg.h>
> +#include <time.h>
> +#include <string.h>
> +#include <getopt.h>
> +#include <errno.h>
> +#include <inttypes.h>
> +
> +#include <infiniband/common.h>
> +#include <infiniband/umad.h>
> +#include <infiniband/mad.h>
> +
> +#include <infiniband/ibnetdisc.h>
> +#include <complib/cl_nodenamemap.h>
> +
> +#include "internal.h"
> +#include "chassis.h"
> +
> +static int timeout_ms = 2000;
> +static int show_progress = 0;
> +
> +static char *linkwidth_str[] = {
> +	"??",
> +	"1x",
> +	"4x",
> +	"??",
> +	"8x",
> +	"??",
> +	"??",
> +	"??",
> +	"12x"
> +};
> +
> +static char *linkspeed_str[] = {
> +	"???",
> +	"SDR",
> +	"DDR",
> +	"???",
> +	"QDR"
> +};
> +
> +static char *linkspeed_datarate_str[] = {
> +	"???",
> +	"2.5 Gbps",
> +	"5.0 Gbps",
> +	"???",
> +	"10.0 Gbps"
> +};
> +
> +static char *linkstate_str[] = {
> +	"No State",
> +	"Down",
> +	"Init",
> +	"Armed",
> +	"Active"
> +};
> +
> +static char *physstate_str[] = {
> +	"No State",
> +	"Sleep",
> +	"Polling",
> +	"Disabled",
> +	"PortConfigTraining",
> +	"LinkUp",
> +	"LinkErrorRecovery",
> +	"Phy Test"
> +};
> +
> +char *
> +ibnd_linkwidth_str(int link_width)
> +{
> +	if (link_width > 8)
> +		return linkwidth_str[0];
> +	else
> +		return linkwidth_str[link_width];
> +}
> +
> +char *
> +ibnd_linkspeed_str(int link_speed, int data_rate)
> +{
> +	if (link_speed > 4)
> +		return linkspeed_str[0];
> +	else if (data_rate)
> +		return linkspeed_datarate_str[link_speed];
> +	else
> +		return linkspeed_str[link_speed];
> +}
> +char *
> +ibnd_linkstate_str(int link_state)
> +{
> +	if (link_state > 4)
> +		return linkstate_str[0];
> +	else
> +		return linkstate_str[link_state];
> +}
> +
> +char *
> +ibnd_physstate_str(int phys_state)
> +{
> +	if (phys_state > 7)
> +		return physstate_str[0];
> +	else
> +		return physstate_str[phys_state];
> +}
> +
> +void
> +decode_port_info(void * rcv_buf, ibnd_port_info_t *pi)
> +{
> +	mad_decode_field(rcv_buf, IB_PORT_LID_F, &pi->lid);
> +	mad_decode_field(rcv_buf, IB_PORT_SMLID_F, &pi->smlid);
> +
> +	mad_decode_field(rcv_buf, IB_PORT_LINK_SPEED_SUPPORTED_F, &pi->link_speed_supported);
> +	mad_decode_field(rcv_buf, IB_PORT_LINK_SPEED_ENABLED_F, &pi->link_speed_enabled);
> +	mad_decode_field(rcv_buf, IB_PORT_LINK_SPEED_ACTIVE_F, &pi->link_speed_active);
> +
> +	mad_decode_field(rcv_buf, IB_PORT_LOCAL_PORT_F, &pi->local_port);
> +	mad_decode_field(rcv_buf, IB_PORT_LINK_WIDTH_SUPPORTED_F, &pi->link_width_supported);
> +	mad_decode_field(rcv_buf, IB_PORT_LINK_WIDTH_ENABLED_F, &pi->link_width_enabled);
> +
> +	mad_decode_field(rcv_buf, IB_PORT_LINK_WIDTH_ACTIVE_F, &pi->link_width_active);
> +
> +	mad_decode_field(rcv_buf, IB_PORT_DIAG_F, &pi->diag_code);
> +	mad_decode_field(rcv_buf, IB_PORT_MKEY_LEASE_F, &pi->mkey_lease);
> +	mad_decode_field(rcv_buf, IB_PORT_CAPMASK_F, &pi->capability_mask);
> +	mad_decode_field(rcv_buf, IB_PORT_MKEY_F, &pi->mkey);
> +	mad_decode_field(rcv_buf, IB_PORT_GID_PREFIX_F, &pi->gid_prefix);
> +
> +	mad_decode_field(rcv_buf, IB_PORT_STATE_F, &pi->link_state);
> +	mad_decode_field(rcv_buf, IB_PORT_PHYS_STATE_F, &pi->phys_state);
> +
> +	mad_decode_field(rcv_buf, IB_PORT_LINK_DOWN_DEF_F, &pi->link_down_def_state);
> +	mad_decode_field(rcv_buf, IB_PORT_MKEY_PROT_BITS_F, &pi->mkey_prot_bits);
> +
> +	mad_decode_field(rcv_buf, IB_PORT_LMC_F, &pi->lmc);
> +	mad_decode_field(rcv_buf, IB_PORT_NEIGHBOR_MTU_F, &pi->neighbor_mtu);
> +	mad_decode_field(rcv_buf, IB_PORT_SMSL_F, &pi->smsl);
> +	mad_decode_field(rcv_buf, IB_PORT_INIT_TYPE_F, &pi->init_type);
> +
> +	mad_decode_field(rcv_buf, IB_PORT_VL_CAP_F, &pi->vl_capability);
> +	mad_decode_field(rcv_buf, IB_PORT_VL_HIGH_LIMIT_F, &pi->vl_high_limit);
> +	mad_decode_field(rcv_buf, IB_PORT_VL_ARBITRATION_HIGH_CAP_F, &pi->vl_arb_high_cap);
> +	mad_decode_field(rcv_buf, IB_PORT_VL_ARBITRATION_LOW_CAP_F, &pi->vl_arb_low_cap);
> +
> +	mad_decode_field(rcv_buf, IB_PORT_INIT_TYPE_REPLY_F, &pi->init_reply);
> +	mad_decode_field(rcv_buf, IB_PORT_MTU_CAP_F, &pi->mtu_cap);
> +	mad_decode_field(rcv_buf, IB_PORT_VL_STALL_COUNT_F, &pi->vl_stall_count);
> +	mad_decode_field(rcv_buf, IB_PORT_HOQ_LIFE_F, &pi->hoq_lifetime);
> +	mad_decode_field(rcv_buf, IB_PORT_OPER_VLS_F, &pi->oper_vls);
> +	mad_decode_field(rcv_buf, IB_PORT_PART_EN_INB_F, &pi->partition_enforce_in);
> +	mad_decode_field(rcv_buf, IB_PORT_PART_EN_OUTB_F, &pi->partition_enforce_out);
> +	mad_decode_field(rcv_buf, IB_PORT_FILTER_RAW_INB_F, &pi->filter_raw_in);
> +	mad_decode_field(rcv_buf, IB_PORT_FILTER_RAW_OUTB_F, &pi->filter_raw_out);
> +	mad_decode_field(rcv_buf, IB_PORT_MKEY_VIOL_F, &pi->mkey_violations);
> +	mad_decode_field(rcv_buf, IB_PORT_PKEY_VIOL_F, &pi->pkey_violations);
> +	mad_decode_field(rcv_buf, IB_PORT_QKEY_VIOL_F, &pi->qkey_violations);
> +
> +	mad_decode_field(rcv_buf, IB_PORT_GUID_CAP_F, &pi->guid_capabilities);
> +
> +	mad_decode_field(rcv_buf, IB_PORT_CLIENT_REREG_F, &pi->client_rereg);
> +	mad_decode_field(rcv_buf, IB_PORT_SUBN_TIMEOUT_F, &pi->subnet_timeout);
> +	mad_decode_field(rcv_buf, IB_PORT_RESP_TIME_VAL_F, &pi->response_time_val);
> +	mad_decode_field(rcv_buf, IB_PORT_LOCAL_PHYS_ERR_F, &pi->local_phys_error);
> +	mad_decode_field(rcv_buf, IB_PORT_OVERRUN_ERR_F, &pi->overrun_error);
> +	mad_decode_field(rcv_buf, IB_PORT_MAX_CREDIT_HINT_F, &pi->max_credit_hint);
> +	mad_decode_field(rcv_buf, IB_PORT_LINK_ROUND_TRIP_F, &pi->link_round_trip);
> +}
> +
> +static int
> +get_port_info(struct ibnd_fabric *fabric, struct ibnd_port *port,
> +		int portnum, ib_portid_t *portid)
> +{
> +	char portinfo[64];
> +	void *pi = portinfo;
> +
> +	port->port.portnum = portnum;
> +
> +	if (!smp_query_via(pi, portid, IB_ATTR_PORT_INFO, portnum, timeout_ms,
> +			fabric->ibmad_port))
> +		return -1;
> +
> +	decode_port_info(pi, &port->port.info);
> +
> +	IBND_DEBUG("portid %s portnum %d: lid %d state %d physstate %d %s %s\n",
> +		portid2str(portid), portnum, port->port.info.lid, port->port.info.link_state,
> +		port->port.info.phys_state, ibnd_linkwidth_str(port->port.info.link_width_active),
> +		ibnd_linkspeed_str(port->port.info.link_speed_active, 0));
> +	return 1;
> +}
> +
> +static void
> +decode_node_info(void * rcv_buf, ibnd_node_info_t *ni)
> +{
> +	mad_decode_field(rcv_buf, IB_NODE_BASE_VERS_F, &ni->base_ver);
> +	mad_decode_field(rcv_buf, IB_NODE_CLASS_VERS_F, &ni->class_ver);
> +	mad_decode_field(rcv_buf, IB_NODE_TYPE_F, &ni->type);
> +	mad_decode_field(rcv_buf, IB_NODE_NPORTS_F, &ni->numports);
> +	mad_decode_field(rcv_buf, IB_NODE_SYSTEM_GUID_F, &ni->sysimgguid);
> +	mad_decode_field(rcv_buf, IB_NODE_GUID_F, &ni->nodeguid);
> +	mad_decode_field(rcv_buf, IB_NODE_PORT_GUID_F, &ni->nodeportguid);
> +	mad_decode_field(rcv_buf, IB_NODE_PARTITION_CAP_F, &ni->partition_cap);
> +	mad_decode_field(rcv_buf, IB_NODE_DEVID_F, &ni->devid);
> +	mad_decode_field(rcv_buf, IB_NODE_REVISION_F, &ni->revision);
> +	mad_decode_field(rcv_buf, IB_NODE_LOCAL_PORT_F, &ni->localport);
> +	mad_decode_field(rcv_buf, IB_NODE_VENDORID_F, &ni->vendid);
> +}
> +
> +/*
> + * Returns -1 if error.
> + */
> +static int
> +query_node_info(struct ibnd_fabric *fabric, struct ibnd_node *node, ib_portid_t *portid)
> +{
> +	char nodeinfo[64];
> +	void *ni = nodeinfo;
> +	if (!smp_query_via(ni, portid, IB_ATTR_NODE_INFO, 0, timeout_ms,
> +			fabric->ibmad_port))
> +		return -1;
> +	decode_node_info(ni, &(node->node.info));
> +	return (0);
> +}
> +
> +/*
> + * Returns 0 if non switch node is found, 1 if switch is found, -1 if error.
> + */
> +static int
> +query_node(struct ibnd_fabric *fabric, struct ibnd_node *inode,
> +		struct ibnd_port *iport, ib_portid_t *portid)
> +{
> +	char portinfo[64];
> +	void *pi = portinfo;
> +	char switchinfo[64];
> +	void *si = switchinfo;
> +	ibnd_node_t *node = &(inode->node);
> +	ibnd_port_t *port = &(iport->port);
> +	void *nd = inode->node.nodedesc;
> +
> +	if (query_node_info(fabric, inode, portid))
> +		return -1;
> +
> +	port->portnum = node->info.localport;
> +	port->guid = node->info.nodeportguid;
> +
> +	if (!smp_query_via(nd, portid, IB_ATTR_NODE_DESC, 0, timeout_ms,
> +			fabric->ibmad_port))
> +		return -1;
> +
> +	if (!smp_query_via(pi, portid, IB_ATTR_PORT_INFO, 0, timeout_ms,
> +			fabric->ibmad_port))
> +		return -1;
> +	decode_port_info(pi, &port->info);
> +
> +	if (node->info.type != IBND_SWITCH_NODE)
> +		return 0;
> +
> +	node->smalid = port->info.lid;
> +	node->smalmc = port->info.lmc;
> +
> +	/* after we have the sma information find out the real PortInfo for this port */
> +	if (!smp_query_via(pi, portid, IB_ATTR_PORT_INFO, node->info.localport, timeout_ms,
> +			fabric->ibmad_port))
> +		return -1;
> +	decode_port_info(pi, &port->info);
> +
> +        if (!smp_query_via(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout_ms,
> +			fabric->ibmad_port))
> +                node->sw_info.smaenhsp0 = 0;	/* assume base SP0 */
> +	else
> +		mad_decode_field(si, IB_SW_ENHANCED_PORT0_F, &node->sw_info.smaenhsp0);
> +
> +	IBND_DEBUG("portid %s: got switch node %" PRIx64 " '%s'\n",
> +	      portid2str(portid), node->info.nodeguid, node->nodedesc);
> +	return 1;
> +}
> +
> +static int
> +add_port_to_dpath(ib_dr_path_t *path, int nextport)
> +{
> +	if (path->cnt+2 >= sizeof(path->p))
> +		return -1;
> +	++path->cnt;
> +	path->p[path->cnt] = nextport;
> +	return path->cnt;
> +}
> +
> +static int
> +extend_dpath(struct ibnd_fabric *f, ib_dr_path_t *path, int nextport)
> +{
> +	int rc = add_port_to_dpath(path, nextport);
> +	if ((rc != -1) && (path->cnt > f->fabric.maxhops_discovered))
> +		f->fabric.maxhops_discovered = path->cnt;
> +	return (rc);
> +}
> +
> +static void
> +dump_endnode(ib_portid_t *path, char *prompt,
> +		struct ibnd_node *node, struct ibnd_port *port)
> +{
> +	if (!show_progress)
> +		return;
> +
> +	printf("%s -> %s %s {%016" PRIx64 "} portnum %d lid %d-%d\"%s\"\n",
> +		portid2str(path), prompt,
> +		ibnd_node_type_str((ibnd_node_t *)node),
> +		node->node.info.nodeguid,
> +		node->node.info.type == IBND_SWITCH_NODE ? 0 : port->port.portnum,
> +		port->port.info.lid, port->port.info.lid + (1 << port->port.info.lmc) - 1,
> +		node->node.nodedesc);
> +}
> +
> +static struct ibnd_node *
> +find_existing_node(struct ibnd_fabric *fabric, struct ibnd_node *new)
> +{
> +	int hash = HASHGUID(new->node.info.nodeguid) % HTSZ;
> +	struct ibnd_node *node;
> +
> +	for (node = fabric->nodestbl[hash]; node; node = node->htnext)
> +		if (node->node.info.nodeguid == new->node.info.nodeguid)
> +			return node;
> +
> +	return NULL;
> +}
> +
> +ibnd_node_t *
> +ibnd_find_node_guid(ibnd_fabric_t *fabric, uint64_t guid)
> +{
> +	struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(fabric);
> +	int hash = HASHGUID(guid) % HTSZ;
> +	struct ibnd_node *node;
> +
> +	for (node = f->nodestbl[hash]; node; node = node->htnext)
> +		if (node->node.info.nodeguid == guid)
> +			return (ibnd_node_t *)node;
> +
> +	return NULL;
> +}
> +
> +ibnd_node_t *
> +ibnd_update_node(ibnd_node_t *node)
> +{
> +	char portinfo[64];
> +	void *pi = portinfo;
> +	ibnd_port_info_t port0_info;
> +	char switchinfo[64];
> +	void *si = switchinfo;
> +	void *nd = node->nodedesc;
> +	int p = 0;
> +	struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(node->fabric);
> +	struct ibnd_node *n = CONV_NODE_INTERNAL(node);
> +
> +	if (query_node_info(f, n, &(n->node.path_portid)))
> +		return (NULL);
> +
> +	if (!smp_query_via(nd, &(n->node.path_portid), IB_ATTR_NODE_DESC, 0, timeout_ms,
> +			f->ibmad_port))
> +		return (NULL);
> +
> +	/* update all the port info's */
> +	for (p = 1; p >= n->node.info.numports; p++) {
> +		get_port_info(f, CONV_PORT_INTERNAL(n->node.ports[p]), p, &(n->node.path_portid));
> +	}
> +
> +	if (n->node.info.type != IBND_SWITCH_NODE)
> +		goto done;
> +
> +	if (!smp_query_via(pi, &(n->node.path_portid), IB_ATTR_PORT_INFO, 0, timeout_ms,
> +			f->ibmad_port))
> +		return (NULL);
> +	decode_port_info(pi, &port0_info);
> +
> +	n->node.smalid = port0_info.lid;
> +	n->node.smalmc = port0_info.lmc;
> +
> +        if (!smp_query_via(si, &(n->node.path_portid), IB_ATTR_SWITCH_INFO, 0, timeout_ms,
> +			f->ibmad_port))
> +                node->sw_info.smaenhsp0 = 0;	/* assume base SP0 */
> +	else
> +		mad_decode_field(si, IB_SW_ENHANCED_PORT0_F, &n->node.sw_info.smaenhsp0);
> +
> +done:
> +	return (node);
> +}
> +
> +ibnd_node_t *
> +ibnd_find_node_dr(ibnd_fabric_t *fabric, char *dr_str)
> +{
> +	struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(fabric);
> +	int i = 0;
> +	ibnd_node_t *rc = f->fabric.from_node;
> +	ib_dr_path_t path;
> +
> +	if (str2drpath(&path, dr_str, 0, 0) == -1) {
> +		return (NULL);
> +	}
> +
> +	for (i = 0; i <= path.cnt; i++) {
> +		ibnd_port_t *remote_port = NULL;
> +		if (path.p[i] == 0)
> +			continue;
> +		if (!rc->ports)
> +			return (NULL);
> +
> +		remote_port = rc->ports[path.p[i]]->remoteport;
> +		if (!remote_port)
> +			return (NULL);
> +
> +		rc = remote_port->node;
> +	}
> +
> +	return (rc);
> +}
> +
> +static void
> +add_to_nodeguid_hash(struct ibnd_node *node, struct ibnd_node *hash[])
> +{
> +	int hash_idx = HASHGUID(node->node.info.nodeguid) % HTSZ;
> +
> +	node->htnext = hash[hash_idx];
> +	hash[hash_idx] = node;
> +}
> +
> +static void
> +add_to_portguid_hash(struct ibnd_port *port, struct ibnd_port *hash[])
> +{
> +	int hash_idx = HASHGUID(port->port.guid) % HTSZ;
> +
> +	port->htnext = hash[hash_idx];
> +	hash[hash_idx] = port;
> +}
> +
> +static void
> +add_to_type_list(struct ibnd_node*node, struct ibnd_fabric *fabric)
> +{
> +	switch (node->node.info.type) {
> +		case IBND_CA_NODE:
> +			node->type_next = fabric->ch_adapters;
> +			fabric->ch_adapters = node;
> +			break;
> +		case IBND_SWITCH_NODE:
> +			node->type_next = fabric->switches;
> +			fabric->switches = node;
> +			break;
> +		case IBND_ROUTER_NODE:
> +			node->type_next = fabric->routers;
> +			fabric->routers = node;
> +			break;
> +	}
> +}
> +
> +static void
> +add_to_nodedist(struct ibnd_node *node, struct ibnd_fabric *fabric)
> +{
> +	int dist = node->node.dist;
> +	if (node->node.info.type != IBND_SWITCH_NODE)
> +			dist = MAXHOPS; 	/* special Ca list */
> +
> +	node->dnext = fabric->nodesdist[dist];
> +	fabric->nodesdist[dist] = node;
> +}
> +
> +
> +static struct ibnd_node *
> +create_node(struct ibnd_fabric *fabric, struct ibnd_node *temp, ib_portid_t *path, int dist)
> +{
> +	struct ibnd_node *node;
> +
> +	node = malloc(sizeof(*node));
> +	if (!node) {
> +		IBPANIC("OOM: node creation failed\n");
> +		return NULL;
> +	}
> +
> +	memcpy(node, temp, sizeof(*node));
> +	node->node.dist = dist;
> +	node->node.path_portid = *path;
> +	node->node.fabric = (ibnd_fabric_t *)fabric;
> +
> +	add_to_nodeguid_hash(node, fabric->nodestbl);
> +
> +	/* add this to the all nodes list */
> +	node->node.next = fabric->fabric.nodes;
> +	fabric->fabric.nodes = (ibnd_node_t *)node;
> +
> +	add_to_type_list(node, fabric);
> +	add_to_nodedist(node, fabric);
> +
> +	return node;
> +}
> +
> +static struct ibnd_port *
> +find_existing_port_node(struct ibnd_node *node, struct ibnd_port *port)
> +{
> +	if (port->port.portnum > node->node.info.numports || node->node.ports == NULL )
> +		return (NULL);
> +
> +	return (CONV_PORT_INTERNAL(node->node.ports[port->port.portnum]));
> +}
> +
> +static struct ibnd_port *
> +add_port_to_node(struct ibnd_fabric *fabric, struct ibnd_node *node, struct ibnd_port *temp)
> +{
> +	struct ibnd_port *port;
> +
> +	port = malloc(sizeof(*port));
> +	if (!port)
> +		return NULL;
> +
> +	memcpy(port, temp, sizeof(*port));
> +	port->port.node = (ibnd_node_t *)node;
> +	port->port.ext_portnum = 0;
> +
> +	if (node->node.ports == NULL) {
> +		node->node.ports = calloc(sizeof(*node->node.ports), node->node.info.numports + 1);
> +		if (!node->node.ports) {
> +			IBND_ERROR("Failed to allocate the ports array\n");
> +			return (NULL);
> +		}
> +	}
> +
> +	node->node.ports[temp->port.portnum] = (ibnd_port_t *)port;
> +
> +	add_to_portguid_hash(port, fabric->portstbl);
> +	return port;
> +}
> +
> +static void
> +link_ports(struct ibnd_node *node, struct ibnd_port *port,
> +		struct ibnd_node *remotenode, struct ibnd_port *remoteport)
> +{
> +	IBND_DEBUG("linking: 0x%" PRIx64 " %p->%p:%u and 0x%" PRIx64 " %p->%p:%u\n",
> +		node->node.info.nodeguid, node, port, port->port.portnum,
> +		remotenode->node.info.nodeguid, remotenode,
> +		remoteport, remoteport->port.portnum);
> +	if (port->port.remoteport)
> +		port->port.remoteport->remoteport = NULL;
> +	if (remoteport->port.remoteport)
> +		remoteport->port.remoteport->remoteport = NULL;
> +	port->port.remoteport = (ibnd_port_t *)remoteport;
> +	remoteport->port.remoteport = (ibnd_port_t *)port;
> +}
> +
> +static int
> +get_remote_node(struct ibnd_fabric *fabric, struct ibnd_node *node, struct ibnd_port *port, ib_portid_t *path,
> +		int portnum, int dist)
> +{
> +	struct ibnd_node node_buf;
> +	struct ibnd_port port_buf;
> +	struct ibnd_node *remotenode, *oldnode;
> +	struct ibnd_port *remoteport, *oldport;
> +
> +	memset(&node_buf, 0, sizeof(node_buf));
> +	memset(&port_buf, 0, sizeof(port_buf));
> +
> +	IBND_DEBUG("handle node %p port %p:%d dist %d\n", node, port, portnum, dist);
> +	if (port->port.info.phys_state != 5)	/* LinkUp */
> +		return -1;
> +
> +	if (extend_dpath(fabric, &path->drpath, portnum) < 0)
> +		return -1;
> +
> +	if (query_node(fabric, &node_buf, &port_buf, path) < 0) {
> +		IBWARN("NodeInfo on %s failed, skipping port",
> +			portid2str(path));
> +		path->drpath.cnt--;	/* restore path */
> +		return -1;
> +	}
> +
> +	oldnode = find_existing_node(fabric, &node_buf);
> +	if (oldnode)
> +		remotenode = oldnode;
> +	else if (!(remotenode = create_node(fabric, &node_buf, path, dist + 1)))
> +		IBPANIC("no memory");
> +
> +	oldport = find_existing_port_node(remotenode, &port_buf);
> +	if (oldport) {
> +		remoteport = oldport;
> +	} else if (!(remoteport = add_port_to_node(fabric, remotenode, &port_buf)))
> +		IBPANIC("no memory");
> +
> +	dump_endnode(path, oldnode ? "known remote" : "new remote",
> +			remotenode, remoteport);
> +
> +	link_ports(node, port, remotenode, remoteport);
> +
> +	path->drpath.cnt--;	/* restore path */
> +	return 0;
> +}
> +
> +static void *
> +ibnd_init_port(char *dev_name, int dev_port)
> +{
> +	int mgmt_classes[2] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS};
> +
> +	/* Crank up the mad lib */
> +	return (mad_rpc_open_port(dev_name, dev_port, mgmt_classes, 2));
> +}
> +
> +ibnd_fabric_t *
> +ibnd_discover_fabric(char *dev_name, int dev_port, int timeout_ms,
> +			ib_portid_t *from, int hops)
> +{
> +	struct ibnd_fabric *fabric = NULL;
> +	ib_portid_t my_portid = {0};
> +	struct ibnd_node node_buf;
> +	struct ibnd_port port_buf;
> +	struct ibnd_node *node;
> +	struct ibnd_port *port;
> +	int i;
> +	int dist = 0;
> +	ib_portid_t *path;
> +	int max_hops = MAXHOPS-1; /* default find everything */
> +
> +	/* if not everything how much? */
> +	if (hops >= 0) {
> +		max_hops = hops;
> +	}
> +
> +	/* If not specified start from "my" port */
> +	if (!from) {
> +		from = &my_portid;
> +	}
> +
> +	fabric = malloc(sizeof(*fabric));
> +
> +	if (!fabric) {
> +		IBPANIC("OOM: failed to malloc ibnd_fabric_t\n");
> +		return (NULL);
> +	}
> +
> +	memset(fabric, 0, sizeof(*fabric));
> +
> +	fabric->ibmad_port = ibnd_init_port(dev_name, dev_port);
> +	if (!fabric->ibmad_port) {
> +		IBPANIC("OOM: failed to open \"%s\" port %d\n",
> +			dev_name, dev_port);
> +		goto error;
> +	}
> +
> +	IBND_DEBUG("from %s\n", portid2str(from));
> +
> +	memset(&node_buf, 0, sizeof(node_buf));
> +	memset(&port_buf, 0, sizeof(port_buf));
> +
> +	if (query_node(fabric, &node_buf, &port_buf, from) < 0) {
> +		IBWARN("can't reach node %s\n", portid2str(from));
> +		goto error;
> +	}
> +
> +	node = create_node(fabric, &node_buf, from, 0);
> +	if (!node)
> +		goto error;
> +
> +	fabric->fabric.from_node = (ibnd_node_t *)node;
> +
> +	port = add_port_to_node(fabric, node, &port_buf);
> +	if (!port)
> +		IBPANIC("out of memory");
> +
> +	if (node->node.info.type != IBND_SWITCH_NODE &&
> +	    get_remote_node(fabric, node, port, from, node->node.info.localport, 0) < 0)
> +		return ((ibnd_fabric_t *)fabric);
> +
> +	for (dist = 0; dist <= max_hops; dist++) {
> +
> +		for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
> +
> +			path = &node->node.path_portid;
> +
> +			IBND_DEBUG("dist %d node %p\n", dist, node);
> +			dump_endnode(path, "processing", node, port);
> +
> +			for (i = 1; i <= node->node.info.numports; i++) {
> +				if (i == node->node.info.localport)
> +					continue;
> +
> +				if (get_port_info(fabric, &port_buf, i, path) < 0) {
> +					IBWARN("can't reach node %s port %d", portid2str(path), i);
> +					continue;
> +				}
> +
> +				port = find_existing_port_node(node, &port_buf);
> +				if (port)
> +					continue;
> +
> +				port = add_port_to_node(fabric, node, &port_buf);
> +				if (!port)
> +					IBPANIC("out of memory");
> +
> +				/* If switch, set port GUID to node port GUID */
> +				if (node->node.info.type == IBND_SWITCH_NODE)
> +					port->port.guid = node->node.info.nodeportguid;
> +
> +				get_remote_node(fabric, node, port, path, i, dist);
> +			}
> +		}
> +	}
> +
> +	fabric->fabric.chassis = group_nodes(fabric);
> +
> +	return ((ibnd_fabric_t *)fabric);
> +error:
> +	free(fabric);
> +	return (NULL);
> +}
> +
> +static void
> +destroy_node(struct ibnd_node *node)
> +{
> +	int p = 0;
> +
> +	for (p = 0; p <= node->node.info.numports; p++) {
> +		free(node->node.ports[p]);
> +	}
> +	free(node->node.ports);
> +	free(node);
> +}
> +
> +void
> +ibnd_destroy_fabric(ibnd_fabric_t *fabric)
> +{
> +	struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(fabric);
> +	int dist = 0;
> +	struct ibnd_node *node = NULL;
> +	struct ibnd_node *next = NULL;
> +	ibnd_chassis_t *ch, *ch_next;
> +
> +	ch = f->first_chassis;
> +	while (ch) {
> +		ch_next = ch->next;
> +		free(ch);
> +		ch = ch_next;
> +	}
> +	for (dist = 0; dist <= MAXHOPS; dist++) {
> +		node = f->nodesdist[dist];
> +		while (node) {
> +			next = node->dnext;
> +			destroy_node(node);
> +			node = next;
> +		}
> +	}
> +	if (f->ibmad_port)
> +		mad_rpc_close_port(f->ibmad_port);
> +	free(f);
> +}
> +
> +void
> +ibnd_debug(int i)
> +{
> +	if (i) {
> +		ibdebug++;
> +		madrpc_show_errors(1);
> +		umad_debug(i);
> +	} else {
> +		ibdebug = 0;
> +		madrpc_show_errors(0);
> +		umad_debug(0);
> +	}
> +}
> +
> +void
> +ibnd_show_progress(int i)
> +{
> +	show_progress = i;
> +}
> +
> +const char*
> +ibnd_node_type_str(ibnd_node_t *node)
> +{
> +	switch(node->info.type) {
> +	case IBND_CA_NODE:     return "Ca";
> +	case IBND_SWITCH_NODE: return "Switch";
> +	case IBND_ROUTER_NODE: return "Router";
> +	}
> +	return "??";
> +}
> +
> +const char*
> +ibnd_node_type_str_short(ibnd_node_t *node)
> +{
> +	switch(node->info.type) {
> +	case IBND_SWITCH_NODE: return "SW";
> +	case IBND_CA_NODE:     return "CA";
> +	case IBND_ROUTER_NODE: return "RT";
> +	}
> +	return "??";
> +}
> +
> +
> +void
> +ibnd_iter_nodes(ibnd_fabric_t *fabric,
> +		ibnd_iter_node_func_t func,
> +		void *user_data)
> +{
> +	ibnd_node_t *cur = NULL;
> +
> +	for (cur = fabric->nodes; cur; cur = cur->next) {
> +		func(cur, user_data);
> +	}
> +}
> +
> +
> +void
> +ibnd_iter_nodes_type(ibnd_fabric_t *fabric,
> +		ibnd_iter_node_func_t func,
> +		ibnd_node_type_t node_type,
> +		void *user_data)
> +{
> +	struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(fabric);
> +	struct ibnd_node *list = NULL;
> +	struct ibnd_node *cur = NULL;
> +
> +	switch (node_type) {
> +		case IBND_SWITCH_NODE:
> +			list = f->switches;
> +			break;
> +		case IBND_CA_NODE:
> +			list = f->ch_adapters;
> +			break;
> +		case IBND_ROUTER_NODE:
> +			list = f->routers;
> +			break;
> +		default:
> +			IBND_DEBUG("Invalid node_type specified %d\n", node_type);
> +			break;
> +	}
> +
> +	for (cur = list; cur; cur = cur->type_next) {
> +		func((ibnd_node_t *)cur, user_data);
> +	}
> +}
> +
> diff --git a/infiniband-diags/libibnetdisc/src/internal.h b/infiniband-diags/libibnetdisc/src/internal.h
> new file mode 100644
> index 0000000..89f238f
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/src/internal.h
> @@ -0,0 +1,82 @@
> +/*
> + * Copyright (c) 2008 Lawrence Livermore National Laboratory
> + *
> + * This software is available to you under a choice of one of two
> + * licenses.  You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + *     Redistribution and use in source and binary forms, with or
> + *     without modification, are permitted provided that the following
> + *     conditions are met:
> + *
> + *      - Redistributions of source code must retain the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer.
> + *
> + *      - Redistributions in binary form must reproduce the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer in the documentation and/or other materials
> + *        provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + *
> + */
> +
> +/** =========================================================================
> + * Define the internal data structures.
> + */
> +
> +#ifndef _INTERNAL_H_
> +#define _INTERNAL_H_
> +
> +#include <infiniband/ibnetdisc.h>
> +
> +struct ibnd_node {
> +	/* This member MUST BE FIRST */
> +	ibnd_node_t node;
> +
> +	/* internal use only */
> +	unsigned char ch_found;
> +	struct ibnd_node *htnext; /* hash table list */
> +	struct ibnd_node *dnext; /* nodesdist next */
> +	struct ibnd_node *type_next; /* next based on type */
> +};
> +#define CONV_NODE_INTERNAL(node) ((struct ibnd_node *)node)
> +
> +struct ibnd_port {
> +	/* This member MUST BE FIRST */
> +	ibnd_port_t port;
> +
> +	/* internal use only */
> +	struct ibnd_port *htnext;
> +};
> +#define CONV_PORT_INTERNAL(port) ((struct ibnd_port *)port)
> +
> +struct ibnd_fabric {
> +	/* This member MUST BE FIRST */
> +	ibnd_fabric_t fabric;
> +
> +	/* internal use only */
> +	void *ibmad_port;
> +	struct ibnd_node *nodestbl[HTSZ];
> +	struct ibnd_port *portstbl[HTSZ];
> +	struct ibnd_node *nodesdist[MAXHOPS+1];
> +	ibnd_chassis_t *first_chassis;
> +	ibnd_chassis_t *current_chassis;
> +	ibnd_chassis_t *last_chassis;
> +	struct ibnd_node *switches;
> +	struct ibnd_node *ch_adapters;
> +	struct ibnd_node *routers;
> +};
> +#define CONV_FABRIC_INTERNAL(fabric) ((struct ibnd_fabric *)fabric)
> +
> +#endif /* _INTERNAL_H_ */
> diff --git a/infiniband-diags/libibnetdisc/src/libibnetdisc.map b/infiniband-diags/libibnetdisc/src/libibnetdisc.map
> new file mode 100644
> index 0000000..5e8c315
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/src/libibnetdisc.map
> @@ -0,0 +1,27 @@
> +IBNETDISC_1.0 {
> +	global:
> +		ibnd_debug;
> +		ibnd_show_progress;
> +		ibnd_discover_fabric;
> +		ibnd_cache_fabric;
> +		ibnd_read_fabric;
> +		ibnd_destroy_fabric;
> +		ibnd_find_node_guid;
> +		ibnd_update_node;
> +		ibnd_find_node_dr;
> +		ibnd_linkwidth_str;
> +		ibnd_linkspeed_str;
> +		ibnd_node_type_str;
> +		ibnd_node_type_str_short;
> +		ibnd_is_xsigo_guid;
> +		ibnd_is_xsigo_tca;
> +		ibnd_is_xsigo_hca;
> +		ibnd_get_chassis_guid;
> +		ibnd_get_chassis_type;
> +		ibnd_get_chassis_slot_str;
> +		ibnd_linkstate_str;
> +		ibnd_physstate_str;
> +		ibnd_iter_nodes;
> +		ibnd_iter_nodes_type;
> +	local: *;
> +};
> diff --git a/infiniband-diags/libibnetdisc/test/iblinkinfotest.c b/infiniband-diags/libibnetdisc/test/iblinkinfotest.c
> new file mode 100644
> index 0000000..6e63f4a
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/test/iblinkinfotest.c
> @@ -0,0 +1,395 @@
> +/*
> + * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
> + * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
> + * Copyright (c) 2008 Lawrence Livermore National Lab.  All rights reserved.
> + *
> + * This software is available to you under a choice of one of two
> + * licenses.  You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + *     Redistribution and use in source and binary forms, with or
> + *     without modification, are permitted provided that the following
> + *     conditions are met:
> + *
> + *      - Redistributions of source code must retain the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer.
> + *
> + *      - Redistributions in binary form must reproduce the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer in the documentation and/or other materials
> + *        provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + *
> + */
> +
> +#if HAVE_CONFIG_H
> +#  include <config.h>
> +#endif /* HAVE_CONFIG_H */
> +
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <stdarg.h>
> +#include <time.h>
> +#include <string.h>
> +#include <getopt.h>
> +#include <errno.h>
> +#include <inttypes.h>
> +
> +#include <infiniband/complib/cl_nodenamemap.h>
> +#include <infiniband/ibnetdisc.h>
> +
> +char *argv0 = "iblinkinfotest";
> +static FILE *f;
> +
> +static char *node_name_map_file = NULL;
> +static nn_map_t *node_name_map = NULL;
> +
> +static int timeout_ms = 500;
> +
> +static int debug = 0;
> +#define	DEBUG(str, args...) \
> +	if (debug) fprintf(stderr, str, ##args)
> +
> +static int down_links_only = 0;
> +static int line_mode = 0;
> +static int add_sw_settings = 0;
> +static int print_port_guids = 0;
> +
> +static unsigned int
> +get_max(unsigned int num)
> +{
> +	unsigned int v = num; // 32-bit word to find the log base 2 of
> +	unsigned r = 0; // r will be lg(v)
> +
> +	while (v >>= 1) // unroll for more speed...
> +	{
> +		r++;
> +	}
> +
> +	return (1 << r);
> +}
> +
> +void
> +get_msg(char *width_msg, char *speed_msg, int msg_size, ibnd_port_t *port)
> +{
> +	int max_speed = 0;
> +
> +	int max_width = get_max(port->info.link_width_supported
> +				& port->remoteport->info.link_width_supported);
> +	if ((max_width & port->info.link_width_active) == 0) {
> +		// we are not at the max supported width
> +		// print what we could be at.
> +		snprintf(width_msg, msg_size, "Could be %s",
> +			ibnd_linkwidth_str(max_width));
> +	}
> +
> +	max_speed = get_max(port->info.link_speed_supported
> +				& port->remoteport->info.link_speed_supported);
> +	if ((max_speed & port->info.link_speed_active) == 0) {
> +		// we are not at the max supported speed
> +		// print what we could be at.
> +		snprintf(speed_msg, msg_size, "Could be %s",
> +			ibnd_linkspeed_str(max_speed, 1));
> +	}
> +}
> +
> +void
> +print_port(ibnd_node_t *node, ibnd_port_t *port)
> +{
> +	char remote_guid_str[256];
> +	char remote_str[256];
> +	char link_str[256];
> +	char width_msg[256];
> +	char speed_msg[256];
> +	char ext_port_str[256];
> +
> +	if (!port)
> +		return;
> +
> +	remote_guid_str[0] = '\0';
> +	remote_str[0] = '\0';
> +	link_str[0] = '\0';
> +	width_msg[0] = '\0';
> +	speed_msg[0] = '\0';
> +
> +	if (port->remoteport) {
> +		char  remote_name_buf[256];
> +		strncpy(remote_name_buf, port->remoteport->node->nodedesc, 256);
> +
> +		if (port->remoteport->ext_portnum)
> +			snprintf(ext_port_str, 256, "%d", port->remoteport->ext_portnum);
> +		else
> +			ext_port_str[0] = '\0';
> +
> +		get_msg(width_msg, speed_msg, 256, port);
> +		if (line_mode) {
> +			if (print_port_guids) {
> +				snprintf(remote_guid_str, 256,
> +					"0x%016lx ",
> +					port->remoteport->guid);
> +			} else {
> +				snprintf(remote_guid_str, 256,
> +					"0x%016lx ",
> +					port->remoteport->node->info.nodeguid);
> +			}
> +		}
> +
> +		snprintf(remote_str, 256,
> +			"%s%6d %4d[%2s] \"%s\" (%s %s)\n",
> +			remote_guid_str,
> +			port->remoteport->info.lid ?
> +				port->remoteport->info.lid :
> +				port->remoteport->node->smalid,
> +			port->remoteport->portnum,
> +			ext_port_str,
> +			remap_node_name(node_name_map,
> +				port->remoteport->node->info.nodeguid,
> +				remote_name_buf),
> +			width_msg,
> +			speed_msg
> +			);
> +	} else {
> +		snprintf(remote_str, 256,
> +			"%6s %4s[%2s] \"\" ( )\n", "", "", "");
> +	}
> +
> +	if (add_sw_settings) {
> +		snprintf(link_str, 256,
> +			"(%3s %s %6s/%8s) (HOQ:%d VL_Stall:%d)",
> +			ibnd_linkwidth_str(port->info.link_width_active),
> +			ibnd_linkspeed_str(port->info.link_speed_active, 1),
> +			ibnd_linkstate_str(port->info.link_state),
> +			ibnd_physstate_str(port->info.phys_state),
> +			port->info.hoq_lifetime,
> +			port->info.vl_stall_count
> +			);
> +	} else {
> +		snprintf(link_str, 256,
> +			"(%3s %s %6s/%8s)",
> +			ibnd_linkwidth_str(port->info.link_width_active),
> +			ibnd_linkspeed_str(port->info.link_speed_active, 1),
> +			ibnd_linkstate_str(port->info.link_state),
> +			ibnd_physstate_str(port->info.phys_state)
> +			);
> +	}
> +
> +	if (port->ext_portnum)
> +		snprintf(ext_port_str, 256, "%d", port->ext_portnum);
> +	else
> +		ext_port_str[0] = '\0';
> +
> +	if (line_mode) {
> +		char  name_buf[256];
> +		strncpy(name_buf, node->nodedesc, 256);
> +		printf("0x%016lx \"%30s\" %6d %4d[%2s] ==%s==>  %s",
> +			node->info.nodeguid,
> +			remap_node_name(node_name_map,
> +				node->info.nodeguid,
> +				name_buf),
> +			node->smalid, port->portnum,
> +			ext_port_str,
> +			link_str,
> +			remote_str
> +			);
> +	} else {
> +		printf("      %6d %4d[%2s] ==%s==>  %s",
> +			node->smalid, port->portnum,
> +			ext_port_str,
> +			link_str,
> +			remote_str
> +			);
> +	}
> +}
> +
> +void
> +print_switch(ibnd_node_t *node, void *user_data)
> +{
> +	int i = 0;
> +
> +	if (!line_mode) {
> +		char  name_buf[256];
> +		strncpy(name_buf, node->nodedesc, 256);
> +		printf("Switch 0x%016lx %s:\n",
> +			node->info.nodeguid,
> +			remap_node_name(node_name_map,
> +				node->info.nodeguid,
> +				name_buf));
> +	}
> +
> +	for (i = 1; i <= node->info.numports; i++) {
> +		ibnd_port_t *port = node->ports[i];
> +		if (!port)
> +			continue;
> +		if (!down_links_only || port->info.link_state == IBND_LINK_DOWN) {
> +			print_port(node, port);
> +		}
> +	}
> +}
> +
> +void
> +usage(void)
> +{
> +	fprintf(stderr,
> +		"Usage: %s [-hclp -S <guid> -D <direct route> -C <ca_name> -P <ca_port>]\n"
> +		"   Report link speed and connection for each port of each switch which is active\n"
> +		"   -h This help message\n"
> +		"   -S <guid> output only the node specified by guid\n"
> +		"   -D <direct route> print only node specified by <direct route>\n"
> +		"   -f <dr_path> specify node to start \"from\"\n"
> +		"   -n <hops> Number of hops to include away from specified node\n"
> +		"   -d print only down links\n"
> +		"   -l (line mode) print all information for each link on each line\n"
> +		"   -p print additional switch settings (PktLifeTime,HoqLife,VLStallCount)\n"
> +
> +
> +		"   -t <timeout_ms> timeout for any single fabric query\n"
> +		"   -s show errors\n"
> +		"   --node-name-map <map_file> use specified node name map\n"
> +
> +		"   -C <ca_name> use selected Channel Adaptor name for queries\n"
> +		"   -P <ca_port> use selected channel adaptor port for queries\n"
> +		"   -g print port guids instead of node guids\n"
> +		"   --debug print debug messages\n"
> +		,
> +			argv0);
> +	exit(-1);
> +}
> +
> +int
> +main(int argc, char **argv)
> +{
> +	char *ca = 0;
> +	int ca_port = 0;
> +	ibnd_fabric_t *fabric = NULL;
> +	uint64_t guid = 0;
> +	char *dr_path = NULL;
> +	char *from = NULL;
> +	int hops = 0;
> +	ib_portid_t port_id;
> +
> +	static char const str_opts[] = "S:D:n:C:P:t:sldgphuf:";
> +	static const struct option long_opts[] = {
> +		{ "S", 1, 0, 'S'},
> +		{ "D", 1, 0, 'D'},
> +		{ "num-hops", 1, 0, 'n'},
> +		{ "down-links-only", 0, 0, 'd'},
> +		{ "line-mode", 0, 0, 'l'},
> +		{ "ca-name", 1, 0, 'C'},
> +		{ "ca-port", 1, 0, 'P'},
> +		{ "timeout", 1, 0, 't'},
> +		{ "show", 0, 0, 's'},
> +		{ "print-port-guids", 0, 0, 'g'},
> +		{ "print-additional", 0, 0, 'p'},
> +		{ "help", 0, 0, 'h'},
> +		{ "usage", 0, 0, 'u'},
> +		{ "node-name-map", 1, 0, 1},
> +		{ "debug", 0, 0, 2},
> +		{ "from", 1, 0, 'f'},
> +		{ }
> +	};
> +
> +	f = stdout;
> +
> +	argv0 = argv[0];
> +
> +	while (1) {
> +		int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);
> +		if ( ch == -1 )
> +			break;
> +		switch(ch) {
> +		case 1:
> +			node_name_map_file = strdup(optarg);
> +			break;
> +		case 2:
> +			debug = 1;
> +			ibnd_debug(1);
> +			break;
> +		case 'f':
> +			from = strdup(optarg);
> +			break;
> +		case 'C':
> +			ca = strdup(optarg);
> +			break;
> +		case 'P':
> +			ca_port = strtoul(optarg, 0, 0);
> +			break;
> +		case 'D':
> +			dr_path = strdup(optarg);
> +			break;
> +		case 'n':
> +			hops = (int)strtol(optarg, NULL, 0);
> +			break;
> +		case 'd':
> +			down_links_only = 1;
> +			break;
> +		case 'l':
> +			line_mode = 1;
> +			break;
> +		case 't':
> +			timeout_ms = strtoul(optarg, 0, 0);
> +			break;
> +		case 'g':
> +			print_port_guids = 1;
> +			break;
> +		case 'S':
> +			guid = (uint64_t)strtoull(optarg, 0, 0);
> +			break;
> +		case 'p':
> +			add_sw_settings = 1;
> +			break;
> +		default:
> +			usage();
> +			break;
> +		}
> +	}
> +	argc -= optind;
> +	argv += optind;
> +
> +	if (argc && !(f = fopen(argv[0], "w")))
> +		fprintf(stderr, "can't open file %s for writing", argv[0]);
> +
> +	node_name_map = open_node_name_map(node_name_map_file);
> +
> +	if (from) {
> +		/* only scan part of the fabric */
> +		str2drpath(&(port_id.drpath), from, 0, 0);
> +		if ((fabric = ibnd_discover_fabric(ca, ca_port, timeout_ms, &port_id, hops)) == NULL) {
> +			fprintf(stderr, "discover failed\n");
> +			exit(1);
> +		}
> +		guid = 0;
> +	} else {
> +		if ((fabric = ibnd_discover_fabric(ca, ca_port, timeout_ms, NULL, -1)) == NULL) {
> +			fprintf(stderr, "discover failed\n");
> +			exit(1);
> +		}
> +	}
> +
> +	if (guid) {
> +		ibnd_node_t *sw = ibnd_find_node_guid(fabric, guid);
> +		print_switch(sw, NULL);
> +	} else if (dr_path) {
> +		ibnd_node_t *sw = ibnd_find_node_dr(fabric, dr_path);
> +		print_switch(sw, NULL);
> +	} else {
> +		ibnd_iter_nodes_type(fabric, print_switch, IBND_SWITCH_NODE, NULL);
> +	}
> +
> +	ibnd_destroy_fabric(fabric);
> +
> +	close_node_name_map(node_name_map);
> +	exit(0);
> +}
> diff --git a/infiniband-diags/libibnetdisc/test/ibnetdisctest.c b/infiniband-diags/libibnetdisc/test/ibnetdisctest.c
> new file mode 100644
> index 0000000..fc6e234
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/test/ibnetdisctest.c
> @@ -0,0 +1,675 @@
> +/*
> + * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
> + * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
> + * Copyright (c) 2008 Lawrence Livermore National Lab.  All rights reserved.
> + *
> + * This software is available to you under a choice of one of two
> + * licenses.  You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + *     Redistribution and use in source and binary forms, with or
> + *     without modification, are permitted provided that the following
> + *     conditions are met:
> + *
> + *      - Redistributions of source code must retain the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer.
> + *
> + *      - Redistributions in binary form must reproduce the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer in the documentation and/or other materials
> + *        provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + *
> + */
> +
> +#if HAVE_CONFIG_H
> +#  include <config.h>
> +#endif /* HAVE_CONFIG_H */
> +
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <stdarg.h>
> +#include <time.h>
> +#include <string.h>
> +#include <getopt.h>
> +#include <errno.h>
> +#include <inttypes.h>
> +
> +#include <infiniband/complib/cl_nodenamemap.h>
> +#include <infiniband/ibnetdisc.h>
> +#include <infiniband/common.h>
> +
> +static int verbose;
> +#define LIST_CA_NODE	 (1 << IBND_CA_NODE)
> +#define LIST_SWITCH_NODE (1 << IBND_SWITCH_NODE)
> +#define LIST_ROUTER_NODE (1 << IBND_ROUTER_NODE)
> +
> +char *argv0 = "ibnetdiscover";
> +static FILE *f;
> +
> +static char *node_name_map_file = NULL;
> +static nn_map_t *node_name_map = NULL;
> +
> +static int timeout_ms = 2000;
> +
> +static int debug = 0;
> +#define        DEBUG(str, args...) \
> +       if (debug) fprintf(stderr, str, ##args)
> +
> +
> +char *
> +node_name(ibnd_node_t *node)
> +{
> +	static char buf[256];
> +
> +	switch(node->info.type) {
> +	case IBND_CA_NODE:
> +		sprintf(buf, "\"%s", "H");
> +		break;
> +	case IBND_SWITCH_NODE:
> +		sprintf(buf, "\"%s", "S");
> +		break;
> +	case IBND_ROUTER_NODE:
> +		sprintf(buf, "\"%s", "R");
> +		break;
> +	default:
> +		sprintf(buf, "\"%s", "?");
> +		break;
> +	}
> +	sprintf(buf+2, "-%016" PRIx64 "\"", node->info.nodeguid);
> +
> +	return buf;
> +}
> +
> +void
> +list_node(ibnd_node_t *node, void *user_data)
> +{
> +	char *nodename = remap_node_name(node_name_map, node->info.nodeguid,
> +					      node->nodedesc);
> +
> +	fprintf(f, "%s\t : 0x%016" PRIx64 " ports %d devid 0x%x vendid 0x%x \"%s\"\n",
> +		ibnd_node_type_str(node),
> +		node->info.nodeguid, node->info.numports, node->info.devid,
> +		node->info.vendid,
> +		nodename);
> +
> +	free(nodename);
> +}
> +
> +void
> +list_nodes(ibnd_fabric_t *fabric, int list)
> +{
> +	if (list & LIST_CA_NODE) {
> +		ibnd_iter_nodes_type(fabric, list_node, IBND_CA_NODE, NULL);
> +	}
> +	if (list & LIST_SWITCH_NODE) {
> +		ibnd_iter_nodes_type(fabric, list_node, IBND_SWITCH_NODE, NULL);
> +	}
> +	if (list & LIST_ROUTER_NODE) {
> +		ibnd_iter_nodes_type(fabric, list_node, IBND_ROUTER_NODE, NULL);
> +	}
> +}
> +
> +void
> +out_ids(ibnd_node_t *node, int group, char *chname)
> +{
> +	fprintf(f, "\nvendid=0x%x\ndevid=0x%x\n", node->info.vendid, node->info.devid);
> +	if (node->info.sysimgguid)
> +		fprintf(f, "sysimgguid=0x%" PRIx64, node->info.sysimgguid);
> +	if (group
> +	    && node->chassis && node->chassis->chassisnum) {
> +		fprintf(f, "\t\t# Chassis %d", node->chassis->chassisnum);
> +		if (chname)
> +			fprintf(f, " (%s)", clean_nodedesc(chname));
> +		if (ibnd_is_xsigo_tca(node->info.nodeguid)
> +				&& node->ports[1]
> +				&& node->ports[1]->remoteport)
> +			fprintf(f, " slot %d", node->ports[1]->remoteport->portnum);
> +	}
> +	fprintf(f, "\n");
> +}
> +
> +
> +uint64_t
> +out_chassis(ibnd_fabric_t *fabric, int chassisnum)
> +{
> +	uint64_t guid;
> +
> +	fprintf(f, "\nChassis %d", chassisnum);
> +	guid = ibnd_get_chassis_guid(fabric, chassisnum);
> +	if (guid)
> +		fprintf(f, " (guid 0x%" PRIx64 ")", guid);
> +	fprintf(f, "\n");
> +	return guid;
> +}
> +
> +void
> +out_switch(ibnd_node_t *node, int group, char *chname)
> +{
> +	char *str;
> +	char  str2[256];
> +	char *nodename = NULL;
> +
> +	out_ids(node, group, chname);
> +	fprintf(f, "switchguid=0x%" PRIx64, node->info.nodeguid);
> +	fprintf(f, "(%" PRIx64 ")", node->info.nodeportguid);
> +	if (group) {
> +		str = ibnd_get_chassis_type(node);
> +		if (str)
> +			fprintf(f, "%s ", str);
> +		str = ibnd_get_chassis_slot_str(node, str2, 256);
> +		if (str)
> +			fprintf(f, "%s", str);
> +	}
> +
> +	nodename = remap_node_name(node_name_map, node->info.nodeguid,
> +				node->nodedesc);
> +
> +	fprintf(f, "\nSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d\n",
> +		node->info.numports, node_name(node),
> +		nodename,
> +		node->sw_info.smaenhsp0 ? "enhanced" : "base",
> +		node->smalid, node->smalmc);
> +
> +	free(nodename);
> +}
> +
> +void
> +out_ca(ibnd_node_t *node, int group, char *chname)
> +{
> +	char *node_type;
> +	char *node_type2;
> +
> +	out_ids(node, group, chname);
> +	switch(node->info.type) {
> +	case IBND_CA_NODE:
> +		node_type = "ca";
> +		node_type2 = "Ca";
> +		break;
> +	case IBND_ROUTER_NODE:
> +		node_type = "rt";
> +		node_type2 = "Rt";
> +		break;
> +	default:
> +		node_type = "???";
> +		node_type2 = "???";
> +		break;
> +	}
> +
> +	fprintf(f, "%sguid=0x%" PRIx64 "\n", node_type, node->info.nodeguid);
> +	fprintf(f, "%s\t%d %s\t\t# \"%s\"",
> +		node_type2, node->info.numports, node_name(node),
> +		clean_nodedesc(node->nodedesc));
> +	if (group && ibnd_is_xsigo_hca(node->info.nodeguid))
> +		fprintf(f, " (scp)");
> +	fprintf(f, "\n");
> +}
> +
> +#define OUT_BUFFER_SIZE 16
> +static char *
> +out_ext_port(ibnd_port_t *port, int group)
> +{
> +	static char mapping[OUT_BUFFER_SIZE];
> +
> +	if (group && port->ext_portnum != 0) {
> +		snprintf(mapping, OUT_BUFFER_SIZE,
> +			"[ext %d]", port->ext_portnum);
> +		return (mapping);
> +	}
> +
> +	return (NULL);
> +}
> +
> +void
> +out_switch_port(ibnd_port_t *port, int group)
> +{
> +	char *ext_port_str = NULL;
> +	char *rem_nodename = NULL;
> +
> +	DEBUG("port %p:%d remoteport %p\n", port, port->portnum, port->remoteport);
> +	fprintf(f, "[%d]", port->portnum);
> +
> +	ext_port_str = out_ext_port(port, group);
> +	if (ext_port_str)
> +		fprintf(f, "%s", ext_port_str);
> +
> +	rem_nodename = remap_node_name(node_name_map,
> +				port->remoteport->node->info.nodeguid,
> +				port->remoteport->node->nodedesc);
> +
> +	ext_port_str = out_ext_port(port->remoteport, group);
> +	fprintf(f, "\t%s[%d]%s",
> +		node_name(port->remoteport->node),
> +		port->remoteport->portnum,
> +		ext_port_str ? ext_port_str : "");
> +	if (port->remoteport->node->info.type != IBND_SWITCH_NODE)
> +		fprintf(f, "(%" PRIx64 ") ", port->remoteport->guid);
> +	fprintf(f, "\t\t# \"%s\" lid %d %s%s",
> +		rem_nodename,
> +		port->remoteport->node->info.type == IBND_SWITCH_NODE ?  port->remoteport->node->smalid : port->remoteport->info.lid,
> +		ibnd_linkwidth_str(port->info.link_width_active),
> +		ibnd_linkspeed_str(port->info.link_speed_active, 0));
> +
> +	if (ibnd_is_xsigo_tca(port->remoteport->guid))
> +		fprintf(f, " slot %d", port->portnum);
> +	else if (ibnd_is_xsigo_hca(port->remoteport->guid))
> +		fprintf(f, " (scp)");
> +	fprintf(f, "\n");
> +
> +	free(rem_nodename);
> +}
> +
> +void
> +out_ca_port(ibnd_port_t *port, int group)
> +{
> +	char *str = NULL;
> +	char *rem_nodename = NULL;
> +
> +	fprintf(f, "[%d]", port->portnum);
> +	if (port->node->info.type != IBND_SWITCH_NODE)
> +		fprintf(f, "(%" PRIx64 ") ", port->guid);
> +	fprintf(f, "\t%s[%d]",
> +		node_name(port->remoteport->node),
> +		port->remoteport->portnum);
> +	str = out_ext_port(port->remoteport, group);
> +	if (str)
> +		fprintf(f, "%s", str);
> +	if (port->remoteport->node->info.type != IBND_SWITCH_NODE)
> +		fprintf(f, " (%" PRIx64 ") ", port->remoteport->guid);
> +
> +	rem_nodename = remap_node_name(node_name_map,
> +				port->remoteport->node->info.nodeguid,
> +				port->remoteport->node->nodedesc);
> +
> +	fprintf(f, "\t\t# lid %d lmc %d \"%s\" lid %d %s%s\n",
> +		port->info.lid, port->info.lmc, rem_nodename,
> +		port->remoteport->node->info.type == IBND_SWITCH_NODE ?  port->remoteport->node->smalid : port->remoteport->info.lid,
> +		ibnd_linkwidth_str(port->info.link_width_active),
> +		ibnd_linkspeed_str(port->info.link_speed_active, 0));
> +
> +	free(rem_nodename);
> +}
> +
> +struct iter_user_data {
> +	int group;
> +	int skip_chassis_nodes;
> +};
> +
> +static void
> +switch_iter_func(ibnd_node_t *node, void *iter_user_data)
> +{
> +	ibnd_port_t *port;
> +	int p = 0;
> +	struct iter_user_data *data = (struct iter_user_data *)iter_user_data;
> +
> +	DEBUG("SWITCH: node %p\n", node);
> +
> +	/* skip chassis based switches if flagged */
> +	if (data->skip_chassis_nodes && node->chassis && node->chassis->chassisnum)
> +		return;
> +
> +	out_switch(node, data->group, NULL);
> +	for (p = 1; p <= node->info.numports; p++) {
> +		port = node->ports[p];
> +		if (port && port->remoteport)
> +			out_switch_port(port, data->group);
> +	}
> +}
> +
> +static void
> +ca_iter_func(ibnd_node_t *node, void *iter_user_data)
> +{
> +	ibnd_port_t *port;
> +	int p = 0;
> +	struct iter_user_data *data = (struct iter_user_data *)iter_user_data;
> +
> +	DEBUG("CA: node %p\n", node);
> +	/* Now, skip chassis based CAs */
> +	if (data->group && node->chassis && node->chassis->chassisnum)
> +		return;
> +	out_ca(node, data->group, NULL);
> +
> +	for (p = 1; p <= node->info.numports; p++) {
> +		port = node->ports[p];
> +		if (port && port->remoteport)
> +			out_ca_port(port, data->group);
> +	}
> +}
> +
> +static void
> +router_iter_func(ibnd_node_t *node, void *iter_user_data)
> +{
> +	ibnd_port_t *port;
> +	int p = 0;
> +	struct iter_user_data *data = (struct iter_user_data *)iter_user_data;
> +
> +	DEBUG("RT: node %p\n", node);
> +	/* Now, skip chassis based RTs */
> +	if (data->group && node->chassis && node->chassis->chassisnum)
> +		return;
> +	out_ca(node, data->group, NULL);
> +	for (p = 1; p <= node->info.numports; p++) {
> +		port = node->ports[p];
> +		if (port && port->remoteport)
> +			out_ca_port(port, data->group);
> +	}
> +}
> +
> +int
> +dump_topology(int group, ibnd_fabric_t *fabric)
> +{
> +	ibnd_node_t *node;
> +	ibnd_port_t *port;
> +	int i = 0, p = 0;
> +	time_t t = time(0);
> +	uint64_t chguid;
> +	char *chname = NULL;
> +	struct iter_user_data iter_user_data;
> +
> +	fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t));
> +	fprintf(f, "# Max of %d hops discovered\n", fabric->maxhops_discovered);
> +	fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n",
> +		fabric->from_node->info.nodeguid, fabric->from_node->info.nodeportguid);
> +
> +	/* Make pass on switches */
> +	if (group) {
> +		ibnd_chassis_t *ch = NULL;
> +
> +		/* Chassis based switches first */
> +		for (ch = fabric->chassis; ch; ch = ch->next) {
> +			int n = 0;
> +
> +			if (!ch->chassisnum)
> +				continue;
> +			chguid = out_chassis(fabric, ch->chassisnum);
> +
> +			chname = NULL;
> +/**
> + * Will this work for Xsigo?
> + */
> +			if (ibnd_is_xsigo_guid(chguid)) {
> +				for (node = ch->nodes; node;
> +						node = node->next_chassis_node) {
> +					if (ibnd_is_xsigo_hca(node->info.nodeguid)) {
> +						chname = node->nodedesc;
> +						fprintf(f, "Hostname: %s\n", clean_nodedesc(node->nodedesc));
> +					}
> +				}
> +
> +#if 0
> +/**
> + * vs. this?
> + * I don't want to expose the nodesdist array to the end user.
> + */
> +				for (node = fabric->nodesdist[MAXHOPS]; node; node = node->dnext) {
> +					if (!node->chrecord ||
> +					    !node->chrecord->chassisnum)
> +						continue;
> +
> +					if (node->chrecord->chassisnum != ch->chassisnum)
> +						continue;
> +
> +					if (ibnd_is_xsigo_hca(node->nodeguid)) {
> +						chname = node->nodedesc;
> +						fprintf(f, "Hostname: %s\n", clean_nodedesc(node->nodedesc));
> +					}
> +				}
> +#endif
> +			}
> +
> +			fprintf(f, "\n# Spine Nodes");
> +			for (n = 1; n <= SPINES_MAX_NUM; n++) {
> +				if (ch->spinenode[n]) {
> +					out_switch(ch->spinenode[n], group, chname);
> +					for (p = 1; p <= ch->spinenode[n]->info.numports; p++) {
> +						port = ch->spinenode[n]->ports[p];
> +						if (port && port->remoteport)
> +							out_switch_port(port, group);
> +					}
> +				}
> +			}
> +			fprintf(f, "\n# Line Nodes");
> +			for (n = 1; n <= LINES_MAX_NUM; n++) {
> +				if (ch->linenode[n]) {
> +					out_switch(ch->linenode[n], group, chname);
> +					for (p = 1; p <= ch->linenode[n]->info.numports; p++) {
> +						port = ch->linenode[n]->ports[p];
> +						if (port && port->remoteport)
> +							out_switch_port(port, group);
> +					}
> +				}
> +			}
> +
> +			fprintf(f, "\n# Chassis Switches");
> +			for (node = ch->nodes; node;
> +					node = node->next_chassis_node) {
> +				if (node->info.type == IBND_SWITCH_NODE) {
> +					out_switch(node, group, chname);
> +					for (p = 1; p <= node->info.numports; p++) {
> +						port = node->ports[p];
> +						if (port && port->remoteport)
> +							out_switch_port(port, group);
> +					}
> +				}
> +			}
> +
> +			fprintf(f, "\n# Chassis CAs");
> +			for (node = ch->nodes; node;
> +					node = node->next_chassis_node) {
> +				if (node->info.type == IBND_CA_NODE) {
> +					out_ca(node, group, chname);
> +					for (p = 1; p <= node->info.numports; p++) {
> +						port = node->ports[p];
> +						if (port && port->remoteport)
> +							out_ca_port(port, group);
> +					}
> +				}
> +			}
> +
> +		}
> +
> +	} else { /* !group */
> +		iter_user_data.group = group;
> +		iter_user_data.skip_chassis_nodes = 0;
> +
> +		ibnd_iter_nodes_type(fabric, switch_iter_func,
> +				IBND_SWITCH_NODE, &iter_user_data);
> +	}
> +
> +	chname = NULL;
> +	if (group) {
> +		iter_user_data.group = group;
> +		iter_user_data.skip_chassis_nodes = 1;
> +
> +		fprintf(f, "\nNon-Chassis Nodes\n");
> +		ibnd_iter_nodes_type(fabric, switch_iter_func,
> +				IBND_SWITCH_NODE, &iter_user_data);
> +
> +	}
> +
> +	iter_user_data.group = group;
> +	iter_user_data.skip_chassis_nodes = 0;
> +
> +	/* Make pass on CAs */
> +	ibnd_iter_nodes_type(fabric, ca_iter_func, IBND_CA_NODE,
> +			&iter_user_data);
> +
> +	/* make pass on routers */
> +	ibnd_iter_nodes_type(fabric, router_iter_func, IBND_ROUTER_NODE,
> +			&iter_user_data);
> +
> +	return i;
> +}
> +
> +
> +void dump_ports_report (ibnd_node_t *node, void *user_data)
> +{
> +	int p = 0;
> +	ibnd_port_t *port = NULL;
> +
> +	/* for each port */
> +	for (p = node->info.numports, port = node->ports[p];
> +	     p > 0;
> +	     port = node->ports[--p]) {
> +		if (port == NULL)
> +			continue;
> +
> +		fprintf(stdout,
> +			"%2s %5d %2d 0x%016" PRIx64 " %s %s",
> +			ibnd_node_type_str_short(node),
> +			node->info.type == IBND_SWITCH_NODE ? node->smalid : port->info.lid,
> +			port->portnum,
> +			port->guid,
> +			ibnd_linkwidth_str(port->info.link_width_active),
> +			ibnd_linkspeed_str(port->info.link_speed_active, 0));
> +		if (port->remoteport)
> +			fprintf(stdout,
> +				" - %2s %5d %2d 0x%016" PRIx64
> +				" ( '%s' - '%s' )\n",
> +				ibnd_node_type_str_short(port->remoteport->node),
> +				port->remoteport->node->info.type == IBND_SWITCH_NODE ?
> +					port->remoteport->node->smalid : port->remoteport->info.lid,
> +				port->remoteport->portnum,
> +				port->remoteport->guid,
> +				port->node->nodedesc,
> +				port->remoteport->node->nodedesc);
> +		else
> +			fprintf(stdout, "%36s'%s'\n", "",
> +				port->node->nodedesc);
> +	}
> +}
> +
> +void
> +usage(void)
> +{
> +	fprintf(stderr, "Usage: %s [-d(ebug)] -s(how) -l(ist) -g(rouping) -H(ca_list) -S(witch_list) -R(outer_list) -V(ersion) -C ca_name -P ca_port "
> +			"-t(imeout) timeout_ms --node-name-map node-name-map] -p(orts) [<topology-file>]\n",
> +			argv0);
> +	fprintf(stderr, "       --node-name-map <node-name-map> specify a node name map file\n");
> +	exit(-1);
> +}
> +
> +int
> +main(int argc, char **argv)
> +{
> +	int list = 0;
> +	char *ca = 0;
> +	int ca_port = 0;
> +	int group = 0;
> +	int ports_report = 0;
> +	ibnd_fabric_t *fabric = NULL;
> +
> +	static char const str_opts[] = "C:P:t:devslgHSRpVhu";
> +	static const struct option long_opts[] = {
> +		{ "C", 1, 0, 'C'},
> +		{ "P", 1, 0, 'P'},
> +		{ "debug", 0, 0, 'd'},
> +		{ "verbose", 0, 0, 'v'},
> +		{ "show", 0, 0, 's'},
> +		{ "list", 0, 0, 'l'},
> +		{ "grouping", 0, 0, 'g'},
> +		{ "Hca_list", 0, 0, 'H'},
> +		{ "Switch_list", 0, 0, 'S'},
> +		{ "Router_list", 0, 0, 'R'},
> +		{ "timeout", 1, 0, 't'},
> +		{ "node-name-map", 1, 0, 1},
> +		{ "ports", 0, 0, 'p'},
> +		{ "Version", 0, 0, 'V'},
> +		{ "help", 0, 0, 'h'},
> +		{ "usage", 0, 0, 'u'},
> +		{ }
> +	};
> +
> +	f = stdout;
> +
> +	argv0 = argv[0];
> +
> +	while (1) {
> +		int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);
> +		if ( ch == -1 )
> +			break;
> +		switch(ch) {
> +		case 1:
> +			node_name_map_file = strdup(optarg);
> +			break;
> +		case 'C':
> +			ca = optarg;
> +			break;
> +		case 'P':
> +			ca_port = strtoul(optarg, 0, 0);
> +			break;
> +		case 'd':
> +			debug = 1;
> +			ibnd_debug(1);
> +			break;
> +		case 't':
> +			timeout_ms = strtoul(optarg, 0, 0);
> +			break;
> +		case 'v':
> +			verbose++;
> +			break;
> +		case 's':
> +			ibnd_show_progress(1);
> +			break;
> +		case 'l':
> +			list = LIST_CA_NODE | LIST_SWITCH_NODE | LIST_ROUTER_NODE;
> +			break;
> +		case 'g':
> +			group = 1;
> +			break;
> +		case 'S':
> +			list |= LIST_SWITCH_NODE;
> +			break;
> +		case 'H':
> +			list |= LIST_CA_NODE;
> +			break;
> +		case 'R':
> +			list |= LIST_ROUTER_NODE;
> +			break;
> +		case 'p':
> +			ports_report = 1;
> +			break;
> +		default:
> +			usage();
> +			break;
> +		}
> +	}
> +	argc -= optind;
> +	argv += optind;
> +
> +	if (argc && !(f = fopen(argv[0], "w")))
> +		fprintf(stderr, "can't open file %s for writing", argv[0]);
> +
> +	node_name_map = open_node_name_map(node_name_map_file);
> +
> +	if ((fabric = ibnd_discover_fabric(ca, ca_port, timeout_ms, NULL, -1)) == NULL) {
> +		fprintf(stderr, "discover failed\n");
> +		exit(1);
> +	}
> +
> +	if (ports_report)
> +		ibnd_iter_nodes(fabric,
> +				dump_ports_report,
> +				NULL);
> +	else if (list)
> +		list_nodes(fabric, list);
> +	else
> +		dump_topology(group, fabric);
> +
> +	ibnd_destroy_fabric(fabric);
> +	close_node_name_map(node_name_map);
> +	exit(0);
> +}
> diff --git a/infiniband-diags/libibnetdisc/test/testleaks.c b/infiniband-diags/libibnetdisc/test/testleaks.c
> new file mode 100644
> index 0000000..3fbf7af
> --- /dev/null
> +++ b/infiniband-diags/libibnetdisc/test/testleaks.c
> @@ -0,0 +1,268 @@
> +/*
> + * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
> + * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
> + * Copyright (c) 2008 Lawrence Livermore National Lab.  All rights reserved.
> + *
> + * This software is available to you under a choice of one of two
> + * licenses.  You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + *     Redistribution and use in source and binary forms, with or
> + *     without modification, are permitted provided that the following
> + *     conditions are met:
> + *
> + *      - Redistributions of source code must retain the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer.
> + *
> + *      - Redistributions in binary form must reproduce the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer in the documentation and/or other materials
> + *        provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + *
> + */
> +
> +#if HAVE_CONFIG_H
> +#  include <config.h>
> +#endif /* HAVE_CONFIG_H */
> +
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <stdarg.h>
> +#include <time.h>
> +#include <string.h>
> +#include <getopt.h>
> +#include <errno.h>
> +#include <inttypes.h>
> +
> +#include <infiniband/complib/cl_nodenamemap.h>
> +#include <infiniband/ibnetdisc.h>
> +
> +char *argv0 = "iblinkinfotest";
> +static FILE *f;
> +
> +static int timeout_ms = 500;
> +
> +void
> +print_port(ibnd_node_t *node, ibnd_port_t *port)
> +{
> +	char remote_guid_str[256];
> +	char remote_str[256];
> +	char link_str[256];
> +	char speed_msg[256];
> +	char ext_port_str[256];
> +
> +	if (!port)
> +		return;
> +
> +	remote_guid_str[0] = '\0';
> +	remote_str[0] = '\0';
> +	link_str[0] = '\0';
> +	speed_msg[0] = '\0';
> +
> +	if (port->remoteport) {
> +		char  remote_name_buf[256];
> +		strncpy(remote_name_buf, port->remoteport->node->nodedesc, 256);
> +
> +		if (port->remoteport->ext_portnum)
> +			snprintf(ext_port_str, 256, "%d", port->remoteport->ext_portnum);
> +		else
> +			ext_port_str[0] = '\0';
> +
> +		snprintf(remote_str, 256,
> +			"%s%6d %4d[%2s] \"%s\" (%s)\n",
> +			remote_guid_str,
> +			port->remoteport->info.lid ?
> +				port->remoteport->info.lid :
> +				port->remoteport->node->smalid,
> +			port->remoteport->portnum,
> +			ext_port_str,
> +			port->remoteport->node->nodedesc,
> +			speed_msg
> +			);
> +	} else {
> +		snprintf(remote_str, 256,
> +			"%6s %4s[%2s] \"\" ( )\n", "", "", "");
> +	}
> +
> +	snprintf(link_str, 256,
> +		"(%3s %s %6s/%8s)",
> +		ibnd_linkwidth_str(port->info.link_width_active),
> +		ibnd_linkspeed_str(port->info.link_speed_active, 0),
> +		ibnd_linkstate_str(port->info.link_state),
> +		ibnd_physstate_str(port->info.phys_state)
> +		);
> +
> +	if (port->ext_portnum)
> +		snprintf(ext_port_str, 256, "%d", port->ext_portnum);
> +	else
> +		ext_port_str[0] = '\0';
> +
> +	printf("      %6d %4d[%2s] ==%s==>  %s",
> +		node->smalid, port->portnum,
> +		ext_port_str,
> +		link_str,
> +		remote_str
> +		);
> +}
> +
> +void
> +print_switch(ibnd_node_t *node, void *user_data)
> +{
> +	int i = 0;
> +
> +	for (i = 1; i <= node->info.numports; i++) {
> +		ibnd_port_t *port = node->ports[i];
> +		if (!port)
> +			continue;
> +		if (port->info.link_state == IBND_LINK_DOWN) {
> +			print_port(node, port);
> +		}
> +	}
> +}
> +
> +void
> +usage(void)
> +{
> +	fprintf(stderr,
> +		"Usage: %s [-hclp -S <guid> -D <direct route> -C <ca_name> -P <ca_port>]\n"
> +		"   Report link speed and connection for each port of each switch which is active\n"
> +		"   -h This help message\n"
> +		"   -i <iters> Number of iterations to run (default -1 == infinate)\n"
> +
> +		"   -S <guid> output only the node specified by guid\n"
> +		"   -D <direct route> print only node specified by <direct route>\n"
> +		"   -f <dr_path> specify node to start \"from\"\n"
> +		"   -n <hops> Number of hops to include away from specified node\n"
> +
> +		"   -t <timeout_ms> timeout for any single fabric query\n"
> +		"   -s show errors\n"
> +
> +		"   -C <ca_name> use selected Channel Adaptor name for queries\n"
> +		"   -P <ca_port> use selected channel adaptor port for queries\n"
> +		"   --debug print debug messages\n"
> +		,
> +			argv0);
> +	exit(-1);
> +}
> +
> +int
> +main(int argc, char **argv)
> +{
> +	char *ca = 0;
> +	int ca_port = 0;
> +	ibnd_fabric_t *fabric = NULL;
> +	uint64_t guid = 0;
> +	char *dr_path = NULL;
> +	char *from = NULL;
> +	int hops = 0;
> +	ib_portid_t port_id;
> +	int iters = -1;
> +
> +	static char const str_opts[] = "S:D:n:C:P:t:shuf:i:";
> +	static const struct option long_opts[] = {
> +		{ "S", 1, 0, 'S'},
> +		{ "D", 1, 0, 'D'},
> +		{ "num-hops", 1, 0, 'n'},
> +		{ "ca-name", 1, 0, 'C'},
> +		{ "ca-port", 1, 0, 'P'},
> +		{ "timeout", 1, 0, 't'},
> +		{ "show", 0, 0, 's'},
> +		{ "help", 0, 0, 'h'},
> +		{ "usage", 0, 0, 'u'},
> +		{ "debug", 0, 0, 2},
> +		{ "from", 1, 0, 'f'},
> +		{ "iters", 1, 0, 'i'},
> +		{ }
> +	};
> +
> +	f = stdout;
> +
> +	argv0 = argv[0];
> +
> +	while (1) {
> +		int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);
> +		if ( ch == -1 )
> +			break;
> +		switch(ch) {
> +		case 2:
> +			ibnd_debug(1);
> +			break;
> +		case 'f':
> +			from = strdup(optarg);
> +			break;
> +		case 'C':
> +			ca = strdup(optarg);
> +			break;
> +		case 'P':
> +			ca_port = strtoul(optarg, 0, 0);
> +			break;
> +		case 'D':
> +			dr_path = strdup(optarg);
> +			break;
> +		case 'n':
> +			hops = (int)strtol(optarg, NULL, 0);
> +			break;
> +		case 'i':
> +			iters = (int)strtol(optarg, NULL, 0);
> +			break;
> +		case 't':
> +			timeout_ms = strtoul(optarg, 0, 0);
> +			break;
> +		case 'S':
> +			guid = (uint64_t)strtoull(optarg, 0, 0);
> +			break;
> +		default:
> +			usage();
> +			break;
> +		}
> +	}
> +	argc -= optind;
> +	argv += optind;
> +
> +	while (iters == -1 || iters-- > 0) {
> +		if (from) {
> +			/* only scan part of the fabric */
> +			str2drpath(&(port_id.drpath), from, 0, 0);
> +			if ((fabric = ibnd_discover_fabric(ca, ca_port, timeout_ms, &port_id, hops)) == NULL) {
> +				fprintf(stderr, "discover failed\n");
> +				exit(1);
> +			}
> +			guid = 0;
> +		} else {
> +			if ((fabric = ibnd_discover_fabric(ca, ca_port, timeout_ms, NULL, -1)) == NULL) {
> +				fprintf(stderr, "discover failed\n");
> +				exit(1);
> +			}
> +		}
> +
> +#if 0
> +		if (guid) {
> +			ibnd_node_t *sw = ibnd_find_node_guid(fabric, guid);
> +			print_switch(sw, NULL);
> +		} else if (dr_path) {
> +			ibnd_node_t *sw = ibnd_find_node_dr(fabric, dr_path);
> +			print_switch(sw, NULL);
> +		} else {
> +			ibnd_iter_nodes_type(fabric, print_switch, IBND_SWITCH_NODE, NULL);
> +		}
> +#endif
> +
> +		ibnd_destroy_fabric(fabric);
> +	}
> +
> +	exit(0);
> +}
-- 
Albert Chu
chu11 at llnl.gov
Computer Scientist
High Performance Systems Division
Lawrence Livermore National Laboratory




More information about the general mailing list