xref: /trueos/contrib/ofed/management/opensm/opensm/osm_sm.c (revision 8fe640108653f13042f1b15213769e338aa524f6)
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 
66 extern void osm_lft_rcv_process(IN void *context, IN void *data);
67 extern void osm_mft_rcv_process(IN void *context, IN void *data);
68 extern void osm_nd_rcv_process(IN void *context, IN void *data);
69 extern void osm_ni_rcv_process(IN void *context, IN void *data);
70 extern void osm_pkey_rcv_process(IN void *context, IN void *data);
71 extern void osm_pi_rcv_process(IN void *context, IN void *data);
72 extern void osm_slvl_rcv_process(IN void *context, IN void *p_data);
73 extern void osm_sminfo_rcv_process(IN void *context, IN void *data);
74 extern void osm_si_rcv_process(IN void *context, IN void *data);
75 extern void osm_trap_rcv_process(IN void *context, IN void *data);
76 extern void osm_vla_rcv_process(IN void *context, IN void *data);
77 
78 extern void osm_state_mgr_process(IN osm_sm_t * sm, IN osm_signal_t signal);
79 extern void osm_sm_state_mgr_polling_callback(IN void *context);
80 
81 /**********************************************************************
82  **********************************************************************/
osm_sm_process(osm_sm_t * sm,osm_signal_t signal)83 static 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 
__osm_sm_sweeper(IN void * p_ptr)93 static 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 
sm_sweep(void * arg)136 static 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 
sweep_fail_process(IN void * context,IN void * p_data)147 static 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  **********************************************************************/
osm_sm_construct(IN osm_sm_t * const p_sm)157 void 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  **********************************************************************/
osm_sm_shutdown(IN osm_sm_t * const p_sm)177 void 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  **********************************************************************/
osm_sm_destroy(IN osm_sm_t * const p_sm)226 void 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  **********************************************************************/
246 ib_api_status_t
osm_sm_init(IN osm_sm_t * const p_sm,IN osm_subn_t * const p_subn,IN osm_db_t * const p_db,IN osm_vendor_t * const p_vendor,IN osm_mad_pool_t * const p_mad_pool,IN osm_vl15_t * const p_vl15,IN osm_log_t * const p_log,IN osm_stats_t * const p_stats,IN cl_dispatcher_t * const p_disp,IN cl_plock_t * const p_lock)247 osm_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 
401 Exit:
402 	OSM_LOG_EXIT(p_log);
403 	return (status);
404 }
405 
406 /**********************************************************************
407  **********************************************************************/
osm_sm_signal(osm_sm_t * p_sm,osm_signal_t signal)408 void 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  **********************************************************************/
osm_sm_sweep(IN osm_sm_t * const p_sm)418 void 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  **********************************************************************/
427 ib_api_status_t
osm_sm_bind(IN osm_sm_t * const p_sm,IN const ib_net64_t port_guid)428 osm_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 
443 Exit:
444 	OSM_LOG_EXIT(p_sm->p_log);
445 	return (status);
446 }
447 
448 /**********************************************************************
449  **********************************************************************/
450 static ib_api_status_t
__osm_sm_mgrp_process(IN osm_sm_t * const p_sm,IN osm_mgrp_t * const p_mgrp,IN const ib_net64_t port_guid,IN osm_mcast_req_type_t req_type)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  **********************************************************************/
481 static ib_api_status_t
__osm_sm_mgrp_connect(IN osm_sm_t * const p_sm,IN osm_mgrp_t * const p_mgrp,IN const ib_net64_t port_guid,IN osm_mcast_req_type_t req_type)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  **********************************************************************/
492 static void
__osm_sm_mgrp_disconnect(IN osm_sm_t * const p_sm,IN osm_mgrp_t * const p_mgrp,IN const ib_net64_t port_guid)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  **********************************************************************/
503 ib_api_status_t
osm_sm_mcgrp_join(IN osm_sm_t * const p_sm,IN const ib_net16_t mlid,IN const ib_net64_t port_guid,IN osm_mcast_req_type_t req_type)504 osm_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 
585 Exit:
586 	OSM_LOG_EXIT(p_sm->p_log);
587 	return (status);
588 }
589 
590 /**********************************************************************
591  **********************************************************************/
592 ib_api_status_t
osm_sm_mcgrp_leave(IN osm_sm_t * const p_sm,IN const ib_net16_t mlid,IN const ib_net64_t port_guid)593 osm_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 
641 Exit:
642 	OSM_LOG_EXIT(p_sm->p_log);
643 	return (status);
644 }
645 
osm_set_sm_priority(osm_sm_t * sm,uint8_t priority)646 void 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