1/*
2 * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
3 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
4 * Copyright (c) 2002-2015 Mellanox Technologies LTD. All rights reserved.
5 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
6 * Copyright (c) 2009 HNR Consulting. All rights reserved.
7 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
8 *
9 * This software is available to you under a choice of one of two
10 * licenses.  You may choose to be licensed under the terms of the GNU
11 * General Public License (GPL) Version 2, available from the file
12 * COPYING in the main directory of this source tree, or the
13 * OpenIB.org BSD license below:
14 *
15 *     Redistribution and use in source and binary forms, with or
16 *     without modification, are permitted provided that the following
17 *     conditions are met:
18 *
19 *      - Redistributions of source code must retain the above
20 *        copyright notice, this list of conditions and the following
21 *        disclaimer.
22 *
23 *      - Redistributions in binary form must reproduce the above
24 *        copyright notice, this list of conditions and the following
25 *        disclaimer in the documentation and/or other materials
26 *        provided with the distribution.
27 *
28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
32 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
33 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35 * SOFTWARE.
36 *
37 */
38
39/*
40 * Abstract:
41 *    Implementation of osm_state_mgr_t.
42 * This file implements the State Manager object.
43 */
44
45#if HAVE_CONFIG_H
46#  include <config.h>
47#endif				/* HAVE_CONFIG_H */
48
49#include <unistd.h>
50#include <stdlib.h>
51#include <string.h>
52#include <iba/ib_types.h>
53#include <complib/cl_passivelock.h>
54#include <complib/cl_debug.h>
55#include <complib/cl_qmap.h>
56#include <opensm/osm_file_ids.h>
57#define FILE_ID OSM_FILE_STATE_MGR_C
58#include <opensm/osm_sm.h>
59#include <opensm/osm_madw.h>
60#include <opensm/osm_switch.h>
61#include <opensm/osm_log.h>
62#include <opensm/osm_subnet.h>
63#include <opensm/osm_helper.h>
64#include <opensm/osm_msgdef.h>
65#include <opensm/osm_node.h>
66#include <opensm/osm_port.h>
67#include <vendor/osm_vendor_api.h>
68#include <opensm/osm_inform.h>
69#include <opensm/osm_opensm.h>
70#include <opensm/osm_congestion_control.h>
71#include <opensm/osm_db.h>
72#include <opensm/osm_service.h>
73#include <opensm/osm_guid.h>
74
75extern void osm_drop_mgr_process(IN osm_sm_t * sm);
76extern int osm_qos_setup(IN osm_opensm_t * p_osm);
77extern int osm_pkey_mgr_process(IN osm_opensm_t * p_osm);
78extern int osm_mcast_mgr_process(IN osm_sm_t * sm, boolean_t config_all);
79extern int osm_link_mgr_process(IN osm_sm_t * sm, IN uint8_t state);
80extern void osm_guid_mgr_process(IN osm_sm_t * sm);
81
82static void state_mgr_up_msg(IN const osm_sm_t * sm)
83{
84	/*
85	 * This message should be written only once - when the
86	 * SM moves to Master state and the subnet is up for
87	 * the first time.
88	 */
89	osm_log_v2(sm->p_log, sm->p_subn->first_time_master_sweep ?
90		   OSM_LOG_SYS : OSM_LOG_INFO, FILE_ID, "SUBNET UP\n");
91
92	OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE,
93			sm->p_subn->opt.sweep_interval ?
94			"SUBNET UP" : "SUBNET UP (sweep disabled)");
95}
96
97static void state_mgr_reset_node_count(IN cl_map_item_t * p_map_item,
98				       IN void *context)
99{
100	osm_node_t *p_node = (osm_node_t *) p_map_item;
101
102	p_node->discovery_count = 0;
103
104	memset(p_node->physp_discovered, 0, sizeof(uint8_t) * p_node->physp_tbl_size);
105}
106
107static void state_mgr_reset_port_count(IN cl_map_item_t * p_map_item,
108				       IN void *context)
109{
110	osm_port_t *p_port = (osm_port_t *) p_map_item;
111
112	p_port->discovery_count = 0;
113}
114
115static void state_mgr_reset_switch_count(IN cl_map_item_t * p_map_item,
116					 IN void *context)
117{
118	osm_switch_t *p_sw = (osm_switch_t *) p_map_item;
119
120	if (p_sw->max_lid_ho != 0)
121		p_sw->need_update = 1;
122}
123
124static void state_mgr_get_sw_info(IN cl_map_item_t * p_object, IN void *context)
125{
126	osm_node_t *p_node;
127	osm_physp_t *p_physp;
128	osm_dr_path_t *p_dr_path;
129	osm_madw_context_t mad_context;
130	osm_switch_t *const p_sw = (osm_switch_t *) p_object;
131	osm_sm_t *sm = context;
132	ib_api_status_t status;
133
134	OSM_LOG_ENTER(sm->p_log);
135
136	p_node = p_sw->p_node;
137	p_physp = osm_node_get_physp_ptr(p_node, 0);
138	p_dr_path = osm_physp_get_dr_path_ptr(p_physp);
139
140	memset(&mad_context, 0, sizeof(mad_context));
141
142	mad_context.si_context.node_guid = osm_node_get_node_guid(p_node);
143	mad_context.si_context.set_method = FALSE;
144	mad_context.si_context.light_sweep = TRUE;
145	mad_context.si_context.lft_top_change = FALSE;
146
147	status = osm_req_get(sm, p_dr_path, IB_MAD_ATTR_SWITCH_INFO, 0,
148			     FALSE, ib_port_info_get_m_key(&p_physp->port_info),
149			     OSM_MSG_LIGHT_SWEEP_FAIL, &mad_context);
150	if (status != IB_SUCCESS)
151		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3304: "
152			"Request for SwitchInfo from 0x%" PRIx64 " failed (%s)\n",
153			cl_ntoh64(osm_node_get_node_guid(p_node)),
154			ib_get_err_str(status));
155
156	OSM_LOG_EXIT(sm->p_log);
157}
158
159/**********************************************************************
160 Initiate a remote port info request for the given physical port
161 **********************************************************************/
162static void state_mgr_get_remote_port_info(IN osm_sm_t * sm,
163					   IN osm_physp_t * p_physp)
164{
165	osm_dr_path_t *p_dr_path;
166	osm_dr_path_t rem_node_dr_path;
167	osm_madw_context_t mad_context;
168	ib_api_status_t status;
169
170	OSM_LOG_ENTER(sm->p_log);
171
172	/* generate a dr path leaving on the physp to the remote node */
173	p_dr_path = osm_physp_get_dr_path_ptr(p_physp);
174	memcpy(&rem_node_dr_path, p_dr_path, sizeof(osm_dr_path_t));
175	if (osm_dr_path_extend(&rem_node_dr_path, osm_physp_get_port_num(p_physp))) {
176		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 332D: "
177			"DR path with hop count %d couldn't be extended "
178			"so skipping PortInfo query\n",
179			p_dr_path->hop_count);
180		goto Exit;
181	}
182
183	memset(&mad_context, 0, sizeof(mad_context));
184
185	mad_context.pi_context.node_guid =
186	    osm_node_get_node_guid(osm_physp_get_node_ptr(p_physp));
187	mad_context.pi_context.port_guid = p_physp->port_guid;
188	mad_context.pi_context.set_method = FALSE;
189	mad_context.pi_context.light_sweep = TRUE;
190	mad_context.pi_context.active_transition = FALSE;
191	mad_context.pi_context.client_rereg = FALSE;
192
193	/* note that with some negative logic - if the query failed it means
194	 * that there is no point in going to heavy sweep */
195	status = osm_req_get(sm, &rem_node_dr_path, IB_MAD_ATTR_PORT_INFO, 0,
196			     TRUE, 0, CL_DISP_MSGID_NONE, &mad_context);
197	if (status != IB_SUCCESS)
198		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 332E: "
199			"Request for remote PortInfo from 0x%" PRIx64 " failed (%s)\n",
200			cl_ntoh64(p_physp->port_guid), ib_get_err_str(status));
201
202Exit:
203	OSM_LOG_EXIT(sm->p_log);
204}
205
206/**********************************************************************
207 Initiates a thorough sweep of the subnet.
208 Used when there is suspicion that something on the subnet has changed.
209**********************************************************************/
210static ib_api_status_t state_mgr_sweep_hop_0(IN osm_sm_t * sm)
211{
212	ib_api_status_t status;
213	osm_dr_path_t dr_path;
214	osm_bind_handle_t h_bind;
215	uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX];
216
217	OSM_LOG_ENTER(sm->p_log);
218
219	memset(path_array, 0, sizeof(path_array));
220
221	/*
222	 * First, get the bind handle.
223	 */
224	h_bind = osm_sm_mad_ctrl_get_bind_handle(&sm->mad_ctrl);
225	if (h_bind != OSM_BIND_INVALID_HANDLE) {
226		OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE,
227				"INITIATING HEAVY SWEEP");
228		/*
229		 * Start the sweep by clearing the port counts, then
230		 * get our own NodeInfo at 0 hops.
231		 */
232		CL_PLOCK_ACQUIRE(sm->p_lock);
233
234		cl_qmap_apply_func(&sm->p_subn->node_guid_tbl,
235				   state_mgr_reset_node_count, sm);
236
237		cl_qmap_apply_func(&sm->p_subn->port_guid_tbl,
238				   state_mgr_reset_port_count, sm);
239
240		cl_qmap_apply_func(&sm->p_subn->sw_guid_tbl,
241				   state_mgr_reset_switch_count, sm);
242
243		/* Set the in_sweep_hop_0 flag in subn to be TRUE.
244		 * This will indicate the sweeping not to continue beyond the
245		 * the current node.
246		 * This is relevant for the case of SM on switch, since in the
247		 * switch info we need to signal somehow not to continue
248		 * the sweeping. */
249		sm->p_subn->in_sweep_hop_0 = TRUE;
250
251		CL_PLOCK_RELEASE(sm->p_lock);
252
253		osm_dr_path_init(&dr_path, 0, path_array);
254		CL_PLOCK_ACQUIRE(sm->p_lock);
255		status = osm_req_get(sm, &dr_path, IB_MAD_ATTR_NODE_INFO, 0,
256				     TRUE, 0, CL_DISP_MSGID_NONE, NULL);
257		CL_PLOCK_RELEASE(sm->p_lock);
258		if (status != IB_SUCCESS)
259			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3305: "
260				"Request for NodeInfo failed (%s)\n",
261				ib_get_err_str(status));
262	} else {
263		OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
264			"No bound ports. Deferring sweep...\n");
265		status = IB_INVALID_STATE;
266	}
267
268	OSM_LOG_EXIT(sm->p_log);
269	return status;
270}
271
272/**********************************************************************
273 Clear out all existing port lid assignments
274**********************************************************************/
275static ib_api_status_t state_mgr_clean_known_lids(IN osm_sm_t * sm)
276{
277	ib_api_status_t status = IB_SUCCESS;
278	cl_ptr_vector_t *p_vec = &(sm->p_subn->port_lid_tbl);
279	uint32_t i;
280
281	OSM_LOG_ENTER(sm->p_log);
282
283	/* we need a lock here! */
284	CL_PLOCK_ACQUIRE(sm->p_lock);
285
286	for (i = 0; i < cl_ptr_vector_get_size(p_vec); i++)
287		cl_ptr_vector_set(p_vec, i, NULL);
288
289	CL_PLOCK_RELEASE(sm->p_lock);
290
291	OSM_LOG_EXIT(sm->p_log);
292	return status;
293}
294
295/**********************************************************************
296 Clear SA cache
297**********************************************************************/
298static ib_api_status_t state_mgr_sa_clean(IN osm_sm_t * sm)
299{
300	ib_api_status_t status = IB_SUCCESS;
301	cl_qmap_t *p_port_guid_tbl;
302	osm_assigned_guids_t *p_assigned_guids, *p_next_assigned_guids;
303	osm_alias_guid_t *p_alias_guid, *p_next_alias_guid;
304	osm_mcm_port_t *mcm_port;
305	osm_subn_t * p_subn;
306	osm_port_t *p_port;
307	osm_infr_t *p_infr;
308	osm_svcr_t *p_svcr;
309
310	OSM_LOG_ENTER(sm->p_log);
311
312	p_subn = sm->p_subn;
313
314	/* we need a lock here! */
315	CL_PLOCK_EXCL_ACQUIRE(sm->p_lock);
316
317	if (p_subn->opt.drop_event_subscriptions) {
318		/* Clean InformInfo records */
319		p_infr = (osm_infr_t *) cl_qlist_remove_head(&p_subn->sa_infr_list);
320		while (p_infr !=
321		       (osm_infr_t *) cl_qlist_end(&p_subn->sa_infr_list)) {
322			osm_infr_delete(p_infr);
323			p_infr = (osm_infr_t *) cl_qlist_remove_head(&p_subn->sa_infr_list);
324		}
325
326		/* For now, treat Service Records in same category as InformInfos */
327		/* Clean Service records */
328		p_svcr = (osm_svcr_t *) cl_qlist_remove_head(&p_subn->sa_sr_list);
329		while (p_svcr !=
330		       (osm_svcr_t *) cl_qlist_end(&p_subn->sa_sr_list)) {
331			osm_svcr_delete(p_svcr);
332			p_svcr = (osm_svcr_t *) cl_qlist_remove_head(&p_subn->sa_sr_list);
333		}
334	}
335
336	/* Clean Multicast member list on each port */
337	p_port_guid_tbl = &p_subn->port_guid_tbl;
338	for (p_port = (osm_port_t *) cl_qmap_head(p_port_guid_tbl);
339	     p_port != (osm_port_t *) cl_qmap_end(p_port_guid_tbl);
340	     p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) {
341		while (!cl_is_qlist_empty(&p_port->mcm_list)) {
342			mcm_port = cl_item_obj(cl_qlist_head(&p_port->mcm_list),
343					       mcm_port, list_item);
344			osm_mgrp_delete_port(p_subn, sm->p_log, mcm_port->mgrp,
345					     p_port);
346		}
347		/* Hack - clean alias guid table from physp */
348		free(p_port->p_physp->p_guids);
349		p_port->p_physp->p_guids = NULL;
350	}
351
352	/* Clean Alias Guid work objects */
353	while (cl_qlist_count(&p_subn->alias_guid_list))
354		osm_guid_work_obj_delete((osm_guidinfo_work_obj_t *)
355			cl_qlist_remove_head(&p_subn->alias_guid_list));
356
357	/* Clean Assigned GUIDs table */
358	p_next_assigned_guids = (osm_assigned_guids_t *)
359				cl_qmap_head(&p_subn->assigned_guids_tbl);
360	while (p_next_assigned_guids !=
361	       (osm_assigned_guids_t *) cl_qmap_end(&p_subn->assigned_guids_tbl)) {
362		p_assigned_guids = p_next_assigned_guids;
363		p_next_assigned_guids = (osm_assigned_guids_t *)
364					cl_qmap_next(&p_assigned_guids->map_item);
365		cl_qmap_remove_item(&p_subn->assigned_guids_tbl,
366				    &p_assigned_guids->map_item);
367		osm_assigned_guids_delete(&p_assigned_guids);
368        }
369
370	/* Clean Alias GUIDs table */
371	p_next_alias_guid = (osm_alias_guid_t *)
372			    cl_qmap_head(&p_subn->alias_port_guid_tbl);
373	while (p_next_alias_guid !=
374	       (osm_alias_guid_t *) cl_qmap_end(&p_subn->alias_port_guid_tbl)) {
375		p_alias_guid = p_next_alias_guid;
376		p_next_alias_guid = (osm_alias_guid_t *)
377				    cl_qmap_next(&p_alias_guid->map_item);
378		if (osm_alias_guid_get_alias_guid(p_alias_guid) !=
379		    osm_alias_guid_get_base_guid(p_alias_guid)) {
380			/* Clean if it's not base port GUID */
381			cl_qmap_remove_item(&p_subn->alias_port_guid_tbl,
382					    &p_alias_guid->map_item);
383			osm_alias_guid_delete(&p_alias_guid);
384		}
385	}
386
387	p_subn->p_osm->sa.dirty = TRUE;
388
389	CL_PLOCK_RELEASE(sm->p_lock);
390	OSM_LOG_EXIT(sm->p_log);
391	return status;
392}
393
394/**********************************************************************
395 Notifies the transport layer that the local LID has changed,
396 which give it a chance to update address vectors, etc..
397**********************************************************************/
398static ib_api_status_t state_mgr_notify_lid_change(IN osm_sm_t * sm)
399{
400	ib_api_status_t status;
401	osm_bind_handle_t h_bind;
402
403	OSM_LOG_ENTER(sm->p_log);
404
405	/*
406	 * First, get the bind handle.
407	 */
408	h_bind = osm_sm_mad_ctrl_get_bind_handle(&sm->mad_ctrl);
409	if (h_bind == OSM_BIND_INVALID_HANDLE) {
410		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3306: "
411			"No bound ports\n");
412		status = IB_ERROR;
413		goto Exit;
414	}
415
416	/*
417	 * Notify the transport layer that we changed the local LID.
418	 */
419	status = osm_vendor_local_lid_change(h_bind);
420	if (status != IB_SUCCESS)
421		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3307: "
422			"Vendor LID update failed (%s)\n",
423			ib_get_err_str(status));
424
425Exit:
426	OSM_LOG_EXIT(sm->p_log);
427	return status;
428}
429
430/**********************************************************************
431 Returns true if the SM port is down.
432 The SM's port object must exist in the port_guid table.
433**********************************************************************/
434static boolean_t state_mgr_is_sm_port_down(IN osm_sm_t * sm)
435{
436	ib_net64_t port_guid;
437	osm_port_t *p_port;
438	osm_physp_t *p_physp;
439	uint8_t state;
440
441	OSM_LOG_ENTER(sm->p_log);
442
443	port_guid = sm->p_subn->sm_port_guid;
444
445	/*
446	 * If we don't know our own port guid yet, assume the port is down.
447	 */
448	if (port_guid == 0) {
449		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3308: "
450			"SM port GUID unknown\n");
451		state = IB_LINK_DOWN;
452		goto Exit;
453	}
454
455	CL_ASSERT(port_guid);
456
457	CL_PLOCK_ACQUIRE(sm->p_lock);
458	p_port = osm_get_port_by_guid(sm->p_subn, port_guid);
459	if (!p_port) {
460		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3309: "
461			"SM port with GUID:%016" PRIx64 " is unknown\n",
462			cl_ntoh64(port_guid));
463		state = IB_LINK_DOWN;
464		CL_PLOCK_RELEASE(sm->p_lock);
465		goto Exit;
466	}
467
468	p_physp = p_port->p_physp;
469
470	CL_ASSERT(p_physp);
471
472	if (p_port->p_node->sw &&
473	    !ib_switch_info_is_enhanced_port0(&p_port->p_node->sw->switch_info))
474		state = IB_LINK_ACTIVE;	/* base SP0 */
475	else
476		state = osm_physp_get_port_state(p_physp);
477
478	if (!p_port->discovery_count) {
479		OSM_LOG(sm->p_log, OSM_LOG_ERROR,
480			"ERR 330A: Failed to discover SM port\n");
481		state = IB_LINK_DOWN;
482	}
483
484	CL_PLOCK_RELEASE(sm->p_lock);
485
486Exit:
487	OSM_LOG_EXIT(sm->p_log);
488	return (state == IB_LINK_DOWN);
489}
490
491/**********************************************************************
492 Sweeps the node 1 hop away.
493 This sets off a "chain reaction" that causes discovery of the subnet.
494 Used when there is suspicion that something on the subnet has changed.
495**********************************************************************/
496static ib_api_status_t state_mgr_sweep_hop_1(IN osm_sm_t * sm)
497{
498	ib_api_status_t status = IB_SUCCESS;
499	osm_madw_context_t context;
500	osm_node_t *p_node;
501	osm_port_t *p_port;
502	osm_dr_path_t hop_1_path;
503	ib_net64_t port_guid;
504	uint8_t port_num;
505	uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX];
506	uint8_t num_ports;
507	osm_physp_t *p_ext_physp;
508
509	OSM_LOG_ENTER(sm->p_log);
510
511	/*
512	 * First, get our own port and node objects.
513	 */
514	port_guid = sm->p_subn->sm_port_guid;
515
516	CL_ASSERT(port_guid);
517
518	/* Set the in_sweep_hop_0 flag in subn to be FALSE.
519	 * This will indicate the sweeping to continue beyond the
520	 * the current node.
521	 * This is relevant for the case of SM on switch, since in the
522	 * switch info we need to signal that the sweeping should
523	 * continue through the switch. */
524	sm->p_subn->in_sweep_hop_0 = FALSE;
525
526	p_port = osm_get_port_by_guid(sm->p_subn, port_guid);
527	if (!p_port) {
528		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3310: "
529			"No SM port object\n");
530		status = IB_ERROR;
531		goto Exit;
532	}
533
534	p_node = p_port->p_node;
535	CL_ASSERT(p_node);
536
537	port_num = ib_node_info_get_local_port_num(&p_node->node_info);
538
539	OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
540		"Probing hop 1 on local port %u\n", port_num);
541
542	memset(path_array, 0, sizeof(path_array));
543	/* the hop_1 operations depend on the type of our node.
544	 * Currently - legal nodes that can host SM are SW and CA */
545	switch (osm_node_get_type(p_node)) {
546	case IB_NODE_TYPE_CA:
547	case IB_NODE_TYPE_ROUTER:
548		memset(&context, 0, sizeof(context));
549		context.ni_context.node_guid = osm_node_get_node_guid(p_node);
550		context.ni_context.port_num = port_num;
551
552		path_array[1] = port_num;
553
554		osm_dr_path_init(&hop_1_path, 1, path_array);
555		CL_PLOCK_ACQUIRE(sm->p_lock);
556		status = osm_req_get(sm, &hop_1_path, IB_MAD_ATTR_NODE_INFO, 0,
557				     TRUE, 0, CL_DISP_MSGID_NONE, &context);
558		CL_PLOCK_RELEASE(sm->p_lock);
559		if (status != IB_SUCCESS)
560			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3311: "
561				"Request for NodeInfo failed (%s)\n",
562				ib_get_err_str(status));
563		break;
564
565	case IB_NODE_TYPE_SWITCH:
566		/* Need to go over all the ports of the switch, and send a
567		 * node_info from them. This doesn't include the port 0 of the
568		 * switch, which hosts the SM.
569		 * Note: We'll send another switchInfo on port 0, since if no
570		 * ports are connected, we still want to get some response, and
571		 * have the subnet come up.
572		 */
573		num_ports = osm_node_get_num_physp(p_node);
574		for (port_num = 1; port_num < num_ports; port_num++) {
575			/* go through the port only if the port is not DOWN */
576			p_ext_physp = osm_node_get_physp_ptr(p_node, port_num);
577			if (p_ext_physp && ib_port_info_get_port_state
578			    (&(p_ext_physp->port_info)) > IB_LINK_DOWN) {
579				memset(&context, 0, sizeof(context));
580				context.ni_context.node_guid =
581				    osm_node_get_node_guid(p_node);
582				context.ni_context.port_num = port_num;
583
584				path_array[1] = port_num;
585				osm_dr_path_init(&hop_1_path, 1, path_array);
586				CL_PLOCK_ACQUIRE(sm->p_lock);
587				status = osm_req_get(sm, &hop_1_path,
588						     IB_MAD_ATTR_NODE_INFO, 0,
589						     TRUE, 0,
590						     CL_DISP_MSGID_NONE,
591						     &context);
592				CL_PLOCK_RELEASE(sm->p_lock);
593				if (status != IB_SUCCESS)
594					OSM_LOG(sm->p_log, OSM_LOG_ERROR,
595						"ERR 3312: "
596						"Request for NodeInfo failed (%s)\n",
597						ib_get_err_str(status));
598			}
599		}
600		break;
601
602	default:
603		OSM_LOG(sm->p_log, OSM_LOG_ERROR,
604			"ERR 3313: Unknown node type %d (%s)\n",
605			osm_node_get_type(p_node), p_node->print_desc);
606	}
607
608Exit:
609	OSM_LOG_EXIT(sm->p_log);
610	return status;
611}
612
613static void query_sm_info(cl_map_item_t * item, void *cxt)
614{
615	osm_madw_context_t context;
616	osm_remote_sm_t *r_sm = cl_item_obj(item, r_sm, map_item);
617	osm_sm_t *sm = cxt;
618	ib_api_status_t ret;
619	osm_port_t *p_port;
620
621	p_port= osm_get_port_by_guid(sm->p_subn, r_sm->smi.guid);
622	if (p_port == NULL) {
623		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3340: "
624			"No port object on given sm object\n");
625		return;
626        }
627
628	context.smi_context.port_guid = r_sm->smi.guid;
629	context.smi_context.set_method = FALSE;
630	context.smi_context.light_sweep = TRUE;
631
632	ret = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_port->p_physp),
633			  IB_MAD_ATTR_SM_INFO, 0, FALSE,
634			  ib_port_info_get_m_key(&p_port->p_physp->port_info),
635			  CL_DISP_MSGID_NONE, &context);
636	if (ret != IB_SUCCESS)
637		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3314: "
638			"Failure requesting SMInfo (%s)\n",
639			ib_get_err_str(ret));
640}
641
642static void state_mgr_reset_state_change_bit(IN cl_map_item_t * obj,
643					     IN void *context)
644{
645	osm_madw_context_t mad_context;
646	osm_switch_t *p_sw = (osm_switch_t *) obj;
647	osm_sm_t *sm = context;
648	osm_node_t *p_node;
649	osm_physp_t *p_physp;
650	osm_dr_path_t *p_path;
651	ib_api_status_t status;
652	ib_switch_info_t si;
653
654	OSM_LOG_ENTER(sm->p_log);
655
656	CL_ASSERT(p_sw);
657
658	p_node = p_sw->p_node;
659
660	CL_ASSERT(p_node);
661
662	p_physp = osm_node_get_physp_ptr(p_node, 0);
663	p_path = osm_physp_get_dr_path_ptr(p_physp);
664
665	if (!ib_switch_info_get_state_change(&p_sw->switch_info))
666		goto exit;
667
668	si = p_sw->switch_info;
669
670	ib_switch_info_state_change_set(&si);
671
672	OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
673		"Resetting PortStateChange on switch GUID 0x%016" PRIx64 "\n",
674		cl_ntoh64(osm_node_get_node_guid(p_node)));
675
676	mad_context.si_context.light_sweep = FALSE;
677	mad_context.si_context.node_guid = osm_node_get_node_guid(p_node);
678	mad_context.si_context.set_method = TRUE;
679	mad_context.si_context.lft_top_change = FALSE;
680
681	status = osm_req_set(sm, p_path, (uint8_t *) &si,
682			     sizeof(si), IB_MAD_ATTR_SWITCH_INFO,
683			     0, FALSE,
684			     ib_port_info_get_m_key(&p_physp->port_info),
685			     CL_DISP_MSGID_NONE, &mad_context);
686
687	if (status != IB_SUCCESS)
688		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 332A: "
689			"Sending SwitchInfo attribute failed (%s)\n",
690			ib_get_err_str(status));
691
692exit:
693	OSM_LOG_EXIT(sm->p_log);
694}
695
696static void state_mgr_update_node_desc(IN cl_map_item_t * obj, IN void *context)
697{
698	osm_madw_context_t mad_context;
699	osm_node_t *p_node = (osm_node_t *) obj;
700	osm_sm_t *sm = context;
701	osm_physp_t *p_physp = NULL;
702	unsigned i, num_ports;
703	ib_api_status_t status;
704
705	OSM_LOG_ENTER(sm->p_log);
706
707	CL_ASSERT(p_node);
708
709	OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
710		"Updating NodeDesc for 0x%016" PRIx64 "\n",
711		cl_ntoh64(osm_node_get_node_guid(p_node)));
712
713	/* get a physp to request from. */
714	num_ports = osm_node_get_num_physp(p_node);
715	for (i = 0; i < num_ports; i++)
716		if ((p_physp = osm_node_get_physp_ptr(p_node, i)))
717			break;
718
719	if (!p_physp) {
720		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 331C: "
721			"Failed to find any valid physical port object.\n");
722		goto exit;
723	}
724
725	mad_context.nd_context.node_guid = osm_node_get_node_guid(p_node);
726
727	status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_physp),
728			     IB_MAD_ATTR_NODE_DESC, 0, FALSE,
729			     ib_port_info_get_m_key(&p_physp->port_info),
730			     CL_DISP_MSGID_NONE, &mad_context);
731	if (status != IB_SUCCESS)
732		OSM_LOG(sm->p_log, OSM_LOG_ERROR,
733			"ERR 331B: Failure initiating NodeDescription request "
734			"(%s) to 0x%016" PRIx64 "\n", ib_get_err_str(status),
735			cl_ntoh64(osm_node_get_node_guid(p_node)));
736
737exit:
738	OSM_LOG_EXIT(sm->p_log);
739}
740
741void osm_reset_switch_state_change_bit(IN osm_opensm_t *osm)
742{
743	CL_PLOCK_ACQUIRE(&osm->lock);
744	cl_qmap_apply_func(&osm->subn.sw_guid_tbl, state_mgr_reset_state_change_bit,
745			   &osm->sm);
746	CL_PLOCK_RELEASE(&osm->lock);
747}
748
749void osm_update_node_desc(IN osm_opensm_t *osm)
750{
751	CL_PLOCK_ACQUIRE(&osm->lock);
752	cl_qmap_apply_func(&osm->subn.node_guid_tbl, state_mgr_update_node_desc,
753			   &osm->sm);
754	CL_PLOCK_RELEASE(&osm->lock);
755}
756
757/**********************************************************************
758 During a light sweep, check each node to see if the node description
759 is valid and if not issue a ND query.
760**********************************************************************/
761static void state_mgr_get_node_desc(IN cl_map_item_t * obj, IN void *context)
762{
763	osm_node_t *p_node = (osm_node_t *) obj;
764	osm_sm_t *sm = context;
765
766	OSM_LOG_ENTER(sm->p_log);
767
768	CL_ASSERT(p_node);
769
770	if (p_node->print_desc
771	    && strcmp(p_node->print_desc, OSM_NODE_DESC_UNKNOWN))
772		/* if ND is valid, do nothing */
773		goto exit;
774
775	OSM_LOG(sm->p_log, OSM_LOG_ERROR,
776		"ERR 3319: Unknown node description for node GUID "
777		"0x%016" PRIx64 ".  Reissuing ND query\n",
778		cl_ntoh64(osm_node_get_node_guid(p_node)));
779
780	state_mgr_update_node_desc(obj, context);
781
782exit:
783	OSM_LOG_EXIT(sm->p_log);
784}
785
786/**********************************************************************
787 Initiates a lightweight sweep of the subnet.
788 Used during normal sweeps after the subnet is up.
789**********************************************************************/
790static ib_api_status_t state_mgr_light_sweep_start(IN osm_sm_t * sm)
791{
792	ib_api_status_t status = IB_SUCCESS;
793	osm_bind_handle_t h_bind;
794	cl_qmap_t *p_sw_tbl;
795	cl_map_item_t *p_next;
796	osm_node_t *p_node;
797	osm_physp_t *p_physp;
798	uint8_t port_num;
799
800	OSM_LOG_ENTER(sm->p_log);
801
802	p_sw_tbl = &sm->p_subn->sw_guid_tbl;
803
804	/*
805	 * First, get the bind handle.
806	 */
807	h_bind = osm_sm_mad_ctrl_get_bind_handle(&sm->mad_ctrl);
808	if (h_bind == OSM_BIND_INVALID_HANDLE) {
809		OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
810			"No bound ports. Deferring sweep...\n");
811		status = IB_INVALID_STATE;
812		goto _exit;
813	}
814
815	OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, "INITIATING LIGHT SWEEP");
816	CL_PLOCK_ACQUIRE(sm->p_lock);
817	cl_qmap_apply_func(p_sw_tbl, state_mgr_get_sw_info, sm);
818	CL_PLOCK_RELEASE(sm->p_lock);
819
820	CL_PLOCK_ACQUIRE(sm->p_lock);
821	cl_qmap_apply_func(&sm->p_subn->node_guid_tbl, state_mgr_get_node_desc,
822			   sm);
823	CL_PLOCK_RELEASE(sm->p_lock);
824
825	/* now scan the list of physical ports that were not down but have no remote port */
826	CL_PLOCK_ACQUIRE(sm->p_lock);
827	p_next = cl_qmap_head(&sm->p_subn->node_guid_tbl);
828	while (p_next != cl_qmap_end(&sm->p_subn->node_guid_tbl)) {
829		p_node = (osm_node_t *) p_next;
830		p_next = cl_qmap_next(p_next);
831
832		for (port_num = 1; port_num < osm_node_get_num_physp(p_node);
833		     port_num++) {
834			p_physp = osm_node_get_physp_ptr(p_node, port_num);
835			if (p_physp && (osm_physp_get_port_state(p_physp) !=
836					IB_LINK_DOWN)
837			    && !osm_physp_get_remote(p_physp)) {
838				OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3315: "
839					"Unknown remote side for node 0x%016"
840					PRIx64
841					" (%s) port %u. Adding to light sweep sampling list\n",
842					cl_ntoh64(osm_node_get_node_guid
843						  (p_node)),
844					p_node->print_desc, port_num);
845
846				osm_dump_dr_path_v2(sm->p_log,
847						    osm_physp_get_dr_path_ptr
848						    (p_physp), FILE_ID, OSM_LOG_ERROR);
849
850				state_mgr_get_remote_port_info(sm, p_physp);
851			}
852		}
853	}
854
855	cl_qmap_apply_func(&sm->p_subn->sm_guid_tbl, query_sm_info, sm);
856
857	CL_PLOCK_RELEASE(sm->p_lock);
858
859_exit:
860	OSM_LOG_EXIT(sm->p_log);
861	return status;
862}
863
864/**********************************************************************
865 * Go over all the remote SMs (as updated in the sm_guid_tbl).
866 * Find if there is a remote sm that is a master SM.
867 * If there is a remote master SM - return a pointer to it,
868 * else - return NULL.
869 **********************************************************************/
870static osm_remote_sm_t *state_mgr_exists_other_master_sm(IN osm_sm_t * sm)
871{
872	cl_qmap_t *p_sm_tbl;
873	osm_remote_sm_t *p_sm;
874	osm_remote_sm_t *p_sm_res = NULL;
875	osm_node_t *p_node;
876
877	OSM_LOG_ENTER(sm->p_log);
878
879	p_sm_tbl = &sm->p_subn->sm_guid_tbl;
880
881	/* go over all the remote SMs */
882	for (p_sm = (osm_remote_sm_t *) cl_qmap_head(p_sm_tbl);
883	     p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl);
884	     p_sm = (osm_remote_sm_t *) cl_qmap_next(&p_sm->map_item)) {
885		/* If the sm is in MASTER state - return a pointer to it */
886		p_node = osm_get_node_by_guid(sm->p_subn, p_sm->smi.guid);
887		if (ib_sminfo_get_state(&p_sm->smi) == IB_SMINFO_STATE_MASTER) {
888			OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
889				"Found remote master SM with guid:0x%016" PRIx64
890				" (node %s)\n", cl_ntoh64(p_sm->smi.guid),
891				p_node ? p_node->print_desc : "UNKNOWN");
892			p_sm_res = p_sm;
893			goto Exit;
894		}
895	}
896
897Exit:
898	OSM_LOG_EXIT(sm->p_log);
899	return p_sm_res;
900}
901
902/**********************************************************************
903 * Go over all remote SMs (as updated in the sm_guid_tbl).
904 * Find the one with the highest priority and lowest guid.
905 * Compare this SM to the local SM. If the local SM is higher -
906 * return NULL, if the remote SM is higher - return a pointer to it.
907 **********************************************************************/
908static osm_remote_sm_t *state_mgr_get_highest_sm(IN osm_sm_t * sm)
909{
910	cl_qmap_t *p_sm_tbl;
911	osm_remote_sm_t *p_sm = NULL;
912	osm_remote_sm_t *p_highest_sm;
913	uint8_t highest_sm_priority;
914	ib_net64_t highest_sm_guid;
915	osm_node_t *p_node;
916
917	OSM_LOG_ENTER(sm->p_log);
918
919	p_sm_tbl = &sm->p_subn->sm_guid_tbl;
920
921	/* Start with the local sm as the standard */
922	p_highest_sm = NULL;
923	highest_sm_priority = sm->p_subn->opt.sm_priority;
924	highest_sm_guid = sm->p_subn->sm_port_guid;
925
926	/* go over all the remote SMs */
927	for (p_sm = (osm_remote_sm_t *) cl_qmap_head(p_sm_tbl);
928	     p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl);
929	     p_sm = (osm_remote_sm_t *) cl_qmap_next(&p_sm->map_item)) {
930
931		/* If the sm is in NOTACTIVE state - continue */
932		if (ib_sminfo_get_state(&p_sm->smi) ==
933		    IB_SMINFO_STATE_NOTACTIVE)
934			continue;
935
936		if (osm_sm_is_greater_than(ib_sminfo_get_priority(&p_sm->smi),
937					   p_sm->smi.guid, highest_sm_priority,
938					   highest_sm_guid)) {
939			/* the new p_sm is with higher priority - update the highest_sm */
940			/* to this sm */
941			p_highest_sm = p_sm;
942			highest_sm_priority =
943			    ib_sminfo_get_priority(&p_sm->smi);
944			highest_sm_guid = p_sm->smi.guid;
945		}
946	}
947
948	if (p_highest_sm != NULL) {
949		p_node = osm_get_node_by_guid(sm->p_subn, p_highest_sm->smi.guid);
950		OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
951			"Found higher priority SM with guid: %016" PRIx64 " (node %s)\n",
952			cl_ntoh64(p_highest_sm->smi.guid),
953			p_node ? p_node->print_desc : "UNKNOWN");
954	}
955	OSM_LOG_EXIT(sm->p_log);
956	return p_highest_sm;
957}
958
959/**********************************************************************
960 * Send SubnSet(SMInfo) SMP with HANDOVER attribute to the
961 * remote_sm indicated.
962 **********************************************************************/
963static void state_mgr_send_handover(IN osm_sm_t * sm, IN osm_remote_sm_t * p_sm)
964{
965	uint8_t payload[IB_SMP_DATA_SIZE];
966	ib_sm_info_t *p_smi = (ib_sm_info_t *) payload;
967	osm_madw_context_t context;
968	const osm_port_t *p_port;
969	ib_api_status_t status;
970
971	OSM_LOG_ENTER(sm->p_log);
972
973	/*
974	 * Send a query of SubnSet(SMInfo) HANDOVER to the remote sm given.
975	 */
976
977	memset(&context, 0, sizeof(context));
978	p_port = osm_get_port_by_guid(sm->p_subn, p_sm->smi.guid);
979	if (p_port == NULL) {
980		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3316: "
981			"No port object on given remote_sm object\n");
982		goto Exit;
983	}
984
985	/* update the master_guid in the sm_state_mgr object according to */
986	/* the guid of the port where the new Master SM should reside. */
987	OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
988		"Handing over mastership. Updating sm_state_mgr master_guid: %016"
989		PRIx64 " (node %s)\n", cl_ntoh64(p_port->guid),
990		p_port->p_node ? p_port->p_node->print_desc : "UNKNOWN");
991	sm->master_sm_guid = p_port->guid;
992
993	context.smi_context.port_guid = p_port->guid;
994	context.smi_context.set_method = TRUE;
995
996	memset(payload, 0, sizeof(payload));
997	p_smi->guid = sm->p_subn->sm_port_guid;
998	p_smi->act_count = cl_hton32(sm->p_subn->p_osm->stats.qp0_mads_sent);
999	p_smi->pri_state = (uint8_t) (sm->p_subn->sm_state |
1000				      sm->p_subn->opt.sm_priority << 4);
1001	p_smi->sm_key = sm->p_subn->opt.sm_key;
1002
1003	CL_PLOCK_ACQUIRE(sm->p_lock);
1004	status = osm_req_set(sm, osm_physp_get_dr_path_ptr(p_port->p_physp),
1005			     payload, sizeof(payload), IB_MAD_ATTR_SM_INFO,
1006			     IB_SMINFO_ATTR_MOD_HANDOVER, FALSE,
1007			     ib_port_info_get_m_key(&p_port->p_physp->port_info),
1008			     CL_DISP_MSGID_NONE, &context);
1009	CL_PLOCK_RELEASE(sm->p_lock);
1010
1011	if (status != IB_SUCCESS)
1012		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3317: "
1013			"Failure requesting SMInfo (%s), remote SM at 0x%"
1014			PRIx64 " (node %s)\n",
1015			ib_get_err_str(status), cl_ntoh64(p_port->guid),
1016			p_port->p_node ? p_port->p_node->print_desc : "UNKNOWN");
1017
1018Exit:
1019	OSM_LOG_EXIT(sm->p_log);
1020}
1021
1022/**********************************************************************
1023 * Send Trap 64 on all new ports.
1024 **********************************************************************/
1025static void state_mgr_report_new_ports(IN osm_sm_t * sm)
1026{
1027	ib_gid_t port_gid;
1028	ib_mad_notice_attr_t notice;
1029	ib_api_status_t status;
1030	ib_net64_t port_guid;
1031	cl_map_item_t *p_next;
1032	osm_port_t *p_port;
1033	uint16_t min_lid_ho;
1034	uint16_t max_lid_ho;
1035
1036	OSM_LOG_ENTER(sm->p_log);
1037
1038	CL_PLOCK_ACQUIRE(sm->p_lock);
1039	p_next = cl_qmap_head(&sm->p_subn->port_guid_tbl);
1040	while (p_next != cl_qmap_end(&sm->p_subn->port_guid_tbl)) {
1041		p_port = (osm_port_t *) p_next;
1042		p_next = cl_qmap_next(p_next);
1043
1044		if (!p_port->is_new)
1045			continue;
1046
1047		port_guid = osm_port_get_guid(p_port);
1048		/* issue a notice - trap 64 (SM_GID_IN_SERVICE_TRAP) */
1049
1050		/* details of the notice */
1051		notice.generic_type = 0x80 | IB_NOTICE_TYPE_SUBN_MGMT;	/* is generic subn mgt type */
1052		ib_notice_set_prod_type_ho(&notice, 4);	/* A Class Manager generator */
1053		/* endport becomes reachable */
1054		notice.g_or_v.generic.trap_num = CL_HTON16(SM_GID_IN_SERVICE_TRAP); /* 64 */
1055		/* The sm_base_lid is saved in network order already. */
1056		notice.issuer_lid = sm->p_subn->sm_base_lid;
1057		/* following C14-72.1.1 and table 119 p739 */
1058		/* we need to provide the GID */
1059		port_gid.unicast.prefix = sm->p_subn->opt.subnet_prefix;
1060		port_gid.unicast.interface_id = port_guid;
1061		memcpy(&(notice.data_details.ntc_64_67.gid), &(port_gid),
1062		       sizeof(ib_gid_t));
1063
1064		/* According to page 653 - the issuer gid in this case of trap
1065		 * is the SM gid, since the SM is the initiator of this trap. */
1066		notice.issuer_gid.unicast.prefix =
1067		    sm->p_subn->opt.subnet_prefix;
1068		notice.issuer_gid.unicast.interface_id =
1069		    sm->p_subn->sm_port_guid;
1070
1071		status = osm_report_notice(sm->p_log, sm->p_subn, &notice);
1072		if (status != IB_SUCCESS)
1073			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3318: "
1074				"Error sending trap reports on GUID:0x%016"
1075				PRIx64 " (%s)\n", port_gid.unicast.interface_id,
1076				ib_get_err_str(status));
1077		osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho);
1078		OSM_LOG(sm->p_log, OSM_LOG_INFO,
1079			"Discovered new port with GUID:0x%016" PRIx64
1080			" LID range [%u,%u] of node: %s\n",
1081			cl_ntoh64(port_gid.unicast.interface_id),
1082			min_lid_ho, max_lid_ho,
1083			p_port->p_node ? p_port->p_node->
1084			print_desc : "UNKNOWN");
1085
1086		p_port->is_new = 0;
1087	}
1088	CL_PLOCK_RELEASE(sm->p_lock);
1089
1090	OSM_LOG_EXIT(sm->p_log);
1091}
1092
1093/**********************************************************************
1094 * Make sure that the lid_port_tbl of the subnet has only the ports
1095 * that are recognized, and in the correct lid place. There could be
1096 * errors if we wanted to assign a certain port with lid X, but that
1097 * request didn't reach the port. In this case port_lid_tbl will have
1098 * the port under lid X, though the port isn't updated with this lid.
1099 * We will run a new heavy sweep (since there were errors in the
1100 * initialization), but here we'll clean the database from incorrect
1101 * information.
1102 **********************************************************************/
1103static void state_mgr_check_tbl_consistency(IN osm_sm_t * sm)
1104{
1105	cl_qmap_t *p_port_guid_tbl;
1106	osm_port_t *p_port;
1107	osm_port_t *p_next_port;
1108	cl_ptr_vector_t *p_port_lid_tbl;
1109	size_t max_lid, ref_size, curr_size, lid;
1110	osm_port_t *p_port_ref, *p_port_stored;
1111	cl_ptr_vector_t ref_port_lid_tbl;
1112	uint16_t min_lid_ho;
1113	uint16_t max_lid_ho;
1114	uint16_t lid_ho;
1115
1116	OSM_LOG_ENTER(sm->p_log);
1117
1118	if (sm->lid_mgr.dirty == FALSE)
1119		goto Exit;
1120
1121	sm->lid_mgr.dirty = FALSE;
1122
1123	cl_ptr_vector_construct(&ref_port_lid_tbl);
1124	cl_ptr_vector_init(&ref_port_lid_tbl,
1125			   cl_ptr_vector_get_size(&sm->p_subn->port_lid_tbl),
1126			   OSM_SUBNET_VECTOR_GROW_SIZE);
1127
1128	p_port_guid_tbl = &sm->p_subn->port_guid_tbl;
1129
1130	/* Let's go over all the ports according to port_guid_tbl,
1131	 * and add the port to a reference port_lid_tbl. */
1132	p_next_port = (osm_port_t *) cl_qmap_head(p_port_guid_tbl);
1133	while (p_next_port != (osm_port_t *) cl_qmap_end(p_port_guid_tbl)) {
1134		p_port = p_next_port;
1135		p_next_port =
1136		    (osm_port_t *) cl_qmap_next(&p_next_port->map_item);
1137
1138		osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho);
1139		for (lid_ho = min_lid_ho; lid_ho <= max_lid_ho; lid_ho++)
1140			cl_ptr_vector_set(&ref_port_lid_tbl, lid_ho, p_port);
1141	}
1142
1143	p_port_lid_tbl = &sm->p_subn->port_lid_tbl;
1144
1145	ref_size = cl_ptr_vector_get_size(&ref_port_lid_tbl);
1146	curr_size = cl_ptr_vector_get_size(p_port_lid_tbl);
1147	/* They should be the same, but compare it anyway */
1148	max_lid = (ref_size > curr_size) ? ref_size : curr_size;
1149
1150	for (lid = 1; lid < max_lid; lid++) {
1151		p_port_ref = NULL;
1152		p_port_stored = NULL;
1153		cl_ptr_vector_at(p_port_lid_tbl, lid, (void *)&p_port_stored);
1154		cl_ptr_vector_at(&ref_port_lid_tbl, lid, (void *)&p_port_ref);
1155
1156		if (p_port_stored == p_port_ref)
1157			/* This is the "good" case - both entries are the
1158			 * same for this lid. Nothing to do. */
1159			continue;
1160
1161		if (p_port_ref == NULL) {
1162			/* There is an object in the subnet database for this
1163			 * lid, but no such object exists in the reference
1164			 * port_list_tbl. This can occur if we wanted to assign
1165			 * a certain port with some lid (different than the one
1166			 * pre-assigned to it), and the port didn't get the
1167			 * PortInfo Set request. Due to this, the port is
1168			 * updated with its original lid in our database
1169			 * rather than the new lid we wanted to give it. */
1170			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3322: "
1171				"lid %zu is wrongly assigned to port 0x%016"
1172				PRIx64 " (\'%s\' port %u) in port_lid_tbl\n",
1173				lid,
1174				cl_ntoh64(osm_port_get_guid(p_port_stored)),
1175				p_port_stored->p_node->print_desc,
1176				p_port_stored->p_physp->port_num);
1177		} else if (p_port_stored == NULL)
1178			/* There is an object in the new database, but no
1179			 * object in our subnet database. This is the matching
1180			 * case of the prior check - the port still has its
1181			 * original lid. */
1182			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3323: "
1183				"port 0x%016" PRIx64 " (\'%s\' port %u)"
1184				" exists in new port_lid_tbl under lid %zu,"
1185				" but missing in subnet port_lid_tbl db\n",
1186				cl_ntoh64(osm_port_get_guid(p_port_ref)),
1187				p_port_ref->p_node->print_desc,
1188				p_port_ref->p_physp->port_num, lid);
1189		else {
1190			/* if we reached here then p_port_stored != p_port_ref.
1191			 * We were trying to set a lid to p_port_stored, but
1192			 * it didn't reach it, and p_port_ref also didn't get
1193			 * the lid update. */
1194			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3324: "
1195				"lid %zu has port 0x%016" PRIx64
1196				" (\'%s\' port %u) in new port_lid_tbl db, "
1197				"and port 0x%016" PRIx64 " (\'%s\' port %u)"
1198				" in subnet port_lid_tbl db\n", lid,
1199				cl_ntoh64(osm_port_get_guid(p_port_ref)),
1200				p_port_ref->p_node->print_desc,
1201				p_port_ref->p_physp->port_num,
1202				cl_ntoh64(osm_port_get_guid(p_port_stored)),
1203				p_port_stored->p_node->print_desc,
1204				p_port_stored->p_physp->port_num);
1205		}
1206
1207		/*
1208		 * Clear the lid of the port in order to ignore it
1209		 *  in routing phase
1210		 */
1211		if (p_port_stored) {
1212			OSM_LOG(sm->p_log, OSM_LOG_INFO, "Clearing Lid for "
1213				"port 0x%016" PRIx64 "\n",
1214				cl_ntoh64(osm_port_get_guid(p_port_stored)));
1215			osm_port_clear_base_lid(p_port_stored);
1216			cl_ptr_vector_set(p_port_lid_tbl, lid, NULL);
1217		}
1218
1219		/* Make sure we'll do another heavy sweep. */
1220		sm->p_subn->subnet_initialization_error = TRUE;
1221	}
1222
1223	cl_ptr_vector_destroy(&ref_port_lid_tbl);
1224
1225Exit:
1226	OSM_LOG_EXIT(sm->p_log);
1227}
1228
1229static void check_switch_lft(cl_map_item_t * item, void *log)
1230{
1231	osm_switch_t *sw = (osm_switch_t *) item;
1232
1233	if (!sw->new_lft)
1234		return;
1235
1236	if (memcmp(sw->lft, sw->new_lft, sw->max_lid_ho + 1))
1237		osm_log_v2(log, OSM_LOG_ERROR, FILE_ID, "ERR 331D: "
1238			   "LFT of switch 0x%016" PRIx64 " (%s) is not up to date\n",
1239			   cl_ntoh64(sw->p_node->node_info.node_guid),
1240			   sw->p_node->print_desc);
1241}
1242
1243int wait_for_pending_transactions(osm_stats_t * stats)
1244{
1245#ifdef HAVE_LIBPTHREAD
1246	pthread_mutex_lock(&stats->mutex);
1247	while (stats->qp0_mads_outstanding && !osm_exit_flag)
1248		pthread_cond_wait(&stats->cond, &stats->mutex);
1249	pthread_mutex_unlock(&stats->mutex);
1250#else
1251	while (1) {
1252		unsigned count = stats->qp0_mads_outstanding;
1253		if (!count || osm_exit_flag)
1254			break;
1255		cl_event_wait_on(&stats->event, EVENT_NO_TIMEOUT, TRUE);
1256	}
1257#endif
1258	return osm_exit_flag;
1259}
1260
1261static void do_sweep(osm_sm_t * sm)
1262{
1263	ib_api_status_t status;
1264	osm_remote_sm_t *p_remote_sm;
1265	unsigned config_parsed = 0;
1266
1267	if (sm->p_subn->force_first_time_master_sweep) {
1268		sm->p_subn->force_heavy_sweep = TRUE;
1269		sm->p_subn->coming_out_of_standby = TRUE;
1270		sm->p_subn->first_time_master_sweep = TRUE;
1271		sm->p_subn->force_first_time_master_sweep = FALSE;
1272	}
1273
1274	/* after subnet initialization error, run heavy sweep */
1275	if (sm->p_subn->subnet_initialization_error)
1276		sm->p_subn->force_heavy_sweep = TRUE;
1277
1278	if (sm->p_subn->force_heavy_sweep) {
1279		if (osm_subn_rescan_conf_files(sm->p_subn) < 0)
1280			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 331A: "
1281				"osm_subn_rescan_conf_file failed\n");
1282		else
1283			config_parsed = 1;
1284	}
1285
1286	if (sm->p_subn->sm_state != IB_SMINFO_STATE_MASTER &&
1287	    sm->p_subn->sm_state != IB_SMINFO_STATE_DISCOVERING)
1288		return;
1289
1290	if (sm->p_subn->coming_out_of_standby) {
1291		/*
1292		 * Need to force re-write of sm_base_lid to all ports
1293		 * to do that we want all the ports to be considered
1294		 * foreign
1295		 */
1296		state_mgr_clean_known_lids(sm);
1297
1298		/*
1299		 * Need to clean SA cache when state changes to STANDBY
1300		 * after handover.
1301		 */
1302		state_mgr_sa_clean(sm);
1303
1304		/*
1305		 * Need to reconfigure LFTs, PKEYs, and QoS on all switches
1306		 * when coming out of STANDBY
1307		 */
1308		sm->p_subn->need_update = 1;
1309	}
1310
1311	sm->master_sm_found = 0;
1312
1313	/*
1314	 * If we already have switches, then try a light sweep.
1315	 * Otherwise, this is probably our first discovery pass
1316	 * or we are connected in loopback. In both cases do a
1317	 * heavy sweep.
1318	 * Note: If we are connected in loopback we want a heavy
1319	 * sweep, since we will not be getting any traps if there is
1320	 * a lost connection.
1321	 */
1322	/*  if we are in DISCOVERING state - this means it is either in
1323	 *  initializing or wake up from STANDBY - run the heavy sweep */
1324	if (cl_qmap_count(&sm->p_subn->sw_guid_tbl)
1325	    && sm->p_subn->sm_state != IB_SMINFO_STATE_DISCOVERING
1326	    && sm->p_subn->opt.force_heavy_sweep == FALSE
1327	    && sm->p_subn->force_heavy_sweep == FALSE
1328	    && sm->p_subn->force_reroute == FALSE
1329	    && sm->p_subn->subnet_initialization_error == FALSE
1330	    && (state_mgr_light_sweep_start(sm) == IB_SUCCESS)) {
1331		if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats))
1332			return;
1333		if (!sm->p_subn->force_heavy_sweep) {
1334			if (sm->p_subn->opt.sa_db_dump &&
1335			    !osm_sa_db_file_dump(sm->p_subn->p_osm))
1336				osm_opensm_report_event(sm->p_subn->p_osm,
1337							OSM_EVENT_ID_SA_DB_DUMPED,
1338							NULL);
1339			OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE,
1340					"LIGHT SWEEP COMPLETE");
1341			return;
1342		}
1343	}
1344
1345	/*
1346	 * Unicast cache should be invalidated when subnet re-route is
1347	 * requested, and when OpenSM comes out of standby state.
1348	 */
1349	if (sm->p_subn->opt.use_ucast_cache &&
1350	    (sm->p_subn->force_reroute || sm->p_subn->coming_out_of_standby))
1351		osm_ucast_cache_invalidate(&sm->ucast_mgr);
1352
1353	/*
1354	 * If we don't need to do a heavy sweep and we want to do a reroute,
1355	 * just reroute only.
1356	 */
1357	if (cl_qmap_count(&sm->p_subn->sw_guid_tbl)
1358	    && sm->p_subn->sm_state != IB_SMINFO_STATE_DISCOVERING
1359	    && sm->p_subn->opt.force_heavy_sweep == FALSE
1360	    && sm->p_subn->force_heavy_sweep == FALSE
1361	    && sm->p_subn->force_reroute == TRUE
1362	    && sm->p_subn->subnet_initialization_error == FALSE) {
1363		/* Reset flag */
1364		sm->p_subn->force_reroute = FALSE;
1365
1366		/* Re-program the switches fully */
1367		sm->p_subn->ignore_existing_lfts = TRUE;
1368
1369		if (osm_ucast_mgr_process(&sm->ucast_mgr)) {
1370			OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE,
1371					"REROUTE FAILED");
1372			return;
1373		}
1374		osm_qos_setup(sm->p_subn->p_osm);
1375
1376		/* Reset flag */
1377		sm->p_subn->ignore_existing_lfts = FALSE;
1378
1379		if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats))
1380			return;
1381
1382		osm_congestion_control_setup(sm->p_subn->p_osm);
1383
1384		if (osm_congestion_control_wait_pending_transactions(sm->p_subn->p_osm))
1385			return;
1386
1387		if (!sm->p_subn->subnet_initialization_error) {
1388			OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE,
1389					"REROUTE COMPLETE");
1390			osm_opensm_report_event(sm->p_subn->p_osm,
1391						OSM_EVENT_ID_UCAST_ROUTING_DONE,
1392						(void *) UCAST_ROUTING_REROUTE);
1393			return;
1394		}
1395	}
1396
1397	osm_opensm_report_event(sm->p_subn->p_osm,
1398				OSM_EVENT_ID_HEAVY_SWEEP_START, NULL);
1399
1400	/* go to heavy sweep */
1401repeat_discovery:
1402
1403	/* First of all - unset all flags */
1404	sm->p_subn->force_heavy_sweep = FALSE;
1405	sm->p_subn->force_reroute = FALSE;
1406	sm->p_subn->subnet_initialization_error = FALSE;
1407
1408	/* Reset tracking values in case limiting component got removed
1409	 * from fabric. */
1410	sm->p_subn->min_ca_mtu = IB_MAX_MTU;
1411	sm->p_subn->min_ca_rate = IB_PATH_RECORD_RATE_300_GBS;
1412	sm->p_subn->min_data_vls = IB_MAX_NUM_VLS - 1;
1413	sm->p_subn->min_sw_data_vls = IB_MAX_NUM_VLS - 1;
1414
1415	/* rescan configuration updates */
1416	if (!config_parsed && osm_subn_rescan_conf_files(sm->p_subn) < 0)
1417		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 331A: "
1418			"osm_subn_rescan_conf_file failed\n");
1419
1420	if (sm->p_subn->sm_state != IB_SMINFO_STATE_MASTER)
1421		sm->p_subn->need_update = 1;
1422
1423	status = state_mgr_sweep_hop_0(sm);
1424	if (status != IB_SUCCESS ||
1425	    wait_for_pending_transactions(&sm->p_subn->p_osm->stats))
1426		return;
1427
1428	if (state_mgr_is_sm_port_down(sm) == TRUE) {
1429		if (sm->p_subn->last_sm_port_state) {
1430			sm->p_subn->last_sm_port_state = 0;
1431			state_mgr_sa_clean(sm);
1432			osm_log_v2(sm->p_log, OSM_LOG_SYS, FILE_ID,
1433				   "SM port is down\n");
1434			OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE,
1435					"SM PORT DOWN");
1436		}
1437
1438		/* Run the drop manager - we want to clear all records */
1439		osm_drop_mgr_process(sm);
1440
1441		/* Move to DISCOVERING state */
1442		if (sm->p_subn->sm_state != IB_SMINFO_STATE_DISCOVERING)
1443			osm_sm_state_mgr_process(sm, OSM_SM_SIGNAL_DISCOVER);
1444		osm_opensm_report_event(sm->p_subn->p_osm,
1445					OSM_EVENT_ID_STATE_CHANGE, NULL);
1446		return;
1447	} else {
1448		if (!sm->p_subn->last_sm_port_state) {
1449			sm->p_subn->last_sm_port_state = 1;
1450			osm_log_v2(sm->p_log, OSM_LOG_SYS, FILE_ID,
1451				   "SM port is up\n");
1452			OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE,
1453					"SM PORT UP");
1454		}
1455	}
1456
1457	status = state_mgr_sweep_hop_1(sm);
1458	if (status != IB_SUCCESS ||
1459	    wait_for_pending_transactions(&sm->p_subn->p_osm->stats))
1460		return;
1461
1462	/* discovery completed - check other sm presence */
1463	if (sm->master_sm_found) {
1464		/*
1465		 * Call the sm_state_mgr with signal
1466		 * MASTER_OR_HIGHER_SM_DETECTED_DONE
1467		 */
1468		osm_sm_state_mgr_process(sm,
1469					 OSM_SM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED);
1470		OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE,
1471				"ENTERING STANDBY STATE");
1472		/* notify master SM about us */
1473		osm_send_trap144(sm, 0);
1474		osm_opensm_report_event(sm->p_subn->p_osm,
1475					OSM_EVENT_ID_STATE_CHANGE, NULL);
1476		return;
1477	}
1478
1479	/* if new sweep requested - don't bother with the rest */
1480	if (sm->p_subn->force_heavy_sweep) {
1481		config_parsed = 0;
1482		goto repeat_discovery;
1483	}
1484
1485	osm_opensm_report_event(sm->p_subn->p_osm,
1486				OSM_EVENT_ID_HEAVY_SWEEP_DONE, NULL);
1487
1488	OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, "HEAVY SWEEP COMPLETE");
1489
1490	osm_drop_mgr_process(sm);
1491
1492	/* If we are MASTER - get the highest remote_sm, and
1493	 * see if it is higher than our local sm.
1494	 */
1495	if (sm->p_subn->sm_state == IB_SMINFO_STATE_MASTER) {
1496		p_remote_sm = state_mgr_get_highest_sm(sm);
1497		if (p_remote_sm != NULL) {
1498			/* report new ports (trap 64) before leaving MASTER */
1499			state_mgr_report_new_ports(sm);
1500
1501			/* need to handover the mastership
1502			 * to the remote sm, and move to standby */
1503			state_mgr_send_handover(sm, p_remote_sm);
1504			osm_sm_state_mgr_process(sm,
1505						 OSM_SM_SIGNAL_HANDOVER_SENT);
1506			return;
1507		} else {
1508			/* We are the highest sm - check to see if there is
1509			 * a remote SM that is in master state. */
1510			p_remote_sm = state_mgr_exists_other_master_sm(sm);
1511			if (p_remote_sm != NULL) {
1512				/* There is a remote SM that is master.
1513				 * need to wait for that SM to relinquish control
1514				 * of its portion of the subnet. C14-60.2.1.
1515				 * Also - need to start polling on that SM. */
1516				CL_PLOCK_EXCL_ACQUIRE(sm->p_lock);
1517				sm->polling_sm_guid = p_remote_sm->smi.guid;
1518				CL_PLOCK_RELEASE(sm->p_lock);
1519				osm_sm_state_mgr_process(sm,
1520							 OSM_SM_SIGNAL_WAIT_FOR_HANDOVER);
1521				return;
1522			} else if (sm->polling_sm_guid) {
1523				/* Stop polling SM if it's not found */
1524				osm_sm_state_mgr_process(sm,
1525							 OSM_SM_SIGNAL_POLLING_TIMEOUT);
1526				return;
1527			}
1528		}
1529	}
1530
1531	/*
1532	 * If we are not MASTER already - this means that we are
1533	 * in discovery state. call osm_sm_state_mgr with signal
1534	 * DISCOVERY_COMPLETED
1535	 */
1536	if (sm->p_subn->sm_state == IB_SMINFO_STATE_DISCOVERING)
1537		osm_sm_state_mgr_process(sm, OSM_SM_SIGNAL_DISCOVERY_COMPLETED);
1538
1539	osm_reset_switch_state_change_bit(sm->p_subn->p_osm);
1540	if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats))
1541		return;
1542
1543	osm_pkey_mgr_process(sm->p_subn->p_osm);
1544
1545	/* try to restore SA DB (this should be before lid_mgr
1546	   because we may want to disable clients reregistration
1547	   when SA DB is restored) */
1548	osm_sa_db_file_load(sm->p_subn->p_osm);
1549
1550	if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats))
1551		return;
1552
1553	OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE,
1554			"PKEY setup completed - STARTING SM LID CONFIG");
1555
1556	osm_lid_mgr_process_sm(&sm->lid_mgr);
1557	if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats))
1558		return;
1559
1560	OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE,
1561			"SM LID ASSIGNMENT COMPLETE - STARTING SUBNET LID CONFIG");
1562	state_mgr_notify_lid_change(sm);
1563
1564	osm_lid_mgr_process_subnet(&sm->lid_mgr);
1565	if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats))
1566		return;
1567
1568	/* At this point we need to check the consistency of
1569	 * the port_lid_tbl under the subnet. There might be
1570	 * errors in it if PortInfo Set requests didn't reach
1571	 * their destination. */
1572	state_mgr_check_tbl_consistency(sm);
1573
1574	OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE,
1575			"LID ASSIGNMENT COMPLETE - STARTING SWITCH TABLE CONFIG");
1576
1577	/*
1578	 * Proceed with unicast forwarding table configuration; if it fails
1579	 * return early to wait for a trap or the next sweep interval.
1580	 */
1581
1582	if (!sm->ucast_mgr.cache_valid ||
1583	    osm_ucast_cache_process(&sm->ucast_mgr)) {
1584		if (osm_ucast_mgr_process(&sm->ucast_mgr)) {
1585			osm_ucast_cache_invalidate(&sm->ucast_mgr);
1586			return;
1587		}
1588	}
1589
1590	osm_qos_setup(sm->p_subn->p_osm);
1591
1592	if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats))
1593		return;
1594
1595	/* We are done setting all LFTs so clear the ignore existing.
1596	 * From now on, as long as we are still master, we want to
1597	 * take into account these lfts. */
1598	sm->p_subn->ignore_existing_lfts = FALSE;
1599
1600	OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE,
1601			"SWITCHES CONFIGURED FOR UNICAST");
1602	osm_opensm_report_event(sm->p_subn->p_osm,
1603				OSM_EVENT_ID_UCAST_ROUTING_DONE,
1604				(void *) UCAST_ROUTING_HEAVY_SWEEP);
1605
1606	if (!sm->p_subn->opt.disable_multicast) {
1607		osm_mcast_mgr_process(sm, TRUE);
1608		if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats))
1609			return;
1610		OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE,
1611				"SWITCHES CONFIGURED FOR MULTICAST");
1612	}
1613
1614	osm_guid_mgr_process(sm);
1615	if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats))
1616		return;
1617	OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, "ALIAS GUIDS CONFIGURED");
1618
1619	/*
1620	 * The LINK_PORTS state is required since we cannot count on
1621	 * the port state change MADs to succeed. This is an artifact
1622	 * of the spec defining state change from state X to state X
1623	 * as an error. The hardware then is not required to process
1624	 * other parameters provided by the Set(PortInfo) Packet.
1625	 */
1626
1627	osm_link_mgr_process(sm, IB_LINK_NO_CHANGE);
1628	if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats))
1629		return;
1630
1631	OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE,
1632			"LINKS PORTS CONFIGURED - SET LINKS TO ARMED STATE");
1633
1634	osm_link_mgr_process(sm, IB_LINK_ARMED);
1635	if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats))
1636		return;
1637
1638	OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE,
1639			"LINKS ARMED - SET LINKS TO ACTIVE STATE");
1640
1641	osm_link_mgr_process(sm, IB_LINK_ACTIVE);
1642	if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats))
1643		return;
1644
1645	/*
1646	 * The sweep completed!
1647	 */
1648
1649	/* Now do GSI configuration */
1650
1651	osm_congestion_control_setup(sm->p_subn->p_osm);
1652
1653	if (osm_congestion_control_wait_pending_transactions(sm->p_subn->p_osm))
1654		return;
1655
1656	/*
1657	 * Send trap 64 on newly discovered endports
1658	 */
1659	state_mgr_report_new_ports(sm);
1660
1661	/* check switch lft buffers assignments */
1662	cl_qmap_apply_func(&sm->p_subn->sw_guid_tbl, check_switch_lft,
1663			   sm->p_log);
1664
1665	/* in any case we zero this flag */
1666	sm->p_subn->coming_out_of_standby = FALSE;
1667	sm->p_subn->first_time_master_sweep = FALSE;
1668
1669	/* If there were errors - then the subnet is not really up */
1670	if (sm->p_subn->subnet_initialization_error == TRUE) {
1671		osm_log_v2(sm->p_log, OSM_LOG_SYS, FILE_ID,
1672			   "Errors during initialization\n");
1673		OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_ERROR,
1674				"ERRORS DURING INITIALIZATION");
1675	} else {
1676		sm->p_subn->need_update = 0;
1677		osm_dump_all(sm->p_subn->p_osm);
1678		state_mgr_up_msg(sm);
1679
1680		if ((OSM_LOG_IS_ACTIVE_V2(sm->p_log, OSM_LOG_VERBOSE) ||
1681		    sm->p_subn->opt.sa_db_dump) &&
1682		    !osm_sa_db_file_dump(sm->p_subn->p_osm))
1683			osm_opensm_report_event(sm->p_subn->p_osm,
1684						OSM_EVENT_ID_SA_DB_DUMPED,
1685						NULL);
1686	}
1687
1688	/*
1689	 * Finally signal the subnet up event
1690	 */
1691	cl_event_signal(&sm->subnet_up_event);
1692
1693	/* if we got a signal to force heavy sweep or errors
1694	 * in the middle of the sweep - try another sweep. */
1695	if (sm->p_subn->force_heavy_sweep)
1696		osm_sm_signal(sm, OSM_SIGNAL_SWEEP);
1697
1698	/* Write a new copy of our persistent guid2mkey database */
1699	osm_db_store(sm->p_subn->p_g2m, sm->p_subn->opt.fsync_high_avail_files);
1700	osm_db_store(sm->p_subn->p_neighbor,
1701		     sm->p_subn->opt.fsync_high_avail_files);
1702
1703	osm_opensm_report_event(sm->p_subn->p_osm, OSM_EVENT_ID_SUBNET_UP,
1704				NULL);
1705}
1706
1707static void do_process_mgrp_queue(osm_sm_t * sm)
1708{
1709	if (sm->p_subn->sm_state != IB_SMINFO_STATE_MASTER)
1710		return;
1711	if (!sm->p_subn->opt.disable_multicast) {
1712		osm_mcast_mgr_process(sm, FALSE);
1713		wait_for_pending_transactions(&sm->p_subn->p_osm->stats);
1714	}
1715}
1716
1717static void do_process_guid_queue(osm_sm_t *sm)
1718{
1719	osm_guid_mgr_process(sm);
1720	wait_for_pending_transactions(&sm->p_subn->p_osm->stats);
1721}
1722
1723void osm_state_mgr_process(IN osm_sm_t * sm, IN osm_signal_t signal)
1724{
1725	CL_ASSERT(sm);
1726
1727	OSM_LOG_ENTER(sm->p_log);
1728
1729	OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Received signal %s in state %s\n",
1730		osm_get_sm_signal_str(signal),
1731		osm_get_sm_mgr_state_str(sm->p_subn->sm_state));
1732
1733	switch (signal) {
1734	case OSM_SIGNAL_SWEEP:
1735		if (!sm->p_subn->sweeping_enabled) {
1736			OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "sweeping disabled - "
1737				"ignoring signal %s in state %s\n",
1738				osm_get_sm_signal_str(signal),
1739				osm_get_sm_mgr_state_str(sm->p_subn->sm_state));
1740		} else
1741			do_sweep(sm);
1742		break;
1743	case OSM_SIGNAL_IDLE_TIME_PROCESS_REQUEST:
1744		do_process_mgrp_queue(sm);
1745		break;
1746	case OSM_SIGNAL_GUID_PROCESS_REQUEST:
1747		do_process_guid_queue(sm);
1748		break;
1749	default:
1750		CL_ASSERT(FALSE);
1751		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3320: "
1752			"Invalid SM signal %u\n", signal);
1753		break;
1754	}
1755
1756	OSM_LOG_EXIT(sm->p_log);
1757}
1758