1321936Shselasky/* 2321936Shselasky * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. 3321936Shselasky * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. 4321936Shselasky * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5321936Shselasky * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. 6321936Shselasky * 7321936Shselasky * This software is available to you under a choice of one of two 8321936Shselasky * licenses. You may choose to be licensed under the terms of the GNU 9321936Shselasky * General Public License (GPL) Version 2, available from the file 10321936Shselasky * COPYING in the main directory of this source tree, or the 11321936Shselasky * OpenIB.org BSD license below: 12321936Shselasky * 13321936Shselasky * Redistribution and use in source and binary forms, with or 14321936Shselasky * without modification, are permitted provided that the following 15321936Shselasky * conditions are met: 16321936Shselasky * 17321936Shselasky * - Redistributions of source code must retain the above 18321936Shselasky * copyright notice, this list of conditions and the following 19321936Shselasky * disclaimer. 20321936Shselasky * 21321936Shselasky * - Redistributions in binary form must reproduce the above 22321936Shselasky * copyright notice, this list of conditions and the following 23321936Shselasky * disclaimer in the documentation and/or other materials 24321936Shselasky * provided with the distribution. 25321936Shselasky * 26321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 30321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33321936Shselasky * SOFTWARE. 34321936Shselasky * 35321936Shselasky */ 36321936Shselasky 37321936Shselasky/* 38321936Shselasky * Abstract: 39321936Shselasky * Implementation of osm_sminfo_rcv_t. 40321936Shselasky * This object represents the SMInfo Receiver object. 41321936Shselasky * This object is part of the opensm family of objects. 42321936Shselasky */ 43321936Shselasky 44321936Shselasky#if HAVE_CONFIG_H 45321936Shselasky# include <config.h> 46321936Shselasky#endif /* HAVE_CONFIG_H */ 47321936Shselasky 48321936Shselasky#include <stdlib.h> 49321936Shselasky#include <string.h> 50321936Shselasky#include <iba/ib_types.h> 51321936Shselasky#include <complib/cl_qmap.h> 52321936Shselasky#include <complib/cl_passivelock.h> 53321936Shselasky#include <complib/cl_debug.h> 54321936Shselasky#include <opensm/osm_file_ids.h> 55321936Shselasky#define FILE_ID OSM_FILE_SMINFO_RCV_C 56321936Shselasky#include <opensm/osm_madw.h> 57321936Shselasky#include <opensm/osm_log.h> 58321936Shselasky#include <opensm/osm_node.h> 59321936Shselasky#include <opensm/osm_helper.h> 60321936Shselasky#include <opensm/osm_subnet.h> 61321936Shselasky#include <opensm/osm_sm.h> 62321936Shselasky#include <opensm/osm_opensm.h> 63321936Shselasky 64321936Shselasky/********************************************************************** 65321936Shselasky Return TRUE if the remote sm given (by ib_sm_info_t) is higher, 66321936Shselasky return FALSE otherwise. 67321936Shselasky By higher - we mean: SM with higher priority or with same priority 68321936Shselasky and lower GUID. 69321936Shselasky**********************************************************************/ 70321936Shselaskystatic boolean_t smi_rcv_remote_sm_is_higher(IN osm_sm_t * sm, 71321936Shselasky IN const ib_sm_info_t * p_rem_smi) 72321936Shselasky{ 73321936Shselasky return osm_sm_is_greater_than(ib_sminfo_get_priority(p_rem_smi), 74321936Shselasky p_rem_smi->guid, 75321936Shselasky sm->p_subn->opt.sm_priority, 76321936Shselasky sm->p_subn->sm_port_guid); 77321936Shselasky 78321936Shselasky} 79321936Shselasky 80321936Shselaskystatic void smi_rcv_process_get_request(IN osm_sm_t * sm, 81321936Shselasky IN const osm_madw_t * p_madw, 82321936Shselasky IN boolean_t fill_sm_key) 83321936Shselasky{ 84321936Shselasky uint8_t payload[IB_SMP_DATA_SIZE]; 85321936Shselasky ib_sm_info_t *p_smi = (ib_sm_info_t *) payload; 86321936Shselasky ib_api_status_t status; 87321936Shselasky 88321936Shselasky OSM_LOG_ENTER(sm->p_log); 89321936Shselasky 90321936Shselasky CL_ASSERT(p_madw); 91321936Shselasky 92321936Shselasky /* No real need to grab the lock for this function. */ 93321936Shselasky memset(payload, 0, sizeof(payload)); 94321936Shselasky 95321936Shselasky CL_ASSERT(osm_madw_get_smp_ptr(p_madw)->method == IB_MAD_METHOD_GET); 96321936Shselasky 97321936Shselasky p_smi->guid = sm->p_subn->sm_port_guid; 98321936Shselasky p_smi->act_count = cl_hton32(sm->p_subn->p_osm->stats.qp0_mads_sent); 99321936Shselasky p_smi->pri_state = (uint8_t) (sm->p_subn->sm_state | 100321936Shselasky sm->p_subn->opt.sm_priority << 4); 101321936Shselasky p_smi->sm_key = fill_sm_key ? sm->p_subn->opt.sm_key : 0; 102321936Shselasky 103321936Shselasky status = osm_resp_send(sm, p_madw, 0, payload); 104321936Shselasky if (status != IB_SUCCESS) { 105321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F02: " 106321936Shselasky "Error sending SMInfo response (%s)\n", 107321936Shselasky ib_get_err_str(status)); 108321936Shselasky goto Exit; 109321936Shselasky } 110321936Shselasky 111321936ShselaskyExit: 112321936Shselasky OSM_LOG_EXIT(sm->p_log); 113321936Shselasky} 114321936Shselasky 115321936Shselasky/********************************************************************** 116321936Shselasky * Check if the p_smp received is legal. 117321936Shselasky * Current checks: 118321936Shselasky * MADHeader:AttributeModifier of ACKNOWLEDGE that was not sent by a 119321936Shselasky * Standby SM. 120321936Shselasky * MADHeader:AttributeModifiers of HANDOVER/DISABLE/STANDBY/DISCOVER 121321936Shselasky * that was not sent by a Master SM. 122321936Shselasky * FUTURE - TO DO: 123321936Shselasky * Check that the SM_Key matches. 124321936Shselasky **********************************************************************/ 125321936Shselaskystatic ib_api_status_t smi_rcv_check_set_req_legality(IN const ib_smp_t * p_smp) 126321936Shselasky{ 127321936Shselasky ib_sm_info_t *p_smi; 128321936Shselasky 129321936Shselasky p_smi = ib_smp_get_payload_ptr(p_smp); 130321936Shselasky 131321936Shselasky if (p_smp->attr_mod == IB_SMINFO_ATTR_MOD_ACKNOWLEDGE) { 132321936Shselasky if (ib_sminfo_get_state(p_smi) == IB_SMINFO_STATE_STANDBY) 133321936Shselasky return IB_SUCCESS; 134321936Shselasky } else if (p_smp->attr_mod == IB_SMINFO_ATTR_MOD_HANDOVER || 135321936Shselasky p_smp->attr_mod == IB_SMINFO_ATTR_MOD_DISABLE || 136321936Shselasky p_smp->attr_mod == IB_SMINFO_ATTR_MOD_STANDBY || 137321936Shselasky p_smp->attr_mod == IB_SMINFO_ATTR_MOD_DISCOVER) { 138321936Shselasky if (ib_sminfo_get_state(p_smi) == IB_SMINFO_STATE_MASTER) 139321936Shselasky return IB_SUCCESS; 140321936Shselasky } 141321936Shselasky 142321936Shselasky return IB_INVALID_PARAMETER; 143321936Shselasky} 144321936Shselasky 145321936Shselaskystatic void smi_rcv_process_set_request(IN osm_sm_t * sm, 146321936Shselasky IN const osm_madw_t * p_madw) 147321936Shselasky{ 148321936Shselasky uint8_t payload[IB_SMP_DATA_SIZE]; 149321936Shselasky ib_smp_t *p_smp; 150321936Shselasky ib_sm_info_t *p_smi = (ib_sm_info_t *) payload; 151321936Shselasky ib_sm_info_t *sm_smi; 152321936Shselasky ib_api_status_t status; 153321936Shselasky osm_sm_signal_t sm_signal; 154321936Shselasky 155321936Shselasky OSM_LOG_ENTER(sm->p_log); 156321936Shselasky 157321936Shselasky CL_ASSERT(p_madw); 158321936Shselasky 159321936Shselasky memset(payload, 0, sizeof(payload)); 160321936Shselasky 161321936Shselasky p_smp = osm_madw_get_smp_ptr(p_madw); 162321936Shselasky sm_smi = ib_smp_get_payload_ptr(p_smp); 163321936Shselasky 164321936Shselasky if (p_smp->method != IB_MAD_METHOD_SET) { 165321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F03: " 166321936Shselasky "Unsupported set method 0x%X\n", p_smp->method); 167321936Shselasky goto Exit; 168321936Shselasky } 169321936Shselasky 170321936Shselasky CL_PLOCK_ACQUIRE(sm->p_lock); 171321936Shselasky 172321936Shselasky p_smi->guid = sm->p_subn->sm_port_guid; 173321936Shselasky p_smi->act_count = cl_hton32(sm->p_subn->p_osm->stats.qp0_mads_sent); 174321936Shselasky p_smi->pri_state = (uint8_t) (sm->p_subn->sm_state | 175321936Shselasky sm->p_subn->opt.sm_priority << 4); 176321936Shselasky p_smi->sm_key = sm->p_subn->opt.sm_key; 177321936Shselasky 178321936Shselasky /* Check the legality of the packet */ 179321936Shselasky status = smi_rcv_check_set_req_legality(p_smp); 180321936Shselasky if (status != IB_SUCCESS) { 181321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F04: " 182321936Shselasky "Check legality failed. AttributeModifier:0x%X RemoteState:%s\n", 183321936Shselasky p_smp->attr_mod, 184321936Shselasky osm_get_sm_mgr_state_str(ib_sminfo_get_state(sm_smi))); 185321936Shselasky status = osm_resp_send(sm, p_madw, 7, payload); 186321936Shselasky if (status != IB_SUCCESS) 187321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F05: " 188321936Shselasky "Error sending SMInfo response (%s)\n", 189321936Shselasky ib_get_err_str(status)); 190321936Shselasky CL_PLOCK_RELEASE(sm->p_lock); 191321936Shselasky goto Exit; 192321936Shselasky } 193321936Shselasky 194321936Shselasky /* translate from IB_SMINFO_ATTR to OSM_SM_SIGNAL */ 195321936Shselasky switch (p_smp->attr_mod) { 196321936Shselasky case IB_SMINFO_ATTR_MOD_HANDOVER: 197321936Shselasky sm_signal = OSM_SM_SIGNAL_HANDOVER; 198321936Shselasky break; 199321936Shselasky case IB_SMINFO_ATTR_MOD_ACKNOWLEDGE: 200321936Shselasky sm_signal = OSM_SM_SIGNAL_ACKNOWLEDGE; 201321936Shselasky break; 202321936Shselasky case IB_SMINFO_ATTR_MOD_DISABLE: 203321936Shselasky sm_signal = OSM_SM_SIGNAL_DISABLE; 204321936Shselasky break; 205321936Shselasky case IB_SMINFO_ATTR_MOD_STANDBY: 206321936Shselasky sm_signal = OSM_SM_SIGNAL_STANDBY; 207321936Shselasky break; 208321936Shselasky case IB_SMINFO_ATTR_MOD_DISCOVER: 209321936Shselasky sm_signal = OSM_SM_SIGNAL_DISCOVER; 210321936Shselasky break; 211321936Shselasky default: 212321936Shselasky /* 213321936Shselasky This code shouldn't be reached - checked in the 214321936Shselasky check legality 215321936Shselasky */ 216321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F06: " 217321936Shselasky "THIS CODE SHOULD NOT BE REACHED!!\n"); 218321936Shselasky CL_PLOCK_RELEASE(sm->p_lock); 219321936Shselasky goto Exit; 220321936Shselasky } 221321936Shselasky 222321936Shselasky CL_PLOCK_RELEASE(sm->p_lock); 223321936Shselasky 224321936Shselasky /* check legality of the needed transition in the SM state machine */ 225321936Shselasky status = osm_sm_state_mgr_check_legality(sm, sm_signal); 226321936Shselasky if (status != IB_SUCCESS) { 227321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F07: " 228321936Shselasky "Failed check of legality of needed SM transition. " 229321936Shselasky "AttributeModifier:0x%X RemoteState:%s\n", 230321936Shselasky p_smp->attr_mod, 231321936Shselasky osm_get_sm_mgr_state_str(ib_sminfo_get_state(sm_smi))); 232321936Shselasky status = osm_resp_send(sm, p_madw, 7, payload); 233321936Shselasky if (status != IB_SUCCESS) 234321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F08: " 235321936Shselasky "Error sending SMInfo response (%s)\n", 236321936Shselasky ib_get_err_str(status)); 237321936Shselasky goto Exit; 238321936Shselasky } 239321936Shselasky 240321936Shselasky /* the SubnSet(SMInfo) command is ok. Send a response. */ 241321936Shselasky status = osm_resp_send(sm, p_madw, 0, payload); 242321936Shselasky if (status != IB_SUCCESS) 243321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F09: " 244321936Shselasky "Error sending SMInfo response (%s)\n", 245321936Shselasky ib_get_err_str(status)); 246321936Shselasky 247321936Shselasky /* it is a legal packet - act according to it */ 248321936Shselasky 249321936Shselasky /* if the AttributeModifier is STANDBY - need to save on the sm in */ 250321936Shselasky /* the master_sm_guid variable - the guid of the current master. */ 251321936Shselasky if (p_smp->attr_mod == IB_SMINFO_ATTR_MOD_STANDBY) { 252321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 253321936Shselasky "Received a STANDBY signal. Updating " 254321936Shselasky "sm_state_mgr master_guid: 0x%016" PRIx64 "\n", 255321936Shselasky cl_ntoh64(sm_smi->guid)); 256321936Shselasky CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); 257321936Shselasky sm->master_sm_guid = sm_smi->guid; 258321936Shselasky CL_PLOCK_RELEASE(sm->p_lock); 259321936Shselasky } 260321936Shselasky 261321936Shselasky status = osm_sm_state_mgr_process(sm, sm_signal); 262321936Shselasky 263321936Shselasky if (status != IB_SUCCESS) 264321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F10: " 265321936Shselasky "Error in SM state transition (%s)\n", 266321936Shselasky ib_get_err_str(status)); 267321936Shselasky 268321936ShselaskyExit: 269321936Shselasky OSM_LOG_EXIT(sm->p_log); 270321936Shselasky} 271321936Shselasky 272321936Shselaskystatic void smi_rcv_process_get_sm(IN osm_sm_t * sm, 273321936Shselasky IN const osm_remote_sm_t * p_sm, 274321936Shselasky boolean_t light_sweep) 275321936Shselasky{ 276321936Shselasky const ib_sm_info_t *p_smi; 277321936Shselasky 278321936Shselasky OSM_LOG_ENTER(sm->p_log); 279321936Shselasky 280321936Shselasky p_smi = &p_sm->smi; 281321936Shselasky 282321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 283321936Shselasky "Detected SM 0x%016" PRIx64 " in state %u (%s)\n", 284321936Shselasky cl_ntoh64(p_smi->guid), ib_sminfo_get_state(p_smi), 285321936Shselasky osm_get_sm_mgr_state_str(ib_sminfo_get_state(p_smi))); 286321936Shselasky 287321936Shselasky /* Check the state of this SM vs. our own. */ 288321936Shselasky switch (sm->p_subn->sm_state) { 289321936Shselasky case IB_SMINFO_STATE_NOTACTIVE: 290321936Shselasky break; 291321936Shselasky 292321936Shselasky case IB_SMINFO_STATE_DISCOVERING: 293321936Shselasky switch (ib_sminfo_get_state(p_smi)) { 294321936Shselasky case IB_SMINFO_STATE_NOTACTIVE: 295321936Shselasky break; 296321936Shselasky case IB_SMINFO_STATE_MASTER: 297321936Shselasky sm->master_sm_found = 1; 298321936Shselasky /* save on the sm the guid of the current master. */ 299321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 300321936Shselasky "Found master SM. Updating sm_state_mgr master_guid: 0x%016" 301321936Shselasky PRIx64 "\n", cl_ntoh64(p_smi->guid)); 302321936Shselasky sm->master_sm_guid = p_smi->guid; 303321936Shselasky break; 304321936Shselasky case IB_SMINFO_STATE_DISCOVERING: 305321936Shselasky case IB_SMINFO_STATE_STANDBY: 306321936Shselasky if (smi_rcv_remote_sm_is_higher(sm, p_smi)) { 307321936Shselasky /* the remote is a higher sm - need to stop sweeping */ 308321936Shselasky sm->master_sm_found = 1; 309321936Shselasky /* save on the sm the guid of the higher SM we found - */ 310321936Shselasky /* we will poll it - as long as it lives - we should be in Standby. */ 311321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 312321936Shselasky "Found higher SM. Updating sm_state_mgr master_guid:" 313321936Shselasky " 0x%016" PRIx64 "\n", 314321936Shselasky cl_ntoh64(p_smi->guid)); 315321936Shselasky sm->master_sm_guid = p_smi->guid; 316321936Shselasky } 317321936Shselasky break; 318321936Shselasky default: 319321936Shselasky break; 320321936Shselasky } 321321936Shselasky break; 322321936Shselasky 323321936Shselasky case IB_SMINFO_STATE_STANDBY: 324321936Shselasky /* if the guid of the SM that sent us this response is equal to the */ 325321936Shselasky /* p_sm_mgr->master_guid - then this is a signal that the polling */ 326321936Shselasky switch (ib_sminfo_get_state(p_smi)) { 327321936Shselasky case IB_SMINFO_STATE_MASTER: 328321936Shselasky /* This means the master is alive */ 329321936Shselasky /* Signal that to the SM state mgr */ 330321936Shselasky osm_sm_state_mgr_signal_master_is_alive(sm); 331321936Shselasky 332321936Shselasky if (!smi_rcv_remote_sm_is_higher(sm, p_smi)) 333321936Shselasky osm_send_trap144(sm, 334321936Shselasky TRAP_144_MASK_SM_PRIORITY_CHANGE); 335321936Shselasky break; 336321936Shselasky case IB_SMINFO_STATE_STANDBY: 337321936Shselasky /* This should be the response from the sm we are polling. */ 338321936Shselasky /* If it is - then signal master is alive */ 339321936Shselasky if (sm->master_sm_guid == p_sm->smi.guid) { 340321936Shselasky /* Make sure that it is an SM with higher priority than us. 341321936Shselasky If we started polling it when it was master, and it moved 342321936Shselasky to standby - then it might be with a lower priority than 343321936Shselasky us - and then we don't want to continue polling it. */ 344321936Shselasky if (smi_rcv_remote_sm_is_higher(sm, p_smi)) 345321936Shselasky osm_sm_state_mgr_signal_master_is_alive 346321936Shselasky (sm); 347321936Shselasky } 348321936Shselasky break; 349321936Shselasky default: 350321936Shselasky /* any other state - do nothing */ 351321936Shselasky break; 352321936Shselasky } 353321936Shselasky break; 354321936Shselasky 355321936Shselasky case IB_SMINFO_STATE_MASTER: 356321936Shselasky switch (ib_sminfo_get_state(p_smi)) { 357321936Shselasky case IB_SMINFO_STATE_MASTER: 358321936Shselasky /* If this is a response due to our polling, this means that we are 359321936Shselasky * waiting for a handover from this SM, and it is still alive - 360321936Shselasky * signal that. If we detected the remote SM with higher priority 361321936Shselasky * we should init a heavy sweep in order to go STANDBY. If we 362321936Shselasky * detected a remote SM with lower priority, we should resend trap144 363321936Shselasky * as it might not get it and we don't want to wait for a HANDOVER 364321936Shselasky * forever. 365321936Shselasky */ 366321936Shselasky if (sm->polling_sm_guid) { 367321936Shselasky if (smi_rcv_remote_sm_is_higher(sm, p_smi)) 368321936Shselasky sm->p_subn->force_heavy_sweep = TRUE; 369321936Shselasky else { 370321936Shselasky /* Update master_sm_guid to the GUID of the newly 371321936Shselasky * found MASTER SM and send trap 144 to it. 372321936Shselasky */ 373321936Shselasky sm->master_sm_guid = sm->polling_sm_guid; 374321936Shselasky osm_send_trap144(sm, TRAP_144_MASK_SM_PRIORITY_CHANGE); 375321936Shselasky } 376321936Shselasky osm_sm_state_mgr_signal_master_is_alive(sm); 377321936Shselasky } else { 378321936Shselasky /* This is a response we got while sweeping the subnet. 379321936Shselasky * 380321936Shselasky * If this is during a heavy sweep, we will handle a case of 381321936Shselasky * handover needed later on, when the sweep is done and all 382321936Shselasky * SMs are recognized. 383321936Shselasky * 384321936Shselasky * If this is during a light sweep, initiate a heavy sweep 385321936Shselasky * to initiate handover scenarios. 386321936Shselasky * 387321936Shselasky * Note that it does not matter if the remote SM is lower 388321936Shselasky * or higher priority. If it is lower priority, we must 389321936Shselasky * wait for it HANDOVER. If it is higher priority, we need 390321936Shselasky * to HANDOVER to it. Both cases are handled after doing 391321936Shselasky * a heavy sweep. 392321936Shselasky */ 393321936Shselasky if (light_sweep) 394321936Shselasky sm->p_subn->force_heavy_sweep = TRUE; 395321936Shselasky } 396321936Shselasky break; 397321936Shselasky case IB_SMINFO_STATE_STANDBY: 398321936Shselasky if (light_sweep && 399321936Shselasky smi_rcv_remote_sm_is_higher(sm, p_smi)) 400321936Shselasky sm->p_subn->force_heavy_sweep = TRUE; 401321936Shselasky break; 402321936Shselasky default: 403321936Shselasky /* any other state - do nothing */ 404321936Shselasky break; 405321936Shselasky } 406321936Shselasky break; 407321936Shselasky 408321936Shselasky default: 409321936Shselasky break; 410321936Shselasky } 411321936Shselasky 412321936Shselasky OSM_LOG_EXIT(sm->p_log); 413321936Shselasky} 414321936Shselasky 415321936Shselaskystatic void smi_rcv_process_get_response(IN osm_sm_t * sm, 416321936Shselasky IN const osm_madw_t * p_madw) 417321936Shselasky{ 418321936Shselasky const ib_smp_t *p_smp; 419321936Shselasky const ib_sm_info_t *p_smi; 420321936Shselasky cl_qmap_t *p_sm_tbl; 421321936Shselasky osm_port_t *p_port; 422321936Shselasky ib_net64_t port_guid; 423321936Shselasky osm_remote_sm_t *p_sm; 424321936Shselasky char buf[256]; 425321936Shselasky 426321936Shselasky OSM_LOG_ENTER(sm->p_log); 427321936Shselasky 428321936Shselasky CL_ASSERT(p_madw); 429321936Shselasky 430321936Shselasky p_smp = osm_madw_get_smp_ptr(p_madw); 431321936Shselasky 432321936Shselasky if (p_smp->method != IB_MAD_METHOD_GET_RESP) { 433321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F11: " 434321936Shselasky "Unsupported response method 0x%X\n", p_smp->method); 435321936Shselasky goto Exit; 436321936Shselasky } 437321936Shselasky 438321936Shselasky p_smi = ib_smp_get_payload_ptr(p_smp); 439321936Shselasky p_sm_tbl = &sm->p_subn->sm_guid_tbl; 440321936Shselasky port_guid = p_smi->guid; 441321936Shselasky 442321936Shselasky osm_dump_sm_info_v2(sm->p_log, p_smi, FILE_ID, OSM_LOG_DEBUG); 443321936Shselasky 444321936Shselasky /* Check that the sm_key of the found SM is the same as ours, 445321936Shselasky or is zero. If not - OpenSM should ignore this SM */ 446321936Shselasky if (sm->p_subn->opt.sm_key != 0 && p_smi->sm_key != sm->p_subn->opt.sm_key) { 447321936Shselasky if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR) 448321936Shselasky sprint_uint8_arr(buf, sizeof(buf), 449321936Shselasky p_smp->initial_path, p_smp->hop_count + 1); 450321936Shselasky else 451321936Shselasky sprintf(buf, "LID %u", 452321936Shselasky cl_ntoh16(p_madw->mad_addr.addr_type.smi.source_lid)); 453321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F18: " 454321936Shselasky "Got SM (%s) with sm_key 0x%016" PRIx64 " that doesn't match our " 455321936Shselasky "local sm_key. Ignoring SMInfo\n", buf, cl_ntoh64(p_smi->sm_key)); 456321936Shselasky osm_log_v2(sm->p_log, OSM_LOG_SYS, FILE_ID, 457321936Shselasky "Found remote SM (%s) with non-matching sm_key\n", buf); 458321936Shselasky goto Exit; 459321936Shselasky } 460321936Shselasky 461321936Shselasky /* Determine if we already have another SM object for this SM. */ 462321936Shselasky CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); 463321936Shselasky 464321936Shselasky p_port = osm_get_port_by_guid(sm->p_subn, port_guid); 465321936Shselasky if (!p_port) { 466321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F12: " 467321936Shselasky "No port object for this SM\n"); 468321936Shselasky goto _unlock_and_exit; 469321936Shselasky } 470321936Shselasky 471321936Shselasky if (osm_port_get_guid(p_port) != p_smi->guid) { 472321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F13: " 473321936Shselasky "Bogus SM port GUID, Expected 0x%016" PRIx64 474321936Shselasky ", Received 0x%016" PRIx64 "\n", 475321936Shselasky cl_ntoh64(osm_port_get_guid(p_port)), 476321936Shselasky cl_ntoh64(p_smi->guid)); 477321936Shselasky goto _unlock_and_exit; 478321936Shselasky } 479321936Shselasky 480321936Shselasky if (port_guid == sm->p_subn->sm_port_guid) { 481321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, 482321936Shselasky "Self query response received - SM port 0x%016" PRIx64 483321936Shselasky "\n", cl_ntoh64(port_guid)); 484321936Shselasky goto _unlock_and_exit; 485321936Shselasky } 486321936Shselasky 487321936Shselasky p_sm = (osm_remote_sm_t *) cl_qmap_get(p_sm_tbl, port_guid); 488321936Shselasky if (p_sm == (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) { 489321936Shselasky p_sm = malloc(sizeof(*p_sm)); 490321936Shselasky if (p_sm == NULL) { 491321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F14: " 492321936Shselasky "Unable to allocate SM object\n"); 493321936Shselasky goto _unlock_and_exit; 494321936Shselasky } 495321936Shselasky 496321936Shselasky osm_remote_sm_init(p_sm, p_smi); 497321936Shselasky 498321936Shselasky cl_qmap_insert(p_sm_tbl, port_guid, &p_sm->map_item); 499321936Shselasky } else 500321936Shselasky /* We already know this SM. Update the SMInfo attribute. */ 501321936Shselasky p_sm->smi = *p_smi; 502321936Shselasky 503321936Shselasky smi_rcv_process_get_sm(sm, p_sm, 504321936Shselasky osm_madw_get_smi_context_ptr(p_madw)-> 505321936Shselasky light_sweep); 506321936Shselasky 507321936Shselasky_unlock_and_exit: 508321936Shselasky CL_PLOCK_RELEASE(sm->p_lock); 509321936Shselasky 510321936ShselaskyExit: 511321936Shselasky OSM_LOG_EXIT(sm->p_log); 512321936Shselasky} 513321936Shselasky 514321936Shselaskystatic void smi_rcv_process_set_response(IN osm_sm_t * sm, 515321936Shselasky IN const osm_madw_t * p_madw) 516321936Shselasky{ 517321936Shselasky const ib_smp_t *p_smp; 518321936Shselasky const ib_sm_info_t *p_smi; 519321936Shselasky 520321936Shselasky OSM_LOG_ENTER(sm->p_log); 521321936Shselasky 522321936Shselasky CL_ASSERT(p_madw); 523321936Shselasky 524321936Shselasky p_smp = osm_madw_get_smp_ptr(p_madw); 525321936Shselasky if (ib_smp_get_status(p_smp)) { 526321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 527321936Shselasky "MAD status 0x%x received\n", 528321936Shselasky cl_ntoh16(ib_smp_get_status(p_smp))); 529321936Shselasky goto Exit; 530321936Shselasky } 531321936Shselasky 532321936Shselasky if (p_smp->method != IB_MAD_METHOD_GET_RESP) { 533321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F16: " 534321936Shselasky "Unsupported response method 0x%X\n", p_smp->method); 535321936Shselasky goto Exit; 536321936Shselasky } 537321936Shselasky 538321936Shselasky p_smi = ib_smp_get_payload_ptr(p_smp); 539321936Shselasky osm_dump_sm_info_v2(sm->p_log, p_smi, FILE_ID, OSM_LOG_DEBUG); 540321936Shselasky 541321936Shselasky /* Check the AttributeModifier */ 542321936Shselasky if (p_smp->attr_mod != IB_SMINFO_ATTR_MOD_HANDOVER) { 543321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F17: " 544321936Shselasky "Unsupported attribute modifier 0x%X, " 545321936Shselasky "expected ATTR_MOD_HANDOVER\n", 546321936Shselasky p_smp->attr_mod); 547321936Shselasky goto Exit; 548321936Shselasky } 549321936Shselasky 550321936Shselasky /* This is a response on a HANDOVER request - Nothing to do. */ 551321936Shselasky 552321936ShselaskyExit: 553321936Shselasky OSM_LOG_EXIT(sm->p_log); 554321936Shselasky} 555321936Shselasky 556321936Shselaskyvoid osm_sminfo_rcv_process(IN void *context, IN void *data) 557321936Shselasky{ 558321936Shselasky osm_sm_t *sm = context; 559321936Shselasky osm_madw_t *p_madw = data; 560321936Shselasky ib_smp_t *p_smp; 561321936Shselasky osm_smi_context_t *p_smi_context; 562321936Shselasky 563321936Shselasky OSM_LOG_ENTER(sm->p_log); 564321936Shselasky 565321936Shselasky CL_ASSERT(p_madw); 566321936Shselasky 567321936Shselasky p_smp = osm_madw_get_smp_ptr(p_madw); 568321936Shselasky if (ib_smp_get_status(p_smp)) { 569321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_DEBUG, 570321936Shselasky "MAD status 0x%x received\n", 571321936Shselasky cl_ntoh16(ib_smp_get_status(p_smp))); 572321936Shselasky goto Exit; 573321936Shselasky } 574321936Shselasky 575321936Shselasky /* Determine if this is a request for our own SMInfo or if 576321936Shselasky this is a response to our request for another SM's SMInfo. */ 577321936Shselasky if (ib_smp_is_response(p_smp)) { 578321936Shselasky const ib_sm_info_t *p_smi = ib_smp_get_payload_ptr(p_smp); 579321936Shselasky 580321936Shselasky /* Get the context - to see if this is a response to a Get or Set method */ 581321936Shselasky p_smi_context = osm_madw_get_smi_context_ptr(p_madw); 582321936Shselasky 583321936Shselasky /* Verify that response is from expected port and there is 584321936Shselasky no port moving issue. */ 585321936Shselasky if (p_smi_context->port_guid != p_smi->guid) { 586321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F19: " 587321936Shselasky "Unexpected SM port GUID in response" 588321936Shselasky ", Expected 0x%016" PRIx64 589321936Shselasky ", Received 0x%016" PRIx64 "\n", 590321936Shselasky cl_ntoh64(p_smi_context->port_guid), 591321936Shselasky cl_ntoh64(p_smi->guid)); 592321936Shselasky goto Exit; 593321936Shselasky } 594321936Shselasky 595321936Shselasky if (p_smi_context->set_method == FALSE) 596321936Shselasky /* this is a response to a Get method */ 597321936Shselasky smi_rcv_process_get_response(sm, p_madw); 598321936Shselasky else 599321936Shselasky /* this is a response to a Set method */ 600321936Shselasky smi_rcv_process_set_response(sm, p_madw); 601321936Shselasky } else { 602321936Shselasky osm_port_t * p_port; 603321936Shselasky ib_net64_t my_mkey; 604321936Shselasky uint8_t mpb; 605321936Shselasky char buf[256]; 606321936Shselasky 607321936Shselasky if(!(p_port = osm_get_port_by_guid(sm->p_subn, 608321936Shselasky sm->p_subn->sm_port_guid))) 609321936Shselasky goto Exit; 610321936Shselasky 611321936Shselasky if (!p_port->p_physp) 612321936Shselasky goto Exit; 613321936Shselasky 614321936Shselasky my_mkey = ib_port_info_get_m_key(&p_port->p_physp->port_info); 615321936Shselasky mpb = my_mkey ? ib_port_info_get_mpb(&p_port->p_physp->port_info) : 0; 616321936Shselasky 617321936Shselasky if (p_smp->method == IB_MAD_METHOD_GET) { 618321936Shselasky /* M-Key Authentication */ 619321936Shselasky if (my_mkey && mpb > 1 && my_mkey != p_smp->m_key) { 620321936Shselasky if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR) 621321936Shselasky sprint_uint8_arr(buf, sizeof(buf), 622321936Shselasky p_smp->return_path, p_smp->hop_count + 1); 623321936Shselasky else 624321936Shselasky sprintf(buf, "LID %u", 625321936Shselasky cl_ntoh16(p_madw->mad_addr.addr_type.smi.source_lid)); 626321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F1A: " 627321936Shselasky "SMInfo(GET) sender (%s) authentication failure." 628321936Shselasky "Ignoring SMInfo\n", buf); 629321936Shselasky goto Exit; 630321936Shselasky } 631321936Shselasky /* If protection bits == 1 but MKEY mismatch, return SM-KEY = 0 */ 632321936Shselasky if (my_mkey && mpb == 1 && my_mkey != p_smp->m_key) 633321936Shselasky smi_rcv_process_get_request(sm, p_madw, FALSE); 634321936Shselasky else 635321936Shselasky smi_rcv_process_get_request(sm, p_madw, TRUE); 636321936Shselasky } else { 637321936Shselasky /* M-Key Authentication */ 638321936Shselasky if (my_mkey && my_mkey != p_smp->m_key) { 639321936Shselasky if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR) 640321936Shselasky sprint_uint8_arr(buf, sizeof(buf), 641321936Shselasky p_smp->return_path, p_smp->hop_count + 1); 642321936Shselasky else 643321936Shselasky sprintf(buf, "LID %u", 644321936Shselasky cl_ntoh16(p_madw->mad_addr.addr_type.smi.source_lid)); 645321936Shselasky OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F1B: " 646321936Shselasky "SMInfo(SET) sender (%s) authentication failure." 647321936Shselasky "Ignoring SMInfo\n", buf); 648321936Shselasky goto Exit; 649321936Shselasky } 650321936Shselasky /* This should be a SubnSet request */ 651321936Shselasky smi_rcv_process_set_request(sm, p_madw); 652321936Shselasky } 653321936Shselasky } 654321936Shselasky 655321936ShselaskyExit: 656321936Shselasky OSM_LOG_EXIT(sm->p_log); 657321936Shselasky} 658