1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3219820Sjeff * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. 4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5219820Sjeff * 6219820Sjeff * This software is available to you under a choice of one of two 7219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 8219820Sjeff * General Public License (GPL) Version 2, available from the file 9219820Sjeff * COPYING in the main directory of this source tree, or the 10219820Sjeff * OpenIB.org BSD license below: 11219820Sjeff * 12219820Sjeff * Redistribution and use in source and binary forms, with or 13219820Sjeff * without modification, are permitted provided that the following 14219820Sjeff * conditions are met: 15219820Sjeff * 16219820Sjeff * - Redistributions of source code must retain the above 17219820Sjeff * copyright notice, this list of conditions and the following 18219820Sjeff * disclaimer. 19219820Sjeff * 20219820Sjeff * - Redistributions in binary form must reproduce the above 21219820Sjeff * copyright notice, this list of conditions and the following 22219820Sjeff * disclaimer in the documentation and/or other materials 23219820Sjeff * provided with the distribution. 24219820Sjeff * 25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32219820Sjeff * SOFTWARE. 33219820Sjeff * 34219820Sjeff */ 35219820Sjeff 36219820Sjeff/* 37219820Sjeff * Abstract: 38219820Sjeff * Implementation of osm_physp_t. 39219820Sjeff * This object represents an Infiniband Port. 40219820Sjeff * This object is part of the opensm family of objects. 41219820Sjeff */ 42219820Sjeff 43219820Sjeff#if HAVE_CONFIG_H 44219820Sjeff# include <config.h> 45219820Sjeff#endif /* HAVE_CONFIG_H */ 46219820Sjeff 47219820Sjeff#include <stdlib.h> 48219820Sjeff#include <string.h> 49219820Sjeff#include <complib/cl_debug.h> 50219820Sjeff#include <iba/ib_types.h> 51219820Sjeff#include <opensm/osm_port.h> 52219820Sjeff#include <opensm/osm_node.h> 53219820Sjeff#include <opensm/osm_madw.h> 54219820Sjeff#include <opensm/osm_mcm_info.h> 55219820Sjeff#include <opensm/osm_switch.h> 56219820Sjeff 57219820Sjeff/********************************************************************** 58219820Sjeff **********************************************************************/ 59219820Sjeffvoid osm_physp_construct(IN osm_physp_t * const p_physp) 60219820Sjeff{ 61219820Sjeff memset(p_physp, 0, sizeof(*p_physp)); 62219820Sjeff osm_dr_path_construct(&p_physp->dr_path); 63219820Sjeff cl_ptr_vector_construct(&p_physp->slvl_by_port); 64219820Sjeff osm_pkey_tbl_construct(&p_physp->pkeys); 65219820Sjeff} 66219820Sjeff 67219820Sjeff/********************************************************************** 68219820Sjeff **********************************************************************/ 69219820Sjeffvoid osm_physp_destroy(IN osm_physp_t * const p_physp) 70219820Sjeff{ 71219820Sjeff size_t num_slvl, i; 72219820Sjeff 73219820Sjeff /* the physp might be uninitialized */ 74219820Sjeff if (p_physp->port_guid) { 75219820Sjeff /* free the SL2VL Tables */ 76219820Sjeff num_slvl = cl_ptr_vector_get_size(&p_physp->slvl_by_port); 77219820Sjeff for (i = 0; i < num_slvl; i++) 78219820Sjeff free(cl_ptr_vector_get(&p_physp->slvl_by_port, i)); 79219820Sjeff cl_ptr_vector_destroy(&p_physp->slvl_by_port); 80219820Sjeff 81219820Sjeff /* free the P_Key Tables */ 82219820Sjeff osm_pkey_tbl_destroy(&p_physp->pkeys); 83219820Sjeff 84219820Sjeff memset(p_physp, 0, sizeof(*p_physp)); 85219820Sjeff osm_dr_path_construct(&p_physp->dr_path); /* clear dr_path */ 86219820Sjeff } 87219820Sjeff} 88219820Sjeff 89219820Sjeff/********************************************************************** 90219820Sjeff **********************************************************************/ 91219820Sjeffvoid 92219820Sjeffosm_physp_init(IN osm_physp_t * const p_physp, 93219820Sjeff IN const ib_net64_t port_guid, 94219820Sjeff IN const uint8_t port_num, 95219820Sjeff IN const struct osm_node *const p_node, 96219820Sjeff IN const osm_bind_handle_t h_bind, 97219820Sjeff IN const uint8_t hop_count, 98219820Sjeff IN const uint8_t * const p_initial_path) 99219820Sjeff{ 100219820Sjeff uint16_t num_slvl, i; 101219820Sjeff ib_slvl_table_t *p_slvl; 102219820Sjeff 103219820Sjeff CL_ASSERT(p_node); 104219820Sjeff 105219820Sjeff osm_physp_construct(p_physp); 106219820Sjeff p_physp->port_guid = port_guid; 107219820Sjeff p_physp->port_num = port_num; 108219820Sjeff p_physp->healthy = TRUE; 109219820Sjeff p_physp->need_update = 2; 110219820Sjeff p_physp->p_node = (struct osm_node *)p_node; 111219820Sjeff 112219820Sjeff osm_dr_path_init(&p_physp->dr_path, h_bind, hop_count, p_initial_path); 113219820Sjeff 114219820Sjeff /* allocate enough SL2VL tables */ 115219820Sjeff if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH) 116219820Sjeff /* we need node num ports + 1 SL2VL tables */ 117219820Sjeff num_slvl = osm_node_get_num_physp(p_node) + 1; 118219820Sjeff else 119219820Sjeff /* An end node - we need only one SL2VL */ 120219820Sjeff num_slvl = 1; 121219820Sjeff 122219820Sjeff cl_ptr_vector_init(&p_physp->slvl_by_port, num_slvl, 1); 123219820Sjeff for (i = 0; i < num_slvl; i++) { 124219820Sjeff p_slvl = (ib_slvl_table_t *) malloc(sizeof(ib_slvl_table_t)); 125219820Sjeff if (!p_slvl) 126219820Sjeff break; 127219820Sjeff memset(p_slvl, 0, sizeof(ib_slvl_table_t)); 128219820Sjeff cl_ptr_vector_set(&p_physp->slvl_by_port, i, p_slvl); 129219820Sjeff } 130219820Sjeff 131219820Sjeff /* initialize the pkey table */ 132219820Sjeff osm_pkey_tbl_init(&p_physp->pkeys); 133219820Sjeff} 134219820Sjeff 135219820Sjeff/********************************************************************** 136219820Sjeff **********************************************************************/ 137219820Sjeffvoid osm_port_delete(IN OUT osm_port_t ** const pp_port) 138219820Sjeff{ 139219820Sjeff /* cleanup all mcm recs attached */ 140219820Sjeff osm_port_remove_all_mgrp(*pp_port); 141219820Sjeff free(*pp_port); 142219820Sjeff *pp_port = NULL; 143219820Sjeff} 144219820Sjeff 145219820Sjeff/********************************************************************** 146219820Sjeff **********************************************************************/ 147219820Sjeffstatic void 148219820Sjeffosm_port_init(IN osm_port_t * const p_port, 149219820Sjeff IN const ib_node_info_t * p_ni, 150219820Sjeff IN osm_node_t * const p_parent_node) 151219820Sjeff{ 152219820Sjeff ib_net64_t port_guid; 153219820Sjeff osm_physp_t *p_physp; 154219820Sjeff uint8_t port_num; 155219820Sjeff 156219820Sjeff CL_ASSERT(p_port); 157219820Sjeff CL_ASSERT(p_ni); 158219820Sjeff CL_ASSERT(p_parent_node); 159219820Sjeff 160219820Sjeff memset(p_port, 0, sizeof(*p_port)); 161219820Sjeff cl_qlist_init(&p_port->mcm_list); 162219820Sjeff p_port->p_node = (struct osm_node *)p_parent_node; 163219820Sjeff port_guid = p_ni->port_guid; 164219820Sjeff p_port->guid = port_guid; 165219820Sjeff port_num = p_ni->node_type == IB_NODE_TYPE_SWITCH ? 166219820Sjeff 0 : ib_node_info_get_local_port_num(p_ni); 167219820Sjeff 168219820Sjeff /* 169219820Sjeff Get the pointers to the physical node objects "owned" by this 170219820Sjeff logical port GUID. 171219820Sjeff For switches, port '0' is owned; for HCA's and routers, 172219820Sjeff only the singular part that has this GUID is owned. 173219820Sjeff */ 174219820Sjeff p_physp = osm_node_get_physp_ptr(p_parent_node, port_num); 175219820Sjeff CL_ASSERT(port_guid == osm_physp_get_port_guid(p_physp)); 176219820Sjeff p_port->p_physp = p_physp; 177219820Sjeff} 178219820Sjeff 179219820Sjeff/********************************************************************** 180219820Sjeff **********************************************************************/ 181219820Sjeffosm_port_t *osm_port_new(IN const ib_node_info_t * p_ni, 182219820Sjeff IN osm_node_t * const p_parent_node) 183219820Sjeff{ 184219820Sjeff osm_port_t *p_port; 185219820Sjeff 186219820Sjeff p_port = malloc(sizeof(*p_port)); 187219820Sjeff if (p_port != NULL) { 188219820Sjeff memset(p_port, 0, sizeof(*p_port)); 189219820Sjeff osm_port_init(p_port, p_ni, p_parent_node); 190219820Sjeff } 191219820Sjeff 192219820Sjeff return (p_port); 193219820Sjeff} 194219820Sjeff 195219820Sjeff/********************************************************************** 196219820Sjeff **********************************************************************/ 197219820Sjeffvoid 198219820Sjeffosm_port_get_lid_range_ho(IN const osm_port_t * const p_port, 199219820Sjeff IN uint16_t * const p_min_lid, 200219820Sjeff IN uint16_t * const p_max_lid) 201219820Sjeff{ 202219820Sjeff uint8_t lmc; 203219820Sjeff 204219820Sjeff *p_min_lid = cl_ntoh16(osm_port_get_base_lid(p_port)); 205219820Sjeff lmc = osm_port_get_lmc(p_port); 206219820Sjeff *p_max_lid = (uint16_t) (*p_min_lid + (1 << lmc) - 1); 207219820Sjeff} 208219820Sjeff 209219820Sjeff/********************************************************************** 210219820Sjeff **********************************************************************/ 211219820Sjeffib_api_status_t 212219820Sjeffosm_get_port_by_base_lid(IN const osm_subn_t * const p_subn, 213219820Sjeff IN const ib_net16_t lid, 214219820Sjeff IN OUT const osm_port_t ** const pp_port) 215219820Sjeff{ 216219820Sjeff ib_api_status_t status; 217219820Sjeff uint16_t base_lid; 218219820Sjeff uint8_t lmc; 219219820Sjeff 220219820Sjeff *pp_port = NULL; 221219820Sjeff 222219820Sjeff /* Loop on lmc from 0 up through max LMC possible */ 223219820Sjeff for (lmc = 0; lmc <= IB_PORT_LMC_MAX; lmc++) { 224219820Sjeff /* Calculate a base LID assuming this is the real LMC */ 225219820Sjeff base_lid = cl_ntoh16(lid) & ~((1 << lmc) - 1); 226219820Sjeff 227219820Sjeff /* Look for a match */ 228219820Sjeff status = cl_ptr_vector_at(&p_subn->port_lid_tbl, 229219820Sjeff base_lid, (void **)pp_port); 230219820Sjeff if ((status == CL_SUCCESS) && (*pp_port != NULL)) { 231219820Sjeff /* Determine if base LID "tested" is the real base LID */ 232219820Sjeff /* This is true if the LMC "tested" is the port's actual LMC */ 233219820Sjeff if (lmc == osm_port_get_lmc(*pp_port)) { 234219820Sjeff status = IB_SUCCESS; 235219820Sjeff goto Found; 236219820Sjeff } 237219820Sjeff } 238219820Sjeff } 239219820Sjeff *pp_port = NULL; 240219820Sjeff status = IB_NOT_FOUND; 241219820Sjeff 242219820SjeffFound: 243219820Sjeff return status; 244219820Sjeff} 245219820Sjeff 246219820Sjeff/********************************************************************** 247219820Sjeff **********************************************************************/ 248219820Sjeffib_api_status_t 249219820Sjeffosm_port_add_mgrp(IN osm_port_t * const p_port, IN const ib_net16_t mlid) 250219820Sjeff{ 251219820Sjeff ib_api_status_t status = IB_SUCCESS; 252219820Sjeff osm_mcm_info_t *p_mcm; 253219820Sjeff 254219820Sjeff p_mcm = osm_mcm_info_new(mlid); 255219820Sjeff if (p_mcm) 256219820Sjeff cl_qlist_insert_tail(&p_port->mcm_list, 257219820Sjeff (cl_list_item_t *) p_mcm); 258219820Sjeff else 259219820Sjeff status = IB_INSUFFICIENT_MEMORY; 260219820Sjeff 261219820Sjeff return (status); 262219820Sjeff} 263219820Sjeff 264219820Sjeff/********************************************************************** 265219820Sjeff **********************************************************************/ 266219820Sjeffstatic cl_status_t 267219820Sjeff__osm_port_mgrp_find_func(IN const cl_list_item_t * const p_list_item, 268219820Sjeff IN void *context) 269219820Sjeff{ 270219820Sjeff if (*((ib_net16_t *) context) == ((osm_mcm_info_t *) p_list_item)->mlid) 271219820Sjeff return (CL_SUCCESS); 272219820Sjeff else 273219820Sjeff return (CL_NOT_FOUND); 274219820Sjeff} 275219820Sjeff 276219820Sjeff/********************************************************************** 277219820Sjeff **********************************************************************/ 278219820Sjeffvoid 279219820Sjeffosm_port_remove_mgrp(IN osm_port_t * const p_port, IN const ib_net16_t mlid) 280219820Sjeff{ 281219820Sjeff cl_list_item_t *p_mcm; 282219820Sjeff 283219820Sjeff p_mcm = cl_qlist_find_from_head(&p_port->mcm_list, 284219820Sjeff __osm_port_mgrp_find_func, &mlid); 285219820Sjeff 286219820Sjeff if (p_mcm != cl_qlist_end(&p_port->mcm_list)) { 287219820Sjeff cl_qlist_remove_item(&p_port->mcm_list, p_mcm); 288219820Sjeff osm_mcm_info_delete((osm_mcm_info_t *) p_mcm); 289219820Sjeff } 290219820Sjeff} 291219820Sjeff 292219820Sjeff/********************************************************************** 293219820Sjeff **********************************************************************/ 294219820Sjeffvoid osm_port_remove_all_mgrp(IN osm_port_t * const p_port) 295219820Sjeff{ 296219820Sjeff cl_list_item_t *p_mcm; 297219820Sjeff 298219820Sjeff p_mcm = cl_qlist_remove_head(&p_port->mcm_list); 299219820Sjeff while (p_mcm != cl_qlist_end(&p_port->mcm_list)) { 300219820Sjeff osm_mcm_info_delete((osm_mcm_info_t *) p_mcm); 301219820Sjeff p_mcm = cl_qlist_remove_head(&p_port->mcm_list); 302219820Sjeff } 303219820Sjeff} 304219820Sjeff 305219820Sjeff/********************************************************************** 306219820Sjeff **********************************************************************/ 307219820Sjeffuint8_t 308219820Sjeffosm_physp_calc_link_mtu(IN osm_log_t * p_log, IN const osm_physp_t * p_physp) 309219820Sjeff{ 310219820Sjeff const osm_physp_t *p_remote_physp; 311219820Sjeff uint8_t mtu; 312219820Sjeff uint8_t remote_mtu; 313219820Sjeff 314219820Sjeff OSM_LOG_ENTER(p_log); 315219820Sjeff 316219820Sjeff p_remote_physp = osm_physp_get_remote(p_physp); 317219820Sjeff if (p_remote_physp) { 318219820Sjeff /* use the available MTU */ 319219820Sjeff mtu = ib_port_info_get_mtu_cap(&p_physp->port_info); 320219820Sjeff 321219820Sjeff remote_mtu = 322219820Sjeff ib_port_info_get_mtu_cap(&p_remote_physp->port_info); 323219820Sjeff 324219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, 325219820Sjeff "Remote port 0x%016" PRIx64 " port = %u : " 326219820Sjeff "MTU = %u. This Port MTU: %u\n", 327219820Sjeff cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)), 328219820Sjeff osm_physp_get_port_num(p_remote_physp), 329219820Sjeff remote_mtu, mtu); 330219820Sjeff 331219820Sjeff if (mtu != remote_mtu) { 332219820Sjeff if (mtu > remote_mtu) 333219820Sjeff mtu = remote_mtu; 334219820Sjeff 335219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, 336219820Sjeff "MTU mismatch between ports." 337219820Sjeff "\n\t\t\t\tPort 0x%016" PRIx64 ", port %u" 338219820Sjeff " and port 0x%016" PRIx64 ", port %u." 339219820Sjeff "\n\t\t\t\tUsing lower MTU of %u\n", 340219820Sjeff cl_ntoh64(osm_physp_get_port_guid(p_physp)), 341219820Sjeff osm_physp_get_port_num(p_physp), 342219820Sjeff cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)), 343219820Sjeff osm_physp_get_port_num(p_remote_physp),mtu); 344219820Sjeff } 345219820Sjeff } else 346219820Sjeff mtu = ib_port_info_get_neighbor_mtu(&p_physp->port_info); 347219820Sjeff 348219820Sjeff if (mtu == 0) { 349219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, "ERR 4101: " 350219820Sjeff "Invalid MTU = 0. Forcing correction to 256\n"); 351219820Sjeff mtu = 1; 352219820Sjeff } 353219820Sjeff 354219820Sjeff OSM_LOG_EXIT(p_log); 355219820Sjeff return (mtu); 356219820Sjeff} 357219820Sjeff 358219820Sjeff/********************************************************************** 359219820Sjeff **********************************************************************/ 360219820Sjeffuint8_t 361219820Sjeffosm_physp_calc_link_op_vls(IN osm_log_t * p_log, 362219820Sjeff IN const osm_subn_t * p_subn, 363219820Sjeff IN const osm_physp_t * p_physp) 364219820Sjeff{ 365219820Sjeff const osm_physp_t *p_remote_physp; 366219820Sjeff uint8_t op_vls; 367219820Sjeff uint8_t remote_op_vls; 368219820Sjeff 369219820Sjeff OSM_LOG_ENTER(p_log); 370219820Sjeff 371219820Sjeff p_remote_physp = osm_physp_get_remote(p_physp); 372219820Sjeff if (p_remote_physp) { 373219820Sjeff /* use the available VLCap */ 374219820Sjeff op_vls = ib_port_info_get_vl_cap(&p_physp->port_info); 375219820Sjeff 376219820Sjeff remote_op_vls = 377219820Sjeff ib_port_info_get_vl_cap(&p_remote_physp->port_info); 378219820Sjeff 379219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, 380219820Sjeff "Remote port 0x%016" PRIx64 " port = 0x%X : " 381219820Sjeff "VL_CAP = %u. This port VL_CAP = %u\n", 382219820Sjeff cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)), 383219820Sjeff osm_physp_get_port_num(p_remote_physp), 384219820Sjeff remote_op_vls, op_vls); 385219820Sjeff 386219820Sjeff if (op_vls != remote_op_vls) { 387219820Sjeff if (op_vls > remote_op_vls) 388219820Sjeff op_vls = remote_op_vls; 389219820Sjeff 390219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, 391219820Sjeff "OP_VLS mismatch between ports." 392219820Sjeff "\n\t\t\t\tPort 0x%016" PRIx64 ", port 0x%X" 393219820Sjeff " and port 0x%016" PRIx64 ", port 0x%X." 394219820Sjeff "\n\t\t\t\tUsing lower OP_VLS of %u\n", 395219820Sjeff cl_ntoh64(osm_physp_get_port_guid(p_physp)), 396219820Sjeff osm_physp_get_port_num(p_physp), 397219820Sjeff cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)), 398219820Sjeff osm_physp_get_port_num(p_remote_physp), op_vls); 399219820Sjeff } 400219820Sjeff } else 401219820Sjeff op_vls = ib_port_info_get_op_vls(&p_physp->port_info); 402219820Sjeff 403219820Sjeff /* support user limitation of max_op_vls */ 404219820Sjeff if (op_vls > p_subn->opt.max_op_vls) 405219820Sjeff op_vls = p_subn->opt.max_op_vls; 406219820Sjeff 407219820Sjeff if (op_vls == 0) { 408219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, "ERR 4102: " 409219820Sjeff "Invalid OP_VLS = 0. Forcing correction to 1 (VL0)\n"); 410219820Sjeff op_vls = 1; 411219820Sjeff } 412219820Sjeff 413219820Sjeff OSM_LOG_EXIT(p_log); 414219820Sjeff return (op_vls); 415219820Sjeff} 416219820Sjeff 417219820Sjeffstatic inline uint64_t __osm_ptr_to_key(void const *p) 418219820Sjeff{ 419219820Sjeff uint64_t k = 0; 420219820Sjeff 421219820Sjeff memcpy(&k, p, sizeof(void *)); 422219820Sjeff return k; 423219820Sjeff} 424219820Sjeff 425219820Sjeffstatic inline void *__osm_key_to_ptr(uint64_t k) 426219820Sjeff{ 427219820Sjeff void *p = 0; 428219820Sjeff 429219820Sjeff memcpy(&p, &k, sizeof(void *)); 430219820Sjeff return p; 431219820Sjeff} 432219820Sjeff 433219820Sjeff/********************************************************************** 434219820Sjeff Traverse the fabric from the SM node following the DR path given and 435219820Sjeff add every phys port traversed to the map. Avoid tracking the first and 436219820Sjeff last phys ports (going into the first switch and into the target port). 437219820Sjeff **********************************************************************/ 438219820Sjeffstatic cl_status_t 439219820Sjeff__osm_physp_get_dr_physp_set(IN osm_log_t * p_log, 440219820Sjeff IN osm_subn_t const *p_subn, 441219820Sjeff IN osm_dr_path_t const *p_path, 442219820Sjeff OUT cl_map_t * p_physp_map) 443219820Sjeff{ 444219820Sjeff osm_port_t *p_port; 445219820Sjeff osm_physp_t *p_physp; 446219820Sjeff osm_node_t *p_node; 447219820Sjeff uint8_t hop; 448219820Sjeff cl_status_t status = CL_SUCCESS; 449219820Sjeff 450219820Sjeff OSM_LOG_ENTER(p_log); 451219820Sjeff 452219820Sjeff /* find the OSM node */ 453219820Sjeff p_port = osm_get_port_by_guid(p_subn, p_subn->sm_port_guid); 454219820Sjeff if (!p_port) { 455219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4103: " 456219820Sjeff "Failed to find the SM own port by guid\n"); 457219820Sjeff status = CL_ERROR; 458219820Sjeff goto Exit; 459219820Sjeff } 460219820Sjeff 461219820Sjeff /* get the node of the SM */ 462219820Sjeff p_node = p_port->p_node; 463219820Sjeff 464219820Sjeff /* 465219820Sjeff traverse the path adding the nodes to the table 466219820Sjeff start after the first dummy hop and stop just before the 467219820Sjeff last one 468219820Sjeff */ 469219820Sjeff for (hop = 1; hop < p_path->hop_count - 1; hop++) { 470219820Sjeff /* go out using the phys port of the path */ 471219820Sjeff p_physp = osm_node_get_physp_ptr(p_node, p_path->path[hop]); 472219820Sjeff 473219820Sjeff /* make sure we got a valid port and it has a remote port */ 474219820Sjeff if (!p_physp) { 475219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4104: " 476219820Sjeff "DR Traversal stopped on invalid port at hop:%u\n", 477219820Sjeff hop); 478219820Sjeff status = CL_ERROR; 479219820Sjeff goto Exit; 480219820Sjeff } 481219820Sjeff 482219820Sjeff /* we track the ports we go out along the path */ 483219820Sjeff if (hop > 1) 484219820Sjeff cl_map_insert(p_physp_map, __osm_ptr_to_key(p_physp), 485219820Sjeff NULL); 486219820Sjeff 487219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, 488219820Sjeff "Traversed through node: 0x%016" PRIx64 489219820Sjeff " port:%u\n", 490219820Sjeff cl_ntoh64(p_node->node_info.node_guid), 491219820Sjeff p_path->path[hop]); 492219820Sjeff 493219820Sjeff if (!(p_physp = osm_physp_get_remote(p_physp))) { 494219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4106: " 495219820Sjeff "DR Traversal stopped on missing remote physp at hop:%u\n", 496219820Sjeff hop); 497219820Sjeff status = CL_ERROR; 498219820Sjeff goto Exit; 499219820Sjeff } 500219820Sjeff 501219820Sjeff p_node = osm_physp_get_node_ptr(p_physp); 502219820Sjeff } 503219820Sjeff 504219820SjeffExit: 505219820Sjeff OSM_LOG_EXIT(p_log); 506219820Sjeff return status; 507219820Sjeff} 508219820Sjeff 509219820Sjeff/********************************************************************** 510219820Sjeff **********************************************************************/ 511219820Sjeffstatic void 512219820Sjeff__osm_physp_update_new_dr_path(IN osm_physp_t const *p_dest_physp, 513219820Sjeff IN cl_map_t * p_visited_map, 514219820Sjeff IN osm_bind_handle_t * h_bind) 515219820Sjeff{ 516219820Sjeff cl_list_t tmpPortsList; 517219820Sjeff osm_physp_t *p_physp, *p_src_physp = NULL; 518219820Sjeff uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX]; 519219820Sjeff uint8_t i = 0; 520219820Sjeff osm_dr_path_t *p_dr_path; 521219820Sjeff 522219820Sjeff cl_list_construct(&tmpPortsList); 523219820Sjeff cl_list_init(&tmpPortsList, 10); 524219820Sjeff 525219820Sjeff cl_list_insert_head(&tmpPortsList, p_dest_physp); 526219820Sjeff /* get the output port where we need to come from */ 527219820Sjeff p_physp = (osm_physp_t *) cl_map_get(p_visited_map, 528219820Sjeff __osm_ptr_to_key(p_dest_physp)); 529219820Sjeff while (p_physp != NULL) { 530219820Sjeff cl_list_insert_head(&tmpPortsList, p_physp); 531219820Sjeff /* get the input port through where we reached the output port */ 532219820Sjeff p_src_physp = p_physp; 533219820Sjeff p_physp = (osm_physp_t *) cl_map_get(p_visited_map, 534219820Sjeff __osm_ptr_to_key(p_physp)); 535219820Sjeff /* if we reached a null p_physp - this means we are at the begining 536219820Sjeff of the path. Break. */ 537219820Sjeff if (p_physp == NULL) 538219820Sjeff break; 539219820Sjeff /* get the output port */ 540219820Sjeff p_physp = (osm_physp_t *) cl_map_get(p_visited_map, 541219820Sjeff __osm_ptr_to_key(p_physp)); 542219820Sjeff } 543219820Sjeff 544219820Sjeff memset(path_array, 0, sizeof(path_array)); 545219820Sjeff p_physp = (osm_physp_t *) cl_list_remove_head(&tmpPortsList); 546219820Sjeff while (p_physp != NULL) { 547219820Sjeff i++; 548219820Sjeff path_array[i] = p_physp->port_num; 549219820Sjeff p_physp = (osm_physp_t *) cl_list_remove_head(&tmpPortsList); 550219820Sjeff } 551219820Sjeff if (p_src_physp) { 552219820Sjeff p_dr_path = osm_physp_get_dr_path_ptr(p_src_physp); 553219820Sjeff osm_dr_path_init(p_dr_path, h_bind, i, path_array); 554219820Sjeff } 555219820Sjeff 556219820Sjeff cl_list_destroy(&tmpPortsList); 557219820Sjeff} 558219820Sjeff 559219820Sjeff/********************************************************************** 560219820Sjeff **********************************************************************/ 561219820Sjeffvoid 562219820Sjeffosm_physp_replace_dr_path_with_alternate_dr_path(IN osm_log_t * p_log, 563219820Sjeff IN osm_subn_t const *p_subn, 564219820Sjeff IN osm_physp_t const 565219820Sjeff *p_dest_physp, 566219820Sjeff IN osm_bind_handle_t * h_bind) 567219820Sjeff{ 568219820Sjeff cl_map_t physp_map; 569219820Sjeff cl_map_t visited_map; 570219820Sjeff osm_dr_path_t *p_dr_path; 571219820Sjeff cl_list_t *p_currPortsList; 572219820Sjeff cl_list_t *p_nextPortsList; 573219820Sjeff osm_port_t *p_port; 574219820Sjeff osm_physp_t *p_physp, *p_remote_physp; 575219820Sjeff ib_net64_t port_guid; 576219820Sjeff boolean_t next_list_is_full = TRUE, reached_dest = FALSE; 577219820Sjeff uint8_t num_ports, port_num; 578219820Sjeff 579219820Sjeff p_nextPortsList = (cl_list_t *) malloc(sizeof(cl_list_t)); 580219820Sjeff if (!p_nextPortsList) 581219820Sjeff return; 582219820Sjeff 583219820Sjeff /* 584219820Sjeff initialize the map of all port participating in current dr path 585219820Sjeff not including first and last switches 586219820Sjeff */ 587219820Sjeff cl_map_construct(&physp_map); 588219820Sjeff cl_map_init(&physp_map, 4); 589219820Sjeff cl_map_construct(&visited_map); 590219820Sjeff cl_map_init(&visited_map, 4); 591219820Sjeff p_dr_path = osm_physp_get_dr_path_ptr(p_dest_physp); 592219820Sjeff __osm_physp_get_dr_physp_set(p_log, p_subn, p_dr_path, &physp_map); 593219820Sjeff 594219820Sjeff /* 595219820Sjeff BFS from OSM port until we find the target physp but avoid 596219820Sjeff going through mapped ports 597219820Sjeff */ 598219820Sjeff cl_list_construct(p_nextPortsList); 599219820Sjeff cl_list_init(p_nextPortsList, 10); 600219820Sjeff 601219820Sjeff port_guid = p_subn->sm_port_guid; 602219820Sjeff 603219820Sjeff CL_ASSERT(port_guid); 604219820Sjeff 605219820Sjeff p_port = osm_get_port_by_guid(p_subn, port_guid); 606219820Sjeff if (!p_port) { 607219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4105: No SM port object\n"); 608219820Sjeff goto Exit; 609219820Sjeff } 610219820Sjeff 611219820Sjeff /* 612219820Sjeff HACK: We are assuming SM is running on HCA, so when getting the default 613219820Sjeff port we'll get the port connected to the rest of the subnet. If SM is 614219820Sjeff running on SWITCH - we should try to get a dr path from all switch ports. 615219820Sjeff */ 616219820Sjeff p_physp = p_port->p_physp; 617219820Sjeff 618219820Sjeff CL_ASSERT(p_physp); 619219820Sjeff 620219820Sjeff cl_list_insert_tail(p_nextPortsList, p_physp); 621219820Sjeff 622219820Sjeff while (next_list_is_full == TRUE) { 623219820Sjeff next_list_is_full = FALSE; 624219820Sjeff p_currPortsList = p_nextPortsList; 625219820Sjeff p_nextPortsList = (cl_list_t *) malloc(sizeof(cl_list_t)); 626219820Sjeff if (!p_nextPortsList) { 627219820Sjeff p_nextPortsList = p_currPortsList; 628219820Sjeff goto Exit; 629219820Sjeff } 630219820Sjeff cl_list_construct(p_nextPortsList); 631219820Sjeff cl_list_init(p_nextPortsList, 10); 632219820Sjeff p_physp = (osm_physp_t *) cl_list_remove_head(p_currPortsList); 633219820Sjeff while (p_physp != NULL) { 634219820Sjeff /* If we are in a switch - need to go out through all 635219820Sjeff the other physical ports of the switch */ 636219820Sjeff num_ports = osm_node_get_num_physp(p_physp->p_node); 637219820Sjeff 638219820Sjeff for (port_num = 1; port_num < num_ports; port_num++) { 639219820Sjeff if (osm_node_get_type(p_physp->p_node) == 640219820Sjeff IB_NODE_TYPE_SWITCH) 641219820Sjeff p_remote_physp = 642219820Sjeff osm_node_get_physp_ptr(p_physp-> 643219820Sjeff p_node, 644219820Sjeff port_num); 645219820Sjeff else 646219820Sjeff /* this is HCA or router - the remote port is just the port connected 647219820Sjeff on the other side */ 648219820Sjeff p_remote_physp = 649219820Sjeff p_physp->p_remote_physp; 650219820Sjeff 651219820Sjeff /* 652219820Sjeff make sure that all of the following occurred: 653219820Sjeff 1. The port isn't NULL 654219820Sjeff 2. This is not the port we came from 655219820Sjeff 3. The port is not in the physp_map 656219820Sjeff 4. This port haven't been visited before 657219820Sjeff */ 658219820Sjeff if (p_remote_physp && 659219820Sjeff p_remote_physp != p_physp && 660219820Sjeff cl_map_get(&physp_map, 661219820Sjeff __osm_ptr_to_key(p_remote_physp)) 662219820Sjeff == NULL 663219820Sjeff && cl_map_get(&visited_map, 664219820Sjeff __osm_ptr_to_key 665219820Sjeff (p_remote_physp)) == NULL) { 666219820Sjeff /* Insert the port into the visited_map, and save its source port */ 667219820Sjeff cl_map_insert(&visited_map, 668219820Sjeff __osm_ptr_to_key 669219820Sjeff (p_remote_physp), 670219820Sjeff p_physp); 671219820Sjeff 672219820Sjeff /* Is this the p_dest_physp? */ 673219820Sjeff if (p_remote_physp == p_dest_physp) { 674219820Sjeff /* update the new dr path */ 675219820Sjeff __osm_physp_update_new_dr_path 676219820Sjeff (p_dest_physp, &visited_map, 677219820Sjeff h_bind); 678219820Sjeff reached_dest = TRUE; 679219820Sjeff break; 680219820Sjeff } 681219820Sjeff 682219820Sjeff /* add the p_remote_physp to the nextPortsList */ 683219820Sjeff cl_list_insert_tail(p_nextPortsList, 684219820Sjeff p_remote_physp); 685219820Sjeff next_list_is_full = TRUE; 686219820Sjeff } 687219820Sjeff } 688219820Sjeff 689219820Sjeff p_physp = (osm_physp_t *) 690219820Sjeff cl_list_remove_head(p_currPortsList); 691219820Sjeff if (reached_dest == TRUE) { 692219820Sjeff /* free the rest of the currPortsList */ 693219820Sjeff while (p_physp != NULL) 694219820Sjeff p_physp = (osm_physp_t *) 695219820Sjeff cl_list_remove_head 696219820Sjeff (p_currPortsList); 697219820Sjeff /* free the nextPortsList, if items were added to it */ 698219820Sjeff p_physp = (osm_physp_t *) 699219820Sjeff cl_list_remove_head(p_nextPortsList); 700219820Sjeff while (p_physp != NULL) 701219820Sjeff p_physp = (osm_physp_t *) 702219820Sjeff cl_list_remove_head 703219820Sjeff (p_nextPortsList); 704219820Sjeff next_list_is_full = FALSE; 705219820Sjeff } 706219820Sjeff } 707219820Sjeff cl_list_destroy(p_currPortsList); 708219820Sjeff free(p_currPortsList); 709219820Sjeff } 710219820Sjeff 711219820Sjeff /* cleanup */ 712219820SjeffExit: 713219820Sjeff cl_list_destroy(p_nextPortsList); 714219820Sjeff free(p_nextPortsList); 715219820Sjeff cl_map_destroy(&physp_map); 716219820Sjeff cl_map_destroy(&visited_map); 717219820Sjeff} 718219820Sjeff 719219820Sjeff/********************************************************************** 720219820Sjeff **********************************************************************/ 721219820Sjeffboolean_t osm_link_is_healthy(IN const osm_physp_t * const p_physp) 722219820Sjeff{ 723219820Sjeff osm_physp_t *p_remote_physp; 724219820Sjeff 725219820Sjeff CL_ASSERT(p_physp); 726219820Sjeff p_remote_physp = p_physp->p_remote_physp; 727219820Sjeff if (p_remote_physp != NULL) 728219820Sjeff return ((p_physp->healthy) & (p_remote_physp->healthy)); 729219820Sjeff /* the other side is not known - consider the link as healthy */ 730219820Sjeff return (TRUE); 731219820Sjeff} 732219820Sjeff 733219820Sjeff/********************************************************************** 734219820Sjeff **********************************************************************/ 735219820Sjeffvoid 736219820Sjeffosm_physp_set_pkey_tbl(IN osm_log_t * p_log, 737219820Sjeff IN const osm_subn_t * p_subn, 738219820Sjeff IN osm_physp_t * const p_physp, 739219820Sjeff IN ib_pkey_table_t * p_pkey_tbl, IN uint16_t block_num) 740219820Sjeff{ 741219820Sjeff uint16_t max_blocks; 742219820Sjeff 743219820Sjeff CL_ASSERT(p_pkey_tbl); 744219820Sjeff /* 745219820Sjeff (14.2.5.7) - the block number valid values are 0-2047, and are 746219820Sjeff further limited by the size of the P_Key table specified by 747219820Sjeff the PartitionCap on the node. 748219820Sjeff */ 749219820Sjeff if (!p_physp->p_node->sw || p_physp->port_num == 0) 750219820Sjeff /* 751219820Sjeff The maximum blocks is defined in the node info: partition cap 752219820Sjeff for CA, router, and switch management ports. 753219820Sjeff */ 754219820Sjeff max_blocks = 755219820Sjeff (cl_ntoh16(p_physp->p_node->node_info.partition_cap) + 756219820Sjeff IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) 757219820Sjeff / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; 758219820Sjeff else 759219820Sjeff /* 760219820Sjeff This is a switch, and not a management port. The maximum 761219820Sjeff blocks is defined in the switch info: partition enforcement 762219820Sjeff cap. 763219820Sjeff */ 764219820Sjeff max_blocks = 765219820Sjeff (cl_ntoh16(p_physp->p_node->sw->switch_info.enforce_cap) + 766219820Sjeff IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 767219820Sjeff 1) / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; 768219820Sjeff 769219820Sjeff if (block_num >= max_blocks) { 770219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4108: " 771219820Sjeff "Got illegal set for block number:%u " 772219820Sjeff "For GUID: %" PRIx64 " port number:%u\n", 773219820Sjeff block_num, 774219820Sjeff cl_ntoh64(p_physp->p_node->node_info.node_guid), 775219820Sjeff p_physp->port_num); 776219820Sjeff return; 777219820Sjeff } 778219820Sjeff 779219820Sjeff osm_pkey_tbl_set(&p_physp->pkeys, block_num, p_pkey_tbl); 780219820Sjeff} 781