1321936Shselasky/* 2321936Shselasky * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. 3321936Shselasky * Copyright (c) 2002-2011 Mellanox Technologies LTD. All rights reserved. 4321936Shselasky * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5321936Shselasky * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved. 6321936Shselasky * Copyright (c) 2009-2011 ZIH, TU Dresden, Federal Republic of Germany. All rights reserved. 7321936Shselasky * 8321936Shselasky * This software is available to you under a choice of one of two 9321936Shselasky * licenses. You may choose to be licensed under the terms of the GNU 10321936Shselasky * General Public License (GPL) Version 2, available from the file 11321936Shselasky * COPYING in the main directory of this source tree, or the 12321936Shselasky * OpenIB.org BSD license below: 13321936Shselasky * 14321936Shselasky * Redistribution and use in source and binary forms, with or 15321936Shselasky * without modification, are permitted provided that the following 16321936Shselasky * conditions are met: 17321936Shselasky * 18321936Shselasky * - Redistributions of source code must retain the above 19321936Shselasky * copyright notice, this list of conditions and the following 20321936Shselasky * disclaimer. 21321936Shselasky * 22321936Shselasky * - Redistributions in binary form must reproduce the above 23321936Shselasky * copyright notice, this list of conditions and the following 24321936Shselasky * disclaimer in the documentation and/or other materials 25321936Shselasky * provided with the distribution. 26321936Shselasky * 27321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 28321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 29321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 30321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 31321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 32321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 33321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 34321936Shselasky * SOFTWARE. 35321936Shselasky * 36321936Shselasky */ 37321936Shselasky 38321936Shselasky/* 39321936Shselasky * Abstract: 40321936Shselasky * Implementation of osm_link_mgr_t. 41321936Shselasky * This file implements the Link Manager object. 42321936Shselasky */ 43321936Shselasky 44321936Shselasky#if HAVE_CONFIG_H 45321936Shselasky# include <config.h> 46321936Shselasky#endif /* HAVE_CONFIG_H */ 47321936Shselasky 48321936Shselasky#include <string.h> 49321936Shselasky#include <iba/ib_types.h> 50321936Shselasky#include <complib/cl_debug.h> 51321936Shselasky#include <opensm/osm_file_ids.h> 52321936Shselasky#define FILE_ID OSM_FILE_LINK_MGR_C 53321936Shselasky#include <opensm/osm_sm.h> 54321936Shselasky#include <opensm/osm_node.h> 55321936Shselasky#include <opensm/osm_switch.h> 56321936Shselasky#include <opensm/osm_helper.h> 57321936Shselasky#include <opensm/osm_msgdef.h> 58321936Shselasky#include <opensm/osm_opensm.h> 59321936Shselasky#include <opensm/osm_db_pack.h> 60321936Shselasky 61321936Shselaskystatic uint8_t link_mgr_get_smsl(IN osm_sm_t * sm, IN osm_physp_t * p_physp) 62321936Shselasky{ 63321936Shselasky osm_opensm_t *p_osm = sm->p_subn->p_osm; 64321936Shselasky struct osm_routing_engine *re = p_osm->routing_engine_used; 65321936Shselasky ib_net16_t slid; 66321936Shselasky ib_net16_t smlid; 67321936Shselasky uint8_t sl; 68321936Shselasky 69321936Shselasky OSM_LOG_ENTER(sm->p_log); 70321936Shselasky 71321936Shselasky if (!(re && re->path_sl && 72321936Shselasky (slid = osm_physp_get_base_lid(p_physp)))) { 73321936Shselasky /* 74321936Shselasky * Use default SL if routing engine does not provide a 75321936Shselasky * path SL lookup callback. 76321936Shselasky */ 77321936Shselasky OSM_LOG_EXIT(sm->p_log); 78321936Shselasky return sm->p_subn->opt.sm_sl; 79321936Shselasky } 80321936Shselasky 81321936Shselasky smlid = sm->p_subn->sm_base_lid; 82321936Shselasky 83321936Shselasky /* Call into routing engine to find proper SL */ 84321936Shselasky sl = re->path_sl(re->context, sm->p_subn->opt.sm_sl, 85321936Shselasky slid, smlid); 86321936Shselasky 87321936Shselasky OSM_LOG_EXIT(sm->p_log); 88321936Shselasky return sl; 89321936Shselasky} 90321936Shselasky 91321936Shselaskystatic int link_mgr_set_physp_pi(osm_sm_t * sm, IN osm_physp_t * p_physp, 92321936Shselasky IN uint8_t port_state) 93321936Shselasky{ 94321936Shselasky uint8_t payload[IB_SMP_DATA_SIZE], payload2[IB_SMP_DATA_SIZE]; 95321936Shselasky ib_port_info_t *p_pi = (ib_port_info_t *) payload; 96321936Shselasky ib_mlnx_ext_port_info_t *p_epi = (ib_mlnx_ext_port_info_t *) payload2; 97321936Shselasky const ib_port_info_t *p_old_pi; 98321936Shselasky const ib_mlnx_ext_port_info_t *p_old_epi; 99321936Shselasky osm_madw_context_t context; 100321936Shselasky osm_node_t *p_node; 101321936Shselasky ib_api_status_t status; 102321936Shselasky uint8_t port_num, mtu, op_vls, smsl = OSM_DEFAULT_SL; 103321936Shselasky boolean_t esp0 = FALSE, send_set = FALSE, send_set2 = FALSE; 104321936Shselasky osm_physp_t *p_remote_physp, *physp0 = NULL; 105321936Shselasky int issue_ext = 0, fdr10_change = 0; 106321936Shselasky int ret = 0; 107321936Shselasky ib_net32_t attr_mod, cap_mask; 108321936Shselasky boolean_t update_mkey = FALSE; 109321936Shselasky ib_net64_t m_key = 0; 110321936Shselasky osm_port_t *p_port; 111321936Shselasky 112321936Shselasky OSM_LOG_ENTER(sm->p_log); 113321936Shselasky 114321936Shselasky p_node = osm_physp_get_node_ptr(p_physp); 115321936Shselasky 116321936Shselasky p_old_pi = &p_physp->port_info; 117321936Shselasky 118321936Shselasky port_num = osm_physp_get_port_num(p_physp); 119321936Shselasky 120321936Shselasky memcpy(payload, p_old_pi, sizeof(ib_port_info_t)); 121321936Shselasky 122321936Shselasky if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH || 123321936Shselasky port_num == 0) { 124321936Shselasky /* Need to make sure LID and SMLID fields in PortInfo are not 0 */ 125321936Shselasky if (!p_pi->base_lid) { 126321936Shselasky p_port = osm_get_port_by_guid(sm->p_subn, 127321936Shselasky osm_physp_get_port_guid(p_physp)); 128321936Shselasky p_pi->base_lid = p_port->lid; 129321936Shselasky sm->lid_mgr.dirty = TRUE; 130321936Shselasky send_set = TRUE; 131321936Shselasky } 132321936Shselasky 133321936Shselasky /* we are initializing the ports with our local sm_base_lid */ 134321936Shselasky p_pi->master_sm_base_lid = sm->p_subn->sm_base_lid; 135321936Shselasky if (p_pi->master_sm_base_lid != p_old_pi->master_sm_base_lid) 136321936Shselasky send_set = TRUE; 137321936Shselasky } 138321936Shselasky 139321936Shselasky if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH) 140321936Shselasky physp0 = osm_node_get_physp_ptr(p_node, 0); 141321936Shselasky 142321936Shselasky if (port_num == 0) { 143321936Shselasky /* 144321936Shselasky CAs don't have a port 0, and for switch port 0, 145321936Shselasky we need to check if this is enhanced or base port 0. 146321936Shselasky For base port 0 the following parameters are not valid 147321936Shselasky (IBA 1.2.1 p.830 table 146). 148321936Shselasky */ 149321936Shselasky if (!p_node->sw) { 150321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 4201: " 151321936Shselasky "Cannot find switch by guid: 0x%" PRIx64 "\n", 152321936Shselasky cl_ntoh64(p_node->node_info.node_guid)); 153321936Shselasky goto Exit; 154321936Shselasky } 155321936Shselasky 156321936Shselasky if (ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info) 157321936Shselasky == FALSE) { 158321936Shselasky 159321936Shselasky /* Even for base port 0 we might have to set smsl 160321936Shselasky (if we are using lash routing) */ 161321936Shselasky smsl = link_mgr_get_smsl(sm, p_physp); 162321936Shselasky if (smsl != ib_port_info_get_master_smsl(p_old_pi)) { 163321936Shselasky send_set = TRUE; 164321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 165321936Shselasky "Setting SMSL to %d on port 0 GUID 0x%016" 166321936Shselasky PRIx64 "\n", smsl, 167321936Shselasky cl_ntoh64(osm_physp_get_port_guid 168321936Shselasky (p_physp))); 169321936Shselasky /* Enter if base lid and master_sm_lid didn't change */ 170321936Shselasky } else if (send_set == FALSE) { 171321936Shselasky /* This means the switch doesn't support 172321936Shselasky enhanced port 0 and we don't need to 173321936Shselasky change SMSL. Can skip it. */ 174321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 175321936Shselasky "Skipping port 0, GUID 0x%016" PRIx64 176321936Shselasky "\n", 177321936Shselasky cl_ntoh64(osm_physp_get_port_guid 178321936Shselasky (p_physp))); 179321936Shselasky goto Exit; 180321936Shselasky } 181321936Shselasky } else 182321936Shselasky esp0 = TRUE; 183321936Shselasky } 184321936Shselasky 185321936Shselasky /* 186321936Shselasky Should never write back a value that is bigger then 3 in 187321936Shselasky the PortPhysicalState field - so can not simply copy! 188321936Shselasky 189321936Shselasky Actually we want to write there: 190321936Shselasky port physical state - no change, 191321936Shselasky link down default state = polling 192321936Shselasky port state - as requested. 193321936Shselasky */ 194321936Shselasky p_pi->state_info2 = 0x02; 195321936Shselasky ib_port_info_set_port_state(p_pi, port_state); 196321936Shselasky 197321936Shselasky /* Determine ports' M_Key */ 198321936Shselasky if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH && 199321936Shselasky osm_physp_get_port_num(p_physp) != 0) 200321936Shselasky m_key = ib_port_info_get_m_key(&physp0->port_info); 201321936Shselasky else 202321936Shselasky m_key = ib_port_info_get_m_key(p_pi); 203321936Shselasky 204321936Shselasky /* Check whether this is base port0 smsl handling only */ 205321936Shselasky if (port_num == 0 && esp0 == FALSE) { 206321936Shselasky ib_port_info_set_master_smsl(p_pi, smsl); 207321936Shselasky goto Send; 208321936Shselasky } 209321936Shselasky 210321936Shselasky /* 211321936Shselasky PAST THIS POINT WE ARE HANDLING EITHER A NON PORT 0 OR ENHANCED PORT 0 212321936Shselasky */ 213321936Shselasky 214321936Shselasky if (ib_port_info_get_link_down_def_state(p_pi) != 215321936Shselasky ib_port_info_get_link_down_def_state(p_old_pi)) 216321936Shselasky send_set = TRUE; 217321936Shselasky 218321936Shselasky /* didn't get PortInfo before */ 219321936Shselasky if (!ib_port_info_get_port_state(p_old_pi)) 220321936Shselasky send_set = TRUE; 221321936Shselasky 222321936Shselasky /* we only change port fields if we do not change state */ 223321936Shselasky if (port_state == IB_LINK_NO_CHANGE) { 224321936Shselasky /* The following fields are relevant only for CA port, router, or Enh. SP0 */ 225321936Shselasky if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH || 226321936Shselasky port_num == 0) { 227321936Shselasky p_pi->m_key = sm->p_subn->opt.m_key; 228321936Shselasky if (memcmp(&p_pi->m_key, &p_old_pi->m_key, 229321936Shselasky sizeof(p_pi->m_key))) { 230321936Shselasky update_mkey = TRUE; 231321936Shselasky send_set = TRUE; 232321936Shselasky } 233321936Shselasky 234321936Shselasky p_pi->subnet_prefix = sm->p_subn->opt.subnet_prefix; 235321936Shselasky if (memcmp(&p_pi->subnet_prefix, 236321936Shselasky &p_old_pi->subnet_prefix, 237321936Shselasky sizeof(p_pi->subnet_prefix))) 238321936Shselasky send_set = TRUE; 239321936Shselasky 240321936Shselasky smsl = link_mgr_get_smsl(sm, p_physp); 241321936Shselasky if (smsl != ib_port_info_get_master_smsl(p_old_pi)) { 242321936Shselasky 243321936Shselasky ib_port_info_set_master_smsl(p_pi, smsl); 244321936Shselasky 245321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 246321936Shselasky "Setting SMSL to %d on GUID 0x%016" 247321936Shselasky PRIx64 ", port %d\n", smsl, 248321936Shselasky cl_ntoh64(osm_physp_get_port_guid 249321936Shselasky (p_physp)), port_num); 250321936Shselasky 251321936Shselasky send_set = TRUE; 252321936Shselasky } 253321936Shselasky 254321936Shselasky p_pi->m_key_lease_period = 255321936Shselasky sm->p_subn->opt.m_key_lease_period; 256321936Shselasky if (memcmp(&p_pi->m_key_lease_period, 257321936Shselasky &p_old_pi->m_key_lease_period, 258321936Shselasky sizeof(p_pi->m_key_lease_period))) 259321936Shselasky send_set = TRUE; 260321936Shselasky 261321936Shselasky p_pi->mkey_lmc = 0; 262321936Shselasky ib_port_info_set_mpb(p_pi, sm->p_subn->opt.m_key_protect_bits); 263321936Shselasky if (esp0 == FALSE || sm->p_subn->opt.lmc_esp0) 264321936Shselasky ib_port_info_set_lmc(p_pi, sm->p_subn->opt.lmc); 265321936Shselasky if (ib_port_info_get_lmc(p_old_pi) != 266321936Shselasky ib_port_info_get_lmc(p_pi) || 267321936Shselasky ib_port_info_get_mpb(p_old_pi) != 268321936Shselasky ib_port_info_get_mpb(p_pi)) 269321936Shselasky send_set = TRUE; 270321936Shselasky 271321936Shselasky ib_port_info_set_timeout(p_pi, 272321936Shselasky sm->p_subn->opt. 273321936Shselasky subnet_timeout); 274321936Shselasky if (ib_port_info_get_timeout(p_pi) != 275321936Shselasky ib_port_info_get_timeout(p_old_pi)) 276321936Shselasky send_set = TRUE; 277321936Shselasky } 278321936Shselasky 279321936Shselasky /* 280321936Shselasky Several timeout mechanisms: 281321936Shselasky */ 282321936Shselasky p_remote_physp = osm_physp_get_remote(p_physp); 283321936Shselasky if (port_num != 0 && p_remote_physp) { 284321936Shselasky if (osm_node_get_type(osm_physp_get_node_ptr(p_physp)) 285321936Shselasky == IB_NODE_TYPE_ROUTER) { 286321936Shselasky ib_port_info_set_hoq_lifetime(p_pi, 287321936Shselasky sm->p_subn-> 288321936Shselasky opt. 289321936Shselasky leaf_head_of_queue_lifetime); 290321936Shselasky } else 291321936Shselasky if (osm_node_get_type 292321936Shselasky (osm_physp_get_node_ptr(p_physp)) == 293321936Shselasky IB_NODE_TYPE_SWITCH) { 294321936Shselasky /* Is remote end CA or router (a leaf port) ? */ 295321936Shselasky if (osm_node_get_type 296321936Shselasky (osm_physp_get_node_ptr(p_remote_physp)) != 297321936Shselasky IB_NODE_TYPE_SWITCH) { 298321936Shselasky ib_port_info_set_hoq_lifetime(p_pi, 299321936Shselasky sm-> 300321936Shselasky p_subn-> 301321936Shselasky opt. 302321936Shselasky leaf_head_of_queue_lifetime); 303321936Shselasky ib_port_info_set_vl_stall_count(p_pi, 304321936Shselasky sm-> 305321936Shselasky p_subn-> 306321936Shselasky opt. 307321936Shselasky leaf_vl_stall_count); 308321936Shselasky } else { 309321936Shselasky ib_port_info_set_hoq_lifetime(p_pi, 310321936Shselasky sm-> 311321936Shselasky p_subn-> 312321936Shselasky opt. 313321936Shselasky head_of_queue_lifetime); 314321936Shselasky ib_port_info_set_vl_stall_count(p_pi, 315321936Shselasky sm-> 316321936Shselasky p_subn-> 317321936Shselasky opt. 318321936Shselasky vl_stall_count); 319321936Shselasky } 320321936Shselasky } 321321936Shselasky if (ib_port_info_get_hoq_lifetime(p_pi) != 322321936Shselasky ib_port_info_get_hoq_lifetime(p_old_pi) || 323321936Shselasky ib_port_info_get_vl_stall_count(p_pi) != 324321936Shselasky ib_port_info_get_vl_stall_count(p_old_pi)) 325321936Shselasky send_set = TRUE; 326321936Shselasky } 327321936Shselasky 328321936Shselasky ib_port_info_set_phy_and_overrun_err_thd(p_pi, 329321936Shselasky sm->p_subn->opt. 330321936Shselasky local_phy_errors_threshold, 331321936Shselasky sm->p_subn->opt. 332321936Shselasky overrun_errors_threshold); 333321936Shselasky if (p_pi->error_threshold != p_old_pi->error_threshold) 334321936Shselasky send_set = TRUE; 335321936Shselasky 336321936Shselasky /* 337321936Shselasky Set the easy common parameters for all port types, 338321936Shselasky then determine the neighbor MTU. 339321936Shselasky */ 340321936Shselasky p_pi->link_width_enabled = p_old_pi->link_width_supported; 341321936Shselasky if (p_pi->link_width_enabled != p_old_pi->link_width_enabled) 342321936Shselasky send_set = TRUE; 343321936Shselasky 344321936Shselasky if (sm->p_subn->opt.force_link_speed && 345321936Shselasky (sm->p_subn->opt.force_link_speed != 15 || 346321936Shselasky ib_port_info_get_link_speed_enabled(p_pi) != 347321936Shselasky ib_port_info_get_link_speed_sup(p_pi))) { 348321936Shselasky ib_port_info_set_link_speed_enabled(p_pi, 349321936Shselasky sm->p_subn->opt. 350321936Shselasky force_link_speed); 351321936Shselasky if (p_pi->link_speed != p_old_pi->link_speed) 352321936Shselasky send_set = TRUE; 353321936Shselasky } 354321936Shselasky 355321936Shselasky if (sm->p_subn->opt.fdr10 && 356321936Shselasky p_physp->ext_port_info.link_speed_supported & FDR10) { 357321936Shselasky if (sm->p_subn->opt.fdr10 == 1) { /* enable */ 358321936Shselasky if (!(p_physp->ext_port_info.link_speed_enabled & FDR10)) 359321936Shselasky fdr10_change = 1; 360321936Shselasky } else { /* disable */ 361321936Shselasky if (p_physp->ext_port_info.link_speed_enabled & FDR10) 362321936Shselasky fdr10_change = 1; 363321936Shselasky } 364321936Shselasky if (fdr10_change) { 365321936Shselasky p_old_epi = &p_physp->ext_port_info; 366321936Shselasky memcpy(payload2, p_old_epi, 367321936Shselasky sizeof(ib_mlnx_ext_port_info_t)); 368321936Shselasky p_epi->state_change_enable = 0x01; 369321936Shselasky if (sm->p_subn->opt.fdr10 == 1) 370321936Shselasky p_epi->link_speed_enabled = FDR10; 371321936Shselasky else 372321936Shselasky p_epi->link_speed_enabled = 0; 373321936Shselasky send_set2 = TRUE; 374321936Shselasky } 375321936Shselasky } 376321936Shselasky 377321936Shselasky if (osm_node_get_type(p_physp->p_node) == IB_NODE_TYPE_SWITCH && 378321936Shselasky osm_physp_get_port_num(p_physp) != 0) { 379321936Shselasky cap_mask = physp0->port_info.capability_mask; 380321936Shselasky } else 381321936Shselasky cap_mask = p_pi->capability_mask; 382321936Shselasky 383321936Shselasky if (cap_mask & IB_PORT_CAP_HAS_EXT_SPEEDS) 384321936Shselasky issue_ext = 1; 385321936Shselasky 386321936Shselasky /* Do peer ports support extended link speeds ? */ 387321936Shselasky if (port_num != 0 && p_remote_physp) { 388321936Shselasky osm_physp_t *rphysp0; 389321936Shselasky ib_net32_t rem_cap_mask; 390321936Shselasky 391321936Shselasky if (osm_node_get_type(p_remote_physp->p_node) == 392321936Shselasky IB_NODE_TYPE_SWITCH) { 393321936Shselasky rphysp0 = osm_node_get_physp_ptr(p_remote_physp->p_node, 0); 394321936Shselasky rem_cap_mask = rphysp0->port_info.capability_mask; 395321936Shselasky } else 396321936Shselasky rem_cap_mask = p_remote_physp->port_info.capability_mask; 397321936Shselasky 398321936Shselasky if (cap_mask & IB_PORT_CAP_HAS_EXT_SPEEDS && 399321936Shselasky rem_cap_mask & IB_PORT_CAP_HAS_EXT_SPEEDS) { 400321936Shselasky if (sm->p_subn->opt.force_link_speed_ext && 401321936Shselasky (sm->p_subn->opt.force_link_speed_ext != IB_LINK_SPEED_EXT_SET_LSES || 402321936Shselasky p_pi->link_speed_ext_enabled != 403321936Shselasky ib_port_info_get_link_speed_ext_sup(p_pi))) { 404321936Shselasky p_pi->link_speed_ext_enabled = sm->p_subn->opt.force_link_speed_ext; 405321936Shselasky if (p_pi->link_speed_ext_enabled != 406321936Shselasky p_old_pi->link_speed_ext_enabled) 407321936Shselasky send_set = TRUE; 408321936Shselasky } 409321936Shselasky } 410321936Shselasky } 411321936Shselasky 412321936Shselasky /* calc new op_vls and mtu */ 413321936Shselasky op_vls = 414321936Shselasky osm_physp_calc_link_op_vls(sm->p_log, sm->p_subn, p_physp, 415321936Shselasky ib_port_info_get_op_vls(p_old_pi)); 416321936Shselasky mtu = osm_physp_calc_link_mtu(sm->p_log, p_physp, 417321936Shselasky ib_port_info_get_neighbor_mtu(p_old_pi)); 418321936Shselasky 419321936Shselasky ib_port_info_set_neighbor_mtu(p_pi, mtu); 420321936Shselasky if (ib_port_info_get_neighbor_mtu(p_pi) != 421321936Shselasky ib_port_info_get_neighbor_mtu(p_old_pi)) 422321936Shselasky send_set = TRUE; 423321936Shselasky 424321936Shselasky ib_port_info_set_op_vls(p_pi, op_vls); 425321936Shselasky if (ib_port_info_get_op_vls(p_pi) != 426321936Shselasky ib_port_info_get_op_vls(p_old_pi)) 427321936Shselasky send_set = TRUE; 428321936Shselasky 429321936Shselasky /* provide the vl_high_limit from the qos mgr */ 430321936Shselasky if (sm->p_subn->opt.qos && 431321936Shselasky p_physp->vl_high_limit != p_old_pi->vl_high_limit) { 432321936Shselasky send_set = TRUE; 433321936Shselasky p_pi->vl_high_limit = p_physp->vl_high_limit; 434321936Shselasky } 435321936Shselasky } 436321936Shselasky 437321936ShselaskySend: 438321936Shselasky context.pi_context.active_transition = FALSE; 439321936Shselasky if (port_state != IB_LINK_NO_CHANGE && 440321936Shselasky port_state != ib_port_info_get_port_state(p_old_pi)) { 441321936Shselasky send_set = TRUE; 442321936Shselasky if (port_state == IB_LINK_ACTIVE) 443321936Shselasky context.pi_context.active_transition = TRUE; 444321936Shselasky } 445321936Shselasky 446321936Shselasky context.pi_context.node_guid = osm_node_get_node_guid(p_node); 447321936Shselasky context.pi_context.port_guid = osm_physp_get_port_guid(p_physp); 448321936Shselasky context.pi_context.set_method = TRUE; 449321936Shselasky context.pi_context.light_sweep = FALSE; 450321936Shselasky context.pi_context.client_rereg = FALSE; 451321936Shselasky 452321936Shselasky /* We need to send the PortInfoSet request with the new sm_lid 453321936Shselasky in the following cases: 454321936Shselasky 1. There is a change in the values (send_set == TRUE) 455321936Shselasky 2. This is a switch external port (so it wasn't handled yet by 456321936Shselasky osm_lid_mgr) and first_time_master_sweep flag on the subnet is TRUE, 457321936Shselasky which means the SM just became master, and it then needs to send at 458321936Shselasky PortInfoSet to every port. 459321936Shselasky */ 460321936Shselasky if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH && port_num 461321936Shselasky && sm->p_subn->first_time_master_sweep == TRUE) 462321936Shselasky send_set = TRUE; 463321936Shselasky 464321936Shselasky if (!send_set) 465321936Shselasky goto SEND_EPI; 466321936Shselasky 467321936Shselasky attr_mod = cl_hton32(port_num); 468321936Shselasky if (issue_ext) 469321936Shselasky attr_mod |= cl_hton32(1 << 31); /* AM SMSupportExtendedSpeeds */ 470321936Shselasky status = osm_req_set(sm, osm_physp_get_dr_path_ptr(p_physp), 471321936Shselasky payload, sizeof(payload), IB_MAD_ATTR_PORT_INFO, 472321936Shselasky attr_mod, FALSE, m_key, 473321936Shselasky CL_DISP_MSGID_NONE, &context); 474321936Shselasky if (status) 475321936Shselasky ret = -1; 476321936Shselasky 477321936Shselasky /* If we sent a new mkey above, update our guid2mkey map 478321936Shselasky now, on the assumption that the SubnSet succeeds 479321936Shselasky */ 480321936Shselasky if (update_mkey) 481321936Shselasky osm_db_guid2mkey_set(sm->p_subn->p_g2m, 482321936Shselasky cl_ntoh64(p_physp->port_guid), 483321936Shselasky cl_ntoh64(p_pi->m_key)); 484321936Shselasky 485321936ShselaskySEND_EPI: 486321936Shselasky if (send_set2) { 487321936Shselasky status = osm_req_set(sm, osm_physp_get_dr_path_ptr(p_physp), 488321936Shselasky payload2, sizeof(payload2), 489321936Shselasky IB_MAD_ATTR_MLNX_EXTENDED_PORT_INFO, 490321936Shselasky cl_hton32(port_num), FALSE, m_key, 491321936Shselasky CL_DISP_MSGID_NONE, &context); 492321936Shselasky if (status) 493321936Shselasky ret = -1; 494321936Shselasky } 495321936Shselasky 496321936ShselaskyExit: 497321936Shselasky OSM_LOG_EXIT(sm->p_log); 498321936Shselasky return ret; 499321936Shselasky} 500321936Shselasky 501321936Shselaskystatic int link_mgr_process_node(osm_sm_t * sm, IN osm_node_t * p_node, 502321936Shselasky IN const uint8_t link_state) 503321936Shselasky{ 504321936Shselasky osm_physp_t *p_physp, *p_physp_remote; 505321936Shselasky uint32_t i, num_physp; 506321936Shselasky int ret = 0; 507321936Shselasky uint8_t current_state; 508321936Shselasky 509321936Shselasky OSM_LOG_ENTER(sm->p_log); 510321936Shselasky 511321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 512321936Shselasky "Node 0x%" PRIx64 " going to %s\n", 513321936Shselasky cl_ntoh64(osm_node_get_node_guid(p_node)), 514321936Shselasky ib_get_port_state_str(link_state)); 515321936Shselasky 516321936Shselasky /* 517321936Shselasky Set the PortInfo for every Physical Port associated 518321936Shselasky with this Port. Start iterating with port 1, since the linkstate 519321936Shselasky is not applicable to the management port on switches. 520321936Shselasky */ 521321936Shselasky num_physp = osm_node_get_num_physp(p_node); 522321936Shselasky for (i = 0; i < num_physp; i++) { 523321936Shselasky /* 524321936Shselasky Don't bother doing anything if this Physical Port is not valid. 525321936Shselasky or if the state of the port is already better then the 526321936Shselasky specified state. 527321936Shselasky */ 528321936Shselasky p_physp = osm_node_get_physp_ptr(p_node, (uint8_t) i); 529321936Shselasky if (!p_physp) 530321936Shselasky continue; 531321936Shselasky 532321936Shselasky current_state = osm_physp_get_port_state(p_physp); 533321936Shselasky if (current_state == IB_LINK_DOWN) 534321936Shselasky continue; 535321936Shselasky 536321936Shselasky /* 537321936Shselasky Set PortState to DOWN in case Remote Physical Port is 538321936Shselasky unreachable. We have to check this for all ports, except 539321936Shselasky port zero. 540321936Shselasky */ 541321936Shselasky p_physp_remote = osm_physp_get_remote(p_physp); 542321936Shselasky if ((i != 0) && (!p_physp_remote || 543321936Shselasky !osm_physp_is_valid(p_physp_remote))) { 544321936Shselasky if (current_state != IB_LINK_INIT) 545321936Shselasky link_mgr_set_physp_pi(sm, p_physp, IB_LINK_DOWN); 546321936Shselasky continue; 547321936Shselasky } 548321936Shselasky 549321936Shselasky /* 550321936Shselasky Normally we only send state update if state is lower 551321936Shselasky then required state. However, we need to send update if 552321936Shselasky no state change required. 553321936Shselasky */ 554321936Shselasky if (link_state != IB_LINK_NO_CHANGE && 555321936Shselasky link_state <= current_state) 556321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 557321936Shselasky "Physical port %u already %s. Skipping\n", 558321936Shselasky p_physp->port_num, 559321936Shselasky ib_get_port_state_str(current_state)); 560321936Shselasky else if (link_mgr_set_physp_pi(sm, p_physp, link_state)) 561321936Shselasky ret = -1; 562321936Shselasky } 563321936Shselasky 564321936Shselasky OSM_LOG_EXIT(sm->p_log); 565321936Shselasky return ret; 566321936Shselasky} 567321936Shselasky 568321936Shselaskyint osm_link_mgr_process(osm_sm_t * sm, IN const uint8_t link_state) 569321936Shselasky{ 570321936Shselasky cl_qmap_t *p_node_guid_tbl; 571321936Shselasky osm_node_t *p_node; 572321936Shselasky int ret = 0; 573321936Shselasky 574321936Shselasky OSM_LOG_ENTER(sm->p_log); 575321936Shselasky 576321936Shselasky p_node_guid_tbl = &sm->p_subn->node_guid_tbl; 577321936Shselasky 578321936Shselasky CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); 579321936Shselasky 580321936Shselasky for (p_node = (osm_node_t *) cl_qmap_head(p_node_guid_tbl); 581321936Shselasky p_node != (osm_node_t *) cl_qmap_end(p_node_guid_tbl); 582321936Shselasky p_node = (osm_node_t *) cl_qmap_next(&p_node->map_item)) 583321936Shselasky if (link_mgr_process_node(sm, p_node, link_state)) 584321936Shselasky ret = -1; 585321936Shselasky 586321936Shselasky CL_PLOCK_RELEASE(sm->p_lock); 587321936Shselasky 588321936Shselasky OSM_LOG_EXIT(sm->p_log); 589321936Shselasky return ret; 590321936Shselasky} 591