1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. 3219820Sjeff * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. 4219820Sjeff * 5219820Sjeff * This software is available to you under a choice of one of two 6219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 7219820Sjeff * General Public License (GPL) Version 2, available from the file 8219820Sjeff * COPYING in the main directory of this source tree, or the 9219820Sjeff * OpenIB.org BSD license below: 10219820Sjeff * 11219820Sjeff * Redistribution and use in source and binary forms, with or 12219820Sjeff * without modification, are permitted provided that the following 13219820Sjeff * conditions are met: 14219820Sjeff * 15219820Sjeff * - Redistributions of source code must retain the above 16219820Sjeff * copyright notice, this list of conditions and the following 17219820Sjeff * disclaimer. 18219820Sjeff * 19219820Sjeff * - Redistributions in binary form must reproduce the above 20219820Sjeff * copyright notice, this list of conditions and the following 21219820Sjeff * disclaimer in the documentation and/or other materials 22219820Sjeff * provided with the distribution. 23219820Sjeff * 24219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31219820Sjeff * SOFTWARE. 32219820Sjeff * 33219820Sjeff */ 34219820Sjeff 35219820Sjeff/*========================================================*/ 36219820Sjeff/* FABRIC SCANNER SPECIFIC DATA */ 37219820Sjeff/*========================================================*/ 38219820Sjeff 39219820Sjeff#if HAVE_CONFIG_H 40219820Sjeff# include <config.h> 41219820Sjeff#endif /* HAVE_CONFIG_H */ 42219820Sjeff 43219820Sjeff#include <stdint.h> 44219820Sjeff#include <stdlib.h> 45219820Sjeff#include <inttypes.h> 46219820Sjeff 47219820Sjeff#include <infiniband/common.h> 48219820Sjeff#include <infiniband/mad.h> 49219820Sjeff 50219820Sjeff#include "ibnetdiscover.h" 51219820Sjeff#include "grouping.h" 52219820Sjeff 53219820Sjeff#define OUT_BUFFER_SIZE 16 54219820Sjeff 55219820Sjeff 56219820Sjeffextern Node *nodesdist[MAXHOPS+1]; /* last is CA list */ 57219820Sjeffextern Node *mynode; 58219820Sjeffextern Port *myport; 59219820Sjeffextern int maxhops_discovered; 60219820Sjeff 61219820SjeffAllChassisList mylist; 62219820Sjeff 63219820Sjeffchar *ChassisTypeStr[5] = { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004" }; 64219820Sjeffchar *ChassisSlotStr[4] = { "", "Line", "Spine", "SRBD" }; 65219820Sjeff 66219820Sjeff 67219820Sjeffchar *get_chassis_type(unsigned char chassistype) 68219820Sjeff{ 69219820Sjeff if (chassistype == UNRESOLVED_CT || chassistype > ISR2004_CT) 70219820Sjeff return NULL; 71219820Sjeff return ChassisTypeStr[chassistype]; 72219820Sjeff} 73219820Sjeff 74219820Sjeffchar *get_chassis_slot(unsigned char chassisslot) 75219820Sjeff{ 76219820Sjeff if (chassisslot == UNRESOLVED_CS || chassisslot > SRBD_CS) 77219820Sjeff return NULL; 78219820Sjeff return ChassisSlotStr[chassisslot]; 79219820Sjeff} 80219820Sjeff 81219820Sjeffstatic struct ChassisList *find_chassisnum(unsigned char chassisnum) 82219820Sjeff{ 83219820Sjeff ChassisList *current; 84219820Sjeff 85219820Sjeff for (current = mylist.first; current; current = current->next) { 86219820Sjeff if (current->chassisnum == chassisnum) 87219820Sjeff return current; 88219820Sjeff } 89219820Sjeff 90219820Sjeff return NULL; 91219820Sjeff} 92219820Sjeff 93219820Sjeffstatic uint64_t topspin_chassisguid(uint64_t guid) 94219820Sjeff{ 95219820Sjeff /* Byte 3 in system image GUID is chassis type, and */ 96219820Sjeff /* Byte 4 is location ID (slot) so just mask off byte 4 */ 97219820Sjeff return guid & 0xffffffff00ffffffULL; 98219820Sjeff} 99219820Sjeff 100219820Sjeffint is_xsigo_guid(uint64_t guid) 101219820Sjeff{ 102219820Sjeff if ((guid & 0xffffff0000000000ULL) == 0x0013970000000000ULL) 103219820Sjeff return 1; 104219820Sjeff else 105219820Sjeff return 0; 106219820Sjeff} 107219820Sjeff 108219820Sjeffstatic int is_xsigo_leafone(uint64_t guid) 109219820Sjeff{ 110219820Sjeff if ((guid & 0xffffffffff000000ULL) == 0x0013970102000000ULL) 111219820Sjeff return 1; 112219820Sjeff else 113219820Sjeff return 0; 114219820Sjeff} 115219820Sjeff 116219820Sjeffint is_xsigo_hca(uint64_t guid) 117219820Sjeff{ 118219820Sjeff /* NodeType 2 is HCA */ 119219820Sjeff if ((guid & 0xffffffff00000000ULL) == 0x0013970200000000ULL) 120219820Sjeff return 1; 121219820Sjeff else 122219820Sjeff return 0; 123219820Sjeff} 124219820Sjeff 125219820Sjeffint is_xsigo_tca(uint64_t guid) 126219820Sjeff{ 127219820Sjeff /* NodeType 3 is TCA */ 128219820Sjeff if ((guid & 0xffffffff00000000ULL) == 0x0013970300000000ULL) 129219820Sjeff return 1; 130219820Sjeff else 131219820Sjeff return 0; 132219820Sjeff} 133219820Sjeff 134219820Sjeffstatic int is_xsigo_ca(uint64_t guid) 135219820Sjeff{ 136219820Sjeff if (is_xsigo_hca(guid) || is_xsigo_tca(guid)) 137219820Sjeff return 1; 138219820Sjeff else 139219820Sjeff return 0; 140219820Sjeff} 141219820Sjeff 142219820Sjeffstatic int is_xsigo_switch(uint64_t guid) 143219820Sjeff{ 144219820Sjeff if ((guid & 0xffffffff00000000ULL) == 0x0013970100000000ULL) 145219820Sjeff return 1; 146219820Sjeff else 147219820Sjeff return 0; 148219820Sjeff} 149219820Sjeff 150219820Sjeffstatic uint64_t xsigo_chassisguid(Node *node) 151219820Sjeff{ 152219820Sjeff if (!is_xsigo_ca(node->sysimgguid)) { 153219820Sjeff /* Byte 3 is NodeType and byte 4 is PortType */ 154219820Sjeff /* If NodeType is 1 (switch), PortType is masked */ 155219820Sjeff if (is_xsigo_switch(node->sysimgguid)) 156219820Sjeff return node->sysimgguid & 0xffffffff00ffffffULL; 157219820Sjeff else 158219820Sjeff return node->sysimgguid; 159219820Sjeff } else { 160219820Sjeff /* Is there a peer port ? */ 161219820Sjeff if (!node->ports->remoteport) 162219820Sjeff return node->sysimgguid; 163219820Sjeff 164219820Sjeff /* If peer port is Leaf 1, use its chassis GUID */ 165219820Sjeff if (is_xsigo_leafone(node->ports->remoteport->node->sysimgguid)) 166219820Sjeff return node->ports->remoteport->node->sysimgguid & 167219820Sjeff 0xffffffff00ffffffULL; 168219820Sjeff else 169219820Sjeff return node->sysimgguid; 170219820Sjeff } 171219820Sjeff} 172219820Sjeff 173219820Sjeffstatic uint64_t get_chassisguid(Node *node) 174219820Sjeff{ 175219820Sjeff if (node->vendid == TS_VENDOR_ID || node->vendid == SS_VENDOR_ID) 176219820Sjeff return topspin_chassisguid(node->sysimgguid); 177219820Sjeff else if (node->vendid == XS_VENDOR_ID || is_xsigo_guid(node->sysimgguid)) 178219820Sjeff return xsigo_chassisguid(node); 179219820Sjeff else 180219820Sjeff return node->sysimgguid; 181219820Sjeff} 182219820Sjeff 183219820Sjeffstatic struct ChassisList *find_chassisguid(Node *node) 184219820Sjeff{ 185219820Sjeff ChassisList *current; 186219820Sjeff uint64_t chguid; 187219820Sjeff 188219820Sjeff chguid = get_chassisguid(node); 189219820Sjeff for (current = mylist.first; current; current = current->next) { 190219820Sjeff if (current->chassisguid == chguid) 191219820Sjeff return current; 192219820Sjeff } 193219820Sjeff 194219820Sjeff return NULL; 195219820Sjeff} 196219820Sjeff 197219820Sjeffuint64_t get_chassis_guid(unsigned char chassisnum) 198219820Sjeff{ 199219820Sjeff ChassisList *chassis; 200219820Sjeff 201219820Sjeff chassis = find_chassisnum(chassisnum); 202219820Sjeff if (chassis) 203219820Sjeff return chassis->chassisguid; 204219820Sjeff else 205219820Sjeff return 0; 206219820Sjeff} 207219820Sjeff 208219820Sjeffstatic int is_router(Node *node) 209219820Sjeff{ 210219820Sjeff return (node->devid == VTR_DEVID_IB_FC_ROUTER || 211219820Sjeff node->devid == VTR_DEVID_IB_IP_ROUTER); 212219820Sjeff} 213219820Sjeff 214219820Sjeffstatic int is_spine_9096(Node *node) 215219820Sjeff{ 216219820Sjeff return (node->devid == VTR_DEVID_SFB4 || 217219820Sjeff node->devid == VTR_DEVID_SFB4_DDR); 218219820Sjeff} 219219820Sjeff 220219820Sjeffstatic int is_spine_9288(Node *node) 221219820Sjeff{ 222219820Sjeff return (node->devid == VTR_DEVID_SFB12 || 223219820Sjeff node->devid == VTR_DEVID_SFB12_DDR); 224219820Sjeff} 225219820Sjeff 226219820Sjeffstatic int is_spine_2004(Node *node) 227219820Sjeff{ 228219820Sjeff return (node->devid == VTR_DEVID_SFB2004); 229219820Sjeff} 230219820Sjeff 231219820Sjeffstatic int is_spine_2012(Node *node) 232219820Sjeff{ 233219820Sjeff return (node->devid == VTR_DEVID_SFB2012); 234219820Sjeff} 235219820Sjeff 236219820Sjeffstatic int is_spine(Node *node) 237219820Sjeff{ 238219820Sjeff return (is_spine_9096(node) || is_spine_9288(node) || 239219820Sjeff is_spine_2004(node) || is_spine_2012(node)); 240219820Sjeff} 241219820Sjeff 242219820Sjeffstatic int is_line_24(Node *node) 243219820Sjeff{ 244219820Sjeff return (node->devid == VTR_DEVID_SLB24 || 245219820Sjeff node->devid == VTR_DEVID_SLB24_DDR || 246219820Sjeff node->devid == VTR_DEVID_SRB2004); 247219820Sjeff} 248219820Sjeff 249219820Sjeffstatic int is_line_8(Node *node) 250219820Sjeff{ 251219820Sjeff return (node->devid == VTR_DEVID_SLB8); 252219820Sjeff} 253219820Sjeff 254219820Sjeffstatic int is_line_2024(Node *node) 255219820Sjeff{ 256219820Sjeff return (node->devid == VTR_DEVID_SLB2024); 257219820Sjeff} 258219820Sjeff 259219820Sjeffstatic int is_line(Node *node) 260219820Sjeff{ 261219820Sjeff return (is_line_24(node) || is_line_8(node) || is_line_2024(node)); 262219820Sjeff} 263219820Sjeff 264219820Sjeffint is_chassis_switch(Node *node) 265219820Sjeff{ 266219820Sjeff return (is_spine(node) || is_line(node)); 267219820Sjeff} 268219820Sjeff 269219820Sjeff/* these structs help find Line (Anafa) slot number while using spine portnum */ 270219820Sjeffint 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 }; 271219820Sjeffint 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 }; 272219820Sjeffint 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 }; 273219820Sjeffint 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 }; 274219820Sjeff 275219820Sjeff/* IPR FCR modules connectivity while using sFB4 port as reference */ 276219820Sjeffint 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 }; 277219820Sjeff 278219820Sjeff/* these structs help find Spine (Anafa) slot number while using spine portnum */ 279219820Sjeffint 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 }; 280219820Sjeffint 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 }; 281219820Sjeffint 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 }; 282219820Sjeffint 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 }; 283219820Sjeff/* 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 }; */ 284219820Sjeff 285219820Sjeffstatic void get_sfb_slot(Node *node, Port *lineport) 286219820Sjeff{ 287219820Sjeff ChassisRecord *ch = node->chrecord; 288219820Sjeff 289219820Sjeff ch->chassisslot = SPINE_CS; 290219820Sjeff if (is_spine_9096(node)) { 291219820Sjeff ch->chassistype = ISR9096_CT; 292219820Sjeff ch->slotnum = spine4_slot_2_slb[lineport->portnum]; 293219820Sjeff ch->anafanum = anafa_spine4_slot_2_slb[lineport->portnum]; 294219820Sjeff } else if (is_spine_9288(node)) { 295219820Sjeff ch->chassistype = ISR9288_CT; 296219820Sjeff ch->slotnum = spine12_slot_2_slb[lineport->portnum]; 297219820Sjeff ch->anafanum = anafa_spine12_slot_2_slb[lineport->portnum]; 298219820Sjeff } else if (is_spine_2012(node)) { 299219820Sjeff ch->chassistype = ISR2012_CT; 300219820Sjeff ch->slotnum = spine12_slot_2_slb[lineport->portnum]; 301219820Sjeff ch->anafanum = anafa_spine12_slot_2_slb[lineport->portnum]; 302219820Sjeff } else if (is_spine_2004(node)) { 303219820Sjeff ch->chassistype = ISR2004_CT; 304219820Sjeff ch->slotnum = spine4_slot_2_slb[lineport->portnum]; 305219820Sjeff ch->anafanum = anafa_spine4_slot_2_slb[lineport->portnum]; 306219820Sjeff } else { 307219820Sjeff IBPANIC("Unexpected node found: guid 0x%016" PRIx64, node->nodeguid); 308219820Sjeff } 309219820Sjeff} 310219820Sjeff 311219820Sjeffstatic void get_router_slot(Node *node, Port *spineport) 312219820Sjeff{ 313219820Sjeff ChassisRecord *ch = node->chrecord; 314219820Sjeff int guessnum = 0; 315219820Sjeff 316219820Sjeff if (!ch) { 317219820Sjeff if (!(node->chrecord = calloc(1, sizeof(ChassisRecord)))) 318219820Sjeff IBPANIC("out of mem"); 319219820Sjeff ch = node->chrecord; 320219820Sjeff } 321219820Sjeff 322219820Sjeff ch->chassisslot = SRBD_CS; 323219820Sjeff if (is_spine_9096(spineport->node)) { 324219820Sjeff ch->chassistype = ISR9096_CT; 325219820Sjeff ch->slotnum = line_slot_2_sfb4[spineport->portnum]; 326219820Sjeff ch->anafanum = ipr_slot_2_sfb4_port[spineport->portnum]; 327219820Sjeff } else if (is_spine_9288(spineport->node)) { 328219820Sjeff ch->chassistype = ISR9288_CT; 329219820Sjeff ch->slotnum = line_slot_2_sfb12[spineport->portnum]; 330219820Sjeff /* this is a smart guess based on nodeguids order on sFB-12 module */ 331219820Sjeff guessnum = spineport->node->nodeguid % 4; 332219820Sjeff /* module 1 <--> remote anafa 3 */ 333219820Sjeff /* module 2 <--> remote anafa 2 */ 334219820Sjeff /* module 3 <--> remote anafa 1 */ 335219820Sjeff ch->anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2)); 336219820Sjeff } else if (is_spine_2012(spineport->node)) { 337219820Sjeff ch->chassistype = ISR2012_CT; 338219820Sjeff ch->slotnum = line_slot_2_sfb12[spineport->portnum]; 339219820Sjeff /* this is a smart guess based on nodeguids order on sFB-12 module */ 340219820Sjeff guessnum = spineport->node->nodeguid % 4; 341219820Sjeff // module 1 <--> remote anafa 3 342219820Sjeff // module 2 <--> remote anafa 2 343219820Sjeff // module 3 <--> remote anafa 1 344219820Sjeff ch->anafanum = (guessnum == 3? 1 : (guessnum == 1 ? 3 : 2)); 345219820Sjeff } else if (is_spine_2004(spineport->node)) { 346219820Sjeff ch->chassistype = ISR2004_CT; 347219820Sjeff ch->slotnum = line_slot_2_sfb4[spineport->portnum]; 348219820Sjeff ch->anafanum = ipr_slot_2_sfb4_port[spineport->portnum]; 349219820Sjeff } else { 350219820Sjeff IBPANIC("Unexpected node found: guid 0x%016" PRIx64, spineport->node->nodeguid); 351219820Sjeff } 352219820Sjeff} 353219820Sjeff 354219820Sjeffstatic void get_slb_slot(ChassisRecord *ch, Port *spineport) 355219820Sjeff{ 356219820Sjeff ch->chassisslot = LINE_CS; 357219820Sjeff if (is_spine_9096(spineport->node)) { 358219820Sjeff ch->chassistype = ISR9096_CT; 359219820Sjeff ch->slotnum = line_slot_2_sfb4[spineport->portnum]; 360219820Sjeff ch->anafanum = anafa_line_slot_2_sfb4[spineport->portnum]; 361219820Sjeff } else if (is_spine_9288(spineport->node)) { 362219820Sjeff ch->chassistype = ISR9288_CT; 363219820Sjeff ch->slotnum = line_slot_2_sfb12[spineport->portnum]; 364219820Sjeff ch->anafanum = anafa_line_slot_2_sfb12[spineport->portnum]; 365219820Sjeff } else if (is_spine_2012(spineport->node)) { 366219820Sjeff ch->chassistype = ISR2012_CT; 367219820Sjeff ch->slotnum = line_slot_2_sfb12[spineport->portnum]; 368219820Sjeff ch->anafanum = anafa_line_slot_2_sfb12[spineport->portnum]; 369219820Sjeff } else if (is_spine_2004(spineport->node)) { 370219820Sjeff ch->chassistype = ISR2004_CT; 371219820Sjeff ch->slotnum = line_slot_2_sfb4[spineport->portnum]; 372219820Sjeff ch->anafanum = anafa_line_slot_2_sfb4[spineport->portnum]; 373219820Sjeff } else { 374219820Sjeff IBPANIC("Unexpected node found: guid 0x%016" PRIx64, spineport->node->nodeguid); 375219820Sjeff } 376219820Sjeff} 377219820Sjeff 378219820Sjeff/* 379219820Sjeff This function called for every Voltaire node in fabric 380219820Sjeff It could be optimized so, but time overhead is very small 381219820Sjeff and its only diag.util 382219820Sjeff*/ 383219820Sjeffstatic void fill_chassis_record(Node *node) 384219820Sjeff{ 385219820Sjeff Port *port; 386219820Sjeff Node *remnode = 0; 387219820Sjeff ChassisRecord *ch = 0; 388219820Sjeff 389219820Sjeff if (node->chrecord) /* somehow this node has already been passed */ 390219820Sjeff return; 391219820Sjeff 392219820Sjeff if (!(node->chrecord = calloc(1, sizeof(ChassisRecord)))) 393219820Sjeff IBPANIC("out of mem"); 394219820Sjeff 395219820Sjeff ch = node->chrecord; 396219820Sjeff 397219820Sjeff /* node is router only in case of using unique lid */ 398219820Sjeff /* (which is lid of chassis router port) */ 399219820Sjeff /* in such case node->ports is actually a requested port... */ 400219820Sjeff if (is_router(node) && is_spine(node->ports->remoteport->node)) 401219820Sjeff get_router_slot(node, node->ports->remoteport); 402219820Sjeff else if (is_spine(node)) { 403219820Sjeff for (port = node->ports; port; port = port->next) { 404219820Sjeff if (!port->remoteport) 405219820Sjeff continue; 406219820Sjeff remnode = port->remoteport->node; 407219820Sjeff if (remnode->type != SWITCH_NODE) { 408219820Sjeff if (!remnode->chrecord) 409219820Sjeff get_router_slot(remnode, port); 410219820Sjeff continue; 411219820Sjeff } 412219820Sjeff if (!ch->chassistype) 413219820Sjeff /* we assume here that remoteport belongs to line */ 414219820Sjeff get_sfb_slot(node, port->remoteport); 415219820Sjeff 416219820Sjeff /* we could break here, but need to find if more routers connected */ 417219820Sjeff } 418219820Sjeff 419219820Sjeff } else if (is_line(node)) { 420219820Sjeff for (port = node->ports; port; port = port->next) { 421219820Sjeff if (port->portnum > 12) 422219820Sjeff continue; 423219820Sjeff if (!port->remoteport) 424219820Sjeff continue; 425219820Sjeff /* we assume here that remoteport belongs to spine */ 426219820Sjeff get_slb_slot(ch, port->remoteport); 427219820Sjeff break; 428219820Sjeff } 429219820Sjeff } 430219820Sjeff 431219820Sjeff return; 432219820Sjeff} 433219820Sjeff 434219820Sjeffstatic int get_line_index(Node *node) 435219820Sjeff{ 436219820Sjeff int retval = 3 * (node->chrecord->slotnum - 1) + node->chrecord->anafanum; 437219820Sjeff 438219820Sjeff if (retval > LINES_MAX_NUM || retval < 1) 439219820Sjeff IBPANIC("Internal error"); 440219820Sjeff return retval; 441219820Sjeff} 442219820Sjeff 443219820Sjeffstatic int get_spine_index(Node *node) 444219820Sjeff{ 445219820Sjeff int retval; 446219820Sjeff 447219820Sjeff if (is_spine_9288(node) || is_spine_2012(node)) 448219820Sjeff retval = 3 * (node->chrecord->slotnum - 1) + node->chrecord->anafanum; 449219820Sjeff else 450219820Sjeff retval = node->chrecord->slotnum; 451219820Sjeff 452219820Sjeff if (retval > SPINES_MAX_NUM || retval < 1) 453219820Sjeff IBPANIC("Internal error"); 454219820Sjeff return retval; 455219820Sjeff} 456219820Sjeff 457219820Sjeffstatic void insert_line_router(Node *node, ChassisList *chassislist) 458219820Sjeff{ 459219820Sjeff int i = get_line_index(node); 460219820Sjeff 461219820Sjeff if (chassislist->linenode[i]) 462219820Sjeff return; /* already filled slot */ 463219820Sjeff 464219820Sjeff chassislist->linenode[i] = node; 465219820Sjeff node->chrecord->chassisnum = chassislist->chassisnum; 466219820Sjeff} 467219820Sjeff 468219820Sjeffstatic void insert_spine(Node *node, ChassisList *chassislist) 469219820Sjeff{ 470219820Sjeff int i = get_spine_index(node); 471219820Sjeff 472219820Sjeff if (chassislist->spinenode[i]) 473219820Sjeff return; /* already filled slot */ 474219820Sjeff 475219820Sjeff chassislist->spinenode[i] = node; 476219820Sjeff node->chrecord->chassisnum = chassislist->chassisnum; 477219820Sjeff} 478219820Sjeff 479219820Sjeffstatic void pass_on_lines_catch_spines(ChassisList *chassislist) 480219820Sjeff{ 481219820Sjeff Node *node, *remnode; 482219820Sjeff Port *port; 483219820Sjeff int i; 484219820Sjeff 485219820Sjeff for (i = 1; i <= LINES_MAX_NUM; i++) { 486219820Sjeff node = chassislist->linenode[i]; 487219820Sjeff 488219820Sjeff if (!(node && is_line(node))) 489219820Sjeff continue; /* empty slot or router */ 490219820Sjeff 491219820Sjeff for (port = node->ports; port; port = port->next) { 492219820Sjeff if (port->portnum > 12) 493219820Sjeff continue; 494219820Sjeff 495219820Sjeff if (!port->remoteport) 496219820Sjeff continue; 497219820Sjeff remnode = port->remoteport->node; 498219820Sjeff 499219820Sjeff if (!remnode->chrecord) 500219820Sjeff continue; /* some error - spine not initialized ? FIXME */ 501219820Sjeff insert_spine(remnode, chassislist); 502219820Sjeff } 503219820Sjeff } 504219820Sjeff} 505219820Sjeff 506219820Sjeffstatic void pass_on_spines_catch_lines(ChassisList *chassislist) 507219820Sjeff{ 508219820Sjeff Node *node, *remnode; 509219820Sjeff Port *port; 510219820Sjeff int i; 511219820Sjeff 512219820Sjeff for (i = 1; i <= SPINES_MAX_NUM; i++) { 513219820Sjeff node = chassislist->spinenode[i]; 514219820Sjeff if (!node) 515219820Sjeff continue; /* empty slot */ 516219820Sjeff for (port = node->ports; port; port = port->next) { 517219820Sjeff if (!port->remoteport) 518219820Sjeff continue; 519219820Sjeff remnode = port->remoteport->node; 520219820Sjeff 521219820Sjeff if (!remnode->chrecord) 522219820Sjeff continue; /* some error - line/router not initialized ? FIXME */ 523219820Sjeff insert_line_router(remnode, chassislist); 524219820Sjeff } 525219820Sjeff } 526219820Sjeff} 527219820Sjeff 528219820Sjeff/* 529219820Sjeff Stupid interpolation algorithm... 530219820Sjeff But nothing to do - have to be compliant with VoltaireSM/NMS 531219820Sjeff*/ 532219820Sjeffstatic void pass_on_spines_interpolate_chguid(ChassisList *chassislist) 533219820Sjeff{ 534219820Sjeff Node *node; 535219820Sjeff int i; 536219820Sjeff 537219820Sjeff for (i = 1; i <= SPINES_MAX_NUM; i++) { 538219820Sjeff node = chassislist->spinenode[i]; 539219820Sjeff if (!node) 540219820Sjeff continue; /* skip the empty slots */ 541219820Sjeff 542219820Sjeff /* take first guid minus one to be consistent with SM */ 543219820Sjeff chassislist->chassisguid = node->nodeguid - 1; 544219820Sjeff break; 545219820Sjeff } 546219820Sjeff} 547219820Sjeff 548219820Sjeff/* 549219820Sjeff This function fills chassislist structure with all nodes 550219820Sjeff in that chassis 551219820Sjeff chassislist structure = structure of one standalone chassis 552219820Sjeff*/ 553219820Sjeffstatic void build_chassis(Node *node, ChassisList *chassislist) 554219820Sjeff{ 555219820Sjeff Node *remnode = 0; 556219820Sjeff Port *port = 0; 557219820Sjeff 558219820Sjeff /* we get here with node = chassis_spine */ 559219820Sjeff chassislist->chassistype = node->chrecord->chassistype; 560219820Sjeff insert_spine(node, chassislist); 561219820Sjeff 562219820Sjeff /* loop: pass on all ports of node */ 563219820Sjeff for (port = node->ports; port; port = port->next) { 564219820Sjeff if (!port->remoteport) 565219820Sjeff continue; 566219820Sjeff remnode = port->remoteport->node; 567219820Sjeff 568219820Sjeff if (!remnode->chrecord) 569219820Sjeff continue; /* some error - line or router not initialized ? FIXME */ 570219820Sjeff 571219820Sjeff insert_line_router(remnode, chassislist); 572219820Sjeff } 573219820Sjeff 574219820Sjeff pass_on_lines_catch_spines(chassislist); 575219820Sjeff /* this pass needed for to catch routers, since routers connected only */ 576219820Sjeff /* to spines in slot 1 or 4 and we could miss them first time */ 577219820Sjeff pass_on_spines_catch_lines(chassislist); 578219820Sjeff 579219820Sjeff /* additional 2 passes needed for to overcome a problem of pure "in-chassis" */ 580219820Sjeff /* connectivity - extra pass to ensure that all related chips/modules */ 581219820Sjeff /* inserted into the chassislist */ 582219820Sjeff pass_on_lines_catch_spines(chassislist); 583219820Sjeff pass_on_spines_catch_lines(chassislist); 584219820Sjeff pass_on_spines_interpolate_chguid(chassislist); 585219820Sjeff} 586219820Sjeff 587219820Sjeff/*========================================================*/ 588219820Sjeff/* INTERNAL TO EXTERNAL PORT MAPPING */ 589219820Sjeff/*========================================================*/ 590219820Sjeff 591219820Sjeff/* 592219820SjeffDescription : On ISR9288/9096 external ports indexing 593219820Sjeff is not matching the internal ( anafa ) port 594219820Sjeff indexes. Use this MAP to translate the data you get from 595219820Sjeff the OpenIB diagnostics (smpquery, ibroute, ibtracert, etc.) 596219820Sjeff 597219820Sjeff 598219820SjeffModule : sLB-24 599219820Sjeff anafa 1 anafa 2 600219820Sjeffext port | 13 14 15 16 17 18 | 19 20 21 22 23 24 601219820Sjeffint port | 22 23 24 18 17 16 | 22 23 24 18 17 16 602219820Sjeffext port | 1 2 3 4 5 6 | 7 8 9 10 11 12 603219820Sjeffint port | 19 20 21 15 14 13 | 19 20 21 15 14 13 604219820Sjeff------------------------------------------------ 605219820Sjeff 606219820SjeffModule : sLB-8 607219820Sjeff anafa 1 anafa 2 608219820Sjeffext port | 13 14 15 16 17 18 | 19 20 21 22 23 24 609219820Sjeffint port | 24 23 22 18 17 16 | 24 23 22 18 17 16 610219820Sjeffext port | 1 2 3 4 5 6 | 7 8 9 10 11 12 611219820Sjeffint port | 21 20 19 15 14 13 | 21 20 19 15 14 13 612219820Sjeff 613219820Sjeff-----------> 614219820Sjeff anafa 1 anafa 2 615219820Sjeffext port | - - 5 - - 6 | - - 7 - - 8 616219820Sjeffint port | 24 23 22 18 17 16 | 24 23 22 18 17 16 617219820Sjeffext port | - - 1 - - 2 | - - 3 - - 4 618219820Sjeffint port | 21 20 19 15 14 13 | 21 20 19 15 14 13 619219820Sjeff------------------------------------------------ 620219820Sjeff 621219820SjeffModule : sLB-2024 622219820Sjeff 623219820Sjeffext port | 13 14 15 16 17 18 19 20 21 22 23 24 624219820SjeffA1 int port| 13 14 15 16 17 18 19 20 21 22 23 24 625219820Sjeffext port | 1 2 3 4 5 6 7 8 9 10 11 12 626219820SjeffA2 int port| 13 14 15 16 17 18 19 20 21 22 23 24 627219820Sjeff--------------------------------------------------- 628219820Sjeff 629219820Sjeff*/ 630219820Sjeff 631219820Sjeffint int2ext_map_slb24[2][25] = { 632219820Sjeff { 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 }, 633219820Sjeff { 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 } 634219820Sjeff }; 635219820Sjeffint int2ext_map_slb8[2][25] = { 636219820Sjeff { 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 }, 637219820Sjeff { 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 } 638219820Sjeff }; 639219820Sjeffint int2ext_map_slb2024[2][25] = { 640219820Sjeff { 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 }, 641219820Sjeff { 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 } 642219820Sjeff }; 643219820Sjeff/* 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 }; */ 644219820Sjeff 645219820Sjeff/* 646219820Sjeff This function relevant only for line modules/chips 647219820Sjeff Returns string with external port index 648219820Sjeff*/ 649219820Sjeffchar *portmapstring(Port *port) 650219820Sjeff{ 651219820Sjeff static char mapping[OUT_BUFFER_SIZE]; 652219820Sjeff ChassisRecord *ch = port->node->chrecord; 653219820Sjeff int portnum = port->portnum; 654219820Sjeff int chipnum = 0; 655219820Sjeff int pindex = 0; 656219820Sjeff Node *node = port->node; 657219820Sjeff 658219820Sjeff if (!ch || !is_line(node) || (portnum < 13 || portnum > 24)) 659219820Sjeff return NULL; 660219820Sjeff 661219820Sjeff if (ch->anafanum < 1 || ch->anafanum > 2) 662219820Sjeff return NULL; 663219820Sjeff 664219820Sjeff memset(mapping, 0, sizeof(mapping)); 665219820Sjeff 666219820Sjeff chipnum = ch->anafanum - 1; 667219820Sjeff 668219820Sjeff if (is_line_24(node)) 669219820Sjeff pindex = int2ext_map_slb24[chipnum][portnum]; 670219820Sjeff else if (is_line_2024(node)) 671219820Sjeff pindex = int2ext_map_slb2024[chipnum][portnum]; 672219820Sjeff else 673219820Sjeff pindex = int2ext_map_slb8[chipnum][portnum]; 674219820Sjeff 675219820Sjeff sprintf(mapping, "[ext %d]", pindex); 676219820Sjeff 677219820Sjeff return mapping; 678219820Sjeff} 679219820Sjeff 680219820Sjeffstatic void add_chassislist() 681219820Sjeff{ 682219820Sjeff if (!(mylist.current = calloc(1, sizeof(ChassisList)))) 683219820Sjeff IBPANIC("out of mem"); 684219820Sjeff 685219820Sjeff if (mylist.first == NULL) { 686219820Sjeff mylist.first = mylist.current; 687219820Sjeff mylist.last = mylist.current; 688219820Sjeff } else { 689219820Sjeff mylist.last->next = mylist.current; 690219820Sjeff mylist.current->next = NULL; 691219820Sjeff mylist.last = mylist.current; 692219820Sjeff } 693219820Sjeff} 694219820Sjeff 695219820Sjeff/* 696219820Sjeff Main grouping function 697219820Sjeff Algorithm: 698219820Sjeff 1. pass on every Voltaire node 699219820Sjeff 2. catch spine chip for every Voltaire node 700219820Sjeff 2.1 build/interpolate chassis around this chip 701219820Sjeff 2.2 go to 1. 702219820Sjeff 3. pass on non Voltaire nodes (SystemImageGUID based grouping) 703219820Sjeff 4. now group non Voltaire nodes by SystemImageGUID 704219820Sjeff*/ 705219820SjeffChassisList *group_nodes() 706219820Sjeff{ 707219820Sjeff Node *node; 708219820Sjeff int dist; 709219820Sjeff int chassisnum = 0; 710219820Sjeff struct ChassisList *chassis; 711219820Sjeff 712219820Sjeff mylist.first = NULL; 713219820Sjeff mylist.current = NULL; 714219820Sjeff mylist.last = NULL; 715219820Sjeff 716219820Sjeff /* first pass on switches and build for every Voltaire node */ 717219820Sjeff /* an appropriate chassis record (slotnum and position) */ 718219820Sjeff /* according to internal connectivity */ 719219820Sjeff /* not very efficient but clear code so... */ 720219820Sjeff for (dist = 0; dist <= maxhops_discovered; dist++) { 721219820Sjeff for (node = nodesdist[dist]; node; node = node->dnext) { 722219820Sjeff if (node->vendid == VTR_VENDOR_ID) 723219820Sjeff fill_chassis_record(node); 724219820Sjeff } 725219820Sjeff } 726219820Sjeff 727219820Sjeff /* separate every Voltaire chassis from each other and build linked list of them */ 728219820Sjeff /* algorithm: catch spine and find all surrounding nodes */ 729219820Sjeff for (dist = 0; dist <= maxhops_discovered; dist++) { 730219820Sjeff for (node = nodesdist[dist]; node; node = node->dnext) { 731219820Sjeff if (node->vendid != VTR_VENDOR_ID) 732219820Sjeff continue; 733219820Sjeff if (!node->chrecord || node->chrecord->chassisnum || !is_spine(node)) 734219820Sjeff continue; 735219820Sjeff add_chassislist(); 736219820Sjeff mylist.current->chassisnum = ++chassisnum; 737219820Sjeff build_chassis(node, mylist.current); 738219820Sjeff } 739219820Sjeff } 740219820Sjeff 741219820Sjeff /* now make pass on nodes for chassis which are not Voltaire */ 742219820Sjeff /* grouped by common SystemImageGUID */ 743219820Sjeff for (dist = 0; dist <= maxhops_discovered; dist++) { 744219820Sjeff for (node = nodesdist[dist]; node; node = node->dnext) { 745219820Sjeff if (node->vendid == VTR_VENDOR_ID) 746219820Sjeff continue; 747219820Sjeff if (node->sysimgguid) { 748219820Sjeff chassis = find_chassisguid(node); 749219820Sjeff if (chassis) 750219820Sjeff chassis->nodecount++; 751219820Sjeff else { 752219820Sjeff /* Possible new chassis */ 753219820Sjeff add_chassislist(); 754219820Sjeff mylist.current->chassisguid = get_chassisguid(node); 755219820Sjeff mylist.current->nodecount = 1; 756219820Sjeff } 757219820Sjeff } 758219820Sjeff } 759219820Sjeff } 760219820Sjeff 761219820Sjeff /* now, make another pass to see which nodes are part of chassis */ 762219820Sjeff /* (defined as chassis->nodecount > 1) */ 763219820Sjeff for (dist = 0; dist <= MAXHOPS; ) { 764219820Sjeff for (node = nodesdist[dist]; node; node = node->dnext) { 765219820Sjeff if (node->vendid == VTR_VENDOR_ID) 766219820Sjeff continue; 767219820Sjeff if (node->sysimgguid) { 768219820Sjeff chassis = find_chassisguid(node); 769219820Sjeff if (chassis && chassis->nodecount > 1) { 770219820Sjeff if (!chassis->chassisnum) 771219820Sjeff chassis->chassisnum = ++chassisnum; 772219820Sjeff if (!node->chrecord) { 773219820Sjeff if (!(node->chrecord = calloc(1, sizeof(ChassisRecord)))) 774219820Sjeff IBPANIC("out of mem"); 775219820Sjeff node->chrecord->chassisnum = chassis->chassisnum; 776219820Sjeff } 777219820Sjeff } 778219820Sjeff } 779219820Sjeff } 780219820Sjeff if (dist == maxhops_discovered) 781219820Sjeff dist = MAXHOPS; /* skip to CAs */ 782219820Sjeff else 783219820Sjeff dist++; 784219820Sjeff } 785219820Sjeff 786219820Sjeff return (mylist.first); 787219820Sjeff} 788