1 /* 2 * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. 3 * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. 4 * Copyright (c) 2008 Lawrence Livermore National Lab. All rights reserved. 5 * Copyright (c) 2010 HNR Consulting. All rights reserved. 6 * 7 * This software is available to you under a choice of one of two 8 * licenses. You may choose to be licensed under the terms of the GNU 9 * General Public License (GPL) Version 2, available from the file 10 * COPYING in the main directory of this source tree, or the 11 * OpenIB.org BSD license below: 12 * 13 * Redistribution and use in source and binary forms, with or 14 * without modification, are permitted provided that the following 15 * conditions are met: 16 * 17 * - Redistributions of source code must retain the above 18 * copyright notice, this list of conditions and the following 19 * disclaimer. 20 * 21 * - Redistributions in binary form must reproduce the above 22 * copyright notice, this list of conditions and the following 23 * disclaimer in the documentation and/or other materials 24 * provided with the distribution. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33 * SOFTWARE. 34 * 35 */ 36 37 /*========================================================*/ 38 /* FABRIC SCANNER SPECIFIC DATA */ 39 /*========================================================*/ 40 41 #if HAVE_CONFIG_H 42 #include <config.h> 43 #endif /* HAVE_CONFIG_H */ 44 45 #include <stdlib.h> 46 #include <inttypes.h> 47 48 #include <infiniband/mad.h> 49 50 #include "internal.h" 51 #include "chassis.h" 52 53 static char *ChassisTypeStr[] = 54 { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004", "ISR4700", "ISR4200" }; 55 static char *ChassisSlotTypeStr[] = { "", "Line", "Spine", "SRBD" }; 56 57 typedef struct chassis_scan { 58 ibnd_chassis_t *first_chassis; 59 ibnd_chassis_t *current_chassis; 60 ibnd_chassis_t *last_chassis; 61 } chassis_scan_t; 62 63 char *ibnd_get_chassis_type(ibnd_node_t * node) 64 { 65 int chassis_type; 66 67 if (!node) { 68 IBND_DEBUG("node parameter NULL\n"); 69 return NULL; 70 } 71 72 if (!node->chassis) 73 return NULL; 74 75 chassis_type = mad_get_field(node->info, 0, IB_NODE_VENDORID_F); 76 77 switch (chassis_type) 78 { 79 case VTR_VENDOR_ID: /* Voltaire chassis */ 80 { 81 if (node->ch_type == UNRESOLVED_CT || node->ch_type > ISR4200_CT) 82 return NULL; 83 return ChassisTypeStr[node->ch_type]; 84 } 85 case MLX_VENDOR_ID: 86 { 87 if (node->ch_type_str[0] == '\0') 88 return NULL; 89 return node->ch_type_str; 90 } 91 default: 92 { 93 break; 94 } 95 } 96 return NULL; 97 } 98 99 char *ibnd_get_chassis_slot_str(ibnd_node_t * node, char *str, size_t size) 100 { 101 int vendor_id; 102 103 if (!node) { 104 IBND_DEBUG("node parameter NULL\n"); 105 return NULL; 106 } 107 108 /* Currently, only if Voltaire or Mellanox chassis */ 109 vendor_id = mad_get_field(node->info, 0,IB_NODE_VENDORID_F); 110 111 if ((vendor_id != VTR_VENDOR_ID) && (vendor_id != MLX_VENDOR_ID)) 112 return NULL; 113 if (!node->chassis) 114 return NULL; 115 if (node->ch_slot == UNRESOLVED_CS || node->ch_slot > SRBD_CS) 116 return NULL; 117 if (!str) 118 return NULL; 119 snprintf(str, size, "%s %d Chip %d", ChassisSlotTypeStr[node->ch_slot], 120 node->ch_slotnum, node->ch_anafanum); 121 return str; 122 } 123 124 static ibnd_chassis_t *find_chassisnum(ibnd_fabric_t * fabric, 125 unsigned char chassisnum) 126 { 127 ibnd_chassis_t *current; 128 129 for (current = fabric->chassis; current; current = current->next) 130 if (current->chassisnum == chassisnum) 131 return current; 132 133 return NULL; 134 } 135 136 static uint64_t topspin_chassisguid(uint64_t guid) 137 { 138 /* Byte 3 in system image GUID is chassis type, and */ 139 /* Byte 4 is location ID (slot) so just mask off byte 4 */ 140 return guid & 0xffffffff00ffffffULL; 141 } 142 143 int ibnd_is_xsigo_guid(uint64_t guid) 144 { 145 if ((guid & 0xffffff0000000000ULL) == 0x0013970000000000ULL) 146 return 1; 147 else 148 return 0; 149 } 150 151 static int is_xsigo_leafone(uint64_t guid) 152 { 153 if ((guid & 0xffffffffff000000ULL) == 0x0013970102000000ULL) 154 return 1; 155 else 156 return 0; 157 } 158 159 int ibnd_is_xsigo_hca(uint64_t guid) 160 { 161 /* NodeType 2 is HCA */ 162 if ((guid & 0xffffffff00000000ULL) == 0x0013970200000000ULL) 163 return 1; 164 else 165 return 0; 166 } 167 168 int ibnd_is_xsigo_tca(uint64_t guid) 169 { 170 /* NodeType 3 is TCA */ 171 if ((guid & 0xffffffff00000000ULL) == 0x0013970300000000ULL) 172 return 1; 173 else 174 return 0; 175 } 176 177 static int is_xsigo_ca(uint64_t guid) 178 { 179 if (ibnd_is_xsigo_hca(guid) || ibnd_is_xsigo_tca(guid)) 180 return 1; 181 else 182 return 0; 183 } 184 185 static int is_xsigo_switch(uint64_t guid) 186 { 187 if ((guid & 0xffffffff00000000ULL) == 0x0013970100000000ULL) 188 return 1; 189 else 190 return 0; 191 } 192 193 static uint64_t xsigo_chassisguid(ibnd_node_t * node) 194 { 195 uint64_t sysimgguid = 196 mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F); 197 uint64_t remote_sysimgguid; 198 199 if (!is_xsigo_ca(sysimgguid)) { 200 /* Byte 3 is NodeType and byte 4 is PortType */ 201 /* If NodeType is 1 (switch), PortType is masked */ 202 if (is_xsigo_switch(sysimgguid)) 203 return sysimgguid & 0xffffffff00ffffffULL; 204 else 205 return sysimgguid; 206 } else { 207 if (!node->ports || !node->ports[1]) 208 return 0; 209 210 /* Is there a peer port ? */ 211 if (!node->ports[1]->remoteport) 212 return sysimgguid; 213 214 /* If peer port is Leaf 1, use its chassis GUID */ 215 remote_sysimgguid = 216 mad_get_field64(node->ports[1]->remoteport->node->info, 0, 217 IB_NODE_SYSTEM_GUID_F); 218 if (is_xsigo_leafone(remote_sysimgguid)) 219 return remote_sysimgguid & 0xffffffff00ffffffULL; 220 else 221 return sysimgguid; 222 } 223 } 224 225 static uint64_t get_chassisguid(ibnd_node_t * node) 226 { 227 uint32_t vendid = mad_get_field(node->info, 0, IB_NODE_VENDORID_F); 228 uint64_t sysimgguid = 229 mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F); 230 231 if (vendid == TS_VENDOR_ID || vendid == SS_VENDOR_ID) 232 return topspin_chassisguid(sysimgguid); 233 else if (vendid == XS_VENDOR_ID || ibnd_is_xsigo_guid(sysimgguid)) 234 return xsigo_chassisguid(node); 235 else 236 return sysimgguid; 237 } 238 239 static ibnd_chassis_t *find_chassisguid(ibnd_fabric_t * fabric, 240 ibnd_node_t * node) 241 { 242 ibnd_chassis_t *current; 243 uint64_t chguid; 244 245 chguid = get_chassisguid(node); 246 for (current = fabric->chassis; current; current = current->next) 247 if (current->chassisguid == chguid) 248 return current; 249 250 return NULL; 251 } 252 253 uint64_t ibnd_get_chassis_guid(ibnd_fabric_t * fabric, unsigned char chassisnum) 254 { 255 ibnd_chassis_t *chassis; 256 257 if (!fabric) { 258 IBND_DEBUG("fabric parameter NULL\n"); 259 return 0; 260 } 261 262 chassis = find_chassisnum(fabric, chassisnum); 263 if (chassis) 264 return chassis->chassisguid; 265 else 266 return 0; 267 } 268 269 static int is_router(ibnd_node_t * n) 270 { 271 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); 272 return (devid == VTR_DEVID_IB_FC_ROUTER || 273 devid == VTR_DEVID_IB_IP_ROUTER); 274 } 275 276 static int is_spine_9096(ibnd_node_t * n) 277 { 278 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); 279 return (devid == VTR_DEVID_SFB4 || devid == VTR_DEVID_SFB4_DDR); 280 } 281 282 static int is_spine_9288(ibnd_node_t * n) 283 { 284 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); 285 return (devid == VTR_DEVID_SFB12 || devid == VTR_DEVID_SFB12_DDR); 286 } 287 288 static int is_spine_2004(ibnd_node_t * n) 289 { 290 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); 291 return (devid == VTR_DEVID_SFB2004); 292 } 293 294 static int is_spine_2012(ibnd_node_t * n) 295 { 296 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); 297 return (devid == VTR_DEVID_SFB2012); 298 } 299 300 static int is_spine_4700(ibnd_node_t * n) 301 { 302 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); 303 return (devid == VTR_DEVID_SFB4700); 304 } 305 306 static int is_spine_4700x2(ibnd_node_t * n) 307 { 308 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); 309 return (devid == VTR_DEVID_SFB4700X2); 310 } 311 312 static int is_spine_4200(ibnd_node_t * n) 313 { 314 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); 315 return (devid == VTR_DEVID_SFB4200); 316 } 317 318 static int is_spine(ibnd_node_t * n) 319 { 320 return (is_spine_9096(n) || is_spine_9288(n) || 321 is_spine_2004(n) || is_spine_2012(n) || 322 is_spine_4700(n) || is_spine_4700x2(n) || 323 is_spine_4200(n)); 324 } 325 326 static int is_line_24(ibnd_node_t * n) 327 { 328 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); 329 return (devid == VTR_DEVID_SLB24 || 330 devid == VTR_DEVID_SLB24_DDR || devid == VTR_DEVID_SRB2004); 331 } 332 333 static int is_line_8(ibnd_node_t * n) 334 { 335 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); 336 return (devid == VTR_DEVID_SLB8); 337 } 338 339 static int is_line_2024(ibnd_node_t * n) 340 { 341 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); 342 return (devid == VTR_DEVID_SLB2024); 343 } 344 345 static int is_line_4700(ibnd_node_t * n) 346 { 347 uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); 348 return (devid == VTR_DEVID_SLB4018); 349 } 350 351 static int is_line(ibnd_node_t * n) 352 { 353 return (is_line_24(n) || is_line_8(n) || 354 is_line_2024(n) || is_line_4700(n)); 355 } 356 357 int is_chassis_switch(ibnd_node_t * n) 358 { 359 return (is_spine(n) || is_line(n)); 360 } 361 362 /* these structs help find Line (Anafa) slot number while using spine portnum */ 363 char line_slot_2_sfb4[37] = { 364 0, 365 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 366 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 367 }; 368 char anafa_line_slot_2_sfb4[37] = { 369 0, 370 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 371 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 372 }; 373 374 char line_slot_2_sfb12[37] = { 375 0, 376 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 377 10, 10, 11, 11, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 378 }; 379 char anafa_line_slot_2_sfb12[37] = { 380 0, 381 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 382 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 383 }; 384 385 /* LB slot = table[spine port] */ 386 char line_slot_2_sfb18[37] = { 387 0, 388 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 389 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18}; 390 /* LB asic num = table[spine port] */ 391 char anafa_line_slot_2_sfb18[37] = { 392 0, 393 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 394 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 395 }; 396 397 /* LB slot = table[spine port] */ 398 char line_slot_2_sfb18x2[37] = { 399 0, 400 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 401 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 402 /* LB asic num = table[spine port] */ 403 char anafa_line_slot_2_sfb18x2[37] = { 404 0, 405 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 406 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 407 }; 408 409 /* LB slot = table[spine port] */ 410 char line_slot_2_sfb4200[37] = { 411 0, 412 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 413 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9}; 414 /* LB asic num = table[spine port] */ 415 char anafa_line_slot_2_sfb4200[37] = { 416 0, 417 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 418 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 419 }; 420 421 /* IPR FCR modules connectivity while using sFB4 port as reference */ 422 char ipr_slot_2_sfb4_port[37] = { 423 0, 424 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 425 3, 2, 1, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 426 }; 427 428 /* these structs help find Spine (Anafa) slot number while using spine portnum */ 429 char spine12_slot_2_slb[37] = { 430 0, 431 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 432 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 433 }; 434 char anafa_spine12_slot_2_slb[37] = { 435 0, 436 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 0, 0, 0, 0, 0, 0, 437 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 438 }; 439 440 char spine4_slot_2_slb[37] = { 441 0, 442 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 443 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 444 }; 445 char anafa_spine4_slot_2_slb[37] = { 446 0, 447 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 448 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 449 }; 450 451 /* FB slot = table[line port] */ 452 char spine18_slot_2_slb[37] = { 453 0, 454 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 455 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 456 }; 457 /* FB asic = table[line port] */ 458 char anafa_spine18_slot_2_slb[37] = { 459 0, 460 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 461 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 462 }; 463 char anafa_spine18x2_slot_2_slb[37] = { 464 0, 465 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 466 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 467 }; 468 469 /* FB slot = table[line port] */ 470 char sfb4200_slot_2_slb[37] = { 471 0, 472 1, 1, 1, 1, 0, 0, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 473 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 474 }; 475 /* FB asic = table[line port] */ 476 char anafa_sfb4200_slot_2_slb[37] = { 477 0, 478 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 479 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 480 }; 481 482 /* reference { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; */ 483 484 static int get_sfb_slot(ibnd_node_t * n, ibnd_port_t * lineport) 485 { 486 n->ch_slot = SPINE_CS; 487 if (is_spine_9096(n)) { 488 n->ch_type = ISR9096_CT; 489 n->ch_slotnum = spine4_slot_2_slb[lineport->portnum]; 490 n->ch_anafanum = anafa_spine4_slot_2_slb[lineport->portnum]; 491 } else if (is_spine_9288(n)) { 492 n->ch_type = ISR9288_CT; 493 n->ch_slotnum = spine12_slot_2_slb[lineport->portnum]; 494 n->ch_anafanum = anafa_spine12_slot_2_slb[lineport->portnum]; 495 } else if (is_spine_2012(n)) { 496 n->ch_type = ISR2012_CT; 497 n->ch_slotnum = spine12_slot_2_slb[lineport->portnum]; 498 n->ch_anafanum = anafa_spine12_slot_2_slb[lineport->portnum]; 499 } else if (is_spine_2004(n)) { 500 n->ch_type = ISR2004_CT; 501 n->ch_slotnum = spine4_slot_2_slb[lineport->portnum]; 502 n->ch_anafanum = anafa_spine4_slot_2_slb[lineport->portnum]; 503 } else if (is_spine_4700(n)) { 504 n->ch_type = ISR4700_CT; 505 n->ch_slotnum = spine18_slot_2_slb[lineport->portnum]; 506 n->ch_anafanum = anafa_spine18_slot_2_slb[lineport->portnum]; 507 } else if (is_spine_4700x2(n)) { 508 n->ch_type = ISR4700_CT; 509 n->ch_slotnum = spine18_slot_2_slb[lineport->portnum]; 510 n->ch_anafanum = anafa_spine18x2_slot_2_slb[lineport->portnum]; 511 } else if (is_spine_4200(n)) { 512 n->ch_type = ISR4200_CT; 513 n->ch_slotnum = sfb4200_slot_2_slb[lineport->portnum]; 514 n->ch_anafanum = anafa_sfb4200_slot_2_slb[lineport->portnum]; 515 } else { 516 IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n", 517 n->guid); 518 } 519 return 0; 520 } 521 522 static int get_router_slot(ibnd_node_t * n, ibnd_port_t * spineport) 523 { 524 uint64_t guessnum = 0; 525 526 n->ch_found = 1; 527 528 n->ch_slot = SRBD_CS; 529 if (is_spine_9096(spineport->node)) { 530 n->ch_type = ISR9096_CT; 531 n->ch_slotnum = line_slot_2_sfb4[spineport->portnum]; 532 n->ch_anafanum = ipr_slot_2_sfb4_port[spineport->portnum]; 533 } else if (is_spine_9288(spineport->node)) { 534 n->ch_type = ISR9288_CT; 535 n->ch_slotnum = line_slot_2_sfb12[spineport->portnum]; 536 /* this is a smart guess based on nodeguids order on sFB-12 module */ 537 guessnum = spineport->node->guid % 4; 538 /* module 1 <--> remote anafa 3 */ 539 /* module 2 <--> remote anafa 2 */ 540 /* module 3 <--> remote anafa 1 */ 541 n->ch_anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2)); 542 } else if (is_spine_2012(spineport->node)) { 543 n->ch_type = ISR2012_CT; 544 n->ch_slotnum = line_slot_2_sfb12[spineport->portnum]; 545 /* this is a smart guess based on nodeguids order on sFB-12 module */ 546 guessnum = spineport->node->guid % 4; 547 // module 1 <--> remote anafa 3 548 // module 2 <--> remote anafa 2 549 // module 3 <--> remote anafa 1 550 n->ch_anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2)); 551 } else if (is_spine_2004(spineport->node)) { 552 n->ch_type = ISR2004_CT; 553 n->ch_slotnum = line_slot_2_sfb4[spineport->portnum]; 554 n->ch_anafanum = ipr_slot_2_sfb4_port[spineport->portnum]; 555 } else { 556 IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n", 557 spineport->node->guid); 558 } 559 return 0; 560 } 561 562 static int get_slb_slot(ibnd_node_t * n, ibnd_port_t * spineport) 563 { 564 n->ch_slot = LINE_CS; 565 if (is_spine_9096(spineport->node)) { 566 n->ch_type = ISR9096_CT; 567 n->ch_slotnum = line_slot_2_sfb4[spineport->portnum]; 568 n->ch_anafanum = anafa_line_slot_2_sfb4[spineport->portnum]; 569 } else if (is_spine_9288(spineport->node)) { 570 n->ch_type = ISR9288_CT; 571 n->ch_slotnum = line_slot_2_sfb12[spineport->portnum]; 572 n->ch_anafanum = anafa_line_slot_2_sfb12[spineport->portnum]; 573 } else if (is_spine_2012(spineport->node)) { 574 n->ch_type = ISR2012_CT; 575 n->ch_slotnum = line_slot_2_sfb12[spineport->portnum]; 576 n->ch_anafanum = anafa_line_slot_2_sfb12[spineport->portnum]; 577 } else if (is_spine_2004(spineport->node)) { 578 n->ch_type = ISR2004_CT; 579 n->ch_slotnum = line_slot_2_sfb4[spineport->portnum]; 580 n->ch_anafanum = anafa_line_slot_2_sfb4[spineport->portnum]; 581 } else if (is_spine_4700(spineport->node)) { 582 n->ch_type = ISR4700_CT; 583 n->ch_slotnum = line_slot_2_sfb18[spineport->portnum]; 584 n->ch_anafanum = anafa_line_slot_2_sfb18[spineport->portnum]; 585 } else if (is_spine_4700x2(spineport->node)) { 586 n->ch_type = ISR4700_CT; 587 n->ch_slotnum = line_slot_2_sfb18x2[spineport->portnum]; 588 n->ch_anafanum = anafa_line_slot_2_sfb18x2[spineport->portnum]; 589 } else if (is_spine_4200(spineport->node)) { 590 n->ch_type = ISR4200_CT; 591 n->ch_slotnum = line_slot_2_sfb4200[spineport->portnum]; 592 n->ch_anafanum = anafa_line_slot_2_sfb4200[spineport->portnum]; 593 } else { 594 IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n", 595 spineport->node->guid); 596 } 597 return 0; 598 } 599 600 601 /* 602 This function called for every Mellanox node in fabric 603 */ 604 static int fill_mellanox_chassis_record(ibnd_node_t * node) 605 { 606 int p = 0; 607 ibnd_port_t *port; 608 609 char node_desc[IB_SMP_DATA_SIZE]; 610 char *system_name; 611 char *system_type; 612 char *system_slot_name; 613 char *node_index; 614 char *iter; 615 int dev_id; 616 617 /* 618 The node description has the following format: 619 620 'MF0;<system name>:<system type>/<system slot name>[:board type]/U<node index>' 621 622 - System slot name in our systems can be L[01-36] , S[01-18] 623 - Node index is always 1 (we don.t have boards with multiple IS4 chips). 624 - System name is taken from the currently configured host name. 625 -The board type is optional and we don.t set it currently - A leaf or spine slot can currently hold a single type of board. 626 */ 627 628 memcpy(node_desc, node->nodedesc, IB_SMP_DATA_SIZE); 629 630 IBND_DEBUG("fill_mellanox_chassis_record: node_desc:%s \n",node_desc); 631 632 if (node->ch_found) /* somehow this node has already been passed */ 633 return 0; 634 635 /* All mellanox IS4 switches have the same vendor id*/ 636 dev_id = mad_get_field(node->info, 0,IB_NODE_DEVID_F); 637 if (dev_id != MLX_DEVID_IS4) 638 return 0; 639 640 if((node_desc[0] != 'M') || 641 (node_desc[1] != 'F') || 642 (node_desc[2] != '0') || 643 (node_desc[3] != ';')) { 644 IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s \n",node_desc); 645 return 0; 646 } 647 648 /* parse system name*/ 649 system_name = &node_desc[4]; 650 for (iter = system_name ; (*iter != ':') && (*iter != '\0') ; iter++); 651 if(*iter == '\0'){ 652 IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get system_name failed) \n",node_desc); 653 return 0; 654 } 655 *iter = '\0'; 656 iter++; 657 /* parse system type*/ 658 system_type = iter; 659 for ( ; (*iter != '/') && (*iter != '\0') ; iter++); 660 if(*iter == '\0'){ 661 IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get system_type failed) \n",node_desc); 662 return 0; 663 } 664 *iter = '\0'; 665 iter++; 666 /* parse system slot name*/ 667 system_slot_name = iter; 668 for ( ; (*iter != '/') && (*iter != ':') && (*iter != '\0') ; iter++); 669 if(*iter == '\0'){ 670 IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get system_slot_name failed) \n",node_desc); 671 return 0; 672 } 673 if(*iter == ':'){ 674 *iter = '\0'; 675 iter++; 676 for ( ; (*iter != '/') && (*iter != '\0') ; iter++); 677 if(*iter == '\0'){ 678 IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get board type failed) \n",node_desc); 679 return 0; 680 } 681 } 682 *iter = '\0'; 683 iter++; 684 node_index = iter; 685 if(node_index[0] != 'U'){ 686 IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get node index) \n",node_desc); 687 return 0; 688 } 689 690 /* set Chip number (node index) */ 691 node->ch_anafanum = (unsigned char) atoi(&node_index[1]); 692 if(node->ch_anafanum != 1){ 693 IBND_DEBUG("Unexpected Chip number:%d \n",node->ch_anafanum); 694 } 695 696 697 /* set Line Spine numbers */ 698 if(system_slot_name[0] == 'L') 699 node->ch_slot = LINE_CS; 700 else if(system_slot_name[0] == 'S') 701 node->ch_slot = SPINE_CS; 702 else{ 703 IBND_DEBUG("fill_mellanox_chassis_record: Unsupported system_slot_name:%s \n",system_slot_name); 704 return 0; 705 } 706 707 /* The switch will be displayed under Line or Spine and not under Chassis switches */ 708 node->ch_found = 1; 709 710 node->ch_slotnum = (unsigned char) atoi(&system_slot_name[1]); 711 if((node->ch_slot == LINE_CS && (node->ch_slotnum > (LINES_MAX_NUM + 1))) || 712 (node->ch_slot == SPINE_CS && (node->ch_slotnum > (SPINES_MAX_NUM + 1)))){ 713 IBND_ERROR("fill_mellanox_chassis_record: invalid slot number:%d \n",node->ch_slotnum); 714 node->ch_slotnum = 0; 715 return 0; 716 } 717 718 /*set ch_type_str*/ 719 strncpy(node->ch_type_str , system_type, sizeof(node->ch_type_str)-1); 720 721 /* Line ports 1-18 are mapped to external ports 1-18*/ 722 if(node->ch_slot == LINE_CS) 723 { 724 for (p = 1; p <= node->numports && p <= 18 ; p++) { 725 port = node->ports[p]; 726 if (!port) 727 continue; 728 port->ext_portnum = p; 729 } 730 } 731 732 return 0; 733 } 734 735 static int insert_mellanox_line_and_spine(ibnd_node_t * node, ibnd_chassis_t * chassis) 736 { 737 if (node->ch_slot == LINE_CS){ 738 739 if (chassis->linenode[node->ch_slotnum]) 740 return 0; /* already filled slot */ 741 742 chassis->linenode[node->ch_slotnum] = node; 743 } 744 else if (node->ch_slot == SPINE_CS){ 745 746 if (chassis->spinenode[node->ch_slotnum]) 747 return 0; /* already filled slot */ 748 749 chassis->spinenode[node->ch_slotnum] = node; 750 } 751 else 752 return 0; 753 754 node->chassis = chassis; 755 756 return 0; 757 } 758 759 760 /* forward declare this */ 761 static void voltaire_portmap(ibnd_port_t * port); 762 /* 763 This function called for every Voltaire node in fabric 764 It could be optimized so, but time overhead is very small 765 and its only diag.util 766 */ 767 static int fill_voltaire_chassis_record(ibnd_node_t * node) 768 { 769 int p = 0; 770 ibnd_port_t *port; 771 ibnd_node_t *remnode = 0; 772 773 if (node->ch_found) /* somehow this node has already been passed */ 774 return 0; 775 node->ch_found = 1; 776 777 /* node is router only in case of using unique lid */ 778 /* (which is lid of chassis router port) */ 779 /* in such case node->ports is actually a requested port... */ 780 if (is_router(node)) 781 /* find the remote node */ 782 for (p = 1; p <= node->numports; p++) { 783 port = node->ports[p]; 784 if (port && is_spine(port->remoteport->node)) 785 get_router_slot(node, port->remoteport); 786 } 787 else if (is_spine(node)) { 788 int is_4700x2 = is_spine_4700x2(node); 789 790 for (p = 1; p <= node->numports; p++) { 791 port = node->ports[p]; 792 if (!port || !port->remoteport) 793 continue; 794 795 /* 796 * Skip ISR4700 double density fabric boards ports 19-36 797 * as they are chassis external ports 798 */ 799 if (is_4700x2 && (port->portnum > 18)) 800 continue; 801 802 remnode = port->remoteport->node; 803 if (remnode->type != IB_NODE_SWITCH) { 804 if (!remnode->ch_found) 805 get_router_slot(remnode, port); 806 continue; 807 } 808 if (!node->ch_type) 809 /* we assume here that remoteport belongs to line */ 810 get_sfb_slot(node, port->remoteport); 811 812 /* we could break here, but need to find if more routers connected */ 813 } 814 815 } else if (is_line(node)) { 816 int is_4700_line = is_line_4700(node); 817 818 for (p = 1; p <= node->numports; p++) { 819 port = node->ports[p]; 820 if (!port || !port->remoteport) 821 continue; 822 823 if ((is_4700_line && (port->portnum > 18)) || 824 (!is_4700_line && (port->portnum > 12))) 825 continue; 826 827 /* we assume here that remoteport belongs to spine */ 828 get_slb_slot(node, port->remoteport); 829 break; 830 } 831 } 832 833 /* for each port of this node, map external ports */ 834 for (p = 1; p <= node->numports; p++) { 835 port = node->ports[p]; 836 if (!port) 837 continue; 838 voltaire_portmap(port); 839 } 840 841 return 0; 842 } 843 844 static int get_line_index(ibnd_node_t * node) 845 { 846 int retval; 847 848 if (is_line_4700(node)) 849 retval = node->ch_slotnum; 850 else 851 retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum; 852 853 if (retval > LINES_MAX_NUM || retval < 1) { 854 printf("%s: retval = %d\n", __FUNCTION__, retval); 855 IBND_ERROR("Internal error\n"); 856 return -1; 857 } 858 return retval; 859 } 860 861 static int get_spine_index(ibnd_node_t * node) 862 { 863 int retval; 864 865 if (is_spine_9288(node) || is_spine_2012(node)) 866 retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum; 867 else if (is_spine_4700(node) || is_spine_4700x2(node)) 868 retval = 2 * (node->ch_slotnum - 1) + node->ch_anafanum; 869 else 870 retval = node->ch_slotnum; 871 872 if (retval > SPINES_MAX_NUM || retval < 1) { 873 IBND_ERROR("Internal error\n"); 874 return -1; 875 } 876 return retval; 877 } 878 879 static int insert_line_router(ibnd_node_t * node, ibnd_chassis_t * chassis) 880 { 881 int i = get_line_index(node); 882 883 if (i < 0) 884 return i; 885 886 if (chassis->linenode[i]) 887 return 0; /* already filled slot */ 888 889 chassis->linenode[i] = node; 890 node->chassis = chassis; 891 return 0; 892 } 893 894 static int insert_spine(ibnd_node_t * node, ibnd_chassis_t * chassis) 895 { 896 int i = get_spine_index(node); 897 898 if (i < 0) 899 return i; 900 901 if (chassis->spinenode[i]) 902 return 0; /* already filled slot */ 903 904 chassis->spinenode[i] = node; 905 node->chassis = chassis; 906 return 0; 907 } 908 909 static int pass_on_lines_catch_spines(ibnd_chassis_t * chassis) 910 { 911 ibnd_node_t *node, *remnode; 912 ibnd_port_t *port; 913 int i, p; 914 915 for (i = 1; i <= LINES_MAX_NUM; i++) { 916 int is_4700_line; 917 918 node = chassis->linenode[i]; 919 920 if (!(node && is_line(node))) 921 continue; /* empty slot or router */ 922 923 is_4700_line = is_line_4700(node); 924 925 for (p = 1; p <= node->numports; p++) { 926 927 port = node->ports[p]; 928 if (!port || !port->remoteport) 929 continue; 930 931 if ((is_4700_line && (port->portnum > 18)) || 932 (!is_4700_line && (port->portnum > 12))) 933 continue; 934 935 remnode = port->remoteport->node; 936 937 if (!remnode->ch_found) 938 continue; /* some error - spine not initialized ? FIXME */ 939 if (insert_spine(remnode, chassis)) 940 return -1; 941 } 942 } 943 return 0; 944 } 945 946 static int pass_on_spines_catch_lines(ibnd_chassis_t * chassis) 947 { 948 ibnd_node_t *node, *remnode; 949 ibnd_port_t *port; 950 int i, p; 951 952 for (i = 1; i <= SPINES_MAX_NUM; i++) { 953 int is_4700x2; 954 955 node = chassis->spinenode[i]; 956 if (!node) 957 continue; /* empty slot */ 958 959 is_4700x2 = is_spine_4700x2(node); 960 961 for (p = 1; p <= node->numports; p++) { 962 port = node->ports[p]; 963 if (!port || !port->remoteport) 964 continue; 965 966 /* 967 * ISR4700 double density fabric board ports 19-36 are 968 * chassis external ports, so skip them 969 */ 970 if (is_4700x2 && (port->portnum > 18)) 971 continue; 972 973 remnode = port->remoteport->node; 974 975 if (!remnode->ch_found) 976 continue; /* some error - line/router not initialized ? FIXME */ 977 978 if (insert_line_router(remnode, chassis)) 979 return -1; 980 } 981 } 982 return 0; 983 } 984 985 /* 986 Stupid interpolation algorithm... 987 But nothing to do - have to be compliant with VoltaireSM/NMS 988 */ 989 static void pass_on_spines_interpolate_chguid(ibnd_chassis_t * chassis) 990 { 991 ibnd_node_t *node; 992 int i; 993 994 for (i = 1; i <= SPINES_MAX_NUM; i++) { 995 node = chassis->spinenode[i]; 996 if (!node) 997 continue; /* skip the empty slots */ 998 999 /* take first guid minus one to be consistent with SM */ 1000 chassis->chassisguid = node->guid - 1; 1001 break; 1002 } 1003 } 1004 1005 /* 1006 This function fills chassis structure with all nodes 1007 in that chassis 1008 chassis structure = structure of one standalone chassis 1009 */ 1010 static int build_chassis(ibnd_node_t * node, ibnd_chassis_t * chassis) 1011 { 1012 int p = 0; 1013 ibnd_node_t *remnode = 0; 1014 ibnd_port_t *port = 0; 1015 1016 /* we get here with node = chassis_spine */ 1017 if (insert_spine(node, chassis)) 1018 return -1; 1019 1020 /* loop: pass on all ports of node */ 1021 for (p = 1; p <= node->numports; p++) { 1022 1023 port = node->ports[p]; 1024 if (!port || !port->remoteport) 1025 continue; 1026 1027 /* 1028 * ISR4700 double density fabric board ports 19-36 are 1029 * chassis external ports, so skip them 1030 */ 1031 if (is_spine_4700x2(node) && (port->portnum > 18)) 1032 continue; 1033 1034 remnode = port->remoteport->node; 1035 1036 if (!remnode->ch_found) 1037 continue; /* some error - line or router not initialized ? FIXME */ 1038 1039 insert_line_router(remnode, chassis); 1040 } 1041 1042 if (pass_on_lines_catch_spines(chassis)) 1043 return -1; 1044 /* this pass needed for to catch routers, since routers connected only */ 1045 /* to spines in slot 1 or 4 and we could miss them first time */ 1046 if (pass_on_spines_catch_lines(chassis)) 1047 return -1; 1048 1049 /* additional 2 passes needed for to overcome a problem of pure "in-chassis" */ 1050 /* connectivity - extra pass to ensure that all related chips/modules */ 1051 /* inserted into the chassis */ 1052 if (pass_on_lines_catch_spines(chassis)) 1053 return -1; 1054 if (pass_on_spines_catch_lines(chassis)) 1055 return -1; 1056 pass_on_spines_interpolate_chguid(chassis); 1057 1058 return 0; 1059 } 1060 1061 /*========================================================*/ 1062 /* INTERNAL TO EXTERNAL PORT MAPPING */ 1063 /*========================================================*/ 1064 1065 /* 1066 Description : On ISR9288/9096 external ports indexing 1067 is not matching the internal ( anafa ) port 1068 indexes. Use this MAP to translate the data you get from 1069 the OpenIB diagnostics (smpquery, ibroute, ibtracert, etc.) 1070 1071 Module : sLB-24 1072 anafa 1 anafa 2 1073 ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24 1074 int port | 22 23 24 18 17 16 | 22 23 24 18 17 16 1075 ext port | 1 2 3 4 5 6 | 7 8 9 10 11 12 1076 int port | 19 20 21 15 14 13 | 19 20 21 15 14 13 1077 ------------------------------------------------ 1078 1079 Module : sLB-8 1080 anafa 1 anafa 2 1081 ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24 1082 int port | 24 23 22 18 17 16 | 24 23 22 18 17 16 1083 ext port | 1 2 3 4 5 6 | 7 8 9 10 11 12 1084 int port | 21 20 19 15 14 13 | 21 20 19 15 14 13 1085 1086 -----------> 1087 anafa 1 anafa 2 1088 ext port | - - 5 - - 6 | - - 7 - - 8 1089 int port | 24 23 22 18 17 16 | 24 23 22 18 17 16 1090 ext port | - - 1 - - 2 | - - 3 - - 4 1091 int port | 21 20 19 15 14 13 | 21 20 19 15 14 13 1092 ------------------------------------------------ 1093 1094 Module : sLB-2024 1095 1096 ext port | 13 14 15 16 17 18 19 20 21 22 23 24 1097 A1 int port| 13 14 15 16 17 18 19 20 21 22 23 24 1098 ext port | 1 2 3 4 5 6 7 8 9 10 11 12 1099 A2 int port| 13 14 15 16 17 18 19 20 21 22 23 24 1100 --------------------------------------------------- 1101 1102 Module : sLB-4018 1103 1104 int port | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 1105 ext port | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1106 --------------------------------------------------- 1107 1108 Module : sFB-4700X2 1109 1110 12X port -> 3 x 4X ports: 1111 1112 A1 int port | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 1113 ext port | 7 7 7 8 8 8 9 9 9 10 10 10 11 11 11 12 12 12 1114 A2 int port | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 1115 ext port | 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 1116 1117 */ 1118 1119 int int2ext_map_slb24[2][25] = { 1120 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 5, 4, 18, 17, 16, 1, 2, 3, 1121 13, 14, 15}, 1122 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 11, 10, 24, 23, 22, 7, 8, 9, 1123 19, 20, 21} 1124 }; 1125 1126 int int2ext_map_slb8[2][25] = { 1127 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 6, 6, 6, 1, 1, 1, 5, 5, 1128 5}, 1129 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 8, 8, 8, 3, 3, 3, 7, 7, 1130 7} 1131 }; 1132 1133 int int2ext_map_slb2024[2][25] = { 1134 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 1135 21, 22, 23, 24}, 1136 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1137 11, 12} 1138 }; 1139 1140 int int2ext_map_slb4018[37] = { 1141 0, 1142 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1143 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 1144 }; 1145 1146 int int2ext_map_sfb4700x2[2][37] = { 1147 {0, 1148 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1149 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12}, 1150 {0, 1151 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1152 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6} 1153 }; 1154 1155 /* reference { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; */ 1156 1157 /* map internal ports to external ports if appropriate */ 1158 static void voltaire_portmap(ibnd_port_t * port) 1159 { 1160 int portnum = port->portnum; 1161 int chipnum = 0; 1162 ibnd_node_t *node = port->node; 1163 int is_4700_line = is_line_4700(node); 1164 int is_4700x2_spine = is_spine_4700x2(node); 1165 1166 if (!node->ch_found || (!is_line(node) && !is_4700x2_spine)) { 1167 port->ext_portnum = 0; 1168 return; 1169 } 1170 1171 if (((is_4700_line || is_4700x2_spine) && 1172 (portnum < 19 || portnum > 36)) || 1173 ((!is_4700_line && !is_4700x2_spine) && 1174 (portnum < 13 || portnum > 24))) { 1175 port->ext_portnum = 0; 1176 return; 1177 } 1178 1179 if (port->node->ch_anafanum < 1 || port->node->ch_anafanum > 2) { 1180 port->ext_portnum = 0; 1181 return; 1182 } 1183 1184 chipnum = port->node->ch_anafanum - 1; 1185 1186 if (is_line_24(node)) 1187 port->ext_portnum = int2ext_map_slb24[chipnum][portnum]; 1188 else if (is_line_2024(node)) 1189 port->ext_portnum = int2ext_map_slb2024[chipnum][portnum]; 1190 /* sLB-4018: Only one asic per LB */ 1191 else if (is_4700_line) 1192 port->ext_portnum = int2ext_map_slb4018[portnum]; 1193 /* sFB-4700X2 4X port */ 1194 else if (is_4700x2_spine) 1195 port->ext_portnum = int2ext_map_sfb4700x2[chipnum][portnum]; 1196 else 1197 port->ext_portnum = int2ext_map_slb8[chipnum][portnum]; 1198 } 1199 1200 static int add_chassis(chassis_scan_t * chassis_scan) 1201 { 1202 if (!(chassis_scan->current_chassis = 1203 calloc(1, sizeof(ibnd_chassis_t)))) { 1204 IBND_ERROR("OOM: failed to allocate chassis object\n"); 1205 return -1; 1206 } 1207 1208 if (chassis_scan->first_chassis == NULL) { 1209 chassis_scan->first_chassis = chassis_scan->current_chassis; 1210 chassis_scan->last_chassis = chassis_scan->current_chassis; 1211 } else { 1212 chassis_scan->last_chassis->next = 1213 chassis_scan->current_chassis; 1214 chassis_scan->last_chassis = chassis_scan->current_chassis; 1215 } 1216 return 0; 1217 } 1218 1219 static void add_node_to_chassis(ibnd_chassis_t * chassis, ibnd_node_t * node) 1220 { 1221 node->chassis = chassis; 1222 node->next_chassis_node = chassis->nodes; 1223 chassis->nodes = node; 1224 } 1225 1226 /* 1227 Main grouping function 1228 Algorithm: 1229 1. pass on every Voltaire node 1230 2. catch spine chip for every Voltaire node 1231 2.1 build/interpolate chassis around this chip 1232 2.2 go to 1. 1233 3. pass on non Voltaire nodes (SystemImageGUID based grouping) 1234 4. now group non Voltaire nodes by SystemImageGUID 1235 Returns: 1236 0 on success, -1 on failure 1237 */ 1238 int group_nodes(ibnd_fabric_t * fabric) 1239 { 1240 ibnd_node_t *node; 1241 int chassisnum = 0; 1242 ibnd_chassis_t *chassis; 1243 ibnd_chassis_t *ch, *ch_next; 1244 chassis_scan_t chassis_scan; 1245 int vendor_id; 1246 1247 chassis_scan.first_chassis = NULL; 1248 chassis_scan.current_chassis = NULL; 1249 chassis_scan.last_chassis = NULL; 1250 1251 /* first pass on switches and build for every Voltaire node */ 1252 /* an appropriate chassis record (slotnum and position) */ 1253 /* according to internal connectivity */ 1254 /* not very efficient but clear code so... */ 1255 for (node = fabric->switches; node; node = node->type_next) { 1256 1257 vendor_id = mad_get_field(node->info, 0,IB_NODE_VENDORID_F); 1258 1259 if (vendor_id == VTR_VENDOR_ID 1260 && fill_voltaire_chassis_record(node)) 1261 goto cleanup; 1262 else if (vendor_id == MLX_VENDOR_ID 1263 && fill_mellanox_chassis_record(node)) 1264 goto cleanup; 1265 1266 } 1267 1268 /* separate every Voltaire chassis from each other and build linked list of them */ 1269 /* algorithm: catch spine and find all surrounding nodes */ 1270 for (node = fabric->switches; node; node = node->type_next) { 1271 if (mad_get_field(node->info, 0, 1272 IB_NODE_VENDORID_F) != VTR_VENDOR_ID) 1273 continue; 1274 if (!node->ch_found 1275 || (node->chassis && node->chassis->chassisnum) 1276 || !is_spine(node)) 1277 continue; 1278 if (add_chassis(&chassis_scan)) 1279 goto cleanup; 1280 chassis_scan.current_chassis->chassisnum = ++chassisnum; 1281 if (build_chassis(node, chassis_scan.current_chassis)) 1282 goto cleanup; 1283 } 1284 1285 /* now make pass on nodes for chassis which are not Voltaire */ 1286 /* grouped by common SystemImageGUID */ 1287 for (node = fabric->nodes; node; node = node->next) { 1288 if (mad_get_field(node->info, 0, 1289 IB_NODE_VENDORID_F) == VTR_VENDOR_ID) 1290 continue; 1291 if (mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F)) { 1292 chassis = find_chassisguid(fabric, node); 1293 if (chassis) 1294 chassis->nodecount++; 1295 else { 1296 /* Possible new chassis */ 1297 if (add_chassis(&chassis_scan)) 1298 goto cleanup; 1299 chassis_scan.current_chassis->chassisguid = 1300 get_chassisguid(node); 1301 chassis_scan.current_chassis->nodecount = 1; 1302 if (!fabric->chassis) 1303 fabric->chassis = chassis_scan.first_chassis; 1304 } 1305 } 1306 } 1307 1308 /* now, make another pass to see which nodes are part of chassis */ 1309 /* (defined as chassis->nodecount > 1) */ 1310 for (node = fabric->nodes; node; node = node->next) { 1311 1312 vendor_id = mad_get_field(node->info, 0,IB_NODE_VENDORID_F); 1313 1314 if (vendor_id == VTR_VENDOR_ID) 1315 continue; 1316 if (mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F)) { 1317 chassis = find_chassisguid(fabric, node); 1318 if (chassis && chassis->nodecount > 1) { 1319 if (!chassis->chassisnum) 1320 chassis->chassisnum = ++chassisnum; 1321 if (!node->ch_found) { 1322 node->ch_found = 1; 1323 add_node_to_chassis(chassis, node); 1324 } 1325 else if (vendor_id == MLX_VENDOR_ID){ 1326 insert_mellanox_line_and_spine(node, chassis); 1327 } 1328 } 1329 } 1330 } 1331 1332 fabric->chassis = chassis_scan.first_chassis; 1333 return 0; 1334 1335 cleanup: 1336 ch = chassis_scan.first_chassis; 1337 while (ch) { 1338 ch_next = ch->next; 1339 free(ch); 1340 ch = ch_next; 1341 } 1342 fabric->chassis = NULL; 1343 return -1; 1344 } 1345