2 * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved.
3 * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved.
5 * This software is available to you under a choice of one of two
6 * licenses. You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * OpenIB.org BSD license below:
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
15 * - Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
19 * - Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials
22 * provided with the distribution.
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35 /*========================================================*/
36 /* FABRIC SCANNER SPECIFIC DATA */
37 /*========================================================*/
41 #endif /* HAVE_CONFIG_H */
47 #include <infiniband/common.h>
48 #include <infiniband/mad.h>
50 #include "ibnetdiscover.h"
53 #define OUT_BUFFER_SIZE 16
56 extern Node *nodesdist[MAXHOPS+1]; /* last is CA list */
59 extern int maxhops_discovered;
61 AllChassisList mylist;
63 char *ChassisTypeStr[5] = { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004" };
64 char *ChassisSlotStr[4] = { "", "Line", "Spine", "SRBD" };
67 char *get_chassis_type(unsigned char chassistype)
69 if (chassistype == UNRESOLVED_CT || chassistype > ISR2004_CT)
71 return ChassisTypeStr[chassistype];
74 char *get_chassis_slot(unsigned char chassisslot)
76 if (chassisslot == UNRESOLVED_CS || chassisslot > SRBD_CS)
78 return ChassisSlotStr[chassisslot];
81 static struct ChassisList *find_chassisnum(unsigned char chassisnum)
85 for (current = mylist.first; current; current = current->next) {
86 if (current->chassisnum == chassisnum)
93 static uint64_t topspin_chassisguid(uint64_t guid)
95 /* Byte 3 in system image GUID is chassis type, and */
96 /* Byte 4 is location ID (slot) so just mask off byte 4 */
97 return guid & 0xffffffff00ffffffULL;
100 int is_xsigo_guid(uint64_t guid)
102 if ((guid & 0xffffff0000000000ULL) == 0x0013970000000000ULL)
108 static int is_xsigo_leafone(uint64_t guid)
110 if ((guid & 0xffffffffff000000ULL) == 0x0013970102000000ULL)
116 int is_xsigo_hca(uint64_t guid)
118 /* NodeType 2 is HCA */
119 if ((guid & 0xffffffff00000000ULL) == 0x0013970200000000ULL)
125 int is_xsigo_tca(uint64_t guid)
127 /* NodeType 3 is TCA */
128 if ((guid & 0xffffffff00000000ULL) == 0x0013970300000000ULL)
134 static int is_xsigo_ca(uint64_t guid)
136 if (is_xsigo_hca(guid) || is_xsigo_tca(guid))
142 static int is_xsigo_switch(uint64_t guid)
144 if ((guid & 0xffffffff00000000ULL) == 0x0013970100000000ULL)
150 static uint64_t xsigo_chassisguid(Node *node)
152 if (!is_xsigo_ca(node->sysimgguid)) {
153 /* Byte 3 is NodeType and byte 4 is PortType */
154 /* If NodeType is 1 (switch), PortType is masked */
155 if (is_xsigo_switch(node->sysimgguid))
156 return node->sysimgguid & 0xffffffff00ffffffULL;
158 return node->sysimgguid;
160 /* Is there a peer port ? */
161 if (!node->ports->remoteport)
162 return node->sysimgguid;
164 /* If peer port is Leaf 1, use its chassis GUID */
165 if (is_xsigo_leafone(node->ports->remoteport->node->sysimgguid))
166 return node->ports->remoteport->node->sysimgguid &
167 0xffffffff00ffffffULL;
169 return node->sysimgguid;
173 static uint64_t get_chassisguid(Node *node)
175 if (node->vendid == TS_VENDOR_ID || node->vendid == SS_VENDOR_ID)
176 return topspin_chassisguid(node->sysimgguid);
177 else if (node->vendid == XS_VENDOR_ID || is_xsigo_guid(node->sysimgguid))
178 return xsigo_chassisguid(node);
180 return node->sysimgguid;
183 static struct ChassisList *find_chassisguid(Node *node)
185 ChassisList *current;
188 chguid = get_chassisguid(node);
189 for (current = mylist.first; current; current = current->next) {
190 if (current->chassisguid == chguid)
197 uint64_t get_chassis_guid(unsigned char chassisnum)
199 ChassisList *chassis;
201 chassis = find_chassisnum(chassisnum);
203 return chassis->chassisguid;
208 static int is_router(Node *node)
210 return (node->devid == VTR_DEVID_IB_FC_ROUTER ||
211 node->devid == VTR_DEVID_IB_IP_ROUTER);
214 static int is_spine_9096(Node *node)
216 return (node->devid == VTR_DEVID_SFB4 ||
217 node->devid == VTR_DEVID_SFB4_DDR);
220 static int is_spine_9288(Node *node)
222 return (node->devid == VTR_DEVID_SFB12 ||
223 node->devid == VTR_DEVID_SFB12_DDR);
226 static int is_spine_2004(Node *node)
228 return (node->devid == VTR_DEVID_SFB2004);
231 static int is_spine_2012(Node *node)
233 return (node->devid == VTR_DEVID_SFB2012);
236 static int is_spine(Node *node)
238 return (is_spine_9096(node) || is_spine_9288(node) ||
239 is_spine_2004(node) || is_spine_2012(node));
242 static int is_line_24(Node *node)
244 return (node->devid == VTR_DEVID_SLB24 ||
245 node->devid == VTR_DEVID_SLB24_DDR ||
246 node->devid == VTR_DEVID_SRB2004);
249 static int is_line_8(Node *node)
251 return (node->devid == VTR_DEVID_SLB8);
254 static int is_line_2024(Node *node)
256 return (node->devid == VTR_DEVID_SLB2024);
259 static int is_line(Node *node)
261 return (is_line_24(node) || is_line_8(node) || is_line_2024(node));
264 int is_chassis_switch(Node *node)
266 return (is_spine(node) || is_line(node));
269 /* these structs help find Line (Anafa) slot number while using spine portnum */
270 int line_slot_2_sfb4[25] = { 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4 };
271 int anafa_line_slot_2_sfb4[25] = { 0, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2 };
272 int line_slot_2_sfb12[25] = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10, 10, 11, 11, 12, 12 };
273 int anafa_line_slot_2_sfb12[25] = { 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 };
275 /* IPR FCR modules connectivity while using sFB4 port as reference */
276 int ipr_slot_2_sfb4_port[25] = { 0, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1 };
278 /* these structs help find Spine (Anafa) slot number while using spine portnum */
279 int spine12_slot_2_slb[25] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
280 int anafa_spine12_slot_2_slb[25]= { 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
281 int spine4_slot_2_slb[25] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
282 int anafa_spine4_slot_2_slb[25] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
283 /* 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 }; */
285 static void get_sfb_slot(Node *node, Port *lineport)
287 ChassisRecord *ch = node->chrecord;
289 ch->chassisslot = SPINE_CS;
290 if (is_spine_9096(node)) {
291 ch->chassistype = ISR9096_CT;
292 ch->slotnum = spine4_slot_2_slb[lineport->portnum];
293 ch->anafanum = anafa_spine4_slot_2_slb[lineport->portnum];
294 } else if (is_spine_9288(node)) {
295 ch->chassistype = ISR9288_CT;
296 ch->slotnum = spine12_slot_2_slb[lineport->portnum];
297 ch->anafanum = anafa_spine12_slot_2_slb[lineport->portnum];
298 } else if (is_spine_2012(node)) {
299 ch->chassistype = ISR2012_CT;
300 ch->slotnum = spine12_slot_2_slb[lineport->portnum];
301 ch->anafanum = anafa_spine12_slot_2_slb[lineport->portnum];
302 } else if (is_spine_2004(node)) {
303 ch->chassistype = ISR2004_CT;
304 ch->slotnum = spine4_slot_2_slb[lineport->portnum];
305 ch->anafanum = anafa_spine4_slot_2_slb[lineport->portnum];
307 IBPANIC("Unexpected node found: guid 0x%016" PRIx64, node->nodeguid);
311 static void get_router_slot(Node *node, Port *spineport)
313 ChassisRecord *ch = node->chrecord;
317 if (!(node->chrecord = calloc(1, sizeof(ChassisRecord))))
318 IBPANIC("out of mem");
322 ch->chassisslot = SRBD_CS;
323 if (is_spine_9096(spineport->node)) {
324 ch->chassistype = ISR9096_CT;
325 ch->slotnum = line_slot_2_sfb4[spineport->portnum];
326 ch->anafanum = ipr_slot_2_sfb4_port[spineport->portnum];
327 } else if (is_spine_9288(spineport->node)) {
328 ch->chassistype = ISR9288_CT;
329 ch->slotnum = line_slot_2_sfb12[spineport->portnum];
330 /* this is a smart guess based on nodeguids order on sFB-12 module */
331 guessnum = spineport->node->nodeguid % 4;
332 /* module 1 <--> remote anafa 3 */
333 /* module 2 <--> remote anafa 2 */
334 /* module 3 <--> remote anafa 1 */
335 ch->anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2));
336 } else if (is_spine_2012(spineport->node)) {
337 ch->chassistype = ISR2012_CT;
338 ch->slotnum = line_slot_2_sfb12[spineport->portnum];
339 /* this is a smart guess based on nodeguids order on sFB-12 module */
340 guessnum = spineport->node->nodeguid % 4;
341 // module 1 <--> remote anafa 3
342 // module 2 <--> remote anafa 2
343 // module 3 <--> remote anafa 1
344 ch->anafanum = (guessnum == 3? 1 : (guessnum == 1 ? 3 : 2));
345 } else if (is_spine_2004(spineport->node)) {
346 ch->chassistype = ISR2004_CT;
347 ch->slotnum = line_slot_2_sfb4[spineport->portnum];
348 ch->anafanum = ipr_slot_2_sfb4_port[spineport->portnum];
350 IBPANIC("Unexpected node found: guid 0x%016" PRIx64, spineport->node->nodeguid);
354 static void get_slb_slot(ChassisRecord *ch, Port *spineport)
356 ch->chassisslot = LINE_CS;
357 if (is_spine_9096(spineport->node)) {
358 ch->chassistype = ISR9096_CT;
359 ch->slotnum = line_slot_2_sfb4[spineport->portnum];
360 ch->anafanum = anafa_line_slot_2_sfb4[spineport->portnum];
361 } else if (is_spine_9288(spineport->node)) {
362 ch->chassistype = ISR9288_CT;
363 ch->slotnum = line_slot_2_sfb12[spineport->portnum];
364 ch->anafanum = anafa_line_slot_2_sfb12[spineport->portnum];
365 } else if (is_spine_2012(spineport->node)) {
366 ch->chassistype = ISR2012_CT;
367 ch->slotnum = line_slot_2_sfb12[spineport->portnum];
368 ch->anafanum = anafa_line_slot_2_sfb12[spineport->portnum];
369 } else if (is_spine_2004(spineport->node)) {
370 ch->chassistype = ISR2004_CT;
371 ch->slotnum = line_slot_2_sfb4[spineport->portnum];
372 ch->anafanum = anafa_line_slot_2_sfb4[spineport->portnum];
374 IBPANIC("Unexpected node found: guid 0x%016" PRIx64, spineport->node->nodeguid);
379 This function called for every Voltaire node in fabric
380 It could be optimized so, but time overhead is very small
381 and its only diag.util
383 static void fill_chassis_record(Node *node)
387 ChassisRecord *ch = 0;
389 if (node->chrecord) /* somehow this node has already been passed */
392 if (!(node->chrecord = calloc(1, sizeof(ChassisRecord))))
393 IBPANIC("out of mem");
397 /* node is router only in case of using unique lid */
398 /* (which is lid of chassis router port) */
399 /* in such case node->ports is actually a requested port... */
400 if (is_router(node) && is_spine(node->ports->remoteport->node))
401 get_router_slot(node, node->ports->remoteport);
402 else if (is_spine(node)) {
403 for (port = node->ports; port; port = port->next) {
404 if (!port->remoteport)
406 remnode = port->remoteport->node;
407 if (remnode->type != SWITCH_NODE) {
408 if (!remnode->chrecord)
409 get_router_slot(remnode, port);
412 if (!ch->chassistype)
413 /* we assume here that remoteport belongs to line */
414 get_sfb_slot(node, port->remoteport);
416 /* we could break here, but need to find if more routers connected */
419 } else if (is_line(node)) {
420 for (port = node->ports; port; port = port->next) {
421 if (port->portnum > 12)
423 if (!port->remoteport)
425 /* we assume here that remoteport belongs to spine */
426 get_slb_slot(ch, port->remoteport);
434 static int get_line_index(Node *node)
436 int retval = 3 * (node->chrecord->slotnum - 1) + node->chrecord->anafanum;
438 if (retval > LINES_MAX_NUM || retval < 1)
439 IBPANIC("Internal error");
443 static int get_spine_index(Node *node)
447 if (is_spine_9288(node) || is_spine_2012(node))
448 retval = 3 * (node->chrecord->slotnum - 1) + node->chrecord->anafanum;
450 retval = node->chrecord->slotnum;
452 if (retval > SPINES_MAX_NUM || retval < 1)
453 IBPANIC("Internal error");
457 static void insert_line_router(Node *node, ChassisList *chassislist)
459 int i = get_line_index(node);
461 if (chassislist->linenode[i])
462 return; /* already filled slot */
464 chassislist->linenode[i] = node;
465 node->chrecord->chassisnum = chassislist->chassisnum;
468 static void insert_spine(Node *node, ChassisList *chassislist)
470 int i = get_spine_index(node);
472 if (chassislist->spinenode[i])
473 return; /* already filled slot */
475 chassislist->spinenode[i] = node;
476 node->chrecord->chassisnum = chassislist->chassisnum;
479 static void pass_on_lines_catch_spines(ChassisList *chassislist)
481 Node *node, *remnode;
485 for (i = 1; i <= LINES_MAX_NUM; i++) {
486 node = chassislist->linenode[i];
488 if (!(node && is_line(node)))
489 continue; /* empty slot or router */
491 for (port = node->ports; port; port = port->next) {
492 if (port->portnum > 12)
495 if (!port->remoteport)
497 remnode = port->remoteport->node;
499 if (!remnode->chrecord)
500 continue; /* some error - spine not initialized ? FIXME */
501 insert_spine(remnode, chassislist);
506 static void pass_on_spines_catch_lines(ChassisList *chassislist)
508 Node *node, *remnode;
512 for (i = 1; i <= SPINES_MAX_NUM; i++) {
513 node = chassislist->spinenode[i];
515 continue; /* empty slot */
516 for (port = node->ports; port; port = port->next) {
517 if (!port->remoteport)
519 remnode = port->remoteport->node;
521 if (!remnode->chrecord)
522 continue; /* some error - line/router not initialized ? FIXME */
523 insert_line_router(remnode, chassislist);
529 Stupid interpolation algorithm...
530 But nothing to do - have to be compliant with VoltaireSM/NMS
532 static void pass_on_spines_interpolate_chguid(ChassisList *chassislist)
537 for (i = 1; i <= SPINES_MAX_NUM; i++) {
538 node = chassislist->spinenode[i];
540 continue; /* skip the empty slots */
542 /* take first guid minus one to be consistent with SM */
543 chassislist->chassisguid = node->nodeguid - 1;
549 This function fills chassislist structure with all nodes
551 chassislist structure = structure of one standalone chassis
553 static void build_chassis(Node *node, ChassisList *chassislist)
558 /* we get here with node = chassis_spine */
559 chassislist->chassistype = node->chrecord->chassistype;
560 insert_spine(node, chassislist);
562 /* loop: pass on all ports of node */
563 for (port = node->ports; port; port = port->next) {
564 if (!port->remoteport)
566 remnode = port->remoteport->node;
568 if (!remnode->chrecord)
569 continue; /* some error - line or router not initialized ? FIXME */
571 insert_line_router(remnode, chassislist);
574 pass_on_lines_catch_spines(chassislist);
575 /* this pass needed for to catch routers, since routers connected only */
576 /* to spines in slot 1 or 4 and we could miss them first time */
577 pass_on_spines_catch_lines(chassislist);
579 /* additional 2 passes needed for to overcome a problem of pure "in-chassis" */
580 /* connectivity - extra pass to ensure that all related chips/modules */
581 /* inserted into the chassislist */
582 pass_on_lines_catch_spines(chassislist);
583 pass_on_spines_catch_lines(chassislist);
584 pass_on_spines_interpolate_chguid(chassislist);
587 /*========================================================*/
588 /* INTERNAL TO EXTERNAL PORT MAPPING */
589 /*========================================================*/
592 Description : On ISR9288/9096 external ports indexing
593 is not matching the internal ( anafa ) port
594 indexes. Use this MAP to translate the data you get from
595 the OpenIB diagnostics (smpquery, ibroute, ibtracert, etc.)
600 ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24
601 int port | 22 23 24 18 17 16 | 22 23 24 18 17 16
602 ext port | 1 2 3 4 5 6 | 7 8 9 10 11 12
603 int port | 19 20 21 15 14 13 | 19 20 21 15 14 13
604 ------------------------------------------------
608 ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24
609 int port | 24 23 22 18 17 16 | 24 23 22 18 17 16
610 ext port | 1 2 3 4 5 6 | 7 8 9 10 11 12
611 int port | 21 20 19 15 14 13 | 21 20 19 15 14 13
615 ext port | - - 5 - - 6 | - - 7 - - 8
616 int port | 24 23 22 18 17 16 | 24 23 22 18 17 16
617 ext port | - - 1 - - 2 | - - 3 - - 4
618 int port | 21 20 19 15 14 13 | 21 20 19 15 14 13
619 ------------------------------------------------
623 ext port | 13 14 15 16 17 18 19 20 21 22 23 24
624 A1 int port| 13 14 15 16 17 18 19 20 21 22 23 24
625 ext port | 1 2 3 4 5 6 7 8 9 10 11 12
626 A2 int port| 13 14 15 16 17 18 19 20 21 22 23 24
627 ---------------------------------------------------
631 int int2ext_map_slb24[2][25] = {
632 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 5, 4, 18, 17, 16, 1, 2, 3, 13, 14, 15 },
633 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 11, 10, 24, 23, 22, 7, 8, 9, 19, 20, 21 }
635 int int2ext_map_slb8[2][25] = {
636 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 6, 6, 6, 1, 1, 1, 5, 5, 5 },
637 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 8, 8, 8, 3, 3, 3, 7, 7, 7 }
639 int int2ext_map_slb2024[2][25] = {
640 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 },
641 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }
643 /* 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 }; */
646 This function relevant only for line modules/chips
647 Returns string with external port index
649 char *portmapstring(Port *port)
651 static char mapping[OUT_BUFFER_SIZE];
652 ChassisRecord *ch = port->node->chrecord;
653 int portnum = port->portnum;
656 Node *node = port->node;
658 if (!ch || !is_line(node) || (portnum < 13 || portnum > 24))
661 if (ch->anafanum < 1 || ch->anafanum > 2)
664 memset(mapping, 0, sizeof(mapping));
666 chipnum = ch->anafanum - 1;
668 if (is_line_24(node))
669 pindex = int2ext_map_slb24[chipnum][portnum];
670 else if (is_line_2024(node))
671 pindex = int2ext_map_slb2024[chipnum][portnum];
673 pindex = int2ext_map_slb8[chipnum][portnum];
675 sprintf(mapping, "[ext %d]", pindex);
680 static void add_chassislist()
682 if (!(mylist.current = calloc(1, sizeof(ChassisList))))
683 IBPANIC("out of mem");
685 if (mylist.first == NULL) {
686 mylist.first = mylist.current;
687 mylist.last = mylist.current;
689 mylist.last->next = mylist.current;
690 mylist.current->next = NULL;
691 mylist.last = mylist.current;
696 Main grouping function
698 1. pass on every Voltaire node
699 2. catch spine chip for every Voltaire node
700 2.1 build/interpolate chassis around this chip
702 3. pass on non Voltaire nodes (SystemImageGUID based grouping)
703 4. now group non Voltaire nodes by SystemImageGUID
705 ChassisList *group_nodes()
710 struct ChassisList *chassis;
713 mylist.current = NULL;
716 /* first pass on switches and build for every Voltaire node */
717 /* an appropriate chassis record (slotnum and position) */
718 /* according to internal connectivity */
719 /* not very efficient but clear code so... */
720 for (dist = 0; dist <= maxhops_discovered; dist++) {
721 for (node = nodesdist[dist]; node; node = node->dnext) {
722 if (node->vendid == VTR_VENDOR_ID)
723 fill_chassis_record(node);
727 /* separate every Voltaire chassis from each other and build linked list of them */
728 /* algorithm: catch spine and find all surrounding nodes */
729 for (dist = 0; dist <= maxhops_discovered; dist++) {
730 for (node = nodesdist[dist]; node; node = node->dnext) {
731 if (node->vendid != VTR_VENDOR_ID)
733 if (!node->chrecord || node->chrecord->chassisnum || !is_spine(node))
736 mylist.current->chassisnum = ++chassisnum;
737 build_chassis(node, mylist.current);
741 /* now make pass on nodes for chassis which are not Voltaire */
742 /* grouped by common SystemImageGUID */
743 for (dist = 0; dist <= maxhops_discovered; dist++) {
744 for (node = nodesdist[dist]; node; node = node->dnext) {
745 if (node->vendid == VTR_VENDOR_ID)
747 if (node->sysimgguid) {
748 chassis = find_chassisguid(node);
750 chassis->nodecount++;
752 /* Possible new chassis */
754 mylist.current->chassisguid = get_chassisguid(node);
755 mylist.current->nodecount = 1;
761 /* now, make another pass to see which nodes are part of chassis */
762 /* (defined as chassis->nodecount > 1) */
763 for (dist = 0; dist <= MAXHOPS; ) {
764 for (node = nodesdist[dist]; node; node = node->dnext) {
765 if (node->vendid == VTR_VENDOR_ID)
767 if (node->sysimgguid) {
768 chassis = find_chassisguid(node);
769 if (chassis && chassis->nodecount > 1) {
770 if (!chassis->chassisnum)
771 chassis->chassisnum = ++chassisnum;
772 if (!node->chrecord) {
773 if (!(node->chrecord = calloc(1, sizeof(ChassisRecord))))
774 IBPANIC("out of mem");
775 node->chrecord->chassisnum = chassis->chassisnum;
780 if (dist == maxhops_discovered)
781 dist = MAXHOPS; /* skip to CAs */
786 return (mylist.first);