xref: /freebsd/contrib/ofed/libibnetdisc/chassis.c (revision 02e9120893770924227138ba49df1edb3896112a)
1 /*
2  * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
3  * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
4  * Copyright (c) 2008 Lawrence Livermore National Lab.  All rights reserved.
5  * Copyright (c) 2010 HNR Consulting.  All rights reserved.
6  *
7  * This software is available to you under a choice of one of two
8  * licenses.  You may choose to be licensed under the terms of the GNU
9  * General Public License (GPL) Version 2, available from the file
10  * COPYING in the main directory of this source tree, or the
11  * OpenIB.org BSD license below:
12  *
13  *     Redistribution and use in source and binary forms, with or
14  *     without modification, are permitted provided that the following
15  *     conditions are met:
16  *
17  *      - Redistributions of source code must retain the above
18  *        copyright notice, this list of conditions and the following
19  *        disclaimer.
20  *
21  *      - Redistributions in binary form must reproduce the above
22  *        copyright notice, this list of conditions and the following
23  *        disclaimer in the documentation and/or other materials
24  *        provided with the distribution.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33  * SOFTWARE.
34  *
35  */
36 
37 /*========================================================*/
38 /*               FABRIC SCANNER SPECIFIC DATA             */
39 /*========================================================*/
40 
41 #if HAVE_CONFIG_H
42 #include <config.h>
43 #endif				/* HAVE_CONFIG_H */
44 
45 #include <stdlib.h>
46 #include <inttypes.h>
47 
48 #include <infiniband/mad.h>
49 
50 #include "internal.h"
51 #include "chassis.h"
52 
53 static char *ChassisTypeStr[] =
54 { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004", "ISR4700", "ISR4200" };
55 static char *ChassisSlotTypeStr[] = { "", "Line", "Spine", "SRBD" };
56 
57 typedef struct chassis_scan {
58 	ibnd_chassis_t *first_chassis;
59 	ibnd_chassis_t *current_chassis;
60 	ibnd_chassis_t *last_chassis;
61 } chassis_scan_t;
62 
63 char *ibnd_get_chassis_type(ibnd_node_t * node)
64 {
65 	int chassis_type;
66 
67 	if (!node) {
68 		IBND_DEBUG("node parameter NULL\n");
69 		return NULL;
70 	}
71 
72 	if (!node->chassis)
73 		return NULL;
74 
75 	chassis_type = mad_get_field(node->info, 0, IB_NODE_VENDORID_F);
76 
77 	switch (chassis_type)
78 	{
79 		case VTR_VENDOR_ID: /* Voltaire chassis */
80 		{
81 			if (node->ch_type == UNRESOLVED_CT || node->ch_type > ISR4200_CT)
82 				return NULL;
83 			return ChassisTypeStr[node->ch_type];
84 		}
85 		case MLX_VENDOR_ID:
86 		{
87 			if (node->ch_type_str[0] == '\0')
88 				return NULL;
89 			return node->ch_type_str;
90 		}
91 		default:
92 		{
93 			break;
94 		}
95 	}
96 	return NULL;
97 }
98 
99 char *ibnd_get_chassis_slot_str(ibnd_node_t * node, char *str, size_t size)
100 {
101 	int vendor_id;
102 
103 	if (!node) {
104 		IBND_DEBUG("node parameter NULL\n");
105 		return NULL;
106 	}
107 
108 	/* Currently, only if Voltaire or Mellanox chassis */
109 	vendor_id = mad_get_field(node->info, 0,IB_NODE_VENDORID_F);
110 
111 	if ((vendor_id != VTR_VENDOR_ID) && (vendor_id != MLX_VENDOR_ID))
112 		return NULL;
113 	if (!node->chassis)
114 		return NULL;
115 	if (node->ch_slot == UNRESOLVED_CS || node->ch_slot > SRBD_CS)
116 		return NULL;
117 	if (!str)
118 		return NULL;
119 	snprintf(str, size, "%s %d Chip %d", ChassisSlotTypeStr[node->ch_slot],
120 		 node->ch_slotnum, node->ch_anafanum);
121 	return str;
122 }
123 
124 static ibnd_chassis_t *find_chassisnum(ibnd_fabric_t * fabric,
125 				       unsigned char chassisnum)
126 {
127 	ibnd_chassis_t *current;
128 
129 	for (current = fabric->chassis; current; current = current->next)
130 		if (current->chassisnum == chassisnum)
131 			return current;
132 
133 	return NULL;
134 }
135 
136 static uint64_t topspin_chassisguid(uint64_t guid)
137 {
138 	/* Byte 3 in system image GUID is chassis type, and */
139 	/* Byte 4 is location ID (slot) so just mask off byte 4 */
140 	return guid & 0xffffffff00ffffffULL;
141 }
142 
143 int ibnd_is_xsigo_guid(uint64_t guid)
144 {
145 	if ((guid & 0xffffff0000000000ULL) == 0x0013970000000000ULL)
146 		return 1;
147 	else
148 		return 0;
149 }
150 
151 static int is_xsigo_leafone(uint64_t guid)
152 {
153 	if ((guid & 0xffffffffff000000ULL) == 0x0013970102000000ULL)
154 		return 1;
155 	else
156 		return 0;
157 }
158 
159 int ibnd_is_xsigo_hca(uint64_t guid)
160 {
161 	/* NodeType 2 is HCA */
162 	if ((guid & 0xffffffff00000000ULL) == 0x0013970200000000ULL)
163 		return 1;
164 	else
165 		return 0;
166 }
167 
168 int ibnd_is_xsigo_tca(uint64_t guid)
169 {
170 	/* NodeType 3 is TCA */
171 	if ((guid & 0xffffffff00000000ULL) == 0x0013970300000000ULL)
172 		return 1;
173 	else
174 		return 0;
175 }
176 
177 static int is_xsigo_ca(uint64_t guid)
178 {
179 	if (ibnd_is_xsigo_hca(guid) || ibnd_is_xsigo_tca(guid))
180 		return 1;
181 	else
182 		return 0;
183 }
184 
185 static int is_xsigo_switch(uint64_t guid)
186 {
187 	if ((guid & 0xffffffff00000000ULL) == 0x0013970100000000ULL)
188 		return 1;
189 	else
190 		return 0;
191 }
192 
193 static uint64_t xsigo_chassisguid(ibnd_node_t * node)
194 {
195 	uint64_t sysimgguid =
196 	    mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F);
197 	uint64_t remote_sysimgguid;
198 
199 	if (!is_xsigo_ca(sysimgguid)) {
200 		/* Byte 3 is NodeType and byte 4 is PortType */
201 		/* If NodeType is 1 (switch), PortType is masked */
202 		if (is_xsigo_switch(sysimgguid))
203 			return sysimgguid & 0xffffffff00ffffffULL;
204 		else
205 			return sysimgguid;
206 	} else {
207 		if (!node->ports || !node->ports[1])
208 			return 0;
209 
210 		/* Is there a peer port ? */
211 		if (!node->ports[1]->remoteport)
212 			return sysimgguid;
213 
214 		/* If peer port is Leaf 1, use its chassis GUID */
215 		remote_sysimgguid =
216 		    mad_get_field64(node->ports[1]->remoteport->node->info, 0,
217 				    IB_NODE_SYSTEM_GUID_F);
218 		if (is_xsigo_leafone(remote_sysimgguid))
219 			return remote_sysimgguid & 0xffffffff00ffffffULL;
220 		else
221 			return sysimgguid;
222 	}
223 }
224 
225 static uint64_t get_chassisguid(ibnd_node_t * node)
226 {
227 	uint32_t vendid = mad_get_field(node->info, 0, IB_NODE_VENDORID_F);
228 	uint64_t sysimgguid =
229 	    mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F);
230 
231 	if (vendid == TS_VENDOR_ID || vendid == SS_VENDOR_ID)
232 		return topspin_chassisguid(sysimgguid);
233 	else if (vendid == XS_VENDOR_ID || ibnd_is_xsigo_guid(sysimgguid))
234 		return xsigo_chassisguid(node);
235 	else
236 		return sysimgguid;
237 }
238 
239 static ibnd_chassis_t *find_chassisguid(ibnd_fabric_t * fabric,
240 					ibnd_node_t * node)
241 {
242 	ibnd_chassis_t *current;
243 	uint64_t chguid;
244 
245 	chguid = get_chassisguid(node);
246 	for (current = fabric->chassis; current; current = current->next)
247 		if (current->chassisguid == chguid)
248 			return current;
249 
250 	return NULL;
251 }
252 
253 uint64_t ibnd_get_chassis_guid(ibnd_fabric_t * fabric, unsigned char chassisnum)
254 {
255 	ibnd_chassis_t *chassis;
256 
257 	if (!fabric) {
258 		IBND_DEBUG("fabric parameter NULL\n");
259 		return 0;
260 	}
261 
262 	chassis = find_chassisnum(fabric, chassisnum);
263 	if (chassis)
264 		return chassis->chassisguid;
265 	else
266 		return 0;
267 }
268 
269 static int is_router(ibnd_node_t * n)
270 {
271 	uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
272 	return (devid == VTR_DEVID_IB_FC_ROUTER ||
273 		devid == VTR_DEVID_IB_IP_ROUTER);
274 }
275 
276 static int is_spine_9096(ibnd_node_t * n)
277 {
278 	uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
279 	return (devid == VTR_DEVID_SFB4 || devid == VTR_DEVID_SFB4_DDR);
280 }
281 
282 static int is_spine_9288(ibnd_node_t * n)
283 {
284 	uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
285 	return (devid == VTR_DEVID_SFB12 || devid == VTR_DEVID_SFB12_DDR);
286 }
287 
288 static int is_spine_2004(ibnd_node_t * n)
289 {
290 	uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
291 	return (devid == VTR_DEVID_SFB2004);
292 }
293 
294 static int is_spine_2012(ibnd_node_t * n)
295 {
296 	uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
297 	return (devid == VTR_DEVID_SFB2012);
298 }
299 
300 static int is_spine_4700(ibnd_node_t * n)
301 {
302 	uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
303 	return (devid == VTR_DEVID_SFB4700);
304 }
305 
306 static int is_spine_4700x2(ibnd_node_t * n)
307 {
308 	uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
309 	return (devid == VTR_DEVID_SFB4700X2);
310 }
311 
312 static int is_spine_4200(ibnd_node_t * n)
313 {
314 	uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
315 	return (devid == VTR_DEVID_SFB4200);
316 }
317 
318 static int is_spine(ibnd_node_t * n)
319 {
320 	return (is_spine_9096(n) || is_spine_9288(n) ||
321 		is_spine_2004(n) || is_spine_2012(n) ||
322 		is_spine_4700(n) || is_spine_4700x2(n) ||
323 		is_spine_4200(n));
324 }
325 
326 static int is_line_24(ibnd_node_t * n)
327 {
328 	uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
329 	return (devid == VTR_DEVID_SLB24 ||
330 		devid == VTR_DEVID_SLB24_DDR || devid == VTR_DEVID_SRB2004);
331 }
332 
333 static int is_line_8(ibnd_node_t * n)
334 {
335 	uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
336 	return (devid == VTR_DEVID_SLB8);
337 }
338 
339 static int is_line_2024(ibnd_node_t * n)
340 {
341 	uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
342 	return (devid == VTR_DEVID_SLB2024);
343 }
344 
345 static int is_line_4700(ibnd_node_t * n)
346 {
347 	uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
348 	return (devid == VTR_DEVID_SLB4018);
349 }
350 
351 static int is_line(ibnd_node_t * n)
352 {
353 	return (is_line_24(n) || is_line_8(n) ||
354 		is_line_2024(n) || is_line_4700(n));
355 }
356 
357 int is_chassis_switch(ibnd_node_t * n)
358 {
359 	return (is_spine(n) || is_line(n));
360 }
361 
362 /* these structs help find Line (Anafa) slot number while using spine portnum */
363 char line_slot_2_sfb4[37] = {
364 	0,
365 	1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3,
366 	4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
367 };
368 char anafa_line_slot_2_sfb4[37] = {
369 	0,
370 	1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2,
371 	1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
372 };
373 
374 char line_slot_2_sfb12[37] = {
375 	0,
376 	1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
377 	10, 10, 11, 11, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
378 };
379 char anafa_line_slot_2_sfb12[37] = {
380 	0,
381 	1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
382 	1, 2, 1, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
383 };
384 
385 /* LB slot = table[spine port] */
386 char line_slot_2_sfb18[37] = {
387 	0,
388 	1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
389 	10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18};
390 /* LB asic num = table[spine port] */
391 char anafa_line_slot_2_sfb18[37] = {
392 	0,
393 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
394 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
395 };
396 
397 /* LB slot = table[spine port] */
398 char line_slot_2_sfb18x2[37] = {
399 	0,
400 	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
401 	0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0};
402 /* LB asic num = table[spine port] */
403 char anafa_line_slot_2_sfb18x2[37] = {
404 	0,
405 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
406 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
407 };
408 
409 /* LB slot = table[spine port] */
410 char line_slot_2_sfb4200[37] = {
411 	0,
412 	1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5,
413 	5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9};
414 /* LB asic num = table[spine port] */
415 char anafa_line_slot_2_sfb4200[37] = {
416 	0,
417 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
418 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
419 };
420 
421 /* IPR FCR modules connectivity while using sFB4 port as reference */
422 char ipr_slot_2_sfb4_port[37] = {
423 	0,
424 	3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1,
425 	3, 2, 1, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
426 };
427 
428 /* these structs help find Spine (Anafa) slot number while using spine portnum */
429 char spine12_slot_2_slb[37] = {
430 	0,
431 	1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0,
432 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
433 };
434 char anafa_spine12_slot_2_slb[37] = {
435 	0,
436 	1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 0, 0, 0, 0, 0, 0,
437 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
438 };
439 
440 char spine4_slot_2_slb[37] = {
441 	0,
442 	1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0,
443 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
444 };
445 char anafa_spine4_slot_2_slb[37] = {
446 	0,
447 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
448 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
449 };
450 
451 /* FB slot = table[line port] */
452 char spine18_slot_2_slb[37] = {
453 	0,
454 	1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
455 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
456 };
457 /* FB asic = table[line port] */
458 char anafa_spine18_slot_2_slb[37] = {
459 	0,
460 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
461 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
462 };
463 char anafa_spine18x2_slot_2_slb[37] = {
464 	0,
465 	2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1,
466 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
467 };
468 
469 /* FB slot = table[line port] */
470 char sfb4200_slot_2_slb[37] = {
471 	0,
472 	1, 1, 1, 1, 0, 0, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
473 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
474 };
475 /* FB asic = table[line port] */
476 char anafa_sfb4200_slot_2_slb[37] = {
477 	0,
478 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
479 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
480 };
481 
482 /*	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 }; */
483 
484 static int get_sfb_slot(ibnd_node_t * n, ibnd_port_t * lineport)
485 {
486 	n->ch_slot = SPINE_CS;
487 	if (is_spine_9096(n)) {
488 		n->ch_type = ISR9096_CT;
489 		n->ch_slotnum = spine4_slot_2_slb[lineport->portnum];
490 		n->ch_anafanum = anafa_spine4_slot_2_slb[lineport->portnum];
491 	} else if (is_spine_9288(n)) {
492 		n->ch_type = ISR9288_CT;
493 		n->ch_slotnum = spine12_slot_2_slb[lineport->portnum];
494 		n->ch_anafanum = anafa_spine12_slot_2_slb[lineport->portnum];
495 	} else if (is_spine_2012(n)) {
496 		n->ch_type = ISR2012_CT;
497 		n->ch_slotnum = spine12_slot_2_slb[lineport->portnum];
498 		n->ch_anafanum = anafa_spine12_slot_2_slb[lineport->portnum];
499 	} else if (is_spine_2004(n)) {
500 		n->ch_type = ISR2004_CT;
501 		n->ch_slotnum = spine4_slot_2_slb[lineport->portnum];
502 		n->ch_anafanum = anafa_spine4_slot_2_slb[lineport->portnum];
503 	} else if (is_spine_4700(n)) {
504 		n->ch_type = ISR4700_CT;
505 		n->ch_slotnum = spine18_slot_2_slb[lineport->portnum];
506 		n->ch_anafanum = anafa_spine18_slot_2_slb[lineport->portnum];
507 	} else if (is_spine_4700x2(n)) {
508 		n->ch_type = ISR4700_CT;
509 		n->ch_slotnum = spine18_slot_2_slb[lineport->portnum];
510 		n->ch_anafanum = anafa_spine18x2_slot_2_slb[lineport->portnum];
511 	} else if (is_spine_4200(n)) {
512 		n->ch_type = ISR4200_CT;
513 		n->ch_slotnum = sfb4200_slot_2_slb[lineport->portnum];
514 		n->ch_anafanum = anafa_sfb4200_slot_2_slb[lineport->portnum];
515 	} else {
516 		IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n",
517 			   n->guid);
518 	}
519 	return 0;
520 }
521 
522 static int get_router_slot(ibnd_node_t * n, ibnd_port_t * spineport)
523 {
524 	uint64_t guessnum = 0;
525 
526 	n->ch_found = 1;
527 
528 	n->ch_slot = SRBD_CS;
529 	if (is_spine_9096(spineport->node)) {
530 		n->ch_type = ISR9096_CT;
531 		n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
532 		n->ch_anafanum = ipr_slot_2_sfb4_port[spineport->portnum];
533 	} else if (is_spine_9288(spineport->node)) {
534 		n->ch_type = ISR9288_CT;
535 		n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
536 		/* this is a smart guess based on nodeguids order on sFB-12 module */
537 		guessnum = spineport->node->guid % 4;
538 		/* module 1 <--> remote anafa 3 */
539 		/* module 2 <--> remote anafa 2 */
540 		/* module 3 <--> remote anafa 1 */
541 		n->ch_anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2));
542 	} else if (is_spine_2012(spineport->node)) {
543 		n->ch_type = ISR2012_CT;
544 		n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
545 		/* this is a smart guess based on nodeguids order on sFB-12 module */
546 		guessnum = spineport->node->guid % 4;
547 		// module 1 <--> remote anafa 3
548 		// module 2 <--> remote anafa 2
549 		// module 3 <--> remote anafa 1
550 		n->ch_anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2));
551 	} else if (is_spine_2004(spineport->node)) {
552 		n->ch_type = ISR2004_CT;
553 		n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
554 		n->ch_anafanum = ipr_slot_2_sfb4_port[spineport->portnum];
555 	} else {
556 		IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n",
557 			   spineport->node->guid);
558 	}
559 	return 0;
560 }
561 
562 static int get_slb_slot(ibnd_node_t * n, ibnd_port_t * spineport)
563 {
564 	n->ch_slot = LINE_CS;
565 	if (is_spine_9096(spineport->node)) {
566 		n->ch_type = ISR9096_CT;
567 		n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
568 		n->ch_anafanum = anafa_line_slot_2_sfb4[spineport->portnum];
569 	} else if (is_spine_9288(spineport->node)) {
570 		n->ch_type = ISR9288_CT;
571 		n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
572 		n->ch_anafanum = anafa_line_slot_2_sfb12[spineport->portnum];
573 	} else if (is_spine_2012(spineport->node)) {
574 		n->ch_type = ISR2012_CT;
575 		n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
576 		n->ch_anafanum = anafa_line_slot_2_sfb12[spineport->portnum];
577 	} else if (is_spine_2004(spineport->node)) {
578 		n->ch_type = ISR2004_CT;
579 		n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
580 		n->ch_anafanum = anafa_line_slot_2_sfb4[spineport->portnum];
581 	} else if (is_spine_4700(spineport->node)) {
582 		n->ch_type = ISR4700_CT;
583 		n->ch_slotnum = line_slot_2_sfb18[spineport->portnum];
584 		n->ch_anafanum = anafa_line_slot_2_sfb18[spineport->portnum];
585 	} else if (is_spine_4700x2(spineport->node)) {
586 		n->ch_type = ISR4700_CT;
587 		n->ch_slotnum = line_slot_2_sfb18x2[spineport->portnum];
588 		n->ch_anafanum = anafa_line_slot_2_sfb18x2[spineport->portnum];
589 	} else if (is_spine_4200(spineport->node)) {
590 		n->ch_type = ISR4200_CT;
591 		n->ch_slotnum = line_slot_2_sfb4200[spineport->portnum];
592 		n->ch_anafanum = anafa_line_slot_2_sfb4200[spineport->portnum];
593 	} else {
594 		IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n",
595 			   spineport->node->guid);
596 	}
597 	return 0;
598 }
599 
600 
601 /*
602 	This function called for every Mellanox node in fabric
603 */
604 static int fill_mellanox_chassis_record(ibnd_node_t * node)
605 {
606 	int p = 0;
607 	ibnd_port_t *port;
608 
609 	char node_desc[IB_SMP_DATA_SIZE];
610 	char *system_name;
611 	char *system_type;
612 	char *system_slot_name;
613 	char *node_index;
614 	char *iter;
615 	int dev_id;
616 
617 	/*
618 	The node description has the following format:
619 
620 	'MF0;<system name>:<system type>/<system slot name>[:board type]/U<node index>'
621 
622      - System slot name in our systems can be L[01-36] , S[01-18]
623      - Node index is always 1 (we don.t have boards with multiple IS4 chips).
624      - System name is taken from the currently configured host name.
625      -The board type is optional and we don.t set it currently  - A leaf or spine slot can currently hold a single type of board.
626 	 */
627 
628 	memcpy(node_desc, node->nodedesc, IB_SMP_DATA_SIZE);
629 
630 	IBND_DEBUG("fill_mellanox_chassis_record: node_desc:%s \n",node_desc);
631 
632 	if (node->ch_found)	/* somehow this node has already been passed */
633 		return 0;
634 
635 	/* All mellanox IS4 switches have the same vendor id*/
636 	dev_id = mad_get_field(node->info, 0,IB_NODE_DEVID_F);
637 	if (dev_id != MLX_DEVID_IS4)
638 		return 0;
639 
640 	if((node_desc[0] != 'M') ||
641 	   (node_desc[1] != 'F') ||
642 	   (node_desc[2] != '0') ||
643 	   (node_desc[3] != ';')) {
644 		IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s \n",node_desc);
645 		return 0;
646 	}
647 
648 	/* parse system name*/
649 	system_name = &node_desc[4];
650 	for (iter = system_name ; (*iter != ':') && (*iter != '\0') ; iter++);
651 	if(*iter == '\0'){
652 		IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get system_name failed) \n",node_desc);
653 		return 0;
654 	}
655 	*iter = '\0';
656 	iter++;
657 	/* parse system type*/
658 	system_type = iter;
659 	for ( ; (*iter != '/') && (*iter != '\0') ; iter++);
660 	if(*iter == '\0'){
661 		IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get system_type failed) \n",node_desc);
662 		return 0;
663 	}
664 	*iter = '\0';
665 	iter++;
666 	/* parse system slot name*/
667 	system_slot_name = iter;
668 	for ( ; (*iter != '/') && (*iter != ':') && (*iter != '\0') ; iter++);
669 	if(*iter == '\0'){
670 		IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get system_slot_name failed) \n",node_desc);
671 		return 0;
672 	}
673 	if(*iter == ':'){
674 		*iter = '\0';
675 		iter++;
676 		for ( ; (*iter != '/') && (*iter != '\0') ; iter++);
677 		if(*iter == '\0'){
678 			IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get board type failed) \n",node_desc);
679 			return 0;
680 		}
681 	}
682 	*iter = '\0';
683 	iter++;
684 	node_index = iter;
685 	if(node_index[0] != 'U'){
686 		IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get node index) \n",node_desc);
687 		return 0;
688 	}
689 
690 	/* set Chip number (node index) */
691 	node->ch_anafanum = (unsigned char) atoi(&node_index[1]);
692 	if(node->ch_anafanum != 1){
693 		IBND_DEBUG("Unexpected Chip number:%d \n",node->ch_anafanum);
694 	}
695 
696 
697 	/* set Line Spine numbers */
698 	if(system_slot_name[0] == 'L')
699 		node->ch_slot = LINE_CS;
700 	else if(system_slot_name[0] == 'S')
701 		node->ch_slot = SPINE_CS;
702 	else{
703 		IBND_DEBUG("fill_mellanox_chassis_record: Unsupported system_slot_name:%s \n",system_slot_name);
704 		return 0;
705 	}
706 
707 	/* The switch will be displayed under Line or Spine and not under Chassis switches */
708 	node->ch_found = 1;
709 
710 	node->ch_slotnum = (unsigned char) atoi(&system_slot_name[1]);
711 	if((node->ch_slot == LINE_CS && (node->ch_slotnum >  (LINES_MAX_NUM + 1))) ||
712 	   (node->ch_slot == SPINE_CS && (node->ch_slotnum > (SPINES_MAX_NUM + 1)))){
713 		IBND_ERROR("fill_mellanox_chassis_record: invalid slot number:%d \n",node->ch_slotnum);
714 		node->ch_slotnum = 0;
715 		return 0;
716 	}
717 
718 	/*set ch_type_str*/
719 	strncpy(node->ch_type_str , system_type, sizeof(node->ch_type_str)-1);
720 
721 	/* Line ports 1-18 are mapped to external ports 1-18*/
722 	if(node->ch_slot == LINE_CS)
723 	{
724 		for (p = 1; p <= node->numports && p <= 18 ; p++) {
725 			port = node->ports[p];
726 			if (!port)
727 				continue;
728 			port->ext_portnum = p;
729 		}
730 	}
731 
732 	return 0;
733 }
734 
735 static int insert_mellanox_line_and_spine(ibnd_node_t * node, ibnd_chassis_t * chassis)
736 {
737 	if (node->ch_slot == LINE_CS){
738 
739 		if (chassis->linenode[node->ch_slotnum])
740 			return 0;	/* already filled slot */
741 
742 		chassis->linenode[node->ch_slotnum] = node;
743 	}
744 	else if (node->ch_slot == SPINE_CS){
745 
746 		if (chassis->spinenode[node->ch_slotnum])
747 			return 0;	/* already filled slot */
748 
749 		chassis->spinenode[node->ch_slotnum] = node;
750 	}
751 	else
752 		return 0;
753 
754 	node->chassis = chassis;
755 
756 	return 0;
757 }
758 
759 
760 /* forward declare this */
761 static void voltaire_portmap(ibnd_port_t * port);
762 /*
763 	This function called for every Voltaire node in fabric
764 	It could be optimized so, but time overhead is very small
765 	and its only diag.util
766 */
767 static int fill_voltaire_chassis_record(ibnd_node_t * node)
768 {
769 	int p = 0;
770 	ibnd_port_t *port;
771 	ibnd_node_t *remnode = 0;
772 
773 	if (node->ch_found)	/* somehow this node has already been passed */
774 		return 0;
775 	node->ch_found = 1;
776 
777 	/* node is router only in case of using unique lid */
778 	/* (which is lid of chassis router port) */
779 	/* in such case node->ports is actually a requested port... */
780 	if (is_router(node))
781 		/* find the remote node */
782 		for (p = 1; p <= node->numports; p++) {
783 			port = node->ports[p];
784 			if (port && is_spine(port->remoteport->node))
785 				get_router_slot(node, port->remoteport);
786 		}
787 	else if (is_spine(node)) {
788 		int is_4700x2 = is_spine_4700x2(node);
789 
790 		for (p = 1; p <= node->numports; p++) {
791 			port = node->ports[p];
792 			if (!port || !port->remoteport)
793 				continue;
794 
795 			/*
796 			 * Skip ISR4700 double density fabric boards ports 19-36
797 			 * as they are chassis external ports
798 			 */
799 			if (is_4700x2 && (port->portnum > 18))
800 				continue;
801 
802 			remnode = port->remoteport->node;
803 			if (remnode->type != IB_NODE_SWITCH) {
804 				if (!remnode->ch_found)
805 					get_router_slot(remnode, port);
806 				continue;
807 			}
808 			if (!node->ch_type)
809 				/* we assume here that remoteport belongs to line */
810 				get_sfb_slot(node, port->remoteport);
811 
812 			/* we could break here, but need to find if more routers connected */
813 		}
814 
815 	} else if (is_line(node)) {
816 		int is_4700_line = is_line_4700(node);
817 
818 		for (p = 1; p <= node->numports; p++) {
819 			port = node->ports[p];
820 			if (!port || !port->remoteport)
821 				continue;
822 
823 			if ((is_4700_line && (port->portnum > 18)) ||
824 			    (!is_4700_line && (port->portnum > 12)))
825 				continue;
826 
827 			/* we assume here that remoteport belongs to spine */
828 			get_slb_slot(node, port->remoteport);
829 			break;
830 		}
831 	}
832 
833 	/* for each port of this node, map external ports */
834 	for (p = 1; p <= node->numports; p++) {
835 		port = node->ports[p];
836 		if (!port)
837 			continue;
838 		voltaire_portmap(port);
839 	}
840 
841 	return 0;
842 }
843 
844 static int get_line_index(ibnd_node_t * node)
845 {
846 	int retval;
847 
848 	if (is_line_4700(node))
849 		retval = node->ch_slotnum;
850 	else
851 		retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum;
852 
853 	if (retval > LINES_MAX_NUM || retval < 1) {
854 		printf("%s: retval = %d\n", __FUNCTION__, retval);
855 		IBND_ERROR("Internal error\n");
856 		return -1;
857 	}
858 	return retval;
859 }
860 
861 static int get_spine_index(ibnd_node_t * node)
862 {
863 	int retval;
864 
865 	if (is_spine_9288(node) || is_spine_2012(node))
866 		retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum;
867 	else if (is_spine_4700(node) || is_spine_4700x2(node))
868 		retval = 2 * (node->ch_slotnum - 1) + node->ch_anafanum;
869 	else
870 		retval = node->ch_slotnum;
871 
872 	if (retval > SPINES_MAX_NUM || retval < 1) {
873 		IBND_ERROR("Internal error\n");
874 		return -1;
875 	}
876 	return retval;
877 }
878 
879 static int insert_line_router(ibnd_node_t * node, ibnd_chassis_t * chassis)
880 {
881 	int i = get_line_index(node);
882 
883 	if (i < 0)
884 		return i;
885 
886 	if (chassis->linenode[i])
887 		return 0;	/* already filled slot */
888 
889 	chassis->linenode[i] = node;
890 	node->chassis = chassis;
891 	return 0;
892 }
893 
894 static int insert_spine(ibnd_node_t * node, ibnd_chassis_t * chassis)
895 {
896 	int i = get_spine_index(node);
897 
898 	if (i < 0)
899 		return i;
900 
901 	if (chassis->spinenode[i])
902 		return 0;	/* already filled slot */
903 
904 	chassis->spinenode[i] = node;
905 	node->chassis = chassis;
906 	return 0;
907 }
908 
909 static int pass_on_lines_catch_spines(ibnd_chassis_t * chassis)
910 {
911 	ibnd_node_t *node, *remnode;
912 	ibnd_port_t *port;
913 	int i, p;
914 
915 	for (i = 1; i <= LINES_MAX_NUM; i++) {
916 		int is_4700_line;
917 
918 		node = chassis->linenode[i];
919 
920 		if (!(node && is_line(node)))
921 			continue;	/* empty slot or router */
922 
923 		is_4700_line = is_line_4700(node);
924 
925 		for (p = 1; p <= node->numports; p++) {
926 
927 			port = node->ports[p];
928 			if (!port || !port->remoteport)
929 				continue;
930 
931 			if ((is_4700_line && (port->portnum > 18)) ||
932 			    (!is_4700_line && (port->portnum > 12)))
933 				continue;
934 
935 			remnode = port->remoteport->node;
936 
937 			if (!remnode->ch_found)
938 				continue;	/* some error - spine not initialized ? FIXME */
939 			if (insert_spine(remnode, chassis))
940 				return -1;
941 		}
942 	}
943 	return 0;
944 }
945 
946 static int pass_on_spines_catch_lines(ibnd_chassis_t * chassis)
947 {
948 	ibnd_node_t *node, *remnode;
949 	ibnd_port_t *port;
950 	int i, p;
951 
952 	for (i = 1; i <= SPINES_MAX_NUM; i++) {
953 		int is_4700x2;
954 
955 		node = chassis->spinenode[i];
956 		if (!node)
957 			continue;	/* empty slot */
958 
959 		is_4700x2 = is_spine_4700x2(node);
960 
961 		for (p = 1; p <= node->numports; p++) {
962 			port = node->ports[p];
963 			if (!port || !port->remoteport)
964 				continue;
965 
966 			/*
967 			 * ISR4700 double density fabric board ports 19-36 are
968 			 * chassis external ports, so skip them
969 			 */
970 			if (is_4700x2 && (port->portnum > 18))
971 				continue;
972 
973 			remnode = port->remoteport->node;
974 
975 			if (!remnode->ch_found)
976 				continue;	/* some error - line/router not initialized ? FIXME */
977 
978 			if (insert_line_router(remnode, chassis))
979 				return -1;
980 		}
981 	}
982 	return 0;
983 }
984 
985 /*
986 	Stupid interpolation algorithm...
987 	But nothing to do - have to be compliant with VoltaireSM/NMS
988 */
989 static void pass_on_spines_interpolate_chguid(ibnd_chassis_t * chassis)
990 {
991 	ibnd_node_t *node;
992 	int i;
993 
994 	for (i = 1; i <= SPINES_MAX_NUM; i++) {
995 		node = chassis->spinenode[i];
996 		if (!node)
997 			continue;	/* skip the empty slots */
998 
999 		/* take first guid minus one to be consistent with SM */
1000 		chassis->chassisguid = node->guid - 1;
1001 		break;
1002 	}
1003 }
1004 
1005 /*
1006 	This function fills chassis structure with all nodes
1007 	in that chassis
1008 	chassis structure = structure of one standalone chassis
1009 */
1010 static int build_chassis(ibnd_node_t * node, ibnd_chassis_t * chassis)
1011 {
1012 	int p = 0;
1013 	ibnd_node_t *remnode = 0;
1014 	ibnd_port_t *port = 0;
1015 
1016 	/* we get here with node = chassis_spine */
1017 	if (insert_spine(node, chassis))
1018 		return -1;
1019 
1020 	/* loop: pass on all ports of node */
1021 	for (p = 1; p <= node->numports; p++) {
1022 
1023 		port = node->ports[p];
1024 		if (!port || !port->remoteport)
1025 			continue;
1026 
1027 		/*
1028 		 * ISR4700 double density fabric board ports 19-36 are
1029 		 * chassis external ports, so skip them
1030 		 */
1031 		if (is_spine_4700x2(node) && (port->portnum > 18))
1032 			continue;
1033 
1034 		remnode = port->remoteport->node;
1035 
1036 		if (!remnode->ch_found)
1037 			continue;	/* some error - line or router not initialized ? FIXME */
1038 
1039 		insert_line_router(remnode, chassis);
1040 	}
1041 
1042 	if (pass_on_lines_catch_spines(chassis))
1043 		return -1;
1044 	/* this pass needed for to catch routers, since routers connected only */
1045 	/* to spines in slot 1 or 4 and we could miss them first time */
1046 	if (pass_on_spines_catch_lines(chassis))
1047 		return -1;
1048 
1049 	/* additional 2 passes needed for to overcome a problem of pure "in-chassis" */
1050 	/* connectivity - extra pass to ensure that all related chips/modules */
1051 	/* inserted into the chassis */
1052 	if (pass_on_lines_catch_spines(chassis))
1053 		return -1;
1054 	if (pass_on_spines_catch_lines(chassis))
1055 		return -1;
1056 	pass_on_spines_interpolate_chguid(chassis);
1057 
1058 	return 0;
1059 }
1060 
1061 /*========================================================*/
1062 /*                INTERNAL TO EXTERNAL PORT MAPPING       */
1063 /*========================================================*/
1064 
1065 /*
1066 Description : On ISR9288/9096 external ports indexing
1067               is not matching the internal ( anafa ) port
1068               indexes. Use this MAP to translate the data you get from
1069               the OpenIB diagnostics (smpquery, ibroute, ibtracert, etc.)
1070 
1071 Module : sLB-24
1072                 anafa 1             anafa 2
1073 ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24
1074 int port | 22 23 24 18 17 16 | 22 23 24 18 17 16
1075 ext port | 1  2  3  4  5  6  | 7  8  9  10 11 12
1076 int port | 19 20 21 15 14 13 | 19 20 21 15 14 13
1077 ------------------------------------------------
1078 
1079 Module : sLB-8
1080                 anafa 1             anafa 2
1081 ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24
1082 int port | 24 23 22 18 17 16 | 24 23 22 18 17 16
1083 ext port | 1  2  3  4  5  6  | 7  8  9  10 11 12
1084 int port | 21 20 19 15 14 13 | 21 20 19 15 14 13
1085 
1086 ----------->
1087                 anafa 1             anafa 2
1088 ext port | -  -  5  -  -  6  | -  -  7  -  -  8
1089 int port | 24 23 22 18 17 16 | 24 23 22 18 17 16
1090 ext port | -  -  1  -  -  2  | -  -  3  -  -  4
1091 int port | 21 20 19 15 14 13 | 21 20 19 15 14 13
1092 ------------------------------------------------
1093 
1094 Module : sLB-2024
1095 
1096 ext port | 13 14 15 16 17 18 19 20 21 22 23 24
1097 A1 int port| 13 14 15 16 17 18 19 20 21 22 23 24
1098 ext port | 1 2 3 4 5 6 7 8 9 10 11 12
1099 A2 int port| 13 14 15 16 17 18 19 20 21 22 23 24
1100 ---------------------------------------------------
1101 
1102 Module : sLB-4018
1103 
1104 int port | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
1105 ext port |  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18
1106 ---------------------------------------------------
1107 
1108 Module : sFB-4700X2
1109 
1110   12X port -> 3 x 4X ports:
1111 
1112 A1 int port | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
1113    ext port |  7  7  7  8  8  8  9  9  9 10 10 10 11 11 11 12 12 12
1114 A2 int port | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
1115    ext port |  1  1  1  2  2  2  3  3  3  4  4  4  5  5  5  6  6  6
1116 
1117 */
1118 
1119 int int2ext_map_slb24[2][25] = {
1120 	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 5, 4, 18, 17, 16, 1, 2, 3,
1121 	 13, 14, 15},
1122 	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 11, 10, 24, 23, 22, 7, 8, 9,
1123 	 19, 20, 21}
1124 };
1125 
1126 int int2ext_map_slb8[2][25] = {
1127 	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 6, 6, 6, 1, 1, 1, 5, 5,
1128 	 5},
1129 	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 8, 8, 8, 3, 3, 3, 7, 7,
1130 	 7}
1131 };
1132 
1133 int int2ext_map_slb2024[2][25] = {
1134 	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20,
1135 	 21, 22, 23, 24},
1136 	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1137 	 11, 12}
1138 };
1139 
1140 int int2ext_map_slb4018[37] = {
1141 	0,
1142 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1143 	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18
1144 };
1145 
1146 int int2ext_map_sfb4700x2[2][37] = {
1147 	{0,
1148 	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1149 	 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12},
1150 	{0,
1151 	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1152 	 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6}
1153 };
1154 
1155 /*	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 }; */
1156 
1157 /* map internal ports to external ports if appropriate */
1158 static void voltaire_portmap(ibnd_port_t * port)
1159 {
1160 	int portnum = port->portnum;
1161 	int chipnum = 0;
1162 	ibnd_node_t *node = port->node;
1163 	int is_4700_line = is_line_4700(node);
1164 	int is_4700x2_spine = is_spine_4700x2(node);
1165 
1166 	if (!node->ch_found || (!is_line(node) && !is_4700x2_spine)) {
1167 		port->ext_portnum = 0;
1168 		return;
1169 	}
1170 
1171 	if (((is_4700_line || is_4700x2_spine) &&
1172 	     (portnum < 19 || portnum > 36)) ||
1173 	    ((!is_4700_line && !is_4700x2_spine) &&
1174 	     (portnum < 13 || portnum > 24))) {
1175 			port->ext_portnum = 0;
1176 		return;
1177 	}
1178 
1179 	if (port->node->ch_anafanum < 1 || port->node->ch_anafanum > 2) {
1180 		port->ext_portnum = 0;
1181 		return;
1182 	}
1183 
1184 	chipnum = port->node->ch_anafanum - 1;
1185 
1186 	if (is_line_24(node))
1187 		port->ext_portnum = int2ext_map_slb24[chipnum][portnum];
1188 	else if (is_line_2024(node))
1189 		port->ext_portnum = int2ext_map_slb2024[chipnum][portnum];
1190 	/* sLB-4018: Only one asic per LB */
1191 	else if (is_4700_line)
1192 		port->ext_portnum = int2ext_map_slb4018[portnum];
1193 	/* sFB-4700X2 4X port */
1194 	else if (is_4700x2_spine)
1195 		port->ext_portnum = int2ext_map_sfb4700x2[chipnum][portnum];
1196 	else
1197 		port->ext_portnum = int2ext_map_slb8[chipnum][portnum];
1198 }
1199 
1200 static int add_chassis(chassis_scan_t * chassis_scan)
1201 {
1202 	if (!(chassis_scan->current_chassis =
1203 	      calloc(1, sizeof(ibnd_chassis_t)))) {
1204 		IBND_ERROR("OOM: failed to allocate chassis object\n");
1205 		return -1;
1206 	}
1207 
1208 	if (chassis_scan->first_chassis == NULL) {
1209 		chassis_scan->first_chassis = chassis_scan->current_chassis;
1210 		chassis_scan->last_chassis = chassis_scan->current_chassis;
1211 	} else {
1212 		chassis_scan->last_chassis->next =
1213 		    chassis_scan->current_chassis;
1214 		chassis_scan->last_chassis = chassis_scan->current_chassis;
1215 	}
1216 	return 0;
1217 }
1218 
1219 static void add_node_to_chassis(ibnd_chassis_t * chassis, ibnd_node_t * node)
1220 {
1221 	node->chassis = chassis;
1222 	node->next_chassis_node = chassis->nodes;
1223 	chassis->nodes = node;
1224 }
1225 
1226 /*
1227 	Main grouping function
1228 	Algorithm:
1229 	1. pass on every Voltaire node
1230 	2. catch spine chip for every Voltaire node
1231 		2.1 build/interpolate chassis around this chip
1232 		2.2 go to 1.
1233 	3. pass on non Voltaire nodes (SystemImageGUID based grouping)
1234 	4. now group non Voltaire nodes by SystemImageGUID
1235 	Returns:
1236 	0 on success, -1 on failure
1237 */
1238 int group_nodes(ibnd_fabric_t * fabric)
1239 {
1240 	ibnd_node_t *node;
1241 	int chassisnum = 0;
1242 	ibnd_chassis_t *chassis;
1243 	ibnd_chassis_t *ch, *ch_next;
1244 	chassis_scan_t chassis_scan;
1245 	int vendor_id;
1246 
1247 	chassis_scan.first_chassis = NULL;
1248 	chassis_scan.current_chassis = NULL;
1249 	chassis_scan.last_chassis = NULL;
1250 
1251 	/* first pass on switches and build for every Voltaire node */
1252 	/* an appropriate chassis record (slotnum and position) */
1253 	/* according to internal connectivity */
1254 	/* not very efficient but clear code so... */
1255 	for (node = fabric->switches; node; node = node->type_next) {
1256 
1257 		vendor_id = mad_get_field(node->info, 0,IB_NODE_VENDORID_F);
1258 
1259 		if (vendor_id == VTR_VENDOR_ID
1260 		    && fill_voltaire_chassis_record(node))
1261 			goto cleanup;
1262 		else if (vendor_id == MLX_VENDOR_ID
1263 			&& fill_mellanox_chassis_record(node))
1264 			goto cleanup;
1265 
1266 	}
1267 
1268 	/* separate every Voltaire chassis from each other and build linked list of them */
1269 	/* algorithm: catch spine and find all surrounding nodes */
1270 	for (node = fabric->switches; node; node = node->type_next) {
1271 		if (mad_get_field(node->info, 0,
1272 				  IB_NODE_VENDORID_F) != VTR_VENDOR_ID)
1273 			continue;
1274 		if (!node->ch_found
1275 		    || (node->chassis && node->chassis->chassisnum)
1276 		    || !is_spine(node))
1277 			continue;
1278 		if (add_chassis(&chassis_scan))
1279 			goto cleanup;
1280 		chassis_scan.current_chassis->chassisnum = ++chassisnum;
1281 		if (build_chassis(node, chassis_scan.current_chassis))
1282 			goto cleanup;
1283 	}
1284 
1285 	/* now make pass on nodes for chassis which are not Voltaire */
1286 	/* grouped by common SystemImageGUID */
1287 	for (node = fabric->nodes; node; node = node->next) {
1288 		if (mad_get_field(node->info, 0,
1289 				  IB_NODE_VENDORID_F) == VTR_VENDOR_ID)
1290 			continue;
1291 		if (mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F)) {
1292 			chassis = find_chassisguid(fabric, node);
1293 			if (chassis)
1294 				chassis->nodecount++;
1295 			else {
1296 				/* Possible new chassis */
1297 				if (add_chassis(&chassis_scan))
1298 					goto cleanup;
1299 				chassis_scan.current_chassis->chassisguid =
1300 				    get_chassisguid(node);
1301 				chassis_scan.current_chassis->nodecount = 1;
1302 				if (!fabric->chassis)
1303 					fabric->chassis = chassis_scan.first_chassis;
1304 			}
1305 		}
1306 	}
1307 
1308 	/* now, make another pass to see which nodes are part of chassis */
1309 	/* (defined as chassis->nodecount > 1) */
1310 	for (node = fabric->nodes; node; node = node->next) {
1311 
1312 		vendor_id = mad_get_field(node->info, 0,IB_NODE_VENDORID_F);
1313 
1314 		if (vendor_id == VTR_VENDOR_ID)
1315 			continue;
1316 		if (mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F)) {
1317 			chassis = find_chassisguid(fabric, node);
1318 			if (chassis && chassis->nodecount > 1) {
1319 				if (!chassis->chassisnum)
1320 					chassis->chassisnum = ++chassisnum;
1321 				if (!node->ch_found) {
1322 					node->ch_found = 1;
1323 					add_node_to_chassis(chassis, node);
1324 				}
1325 				else if (vendor_id == MLX_VENDOR_ID){
1326 					insert_mellanox_line_and_spine(node, chassis);
1327 				}
1328 			}
1329 		}
1330 	}
1331 
1332 	fabric->chassis = chassis_scan.first_chassis;
1333 	return 0;
1334 
1335 cleanup:
1336 	ch = chassis_scan.first_chassis;
1337 	while (ch) {
1338 		ch_next = ch->next;
1339 		free(ch);
1340 		ch = ch_next;
1341 	}
1342 	fabric->chassis = NULL;
1343 	return -1;
1344 }
1345