]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/libibnetdisc/chassis.c
Document r349620, tzdata 2019b.
[FreeBSD/FreeBSD.git] / contrib / ofed / libibnetdisc / chassis.c
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 }