1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3219820Sjeff * Copyright (c) 2002-2008 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_pi_rcv_t. 39219820Sjeff * This object represents the PortInfo Receiver object. 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 <string.h> 48219820Sjeff#include <iba/ib_types.h> 49219820Sjeff#include <complib/cl_qmap.h> 50219820Sjeff#include <complib/cl_passivelock.h> 51219820Sjeff#include <complib/cl_debug.h> 52219820Sjeff#include <vendor/osm_vendor_api.h> 53219820Sjeff#include <opensm/osm_madw.h> 54219820Sjeff#include <opensm/osm_log.h> 55219820Sjeff#include <opensm/osm_node.h> 56219820Sjeff#include <opensm/osm_subnet.h> 57219820Sjeff#include <opensm/osm_mad_pool.h> 58219820Sjeff#include <opensm/osm_msgdef.h> 59219820Sjeff#include <opensm/osm_helper.h> 60219820Sjeff#include <opensm/osm_pkey.h> 61219820Sjeff#include <opensm/osm_remote_sm.h> 62219820Sjeff#include <opensm/osm_opensm.h> 63219820Sjeff#include <opensm/osm_ucast_mgr.h> 64219820Sjeff 65219820Sjeff/********************************************************************** 66219820Sjeff **********************************************************************/ 67219820Sjeffstatic void 68219820Sjeff__osm_pi_rcv_set_sm(IN osm_sm_t * sm, 69219820Sjeff IN osm_physp_t * const p_physp) 70219820Sjeff{ 71219820Sjeff osm_bind_handle_t h_bind; 72219820Sjeff osm_dr_path_t *p_dr_path; 73219820Sjeff 74219820Sjeff OSM_LOG_ENTER(sm->p_log); 75219820Sjeff 76219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 77219820Sjeff "Setting IS_SM bit in port attributes\n"); 78219820Sjeff 79219820Sjeff p_dr_path = osm_physp_get_dr_path_ptr(p_physp); 80219820Sjeff h_bind = osm_dr_path_get_bind_handle(p_dr_path); 81219820Sjeff 82219820Sjeff /* 83219820Sjeff The 'IS_SM' bit isn't already set, so set it. 84219820Sjeff */ 85219820Sjeff osm_vendor_set_sm(h_bind, TRUE); 86219820Sjeff 87219820Sjeff OSM_LOG_EXIT(sm->p_log); 88219820Sjeff} 89219820Sjeff 90219820Sjeff/********************************************************************** 91219820Sjeff **********************************************************************/ 92219820Sjeffstatic void pi_rcv_check_and_fix_lid(osm_log_t *log, ib_port_info_t * const pi, 93219820Sjeff osm_physp_t * p) 94219820Sjeff{ 95219820Sjeff if (cl_ntoh16(pi->base_lid) > IB_LID_UCAST_END_HO) { 96219820Sjeff OSM_LOG(log, OSM_LOG_ERROR, "ERR 0F04: " 97219820Sjeff "Got invalid base LID %u from the network. " 98219820Sjeff "Corrected to %u.\n", cl_ntoh16(pi->base_lid), 99219820Sjeff cl_ntoh16(p->port_info.base_lid)); 100219820Sjeff pi->base_lid = p->port_info.base_lid; 101219820Sjeff } 102219820Sjeff} 103219820Sjeff 104219820Sjeff/********************************************************************** 105219820Sjeff **********************************************************************/ 106219820Sjeffstatic void 107219820Sjeff__osm_pi_rcv_process_endport(IN osm_sm_t * sm, 108219820Sjeff IN osm_physp_t * const p_physp, 109219820Sjeff IN const ib_port_info_t * const p_pi) 110219820Sjeff{ 111219820Sjeff osm_madw_context_t context; 112219820Sjeff ib_api_status_t status; 113219820Sjeff ib_net64_t port_guid; 114219820Sjeff uint8_t rate, mtu; 115219820Sjeff cl_qmap_t *p_sm_tbl; 116219820Sjeff osm_remote_sm_t *p_sm; 117219820Sjeff 118219820Sjeff OSM_LOG_ENTER(sm->p_log); 119219820Sjeff 120219820Sjeff port_guid = osm_physp_get_port_guid(p_physp); 121219820Sjeff 122219820Sjeff /* HACK extended port 0 should be handled too! */ 123219820Sjeff if (osm_physp_get_port_num(p_physp) != 0) { 124219820Sjeff /* track the minimal endport MTU and rate */ 125219820Sjeff mtu = ib_port_info_get_mtu_cap(p_pi); 126219820Sjeff if (mtu < sm->p_subn->min_ca_mtu) { 127219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 128219820Sjeff "Setting endport minimal MTU to:%u defined by port:0x%" 129219820Sjeff PRIx64 "\n", mtu, cl_ntoh64(port_guid)); 130219820Sjeff sm->p_subn->min_ca_mtu = mtu; 131219820Sjeff } 132219820Sjeff 133219820Sjeff rate = ib_port_info_compute_rate(p_pi); 134219820Sjeff if (rate < sm->p_subn->min_ca_rate) { 135219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 136219820Sjeff "Setting endport minimal rate to:%u defined by port:0x%" 137219820Sjeff PRIx64 "\n", rate, cl_ntoh64(port_guid)); 138219820Sjeff sm->p_subn->min_ca_rate = rate; 139219820Sjeff } 140219820Sjeff } 141219820Sjeff 142219820Sjeff if (port_guid == sm->p_subn->sm_port_guid) { 143219820Sjeff /* 144219820Sjeff We received the PortInfo for our own port. 145219820Sjeff */ 146219820Sjeff if (!(p_pi->capability_mask & IB_PORT_CAP_IS_SM)) 147219820Sjeff /* 148219820Sjeff Set the IS_SM bit to indicate our port hosts an SM. 149219820Sjeff */ 150219820Sjeff __osm_pi_rcv_set_sm(sm, p_physp); 151219820Sjeff } else { 152219820Sjeff p_sm_tbl = &sm->p_subn->sm_guid_tbl; 153219820Sjeff if (p_pi->capability_mask & IB_PORT_CAP_IS_SM) { 154219820Sjeff /* 155219820Sjeff * Before querying the SM - we want to make sure we 156219820Sjeff * clean its state, so if the querying fails we 157219820Sjeff * recognize that this SM is not active. 158219820Sjeff */ 159219820Sjeff p_sm = (osm_remote_sm_t *) cl_qmap_get(p_sm_tbl, port_guid); 160219820Sjeff if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) 161219820Sjeff /* clean it up */ 162219820Sjeff p_sm->smi.pri_state = 0xF0 & p_sm->smi.pri_state; 163219820Sjeff if (sm->p_subn->opt.ignore_other_sm) 164219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 165219820Sjeff "Ignoring SM on port 0x%" PRIx64 "\n", 166219820Sjeff cl_ntoh64(port_guid)); 167219820Sjeff else { 168219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 169219820Sjeff "Detected another SM. Requesting SMInfo" 170219820Sjeff "\n\t\t\t\tPort 0x%" PRIx64 "\n", 171219820Sjeff cl_ntoh64(port_guid)); 172219820Sjeff 173219820Sjeff /* 174219820Sjeff This port indicates it's an SM and 175219820Sjeff it's not our own port. 176219820Sjeff Acquire the SMInfo Attribute. 177219820Sjeff */ 178219820Sjeff memset(&context, 0, sizeof(context)); 179219820Sjeff context.smi_context.set_method = FALSE; 180219820Sjeff context.smi_context.port_guid = port_guid; 181219820Sjeff status = osm_req_get(sm, 182219820Sjeff osm_physp_get_dr_path_ptr 183219820Sjeff (p_physp), 184219820Sjeff IB_MAD_ATTR_SM_INFO, 0, 185219820Sjeff CL_DISP_MSGID_NONE, 186219820Sjeff &context); 187219820Sjeff 188219820Sjeff if (status != IB_SUCCESS) 189219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_ERROR, 190219820Sjeff "ERR 0F05: " 191219820Sjeff "Failure requesting SMInfo (%s)\n", 192219820Sjeff ib_get_err_str(status)); 193219820Sjeff } 194219820Sjeff } else { 195219820Sjeff p_sm = (osm_remote_sm_t *) cl_qmap_remove(p_sm_tbl, port_guid); 196219820Sjeff if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) 197219820Sjeff free(p_sm); 198219820Sjeff } 199219820Sjeff } 200219820Sjeff 201219820Sjeff OSM_LOG_EXIT(sm->p_log); 202219820Sjeff} 203219820Sjeff 204219820Sjeff/********************************************************************** 205219820Sjeff The plock must be held before calling this function. 206219820Sjeff**********************************************************************/ 207219820Sjeffstatic void 208219820Sjeff__osm_pi_rcv_process_switch_port(IN osm_sm_t * sm, 209219820Sjeff IN osm_node_t * const p_node, 210219820Sjeff IN osm_physp_t * const p_physp, 211219820Sjeff IN ib_port_info_t * const p_pi) 212219820Sjeff{ 213219820Sjeff ib_api_status_t status = IB_SUCCESS; 214219820Sjeff osm_madw_context_t context; 215219820Sjeff osm_physp_t *p_remote_physp; 216219820Sjeff osm_node_t *p_remote_node; 217219820Sjeff uint8_t port_num; 218219820Sjeff uint8_t remote_port_num; 219219820Sjeff osm_dr_path_t path; 220219820Sjeff 221219820Sjeff OSM_LOG_ENTER(sm->p_log); 222219820Sjeff 223219820Sjeff /* 224219820Sjeff Check the state of the physical port. 225219820Sjeff If there appears to be something on the other end of the wire, 226219820Sjeff then ask for NodeInfo. Ignore the switch management port. 227219820Sjeff */ 228219820Sjeff port_num = osm_physp_get_port_num(p_physp); 229219820Sjeff /* if in_sweep_hop_0 is TRUE, then this means the SM is on the switch, 230219820Sjeff and we got switchInfo of our local switch. Do not continue 231219820Sjeff probing through the switch. */ 232219820Sjeff if (port_num != 0 && sm->p_subn->in_sweep_hop_0 == FALSE) { 233219820Sjeff switch (ib_port_info_get_port_state(p_pi)) { 234219820Sjeff case IB_LINK_DOWN: 235219820Sjeff p_remote_physp = osm_physp_get_remote(p_physp); 236219820Sjeff if (p_remote_physp) { 237219820Sjeff p_remote_node = 238219820Sjeff osm_physp_get_node_ptr(p_remote_physp); 239219820Sjeff remote_port_num = 240219820Sjeff osm_physp_get_port_num(p_remote_physp); 241219820Sjeff 242219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 243219820Sjeff "Unlinking local node 0x%" PRIx64 244219820Sjeff ", port %u" 245219820Sjeff "\n\t\t\t\tand remote node 0x%" PRIx64 246219820Sjeff ", port %u\n", 247219820Sjeff cl_ntoh64(osm_node_get_node_guid 248219820Sjeff (p_node)), port_num, 249219820Sjeff cl_ntoh64(osm_node_get_node_guid 250219820Sjeff (p_remote_node)), 251219820Sjeff remote_port_num); 252219820Sjeff 253219820Sjeff if (sm->ucast_mgr.cache_valid) 254219820Sjeff osm_ucast_cache_add_link(&sm->ucast_mgr, 255219820Sjeff p_physp, 256219820Sjeff p_remote_physp); 257219820Sjeff 258219820Sjeff osm_node_unlink(p_node, (uint8_t) port_num, 259219820Sjeff p_remote_node, 260219820Sjeff (uint8_t) remote_port_num); 261219820Sjeff 262219820Sjeff } 263219820Sjeff break; 264219820Sjeff 265219820Sjeff case IB_LINK_INIT: 266219820Sjeff case IB_LINK_ARMED: 267219820Sjeff case IB_LINK_ACTIVE: 268219820Sjeff /* 269219820Sjeff To avoid looping forever, only probe the port if it 270219820Sjeff is NOT the port that responded to the SMP. 271219820Sjeff 272219820Sjeff Request node info from the other end of this link: 273219820Sjeff 1) Copy the current path from the parent node. 274219820Sjeff 2) Extend the path to the next hop thru this port. 275219820Sjeff 3) Request node info with the new path 276219820Sjeff 277219820Sjeff */ 278219820Sjeff if (p_pi->local_port_num != 279219820Sjeff osm_physp_get_port_num(p_physp)) { 280219820Sjeff path = *osm_physp_get_dr_path_ptr(p_physp); 281219820Sjeff 282219820Sjeff osm_dr_path_extend(&path, 283219820Sjeff osm_physp_get_port_num 284219820Sjeff (p_physp)); 285219820Sjeff 286219820Sjeff memset(&context, 0, sizeof(context)); 287219820Sjeff context.ni_context.node_guid = 288219820Sjeff osm_node_get_node_guid(p_node); 289219820Sjeff context.ni_context.port_num = 290219820Sjeff osm_physp_get_port_num(p_physp); 291219820Sjeff 292219820Sjeff status = osm_req_get(sm, 293219820Sjeff &path, 294219820Sjeff IB_MAD_ATTR_NODE_INFO, 295219820Sjeff 0, 296219820Sjeff CL_DISP_MSGID_NONE, 297219820Sjeff &context); 298219820Sjeff 299219820Sjeff if (status != IB_SUCCESS) 300219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_ERROR, 301219820Sjeff "ERR 0F02: " 302219820Sjeff "Failure initiating NodeInfo request (%s)\n", 303219820Sjeff ib_get_err_str(status)); 304219820Sjeff } else 305219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 306219820Sjeff "Skipping SMP responder port %u\n", 307219820Sjeff p_pi->local_port_num); 308219820Sjeff break; 309219820Sjeff 310219820Sjeff default: 311219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F03: " 312219820Sjeff "Unknown link state = %u, port = %u\n", 313219820Sjeff ib_port_info_get_port_state(p_pi), 314219820Sjeff p_pi->local_port_num); 315219820Sjeff break; 316219820Sjeff } 317219820Sjeff } 318219820Sjeff 319219820Sjeff if (ib_port_info_get_port_state(p_pi) > IB_LINK_INIT && p_node->sw && 320219820Sjeff p_node->sw->need_update == 1) 321219820Sjeff p_node->sw->need_update = 0; 322219820Sjeff 323219820Sjeff if (p_physp->need_update) 324219820Sjeff sm->p_subn->ignore_existing_lfts = TRUE; 325219820Sjeff 326219820Sjeff if (port_num == 0) 327219820Sjeff pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp); 328219820Sjeff 329219820Sjeff /* 330219820Sjeff Update the PortInfo attribute. 331219820Sjeff */ 332219820Sjeff osm_physp_set_port_info(p_physp, p_pi); 333219820Sjeff 334219820Sjeff if (port_num == 0) { 335219820Sjeff /* Determine if base switch port 0 */ 336219820Sjeff if (p_node->sw && 337219820Sjeff !ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info)) 338219820Sjeff /* PortState is not used on BSP0 but just in case it is DOWN */ 339219820Sjeff p_physp->port_info = *p_pi; 340219820Sjeff __osm_pi_rcv_process_endport(sm, p_physp, p_pi); 341219820Sjeff } 342219820Sjeff 343219820Sjeff OSM_LOG_EXIT(sm->p_log); 344219820Sjeff} 345219820Sjeff 346219820Sjeff/********************************************************************** 347219820Sjeff **********************************************************************/ 348219820Sjeffstatic void 349219820Sjeff__osm_pi_rcv_process_ca_or_router_port(IN osm_sm_t * sm, 350219820Sjeff IN osm_node_t * const p_node, 351219820Sjeff IN osm_physp_t * const p_physp, 352219820Sjeff IN ib_port_info_t * const p_pi) 353219820Sjeff{ 354219820Sjeff OSM_LOG_ENTER(sm->p_log); 355219820Sjeff 356219820Sjeff UNUSED_PARAM(p_node); 357219820Sjeff 358219820Sjeff pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp); 359219820Sjeff 360219820Sjeff osm_physp_set_port_info(p_physp, p_pi); 361219820Sjeff 362219820Sjeff __osm_pi_rcv_process_endport(sm, p_physp, p_pi); 363219820Sjeff 364219820Sjeff OSM_LOG_EXIT(sm->p_log); 365219820Sjeff} 366219820Sjeff 367219820Sjeff#define IBM_VENDOR_ID (0x5076) 368219820Sjeff/********************************************************************** 369219820Sjeff **********************************************************************/ 370219820Sjeffstatic void get_pkey_table(IN osm_log_t * p_log, 371219820Sjeff IN osm_sm_t * sm, 372219820Sjeff IN osm_node_t * const p_node, 373219820Sjeff IN osm_physp_t * const p_physp) 374219820Sjeff{ 375219820Sjeff 376219820Sjeff osm_madw_context_t context; 377219820Sjeff ib_api_status_t status; 378219820Sjeff osm_dr_path_t path; 379219820Sjeff uint8_t port_num; 380219820Sjeff uint16_t block_num, max_blocks; 381219820Sjeff uint32_t attr_mod_ho; 382219820Sjeff 383219820Sjeff OSM_LOG_ENTER(p_log); 384219820Sjeff 385219820Sjeff path = *osm_physp_get_dr_path_ptr(p_physp); 386219820Sjeff 387219820Sjeff context.pkey_context.node_guid = osm_node_get_node_guid(p_node); 388219820Sjeff context.pkey_context.port_guid = osm_physp_get_port_guid(p_physp); 389219820Sjeff context.pkey_context.set_method = FALSE; 390219820Sjeff 391219820Sjeff port_num = p_physp->port_num; 392219820Sjeff 393219820Sjeff if (!p_node->sw || port_num == 0) 394219820Sjeff /* The maximum blocks is defined by the node info partition cap for CA, 395219820Sjeff router, and switch management ports. */ 396219820Sjeff max_blocks = 397219820Sjeff (cl_ntoh16(p_node->node_info.partition_cap) + 398219820Sjeff IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) 399219820Sjeff / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; 400219820Sjeff else { 401219820Sjeff /* This is a switch, and not a management port. The maximum blocks 402219820Sjeff is defined in the switch info partition enforcement cap. */ 403219820Sjeff 404219820Sjeff /* Check for IBM eHCA firmware defect in reporting partition enforcement cap */ 405219820Sjeff if (cl_ntoh32(ib_node_info_get_vendor_id(&p_node->node_info)) == 406219820Sjeff IBM_VENDOR_ID) 407219820Sjeff p_node->sw->switch_info.enforce_cap = 0; 408219820Sjeff 409219820Sjeff /* Bail out if this is a switch with no partition enforcement capability */ 410219820Sjeff if (cl_ntoh16(p_node->sw->switch_info.enforce_cap) == 0) 411219820Sjeff goto Exit; 412219820Sjeff 413219820Sjeff max_blocks = (cl_ntoh16(p_node->sw->switch_info.enforce_cap) + 414219820Sjeff IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 415219820Sjeff 1) / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; 416219820Sjeff } 417219820Sjeff 418219820Sjeff for (block_num = 0; block_num < max_blocks; block_num++) { 419219820Sjeff if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH) 420219820Sjeff attr_mod_ho = block_num; 421219820Sjeff else 422219820Sjeff attr_mod_ho = block_num | (port_num << 16); 423219820Sjeff status = osm_req_get(sm, &path, IB_MAD_ATTR_P_KEY_TABLE, 424219820Sjeff cl_hton32(attr_mod_ho), 425219820Sjeff CL_DISP_MSGID_NONE, &context); 426219820Sjeff 427219820Sjeff if (status != IB_SUCCESS) { 428219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0F12: " 429219820Sjeff "Failure initiating PKeyTable request (%s)\n", 430219820Sjeff ib_get_err_str(status)); 431219820Sjeff goto Exit; 432219820Sjeff } 433219820Sjeff } 434219820Sjeff 435219820SjeffExit: 436219820Sjeff OSM_LOG_EXIT(p_log); 437219820Sjeff} 438219820Sjeff 439219820Sjeff/********************************************************************** 440219820Sjeff **********************************************************************/ 441219820Sjeffstatic void 442219820Sjeff__osm_pi_rcv_get_pkey_slvl_vla_tables(IN osm_sm_t * sm, 443219820Sjeff IN osm_node_t * const p_node, 444219820Sjeff IN osm_physp_t * const p_physp) 445219820Sjeff{ 446219820Sjeff OSM_LOG_ENTER(sm->p_log); 447219820Sjeff 448219820Sjeff get_pkey_table(sm->p_log, sm, p_node, p_physp); 449219820Sjeff 450219820Sjeff OSM_LOG_EXIT(sm->p_log); 451219820Sjeff} 452219820Sjeff 453219820Sjeff/********************************************************************** 454219820Sjeff **********************************************************************/ 455219820Sjeffstatic void 456219820Sjeffosm_pi_rcv_process_set(IN osm_sm_t * sm, IN osm_node_t * const p_node, 457219820Sjeff IN const uint8_t port_num, IN osm_madw_t * const p_madw) 458219820Sjeff{ 459219820Sjeff osm_physp_t *p_physp; 460219820Sjeff ib_net64_t port_guid; 461219820Sjeff ib_smp_t *p_smp; 462219820Sjeff ib_port_info_t *p_pi; 463219820Sjeff osm_pi_context_t *p_context; 464219820Sjeff osm_log_level_t level; 465219820Sjeff 466219820Sjeff OSM_LOG_ENTER(sm->p_log); 467219820Sjeff 468219820Sjeff p_context = osm_madw_get_pi_context_ptr(p_madw); 469219820Sjeff 470219820Sjeff CL_ASSERT(p_node); 471219820Sjeff 472219820Sjeff p_physp = osm_node_get_physp_ptr(p_node, port_num); 473219820Sjeff CL_ASSERT(p_physp); 474219820Sjeff 475219820Sjeff port_guid = osm_physp_get_port_guid(p_physp); 476219820Sjeff 477219820Sjeff p_smp = osm_madw_get_smp_ptr(p_madw); 478219820Sjeff p_pi = (ib_port_info_t *) ib_smp_get_payload_ptr(p_smp); 479219820Sjeff 480219820Sjeff /* check for error */ 481219820Sjeff if (cl_ntoh16(p_smp->status) & 0x7fff) { 482219820Sjeff /* If port already ACTIVE, don't treat status 7 as error */ 483219820Sjeff if (p_context->active_transition && 484219820Sjeff (cl_ntoh16(p_smp->status) & 0x7fff) == 0x1c) { 485219820Sjeff level = OSM_LOG_INFO; 486219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_INFO, 487219820Sjeff "Received error status 0x%x for SetResp() during ACTIVE transition\n", 488219820Sjeff cl_ntoh16(p_smp->status) & 0x7fff); 489219820Sjeff /* Should there be a subsequent Get to validate that port is ACTIVE ? */ 490219820Sjeff } else { 491219820Sjeff level = OSM_LOG_ERROR; 492219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F10: " 493219820Sjeff "Received error status for SetResp()\n"); 494219820Sjeff } 495219820Sjeff osm_dump_port_info(sm->p_log, 496219820Sjeff osm_node_get_node_guid(p_node), 497219820Sjeff port_guid, port_num, p_pi, level); 498219820Sjeff } 499219820Sjeff 500219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 501219820Sjeff "Received logical SetResp() for GUID 0x%" PRIx64 502219820Sjeff ", port num %u" 503219820Sjeff "\n\t\t\t\tfor parent node GUID 0x%" PRIx64 504219820Sjeff " TID 0x%" PRIx64 "\n", 505219820Sjeff cl_ntoh64(port_guid), port_num, 506219820Sjeff cl_ntoh64(osm_node_get_node_guid(p_node)), 507219820Sjeff cl_ntoh64(p_smp->trans_id)); 508219820Sjeff 509219820Sjeff osm_physp_set_port_info(p_physp, p_pi); 510219820Sjeff 511219820Sjeff OSM_LOG_EXIT(sm->p_log); 512219820Sjeff} 513219820Sjeff 514219820Sjeff/********************************************************************** 515219820Sjeff **********************************************************************/ 516219820Sjeffvoid osm_pi_rcv_process(IN void *context, IN void *data) 517219820Sjeff{ 518219820Sjeff osm_sm_t *sm = context; 519219820Sjeff osm_madw_t *p_madw = data; 520219820Sjeff ib_port_info_t *p_pi; 521219820Sjeff ib_smp_t *p_smp; 522219820Sjeff osm_port_t *p_port; 523219820Sjeff osm_physp_t *p_physp; 524219820Sjeff osm_dr_path_t *p_dr_path; 525219820Sjeff osm_node_t *p_node; 526219820Sjeff osm_pi_context_t *p_context; 527219820Sjeff ib_net64_t port_guid; 528219820Sjeff ib_net64_t node_guid; 529219820Sjeff uint8_t port_num; 530219820Sjeff 531219820Sjeff OSM_LOG_ENTER(sm->p_log); 532219820Sjeff 533219820Sjeff CL_ASSERT(sm); 534219820Sjeff CL_ASSERT(p_madw); 535219820Sjeff 536219820Sjeff p_smp = osm_madw_get_smp_ptr(p_madw); 537219820Sjeff p_context = osm_madw_get_pi_context_ptr(p_madw); 538219820Sjeff p_pi = (ib_port_info_t *) ib_smp_get_payload_ptr(p_smp); 539219820Sjeff 540219820Sjeff CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_PORT_INFO); 541219820Sjeff 542219820Sjeff port_num = (uint8_t) cl_ntoh32(p_smp->attr_mod); 543219820Sjeff 544219820Sjeff port_guid = p_context->port_guid; 545219820Sjeff node_guid = p_context->node_guid; 546219820Sjeff 547219820Sjeff osm_dump_port_info(sm->p_log, 548219820Sjeff node_guid, port_guid, port_num, p_pi, OSM_LOG_DEBUG); 549219820Sjeff 550219820Sjeff /* On receipt of client reregister, clear the reregister bit so 551219820Sjeff reregistering won't be sent again and again */ 552219820Sjeff if (ib_port_info_get_client_rereg(p_pi)) { 553219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 554219820Sjeff "Client reregister received on response\n"); 555219820Sjeff ib_port_info_set_client_rereg(p_pi, 0); 556219820Sjeff } 557219820Sjeff 558219820Sjeff /* 559219820Sjeff we might get a response during a light sweep looking for a change in 560219820Sjeff the status of a remote port that did not respond in earlier sweeps. 561219820Sjeff So if the context of the Get was light_sweep - we do not need to 562219820Sjeff do anything with the response - just flag that we need a heavy sweep 563219820Sjeff */ 564219820Sjeff if (p_context->light_sweep == TRUE) { 565219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 566219820Sjeff "Got light sweep response from remote port of parent node " 567219820Sjeff "GUID 0x%" PRIx64 " port 0x%016" PRIx64 568219820Sjeff ", Commencing heavy sweep\n", 569219820Sjeff cl_ntoh64(node_guid), cl_ntoh64(port_guid)); 570219820Sjeff sm->p_subn->force_heavy_sweep = TRUE; 571219820Sjeff sm->p_subn->ignore_existing_lfts = TRUE; 572219820Sjeff goto Exit; 573219820Sjeff } 574219820Sjeff 575219820Sjeff CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); 576219820Sjeff p_port = osm_get_port_by_guid(sm->p_subn, port_guid); 577219820Sjeff if (!p_port) { 578219820Sjeff CL_PLOCK_RELEASE(sm->p_lock); 579219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F06: " 580219820Sjeff "No port object for port with GUID 0x%" PRIx64 581219820Sjeff "\n\t\t\t\tfor parent node GUID 0x%" PRIx64 582219820Sjeff ", TID 0x%" PRIx64 "\n", 583219820Sjeff cl_ntoh64(port_guid), 584219820Sjeff cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); 585219820Sjeff goto Exit; 586219820Sjeff } 587219820Sjeff 588219820Sjeff p_node = p_port->p_node; 589219820Sjeff CL_ASSERT(p_node); 590219820Sjeff 591219820Sjeff /* 592219820Sjeff If we were setting the PortInfo, then receiving 593219820Sjeff this attribute was not part of sweeping the subnet. 594219820Sjeff In this case, just update the PortInfo attribute. 595219820Sjeff 596219820Sjeff In an unfortunate blunder, the IB spec defines the 597219820Sjeff return method for Set() as a GetResp(). Thus, we can't 598219820Sjeff use the method (what would have been SetResp()) to determine 599219820Sjeff our course of action. So, we have to carry this extra 600219820Sjeff boolean around to determine if we were doing Get() or Set(). 601219820Sjeff */ 602219820Sjeff if (p_context->set_method) 603219820Sjeff osm_pi_rcv_process_set(sm, p_node, port_num, p_madw); 604219820Sjeff else { 605219820Sjeff p_port->discovery_count++; 606219820Sjeff 607219820Sjeff /* 608219820Sjeff This PortInfo arrived because we did a Get() method, 609219820Sjeff most likely due to a subnet sweep in progress. 610219820Sjeff */ 611219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 612219820Sjeff "Discovered port num %u with GUID 0x%" PRIx64 613219820Sjeff " for parent node GUID 0x%" PRIx64 614219820Sjeff ", TID 0x%" PRIx64 "\n", 615219820Sjeff port_num, cl_ntoh64(port_guid), 616219820Sjeff cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); 617219820Sjeff 618219820Sjeff p_physp = osm_node_get_physp_ptr(p_node, port_num); 619219820Sjeff 620219820Sjeff /* 621219820Sjeff Determine if we encountered a new Physical Port. 622219820Sjeff If so, initialize the new Physical Port then 623219820Sjeff continue processing as normal. 624219820Sjeff */ 625219820Sjeff if (!p_physp) { 626219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 627219820Sjeff "Initializing port number %u\n", port_num); 628219820Sjeff p_physp = &p_node->physp_table[port_num]; 629219820Sjeff osm_physp_init(p_physp, 630219820Sjeff port_guid, 631219820Sjeff port_num, 632219820Sjeff p_node, 633219820Sjeff osm_madw_get_bind_handle(p_madw), 634219820Sjeff p_smp->hop_count, p_smp->initial_path); 635219820Sjeff } else { 636219820Sjeff /* 637219820Sjeff Update the directed route path to this port 638219820Sjeff in case the old path is no longer usable. 639219820Sjeff */ 640219820Sjeff p_dr_path = osm_physp_get_dr_path_ptr(p_physp); 641219820Sjeff osm_dr_path_init(p_dr_path, 642219820Sjeff osm_madw_get_bind_handle(p_madw), 643219820Sjeff p_smp->hop_count, p_smp->initial_path); 644219820Sjeff } 645219820Sjeff 646219820Sjeff /* if port just inited or reached INIT state (external reset) 647219820Sjeff request update for port related tables */ 648219820Sjeff p_physp->need_update = 649219820Sjeff (ib_port_info_get_port_state(p_pi) == IB_LINK_INIT || 650219820Sjeff p_physp->need_update > 1) ? 1 : 0; 651219820Sjeff 652219820Sjeff switch (osm_node_get_type(p_node)) { 653219820Sjeff case IB_NODE_TYPE_CA: 654219820Sjeff case IB_NODE_TYPE_ROUTER: 655219820Sjeff __osm_pi_rcv_process_ca_or_router_port(sm, 656219820Sjeff p_node, p_physp, 657219820Sjeff p_pi); 658219820Sjeff break; 659219820Sjeff case IB_NODE_TYPE_SWITCH: 660219820Sjeff __osm_pi_rcv_process_switch_port(sm, 661219820Sjeff p_node, p_physp, p_pi); 662219820Sjeff break; 663219820Sjeff default: 664219820Sjeff OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F07: " 665219820Sjeff "Unknown node type %u with GUID 0x%" PRIx64 666219820Sjeff "\n", osm_node_get_type(p_node), 667219820Sjeff cl_ntoh64(node_guid)); 668219820Sjeff break; 669219820Sjeff } 670219820Sjeff 671219820Sjeff /* 672219820Sjeff Get the tables on the physp. 673219820Sjeff */ 674219820Sjeff if (p_physp->need_update || sm->p_subn->need_update) 675219820Sjeff __osm_pi_rcv_get_pkey_slvl_vla_tables(sm, p_node, 676219820Sjeff p_physp); 677219820Sjeff 678219820Sjeff } 679219820Sjeff 680219820Sjeff CL_PLOCK_RELEASE(sm->p_lock); 681219820Sjeff 682219820SjeffExit: 683219820Sjeff /* 684219820Sjeff Release the lock before jumping here!! 685219820Sjeff */ 686219820Sjeff OSM_LOG_EXIT(sm->p_log); 687219820Sjeff} 688