1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3219820Sjeff * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5219820Sjeff * Copyright (c) 2008 Xsigo Systems Inc.  All rights reserved.
6219820Sjeff *
7219820Sjeff * This software is available to you under a choice of one of two
8219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
9219820Sjeff * General Public License (GPL) Version 2, available from the file
10219820Sjeff * COPYING in the main directory of this source tree, or the
11219820Sjeff * OpenIB.org BSD license below:
12219820Sjeff *
13219820Sjeff *     Redistribution and use in source and binary forms, with or
14219820Sjeff *     without modification, are permitted provided that the following
15219820Sjeff *     conditions are met:
16219820Sjeff *
17219820Sjeff *      - Redistributions of source code must retain the above
18219820Sjeff *        copyright notice, this list of conditions and the following
19219820Sjeff *        disclaimer.
20219820Sjeff *
21219820Sjeff *      - Redistributions in binary form must reproduce the above
22219820Sjeff *        copyright notice, this list of conditions and the following
23219820Sjeff *        disclaimer in the documentation and/or other materials
24219820Sjeff *        provided with the distribution.
25219820Sjeff *
26219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33219820Sjeff * SOFTWARE.
34219820Sjeff *
35219820Sjeff */
36219820Sjeff
37219820Sjeff/*
38219820Sjeff * Abstract:
39219820Sjeff *    Implementation of osm_sm_t.
40219820Sjeff * This object represents the SM Receiver object.
41219820Sjeff * This object is part of the opensm family of objects.
42219820Sjeff */
43219820Sjeff
44219820Sjeff#if HAVE_CONFIG_H
45219820Sjeff#  include <config.h>
46219820Sjeff#endif				/* HAVE_CONFIG_H */
47219820Sjeff
48219820Sjeff#include <stdlib.h>
49219820Sjeff#include <string.h>
50219820Sjeff#include <iba/ib_types.h>
51219820Sjeff#include <complib/cl_qmap.h>
52219820Sjeff#include <complib/cl_passivelock.h>
53219820Sjeff#include <complib/cl_debug.h>
54219820Sjeff#include <complib/cl_thread.h>
55219820Sjeff#include <opensm/osm_sm.h>
56219820Sjeff#include <opensm/osm_madw.h>
57219820Sjeff#include <opensm/osm_log.h>
58219820Sjeff#include <opensm/osm_node.h>
59219820Sjeff#include <opensm/osm_msgdef.h>
60219820Sjeff#include <opensm/osm_mcm_info.h>
61219820Sjeff#include <opensm/osm_perfmgr.h>
62219820Sjeff#include <opensm/osm_opensm.h>
63219820Sjeff
64219820Sjeff#define  OSM_SM_INITIAL_TID_VALUE 0x1233
65219820Sjeff
66219820Sjeffextern void osm_lft_rcv_process(IN void *context, IN void *data);
67219820Sjeffextern void osm_mft_rcv_process(IN void *context, IN void *data);
68219820Sjeffextern void osm_nd_rcv_process(IN void *context, IN void *data);
69219820Sjeffextern void osm_ni_rcv_process(IN void *context, IN void *data);
70219820Sjeffextern void osm_pkey_rcv_process(IN void *context, IN void *data);
71219820Sjeffextern void osm_pi_rcv_process(IN void *context, IN void *data);
72219820Sjeffextern void osm_slvl_rcv_process(IN void *context, IN void *p_data);
73219820Sjeffextern void osm_sminfo_rcv_process(IN void *context, IN void *data);
74219820Sjeffextern void osm_si_rcv_process(IN void *context, IN void *data);
75219820Sjeffextern void osm_trap_rcv_process(IN void *context, IN void *data);
76219820Sjeffextern void osm_vla_rcv_process(IN void *context, IN void *data);
77219820Sjeff
78219820Sjeffextern void osm_state_mgr_process(IN osm_sm_t * sm, IN osm_signal_t signal);
79219820Sjeffextern void osm_sm_state_mgr_polling_callback(IN void *context);
80219820Sjeff
81219820Sjeff/**********************************************************************
82219820Sjeff **********************************************************************/
83219820Sjeffstatic void osm_sm_process(osm_sm_t * sm, osm_signal_t signal)
84219820Sjeff{
85219820Sjeff#ifdef ENABLE_OSM_PERF_MGR
86219820Sjeff	if (signal == OSM_SIGNAL_PERFMGR_SWEEP)
87219820Sjeff		osm_perfmgr_process(&sm->p_subn->p_osm->perfmgr);
88219820Sjeff	else
89219820Sjeff#endif
90219820Sjeff		osm_state_mgr_process(sm, signal);
91219820Sjeff}
92219820Sjeff
93219820Sjeffstatic void __osm_sm_sweeper(IN void *p_ptr)
94219820Sjeff{
95219820Sjeff	ib_api_status_t status;
96219820Sjeff	osm_sm_t *const p_sm = (osm_sm_t *) p_ptr;
97219820Sjeff	unsigned signals, i;
98219820Sjeff
99219820Sjeff	OSM_LOG_ENTER(p_sm->p_log);
100219820Sjeff
101219820Sjeff	while (p_sm->thread_state == OSM_THREAD_STATE_RUN) {
102219820Sjeff		/*
103219820Sjeff		 * Wait on the event with a timeout.
104219820Sjeff		 * Sweeps may be initiated "off schedule" by simply
105219820Sjeff		 * signaling the event.
106219820Sjeff		 */
107219820Sjeff		status = cl_event_wait_on(&p_sm->signal_event,
108219820Sjeff					  EVENT_NO_TIMEOUT, TRUE);
109219820Sjeff
110219820Sjeff		if (status == CL_SUCCESS)
111219820Sjeff			OSM_LOG(p_sm->p_log, OSM_LOG_DEBUG,
112219820Sjeff				"Off schedule sweep signalled\n");
113219820Sjeff		else if (status != CL_TIMEOUT) {
114219820Sjeff			OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E01: "
115219820Sjeff				"Event wait failed (%s)\n",
116219820Sjeff				CL_STATUS_MSG(status));
117219820Sjeff			continue;
118219820Sjeff		}
119219820Sjeff
120219820Sjeff		if (osm_exit_flag)
121219820Sjeff			break;
122219820Sjeff
123219820Sjeff		cl_spinlock_acquire(&p_sm->signal_lock);
124219820Sjeff		signals = p_sm->signal_mask;
125219820Sjeff		p_sm->signal_mask = 0;
126219820Sjeff		cl_spinlock_release(&p_sm->signal_lock);
127219820Sjeff
128219820Sjeff		for (i = 0; signals; signals >>= 1, i++)
129219820Sjeff			if (signals & 1)
130219820Sjeff				osm_sm_process(p_sm, i);
131219820Sjeff	}
132219820Sjeff
133219820Sjeff	OSM_LOG_EXIT(p_sm->p_log);
134219820Sjeff}
135219820Sjeff
136219820Sjeffstatic void sm_sweep(void *arg)
137219820Sjeff{
138219820Sjeff	osm_sm_t *sm = arg;
139219820Sjeff
140219820Sjeff	/*  do the sweep only if we are in MASTER state */
141219820Sjeff	if (sm->p_subn->sm_state == IB_SMINFO_STATE_MASTER ||
142219820Sjeff	    sm->p_subn->sm_state == IB_SMINFO_STATE_DISCOVERING)
143219820Sjeff		osm_sm_signal(sm, OSM_SIGNAL_SWEEP);
144219820Sjeff	cl_timer_start(&sm->sweep_timer, sm->p_subn->opt.sweep_interval * 1000);
145219820Sjeff}
146219820Sjeff
147219820Sjeffstatic void sweep_fail_process(IN void *context, IN void *p_data)
148219820Sjeff{
149219820Sjeff	osm_sm_t *sm = context;
150219820Sjeff
151219820Sjeff	OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "light sweep failed\n");
152219820Sjeff	sm->p_subn->force_heavy_sweep = TRUE;
153219820Sjeff}
154219820Sjeff
155219820Sjeff/**********************************************************************
156219820Sjeff **********************************************************************/
157219820Sjeffvoid osm_sm_construct(IN osm_sm_t * const p_sm)
158219820Sjeff{
159219820Sjeff	memset(p_sm, 0, sizeof(*p_sm));
160219820Sjeff	p_sm->thread_state = OSM_THREAD_STATE_NONE;
161219820Sjeff	p_sm->sm_trans_id = OSM_SM_INITIAL_TID_VALUE;
162219820Sjeff	cl_spinlock_construct(&p_sm->signal_lock);
163219820Sjeff	cl_spinlock_construct(&p_sm->state_lock);
164219820Sjeff	cl_timer_construct(&p_sm->polling_timer);
165219820Sjeff	cl_event_construct(&p_sm->signal_event);
166219820Sjeff	cl_event_construct(&p_sm->subnet_up_event);
167219820Sjeff	cl_event_wheel_construct(&p_sm->trap_aging_tracker);
168219820Sjeff	cl_thread_construct(&p_sm->sweeper);
169219820Sjeff	cl_spinlock_construct(&p_sm->mgrp_lock);
170219820Sjeff	osm_sm_mad_ctrl_construct(&p_sm->mad_ctrl);
171219820Sjeff	osm_lid_mgr_construct(&p_sm->lid_mgr);
172219820Sjeff	osm_ucast_mgr_construct(&p_sm->ucast_mgr);
173219820Sjeff}
174219820Sjeff
175219820Sjeff/**********************************************************************
176219820Sjeff **********************************************************************/
177219820Sjeffvoid osm_sm_shutdown(IN osm_sm_t * const p_sm)
178219820Sjeff{
179219820Sjeff	boolean_t signal_event = FALSE;
180219820Sjeff
181219820Sjeff	OSM_LOG_ENTER(p_sm->p_log);
182219820Sjeff
183219820Sjeff	/*
184219820Sjeff	 * Signal our threads that we're leaving.
185219820Sjeff	 */
186219820Sjeff	if (p_sm->thread_state != OSM_THREAD_STATE_NONE)
187219820Sjeff		signal_event = TRUE;
188219820Sjeff
189219820Sjeff	p_sm->thread_state = OSM_THREAD_STATE_EXIT;
190219820Sjeff
191219820Sjeff	/*
192219820Sjeff	 * Don't trigger unless event has been initialized.
193219820Sjeff	 * Destroy the thread before we tear down the other objects.
194219820Sjeff	 */
195219820Sjeff	if (signal_event)
196219820Sjeff		cl_event_signal(&p_sm->signal_event);
197219820Sjeff
198219820Sjeff	cl_timer_stop(&p_sm->polling_timer);
199219820Sjeff	cl_timer_stop(&p_sm->sweep_timer);
200219820Sjeff	cl_thread_destroy(&p_sm->sweeper);
201219820Sjeff
202219820Sjeff	/*
203219820Sjeff	 * Always destroy controllers before the corresponding
204219820Sjeff	 * receiver to guarantee that all callbacks from the
205219820Sjeff	 * dispatcher are complete.
206219820Sjeff	 */
207219820Sjeff	osm_sm_mad_ctrl_destroy(&p_sm->mad_ctrl);
208219820Sjeff	cl_disp_unregister(p_sm->ni_disp_h);
209219820Sjeff	cl_disp_unregister(p_sm->pi_disp_h);
210219820Sjeff	cl_disp_unregister(p_sm->si_disp_h);
211219820Sjeff	cl_disp_unregister(p_sm->nd_disp_h);
212219820Sjeff	cl_disp_unregister(p_sm->lft_disp_h);
213219820Sjeff	cl_disp_unregister(p_sm->mft_disp_h);
214219820Sjeff	cl_disp_unregister(p_sm->sm_info_disp_h);
215219820Sjeff	cl_disp_unregister(p_sm->trap_disp_h);
216219820Sjeff	cl_disp_unregister(p_sm->slvl_disp_h);
217219820Sjeff	cl_disp_unregister(p_sm->vla_disp_h);
218219820Sjeff	cl_disp_unregister(p_sm->pkey_disp_h);
219219820Sjeff	cl_disp_unregister(p_sm->sweep_fail_disp_h);
220219820Sjeff
221219820Sjeff	OSM_LOG_EXIT(p_sm->p_log);
222219820Sjeff}
223219820Sjeff
224219820Sjeff/**********************************************************************
225219820Sjeff **********************************************************************/
226219820Sjeffvoid osm_sm_destroy(IN osm_sm_t * const p_sm)
227219820Sjeff{
228219820Sjeff	OSM_LOG_ENTER(p_sm->p_log);
229219820Sjeff	osm_lid_mgr_destroy(&p_sm->lid_mgr);
230219820Sjeff	osm_ucast_mgr_destroy(&p_sm->ucast_mgr);
231219820Sjeff	cl_event_wheel_destroy(&p_sm->trap_aging_tracker);
232219820Sjeff	cl_timer_destroy(&p_sm->sweep_timer);
233219820Sjeff	cl_timer_destroy(&p_sm->polling_timer);
234219820Sjeff	cl_event_destroy(&p_sm->signal_event);
235219820Sjeff	cl_event_destroy(&p_sm->subnet_up_event);
236219820Sjeff	cl_spinlock_destroy(&p_sm->signal_lock);
237219820Sjeff	cl_spinlock_destroy(&p_sm->mgrp_lock);
238219820Sjeff	cl_spinlock_destroy(&p_sm->state_lock);
239219820Sjeff
240219820Sjeff	osm_log(p_sm->p_log, OSM_LOG_SYS, "Exiting SM\n");	/* Format Waived */
241219820Sjeff	OSM_LOG_EXIT(p_sm->p_log);
242219820Sjeff}
243219820Sjeff
244219820Sjeff/**********************************************************************
245219820Sjeff **********************************************************************/
246219820Sjeffib_api_status_t
247219820Sjeffosm_sm_init(IN osm_sm_t * const p_sm,
248219820Sjeff	    IN osm_subn_t * const p_subn,
249219820Sjeff	    IN osm_db_t * const p_db,
250219820Sjeff	    IN osm_vendor_t * const p_vendor,
251219820Sjeff	    IN osm_mad_pool_t * const p_mad_pool,
252219820Sjeff	    IN osm_vl15_t * const p_vl15,
253219820Sjeff	    IN osm_log_t * const p_log,
254219820Sjeff	    IN osm_stats_t * const p_stats,
255219820Sjeff	    IN cl_dispatcher_t * const p_disp, IN cl_plock_t * const p_lock)
256219820Sjeff{
257219820Sjeff	ib_api_status_t status = IB_SUCCESS;
258219820Sjeff
259219820Sjeff	OSM_LOG_ENTER(p_log);
260219820Sjeff
261219820Sjeff	p_sm->p_subn = p_subn;
262219820Sjeff	p_sm->p_db = p_db;
263219820Sjeff	p_sm->p_vendor = p_vendor;
264219820Sjeff	p_sm->p_mad_pool = p_mad_pool;
265219820Sjeff	p_sm->p_vl15 = p_vl15;
266219820Sjeff	p_sm->p_log = p_log;
267219820Sjeff	p_sm->p_disp = p_disp;
268219820Sjeff	p_sm->p_lock = p_lock;
269219820Sjeff
270219820Sjeff	status = cl_spinlock_init(&p_sm->signal_lock);
271219820Sjeff	if (status != CL_SUCCESS)
272219820Sjeff		goto Exit;
273219820Sjeff
274219820Sjeff	status = cl_spinlock_init(&p_sm->state_lock);
275219820Sjeff	if (status != CL_SUCCESS)
276219820Sjeff		goto Exit;
277219820Sjeff
278219820Sjeff	status = cl_event_init(&p_sm->signal_event, FALSE);
279219820Sjeff	if (status != CL_SUCCESS)
280219820Sjeff		goto Exit;
281219820Sjeff
282219820Sjeff	status = cl_event_init(&p_sm->subnet_up_event, FALSE);
283219820Sjeff	if (status != CL_SUCCESS)
284219820Sjeff		goto Exit;
285219820Sjeff
286219820Sjeff	status = cl_timer_init(&p_sm->sweep_timer, sm_sweep, p_sm);
287219820Sjeff	if (status != CL_SUCCESS)
288219820Sjeff		goto Exit;
289219820Sjeff
290219820Sjeff	status = cl_timer_init(&p_sm->polling_timer,
291219820Sjeff			       osm_sm_state_mgr_polling_callback, p_sm);
292219820Sjeff	if (status != CL_SUCCESS)
293219820Sjeff		goto Exit;
294219820Sjeff
295219820Sjeff	cl_qlist_init(&p_sm->mgrp_list);
296219820Sjeff
297219820Sjeff	status = cl_spinlock_init(&p_sm->mgrp_lock);
298219820Sjeff	if (status != CL_SUCCESS)
299219820Sjeff		goto Exit;
300219820Sjeff
301219820Sjeff	status = osm_sm_mad_ctrl_init(&p_sm->mad_ctrl,
302219820Sjeff				      p_sm->p_subn,
303219820Sjeff				      p_sm->p_mad_pool,
304219820Sjeff				      p_sm->p_vl15,
305219820Sjeff				      p_sm->p_vendor,
306219820Sjeff				      p_log, p_stats, p_lock, p_disp);
307219820Sjeff	if (status != IB_SUCCESS)
308219820Sjeff		goto Exit;
309219820Sjeff
310219820Sjeff	status = cl_event_wheel_init(&p_sm->trap_aging_tracker);
311219820Sjeff	if (status != IB_SUCCESS)
312219820Sjeff		goto Exit;
313219820Sjeff
314219820Sjeff	status = osm_lid_mgr_init(&p_sm->lid_mgr, p_sm);
315219820Sjeff	if (status != IB_SUCCESS)
316219820Sjeff		goto Exit;
317219820Sjeff
318219820Sjeff	status = osm_ucast_mgr_init(&p_sm->ucast_mgr, p_sm);
319219820Sjeff	if (status != IB_SUCCESS)
320219820Sjeff		goto Exit;
321219820Sjeff
322219820Sjeff	p_sm->sweep_fail_disp_h = cl_disp_register(p_disp,
323219820Sjeff						   OSM_MSG_LIGHT_SWEEP_FAIL,
324219820Sjeff						   sweep_fail_process, p_sm);
325219820Sjeff	if (p_sm->sweep_fail_disp_h == CL_DISP_INVALID_HANDLE)
326219820Sjeff		goto Exit;
327219820Sjeff
328219820Sjeff	p_sm->ni_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_NODE_INFO,
329219820Sjeff					   osm_ni_rcv_process, p_sm);
330219820Sjeff	if (p_sm->ni_disp_h == CL_DISP_INVALID_HANDLE)
331219820Sjeff		goto Exit;
332219820Sjeff
333219820Sjeff	p_sm->pi_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PORT_INFO,
334219820Sjeff					   osm_pi_rcv_process, p_sm);
335219820Sjeff	if (p_sm->pi_disp_h == CL_DISP_INVALID_HANDLE)
336219820Sjeff		goto Exit;
337219820Sjeff
338219820Sjeff	p_sm->si_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SWITCH_INFO,
339219820Sjeff					   osm_si_rcv_process, p_sm);
340219820Sjeff	if (p_sm->si_disp_h == CL_DISP_INVALID_HANDLE)
341219820Sjeff		goto Exit;
342219820Sjeff
343219820Sjeff	p_sm->nd_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_NODE_DESC,
344219820Sjeff					   osm_nd_rcv_process, p_sm);
345219820Sjeff	if (p_sm->nd_disp_h == CL_DISP_INVALID_HANDLE)
346219820Sjeff		goto Exit;
347219820Sjeff
348219820Sjeff	p_sm->lft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_LFT,
349219820Sjeff					    osm_lft_rcv_process, p_sm);
350219820Sjeff	if (p_sm->lft_disp_h == CL_DISP_INVALID_HANDLE)
351219820Sjeff		goto Exit;
352219820Sjeff
353219820Sjeff	p_sm->mft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_MFT,
354219820Sjeff					    osm_mft_rcv_process, p_sm);
355219820Sjeff	if (p_sm->mft_disp_h == CL_DISP_INVALID_HANDLE)
356219820Sjeff		goto Exit;
357219820Sjeff
358219820Sjeff	p_sm->sm_info_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SM_INFO,
359219820Sjeff						osm_sminfo_rcv_process, p_sm);
360219820Sjeff	if (p_sm->sm_info_disp_h == CL_DISP_INVALID_HANDLE)
361219820Sjeff		goto Exit;
362219820Sjeff
363219820Sjeff	p_sm->trap_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_NOTICE,
364219820Sjeff					     osm_trap_rcv_process, p_sm);
365219820Sjeff	if (p_sm->trap_disp_h == CL_DISP_INVALID_HANDLE)
366219820Sjeff		goto Exit;
367219820Sjeff
368219820Sjeff	p_sm->slvl_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SLVL,
369219820Sjeff					     osm_slvl_rcv_process, p_sm);
370219820Sjeff	if (p_sm->slvl_disp_h == CL_DISP_INVALID_HANDLE)
371219820Sjeff		goto Exit;
372219820Sjeff
373219820Sjeff	p_sm->vla_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_VL_ARB,
374219820Sjeff					    osm_vla_rcv_process, p_sm);
375219820Sjeff	if (p_sm->vla_disp_h == CL_DISP_INVALID_HANDLE)
376219820Sjeff		goto Exit;
377219820Sjeff
378219820Sjeff	p_sm->pkey_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PKEY,
379219820Sjeff					     osm_pkey_rcv_process, p_sm);
380219820Sjeff	if (p_sm->pkey_disp_h == CL_DISP_INVALID_HANDLE)
381219820Sjeff		goto Exit;
382219820Sjeff
383219820Sjeff	p_subn->sm_state = p_subn->opt.sm_inactive ?
384219820Sjeff	    IB_SMINFO_STATE_NOTACTIVE : IB_SMINFO_STATE_DISCOVERING;
385219820Sjeff	osm_report_sm_state(p_sm);
386219820Sjeff
387219820Sjeff	/*
388219820Sjeff	 * Now that the component objects are initialized, start
389219820Sjeff	 * the sweeper thread if the user wants sweeping.
390219820Sjeff	 */
391219820Sjeff	p_sm->thread_state = OSM_THREAD_STATE_RUN;
392219820Sjeff	status = cl_thread_init(&p_sm->sweeper, __osm_sm_sweeper, p_sm,
393219820Sjeff				"opensm sweeper");
394219820Sjeff	if (status != IB_SUCCESS)
395219820Sjeff		goto Exit;
396219820Sjeff
397219820Sjeff	if (p_sm->p_subn->opt.sweep_interval)
398219820Sjeff		cl_timer_start(&p_sm->sweep_timer,
399219820Sjeff			       p_sm->p_subn->opt.sweep_interval * 1000);
400219820Sjeff
401219820SjeffExit:
402219820Sjeff	OSM_LOG_EXIT(p_log);
403219820Sjeff	return (status);
404219820Sjeff}
405219820Sjeff
406219820Sjeff/**********************************************************************
407219820Sjeff **********************************************************************/
408219820Sjeffvoid osm_sm_signal(osm_sm_t * p_sm, osm_signal_t signal)
409219820Sjeff{
410219820Sjeff	cl_spinlock_acquire(&p_sm->signal_lock);
411219820Sjeff	p_sm->signal_mask |= 1 << signal;
412219820Sjeff	cl_event_signal(&p_sm->signal_event);
413219820Sjeff	cl_spinlock_release(&p_sm->signal_lock);
414219820Sjeff}
415219820Sjeff
416219820Sjeff/**********************************************************************
417219820Sjeff **********************************************************************/
418219820Sjeffvoid osm_sm_sweep(IN osm_sm_t * const p_sm)
419219820Sjeff{
420219820Sjeff	OSM_LOG_ENTER(p_sm->p_log);
421219820Sjeff	osm_sm_signal(p_sm, OSM_SIGNAL_SWEEP);
422219820Sjeff	OSM_LOG_EXIT(p_sm->p_log);
423219820Sjeff}
424219820Sjeff
425219820Sjeff/**********************************************************************
426219820Sjeff **********************************************************************/
427219820Sjeffib_api_status_t
428219820Sjeffosm_sm_bind(IN osm_sm_t * const p_sm, IN const ib_net64_t port_guid)
429219820Sjeff{
430219820Sjeff	ib_api_status_t status;
431219820Sjeff
432219820Sjeff	OSM_LOG_ENTER(p_sm->p_log);
433219820Sjeff
434219820Sjeff	status = osm_sm_mad_ctrl_bind(&p_sm->mad_ctrl, port_guid);
435219820Sjeff
436219820Sjeff	if (status != IB_SUCCESS) {
437219820Sjeff		OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E10: "
438219820Sjeff			"SM MAD Controller bind failed (%s)\n",
439219820Sjeff			ib_get_err_str(status));
440219820Sjeff		goto Exit;
441219820Sjeff	}
442219820Sjeff
443219820SjeffExit:
444219820Sjeff	OSM_LOG_EXIT(p_sm->p_log);
445219820Sjeff	return (status);
446219820Sjeff}
447219820Sjeff
448219820Sjeff/**********************************************************************
449219820Sjeff **********************************************************************/
450219820Sjeffstatic ib_api_status_t
451219820Sjeff__osm_sm_mgrp_process(IN osm_sm_t * const p_sm,
452219820Sjeff		      IN osm_mgrp_t * const p_mgrp,
453219820Sjeff		      IN const ib_net64_t port_guid,
454219820Sjeff		      IN osm_mcast_req_type_t req_type)
455219820Sjeff{
456219820Sjeff	osm_mcast_mgr_ctxt_t *ctx;
457219820Sjeff
458219820Sjeff	/*
459219820Sjeff	 * 'Schedule' all the QP0 traffic for when the state manager
460219820Sjeff	 * isn't busy trying to do something else.
461219820Sjeff	 */
462219820Sjeff	ctx = malloc(sizeof(*ctx));
463219820Sjeff	if (!ctx)
464219820Sjeff		return IB_ERROR;
465219820Sjeff	memset(ctx, 0, sizeof(*ctx));
466219820Sjeff	ctx->mlid = p_mgrp->mlid;
467219820Sjeff	ctx->req_type = req_type;
468219820Sjeff	ctx->port_guid = port_guid;
469219820Sjeff
470219820Sjeff	cl_spinlock_acquire(&p_sm->mgrp_lock);
471219820Sjeff	cl_qlist_insert_tail(&p_sm->mgrp_list, &ctx->list_item);
472219820Sjeff	cl_spinlock_release(&p_sm->mgrp_lock);
473219820Sjeff
474219820Sjeff	osm_sm_signal(p_sm, OSM_SIGNAL_IDLE_TIME_PROCESS_REQUEST);
475219820Sjeff
476219820Sjeff	return IB_SUCCESS;
477219820Sjeff}
478219820Sjeff
479219820Sjeff/**********************************************************************
480219820Sjeff **********************************************************************/
481219820Sjeffstatic ib_api_status_t
482219820Sjeff__osm_sm_mgrp_connect(IN osm_sm_t * const p_sm,
483219820Sjeff		      IN osm_mgrp_t * const p_mgrp,
484219820Sjeff		      IN const ib_net64_t port_guid,
485219820Sjeff		      IN osm_mcast_req_type_t req_type)
486219820Sjeff{
487219820Sjeff	return __osm_sm_mgrp_process(p_sm, p_mgrp, port_guid, req_type);
488219820Sjeff}
489219820Sjeff
490219820Sjeff/**********************************************************************
491219820Sjeff **********************************************************************/
492219820Sjeffstatic void
493219820Sjeff__osm_sm_mgrp_disconnect(IN osm_sm_t * const p_sm,
494219820Sjeff			 IN osm_mgrp_t * const p_mgrp,
495219820Sjeff			 IN const ib_net64_t port_guid)
496219820Sjeff{
497219820Sjeff	__osm_sm_mgrp_process(p_sm, p_mgrp, port_guid,
498219820Sjeff			      OSM_MCAST_REQ_TYPE_LEAVE);
499219820Sjeff}
500219820Sjeff
501219820Sjeff/**********************************************************************
502219820Sjeff **********************************************************************/
503219820Sjeffib_api_status_t
504219820Sjeffosm_sm_mcgrp_join(IN osm_sm_t * const p_sm,
505219820Sjeff		  IN const ib_net16_t mlid,
506219820Sjeff		  IN const ib_net64_t port_guid,
507219820Sjeff		  IN osm_mcast_req_type_t req_type)
508219820Sjeff{
509219820Sjeff	osm_mgrp_t *p_mgrp;
510219820Sjeff	osm_port_t *p_port;
511219820Sjeff	ib_api_status_t status = IB_SUCCESS;
512219820Sjeff	osm_mcm_info_t *p_mcm;
513219820Sjeff
514219820Sjeff	OSM_LOG_ENTER(p_sm->p_log);
515219820Sjeff
516219820Sjeff	OSM_LOG(p_sm->p_log, OSM_LOG_VERBOSE,
517219820Sjeff		"Port 0x%016" PRIx64 " joining MLID 0x%X\n",
518219820Sjeff		cl_ntoh64(port_guid), cl_ntoh16(mlid));
519219820Sjeff
520219820Sjeff	/*
521219820Sjeff	 * Acquire the port object for the port joining this group.
522219820Sjeff	 */
523219820Sjeff	CL_PLOCK_EXCL_ACQUIRE(p_sm->p_lock);
524219820Sjeff	p_port = osm_get_port_by_guid(p_sm->p_subn, port_guid);
525219820Sjeff	if (!p_port) {
526219820Sjeff		CL_PLOCK_RELEASE(p_sm->p_lock);
527219820Sjeff		OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E05: "
528219820Sjeff			"No port object for port 0x%016" PRIx64 "\n",
529219820Sjeff			cl_ntoh64(port_guid));
530219820Sjeff		status = IB_INVALID_PARAMETER;
531219820Sjeff		goto Exit;
532219820Sjeff	}
533219820Sjeff
534219820Sjeff	/*
535219820Sjeff	 * If this multicast group does not already exist, create it.
536219820Sjeff	 */
537219820Sjeff	p_mgrp = osm_get_mgrp_by_mlid(p_sm->p_subn, mlid);
538219820Sjeff	if (!p_mgrp || !osm_mgrp_is_guid(p_mgrp, port_guid)) {
539219820Sjeff		/*
540219820Sjeff		 * The group removed or the port is not a
541219820Sjeff		 * member of the group, then fail immediately.
542219820Sjeff		 * This can happen since the spinlock is released briefly
543219820Sjeff		 * before the SA calls this function.
544219820Sjeff		 */
545219820Sjeff		CL_PLOCK_RELEASE(p_sm->p_lock);
546219820Sjeff		OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E12: "
547219820Sjeff			"MC group with mlid 0x%x doesn't exist or "
548219820Sjeff			"port 0x%016" PRIx64 " is not in the group.\n",
549219820Sjeff			cl_ntoh16(mlid), cl_ntoh64(port_guid));
550219820Sjeff		status = IB_NOT_FOUND;
551219820Sjeff		goto Exit;
552219820Sjeff	}
553219820Sjeff
554219820Sjeff	/*
555219820Sjeff	 * Check if the object (according to mlid) already exists on this port.
556219820Sjeff	 * If it does - then no need to update it again, and no need to
557219820Sjeff	 * create the mc tree again. Just goto Exit.
558219820Sjeff	 */
559219820Sjeff	p_mcm = (osm_mcm_info_t *) cl_qlist_head(&p_port->mcm_list);
560219820Sjeff	while (p_mcm != (osm_mcm_info_t *) cl_qlist_end(&p_port->mcm_list)) {
561219820Sjeff		if (p_mcm->mlid == mlid) {
562219820Sjeff			CL_PLOCK_RELEASE(p_sm->p_lock);
563219820Sjeff			OSM_LOG(p_sm->p_log, OSM_LOG_DEBUG,
564219820Sjeff				"Found mlid object for Port:"
565219820Sjeff				"0x%016" PRIx64 " lid:0x%X\n",
566219820Sjeff				cl_ntoh64(port_guid), cl_ntoh16(mlid));
567219820Sjeff			goto Exit;
568219820Sjeff		}
569219820Sjeff		p_mcm = (osm_mcm_info_t *) cl_qlist_next(&p_mcm->list_item);
570219820Sjeff	}
571219820Sjeff
572219820Sjeff	status = osm_port_add_mgrp(p_port, mlid);
573219820Sjeff	if (status != IB_SUCCESS) {
574219820Sjeff		CL_PLOCK_RELEASE(p_sm->p_lock);
575219820Sjeff		OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E03: "
576219820Sjeff			"Unable to associate port 0x%" PRIx64 " to mlid 0x%X\n",
577219820Sjeff			cl_ntoh64(osm_port_get_guid(p_port)),
578219820Sjeff			cl_ntoh16(osm_mgrp_get_mlid(p_mgrp)));
579219820Sjeff		goto Exit;
580219820Sjeff	}
581219820Sjeff
582219820Sjeff	status = __osm_sm_mgrp_connect(p_sm, p_mgrp, port_guid, req_type);
583219820Sjeff	CL_PLOCK_RELEASE(p_sm->p_lock);
584219820Sjeff
585219820SjeffExit:
586219820Sjeff	OSM_LOG_EXIT(p_sm->p_log);
587219820Sjeff	return (status);
588219820Sjeff}
589219820Sjeff
590219820Sjeff/**********************************************************************
591219820Sjeff **********************************************************************/
592219820Sjeffib_api_status_t
593219820Sjeffosm_sm_mcgrp_leave(IN osm_sm_t * const p_sm,
594219820Sjeff		   IN const ib_net16_t mlid, IN const ib_net64_t port_guid)
595219820Sjeff{
596219820Sjeff	osm_mgrp_t *p_mgrp;
597219820Sjeff	osm_port_t *p_port;
598219820Sjeff	ib_api_status_t status = IB_SUCCESS;
599219820Sjeff
600219820Sjeff	OSM_LOG_ENTER(p_sm->p_log);
601219820Sjeff
602219820Sjeff	OSM_LOG(p_sm->p_log, OSM_LOG_VERBOSE,
603219820Sjeff		"Port 0x%" PRIx64 " leaving MLID 0x%X\n",
604219820Sjeff		cl_ntoh64(port_guid), cl_ntoh16(mlid));
605219820Sjeff
606219820Sjeff	/*
607219820Sjeff	 * Acquire the port object for the port leaving this group.
608219820Sjeff	 */
609219820Sjeff	CL_PLOCK_EXCL_ACQUIRE(p_sm->p_lock);
610219820Sjeff
611219820Sjeff	p_port = osm_get_port_by_guid(p_sm->p_subn, port_guid);
612219820Sjeff	if (!p_port) {
613219820Sjeff		CL_PLOCK_RELEASE(p_sm->p_lock);
614219820Sjeff		OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E04: "
615219820Sjeff			"No port object for port 0x%" PRIx64 "\n",
616219820Sjeff			cl_ntoh64(port_guid));
617219820Sjeff		status = IB_INVALID_PARAMETER;
618219820Sjeff		goto Exit;
619219820Sjeff	}
620219820Sjeff
621219820Sjeff	/*
622219820Sjeff	 * Get the multicast group object for this group.
623219820Sjeff	 */
624219820Sjeff	p_mgrp = osm_get_mgrp_by_mlid(p_sm->p_subn, mlid);
625219820Sjeff	if (!p_mgrp) {
626219820Sjeff		CL_PLOCK_RELEASE(p_sm->p_lock);
627219820Sjeff		OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E08: "
628219820Sjeff			"No multicast group for MLID 0x%X\n", cl_ntoh16(mlid));
629219820Sjeff		status = IB_INVALID_PARAMETER;
630219820Sjeff		goto Exit;
631219820Sjeff	}
632219820Sjeff
633219820Sjeff	/*
634219820Sjeff	 * Walk the list of ports in the group, and remove the appropriate one.
635219820Sjeff	 */
636219820Sjeff	osm_port_remove_mgrp(p_port, mlid);
637219820Sjeff
638219820Sjeff	__osm_sm_mgrp_disconnect(p_sm, p_mgrp, port_guid);
639219820Sjeff	CL_PLOCK_RELEASE(p_sm->p_lock);
640219820Sjeff
641219820SjeffExit:
642219820Sjeff	OSM_LOG_EXIT(p_sm->p_log);
643219820Sjeff	return (status);
644219820Sjeff}
645219820Sjeff
646219820Sjeffvoid osm_set_sm_priority(osm_sm_t *sm, uint8_t priority)
647219820Sjeff{
648219820Sjeff	uint8_t old_pri = sm->p_subn->opt.sm_priority;
649219820Sjeff
650219820Sjeff	sm->p_subn->opt.sm_priority = priority;
651219820Sjeff
652219820Sjeff	if (old_pri < priority &&
653219820Sjeff	    sm->p_subn->sm_state == IB_SMINFO_STATE_STANDBY)
654219820Sjeff		osm_send_trap144(sm, TRAP_144_MASK_SM_PRIORITY_CHANGE);
655219820Sjeff}
656