Blame opensm/osm_sminfo_rcv.c

Packit Service 54dbc3
/*
Packit Service 54dbc3
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 * This software is available to you under a choice of one of two
Packit Service 54dbc3
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit Service 54dbc3
 * General Public License (GPL) Version 2, available from the file
Packit Service 54dbc3
 * COPYING in the main directory of this source tree, or the
Packit Service 54dbc3
 * OpenIB.org BSD license below:
Packit Service 54dbc3
 *
Packit Service 54dbc3
 *     Redistribution and use in source and binary forms, with or
Packit Service 54dbc3
 *     without modification, are permitted provided that the following
Packit Service 54dbc3
 *     conditions are met:
Packit Service 54dbc3
 *
Packit Service 54dbc3
 *      - Redistributions of source code must retain the above
Packit Service 54dbc3
 *        copyright notice, this list of conditions and the following
Packit Service 54dbc3
 *        disclaimer.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 *      - Redistributions in binary form must reproduce the above
Packit Service 54dbc3
 *        copyright notice, this list of conditions and the following
Packit Service 54dbc3
 *        disclaimer in the documentation and/or other materials
Packit Service 54dbc3
 *        provided with the distribution.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit Service 54dbc3
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit Service 54dbc3
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit Service 54dbc3
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit Service 54dbc3
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit Service 54dbc3
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit Service 54dbc3
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit Service 54dbc3
 * SOFTWARE.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 */
Packit Service 54dbc3
Packit Service 54dbc3
/*
Packit Service 54dbc3
 * Abstract:
Packit Service 54dbc3
 *    Implementation of osm_sminfo_rcv_t.
Packit Service 54dbc3
 * This object represents the SMInfo Receiver object.
Packit Service 54dbc3
 * This object is part of the opensm family of objects.
Packit Service 54dbc3
 */
Packit Service 54dbc3
Packit Service 54dbc3
#if HAVE_CONFIG_H
Packit Service 54dbc3
#  include <config.h>
Packit Service 54dbc3
#endif				/* HAVE_CONFIG_H */
Packit Service 54dbc3
Packit Service 54dbc3
#include <stdlib.h>
Packit Service 54dbc3
#include <string.h>
Packit Service 54dbc3
#include <iba/ib_types.h>
Packit Service 54dbc3
#include <complib/cl_qmap.h>
Packit Service 54dbc3
#include <complib/cl_passivelock.h>
Packit Service 54dbc3
#include <complib/cl_debug.h>
Packit Service 54dbc3
#include <opensm/osm_file_ids.h>
Packit Service 54dbc3
#define FILE_ID OSM_FILE_SMINFO_RCV_C
Packit Service 54dbc3
#include <opensm/osm_madw.h>
Packit Service 54dbc3
#include <opensm/osm_log.h>
Packit Service 54dbc3
#include <opensm/osm_node.h>
Packit Service 54dbc3
#include <opensm/osm_helper.h>
Packit Service 54dbc3
#include <opensm/osm_subnet.h>
Packit Service 54dbc3
#include <opensm/osm_sm.h>
Packit Service 54dbc3
#include <opensm/osm_opensm.h>
Packit Service 54dbc3
Packit Service 54dbc3
/**********************************************************************
Packit Service 54dbc3
 Return TRUE if the remote sm given (by ib_sm_info_t) is higher,
Packit Service 54dbc3
 return FALSE otherwise.
Packit Service 54dbc3
 By higher - we mean: SM with higher priority or with same priority
Packit Service 54dbc3
 and lower GUID.
Packit Service 54dbc3
**********************************************************************/
Packit Service 54dbc3
static boolean_t smi_rcv_remote_sm_is_higher(IN osm_sm_t * sm,
Packit Service 54dbc3
					     IN const ib_sm_info_t * p_rem_smi)
Packit Service 54dbc3
{
Packit Service 54dbc3
	return osm_sm_is_greater_than(ib_sminfo_get_priority(p_rem_smi),
Packit Service 54dbc3
				      p_rem_smi->guid,
Packit Service 54dbc3
				      sm->p_subn->opt.sm_priority,
Packit Service 54dbc3
				      sm->p_subn->sm_port_guid);
Packit Service 54dbc3
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void smi_rcv_process_get_request(IN osm_sm_t * sm,
Packit Service 54dbc3
					IN const osm_madw_t * p_madw,
Packit Service 54dbc3
					IN boolean_t fill_sm_key)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint8_t payload[IB_SMP_DATA_SIZE];
Packit Service 54dbc3
	ib_sm_info_t *p_smi = (ib_sm_info_t *) payload;
Packit Service 54dbc3
	ib_api_status_t status;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sm->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(p_madw);
Packit Service 54dbc3
Packit Service 54dbc3
	/* No real need to grab the lock for this function. */
Packit Service 54dbc3
	memset(payload, 0, sizeof(payload));
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(osm_madw_get_smp_ptr(p_madw)->method == IB_MAD_METHOD_GET);
Packit Service 54dbc3
Packit Service 54dbc3
	p_smi->guid = sm->p_subn->sm_port_guid;
Packit Service 54dbc3
	p_smi->act_count = cl_hton32(sm->p_subn->p_osm->stats.qp0_mads_sent);
Packit Service 54dbc3
	p_smi->pri_state = (uint8_t) (sm->p_subn->sm_state |
Packit Service 54dbc3
				      sm->p_subn->opt.sm_priority << 4);
Packit Service 54dbc3
	p_smi->sm_key = fill_sm_key ? sm->p_subn->opt.sm_key : 0;
Packit Service 54dbc3
Packit Service 54dbc3
	status = osm_resp_send(sm, p_madw, 0, payload);
Packit Service 54dbc3
	if (status != IB_SUCCESS) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F02: "
Packit Service 54dbc3
			"Error sending SMInfo response (%s)\n",
Packit Service 54dbc3
			ib_get_err_str(status));
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	OSM_LOG_EXIT(sm->p_log);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/**********************************************************************
Packit Service 54dbc3
 * Check if the p_smp received is legal.
Packit Service 54dbc3
 * Current checks:
Packit Service 54dbc3
 *   MADHeader:AttributeModifier of ACKNOWLEDGE that was not sent by a
Packit Service 54dbc3
 *             Standby SM.
Packit Service 54dbc3
 *   MADHeader:AttributeModifiers of HANDOVER/DISABLE/STANDBY/DISCOVER
Packit Service 54dbc3
 *             that was not sent by a Master SM.
Packit Service 54dbc3
 * FUTURE - TO DO:
Packit Service 54dbc3
 *   Check that the SM_Key matches.
Packit Service 54dbc3
 **********************************************************************/
Packit Service 54dbc3
static ib_api_status_t smi_rcv_check_set_req_legality(IN const ib_smp_t * p_smp)
Packit Service 54dbc3
{
Packit Service 54dbc3
	ib_sm_info_t *p_smi;
Packit Service 54dbc3
Packit Service 54dbc3
	p_smi = ib_smp_get_payload_ptr(p_smp);
Packit Service 54dbc3
Packit Service 54dbc3
	if (p_smp->attr_mod == IB_SMINFO_ATTR_MOD_ACKNOWLEDGE) {
Packit Service 54dbc3
		if (ib_sminfo_get_state(p_smi) == IB_SMINFO_STATE_STANDBY)
Packit Service 54dbc3
			return IB_SUCCESS;
Packit Service 54dbc3
	} else if (p_smp->attr_mod == IB_SMINFO_ATTR_MOD_HANDOVER ||
Packit Service 54dbc3
		   p_smp->attr_mod == IB_SMINFO_ATTR_MOD_DISABLE ||
Packit Service 54dbc3
		   p_smp->attr_mod == IB_SMINFO_ATTR_MOD_STANDBY ||
Packit Service 54dbc3
		   p_smp->attr_mod == IB_SMINFO_ATTR_MOD_DISCOVER) {
Packit Service 54dbc3
		if (ib_sminfo_get_state(p_smi) == IB_SMINFO_STATE_MASTER)
Packit Service 54dbc3
			return IB_SUCCESS;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	return IB_INVALID_PARAMETER;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void smi_rcv_process_set_request(IN osm_sm_t * sm,
Packit Service 54dbc3
					IN const osm_madw_t * p_madw)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint8_t payload[IB_SMP_DATA_SIZE];
Packit Service 54dbc3
	ib_smp_t *p_smp;
Packit Service 54dbc3
	ib_sm_info_t *p_smi = (ib_sm_info_t *) payload;
Packit Service 54dbc3
	ib_sm_info_t *sm_smi;
Packit Service 54dbc3
	ib_api_status_t status;
Packit Service 54dbc3
	osm_sm_signal_t sm_signal;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sm->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(p_madw);
Packit Service 54dbc3
Packit Service 54dbc3
	memset(payload, 0, sizeof(payload));
Packit Service 54dbc3
Packit Service 54dbc3
	p_smp = osm_madw_get_smp_ptr(p_madw);
Packit Service 54dbc3
	sm_smi = ib_smp_get_payload_ptr(p_smp);
Packit Service 54dbc3
Packit Service 54dbc3
	if (p_smp->method != IB_MAD_METHOD_SET) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F03: "
Packit Service 54dbc3
			"Unsupported set method 0x%X\n", p_smp->method);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	CL_PLOCK_ACQUIRE(sm->p_lock);
Packit Service 54dbc3
Packit Service 54dbc3
	p_smi->guid = sm->p_subn->sm_port_guid;
Packit Service 54dbc3
	p_smi->act_count = cl_hton32(sm->p_subn->p_osm->stats.qp0_mads_sent);
Packit Service 54dbc3
	p_smi->pri_state = (uint8_t) (sm->p_subn->sm_state |
Packit Service 54dbc3
				      sm->p_subn->opt.sm_priority << 4);
Packit Service 54dbc3
	p_smi->sm_key = sm->p_subn->opt.sm_key;
Packit Service 54dbc3
Packit Service 54dbc3
	/* Check the legality of the packet */
Packit Service 54dbc3
	status = smi_rcv_check_set_req_legality(p_smp);
Packit Service 54dbc3
	if (status != IB_SUCCESS) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F04: "
Packit Service 54dbc3
			"Check legality failed. AttributeModifier:0x%X RemoteState:%s\n",
Packit Service 54dbc3
			p_smp->attr_mod,
Packit Service 54dbc3
			osm_get_sm_mgr_state_str(ib_sminfo_get_state(sm_smi)));
Packit Service 54dbc3
		status = osm_resp_send(sm, p_madw, 7, payload);
Packit Service 54dbc3
		if (status != IB_SUCCESS)
Packit Service 54dbc3
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F05: "
Packit Service 54dbc3
				"Error sending SMInfo response (%s)\n",
Packit Service 54dbc3
				ib_get_err_str(status));
Packit Service 54dbc3
		CL_PLOCK_RELEASE(sm->p_lock);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* translate from IB_SMINFO_ATTR to OSM_SM_SIGNAL */
Packit Service 54dbc3
	switch (p_smp->attr_mod) {
Packit Service 54dbc3
	case IB_SMINFO_ATTR_MOD_HANDOVER:
Packit Service 54dbc3
		sm_signal = OSM_SM_SIGNAL_HANDOVER;
Packit Service 54dbc3
		break;
Packit Service 54dbc3
	case IB_SMINFO_ATTR_MOD_ACKNOWLEDGE:
Packit Service 54dbc3
		sm_signal = OSM_SM_SIGNAL_ACKNOWLEDGE;
Packit Service 54dbc3
		break;
Packit Service 54dbc3
	case IB_SMINFO_ATTR_MOD_DISABLE:
Packit Service 54dbc3
		sm_signal = OSM_SM_SIGNAL_DISABLE;
Packit Service 54dbc3
		break;
Packit Service 54dbc3
	case IB_SMINFO_ATTR_MOD_STANDBY:
Packit Service 54dbc3
		sm_signal = OSM_SM_SIGNAL_STANDBY;
Packit Service 54dbc3
		break;
Packit Service 54dbc3
	case IB_SMINFO_ATTR_MOD_DISCOVER:
Packit Service 54dbc3
		sm_signal = OSM_SM_SIGNAL_DISCOVER;
Packit Service 54dbc3
		break;
Packit Service 54dbc3
	default:
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		   This code shouldn't be reached - checked in the
Packit Service 54dbc3
		   check legality
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F06: "
Packit Service 54dbc3
			"THIS CODE SHOULD NOT BE REACHED!!\n");
Packit Service 54dbc3
		CL_PLOCK_RELEASE(sm->p_lock);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	CL_PLOCK_RELEASE(sm->p_lock);
Packit Service 54dbc3
Packit Service 54dbc3
	/* check legality of the needed transition in the SM state machine */
Packit Service 54dbc3
	status = osm_sm_state_mgr_check_legality(sm, sm_signal);
Packit Service 54dbc3
	if (status != IB_SUCCESS) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F07: "
Packit Service 54dbc3
			"Failed check of legality of needed SM transition. "
Packit Service 54dbc3
			"AttributeModifier:0x%X RemoteState:%s\n",
Packit Service 54dbc3
			p_smp->attr_mod,
Packit Service 54dbc3
			osm_get_sm_mgr_state_str(ib_sminfo_get_state(sm_smi)));
Packit Service 54dbc3
		status = osm_resp_send(sm, p_madw, 7, payload);
Packit Service 54dbc3
		if (status != IB_SUCCESS)
Packit Service 54dbc3
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F08: "
Packit Service 54dbc3
				"Error sending SMInfo response (%s)\n",
Packit Service 54dbc3
				ib_get_err_str(status));
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* the SubnSet(SMInfo) command is ok. Send a response. */
Packit Service 54dbc3
	status = osm_resp_send(sm, p_madw, 0, payload);
Packit Service 54dbc3
	if (status != IB_SUCCESS)
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F09: "
Packit Service 54dbc3
			"Error sending SMInfo response (%s)\n",
Packit Service 54dbc3
			ib_get_err_str(status));
Packit Service 54dbc3
Packit Service 54dbc3
	/* it is a legal packet - act according to it */
Packit Service 54dbc3
Packit Service 54dbc3
	/* if the AttributeModifier is STANDBY - need to save on the sm in */
Packit Service 54dbc3
	/* the master_sm_guid variable - the guid of the current master. */
Packit Service 54dbc3
	if (p_smp->attr_mod == IB_SMINFO_ATTR_MOD_STANDBY) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
			"Received a STANDBY signal. Updating "
Packit Service 54dbc3
			"sm_state_mgr master_guid: 0x%016" PRIx64 "\n",
Packit Service 54dbc3
			cl_ntoh64(sm_smi->guid));
Packit Service 54dbc3
		CL_PLOCK_EXCL_ACQUIRE(sm->p_lock);
Packit Service 54dbc3
		sm->master_sm_guid = sm_smi->guid;
Packit Service 54dbc3
		CL_PLOCK_RELEASE(sm->p_lock);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	status = osm_sm_state_mgr_process(sm, sm_signal);
Packit Service 54dbc3
Packit Service 54dbc3
	if (status != IB_SUCCESS)
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F10: "
Packit Service 54dbc3
			"Error in SM state transition (%s)\n",
Packit Service 54dbc3
			ib_get_err_str(status));
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	OSM_LOG_EXIT(sm->p_log);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void smi_rcv_process_get_sm(IN osm_sm_t * sm,
Packit Service 54dbc3
				   IN const osm_remote_sm_t * p_sm,
Packit Service 54dbc3
				   boolean_t light_sweep)
Packit Service 54dbc3
{
Packit Service 54dbc3
	const ib_sm_info_t *p_smi;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sm->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	p_smi = &p_sm->smi;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
		"Detected SM 0x%016" PRIx64 " in state %u (%s)\n",
Packit Service 54dbc3
		cl_ntoh64(p_smi->guid), ib_sminfo_get_state(p_smi),
Packit Service 54dbc3
		osm_get_sm_mgr_state_str(ib_sminfo_get_state(p_smi)));
Packit Service 54dbc3
Packit Service 54dbc3
	/* Check the state of this SM vs. our own. */
Packit Service 54dbc3
	switch (sm->p_subn->sm_state) {
Packit Service 54dbc3
	case IB_SMINFO_STATE_NOTACTIVE:
Packit Service 54dbc3
		break;
Packit Service 54dbc3
Packit Service 54dbc3
	case IB_SMINFO_STATE_DISCOVERING:
Packit Service 54dbc3
		switch (ib_sminfo_get_state(p_smi)) {
Packit Service 54dbc3
		case IB_SMINFO_STATE_NOTACTIVE:
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		case IB_SMINFO_STATE_MASTER:
Packit Service 54dbc3
			sm->master_sm_found = 1;
Packit Service 54dbc3
			/* save on the sm the guid of the current master. */
Packit Service 54dbc3
			OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
				"Found master SM. Updating sm_state_mgr master_guid: 0x%016"
Packit Service 54dbc3
				PRIx64 "\n", cl_ntoh64(p_smi->guid));
Packit Service 54dbc3
			sm->master_sm_guid = p_smi->guid;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		case IB_SMINFO_STATE_DISCOVERING:
Packit Service 54dbc3
		case IB_SMINFO_STATE_STANDBY:
Packit Service 54dbc3
			if (smi_rcv_remote_sm_is_higher(sm, p_smi)) {
Packit Service 54dbc3
				/* the remote is a higher sm - need to stop sweeping */
Packit Service 54dbc3
				sm->master_sm_found = 1;
Packit Service 54dbc3
				/* save on the sm the guid of the higher SM we found - */
Packit Service 54dbc3
				/* we will poll it - as long as it lives - we should be in Standby. */
Packit Service 54dbc3
				OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
					"Found higher SM. Updating sm_state_mgr master_guid:"
Packit Service 54dbc3
					" 0x%016" PRIx64 "\n",
Packit Service 54dbc3
					cl_ntoh64(p_smi->guid));
Packit Service 54dbc3
				sm->master_sm_guid = p_smi->guid;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		default:
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		}
Packit Service 54dbc3
		break;
Packit Service 54dbc3
Packit Service 54dbc3
	case IB_SMINFO_STATE_STANDBY:
Packit Service 54dbc3
		/* if the guid of the SM that sent us this response is equal to the */
Packit Service 54dbc3
		/* p_sm_mgr->master_guid - then this is a signal that the polling */
Packit Service 54dbc3
		switch (ib_sminfo_get_state(p_smi)) {
Packit Service 54dbc3
		case IB_SMINFO_STATE_MASTER:
Packit Service 54dbc3
			/* This means the master is alive */
Packit Service 54dbc3
			/* Signal that to the SM state mgr */
Packit Service 54dbc3
			osm_sm_state_mgr_signal_master_is_alive(sm);
Packit Service 54dbc3
Packit Service 54dbc3
			if (!smi_rcv_remote_sm_is_higher(sm, p_smi))
Packit Service 54dbc3
				osm_send_trap144(sm,
Packit Service 54dbc3
						 TRAP_144_MASK_SM_PRIORITY_CHANGE);
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		case IB_SMINFO_STATE_STANDBY:
Packit Service 54dbc3
			/* This should be the response from the sm we are polling. */
Packit Service 54dbc3
			/* If it is - then signal master is alive */
Packit Service 54dbc3
			if (sm->master_sm_guid == p_sm->smi.guid) {
Packit Service 54dbc3
				/* Make sure that it is an SM with higher priority than us.
Packit Service 54dbc3
				   If we started polling it when it was master, and it moved
Packit Service 54dbc3
				   to standby - then it might be with a lower priority than
Packit Service 54dbc3
				   us - and then we don't want to continue polling it. */
Packit Service 54dbc3
				if (smi_rcv_remote_sm_is_higher(sm, p_smi))
Packit Service 54dbc3
					osm_sm_state_mgr_signal_master_is_alive
Packit Service 54dbc3
					    (sm);
Packit Service 54dbc3
			}
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		default:
Packit Service 54dbc3
			/* any other state - do nothing */
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		}
Packit Service 54dbc3
		break;
Packit Service 54dbc3
Packit Service 54dbc3
	case IB_SMINFO_STATE_MASTER:
Packit Service 54dbc3
		switch (ib_sminfo_get_state(p_smi)) {
Packit Service 54dbc3
		case IB_SMINFO_STATE_MASTER:
Packit Service 54dbc3
			/* If this is a response due to our polling, this means that we are
Packit Service 54dbc3
			 * waiting for a handover from this SM, and it is still alive -
Packit Service 54dbc3
			 * signal that. If we detected the remote SM with higher priority
Packit Service 54dbc3
			 * we should init a heavy sweep in order to go STANDBY. If we
Packit Service 54dbc3
			 * detected a remote SM with lower priority, we should resend trap144
Packit Service 54dbc3
			 * as it might not get it and we don't want to wait for a HANDOVER
Packit Service 54dbc3
			 * forever.
Packit Service 54dbc3
			 */
Packit Service 54dbc3
			if (sm->polling_sm_guid) {
Packit Service 54dbc3
				if (smi_rcv_remote_sm_is_higher(sm, p_smi))
Packit Service 54dbc3
					sm->p_subn->force_heavy_sweep = TRUE;
Packit Service 54dbc3
				else {
Packit Service 54dbc3
					/* Update master_sm_guid to the GUID of the newly
Packit Service 54dbc3
					 * found MASTER SM and send trap 144 to it.
Packit Service 54dbc3
					 */
Packit Service 54dbc3
					sm->master_sm_guid = sm->polling_sm_guid;
Packit Service 54dbc3
					osm_send_trap144(sm, TRAP_144_MASK_SM_PRIORITY_CHANGE);
Packit Service 54dbc3
				}
Packit Service 54dbc3
				osm_sm_state_mgr_signal_master_is_alive(sm);
Packit Service 54dbc3
			} else {
Packit Service 54dbc3
				/* This is a response we got while sweeping the subnet.
Packit Service 54dbc3
				 *
Packit Service 54dbc3
				 * If this is during a heavy sweep, we will handle a case of
Packit Service 54dbc3
				 * handover needed later on, when the sweep is done and all
Packit Service 54dbc3
				 * SMs are recognized.
Packit Service 54dbc3
				 *
Packit Service 54dbc3
				 * If this is during a light sweep, initiate a heavy sweep
Packit Service 54dbc3
				 * to initiate handover scenarios.
Packit Service 54dbc3
				 *
Packit Service 54dbc3
				 * Note that it does not matter if the remote SM is lower
Packit Service 54dbc3
				 * or higher priority.  If it is lower priority, we must
Packit Service 54dbc3
				 * wait for it HANDOVER.  If it is higher priority, we need
Packit Service 54dbc3
				 * to HANDOVER to it.  Both cases are handled after doing
Packit Service 54dbc3
				 * a heavy sweep.
Packit Service 54dbc3
				 */
Packit Service 54dbc3
				if (light_sweep)
Packit Service 54dbc3
					sm->p_subn->force_heavy_sweep = TRUE;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		case IB_SMINFO_STATE_STANDBY:
Packit Service 54dbc3
			if (light_sweep &&
Packit Service 54dbc3
			    smi_rcv_remote_sm_is_higher(sm, p_smi))
Packit Service 54dbc3
				sm->p_subn->force_heavy_sweep = TRUE;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		default:
Packit Service 54dbc3
			/* any other state - do nothing */
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		}
Packit Service 54dbc3
		break;
Packit Service 54dbc3
Packit Service 54dbc3
	default:
Packit Service 54dbc3
		break;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_EXIT(sm->p_log);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void smi_rcv_process_get_response(IN osm_sm_t * sm,
Packit Service 54dbc3
					 IN const osm_madw_t * p_madw)
Packit Service 54dbc3
{
Packit Service 54dbc3
	const ib_smp_t *p_smp;
Packit Service 54dbc3
	const ib_sm_info_t *p_smi;
Packit Service 54dbc3
	cl_qmap_t *p_sm_tbl;
Packit Service 54dbc3
	osm_port_t *p_port;
Packit Service 54dbc3
	ib_net64_t port_guid;
Packit Service 54dbc3
	osm_remote_sm_t *p_sm;
Packit Service 54dbc3
	char buf[256];
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sm->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(p_madw);
Packit Service 54dbc3
Packit Service 54dbc3
	p_smp = osm_madw_get_smp_ptr(p_madw);
Packit Service 54dbc3
Packit Service 54dbc3
	if (p_smp->method != IB_MAD_METHOD_GET_RESP) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F11: "
Packit Service 54dbc3
			"Unsupported response method 0x%X\n", p_smp->method);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	p_smi = ib_smp_get_payload_ptr(p_smp);
Packit Service 54dbc3
	p_sm_tbl = &sm->p_subn->sm_guid_tbl;
Packit Service 54dbc3
	port_guid = p_smi->guid;
Packit Service 54dbc3
Packit Service 54dbc3
	osm_dump_sm_info_v2(sm->p_log, p_smi, FILE_ID, OSM_LOG_DEBUG);
Packit Service 54dbc3
Packit Service 54dbc3
	/* Check that the sm_key of the found SM is the same as ours,
Packit Service 54dbc3
	   or is zero. If not - OpenSM should ignore this SM */
Packit Service 54dbc3
	if (sm->p_subn->opt.sm_key != 0 && p_smi->sm_key != sm->p_subn->opt.sm_key) {
Packit Service 54dbc3
		if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR)
Packit Service 54dbc3
			sprint_uint8_arr(buf, sizeof(buf),
Packit Service 54dbc3
				p_smp->initial_path, p_smp->hop_count + 1);
Packit Service 54dbc3
		else
Packit Service 54dbc3
			sprintf(buf, "LID %u",
Packit Service 54dbc3
				cl_ntoh16(p_madw->mad_addr.addr_type.smi.source_lid));
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F18: "
Packit Service 54dbc3
			"Got SM (%s) with sm_key 0x%016" PRIx64 " that doesn't match our "
Packit Service 54dbc3
			"local sm_key. Ignoring SMInfo\n", buf, cl_ntoh64(p_smi->sm_key));
Packit Service 54dbc3
		osm_log_v2(sm->p_log, OSM_LOG_SYS, FILE_ID,
Packit Service 54dbc3
			   "Found remote SM (%s) with non-matching sm_key\n", buf);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* Determine if we already have another SM object for this SM. */
Packit Service 54dbc3
	CL_PLOCK_EXCL_ACQUIRE(sm->p_lock);
Packit Service 54dbc3
Packit Service 54dbc3
	p_port = osm_get_port_by_guid(sm->p_subn, port_guid);
Packit Service 54dbc3
	if (!p_port) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F12: "
Packit Service 54dbc3
			"No port object for this SM\n");
Packit Service 54dbc3
		goto _unlock_and_exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (osm_port_get_guid(p_port) != p_smi->guid) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F13: "
Packit Service 54dbc3
			"Bogus SM port GUID, Expected 0x%016" PRIx64
Packit Service 54dbc3
			", Received 0x%016" PRIx64 "\n",
Packit Service 54dbc3
			cl_ntoh64(osm_port_get_guid(p_port)),
Packit Service 54dbc3
			cl_ntoh64(p_smi->guid));
Packit Service 54dbc3
		goto _unlock_and_exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (port_guid == sm->p_subn->sm_port_guid) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
			"Self query response received - SM port 0x%016" PRIx64
Packit Service 54dbc3
			"\n", cl_ntoh64(port_guid));
Packit Service 54dbc3
		goto _unlock_and_exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	p_sm = (osm_remote_sm_t *) cl_qmap_get(p_sm_tbl, port_guid);
Packit Service 54dbc3
	if (p_sm == (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) {
Packit Service 54dbc3
		p_sm = malloc(sizeof(*p_sm));
Packit Service 54dbc3
		if (p_sm == NULL) {
Packit Service 54dbc3
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F14: "
Packit Service 54dbc3
				"Unable to allocate SM object\n");
Packit Service 54dbc3
			goto _unlock_and_exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		osm_remote_sm_init(p_sm, p_smi);
Packit Service 54dbc3
Packit Service 54dbc3
		cl_qmap_insert(p_sm_tbl, port_guid, &p_sm->map_item);
Packit Service 54dbc3
	} else
Packit Service 54dbc3
		/* We already know this SM. Update the SMInfo attribute. */
Packit Service 54dbc3
		p_sm->smi = *p_smi;
Packit Service 54dbc3
Packit Service 54dbc3
	smi_rcv_process_get_sm(sm, p_sm,
Packit Service 54dbc3
			       osm_madw_get_smi_context_ptr(p_madw)->
Packit Service 54dbc3
			       light_sweep);
Packit Service 54dbc3
Packit Service 54dbc3
_unlock_and_exit:
Packit Service 54dbc3
	CL_PLOCK_RELEASE(sm->p_lock);
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	OSM_LOG_EXIT(sm->p_log);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void smi_rcv_process_set_response(IN osm_sm_t * sm,
Packit Service 54dbc3
					 IN const osm_madw_t * p_madw)
Packit Service 54dbc3
{
Packit Service 54dbc3
	const ib_smp_t *p_smp;
Packit Service 54dbc3
	const ib_sm_info_t *p_smi;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sm->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(p_madw);
Packit Service 54dbc3
Packit Service 54dbc3
	p_smp = osm_madw_get_smp_ptr(p_madw);
Packit Service 54dbc3
	if (ib_smp_get_status(p_smp)) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"MAD status 0x%x received\n",
Packit Service 54dbc3
			cl_ntoh16(ib_smp_get_status(p_smp)));
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (p_smp->method != IB_MAD_METHOD_GET_RESP) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F16: "
Packit Service 54dbc3
			"Unsupported response method 0x%X\n", p_smp->method);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	p_smi = ib_smp_get_payload_ptr(p_smp);
Packit Service 54dbc3
	osm_dump_sm_info_v2(sm->p_log, p_smi, FILE_ID, OSM_LOG_DEBUG);
Packit Service 54dbc3
Packit Service 54dbc3
	/* Check the AttributeModifier */
Packit Service 54dbc3
	if (p_smp->attr_mod != IB_SMINFO_ATTR_MOD_HANDOVER) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F17: "
Packit Service 54dbc3
			"Unsupported attribute modifier 0x%X, "
Packit Service 54dbc3
			"expected ATTR_MOD_HANDOVER\n",
Packit Service 54dbc3
			p_smp->attr_mod);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* This is a response on a HANDOVER request - Nothing to do. */
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	OSM_LOG_EXIT(sm->p_log);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
void osm_sminfo_rcv_process(IN void *context, IN void *data)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_sm_t *sm = context;
Packit Service 54dbc3
	osm_madw_t *p_madw = data;
Packit Service 54dbc3
	ib_smp_t *p_smp;
Packit Service 54dbc3
	osm_smi_context_t *p_smi_context;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sm->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(p_madw);
Packit Service 54dbc3
Packit Service 54dbc3
	p_smp = osm_madw_get_smp_ptr(p_madw);
Packit Service 54dbc3
	if (ib_smp_get_status(p_smp)) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"MAD status 0x%x received\n",
Packit Service 54dbc3
			cl_ntoh16(ib_smp_get_status(p_smp)));
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* Determine if this is a request for our own SMInfo or if
Packit Service 54dbc3
	   this is a response to our request for another SM's SMInfo. */
Packit Service 54dbc3
	if (ib_smp_is_response(p_smp)) {
Packit Service 54dbc3
		const ib_sm_info_t *p_smi = ib_smp_get_payload_ptr(p_smp);
Packit Service 54dbc3
Packit Service 54dbc3
		/* Get the context - to see if this is a response to a Get or Set method */
Packit Service 54dbc3
		p_smi_context = osm_madw_get_smi_context_ptr(p_madw);
Packit Service 54dbc3
Packit Service 54dbc3
		/* Verify that response is from expected port and there is
Packit Service 54dbc3
		   no port moving issue. */
Packit Service 54dbc3
		if (p_smi_context->port_guid != p_smi->guid) {
Packit Service 54dbc3
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F19: "
Packit Service 54dbc3
				"Unexpected SM port GUID in response"
Packit Service 54dbc3
				", Expected 0x%016" PRIx64
Packit Service 54dbc3
				", Received 0x%016" PRIx64 "\n",
Packit Service 54dbc3
				cl_ntoh64(p_smi_context->port_guid),
Packit Service 54dbc3
				cl_ntoh64(p_smi->guid));
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		if (p_smi_context->set_method == FALSE)
Packit Service 54dbc3
			/* this is a response to a Get method */
Packit Service 54dbc3
			smi_rcv_process_get_response(sm, p_madw);
Packit Service 54dbc3
		else
Packit Service 54dbc3
			/* this is a response to a Set method */
Packit Service 54dbc3
			smi_rcv_process_set_response(sm, p_madw);
Packit Service 54dbc3
	} else {
Packit Service 54dbc3
		osm_port_t * p_port;
Packit Service 54dbc3
		ib_net64_t my_mkey;
Packit Service 54dbc3
		uint8_t mpb;
Packit Service 54dbc3
		char buf[256];
Packit Service 54dbc3
Packit Service 54dbc3
		if(!(p_port = osm_get_port_by_guid(sm->p_subn,
Packit Service 54dbc3
						   sm->p_subn->sm_port_guid)))
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
Packit Service 54dbc3
		if (!p_port->p_physp)
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
Packit Service 54dbc3
		my_mkey = ib_port_info_get_m_key(&p_port->p_physp->port_info);
Packit Service 54dbc3
		mpb = my_mkey ? ib_port_info_get_mpb(&p_port->p_physp->port_info) : 0;
Packit Service 54dbc3
Packit Service 54dbc3
		if (p_smp->method == IB_MAD_METHOD_GET) {
Packit Service 54dbc3
			/* M-Key Authentication */
Packit Service 54dbc3
			if (my_mkey && mpb > 1 && my_mkey != p_smp->m_key) {
Packit Service 54dbc3
				if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR)
Packit Service 54dbc3
					sprint_uint8_arr(buf, sizeof(buf),
Packit Service 54dbc3
					      p_smp->return_path, p_smp->hop_count + 1);
Packit Service 54dbc3
				else
Packit Service 54dbc3
					sprintf(buf, "LID %u",
Packit Service 54dbc3
						cl_ntoh16(p_madw->mad_addr.addr_type.smi.source_lid));
Packit Service 54dbc3
				OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F1A: "
Packit Service 54dbc3
					"SMInfo(GET) sender (%s) authentication failure."
Packit Service 54dbc3
					"Ignoring SMInfo\n", buf);
Packit Service 54dbc3
				goto Exit;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			/* If protection bits == 1 but MKEY mismatch, return SM-KEY = 0 */
Packit Service 54dbc3
			if (my_mkey && mpb == 1 && my_mkey != p_smp->m_key)
Packit Service 54dbc3
				smi_rcv_process_get_request(sm, p_madw, FALSE);
Packit Service 54dbc3
			else
Packit Service 54dbc3
				smi_rcv_process_get_request(sm, p_madw, TRUE);
Packit Service 54dbc3
		} else {
Packit Service 54dbc3
			/* M-Key Authentication */
Packit Service 54dbc3
			if (my_mkey && my_mkey != p_smp->m_key) {
Packit Service 54dbc3
				if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR)
Packit Service 54dbc3
					sprint_uint8_arr(buf, sizeof(buf),
Packit Service 54dbc3
					      p_smp->return_path, p_smp->hop_count + 1);
Packit Service 54dbc3
				else
Packit Service 54dbc3
					sprintf(buf, "LID %u",
Packit Service 54dbc3
						cl_ntoh16(p_madw->mad_addr.addr_type.smi.source_lid));
Packit Service 54dbc3
				OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F1B: "
Packit Service 54dbc3
					"SMInfo(SET) sender (%s) authentication failure."
Packit Service 54dbc3
					"Ignoring SMInfo\n", buf);
Packit Service 54dbc3
				goto Exit;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			/* This should be a SubnSet request */
Packit Service 54dbc3
			smi_rcv_process_set_request(sm, p_madw);
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	OSM_LOG_EXIT(sm->p_log);
Packit Service 54dbc3
}