1155153Smarius/* 2155153Smarius * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3155153Smarius * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. 4155153Smarius * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5155153Smarius * 6155153Smarius * This software is available to you under a choice of one of two 7155153Smarius * licenses. You may choose to be licensed under the terms of the GNU 8155153Smarius * General Public License (GPL) Version 2, available from the file 9155153Smarius * COPYING in the main directory of this source tree, or the 10155153Smarius * OpenIB.org BSD license below: 11155153Smarius * 12155153Smarius * Redistribution and use in source and binary forms, with or 13155153Smarius * without modification, are permitted provided that the following 14155153Smarius * conditions are met: 15155153Smarius * 16155153Smarius * - Redistributions of source code must retain the above 17155153Smarius * copyright notice, this list of conditions and the following 18155153Smarius * disclaimer. 19155153Smarius * 20155153Smarius * - Redistributions in binary form must reproduce the above 21155153Smarius * copyright notice, this list of conditions and the following 22155153Smarius * disclaimer in the documentation and/or other materials 23155153Smarius * provided with the distribution. 24155153Smarius * 25155153Smarius * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26155153Smarius * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27155153Smarius * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28155153Smarius * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29155153Smarius * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30155153Smarius * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31155153Smarius * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32155153Smarius * SOFTWARE. 33155153Smarius * 34155153Smarius */ 35155153Smarius 36155153Smarius/* 37155153Smarius * Abstract: 38155153Smarius * Implementation of osm_pi_rcv_t. 39166145Smarius * This object represents the PortInfo Receiver object. 40155153Smarius * This object is part of the opensm family of objects. 41155153Smarius */ 42155153Smarius 43155153Smarius#if HAVE_CONFIG_H 44166145Smarius# include <config.h> 45155153Smarius#endif /* HAVE_CONFIG_H */ 46155153Smarius 47155153Smarius#include <string.h> 48155153Smarius#include <iba/ib_types.h> 49155153Smarius#include <complib/cl_qmap.h> 50155153Smarius#include <complib/cl_passivelock.h> 51155153Smarius#include <complib/cl_debug.h> 52155153Smarius#include <vendor/osm_vendor_api.h> 53155153Smarius#include <opensm/osm_madw.h> 54155153Smarius#include <opensm/osm_log.h> 55155153Smarius#include <opensm/osm_node.h> 56155153Smarius#include <opensm/osm_subnet.h> 57155153Smarius#include <opensm/osm_mad_pool.h> 58155153Smarius#include <opensm/osm_msgdef.h> 59162005Smarius#include <opensm/osm_helper.h> 60166145Smarius#include <opensm/osm_pkey.h> 61162005Smarius#include <opensm/osm_remote_sm.h> 62162005Smarius#include <opensm/osm_opensm.h> 63162005Smarius#include <opensm/osm_ucast_mgr.h> 64162005Smarius 65162005Smarius/********************************************************************** 66162005Smarius **********************************************************************/ 67166145Smariusstatic void 68162005Smarius__osm_pi_rcv_set_sm(IN osm_sm_t * sm, 69162005Smarius IN osm_physp_t * const p_physp) 70162005Smarius{ 71162005Smarius osm_bind_handle_t h_bind; 72162005Smarius osm_dr_path_t *p_dr_path; 73162005Smarius 74155153Smarius OSM_LOG_ENTER(sm->p_log); 75155153Smarius 76155153Smarius OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 77155153Smarius "Setting IS_SM bit in port attributes\n"); 78166145Smarius 79166145Smarius p_dr_path = osm_physp_get_dr_path_ptr(p_physp); 80166145Smarius h_bind = osm_dr_path_get_bind_handle(p_dr_path); 81166145Smarius 82155153Smarius /* 83155153Smarius The 'IS_SM' bit isn't already set, so set it. 84162005Smarius */ 85155153Smarius osm_vendor_set_sm(h_bind, TRUE); 86155153Smarius 87155153Smarius OSM_LOG_EXIT(sm->p_log); 88162005Smarius} 89166145Smarius 90166145Smarius/********************************************************************** 91166145Smarius **********************************************************************/ 92166145Smariusstatic void pi_rcv_check_and_fix_lid(osm_log_t *log, ib_port_info_t * const pi, 93166145Smarius osm_physp_t * p) 94155153Smarius{ 95155153Smarius if (cl_ntoh16(pi->base_lid) > IB_LID_UCAST_END_HO) { 96155220Smarius OSM_LOG(log, OSM_LOG_ERROR, "ERR 0F04: " 97155220Smarius "Got invalid base LID %u from the network. " 98155153Smarius "Corrected to %u.\n", cl_ntoh16(pi->base_lid), 99162005Smarius cl_ntoh16(p->port_info.base_lid)); 100155153Smarius pi->base_lid = p->port_info.base_lid; 101155153Smarius } 102155153Smarius} 103155153Smarius 104155220Smarius/********************************************************************** 105155220Smarius **********************************************************************/ 106162005Smariusstatic void 107155220Smarius__osm_pi_rcv_process_endport(IN osm_sm_t * sm, 108155220Smarius IN osm_physp_t * const p_physp, 109155220Smarius IN const ib_port_info_t * const p_pi) 110162005Smarius{ 111155220Smarius osm_madw_context_t context; 112155153Smarius ib_api_status_t status; 113155220Smarius ib_net64_t port_guid; 114155153Smarius uint8_t rate, mtu; 115162005Smarius cl_qmap_t *p_sm_tbl; 116162005Smarius osm_remote_sm_t *p_sm; 117162005Smarius 118162005Smarius OSM_LOG_ENTER(sm->p_log); 119162005Smarius 120162005Smarius port_guid = osm_physp_get_port_guid(p_physp); 121155153Smarius 122155153Smarius /* HACK extended port 0 should be handled too! */ 123155153Smarius if (osm_physp_get_port_num(p_physp) != 0) { 124155153Smarius /* track the minimal endport MTU and rate */ 125155153Smarius mtu = ib_port_info_get_mtu_cap(p_pi); 126155153Smarius if (mtu < sm->p_subn->min_ca_mtu) { 127155153Smarius OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 128155153Smarius "Setting endport minimal MTU to:%u defined by port:0x%" 129162005Smarius PRIx64 "\n", mtu, cl_ntoh64(port_guid)); 130162005Smarius sm->p_subn->min_ca_mtu = mtu; 131162005Smarius } 132162005Smarius 133162005Smarius rate = ib_port_info_compute_rate(p_pi); 134162005Smarius if (rate < sm->p_subn->min_ca_rate) { 135162005Smarius OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 136162005Smarius "Setting endport minimal rate to:%u defined by port:0x%" 137162005Smarius PRIx64 "\n", rate, cl_ntoh64(port_guid)); 138162005Smarius sm->p_subn->min_ca_rate = rate; 139162005Smarius } 140162005Smarius } 141162005Smarius 142162005Smarius if (port_guid == sm->p_subn->sm_port_guid) { 143162005Smarius /* 144162005Smarius We received the PortInfo for our own port. 145162005Smarius */ 146162005Smarius if (!(p_pi->capability_mask & IB_PORT_CAP_IS_SM)) 147162005Smarius /* 148162005Smarius Set the IS_SM bit to indicate our port hosts an SM. 149162005Smarius */ 150162005Smarius __osm_pi_rcv_set_sm(sm, p_physp); 151162005Smarius } else { 152162005Smarius p_sm_tbl = &sm->p_subn->sm_guid_tbl; 153162005Smarius if (p_pi->capability_mask & IB_PORT_CAP_IS_SM) { 154162005Smarius /* 155162005Smarius * Before querying the SM - we want to make sure we 156162005Smarius * clean its state, so if the querying fails we 157162005Smarius * recognize that this SM is not active. 158162005Smarius */ 159162005Smarius p_sm = (osm_remote_sm_t *) cl_qmap_get(p_sm_tbl, port_guid); 160162005Smarius if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) 161162005Smarius /* clean it up */ 162162005Smarius p_sm->smi.pri_state = 0xF0 & p_sm->smi.pri_state; 163155153Smarius if (sm->p_subn->opt.ignore_other_sm) 164155153Smarius OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 165162005Smarius "Ignoring SM on port 0x%" PRIx64 "\n", 166162005Smarius cl_ntoh64(port_guid)); 167162005Smarius else { 168162005Smarius OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 169162005Smarius "Detected another SM. Requesting SMInfo" 170162005Smarius "\n\t\t\t\tPort 0x%" PRIx64 "\n", 171162005Smarius cl_ntoh64(port_guid)); 172162005Smarius 173162005Smarius /* 174162005Smarius This port indicates it's an SM and 175162005Smarius it's not our own port. 176162005Smarius Acquire the SMInfo Attribute. 177162005Smarius */ 178162005Smarius memset(&context, 0, sizeof(context)); 179164125Smarius context.smi_context.set_method = FALSE; 180164125Smarius context.smi_context.port_guid = port_guid; 181162005Smarius status = osm_req_get(sm, 182162005Smarius osm_physp_get_dr_path_ptr 183162005Smarius (p_physp), 184162005Smarius IB_MAD_ATTR_SM_INFO, 0, 185162005Smarius CL_DISP_MSGID_NONE, 186162005Smarius &context); 187162005Smarius 188162005Smarius if (status != IB_SUCCESS) 189162005Smarius OSM_LOG(sm->p_log, OSM_LOG_ERROR, 190162005Smarius "ERR 0F05: " 191162005Smarius "Failure requesting SMInfo (%s)\n", 192162005Smarius ib_get_err_str(status)); 193162005Smarius } 194162005Smarius } else { 195162005Smarius p_sm = (osm_remote_sm_t *) cl_qmap_remove(p_sm_tbl, port_guid); 196162005Smarius if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) 197162005Smarius free(p_sm); 198162005Smarius } 199162005Smarius } 200162005Smarius 201162005Smarius OSM_LOG_EXIT(sm->p_log); 202162005Smarius} 203155153Smarius 204155153Smarius/********************************************************************** 205155153Smarius The plock must be held before calling this function. 206155153Smarius**********************************************************************/ 207155153Smariusstatic void 208155153Smarius__osm_pi_rcv_process_switch_port(IN osm_sm_t * sm, 209155153Smarius IN osm_node_t * const p_node, 210155153Smarius IN osm_physp_t * const p_physp, 211155153Smarius IN ib_port_info_t * const p_pi) 212155153Smarius{ 213155153Smarius ib_api_status_t status = IB_SUCCESS; 214155153Smarius osm_madw_context_t context; 215155153Smarius osm_physp_t *p_remote_physp; 216155153Smarius osm_node_t *p_remote_node; 217155153Smarius uint8_t port_num; 218155153Smarius uint8_t remote_port_num; 219155153Smarius osm_dr_path_t path; 220155153Smarius 221155153Smarius OSM_LOG_ENTER(sm->p_log); 222155153Smarius 223155153Smarius /* 224155153Smarius Check the state of the physical port. 225155153Smarius If there appears to be something on the other end of the wire, 226155153Smarius then ask for NodeInfo. Ignore the switch management port. 227155153Smarius */ 228155153Smarius port_num = osm_physp_get_port_num(p_physp); 229155153Smarius /* if in_sweep_hop_0 is TRUE, then this means the SM is on the switch, 230162005Smarius and we got switchInfo of our local switch. Do not continue 231155153Smarius probing through the switch. */ 232155153Smarius if (port_num != 0 && sm->p_subn->in_sweep_hop_0 == FALSE) { 233155153Smarius switch (ib_port_info_get_port_state(p_pi)) { 234155153Smarius case IB_LINK_DOWN: 235155153Smarius p_remote_physp = osm_physp_get_remote(p_physp); 236155153Smarius if (p_remote_physp) { 237155153Smarius p_remote_node = 238155153Smarius osm_physp_get_node_ptr(p_remote_physp); 239155153Smarius remote_port_num = 240155153Smarius osm_physp_get_port_num(p_remote_physp); 241155153Smarius 242155153Smarius OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 243155153Smarius "Unlinking local node 0x%" PRIx64 244155153Smarius ", port %u" 245155153Smarius "\n\t\t\t\tand remote node 0x%" PRIx64 246155153Smarius ", port %u\n", 247155153Smarius cl_ntoh64(osm_node_get_node_guid 248155153Smarius (p_node)), port_num, 249155153Smarius cl_ntoh64(osm_node_get_node_guid 250155153Smarius (p_remote_node)), 251166145Smarius remote_port_num); 252166145Smarius 253166145Smarius if (sm->ucast_mgr.cache_valid) 254166145Smarius osm_ucast_cache_add_link(&sm->ucast_mgr, 255166145Smarius p_physp, 256166145Smarius p_remote_physp); 257166145Smarius 258166145Smarius osm_node_unlink(p_node, (uint8_t) port_num, 259166145Smarius p_remote_node, 260166145Smarius (uint8_t) remote_port_num); 261166145Smarius 262155153Smarius } 263155153Smarius break; 264166145Smarius 265166145Smarius case IB_LINK_INIT: 266166145Smarius case IB_LINK_ARMED: 267166145Smarius case IB_LINK_ACTIVE: 268166145Smarius /* 269162871Sru To avoid looping forever, only probe the port if it 270162871Sru is NOT the port that responded to the SMP. 271155153Smarius 272162871Sru Request node info from the other end of this link: 273155153Smarius 1) Copy the current path from the parent node. 274162871Sru 2) Extend the path to the next hop thru this port. 275155153Smarius 3) Request node info with the new path 276155153Smarius 277155153Smarius */ 278155153Smarius if (p_pi->local_port_num != 279162871Sru osm_physp_get_port_num(p_physp)) { 280162871Sru path = *osm_physp_get_dr_path_ptr(p_physp); 281155153Smarius 282155153Smarius osm_dr_path_extend(&path, 283155153Smarius osm_physp_get_port_num 284155153Smarius (p_physp)); 285155153Smarius 286155153Smarius memset(&context, 0, sizeof(context)); 287155153Smarius context.ni_context.node_guid = 288155153Smarius osm_node_get_node_guid(p_node); 289155153Smarius context.ni_context.port_num = 290155153Smarius osm_physp_get_port_num(p_physp); 291155153Smarius 292155153Smarius status = osm_req_get(sm, 293155153Smarius &path, 294155153Smarius IB_MAD_ATTR_NODE_INFO, 295155153Smarius 0, 296155153Smarius CL_DISP_MSGID_NONE, 297166145Smarius &context); 298166145Smarius 299166145Smarius if (status != IB_SUCCESS) 300166145Smarius OSM_LOG(sm->p_log, OSM_LOG_ERROR, 301166145Smarius "ERR 0F02: " 302162871Sru "Failure initiating NodeInfo request (%s)\n", 303162871Sru ib_get_err_str(status)); 304155153Smarius } else 305162871Sru OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 306155153Smarius "Skipping SMP responder port %u\n", 307162871Sru p_pi->local_port_num); 308155153Smarius break; 309155153Smarius 310155153Smarius default: 311155153Smarius OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F03: " 312155153Smarius "Unknown link state = %u, port = %u\n", 313155153Smarius ib_port_info_get_port_state(p_pi), 314155153Smarius p_pi->local_port_num); 315155153Smarius break; 316155153Smarius } 317166145Smarius } 318166145Smarius 319166145Smarius if (ib_port_info_get_port_state(p_pi) > IB_LINK_INIT && p_node->sw && 320166145Smarius p_node->sw->need_update == 1) 321166145Smarius p_node->sw->need_update = 0; 322166145Smarius 323166145Smarius if (p_physp->need_update) 324166145Smarius sm->p_subn->ignore_existing_lfts = TRUE; 325166145Smarius 326166145Smarius if (port_num == 0) 327166145Smarius pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp); 328166145Smarius 329166145Smarius /* 330166145Smarius Update the PortInfo attribute. 331166145Smarius */ 332166145Smarius osm_physp_set_port_info(p_physp, p_pi); 333166145Smarius 334166145Smarius if (port_num == 0) { 335166145Smarius /* Determine if base switch port 0 */ 336166145Smarius if (p_node->sw && 337166145Smarius !ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info)) 338166145Smarius /* PortState is not used on BSP0 but just in case it is DOWN */ 339166145Smarius p_physp->port_info = *p_pi; 340155153Smarius __osm_pi_rcv_process_endport(sm, p_physp, p_pi); 341155153Smarius } 342155153Smarius 343155153Smarius OSM_LOG_EXIT(sm->p_log); 344155153Smarius} 345155153Smarius 346155153Smarius/********************************************************************** 347155153Smarius **********************************************************************/ 348155153Smariusstatic void 349155153Smarius__osm_pi_rcv_process_ca_or_router_port(IN osm_sm_t * sm, 350155153Smarius IN osm_node_t * const p_node, 351155153Smarius IN osm_physp_t * const p_physp, 352155153Smarius IN ib_port_info_t * const p_pi) 353155153Smarius{ 354155153Smarius OSM_LOG_ENTER(sm->p_log); 355155153Smarius 356155153Smarius UNUSED_PARAM(p_node); 357155153Smarius 358155153Smarius pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp); 359155153Smarius 360155153Smarius osm_physp_set_port_info(p_physp, p_pi); 361155153Smarius 362155153Smarius __osm_pi_rcv_process_endport(sm, p_physp, p_pi); 363155153Smarius 364155153Smarius OSM_LOG_EXIT(sm->p_log); 365155153Smarius} 366155153Smarius 367155153Smarius#define IBM_VENDOR_ID (0x5076) 368155153Smarius/********************************************************************** 369155153Smarius **********************************************************************/ 370155153Smariusstatic void get_pkey_table(IN osm_log_t * p_log, 371155153Smarius IN osm_sm_t * sm, 372155153Smarius IN osm_node_t * const p_node, 373155153Smarius IN osm_physp_t * const p_physp) 374155153Smarius{ 375155153Smarius 376155153Smarius osm_madw_context_t context; 377155153Smarius ib_api_status_t status; 378155153Smarius osm_dr_path_t path; 379155153Smarius uint8_t port_num; 380155153Smarius uint16_t block_num, max_blocks; 381155153Smarius uint32_t attr_mod_ho; 382155153Smarius 383155153Smarius OSM_LOG_ENTER(p_log); 384155153Smarius 385155153Smarius path = *osm_physp_get_dr_path_ptr(p_physp); 386155153Smarius 387155153Smarius context.pkey_context.node_guid = osm_node_get_node_guid(p_node); 388155153Smarius context.pkey_context.port_guid = osm_physp_get_port_guid(p_physp); 389155153Smarius context.pkey_context.set_method = FALSE; 390155153Smarius 391155153Smarius port_num = p_physp->port_num; 392155153Smarius 393155153Smarius if (!p_node->sw || port_num == 0) 394155153Smarius /* The maximum blocks is defined by the node info partition cap for CA, 395155153Smarius router, and switch management ports. */ 396155153Smarius max_blocks = 397155153Smarius (cl_ntoh16(p_node->node_info.partition_cap) + 398155153Smarius IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) 399155153Smarius / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; 400155153Smarius else { 401155153Smarius /* This is a switch, and not a management port. The maximum blocks 402155153Smarius is defined in the switch info partition enforcement cap. */ 403155153Smarius 404155153Smarius /* Check for IBM eHCA firmware defect in reporting partition enforcement cap */ 405155153Smarius if (cl_ntoh32(ib_node_info_get_vendor_id(&p_node->node_info)) == 406166346Sbrueffer IBM_VENDOR_ID) 407155153Smarius p_node->sw->switch_info.enforce_cap = 0; 408155153Smarius 409155153Smarius /* Bail out if this is a switch with no partition enforcement capability */ 410155153Smarius if (cl_ntoh16(p_node->sw->switch_info.enforce_cap) == 0) 411155153Smarius goto Exit; 412155153Smarius 413155153Smarius max_blocks = (cl_ntoh16(p_node->sw->switch_info.enforce_cap) + 414155153Smarius IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 415155153Smarius 1) / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; 416155153Smarius } 417155153Smarius 418155153Smarius for (block_num = 0; block_num < max_blocks; block_num++) { 419155153Smarius if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH) 420155153Smarius attr_mod_ho = block_num; 421155153Smarius else 422155153Smarius attr_mod_ho = block_num | (port_num << 16); 423155153Smarius status = osm_req_get(sm, &path, IB_MAD_ATTR_P_KEY_TABLE, 424155153Smarius cl_hton32(attr_mod_ho), 425155153Smarius CL_DISP_MSGID_NONE, &context); 426155153Smarius 427155153Smarius if (status != IB_SUCCESS) { 428155153Smarius OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0F12: " 429155153Smarius "Failure initiating PKeyTable request (%s)\n", 430267938Sbapt ib_get_err_str(status)); 431155153Smarius goto Exit; 432155153Smarius } 433155153Smarius } 434155153Smarius 435155153SmariusExit: 436155153Smarius OSM_LOG_EXIT(p_log); 437155153Smarius} 438155153Smarius 439155153Smarius/********************************************************************** 440155153Smarius **********************************************************************/ 441155153Smariusstatic void 442155153Smarius__osm_pi_rcv_get_pkey_slvl_vla_tables(IN osm_sm_t * sm, 443155153Smarius IN osm_node_t * const p_node, 444155153Smarius IN osm_physp_t * const p_physp) 445155153Smarius{ 446155153Smarius OSM_LOG_ENTER(sm->p_log); 447155153Smarius 448155153Smarius get_pkey_table(sm->p_log, sm, p_node, p_physp); 449155153Smarius 450155153Smarius OSM_LOG_EXIT(sm->p_log); 451155153Smarius} 452155153Smarius 453155153Smarius/********************************************************************** 454155153Smarius **********************************************************************/ 455155153Smariusstatic void 456155153Smariusosm_pi_rcv_process_set(IN osm_sm_t * sm, IN osm_node_t * const p_node, 457155153Smarius IN const uint8_t port_num, IN osm_madw_t * const p_madw) 458155153Smarius{ 459155153Smarius osm_physp_t *p_physp; 460155153Smarius ib_net64_t port_guid; 461155153Smarius ib_smp_t *p_smp; 462155153Smarius ib_port_info_t *p_pi; 463155153Smarius osm_pi_context_t *p_context; 464155153Smarius osm_log_level_t level; 465155153Smarius 466155153Smarius OSM_LOG_ENTER(sm->p_log); 467155153Smarius 468155153Smarius p_context = osm_madw_get_pi_context_ptr(p_madw); 469155153Smarius 470155153Smarius CL_ASSERT(p_node); 471155153Smarius 472155153Smarius p_physp = osm_node_get_physp_ptr(p_node, port_num); 473155153Smarius CL_ASSERT(p_physp); 474155153Smarius 475155153Smarius port_guid = osm_physp_get_port_guid(p_physp); 476155153Smarius 477 p_smp = osm_madw_get_smp_ptr(p_madw); 478 p_pi = (ib_port_info_t *) ib_smp_get_payload_ptr(p_smp); 479 480 /* check for error */ 481 if (cl_ntoh16(p_smp->status) & 0x7fff) { 482 /* If port already ACTIVE, don't treat status 7 as error */ 483 if (p_context->active_transition && 484 (cl_ntoh16(p_smp->status) & 0x7fff) == 0x1c) { 485 level = OSM_LOG_INFO; 486 OSM_LOG(sm->p_log, OSM_LOG_INFO, 487 "Received error status 0x%x for SetResp() during ACTIVE transition\n", 488 cl_ntoh16(p_smp->status) & 0x7fff); 489 /* Should there be a subsequent Get to validate that port is ACTIVE ? */ 490 } else { 491 level = OSM_LOG_ERROR; 492 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F10: " 493 "Received error status for SetResp()\n"); 494 } 495 osm_dump_port_info(sm->p_log, 496 osm_node_get_node_guid(p_node), 497 port_guid, port_num, p_pi, level); 498 } 499 500 OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 501 "Received logical SetResp() for GUID 0x%" PRIx64 502 ", port num %u" 503 "\n\t\t\t\tfor parent node GUID 0x%" PRIx64 504 " TID 0x%" PRIx64 "\n", 505 cl_ntoh64(port_guid), port_num, 506 cl_ntoh64(osm_node_get_node_guid(p_node)), 507 cl_ntoh64(p_smp->trans_id)); 508 509 osm_physp_set_port_info(p_physp, p_pi); 510 511 OSM_LOG_EXIT(sm->p_log); 512} 513 514/********************************************************************** 515 **********************************************************************/ 516void osm_pi_rcv_process(IN void *context, IN void *data) 517{ 518 osm_sm_t *sm = context; 519 osm_madw_t *p_madw = data; 520 ib_port_info_t *p_pi; 521 ib_smp_t *p_smp; 522 osm_port_t *p_port; 523 osm_physp_t *p_physp; 524 osm_dr_path_t *p_dr_path; 525 osm_node_t *p_node; 526 osm_pi_context_t *p_context; 527 ib_net64_t port_guid; 528 ib_net64_t node_guid; 529 uint8_t port_num; 530 531 OSM_LOG_ENTER(sm->p_log); 532 533 CL_ASSERT(sm); 534 CL_ASSERT(p_madw); 535 536 p_smp = osm_madw_get_smp_ptr(p_madw); 537 p_context = osm_madw_get_pi_context_ptr(p_madw); 538 p_pi = (ib_port_info_t *) ib_smp_get_payload_ptr(p_smp); 539 540 CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_PORT_INFO); 541 542 port_num = (uint8_t) cl_ntoh32(p_smp->attr_mod); 543 544 port_guid = p_context->port_guid; 545 node_guid = p_context->node_guid; 546 547 osm_dump_port_info(sm->p_log, 548 node_guid, port_guid, port_num, p_pi, OSM_LOG_DEBUG); 549 550 /* On receipt of client reregister, clear the reregister bit so 551 reregistering won't be sent again and again */ 552 if (ib_port_info_get_client_rereg(p_pi)) { 553 OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 554 "Client reregister received on response\n"); 555 ib_port_info_set_client_rereg(p_pi, 0); 556 } 557 558 /* 559 we might get a response during a light sweep looking for a change in 560 the status of a remote port that did not respond in earlier sweeps. 561 So if the context of the Get was light_sweep - we do not need to 562 do anything with the response - just flag that we need a heavy sweep 563 */ 564 if (p_context->light_sweep == TRUE) { 565 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 566 "Got light sweep response from remote port of parent node " 567 "GUID 0x%" PRIx64 " port 0x%016" PRIx64 568 ", Commencing heavy sweep\n", 569 cl_ntoh64(node_guid), cl_ntoh64(port_guid)); 570 sm->p_subn->force_heavy_sweep = TRUE; 571 sm->p_subn->ignore_existing_lfts = TRUE; 572 goto Exit; 573 } 574 575 CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); 576 p_port = osm_get_port_by_guid(sm->p_subn, port_guid); 577 if (!p_port) { 578 CL_PLOCK_RELEASE(sm->p_lock); 579 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F06: " 580 "No port object for port with GUID 0x%" PRIx64 581 "\n\t\t\t\tfor parent node GUID 0x%" PRIx64 582 ", TID 0x%" PRIx64 "\n", 583 cl_ntoh64(port_guid), 584 cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); 585 goto Exit; 586 } 587 588 p_node = p_port->p_node; 589 CL_ASSERT(p_node); 590 591 /* 592 If we were setting the PortInfo, then receiving 593 this attribute was not part of sweeping the subnet. 594 In this case, just update the PortInfo attribute. 595 596 In an unfortunate blunder, the IB spec defines the 597 return method for Set() as a GetResp(). Thus, we can't 598 use the method (what would have been SetResp()) to determine 599 our course of action. So, we have to carry this extra 600 boolean around to determine if we were doing Get() or Set(). 601 */ 602 if (p_context->set_method) 603 osm_pi_rcv_process_set(sm, p_node, port_num, p_madw); 604 else { 605 p_port->discovery_count++; 606 607 /* 608 This PortInfo arrived because we did a Get() method, 609 most likely due to a subnet sweep in progress. 610 */ 611 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 612 "Discovered port num %u with GUID 0x%" PRIx64 613 " for parent node GUID 0x%" PRIx64 614 ", TID 0x%" PRIx64 "\n", 615 port_num, cl_ntoh64(port_guid), 616 cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); 617 618 p_physp = osm_node_get_physp_ptr(p_node, port_num); 619 620 /* 621 Determine if we encountered a new Physical Port. 622 If so, initialize the new Physical Port then 623 continue processing as normal. 624 */ 625 if (!p_physp) { 626 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 627 "Initializing port number %u\n", port_num); 628 p_physp = &p_node->physp_table[port_num]; 629 osm_physp_init(p_physp, 630 port_guid, 631 port_num, 632 p_node, 633 osm_madw_get_bind_handle(p_madw), 634 p_smp->hop_count, p_smp->initial_path); 635 } else { 636 /* 637 Update the directed route path to this port 638 in case the old path is no longer usable. 639 */ 640 p_dr_path = osm_physp_get_dr_path_ptr(p_physp); 641 osm_dr_path_init(p_dr_path, 642 osm_madw_get_bind_handle(p_madw), 643 p_smp->hop_count, p_smp->initial_path); 644 } 645 646 /* if port just inited or reached INIT state (external reset) 647 request update for port related tables */ 648 p_physp->need_update = 649 (ib_port_info_get_port_state(p_pi) == IB_LINK_INIT || 650 p_physp->need_update > 1) ? 1 : 0; 651 652 switch (osm_node_get_type(p_node)) { 653 case IB_NODE_TYPE_CA: 654 case IB_NODE_TYPE_ROUTER: 655 __osm_pi_rcv_process_ca_or_router_port(sm, 656 p_node, p_physp, 657 p_pi); 658 break; 659 case IB_NODE_TYPE_SWITCH: 660 __osm_pi_rcv_process_switch_port(sm, 661 p_node, p_physp, p_pi); 662 break; 663 default: 664 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F07: " 665 "Unknown node type %u with GUID 0x%" PRIx64 666 "\n", osm_node_get_type(p_node), 667 cl_ntoh64(node_guid)); 668 break; 669 } 670 671 /* 672 Get the tables on the physp. 673 */ 674 if (p_physp->need_update || sm->p_subn->need_update) 675 __osm_pi_rcv_get_pkey_slvl_vla_tables(sm, p_node, 676 p_physp); 677 678 } 679 680 CL_PLOCK_RELEASE(sm->p_lock); 681 682Exit: 683 /* 684 Release the lock before jumping here!! 685 */ 686 OSM_LOG_EXIT(sm->p_log); 687} 688