1321936Shselasky/* 2321936Shselasky * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. 3321936Shselasky * Copyright (c) 2002-2012 Mellanox Technologies LTD. All rights reserved. 4321936Shselasky * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5321936Shselasky * Copyright (c) 2009 HNR Consulting. All rights reserved. 6321936Shselasky * Copyright (c) 2013 Oracle and/or its affiliates. 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_pi_rcv_t. 41321936Shselasky * This object represents the PortInfo Receiver object. 42321936Shselasky * This object is part of the opensm family of objects. 43321936Shselasky */ 44321936Shselasky 45321936Shselasky#if HAVE_CONFIG_H 46321936Shselasky# include <config.h> 47321936Shselasky#endif /* HAVE_CONFIG_H */ 48321936Shselasky 49321936Shselasky#include <string.h> 50321936Shselasky#include <stdlib.h> 51321936Shselasky#include <iba/ib_types.h> 52321936Shselasky#include <complib/cl_qmap.h> 53321936Shselasky#include <complib/cl_passivelock.h> 54321936Shselasky#include <complib/cl_debug.h> 55321936Shselasky#include <opensm/osm_file_ids.h> 56321936Shselasky#define FILE_ID OSM_FILE_PORT_INFO_RCV_C 57321936Shselasky#include <vendor/osm_vendor_api.h> 58321936Shselasky#include <opensm/osm_madw.h> 59321936Shselasky#include <opensm/osm_log.h> 60321936Shselasky#include <opensm/osm_node.h> 61321936Shselasky#include <opensm/osm_subnet.h> 62321936Shselasky#include <opensm/osm_mad_pool.h> 63321936Shselasky#include <opensm/osm_msgdef.h> 64321936Shselasky#include <opensm/osm_helper.h> 65321936Shselasky#include <opensm/osm_pkey.h> 66321936Shselasky#include <opensm/osm_remote_sm.h> 67321936Shselasky#include <opensm/osm_opensm.h> 68321936Shselasky#include <opensm/osm_ucast_mgr.h> 69321936Shselasky 70321936Shselaskystatic void pi_rcv_check_and_fix_lid(osm_log_t * log, ib_port_info_t * pi, 71321936Shselasky osm_physp_t * p) 72321936Shselasky{ 73321936Shselasky if (PF(cl_ntoh16(pi->base_lid) > IB_LID_UCAST_END_HO)) { 74321936Shselasky OSM_LOG(log, OSM_LOG_ERROR, "ERR 0F04: " 75321936Shselasky "Got invalid base LID %u from the network. " 76321936Shselasky "Corrected to %u\n", cl_ntoh16(pi->base_lid), 77321936Shselasky cl_ntoh16(p->port_info.base_lid)); 78321936Shselasky pi->base_lid = p->port_info.base_lid; 79321936Shselasky } 80321936Shselasky} 81321936Shselasky 82321936Shselaskystatic void pi_rcv_process_endport(IN osm_sm_t * sm, IN osm_physp_t * p_physp, 83321936Shselasky IN const ib_port_info_t * p_pi) 84321936Shselasky{ 85321936Shselasky osm_madw_context_t context; 86321936Shselasky ib_api_status_t status; 87321936Shselasky ib_net64_t port_guid; 88321936Shselasky int extended; 89321936Shselasky uint8_t rate, mtu, mpb; 90321936Shselasky unsigned data_vls; 91321936Shselasky cl_qmap_t *p_sm_tbl; 92321936Shselasky osm_remote_sm_t *p_sm; 93321936Shselasky 94321936Shselasky OSM_LOG_ENTER(sm->p_log); 95321936Shselasky 96321936Shselasky port_guid = osm_physp_get_port_guid(p_physp); 97321936Shselasky 98321936Shselasky /* HACK extended port 0 should be handled too! */ 99321936Shselasky if (osm_physp_get_port_num(p_physp) != 0 && 100321936Shselasky ib_port_info_get_port_state(p_pi) != IB_LINK_DOWN) { 101321936Shselasky /* track the minimal endport MTU, rate, and operational VLs */ 102321936Shselasky mtu = ib_port_info_get_mtu_cap(p_pi); 103321936Shselasky if (mtu < sm->p_subn->min_ca_mtu) { 104321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 105321936Shselasky "Setting endport minimal MTU to:%u defined by port:0x%" 106321936Shselasky PRIx64 "\n", mtu, cl_ntoh64(port_guid)); 107321936Shselasky sm->p_subn->min_ca_mtu = mtu; 108321936Shselasky } 109321936Shselasky 110321936Shselasky extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS; 111321936Shselasky rate = ib_port_info_compute_rate(p_pi, extended); 112321936Shselasky if (ib_path_compare_rates(rate, sm->p_subn->min_ca_rate) < 0) { 113321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 114321936Shselasky "Setting endport minimal rate to:%u defined by port:0x%" 115321936Shselasky PRIx64 "\n", rate, cl_ntoh64(port_guid)); 116321936Shselasky sm->p_subn->min_ca_rate = rate; 117321936Shselasky } 118321936Shselasky 119321936Shselasky data_vls = 1U << (ib_port_info_get_vl_cap(p_pi) - 1); 120321936Shselasky if (data_vls > 1U << (sm->p_subn->opt.max_op_vls - 1)) 121321936Shselasky data_vls = 1U << (sm->p_subn->opt.max_op_vls - 1); 122321936Shselasky if (data_vls >= IB_MAX_NUM_VLS) 123321936Shselasky data_vls = IB_MAX_NUM_VLS - 1; 124321936Shselasky if ((uint8_t)data_vls < sm->p_subn->min_data_vls) { 125321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 126321936Shselasky "Setting endport minimal data VLs to:%u defined by port:0x%" 127321936Shselasky PRIx64 "\n", data_vls, cl_ntoh64(port_guid)); 128321936Shselasky sm->p_subn->min_data_vls = data_vls; 129321936Shselasky } 130321936Shselasky } 131321936Shselasky 132321936Shselasky /* Check M_Key vs M_Key protect, can we control the port ? */ 133321936Shselasky mpb = ib_port_info_get_mpb(p_pi); 134321936Shselasky if (mpb > 0 && p_pi->m_key == 0) { 135321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_INFO, 136321936Shselasky "Port 0x%" PRIx64 " has unknown M_Key, protection level %u\n", 137321936Shselasky cl_ntoh64(port_guid), mpb); 138321936Shselasky } 139321936Shselasky 140321936Shselasky if (port_guid != sm->p_subn->sm_port_guid) { 141321936Shselasky p_sm_tbl = &sm->p_subn->sm_guid_tbl; 142321936Shselasky if (p_pi->capability_mask & IB_PORT_CAP_IS_SM) { 143321936Shselasky /* 144321936Shselasky * Before querying the SM - we want to make sure we 145321936Shselasky * clean its state, so if the querying fails we 146321936Shselasky * recognize that this SM is not active. 147321936Shselasky */ 148321936Shselasky p_sm = 149321936Shselasky (osm_remote_sm_t *) cl_qmap_get(p_sm_tbl, 150321936Shselasky port_guid); 151321936Shselasky if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) 152321936Shselasky /* clean it up */ 153321936Shselasky p_sm->smi.pri_state = 154321936Shselasky 0xF0 & p_sm->smi.pri_state; 155321936Shselasky if (sm->p_subn->opt.ignore_other_sm) 156321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 157321936Shselasky "Ignoring SM on port 0x%" PRIx64 "\n", 158321936Shselasky cl_ntoh64(port_guid)); 159321936Shselasky else { 160321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 161321936Shselasky "Detected another SM. Requesting SMInfo " 162321936Shselasky "from port 0x%" PRIx64 "\n", 163321936Shselasky cl_ntoh64(port_guid)); 164321936Shselasky 165321936Shselasky /* 166321936Shselasky This port indicates it's an SM and 167321936Shselasky it's not our own port. 168321936Shselasky Acquire the SMInfo Attribute. 169321936Shselasky */ 170321936Shselasky memset(&context, 0, sizeof(context)); 171321936Shselasky context.smi_context.set_method = FALSE; 172321936Shselasky context.smi_context.port_guid = port_guid; 173321936Shselasky status = osm_req_get(sm, 174321936Shselasky osm_physp_get_dr_path_ptr 175321936Shselasky (p_physp), 176321936Shselasky IB_MAD_ATTR_SM_INFO, 0, 177321936Shselasky FALSE, 178321936Shselasky ib_port_info_get_m_key(&p_physp->port_info), 179321936Shselasky CL_DISP_MSGID_NONE, 180321936Shselasky &context); 181321936Shselasky 182321936Shselasky if (status != IB_SUCCESS) 183321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, 184321936Shselasky "ERR 0F05: " 185321936Shselasky "Failure requesting SMInfo (%s) " 186321936Shselasky "from port 0x%" PRIx64 "\n", 187321936Shselasky ib_get_err_str(status), 188321936Shselasky cl_ntoh64(port_guid)); 189321936Shselasky } 190321936Shselasky } else { 191321936Shselasky p_sm = 192321936Shselasky (osm_remote_sm_t *) cl_qmap_remove(p_sm_tbl, 193321936Shselasky port_guid); 194321936Shselasky if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) 195321936Shselasky free(p_sm); 196321936Shselasky } 197321936Shselasky } 198321936Shselasky 199321936Shselasky OSM_LOG_EXIT(sm->p_log); 200321936Shselasky} 201321936Shselasky 202321936Shselasky/********************************************************************** 203321936Shselasky The plock must be held before calling this function. 204321936Shselasky**********************************************************************/ 205321936Shselaskystatic void pi_rcv_process_switch_port0(IN osm_sm_t * sm, 206321936Shselasky IN osm_node_t * p_node, 207321936Shselasky IN osm_physp_t * p_physp, 208321936Shselasky IN ib_port_info_t * p_pi) 209321936Shselasky{ 210321936Shselasky ib_api_status_t status; 211321936Shselasky osm_madw_context_t context; 212321936Shselasky uint8_t port, num_ports; 213321936Shselasky 214321936Shselasky OSM_LOG_ENTER(sm->p_log); 215321936Shselasky 216321936Shselasky if (p_physp->need_update) 217321936Shselasky sm->p_subn->ignore_existing_lfts = TRUE; 218321936Shselasky 219321936Shselasky pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp); 220321936Shselasky 221321936Shselasky /* Update the PortInfo attribute */ 222321936Shselasky osm_physp_set_port_info(p_physp, p_pi, sm); 223321936Shselasky 224321936Shselasky /* Determine if base switch port 0 */ 225321936Shselasky if (p_node->sw && 226321936Shselasky !ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info)) 227321936Shselasky /* PortState is not used on BSP0 but just in case it is DOWN */ 228321936Shselasky p_physp->port_info = *p_pi; 229321936Shselasky 230321936Shselasky /* Now, query PortInfo for the switch external ports */ 231321936Shselasky num_ports = osm_node_get_num_physp(p_node); 232321936Shselasky 233321936Shselasky context.pi_context.node_guid = osm_node_get_node_guid(p_node); 234321936Shselasky context.pi_context.port_guid = osm_physp_get_port_guid(p_physp); 235321936Shselasky context.pi_context.set_method = FALSE; 236321936Shselasky context.pi_context.light_sweep = FALSE; 237321936Shselasky context.pi_context.active_transition = FALSE; 238321936Shselasky context.pi_context.client_rereg = FALSE; 239321936Shselasky 240321936Shselasky for (port = 1; port < num_ports; port++) { 241321936Shselasky status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_physp), 242321936Shselasky IB_MAD_ATTR_PORT_INFO, cl_hton32(port), 243321936Shselasky FALSE, 244321936Shselasky ib_port_info_get_m_key(&p_physp->port_info), 245321936Shselasky CL_DISP_MSGID_NONE, &context); 246321936Shselasky if (status != IB_SUCCESS) 247321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F16: " 248321936Shselasky "Failure initiating PortInfo request (%s)\n", 249321936Shselasky ib_get_err_str(status)); 250321936Shselasky } 251321936Shselasky 252321936Shselasky pi_rcv_process_endport(sm, p_physp, p_pi); 253321936Shselasky OSM_LOG_EXIT(sm->p_log); 254321936Shselasky} 255321936Shselasky 256321936Shselasky/********************************************************************** 257321936Shselasky The plock must be held before calling this function. 258321936Shselasky**********************************************************************/ 259321936Shselaskystatic void pi_rcv_process_switch_ext_port(IN osm_sm_t * sm, 260321936Shselasky IN osm_node_t * p_node, 261321936Shselasky IN osm_physp_t * p_physp, 262321936Shselasky IN ib_port_info_t * p_pi) 263321936Shselasky{ 264321936Shselasky ib_api_status_t status = IB_SUCCESS; 265321936Shselasky osm_madw_context_t context; 266321936Shselasky osm_physp_t *p_remote_physp, *physp0; 267321936Shselasky osm_node_t *p_remote_node; 268321936Shselasky ib_net64_t m_key; 269321936Shselasky unsigned data_vls; 270321936Shselasky uint8_t port_num; 271321936Shselasky uint8_t remote_port_num; 272321936Shselasky osm_dr_path_t path; 273321936Shselasky int mlnx_epi_supported = 0; 274321936Shselasky 275321936Shselasky OSM_LOG_ENTER(sm->p_log); 276321936Shselasky 277321936Shselasky /* 278321936Shselasky Check the state of the physical port. 279321936Shselasky If there appears to be something on the other end of the wire, 280321936Shselasky then ask for NodeInfo. Ignore the switch management port. 281321936Shselasky */ 282321936Shselasky port_num = osm_physp_get_port_num(p_physp); 283321936Shselasky 284321936Shselasky if (sm->p_subn->opt.fdr10) 285321936Shselasky mlnx_epi_supported = is_mlnx_ext_port_info_supported( 286321936Shselasky ib_node_info_get_vendor_id(&p_node->node_info), 287321936Shselasky p_node->node_info.device_id); 288321936Shselasky 289321936Shselasky /* if in_sweep_hop_0 is TRUE, then this means the SM is on the switch, 290321936Shselasky and we got switchInfo of our local switch. Do not continue 291321936Shselasky probing through the switch. */ 292321936Shselasky switch (ib_port_info_get_port_state(p_pi)) { 293321936Shselasky case IB_LINK_DOWN: 294321936Shselasky p_remote_physp = osm_physp_get_remote(p_physp); 295321936Shselasky if (p_remote_physp) { 296321936Shselasky p_remote_node = 297321936Shselasky osm_physp_get_node_ptr(p_remote_physp); 298321936Shselasky remote_port_num = 299321936Shselasky osm_physp_get_port_num(p_remote_physp); 300321936Shselasky 301321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 302321936Shselasky "Unlinking local node 0x%" PRIx64 303321936Shselasky ", port %u" 304321936Shselasky "\n\t\t\t\tand remote node 0x%" PRIx64 305321936Shselasky ", port %u\n", 306321936Shselasky cl_ntoh64(osm_node_get_node_guid 307321936Shselasky (p_node)), port_num, 308321936Shselasky cl_ntoh64(osm_node_get_node_guid 309321936Shselasky (p_remote_node)), 310321936Shselasky remote_port_num); 311321936Shselasky 312321936Shselasky if (sm->ucast_mgr.cache_valid) 313321936Shselasky osm_ucast_cache_add_link(&sm->ucast_mgr, 314321936Shselasky p_physp, 315321936Shselasky p_remote_physp); 316321936Shselasky 317321936Shselasky osm_node_unlink(p_node, (uint8_t) port_num, 318321936Shselasky p_remote_node, 319321936Shselasky (uint8_t) remote_port_num); 320321936Shselasky 321321936Shselasky } 322321936Shselasky break; 323321936Shselasky 324321936Shselasky case IB_LINK_INIT: 325321936Shselasky case IB_LINK_ARMED: 326321936Shselasky case IB_LINK_ACTIVE: 327321936Shselasky physp0 = osm_node_get_physp_ptr(p_node, 0); 328321936Shselasky if (mlnx_epi_supported) { 329321936Shselasky m_key = ib_port_info_get_m_key(&physp0->port_info); 330321936Shselasky 331321936Shselasky context.pi_context.node_guid = osm_node_get_node_guid(p_node); 332321936Shselasky context.pi_context.port_guid = osm_physp_get_port_guid(p_physp); 333321936Shselasky context.pi_context.set_method = FALSE; 334321936Shselasky context.pi_context.light_sweep = FALSE; 335321936Shselasky context.pi_context.active_transition = FALSE; 336321936Shselasky context.pi_context.client_rereg = FALSE; 337321936Shselasky status = osm_req_get(sm, 338321936Shselasky osm_physp_get_dr_path_ptr(p_physp), 339321936Shselasky IB_MAD_ATTR_MLNX_EXTENDED_PORT_INFO, 340321936Shselasky cl_hton32(port_num), FALSE, m_key, 341321936Shselasky CL_DISP_MSGID_NONE, &context); 342321936Shselasky if (status != IB_SUCCESS) 343321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F11: " 344321936Shselasky "Failure initiating MLNX ExtPortInfo request (%s)\n", 345321936Shselasky ib_get_err_str(status)); 346321936Shselasky } 347321936Shselasky if (sm->p_subn->in_sweep_hop_0 == FALSE) { 348321936Shselasky /* 349321936Shselasky To avoid looping forever, only probe the port if it 350321936Shselasky is NOT the port that responded to the SMP. 351321936Shselasky 352321936Shselasky Request node info from the other end of this link: 353321936Shselasky 1) Copy the current path from the parent node. 354321936Shselasky 2) Extend the path to the next hop thru this port. 355321936Shselasky 3) Request node info with the new path 356321936Shselasky 357321936Shselasky */ 358321936Shselasky if (p_pi->local_port_num != 359321936Shselasky osm_physp_get_port_num(p_physp)) { 360321936Shselasky path = *osm_physp_get_dr_path_ptr(p_physp); 361321936Shselasky 362321936Shselasky if (osm_dr_path_extend(&path, 363321936Shselasky osm_physp_get_port_num 364321936Shselasky (p_physp))) { 365321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, 366321936Shselasky "ERR 0F08: " 367321936Shselasky "DR path with hop count %d couldn't be extended\n", 368321936Shselasky path.hop_count); 369321936Shselasky break; 370321936Shselasky } 371321936Shselasky 372321936Shselasky memset(&context, 0, sizeof(context)); 373321936Shselasky context.ni_context.node_guid = 374321936Shselasky osm_node_get_node_guid(p_node); 375321936Shselasky context.ni_context.port_num = 376321936Shselasky osm_physp_get_port_num(p_physp); 377321936Shselasky 378321936Shselasky status = osm_req_get(sm, &path, 379321936Shselasky IB_MAD_ATTR_NODE_INFO, 0, 380321936Shselasky TRUE, 0, 381321936Shselasky CL_DISP_MSGID_NONE, 382321936Shselasky &context); 383321936Shselasky 384321936Shselasky if (status != IB_SUCCESS) 385321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, 386321936Shselasky "ERR 0F02: " 387321936Shselasky "Failure initiating NodeInfo request (%s)\n", 388321936Shselasky ib_get_err_str(status)); 389321936Shselasky } else 390321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 391321936Shselasky "Skipping SMP responder port %u\n", 392321936Shselasky p_pi->local_port_num); 393321936Shselasky } 394321936Shselasky break; 395321936Shselasky 396321936Shselasky default: 397321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F03: " 398321936Shselasky "Unknown link state = %u, port = %u\n", 399321936Shselasky ib_port_info_get_port_state(p_pi), 400321936Shselasky p_pi->local_port_num); 401321936Shselasky break; 402321936Shselasky } 403321936Shselasky 404321936Shselasky if (ib_port_info_get_port_state(p_pi) > IB_LINK_INIT && p_node->sw && 405321936Shselasky !ib_switch_info_get_state_change(&p_node->sw->switch_info) && 406321936Shselasky p_node->sw->need_update == 1) 407321936Shselasky p_node->sw->need_update = 0; 408321936Shselasky 409321936Shselasky if (p_physp->need_update) 410321936Shselasky sm->p_subn->ignore_existing_lfts = TRUE; 411321936Shselasky 412321936Shselasky /* 413321936Shselasky Update the PortInfo attribute. 414321936Shselasky */ 415321936Shselasky osm_physp_set_port_info(p_physp, p_pi, sm); 416321936Shselasky 417321936Shselasky if (ib_port_info_get_port_state(p_pi) == IB_LINK_DOWN) 418321936Shselasky goto Exit; 419321936Shselasky 420321936Shselasky p_remote_physp = osm_physp_get_remote(p_physp); 421321936Shselasky if (p_remote_physp) { 422321936Shselasky p_remote_node = osm_physp_get_node_ptr(p_remote_physp); 423321936Shselasky if (p_remote_node->sw) { 424321936Shselasky data_vls = 1U << (ib_port_info_get_vl_cap(p_pi) - 1); 425321936Shselasky if (data_vls > 1U << (sm->p_subn->opt.max_op_vls - 1)) 426321936Shselasky data_vls = 1U << (sm->p_subn->opt.max_op_vls - 1); 427321936Shselasky if (data_vls >= IB_MAX_NUM_VLS) 428321936Shselasky data_vls = IB_MAX_NUM_VLS - 1; 429321936Shselasky if ((uint8_t)data_vls < sm->p_subn->min_sw_data_vls) { 430321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 431321936Shselasky "Setting switch port minimal data VLs " 432321936Shselasky "to:%u defined by node:0x%" 433321936Shselasky PRIx64 ", port:%u\n", data_vls, 434321936Shselasky cl_ntoh64(osm_node_get_node_guid(p_node)), 435321936Shselasky port_num); 436321936Shselasky sm->p_subn->min_sw_data_vls = data_vls; 437321936Shselasky } 438321936Shselasky } 439321936Shselasky } 440321936Shselasky 441321936ShselaskyExit: 442321936Shselasky OSM_LOG_EXIT(sm->p_log); 443321936Shselasky} 444321936Shselasky 445321936Shselaskystatic void pi_rcv_process_ca_or_router_port(IN osm_sm_t * sm, 446321936Shselasky IN osm_node_t * p_node, 447321936Shselasky IN osm_physp_t * p_physp, 448321936Shselasky IN ib_port_info_t * p_pi) 449321936Shselasky{ 450321936Shselasky OSM_LOG_ENTER(sm->p_log); 451321936Shselasky 452321936Shselasky UNUSED_PARAM(p_node); 453321936Shselasky 454321936Shselasky pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp); 455321936Shselasky 456321936Shselasky osm_physp_set_port_info(p_physp, p_pi, sm); 457321936Shselasky 458321936Shselasky pi_rcv_process_endport(sm, p_physp, p_pi); 459321936Shselasky 460321936Shselasky OSM_LOG_EXIT(sm->p_log); 461321936Shselasky} 462321936Shselasky 463321936Shselasky#define IBM_VENDOR_ID (0x5076) 464321936Shselaskystatic void get_pkey_table(IN osm_log_t * p_log, IN osm_sm_t * sm, 465321936Shselasky IN osm_node_t * p_node, IN osm_physp_t * p_physp) 466321936Shselasky{ 467321936Shselasky 468321936Shselasky osm_madw_context_t context; 469321936Shselasky ib_api_status_t status; 470321936Shselasky osm_dr_path_t path; 471321936Shselasky osm_physp_t *physp0; 472321936Shselasky ib_net64_t m_key; 473321936Shselasky uint8_t port_num; 474321936Shselasky uint16_t block_num, max_blocks; 475321936Shselasky uint32_t attr_mod_ho; 476321936Shselasky 477321936Shselasky OSM_LOG_ENTER(p_log); 478321936Shselasky 479321936Shselasky path = *osm_physp_get_dr_path_ptr(p_physp); 480321936Shselasky 481321936Shselasky context.pkey_context.node_guid = osm_node_get_node_guid(p_node); 482321936Shselasky context.pkey_context.port_guid = osm_physp_get_port_guid(p_physp); 483321936Shselasky context.pkey_context.set_method = FALSE; 484321936Shselasky 485321936Shselasky port_num = p_physp->port_num; 486321936Shselasky 487321936Shselasky if (!p_node->sw || port_num == 0) 488321936Shselasky /* The maximum blocks is defined by the node info partition cap 489321936Shselasky for CA, router, and switch management ports. */ 490321936Shselasky max_blocks = 491321936Shselasky (cl_ntoh16(p_node->node_info.partition_cap) + 492321936Shselasky IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) 493321936Shselasky / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; 494321936Shselasky else { 495321936Shselasky /* This is a switch, and not a management port. The maximum blocks 496321936Shselasky is defined in the switch info partition enforcement cap. */ 497321936Shselasky 498321936Shselasky /* Check for IBM eHCA firmware defect in reporting partition enforcement cap */ 499321936Shselasky if (cl_ntoh32(ib_node_info_get_vendor_id(&p_node->node_info)) == 500321936Shselasky IBM_VENDOR_ID) 501321936Shselasky p_node->sw->switch_info.enforce_cap = 0; 502321936Shselasky 503321936Shselasky /* Bail out if this is a switch with no partition enforcement capability */ 504321936Shselasky if (cl_ntoh16(p_node->sw->switch_info.enforce_cap) == 0) 505321936Shselasky goto Exit; 506321936Shselasky 507321936Shselasky max_blocks = (cl_ntoh16(p_node->sw->switch_info.enforce_cap) + 508321936Shselasky IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 509321936Shselasky 1) / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; 510321936Shselasky } 511321936Shselasky 512321936Shselasky p_physp->pkeys.rcv_blocks_cnt = max_blocks; 513321936Shselasky for (block_num = 0; block_num < max_blocks; block_num++) { 514321936Shselasky if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH || 515321936Shselasky osm_physp_get_port_num(p_physp) == 0) { 516321936Shselasky attr_mod_ho = block_num; 517321936Shselasky m_key = ib_port_info_get_m_key(&p_physp->port_info); 518321936Shselasky } else { 519321936Shselasky attr_mod_ho = block_num | (port_num << 16); 520321936Shselasky physp0 = osm_node_get_physp_ptr(p_node, 0); 521321936Shselasky m_key = ib_port_info_get_m_key(&physp0->port_info); 522321936Shselasky } 523321936Shselasky status = osm_req_get(sm, &path, IB_MAD_ATTR_P_KEY_TABLE, 524321936Shselasky cl_hton32(attr_mod_ho), FALSE, 525321936Shselasky m_key, CL_DISP_MSGID_NONE, &context); 526321936Shselasky 527321936Shselasky if (status != IB_SUCCESS) { 528321936Shselasky OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0F12: " 529321936Shselasky "Failure initiating PKeyTable request (%s)\n", 530321936Shselasky ib_get_err_str(status)); 531321936Shselasky goto Exit; 532321936Shselasky } 533321936Shselasky } 534321936Shselasky 535321936ShselaskyExit: 536321936Shselasky OSM_LOG_EXIT(p_log); 537321936Shselasky} 538321936Shselasky 539321936Shselaskystatic void pi_rcv_get_pkey_slvl_vla_tables(IN osm_sm_t * sm, 540321936Shselasky IN osm_node_t * p_node, 541321936Shselasky IN osm_physp_t * p_physp) 542321936Shselasky{ 543321936Shselasky OSM_LOG_ENTER(sm->p_log); 544321936Shselasky 545321936Shselasky get_pkey_table(sm->p_log, sm, p_node, p_physp); 546321936Shselasky 547321936Shselasky OSM_LOG_EXIT(sm->p_log); 548321936Shselasky} 549321936Shselasky 550321936Shselaskystatic int osm_pi_rcv_update_self(IN osm_sm_t *sm, IN osm_physp_t *p_physp, 551321936Shselasky IN ib_port_info_t *p_pi) 552321936Shselasky{ 553321936Shselasky if (ib_port_info_get_port_state(p_pi) == IB_LINK_DOWN) 554321936Shselasky return 0; 555321936Shselasky 556321936Shselasky if (sm->p_subn->need_update || p_physp->need_update > 1 || 557321936Shselasky ib_port_info_get_port_state(p_pi) == IB_LINK_INIT) 558321936Shselasky return 1; 559321936Shselasky 560321936Shselasky return 0; 561321936Shselasky} 562321936Shselasky 563321936Shselaskystatic void pi_rcv_process_set(IN osm_sm_t * sm, IN osm_node_t * p_node, 564321936Shselasky IN uint8_t port_num, IN osm_madw_t * p_madw) 565321936Shselasky{ 566321936Shselasky osm_physp_t *p_physp; 567321936Shselasky ib_net64_t port_guid; 568321936Shselasky ib_smp_t *p_smp; 569321936Shselasky ib_port_info_t *p_pi; 570321936Shselasky osm_pi_context_t *p_context; 571321936Shselasky osm_log_level_t level; 572321936Shselasky 573321936Shselasky OSM_LOG_ENTER(sm->p_log); 574321936Shselasky 575321936Shselasky p_context = osm_madw_get_pi_context_ptr(p_madw); 576321936Shselasky 577321936Shselasky CL_ASSERT(p_node); 578321936Shselasky 579321936Shselasky p_physp = osm_node_get_physp_ptr(p_node, port_num); 580321936Shselasky CL_ASSERT(p_physp); 581321936Shselasky 582321936Shselasky port_guid = osm_physp_get_port_guid(p_physp); 583321936Shselasky 584321936Shselasky p_smp = osm_madw_get_smp_ptr(p_madw); 585321936Shselasky p_pi = ib_smp_get_payload_ptr(p_smp); 586321936Shselasky 587321936Shselasky /* check for error */ 588321936Shselasky if (cl_ntoh16(p_smp->status) & 0x7fff) { 589321936Shselasky /* If port already ACTIVE, don't treat status 7 as error */ 590321936Shselasky if (p_context->active_transition && 591321936Shselasky (cl_ntoh16(p_smp->status) & 0x7fff) == 0x1c) { 592321936Shselasky level = OSM_LOG_INFO; 593321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_INFO, 594321936Shselasky "Received error status 0x%x for SetResp() during ACTIVE transition\n", 595321936Shselasky cl_ntoh16(p_smp->status) & 0x7fff); 596321936Shselasky /* Should there be a subsequent Get to validate that port is ACTIVE ? */ 597321936Shselasky } else { 598321936Shselasky level = OSM_LOG_ERROR; 599321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F10: " 600321936Shselasky "Received error status for SetResp()\n"); 601321936Shselasky } 602321936Shselasky osm_dump_port_info_v2(sm->p_log, osm_node_get_node_guid(p_node), 603321936Shselasky port_guid, port_num, p_pi, FILE_ID, level); 604321936Shselasky } else 605321936Shselasky osm_physp_set_port_info(p_physp, p_pi, sm); 606321936Shselasky 607321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 608321936Shselasky "Received logical SetResp() for GUID 0x%" PRIx64 609321936Shselasky ", port num %u" 610321936Shselasky "\n\t\t\t\tfor parent node GUID 0x%" PRIx64 611321936Shselasky " TID 0x%" PRIx64 "\n", 612321936Shselasky cl_ntoh64(port_guid), port_num, 613321936Shselasky cl_ntoh64(osm_node_get_node_guid(p_node)), 614321936Shselasky cl_ntoh64(p_smp->trans_id)); 615321936Shselasky 616321936Shselasky 617321936Shselasky OSM_LOG_EXIT(sm->p_log); 618321936Shselasky} 619321936Shselasky 620321936Shselaskystatic int osm_pi_rcv_update_neighbor(IN osm_physp_t *p_physp) 621321936Shselasky{ 622321936Shselasky osm_physp_t *p_rem_physp = p_physp->p_remote_physp; 623321936Shselasky osm_node_t *p_node; 624321936Shselasky 625321936Shselasky /* 626321936Shselasky * Our own port - this is the only case where CA port 627321936Shselasky * is discovered before its' neighbor port 628321936Shselasky */ 629321936Shselasky if (!p_rem_physp) 630321936Shselasky return p_physp->need_update; 631321936Shselasky 632321936Shselasky p_node = osm_physp_get_node_ptr(p_rem_physp); 633321936Shselasky CL_ASSERT(p_node); 634321936Shselasky 635321936Shselasky /* CA/RTR to CA/RTR connection */ 636321936Shselasky if (!p_node->sw) 637321936Shselasky return p_physp->need_update; 638321936Shselasky 639321936Shselasky return (ib_switch_info_get_state_change(&p_node->sw->switch_info) ? 1 : p_physp->need_update); 640321936Shselasky} 641321936Shselasky 642321936Shselaskyvoid osm_pi_rcv_process(IN void *context, IN void *data) 643321936Shselasky{ 644321936Shselasky osm_sm_t *sm = context; 645321936Shselasky osm_madw_t *p_madw = data; 646321936Shselasky ib_port_info_t *p_pi; 647321936Shselasky ib_smp_t *p_smp; 648321936Shselasky osm_port_t *p_port; 649321936Shselasky osm_physp_t *p_physp; 650321936Shselasky osm_dr_path_t *p_dr_path; 651321936Shselasky osm_node_t *p_node; 652321936Shselasky osm_pi_context_t *p_context; 653321936Shselasky ib_net64_t port_guid, node_guid; 654321936Shselasky uint8_t port_num; 655321936Shselasky 656321936Shselasky CL_ASSERT(sm); 657321936Shselasky 658321936Shselasky OSM_LOG_ENTER(sm->p_log); 659321936Shselasky 660321936Shselasky CL_ASSERT(p_madw); 661321936Shselasky 662321936Shselasky p_smp = osm_madw_get_smp_ptr(p_madw); 663321936Shselasky p_context = osm_madw_get_pi_context_ptr(p_madw); 664321936Shselasky p_pi = ib_smp_get_payload_ptr(p_smp); 665321936Shselasky 666321936Shselasky CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_PORT_INFO); 667321936Shselasky 668321936Shselasky /* 669321936Shselasky * Attribute modifier has already been validated upon MAD receive, 670321936Shselasky * which means that port_num has to be valid - it originated from 671321936Shselasky * the request attribute modifier. 672321936Shselasky */ 673321936Shselasky port_num = (uint8_t) cl_ntoh32(p_smp->attr_mod); 674321936Shselasky 675321936Shselasky port_guid = p_context->port_guid; 676321936Shselasky node_guid = p_context->node_guid; 677321936Shselasky 678321936Shselasky osm_dump_port_info_v2(sm->p_log, node_guid, port_guid, port_num, p_pi, 679321936Shselasky FILE_ID, OSM_LOG_DEBUG); 680321936Shselasky 681321936Shselasky /* On receipt of client reregister, clear the reregister bit so 682321936Shselasky reregistering won't be sent again and again */ 683321936Shselasky if (p_context->set_method && 684321936Shselasky (ib_port_info_get_client_rereg(p_pi) || p_context->client_rereg)) { 685321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 686321936Shselasky "Client reregister received on response\n"); 687321936Shselasky ib_port_info_set_client_rereg(p_pi, 0); 688321936Shselasky p_context->client_rereg = FALSE; 689321936Shselasky } 690321936Shselasky 691321936Shselasky /* 692321936Shselasky we might get a response during a light sweep looking for a change in 693321936Shselasky the status of a remote port that did not respond in earlier sweeps. 694321936Shselasky So if the context of the Get was light_sweep - we do not need to 695321936Shselasky do anything with the response - just flag that we need a heavy sweep 696321936Shselasky */ 697321936Shselasky if (p_context->light_sweep == TRUE) { 698321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 699321936Shselasky "Got light sweep response from remote port of parent node " 700321936Shselasky "GUID 0x%" PRIx64 " port 0x%016" PRIx64 701321936Shselasky ", Commencing heavy sweep\n", 702321936Shselasky cl_ntoh64(node_guid), cl_ntoh64(port_guid)); 703321936Shselasky sm->p_subn->force_heavy_sweep = TRUE; 704321936Shselasky sm->p_subn->ignore_existing_lfts = TRUE; 705321936Shselasky goto Exit; 706321936Shselasky } 707321936Shselasky 708321936Shselasky CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); 709321936Shselasky p_port = osm_get_port_by_guid(sm->p_subn, port_guid); 710321936Shselasky if (PF(!p_port)) { 711321936Shselasky CL_PLOCK_RELEASE(sm->p_lock); 712321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F06: " 713321936Shselasky "No port object for port with GUID 0x%" PRIx64 714321936Shselasky "\n\t\t\t\tfor parent node GUID 0x%" PRIx64 715321936Shselasky ", TID 0x%" PRIx64 "\n", 716321936Shselasky cl_ntoh64(port_guid), 717321936Shselasky cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); 718321936Shselasky goto Exit; 719321936Shselasky } 720321936Shselasky 721321936Shselasky p_node = p_port->p_node; 722321936Shselasky CL_ASSERT(p_node); 723321936Shselasky 724321936Shselasky if (PF(p_pi->local_port_num > p_node->node_info.num_ports)) { 725321936Shselasky CL_PLOCK_RELEASE(sm->p_lock); 726321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F15: " 727321936Shselasky "Received PortInfo for port GUID 0x%" PRIx64 " is " 728321936Shselasky "non-compliant and is being ignored since the " 729321936Shselasky "local port num %u > num ports %u\n", 730321936Shselasky cl_ntoh64(port_guid), p_pi->local_port_num, 731321936Shselasky p_node->node_info.num_ports); 732321936Shselasky goto Exit; 733321936Shselasky } 734321936Shselasky 735321936Shselasky /* 736321936Shselasky If we were setting the PortInfo, then receiving 737321936Shselasky this attribute was not part of sweeping the subnet. 738321936Shselasky In this case, just update the PortInfo attribute. 739321936Shselasky 740321936Shselasky In an unfortunate blunder, the IB spec defines the 741321936Shselasky return method for Set() as a GetResp(). Thus, we can't 742321936Shselasky use the method (what would have been SetResp()) to determine 743321936Shselasky our course of action. So, we have to carry this extra 744321936Shselasky boolean around to determine if we were doing Get() or Set(). 745321936Shselasky */ 746321936Shselasky if (p_context->set_method) 747321936Shselasky pi_rcv_process_set(sm, p_node, port_num, p_madw); 748321936Shselasky else { 749321936Shselasky 750321936Shselasky /* 751321936Shselasky This PortInfo arrived because we did a Get() method, 752321936Shselasky most likely due to a subnet sweep in progress. 753321936Shselasky */ 754321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 755321936Shselasky "Discovered port num %u with GUID 0x%" PRIx64 756321936Shselasky " for parent node GUID 0x%" PRIx64 757321936Shselasky ", TID 0x%" PRIx64 "\n", 758321936Shselasky port_num, cl_ntoh64(port_guid), 759321936Shselasky cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); 760321936Shselasky 761321936Shselasky p_physp = osm_node_get_physp_ptr(p_node, port_num); 762321936Shselasky 763321936Shselasky CL_ASSERT(p_physp); 764321936Shselasky 765321936Shselasky /* Update the directed route path to this port 766321936Shselasky in case the old path is no longer usable. */ 767321936Shselasky p_dr_path = osm_physp_get_dr_path_ptr(p_physp); 768321936Shselasky osm_dr_path_init(p_dr_path, p_smp->hop_count, 769321936Shselasky p_smp->initial_path); 770321936Shselasky 771321936Shselasky p_physp->need_update = osm_pi_rcv_update_self(sm, p_physp, p_pi); 772321936Shselasky 773321936Shselasky switch (osm_node_get_type(p_node)) { 774321936Shselasky case IB_NODE_TYPE_CA: 775321936Shselasky case IB_NODE_TYPE_ROUTER: 776321936Shselasky if (!p_node->physp_discovered[port_num]) { 777321936Shselasky p_port->discovery_count++; 778321936Shselasky p_node->physp_discovered[port_num] = 1; 779321936Shselasky } 780321936Shselasky p_physp->need_update = osm_pi_rcv_update_neighbor(p_physp); 781321936Shselasky pi_rcv_process_ca_or_router_port(sm, p_node, p_physp, 782321936Shselasky p_pi); 783321936Shselasky break; 784321936Shselasky case IB_NODE_TYPE_SWITCH: 785321936Shselasky if (!p_node->physp_discovered[port_num]) { 786321936Shselasky p_port->discovery_count++; 787321936Shselasky p_node->physp_discovered[port_num] = 1; 788321936Shselasky } 789321936Shselasky if (port_num == 0) 790321936Shselasky pi_rcv_process_switch_port0(sm, p_node, 791321936Shselasky p_physp, p_pi); 792321936Shselasky else 793321936Shselasky pi_rcv_process_switch_ext_port(sm, p_node, 794321936Shselasky p_physp, p_pi); 795321936Shselasky break; 796321936Shselasky default: 797321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F07: " 798321936Shselasky "Unknown node type %u with GUID 0x%" PRIx64 799321936Shselasky "\n", osm_node_get_type(p_node), 800321936Shselasky cl_ntoh64(node_guid)); 801321936Shselasky break; 802321936Shselasky } 803321936Shselasky 804321936Shselasky /* 805321936Shselasky Get the tables on the physp. 806321936Shselasky */ 807321936Shselasky if (p_physp->need_update || (p_node->sw && 808321936Shselasky p_node->sw->need_update)) 809321936Shselasky pi_rcv_get_pkey_slvl_vla_tables(sm, p_node, p_physp); 810321936Shselasky 811321936Shselasky } 812321936Shselasky 813321936Shselasky CL_PLOCK_RELEASE(sm->p_lock); 814321936Shselasky 815321936ShselaskyExit: 816321936Shselasky /* 817321936Shselasky Release the lock before jumping here!! 818321936Shselasky */ 819321936Shselasky OSM_LOG_EXIT(sm->p_log); 820321936Shselasky} 821