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