[ofw] [PATCH] libibnetdisc: update to latest version

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


Update to git commit 4a55423059e76ccba95aed36dd256510082b1e27.

In order for libibnetdisc to import variables from libibmad, but export
its functions, we define separate MAD_EXPORT defines for the two libraries.
libibnetdisc now uses IBND_EXPORT for locally exported calls.  Users of
libibnetdisc will see both MAD_EXPORT and IBND_EXPORT as dllimport calls.

Signed-off-by: Sean Hefty <sean.hefty at intel.com>
---
Index: ulp/libibnetdisc/include/infiniband/ibnetdisc.h
===================================================================
--- ulp/libibnetdisc/include/infiniband/ibnetdisc.h     (revision 2812)
+++ ulp/libibnetdisc/include/infiniband/ibnetdisc.h     (working copy)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009 Voltaire, 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
@@ -48,9 +49,8 @@
        struct ibnd_node *next; /* all node list in fabric */

        ib_portid_t path_portid;        /* path from "from_node" */
-       int dist;               /* num of hops from "from_node" */
-       int smalid;
-       int smalmc;
+       uint16_t smalid;
+       uint8_t smalmc;

        /* quick cache of switchinfo below */
        int smaenhsp0;
@@ -66,9 +66,14 @@

        char nodedesc[IB_SMP_DATA_SIZE];

-       struct ibnd_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) */
+       struct ibnd_port **ports;       /* array of ports, indexed by port number
+                                          ports[1] == port 1,
+                                          ports[2] == port 2,
+                                          etc...
+                                          Any port in the array MAY BE NULL!
+                                          Most notable is non-switches have no
+                                          port 0 therefore node.ports[0] == NULL
+                                          for those nodes */

        /* chassis info */
        struct ibnd_node *next_chassis_node;    /* next node in ibnd_chassis_t->nodes */
@@ -81,7 +86,6 @@
        /* 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 */
 } ibnd_node_t;

@@ -117,15 +121,24 @@
        ibnd_node_t *nodes;

        /* specific to voltaire type nodes */
-#define SPINES_MAX_NUM 12
+#define SPINES_MAX_NUM 18
 #define LINES_MAX_NUM 36
        ibnd_node_t *spinenode[SPINES_MAX_NUM + 1];
        ibnd_node_t *linenode[LINES_MAX_NUM + 1];
 } ibnd_chassis_t;

 #define HTSZ 137
-#define MAXHOPS                63

+typedef struct ibnd_config {
+       unsigned max_smps;
+       unsigned show_progress;
+       unsigned max_hops;
+       unsigned debug;
+       unsigned timeout_ms;
+       unsigned retries;
+       uint8_t pad[56];
+} ibnd_config_t;
+
 /** =========================================================================
  * Fabric
  * Main fabric object which is returned and represents the data discovered
@@ -140,66 +153,65 @@
        ibnd_node_t *nodes;
        /* NULL terminated list of all chassis found in the fabric */
        ibnd_chassis_t *chassis;
-       int maxhops_discovered;
+       unsigned maxhops_discovered;
+       unsigned total_mads_used;

        /* internal use only */
        ibnd_node_t *nodestbl[HTSZ];
        ibnd_port_t *portstbl[HTSZ];
-       ibnd_node_t *nodesdist[MAXHOPS + 1];
-       ibnd_chassis_t *first_chassis;
-       ibnd_chassis_t *current_chassis;
-       ibnd_chassis_t *last_chassis;
        ibnd_node_t *switches;
        ibnd_node_t *ch_adapters;
        ibnd_node_t *routers;
-       ib_portid_t selfportid;
 } ibnd_fabric_t;

 /** =========================================================================
  * Initialization (fabric operations)
  */
-MAD_EXPORT void ibnd_debug(int i);
-MAD_EXPORT void ibnd_show_progress(int i);

-MAD_EXPORT ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port *ibmad_port,
-                                              ib_portid_t * from, int hops);
+IBND_EXPORT ibnd_fabric_t *ibnd_discover_fabric(char * ca_name,
+                                              int ca_port,
+                                              ib_portid_t * from,
+                                              struct ibnd_config *config);
        /**
-        * open: (required) ibmad_port object from libibmad
+        * ca_name: (optional) name of the CA to use
+        * ca_port: (optional) CA port to use
         * 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
+        *       If NULL start from the CA/CA port specified
+        * config: (optional) additional config options for the scan
         */
-MAD_EXPORT void ibnd_destroy_fabric(ibnd_fabric_t * fabric);
+IBND_EXPORT void ibnd_destroy_fabric(ibnd_fabric_t * fabric);

+IBND_EXPORT ibnd_fabric_t *ibnd_load_fabric(const char *file,
+                                          unsigned int flags);
+
+IBND_EXPORT int ibnd_cache_fabric(ibnd_fabric_t * fabric, const char *file,
+                                unsigned int flags);
+
 /** =========================================================================
  * Node operations
  */
-MAD_EXPORT ibnd_node_t *ibnd_find_node_guid(ibnd_fabric_t * fabric,
+IBND_EXPORT ibnd_node_t *ibnd_find_node_guid(ibnd_fabric_t * fabric,
                                            uint64_t guid);
-MAD_EXPORT ibnd_node_t *ibnd_find_node_dr(ibnd_fabric_t * fabric, char *dr_str);
-MAD_EXPORT ibnd_node_t *ibnd_update_node(struct ibmad_port *ibmad_port,
-                                        ibnd_fabric_t * fabric,
-                                        ibnd_node_t * node);
+IBND_EXPORT ibnd_node_t *ibnd_find_node_dr(ibnd_fabric_t * fabric, char *dr_str);

 typedef void (*ibnd_iter_node_func_t) (ibnd_node_t * node, void *user_data);
-MAD_EXPORT void ibnd_iter_nodes(ibnd_fabric_t * fabric,
+IBND_EXPORT void ibnd_iter_nodes(ibnd_fabric_t * fabric,
                                ibnd_iter_node_func_t func, void *user_data);
-MAD_EXPORT void ibnd_iter_nodes_type(ibnd_fabric_t * fabric,
+IBND_EXPORT void ibnd_iter_nodes_type(ibnd_fabric_t * fabric,
                                     ibnd_iter_node_func_t func,
                                     int node_type, void *user_data);

 /** =========================================================================
  * Chassis queries
  */
-MAD_EXPORT uint64_t ibnd_get_chassis_guid(ibnd_fabric_t * fabric,
+IBND_EXPORT uint64_t ibnd_get_chassis_guid(ibnd_fabric_t * fabric,
                                          unsigned char chassisnum);
-MAD_EXPORT char *ibnd_get_chassis_type(ibnd_node_t * node);
-MAD_EXPORT char *ibnd_get_chassis_slot_str(ibnd_node_t * node,
+IBND_EXPORT char *ibnd_get_chassis_type(ibnd_node_t * node);
+IBND_EXPORT char *ibnd_get_chassis_slot_str(ibnd_node_t * node,
                                           char *str, size_t size);

-MAD_EXPORT int ibnd_is_xsigo_guid(uint64_t guid);
-MAD_EXPORT int ibnd_is_xsigo_tca(uint64_t guid);
-MAD_EXPORT int ibnd_is_xsigo_hca(uint64_t guid);
+IBND_EXPORT int ibnd_is_xsigo_guid(uint64_t guid);
+IBND_EXPORT int ibnd_is_xsigo_tca(uint64_t guid);
+IBND_EXPORT int ibnd_is_xsigo_hca(uint64_t guid);

 #endif                         /* _IBNETDISC_H_ */
Index: ulp/libibnetdisc/include/windows/config.h
===================================================================
--- ulp/libibnetdisc/include/windows/config.h   (revision 0)
+++ ulp/libibnetdisc/include/windows/config.h   (revision 0)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2009 Intel Corp, 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 _CONFIG_H_
+#define _CONFIG_H_
+
+#include <_errno.h>
+#include <io.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define ssize_t SSIZE_T
+#define read _read
+#define write _write
+#define stat _stat
+#define open _open
+#define close _close
+#define lseek _lseek
+#define unlink _unlink
+
+#define IBND_EXPORT    __declspec(dllexport)
+
+#endif /* _CONFIG_H_ */
Index: ulp/libibnetdisc/src/chassis.c
===================================================================
--- ulp/libibnetdisc/src/chassis.c      (revision 2812)
+++ ulp/libibnetdisc/src/chassis.c      (working copy)
@@ -1,7 +1,8 @@
 /*
- * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
  * Copyright (c) 2008 Lawrence Livermore National Lab.  All rights reserved.
+ * Copyright (c) 2010 HNR Consulting.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -38,7 +39,7 @@
 /*========================================================*/

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

 #include <stdlib.h>
@@ -49,24 +50,30 @@
 #include "internal.h"
 #include "chassis.h"

-static char *ChassisTypeStr[5] =
-    { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004" };
+static char *ChassisTypeStr[6] =
+{ "", "ISR9288", "ISR9096", "ISR2012", "ISR2004", "ISR4700" };
 static char *ChassisSlotTypeStr[4] = { "", "Line", "Spine", "SRBD" };

+typedef struct chassis_scan {
+       ibnd_chassis_t *first_chassis;
+       ibnd_chassis_t *current_chassis;
+       ibnd_chassis_t *last_chassis;
+} chassis_scan_t;
+
 char *ibnd_get_chassis_type(ibnd_node_t * node)
 {
        if (!node) {
                IBND_DEBUG("node parameter NULL\n");
-               return (NULL);
+               return NULL;
        }

        /* Currently, only if Voltaire chassis */
        if (mad_get_field(node->info, 0, IB_NODE_VENDORID_F) != VTR_VENDOR_ID)
-               return (NULL);
+               return NULL;
        if (!node->chassis)
-               return (NULL);
-       if (node->ch_type == UNRESOLVED_CT || node->ch_type > ISR2004_CT)
-               return (NULL);
+               return NULL;
+       if (node->ch_type == UNRESOLVED_CT || node->ch_type > ISR4700_CT)
+               return NULL;
        return ChassisTypeStr[node->ch_type];
 }

@@ -74,21 +81,21 @@
 {
        if (!node) {
                IBND_DEBUG("node parameter NULL\n");
-               return (NULL);
+               return NULL;
        }

        /* Currently, only if Voltaire chassis */
        if (mad_get_field(node->info, 0, IB_NODE_VENDORID_F) != VTR_VENDOR_ID)
-               return (NULL);
+               return NULL;
        if (!node->chassis)
-               return (NULL);
+               return NULL;
        if (node->ch_slot == UNRESOLVED_CS || node->ch_slot > SRBD_CS)
-               return (NULL);
+               return NULL;
        if (!str)
-               return (NULL);
+               return NULL;
        snprintf(str, size, "%s %d Chip %d", ChassisSlotTypeStr[node->ch_slot],
                 node->ch_slotnum, node->ch_anafanum);
-       return (str);
+       return str;
 }

 static ibnd_chassis_t *find_chassisnum(ibnd_fabric_t * fabric,
@@ -96,10 +103,9 @@
 {
        ibnd_chassis_t *current;

-       for (current = fabric->first_chassis; current; current = current->next) {
+       for (current = fabric->chassis; current; current = current->next)
                if (current->chassisnum == chassisnum)
                        return current;
-       }

        return NULL;
 }
@@ -176,7 +182,7 @@
                        return sysimgguid;
        } else {
                if (!node->ports || !node->ports[1])
-                       return (0);
+                       return 0;

                /* Is there a peer port ? */
                if (!node->ports[1]->remoteport)
@@ -214,10 +220,9 @@
        uint64_t chguid;

        chguid = get_chassisguid(node);
-       for (current = fabric->first_chassis; current; current = current->next) {
+       for (current = fabric->chassis; current; current = current->next)
                if (current->chassisguid == chguid)
                        return current;
-       }

        return NULL;
 }
@@ -269,10 +274,23 @@
        return (devid == VTR_DEVID_SFB2012);
 }

+static int is_spine_4700(ibnd_node_t * n)
+{
+       uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
+       return (devid == VTR_DEVID_SFB4700);
+}
+
+static int is_spine_4700x2(ibnd_node_t * n)
+{
+       uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
+       return (devid == VTR_DEVID_SFB4700X2);
+}
+
 static int is_spine(ibnd_node_t * n)
 {
        return (is_spine_9096(n) || is_spine_9288(n) ||
-               is_spine_2004(n) || is_spine_2012(n));
+               is_spine_2004(n) || is_spine_2012(n) ||
+               is_spine_4700(n) || is_spine_4700x2(n));
 }

 static int is_line_24(ibnd_node_t * n)
@@ -294,9 +312,16 @@
        return (devid == VTR_DEVID_SLB2024);
 }

+static int is_line_4700(ibnd_node_t * n)
+{
+       uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
+       return (devid == VTR_DEVID_SLB4018);
+}
+
 static int is_line(ibnd_node_t * n)
 {
-       return (is_line_24(n) || is_line_8(n) || is_line_2024(n));
+       return (is_line_24(n) || is_line_8(n) ||
+               is_line_2024(n) || is_line_4700(n));
 }

 int is_chassis_switch(ibnd_node_t * n)
@@ -305,76 +330,136 @@
 }

 /* these structs help find Line (Anafa) slot number while using spine portnum */
-char 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
+char line_slot_2_sfb4[37] = {
+       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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
-char 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
+char anafa_line_slot_2_sfb4[37] = {
+       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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
-char 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
+
+char line_slot_2_sfb12[37] = {
+       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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
-char 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
+char anafa_line_slot_2_sfb12[37] = {
+       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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };

+/* LB slot = table[spine port] */
+char line_slot_2_sfb18[37] = {
+       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, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18};
+/* LB asic num = table[spine port] */
+char anafa_line_slot_2_sfb18[37] = {
+       0,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+/* LB slot = table[spine port] */
+char line_slot_2_sfb18x2[37] = {
+       0,
+       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+       0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0};
+/* LB asic num = table[spine port] */
+char anafa_line_slot_2_sfb18x2[37] = {
+       0,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
 /* IPR FCR modules connectivity while using sFB4 port as reference */
-char 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
+char ipr_slot_2_sfb4_port[37] = {
+       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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };

 /* these structs help find Spine (Anafa) slot number while using spine portnum */
-char 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
+char spine12_slot_2_slb[37] = {
+       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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
-char 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
+char anafa_spine12_slot_2_slb[37] = {
+       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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
-char 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
+
+char spine4_slot_2_slb[37] = {
+       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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
-char 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
+char anafa_spine4_slot_2_slb[37] = {
+       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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };

+/* FB slot = table[line port] */
+char spine18_slot_2_slb[37] = {
+       0,
+       1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+/* FB asic = table[line port] */
+char anafa_spine18_slot_2_slb[37] = {
+       0,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+char anafa_spine18x2_slot_2_slb[37] = {
+       0,
+       2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1,
+       0, 0, 0, 0, 0, 0, 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 int get_sfb_slot(ibnd_node_t * node, ibnd_port_t * lineport)
+static int get_sfb_slot(ibnd_node_t * n, ibnd_port_t * lineport)
 {
-       ibnd_node_t *n = (ibnd_node_t *) node;
-
        n->ch_slot = SPINE_CS;
-       if (is_spine_9096(node)) {
+       if (is_spine_9096(n)) {
                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)) {
+       } else if (is_spine_9288(n)) {
                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)) {
+       } else if (is_spine_2012(n)) {
                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)) {
+       } else if (is_spine_2004(n)) {
                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 if (is_spine_4700(n)) {
+               n->ch_type = ISR4700_CT;
+               n->ch_slotnum = spine18_slot_2_slb[lineport->portnum];
+               n->ch_anafanum = anafa_spine18_slot_2_slb[lineport->portnum];
+       } else if (is_spine_4700x2(n)) {
+               n->ch_type = ISR4700_CT;
+               n->ch_slotnum = spine18_slot_2_slb[lineport->portnum];
+               n->ch_anafanum = anafa_spine18x2_slot_2_slb[lineport->portnum];
        } else {
-               IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64,
-                          node->guid);
-               return (-1);
+               IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n",
+                          n->guid);
+               return -1;
        }
-       return (0);
+       return 0;
 }

 static int get_router_slot(ibnd_node_t * n, ibnd_port_t * spineport)
@@ -411,11 +496,11 @@
                n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
                n->ch_anafanum = ipr_slot_2_sfb4_port[spineport->portnum];
        } else {
-               IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64,
+               IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n",
                           spineport->node->guid);
-               return (-1);
+               return -1;
        }
-       return (0);
+       return 0;
 }

 static int get_slb_slot(ibnd_node_t * n, ibnd_port_t * spineport)
@@ -437,12 +522,20 @@
                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 if (is_spine_4700(spineport->node)) {
+               n->ch_type = ISR4700_CT;
+               n->ch_slotnum = line_slot_2_sfb18[spineport->portnum];
+               n->ch_anafanum = anafa_line_slot_2_sfb18[spineport->portnum];
+       } else if (is_spine_4700x2(spineport->node)) {
+               n->ch_type = ISR4700_CT;
+               n->ch_slotnum = line_slot_2_sfb18x2[spineport->portnum];
+               n->ch_anafanum = anafa_line_slot_2_sfb18x2[spineport->portnum];
        } else {
-               IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64,
+               IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n",
                           spineport->node->guid);
-               return (-1);
+               return -1;
        }
-       return (0);
+       return 0;
 }

 /* forward declare this */
@@ -459,24 +552,34 @@
        ibnd_node_t *remnode = 0;

        if (node->ch_found)     /* somehow this node has already been passed */
-               return (0);
+               return 0;
        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)) {
+       if (is_router(node))
                /* find the remote node */
                for (p = 1; p <= node->numports; p++) {
                        port = node->ports[p];
                        if (port && is_spine(port->remoteport->node))
                                get_router_slot(node, port->remoteport);
                }
-       } else if (is_spine(node)) {
+       else if (is_spine(node)) {
+               int is_4700x2 = is_spine_4700x2(node);
+
                for (p = 1; p <= node->numports; p++) {
                        port = node->ports[p];
                        if (!port || !port->remoteport)
                                continue;
+
+                       /*
+                        * Skip ISR4700 double density fabric boards ports 19-36
+                        * as they are chassis external ports
+                        */
+                       if (is_4700x2 && (port->portnum > 18))
+                               continue;
+
                        remnode = port->remoteport->node;
                        if (remnode->type != IB_NODE_SWITCH) {
                                if (!remnode->ch_found)
@@ -486,19 +589,26 @@
                        if (!node->ch_type)
                                /* we assume here that remoteport belongs to line */
                                if (get_sfb_slot(node, port->remoteport))
-                                       return (-1);
+                                       return -1;

                        /* we could break here, but need to find if more routers connected */
                }

        } else if (is_line(node)) {
+               int is_4700_line = is_line_4700(node);
+
                for (p = 1; p <= node->numports; p++) {
                        port = node->ports[p];
-                       if (!port || port->portnum > 12 || !port->remoteport)
+                       if (!port || !port->remoteport)
                                continue;
+
+                       if ((is_4700_line && (port->portnum > 18)) ||
+                           (!is_4700_line && (port->portnum > 12)))
+                               continue;
+
                        /* we assume here that remoteport belongs to spine */
                        if (get_slb_slot(node, port->remoteport))
-                               return (-1);
+                               return -1;
                        break;
                }
        }
@@ -511,16 +621,22 @@
                voltaire_portmap(port);
        }

-       return (0);
+       return 0;
 }

 static int get_line_index(ibnd_node_t * node)
 {
-       int retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum;
+       int retval;

+       if (is_line_4700(node))
+               retval = node->ch_slotnum;
+       else
+               retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum;
+
        if (retval > LINES_MAX_NUM || retval < 1) {
+               printf("%s: retval = %d\n", __FUNCTION__, retval);
                IBND_ERROR("Internal error\n");
-               return (-1);
+               return -1;
        }
        return retval;
 }
@@ -531,12 +647,14 @@

        if (is_spine_9288(node) || is_spine_2012(node))
                retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum;
+       else if (is_spine_4700(node) || is_spine_4700x2(node))
+               retval = 2 * (node->ch_slotnum - 1) + node->ch_anafanum;
        else
                retval = node->ch_slotnum;

        if (retval > SPINES_MAX_NUM || retval < 1) {
                IBND_ERROR("Internal error\n");
-               return (-1);
+               return -1;
        }
        return retval;
 }
@@ -546,14 +664,14 @@
        int i = get_line_index(node);

        if (i < 0)
-               return (i);
+               return i;

        if (chassis->linenode[i])
-               return (0);     /* already filled slot */
+               return 0;       /* already filled slot */

        chassis->linenode[i] = node;
        node->chassis = chassis;
-       return (0);
+       return 0;
 }

 static int insert_spine(ibnd_node_t * node, ibnd_chassis_t * chassis)
@@ -561,14 +679,14 @@
        int i = get_spine_index(node);

        if (i < 0)
-               return (i);
+               return i;

        if (chassis->spinenode[i])
-               return (0);     /* already filled slot */
+               return 0;       /* already filled slot */

        chassis->spinenode[i] = node;
        node->chassis = chassis;
-       return (0);
+       return 0;
 }

 static int pass_on_lines_catch_spines(ibnd_chassis_t * chassis)
@@ -578,25 +696,34 @@
        int i, p;

        for (i = 1; i <= LINES_MAX_NUM; i++) {
+               int is_4700_line;
+
                node = chassis->linenode[i];

                if (!(node && is_line(node)))
                        continue;       /* empty slot or router */

+               is_4700_line = is_line_4700(node);
+
                for (p = 1; p <= node->numports; p++) {
+
                        port = node->ports[p];
-                       if (!port || port->portnum > 12 || !port->remoteport)
+                       if (!port || !port->remoteport)
                                continue;

+                       if ((is_4700_line && (port->portnum > 18)) ||
+                           (!is_4700_line && (port->portnum > 12)))
+                               continue;
+
                        remnode = port->remoteport->node;

                        if (!remnode->ch_found)
                                continue;       /* some error - spine not initialized ? FIXME */
                        if (insert_spine(remnode, chassis))
-                               return (-1);
+                               return -1;
                }
        }
-       return (0);
+       return 0;
 }

 static int pass_on_spines_catch_lines(ibnd_chassis_t * chassis)
@@ -606,22 +733,36 @@
        int i, p;

        for (i = 1; i <= SPINES_MAX_NUM; i++) {
+               int is_4700x2;
+
                node = chassis->spinenode[i];
                if (!node)
                        continue;       /* empty slot */
+
+               is_4700x2 = is_spine_4700x2(node);
+
                for (p = 1; p <= node->numports; p++) {
                        port = node->ports[p];
                        if (!port || !port->remoteport)
                                continue;
+
+                       /*
+                        * ISR4700 double density fabric board ports 19-36 are
+                        * chassis external ports, so skip them
+                        */
+                       if (is_4700x2 && (port->portnum > 18))
+                               continue;
+
                        remnode = port->remoteport->node;

                        if (!remnode->ch_found)
                                continue;       /* some error - line/router not initialized ? FIXME */
+
                        if (insert_line_router(remnode, chassis))
-                               return (-1);
+                               return -1;
                }
        }
-       return (0);
+       return 0;
 }

 /*
@@ -656,14 +797,23 @@
        ibnd_port_t *port = 0;

        /* we get here with node = chassis_spine */
-       if (insert_spine((ibnd_node_t *) node, chassis))
-               return (-1);
+       if (insert_spine(node, chassis))
+               return -1;

        /* loop: pass on all ports of node */
        for (p = 1; p <= node->numports; p++) {
+
                port = node->ports[p];
                if (!port || !port->remoteport)
                        continue;
+
+               /*
+                * ISR4700 double density fabric board ports 19-36 are
+                * chassis external ports, so skip them
+                */
+               if (is_spine_4700x2(node) && (port->portnum > 18))
+                       continue;
+
                remnode = port->remoteport->node;

                if (!remnode->ch_found)
@@ -673,22 +823,22 @@
        }

        if (pass_on_lines_catch_spines(chassis))
-               return (-1);
+               return -1;
        /* 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 */
        if (pass_on_spines_catch_lines(chassis))
-               return (-1);
+               return -1;

        /* 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 */
        if (pass_on_lines_catch_spines(chassis))
-               return (-1);
+               return -1;
        if (pass_on_spines_catch_lines(chassis))
-               return (-1);
+               return -1;
        pass_on_spines_interpolate_chguid(chassis);

-       return (0);
+       return 0;
 }

 /*========================================================*/
@@ -732,6 +882,21 @@
 A2 int port| 13 14 15 16 17 18 19 20 21 22 23 24
 ---------------------------------------------------

+Module : sLB-4018
+
+int port | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
+ext port |  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18
+---------------------------------------------------
+
+Module : sFB-4700X2
+
+  12X port -> 3 x 4X ports:
+
+A1 int port | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
+   ext port |  7  7  7  8  8  8  9  9  9 10 10 10 11 11 11 12 12 12
+A2 int port | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
+   ext port |  1  1  1  2  2  2  3  3  3  4  4  4  5  5  5  6  6  6
+
 */

 int int2ext_map_slb24[2][25] = {
@@ -740,12 +905,14 @@
        {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},
@@ -753,6 +920,21 @@
         11, 12}
 };

+int int2ext_map_slb4018[37] = {
+       0,
+       0, 0, 0, 0, 0, 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, 13, 14, 15, 16, 17, 18
+};
+
+int int2ext_map_sfb4700x2[2][37] = {
+       {0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12},
+       {0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6}
+};
+
 /*     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 */
@@ -761,12 +943,22 @@
        int portnum = port->portnum;
        int chipnum = 0;
        ibnd_node_t *node = port->node;
+       int is_4700_line = is_line_4700(node);
+       int is_4700x2_spine = is_spine_4700x2(node);

-       if (!node->ch_found || !is_line(node) || (portnum < 13 || portnum > 24)) {
+       if (!node->ch_found || (!is_line(node) && !is_4700x2_spine)) {
                port->ext_portnum = 0;
                return;
        }

+       if (((is_4700_line || is_4700x2_spine) &&
+            (portnum < 19 || portnum > 36)) ||
+           ((!is_4700_line && !is_4700x2_spine) &&
+            (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;
@@ -778,25 +970,33 @@
                port->ext_portnum = int2ext_map_slb24[chipnum][portnum];
        else if (is_line_2024(node))
                port->ext_portnum = int2ext_map_slb2024[chipnum][portnum];
+       /* sLB-4018: Only one asic per LB */
+       else if (is_4700_line)
+               port->ext_portnum = int2ext_map_slb4018[portnum];
+       /* sFB-4700X2 4X port */
+       else if (is_4700x2_spine)
+               port->ext_portnum = int2ext_map_sfb4700x2[chipnum][portnum];
        else
                port->ext_portnum = int2ext_map_slb8[chipnum][portnum];
 }

-static int add_chassis(ibnd_fabric_t * fabric)
+static int add_chassis(chassis_scan_t * chassis_scan)
 {
-       if (!(fabric->current_chassis = calloc(1, sizeof(ibnd_chassis_t)))) {
+       if (!(chassis_scan->current_chassis =
+             calloc(1, sizeof(ibnd_chassis_t)))) {
                IBND_ERROR("OOM: failed to allocate chassis object\n");
-               return (-1);
+               return -1;
        }

-       if (fabric->first_chassis == NULL) {
-               fabric->first_chassis = fabric->current_chassis;
-               fabric->last_chassis = fabric->current_chassis;
+       if (chassis_scan->first_chassis == NULL) {
+               chassis_scan->first_chassis = chassis_scan->current_chassis;
+               chassis_scan->last_chassis = chassis_scan->current_chassis;
        } else {
-               fabric->last_chassis->next = fabric->current_chassis;
-               fabric->last_chassis = fabric->current_chassis;
+               chassis_scan->last_chassis->next =
+                   chassis_scan->current_chassis;
+               chassis_scan->last_chassis = chassis_scan->current_chassis;
        }
-       return (0);
+       return 0;
 }

 static void add_node_to_chassis(ibnd_chassis_t * chassis, ibnd_node_t * node)
@@ -821,103 +1021,95 @@
 int group_nodes(ibnd_fabric_t * fabric)
 {
        ibnd_node_t *node;
-       int dist;
        int chassisnum = 0;
        ibnd_chassis_t *chassis;
+       ibnd_chassis_t *ch, *ch_next;
+       chassis_scan_t chassis_scan;

-       fabric->first_chassis = NULL;
-       fabric->current_chassis = NULL;
+       chassis_scan.first_chassis = NULL;
+       chassis_scan.current_chassis = NULL;
+       chassis_scan.last_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->maxhops_discovered; dist++) {
-               for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
-                       if (mad_get_field(node->info, 0,
-                                         IB_NODE_VENDORID_F) == VTR_VENDOR_ID)
-                               if (fill_voltaire_chassis_record(node))
-                                       return (-1);
-               }
+       for (node = fabric->switches; node; node = node->type_next) {
+               if (mad_get_field(node->info, 0,
+                                 IB_NODE_VENDORID_F) == VTR_VENDOR_ID
+                   && fill_voltaire_chassis_record(node))
+                       goto cleanup;
        }

        /* 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->maxhops_discovered; dist++) {
-               for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
-                       if (mad_get_field(node->info, 0,
-                                         IB_NODE_VENDORID_F) != VTR_VENDOR_ID)
-                               continue;
-                       if (!node->ch_found
-                           || (node->chassis && node->chassis->chassisnum)
-                           || !is_spine(node))
-                               continue;
-                       if (add_chassis(fabric))
-                               return (-1);
-                       fabric->current_chassis->chassisnum = ++chassisnum;
-                       if (build_chassis(node, fabric->current_chassis))
-                               return (-1);
-               }
+       for (node = fabric->switches; node; node = node->type_next) {
+               if (mad_get_field(node->info, 0,
+                                 IB_NODE_VENDORID_F) != VTR_VENDOR_ID)
+                       continue;
+               if (!node->ch_found
+                   || (node->chassis && node->chassis->chassisnum)
+                   || !is_spine(node))
+                       continue;
+               if (add_chassis(&chassis_scan))
+                       goto cleanup;
+               chassis_scan.current_chassis->chassisnum = ++chassisnum;
+               if (build_chassis(node, chassis_scan.current_chassis))
+                       goto cleanup;
        }

        /* now make pass on nodes for chassis which are not Voltaire */
        /* grouped by common SystemImageGUID */
-       for (dist = 0; dist <= fabric->maxhops_discovered; dist++) {
-               for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
-                       if (mad_get_field(node->info, 0,
-                                         IB_NODE_VENDORID_F) == VTR_VENDOR_ID)
-                               continue;
-                       if (mad_get_field64(node->info, 0,
-                                           IB_NODE_SYSTEM_GUID_F)) {
-                               chassis =
-                                   find_chassisguid(fabric,
-                                                    (ibnd_node_t *) node);
-                               if (chassis)
-                                       chassis->nodecount++;
-                               else {
-                                       /* Possible new chassis */
-                                       if (add_chassis(fabric))
-                                               return (-1);
-                                       fabric->current_chassis->chassisguid =
-                                           get_chassisguid((ibnd_node_t *)
-                                                           node);
-                                       fabric->current_chassis->nodecount = 1;
-                               }
+       for (node = fabric->nodes; node; node = node->next) {
+               if (mad_get_field(node->info, 0,
+                                 IB_NODE_VENDORID_F) == VTR_VENDOR_ID)
+                       continue;
+               if (mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F)) {
+                       chassis = find_chassisguid(fabric, node);
+                       if (chassis)
+                               chassis->nodecount++;
+                       else {
+                               /* Possible new chassis */
+                               if (add_chassis(&chassis_scan))
+                                       goto cleanup;
+                               chassis_scan.current_chassis->chassisguid =
+                                   get_chassisguid(node);
+                               chassis_scan.current_chassis->nodecount = 1;
+                               if (!fabric->chassis)
+                                       fabric->chassis = chassis_scan.first_chassis;
                        }
                }
        }

        /* 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 (mad_get_field(node->info, 0,
-                                         IB_NODE_VENDORID_F) == VTR_VENDOR_ID)
-                               continue;
-                       if (mad_get_field64(node->info, 0,
-                                           IB_NODE_SYSTEM_GUID_F)) {
-                               chassis =
-                                   find_chassisguid(fabric,
-                                                    (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);
-                                       }
+       for (node = fabric->nodes; node; node = node->next) {
+               if (mad_get_field(node->info, 0,
+                                 IB_NODE_VENDORID_F) == VTR_VENDOR_ID)
+                       continue;
+               if (mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F)) {
+                       chassis = find_chassisguid(fabric, 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, node);
                                }
                        }
                }
-               if (dist == fabric->maxhops_discovered)
-                       dist = MAXHOPS; /* skip to CAs */
-               else
-                       dist++;
        }

-       fabric->chassis = fabric->first_chassis;
-       return (0);
+       fabric->chassis = chassis_scan.first_chassis;
+       return 0;
+
+cleanup:
+       ch = chassis_scan.first_chassis;
+       while (ch) {
+               ch_next = ch->next;
+               free(ch);
+               ch = ch_next;
+       }
+       fabric->chassis = NULL;
+       return -1;
 }
Index: ulp/libibnetdisc/src/chassis.h
===================================================================
--- ulp/libibnetdisc/src/chassis.h      (revision 2812)
+++ ulp/libibnetdisc/src/chassis.h      (working copy)
@@ -70,6 +70,9 @@
 #define VTR_DEVID_SFB2004              0x5a40
 #define VTR_DEVID_ISR2004              0x5a41
 #define VTR_DEVID_SRB2004              0x5a42
+#define VTR_DEVID_SLB4018              0x5a5b
+#define VTR_DEVID_SFB4700              0x5a5c
+#define VTR_DEVID_SFB4700X2            0x5a5d

 /* Vendor IDs (for chassis based systems) */
 #define VTR_VENDOR_ID                  0x8f1   /* Voltaire */
@@ -78,7 +81,8 @@
 #define XS_VENDOR_ID                   0x1397  /* Xsigo */

 enum ibnd_chassis_type {
-       UNRESOLVED_CT, ISR9288_CT, ISR9096_CT, ISR2012_CT, ISR2004_CT
+       UNRESOLVED_CT, ISR9288_CT, ISR9096_CT, ISR2012_CT, ISR2004_CT,
+       ISR4700_CT
 };
 enum ibnd_chassis_slot_type { UNRESOLVED_CS, LINE_CS, SPINE_CS, SRBD_CS };

Index: ulp/libibnetdisc/src/ibnetdisc.c
===================================================================
--- ulp/libibnetdisc/src/ibnetdisc.c    (revision 2812)
+++ ulp/libibnetdisc/src/ibnetdisc.c    (working copy)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
+ * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
  * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
  * Copyright (c) 2008 Lawrence Livermore National Laboratory
  *
@@ -34,17 +34,14 @@
  */

 #if HAVE_CONFIG_H
-#  include <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>

@@ -57,272 +54,332 @@
 #include "internal.h"
 #include "chassis.h"

-static int show_progress = 0;
-int ibdebug;
+/* forward declare */
+static int query_node_info(smp_engine_t * engine, ib_portid_t * portid,
+                          ibnd_node_t * node);

-void decode_port_info(ibnd_port_t * port)
+static int recv_switch_info(smp_engine_t * engine, ibnd_smp_t * smp,
+                           uint8_t * mad, void *cb_data)
 {
-       port->base_lid = (uint16_t) mad_get_field(port->info, 0, IB_PORT_LID_F);
-       port->lmc = (uint8_t) mad_get_field(port->info, 0, IB_PORT_LMC_F);
+       uint8_t *switch_info = mad + IB_SMP_DATA_OFFS;
+       ibnd_node_t *node = cb_data;
+       memcpy(node->switchinfo, switch_info, sizeof(node->switchinfo));
+       mad_decode_field(node->switchinfo, IB_SW_ENHANCED_PORT0_F,
+                        &node->smaenhsp0);
+       return 0;
 }

-static int get_port_info(struct ibmad_port *ibmad_port,
-                        ibnd_fabric_t * fabric, ibnd_port_t * port,
-                        int portnum, ib_portid_t * portid)
+static int query_switch_info(smp_engine_t * engine, ib_portid_t * portid,
+                            ibnd_node_t * node)
 {
+       node->smaenhsp0 = 0;    /* assume base SP0 */
+       return issue_smp(engine, portid, IB_ATTR_SWITCH_INFO, 0,
+                        recv_switch_info, node);
+}
+
+static int add_port_to_dpath(ib_dr_path_t * path, int nextport)
+{
+       if (path->cnt > sizeof(path->p) - 1)
+               return -1;
+       ++path->cnt;
+       path->p[path->cnt] = (uint8_t) nextport;
+       return path->cnt;
+}
+
+static int extend_dpath(smp_engine_t * engine, ib_portid_t * portid,
+                       int nextport)
+{
+       ibnd_scan_t *scan = engine->user_data;
+       ibnd_fabric_t *fabric = scan->fabric;
+
+       if (scan->cfg->max_hops &&
+           fabric->maxhops_discovered >= scan->cfg->max_hops)
+               return 0;
+
+       if (portid->lid) {
+               /* If we were LID routed we need to set up the drslid */
+               if (!scan->selfportid.lid)
+                       if (ib_resolve_self_via(&scan->selfportid, NULL, NULL,
+                                               scan->ibmad_port) < 0) {
+                               IBND_ERROR("Failed to resolve self\n");
+                               return -1;
+                       }
+               portid->drpath.drslid = (uint16_t) scan->selfportid.lid;
+               portid->drpath.drdlid = 0xFFFF;
+       }
+
+       if (add_port_to_dpath(&portid->drpath, nextport) < 0) {
+               IBND_ERROR("add port %d to DR path failed; %s\n", nextport,
+                          portid2str(portid));
+               return -1;
+       }
+
+       if ((unsigned) portid->drpath.cnt > fabric->maxhops_discovered)
+               fabric->maxhops_discovered = portid->drpath.cnt;
+
+       return 1;
+}
+
+static int recv_node_desc(smp_engine_t * engine, ibnd_smp_t * smp,
+                         uint8_t * mad, void *cb_data)
+{
+       uint8_t *node_desc = mad + IB_SMP_DATA_OFFS;
+       ibnd_node_t *node = cb_data;
+       memcpy(node->nodedesc, node_desc, sizeof(node->nodedesc));
+       return 0;
+}
+
+static int query_node_desc(smp_engine_t * engine, ib_portid_t * portid,
+                          ibnd_node_t * node)
+{
+       return issue_smp(engine, portid, IB_ATTR_NODE_DESC, 0,
+                        recv_node_desc, node);
+}
+
+static void debug_port(ib_portid_t * portid, ibnd_port_t * port)
+{
        char width[64], speed[64];
        int iwidth;
        int ispeed;

-       port->portnum = portnum;
        iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F);
        ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F);
-
-       if (!smp_query_via(port->info, portid, IB_ATTR_PORT_INFO,
-                          portnum, 0, ibmad_port))
-               return -1;
-
-       decode_port_info(port);
-
        IBND_DEBUG
            ("portid %s portnum %d: base lid %d state %d physstate %d %s %s\n",
-            portid2str(portid), portnum, port->base_lid,
+            portid2str(portid), port->portnum, port->base_lid,
             mad_get_field(port->info, 0, IB_PORT_STATE_F),
             mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F),
             mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, width, 64, &iwidth),
             mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, speed, 64, &ispeed));
-       return 0;
 }

-/*
- * Returns -1 if error.
- */
-static int query_node_info(struct ibmad_port *ibmad_port,
-                          ibnd_fabric_t * fabric, ibnd_node_t * node,
-                          ib_portid_t * portid)
+static int recv_port_info(smp_engine_t * engine, ibnd_smp_t * smp,
+                         uint8_t * mad, void *cb_data)
 {
-       if (!smp_query_via(&(node->info), portid, IB_ATTR_NODE_INFO, 0, 0,
-                          ibmad_port))
-               return -1;
+       ibnd_fabric_t *fabric = ((ibnd_scan_t *) engine->user_data)->fabric;
+       ibnd_node_t *node = cb_data;
+       ibnd_port_t *port;
+       uint8_t *port_info = mad + IB_SMP_DATA_OFFS;
+       uint8_t port_num, local_port;

-       /* decode just a couple of fields for quicker reference. */
-       mad_decode_field(node->info, IB_NODE_GUID_F, &(node->guid));
-       mad_decode_field(node->info, IB_NODE_TYPE_F, &(node->type));
-       mad_decode_field(node->info, IB_NODE_NPORTS_F, &(node->numports));
+       port_num = (uint8_t) mad_get_field(mad, 0, IB_MAD_ATTRMOD_F);
+       local_port = (uint8_t) mad_get_field(port_info, 0, IB_PORT_LOCAL_PORT_F);

-       return (0);
-}
+       /* this may have been created before */
+       port = node->ports[port_num];
+       if (!port) {
+               port = node->ports[port_num] = calloc(1, sizeof(*port));
+               if (!port) {
+                       IBND_ERROR("Failed to allocate port\n");
+                       return -1;
+               }
+               port->guid =
+                   mad_get_field64(node->info, 0, IB_NODE_PORT_GUID_F);
+       }

-/*
- * Returns 0 if non switch node is found, 1 if switch is found, -1 if error.
- */
-static int query_node(struct ibmad_port *ibmad_port, ibnd_fabric_t * fabric,
-                     ibnd_node_t * node, ibnd_port_t * port,
-                     ib_portid_t * portid)
-{
-       int rc = 0;
-       void *nd = node->nodedesc;
+       memcpy(port->info, port_info, sizeof(port->info));
+       port->node = node;
+       port->portnum = port_num;
+       port->ext_portnum = 0;
+       port->base_lid = (uint16_t) mad_get_field(port->info, 0, IB_PORT_LID_F);
+       port->lmc = (uint8_t) mad_get_field(port->info, 0, IB_PORT_LMC_F);

-       if ((rc = query_node_info(ibmad_port, fabric, node, portid)) != 0)
-               return rc;
+       if (port_num == 0) {
+               node->smalid = port->base_lid;
+               node->smalmc = port->lmc;
+       } else if (node->type == IB_NODE_SWITCH) {
+               port->base_lid = node->smalid;
+               port->lmc = node->smalmc;
+       }

-       port->portnum = mad_get_field(node->info, 0, IB_NODE_LOCAL_PORT_F);
-       port->guid = mad_get_field64(node->info, 0, IB_NODE_PORT_GUID_F);
+       add_to_portguid_hash(port, fabric->portstbl);

-       if (!smp_query_via(nd, portid, IB_ATTR_NODE_DESC, 0, 0, ibmad_port))
-               return -1;
+       debug_port(&smp->path, port);

-       if (!smp_query_via(port->info, portid, IB_ATTR_PORT_INFO, 0, 0,
-                          ibmad_port))
-               return -1;
-       decode_port_info(port);
+       if (port_num && mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F)
+           == IB_PORT_PHYS_STATE_LINKUP
+           && ((node->type == IB_NODE_SWITCH && port_num != local_port) ||
+               (node == fabric->from_node && port_num == local_port))) {
+               ib_portid_t path = smp->path;
+               if (extend_dpath(engine, &path, port_num) > 0)
+                       query_node_info(engine, &path, node);
+       }

-       if (node->type != IB_NODE_SWITCH)
-               return 0;
-
-       node->smalid = port->base_lid;
-       node->smalmc = port->lmc;
-
-       /* after we have the sma information find out the real PortInfo for this port */
-       if (!smp_query_via(port->info, portid, IB_ATTR_PORT_INFO,
-                          port->portnum, 0, ibmad_port))
-               return -1;
-       decode_port_info(port);
-
-       port->base_lid = (uint16_t) node->smalid;       /* LID is still defined by port 0 */
-       port->lmc = (uint8_t) node->smalmc;
-
-       if (!smp_query_via(node->switchinfo, portid, IB_ATTR_SWITCH_INFO, 0, 0,
-                          ibmad_port))
-               node->smaenhsp0 = 0;    /* assume base SP0 */
-       else
-               mad_decode_field(node->switchinfo, IB_SW_ENHANCED_PORT0_F,
-                                &node->smaenhsp0);
-
-       IBND_DEBUG("portid %s: got switch node %" PRIx64 " '%s'\n",
-                  portid2str(portid), node->guid, node->nodedesc);
        return 0;
 }

-static int add_port_to_dpath(ib_dr_path_t * path, int nextport)
+static int query_port_info(smp_engine_t * engine, ib_portid_t * portid,
+                          ibnd_node_t * node, int portnum)
 {
-       if (path->cnt + 2 >= sizeof(path->p)) {
-               IBND_ERROR("DR path has grown too long\n");
-               return -1;
-       }
-       ++path->cnt;
-       path->p[path->cnt] = (uint8_t) nextport;
-       return path->cnt;
+       IBND_DEBUG("Query Port Info; %s (0x%" PRIx64 "):%d\n",
+                  portid2str(portid), node->guid, portnum);
+       return issue_smp(engine, portid, IB_ATTR_PORT_INFO, portnum,
+                        recv_port_info, node);
 }

-static void retract_dpath(ib_portid_t * path)
+static ibnd_node_t *create_node(smp_engine_t * engine, ib_portid_t * path,
+                               uint8_t * node_info)
 {
-       path->drpath.cnt--;     /* restore path */
-       if (path->drpath.cnt == 0 && path->lid) {
-               /* return to lid based routing on this path */
-               path->drpath.drslid = 0;
-               path->drpath.drdlid = 0;
+       ibnd_fabric_t *fabric = ((ibnd_scan_t *) engine->user_data)->fabric;
+       ibnd_node_t *rc = calloc(1, sizeof(*rc));
+       if (!rc) {
+               IBND_ERROR("OOM: node creation failed\n");
+               return NULL;
        }
-}

-static int extend_dpath(struct ibmad_port *ibmad_port, ibnd_fabric_t * fabric,
-                       ib_portid_t * portid, int nextport)
-{
-       int rc = 0;
+       /* decode just a couple of fields for quicker reference. */
+       mad_decode_field(node_info, IB_NODE_GUID_F, &rc->guid);
+       mad_decode_field(node_info, IB_NODE_TYPE_F, &rc->type);
+       mad_decode_field(node_info, IB_NODE_NPORTS_F, &rc->numports);

-       if (portid->lid) {
-               /* If we were LID routed we need to set up the drslid */
-               if (!fabric->selfportid.lid)
-                       if (ib_resolve_self_via(&fabric->selfportid, NULL, NULL,
-                                               ibmad_port) < 0) {
-                               IBND_ERROR("Failed to resolve self\n");
-                               return -1;
-                       }
-
-               portid->drpath.drslid = (uint16_t) fabric->selfportid.lid;
-               portid->drpath.drdlid = 0xFFFF;
+       rc->ports = calloc(rc->numports + 1, sizeof(*rc->ports));
+       if (!rc->ports) {
+               free(rc);
+               IBND_ERROR("OOM: Failed to allocate the ports array\n");
+               return NULL;
        }

-       rc = add_port_to_dpath(&portid->drpath, nextport);
+       rc->path_portid = *path;
+       memcpy(rc->info, node_info, sizeof(rc->info));

-       if ((rc != -1) && (portid->drpath.cnt > fabric->maxhops_discovered))
-               fabric->maxhops_discovered = portid->drpath.cnt;
-       return (rc);
+       add_to_nodeguid_hash(rc, fabric->nodestbl);
+
+       /* add this to the all nodes list */
+       rc->next = fabric->nodes;
+       fabric->nodes = rc;
+
+       add_to_type_list(rc, fabric);
+
+       return rc;
 }

+static int get_last_port(ib_portid_t * path)
+{
+       return path->drpath.p[path->drpath.cnt];
+}
+
+static void link_ports(ibnd_node_t * node, ibnd_port_t * port,
+                      ibnd_node_t * remotenode, ibnd_port_t * remoteport)
+{
+       IBND_DEBUG("linking: 0x%" PRIx64 " %p->%p:%u and 0x%" PRIx64
+                  " %p->%p:%u\n", node->guid, node, port, port->portnum,
+                  remotenode->guid, remotenode, remoteport,
+                  remoteport->portnum);
+       if (port->remoteport)
+               port->remoteport->remoteport = NULL;
+       if (remoteport->remoteport)
+               remoteport->remoteport->remoteport = NULL;
+       port->remoteport = remoteport;
+       remoteport->remoteport = port;
+}
+
 static void dump_endnode(ib_portid_t * path, char *prompt,
                         ibnd_node_t * node, ibnd_port_t * port)
 {
        char type[64];
-       if (!show_progress)
-               return;
-
-       mad_dump_node_type(type, 64, &(node->type), sizeof(int));
-       printf("%s -> %s %s {%016" PRIx64 "} portnum %d base lid %d-%d\"%s\"\n",
+       mad_dump_node_type(type, sizeof(type), &node->type, sizeof(int));
+       printf("%s -> %s %s {%016" PRIx64 "} portnum %d lid %d-%d \"%s\"\n",
               portid2str(path), prompt, type, node->guid,
               node->type == IB_NODE_SWITCH ? 0 : port->portnum,
-              port->base_lid,
-              port->base_lid + (1 << port->lmc) - 1, node->nodedesc);
+              port->base_lid, port->base_lid + (1 << port->lmc) - 1,
+              node->nodedesc);
 }

-static ibnd_node_t *find_existing_node(ibnd_fabric_t * fabric,
-                                      ibnd_node_t * new)
+static int recv_node_info(smp_engine_t * engine, ibnd_smp_t * smp,
+                         uint8_t * mad, void *cb_data)
 {
-       int hash = HASHGUID(new->guid) % HTSZ;
+       ibnd_scan_t *scan = engine->user_data;
+       ibnd_fabric_t *fabric = scan->fabric;
+       int i = 0;
+       uint8_t *node_info = mad + IB_SMP_DATA_OFFS;
+       ibnd_node_t *rem_node = cb_data;
        ibnd_node_t *node;
+       int node_is_new = 0;
+       uint64_t node_guid = mad_get_field64(node_info, 0, IB_NODE_GUID_F);
+       uint64_t port_guid = mad_get_field64(node_info, 0, IB_NODE_PORT_GUID_F);
+       int port_num = mad_get_field(node_info, 0, IB_NODE_LOCAL_PORT_F);
+       ibnd_port_t *port = NULL;

-       for (node = fabric->nodestbl[hash]; node; node = node->htnext)
-               if (node->guid == new->guid)
-                       return node;
+       node = ibnd_find_node_guid(fabric, node_guid);
+       if (!node) {
+               node = create_node(engine, &smp->path, node_info);
+               if (!node)
+                       return -1;
+               node_is_new = 1;
+       }
+       IBND_DEBUG("Found %s node GUID 0x%" PRIx64 " (%s)\n",
+                  node_is_new ? "new" : "old", node->guid,
+                  portid2str(&smp->path));

-       return NULL;
-}
+       port = node->ports[port_num];
+       if (!port) {
+               /* If we have not see this port before create a shell for it */
+               port = node->ports[port_num] = calloc(1, sizeof(*port));
+               port->node = node;
+               port->portnum = port_num;
+       }
+       port->guid = port_guid;

-ibnd_node_t *ibnd_find_node_guid(ibnd_fabric_t * fabric, uint64_t guid)
-{
-       int hash = HASHGUID(guid) % HTSZ;
-       ibnd_node_t *node;
+       if (scan->cfg->show_progress)
+               dump_endnode(&smp->path, node_is_new ? "new" : "known",
+                            node, port);

-       if (!fabric) {
-               IBND_DEBUG("fabric parameter NULL\n");
-               return (NULL);
+       if (rem_node == NULL)   /* this is the start node */
+               fabric->from_node = node;
+       else {
+               /* link ports... */
+               int rem_port_num = get_last_port(&smp->path);
+
+               if (!rem_node->ports[rem_port_num]) {
+                       IBND_ERROR("Internal Error; "
+                                  "Node(%p) 0x%" PRIx64
+                                  " Port %d no port created!?!?!?\n\n",
+                                  rem_node, rem_node->guid, rem_port_num);
+                       return -1;
+               }
+
+               link_ports(node, port, rem_node, rem_node->ports[rem_port_num]);
        }

-       for (node = fabric->nodestbl[hash]; node; node = node->htnext)
-               if (node->guid == guid)
-                       return (ibnd_node_t *) node;
+       if (node_is_new) {
+               query_node_desc(engine, &smp->path, node);

-       return NULL;
+               if (node->type == IB_NODE_SWITCH) {
+                       query_switch_info(engine, &smp->path, node);
+                       for (i = 0; i <= node->numports; i++)
+                               query_port_info(engine, &smp->path, node, i);
+               }
+       }
+
+       if (node->type != IB_NODE_SWITCH)
+               query_port_info(engine, &smp->path, node, port_num);
+
+       return 0;
 }

-static int _check_ibmad_port(struct ibmad_port *ibmad_port)
+static int query_node_info(smp_engine_t * engine, ib_portid_t * portid,
+                          ibnd_node_t * node)
 {
-       if (!ibmad_port) {
-               IBND_DEBUG("ibmad_port must be specified\n");
-               return (-1);
-       }
-       if (mad_rpc_class_agent(ibmad_port, IB_SMI_CLASS) == -1
-           || mad_rpc_class_agent(ibmad_port, IB_SMI_DIRECT_CLASS) == -1) {
-               IBND_DEBUG("ibmad_port must be opened with "
-                          "IB_SMI_CLASS && IB_SMI_DIRECT_CLASS\n");
-               return (-1);
-       }
-       return (0);
+       IBND_DEBUG("Query Node Info; %s\n", portid2str(portid));
+       return issue_smp(engine, portid, IB_ATTR_NODE_INFO, 0,
+                        recv_node_info, node);
 }

-ibnd_node_t *ibnd_update_node(struct ibmad_port * ibmad_port,
-                             ibnd_fabric_t * fabric, ibnd_node_t * node)
+ibnd_node_t *ibnd_find_node_guid(ibnd_fabric_t * fabric, uint64_t guid)
 {
-       char portinfo_port0[IB_SMP_DATA_SIZE];
-       void *nd = node->nodedesc;
-       int p = 0;
+       int hash = HASHGUID(guid) % HTSZ;
+       ibnd_node_t *node;

-       if (_check_ibmad_port(ibmad_port) < 0)
-               return (NULL);
-
        if (!fabric) {
                IBND_DEBUG("fabric parameter NULL\n");
-               return (NULL);
+               return NULL;
        }

-       if (!node) {
-               IBND_DEBUG("node parameter NULL\n");
-               return (NULL);
-       }
+       for (node = fabric->nodestbl[hash]; node; node = node->htnext)
+               if (node->guid == guid)
+                       return node;

-       if (query_node_info(ibmad_port, fabric, node, &(node->path_portid)))
-               return (NULL);
-
-       if (!smp_query_via(nd, &(node->path_portid), IB_ATTR_NODE_DESC, 0, 0,
-                          ibmad_port))
-               return (NULL);
-
-       /* update all the port info's */
-       for (p = 1; p >= node->numports; p++) {
-               get_port_info(ibmad_port, fabric, node->ports[p],
-                             p, &(node->path_portid));
-       }
-
-       if (node->type != IB_NODE_SWITCH)
-               goto done;
-
-       if (!smp_query_via
-           (portinfo_port0, &(node->path_portid), IB_ATTR_PORT_INFO, 0, 0,
-            ibmad_port))
-               return (NULL);
-
-       node->smalid = mad_get_field(portinfo_port0, 0, IB_PORT_LID_F);
-       node->smalmc = mad_get_field(portinfo_port0, 0, IB_PORT_LMC_F);
-
-       if (!smp_query_via(node->switchinfo, &(node->path_portid),
-                          IB_ATTR_SWITCH_INFO, 0, 0, ibmad_port))
-               node->smaenhsp0 = 0;    /* assume base SP0 */
-       else
-               mad_decode_field(node->switchinfo, IB_SW_ENHANCED_PORT0_F,
-                                &node->smaenhsp0);
-
-done:
-       return (node);
+       return NULL;
 }

 ibnd_node_t *ibnd_find_node_dr(ibnd_fabric_t * fabric, char *dr_str)
@@ -333,33 +390,32 @@

        if (!fabric) {
                IBND_DEBUG("fabric parameter NULL\n");
-               return (NULL);
+               return NULL;
        }

        rc = fabric->from_node;

-       if (str2drpath(&path, dr_str, 0, 0) == -1) {
-               return (NULL);
-       }
+       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);
+                       return NULL;

                remote_port = rc->ports[path.p[i]]->remoteport;
                if (!remote_port)
-                       return (NULL);
+                       return NULL;

                rc = remote_port->node;
        }

-       return (rc);
+       return rc;
 }

-static void add_to_nodeguid_hash(ibnd_node_t * node, ibnd_node_t * hash[])
+void add_to_nodeguid_hash(ibnd_node_t * node, ibnd_node_t * hash[])
 {
        int hash_idx = HASHGUID(node->guid) % HTSZ;

@@ -367,7 +423,7 @@
        hash[hash_idx] = node;
 }

-static void add_to_portguid_hash(ibnd_port_t * port, ibnd_port_t * hash[])
+void add_to_portguid_hash(ibnd_port_t * port, ibnd_port_t * hash[])
 {
        int hash_idx = HASHGUID(port->guid) % HTSZ;

@@ -375,7 +431,7 @@
        hash[hash_idx] = port;
 }

-static void add_to_type_list(ibnd_node_t * node, ibnd_fabric_t * fabric)
+void add_to_type_list(ibnd_node_t * node, ibnd_fabric_t * fabric)
 {
        switch (node->type) {
        case IB_NODE_CA:
@@ -393,291 +449,106 @@
        }
 }

-static void add_to_nodedist(ibnd_node_t * node, ibnd_fabric_t * fabric)
+static int set_config(struct ibnd_config *config, struct ibnd_config *cfg)
 {
-       int dist = node->dist;
-       if (node->type != IB_NODE_SWITCH)
-               dist = MAXHOPS; /* special Ca list */
+       if (!config)
+               return (-EINVAL);

-       node->dnext = fabric->nodesdist[dist];
-       fabric->nodesdist[dist] = node;
-}
+       if (cfg)
+               memcpy(config, cfg, sizeof(*config));

-static ibnd_node_t *create_node(ibnd_fabric_t * fabric,
-                               ibnd_node_t * temp, ib_portid_t * path,
-                               int dist)
-{
-       ibnd_node_t *node;
+       if (!config->max_smps)
+               config->max_smps = DEFAULT_MAX_SMP_ON_WIRE;
+       if (!config->timeout_ms)
+               config->timeout_ms = DEFAULT_TIMEOUT;
+       if (!config->retries)
+               config->retries = DEFAULT_RETRIES;

-       node = malloc(sizeof(*node));
-       if (!node) {
-               IBND_ERROR("OOM: node creation failed\n");
-               return (NULL);
-       }
-
-       memcpy(node, temp, sizeof(*node));
-       node->dist = dist;
-       node->path_portid = *path;
-
-       add_to_nodeguid_hash(node, fabric->nodestbl);
-
-       /* add this to the all nodes list */
-       node->next = fabric->nodes;
-       fabric->nodes = (ibnd_node_t *) node;
-
-       add_to_type_list(node, fabric);
-       add_to_nodedist(node, fabric);
-
-       return node;
+       return (0);
 }

-static struct ibnd_port *find_existing_port_node(ibnd_node_t * node,
-                                                ibnd_port_t * port)
+ibnd_fabric_t *ibnd_discover_fabric(char * ca_name, int ca_port,
+                                   ib_portid_t * from,
+                                   struct ibnd_config *cfg)
 {
-       if (port->portnum > node->numports || node->ports == NULL)
-               return (NULL);
-
-       return (node->ports[port->portnum]);
-}
-
-static struct ibnd_port *add_port_to_node(ibnd_fabric_t * fabric,
-                                         ibnd_node_t * node,
-                                         ibnd_port_t * temp)
-{
-       ibnd_port_t *port;
-
-       if (node->ports == NULL) {
-               node->ports = calloc(sizeof(*node->ports), node->numports + 1);
-               if (!node->ports) {
-                       IBND_ERROR("Failed to allocate the ports array\n");
-                       return (NULL);
-               }
-       }
-
-       port = malloc(sizeof(*port));
-       if (!port) {
-               IBND_ERROR("Failed to allocate port\n");
-               return NULL;
-       }
-
-       memcpy(port, temp, sizeof(*port));
-       port->node = (ibnd_node_t *) node;
-       port->ext_portnum = 0;
-
-       node->ports[temp->portnum] = (ibnd_port_t *) port;
-
-       add_to_portguid_hash(port, fabric->portstbl);
-       return port;
-}
-
-static void link_ports(ibnd_node_t * node, ibnd_port_t * port,
-                      ibnd_node_t * remotenode, ibnd_port_t * remoteport)
-{
-       IBND_DEBUG("linking: 0x%" PRIx64 " %p->%p:%u and 0x%" PRIx64
-                  " %p->%p:%u\n", node->guid, node, port, port->portnum,
-                  remotenode->guid, remotenode, remoteport,
-                  remoteport->portnum);
-       if (port->remoteport)
-               port->remoteport->remoteport = NULL;
-       if (remoteport->remoteport)
-               remoteport->remoteport->remoteport = NULL;
-       port->remoteport = (ibnd_port_t *) remoteport;
-       remoteport->remoteport = (ibnd_port_t *) port;
-}
-
-static int get_remote_node(struct ibmad_port *ibmad_port,
-                          ibnd_fabric_t * fabric, ibnd_node_t * node,
-                          ibnd_port_t * port, ib_portid_t * path,
-                          int portnum, int dist)
-{
-       int rc = 0;
-       ibnd_node_t node_buf;
-       ibnd_port_t port_buf;
-       ibnd_node_t *remotenode, *oldnode;
-       ibnd_port_t *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 (mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F)
-           != IB_PORT_PHYS_STATE_LINKUP)
-               return 1;       /* positive == non-fatal error */
-
-       if (extend_dpath(ibmad_port, fabric, path, portnum) < 0)
-               return -1;
-
-       if (query_node(ibmad_port, fabric, &node_buf, &port_buf, path)) {
-               IBND_ERROR("Query remote node (%s) failed, skipping port\n",
-                          portid2str(path));
-               retract_dpath(path);
-               return 1;       /* positive == non-fatal error */
-       }
-
-       oldnode = find_existing_node(fabric, &node_buf);
-       if (oldnode)
-               remotenode = oldnode;
-       else if (!(remotenode = create_node(fabric, &node_buf, path, dist + 1))) {
-               rc = -1;
-               goto error;
-       }
-
-       oldport = find_existing_port_node(remotenode, &port_buf);
-       if (oldport) {
-               remoteport = oldport;
-       } else if (!(remoteport = add_port_to_node(fabric, remotenode,
-                                                  &port_buf))) {
-               IBND_ERROR("OOM failed to add port to node\n");
-               rc = -1;
-               goto error;
-       }
-
-       dump_endnode(path, oldnode ? "known remote" : "new remote",
-                    remotenode, remoteport);
-
-       link_ports(node, port, remotenode, remoteport);
-
-error:
-       retract_dpath(path);
-       return (rc);
-}
-
-ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port * ibmad_port,
-                                   ib_portid_t * from, int hops)
-{
-       int rc = 0;
+       struct ibnd_config config = { 0 };
        ibnd_fabric_t *fabric = NULL;
        ib_portid_t my_portid = { 0 };
-       ibnd_node_t node_buf;
-       ibnd_port_t port_buf;
-       ibnd_node_t *node;
-       ibnd_port_t *port;
-       int i;
-       int dist = 0;
-       ib_portid_t *path;
-       int max_hops = MAXHOPS - 1;     /* default find everything */
+       smp_engine_t engine;
+       ibnd_scan_t scan;
+       int nc = 2;
+       int mc[2] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS };

-       if (_check_ibmad_port(ibmad_port) < 0)
-               return (NULL);
-
-       /* if not everything how much? */
-       if (hops >= 0) {
-               max_hops = hops;
+       if (set_config(&config, cfg)) {
+               IBND_ERROR("Invalid ibnd_config\n");
+               return NULL;
        }

        /* If not specified start from "my" port */
        if (!from)
                from = &my_portid;

-       fabric = malloc(sizeof(*fabric));
-
+       fabric = calloc(1, sizeof(*fabric));
        if (!fabric) {
-               IBND_ERROR("OOM: failed to malloc ibnd_fabric_t\n");
-               return (NULL);
+               IBND_ERROR("OOM: failed to calloc ibnd_fabric_t\n");
+               return NULL;
        }

        memset(fabric, 0, sizeof(*fabric));

-       IBND_DEBUG("from %s\n", portid2str(from));
+       memset(&scan.selfportid, 0, sizeof(scan.selfportid));
+       scan.fabric = fabric;
+       scan.cfg = &config;

-       memset(&node_buf, 0, sizeof(node_buf));
-       memset(&port_buf, 0, sizeof(port_buf));
+       if (smp_engine_init(&engine, ca_name, ca_port, &scan, &config)) {
+               free(fabric);
+               return (NULL);
+       }

-       if (query_node(ibmad_port, fabric, &node_buf, &port_buf, from)) {
-               IBND_DEBUG("can't reach node %s\n", portid2str(from));
-               goto error;
+       scan.ibmad_port = mad_rpc_open_port(ca_name, ca_port, mc, nc);
+       if (!scan.ibmad_port) {
+               IBND_ERROR("can't open MAD port (%s:%d)\n", ca_name, ca_port);
+               smp_engine_destroy(&engine);
+               return (NULL);
        }
+       mad_rpc_set_timeout(scan.ibmad_port, cfg->timeout_ms);
+       mad_rpc_set_retries(scan.ibmad_port, cfg->retries);

-       node = create_node(fabric, &node_buf, from, 0);
-       if (!node)
-               goto error;
+       IBND_DEBUG("from %s\n", portid2str(from));

-       fabric->from_node = (ibnd_node_t *) node;
-
-       port = add_port_to_node(fabric, node, &port_buf);
-       if (!port)
-               goto error;
-
-       if (node->type != IB_NODE_SWITCH) {
-               rc = get_remote_node(ibmad_port, fabric, node, port, from,
-                                    mad_get_field(node->info, 0,
-                                                  IB_NODE_LOCAL_PORT_F), 0);
-               if (rc < 0)
+       if (!query_node_info(&engine, from, NULL))
+               if (process_mads(&engine) != 0)
                        goto error;
-               if (rc > 0)             /* non-fatal error, nothing more to be done */
-                       return ((ibnd_fabric_t *) fabric);
-       }

-       for (dist = 0; dist <= max_hops; dist++) {
+       fabric->total_mads_used = engine.total_smps;

-               for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
-
-                       path = &node->path_portid;
-
-                       IBND_DEBUG("dist %d node %p\n", dist, node);
-                       dump_endnode(path, "processing", node, port);
-
-                       for (i = 1; i <= node->numports; i++) {
-                               if (i == mad_get_field(node->info, 0,
-                                                      IB_NODE_LOCAL_PORT_F))
-                                       continue;
-
-                               if (get_port_info(ibmad_port, fabric,
-                                                 &port_buf, i, path)) {
-                                       IBND_ERROR
-                                           ("can't reach node %s port %d\n",
-                                            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)
-                                       goto error;
-
-                               /* If switch, set port GUID to node port GUID */
-                               if (node->type == IB_NODE_SWITCH) {
-                                       port->guid =
-                                           mad_get_field64(node->info, 0,
-                                                           IB_NODE_PORT_GUID_F);
-                               }
-
-                               if (get_remote_node(ibmad_port, fabric, node,
-                                                   port, path, i, dist) < 0)
-                                       goto error;
-                       }
-               }
-       }
-
        if (group_nodes(fabric))
                goto error;

-       return ((ibnd_fabric_t *) fabric);
+       smp_engine_destroy(&engine);
+       mad_rpc_close_port(scan.ibmad_port);
+       return fabric;
 error:
-       ibnd_destroy_fabric((ibnd_fabric_t *) fabric);
-       return (NULL);
+       smp_engine_destroy(&engine);
+       mad_rpc_close_port(scan.ibmad_port);
+       ibnd_destroy_fabric(fabric);
+       return NULL;
 }

-static void destroy_node(ibnd_node_t * node)
+void destroy_node(ibnd_node_t * node)
 {
        int p = 0;

-       for (p = 0; p <= node->numports; p++) {
-               free(node->ports[p]);
+       if (node->ports) {
+               for (p = 0; p <= node->numports; p++)
+                       free(node->ports[p]);
+               free(node->ports);
        }
-       free(node->ports);
        free(node);
 }

 void ibnd_destroy_fabric(ibnd_fabric_t * fabric)
 {
-       int dist = 0;
        ibnd_node_t *node = NULL;
        ibnd_node_t *next = NULL;
        ibnd_chassis_t *ch, *ch_next;
@@ -685,41 +556,21 @@
        if (!fabric)
                return;

-       ch = fabric->first_chassis;
+       ch = fabric->chassis;
        while (ch) {
                ch_next = ch->next;
                free(ch);
                ch = ch_next;
        }
-       for (dist = 0; dist <= MAXHOPS; dist++) {
-               node = fabric->nodesdist[dist];
-               while (node) {
-                       next = node->dnext;
-                       destroy_node(node);
-                       node = next;
-               }
+       node = fabric->nodes;
+       while (node) {
+               next = node->next;
+               destroy_node(node);
+               node = next;
        }
        free(fabric);
 }

-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;
-}
-
 void ibnd_iter_nodes(ibnd_fabric_t * fabric, ibnd_iter_node_func_t func,
                     void *user_data)
 {
@@ -735,9 +586,8 @@
                return;
        }

-       for (cur = fabric->nodes; cur; cur = cur->next) {
+       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,
@@ -771,7 +621,6 @@
                break;
        }

-       for (cur = list; cur; cur = cur->type_next) {
-               func((ibnd_node_t *) cur, user_data);
-       }
+       for (cur = list; cur; cur = cur->type_next)
+               func(cur, user_data);
 }
Index: ulp/libibnetdisc/src/ibnetdisc_cache.c
===================================================================
--- ulp/libibnetdisc/src/ibnetdisc_cache.c      (revision 0)
+++ ulp/libibnetdisc/src/ibnetdisc_cache.c      (revision 0)
@@ -0,0 +1,942 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <infiniband/ibnetdisc.h>
+
+#include "internal.h"
+#include "chassis.h"
+
+/* For this caching lib, we always cache little endian */
+
+/* Cache format
+ *
+ * Bytes 1-4 - magic number
+ * Bytes 5-8 - version number
+ * Bytes 9-12 - node count
+ * Bytes 13-16 - port count
+ * Bytes 17-24 - "from node" guid
+ * Bytes 25-28 - maxhops discovered
+ * Bytes X-Y - nodes (variable length)
+ * Bytes X-Y - ports (variable length)
+ *
+ * Nodes are cached as
+ *
+ * 2 bytes - smalid
+ * 1 byte - smalmc
+ * 1 byte - smaenhsp0 flag
+ * IB_SMP_DATA_SIZE bytes - switchinfo
+ * 8 bytes - guid
+ * 1 byte - type
+ * 1 byte - numports
+ * IB_SMP_DATA_SIZE bytes - info
+ * IB_SMP_DATA_SIZE bytes - nodedesc
+ * 1 byte - number of ports stored
+ * 8 bytes - portguid A
+ * 1 byte - port num A
+ * 8 bytes - portguid B
+ * 1 byte - port num B
+ * ... etc., depending on number of ports stored
+ *
+ * Ports are cached as
+ *
+ * 8 bytes - guid
+ * 1 byte - portnum
+ * 1 byte - external portnum
+ * 2 bytes - base lid
+ * 1 byte - lmc
+ * IB_SMP_DATA_SIZE bytes - info
+ * 8 bytes - node guid port "owned" by
+ * 1 byte - flag indicating if remote port exists
+ * 8 bytes - port guid remotely connected to
+ * 1 byte - port num remotely connected to
+ */
+
+/* Structs that hold cache info temporarily before
+ * the real structs can be reconstructed.
+ */
+
+typedef struct ibnd_port_cache_key {
+       uint64_t guid;
+       uint8_t portnum;
+} ibnd_port_cache_key_t;
+
+typedef struct ibnd_node_cache {
+       ibnd_node_t *node;
+       uint8_t ports_stored_count;
+       ibnd_port_cache_key_t *port_cache_keys;
+       struct ibnd_node_cache *next;
+       struct ibnd_node_cache *htnext;
+       int node_stored_to_fabric;
+} ibnd_node_cache_t;
+
+typedef struct ibnd_port_cache {
+       ibnd_port_t *port;
+       uint64_t node_guid;
+       uint8_t remoteport_flag;
+       ibnd_port_cache_key_t remoteport_cache_key;
+       struct ibnd_port_cache *next;
+       struct ibnd_port_cache *htnext;
+       int port_stored_to_fabric;
+} ibnd_port_cache_t;
+
+typedef struct ibnd_fabric_cache {
+       ibnd_fabric_t *fabric;
+       uint64_t from_node_guid;
+       ibnd_node_cache_t *nodes_cache;
+       ibnd_port_cache_t *ports_cache;
+       ibnd_node_cache_t *nodescachetbl[HTSZ];
+       ibnd_port_cache_t *portscachetbl[HTSZ];
+} ibnd_fabric_cache_t;
+
+#define IBND_FABRIC_CACHE_BUFLEN  4096
+#define IBND_FABRIC_CACHE_MAGIC   0x8FE7832B
+#define IBND_FABRIC_CACHE_VERSION 0x00000001
+
+#define IBND_FABRIC_CACHE_COUNT_OFFSET 8
+
+#define IBND_FABRIC_CACHE_HEADER_LEN   (28)
+#define IBND_NODE_CACHE_HEADER_LEN     (15 + IB_SMP_DATA_SIZE*3)
+#define IBND_PORT_CACHE_KEY_LEN        (8 + 1)
+#define IBND_PORT_CACHE_LEN            (31 + IB_SMP_DATA_SIZE)
+
+static ssize_t ibnd_read(int fd, void *buf, size_t count)
+{
+       size_t count_done = 0;
+       ssize_t ret;
+
+       while ((count - count_done) > 0) {
+               ret = read(fd, ((char *) buf) + count_done, count - count_done);
+               if (ret < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       else {
+                               IBND_DEBUG("read: %s\n", strerror(errno));
+                               return -1;
+                       }
+               }
+               if (!ret)
+                       break;
+               count_done += ret;
+       }
+
+       if (count_done != count) {
+               IBND_DEBUG("read: read short\n");
+               return -1;
+       }
+
+       return count_done;
+}
+
+static size_t _unmarshall8(uint8_t * inbuf, uint8_t * num)
+{
+       (*num) = inbuf[0];
+
+       return (sizeof(*num));
+}
+
+static size_t _unmarshall16(uint8_t * inbuf, uint16_t * num)
+{
+       (*num) = (uint64_t) inbuf[0];
+       (*num) |= ((uint16_t) inbuf[1] << 8);
+
+       return (sizeof(*num));
+}
+
+static size_t _unmarshall32(uint8_t * inbuf, uint32_t * num)
+{
+       (*num) = (uint32_t) inbuf[0];
+       (*num) |= ((uint32_t) inbuf[1] << 8);
+       (*num) |= ((uint32_t) inbuf[2] << 16);
+       (*num) |= ((uint32_t) inbuf[3] << 24);
+
+       return (sizeof(*num));
+}
+
+static size_t _unmarshall64(uint8_t * inbuf, uint64_t * num)
+{
+       (*num) = (uint64_t) inbuf[0];
+       (*num) |= ((uint64_t) inbuf[1] << 8);
+       (*num) |= ((uint64_t) inbuf[2] << 16);
+       (*num) |= ((uint64_t) inbuf[3] << 24);
+       (*num) |= ((uint64_t) inbuf[4] << 32);
+       (*num) |= ((uint64_t) inbuf[5] << 40);
+       (*num) |= ((uint64_t) inbuf[6] << 48);
+       (*num) |= ((uint64_t) inbuf[7] << 56);
+
+       return (sizeof(*num));
+}
+
+static size_t _unmarshall_buf(const void *inbuf, void *outbuf, unsigned int len)
+{
+       memcpy(outbuf, inbuf, len);
+
+       return len;
+}
+
+static int _load_header_info(int fd, ibnd_fabric_cache_t * fabric_cache,
+                            unsigned int *node_count, unsigned int *port_count)
+{
+       uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
+       uint32_t magic = 0;
+       uint32_t version = 0;
+       size_t offset = 0;
+       uint32_t tmp32;
+
+       if (ibnd_read(fd, buf, IBND_FABRIC_CACHE_HEADER_LEN) < 0)
+               return -1;
+
+       offset += _unmarshall32(buf + offset, &magic);
+
+       if (magic != IBND_FABRIC_CACHE_MAGIC) {
+               IBND_DEBUG("invalid fabric cache file\n");
+               return -1;
+       }
+
+       offset += _unmarshall32(buf + offset, &version);
+
+       if (version != IBND_FABRIC_CACHE_VERSION) {
+               IBND_DEBUG("invalid fabric cache version\n");
+               return -1;
+       }
+
+       offset += _unmarshall32(buf + offset, node_count);
+       offset += _unmarshall32(buf + offset, port_count);
+
+       offset += _unmarshall64(buf + offset, &fabric_cache->from_node_guid);
+       offset += _unmarshall32(buf + offset, &tmp32);
+       fabric_cache->fabric->maxhops_discovered = tmp32;
+
+       return 0;
+}
+
+static void _destroy_ibnd_node_cache(ibnd_node_cache_t * node_cache)
+{
+       free(node_cache->port_cache_keys);
+       if (!node_cache->node_stored_to_fabric && node_cache->node)
+               destroy_node(node_cache->node);
+       free(node_cache);
+}
+
+static void _destroy_ibnd_fabric_cache(ibnd_fabric_cache_t * fabric_cache)
+{
+       ibnd_node_cache_t *node_cache;
+       ibnd_node_cache_t *node_cache_next;
+       ibnd_port_cache_t *port_cache;
+       ibnd_port_cache_t *port_cache_next;
+
+       if (!fabric_cache)
+               return;
+
+       node_cache = fabric_cache->nodes_cache;
+       while (node_cache) {
+               node_cache_next = node_cache->next;
+
+               _destroy_ibnd_node_cache(node_cache);
+
+               node_cache = node_cache_next;
+       }
+
+       port_cache = fabric_cache->ports_cache;
+       while (port_cache) {
+               port_cache_next = port_cache->next;
+
+               if (!port_cache->port_stored_to_fabric && port_cache->port)
+                       free(port_cache->port);
+               free(port_cache);
+
+               port_cache = port_cache_next;
+       }
+
+       free(fabric_cache);
+}
+
+static void store_node_cache(ibnd_node_cache_t * node_cache,
+                            ibnd_fabric_cache_t * fabric_cache)
+{
+       int hash_indx = HASHGUID(node_cache->node->guid) % HTSZ;
+
+       node_cache->next = fabric_cache->nodes_cache;
+       fabric_cache->nodes_cache = node_cache;
+
+       node_cache->htnext = fabric_cache->nodescachetbl[hash_indx];
+       fabric_cache->nodescachetbl[hash_indx] = node_cache;
+}
+
+static int _load_node(int fd, ibnd_fabric_cache_t * fabric_cache)
+{
+       uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
+       ibnd_node_cache_t *node_cache = NULL;
+       ibnd_node_t *node = NULL;
+       size_t offset = 0;
+       uint8_t tmp8;
+
+       node_cache = (ibnd_node_cache_t *) malloc(sizeof(ibnd_node_cache_t));
+       if (!node_cache) {
+               IBND_DEBUG("OOM: node_cache\n");
+               return -1;
+       }
+       memset(node_cache, '\0', sizeof(ibnd_node_cache_t));
+
+       node = (ibnd_node_t *) malloc(sizeof(ibnd_node_t));
+       if (!node) {
+               IBND_DEBUG("OOM: node\n");
+               return -1;
+       }
+       memset(node, '\0', sizeof(ibnd_node_t));
+
+       node_cache->node = node;
+
+       if (ibnd_read(fd, buf, IBND_NODE_CACHE_HEADER_LEN) < 0)
+               goto cleanup;
+
+       offset += _unmarshall16(buf + offset, &node->smalid);
+       offset += _unmarshall8(buf + offset, &node->smalmc);
+       offset += _unmarshall8(buf + offset, &tmp8);
+       node->smaenhsp0 = tmp8;
+       offset += _unmarshall_buf(buf + offset, node->switchinfo,
+                                 IB_SMP_DATA_SIZE);
+       offset += _unmarshall64(buf + offset, &node->guid);
+       offset += _unmarshall8(buf + offset, &tmp8);
+       node->type = tmp8;
+       offset += _unmarshall8(buf + offset, &tmp8);
+       node->numports = tmp8;
+       offset += _unmarshall_buf(buf + offset, node->info, IB_SMP_DATA_SIZE);
+       offset += _unmarshall_buf(buf + offset, node->nodedesc,
+                                 IB_SMP_DATA_SIZE);
+
+       offset += _unmarshall8(buf + offset, &node_cache->ports_stored_count);
+
+       if (node_cache->ports_stored_count) {
+               unsigned int tomalloc = 0;
+               unsigned int toread = 0;
+               unsigned int i;
+
+               tomalloc =
+                   sizeof(ibnd_port_cache_key_t) *
+                   node_cache->ports_stored_count;
+
+               toread =
+                   IBND_PORT_CACHE_KEY_LEN * node_cache->ports_stored_count;
+
+               node_cache->port_cache_keys =
+                   (ibnd_port_cache_key_t *) malloc(tomalloc);
+               if (!node_cache->port_cache_keys) {
+                       IBND_DEBUG("OOM: node_cache port_cache_keys\n");
+                       goto cleanup;
+               }
+
+               if (ibnd_read(fd, buf, toread) < 0)
+                       goto cleanup;
+
+               offset = 0;
+
+               for (i = 0; i < node_cache->ports_stored_count; i++) {
+                       offset +=
+                           _unmarshall64(buf + offset,
+                                         &node_cache->port_cache_keys[i].guid);
+                       offset +=
+                           _unmarshall8(buf + offset,
+                                        &node_cache->
+                                        port_cache_keys[i].portnum);
+               }
+       }
+
+       store_node_cache(node_cache, fabric_cache);
+
+       return 0;
+
+cleanup:
+       _destroy_ibnd_node_cache(node_cache);
+       return -1;
+}
+
+static void store_port_cache(ibnd_port_cache_t * port_cache,
+                            ibnd_fabric_cache_t * fabric_cache)
+{
+       int hash_indx = HASHGUID(port_cache->port->guid) % HTSZ;
+
+       port_cache->next = fabric_cache->ports_cache;
+       fabric_cache->ports_cache = port_cache;
+
+       port_cache->htnext = fabric_cache->portscachetbl[hash_indx];
+       fabric_cache->portscachetbl[hash_indx] = port_cache;
+}
+
+static int _load_port(int fd, ibnd_fabric_cache_t * fabric_cache)
+{
+       uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
+       ibnd_port_cache_t *port_cache = NULL;
+       ibnd_port_t *port = NULL;
+       size_t offset = 0;
+       uint8_t tmp8;
+
+       port_cache = (ibnd_port_cache_t *) malloc(sizeof(ibnd_port_cache_t));
+       if (!port_cache) {
+               IBND_DEBUG("OOM: port_cache\n");
+               return -1;
+       }
+       memset(port_cache, '\0', sizeof(ibnd_port_cache_t));
+
+       port = (ibnd_port_t *) malloc(sizeof(ibnd_port_t));
+       if (!port) {
+               IBND_DEBUG("OOM: port\n");
+               return -1;
+       }
+       memset(port, '\0', sizeof(ibnd_port_t));
+
+       port_cache->port = port;
+
+       if (ibnd_read(fd, buf, IBND_PORT_CACHE_LEN) < 0)
+               goto cleanup;
+
+       offset += _unmarshall64(buf + offset, &port->guid);
+       offset += _unmarshall8(buf + offset, &tmp8);
+       port->portnum = tmp8;
+       offset += _unmarshall8(buf + offset, &tmp8);
+       port->ext_portnum = tmp8;
+       offset += _unmarshall16(buf + offset, &port->base_lid);
+       offset += _unmarshall8(buf + offset, &port->lmc);
+       offset += _unmarshall_buf(buf + offset, port->info, IB_SMP_DATA_SIZE);
+       offset += _unmarshall64(buf + offset, &port_cache->node_guid);
+       offset += _unmarshall8(buf + offset, &port_cache->remoteport_flag);
+       offset +=
+           _unmarshall64(buf + offset, &port_cache->remoteport_cache_key.guid);
+       offset +=
+           _unmarshall8(buf + offset,
+                        &port_cache->remoteport_cache_key.portnum);
+
+       store_port_cache(port_cache, fabric_cache);
+
+       return 0;
+
+cleanup:
+       free(port);
+       free(port_cache);
+       return -1;
+}
+
+static ibnd_port_cache_t *_find_port(ibnd_fabric_cache_t * fabric_cache,
+                                    ibnd_port_cache_key_t * port_cache_key)
+{
+       int hash_indx = HASHGUID(port_cache_key->guid) % HTSZ;
+       ibnd_port_cache_t *port_cache;
+
+       for (port_cache = fabric_cache->portscachetbl[hash_indx];
+            port_cache; port_cache = port_cache->htnext) {
+               if (port_cache->port->guid == port_cache_key->guid
+                   && port_cache->port->portnum == port_cache_key->portnum)
+                       return port_cache;
+       }
+
+       return NULL;
+}
+
+static ibnd_node_cache_t *_find_node(ibnd_fabric_cache_t * fabric_cache,
+                                    uint64_t guid)
+{
+       int hash_indx = HASHGUID(guid) % HTSZ;
+       ibnd_node_cache_t *node_cache;
+
+       for (node_cache = fabric_cache->nodescachetbl[hash_indx];
+            node_cache; node_cache = node_cache->htnext) {
+               if (node_cache->node->guid == guid)
+                       return node_cache;
+       }
+
+       return NULL;
+}
+
+static int _fill_port(ibnd_fabric_cache_t * fabric_cache, ibnd_node_t * node,
+                     ibnd_port_cache_key_t * port_cache_key)
+{
+       ibnd_port_cache_t *port_cache;
+
+       if (!(port_cache = _find_port(fabric_cache, port_cache_key))) {
+               IBND_DEBUG("Cache invalid: cannot find port\n");
+               return -1;
+       }
+
+       if (port_cache->port_stored_to_fabric) {
+               IBND_DEBUG("Cache invalid: duplicate port discovered\n");
+               return -1;
+       }
+
+       node->ports[port_cache->port->portnum] = port_cache->port;
+       port_cache->port_stored_to_fabric++;
+
+       /* achu: needed if user wishes to re-cache a loaded fabric.
+        * Otherwise, mostly unnecessary to do this.
+        */
+       add_to_portguid_hash(port_cache->port, fabric_cache->fabric->portstbl);
+       return 0;
+}
+
+static int _rebuild_nodes(ibnd_fabric_cache_t * fabric_cache)
+{
+       ibnd_node_cache_t *node_cache;
+       ibnd_node_cache_t *node_cache_next;
+
+       node_cache = fabric_cache->nodes_cache;
+       while (node_cache) {
+               ibnd_node_t *node;
+               int i;
+
+               node_cache_next = node_cache->next;
+
+               node = node_cache->node;
+
+               /* Insert node into appropriate data structures */
+
+               node->next = fabric_cache->fabric->nodes;
+               fabric_cache->fabric->nodes = node;
+
+               add_to_nodeguid_hash(node_cache->node,
+                                    fabric_cache->fabric->nodestbl);
+
+               add_to_type_list(node_cache->node, fabric_cache->fabric);
+
+               node_cache->node_stored_to_fabric++;
+
+               /* Rebuild node ports array */
+
+               if (!(node->ports =
+                     calloc(sizeof(*node->ports), node->numports + 1))) {
+                       IBND_DEBUG("OOM: node->ports\n");
+                       return -1;
+               }
+
+               for (i = 0; i < node_cache->ports_stored_count; i++) {
+                       if (_fill_port(fabric_cache, node,
+                                      &node_cache->port_cache_keys[i]) < 0)
+                               return -1;
+               }
+
+               node_cache = node_cache_next;
+       }
+
+       return 0;
+}
+
+static int _rebuild_ports(ibnd_fabric_cache_t * fabric_cache)
+{
+       ibnd_port_cache_t *port_cache;
+       ibnd_port_cache_t *port_cache_next;
+
+       port_cache = fabric_cache->ports_cache;
+       while (port_cache) {
+               ibnd_node_cache_t *node_cache;
+               ibnd_port_cache_t *remoteport_cache;
+               ibnd_port_t *port;
+
+               port_cache_next = port_cache->next;
+
+               port = port_cache->port;
+
+               if (!(node_cache =
+                     _find_node(fabric_cache, port_cache->node_guid))) {
+                       IBND_DEBUG("Cache invalid: cannot find node\n");
+                       return -1;
+               }
+
+               port->node = node_cache->node;
+
+               if (port_cache->remoteport_flag) {
+                       if (!(remoteport_cache = _find_port(fabric_cache,
+                                                           &port_cache->remoteport_cache_key)))
+                       {
+                               IBND_DEBUG
+                                   ("Cache invalid: cannot find remote port\n");
+                               return -1;
+                       }
+
+                       port->remoteport = remoteport_cache->port;
+               } else
+                       port->remoteport = NULL;
+
+               port_cache = port_cache_next;
+       }
+
+       return 0;
+}
+
+ibnd_fabric_t *ibnd_load_fabric(const char *file, unsigned int flags)
+{
+       unsigned int node_count = 0;
+       unsigned int port_count = 0;
+       ibnd_fabric_cache_t *fabric_cache = NULL;
+       ibnd_fabric_t *fabric = NULL;
+       ibnd_node_cache_t *node_cache = NULL;
+       int fd = -1;
+       unsigned int i;
+
+       if (!file) {
+               IBND_DEBUG("file parameter NULL\n");
+               return NULL;
+       }
+
+       if ((fd = open(file, O_RDONLY)) < 0) {
+               IBND_DEBUG("open: %s\n", strerror(errno));
+               return NULL;
+       }
+
+       fabric_cache =
+           (ibnd_fabric_cache_t *) malloc(sizeof(ibnd_fabric_cache_t));
+       if (!fabric_cache) {
+               IBND_DEBUG("OOM: fabric_cache\n");
+               goto cleanup;
+       }
+       memset(fabric_cache, '\0', sizeof(ibnd_fabric_cache_t));
+
+       fabric = (ibnd_fabric_t *) malloc(sizeof(ibnd_fabric_t));
+       if (!fabric) {
+               IBND_DEBUG("OOM: fabric\n");
+               goto cleanup;
+       }
+       memset(fabric, '\0', sizeof(ibnd_fabric_t));
+
+       fabric_cache->fabric = fabric;
+
+       if (_load_header_info(fd, fabric_cache, &node_count, &port_count) < 0)
+               goto cleanup;
+
+       for (i = 0; i < node_count; i++) {
+               if (_load_node(fd, fabric_cache) < 0)
+                       goto cleanup;
+       }
+
+       for (i = 0; i < port_count; i++) {
+               if (_load_port(fd, fabric_cache) < 0)
+                       goto cleanup;
+       }
+
+       /* Special case - find from node */
+       if (!(node_cache =
+             _find_node(fabric_cache, fabric_cache->from_node_guid))) {
+               IBND_DEBUG("Cache invalid: cannot find from node\n");
+               goto cleanup;
+       }
+       fabric->from_node = node_cache->node;
+
+       if (_rebuild_nodes(fabric_cache) < 0)
+               goto cleanup;
+
+       if (_rebuild_ports(fabric_cache) < 0)
+               goto cleanup;
+
+       if (group_nodes(fabric))
+               goto cleanup;
+
+       _destroy_ibnd_fabric_cache(fabric_cache);
+       close(fd);
+       return fabric;
+
+cleanup:
+       ibnd_destroy_fabric(fabric);
+       _destroy_ibnd_fabric_cache(fabric_cache);
+       close(fd);
+       return NULL;
+}
+
+static ssize_t ibnd_write(int fd, const void *buf, size_t count)
+{
+       size_t count_done = 0;
+       ssize_t ret;
+
+       while ((count - count_done) > 0) {
+               ret = write(fd, ((char *) buf) + count_done, count - count_done);
+               if (ret < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       else {
+                               IBND_DEBUG("write: %s\n", strerror(errno));
+                               return -1;
+                       }
+               }
+               count_done += ret;
+       }
+       return count_done;
+}
+
+static size_t _marshall8(uint8_t * outbuf, uint8_t num)
+{
+       outbuf[0] = num;
+
+       return (sizeof(num));
+}
+
+static size_t _marshall16(uint8_t * outbuf, uint16_t num)
+{
+       outbuf[0] = num & 0x00FF;
+       outbuf[1] = (num & 0xFF00) >> 8;
+
+       return (sizeof(num));
+}
+
+static size_t _marshall32(uint8_t * outbuf, uint32_t num)
+{
+       outbuf[0] = num & 0x000000FF;
+       outbuf[1] = (num & 0x0000FF00) >> 8;
+       outbuf[2] = (num & 0x00FF0000) >> 16;
+       outbuf[3] = (num & 0xFF000000) >> 24;
+
+       return (sizeof(num));
+}
+
+static size_t _marshall64(uint8_t * outbuf, uint64_t num)
+{
+       outbuf[0] = (uint8_t) num;
+       outbuf[1] = (uint8_t) (num >> 8);
+       outbuf[2] = (uint8_t) (num >> 16);
+       outbuf[3] = (uint8_t) (num >> 24);
+       outbuf[4] = (uint8_t) (num >> 32);
+       outbuf[5] = (uint8_t) (num >> 40);
+       outbuf[6] = (uint8_t) (num >> 48);
+       outbuf[7] = (uint8_t) (num >> 56);
+
+       return (sizeof(num));
+}
+
+static size_t _marshall_buf(void *outbuf, const void *inbuf, unsigned int len)
+{
+       memcpy(outbuf, inbuf, len);
+
+       return len;
+}
+
+static int _cache_header_info(int fd, ibnd_fabric_t * fabric)
+{
+       uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
+       size_t offset = 0;
+
+       /* Store magic number, version, and other important info */
+       /* For this caching lib, we always assume cached as little endian */
+
+       offset += _marshall32(buf + offset, IBND_FABRIC_CACHE_MAGIC);
+       offset += _marshall32(buf + offset, IBND_FABRIC_CACHE_VERSION);
+       /* save space for node count */
+       offset += _marshall32(buf + offset, 0);
+       /* save space for port count */
+       offset += _marshall32(buf + offset, 0);
+       offset += _marshall64(buf + offset, fabric->from_node->guid);
+       offset += _marshall32(buf + offset, fabric->maxhops_discovered);
+
+       if (ibnd_write(fd, buf, offset) < 0)
+               return -1;
+
+       return 0;
+}
+
+static int _cache_header_counts(int fd, unsigned int node_count,
+                               unsigned int port_count)
+{
+       uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
+       size_t offset = 0;
+
+       offset += _marshall32(buf + offset, node_count);
+       offset += _marshall32(buf + offset, port_count);
+
+       if (lseek(fd, IBND_FABRIC_CACHE_COUNT_OFFSET, SEEK_SET) < 0) {
+               IBND_DEBUG("lseek: %s\n", strerror(errno));
+               return -1;
+       }
+
+       if (ibnd_write(fd, buf, offset) < 0)
+               return -1;
+
+       return 0;
+}
+
+static int _cache_node(int fd, ibnd_node_t * node)
+{
+       uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
+       size_t offset = 0;
+       size_t ports_stored_offset = 0;
+       uint8_t ports_stored_count = 0;
+       int i;
+
+       offset += _marshall16(buf + offset, node->smalid);
+       offset += _marshall8(buf + offset, node->smalmc);
+       offset += _marshall8(buf + offset, (uint8_t) node->smaenhsp0);
+       offset += _marshall_buf(buf + offset, node->switchinfo,
+                               IB_SMP_DATA_SIZE);
+       offset += _marshall64(buf + offset, node->guid);
+       offset += _marshall8(buf + offset, (uint8_t) node->type);
+       offset += _marshall8(buf + offset, (uint8_t) node->numports);
+       offset += _marshall_buf(buf + offset, node->info, IB_SMP_DATA_SIZE);
+       offset += _marshall_buf(buf + offset, node->nodedesc, IB_SMP_DATA_SIZE);
+       /* need to come back later and store number of stored ports
+        * because port entries can be NULL or (in the case of switches)
+        * there is an additional port 0 not accounted for in numports.
+        */
+       ports_stored_offset = offset;
+       offset += sizeof(uint8_t);
+
+       for (i = 0; i <= node->numports; i++) {
+               if (node->ports[i]) {
+                       offset += _marshall64(buf + offset,
+                                             node->ports[i]->guid);
+                       offset += _marshall8(buf + offset,
+                                            (uint8_t) node->ports[i]->portnum);
+                       ports_stored_count++;
+               }
+       }
+
+       /* go back and store number of port keys stored */
+       _marshall8(buf + ports_stored_offset, ports_stored_count);
+
+       if (ibnd_write(fd, buf, offset) < 0)
+               return -1;
+
+       return 0;
+}
+
+static int _cache_port(int fd, ibnd_port_t * port)
+{
+       uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
+       size_t offset = 0;
+
+       offset += _marshall64(buf + offset, port->guid);
+       offset += _marshall8(buf + offset, (uint8_t) port->portnum);
+       offset += _marshall8(buf + offset, (uint8_t) port->ext_portnum);
+       offset += _marshall16(buf + offset, port->base_lid);
+       offset += _marshall8(buf + offset, port->lmc);
+       offset += _marshall_buf(buf + offset, port->info, IB_SMP_DATA_SIZE);
+       offset += _marshall64(buf + offset, port->node->guid);
+       if (port->remoteport) {
+               offset += _marshall8(buf + offset, 1);
+               offset += _marshall64(buf + offset, port->remoteport->guid);
+               offset += _marshall8(buf + offset, (uint8_t) port->remoteport->portnum);
+       } else {
+               offset += _marshall8(buf + offset, 0);
+               offset += _marshall64(buf + offset, 0);
+               offset += _marshall8(buf + offset, 0);
+       }
+
+       if (ibnd_write(fd, buf, offset) < 0)
+               return -1;
+
+       return 0;
+}
+
+int ibnd_cache_fabric(ibnd_fabric_t * fabric, const char *file,
+                     unsigned int flags)
+{
+       struct stat statbuf;
+       ibnd_node_t *node = NULL;
+       ibnd_node_t *node_next = NULL;
+       unsigned int node_count = 0;
+       ibnd_port_t *port = NULL;
+       ibnd_port_t *port_next = NULL;
+       unsigned int port_count = 0;
+       int fd;
+       int i;
+
+       if (!fabric) {
+               IBND_DEBUG("fabric parameter NULL\n");
+               return -1;
+       }
+
+       if (!file) {
+               IBND_DEBUG("file parameter NULL\n");
+               return -1;
+       }
+
+       if (!stat(file, &statbuf)) {
+               IBND_DEBUG("file '%s' already exists\n", file);
+               return -1;
+       }
+
+       if ((fd = open(file, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) {
+               IBND_DEBUG("open: %s\n", strerror(errno));
+               return -1;
+       }
+
+       if (_cache_header_info(fd, fabric) < 0)
+               goto cleanup;
+
+       node = fabric->nodes;
+       while (node) {
+               node_next = node->next;
+
+               if (_cache_node(fd, node) < 0)
+                       goto cleanup;
+
+               node_count++;
+               node = node_next;
+       }
+
+       for (i = 0; i < HTSZ; i++) {
+               port = fabric->portstbl[i];
+               while (port) {
+                       port_next = port->htnext;
+
+                       if (_cache_port(fd, port) < 0)
+                               goto cleanup;
+
+                       port_count++;
+                       port = port_next;
+               }
+       }
+
+       if (_cache_header_counts(fd, node_count, port_count) < 0)
+               goto cleanup;
+
+       if (close(fd) < 0) {
+               IBND_DEBUG("close: %s\n", strerror(errno));
+               goto cleanup;
+       }
+
+       return 0;
+
+cleanup:
+       unlink(file);
+       close(fd);
+       return -1;
+}
Index: ulp/libibnetdisc/src/internal.h
===================================================================
--- ulp/libibnetdisc/src/internal.h     (revision 2812)
+++ ulp/libibnetdisc/src/internal.h     (working copy)
@@ -39,6 +39,7 @@
 #define _INTERNAL_H_

 #include <infiniband/ibnetdisc.h>
+#include <complib/cl_qmap.h>

 #define        IBND_DEBUG(fmt, ...) \
        if (ibdebug) { \
@@ -50,4 +51,57 @@
 /* HASH table defines */
 #define HASHGUID(guid) ((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103)))

+#define MAXHOPS         63
+
+#define DEFAULT_MAX_SMP_ON_WIRE 2
+#define DEFAULT_TIMEOUT 1000
+#define DEFAULT_RETRIES 3
+
+typedef struct ibnd_scan {
+       ib_portid_t selfportid;
+       ibnd_fabric_t *fabric;
+       struct ibnd_config *cfg;
+       struct ibmad_port *ibmad_port;
+} ibnd_scan_t;
+
+typedef struct ibnd_smp ibnd_smp_t;
+typedef struct smp_engine smp_engine_t;
+typedef int (*smp_comp_cb_t) (smp_engine_t * engine, ibnd_smp_t * smp,
+                             uint8_t * mad_resp, void *cb_data);
+struct ibnd_smp {
+       cl_map_item_t on_wire;
+       struct ibnd_smp *qnext;
+       smp_comp_cb_t cb;
+       void *cb_data;
+       ib_portid_t path;
+       ib_rpc_t rpc;
+};
+
+struct smp_engine {
+       int umad_fd;
+       int smi_agent;
+       int smi_dir_agent;
+       ibnd_smp_t *smp_queue_head;
+       ibnd_smp_t *smp_queue_tail;
+       void *user_data;
+       cl_qmap_t smps_on_wire;
+       struct ibnd_config *cfg;
+       unsigned total_smps;
+};
+
+int smp_engine_init(smp_engine_t * engine, char * ca_name, int ca_port,
+                   void *user_data, ibnd_config_t *cfg);
+int issue_smp(smp_engine_t * engine, ib_portid_t * portid,
+             unsigned attrid, unsigned mod, smp_comp_cb_t cb, void *cb_data);
+int process_mads(smp_engine_t * engine);
+void smp_engine_destroy(smp_engine_t * engine);
+
+void add_to_nodeguid_hash(ibnd_node_t * node, ibnd_node_t * hash[]);
+
+void add_to_portguid_hash(ibnd_port_t * port, ibnd_port_t * hash[]);
+
+void add_to_type_list(ibnd_node_t * node, ibnd_fabric_t * fabric);
+
+void destroy_node(ibnd_node_t * node);
+
 #endif                         /* _INTERNAL_H_ */
Index: ulp/libibnetdisc/src/query_smp.c
===================================================================
--- ulp/libibnetdisc/src/query_smp.c    (revision 0)
+++ ulp/libibnetdisc/src/query_smp.c    (revision 0)
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2010 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 */
+
+#include <errno.h>
+#include <infiniband/ibnetdisc.h>
+#include <infiniband/umad.h>
+#include "internal.h"
+
+static void queue_smp(smp_engine_t * engine, ibnd_smp_t * smp)
+{
+       smp->qnext = NULL;
+       if (!engine->smp_queue_head) {
+               engine->smp_queue_head = smp;
+               engine->smp_queue_tail = smp;
+       } else {
+               engine->smp_queue_tail->qnext = smp;
+               engine->smp_queue_tail = smp;
+       }
+}
+
+static ibnd_smp_t *get_smp(smp_engine_t * engine)
+{
+       ibnd_smp_t *head = engine->smp_queue_head;
+       ibnd_smp_t *tail = engine->smp_queue_tail;
+       ibnd_smp_t *rc = head;
+       if (head) {
+               if (tail == head)
+                       engine->smp_queue_tail = NULL;
+               engine->smp_queue_head = head->qnext;
+       }
+       return rc;
+}
+
+static int send_smp(ibnd_smp_t * smp, smp_engine_t * engine)
+{
+       int rc = 0;
+       uint8_t umad[1024];
+       ib_rpc_t *rpc = &smp->rpc;
+       int agent = 0;
+
+       memset(umad, 0, umad_size() + IB_MAD_SIZE);
+
+       if (rpc->mgtclass == IB_SMI_CLASS) {
+               agent = engine->smi_agent;
+       } else if (rpc->mgtclass == IB_SMI_DIRECT_CLASS) {
+               agent = engine->smi_dir_agent;
+       } else {
+               IBND_ERROR("Invalid class for RPC\n");
+               return (-EIO);
+       }
+
+       if ((rc = mad_build_pkt(umad, &smp->rpc, &smp->path, NULL, NULL))
+           < 0) {
+               IBND_ERROR("mad_build_pkt failed; %d\n", rc);
+               return rc;
+       }
+
+       if ((rc = umad_send(engine->umad_fd, agent, umad, IB_MAD_SIZE,
+                           engine->cfg->timeout_ms, engine->cfg->retries)) < 0) {
+               IBND_ERROR("send failed; %d\n", rc);
+               return rc;
+       }
+
+       return 0;
+}
+
+static int process_smp_queue(smp_engine_t * engine)
+{
+       int rc = 0;
+       ibnd_smp_t *smp;
+       while (cl_qmap_count(&engine->smps_on_wire)
+              < engine->cfg->max_smps) {
+               smp = get_smp(engine);
+               if (!smp)
+                       return 0;
+
+               if ((rc = send_smp(smp, engine)) != 0) {
+                       free(smp);
+                       return rc;
+               }
+               cl_qmap_insert(&engine->smps_on_wire, (uint32_t) smp->rpc.trid,
+                              (cl_map_item_t *) smp);
+               engine->total_smps++;
+       }
+       return 0;
+}
+
+int issue_smp(smp_engine_t * engine, ib_portid_t * portid,
+             unsigned attrid, unsigned mod, smp_comp_cb_t cb, void *cb_data)
+{
+       ibnd_smp_t *smp = calloc(1, sizeof *smp);
+       if (!smp) {
+               IBND_ERROR("OOM\n");
+               return -ENOMEM;
+       }
+
+       smp->cb = cb;
+       smp->cb_data = cb_data;
+       smp->path = *portid;
+       smp->rpc.method = IB_MAD_METHOD_GET;
+       smp->rpc.attr.id = attrid;
+       smp->rpc.attr.mod = mod;
+       smp->rpc.timeout = engine->cfg->timeout_ms;
+       smp->rpc.datasz = IB_SMP_DATA_SIZE;
+       smp->rpc.dataoffs = IB_SMP_DATA_OFFS;
+       smp->rpc.trid = mad_trid();
+
+       if (portid->lid <= 0 || portid->drpath.drslid == 0xffff ||
+           portid->drpath.drdlid == 0xffff)
+               smp->rpc.mgtclass = IB_SMI_DIRECT_CLASS;        /* direct SMI */
+       else
+               smp->rpc.mgtclass = IB_SMI_CLASS;       /* Lid routed SMI */
+
+       portid->sl = 0;
+       portid->qp = 0;
+
+       queue_smp(engine, smp);
+       return process_smp_queue(engine);
+}
+
+static int process_one_recv(smp_engine_t * engine)
+{
+       int rc = 0;
+       int status = 0;
+       ibnd_smp_t *smp;
+       uint8_t *mad;
+       uint32_t trid;
+       uint8_t umad[sizeof(struct ib_user_mad) + IB_MAD_SIZE];
+       int length = umad_size() + IB_MAD_SIZE;
+
+       memset(umad, 0, sizeof(umad));
+
+       /* wait for the next message */
+       if ((rc = umad_recv(engine->umad_fd, umad, &length,
+                           0)) < 0) {
+               if (rc == -EWOULDBLOCK)
+                       return 0;
+               IBND_ERROR("umad_recv failed: %d\n", rc);
+               return -1;
+       }
+
+       mad = umad_get_mad(umad);
+       trid = (uint32_t) mad_get_field64(mad, 0, IB_MAD_TRID_F);
+
+       smp = (ibnd_smp_t *) cl_qmap_remove(&engine->smps_on_wire, trid);
+       if ((cl_map_item_t *) smp == cl_qmap_end(&engine->smps_on_wire)) {
+               IBND_ERROR("Failed to find matching smp for trid (%x)\n", trid);
+               return -1;
+       }
+
+       rc = process_smp_queue(engine);
+       if (rc)
+               goto error;
+
+       if ((status = umad_status(umad))) {
+               IBND_ERROR("umad (%s Attr 0x%x:%u) bad status %d; %s\n",
+                          portid2str(&smp->path), smp->rpc.attr.id,
+                          smp->rpc.attr.mod, status, strerror(status));
+       } else if ((status = mad_get_field(mad, 0, IB_DRSMP_STATUS_F))) {
+               IBND_ERROR("mad (%s Attr 0x%x:%u) bad status 0x%x\n",
+                          portid2str(&smp->path), smp->rpc.attr.id,
+                          smp->rpc.attr.mod, status);
+       } else
+               rc = smp->cb(engine, smp, mad, smp->cb_data);
+
+error:
+       free(smp);
+       return rc;
+}
+
+int smp_engine_init(smp_engine_t * engine, char * ca_name, int ca_port,
+                   void *user_data, ibnd_config_t *cfg)
+{
+       memset(engine, 0, sizeof(*engine));
+
+       if (umad_init() < 0) {
+               IBND_ERROR("umad_init failed\n");
+               return -EIO;
+       }
+
+       engine->umad_fd = umad_open_port(ca_name, ca_port);
+       if (engine->umad_fd < 0) {
+               IBND_ERROR("can't open UMAD port (%s:%d)\n", ca_name, ca_port);
+               return -EIO;
+       }
+
+       if ((engine->smi_agent = umad_register(engine->umad_fd,
+            IB_SMI_CLASS, 1, 0, 0)) < 0) {
+               IBND_ERROR("Failed to register SMI agent on (%s:%d)\n",
+                          ca_name, ca_port);
+               goto eio_close;
+       }
+
+       if ((engine->smi_dir_agent = umad_register(engine->umad_fd,
+            IB_SMI_DIRECT_CLASS, 1, 0, 0)) < 0) {
+               IBND_ERROR("Failed to register SMI_DIRECT agent on (%s:%d)\n",
+                          ca_name, ca_port);
+               goto eio_close;
+       }
+
+       engine->user_data = user_data;
+       cl_qmap_init(&engine->smps_on_wire);
+       engine->cfg = cfg;
+       return (0);
+
+eio_close:
+       umad_close_port(engine->umad_fd);
+       return (-EIO);
+}
+
+void smp_engine_destroy(smp_engine_t * engine)
+{
+       cl_map_item_t *item;
+       ibnd_smp_t *smp;
+
+       /* remove queued smps */
+       smp = get_smp(engine);
+       if (smp)
+               IBND_ERROR("outstanding SMP's\n");
+       for ( /* */ ; smp; smp = get_smp(engine))
+               free(smp);
+
+       /* remove smps from the wire queue */
+       item = cl_qmap_head(&engine->smps_on_wire);
+       if (item != cl_qmap_end(&engine->smps_on_wire))
+               IBND_ERROR("outstanding SMP's on wire\n");
+       for ( /* */ ; item != cl_qmap_end(&engine->smps_on_wire);
+            item = cl_qmap_head(&engine->smps_on_wire)) {
+               cl_qmap_remove_item(&engine->smps_on_wire, item);
+               free(item);
+       }
+
+       umad_close_port(engine->umad_fd);
+}
+
+int process_mads(smp_engine_t * engine)
+{
+       int rc;
+       while (!cl_is_qmap_empty(&engine->smps_on_wire))
+               if ((rc = process_one_recv(engine)) != 0)
+                       return rc;
+       return 0;
+}
Index: ulp/libibnetdisc/src/Sources
===================================================================
--- ulp/libibnetdisc/src/Sources        (revision 2812)
+++ ulp/libibnetdisc/src/Sources        (working copy)
@@ -12,13 +12,10 @@
 DLLENTRY = DllMain
 USE_MSVCRT = 1

-SOURCES = \
-       ibnetdisc_main.cpp \
-       ibnetdisc.c \
-       chassis.c
+SOURCES = ibnetdisc_main.cpp ibnetdisc.c chassis.c query_smp.c ibnetdisc_cache.c

 INCLUDES =     ..\include\infiniband;\
-                       ..\include;\
+                       ..\include;..\include\windows;\
                        ..\..\libibmad\include;\
                        ..\..\..\tools\infiniband-diags\include;\
                        ..\..\libibverbs\include;\
@@ -28,6 +25,7 @@
                        ..\..\..\inc\user\linux;

 USER_C_FLAGS = $(USER_C_FLAGS)
+C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H

 TARGETLIBS = \
        $(SDK_LIB_PATH)\kernel32.lib    \
@@ -38,8 +36,10 @@
        $(SDK_LIB_PATH)\ole32.lib               \
 !if $(FREEBUILD)
        $(TARGETPATH)\*\libibumad.lib   \
-       $(TARGETPATH)\*\libibmad.lib
+       $(TARGETPATH)\*\libibmad.lib    \
+       $(TARGETPATH)\*\complib.lib
 !else
        $(TARGETPATH)\*\libibumadd.lib  \
-       $(TARGETPATH)\*\libibmadd.lib
+       $(TARGETPATH)\*\libibmadd.lib   \
+       $(TARGETPATH)\*\complibd.lib
 !endif




More information about the ofw mailing list