1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3219820Sjeff * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved.
4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5219820Sjeff *
6219820Sjeff * This software is available to you under a choice of one of two
7219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
8219820Sjeff * General Public License (GPL) Version 2, available from the file
9219820Sjeff * COPYING in the main directory of this source tree, or the
10219820Sjeff * OpenIB.org BSD license below:
11219820Sjeff *
12219820Sjeff *     Redistribution and use in source and binary forms, with or
13219820Sjeff *     without modification, are permitted provided that the following
14219820Sjeff *     conditions are met:
15219820Sjeff *
16219820Sjeff *      - Redistributions of source code must retain the above
17219820Sjeff *        copyright notice, this list of conditions and the following
18219820Sjeff *        disclaimer.
19219820Sjeff *
20219820Sjeff *      - Redistributions in binary form must reproduce the above
21219820Sjeff *        copyright notice, this list of conditions and the following
22219820Sjeff *        disclaimer in the documentation and/or other materials
23219820Sjeff *        provided with the distribution.
24219820Sjeff *
25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32219820Sjeff * SOFTWARE.
33219820Sjeff *
34219820Sjeff */
35219820Sjeff
36219820Sjeff/*
37219820Sjeff * Abstract:
38219820Sjeff *    Implementation of osm_lid_mgr_t.
39219820Sjeff * This file implements the LID Manager object which is responsible for
40219820Sjeff * assigning LIDs to all ports on the subnet.
41219820Sjeff *
42219820Sjeff * DATA STRUCTURES:
43219820Sjeff *  p_subn->port_lid_tbl : a vector pointing from lid to its port.
44219820Sjeff *  osm db guid2lid domain : a hash from guid to lid (min lid).
45219820Sjeff *  p_subn->port_guid_tbl : a map from guid to discovered port obj.
46219820Sjeff *
47219820Sjeff * ALGORITHM:
48219820Sjeff *
49219820Sjeff * 0. we define a function to obtain the correct port lid:
50219820Sjeff *    __osm_lid_mgr_get_port_lid( p_mgr, port, &min_lid ):
51219820Sjeff *    0.1 if the port info lid matches the guid2lid return 0
52219820Sjeff *    0.2 if the port info has a lid and that range is empty in
53219820Sjeff *        port_lid_tbl, return 0 and update the port_lid_tbl and
54219820Sjeff *        guid2lid
55219820Sjeff *    0.3 else find an empty space in port_lid_tbl, update the
56219820Sjeff *    port_lid_tbl and guid2lid, return 1 to flag a change required.
57219820Sjeff *
58219820Sjeff * 1. During initialization:
59219820Sjeff *   1.1 initialize the guid2lid database domain.
60219820Sjeff *   1.2 if reassign_lid is not set:
61219820Sjeff *   1.2.1 read the persistent data for the domain.
62219820Sjeff *   1.2.2 validate no duplicate use of lids and lids are 2^(lmc-1)
63219820Sjeff *
64219820Sjeff * 2. During SM port lid assignment:
65219820Sjeff *   2.1 if reassign_lids is set, make it 2^lmc
66219820Sjeff *   2.2 cleanup all port_lid_tbl and re-fill it according to guid2lid
67219820Sjeff *   2.3 call __osm_lid_mgr_get_port_lid the SM port
68219820Sjeff *   2.4 set the port info
69219820Sjeff *
70219820Sjeff * 3. During all other ports lid assignment:
71219820Sjeff *   3.1 go through all ports in the subnet
72219820Sjeff *   3.1.1 call __osm_lid_mgr_get_port_min_lid
73219820Sjeff *   3.1.2 if a change required send the port info
74219820Sjeff *   3.2 if any change send the signal PENDING...
75219820Sjeff *
76219820Sjeff * 4. Store the guid2lid
77219820Sjeff */
78219820Sjeff
79219820Sjeff#if HAVE_CONFIG_H
80219820Sjeff#  include <config.h>
81219820Sjeff#endif				/* HAVE_CONFIG_H */
82219820Sjeff
83219820Sjeff#include <stdlib.h>
84219820Sjeff#include <string.h>
85219820Sjeff#include <iba/ib_types.h>
86219820Sjeff#include <complib/cl_qmap.h>
87219820Sjeff#include <complib/cl_debug.h>
88219820Sjeff#include <opensm/osm_lid_mgr.h>
89219820Sjeff#include <opensm/osm_sm.h>
90219820Sjeff#include <opensm/osm_log.h>
91219820Sjeff#include <opensm/osm_node.h>
92219820Sjeff#include <opensm/osm_switch.h>
93219820Sjeff#include <opensm/osm_helper.h>
94219820Sjeff#include <opensm/osm_msgdef.h>
95219820Sjeff#include <vendor/osm_vendor_api.h>
96219820Sjeff#include <opensm/osm_db_pack.h>
97219820Sjeff
98219820Sjeff/**********************************************************************
99219820Sjeff  lid range item of qlist
100219820Sjeff **********************************************************************/
101219820Sjefftypedef struct osm_lid_mgr_range {
102219820Sjeff	cl_list_item_t item;
103219820Sjeff	uint16_t min_lid;
104219820Sjeff	uint16_t max_lid;
105219820Sjeff} osm_lid_mgr_range_t;
106219820Sjeff
107219820Sjeff/**********************************************************************
108219820Sjeff **********************************************************************/
109219820Sjeffvoid osm_lid_mgr_construct(IN osm_lid_mgr_t * const p_mgr)
110219820Sjeff{
111219820Sjeff	memset(p_mgr, 0, sizeof(*p_mgr));
112219820Sjeff	cl_ptr_vector_construct(&p_mgr->used_lids);
113219820Sjeff}
114219820Sjeff
115219820Sjeff/**********************************************************************
116219820Sjeff **********************************************************************/
117219820Sjeffvoid osm_lid_mgr_destroy(IN osm_lid_mgr_t * const p_mgr)
118219820Sjeff{
119219820Sjeff	cl_list_item_t *p_item;
120219820Sjeff
121219820Sjeff	OSM_LOG_ENTER(p_mgr->p_log);
122219820Sjeff
123219820Sjeff	cl_ptr_vector_destroy(&p_mgr->used_lids);
124219820Sjeff	p_item = cl_qlist_remove_head(&p_mgr->free_ranges);
125219820Sjeff	while (p_item != cl_qlist_end(&p_mgr->free_ranges)) {
126219820Sjeff		free((osm_lid_mgr_range_t *) p_item);
127219820Sjeff		p_item = cl_qlist_remove_head(&p_mgr->free_ranges);
128219820Sjeff	}
129219820Sjeff	OSM_LOG_EXIT(p_mgr->p_log);
130219820Sjeff}
131219820Sjeff
132219820Sjeff/**********************************************************************
133219820SjeffValidate the guid to lid data by making sure that under the current
134219820SjeffLMC we did not get duplicates. If we do flag them as errors and remove
135219820Sjeffthe entry.
136219820Sjeff**********************************************************************/
137219820Sjeffstatic void __osm_lid_mgr_validate_db(IN osm_lid_mgr_t * p_mgr)
138219820Sjeff{
139219820Sjeff	cl_qlist_t guids;
140219820Sjeff	osm_db_guid_elem_t *p_item;
141219820Sjeff	uint16_t lid;
142219820Sjeff	uint16_t min_lid;
143219820Sjeff	uint16_t max_lid;
144219820Sjeff	uint16_t lmc_mask;
145219820Sjeff	boolean_t lids_ok;
146219820Sjeff
147219820Sjeff	OSM_LOG_ENTER(p_mgr->p_log);
148219820Sjeff
149219820Sjeff	if (p_mgr->p_subn->opt.lmc)
150219820Sjeff		lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
151219820Sjeff	else
152219820Sjeff		lmc_mask = 0xffff;
153219820Sjeff
154219820Sjeff	cl_qlist_init(&guids);
155219820Sjeff
156219820Sjeff	if (osm_db_guid2lid_guids(p_mgr->p_g2l, &guids)) {
157219820Sjeff		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0310: "
158219820Sjeff			"could not get guid list\n");
159219820Sjeff		goto Exit;
160219820Sjeff	}
161219820Sjeff
162219820Sjeff	p_item = (osm_db_guid_elem_t *) cl_qlist_remove_head(&guids);
163219820Sjeff	while ((cl_list_item_t *) p_item != cl_qlist_end(&guids)) {
164219820Sjeff		if (osm_db_guid2lid_get
165219820Sjeff		    (p_mgr->p_g2l, p_item->guid, &min_lid, &max_lid))
166219820Sjeff			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0311: "
167219820Sjeff				"could not get lid for guid:0x%016" PRIx64 "\n",
168219820Sjeff				p_item->guid);
169219820Sjeff		else {
170219820Sjeff			lids_ok = TRUE;
171219820Sjeff
172219820Sjeff			if ((min_lid > max_lid) || (min_lid == 0)
173219820Sjeff			    || (p_item->guid == 0)
174219820Sjeff			    || (max_lid > p_mgr->p_subn->max_ucast_lid_ho)) {
175219820Sjeff				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0312: "
176219820Sjeff					"Illegal LID range [%u:%u] for "
177219820Sjeff					"guid:0x%016" PRIx64 "\n", min_lid,
178219820Sjeff					max_lid, p_item->guid);
179219820Sjeff				lids_ok = FALSE;
180219820Sjeff			} else if ((min_lid != max_lid)
181219820Sjeff				   && ((min_lid & lmc_mask) != min_lid)) {
182219820Sjeff				/* check that if the lids define a range that is valid
183219820Sjeff				   for the current LMC mask */
184219820Sjeff				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0313: "
185219820Sjeff					"LID range [%u:%u] for guid:0x%016"
186219820Sjeff					PRIx64
187219820Sjeff					" is not aligned according to mask:0x%04x\n",
188219820Sjeff					min_lid, max_lid, p_item->guid,
189219820Sjeff					lmc_mask);
190219820Sjeff				lids_ok = FALSE;
191219820Sjeff			} else {
192219820Sjeff				/* check if the lids were not previously assigned */
193219820Sjeff				for (lid = min_lid; lid <= max_lid; lid++) {
194219820Sjeff					if ((cl_ptr_vector_get_size
195219820Sjeff					     (&p_mgr->used_lids) > lid)
196219820Sjeff					    &&
197219820Sjeff					    (cl_ptr_vector_get
198219820Sjeff					     (&p_mgr->used_lids, lid))) {
199219820Sjeff						OSM_LOG(p_mgr->p_log,
200219820Sjeff							OSM_LOG_ERROR, "ERR 0314: "
201219820Sjeff							"0x%04x for guid:0x%016"
202219820Sjeff							PRIx64
203219820Sjeff							" was previously used\n",
204219820Sjeff							lid, p_item->guid);
205219820Sjeff						lids_ok = FALSE;
206219820Sjeff					}
207219820Sjeff				}
208219820Sjeff			}
209219820Sjeff
210219820Sjeff			if (!lids_ok) {
211219820Sjeff				if (osm_db_guid2lid_delete
212219820Sjeff				    (p_mgr->p_g2l, p_item->guid))
213219820Sjeff					OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
214219820Sjeff						"ERR 0315: "
215219820Sjeff						"failed to delete entry for "
216219820Sjeff						"guid:0x%016" PRIx64 "\n",
217219820Sjeff						p_item->guid);
218219820Sjeff			} else {
219219820Sjeff				/* mark it was visited */
220219820Sjeff				for (lid = min_lid; lid <= max_lid; lid++)
221219820Sjeff					cl_ptr_vector_set(&p_mgr->used_lids,
222219820Sjeff							  lid, (void *)1);
223219820Sjeff			}
224219820Sjeff		}		/* got a lid */
225219820Sjeff		free(p_item);
226219820Sjeff		p_item = (osm_db_guid_elem_t *) cl_qlist_remove_head(&guids);
227219820Sjeff	}			/* all guids */
228219820SjeffExit:
229219820Sjeff	OSM_LOG_EXIT(p_mgr->p_log);
230219820Sjeff}
231219820Sjeff
232219820Sjeff/**********************************************************************
233219820Sjeff **********************************************************************/
234219820Sjeffib_api_status_t
235219820Sjeffosm_lid_mgr_init(IN osm_lid_mgr_t * const p_mgr, IN osm_sm_t *sm)
236219820Sjeff{
237219820Sjeff	ib_api_status_t status = IB_SUCCESS;
238219820Sjeff
239219820Sjeff	OSM_LOG_ENTER(sm->p_log);
240219820Sjeff
241219820Sjeff	osm_lid_mgr_construct(p_mgr);
242219820Sjeff
243219820Sjeff	p_mgr->sm = sm;
244219820Sjeff	p_mgr->p_log = sm->p_log;
245219820Sjeff	p_mgr->p_subn = sm->p_subn;
246219820Sjeff	p_mgr->p_db = sm->p_db;
247219820Sjeff	p_mgr->p_lock = sm->p_lock;
248219820Sjeff
249219820Sjeff	/* we initialize and restore the db domain of guid to lid map */
250219820Sjeff	p_mgr->p_g2l = osm_db_domain_init(p_mgr->p_db, "/guid2lid");
251219820Sjeff	if (!p_mgr->p_g2l) {
252219820Sjeff		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0316: "
253219820Sjeff			"Error initializing Guid-to-Lid persistent database\n");
254219820Sjeff		status = IB_ERROR;
255219820Sjeff		goto Exit;
256219820Sjeff	}
257219820Sjeff
258219820Sjeff	cl_ptr_vector_init(&p_mgr->used_lids, 100, 40);
259219820Sjeff	cl_qlist_init(&p_mgr->free_ranges);
260219820Sjeff
261219820Sjeff	/* we use the stored guid to lid table if not forced to reassign */
262219820Sjeff	if (!p_mgr->p_subn->opt.reassign_lids) {
263219820Sjeff		if (osm_db_restore(p_mgr->p_g2l)) {
264219820Sjeff#ifndef __WIN__
265219820Sjeff			/*
266219820Sjeff			 * When Windows is BSODing, it might corrupt files that
267219820Sjeff			 * were previously opened for writing, even if the files
268219820Sjeff			 * are closed, so we might see corrupted guid2lid file.
269219820Sjeff			 */
270219820Sjeff			if (p_mgr->p_subn->opt.exit_on_fatal) {
271219820Sjeff				osm_log(p_mgr->p_log, OSM_LOG_SYS,
272219820Sjeff					"FATAL: Error restoring Guid-to-Lid "
273219820Sjeff					"persistent database\n");
274219820Sjeff				status = IB_ERROR;
275219820Sjeff				goto Exit;
276219820Sjeff			} else
277219820Sjeff#endif
278219820Sjeff				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
279219820Sjeff					"ERR 0317: Error restoring Guid-to-Lid "
280219820Sjeff					"persistent database\n");
281219820Sjeff		}
282219820Sjeff
283219820Sjeff		/* we need to make sure we did not get duplicates with
284219820Sjeff		   current lmc */
285219820Sjeff		__osm_lid_mgr_validate_db(p_mgr);
286219820Sjeff	}
287219820Sjeff
288219820SjeffExit:
289219820Sjeff	OSM_LOG_EXIT(p_mgr->p_log);
290219820Sjeff	return (status);
291219820Sjeff}
292219820Sjeff
293219820Sjeffstatic uint16_t __osm_trim_lid(IN uint16_t lid)
294219820Sjeff{
295219820Sjeff	if ((lid > IB_LID_UCAST_END_HO) || (lid < IB_LID_UCAST_START_HO))
296219820Sjeff		return 0;
297219820Sjeff	return lid;
298219820Sjeff}
299219820Sjeff
300219820Sjeff/**********************************************************************
301219820Sjeff initialize the manager for a new sweep:
302219820Sjeff scans the known persistent assignment and port_lid_tbl
303219820Sjeff re-calculate all empty ranges.
304219820Sjeff cleanup invalid port_lid_tbl entries
305219820Sjeff**********************************************************************/
306219820Sjeffstatic int __osm_lid_mgr_init_sweep(IN osm_lid_mgr_t * const p_mgr)
307219820Sjeff{
308219820Sjeff	cl_ptr_vector_t *p_discovered_vec = &p_mgr->p_subn->port_lid_tbl;
309219820Sjeff	cl_ptr_vector_t *p_persistent_vec = &p_mgr->used_lids;
310219820Sjeff	uint16_t max_defined_lid;
311219820Sjeff	uint16_t max_persistent_lid;
312219820Sjeff	uint16_t max_discovered_lid;
313219820Sjeff	uint16_t lid;
314219820Sjeff	uint16_t disc_min_lid;
315219820Sjeff	uint16_t disc_max_lid;
316219820Sjeff	uint16_t db_min_lid;
317219820Sjeff	uint16_t db_max_lid;
318219820Sjeff	int status = 0;
319219820Sjeff	cl_list_item_t *p_item;
320219820Sjeff	boolean_t is_free;
321219820Sjeff	osm_lid_mgr_range_t *p_range = NULL;
322219820Sjeff	osm_port_t *p_port;
323219820Sjeff	cl_qmap_t *p_port_guid_tbl;
324219820Sjeff	uint8_t lmc_num_lids = (uint8_t) (1 << p_mgr->p_subn->opt.lmc);
325219820Sjeff	uint16_t lmc_mask;
326219820Sjeff	uint16_t req_lid, num_lids;
327219820Sjeff
328219820Sjeff	OSM_LOG_ENTER(p_mgr->p_log);
329219820Sjeff
330219820Sjeff	if (p_mgr->p_subn->opt.lmc)
331219820Sjeff		lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
332219820Sjeff	else
333219820Sjeff		lmc_mask = 0xffff;
334219820Sjeff
335219820Sjeff	/* if we came out of standby we need to discard any previous guid2lid
336219820Sjeff	   info we might have.
337219820Sjeff	   Do this only if the honor_guid2lid_file option is FALSE. If not, then
338219820Sjeff	   need to honor this file. */
339219820Sjeff	if (p_mgr->p_subn->coming_out_of_standby == TRUE) {
340219820Sjeff		if (p_mgr->p_subn->opt.honor_guid2lid_file == FALSE) {
341219820Sjeff			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
342219820Sjeff				"Ignore guid2lid file when coming out of standby\n");
343219820Sjeff			osm_db_clear(p_mgr->p_g2l);
344219820Sjeff			for (lid = 0;
345219820Sjeff			     lid < cl_ptr_vector_get_size(&p_mgr->used_lids);
346219820Sjeff			     lid++)
347219820Sjeff				cl_ptr_vector_set(p_persistent_vec, lid, NULL);
348219820Sjeff		} else {
349219820Sjeff			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
350219820Sjeff				"Honor current guid2lid file when coming out "
351219820Sjeff				"of standby\n");
352219820Sjeff			osm_db_clear(p_mgr->p_g2l);
353219820Sjeff			if (osm_db_restore(p_mgr->p_g2l))
354219820Sjeff				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0306: "
355219820Sjeff					"Error restoring Guid-to-Lid "
356219820Sjeff					"persistent database. Ignoring it\n");
357219820Sjeff		}
358219820Sjeff	}
359219820Sjeff
360219820Sjeff	/* we need to cleanup the empty ranges list */
361219820Sjeff	p_item = cl_qlist_remove_head(&p_mgr->free_ranges);
362219820Sjeff	while (p_item != cl_qlist_end(&p_mgr->free_ranges)) {
363219820Sjeff		free((osm_lid_mgr_range_t *) p_item);
364219820Sjeff		p_item = cl_qlist_remove_head(&p_mgr->free_ranges);
365219820Sjeff	}
366219820Sjeff
367219820Sjeff	/* first clean up the port_by_lid_tbl */
368219820Sjeff	for (lid = 0; lid < cl_ptr_vector_get_size(p_discovered_vec); lid++)
369219820Sjeff		cl_ptr_vector_set(p_discovered_vec, lid, NULL);
370219820Sjeff
371219820Sjeff	/* we if are in the first sweep and in reassign lids mode
372219820Sjeff	   we should ignore all the available info and simply define one
373219820Sjeff	   huge empty range */
374219820Sjeff	if ((p_mgr->p_subn->first_time_master_sweep == TRUE) &&
375219820Sjeff	    (p_mgr->p_subn->opt.reassign_lids == TRUE)) {
376219820Sjeff		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
377219820Sjeff			"Skipping all lids as we are reassigning them\n");
378219820Sjeff		p_range =
379219820Sjeff		    (osm_lid_mgr_range_t *) malloc(sizeof(osm_lid_mgr_range_t));
380219820Sjeff		if (p_range)
381219820Sjeff			p_range->min_lid = 1;
382219820Sjeff		goto AfterScanningLids;
383219820Sjeff	}
384219820Sjeff
385219820Sjeff	/* go over all discovered ports and mark their entries */
386219820Sjeff	p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl;
387219820Sjeff
388219820Sjeff	for (p_port = (osm_port_t *) cl_qmap_head(p_port_guid_tbl);
389219820Sjeff	     p_port != (osm_port_t *) cl_qmap_end(p_port_guid_tbl);
390219820Sjeff	     p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) {
391219820Sjeff		osm_port_get_lid_range_ho(p_port, &disc_min_lid, &disc_max_lid);
392219820Sjeff		disc_min_lid = __osm_trim_lid(disc_min_lid);
393219820Sjeff		disc_max_lid = __osm_trim_lid(disc_max_lid);
394219820Sjeff		for (lid = disc_min_lid; lid <= disc_max_lid; lid++)
395219820Sjeff			cl_ptr_vector_set(p_discovered_vec, lid, p_port);
396219820Sjeff		/* make sure the guid2lid entry is valid. If not, clean it. */
397219820Sjeff		if (!osm_db_guid2lid_get(p_mgr->p_g2l,
398219820Sjeff					 cl_ntoh64(osm_port_get_guid(p_port)),
399219820Sjeff					 &db_min_lid, &db_max_lid)) {
400219820Sjeff			if (!p_port->p_node->sw ||
401219820Sjeff			    osm_switch_sp0_is_lmc_capable(p_port->p_node->sw,
402219820Sjeff							  p_mgr->p_subn))
403219820Sjeff				num_lids = lmc_num_lids;
404219820Sjeff			else
405219820Sjeff				num_lids = 1;
406219820Sjeff
407219820Sjeff			if ((num_lids != 1) &&
408219820Sjeff			    (((db_min_lid & lmc_mask) != db_min_lid) ||
409219820Sjeff			     (db_max_lid - db_min_lid + 1 < num_lids))) {
410219820Sjeff				/* Not aligned, or not wide enough, then remove the entry */
411219820Sjeff				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
412219820Sjeff					"Cleaning persistent entry for guid:"
413219820Sjeff					"0x%016" PRIx64 " illegal range:"
414219820Sjeff					"[0x%x:0x%x]\n",
415219820Sjeff					cl_ntoh64(osm_port_get_guid(p_port)),
416219820Sjeff					db_min_lid, db_max_lid);
417219820Sjeff				osm_db_guid2lid_delete(p_mgr->p_g2l,
418219820Sjeff						       cl_ntoh64
419219820Sjeff						       (osm_port_get_guid
420219820Sjeff							(p_port)));
421219820Sjeff				for (lid = db_min_lid; lid <= db_max_lid; lid++)
422219820Sjeff					cl_ptr_vector_set(p_persistent_vec, lid,
423219820Sjeff							  NULL);
424219820Sjeff			}
425219820Sjeff		}
426219820Sjeff	}
427219820Sjeff
428219820Sjeff	/*
429219820Sjeff	   Our task is to find free lid ranges.
430219820Sjeff	   A lid can be used if
431219820Sjeff	   1. a persistent assignment exists
432219820Sjeff	   2. the lid is used by a discovered port that does not have a persistent
433219820Sjeff	   assignment.
434219820Sjeff
435219820Sjeff	   scan through all lid values of both the persistent table and
436219820Sjeff	   discovered table.
437219820Sjeff	   If the lid has an assigned port in the discovered table:
438219820Sjeff	   * make sure the lid matches the persistent table, or
439219820Sjeff	   * there is no other persistent assignment for that lid.
440219820Sjeff	   * else cleanup the port_by_lid_tbl, mark this as empty range.
441219820Sjeff	   Else if the lid does not have an entry in the persistent table
442219820Sjeff	   mark it as free.
443219820Sjeff	 */
444219820Sjeff
445219820Sjeff	/* find the range of lids to scan */
446219820Sjeff	max_discovered_lid =
447219820Sjeff	    (uint16_t) cl_ptr_vector_get_size(p_discovered_vec);
448219820Sjeff	max_persistent_lid =
449219820Sjeff	    (uint16_t) cl_ptr_vector_get_size(p_persistent_vec);
450219820Sjeff
451219820Sjeff	/* but the vectors have one extra entry for lid=0 */
452219820Sjeff	if (max_discovered_lid)
453219820Sjeff		max_discovered_lid--;
454219820Sjeff	if (max_persistent_lid)
455219820Sjeff		max_persistent_lid--;
456219820Sjeff
457219820Sjeff	if (max_persistent_lid > max_discovered_lid)
458219820Sjeff		max_defined_lid = max_persistent_lid;
459219820Sjeff	else
460219820Sjeff		max_defined_lid = max_discovered_lid;
461219820Sjeff
462219820Sjeff	for (lid = 1; lid <= max_defined_lid; lid++) {
463219820Sjeff		is_free = TRUE;
464219820Sjeff		/* first check to see if the lid is used by a persistent assignment */
465219820Sjeff		if ((lid <= max_persistent_lid)
466219820Sjeff		    && cl_ptr_vector_get(p_persistent_vec, lid)) {
467219820Sjeff			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
468219820Sjeff				"0x%04x is not free as its mapped by the "
469219820Sjeff				"persistent db\n", lid);
470219820Sjeff			is_free = FALSE;
471219820Sjeff		} else {
472219820Sjeff			/* check this is a discovered port */
473219820Sjeff			if (lid <= max_discovered_lid
474219820Sjeff			    && (p_port = (osm_port_t *)
475219820Sjeff				cl_ptr_vector_get(p_discovered_vec, lid))) {
476219820Sjeff				/* we have a port. Now lets see if we can preserve its lid range. */
477219820Sjeff				/* For that, we need to make sure:
478219820Sjeff				   1. The port has a (legal) persistency entry. Then the local lid
479219820Sjeff				   is free (we will use the persistency value).
480219820Sjeff				   2. Can the port keep its local assignment?
481219820Sjeff				   a. Make sure the lid a aligned.
482219820Sjeff				   b. Make sure all needed lids (for the lmc) are free according
483219820Sjeff				   to persistency table.
484219820Sjeff				 */
485219820Sjeff				/* qualify the guid of the port is not persistently mapped to
486219820Sjeff				   another range */
487219820Sjeff				if (!osm_db_guid2lid_get(p_mgr->p_g2l,
488219820Sjeff							 cl_ntoh64
489219820Sjeff							 (osm_port_get_guid
490219820Sjeff							  (p_port)),
491219820Sjeff							 &db_min_lid,
492219820Sjeff							 &db_max_lid)) {
493219820Sjeff					OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
494219820Sjeff						"0x%04x is free as it was "
495219820Sjeff						"discovered but mapped by the "
496219820Sjeff						"persistent db to [0x%04x:0x%04x]\n",
497219820Sjeff						lid, db_min_lid, db_max_lid);
498219820Sjeff				} else {
499219820Sjeff					/* can the port keep its assignment ? */
500219820Sjeff					/* get the lid range of that port, and the required number
501219820Sjeff					   of lids we are about to assign to it */
502219820Sjeff					osm_port_get_lid_range_ho(p_port,
503219820Sjeff								  &disc_min_lid,
504219820Sjeff								  &disc_max_lid);
505219820Sjeff					if (!p_port->p_node->sw
506219820Sjeff					    ||
507219820Sjeff					    osm_switch_sp0_is_lmc_capable
508219820Sjeff					    (p_port->p_node->sw,
509219820Sjeff					     p_mgr->p_subn)) {
510219820Sjeff						disc_max_lid =
511219820Sjeff						    disc_min_lid +
512219820Sjeff						    lmc_num_lids - 1;
513219820Sjeff						num_lids = lmc_num_lids;
514219820Sjeff					} else
515219820Sjeff						num_lids = 1;
516219820Sjeff
517219820Sjeff					/* Make sure the lid is aligned */
518219820Sjeff					if ((num_lids != 1)
519219820Sjeff					    && ((disc_min_lid & lmc_mask) !=
520219820Sjeff						disc_min_lid)) {
521219820Sjeff						/* The lid cannot be used */
522219820Sjeff						OSM_LOG(p_mgr->p_log,
523219820Sjeff							OSM_LOG_DEBUG,
524219820Sjeff							"0x%04x is free as it was "
525219820Sjeff							"discovered but not aligned\n",
526219820Sjeff							lid);
527219820Sjeff					} else {
528219820Sjeff						/* check that all needed lids are not persistently mapped */
529219820Sjeff						is_free = FALSE;
530219820Sjeff						for (req_lid = disc_min_lid + 1;
531219820Sjeff						     req_lid <= disc_max_lid;
532219820Sjeff						     req_lid++) {
533219820Sjeff							if ((req_lid <=
534219820Sjeff							     max_persistent_lid)
535219820Sjeff							    &&
536219820Sjeff							    cl_ptr_vector_get
537219820Sjeff							    (p_persistent_vec,
538219820Sjeff							     req_lid)) {
539219820Sjeff								OSM_LOG(p_mgr->
540219820Sjeff									p_log,
541219820Sjeff									OSM_LOG_DEBUG,
542219820Sjeff									"0x%04x is free as it was discovered "
543219820Sjeff									"but mapped\n",
544219820Sjeff									lid);
545219820Sjeff								is_free = TRUE;
546219820Sjeff								break;
547219820Sjeff							}
548219820Sjeff						}
549219820Sjeff
550219820Sjeff						if (is_free == FALSE) {
551219820Sjeff							/* This port will use its local lid, and consume the entire required lid range.
552219820Sjeff							   Thus we can skip that range. */
553219820Sjeff							/* If the disc_max_lid is greater then lid, we can skip right to it,
554219820Sjeff							   since we've done all neccessary checks on the lids in between. */
555219820Sjeff							if (disc_max_lid > lid)
556219820Sjeff								lid =
557219820Sjeff								    disc_max_lid;
558219820Sjeff						}
559219820Sjeff					}
560219820Sjeff				}
561219820Sjeff			}
562219820Sjeff		}
563219820Sjeff
564219820Sjeff		if (is_free) {
565219820Sjeff			if (p_range)
566219820Sjeff				p_range->max_lid = lid;
567219820Sjeff			else {
568219820Sjeff				p_range = (osm_lid_mgr_range_t *)
569219820Sjeff				    malloc(sizeof(osm_lid_mgr_range_t));
570219820Sjeff				if (p_range) {
571219820Sjeff					p_range->min_lid = lid;
572219820Sjeff					p_range->max_lid = lid;
573219820Sjeff				}
574219820Sjeff			}
575219820Sjeff		} else {
576219820Sjeff			/* this lid is used so we need to finalize the previous free range */
577219820Sjeff			if (p_range) {
578219820Sjeff				cl_qlist_insert_tail(&p_mgr->free_ranges,
579219820Sjeff						     &p_range->item);
580219820Sjeff				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
581219820Sjeff					"new free lid range [%u:%u]\n",
582219820Sjeff					p_range->min_lid, p_range->max_lid);
583219820Sjeff				p_range = NULL;
584219820Sjeff			}
585219820Sjeff		}
586219820Sjeff	}
587219820Sjeff
588219820SjeffAfterScanningLids:
589219820Sjeff	/* after scanning all known lids we need to extend the last range
590219820Sjeff	   to the max allowed lid */
591219820Sjeff	if (!p_range) {
592219820Sjeff		p_range =
593219820Sjeff		    (osm_lid_mgr_range_t *) malloc(sizeof(osm_lid_mgr_range_t));
594219820Sjeff		/*
595219820Sjeff		   The p_range can be NULL in one of 2 cases:
596219820Sjeff		   1. If max_defined_lid == 0. In this case, we want the
597219820Sjeff		   entire range.
598219820Sjeff		   2. If all lids discovered in the loop where mapped. In this
599219820Sjeff		   case, no free range exists and we want to define it after the
600219820Sjeff		   last mapped lid.
601219820Sjeff		 */
602219820Sjeff		if (p_range)
603219820Sjeff			p_range->min_lid = lid;
604219820Sjeff	}
605219820Sjeff	if (p_range) {
606219820Sjeff		p_range->max_lid = p_mgr->p_subn->max_ucast_lid_ho;
607219820Sjeff		cl_qlist_insert_tail(&p_mgr->free_ranges, &p_range->item);
608219820Sjeff		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
609219820Sjeff			"final free lid range [%u:%u]\n",
610219820Sjeff			p_range->min_lid, p_range->max_lid);
611219820Sjeff	}
612219820Sjeff
613219820Sjeff	OSM_LOG_EXIT(p_mgr->p_log);
614219820Sjeff	return status;
615219820Sjeff}
616219820Sjeff
617219820Sjeff/**********************************************************************
618219820Sjeff check if the given range of lids is free
619219820Sjeff**********************************************************************/
620219820Sjeffstatic boolean_t
621219820Sjeff__osm_lid_mgr_is_range_not_persistent(IN osm_lid_mgr_t * const p_mgr,
622219820Sjeff				      IN const uint16_t lid,
623219820Sjeff				      IN const uint16_t num_lids)
624219820Sjeff{
625219820Sjeff	uint16_t i;
626219820Sjeff	cl_status_t status;
627219820Sjeff	osm_port_t *p_port;
628219820Sjeff	const uint8_t start_lid = (uint8_t) (1 << p_mgr->p_subn->opt.lmc);
629219820Sjeff	const cl_ptr_vector_t *const p_tbl = &p_mgr->used_lids;
630219820Sjeff
631219820Sjeff	if (lid < start_lid)
632219820Sjeff		return (FALSE);
633219820Sjeff
634219820Sjeff	for (i = lid; i < lid + num_lids; i++) {
635219820Sjeff		status = cl_ptr_vector_at(p_tbl, i, (void *)&p_port);
636219820Sjeff		if (status == CL_SUCCESS) {
637219820Sjeff			if (p_port != NULL)
638219820Sjeff				return (FALSE);
639219820Sjeff		} else
640219820Sjeff			/*
641219820Sjeff			   We are out of range in the array.
642219820Sjeff			   Consider all further entries "free".
643219820Sjeff			 */
644219820Sjeff			return (TRUE);
645219820Sjeff	}
646219820Sjeff
647219820Sjeff	return (TRUE);
648219820Sjeff}
649219820Sjeff
650219820Sjeff/**********************************************************************
651219820Sjefffind a free lid range
652219820Sjeff**********************************************************************/
653219820Sjeffstatic void
654219820Sjeff__osm_lid_mgr_find_free_lid_range(IN osm_lid_mgr_t * const p_mgr,
655219820Sjeff				  IN const uint8_t num_lids,
656219820Sjeff				  OUT uint16_t * const p_min_lid,
657219820Sjeff				  OUT uint16_t * const p_max_lid)
658219820Sjeff{
659219820Sjeff	uint16_t lid;
660219820Sjeff	cl_list_item_t *p_item;
661219820Sjeff	cl_list_item_t *p_next_item;
662219820Sjeff	osm_lid_mgr_range_t *p_range = NULL;
663219820Sjeff	uint8_t lmc_num_lids;
664219820Sjeff	uint16_t lmc_mask;
665219820Sjeff
666219820Sjeff	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "LMC = %u, number LIDs = %u\n",
667219820Sjeff		p_mgr->p_subn->opt.lmc, num_lids);
668219820Sjeff
669219820Sjeff	lmc_num_lids = (1 << p_mgr->p_subn->opt.lmc);
670219820Sjeff	if (p_mgr->p_subn->opt.lmc)
671219820Sjeff		lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
672219820Sjeff	else
673219820Sjeff		lmc_mask = 0xffff;
674219820Sjeff
675219820Sjeff	/*
676219820Sjeff	   Search the list of free lid ranges for a range which is big enough
677219820Sjeff	 */
678219820Sjeff	p_item = cl_qlist_head(&p_mgr->free_ranges);
679219820Sjeff	while (p_item != cl_qlist_end(&p_mgr->free_ranges)) {
680219820Sjeff		p_next_item = cl_qlist_next(p_item);
681219820Sjeff		p_range = (osm_lid_mgr_range_t *) p_item;
682219820Sjeff
683219820Sjeff		lid = p_range->min_lid;
684219820Sjeff
685219820Sjeff		/* if we require more then one lid we must align to LMC */
686219820Sjeff		if (num_lids > 1) {
687219820Sjeff			if ((lid & lmc_mask) != lid)
688219820Sjeff				lid = (lid + lmc_num_lids) & lmc_mask;
689219820Sjeff		}
690219820Sjeff
691219820Sjeff		/* but we can be out of the range */
692219820Sjeff		if (lid + num_lids - 1 <= p_range->max_lid) {
693219820Sjeff			/* ok let us use that range */
694219820Sjeff			if (lid + num_lids - 1 == p_range->max_lid)
695219820Sjeff				/* we consumed the entire range */
696219820Sjeff				cl_qlist_remove_item(&p_mgr->free_ranges,
697219820Sjeff						     p_item);
698219820Sjeff			else
699219820Sjeff				/* only update the available range */
700219820Sjeff				p_range->min_lid = lid + num_lids;
701219820Sjeff
702219820Sjeff			*p_min_lid = lid;
703219820Sjeff			*p_max_lid = (uint16_t) (lid + num_lids - 1);
704219820Sjeff			return;
705219820Sjeff		}
706219820Sjeff		p_item = p_next_item;
707219820Sjeff	}
708219820Sjeff
709219820Sjeff	/*
710219820Sjeff	   Couldn't find a free range of lids.
711219820Sjeff	 */
712219820Sjeff	*p_min_lid = *p_max_lid = 0;
713219820Sjeff	/* if we run out of lids, give an error and abort! */
714219820Sjeff	OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0307: "
715219820Sjeff		"OPENSM RAN OUT OF LIDS!!!\n");
716219820Sjeff	CL_ASSERT(0);
717219820Sjeff}
718219820Sjeff
719219820Sjeff/**********************************************************************
720219820Sjeff **********************************************************************/
721219820Sjeffstatic void
722219820Sjeff__osm_lid_mgr_cleanup_discovered_port_lid_range(IN osm_lid_mgr_t * p_mgr,
723219820Sjeff						IN osm_port_t * p_port)
724219820Sjeff{
725219820Sjeff	cl_ptr_vector_t *p_discovered_vec = &p_mgr->p_subn->port_lid_tbl;
726219820Sjeff	uint16_t lid, min_lid, max_lid;
727219820Sjeff	uint16_t max_tbl_lid =
728219820Sjeff	    (uint16_t) (cl_ptr_vector_get_size(p_discovered_vec));
729219820Sjeff
730219820Sjeff	osm_port_get_lid_range_ho(p_port, &min_lid, &max_lid);
731219820Sjeff	min_lid = __osm_trim_lid(min_lid);
732219820Sjeff	max_lid = __osm_trim_lid(max_lid);
733219820Sjeff	for (lid = min_lid; lid <= max_lid; lid++) {
734219820Sjeff		if ((lid < max_tbl_lid) &&
735219820Sjeff		    (p_port ==
736219820Sjeff		     (osm_port_t *) cl_ptr_vector_get(p_discovered_vec, lid)))
737219820Sjeff			cl_ptr_vector_set(p_discovered_vec, lid, NULL);
738219820Sjeff	}
739219820Sjeff}
740219820Sjeff
741219820Sjeff/**********************************************************************
742219820Sjeff 0.1 if the port info lid matches the guid2lid return 0
743219820Sjeff 0.2 if the port info has a lid and that range is empty in
744219820Sjeff     port_lid_tbl, return 0 and update the port_lid_tbl and
745219820Sjeff     guid2lid
746219820Sjeff 0.3 else find an empty space in port_lid_tbl, update the
747219820Sjeff port_lid_tbl and guid2lid, return 1 to flag a change required.
748219820Sjeff**********************************************************************/
749219820Sjeffstatic int
750219820Sjeff__osm_lid_mgr_get_port_lid(IN osm_lid_mgr_t * const p_mgr,
751219820Sjeff			   IN osm_port_t * const p_port,
752219820Sjeff			   OUT uint16_t * const p_min_lid,
753219820Sjeff			   OUT uint16_t * const p_max_lid)
754219820Sjeff{
755219820Sjeff	uint16_t lid, min_lid, max_lid;
756219820Sjeff	uint64_t guid;
757219820Sjeff	uint8_t num_lids = (1 << p_mgr->p_subn->opt.lmc);
758219820Sjeff	int lid_changed = 0;
759219820Sjeff	uint16_t lmc_mask;
760219820Sjeff
761219820Sjeff	OSM_LOG_ENTER(p_mgr->p_log);
762219820Sjeff
763219820Sjeff	if (p_mgr->p_subn->opt.lmc)
764219820Sjeff		lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
765219820Sjeff	else
766219820Sjeff		lmc_mask = 0xffff;
767219820Sjeff
768219820Sjeff	/* get the lid from the guid2lid */
769219820Sjeff	guid = cl_ntoh64(osm_port_get_guid(p_port));
770219820Sjeff
771219820Sjeff	/* if the port is a base switch port 0 then we only need one lid */
772219820Sjeff	if (p_port->p_node->sw &&
773219820Sjeff	    !osm_switch_sp0_is_lmc_capable(p_port->p_node->sw, p_mgr->p_subn))
774219820Sjeff		num_lids = 1;
775219820Sjeff
776219820Sjeff	/* if the port matches the guid2lid */
777219820Sjeff	if (!osm_db_guid2lid_get(p_mgr->p_g2l, guid, &min_lid, &max_lid)) {
778219820Sjeff		*p_min_lid = min_lid;
779219820Sjeff		*p_max_lid = min_lid + num_lids - 1;
780219820Sjeff		if (min_lid == cl_ntoh16(osm_port_get_base_lid(p_port))) {
781219820Sjeff			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "0x%016" PRIx64
782219820Sjeff				" matches its known lid:%u\n", guid, min_lid);
783219820Sjeff			goto Exit;
784219820Sjeff		} else {
785219820Sjeff			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
786219820Sjeff				"0x%016" PRIx64 " with lid:%u "
787219820Sjeff				"does not match its known lid:%u\n",
788219820Sjeff				guid, cl_ntoh16(osm_port_get_base_lid(p_port)),
789219820Sjeff				min_lid);
790219820Sjeff			__osm_lid_mgr_cleanup_discovered_port_lid_range(p_mgr,
791219820Sjeff									p_port);
792219820Sjeff			/* we still need to send the setting to the target port */
793219820Sjeff			lid_changed = 1;
794219820Sjeff			goto Exit;
795219820Sjeff		}
796219820Sjeff	} else
797219820Sjeff		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
798219820Sjeff			"0x%016" PRIx64 " has no persistent lid assigned\n",
799219820Sjeff			guid);
800219820Sjeff
801219820Sjeff	/* if the port info carries a lid it must be lmc aligned and not mapped
802219820Sjeff	   by the pesistent storage  */
803219820Sjeff	min_lid = cl_ntoh16(osm_port_get_base_lid(p_port));
804219820Sjeff
805219820Sjeff	/* we want to ignore the discovered lid if we are also on first sweep of
806219820Sjeff	   reassign lids flow */
807219820Sjeff	if (min_lid &&
808219820Sjeff	    !((p_mgr->p_subn->first_time_master_sweep == TRUE) &&
809219820Sjeff	      (p_mgr->p_subn->opt.reassign_lids == TRUE))) {
810219820Sjeff		/* make sure lid is valid */
811219820Sjeff		if ((num_lids == 1) || ((min_lid & lmc_mask) == min_lid)) {
812219820Sjeff			/* is it free */
813219820Sjeff			if (__osm_lid_mgr_is_range_not_persistent
814219820Sjeff			    (p_mgr, min_lid, num_lids)) {
815219820Sjeff				*p_min_lid = min_lid;
816219820Sjeff				*p_max_lid = min_lid + num_lids - 1;
817219820Sjeff				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
818219820Sjeff					"0x%016" PRIx64
819219820Sjeff					" lid range:[%u-%u] is free\n",
820219820Sjeff					guid, *p_min_lid, *p_max_lid);
821219820Sjeff				goto NewLidSet;
822219820Sjeff			} else
823219820Sjeff				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
824219820Sjeff					"0x%016" PRIx64 " existing lid "
825219820Sjeff					"range:[%u:%u] is not free\n",
826219820Sjeff					guid, min_lid, min_lid + num_lids - 1);
827219820Sjeff		} else
828219820Sjeff			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
829219820Sjeff				"0x%016" PRIx64 " existing lid range:"
830219820Sjeff				"[%u:%u] is not lmc aligned\n",
831219820Sjeff				guid, min_lid, min_lid + num_lids - 1);
832219820Sjeff	}
833219820Sjeff
834219820Sjeff	/* first cleanup the existing discovered lid range */
835219820Sjeff	__osm_lid_mgr_cleanup_discovered_port_lid_range(p_mgr, p_port);
836219820Sjeff
837219820Sjeff	/* find an empty space */
838219820Sjeff	__osm_lid_mgr_find_free_lid_range(p_mgr, num_lids, p_min_lid,
839219820Sjeff					  p_max_lid);
840219820Sjeff	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
841219820Sjeff		"0x%016" PRIx64 " assigned a new lid range:[%u-%u]\n",
842219820Sjeff		guid, *p_min_lid, *p_max_lid);
843219820Sjeff	lid_changed = 1;
844219820Sjeff
845219820SjeffNewLidSet:
846219820Sjeff	/* update the guid2lid db and used_lids */
847219820Sjeff	osm_db_guid2lid_set(p_mgr->p_g2l, guid, *p_min_lid, *p_max_lid);
848219820Sjeff	for (lid = *p_min_lid; lid <= *p_max_lid; lid++)
849219820Sjeff		cl_ptr_vector_set(&p_mgr->used_lids, lid, (void *)1);
850219820Sjeff
851219820SjeffExit:
852219820Sjeff	/* make sure the assigned lids are marked in port_lid_tbl */
853219820Sjeff	for (lid = *p_min_lid; lid <= *p_max_lid; lid++)
854219820Sjeff		cl_ptr_vector_set(&p_mgr->p_subn->port_lid_tbl, lid, p_port);
855219820Sjeff
856219820Sjeff	OSM_LOG_EXIT(p_mgr->p_log);
857219820Sjeff	return lid_changed;
858219820Sjeff}
859219820Sjeff
860219820Sjeff/**********************************************************************
861219820Sjeff Set to INIT the remote port of the given physical port
862219820Sjeff **********************************************************************/
863219820Sjeffstatic void
864219820Sjeff__osm_lid_mgr_set_remote_pi_state_to_init(IN osm_lid_mgr_t * const p_mgr,
865219820Sjeff					  IN osm_physp_t * const p_physp)
866219820Sjeff{
867219820Sjeff	osm_physp_t *p_rem_physp = osm_physp_get_remote(p_physp);
868219820Sjeff
869219820Sjeff	if (p_rem_physp == NULL)
870219820Sjeff		return;
871219820Sjeff
872219820Sjeff	/* but in some rare cases the remote side might be non responsive */
873219820Sjeff	ib_port_info_set_port_state(&p_rem_physp->port_info, IB_LINK_INIT);
874219820Sjeff}
875219820Sjeff
876219820Sjeff/**********************************************************************
877219820Sjeff **********************************************************************/
878219820Sjeffstatic boolean_t
879219820Sjeff__osm_lid_mgr_set_physp_pi(IN osm_lid_mgr_t * const p_mgr,
880219820Sjeff			   IN osm_port_t * const p_port,
881219820Sjeff			   IN osm_physp_t * const p_physp,
882219820Sjeff			   IN ib_net16_t const lid)
883219820Sjeff{
884219820Sjeff	uint8_t payload[IB_SMP_DATA_SIZE];
885219820Sjeff	ib_port_info_t *p_pi = (ib_port_info_t *) payload;
886219820Sjeff	const ib_port_info_t *p_old_pi;
887219820Sjeff	osm_madw_context_t context;
888219820Sjeff	osm_node_t *p_node;
889219820Sjeff	ib_api_status_t status;
890219820Sjeff	uint8_t mtu;
891219820Sjeff	uint8_t op_vls;
892219820Sjeff	uint8_t port_num;
893219820Sjeff	boolean_t send_set = FALSE;
894219820Sjeff
895219820Sjeff	OSM_LOG_ENTER(p_mgr->p_log);
896219820Sjeff
897219820Sjeff	/*
898219820Sjeff	   Don't bother doing anything if this Physical Port is not valid.
899219820Sjeff	   This allows simplified code in the caller.
900219820Sjeff	 */
901219820Sjeff	if (!p_physp)
902219820Sjeff		goto Exit;
903219820Sjeff
904219820Sjeff	port_num = osm_physp_get_port_num(p_physp);
905219820Sjeff	p_node = osm_physp_get_node_ptr(p_physp);
906219820Sjeff
907219820Sjeff	if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH && port_num != 0) {
908219820Sjeff		/*
909219820Sjeff		   Switch ports that are not numbered 0 should not be set
910219820Sjeff		   with the following attributes as they are set later
911219820Sjeff		   (during NO_CHANGE state in link mgr).
912219820Sjeff		 */
913219820Sjeff		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
914219820Sjeff			"Skipping switch port %u, GUID 0x%016" PRIx64 "\n",
915219820Sjeff			port_num, cl_ntoh64(osm_physp_get_port_guid(p_physp)));
916219820Sjeff		goto Exit;
917219820Sjeff	}
918219820Sjeff
919219820Sjeff	p_old_pi = &p_physp->port_info;
920219820Sjeff
921219820Sjeff	/*
922219820Sjeff	   First, copy existing parameters from the PortInfo attribute we
923219820Sjeff	   already have for this node.
924219820Sjeff
925219820Sjeff	   Second, update with default values that we know must be set for
926219820Sjeff	   every Physical Port and the LID and set the neighbor MTU field
927219820Sjeff	   appropriately.
928219820Sjeff
929219820Sjeff	   Third, send the SMP to this physical port.
930219820Sjeff	 */
931219820Sjeff
932219820Sjeff	memset(payload, 0, IB_SMP_DATA_SIZE);
933219820Sjeff	memcpy(payload, p_old_pi, sizeof(ib_port_info_t));
934219820Sjeff
935219820Sjeff	/*
936219820Sjeff	   Should never write back a value that is bigger then 3 in
937219820Sjeff	   the PortPhysicalState field, so cannot simply copy!
938219820Sjeff
939219820Sjeff	   Actually we want to write there:
940219820Sjeff	   port physical state - no change
941219820Sjeff	   link down default state = polling
942219820Sjeff	   port state - no change
943219820Sjeff	 */
944219820Sjeff	p_pi->state_info2 = 0x02;
945219820Sjeff	ib_port_info_set_port_state(p_pi, IB_LINK_NO_CHANGE);
946219820Sjeff
947219820Sjeff	if (ib_port_info_get_link_down_def_state(p_pi) !=
948219820Sjeff	    ib_port_info_get_link_down_def_state(p_old_pi))
949219820Sjeff		send_set = TRUE;
950219820Sjeff
951219820Sjeff	/* didn't get PortInfo before */
952219820Sjeff	if (!ib_port_info_get_port_state(p_old_pi))
953219820Sjeff		send_set = TRUE;
954219820Sjeff
955219820Sjeff	p_pi->m_key = p_mgr->p_subn->opt.m_key;
956219820Sjeff	if (memcmp(&p_pi->m_key, &p_old_pi->m_key, sizeof(p_pi->m_key)))
957219820Sjeff		send_set = TRUE;
958219820Sjeff
959219820Sjeff	p_pi->subnet_prefix = p_mgr->p_subn->opt.subnet_prefix;
960219820Sjeff	if (memcmp(&p_pi->subnet_prefix, &p_old_pi->subnet_prefix,
961219820Sjeff		   sizeof(p_pi->subnet_prefix)))
962219820Sjeff		send_set = TRUE;
963219820Sjeff
964219820Sjeff	p_pi->base_lid = lid;
965219820Sjeff	if (memcmp(&p_pi->base_lid, &p_old_pi->base_lid,
966219820Sjeff		   sizeof(p_pi->base_lid)))
967219820Sjeff		send_set = TRUE;
968219820Sjeff
969219820Sjeff	/* we are updating the ports with our local sm_base_lid */
970219820Sjeff	p_pi->master_sm_base_lid = p_mgr->p_subn->sm_base_lid;
971219820Sjeff	if (memcmp(&p_pi->master_sm_base_lid, &p_old_pi->master_sm_base_lid,
972219820Sjeff		   sizeof(p_pi->master_sm_base_lid)))
973219820Sjeff		send_set = TRUE;
974219820Sjeff
975219820Sjeff	p_pi->m_key_lease_period = p_mgr->p_subn->opt.m_key_lease_period;
976219820Sjeff	if (memcmp(&p_pi->m_key_lease_period, &p_old_pi->m_key_lease_period,
977219820Sjeff		   sizeof(p_pi->m_key_lease_period)))
978219820Sjeff		send_set = TRUE;
979219820Sjeff
980219820Sjeff	/*
981219820Sjeff	   we want to set the timeout for both the switch port 0
982219820Sjeff	   and the CA ports
983219820Sjeff	 */
984219820Sjeff	ib_port_info_set_timeout(p_pi, p_mgr->p_subn->opt.subnet_timeout);
985219820Sjeff	if (ib_port_info_get_timeout(p_pi) !=
986219820Sjeff	    ib_port_info_get_timeout(p_old_pi))
987219820Sjeff		send_set = TRUE;
988219820Sjeff
989219820Sjeff	if (port_num != 0) {
990219820Sjeff		/*
991219820Sjeff		   CAs don't have a port 0, and for switch port 0,
992219820Sjeff		   the state bits are ignored.
993219820Sjeff		   This is not the switch management port
994219820Sjeff		 */
995219820Sjeff		p_pi->link_width_enabled = p_old_pi->link_width_supported;
996219820Sjeff		if (memcmp(&p_pi->link_width_enabled,
997219820Sjeff			   &p_old_pi->link_width_enabled,
998219820Sjeff			   sizeof(p_pi->link_width_enabled)))
999219820Sjeff			send_set = TRUE;
1000219820Sjeff
1001219820Sjeff		/* M_KeyProtectBits are always zero */
1002219820Sjeff		p_pi->mkey_lmc = p_mgr->p_subn->opt.lmc;
1003219820Sjeff		if (memcmp(&p_pi->mkey_lmc, &p_old_pi->mkey_lmc,
1004219820Sjeff			   sizeof(p_pi->mkey_lmc)))
1005219820Sjeff			send_set = TRUE;
1006219820Sjeff
1007219820Sjeff		/* calc new op_vls and mtu */
1008219820Sjeff		op_vls =
1009219820Sjeff		    osm_physp_calc_link_op_vls(p_mgr->p_log, p_mgr->p_subn,
1010219820Sjeff					       p_physp);
1011219820Sjeff		mtu = osm_physp_calc_link_mtu(p_mgr->p_log, p_physp);
1012219820Sjeff
1013219820Sjeff		ib_port_info_set_neighbor_mtu(p_pi, mtu);
1014219820Sjeff
1015219820Sjeff		if (ib_port_info_get_neighbor_mtu(p_pi) !=
1016219820Sjeff		    ib_port_info_get_neighbor_mtu(p_old_pi))
1017219820Sjeff			send_set = TRUE;
1018219820Sjeff
1019219820Sjeff		ib_port_info_set_op_vls(p_pi, op_vls);
1020219820Sjeff		if (ib_port_info_get_op_vls(p_pi) !=
1021219820Sjeff		    ib_port_info_get_op_vls(p_old_pi))
1022219820Sjeff			send_set = TRUE;
1023219820Sjeff
1024219820Sjeff		/*
1025219820Sjeff		   Several timeout mechanisms:
1026219820Sjeff		 */
1027219820Sjeff		ib_port_info_set_phy_and_overrun_err_thd(p_pi,
1028219820Sjeff							 p_mgr->p_subn->opt.
1029219820Sjeff							 local_phy_errors_threshold,
1030219820Sjeff							 p_mgr->p_subn->opt.
1031219820Sjeff							 overrun_errors_threshold);
1032219820Sjeff
1033219820Sjeff		if (memcmp(&p_pi->error_threshold, &p_old_pi->error_threshold,
1034219820Sjeff			   sizeof(p_pi->error_threshold)))
1035219820Sjeff			send_set = TRUE;
1036219820Sjeff
1037219820Sjeff		/*
1038219820Sjeff		   To reset the port state machine we can send
1039219820Sjeff		   PortInfo.State = DOWN. (see: 7.2.7 p171 lines:10-19)
1040219820Sjeff		 */
1041219820Sjeff		if ((mtu != ib_port_info_get_neighbor_mtu(p_old_pi)) ||
1042219820Sjeff		    (op_vls != ib_port_info_get_op_vls(p_old_pi))) {
1043219820Sjeff			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1044219820Sjeff				"Sending Link Down to GUID 0x%016"
1045219820Sjeff				PRIx64 " port %d due to op_vls or "
1046219820Sjeff				"mtu change. MTU:%u,%u VL_CAP:%u,%u\n",
1047219820Sjeff				cl_ntoh64(osm_physp_get_port_guid(p_physp)),
1048219820Sjeff				port_num, mtu,
1049219820Sjeff				ib_port_info_get_neighbor_mtu(p_old_pi),
1050219820Sjeff				op_vls, ib_port_info_get_op_vls(p_old_pi));
1051219820Sjeff
1052219820Sjeff			/*
1053219820Sjeff			   we need to make sure the internal DB will follow the
1054219820Sjeff			   fact that the remote port is also going through
1055219820Sjeff			   "down" state into "init"...
1056219820Sjeff			 */
1057219820Sjeff			__osm_lid_mgr_set_remote_pi_state_to_init(p_mgr,
1058219820Sjeff								  p_physp);
1059219820Sjeff
1060219820Sjeff			ib_port_info_set_port_state(p_pi, IB_LINK_DOWN);
1061219820Sjeff			if (ib_port_info_get_port_state(p_pi) !=
1062219820Sjeff			    ib_port_info_get_port_state(p_old_pi))
1063219820Sjeff				send_set = TRUE;
1064219820Sjeff		}
1065219820Sjeff	} else {
1066219820Sjeff		/*
1067219820Sjeff		   For Port 0, NeighborMTU is relevant only for Enh. SP0.
1068219820Sjeff		   In this case, we'll set the MTU according to the mtu_cap
1069219820Sjeff		 */
1070219820Sjeff		ib_port_info_set_neighbor_mtu(p_pi,
1071219820Sjeff					      ib_port_info_get_mtu_cap
1072219820Sjeff					      (p_old_pi));
1073219820Sjeff		if (ib_port_info_get_neighbor_mtu(p_pi) !=
1074219820Sjeff		    ib_port_info_get_neighbor_mtu(p_old_pi))
1075219820Sjeff			send_set = TRUE;
1076219820Sjeff
1077219820Sjeff		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1078219820Sjeff			"Updating neighbor_mtu on switch GUID 0x%016" PRIx64
1079219820Sjeff			" port 0 to:%u\n",
1080219820Sjeff			cl_ntoh64(osm_physp_get_port_guid(p_physp)),
1081219820Sjeff			ib_port_info_get_neighbor_mtu(p_pi));
1082219820Sjeff
1083219820Sjeff		/* Determine if enhanced switch port 0 and if so set LMC */
1084219820Sjeff		if (osm_switch_sp0_is_lmc_capable(p_node->sw, p_mgr->p_subn)) {
1085219820Sjeff			/* M_KeyProtectBits are always zero */
1086219820Sjeff			p_pi->mkey_lmc = p_mgr->p_subn->opt.lmc;
1087219820Sjeff			if (memcmp(&p_pi->mkey_lmc, &p_old_pi->mkey_lmc,
1088219820Sjeff				   sizeof(p_pi->mkey_lmc)))
1089219820Sjeff				send_set = TRUE;
1090219820Sjeff		}
1091219820Sjeff	}
1092219820Sjeff
1093219820Sjeff	context.pi_context.node_guid = osm_node_get_node_guid(p_node);
1094219820Sjeff	context.pi_context.port_guid = osm_physp_get_port_guid(p_physp);
1095219820Sjeff	context.pi_context.set_method = TRUE;
1096219820Sjeff	context.pi_context.light_sweep = FALSE;
1097219820Sjeff	context.pi_context.active_transition = FALSE;
1098219820Sjeff
1099219820Sjeff	/*
1100219820Sjeff	   We need to set the cli_rereg bit when we are in first_time_master_sweep
1101219820Sjeff	   for ports supporting the ClientReregistration Vol1 (v1.2) p811 14.4.11
1102219820Sjeff	   Also, if this port was just now discovered, then we should also set
1103219820Sjeff	   the cli_rereg bit. We know that the port was just discovered if its
1104219820Sjeff	   is_new field is set.
1105219820Sjeff	 */
1106219820Sjeff	if ((p_mgr->p_subn->first_time_master_sweep == TRUE || p_port->is_new)
1107219820Sjeff	    && !p_mgr->p_subn->opt.no_clients_rereg
1108219820Sjeff	    && (p_old_pi->capability_mask & IB_PORT_CAP_HAS_CLIENT_REREG)) {
1109219820Sjeff		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1110219820Sjeff			"Seting client rereg on %s, port %d\n",
1111219820Sjeff			p_port->p_node->print_desc, p_port->p_physp->port_num);
1112219820Sjeff		ib_port_info_set_client_rereg(p_pi, 1);
1113219820Sjeff		send_set = TRUE;
1114219820Sjeff	} else
1115219820Sjeff		ib_port_info_set_client_rereg(p_pi, 0);
1116219820Sjeff
1117219820Sjeff	/* We need to send the PortInfo Set request with the new sm_lid
1118219820Sjeff	   in the following cases:
1119219820Sjeff	   1. There is a change in the values (send_set == TRUE)
1120219820Sjeff	   2. first_time_master_sweep flag on the subnet is TRUE. This means the
1121219820Sjeff	   SM just became master, and it then needs to send a PortInfo Set to
1122219820Sjeff	   every port.
1123219820Sjeff	 */
1124219820Sjeff	if (p_mgr->p_subn->first_time_master_sweep == TRUE)
1125219820Sjeff		send_set = TRUE;
1126219820Sjeff
1127219820Sjeff	if (send_set) {
1128219820Sjeff		p_mgr->send_set_reqs = TRUE;
1129219820Sjeff		status = osm_req_set(p_mgr->sm,
1130219820Sjeff				     osm_physp_get_dr_path_ptr(p_physp),
1131219820Sjeff				     payload,
1132219820Sjeff				     sizeof(payload),
1133219820Sjeff				     IB_MAD_ATTR_PORT_INFO,
1134219820Sjeff				     cl_hton32(osm_physp_get_port_num(p_physp)),
1135219820Sjeff				     CL_DISP_MSGID_NONE, &context);
1136219820Sjeff	}
1137219820Sjeff
1138219820SjeffExit:
1139219820Sjeff	OSM_LOG_EXIT(p_mgr->p_log);
1140219820Sjeff	return send_set;
1141219820Sjeff}
1142219820Sjeff
1143219820Sjeff/**********************************************************************
1144219820Sjeff Processes our own node
1145219820Sjeff Lock must already be held.
1146219820Sjeff**********************************************************************/
1147219820Sjeffstatic boolean_t
1148219820Sjeff__osm_lid_mgr_process_our_sm_node(IN osm_lid_mgr_t * const p_mgr)
1149219820Sjeff{
1150219820Sjeff	osm_port_t *p_port;
1151219820Sjeff	uint16_t min_lid_ho;
1152219820Sjeff	uint16_t max_lid_ho;
1153219820Sjeff	boolean_t res = TRUE;
1154219820Sjeff
1155219820Sjeff	OSM_LOG_ENTER(p_mgr->p_log);
1156219820Sjeff
1157219820Sjeff	/*
1158219820Sjeff	   Acquire our own port object.
1159219820Sjeff	 */
1160219820Sjeff	p_port =
1161219820Sjeff	    osm_get_port_by_guid(p_mgr->p_subn, p_mgr->p_subn->sm_port_guid);
1162219820Sjeff	if (!p_port) {
1163219820Sjeff		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0308: "
1164219820Sjeff			"Can't acquire SM's port object, GUID 0x%016" PRIx64
1165219820Sjeff			"\n", cl_ntoh64(p_mgr->p_subn->sm_port_guid));
1166219820Sjeff		res = FALSE;
1167219820Sjeff		goto Exit;
1168219820Sjeff	}
1169219820Sjeff
1170219820Sjeff	/*
1171219820Sjeff	   Determine the LID this SM will use for its own port.
1172219820Sjeff	   Be careful.  With an LMC > 0, the bottom of the LID range becomes
1173219820Sjeff	   unusable, since port hardware will mask off least significant bits,
1174219820Sjeff	   leaving a LID of 0 (invalid).  Therefore, make sure that we always
1175219820Sjeff	   configure the SM with a LID that has non-zero bits, even after
1176219820Sjeff	   LMC masking by hardware.
1177219820Sjeff	 */
1178219820Sjeff	__osm_lid_mgr_get_port_lid(p_mgr, p_port, &min_lid_ho, &max_lid_ho);
1179219820Sjeff	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1180219820Sjeff		"Current base LID is %u\n", min_lid_ho);
1181219820Sjeff	/*
1182219820Sjeff	   Update subnet object.
1183219820Sjeff	 */
1184219820Sjeff	p_mgr->p_subn->master_sm_base_lid = cl_hton16(min_lid_ho);
1185219820Sjeff	p_mgr->p_subn->sm_base_lid = cl_hton16(min_lid_ho);
1186219820Sjeff
1187219820Sjeff	OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
1188219820Sjeff		"Assigning SM's port 0x%016" PRIx64
1189219820Sjeff		"\n\t\t\t\tto LID range [%u,%u]\n",
1190219820Sjeff		cl_ntoh64(osm_port_get_guid(p_port)), min_lid_ho, max_lid_ho);
1191219820Sjeff
1192219820Sjeff	/*
1193219820Sjeff	   Set the PortInfo the Physical Port associated with this Port.
1194219820Sjeff	 */
1195219820Sjeff	__osm_lid_mgr_set_physp_pi(p_mgr, p_port, p_port->p_physp,
1196219820Sjeff				   cl_hton16(min_lid_ho));
1197219820Sjeff
1198219820SjeffExit:
1199219820Sjeff	OSM_LOG_EXIT(p_mgr->p_log);
1200219820Sjeff	return res;
1201219820Sjeff}
1202219820Sjeff
1203219820Sjeff/**********************************************************************
1204219820Sjeff **********************************************************************/
1205219820Sjeffosm_signal_t osm_lid_mgr_process_sm(IN osm_lid_mgr_t * const p_mgr)
1206219820Sjeff{
1207219820Sjeff	osm_signal_t signal = OSM_SIGNAL_DONE_PENDING;
1208219820Sjeff
1209219820Sjeff	OSM_LOG_ENTER(p_mgr->p_log);
1210219820Sjeff
1211219820Sjeff	CL_ASSERT(p_mgr->p_subn->sm_port_guid);
1212219820Sjeff
1213219820Sjeff	CL_PLOCK_EXCL_ACQUIRE(p_mgr->p_lock);
1214219820Sjeff
1215219820Sjeff	/* initialize the port_lid_tbl and empty ranges list following the
1216219820Sjeff	   persistent db */
1217219820Sjeff	__osm_lid_mgr_init_sweep(p_mgr);
1218219820Sjeff
1219219820Sjeff	/* Set the send_set_reqs of the p_mgr to FALSE, and
1220219820Sjeff	   we'll see if any set requests were sent. If not -
1221219820Sjeff	   can signal OSM_SIGNAL_DONE */
1222219820Sjeff	p_mgr->send_set_reqs = FALSE;
1223219820Sjeff	if (__osm_lid_mgr_process_our_sm_node(p_mgr) == FALSE)
1224219820Sjeff		/* The initialization failed */
1225219820Sjeff		signal = OSM_SIGNAL_DONE;
1226219820Sjeff
1227219820Sjeff	if (p_mgr->send_set_reqs == FALSE)
1228219820Sjeff		signal = OSM_SIGNAL_DONE;
1229219820Sjeff
1230219820Sjeff	CL_PLOCK_RELEASE(p_mgr->p_lock);
1231219820Sjeff
1232219820Sjeff	OSM_LOG_EXIT(p_mgr->p_log);
1233219820Sjeff	return (signal);
1234219820Sjeff}
1235219820Sjeff
1236219820Sjeff/**********************************************************************
1237219820Sjeff 1 go through all ports in the subnet.
1238219820Sjeff 1.1 call __osm_lid_mgr_get_port_min_lid
1239219820Sjeff 1.2 if a change is required send the port info
1240219820Sjeff 2 if any change send the signal PENDING...
1241219820Sjeff**********************************************************************/
1242219820Sjeffosm_signal_t osm_lid_mgr_process_subnet(IN osm_lid_mgr_t * const p_mgr)
1243219820Sjeff{
1244219820Sjeff	osm_signal_t signal;
1245219820Sjeff	cl_qmap_t *p_port_guid_tbl;
1246219820Sjeff	osm_port_t *p_port;
1247219820Sjeff	ib_net64_t port_guid;
1248219820Sjeff	uint16_t min_lid_ho, max_lid_ho;
1249219820Sjeff	int lid_changed;
1250219820Sjeff
1251219820Sjeff	CL_ASSERT(p_mgr);
1252219820Sjeff
1253219820Sjeff	OSM_LOG_ENTER(p_mgr->p_log);
1254219820Sjeff
1255219820Sjeff	CL_PLOCK_EXCL_ACQUIRE(p_mgr->p_lock);
1256219820Sjeff
1257219820Sjeff	CL_ASSERT(p_mgr->p_subn->sm_port_guid);
1258219820Sjeff
1259219820Sjeff	/* Set the send_set_reqs of the p_mgr to FALSE, and
1260219820Sjeff	   we'll see if any set requests were sent. If not -
1261219820Sjeff	   can signal OSM_SIGNAL_DONE */
1262219820Sjeff	p_mgr->send_set_reqs = FALSE;
1263219820Sjeff
1264219820Sjeff	p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl;
1265219820Sjeff
1266219820Sjeff	for (p_port = (osm_port_t *) cl_qmap_head(p_port_guid_tbl);
1267219820Sjeff	     p_port != (osm_port_t *) cl_qmap_end(p_port_guid_tbl);
1268219820Sjeff	     p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) {
1269219820Sjeff		port_guid = osm_port_get_guid(p_port);
1270219820Sjeff
1271219820Sjeff		/*
1272219820Sjeff		   Our own port is a special case in that we want to
1273219820Sjeff		   assign a LID to ourselves first, since we have to
1274219820Sjeff		   advertise that LID value to the other ports.
1275219820Sjeff
1276219820Sjeff		   For that reason, our node is treated separately and
1277219820Sjeff		   we will not add it to any of these lists.
1278219820Sjeff		 */
1279219820Sjeff		if (port_guid == p_mgr->p_subn->sm_port_guid) {
1280219820Sjeff			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1281219820Sjeff				"Skipping our own port 0x%016" PRIx64 "\n",
1282219820Sjeff				cl_ntoh64(port_guid));
1283219820Sjeff			continue;
1284219820Sjeff		}
1285219820Sjeff
1286219820Sjeff		/*
1287219820Sjeff		   get the port lid range - we need to send it on first active
1288219820Sjeff		   sweep or if there was a change (the result of
1289219820Sjeff		   __osm_lid_mgr_get_port_lid)
1290219820Sjeff		 */
1291219820Sjeff		lid_changed =
1292219820Sjeff		    __osm_lid_mgr_get_port_lid(p_mgr, p_port, &min_lid_ho,
1293219820Sjeff					       &max_lid_ho);
1294219820Sjeff
1295219820Sjeff		/* we can call the function to update the port info as it known
1296219820Sjeff		   to look for any field change and will only send an updated
1297219820Sjeff		   if required */
1298219820Sjeff		OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
1299219820Sjeff			"Assigned port 0x%016" PRIx64
1300219820Sjeff			", LID [%u,%u]\n", cl_ntoh64(port_guid),
1301219820Sjeff			min_lid_ho, max_lid_ho);
1302219820Sjeff
1303219820Sjeff		/* the proc returns the fact it sent a set port info */
1304219820Sjeff		if (__osm_lid_mgr_set_physp_pi
1305219820Sjeff		    (p_mgr, p_port, p_port->p_physp, cl_hton16(min_lid_ho)))
1306219820Sjeff			p_mgr->send_set_reqs = TRUE;
1307219820Sjeff	}			/* all ports */
1308219820Sjeff
1309219820Sjeff	/* store the guid to lid table in persistent db */
1310219820Sjeff	osm_db_store(p_mgr->p_g2l);
1311219820Sjeff
1312219820Sjeff	if (p_mgr->send_set_reqs == FALSE)
1313219820Sjeff		signal = OSM_SIGNAL_DONE;
1314219820Sjeff	else
1315219820Sjeff		signal = OSM_SIGNAL_DONE_PENDING;
1316219820Sjeff
1317219820Sjeff	CL_PLOCK_RELEASE(p_mgr->p_lock);
1318219820Sjeff
1319219820Sjeff	OSM_LOG_EXIT(p_mgr->p_log);
1320219820Sjeff	return (signal);
1321219820Sjeff}
1322