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.
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:
13 * Redistribution and use in source and binary forms, with or
14 * without modification, are permitted provided that the following
17 * - Redistributions of source code must retain the above
18 * copyright notice, this list of conditions and the following
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.
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
37 /*========================================================*/
38 /* FABRIC SCANNER SPECIFIC DATA */
39 /*========================================================*/
43 #endif /* HAVE_CONFIG_H */
48 #include <infiniband/mad.h>
53 static char *ChassisTypeStr[] =
54 { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004", "ISR4700", "ISR4200" };
55 static char *ChassisSlotTypeStr[] = { "", "Line", "Spine", "SRBD" };
57 typedef struct chassis_scan {
58 ibnd_chassis_t *first_chassis;
59 ibnd_chassis_t *current_chassis;
60 ibnd_chassis_t *last_chassis;
63 char *ibnd_get_chassis_type(ibnd_node_t * node)
68 IBND_DEBUG("node parameter NULL\n");
75 chassis_type = mad_get_field(node->info, 0, IB_NODE_VENDORID_F);
79 case VTR_VENDOR_ID: /* Voltaire chassis */
81 if (node->ch_type == UNRESOLVED_CT || node->ch_type > ISR4200_CT)
83 return ChassisTypeStr[node->ch_type];
87 if (node->ch_type_str[0] == '\0')
89 return node->ch_type_str;
99 char *ibnd_get_chassis_slot_str(ibnd_node_t * node, char *str, size_t size)
104 IBND_DEBUG("node parameter NULL\n");
108 /* Currently, only if Voltaire or Mellanox chassis */
109 vendor_id = mad_get_field(node->info, 0,IB_NODE_VENDORID_F);
111 if ((vendor_id != VTR_VENDOR_ID) && (vendor_id != MLX_VENDOR_ID))
115 if (node->ch_slot == UNRESOLVED_CS || node->ch_slot > SRBD_CS)
119 snprintf(str, size, "%s %d Chip %d", ChassisSlotTypeStr[node->ch_slot],
120 node->ch_slotnum, node->ch_anafanum);
124 static ibnd_chassis_t *find_chassisnum(ibnd_fabric_t * fabric,
125 unsigned char chassisnum)
127 ibnd_chassis_t *current;
129 for (current = fabric->chassis; current; current = current->next)
130 if (current->chassisnum == chassisnum)
136 static uint64_t topspin_chassisguid(uint64_t guid)
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;
143 int ibnd_is_xsigo_guid(uint64_t guid)
145 if ((guid & 0xffffff0000000000ULL) == 0x0013970000000000ULL)
151 static int is_xsigo_leafone(uint64_t guid)
153 if ((guid & 0xffffffffff000000ULL) == 0x0013970102000000ULL)
159 int ibnd_is_xsigo_hca(uint64_t guid)
161 /* NodeType 2 is HCA */
162 if ((guid & 0xffffffff00000000ULL) == 0x0013970200000000ULL)
168 int ibnd_is_xsigo_tca(uint64_t guid)
170 /* NodeType 3 is TCA */
171 if ((guid & 0xffffffff00000000ULL) == 0x0013970300000000ULL)
177 static int is_xsigo_ca(uint64_t guid)
179 if (ibnd_is_xsigo_hca(guid) || ibnd_is_xsigo_tca(guid))
185 static int is_xsigo_switch(uint64_t guid)
187 if ((guid & 0xffffffff00000000ULL) == 0x0013970100000000ULL)
193 static uint64_t xsigo_chassisguid(ibnd_node_t * node)
195 uint64_t sysimgguid =
196 mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F);
197 uint64_t remote_sysimgguid;
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;
207 if (!node->ports || !node->ports[1])
210 /* Is there a peer port ? */
211 if (!node->ports[1]->remoteport)
214 /* If peer port is Leaf 1, use its chassis GUID */
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;
225 static uint64_t get_chassisguid(ibnd_node_t * node)
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);
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);
239 static ibnd_chassis_t *find_chassisguid(ibnd_fabric_t * fabric,
242 ibnd_chassis_t *current;
245 chguid = get_chassisguid(node);
246 for (current = fabric->chassis; current; current = current->next)
247 if (current->chassisguid == chguid)
253 uint64_t ibnd_get_chassis_guid(ibnd_fabric_t * fabric, unsigned char chassisnum)
255 ibnd_chassis_t *chassis;
258 IBND_DEBUG("fabric parameter NULL\n");
262 chassis = find_chassisnum(fabric, chassisnum);
264 return chassis->chassisguid;
269 static int is_router(ibnd_node_t * n)
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);
276 static int is_spine_9096(ibnd_node_t * n)
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);
282 static int is_spine_9288(ibnd_node_t * n)
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);
288 static int is_spine_2004(ibnd_node_t * n)
290 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
291 return (devid == VTR_DEVID_SFB2004);
294 static int is_spine_2012(ibnd_node_t * n)
296 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
297 return (devid == VTR_DEVID_SFB2012);
300 static int is_spine_4700(ibnd_node_t * n)
302 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
303 return (devid == VTR_DEVID_SFB4700);
306 static int is_spine_4700x2(ibnd_node_t * n)
308 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
309 return (devid == VTR_DEVID_SFB4700X2);
312 static int is_spine_4200(ibnd_node_t * n)
314 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
315 return (devid == VTR_DEVID_SFB4200);
318 static int is_spine(ibnd_node_t * n)
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) ||
326 static int is_line_24(ibnd_node_t * n)
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);
333 static int is_line_8(ibnd_node_t * n)
335 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
336 return (devid == VTR_DEVID_SLB8);
339 static int is_line_2024(ibnd_node_t * n)
341 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
342 return (devid == VTR_DEVID_SLB2024);
345 static int is_line_4700(ibnd_node_t * n)
347 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
348 return (devid == VTR_DEVID_SLB4018);
351 static int is_line(ibnd_node_t * n)
353 return (is_line_24(n) || is_line_8(n) ||
354 is_line_2024(n) || is_line_4700(n));
357 int is_chassis_switch(ibnd_node_t * n)
359 return (is_spine(n) || is_line(n));
362 /* these structs help find Line (Anafa) slot number while using spine portnum */
363 char line_slot_2_sfb4[37] = {
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
368 char anafa_line_slot_2_sfb4[37] = {
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
374 char line_slot_2_sfb12[37] = {
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
379 char anafa_line_slot_2_sfb12[37] = {
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
385 /* LB slot = table[spine port] */
386 char line_slot_2_sfb18[37] = {
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] = {
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
397 /* LB slot = table[spine port] */
398 char line_slot_2_sfb18x2[37] = {
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] = {
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
409 /* LB slot = table[spine port] */
410 char line_slot_2_sfb4200[37] = {
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] = {
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
421 /* IPR FCR modules connectivity while using sFB4 port as reference */
422 char ipr_slot_2_sfb4_port[37] = {
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
428 /* these structs help find Spine (Anafa) slot number while using spine portnum */
429 char spine12_slot_2_slb[37] = {
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
434 char anafa_spine12_slot_2_slb[37] = {
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
440 char spine4_slot_2_slb[37] = {
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
445 char anafa_spine4_slot_2_slb[37] = {
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
451 /* FB slot = table[line port] */
452 char spine18_slot_2_slb[37] = {
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
457 /* FB asic = table[line port] */
458 char anafa_spine18_slot_2_slb[37] = {
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
463 char anafa_spine18x2_slot_2_slb[37] = {
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
469 /* FB slot = table[line port] */
470 char sfb4200_slot_2_slb[37] = {
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
475 /* FB asic = table[line port] */
476 char anafa_sfb4200_slot_2_slb[37] = {
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
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 }; */
484 static int get_sfb_slot(ibnd_node_t * n, ibnd_port_t * lineport)
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];
516 IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n",
522 static int get_router_slot(ibnd_node_t * n, ibnd_port_t * spineport)
524 uint64_t guessnum = 0;
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];
556 IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n",
557 spineport->node->guid);
562 static int get_slb_slot(ibnd_node_t * n, ibnd_port_t * spineport)
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];
594 IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n",
595 spineport->node->guid);
602 This function called for every Mellanox node in fabric
604 static int fill_mellanox_chassis_record(ibnd_node_t * node)
609 char node_desc[IB_SMP_DATA_SIZE];
612 char *system_slot_name;
618 The node description has the following format:
620 'MF0;<system name>:<system type>/<system slot name>[:board type]/U<node index>'
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.
628 memcpy(node_desc, node->nodedesc, IB_SMP_DATA_SIZE);
630 IBND_DEBUG("fill_mellanox_chassis_record: node_desc:%s \n",node_desc);
632 if (node->ch_found) /* somehow this node has already been passed */
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)
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);
648 /* parse system name*/
649 system_name = &node_desc[4];
650 for (iter = system_name ; (*iter != ':') && (*iter != '\0') ; iter++);
652 IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get system_name failed) \n",node_desc);
657 /* parse system type*/
659 for ( ; (*iter != '/') && (*iter != '\0') ; iter++);
661 IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get system_type failed) \n",node_desc);
666 /* parse system slot name*/
667 system_slot_name = iter;
668 for ( ; (*iter != '/') && (*iter != ':') && (*iter != '\0') ; iter++);
670 IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get system_slot_name failed) \n",node_desc);
676 for ( ; (*iter != '/') && (*iter != '\0') ; iter++);
678 IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get board type failed) \n",node_desc);
685 if(node_index[0] != 'U'){
686 IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get node index) \n",node_desc);
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);
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;
703 IBND_DEBUG("fill_mellanox_chassis_record: Unsupported system_slot_name:%s \n",system_slot_name);
707 /* The switch will be displayed under Line or Spine and not under Chassis switches */
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;
719 strncpy(node->ch_type_str , system_type, sizeof(node->ch_type_str)-1);
721 /* Line ports 1-18 are mapped to external ports 1-18*/
722 if(node->ch_slot == LINE_CS)
724 for (p = 1; p <= node->numports && p <= 18 ; p++) {
725 port = node->ports[p];
728 port->ext_portnum = p;
735 static int insert_mellanox_line_and_spine(ibnd_node_t * node, ibnd_chassis_t * chassis)
737 if (node->ch_slot == LINE_CS){
739 if (chassis->linenode[node->ch_slotnum])
740 return 0; /* already filled slot */
742 chassis->linenode[node->ch_slotnum] = node;
744 else if (node->ch_slot == SPINE_CS){
746 if (chassis->spinenode[node->ch_slotnum])
747 return 0; /* already filled slot */
749 chassis->spinenode[node->ch_slotnum] = node;
754 node->chassis = chassis;
760 /* forward declare this */
761 static void voltaire_portmap(ibnd_port_t * port);
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
767 static int fill_voltaire_chassis_record(ibnd_node_t * node)
771 ibnd_node_t *remnode = 0;
773 if (node->ch_found) /* somehow this node has already been passed */
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... */
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);
787 else if (is_spine(node)) {
788 int is_4700x2 = is_spine_4700x2(node);
790 for (p = 1; p <= node->numports; p++) {
791 port = node->ports[p];
792 if (!port || !port->remoteport)
796 * Skip ISR4700 double density fabric boards ports 19-36
797 * as they are chassis external ports
799 if (is_4700x2 && (port->portnum > 18))
802 remnode = port->remoteport->node;
803 if (remnode->type != IB_NODE_SWITCH) {
804 if (!remnode->ch_found)
805 get_router_slot(remnode, port);
809 /* we assume here that remoteport belongs to line */
810 get_sfb_slot(node, port->remoteport);
812 /* we could break here, but need to find if more routers connected */
815 } else if (is_line(node)) {
816 int is_4700_line = is_line_4700(node);
818 for (p = 1; p <= node->numports; p++) {
819 port = node->ports[p];
820 if (!port || !port->remoteport)
823 if ((is_4700_line && (port->portnum > 18)) ||
824 (!is_4700_line && (port->portnum > 12)))
827 /* we assume here that remoteport belongs to spine */
828 get_slb_slot(node, port->remoteport);
833 /* for each port of this node, map external ports */
834 for (p = 1; p <= node->numports; p++) {
835 port = node->ports[p];
838 voltaire_portmap(port);
844 static int get_line_index(ibnd_node_t * node)
848 if (is_line_4700(node))
849 retval = node->ch_slotnum;
851 retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum;
853 if (retval > LINES_MAX_NUM || retval < 1) {
854 printf("%s: retval = %d\n", __FUNCTION__, retval);
855 IBND_ERROR("Internal error\n");
861 static int get_spine_index(ibnd_node_t * node)
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;
870 retval = node->ch_slotnum;
872 if (retval > SPINES_MAX_NUM || retval < 1) {
873 IBND_ERROR("Internal error\n");
879 static int insert_line_router(ibnd_node_t * node, ibnd_chassis_t * chassis)
881 int i = get_line_index(node);
886 if (chassis->linenode[i])
887 return 0; /* already filled slot */
889 chassis->linenode[i] = node;
890 node->chassis = chassis;
894 static int insert_spine(ibnd_node_t * node, ibnd_chassis_t * chassis)
896 int i = get_spine_index(node);
901 if (chassis->spinenode[i])
902 return 0; /* already filled slot */
904 chassis->spinenode[i] = node;
905 node->chassis = chassis;
909 static int pass_on_lines_catch_spines(ibnd_chassis_t * chassis)
911 ibnd_node_t *node, *remnode;
915 for (i = 1; i <= LINES_MAX_NUM; i++) {
918 node = chassis->linenode[i];
920 if (!(node && is_line(node)))
921 continue; /* empty slot or router */
923 is_4700_line = is_line_4700(node);
925 for (p = 1; p <= node->numports; p++) {
927 port = node->ports[p];
928 if (!port || !port->remoteport)
931 if ((is_4700_line && (port->portnum > 18)) ||
932 (!is_4700_line && (port->portnum > 12)))
935 remnode = port->remoteport->node;
937 if (!remnode->ch_found)
938 continue; /* some error - spine not initialized ? FIXME */
939 if (insert_spine(remnode, chassis))
946 static int pass_on_spines_catch_lines(ibnd_chassis_t * chassis)
948 ibnd_node_t *node, *remnode;
952 for (i = 1; i <= SPINES_MAX_NUM; i++) {
955 node = chassis->spinenode[i];
957 continue; /* empty slot */
959 is_4700x2 = is_spine_4700x2(node);
961 for (p = 1; p <= node->numports; p++) {
962 port = node->ports[p];
963 if (!port || !port->remoteport)
967 * ISR4700 double density fabric board ports 19-36 are
968 * chassis external ports, so skip them
970 if (is_4700x2 && (port->portnum > 18))
973 remnode = port->remoteport->node;
975 if (!remnode->ch_found)
976 continue; /* some error - line/router not initialized ? FIXME */
978 if (insert_line_router(remnode, chassis))
986 Stupid interpolation algorithm...
987 But nothing to do - have to be compliant with VoltaireSM/NMS
989 static void pass_on_spines_interpolate_chguid(ibnd_chassis_t * chassis)
994 for (i = 1; i <= SPINES_MAX_NUM; i++) {
995 node = chassis->spinenode[i];
997 continue; /* skip the empty slots */
999 /* take first guid minus one to be consistent with SM */
1000 chassis->chassisguid = node->guid - 1;
1006 This function fills chassis structure with all nodes
1008 chassis structure = structure of one standalone chassis
1010 static int build_chassis(ibnd_node_t * node, ibnd_chassis_t * chassis)
1013 ibnd_node_t *remnode = 0;
1014 ibnd_port_t *port = 0;
1016 /* we get here with node = chassis_spine */
1017 if (insert_spine(node, chassis))
1020 /* loop: pass on all ports of node */
1021 for (p = 1; p <= node->numports; p++) {
1023 port = node->ports[p];
1024 if (!port || !port->remoteport)
1028 * ISR4700 double density fabric board ports 19-36 are
1029 * chassis external ports, so skip them
1031 if (is_spine_4700x2(node) && (port->portnum > 18))
1034 remnode = port->remoteport->node;
1036 if (!remnode->ch_found)
1037 continue; /* some error - line or router not initialized ? FIXME */
1039 insert_line_router(remnode, chassis);
1042 if (pass_on_lines_catch_spines(chassis))
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))
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))
1054 if (pass_on_spines_catch_lines(chassis))
1056 pass_on_spines_interpolate_chguid(chassis);
1061 /*========================================================*/
1062 /* INTERNAL TO EXTERNAL PORT MAPPING */
1063 /*========================================================*/
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.)
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 ------------------------------------------------
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
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 ------------------------------------------------
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 ---------------------------------------------------
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 ---------------------------------------------------
1110 12X port -> 3 x 4X ports:
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
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,
1122 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 11, 10, 24, 23, 22, 7, 8, 9,
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,
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,
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,
1136 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1140 int int2ext_map_slb4018[37] = {
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
1146 int int2ext_map_sfb4700x2[2][37] = {
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},
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}
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 }; */
1157 /* map internal ports to external ports if appropriate */
1158 static void voltaire_portmap(ibnd_port_t * port)
1160 int portnum = port->portnum;
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);
1166 if (!node->ch_found || (!is_line(node) && !is_4700x2_spine)) {
1167 port->ext_portnum = 0;
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;
1179 if (port->node->ch_anafanum < 1 || port->node->ch_anafanum > 2) {
1180 port->ext_portnum = 0;
1184 chipnum = port->node->ch_anafanum - 1;
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];
1197 port->ext_portnum = int2ext_map_slb8[chipnum][portnum];
1200 static int add_chassis(chassis_scan_t * chassis_scan)
1202 if (!(chassis_scan->current_chassis =
1203 calloc(1, sizeof(ibnd_chassis_t)))) {
1204 IBND_ERROR("OOM: failed to allocate chassis object\n");
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;
1212 chassis_scan->last_chassis->next =
1213 chassis_scan->current_chassis;
1214 chassis_scan->last_chassis = chassis_scan->current_chassis;
1219 static void add_node_to_chassis(ibnd_chassis_t * chassis, ibnd_node_t * node)
1221 node->chassis = chassis;
1222 node->next_chassis_node = chassis->nodes;
1223 chassis->nodes = node;
1227 Main grouping function
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
1233 3. pass on non Voltaire nodes (SystemImageGUID based grouping)
1234 4. now group non Voltaire nodes by SystemImageGUID
1236 0 on success, -1 on failure
1238 int group_nodes(ibnd_fabric_t * fabric)
1242 ibnd_chassis_t *chassis;
1243 ibnd_chassis_t *ch, *ch_next;
1244 chassis_scan_t chassis_scan;
1247 chassis_scan.first_chassis = NULL;
1248 chassis_scan.current_chassis = NULL;
1249 chassis_scan.last_chassis = NULL;
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) {
1257 vendor_id = mad_get_field(node->info, 0,IB_NODE_VENDORID_F);
1259 if (vendor_id == VTR_VENDOR_ID
1260 && fill_voltaire_chassis_record(node))
1262 else if (vendor_id == MLX_VENDOR_ID
1263 && fill_mellanox_chassis_record(node))
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)
1275 || (node->chassis && node->chassis->chassisnum)
1278 if (add_chassis(&chassis_scan))
1280 chassis_scan.current_chassis->chassisnum = ++chassisnum;
1281 if (build_chassis(node, chassis_scan.current_chassis))
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)
1291 if (mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F)) {
1292 chassis = find_chassisguid(fabric, node);
1294 chassis->nodecount++;
1296 /* Possible new chassis */
1297 if (add_chassis(&chassis_scan))
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;
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) {
1312 vendor_id = mad_get_field(node->info, 0,IB_NODE_VENDORID_F);
1314 if (vendor_id == VTR_VENDOR_ID)
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) {
1323 add_node_to_chassis(chassis, node);
1325 else if (vendor_id == MLX_VENDOR_ID){
1326 insert_mellanox_line_and_spine(node, chassis);
1332 fabric->chassis = chassis_scan.first_chassis;
1336 ch = chassis_scan.first_chassis;
1342 fabric->chassis = NULL;