1/*
2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 * Copyright (c) 2008 Xsigo Systems Inc.  All rights reserved.
6 *
7 * This software is available to you under a choice of one of two
8 * licenses.  You may choose to be licensed under the terms of the GNU
9 * General Public License (GPL) Version 2, available from the file
10 * COPYING in the main directory of this source tree, or the
11 * OpenIB.org BSD license below:
12 *
13 *     Redistribution and use in source and binary forms, with or
14 *     without modification, are permitted provided that the following
15 *     conditions are met:
16 *
17 *      - Redistributions of source code must retain the above
18 *        copyright notice, this list of conditions and the following
19 *        disclaimer.
20 *
21 *      - Redistributions in binary form must reproduce the above
22 *        copyright notice, this list of conditions and the following
23 *        disclaimer in the documentation and/or other materials
24 *        provided with the distribution.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 * SOFTWARE.
34 *
35 */
36
37/*
38 * Abstract:
39 *    Implementation of osm_sm_t.
40 * This object represents the SM Receiver object.
41 * This object is part of the opensm family of objects.
42 */
43
44#if HAVE_CONFIG_H
45#  include <config.h>
46#endif				/* HAVE_CONFIG_H */
47
48#include <stdlib.h>
49#include <string.h>
50#include <iba/ib_types.h>
51#include <complib/cl_qmap.h>
52#include <complib/cl_passivelock.h>
53#include <complib/cl_debug.h>
54#include <complib/cl_thread.h>
55#include <opensm/osm_sm.h>
56#include <opensm/osm_madw.h>
57#include <opensm/osm_log.h>
58#include <opensm/osm_node.h>
59#include <opensm/osm_msgdef.h>
60#include <opensm/osm_mcm_info.h>
61#include <opensm/osm_perfmgr.h>
62#include <opensm/osm_opensm.h>
63
64#define  OSM_SM_INITIAL_TID_VALUE 0x1233
65
66extern void osm_lft_rcv_process(IN void *context, IN void *data);
67extern void osm_mft_rcv_process(IN void *context, IN void *data);
68extern void osm_nd_rcv_process(IN void *context, IN void *data);
69extern void osm_ni_rcv_process(IN void *context, IN void *data);
70extern void osm_pkey_rcv_process(IN void *context, IN void *data);
71extern void osm_pi_rcv_process(IN void *context, IN void *data);
72extern void osm_slvl_rcv_process(IN void *context, IN void *p_data);
73extern void osm_sminfo_rcv_process(IN void *context, IN void *data);
74extern void osm_si_rcv_process(IN void *context, IN void *data);
75extern void osm_trap_rcv_process(IN void *context, IN void *data);
76extern void osm_vla_rcv_process(IN void *context, IN void *data);
77
78extern void osm_state_mgr_process(IN osm_sm_t * sm, IN osm_signal_t signal);
79extern void osm_sm_state_mgr_polling_callback(IN void *context);
80
81/**********************************************************************
82 **********************************************************************/
83static void osm_sm_process(osm_sm_t * sm, osm_signal_t signal)
84{
85#ifdef ENABLE_OSM_PERF_MGR
86	if (signal == OSM_SIGNAL_PERFMGR_SWEEP)
87		osm_perfmgr_process(&sm->p_subn->p_osm->perfmgr);
88	else
89#endif
90		osm_state_mgr_process(sm, signal);
91}
92
93static void __osm_sm_sweeper(IN void *p_ptr)
94{
95	ib_api_status_t status;
96	osm_sm_t *const p_sm = (osm_sm_t *) p_ptr;
97	unsigned signals, i;
98
99	OSM_LOG_ENTER(p_sm->p_log);
100
101	while (p_sm->thread_state == OSM_THREAD_STATE_RUN) {
102		/*
103		 * Wait on the event with a timeout.
104		 * Sweeps may be initiated "off schedule" by simply
105		 * signaling the event.
106		 */
107		status = cl_event_wait_on(&p_sm->signal_event,
108					  EVENT_NO_TIMEOUT, TRUE);
109
110		if (status == CL_SUCCESS)
111			OSM_LOG(p_sm->p_log, OSM_LOG_DEBUG,
112				"Off schedule sweep signalled\n");
113		else if (status != CL_TIMEOUT) {
114			OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E01: "
115				"Event wait failed (%s)\n",
116				CL_STATUS_MSG(status));
117			continue;
118		}
119
120		if (osm_exit_flag)
121			break;
122
123		cl_spinlock_acquire(&p_sm->signal_lock);
124		signals = p_sm->signal_mask;
125		p_sm->signal_mask = 0;
126		cl_spinlock_release(&p_sm->signal_lock);
127
128		for (i = 0; signals; signals >>= 1, i++)
129			if (signals & 1)
130				osm_sm_process(p_sm, i);
131	}
132
133	OSM_LOG_EXIT(p_sm->p_log);
134}
135
136static void sm_sweep(void *arg)
137{
138	osm_sm_t *sm = arg;
139
140	/*  do the sweep only if we are in MASTER state */
141	if (sm->p_subn->sm_state == IB_SMINFO_STATE_MASTER ||
142	    sm->p_subn->sm_state == IB_SMINFO_STATE_DISCOVERING)
143		osm_sm_signal(sm, OSM_SIGNAL_SWEEP);
144	cl_timer_start(&sm->sweep_timer, sm->p_subn->opt.sweep_interval * 1000);
145}
146
147static void sweep_fail_process(IN void *context, IN void *p_data)
148{
149	osm_sm_t *sm = context;
150
151	OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "light sweep failed\n");
152	sm->p_subn->force_heavy_sweep = TRUE;
153}
154
155/**********************************************************************
156 **********************************************************************/
157void osm_sm_construct(IN osm_sm_t * const p_sm)
158{
159	memset(p_sm, 0, sizeof(*p_sm));
160	p_sm->thread_state = OSM_THREAD_STATE_NONE;
161	p_sm->sm_trans_id = OSM_SM_INITIAL_TID_VALUE;
162	cl_spinlock_construct(&p_sm->signal_lock);
163	cl_spinlock_construct(&p_sm->state_lock);
164	cl_timer_construct(&p_sm->polling_timer);
165	cl_event_construct(&p_sm->signal_event);
166	cl_event_construct(&p_sm->subnet_up_event);
167	cl_event_wheel_construct(&p_sm->trap_aging_tracker);
168	cl_thread_construct(&p_sm->sweeper);
169	cl_spinlock_construct(&p_sm->mgrp_lock);
170	osm_sm_mad_ctrl_construct(&p_sm->mad_ctrl);
171	osm_lid_mgr_construct(&p_sm->lid_mgr);
172	osm_ucast_mgr_construct(&p_sm->ucast_mgr);
173}
174
175/**********************************************************************
176 **********************************************************************/
177void osm_sm_shutdown(IN osm_sm_t * const p_sm)
178{
179	boolean_t signal_event = FALSE;
180
181	OSM_LOG_ENTER(p_sm->p_log);
182
183	/*
184	 * Signal our threads that we're leaving.
185	 */
186	if (p_sm->thread_state != OSM_THREAD_STATE_NONE)
187		signal_event = TRUE;
188
189	p_sm->thread_state = OSM_THREAD_STATE_EXIT;
190
191	/*
192	 * Don't trigger unless event has been initialized.
193	 * Destroy the thread before we tear down the other objects.
194	 */
195	if (signal_event)
196		cl_event_signal(&p_sm->signal_event);
197
198	cl_timer_stop(&p_sm->polling_timer);
199	cl_timer_stop(&p_sm->sweep_timer);
200	cl_thread_destroy(&p_sm->sweeper);
201
202	/*
203	 * Always destroy controllers before the corresponding
204	 * receiver to guarantee that all callbacks from the
205	 * dispatcher are complete.
206	 */
207	osm_sm_mad_ctrl_destroy(&p_sm->mad_ctrl);
208	cl_disp_unregister(p_sm->ni_disp_h);
209	cl_disp_unregister(p_sm->pi_disp_h);
210	cl_disp_unregister(p_sm->si_disp_h);
211	cl_disp_unregister(p_sm->nd_disp_h);
212	cl_disp_unregister(p_sm->lft_disp_h);
213	cl_disp_unregister(p_sm->mft_disp_h);
214	cl_disp_unregister(p_sm->sm_info_disp_h);
215	cl_disp_unregister(p_sm->trap_disp_h);
216	cl_disp_unregister(p_sm->slvl_disp_h);
217	cl_disp_unregister(p_sm->vla_disp_h);
218	cl_disp_unregister(p_sm->pkey_disp_h);
219	cl_disp_unregister(p_sm->sweep_fail_disp_h);
220
221	OSM_LOG_EXIT(p_sm->p_log);
222}
223
224/**********************************************************************
225 **********************************************************************/
226void osm_sm_destroy(IN osm_sm_t * const p_sm)
227{
228	OSM_LOG_ENTER(p_sm->p_log);
229	osm_lid_mgr_destroy(&p_sm->lid_mgr);
230	osm_ucast_mgr_destroy(&p_sm->ucast_mgr);
231	cl_event_wheel_destroy(&p_sm->trap_aging_tracker);
232	cl_timer_destroy(&p_sm->sweep_timer);
233	cl_timer_destroy(&p_sm->polling_timer);
234	cl_event_destroy(&p_sm->signal_event);
235	cl_event_destroy(&p_sm->subnet_up_event);
236	cl_spinlock_destroy(&p_sm->signal_lock);
237	cl_spinlock_destroy(&p_sm->mgrp_lock);
238	cl_spinlock_destroy(&p_sm->state_lock);
239
240	osm_log(p_sm->p_log, OSM_LOG_SYS, "Exiting SM\n");	/* Format Waived */
241	OSM_LOG_EXIT(p_sm->p_log);
242}
243
244/**********************************************************************
245 **********************************************************************/
246ib_api_status_t
247osm_sm_init(IN osm_sm_t * const p_sm,
248	    IN osm_subn_t * const p_subn,
249	    IN osm_db_t * const p_db,
250	    IN osm_vendor_t * const p_vendor,
251	    IN osm_mad_pool_t * const p_mad_pool,
252	    IN osm_vl15_t * const p_vl15,
253	    IN osm_log_t * const p_log,
254	    IN osm_stats_t * const p_stats,
255	    IN cl_dispatcher_t * const p_disp, IN cl_plock_t * const p_lock)
256{
257	ib_api_status_t status = IB_SUCCESS;
258
259	OSM_LOG_ENTER(p_log);
260
261	p_sm->p_subn = p_subn;
262	p_sm->p_db = p_db;
263	p_sm->p_vendor = p_vendor;
264	p_sm->p_mad_pool = p_mad_pool;
265	p_sm->p_vl15 = p_vl15;
266	p_sm->p_log = p_log;
267	p_sm->p_disp = p_disp;
268	p_sm->p_lock = p_lock;
269
270	status = cl_spinlock_init(&p_sm->signal_lock);
271	if (status != CL_SUCCESS)
272		goto Exit;
273
274	status = cl_spinlock_init(&p_sm->state_lock);
275	if (status != CL_SUCCESS)
276		goto Exit;
277
278	status = cl_event_init(&p_sm->signal_event, FALSE);
279	if (status != CL_SUCCESS)
280		goto Exit;
281
282	status = cl_event_init(&p_sm->subnet_up_event, FALSE);
283	if (status != CL_SUCCESS)
284		goto Exit;
285
286	status = cl_timer_init(&p_sm->sweep_timer, sm_sweep, p_sm);
287	if (status != CL_SUCCESS)
288		goto Exit;
289
290	status = cl_timer_init(&p_sm->polling_timer,
291			       osm_sm_state_mgr_polling_callback, p_sm);
292	if (status != CL_SUCCESS)
293		goto Exit;
294
295	cl_qlist_init(&p_sm->mgrp_list);
296
297	status = cl_spinlock_init(&p_sm->mgrp_lock);
298	if (status != CL_SUCCESS)
299		goto Exit;
300
301	status = osm_sm_mad_ctrl_init(&p_sm->mad_ctrl,
302				      p_sm->p_subn,
303				      p_sm->p_mad_pool,
304				      p_sm->p_vl15,
305				      p_sm->p_vendor,
306				      p_log, p_stats, p_lock, p_disp);
307	if (status != IB_SUCCESS)
308		goto Exit;
309
310	status = cl_event_wheel_init(&p_sm->trap_aging_tracker);
311	if (status != IB_SUCCESS)
312		goto Exit;
313
314	status = osm_lid_mgr_init(&p_sm->lid_mgr, p_sm);
315	if (status != IB_SUCCESS)
316		goto Exit;
317
318	status = osm_ucast_mgr_init(&p_sm->ucast_mgr, p_sm);
319	if (status != IB_SUCCESS)
320		goto Exit;
321
322	p_sm->sweep_fail_disp_h = cl_disp_register(p_disp,
323						   OSM_MSG_LIGHT_SWEEP_FAIL,
324						   sweep_fail_process, p_sm);
325	if (p_sm->sweep_fail_disp_h == CL_DISP_INVALID_HANDLE)
326		goto Exit;
327
328	p_sm->ni_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_NODE_INFO,
329					   osm_ni_rcv_process, p_sm);
330	if (p_sm->ni_disp_h == CL_DISP_INVALID_HANDLE)
331		goto Exit;
332
333	p_sm->pi_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PORT_INFO,
334					   osm_pi_rcv_process, p_sm);
335	if (p_sm->pi_disp_h == CL_DISP_INVALID_HANDLE)
336		goto Exit;
337
338	p_sm->si_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SWITCH_INFO,
339					   osm_si_rcv_process, p_sm);
340	if (p_sm->si_disp_h == CL_DISP_INVALID_HANDLE)
341		goto Exit;
342
343	p_sm->nd_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_NODE_DESC,
344					   osm_nd_rcv_process, p_sm);
345	if (p_sm->nd_disp_h == CL_DISP_INVALID_HANDLE)
346		goto Exit;
347
348	p_sm->lft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_LFT,
349					    osm_lft_rcv_process, p_sm);
350	if (p_sm->lft_disp_h == CL_DISP_INVALID_HANDLE)
351		goto Exit;
352
353	p_sm->mft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_MFT,
354					    osm_mft_rcv_process, p_sm);
355	if (p_sm->mft_disp_h == CL_DISP_INVALID_HANDLE)
356		goto Exit;
357
358	p_sm->sm_info_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SM_INFO,
359						osm_sminfo_rcv_process, p_sm);
360	if (p_sm->sm_info_disp_h == CL_DISP_INVALID_HANDLE)
361		goto Exit;
362
363	p_sm->trap_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_NOTICE,
364					     osm_trap_rcv_process, p_sm);
365	if (p_sm->trap_disp_h == CL_DISP_INVALID_HANDLE)
366		goto Exit;
367
368	p_sm->slvl_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SLVL,
369					     osm_slvl_rcv_process, p_sm);
370	if (p_sm->slvl_disp_h == CL_DISP_INVALID_HANDLE)
371		goto Exit;
372
373	p_sm->vla_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_VL_ARB,
374					    osm_vla_rcv_process, p_sm);
375	if (p_sm->vla_disp_h == CL_DISP_INVALID_HANDLE)
376		goto Exit;
377
378	p_sm->pkey_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PKEY,
379					     osm_pkey_rcv_process, p_sm);
380	if (p_sm->pkey_disp_h == CL_DISP_INVALID_HANDLE)
381		goto Exit;
382
383	p_subn->sm_state = p_subn->opt.sm_inactive ?
384	    IB_SMINFO_STATE_NOTACTIVE : IB_SMINFO_STATE_DISCOVERING;
385	osm_report_sm_state(p_sm);
386
387	/*
388	 * Now that the component objects are initialized, start
389	 * the sweeper thread if the user wants sweeping.
390	 */
391	p_sm->thread_state = OSM_THREAD_STATE_RUN;
392	status = cl_thread_init(&p_sm->sweeper, __osm_sm_sweeper, p_sm,
393				"opensm sweeper");
394	if (status != IB_SUCCESS)
395		goto Exit;
396
397	if (p_sm->p_subn->opt.sweep_interval)
398		cl_timer_start(&p_sm->sweep_timer,
399			       p_sm->p_subn->opt.sweep_interval * 1000);
400
401Exit:
402	OSM_LOG_EXIT(p_log);
403	return (status);
404}
405
406/**********************************************************************
407 **********************************************************************/
408void osm_sm_signal(osm_sm_t * p_sm, osm_signal_t signal)
409{
410	cl_spinlock_acquire(&p_sm->signal_lock);
411	p_sm->signal_mask |= 1 << signal;
412	cl_event_signal(&p_sm->signal_event);
413	cl_spinlock_release(&p_sm->signal_lock);
414}
415
416/**********************************************************************
417 **********************************************************************/
418void osm_sm_sweep(IN osm_sm_t * const p_sm)
419{
420	OSM_LOG_ENTER(p_sm->p_log);
421	osm_sm_signal(p_sm, OSM_SIGNAL_SWEEP);
422	OSM_LOG_EXIT(p_sm->p_log);
423}
424
425/**********************************************************************
426 **********************************************************************/
427ib_api_status_t
428osm_sm_bind(IN osm_sm_t * const p_sm, IN const ib_net64_t port_guid)
429{
430	ib_api_status_t status;
431
432	OSM_LOG_ENTER(p_sm->p_log);
433
434	status = osm_sm_mad_ctrl_bind(&p_sm->mad_ctrl, port_guid);
435
436	if (status != IB_SUCCESS) {
437		OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E10: "
438			"SM MAD Controller bind failed (%s)\n",
439			ib_get_err_str(status));
440		goto Exit;
441	}
442
443Exit:
444	OSM_LOG_EXIT(p_sm->p_log);
445	return (status);
446}
447
448/**********************************************************************
449 **********************************************************************/
450static ib_api_status_t
451__osm_sm_mgrp_process(IN osm_sm_t * const p_sm,
452		      IN osm_mgrp_t * const p_mgrp,
453		      IN const ib_net64_t port_guid,
454		      IN osm_mcast_req_type_t req_type)
455{
456	osm_mcast_mgr_ctxt_t *ctx;
457
458	/*
459	 * 'Schedule' all the QP0 traffic for when the state manager
460	 * isn't busy trying to do something else.
461	 */
462	ctx = malloc(sizeof(*ctx));
463	if (!ctx)
464		return IB_ERROR;
465	memset(ctx, 0, sizeof(*ctx));
466	ctx->mlid = p_mgrp->mlid;
467	ctx->req_type = req_type;
468	ctx->port_guid = port_guid;
469
470	cl_spinlock_acquire(&p_sm->mgrp_lock);
471	cl_qlist_insert_tail(&p_sm->mgrp_list, &ctx->list_item);
472	cl_spinlock_release(&p_sm->mgrp_lock);
473
474	osm_sm_signal(p_sm, OSM_SIGNAL_IDLE_TIME_PROCESS_REQUEST);
475
476	return IB_SUCCESS;
477}
478
479/**********************************************************************
480 **********************************************************************/
481static ib_api_status_t
482__osm_sm_mgrp_connect(IN osm_sm_t * const p_sm,
483		      IN osm_mgrp_t * const p_mgrp,
484		      IN const ib_net64_t port_guid,
485		      IN osm_mcast_req_type_t req_type)
486{
487	return __osm_sm_mgrp_process(p_sm, p_mgrp, port_guid, req_type);
488}
489
490/**********************************************************************
491 **********************************************************************/
492static void
493__osm_sm_mgrp_disconnect(IN osm_sm_t * const p_sm,
494			 IN osm_mgrp_t * const p_mgrp,
495			 IN const ib_net64_t port_guid)
496{
497	__osm_sm_mgrp_process(p_sm, p_mgrp, port_guid,
498			      OSM_MCAST_REQ_TYPE_LEAVE);
499}
500
501/**********************************************************************
502 **********************************************************************/
503ib_api_status_t
504osm_sm_mcgrp_join(IN osm_sm_t * const p_sm,
505		  IN const ib_net16_t mlid,
506		  IN const ib_net64_t port_guid,
507		  IN osm_mcast_req_type_t req_type)
508{
509	osm_mgrp_t *p_mgrp;
510	osm_port_t *p_port;
511	ib_api_status_t status = IB_SUCCESS;
512	osm_mcm_info_t *p_mcm;
513
514	OSM_LOG_ENTER(p_sm->p_log);
515
516	OSM_LOG(p_sm->p_log, OSM_LOG_VERBOSE,
517		"Port 0x%016" PRIx64 " joining MLID 0x%X\n",
518		cl_ntoh64(port_guid), cl_ntoh16(mlid));
519
520	/*
521	 * Acquire the port object for the port joining this group.
522	 */
523	CL_PLOCK_EXCL_ACQUIRE(p_sm->p_lock);
524	p_port = osm_get_port_by_guid(p_sm->p_subn, port_guid);
525	if (!p_port) {
526		CL_PLOCK_RELEASE(p_sm->p_lock);
527		OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E05: "
528			"No port object for port 0x%016" PRIx64 "\n",
529			cl_ntoh64(port_guid));
530		status = IB_INVALID_PARAMETER;
531		goto Exit;
532	}
533
534	/*
535	 * If this multicast group does not already exist, create it.
536	 */
537	p_mgrp = osm_get_mgrp_by_mlid(p_sm->p_subn, mlid);
538	if (!p_mgrp || !osm_mgrp_is_guid(p_mgrp, port_guid)) {
539		/*
540		 * The group removed or the port is not a
541		 * member of the group, then fail immediately.
542		 * This can happen since the spinlock is released briefly
543		 * before the SA calls this function.
544		 */
545		CL_PLOCK_RELEASE(p_sm->p_lock);
546		OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E12: "
547			"MC group with mlid 0x%x doesn't exist or "
548			"port 0x%016" PRIx64 " is not in the group.\n",
549			cl_ntoh16(mlid), cl_ntoh64(port_guid));
550		status = IB_NOT_FOUND;
551		goto Exit;
552	}
553
554	/*
555	 * Check if the object (according to mlid) already exists on this port.
556	 * If it does - then no need to update it again, and no need to
557	 * create the mc tree again. Just goto Exit.
558	 */
559	p_mcm = (osm_mcm_info_t *) cl_qlist_head(&p_port->mcm_list);
560	while (p_mcm != (osm_mcm_info_t *) cl_qlist_end(&p_port->mcm_list)) {
561		if (p_mcm->mlid == mlid) {
562			CL_PLOCK_RELEASE(p_sm->p_lock);
563			OSM_LOG(p_sm->p_log, OSM_LOG_DEBUG,
564				"Found mlid object for Port:"
565				"0x%016" PRIx64 " lid:0x%X\n",
566				cl_ntoh64(port_guid), cl_ntoh16(mlid));
567			goto Exit;
568		}
569		p_mcm = (osm_mcm_info_t *) cl_qlist_next(&p_mcm->list_item);
570	}
571
572	status = osm_port_add_mgrp(p_port, mlid);
573	if (status != IB_SUCCESS) {
574		CL_PLOCK_RELEASE(p_sm->p_lock);
575		OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E03: "
576			"Unable to associate port 0x%" PRIx64 " to mlid 0x%X\n",
577			cl_ntoh64(osm_port_get_guid(p_port)),
578			cl_ntoh16(osm_mgrp_get_mlid(p_mgrp)));
579		goto Exit;
580	}
581
582	status = __osm_sm_mgrp_connect(p_sm, p_mgrp, port_guid, req_type);
583	CL_PLOCK_RELEASE(p_sm->p_lock);
584
585Exit:
586	OSM_LOG_EXIT(p_sm->p_log);
587	return (status);
588}
589
590/**********************************************************************
591 **********************************************************************/
592ib_api_status_t
593osm_sm_mcgrp_leave(IN osm_sm_t * const p_sm,
594		   IN const ib_net16_t mlid, IN const ib_net64_t port_guid)
595{
596	osm_mgrp_t *p_mgrp;
597	osm_port_t *p_port;
598	ib_api_status_t status = IB_SUCCESS;
599
600	OSM_LOG_ENTER(p_sm->p_log);
601
602	OSM_LOG(p_sm->p_log, OSM_LOG_VERBOSE,
603		"Port 0x%" PRIx64 " leaving MLID 0x%X\n",
604		cl_ntoh64(port_guid), cl_ntoh16(mlid));
605
606	/*
607	 * Acquire the port object for the port leaving this group.
608	 */
609	CL_PLOCK_EXCL_ACQUIRE(p_sm->p_lock);
610
611	p_port = osm_get_port_by_guid(p_sm->p_subn, port_guid);
612	if (!p_port) {
613		CL_PLOCK_RELEASE(p_sm->p_lock);
614		OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E04: "
615			"No port object for port 0x%" PRIx64 "\n",
616			cl_ntoh64(port_guid));
617		status = IB_INVALID_PARAMETER;
618		goto Exit;
619	}
620
621	/*
622	 * Get the multicast group object for this group.
623	 */
624	p_mgrp = osm_get_mgrp_by_mlid(p_sm->p_subn, mlid);
625	if (!p_mgrp) {
626		CL_PLOCK_RELEASE(p_sm->p_lock);
627		OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E08: "
628			"No multicast group for MLID 0x%X\n", cl_ntoh16(mlid));
629		status = IB_INVALID_PARAMETER;
630		goto Exit;
631	}
632
633	/*
634	 * Walk the list of ports in the group, and remove the appropriate one.
635	 */
636	osm_port_remove_mgrp(p_port, mlid);
637
638	__osm_sm_mgrp_disconnect(p_sm, p_mgrp, port_guid);
639	CL_PLOCK_RELEASE(p_sm->p_lock);
640
641Exit:
642	OSM_LOG_EXIT(p_sm->p_log);
643	return (status);
644}
645
646void osm_set_sm_priority(osm_sm_t *sm, uint8_t priority)
647{
648	uint8_t old_pri = sm->p_subn->opt.sm_priority;
649
650	sm->p_subn->opt.sm_priority = priority;
651
652	if (old_pri < priority &&
653	    sm->p_subn->sm_state == IB_SMINFO_STATE_STANDBY)
654		osm_send_trap144(sm, TRAP_144_MASK_SM_PRIORITY_CHANGE);
655}
656