1/* 2 * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. 3 * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. 4 * 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: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * - Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 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. 23 * 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 31 * SOFTWARE. 32 * 33 */ 34 35/*========================================================*/ 36/* FABRIC SCANNER SPECIFIC DATA */ 37/*========================================================*/ 38 39#if HAVE_CONFIG_H 40# include <config.h> 41#endif /* HAVE_CONFIG_H */ 42 43#include <stdint.h> 44#include <stdlib.h> 45#include <inttypes.h> 46 47#include <infiniband/common.h> 48#include <infiniband/mad.h> 49 50#include "ibnetdiscover.h" 51#include "grouping.h" 52 53#define OUT_BUFFER_SIZE 16 54 55 56extern Node *nodesdist[MAXHOPS+1]; /* last is CA list */ 57extern Node *mynode; 58extern Port *myport; 59extern int maxhops_discovered; 60 61AllChassisList mylist; 62 63char *ChassisTypeStr[5] = { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004" }; 64char *ChassisSlotStr[4] = { "", "Line", "Spine", "SRBD" }; 65 66 67char *get_chassis_type(unsigned char chassistype) 68{ 69 if (chassistype == UNRESOLVED_CT || chassistype > ISR2004_CT) 70 return NULL; 71 return ChassisTypeStr[chassistype]; 72} 73 74char *get_chassis_slot(unsigned char chassisslot) 75{ 76 if (chassisslot == UNRESOLVED_CS || chassisslot > SRBD_CS) 77 return NULL; 78 return ChassisSlotStr[chassisslot]; 79} 80 81static struct ChassisList *find_chassisnum(unsigned char chassisnum) 82{ 83 ChassisList *current; 84 85 for (current = mylist.first; current; current = current->next) { 86 if (current->chassisnum == chassisnum) 87 return current; 88 } 89 90 return NULL; 91} 92 93static uint64_t topspin_chassisguid(uint64_t guid) 94{ 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; 98} 99 100int is_xsigo_guid(uint64_t guid) 101{ 102 if ((guid & 0xffffff0000000000ULL) == 0x0013970000000000ULL) 103 return 1; 104 else 105 return 0; 106} 107 108static int is_xsigo_leafone(uint64_t guid) 109{ 110 if ((guid & 0xffffffffff000000ULL) == 0x0013970102000000ULL) 111 return 1; 112 else 113 return 0; 114} 115 116int is_xsigo_hca(uint64_t guid) 117{ 118 /* NodeType 2 is HCA */ 119 if ((guid & 0xffffffff00000000ULL) == 0x0013970200000000ULL) 120 return 1; 121 else 122 return 0; 123} 124 125int is_xsigo_tca(uint64_t guid) 126{ 127 /* NodeType 3 is TCA */ 128 if ((guid & 0xffffffff00000000ULL) == 0x0013970300000000ULL) 129 return 1; 130 else 131 return 0; 132} 133 134static int is_xsigo_ca(uint64_t guid) 135{ 136 if (is_xsigo_hca(guid) || is_xsigo_tca(guid)) 137 return 1; 138 else 139 return 0; 140} 141 142static int is_xsigo_switch(uint64_t guid) 143{ 144 if ((guid & 0xffffffff00000000ULL) == 0x0013970100000000ULL) 145 return 1; 146 else 147 return 0; 148} 149 150static uint64_t xsigo_chassisguid(Node *node) 151{ 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; 157 else 158 return node->sysimgguid; 159 } else { 160 /* Is there a peer port ? */ 161 if (!node->ports->remoteport) 162 return node->sysimgguid; 163 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; 168 else 169 return node->sysimgguid; 170 } 171} 172 173static uint64_t get_chassisguid(Node *node) 174{ 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); 179 else 180 return node->sysimgguid; 181} 182 183static struct ChassisList *find_chassisguid(Node *node) 184{ 185 ChassisList *current; 186 uint64_t chguid; 187 188 chguid = get_chassisguid(node); 189 for (current = mylist.first; current; current = current->next) { 190 if (current->chassisguid == chguid) 191 return current; 192 } 193 194 return NULL; 195} 196 197uint64_t get_chassis_guid(unsigned char chassisnum) 198{ 199 ChassisList *chassis; 200 201 chassis = find_chassisnum(chassisnum); 202 if (chassis) 203 return chassis->chassisguid; 204 else 205 return 0; 206} 207 208static int is_router(Node *node) 209{ 210 return (node->devid == VTR_DEVID_IB_FC_ROUTER || 211 node->devid == VTR_DEVID_IB_IP_ROUTER); 212} 213 214static int is_spine_9096(Node *node) 215{ 216 return (node->devid == VTR_DEVID_SFB4 || 217 node->devid == VTR_DEVID_SFB4_DDR); 218} 219 220static int is_spine_9288(Node *node) 221{ 222 return (node->devid == VTR_DEVID_SFB12 || 223 node->devid == VTR_DEVID_SFB12_DDR); 224} 225 226static int is_spine_2004(Node *node) 227{ 228 return (node->devid == VTR_DEVID_SFB2004); 229} 230 231static int is_spine_2012(Node *node) 232{ 233 return (node->devid == VTR_DEVID_SFB2012); 234} 235 236static int is_spine(Node *node) 237{ 238 return (is_spine_9096(node) || is_spine_9288(node) || 239 is_spine_2004(node) || is_spine_2012(node)); 240} 241 242static int is_line_24(Node *node) 243{ 244 return (node->devid == VTR_DEVID_SLB24 || 245 node->devid == VTR_DEVID_SLB24_DDR || 246 node->devid == VTR_DEVID_SRB2004); 247} 248 249static int is_line_8(Node *node) 250{ 251 return (node->devid == VTR_DEVID_SLB8); 252} 253 254static int is_line_2024(Node *node) 255{ 256 return (node->devid == VTR_DEVID_SLB2024); 257} 258 259static int is_line(Node *node) 260{ 261 return (is_line_24(node) || is_line_8(node) || is_line_2024(node)); 262} 263 264int is_chassis_switch(Node *node) 265{ 266 return (is_spine(node) || is_line(node)); 267} 268 269/* these structs help find Line (Anafa) slot number while using spine portnum */ 270int 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 }; 271int 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 }; 272int 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 }; 273int 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 }; 274 275/* IPR FCR modules connectivity while using sFB4 port as reference */ 276int 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 }; 277 278/* these structs help find Spine (Anafa) slot number while using spine portnum */ 279int 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 }; 280int 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 }; 281int 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 }; 282int 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 }; */ 284 285static void get_sfb_slot(Node *node, Port *lineport) 286{ 287 ChassisRecord *ch = node->chrecord; 288 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]; 306 } else { 307 IBPANIC("Unexpected node found: guid 0x%016" PRIx64, node->nodeguid); 308 } 309} 310 311static void get_router_slot(Node *node, Port *spineport) 312{ 313 ChassisRecord *ch = node->chrecord; 314 int guessnum = 0; 315 316 if (!ch) { 317 if (!(node->chrecord = calloc(1, sizeof(ChassisRecord)))) 318 IBPANIC("out of mem"); 319 ch = node->chrecord; 320 } 321 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]; 349 } else { 350 IBPANIC("Unexpected node found: guid 0x%016" PRIx64, spineport->node->nodeguid); 351 } 352} 353 354static void get_slb_slot(ChassisRecord *ch, Port *spineport) 355{ 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]; 373 } else { 374 IBPANIC("Unexpected node found: guid 0x%016" PRIx64, spineport->node->nodeguid); 375 } 376} 377 378/* 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 382*/ 383static void fill_chassis_record(Node *node) 384{ 385 Port *port; 386 Node *remnode = 0; 387 ChassisRecord *ch = 0; 388 389 if (node->chrecord) /* somehow this node has already been passed */ 390 return; 391 392 if (!(node->chrecord = calloc(1, sizeof(ChassisRecord)))) 393 IBPANIC("out of mem"); 394 395 ch = node->chrecord; 396 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) 405 continue; 406 remnode = port->remoteport->node; 407 if (remnode->type != SWITCH_NODE) { 408 if (!remnode->chrecord) 409 get_router_slot(remnode, port); 410 continue; 411 } 412 if (!ch->chassistype) 413 /* we assume here that remoteport belongs to line */ 414 get_sfb_slot(node, port->remoteport); 415 416 /* we could break here, but need to find if more routers connected */ 417 } 418 419 } else if (is_line(node)) { 420 for (port = node->ports; port; port = port->next) { 421 if (port->portnum > 12) 422 continue; 423 if (!port->remoteport) 424 continue; 425 /* we assume here that remoteport belongs to spine */ 426 get_slb_slot(ch, port->remoteport); 427 break; 428 } 429 } 430 431 return; 432} 433 434static int get_line_index(Node *node) 435{ 436 int retval = 3 * (node->chrecord->slotnum - 1) + node->chrecord->anafanum; 437 438 if (retval > LINES_MAX_NUM || retval < 1) 439 IBPANIC("Internal error"); 440 return retval; 441} 442 443static int get_spine_index(Node *node) 444{ 445 int retval; 446 447 if (is_spine_9288(node) || is_spine_2012(node)) 448 retval = 3 * (node->chrecord->slotnum - 1) + node->chrecord->anafanum; 449 else 450 retval = node->chrecord->slotnum; 451 452 if (retval > SPINES_MAX_NUM || retval < 1) 453 IBPANIC("Internal error"); 454 return retval; 455} 456 457static void insert_line_router(Node *node, ChassisList *chassislist) 458{ 459 int i = get_line_index(node); 460 461 if (chassislist->linenode[i]) 462 return; /* already filled slot */ 463 464 chassislist->linenode[i] = node; 465 node->chrecord->chassisnum = chassislist->chassisnum; 466} 467 468static void insert_spine(Node *node, ChassisList *chassislist) 469{ 470 int i = get_spine_index(node); 471 472 if (chassislist->spinenode[i]) 473 return; /* already filled slot */ 474 475 chassislist->spinenode[i] = node; 476 node->chrecord->chassisnum = chassislist->chassisnum; 477} 478 479static void pass_on_lines_catch_spines(ChassisList *chassislist) 480{ 481 Node *node, *remnode; 482 Port *port; 483 int i; 484 485 for (i = 1; i <= LINES_MAX_NUM; i++) { 486 node = chassislist->linenode[i]; 487 488 if (!(node && is_line(node))) 489 continue; /* empty slot or router */ 490 491 for (port = node->ports; port; port = port->next) { 492 if (port->portnum > 12) 493 continue; 494 495 if (!port->remoteport) 496 continue; 497 remnode = port->remoteport->node; 498 499 if (!remnode->chrecord) 500 continue; /* some error - spine not initialized ? FIXME */ 501 insert_spine(remnode, chassislist); 502 } 503 } 504} 505 506static void pass_on_spines_catch_lines(ChassisList *chassislist) 507{ 508 Node *node, *remnode; 509 Port *port; 510 int i; 511 512 for (i = 1; i <= SPINES_MAX_NUM; i++) { 513 node = chassislist->spinenode[i]; 514 if (!node) 515 continue; /* empty slot */ 516 for (port = node->ports; port; port = port->next) { 517 if (!port->remoteport) 518 continue; 519 remnode = port->remoteport->node; 520 521 if (!remnode->chrecord) 522 continue; /* some error - line/router not initialized ? FIXME */ 523 insert_line_router(remnode, chassislist); 524 } 525 } 526} 527 528/* 529 Stupid interpolation algorithm... 530 But nothing to do - have to be compliant with VoltaireSM/NMS 531*/ 532static void pass_on_spines_interpolate_chguid(ChassisList *chassislist) 533{ 534 Node *node; 535 int i; 536 537 for (i = 1; i <= SPINES_MAX_NUM; i++) { 538 node = chassislist->spinenode[i]; 539 if (!node) 540 continue; /* skip the empty slots */ 541 542 /* take first guid minus one to be consistent with SM */ 543 chassislist->chassisguid = node->nodeguid - 1; 544 break; 545 } 546} 547 548/* 549 This function fills chassislist structure with all nodes 550 in that chassis 551 chassislist structure = structure of one standalone chassis 552*/ 553static void build_chassis(Node *node, ChassisList *chassislist) 554{ 555 Node *remnode = 0; 556 Port *port = 0; 557 558 /* we get here with node = chassis_spine */ 559 chassislist->chassistype = node->chrecord->chassistype; 560 insert_spine(node, chassislist); 561 562 /* loop: pass on all ports of node */ 563 for (port = node->ports; port; port = port->next) { 564 if (!port->remoteport) 565 continue; 566 remnode = port->remoteport->node; 567 568 if (!remnode->chrecord) 569 continue; /* some error - line or router not initialized ? FIXME */ 570 571 insert_line_router(remnode, chassislist); 572 } 573 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); 578 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); 585} 586 587/*========================================================*/ 588/* INTERNAL TO EXTERNAL PORT MAPPING */ 589/*========================================================*/ 590 591/* 592Description : 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.) 596 597 598Module : sLB-24 599 anafa 1 anafa 2 600ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24 601int port | 22 23 24 18 17 16 | 22 23 24 18 17 16 602ext port | 1 2 3 4 5 6 | 7 8 9 10 11 12 603int port | 19 20 21 15 14 13 | 19 20 21 15 14 13 604------------------------------------------------ 605 606Module : sLB-8 607 anafa 1 anafa 2 608ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24 609int port | 24 23 22 18 17 16 | 24 23 22 18 17 16 610ext port | 1 2 3 4 5 6 | 7 8 9 10 11 12 611int port | 21 20 19 15 14 13 | 21 20 19 15 14 13 612 613-----------> 614 anafa 1 anafa 2 615ext port | - - 5 - - 6 | - - 7 - - 8 616int port | 24 23 22 18 17 16 | 24 23 22 18 17 16 617ext port | - - 1 - - 2 | - - 3 - - 4 618int port | 21 20 19 15 14 13 | 21 20 19 15 14 13 619------------------------------------------------ 620 621Module : sLB-2024 622 623ext port | 13 14 15 16 17 18 19 20 21 22 23 24 624A1 int port| 13 14 15 16 17 18 19 20 21 22 23 24 625ext port | 1 2 3 4 5 6 7 8 9 10 11 12 626A2 int port| 13 14 15 16 17 18 19 20 21 22 23 24 627--------------------------------------------------- 628 629*/ 630 631int 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 } 634 }; 635int 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 } 638 }; 639int 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 } 642 }; 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 }; */ 644 645/* 646 This function relevant only for line modules/chips 647 Returns string with external port index 648*/ 649char *portmapstring(Port *port) 650{ 651 static char mapping[OUT_BUFFER_SIZE]; 652 ChassisRecord *ch = port->node->chrecord; 653 int portnum = port->portnum; 654 int chipnum = 0; 655 int pindex = 0; 656 Node *node = port->node; 657 658 if (!ch || !is_line(node) || (portnum < 13 || portnum > 24)) 659 return NULL; 660 661 if (ch->anafanum < 1 || ch->anafanum > 2) 662 return NULL; 663 664 memset(mapping, 0, sizeof(mapping)); 665 666 chipnum = ch->anafanum - 1; 667 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]; 672 else 673 pindex = int2ext_map_slb8[chipnum][portnum]; 674 675 sprintf(mapping, "[ext %d]", pindex); 676 677 return mapping; 678} 679 680static void add_chassislist() 681{ 682 if (!(mylist.current = calloc(1, sizeof(ChassisList)))) 683 IBPANIC("out of mem"); 684 685 if (mylist.first == NULL) { 686 mylist.first = mylist.current; 687 mylist.last = mylist.current; 688 } else { 689 mylist.last->next = mylist.current; 690 mylist.current->next = NULL; 691 mylist.last = mylist.current; 692 } 693} 694 695/* 696 Main grouping function 697 Algorithm: 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 701 2.2 go to 1. 702 3. pass on non Voltaire nodes (SystemImageGUID based grouping) 703 4. now group non Voltaire nodes by SystemImageGUID 704*/ 705ChassisList *group_nodes() 706{ 707 Node *node; 708 int dist; 709 int chassisnum = 0; 710 struct ChassisList *chassis; 711 712 mylist.first = NULL; 713 mylist.current = NULL; 714 mylist.last = NULL; 715 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); 724 } 725 } 726 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) 732 continue; 733 if (!node->chrecord || node->chrecord->chassisnum || !is_spine(node)) 734 continue; 735 add_chassislist(); 736 mylist.current->chassisnum = ++chassisnum; 737 build_chassis(node, mylist.current); 738 } 739 } 740 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) 746 continue; 747 if (node->sysimgguid) { 748 chassis = find_chassisguid(node); 749 if (chassis) 750 chassis->nodecount++; 751 else { 752 /* Possible new chassis */ 753 add_chassislist(); 754 mylist.current->chassisguid = get_chassisguid(node); 755 mylist.current->nodecount = 1; 756 } 757 } 758 } 759 } 760 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) 766 continue; 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; 776 } 777 } 778 } 779 } 780 if (dist == maxhops_discovered) 781 dist = MAXHOPS; /* skip to CAs */ 782 else 783 dist++; 784 } 785 786 return (mylist.first); 787} 788