All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/2] libibnetdisc: Convert to a multi-smp algorithm
@ 2010-02-18 20:49 Ira Weiny
       [not found] ` <20100218124933.c018a23d.weiny2-i2BcT+NCU+M@public.gmane.org>
  0 siblings, 1 reply; 27+ messages in thread
From: Ira Weiny @ 2010-02-18 20:49 UTC (permalink / raw)
  To: Sasha Khapyorsky
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Hal Rosenstock


From: Ira Weiny <weiny2-i2BcT+NCU+M@public.gmane.org>
Date: Fri, 22 Jan 2010 17:33:30 -0800
Subject: [PATCH] libibnetdisc: Convert to a multi-smp algorithm

v3: change DEFAULT_MAX_SMP_ON_WIRE to 2

	Allow for multiple SMP's to be on the wire at a single time.  This
	algorithm splits the processing of SMP's to a small smp engine which
	may be useful to split out in the future.

Signed-off-by: Ira Weiny <weiny2-i2BcT+NCU+M@public.gmane.org>
---
 infiniband-diags/libibnetdisc/Makefile.am     |    2 +-
 infiniband-diags/libibnetdisc/src/ibnetdisc.c |  626 ++++++++++---------------
 infiniband-diags/libibnetdisc/src/internal.h  |   39 ++-
 infiniband-diags/libibnetdisc/src/query_smp.c |  249 ++++++++++
 4 files changed, 535 insertions(+), 381 deletions(-)
 create mode 100644 infiniband-diags/libibnetdisc/src/query_smp.c

diff --git a/infiniband-diags/libibnetdisc/Makefile.am b/infiniband-diags/libibnetdisc/Makefile.am
index a46dbc8..f30d3cc 100644
--- a/infiniband-diags/libibnetdisc/Makefile.am
+++ b/infiniband-diags/libibnetdisc/Makefile.am
@@ -23,7 +23,7 @@ libibnetdisc_version_script =
 endif
 
 libibnetdisc_la_SOURCES = src/ibnetdisc.c src/ibnetdisc_cache.c src/chassis.c \
-			  src/chassis.h src/internal.h
+			  src/chassis.h src/internal.h src/query_smp.c
 libibnetdisc_la_CFLAGS = -Wall $(DBGFLAGS)
 libibnetdisc_la_LDFLAGS = -version-info $(ibnetdisc_api_version) \
 	-export-dynamic $(libibnetdisc_version_script) \
diff --git a/infiniband-diags/libibnetdisc/src/ibnetdisc.c b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
index d0c97a1..7a9adbc 100644
--- a/infiniband-diags/libibnetdisc/src/ibnetdisc.c
+++ b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
@@ -57,100 +57,32 @@
 static int show_progress = 0;
 int ibdebug;
 
-int query_port_info(struct ibmad_port *ibmad_port, ib_portid_t * portid,
-		    int portnum, ibnd_port_t * port)
-{
-	char width[64], speed[64];
-	int iwidth;
-	int ispeed;
-
-	if (!smp_query_via(port->info, portid, IB_ATTR_PORT_INFO,
-			   portnum, 0, ibmad_port))
-		return -1;
-
-	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);
-	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);
-	IBND_DEBUG
-	    ("portid %s portnum %d: base lid %d state %d physstate %d %s %s\n",
-	     portid2str(portid), 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));
+/* forward declare */
+int query_node_info(smp_engine_t * engine, ib_portid_t * portid,
+		    ibnd_node_t * node);
 
-	return 0;
-}
 
-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_switch_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;
-
-	/* 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));
-
+	uint8_t *switch_info = mad + IB_SMP_DATA_OFFS;
+	ibnd_node_t * node = (ibnd_node_t *)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 query_node(struct ibmad_port *ibmad_port, ibnd_fabric_t * fabric,
-		      ibnd_node_t * node, ibnd_port_t * port,
-		      ib_portid_t * portid)
+static int query_switch_info(smp_engine_t * engine, ib_portid_t * portid,
+		      ibnd_node_t *node)
 {
-	int rc = 0;
-	void *nd = node->nodedesc;
-
-	if ((rc = query_node_info(ibmad_port, fabric, node, portid)) != 0)
-		return rc;
-
-	if (!smp_query_via(nd, portid, IB_ATTR_NODE_DESC, 0, 0, ibmad_port))
-		return -1;
-
-	if ((rc = query_port_info(ibmad_port, portid, 0, port)) != 0)
-		return rc;
-
-	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);
-
-	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
-	 * the external port */
-	if ((rc =
-	     query_port_info(ibmad_port, portid, port->portnum, port)) != 0)
-		return rc;
-
-	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;
+	node->smaenhsp0 = 0;	/* assume base SP0 */
+	return (issue_smp(engine, portid, IB_ATTR_SWITCH_INFO, 0, recv_switch_info,
+			  (void *)node));
 }
 
 static int add_port_to_dpath(ib_dr_path_t * path, int nextport)
 {
 	if (path->cnt + 2 >= sizeof(path->p)) {
-		IBND_ERROR("DR path has grown too long\n");
 		return -1;
 	}
 	++path->cnt;
@@ -158,6 +90,7 @@ static int add_port_to_dpath(ib_dr_path_t * path, int nextport)
 	return path->cnt;
 }
 
+#if 0
 static void retract_dpath(ib_portid_t * path)
 {
 	path->drpath.cnt--;	/* restore path */
@@ -167,17 +100,19 @@ static void retract_dpath(ib_portid_t * path)
 		path->drpath.drdlid = 0;
 	}
 }
+#endif
 
-static int extend_dpath(struct ibmad_port *ibmad_port, ibnd_fabric_t * fabric,
-			ibnd_scan_t * scan, ib_portid_t * portid, int nextport)
+static int extend_dpath(smp_engine_t * engine, ib_portid_t * portid, int nextport)
 {
 	int rc = 0;
+	ibnd_scan_t *scan = (ibnd_scan_t *)engine->user_data;
+	ibnd_fabric_t *fabric = scan->fabric;
 
 	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,
-						ibmad_port) < 0) {
+						engine->ibmad_port) < 0) {
 				IBND_ERROR("Failed to resolve self\n");
 				return -1;
 			}
@@ -187,38 +122,238 @@ static int extend_dpath(struct ibmad_port *ibmad_port, ibnd_fabric_t * fabric,
 	}
 
 	rc = add_port_to_dpath(&portid->drpath, nextport);
+	if (rc < 0)
+		IBND_ERROR("add port %d to DR path failed; %s\n", nextport,
+			   portid2str(portid));
 
 	if (rc != -1 && portid->drpath.cnt > fabric->maxhops_discovered)
 		fabric->maxhops_discovered = portid->drpath.cnt;
 	return rc;
 }
 
-static void dump_endnode(ib_portid_t * path, char *prompt,
-			 ibnd_node_t * node, ibnd_port_t * port)
+static int recv_node_desc(smp_engine_t * engine, ibnd_smp_t * smp,
+			  uint8_t *mad, void *cb_data)
 {
-	char type[64];
-	if (!show_progress)
-		return;
+	uint8_t *node_desc = mad + IB_SMP_DATA_OFFS;
+	ibnd_node_t *node = (ibnd_node_t *)cb_data;
+	memcpy(node->nodedesc, node_desc, sizeof(node->nodedesc));
+	return 0;
+}
+
+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,
+			  (void *)node));
+}
+
+static void debug_port(ib_portid_t *portid, ibnd_port_t * port)
+{
+	char width[64], speed[64];
+	int iwidth;
+	int ispeed;
+
+	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);
+	IBND_DEBUG
+	    ("portid %s portnum %d: base lid %d state %d physstate %d %s %s\n",
+	     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));
+}
+
+static int recv_port_info(smp_engine_t *engine, ibnd_smp_t * smp,
+			  uint8_t *mad, void *cb_data)
+{
+	ibnd_fabric_t *fabric = ((ibnd_scan_t *)engine->user_data)->fabric;
+	ibnd_node_t *node = (ibnd_node_t *)cb_data;
+	ibnd_port_t *port;
+	uint8_t *port_info = mad + IB_SMP_DATA_OFFS;
+	uint8_t port_num, local_port;
+
+	port_num = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F);
+	local_port = mad_get_field(port_info, 0, IB_PORT_LOCAL_PORT_F);
+
+	/* 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;
+		}
+	}
+
+	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 (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;
+	}
+
+	add_to_portguid_hash(port, fabric->portstbl);
+
+	debug_port(&smp->path, port);
 
-	mad_dump_node_type(type, 64, &node->type, sizeof(int));
-	printf("%s -> %s %s {%016" PRIx64 "} portnum %d base 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);
+	if (port_num &&
+	    (mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F)
+	    == IB_PORT_PHYS_STATE_LINKUP)
+		&&
+	    (node->type == IB_NODE_SWITCH || node == fabric->from_node)) {
+
+		ib_portid_t path = smp->path;
+		if (extend_dpath(engine, &path, port_num) != -1)
+			query_node_info(engine, &path, node);
+	}
+
+	return 0;
+}
+int query_port_info(smp_engine_t * engine, ib_portid_t * portid,
+		    ibnd_node_t *node, int portnum)
+{
+	IBND_DEBUG("Query Port Info; %s (%lx):%d\n", portid2str(portid),
+		   node->guid, portnum);
+	return (issue_smp(engine, portid, IB_ATTR_PORT_INFO, portnum, recv_port_info,
+			  (void *)node));
 }
 
-static ibnd_node_t *find_existing_node(ibnd_fabric_t * fabric,
-				       ibnd_node_t * new)
+static ibnd_node_t *create_node(smp_engine_t * engine, ib_portid_t * path,
+				uint8_t *node_info)
 {
-	int hash = HASHGUID(new->guid) % HTSZ;
+	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;
+	}
+
+	/* 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));
+
+	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->path_portid = *path;
+	memcpy(rc->info, node_info, sizeof(rc->info));
+
+	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 = (ibnd_port_t *) remoteport;
+	remoteport->remoteport = (ibnd_port_t *) port;
+}
+
+static int recv_node_info(smp_engine_t *engine, ibnd_smp_t * smp,
+			  uint8_t *mad, void *cb_data)
+{
+	ibnd_fabric_t *fabric = ((ibnd_scan_t *)engine->user_data)->fabric;
+	int i = 0;
+	uint8_t *node_info = mad + IB_SMP_DATA_OFFS;
+	ibnd_node_t * rem_node = (ibnd_node_t *)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 %lx (%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;
+
+	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) %lx 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]);
+	}
+
+	if (!node_is_new)
+		return 0;
+
+	query_node_desc(engine, &smp->path, node);
+
+	if (node->type == IB_NODE_SWITCH)
+		query_switch_info(engine, &smp->path, node);
+
+	/* process all the ports on this node */
+	for (i = (node->type == IB_NODE_SWITCH) ? 0 : 1;
+		i <= node->numports; i++) {
+			query_port_info(engine, &smp->path, node, i);
+	}
+
+	return 0;
+}
+
+int query_node_info(smp_engine_t * engine, ib_portid_t * portid,
+		    ibnd_node_t * node)
+{
+	IBND_DEBUG("Query Node Info; %s\n", portid2str(portid));
+	return (issue_smp(engine, portid, IB_ATTR_NODE_INFO, 0, recv_node_info,
+			  (void *)node));
 }
 
 ibnd_node_t *ibnd_find_node_guid(ibnd_fabric_t * fabric, uint64_t guid)
@@ -321,205 +456,13 @@ void add_to_type_list(ibnd_node_t * node, ibnd_fabric_t * fabric)
 	}
 }
 
-static int add_to_nodedist(ibnd_node_t * node, ibnd_scan_t * scan,
-			   ib_portid_t * path, int dist)
-{
-	ibnd_node_scan_t *node_scan;
-
-	node_scan = malloc(sizeof(*node_scan));
-	if (!node_scan) {
-		IBND_ERROR("OOM: node scan creation failed\n");
-		return -1;
-	}
-	node_scan->node = node;
-
-	if (node->type != IB_NODE_SWITCH)
-		dist = MAXHOPS;	/* special Ca list */
-
-	node_scan->dnext = scan->nodesdist[dist];
-	scan->nodesdist[dist] = node_scan;
-
-	return 0;
-}
-
-static ibnd_node_t *create_node(ibnd_fabric_t * fabric, ibnd_scan_t * scan,
-				ibnd_node_t * temp, ib_portid_t * path,
-				int dist)
-{
-	ibnd_node_t *node;
-
-	node = malloc(sizeof(*node));
-	if (!node) {
-		IBND_ERROR("OOM: node creation failed\n");
-		return NULL;
-	}
-
-	memcpy(node, temp, sizeof(*node));
-	node->path_portid = *path;
-
-	add_to_nodeguid_hash(node, fabric->nodestbl);
-
-	/* add this to the all nodes list */
-	node->next = fabric->nodes;
-	fabric->nodes = node;
-
-	add_to_type_list(node, fabric);
-
-	if (add_to_nodedist(node, scan, path, dist) < 0) {
-		free(node);
-		return NULL;
-	}
-
-	return node;
-}
-
-static struct ibnd_port *find_existing_port_node(ibnd_node_t * node,
-						 ibnd_port_t * port)
-{
-	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 = node;
-	port->ext_portnum = 0;
-
-	node->ports[temp->portnum] = 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_scan_t * scan,
-			   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 (portnum > 0 && extend_dpath(ibmad_port, fabric, scan, 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, scan, &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;
-}
-
-static void ibnd_scan_destroy(ibnd_scan_t * scan)
-{
-	int dist = 0;
-	int max_hops = MAXHOPS - 1;
-	ibnd_node_scan_t *node_scan;
-	ibnd_node_scan_t *next;
-
-	for (dist = 0; dist <= max_hops; dist++) {
-		node_scan = scan->nodesdist[dist];
-		while (node_scan) {
-			next = node_scan->dnext;
-			free(node_scan);
-			node_scan = next;
-		}
-	}
-}
-
 ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port *ibmad_port,
 				    ib_portid_t * from, int hops)
 {
-	int rc = 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_node_scan_t *node_scan;
-	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;
 
 	if (_check_ibmad_port(ibmad_port) < 0)
@@ -534,100 +477,33 @@ ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port *ibmad_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");
+		IBND_ERROR("OOM: failed to calloc ibnd_fabric_t\n");
 		return NULL;
 	}
 
 	memset(fabric, 0, sizeof(*fabric));
 
-	memset(&scan, '\0', sizeof(ibnd_scan_t));
-
-	IBND_DEBUG("from %s\n", portid2str(from));
-
-	memset(&node_buf, 0, sizeof(node_buf));
-	memset(&port_buf, 0, sizeof(port_buf));
+	memset(&(scan.selfportid), 0, sizeof(scan.selfportid));
+	scan.fabric = fabric;
 
-	if (query_node(ibmad_port, fabric, &node_buf, &port_buf, from)) {
-		IBND_DEBUG("can't reach node %s\n", portid2str(from));
-		goto error;
-	}
-
-	node = create_node(fabric, &scan, &node_buf, from, 0);
-	if (!node)
-		goto error;
+	smp_engine_init(&engine, ibmad_port, &scan, DEFAULT_MAX_SMP_ON_WIRE);
 
-	fabric->from_node = (ibnd_node_t *) node;
-
-	port = add_port_to_node(fabric, node, &port_buf);
-	if (!port)
-		goto error;
+	IBND_DEBUG("from %s\n", portid2str(from));
 
-	rc = get_remote_node(ibmad_port, fabric, &scan, node, port, from,
-			     mad_get_field(node->info, 0, IB_NODE_LOCAL_PORT_F),
-			     0);
-	if (rc < 0)
-		goto error;
-	if (rc > 0)		/* non-fatal error, nothing more to be done */
-		return fabric;
-
-	for (dist = 0; dist <= max_hops; dist++) {
-
-		for (node_scan = scan.nodesdist[dist]; node_scan;
-		     node_scan = node_scan->dnext) {
-			node = node_scan->node;
-
-			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 (query_port_info(ibmad_port, path, i,
-						    &port_buf)) {
-					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, &scan,
-						    node, port, path, i,
-						    dist) < 0)
-					goto error;
-			}
-		}
+	if (!query_node_info(&engine, from, NULL)) {
+		if (process_mads(&engine) != 0)
+			goto error;
 	}
 
 	if (group_nodes(fabric))
 		goto error;
 
-	ibnd_scan_destroy(&scan);
+	smp_engine_destroy(&engine);
 	return fabric;
 error:
-	ibnd_scan_destroy(&scan);
+	smp_engine_destroy(&engine);
 	ibnd_destroy_fabric(fabric);
 	return NULL;
 }
diff --git a/infiniband-diags/libibnetdisc/src/internal.h b/infiniband-diags/libibnetdisc/src/internal.h
index 348bd0f..61b644d 100644
--- a/infiniband-diags/libibnetdisc/src/internal.h
+++ b/infiniband-diags/libibnetdisc/src/internal.h
@@ -39,6 +39,7 @@
 #define _INTERNAL_H_
 
 #include <infiniband/ibnetdisc.h>
+#include <complib/cl_qmap.h>
 
 #define	IBND_DEBUG(fmt, ...) \
 	if (ibdebug) { \
@@ -52,16 +53,44 @@
 
 #define MAXHOPS         63
 
-typedef struct ibnd_node_scan {
-	ibnd_node_t *node;
-	struct ibnd_node_scan *dnext;	/* nodesdist next */
-} ibnd_node_scan_t;
+#define DEFAULT_MAX_SMP_ON_WIRE 2
 
 typedef struct ibnd_scan {
-	ibnd_node_scan_t *nodesdist[MAXHOPS + 1];
 	ib_portid_t selfportid;
+	ibnd_fabric_t *fabric;
 } 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 {
+	struct ibmad_port *ibmad_port;
+	ibnd_smp_t *smp_queue_head;
+	ibnd_smp_t *smp_queue_tail;
+	void * user_data;
+	cl_qmap_t smps_on_wire;
+	int num_smps_outstanding;
+	int max_smps_on_wire;
+};
+
+void smp_engine_init(smp_engine_t * engine, struct ibmad_port *ibmad_port,
+		     void * user_data, int max_smps_on_wire);
+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[]);
diff --git a/infiniband-diags/libibnetdisc/src/query_smp.c b/infiniband-diags/libibnetdisc/src/query_smp.c
new file mode 100644
index 0000000..5571314
--- /dev/null
+++ b/infiniband-diags/libibnetdisc/src/query_smp.c
@@ -0,0 +1,249 @@
+/*
+ * 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.
+ *
+ */
+
+#include <errno.h>
+#include <infiniband/ibnetdisc.h>
+#include <infiniband/umad.h>
+#include "internal.h"
+
+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;
+	}
+}
+
+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;
+}
+
+int send_smp(ibnd_smp_t * smp, struct ibmad_port *srcport)
+{
+	int rc = 0;
+	uint8_t umad[1024];
+	ib_rpc_t *rpc = &smp->rpc;
+
+	memset(umad, 0, umad_size() + IB_MAD_SIZE);
+
+	if ((rc = mad_build_pkt(umad, &smp->rpc, &smp->path, NULL, NULL))
+	    < 0) {
+		IBND_ERROR("mad_build_pkt failed; %d", rc);
+		return rc;
+	}
+
+	if ((rc = umad_send(mad_rpc_portid(srcport),
+			    mad_rpc_class_agent(srcport, rpc->mgtclass),
+			    umad, IB_MAD_SIZE,
+			    mad_get_timeout(srcport, rpc->timeout),
+			    mad_get_retries(srcport))) < 0) {
+		IBND_ERROR("send failed; %d", 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->max_smps_on_wire) {
+		smp = get_smp(engine);
+		if (!smp)
+			return 0;
+
+		cl_qmap_insert(&engine->smps_on_wire, (uint32_t)smp->rpc.trid,
+			       (cl_map_item_t *)smp);
+		if ((rc = send_smp(smp, engine->ibmad_port)) != 0)
+			return rc;
+	}
+	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");
+		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 = mad_get_timeout(engine->ibmad_port, 0);
+	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;
+
+	engine->num_smps_outstanding++;
+	queue_smp(engine, smp);
+	return (process_smp_queue(engine));
+}
+
+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[umad_size() + IB_MAD_SIZE];
+	int length = umad_size() + IB_MAD_SIZE;
+
+	memset(umad, 0, sizeof(umad));
+
+	/* wait for the next message */
+	if ((rc = umad_recv(mad_rpc_portid(engine->ibmad_port), umad, &length,
+			    0)) < 0) {
+		if (rc == -EWOULDBLOCK)
+			return 0;
+		IBND_ERROR("umad_recv failed: %d\n", rc);
+		return -1;
+	}
+
+	rc = process_smp_queue(engine);
+
+	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;
+	}
+
+	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);
+	engine->num_smps_outstanding--;
+	return (rc);
+}
+
+void smp_engine_init(smp_engine_t * engine, struct ibmad_port *ibmad_port,
+		     void * user_data, int max_smps_on_wire)
+{
+	memset(engine, '\0', sizeof(*engine));
+	engine->ibmad_port = ibmad_port;
+	engine->user_data = user_data;
+	cl_qmap_init(&engine->smps_on_wire);
+	engine->num_smps_outstanding = 0;
+	engine->max_smps_on_wire = max_smps_on_wire;
+}
+
+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);
+	}
+
+	engine->num_smps_outstanding = 0;
+}
+
+int process_mads(smp_engine_t *engine)
+{
+	int rc = 0;
+	while (engine->num_smps_outstanding > 0) {
+		if ((rc = process_smp_queue(engine)) != 0)
+			return rc;
+		while (!cl_is_qmap_empty(&engine->smps_on_wire))
+			if ((rc = process_one_recv(engine)) != 0)
+				return rc;
+	}
+	return 0;
+}
+
-- 
1.5.4.5

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2010-05-11 23:44 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-02-18 20:49 [PATCH v3 1/2] libibnetdisc: Convert to a multi-smp algorithm Ira Weiny
     [not found] ` <20100218124933.c018a23d.weiny2-i2BcT+NCU+M@public.gmane.org>
2010-04-13 10:46   ` Sasha Khapyorsky
2010-04-13 13:25     ` Sasha Khapyorsky
2010-04-13 20:30       ` Ira Weiny
     [not found]         ` <20100413133028.b55a0cb1.weiny2-i2BcT+NCU+M@public.gmane.org>
2010-04-14  9:58           ` Sasha Khapyorsky
2010-04-23  2:12       ` Ira Weiny
     [not found]         ` <20100422191231.bf6021fb.weiny2-i2BcT+NCU+M@public.gmane.org>
2010-05-07 20:50           ` Sasha Khapyorsky
     [not found]             ` <20100507205052.GW7099-o14lFNPAa+WKTadZzrrH2Q@public.gmane.org>
2010-05-10 20:53               ` Ira Weiny
     [not found]                 ` <20100510135353.257d76c0.weiny2-i2BcT+NCU+M@public.gmane.org>
2010-05-11 16:42                   ` Sasha Khapyorsky
2010-05-11 23:44                     ` Ira Weiny
2010-04-13 16:53     ` Sasha Khapyorsky
2010-04-13 16:58       ` [PATCH] libibnetdisc: don't try to cross discovery over CA Sasha Khapyorsky
2010-04-13 17:07     ` [PATCH v3 1/2] libibnetdisc: Convert to a multi-smp algorithm Ira Weiny
2010-04-13 17:18     ` Sasha Khapyorsky
2010-04-13 18:24       ` Ira Weiny
     [not found]         ` <20100413112412.de66586d.weiny2-i2BcT+NCU+M@public.gmane.org>
2010-04-14  9:59           ` [PATCH] libibnetdisc: don't query CA ports not connected to a fabric Sasha Khapyorsky
2010-04-13 16:38   ` [PATCH] libibnetdisc: fix outstanding SMPs countung Sasha Khapyorsky
2010-04-13 20:38     ` Ira Weiny
     [not found]       ` <20100413133826.00a8afc5.weiny2-i2BcT+NCU+M@public.gmane.org>
2010-04-13 20:44         ` Ira Weiny
     [not found]           ` <20100413134446.72eb336a.weiny2-i2BcT+NCU+M@public.gmane.org>
2010-04-14 10:23             ` Sasha Khapyorsky
2010-04-14 16:52               ` Ira Weiny
     [not found]                 ` <0EEE4F40-F1DD-46A6-B756-3C46DA06B403-i2BcT+NCU+M@public.gmane.org>
2010-04-16 12:05                   ` Sasha Khapyorsky
2010-04-16 12:21                     ` [PATCH] libibnetdisc: fix memory leak in case of send_smps() failure Sasha Khapyorsky
2010-04-18 15:49                     ` [PATCH] libibnetdisc: fix outstanding SMPs countung Sasha Khapyorsky
2010-04-18 15:56                       ` [PATCH] libibnetdiscover: more outstanding MADs counting fix Sasha Khapyorsky
2010-04-18 16:03                         ` [PATCH] libibnetdisc: remove not needed process_smp_queue() call Sasha Khapyorsky
2010-04-18 16:10                           ` [PATCH] libibnetdisc: remove not needed num_smps_outstanding counter Sasha Khapyorsky

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.