/* * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. * Copyright (c) 2008 Lawrence Livermore National Lab. All rights reserved. * Copyright (c) 2010 HNR Consulting. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ /*========================================================*/ /* FABRIC SCANNER SPECIFIC DATA */ /*========================================================*/ #include #include #include #include "internal.h" #include "chassis.h" static const char * const ChassisTypeStr[] = { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004", "ISR4700", "ISR4200" }; static const char * const ChassisSlotTypeStr[] = { "", "Line", "Spine", "SRBD" }; typedef struct chassis_scan { ibnd_chassis_t *first_chassis; ibnd_chassis_t *current_chassis; ibnd_chassis_t *last_chassis; } chassis_scan_t; const char *ibnd_get_chassis_type(ibnd_node_t * node) { int chassis_type; if (!node) { IBND_DEBUG("node parameter NULL\n"); return NULL; } if (!node->chassis) return NULL; chassis_type = mad_get_field(node->info, 0, IB_NODE_VENDORID_F); switch (chassis_type) { case VTR_VENDOR_ID: /* Voltaire chassis */ { if (node->ch_type == UNRESOLVED_CT || node->ch_type > ISR4200_CT) return NULL; return ChassisTypeStr[node->ch_type]; } case MLX_VENDOR_ID: { if (node->ch_type_str[0] == '\0') return NULL; return node->ch_type_str; } default: { break; } } return NULL; } char *ibnd_get_chassis_slot_str(ibnd_node_t * node, char *str, size_t size) { int vendor_id; if (!node) { IBND_DEBUG("node parameter NULL\n"); return NULL; } /* Currently, only if Voltaire or Mellanox chassis */ vendor_id = mad_get_field(node->info, 0,IB_NODE_VENDORID_F); if ((vendor_id != VTR_VENDOR_ID) && (vendor_id != MLX_VENDOR_ID)) return NULL; if (!node->chassis) return NULL; if (node->ch_slot == UNRESOLVED_CS || node->ch_slot > SRBD_CS) return NULL; if (!str) return NULL; snprintf(str, size, "%s %d Chip %d", ChassisSlotTypeStr[node->ch_slot], node->ch_slotnum, node->ch_anafanum); return str; } static ibnd_chassis_t *find_chassisnum(ibnd_fabric_t * fabric, unsigned char chassisnum) { ibnd_chassis_t *current; for (current = fabric->chassis; current; current = current->next) if (current->chassisnum == chassisnum) return current; return NULL; } static uint64_t topspin_chassisguid(uint64_t guid) { /* Byte 3 in system image GUID is chassis type, and */ /* Byte 4 is location ID (slot) so just mask off byte 4 */ return guid & 0xffffffff00ffffffULL; } int ibnd_is_xsigo_guid(uint64_t guid) { if ((guid & 0xffffff0000000000ULL) == 0x0013970000000000ULL) return 1; else return 0; } static int is_xsigo_leafone(uint64_t guid) { if ((guid & 0xffffffffff000000ULL) == 0x0013970102000000ULL) return 1; else return 0; } int ibnd_is_xsigo_hca(uint64_t guid) { /* NodeType 2 is HCA */ if ((guid & 0xffffffff00000000ULL) == 0x0013970200000000ULL) return 1; else return 0; } int ibnd_is_xsigo_tca(uint64_t guid) { /* NodeType 3 is TCA */ if ((guid & 0xffffffff00000000ULL) == 0x0013970300000000ULL) return 1; else return 0; } static int is_xsigo_ca(uint64_t guid) { if (ibnd_is_xsigo_hca(guid) || ibnd_is_xsigo_tca(guid)) return 1; else return 0; } static int is_xsigo_switch(uint64_t guid) { if ((guid & 0xffffffff00000000ULL) == 0x0013970100000000ULL) return 1; else return 0; } static uint64_t xsigo_chassisguid(ibnd_node_t * node) { uint64_t sysimgguid = mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F); uint64_t remote_sysimgguid; if (!is_xsigo_ca(sysimgguid)) { /* Byte 3 is NodeType and byte 4 is PortType */ /* If NodeType is 1 (switch), PortType is masked */ if (is_xsigo_switch(sysimgguid)) return sysimgguid & 0xffffffff00ffffffULL; else return sysimgguid; } else { if (!node->ports || !node->ports[1]) return 0; /* Is there a peer port ? */ if (!node->ports[1]->remoteport) return sysimgguid; /* If peer port is Leaf 1, use its chassis GUID */ remote_sysimgguid = mad_get_field64(node->ports[1]->remoteport->node->info, 0, IB_NODE_SYSTEM_GUID_F); if (is_xsigo_leafone(remote_sysimgguid)) return remote_sysimgguid & 0xffffffff00ffffffULL; else return sysimgguid; } } static uint64_t get_chassisguid(ibnd_node_t * node) { uint32_t vendid = mad_get_field(node->info, 0, IB_NODE_VENDORID_F); uint64_t sysimgguid = mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F); if (vendid == TS_VENDOR_ID || vendid == SS_VENDOR_ID) return topspin_chassisguid(sysimgguid); else if (vendid == XS_VENDOR_ID || ibnd_is_xsigo_guid(sysimgguid)) return xsigo_chassisguid(node); else return sysimgguid; } static ibnd_chassis_t *find_chassisguid(ibnd_fabric_t * fabric, ibnd_node_t * node) { ibnd_chassis_t *current; uint64_t chguid; chguid = get_chassisguid(node); for (current = fabric->chassis; current; current = current->next) if (current->chassisguid == chguid) return current; return NULL; } uint64_t ibnd_get_chassis_guid(ibnd_fabric_t * fabric, unsigned char chassisnum) { ibnd_chassis_t *chassis; if (!fabric) { IBND_DEBUG("fabric parameter NULL\n"); return 0; } chassis = find_chassisnum(fabric, chassisnum); if (chassis) return chassis->chassisguid; else return 0; } static int is_router(ibnd_node_t * n) { uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); return (devid == VTR_DEVID_IB_FC_ROUTER || devid == VTR_DEVID_IB_IP_ROUTER); } static int is_spine_9096(ibnd_node_t * n) { uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); return (devid == VTR_DEVID_SFB4 || devid == VTR_DEVID_SFB4_DDR); } static int is_spine_9288(ibnd_node_t * n) { uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); return (devid == VTR_DEVID_SFB12 || devid == VTR_DEVID_SFB12_DDR); } static int is_spine_2004(ibnd_node_t * n) { uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); return (devid == VTR_DEVID_SFB2004); } static int is_spine_2012(ibnd_node_t * n) { uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); return (devid == VTR_DEVID_SFB2012); } static int is_spine_4700(ibnd_node_t * n) { uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); return (devid == VTR_DEVID_SFB4700); } static int is_spine_4700x2(ibnd_node_t * n) { uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); return (devid == VTR_DEVID_SFB4700X2); } static int is_spine_4200(ibnd_node_t * n) { uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); return (devid == VTR_DEVID_SFB4200); } static int is_spine(ibnd_node_t * n) { return (is_spine_9096(n) || is_spine_9288(n) || is_spine_2004(n) || is_spine_2012(n) || is_spine_4700(n) || is_spine_4700x2(n) || is_spine_4200(n)); } static int is_line_24(ibnd_node_t * n) { uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); return (devid == VTR_DEVID_SLB24 || devid == VTR_DEVID_SLB24_DDR || devid == VTR_DEVID_SRB2004); } static int is_line_8(ibnd_node_t * n) { uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); return (devid == VTR_DEVID_SLB8); } static int is_line_2024(ibnd_node_t * n) { uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); return (devid == VTR_DEVID_SLB2024); } static int is_line_4700(ibnd_node_t * n) { uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); return (devid == VTR_DEVID_SLB4018); } static int is_line(ibnd_node_t * n) { return (is_line_24(n) || is_line_8(n) || is_line_2024(n) || is_line_4700(n)); } /* these structs help find Line (Anafa) slot number while using spine portnum */ static const char line_slot_2_sfb4[37] = { 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const char anafa_line_slot_2_sfb4[37] = { 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const char line_slot_2_sfb12[37] = { 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const char anafa_line_slot_2_sfb12[37] = { 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* LB slot = table[spine port] */ static const char line_slot_2_sfb18[37] = { 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, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18}; /* LB asic num = table[spine port] */ static const char anafa_line_slot_2_sfb18[37] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; /* LB slot = table[spine port] */ static const char line_slot_2_sfb18x2[37] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* LB asic num = table[spine port] */ static const char anafa_line_slot_2_sfb18x2[37] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* LB slot = table[spine port] */ static const char line_slot_2_sfb4200[37] = { 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9}; /* LB asic num = table[spine port] */ static const char anafa_line_slot_2_sfb4200[37] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; /* IPR FCR modules connectivity while using sFB4 port as reference */ static const char ipr_slot_2_sfb4_port[37] = { 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* these structs help find Spine (Anafa) slot number while using spine portnum */ static const char spine12_slot_2_slb[37] = { 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const char anafa_spine12_slot_2_slb[37] = { 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const char spine4_slot_2_slb[37] = { 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const char anafa_spine4_slot_2_slb[37] = { 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* FB slot = table[line port] */ static const char spine18_slot_2_slb[37] = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* FB asic = table[line port] */ static const char anafa_spine18_slot_2_slb[37] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const char anafa_spine18x2_slot_2_slb[37] = { 0, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* FB slot = table[line port] */ static const char sfb4200_slot_2_slb[37] = { 0, 1, 1, 1, 1, 0, 0, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* FB asic = table[line port] */ static const char anafa_sfb4200_slot_2_slb[37] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 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 }; */ static int get_sfb_slot(ibnd_node_t * n, ibnd_port_t * lineport) { n->ch_slot = SPINE_CS; if (is_spine_9096(n)) { n->ch_type = ISR9096_CT; n->ch_slotnum = spine4_slot_2_slb[lineport->portnum]; n->ch_anafanum = anafa_spine4_slot_2_slb[lineport->portnum]; } else if (is_spine_9288(n)) { n->ch_type = ISR9288_CT; n->ch_slotnum = spine12_slot_2_slb[lineport->portnum]; n->ch_anafanum = anafa_spine12_slot_2_slb[lineport->portnum]; } else if (is_spine_2012(n)) { n->ch_type = ISR2012_CT; n->ch_slotnum = spine12_slot_2_slb[lineport->portnum]; n->ch_anafanum = anafa_spine12_slot_2_slb[lineport->portnum]; } else if (is_spine_2004(n)) { n->ch_type = ISR2004_CT; n->ch_slotnum = spine4_slot_2_slb[lineport->portnum]; n->ch_anafanum = anafa_spine4_slot_2_slb[lineport->portnum]; } else if (is_spine_4700(n)) { n->ch_type = ISR4700_CT; n->ch_slotnum = spine18_slot_2_slb[lineport->portnum]; n->ch_anafanum = anafa_spine18_slot_2_slb[lineport->portnum]; } else if (is_spine_4700x2(n)) { n->ch_type = ISR4700_CT; n->ch_slotnum = spine18_slot_2_slb[lineport->portnum]; n->ch_anafanum = anafa_spine18x2_slot_2_slb[lineport->portnum]; } else if (is_spine_4200(n)) { n->ch_type = ISR4200_CT; n->ch_slotnum = sfb4200_slot_2_slb[lineport->portnum]; n->ch_anafanum = anafa_sfb4200_slot_2_slb[lineport->portnum]; } else { IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n", n->guid); } return 0; } static int get_router_slot(ibnd_node_t * n, ibnd_port_t * spineport) { uint64_t guessnum = 0; n->ch_found = 1; n->ch_slot = SRBD_CS; if (is_spine_9096(spineport->node)) { n->ch_type = ISR9096_CT; n->ch_slotnum = line_slot_2_sfb4[spineport->portnum]; n->ch_anafanum = ipr_slot_2_sfb4_port[spineport->portnum]; } else if (is_spine_9288(spineport->node)) { n->ch_type = ISR9288_CT; n->ch_slotnum = line_slot_2_sfb12[spineport->portnum]; /* this is a smart guess based on nodeguids order on sFB-12 module */ guessnum = spineport->node->guid % 4; /* module 1 <--> remote anafa 3 */ /* module 2 <--> remote anafa 2 */ /* module 3 <--> remote anafa 1 */ n->ch_anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2)); } else if (is_spine_2012(spineport->node)) { n->ch_type = ISR2012_CT; n->ch_slotnum = line_slot_2_sfb12[spineport->portnum]; /* this is a smart guess based on nodeguids order on sFB-12 module */ guessnum = spineport->node->guid % 4; // module 1 <--> remote anafa 3 // module 2 <--> remote anafa 2 // module 3 <--> remote anafa 1 n->ch_anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2)); } else if (is_spine_2004(spineport->node)) { n->ch_type = ISR2004_CT; n->ch_slotnum = line_slot_2_sfb4[spineport->portnum]; n->ch_anafanum = ipr_slot_2_sfb4_port[spineport->portnum]; } else { IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n", spineport->node->guid); } return 0; } static int get_slb_slot(ibnd_node_t * n, ibnd_port_t * spineport) { n->ch_slot = LINE_CS; if (is_spine_9096(spineport->node)) { n->ch_type = ISR9096_CT; n->ch_slotnum = line_slot_2_sfb4[spineport->portnum]; n->ch_anafanum = anafa_line_slot_2_sfb4[spineport->portnum]; } else if (is_spine_9288(spineport->node)) { n->ch_type = ISR9288_CT; n->ch_slotnum = line_slot_2_sfb12[spineport->portnum]; n->ch_anafanum = anafa_line_slot_2_sfb12[spineport->portnum]; } else if (is_spine_2012(spineport->node)) { n->ch_type = ISR2012_CT; n->ch_slotnum = line_slot_2_sfb12[spineport->portnum]; n->ch_anafanum = anafa_line_slot_2_sfb12[spineport->portnum]; } else if (is_spine_2004(spineport->node)) { n->ch_type = ISR2004_CT; n->ch_slotnum = line_slot_2_sfb4[spineport->portnum]; n->ch_anafanum = anafa_line_slot_2_sfb4[spineport->portnum]; } else if (is_spine_4700(spineport->node)) { n->ch_type = ISR4700_CT; n->ch_slotnum = line_slot_2_sfb18[spineport->portnum]; n->ch_anafanum = anafa_line_slot_2_sfb18[spineport->portnum]; } else if (is_spine_4700x2(spineport->node)) { n->ch_type = ISR4700_CT; n->ch_slotnum = line_slot_2_sfb18x2[spineport->portnum]; n->ch_anafanum = anafa_line_slot_2_sfb18x2[spineport->portnum]; } else if (is_spine_4200(spineport->node)) { n->ch_type = ISR4200_CT; n->ch_slotnum = line_slot_2_sfb4200[spineport->portnum]; n->ch_anafanum = anafa_line_slot_2_sfb4200[spineport->portnum]; } else { IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n", spineport->node->guid); } return 0; } /* This function called for every Mellanox node in fabric */ static int fill_mellanox_chassis_record(ibnd_node_t * node) { int p = 0; ibnd_port_t *port; char node_desc[IB_SMP_DATA_SIZE + 1]; char *system_name; char *system_type; char *system_slot_name; char *node_index; char *iter; int dev_id; /* The node description has the following format: 'MF0;:/[:board type]/U' - System slot name in our systems can be L[01-36] , S[01-18] - Node index is always 1 (we don.t have boards with multiple IS4 chips). - System name is taken from the currently configured host name. -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. */ memcpy(node_desc, node->nodedesc, IB_SMP_DATA_SIZE); node_desc[IB_SMP_DATA_SIZE] = '\0'; IBND_DEBUG("fill_mellanox_chassis_record: node_desc:%s \n",node_desc); if (node->ch_found) /* somehow this node has already been passed */ return 0; /* All mellanox IS4 switches have the same vendor id*/ dev_id = mad_get_field(node->info, 0,IB_NODE_DEVID_F); if (dev_id != MLX_DEVID_IS4) return 0; if((node_desc[0] != 'M') || (node_desc[1] != 'F') || (node_desc[2] != '0') || (node_desc[3] != ';')) { IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s \n",node_desc); return 0; } /* parse system name*/ system_name = &node_desc[4]; for (iter = system_name ; (*iter != ':') && (*iter != '\0') ; iter++); if(*iter == '\0'){ IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get system_name failed) \n",node_desc); return 0; } *iter = '\0'; iter++; /* parse system type*/ system_type = iter; for ( ; (*iter != '/') && (*iter != '\0') ; iter++); if(*iter == '\0'){ IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get system_type failed) \n",node_desc); return 0; } *iter = '\0'; iter++; /* parse system slot name*/ system_slot_name = iter; for ( ; (*iter != '/') && (*iter != ':') && (*iter != '\0') ; iter++); if(*iter == '\0'){ IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get system_slot_name failed) \n",node_desc); return 0; } if(*iter == ':'){ *iter = '\0'; iter++; for ( ; (*iter != '/') && (*iter != '\0') ; iter++); if(*iter == '\0'){ IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get board type failed) \n",node_desc); return 0; } } *iter = '\0'; iter++; node_index = iter; if(node_index[0] != 'U'){ IBND_DEBUG("fill_mellanox_chassis_record: Unsupported node description format:%s - (get node index) \n",node_desc); return 0; } /* set Chip number (node index) */ node->ch_anafanum = (unsigned char) atoi(&node_index[1]); if(node->ch_anafanum != 1){ IBND_DEBUG("Unexpected Chip number:%d \n",node->ch_anafanum); } /* set Line Spine numbers */ if(system_slot_name[0] == 'L') node->ch_slot = LINE_CS; else if(system_slot_name[0] == 'S') node->ch_slot = SPINE_CS; else{ IBND_DEBUG("fill_mellanox_chassis_record: Unsupported system_slot_name:%s \n",system_slot_name); return 0; } /* The switch will be displayed under Line or Spine and not under Chassis switches */ node->ch_found = 1; node->ch_slotnum = (unsigned char) atoi(&system_slot_name[1]); if((node->ch_slot == LINE_CS && (node->ch_slotnum > (LINES_MAX_NUM + 1))) || (node->ch_slot == SPINE_CS && (node->ch_slotnum > (SPINES_MAX_NUM + 1)))){ IBND_ERROR("fill_mellanox_chassis_record: invalid slot number:%d \n",node->ch_slotnum); node->ch_slotnum = 0; return 0; } /*set ch_type_str*/ strncpy(node->ch_type_str , system_type, sizeof(node->ch_type_str)-1); /* Line ports 1-18 are mapped to external ports 1-18*/ if(node->ch_slot == LINE_CS) { for (p = 1; p <= node->numports && p <= 18 ; p++) { port = node->ports[p]; if (!port) continue; port->ext_portnum = p; } } return 0; } static int insert_mellanox_line_and_spine(ibnd_node_t * node, ibnd_chassis_t * chassis) { if (node->ch_slot == LINE_CS){ if (chassis->linenode[node->ch_slotnum]) return 0; /* already filled slot */ chassis->linenode[node->ch_slotnum] = node; } else if (node->ch_slot == SPINE_CS){ if (chassis->spinenode[node->ch_slotnum]) return 0; /* already filled slot */ chassis->spinenode[node->ch_slotnum] = node; } else return 0; node->chassis = chassis; return 0; } /* forward declare this */ static void voltaire_portmap(ibnd_port_t * port); /* This function called for every Voltaire node in fabric It could be optimized so, but time overhead is very small and its only diag.util */ static int fill_voltaire_chassis_record(ibnd_node_t * node) { int p = 0; ibnd_port_t *port; ibnd_node_t *remnode = NULL; if (node->ch_found) /* somehow this node has already been passed */ return 0; node->ch_found = 1; /* node is router only in case of using unique lid */ /* (which is lid of chassis router port) */ /* in such case node->ports is actually a requested port... */ if (is_router(node)) /* find the remote node */ for (p = 1; p <= node->numports; p++) { port = node->ports[p]; if (port && is_spine(port->remoteport->node)) get_router_slot(node, port->remoteport); } else if (is_spine(node)) { int is_4700x2 = is_spine_4700x2(node); for (p = 1; p <= node->numports; p++) { port = node->ports[p]; if (!port || !port->remoteport) continue; /* * Skip ISR4700 double density fabric boards ports 19-36 * as they are chassis external ports */ if (is_4700x2 && (port->portnum > 18)) continue; remnode = port->remoteport->node; if (remnode->type != IB_NODE_SWITCH) { if (!remnode->ch_found) get_router_slot(remnode, port); continue; } if (!node->ch_type) /* we assume here that remoteport belongs to line */ get_sfb_slot(node, port->remoteport); /* we could break here, but need to find if more routers connected */ } } else if (is_line(node)) { int is_4700_line = is_line_4700(node); for (p = 1; p <= node->numports; p++) { port = node->ports[p]; if (!port || !port->remoteport) continue; if ((is_4700_line && (port->portnum > 18)) || (!is_4700_line && (port->portnum > 12))) continue; /* we assume here that remoteport belongs to spine */ get_slb_slot(node, port->remoteport); break; } } /* for each port of this node, map external ports */ for (p = 1; p <= node->numports; p++) { port = node->ports[p]; if (!port) continue; voltaire_portmap(port); } return 0; } static int get_line_index(ibnd_node_t * node) { int retval; if (is_line_4700(node)) retval = node->ch_slotnum; else retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum; if (retval > LINES_MAX_NUM || retval < 1) { printf("%s: retval = %d\n", __FUNCTION__, retval); IBND_ERROR("Internal error\n"); return -1; } return retval; } static int get_spine_index(ibnd_node_t * node) { int retval; if (is_spine_9288(node) || is_spine_2012(node)) retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum; else if (is_spine_4700(node) || is_spine_4700x2(node)) retval = 2 * (node->ch_slotnum - 1) + node->ch_anafanum; else retval = node->ch_slotnum; if (retval > SPINES_MAX_NUM || retval < 1) { IBND_ERROR("Internal error\n"); return -1; } return retval; } static int insert_line_router(ibnd_node_t * node, ibnd_chassis_t * chassis) { int i = get_line_index(node); if (i < 0) return i; if (chassis->linenode[i]) return 0; /* already filled slot */ chassis->linenode[i] = node; node->chassis = chassis; return 0; } static int insert_spine(ibnd_node_t * node, ibnd_chassis_t * chassis) { int i = get_spine_index(node); if (i < 0) return i; if (chassis->spinenode[i]) return 0; /* already filled slot */ chassis->spinenode[i] = node; node->chassis = chassis; return 0; } static int pass_on_lines_catch_spines(ibnd_chassis_t * chassis) { ibnd_node_t *node, *remnode; ibnd_port_t *port; int i, p; for (i = 1; i <= LINES_MAX_NUM; i++) { int is_4700_line; node = chassis->linenode[i]; if (!(node && is_line(node))) continue; /* empty slot or router */ is_4700_line = is_line_4700(node); for (p = 1; p <= node->numports; p++) { port = node->ports[p]; if (!port || !port->remoteport) continue; if ((is_4700_line && (port->portnum > 18)) || (!is_4700_line && (port->portnum > 12))) continue; remnode = port->remoteport->node; if (!remnode->ch_found) continue; /* some error - spine not initialized ? FIXME */ if (insert_spine(remnode, chassis)) return -1; } } return 0; } static int pass_on_spines_catch_lines(ibnd_chassis_t * chassis) { ibnd_node_t *node, *remnode; ibnd_port_t *port; int i, p; for (i = 1; i <= SPINES_MAX_NUM; i++) { int is_4700x2; node = chassis->spinenode[i]; if (!node) continue; /* empty slot */ is_4700x2 = is_spine_4700x2(node); for (p = 1; p <= node->numports; p++) { port = node->ports[p]; if (!port || !port->remoteport) continue; /* * ISR4700 double density fabric board ports 19-36 are * chassis external ports, so skip them */ if (is_4700x2 && (port->portnum > 18)) continue; remnode = port->remoteport->node; if (!remnode->ch_found) continue; /* some error - line/router not initialized ? FIXME */ if (insert_line_router(remnode, chassis)) return -1; } } return 0; } /* Stupid interpolation algorithm... But nothing to do - have to be compliant with VoltaireSM/NMS */ static void pass_on_spines_interpolate_chguid(ibnd_chassis_t * chassis) { ibnd_node_t *node; int i; for (i = 1; i <= SPINES_MAX_NUM; i++) { node = chassis->spinenode[i]; if (!node) continue; /* skip the empty slots */ /* take first guid minus one to be consistent with SM */ chassis->chassisguid = node->guid - 1; break; } } /* This function fills chassis structure with all nodes in that chassis chassis structure = structure of one standalone chassis */ static int build_chassis(ibnd_node_t * node, ibnd_chassis_t * chassis) { int p = 0; ibnd_node_t *remnode = NULL; ibnd_port_t *port = NULL; /* we get here with node = chassis_spine */ if (insert_spine(node, chassis)) return -1; /* loop: pass on all ports of node */ for (p = 1; p <= node->numports; p++) { port = node->ports[p]; if (!port || !port->remoteport) continue; /* * ISR4700 double density fabric board ports 19-36 are * chassis external ports, so skip them */ if (is_spine_4700x2(node) && (port->portnum > 18)) continue; remnode = port->remoteport->node; if (!remnode->ch_found) continue; /* some error - line or router not initialized ? FIXME */ insert_line_router(remnode, chassis); } if (pass_on_lines_catch_spines(chassis)) return -1; /* this pass needed for to catch routers, since routers connected only */ /* to spines in slot 1 or 4 and we could miss them first time */ if (pass_on_spines_catch_lines(chassis)) return -1; /* additional 2 passes needed for to overcome a problem of pure "in-chassis" */ /* connectivity - extra pass to ensure that all related chips/modules */ /* inserted into the chassis */ if (pass_on_lines_catch_spines(chassis)) return -1; if (pass_on_spines_catch_lines(chassis)) return -1; pass_on_spines_interpolate_chguid(chassis); return 0; } /*========================================================*/ /* INTERNAL TO EXTERNAL PORT MAPPING */ /*========================================================*/ /* Description : On ISR9288/9096 external ports indexing is not matching the internal ( anafa ) port indexes. Use this MAP to translate the data you get from the OpenIB diagnostics (smpquery, ibroute, ibtracert, etc.) Module : sLB-24 anafa 1 anafa 2 ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24 int port | 22 23 24 18 17 16 | 22 23 24 18 17 16 ext port | 1 2 3 4 5 6 | 7 8 9 10 11 12 int port | 19 20 21 15 14 13 | 19 20 21 15 14 13 ------------------------------------------------ Module : sLB-8 anafa 1 anafa 2 ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24 int port | 24 23 22 18 17 16 | 24 23 22 18 17 16 ext port | 1 2 3 4 5 6 | 7 8 9 10 11 12 int port | 21 20 19 15 14 13 | 21 20 19 15 14 13 -----------> anafa 1 anafa 2 ext port | - - 5 - - 6 | - - 7 - - 8 int port | 24 23 22 18 17 16 | 24 23 22 18 17 16 ext port | - - 1 - - 2 | - - 3 - - 4 int port | 21 20 19 15 14 13 | 21 20 19 15 14 13 ------------------------------------------------ Module : sLB-2024 ext port | 13 14 15 16 17 18 19 20 21 22 23 24 A1 int port| 13 14 15 16 17 18 19 20 21 22 23 24 ext port | 1 2 3 4 5 6 7 8 9 10 11 12 A2 int port| 13 14 15 16 17 18 19 20 21 22 23 24 --------------------------------------------------- Module : sLB-4018 int port | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 ext port | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 --------------------------------------------------- Module : sFB-4700X2 12X port -> 3 x 4X ports: A1 int port | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 ext port | 7 7 7 8 8 8 9 9 9 10 10 10 11 11 11 12 12 12 A2 int port | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 ext port | 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 */ static int int2ext_map_slb24[2][25] = { {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}, {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} }; static int int2ext_map_slb8[2][25] = { {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}, {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} }; static int int2ext_map_slb2024[2][25] = { {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}, {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} }; static int int2ext_map_slb4018[37] = { 0, 0, 0, 0, 0, 0, 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, 13, 14, 15, 16, 17, 18 }; static int int2ext_map_sfb4700x2[2][37] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6} }; /* 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 }; */ /* map internal ports to external ports if appropriate */ static void voltaire_portmap(ibnd_port_t * port) { int portnum = port->portnum; int chipnum = 0; ibnd_node_t *node = port->node; int is_4700_line = is_line_4700(node); int is_4700x2_spine = is_spine_4700x2(node); if (!node->ch_found || (!is_line(node) && !is_4700x2_spine)) { port->ext_portnum = 0; return; } if (((is_4700_line || is_4700x2_spine) && (portnum < 19 || portnum > 36)) || ((!is_4700_line && !is_4700x2_spine) && (portnum < 13 || portnum > 24))) { port->ext_portnum = 0; return; } if (port->node->ch_anafanum < 1 || port->node->ch_anafanum > 2) { port->ext_portnum = 0; return; } chipnum = port->node->ch_anafanum - 1; if (is_line_24(node)) port->ext_portnum = int2ext_map_slb24[chipnum][portnum]; else if (is_line_2024(node)) port->ext_portnum = int2ext_map_slb2024[chipnum][portnum]; /* sLB-4018: Only one asic per LB */ else if (is_4700_line) port->ext_portnum = int2ext_map_slb4018[portnum]; /* sFB-4700X2 4X port */ else if (is_4700x2_spine) port->ext_portnum = int2ext_map_sfb4700x2[chipnum][portnum]; else port->ext_portnum = int2ext_map_slb8[chipnum][portnum]; } static int add_chassis(chassis_scan_t * chassis_scan) { if (!(chassis_scan->current_chassis = calloc(1, sizeof(ibnd_chassis_t)))) { IBND_ERROR("OOM: failed to allocate chassis object\n"); return -1; } if (chassis_scan->first_chassis == NULL) { chassis_scan->first_chassis = chassis_scan->current_chassis; chassis_scan->last_chassis = chassis_scan->current_chassis; } else { chassis_scan->last_chassis->next = chassis_scan->current_chassis; chassis_scan->last_chassis = chassis_scan->current_chassis; } return 0; } static void add_node_to_chassis(ibnd_chassis_t * chassis, ibnd_node_t * node) { node->chassis = chassis; node->next_chassis_node = chassis->nodes; chassis->nodes = node; } /* Main grouping function Algorithm: 1. pass on every Voltaire node 2. catch spine chip for every Voltaire node 2.1 build/interpolate chassis around this chip 2.2 go to 1. 3. pass on non Voltaire nodes (SystemImageGUID based grouping) 4. now group non Voltaire nodes by SystemImageGUID Returns: 0 on success, -1 on failure */ int group_nodes(ibnd_fabric_t * fabric) { ibnd_node_t *node; int chassisnum = 0; ibnd_chassis_t *chassis; ibnd_chassis_t *ch, *ch_next; chassis_scan_t chassis_scan; int vendor_id; chassis_scan.first_chassis = NULL; chassis_scan.current_chassis = NULL; chassis_scan.last_chassis = NULL; /* first pass on switches and build for every Voltaire node */ /* an appropriate chassis record (slotnum and position) */ /* according to internal connectivity */ /* not very efficient but clear code so... */ for (node = fabric->switches; node; node = node->type_next) { vendor_id = mad_get_field(node->info, 0,IB_NODE_VENDORID_F); if (vendor_id == VTR_VENDOR_ID && fill_voltaire_chassis_record(node)) goto cleanup; else if (vendor_id == MLX_VENDOR_ID && fill_mellanox_chassis_record(node)) goto cleanup; } /* separate every Voltaire chassis from each other and build linked list of them */ /* algorithm: catch spine and find all surrounding nodes */ for (node = fabric->switches; node; node = node->type_next) { if (mad_get_field(node->info, 0, IB_NODE_VENDORID_F) != VTR_VENDOR_ID) continue; if (!node->ch_found || (node->chassis && node->chassis->chassisnum) || !is_spine(node)) continue; if (add_chassis(&chassis_scan)) goto cleanup; chassis_scan.current_chassis->chassisnum = ++chassisnum; if (build_chassis(node, chassis_scan.current_chassis)) goto cleanup; } /* now make pass on nodes for chassis which are not Voltaire */ /* grouped by common SystemImageGUID */ for (node = fabric->nodes; node; node = node->next) { if (mad_get_field(node->info, 0, IB_NODE_VENDORID_F) == VTR_VENDOR_ID) continue; if (mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F)) { chassis = find_chassisguid(fabric, node); if (chassis) chassis->nodecount++; else { /* Possible new chassis */ if (add_chassis(&chassis_scan)) goto cleanup; chassis_scan.current_chassis->chassisguid = get_chassisguid(node); chassis_scan.current_chassis->nodecount = 1; if (!fabric->chassis) fabric->chassis = chassis_scan.first_chassis; } } } /* now, make another pass to see which nodes are part of chassis */ /* (defined as chassis->nodecount > 1) */ for (node = fabric->nodes; node; node = node->next) { vendor_id = mad_get_field(node->info, 0,IB_NODE_VENDORID_F); if (vendor_id == VTR_VENDOR_ID) continue; if (mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F)) { chassis = find_chassisguid(fabric, node); if (chassis && chassis->nodecount > 1) { if (!chassis->chassisnum) chassis->chassisnum = ++chassisnum; if (!node->ch_found) { node->ch_found = 1; add_node_to_chassis(chassis, node); } else if (vendor_id == MLX_VENDOR_ID){ insert_mellanox_line_and_spine(node, chassis); } } } } fabric->chassis = chassis_scan.first_chassis; return 0; cleanup: ch = chassis_scan.first_chassis; while (ch) { ch_next = ch->next; free(ch); ch = ch_next; } fabric->chassis = NULL; return -1; }