1 /* 2 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2002-2012 Mellanox Technologies LTD. All rights reserved. 4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5 * Copyright (c) 2009 HNR Consulting. All rights reserved. 6 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. 7 * 8 * This software is available to you under a choice of one of two 9 * licenses. You may choose to be licensed under the terms of the GNU 10 * General Public License (GPL) Version 2, available from the file 11 * COPYING in the main directory of this source tree, or the 12 * OpenIB.org BSD license below: 13 * 14 * Redistribution and use in source and binary forms, with or 15 * without modification, are permitted provided that the following 16 * conditions are met: 17 * 18 * - Redistributions of source code must retain the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer. 21 * 22 * - Redistributions in binary form must reproduce the above 23 * copyright notice, this list of conditions and the following 24 * disclaimer in the documentation and/or other materials 25 * provided with the distribution. 26 * 27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 28 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 29 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 30 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 31 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 32 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 33 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 34 * SOFTWARE. 35 * 36 */ 37 38 /* 39 * Abstract: 40 * Implementation of osm_pi_rcv_t. 41 * This object represents the PortInfo Receiver object. 42 * This object is part of the opensm family of objects. 43 */ 44 45 #if HAVE_CONFIG_H 46 # include <config.h> 47 #endif /* HAVE_CONFIG_H */ 48 49 #include <string.h> 50 #include <stdlib.h> 51 #include <iba/ib_types.h> 52 #include <complib/cl_qmap.h> 53 #include <complib/cl_passivelock.h> 54 #include <complib/cl_debug.h> 55 #include <opensm/osm_file_ids.h> 56 #define FILE_ID OSM_FILE_PORT_INFO_RCV_C 57 #include <vendor/osm_vendor_api.h> 58 #include <opensm/osm_madw.h> 59 #include <opensm/osm_log.h> 60 #include <opensm/osm_node.h> 61 #include <opensm/osm_subnet.h> 62 #include <opensm/osm_mad_pool.h> 63 #include <opensm/osm_msgdef.h> 64 #include <opensm/osm_helper.h> 65 #include <opensm/osm_pkey.h> 66 #include <opensm/osm_remote_sm.h> 67 #include <opensm/osm_opensm.h> 68 #include <opensm/osm_ucast_mgr.h> 69 70 static void pi_rcv_check_and_fix_lid(osm_log_t * log, ib_port_info_t * pi, 71 osm_physp_t * p) 72 { 73 if (PF(cl_ntoh16(pi->base_lid) > IB_LID_UCAST_END_HO)) { 74 OSM_LOG(log, OSM_LOG_ERROR, "ERR 0F04: " 75 "Got invalid base LID %u from the network. " 76 "Corrected to %u\n", cl_ntoh16(pi->base_lid), 77 cl_ntoh16(p->port_info.base_lid)); 78 pi->base_lid = p->port_info.base_lid; 79 } 80 } 81 82 static void pi_rcv_process_endport(IN osm_sm_t * sm, IN osm_physp_t * p_physp, 83 IN const ib_port_info_t * p_pi) 84 { 85 osm_madw_context_t context; 86 ib_api_status_t status; 87 ib_net64_t port_guid; 88 int extended; 89 uint8_t rate, mtu, mpb; 90 unsigned data_vls; 91 cl_qmap_t *p_sm_tbl; 92 osm_remote_sm_t *p_sm; 93 94 OSM_LOG_ENTER(sm->p_log); 95 96 port_guid = osm_physp_get_port_guid(p_physp); 97 98 /* HACK extended port 0 should be handled too! */ 99 if (osm_physp_get_port_num(p_physp) != 0 && 100 ib_port_info_get_port_state(p_pi) != IB_LINK_DOWN) { 101 /* track the minimal endport MTU, rate, and operational VLs */ 102 mtu = ib_port_info_get_mtu_cap(p_pi); 103 if (mtu < sm->p_subn->min_ca_mtu) { 104 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 105 "Setting endport minimal MTU to:%u defined by port:0x%" 106 PRIx64 "\n", mtu, cl_ntoh64(port_guid)); 107 sm->p_subn->min_ca_mtu = mtu; 108 } 109 110 extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS; 111 rate = ib_port_info_compute_rate(p_pi, extended); 112 if (ib_path_compare_rates(rate, sm->p_subn->min_ca_rate) < 0) { 113 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 114 "Setting endport minimal rate to:%u defined by port:0x%" 115 PRIx64 "\n", rate, cl_ntoh64(port_guid)); 116 sm->p_subn->min_ca_rate = rate; 117 } 118 119 data_vls = 1U << (ib_port_info_get_vl_cap(p_pi) - 1); 120 if (data_vls > 1U << (sm->p_subn->opt.max_op_vls - 1)) 121 data_vls = 1U << (sm->p_subn->opt.max_op_vls - 1); 122 if (data_vls >= IB_MAX_NUM_VLS) 123 data_vls = IB_MAX_NUM_VLS - 1; 124 if ((uint8_t)data_vls < sm->p_subn->min_data_vls) { 125 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 126 "Setting endport minimal data VLs to:%u defined by port:0x%" 127 PRIx64 "\n", data_vls, cl_ntoh64(port_guid)); 128 sm->p_subn->min_data_vls = data_vls; 129 } 130 } 131 132 /* Check M_Key vs M_Key protect, can we control the port ? */ 133 mpb = ib_port_info_get_mpb(p_pi); 134 if (mpb > 0 && p_pi->m_key == 0) { 135 OSM_LOG(sm->p_log, OSM_LOG_INFO, 136 "Port 0x%" PRIx64 " has unknown M_Key, protection level %u\n", 137 cl_ntoh64(port_guid), mpb); 138 } 139 140 if (port_guid != sm->p_subn->sm_port_guid) { 141 p_sm_tbl = &sm->p_subn->sm_guid_tbl; 142 if (p_pi->capability_mask & IB_PORT_CAP_IS_SM) { 143 /* 144 * Before querying the SM - we want to make sure we 145 * clean its state, so if the querying fails we 146 * recognize that this SM is not active. 147 */ 148 p_sm = 149 (osm_remote_sm_t *) cl_qmap_get(p_sm_tbl, 150 port_guid); 151 if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) 152 /* clean it up */ 153 p_sm->smi.pri_state = 154 0xF0 & p_sm->smi.pri_state; 155 if (sm->p_subn->opt.ignore_other_sm) 156 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 157 "Ignoring SM on port 0x%" PRIx64 "\n", 158 cl_ntoh64(port_guid)); 159 else { 160 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 161 "Detected another SM. Requesting SMInfo " 162 "from port 0x%" PRIx64 "\n", 163 cl_ntoh64(port_guid)); 164 165 /* 166 This port indicates it's an SM and 167 it's not our own port. 168 Acquire the SMInfo Attribute. 169 */ 170 memset(&context, 0, sizeof(context)); 171 context.smi_context.set_method = FALSE; 172 context.smi_context.port_guid = port_guid; 173 status = osm_req_get(sm, 174 osm_physp_get_dr_path_ptr 175 (p_physp), 176 IB_MAD_ATTR_SM_INFO, 0, 177 FALSE, 178 ib_port_info_get_m_key(&p_physp->port_info), 179 CL_DISP_MSGID_NONE, 180 &context); 181 182 if (status != IB_SUCCESS) 183 OSM_LOG(sm->p_log, OSM_LOG_ERROR, 184 "ERR 0F05: " 185 "Failure requesting SMInfo (%s) " 186 "from port 0x%" PRIx64 "\n", 187 ib_get_err_str(status), 188 cl_ntoh64(port_guid)); 189 } 190 } else { 191 p_sm = 192 (osm_remote_sm_t *) cl_qmap_remove(p_sm_tbl, 193 port_guid); 194 if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) 195 free(p_sm); 196 } 197 } 198 199 OSM_LOG_EXIT(sm->p_log); 200 } 201 202 /********************************************************************** 203 The plock must be held before calling this function. 204 **********************************************************************/ 205 static void pi_rcv_process_switch_port0(IN osm_sm_t * sm, 206 IN osm_node_t * p_node, 207 IN osm_physp_t * p_physp, 208 IN ib_port_info_t * p_pi) 209 { 210 ib_api_status_t status; 211 osm_madw_context_t context; 212 uint8_t port, num_ports; 213 214 OSM_LOG_ENTER(sm->p_log); 215 216 if (p_physp->need_update) 217 sm->p_subn->ignore_existing_lfts = TRUE; 218 219 pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp); 220 221 /* Update the PortInfo attribute */ 222 osm_physp_set_port_info(p_physp, p_pi, sm); 223 224 /* Determine if base switch port 0 */ 225 if (p_node->sw && 226 !ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info)) 227 /* PortState is not used on BSP0 but just in case it is DOWN */ 228 p_physp->port_info = *p_pi; 229 230 /* Now, query PortInfo for the switch external ports */ 231 num_ports = osm_node_get_num_physp(p_node); 232 233 context.pi_context.node_guid = osm_node_get_node_guid(p_node); 234 context.pi_context.port_guid = osm_physp_get_port_guid(p_physp); 235 context.pi_context.set_method = FALSE; 236 context.pi_context.light_sweep = FALSE; 237 context.pi_context.active_transition = FALSE; 238 context.pi_context.client_rereg = FALSE; 239 240 for (port = 1; port < num_ports; port++) { 241 status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_physp), 242 IB_MAD_ATTR_PORT_INFO, cl_hton32(port), 243 FALSE, 244 ib_port_info_get_m_key(&p_physp->port_info), 245 CL_DISP_MSGID_NONE, &context); 246 if (status != IB_SUCCESS) 247 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F16: " 248 "Failure initiating PortInfo request (%s)\n", 249 ib_get_err_str(status)); 250 } 251 252 pi_rcv_process_endport(sm, p_physp, p_pi); 253 OSM_LOG_EXIT(sm->p_log); 254 } 255 256 /********************************************************************** 257 The plock must be held before calling this function. 258 **********************************************************************/ 259 static void pi_rcv_process_switch_ext_port(IN osm_sm_t * sm, 260 IN osm_node_t * p_node, 261 IN osm_physp_t * p_physp, 262 IN ib_port_info_t * p_pi) 263 { 264 ib_api_status_t status = IB_SUCCESS; 265 osm_madw_context_t context; 266 osm_physp_t *p_remote_physp, *physp0; 267 osm_node_t *p_remote_node; 268 ib_net64_t m_key; 269 unsigned data_vls; 270 uint8_t port_num; 271 uint8_t remote_port_num; 272 osm_dr_path_t path; 273 int mlnx_epi_supported = 0; 274 275 OSM_LOG_ENTER(sm->p_log); 276 277 /* 278 Check the state of the physical port. 279 If there appears to be something on the other end of the wire, 280 then ask for NodeInfo. Ignore the switch management port. 281 */ 282 port_num = osm_physp_get_port_num(p_physp); 283 284 if (sm->p_subn->opt.fdr10) 285 mlnx_epi_supported = is_mlnx_ext_port_info_supported( 286 ib_node_info_get_vendor_id(&p_node->node_info), 287 p_node->node_info.device_id); 288 289 /* if in_sweep_hop_0 is TRUE, then this means the SM is on the switch, 290 and we got switchInfo of our local switch. Do not continue 291 probing through the switch. */ 292 switch (ib_port_info_get_port_state(p_pi)) { 293 case IB_LINK_DOWN: 294 p_remote_physp = osm_physp_get_remote(p_physp); 295 if (p_remote_physp) { 296 p_remote_node = 297 osm_physp_get_node_ptr(p_remote_physp); 298 remote_port_num = 299 osm_physp_get_port_num(p_remote_physp); 300 301 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 302 "Unlinking local node 0x%" PRIx64 303 ", port %u" 304 "\n\t\t\t\tand remote node 0x%" PRIx64 305 ", port %u\n", 306 cl_ntoh64(osm_node_get_node_guid 307 (p_node)), port_num, 308 cl_ntoh64(osm_node_get_node_guid 309 (p_remote_node)), 310 remote_port_num); 311 312 if (sm->ucast_mgr.cache_valid) 313 osm_ucast_cache_add_link(&sm->ucast_mgr, 314 p_physp, 315 p_remote_physp); 316 317 osm_node_unlink(p_node, (uint8_t) port_num, 318 p_remote_node, 319 (uint8_t) remote_port_num); 320 321 } 322 break; 323 324 case IB_LINK_INIT: 325 case IB_LINK_ARMED: 326 case IB_LINK_ACTIVE: 327 physp0 = osm_node_get_physp_ptr(p_node, 0); 328 if (mlnx_epi_supported) { 329 m_key = ib_port_info_get_m_key(&physp0->port_info); 330 331 context.pi_context.node_guid = osm_node_get_node_guid(p_node); 332 context.pi_context.port_guid = osm_physp_get_port_guid(p_physp); 333 context.pi_context.set_method = FALSE; 334 context.pi_context.light_sweep = FALSE; 335 context.pi_context.active_transition = FALSE; 336 context.pi_context.client_rereg = FALSE; 337 status = osm_req_get(sm, 338 osm_physp_get_dr_path_ptr(p_physp), 339 IB_MAD_ATTR_MLNX_EXTENDED_PORT_INFO, 340 cl_hton32(port_num), FALSE, m_key, 341 CL_DISP_MSGID_NONE, &context); 342 if (status != IB_SUCCESS) 343 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F11: " 344 "Failure initiating MLNX ExtPortInfo request (%s)\n", 345 ib_get_err_str(status)); 346 } 347 if (sm->p_subn->in_sweep_hop_0 == FALSE) { 348 /* 349 To avoid looping forever, only probe the port if it 350 is NOT the port that responded to the SMP. 351 352 Request node info from the other end of this link: 353 1) Copy the current path from the parent node. 354 2) Extend the path to the next hop thru this port. 355 3) Request node info with the new path 356 357 */ 358 if (p_pi->local_port_num != 359 osm_physp_get_port_num(p_physp)) { 360 path = *osm_physp_get_dr_path_ptr(p_physp); 361 362 if (osm_dr_path_extend(&path, 363 osm_physp_get_port_num 364 (p_physp))) { 365 OSM_LOG(sm->p_log, OSM_LOG_ERROR, 366 "ERR 0F08: " 367 "DR path with hop count %d couldn't be extended\n", 368 path.hop_count); 369 break; 370 } 371 372 memset(&context, 0, sizeof(context)); 373 context.ni_context.node_guid = 374 osm_node_get_node_guid(p_node); 375 context.ni_context.port_num = 376 osm_physp_get_port_num(p_physp); 377 378 status = osm_req_get(sm, &path, 379 IB_MAD_ATTR_NODE_INFO, 0, 380 TRUE, 0, 381 CL_DISP_MSGID_NONE, 382 &context); 383 384 if (status != IB_SUCCESS) 385 OSM_LOG(sm->p_log, OSM_LOG_ERROR, 386 "ERR 0F02: " 387 "Failure initiating NodeInfo request (%s)\n", 388 ib_get_err_str(status)); 389 } else 390 OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 391 "Skipping SMP responder port %u\n", 392 p_pi->local_port_num); 393 } 394 break; 395 396 default: 397 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F03: " 398 "Unknown link state = %u, port = %u\n", 399 ib_port_info_get_port_state(p_pi), 400 p_pi->local_port_num); 401 break; 402 } 403 404 if (ib_port_info_get_port_state(p_pi) > IB_LINK_INIT && p_node->sw && 405 !ib_switch_info_get_state_change(&p_node->sw->switch_info) && 406 p_node->sw->need_update == 1) 407 p_node->sw->need_update = 0; 408 409 if (p_physp->need_update) 410 sm->p_subn->ignore_existing_lfts = TRUE; 411 412 /* 413 Update the PortInfo attribute. 414 */ 415 osm_physp_set_port_info(p_physp, p_pi, sm); 416 417 if (ib_port_info_get_port_state(p_pi) == IB_LINK_DOWN) 418 goto Exit; 419 420 p_remote_physp = osm_physp_get_remote(p_physp); 421 if (p_remote_physp) { 422 p_remote_node = osm_physp_get_node_ptr(p_remote_physp); 423 if (p_remote_node->sw) { 424 data_vls = 1U << (ib_port_info_get_vl_cap(p_pi) - 1); 425 if (data_vls > 1U << (sm->p_subn->opt.max_op_vls - 1)) 426 data_vls = 1U << (sm->p_subn->opt.max_op_vls - 1); 427 if (data_vls >= IB_MAX_NUM_VLS) 428 data_vls = IB_MAX_NUM_VLS - 1; 429 if ((uint8_t)data_vls < sm->p_subn->min_sw_data_vls) { 430 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 431 "Setting switch port minimal data VLs " 432 "to:%u defined by node:0x%" 433 PRIx64 ", port:%u\n", data_vls, 434 cl_ntoh64(osm_node_get_node_guid(p_node)), 435 port_num); 436 sm->p_subn->min_sw_data_vls = data_vls; 437 } 438 } 439 } 440 441 Exit: 442 OSM_LOG_EXIT(sm->p_log); 443 } 444 445 static void pi_rcv_process_ca_or_router_port(IN osm_sm_t * sm, 446 IN osm_node_t * p_node, 447 IN osm_physp_t * p_physp, 448 IN ib_port_info_t * p_pi) 449 { 450 OSM_LOG_ENTER(sm->p_log); 451 452 UNUSED_PARAM(p_node); 453 454 pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp); 455 456 osm_physp_set_port_info(p_physp, p_pi, sm); 457 458 pi_rcv_process_endport(sm, p_physp, p_pi); 459 460 OSM_LOG_EXIT(sm->p_log); 461 } 462 463 #define IBM_VENDOR_ID (0x5076) 464 static void get_pkey_table(IN osm_log_t * p_log, IN osm_sm_t * sm, 465 IN osm_node_t * p_node, IN osm_physp_t * p_physp) 466 { 467 468 osm_madw_context_t context; 469 ib_api_status_t status; 470 osm_dr_path_t path; 471 osm_physp_t *physp0; 472 ib_net64_t m_key; 473 uint8_t port_num; 474 uint16_t block_num, max_blocks; 475 uint32_t attr_mod_ho; 476 477 OSM_LOG_ENTER(p_log); 478 479 path = *osm_physp_get_dr_path_ptr(p_physp); 480 481 context.pkey_context.node_guid = osm_node_get_node_guid(p_node); 482 context.pkey_context.port_guid = osm_physp_get_port_guid(p_physp); 483 context.pkey_context.set_method = FALSE; 484 485 port_num = p_physp->port_num; 486 487 if (!p_node->sw || port_num == 0) 488 /* The maximum blocks is defined by the node info partition cap 489 for CA, router, and switch management ports. */ 490 max_blocks = 491 (cl_ntoh16(p_node->node_info.partition_cap) + 492 IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) 493 / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; 494 else { 495 /* This is a switch, and not a management port. The maximum blocks 496 is defined in the switch info partition enforcement cap. */ 497 498 /* Check for IBM eHCA firmware defect in reporting partition enforcement cap */ 499 if (cl_ntoh32(ib_node_info_get_vendor_id(&p_node->node_info)) == 500 IBM_VENDOR_ID) 501 p_node->sw->switch_info.enforce_cap = 0; 502 503 /* Bail out if this is a switch with no partition enforcement capability */ 504 if (cl_ntoh16(p_node->sw->switch_info.enforce_cap) == 0) 505 goto Exit; 506 507 max_blocks = (cl_ntoh16(p_node->sw->switch_info.enforce_cap) + 508 IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 509 1) / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; 510 } 511 512 p_physp->pkeys.rcv_blocks_cnt = max_blocks; 513 for (block_num = 0; block_num < max_blocks; block_num++) { 514 if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH || 515 osm_physp_get_port_num(p_physp) == 0) { 516 attr_mod_ho = block_num; 517 m_key = ib_port_info_get_m_key(&p_physp->port_info); 518 } else { 519 attr_mod_ho = block_num | (port_num << 16); 520 physp0 = osm_node_get_physp_ptr(p_node, 0); 521 m_key = ib_port_info_get_m_key(&physp0->port_info); 522 } 523 status = osm_req_get(sm, &path, IB_MAD_ATTR_P_KEY_TABLE, 524 cl_hton32(attr_mod_ho), FALSE, 525 m_key, CL_DISP_MSGID_NONE, &context); 526 527 if (status != IB_SUCCESS) { 528 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0F12: " 529 "Failure initiating PKeyTable request (%s)\n", 530 ib_get_err_str(status)); 531 goto Exit; 532 } 533 } 534 535 Exit: 536 OSM_LOG_EXIT(p_log); 537 } 538 539 static void pi_rcv_get_pkey_slvl_vla_tables(IN osm_sm_t * sm, 540 IN osm_node_t * p_node, 541 IN osm_physp_t * p_physp) 542 { 543 OSM_LOG_ENTER(sm->p_log); 544 545 get_pkey_table(sm->p_log, sm, p_node, p_physp); 546 547 OSM_LOG_EXIT(sm->p_log); 548 } 549 550 static int osm_pi_rcv_update_self(IN osm_sm_t *sm, IN osm_physp_t *p_physp, 551 IN ib_port_info_t *p_pi) 552 { 553 if (ib_port_info_get_port_state(p_pi) == IB_LINK_DOWN) 554 return 0; 555 556 if (sm->p_subn->need_update || p_physp->need_update > 1 || 557 ib_port_info_get_port_state(p_pi) == IB_LINK_INIT) 558 return 1; 559 560 return 0; 561 } 562 563 static void pi_rcv_process_set(IN osm_sm_t * sm, IN osm_node_t * p_node, 564 IN uint8_t port_num, IN osm_madw_t * p_madw) 565 { 566 osm_physp_t *p_physp; 567 ib_net64_t port_guid; 568 ib_smp_t *p_smp; 569 ib_port_info_t *p_pi; 570 osm_pi_context_t *p_context; 571 osm_log_level_t level; 572 573 OSM_LOG_ENTER(sm->p_log); 574 575 p_context = osm_madw_get_pi_context_ptr(p_madw); 576 577 CL_ASSERT(p_node); 578 579 p_physp = osm_node_get_physp_ptr(p_node, port_num); 580 CL_ASSERT(p_physp); 581 582 port_guid = osm_physp_get_port_guid(p_physp); 583 584 p_smp = osm_madw_get_smp_ptr(p_madw); 585 p_pi = ib_smp_get_payload_ptr(p_smp); 586 587 /* check for error */ 588 if (cl_ntoh16(p_smp->status) & 0x7fff) { 589 /* If port already ACTIVE, don't treat status 7 as error */ 590 if (p_context->active_transition && 591 (cl_ntoh16(p_smp->status) & 0x7fff) == 0x1c) { 592 level = OSM_LOG_INFO; 593 OSM_LOG(sm->p_log, OSM_LOG_INFO, 594 "Received error status 0x%x for SetResp() during ACTIVE transition\n", 595 cl_ntoh16(p_smp->status) & 0x7fff); 596 /* Should there be a subsequent Get to validate that port is ACTIVE ? */ 597 } else { 598 level = OSM_LOG_ERROR; 599 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F10: " 600 "Received error status for SetResp()\n"); 601 } 602 osm_dump_port_info_v2(sm->p_log, osm_node_get_node_guid(p_node), 603 port_guid, port_num, p_pi, FILE_ID, level); 604 } else 605 osm_physp_set_port_info(p_physp, p_pi, sm); 606 607 OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 608 "Received logical SetResp() for GUID 0x%" PRIx64 609 ", port num %u" 610 "\n\t\t\t\tfor parent node GUID 0x%" PRIx64 611 " TID 0x%" PRIx64 "\n", 612 cl_ntoh64(port_guid), port_num, 613 cl_ntoh64(osm_node_get_node_guid(p_node)), 614 cl_ntoh64(p_smp->trans_id)); 615 616 617 OSM_LOG_EXIT(sm->p_log); 618 } 619 620 static int osm_pi_rcv_update_neighbor(IN osm_physp_t *p_physp) 621 { 622 osm_physp_t *p_rem_physp = p_physp->p_remote_physp; 623 osm_node_t *p_node; 624 625 /* 626 * Our own port - this is the only case where CA port 627 * is discovered before its' neighbor port 628 */ 629 if (!p_rem_physp) 630 return p_physp->need_update; 631 632 p_node = osm_physp_get_node_ptr(p_rem_physp); 633 CL_ASSERT(p_node); 634 635 /* CA/RTR to CA/RTR connection */ 636 if (!p_node->sw) 637 return p_physp->need_update; 638 639 return (ib_switch_info_get_state_change(&p_node->sw->switch_info) ? 1 : p_physp->need_update); 640 } 641 642 void osm_pi_rcv_process(IN void *context, IN void *data) 643 { 644 osm_sm_t *sm = context; 645 osm_madw_t *p_madw = data; 646 ib_port_info_t *p_pi; 647 ib_smp_t *p_smp; 648 osm_port_t *p_port; 649 osm_physp_t *p_physp; 650 osm_dr_path_t *p_dr_path; 651 osm_node_t *p_node; 652 osm_pi_context_t *p_context; 653 ib_net64_t port_guid, node_guid; 654 uint8_t port_num; 655 656 CL_ASSERT(sm); 657 658 OSM_LOG_ENTER(sm->p_log); 659 660 CL_ASSERT(p_madw); 661 662 p_smp = osm_madw_get_smp_ptr(p_madw); 663 p_context = osm_madw_get_pi_context_ptr(p_madw); 664 p_pi = ib_smp_get_payload_ptr(p_smp); 665 666 CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_PORT_INFO); 667 668 /* 669 * Attribute modifier has already been validated upon MAD receive, 670 * which means that port_num has to be valid - it originated from 671 * the request attribute modifier. 672 */ 673 port_num = (uint8_t) cl_ntoh32(p_smp->attr_mod); 674 675 port_guid = p_context->port_guid; 676 node_guid = p_context->node_guid; 677 678 osm_dump_port_info_v2(sm->p_log, node_guid, port_guid, port_num, p_pi, 679 FILE_ID, OSM_LOG_DEBUG); 680 681 /* On receipt of client reregister, clear the reregister bit so 682 reregistering won't be sent again and again */ 683 if (p_context->set_method && 684 (ib_port_info_get_client_rereg(p_pi) || p_context->client_rereg)) { 685 OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 686 "Client reregister received on response\n"); 687 ib_port_info_set_client_rereg(p_pi, 0); 688 p_context->client_rereg = FALSE; 689 } 690 691 /* 692 we might get a response during a light sweep looking for a change in 693 the status of a remote port that did not respond in earlier sweeps. 694 So if the context of the Get was light_sweep - we do not need to 695 do anything with the response - just flag that we need a heavy sweep 696 */ 697 if (p_context->light_sweep == TRUE) { 698 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 699 "Got light sweep response from remote port of parent node " 700 "GUID 0x%" PRIx64 " port 0x%016" PRIx64 701 ", Commencing heavy sweep\n", 702 cl_ntoh64(node_guid), cl_ntoh64(port_guid)); 703 sm->p_subn->force_heavy_sweep = TRUE; 704 sm->p_subn->ignore_existing_lfts = TRUE; 705 goto Exit; 706 } 707 708 CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); 709 p_port = osm_get_port_by_guid(sm->p_subn, port_guid); 710 if (PF(!p_port)) { 711 CL_PLOCK_RELEASE(sm->p_lock); 712 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F06: " 713 "No port object for port with GUID 0x%" PRIx64 714 "\n\t\t\t\tfor parent node GUID 0x%" PRIx64 715 ", TID 0x%" PRIx64 "\n", 716 cl_ntoh64(port_guid), 717 cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); 718 goto Exit; 719 } 720 721 p_node = p_port->p_node; 722 CL_ASSERT(p_node); 723 724 if (PF(p_pi->local_port_num > p_node->node_info.num_ports)) { 725 CL_PLOCK_RELEASE(sm->p_lock); 726 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F15: " 727 "Received PortInfo for port GUID 0x%" PRIx64 " is " 728 "non-compliant and is being ignored since the " 729 "local port num %u > num ports %u\n", 730 cl_ntoh64(port_guid), p_pi->local_port_num, 731 p_node->node_info.num_ports); 732 goto Exit; 733 } 734 735 /* 736 If we were setting the PortInfo, then receiving 737 this attribute was not part of sweeping the subnet. 738 In this case, just update the PortInfo attribute. 739 740 In an unfortunate blunder, the IB spec defines the 741 return method for Set() as a GetResp(). Thus, we can't 742 use the method (what would have been SetResp()) to determine 743 our course of action. So, we have to carry this extra 744 boolean around to determine if we were doing Get() or Set(). 745 */ 746 if (p_context->set_method) 747 pi_rcv_process_set(sm, p_node, port_num, p_madw); 748 else { 749 750 /* 751 This PortInfo arrived because we did a Get() method, 752 most likely due to a subnet sweep in progress. 753 */ 754 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 755 "Discovered port num %u with GUID 0x%" PRIx64 756 " for parent node GUID 0x%" PRIx64 757 ", TID 0x%" PRIx64 "\n", 758 port_num, cl_ntoh64(port_guid), 759 cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); 760 761 p_physp = osm_node_get_physp_ptr(p_node, port_num); 762 763 CL_ASSERT(p_physp); 764 765 /* Update the directed route path to this port 766 in case the old path is no longer usable. */ 767 p_dr_path = osm_physp_get_dr_path_ptr(p_physp); 768 osm_dr_path_init(p_dr_path, p_smp->hop_count, 769 p_smp->initial_path); 770 771 p_physp->need_update = osm_pi_rcv_update_self(sm, p_physp, p_pi); 772 773 switch (osm_node_get_type(p_node)) { 774 case IB_NODE_TYPE_CA: 775 case IB_NODE_TYPE_ROUTER: 776 if (!p_node->physp_discovered[port_num]) { 777 p_port->discovery_count++; 778 p_node->physp_discovered[port_num] = 1; 779 } 780 p_physp->need_update = osm_pi_rcv_update_neighbor(p_physp); 781 pi_rcv_process_ca_or_router_port(sm, p_node, p_physp, 782 p_pi); 783 break; 784 case IB_NODE_TYPE_SWITCH: 785 if (!p_node->physp_discovered[port_num]) { 786 p_port->discovery_count++; 787 p_node->physp_discovered[port_num] = 1; 788 } 789 if (port_num == 0) 790 pi_rcv_process_switch_port0(sm, p_node, 791 p_physp, p_pi); 792 else 793 pi_rcv_process_switch_ext_port(sm, p_node, 794 p_physp, p_pi); 795 break; 796 default: 797 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F07: " 798 "Unknown node type %u with GUID 0x%" PRIx64 799 "\n", osm_node_get_type(p_node), 800 cl_ntoh64(node_guid)); 801 break; 802 } 803 804 /* 805 Get the tables on the physp. 806 */ 807 if (p_physp->need_update || (p_node->sw && 808 p_node->sw->need_update)) 809 pi_rcv_get_pkey_slvl_vla_tables(sm, p_node, p_physp); 810 811 } 812 813 CL_PLOCK_RELEASE(sm->p_lock); 814 815 Exit: 816 /* 817 Release the lock before jumping here!! 818 */ 819 OSM_LOG_EXIT(sm->p_log); 820 } 821