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

Ira Weiny weiny2 at llnl.gov
Tue Dec 23 11:34:49 PST 2008


On Sun, 21 Dec 2008 17:21:00 +0200
Sasha Khapyorsky <sashak at voltaire.com> wrote:

> Hi Ira,
> 
> Some initial comments...
> 
> On 16:20 Thu 11 Dec     , 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])
> 
> I cannot find where syslog.h is actually used in infiniband-diags.

Ok, I will remove it both places.  Also I don't think it is necessary to check
for the other headers again here.

It looks like I have some other duplication with the enable-test-utils option.
I have fixed this as well.

> 
> > +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
> 
> Having --rpath in Makefiles is not permitted by FC and RH package review
> process. I know that it is not something introduced by this patch and
> infiniband-diags/Makefile.am has it already, but I think to clean this
> up some days.

Ok, I removed them.  Better to start things off right!

> 
> > +
> > +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 \
> 
> Files *.spec.in and *.spec don't exist anymore and 'make dist' fails.

My bad.  :-(  sorry...

> 
> > +	$(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)
> > +
> > +/** =========================================================================
> > + * 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;
> 
> What is the reason to redeclear custom NodeInfo and PortInfo structures?
> The original are defined by IBA and there are lot of utilities to work
> with them. Wouldn't it be better to use it as is?
>

[DISCLAIMER] First I want to answer your questions directly.  However, after
             writing this information, discussing with Al, and thinking it
             over.  I think I see where you are coming from and I _may_ agree
             with you.  So after reading these responses please read my
             thoughts regarding libibmad and this new lib.


I have 3 reasons I did it this way:

   1) This is pretty much the way that ibnetdiscover did things
      (By using mad_decode_field into these single fields)

   2) This makes libibnetdisc only dependent on libibmad rather than the OpenSM
      libs.  We have had some people complain that the diags require opensm-*
      things to be installed.  (This assumes you want to use ib_port_info_t from
      ib_types.h)

   3) This structure is in host byte order and calls out each field
      independently rather than having to have intimate knowledge of the
      PortInfo wire packet.
      
      For example this is the code used in iblinkinfo with the above structure.


		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)
			);

Here is the code if you use the ib_port_info_t from ib_types.h

		snprintf(link_str, 256,
			"(%3s %s %6s/%8s)",
			ibnd_linkwidth_str(port->info.link_width_active),
			ibnd_linkspeed_str(IB_PORT_LINK_SPEED_ACTIVE_MASK(port->info.link_speed), 1),
			ibnd_linkstate_str(IB_PORT_STATE_MASK(port->info.state_info1)),
			ibnd_physstate_str(IB_PORT_PHYS_STATE_MASK(port->info.state_info2) >> IB_PORT_PHYS_STATE_SHIFT)
                       //   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                       //   This is particularly nasty compared to the above.
			);

I no longer agree with reason 1 and 2.  However, reason 3 I believe is enough
justification to declare a new type.

   [DISCLAIMER] item 3 might be a mute point as well if you redefine what
   libibnetdisc is supposed to be.  See below.

> 
> > +
> > +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. */
> 
> Similar functions exist in libibmad. Why do we need another set?

2 reasons.

   1) The strings returned are not compatible with the current output of
      ibnetdiscover and iblinkinfo...  I was trying to make sure that the
      library returned string which were backwards compatible.  That is
      actually the reason for the extra "data_rate" parameter of linkspeed.
      iblinkinfo and ibnetdiscover print this differently.  :-(

   2) But more importantly this is an ease of use issue.

      This:

		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)
			);

      Becomes this:

      char buf[256];
      ...
		snprintf(link_str, 256,
			"(%3s %s %6s/%8s)",
         mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, buf, 256, &port->info.link_width_active);
         mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, buf, 256, &port->info.link_speed_active);
                   //   ^^^^^^^^^^^^^^^^^
                   //   Not backwards compatible with the current ibnetdiscover
                   //   as it prints the data as "2.5 Gbps" rather than "SDR"
         mad_dump_val(IB_PORT_STATE_F, buf, 256, &port->info.link_state);
         mad_dump_val(IB_PORT_PHYS_STATE_F, buf, 256,
         &port->info.phys_state););

      Users don't need to go look up in mad.h for the field enum to print
      something they already have; "link_width_active".


Anyway, I think I am starting to see the difference in what we are thinking...

The ibnd_*_str functions and the ibnd_port_info_t were designed based on
libibnetdisc being a "one stop shop" for this data.  I envisioned this library
being a wrapper around lower level libraries which would abstract away some
details, something like this.

  +----------+  +----------+
  |  diag1   |  |  diag2   |
  +----------+  +----------+
          |         |
       +-----------------+
       |  libibnetdisc   |
       +-----------------+
               |
       +-----------------+
       |  libibmad       |
       +-----------------+

I think what you had in mind was something like:

                       +--------+                     
                      -| diag 1 |-                    
                     / +--------+ \                   
  +-----------------+  +--------+  +-----------------+
  |  libibnetdisc   | -| diag 2 |--|  libibmad       |
  +-----------------+  +--------+  +-----------------+
              \                          /
               --------------------------

In this case users of libibnetdisc might get back something like:

   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 */
	   struct port *remoteport; /* null if SMA, or does not exist */
	   void *port_info; /* or uint8_t port_info[port_info_size] */
   } ibnd_port_t;

and decode port_info like this:

   uint32_t lid = mad_get_field(port->port_info, 0, IB_PORT_LID_F);
   mad_dump_val(IB_PORT_LID_F, port->port_info, &lid);

Is that what you are thinking?  If this is the case I don't think I object.  I
think it makes the end user of libibnetdisc work harder but it does offer some
advantages, namely less redefinition and a bit more flexibility.

That said, I would like to clean up the mad interface at the same time.  Just
figuring out the examples to write in this email have taken a lot of time.  I
don't think this is a good thing.

Here are some examples:

add something like:

static inline char *
mad_snprint_field(uint8_t *buf, int base_offs, int field,
               char *print_buf, int print_buf_size)

Therefore the above could be used in a print statement like:

   char tmp[256];
   printf("lid %s\n", mad_snprint_field(port->port_info, 0, IB_PORT_LID_F, tmp,
   256));

   [Although lid is a bad example since it could be done with "%d"...  But you
   get what I mean.]

And along those lines the difference between mad_dump_field and mad_dump_val
needs to be made more clear.  They have the same signature but one has a lot of
formating added to it which I don't think is appropriate at this level.

   "LinkState:.......................Active"
    vs.
   "Active"

Also, I don't think that the following declarations need to be public.

/* dump.c */
ib_mad_dump_fn
	mad_dump_int, mad_dump_uint, mad_dump_hex, mad_dump_rhex,
	mad_dump_bitfield, mad_dump_array, mad_dump_string,
	mad_dump_linkwidth, mad_dump_linkwidthsup, mad_dump_linkwidthen,
	mad_dump_linkdowndefstate,
	mad_dump_linkspeed, mad_dump_linkspeedsup, mad_dump_linkspeeden,
	mad_dump_portstate, mad_dump_portstates,
	mad_dump_physportstate, mad_dump_portcapmask,
	mad_dump_mtu, mad_dump_vlcap, mad_dump_opervls,
	mad_dump_node_type,
	mad_dump_sltovl, mad_dump_vlarbitration,
	mad_dump_nodedesc, mad_dump_nodeinfo, mad_dump_portinfo, mad_dump_switchinfo,
	mad_dump_perfcounters, mad_dump_perfcounters_ext;

int	_mad_dump(ib_mad_dump_fn *fn, char *name, void *val, int valsz);
char *	_mad_dump_field(ib_field_t *f, char *name, char *buf, int bufsz,
			void *val);
int	_mad_print_field(ib_field_t *f, char *name, void *val, int valsz);
char *	_mad_dump_val(ib_field_t *f, char *buf, int bufsz, void *val);

They confuse the ibmad layer.

If this is what you would like I will rework the library.  Perhaps starting to
clean up libibmad along the way?

Ira

> 
> Sasha
> 
> > +
> > +/** =========================================================================
> > + * 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);
> > +}
> > -- 
> > 1.5.4.5
> > 



More information about the general mailing list