1/*
2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 *
6 * This software is available to you under a choice of one of two
7 * licenses.  You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * OpenIB.org BSD license below:
11 *
12 *     Redistribution and use in source and binary forms, with or
13 *     without modification, are permitted provided that the following
14 *     conditions are met:
15 *
16 *      - Redistributions of source code must retain the above
17 *        copyright notice, this list of conditions and the following
18 *        disclaimer.
19 *
20 *      - Redistributions in binary form must reproduce the above
21 *        copyright notice, this list of conditions and the following
22 *        disclaimer in the documentation and/or other materials
23 *        provided with the distribution.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * SOFTWARE.
33 *
34 */
35
36/*
37 * Abstract:
38 *    Implementation of osm_lid_mgr_t.
39 * This file implements the LID Manager object which is responsible for
40 * assigning LIDs to all ports on the subnet.
41 *
42 * DATA STRUCTURES:
43 *  p_subn->port_lid_tbl : a vector pointing from lid to its port.
44 *  osm db guid2lid domain : a hash from guid to lid (min lid).
45 *  p_subn->port_guid_tbl : a map from guid to discovered port obj.
46 *
47 * ALGORITHM:
48 *
49 * 0. we define a function to obtain the correct port lid:
50 *    __osm_lid_mgr_get_port_lid( p_mgr, port, &min_lid ):
51 *    0.1 if the port info lid matches the guid2lid return 0
52 *    0.2 if the port info has a lid and that range is empty in
53 *        port_lid_tbl, return 0 and update the port_lid_tbl and
54 *        guid2lid
55 *    0.3 else find an empty space in port_lid_tbl, update the
56 *    port_lid_tbl and guid2lid, return 1 to flag a change required.
57 *
58 * 1. During initialization:
59 *   1.1 initialize the guid2lid database domain.
60 *   1.2 if reassign_lid is not set:
61 *   1.2.1 read the persistent data for the domain.
62 *   1.2.2 validate no duplicate use of lids and lids are 2^(lmc-1)
63 *
64 * 2. During SM port lid assignment:
65 *   2.1 if reassign_lids is set, make it 2^lmc
66 *   2.2 cleanup all port_lid_tbl and re-fill it according to guid2lid
67 *   2.3 call __osm_lid_mgr_get_port_lid the SM port
68 *   2.4 set the port info
69 *
70 * 3. During all other ports lid assignment:
71 *   3.1 go through all ports in the subnet
72 *   3.1.1 call __osm_lid_mgr_get_port_min_lid
73 *   3.1.2 if a change required send the port info
74 *   3.2 if any change send the signal PENDING...
75 *
76 * 4. Store the guid2lid
77 */
78
79#if HAVE_CONFIG_H
80#  include <config.h>
81#endif				/* HAVE_CONFIG_H */
82
83#include <stdlib.h>
84#include <string.h>
85#include <iba/ib_types.h>
86#include <complib/cl_qmap.h>
87#include <complib/cl_debug.h>
88#include <opensm/osm_lid_mgr.h>
89#include <opensm/osm_sm.h>
90#include <opensm/osm_log.h>
91#include <opensm/osm_node.h>
92#include <opensm/osm_switch.h>
93#include <opensm/osm_helper.h>
94#include <opensm/osm_msgdef.h>
95#include <vendor/osm_vendor_api.h>
96#include <opensm/osm_db_pack.h>
97
98/**********************************************************************
99  lid range item of qlist
100 **********************************************************************/
101typedef struct osm_lid_mgr_range {
102	cl_list_item_t item;
103	uint16_t min_lid;
104	uint16_t max_lid;
105} osm_lid_mgr_range_t;
106
107/**********************************************************************
108 **********************************************************************/
109void osm_lid_mgr_construct(IN osm_lid_mgr_t * const p_mgr)
110{
111	memset(p_mgr, 0, sizeof(*p_mgr));
112	cl_ptr_vector_construct(&p_mgr->used_lids);
113}
114
115/**********************************************************************
116 **********************************************************************/
117void osm_lid_mgr_destroy(IN osm_lid_mgr_t * const p_mgr)
118{
119	cl_list_item_t *p_item;
120
121	OSM_LOG_ENTER(p_mgr->p_log);
122
123	cl_ptr_vector_destroy(&p_mgr->used_lids);
124	p_item = cl_qlist_remove_head(&p_mgr->free_ranges);
125	while (p_item != cl_qlist_end(&p_mgr->free_ranges)) {
126		free((osm_lid_mgr_range_t *) p_item);
127		p_item = cl_qlist_remove_head(&p_mgr->free_ranges);
128	}
129	OSM_LOG_EXIT(p_mgr->p_log);
130}
131
132/**********************************************************************
133Validate the guid to lid data by making sure that under the current
134LMC we did not get duplicates. If we do flag them as errors and remove
135the entry.
136**********************************************************************/
137static void __osm_lid_mgr_validate_db(IN osm_lid_mgr_t * p_mgr)
138{
139	cl_qlist_t guids;
140	osm_db_guid_elem_t *p_item;
141	uint16_t lid;
142	uint16_t min_lid;
143	uint16_t max_lid;
144	uint16_t lmc_mask;
145	boolean_t lids_ok;
146
147	OSM_LOG_ENTER(p_mgr->p_log);
148
149	if (p_mgr->p_subn->opt.lmc)
150		lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
151	else
152		lmc_mask = 0xffff;
153
154	cl_qlist_init(&guids);
155
156	if (osm_db_guid2lid_guids(p_mgr->p_g2l, &guids)) {
157		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0310: "
158			"could not get guid list\n");
159		goto Exit;
160	}
161
162	p_item = (osm_db_guid_elem_t *) cl_qlist_remove_head(&guids);
163	while ((cl_list_item_t *) p_item != cl_qlist_end(&guids)) {
164		if (osm_db_guid2lid_get
165		    (p_mgr->p_g2l, p_item->guid, &min_lid, &max_lid))
166			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0311: "
167				"could not get lid for guid:0x%016" PRIx64 "\n",
168				p_item->guid);
169		else {
170			lids_ok = TRUE;
171
172			if ((min_lid > max_lid) || (min_lid == 0)
173			    || (p_item->guid == 0)
174			    || (max_lid > p_mgr->p_subn->max_ucast_lid_ho)) {
175				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0312: "
176					"Illegal LID range [%u:%u] for "
177					"guid:0x%016" PRIx64 "\n", min_lid,
178					max_lid, p_item->guid);
179				lids_ok = FALSE;
180			} else if ((min_lid != max_lid)
181				   && ((min_lid & lmc_mask) != min_lid)) {
182				/* check that if the lids define a range that is valid
183				   for the current LMC mask */
184				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0313: "
185					"LID range [%u:%u] for guid:0x%016"
186					PRIx64
187					" is not aligned according to mask:0x%04x\n",
188					min_lid, max_lid, p_item->guid,
189					lmc_mask);
190				lids_ok = FALSE;
191			} else {
192				/* check if the lids were not previously assigned */
193				for (lid = min_lid; lid <= max_lid; lid++) {
194					if ((cl_ptr_vector_get_size
195					     (&p_mgr->used_lids) > lid)
196					    &&
197					    (cl_ptr_vector_get
198					     (&p_mgr->used_lids, lid))) {
199						OSM_LOG(p_mgr->p_log,
200							OSM_LOG_ERROR, "ERR 0314: "
201							"0x%04x for guid:0x%016"
202							PRIx64
203							" was previously used\n",
204							lid, p_item->guid);
205						lids_ok = FALSE;
206					}
207				}
208			}
209
210			if (!lids_ok) {
211				if (osm_db_guid2lid_delete
212				    (p_mgr->p_g2l, p_item->guid))
213					OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
214						"ERR 0315: "
215						"failed to delete entry for "
216						"guid:0x%016" PRIx64 "\n",
217						p_item->guid);
218			} else {
219				/* mark it was visited */
220				for (lid = min_lid; lid <= max_lid; lid++)
221					cl_ptr_vector_set(&p_mgr->used_lids,
222							  lid, (void *)1);
223			}
224		}		/* got a lid */
225		free(p_item);
226		p_item = (osm_db_guid_elem_t *) cl_qlist_remove_head(&guids);
227	}			/* all guids */
228Exit:
229	OSM_LOG_EXIT(p_mgr->p_log);
230}
231
232/**********************************************************************
233 **********************************************************************/
234ib_api_status_t
235osm_lid_mgr_init(IN osm_lid_mgr_t * const p_mgr, IN osm_sm_t *sm)
236{
237	ib_api_status_t status = IB_SUCCESS;
238
239	OSM_LOG_ENTER(sm->p_log);
240
241	osm_lid_mgr_construct(p_mgr);
242
243	p_mgr->sm = sm;
244	p_mgr->p_log = sm->p_log;
245	p_mgr->p_subn = sm->p_subn;
246	p_mgr->p_db = sm->p_db;
247	p_mgr->p_lock = sm->p_lock;
248
249	/* we initialize and restore the db domain of guid to lid map */
250	p_mgr->p_g2l = osm_db_domain_init(p_mgr->p_db, "/guid2lid");
251	if (!p_mgr->p_g2l) {
252		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0316: "
253			"Error initializing Guid-to-Lid persistent database\n");
254		status = IB_ERROR;
255		goto Exit;
256	}
257
258	cl_ptr_vector_init(&p_mgr->used_lids, 100, 40);
259	cl_qlist_init(&p_mgr->free_ranges);
260
261	/* we use the stored guid to lid table if not forced to reassign */
262	if (!p_mgr->p_subn->opt.reassign_lids) {
263		if (osm_db_restore(p_mgr->p_g2l)) {
264#ifndef __WIN__
265			/*
266			 * When Windows is BSODing, it might corrupt files that
267			 * were previously opened for writing, even if the files
268			 * are closed, so we might see corrupted guid2lid file.
269			 */
270			if (p_mgr->p_subn->opt.exit_on_fatal) {
271				osm_log(p_mgr->p_log, OSM_LOG_SYS,
272					"FATAL: Error restoring Guid-to-Lid "
273					"persistent database\n");
274				status = IB_ERROR;
275				goto Exit;
276			} else
277#endif
278				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
279					"ERR 0317: Error restoring Guid-to-Lid "
280					"persistent database\n");
281		}
282
283		/* we need to make sure we did not get duplicates with
284		   current lmc */
285		__osm_lid_mgr_validate_db(p_mgr);
286	}
287
288Exit:
289	OSM_LOG_EXIT(p_mgr->p_log);
290	return (status);
291}
292
293static uint16_t __osm_trim_lid(IN uint16_t lid)
294{
295	if ((lid > IB_LID_UCAST_END_HO) || (lid < IB_LID_UCAST_START_HO))
296		return 0;
297	return lid;
298}
299
300/**********************************************************************
301 initialize the manager for a new sweep:
302 scans the known persistent assignment and port_lid_tbl
303 re-calculate all empty ranges.
304 cleanup invalid port_lid_tbl entries
305**********************************************************************/
306static int __osm_lid_mgr_init_sweep(IN osm_lid_mgr_t * const p_mgr)
307{
308	cl_ptr_vector_t *p_discovered_vec = &p_mgr->p_subn->port_lid_tbl;
309	cl_ptr_vector_t *p_persistent_vec = &p_mgr->used_lids;
310	uint16_t max_defined_lid;
311	uint16_t max_persistent_lid;
312	uint16_t max_discovered_lid;
313	uint16_t lid;
314	uint16_t disc_min_lid;
315	uint16_t disc_max_lid;
316	uint16_t db_min_lid;
317	uint16_t db_max_lid;
318	int status = 0;
319	cl_list_item_t *p_item;
320	boolean_t is_free;
321	osm_lid_mgr_range_t *p_range = NULL;
322	osm_port_t *p_port;
323	cl_qmap_t *p_port_guid_tbl;
324	uint8_t lmc_num_lids = (uint8_t) (1 << p_mgr->p_subn->opt.lmc);
325	uint16_t lmc_mask;
326	uint16_t req_lid, num_lids;
327
328	OSM_LOG_ENTER(p_mgr->p_log);
329
330	if (p_mgr->p_subn->opt.lmc)
331		lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
332	else
333		lmc_mask = 0xffff;
334
335	/* if we came out of standby we need to discard any previous guid2lid
336	   info we might have.
337	   Do this only if the honor_guid2lid_file option is FALSE. If not, then
338	   need to honor this file. */
339	if (p_mgr->p_subn->coming_out_of_standby == TRUE) {
340		if (p_mgr->p_subn->opt.honor_guid2lid_file == FALSE) {
341			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
342				"Ignore guid2lid file when coming out of standby\n");
343			osm_db_clear(p_mgr->p_g2l);
344			for (lid = 0;
345			     lid < cl_ptr_vector_get_size(&p_mgr->used_lids);
346			     lid++)
347				cl_ptr_vector_set(p_persistent_vec, lid, NULL);
348		} else {
349			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
350				"Honor current guid2lid file when coming out "
351				"of standby\n");
352			osm_db_clear(p_mgr->p_g2l);
353			if (osm_db_restore(p_mgr->p_g2l))
354				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0306: "
355					"Error restoring Guid-to-Lid "
356					"persistent database. Ignoring it\n");
357		}
358	}
359
360	/* we need to cleanup the empty ranges list */
361	p_item = cl_qlist_remove_head(&p_mgr->free_ranges);
362	while (p_item != cl_qlist_end(&p_mgr->free_ranges)) {
363		free((osm_lid_mgr_range_t *) p_item);
364		p_item = cl_qlist_remove_head(&p_mgr->free_ranges);
365	}
366
367	/* first clean up the port_by_lid_tbl */
368	for (lid = 0; lid < cl_ptr_vector_get_size(p_discovered_vec); lid++)
369		cl_ptr_vector_set(p_discovered_vec, lid, NULL);
370
371	/* we if are in the first sweep and in reassign lids mode
372	   we should ignore all the available info and simply define one
373	   huge empty range */
374	if ((p_mgr->p_subn->first_time_master_sweep == TRUE) &&
375	    (p_mgr->p_subn->opt.reassign_lids == TRUE)) {
376		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
377			"Skipping all lids as we are reassigning them\n");
378		p_range =
379		    (osm_lid_mgr_range_t *) malloc(sizeof(osm_lid_mgr_range_t));
380		if (p_range)
381			p_range->min_lid = 1;
382		goto AfterScanningLids;
383	}
384
385	/* go over all discovered ports and mark their entries */
386	p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl;
387
388	for (p_port = (osm_port_t *) cl_qmap_head(p_port_guid_tbl);
389	     p_port != (osm_port_t *) cl_qmap_end(p_port_guid_tbl);
390	     p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) {
391		osm_port_get_lid_range_ho(p_port, &disc_min_lid, &disc_max_lid);
392		disc_min_lid = __osm_trim_lid(disc_min_lid);
393		disc_max_lid = __osm_trim_lid(disc_max_lid);
394		for (lid = disc_min_lid; lid <= disc_max_lid; lid++)
395			cl_ptr_vector_set(p_discovered_vec, lid, p_port);
396		/* make sure the guid2lid entry is valid. If not, clean it. */
397		if (!osm_db_guid2lid_get(p_mgr->p_g2l,
398					 cl_ntoh64(osm_port_get_guid(p_port)),
399					 &db_min_lid, &db_max_lid)) {
400			if (!p_port->p_node->sw ||
401			    osm_switch_sp0_is_lmc_capable(p_port->p_node->sw,
402							  p_mgr->p_subn))
403				num_lids = lmc_num_lids;
404			else
405				num_lids = 1;
406
407			if ((num_lids != 1) &&
408			    (((db_min_lid & lmc_mask) != db_min_lid) ||
409			     (db_max_lid - db_min_lid + 1 < num_lids))) {
410				/* Not aligned, or not wide enough, then remove the entry */
411				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
412					"Cleaning persistent entry for guid:"
413					"0x%016" PRIx64 " illegal range:"
414					"[0x%x:0x%x]\n",
415					cl_ntoh64(osm_port_get_guid(p_port)),
416					db_min_lid, db_max_lid);
417				osm_db_guid2lid_delete(p_mgr->p_g2l,
418						       cl_ntoh64
419						       (osm_port_get_guid
420							(p_port)));
421				for (lid = db_min_lid; lid <= db_max_lid; lid++)
422					cl_ptr_vector_set(p_persistent_vec, lid,
423							  NULL);
424			}
425		}
426	}
427
428	/*
429	   Our task is to find free lid ranges.
430	   A lid can be used if
431	   1. a persistent assignment exists
432	   2. the lid is used by a discovered port that does not have a persistent
433	   assignment.
434
435	   scan through all lid values of both the persistent table and
436	   discovered table.
437	   If the lid has an assigned port in the discovered table:
438	   * make sure the lid matches the persistent table, or
439	   * there is no other persistent assignment for that lid.
440	   * else cleanup the port_by_lid_tbl, mark this as empty range.
441	   Else if the lid does not have an entry in the persistent table
442	   mark it as free.
443	 */
444
445	/* find the range of lids to scan */
446	max_discovered_lid =
447	    (uint16_t) cl_ptr_vector_get_size(p_discovered_vec);
448	max_persistent_lid =
449	    (uint16_t) cl_ptr_vector_get_size(p_persistent_vec);
450
451	/* but the vectors have one extra entry for lid=0 */
452	if (max_discovered_lid)
453		max_discovered_lid--;
454	if (max_persistent_lid)
455		max_persistent_lid--;
456
457	if (max_persistent_lid > max_discovered_lid)
458		max_defined_lid = max_persistent_lid;
459	else
460		max_defined_lid = max_discovered_lid;
461
462	for (lid = 1; lid <= max_defined_lid; lid++) {
463		is_free = TRUE;
464		/* first check to see if the lid is used by a persistent assignment */
465		if ((lid <= max_persistent_lid)
466		    && cl_ptr_vector_get(p_persistent_vec, lid)) {
467			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
468				"0x%04x is not free as its mapped by the "
469				"persistent db\n", lid);
470			is_free = FALSE;
471		} else {
472			/* check this is a discovered port */
473			if (lid <= max_discovered_lid
474			    && (p_port = (osm_port_t *)
475				cl_ptr_vector_get(p_discovered_vec, lid))) {
476				/* we have a port. Now lets see if we can preserve its lid range. */
477				/* For that, we need to make sure:
478				   1. The port has a (legal) persistency entry. Then the local lid
479				   is free (we will use the persistency value).
480				   2. Can the port keep its local assignment?
481				   a. Make sure the lid a aligned.
482				   b. Make sure all needed lids (for the lmc) are free according
483				   to persistency table.
484				 */
485				/* qualify the guid of the port is not persistently mapped to
486				   another range */
487				if (!osm_db_guid2lid_get(p_mgr->p_g2l,
488							 cl_ntoh64
489							 (osm_port_get_guid
490							  (p_port)),
491							 &db_min_lid,
492							 &db_max_lid)) {
493					OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
494						"0x%04x is free as it was "
495						"discovered but mapped by the "
496						"persistent db to [0x%04x:0x%04x]\n",
497						lid, db_min_lid, db_max_lid);
498				} else {
499					/* can the port keep its assignment ? */
500					/* get the lid range of that port, and the required number
501					   of lids we are about to assign to it */
502					osm_port_get_lid_range_ho(p_port,
503								  &disc_min_lid,
504								  &disc_max_lid);
505					if (!p_port->p_node->sw
506					    ||
507					    osm_switch_sp0_is_lmc_capable
508					    (p_port->p_node->sw,
509					     p_mgr->p_subn)) {
510						disc_max_lid =
511						    disc_min_lid +
512						    lmc_num_lids - 1;
513						num_lids = lmc_num_lids;
514					} else
515						num_lids = 1;
516
517					/* Make sure the lid is aligned */
518					if ((num_lids != 1)
519					    && ((disc_min_lid & lmc_mask) !=
520						disc_min_lid)) {
521						/* The lid cannot be used */
522						OSM_LOG(p_mgr->p_log,
523							OSM_LOG_DEBUG,
524							"0x%04x is free as it was "
525							"discovered but not aligned\n",
526							lid);
527					} else {
528						/* check that all needed lids are not persistently mapped */
529						is_free = FALSE;
530						for (req_lid = disc_min_lid + 1;
531						     req_lid <= disc_max_lid;
532						     req_lid++) {
533							if ((req_lid <=
534							     max_persistent_lid)
535							    &&
536							    cl_ptr_vector_get
537							    (p_persistent_vec,
538							     req_lid)) {
539								OSM_LOG(p_mgr->
540									p_log,
541									OSM_LOG_DEBUG,
542									"0x%04x is free as it was discovered "
543									"but mapped\n",
544									lid);
545								is_free = TRUE;
546								break;
547							}
548						}
549
550						if (is_free == FALSE) {
551							/* This port will use its local lid, and consume the entire required lid range.
552							   Thus we can skip that range. */
553							/* If the disc_max_lid is greater then lid, we can skip right to it,
554							   since we've done all neccessary checks on the lids in between. */
555							if (disc_max_lid > lid)
556								lid =
557								    disc_max_lid;
558						}
559					}
560				}
561			}
562		}
563
564		if (is_free) {
565			if (p_range)
566				p_range->max_lid = lid;
567			else {
568				p_range = (osm_lid_mgr_range_t *)
569				    malloc(sizeof(osm_lid_mgr_range_t));
570				if (p_range) {
571					p_range->min_lid = lid;
572					p_range->max_lid = lid;
573				}
574			}
575		} else {
576			/* this lid is used so we need to finalize the previous free range */
577			if (p_range) {
578				cl_qlist_insert_tail(&p_mgr->free_ranges,
579						     &p_range->item);
580				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
581					"new free lid range [%u:%u]\n",
582					p_range->min_lid, p_range->max_lid);
583				p_range = NULL;
584			}
585		}
586	}
587
588AfterScanningLids:
589	/* after scanning all known lids we need to extend the last range
590	   to the max allowed lid */
591	if (!p_range) {
592		p_range =
593		    (osm_lid_mgr_range_t *) malloc(sizeof(osm_lid_mgr_range_t));
594		/*
595		   The p_range can be NULL in one of 2 cases:
596		   1. If max_defined_lid == 0. In this case, we want the
597		   entire range.
598		   2. If all lids discovered in the loop where mapped. In this
599		   case, no free range exists and we want to define it after the
600		   last mapped lid.
601		 */
602		if (p_range)
603			p_range->min_lid = lid;
604	}
605	if (p_range) {
606		p_range->max_lid = p_mgr->p_subn->max_ucast_lid_ho;
607		cl_qlist_insert_tail(&p_mgr->free_ranges, &p_range->item);
608		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
609			"final free lid range [%u:%u]\n",
610			p_range->min_lid, p_range->max_lid);
611	}
612
613	OSM_LOG_EXIT(p_mgr->p_log);
614	return status;
615}
616
617/**********************************************************************
618 check if the given range of lids is free
619**********************************************************************/
620static boolean_t
621__osm_lid_mgr_is_range_not_persistent(IN osm_lid_mgr_t * const p_mgr,
622				      IN const uint16_t lid,
623				      IN const uint16_t num_lids)
624{
625	uint16_t i;
626	cl_status_t status;
627	osm_port_t *p_port;
628	const uint8_t start_lid = (uint8_t) (1 << p_mgr->p_subn->opt.lmc);
629	const cl_ptr_vector_t *const p_tbl = &p_mgr->used_lids;
630
631	if (lid < start_lid)
632		return (FALSE);
633
634	for (i = lid; i < lid + num_lids; i++) {
635		status = cl_ptr_vector_at(p_tbl, i, (void *)&p_port);
636		if (status == CL_SUCCESS) {
637			if (p_port != NULL)
638				return (FALSE);
639		} else
640			/*
641			   We are out of range in the array.
642			   Consider all further entries "free".
643			 */
644			return (TRUE);
645	}
646
647	return (TRUE);
648}
649
650/**********************************************************************
651find a free lid range
652**********************************************************************/
653static void
654__osm_lid_mgr_find_free_lid_range(IN osm_lid_mgr_t * const p_mgr,
655				  IN const uint8_t num_lids,
656				  OUT uint16_t * const p_min_lid,
657				  OUT uint16_t * const p_max_lid)
658{
659	uint16_t lid;
660	cl_list_item_t *p_item;
661	cl_list_item_t *p_next_item;
662	osm_lid_mgr_range_t *p_range = NULL;
663	uint8_t lmc_num_lids;
664	uint16_t lmc_mask;
665
666	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "LMC = %u, number LIDs = %u\n",
667		p_mgr->p_subn->opt.lmc, num_lids);
668
669	lmc_num_lids = (1 << p_mgr->p_subn->opt.lmc);
670	if (p_mgr->p_subn->opt.lmc)
671		lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
672	else
673		lmc_mask = 0xffff;
674
675	/*
676	   Search the list of free lid ranges for a range which is big enough
677	 */
678	p_item = cl_qlist_head(&p_mgr->free_ranges);
679	while (p_item != cl_qlist_end(&p_mgr->free_ranges)) {
680		p_next_item = cl_qlist_next(p_item);
681		p_range = (osm_lid_mgr_range_t *) p_item;
682
683		lid = p_range->min_lid;
684
685		/* if we require more then one lid we must align to LMC */
686		if (num_lids > 1) {
687			if ((lid & lmc_mask) != lid)
688				lid = (lid + lmc_num_lids) & lmc_mask;
689		}
690
691		/* but we can be out of the range */
692		if (lid + num_lids - 1 <= p_range->max_lid) {
693			/* ok let us use that range */
694			if (lid + num_lids - 1 == p_range->max_lid)
695				/* we consumed the entire range */
696				cl_qlist_remove_item(&p_mgr->free_ranges,
697						     p_item);
698			else
699				/* only update the available range */
700				p_range->min_lid = lid + num_lids;
701
702			*p_min_lid = lid;
703			*p_max_lid = (uint16_t) (lid + num_lids - 1);
704			return;
705		}
706		p_item = p_next_item;
707	}
708
709	/*
710	   Couldn't find a free range of lids.
711	 */
712	*p_min_lid = *p_max_lid = 0;
713	/* if we run out of lids, give an error and abort! */
714	OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0307: "
715		"OPENSM RAN OUT OF LIDS!!!\n");
716	CL_ASSERT(0);
717}
718
719/**********************************************************************
720 **********************************************************************/
721static void
722__osm_lid_mgr_cleanup_discovered_port_lid_range(IN osm_lid_mgr_t * p_mgr,
723						IN osm_port_t * p_port)
724{
725	cl_ptr_vector_t *p_discovered_vec = &p_mgr->p_subn->port_lid_tbl;
726	uint16_t lid, min_lid, max_lid;
727	uint16_t max_tbl_lid =
728	    (uint16_t) (cl_ptr_vector_get_size(p_discovered_vec));
729
730	osm_port_get_lid_range_ho(p_port, &min_lid, &max_lid);
731	min_lid = __osm_trim_lid(min_lid);
732	max_lid = __osm_trim_lid(max_lid);
733	for (lid = min_lid; lid <= max_lid; lid++) {
734		if ((lid < max_tbl_lid) &&
735		    (p_port ==
736		     (osm_port_t *) cl_ptr_vector_get(p_discovered_vec, lid)))
737			cl_ptr_vector_set(p_discovered_vec, lid, NULL);
738	}
739}
740
741/**********************************************************************
742 0.1 if the port info lid matches the guid2lid return 0
743 0.2 if the port info has a lid and that range is empty in
744     port_lid_tbl, return 0 and update the port_lid_tbl and
745     guid2lid
746 0.3 else find an empty space in port_lid_tbl, update the
747 port_lid_tbl and guid2lid, return 1 to flag a change required.
748**********************************************************************/
749static int
750__osm_lid_mgr_get_port_lid(IN osm_lid_mgr_t * const p_mgr,
751			   IN osm_port_t * const p_port,
752			   OUT uint16_t * const p_min_lid,
753			   OUT uint16_t * const p_max_lid)
754{
755	uint16_t lid, min_lid, max_lid;
756	uint64_t guid;
757	uint8_t num_lids = (1 << p_mgr->p_subn->opt.lmc);
758	int lid_changed = 0;
759	uint16_t lmc_mask;
760
761	OSM_LOG_ENTER(p_mgr->p_log);
762
763	if (p_mgr->p_subn->opt.lmc)
764		lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
765	else
766		lmc_mask = 0xffff;
767
768	/* get the lid from the guid2lid */
769	guid = cl_ntoh64(osm_port_get_guid(p_port));
770
771	/* if the port is a base switch port 0 then we only need one lid */
772	if (p_port->p_node->sw &&
773	    !osm_switch_sp0_is_lmc_capable(p_port->p_node->sw, p_mgr->p_subn))
774		num_lids = 1;
775
776	/* if the port matches the guid2lid */
777	if (!osm_db_guid2lid_get(p_mgr->p_g2l, guid, &min_lid, &max_lid)) {
778		*p_min_lid = min_lid;
779		*p_max_lid = min_lid + num_lids - 1;
780		if (min_lid == cl_ntoh16(osm_port_get_base_lid(p_port))) {
781			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "0x%016" PRIx64
782				" matches its known lid:%u\n", guid, min_lid);
783			goto Exit;
784		} else {
785			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
786				"0x%016" PRIx64 " with lid:%u "
787				"does not match its known lid:%u\n",
788				guid, cl_ntoh16(osm_port_get_base_lid(p_port)),
789				min_lid);
790			__osm_lid_mgr_cleanup_discovered_port_lid_range(p_mgr,
791									p_port);
792			/* we still need to send the setting to the target port */
793			lid_changed = 1;
794			goto Exit;
795		}
796	} else
797		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
798			"0x%016" PRIx64 " has no persistent lid assigned\n",
799			guid);
800
801	/* if the port info carries a lid it must be lmc aligned and not mapped
802	   by the pesistent storage  */
803	min_lid = cl_ntoh16(osm_port_get_base_lid(p_port));
804
805	/* we want to ignore the discovered lid if we are also on first sweep of
806	   reassign lids flow */
807	if (min_lid &&
808	    !((p_mgr->p_subn->first_time_master_sweep == TRUE) &&
809	      (p_mgr->p_subn->opt.reassign_lids == TRUE))) {
810		/* make sure lid is valid */
811		if ((num_lids == 1) || ((min_lid & lmc_mask) == min_lid)) {
812			/* is it free */
813			if (__osm_lid_mgr_is_range_not_persistent
814			    (p_mgr, min_lid, num_lids)) {
815				*p_min_lid = min_lid;
816				*p_max_lid = min_lid + num_lids - 1;
817				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
818					"0x%016" PRIx64
819					" lid range:[%u-%u] is free\n",
820					guid, *p_min_lid, *p_max_lid);
821				goto NewLidSet;
822			} else
823				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
824					"0x%016" PRIx64 " existing lid "
825					"range:[%u:%u] is not free\n",
826					guid, min_lid, min_lid + num_lids - 1);
827		} else
828			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
829				"0x%016" PRIx64 " existing lid range:"
830				"[%u:%u] is not lmc aligned\n",
831				guid, min_lid, min_lid + num_lids - 1);
832	}
833
834	/* first cleanup the existing discovered lid range */
835	__osm_lid_mgr_cleanup_discovered_port_lid_range(p_mgr, p_port);
836
837	/* find an empty space */
838	__osm_lid_mgr_find_free_lid_range(p_mgr, num_lids, p_min_lid,
839					  p_max_lid);
840	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
841		"0x%016" PRIx64 " assigned a new lid range:[%u-%u]\n",
842		guid, *p_min_lid, *p_max_lid);
843	lid_changed = 1;
844
845NewLidSet:
846	/* update the guid2lid db and used_lids */
847	osm_db_guid2lid_set(p_mgr->p_g2l, guid, *p_min_lid, *p_max_lid);
848	for (lid = *p_min_lid; lid <= *p_max_lid; lid++)
849		cl_ptr_vector_set(&p_mgr->used_lids, lid, (void *)1);
850
851Exit:
852	/* make sure the assigned lids are marked in port_lid_tbl */
853	for (lid = *p_min_lid; lid <= *p_max_lid; lid++)
854		cl_ptr_vector_set(&p_mgr->p_subn->port_lid_tbl, lid, p_port);
855
856	OSM_LOG_EXIT(p_mgr->p_log);
857	return lid_changed;
858}
859
860/**********************************************************************
861 Set to INIT the remote port of the given physical port
862 **********************************************************************/
863static void
864__osm_lid_mgr_set_remote_pi_state_to_init(IN osm_lid_mgr_t * const p_mgr,
865					  IN osm_physp_t * const p_physp)
866{
867	osm_physp_t *p_rem_physp = osm_physp_get_remote(p_physp);
868
869	if (p_rem_physp == NULL)
870		return;
871
872	/* but in some rare cases the remote side might be non responsive */
873	ib_port_info_set_port_state(&p_rem_physp->port_info, IB_LINK_INIT);
874}
875
876/**********************************************************************
877 **********************************************************************/
878static boolean_t
879__osm_lid_mgr_set_physp_pi(IN osm_lid_mgr_t * const p_mgr,
880			   IN osm_port_t * const p_port,
881			   IN osm_physp_t * const p_physp,
882			   IN ib_net16_t const lid)
883{
884	uint8_t payload[IB_SMP_DATA_SIZE];
885	ib_port_info_t *p_pi = (ib_port_info_t *) payload;
886	const ib_port_info_t *p_old_pi;
887	osm_madw_context_t context;
888	osm_node_t *p_node;
889	ib_api_status_t status;
890	uint8_t mtu;
891	uint8_t op_vls;
892	uint8_t port_num;
893	boolean_t send_set = FALSE;
894
895	OSM_LOG_ENTER(p_mgr->p_log);
896
897	/*
898	   Don't bother doing anything if this Physical Port is not valid.
899	   This allows simplified code in the caller.
900	 */
901	if (!p_physp)
902		goto Exit;
903
904	port_num = osm_physp_get_port_num(p_physp);
905	p_node = osm_physp_get_node_ptr(p_physp);
906
907	if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH && port_num != 0) {
908		/*
909		   Switch ports that are not numbered 0 should not be set
910		   with the following attributes as they are set later
911		   (during NO_CHANGE state in link mgr).
912		 */
913		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
914			"Skipping switch port %u, GUID 0x%016" PRIx64 "\n",
915			port_num, cl_ntoh64(osm_physp_get_port_guid(p_physp)));
916		goto Exit;
917	}
918
919	p_old_pi = &p_physp->port_info;
920
921	/*
922	   First, copy existing parameters from the PortInfo attribute we
923	   already have for this node.
924
925	   Second, update with default values that we know must be set for
926	   every Physical Port and the LID and set the neighbor MTU field
927	   appropriately.
928
929	   Third, send the SMP to this physical port.
930	 */
931
932	memset(payload, 0, IB_SMP_DATA_SIZE);
933	memcpy(payload, p_old_pi, sizeof(ib_port_info_t));
934
935	/*
936	   Should never write back a value that is bigger then 3 in
937	   the PortPhysicalState field, so cannot simply copy!
938
939	   Actually we want to write there:
940	   port physical state - no change
941	   link down default state = polling
942	   port state - no change
943	 */
944	p_pi->state_info2 = 0x02;
945	ib_port_info_set_port_state(p_pi, IB_LINK_NO_CHANGE);
946
947	if (ib_port_info_get_link_down_def_state(p_pi) !=
948	    ib_port_info_get_link_down_def_state(p_old_pi))
949		send_set = TRUE;
950
951	/* didn't get PortInfo before */
952	if (!ib_port_info_get_port_state(p_old_pi))
953		send_set = TRUE;
954
955	p_pi->m_key = p_mgr->p_subn->opt.m_key;
956	if (memcmp(&p_pi->m_key, &p_old_pi->m_key, sizeof(p_pi->m_key)))
957		send_set = TRUE;
958
959	p_pi->subnet_prefix = p_mgr->p_subn->opt.subnet_prefix;
960	if (memcmp(&p_pi->subnet_prefix, &p_old_pi->subnet_prefix,
961		   sizeof(p_pi->subnet_prefix)))
962		send_set = TRUE;
963
964	p_pi->base_lid = lid;
965	if (memcmp(&p_pi->base_lid, &p_old_pi->base_lid,
966		   sizeof(p_pi->base_lid)))
967		send_set = TRUE;
968
969	/* we are updating the ports with our local sm_base_lid */
970	p_pi->master_sm_base_lid = p_mgr->p_subn->sm_base_lid;
971	if (memcmp(&p_pi->master_sm_base_lid, &p_old_pi->master_sm_base_lid,
972		   sizeof(p_pi->master_sm_base_lid)))
973		send_set = TRUE;
974
975	p_pi->m_key_lease_period = p_mgr->p_subn->opt.m_key_lease_period;
976	if (memcmp(&p_pi->m_key_lease_period, &p_old_pi->m_key_lease_period,
977		   sizeof(p_pi->m_key_lease_period)))
978		send_set = TRUE;
979
980	/*
981	   we want to set the timeout for both the switch port 0
982	   and the CA ports
983	 */
984	ib_port_info_set_timeout(p_pi, p_mgr->p_subn->opt.subnet_timeout);
985	if (ib_port_info_get_timeout(p_pi) !=
986	    ib_port_info_get_timeout(p_old_pi))
987		send_set = TRUE;
988
989	if (port_num != 0) {
990		/*
991		   CAs don't have a port 0, and for switch port 0,
992		   the state bits are ignored.
993		   This is not the switch management port
994		 */
995		p_pi->link_width_enabled = p_old_pi->link_width_supported;
996		if (memcmp(&p_pi->link_width_enabled,
997			   &p_old_pi->link_width_enabled,
998			   sizeof(p_pi->link_width_enabled)))
999			send_set = TRUE;
1000
1001		/* M_KeyProtectBits are always zero */
1002		p_pi->mkey_lmc = p_mgr->p_subn->opt.lmc;
1003		if (memcmp(&p_pi->mkey_lmc, &p_old_pi->mkey_lmc,
1004			   sizeof(p_pi->mkey_lmc)))
1005			send_set = TRUE;
1006
1007		/* calc new op_vls and mtu */
1008		op_vls =
1009		    osm_physp_calc_link_op_vls(p_mgr->p_log, p_mgr->p_subn,
1010					       p_physp);
1011		mtu = osm_physp_calc_link_mtu(p_mgr->p_log, p_physp);
1012
1013		ib_port_info_set_neighbor_mtu(p_pi, mtu);
1014
1015		if (ib_port_info_get_neighbor_mtu(p_pi) !=
1016		    ib_port_info_get_neighbor_mtu(p_old_pi))
1017			send_set = TRUE;
1018
1019		ib_port_info_set_op_vls(p_pi, op_vls);
1020		if (ib_port_info_get_op_vls(p_pi) !=
1021		    ib_port_info_get_op_vls(p_old_pi))
1022			send_set = TRUE;
1023
1024		/*
1025		   Several timeout mechanisms:
1026		 */
1027		ib_port_info_set_phy_and_overrun_err_thd(p_pi,
1028							 p_mgr->p_subn->opt.
1029							 local_phy_errors_threshold,
1030							 p_mgr->p_subn->opt.
1031							 overrun_errors_threshold);
1032
1033		if (memcmp(&p_pi->error_threshold, &p_old_pi->error_threshold,
1034			   sizeof(p_pi->error_threshold)))
1035			send_set = TRUE;
1036
1037		/*
1038		   To reset the port state machine we can send
1039		   PortInfo.State = DOWN. (see: 7.2.7 p171 lines:10-19)
1040		 */
1041		if ((mtu != ib_port_info_get_neighbor_mtu(p_old_pi)) ||
1042		    (op_vls != ib_port_info_get_op_vls(p_old_pi))) {
1043			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1044				"Sending Link Down to GUID 0x%016"
1045				PRIx64 " port %d due to op_vls or "
1046				"mtu change. MTU:%u,%u VL_CAP:%u,%u\n",
1047				cl_ntoh64(osm_physp_get_port_guid(p_physp)),
1048				port_num, mtu,
1049				ib_port_info_get_neighbor_mtu(p_old_pi),
1050				op_vls, ib_port_info_get_op_vls(p_old_pi));
1051
1052			/*
1053			   we need to make sure the internal DB will follow the
1054			   fact that the remote port is also going through
1055			   "down" state into "init"...
1056			 */
1057			__osm_lid_mgr_set_remote_pi_state_to_init(p_mgr,
1058								  p_physp);
1059
1060			ib_port_info_set_port_state(p_pi, IB_LINK_DOWN);
1061			if (ib_port_info_get_port_state(p_pi) !=
1062			    ib_port_info_get_port_state(p_old_pi))
1063				send_set = TRUE;
1064		}
1065	} else {
1066		/*
1067		   For Port 0, NeighborMTU is relevant only for Enh. SP0.
1068		   In this case, we'll set the MTU according to the mtu_cap
1069		 */
1070		ib_port_info_set_neighbor_mtu(p_pi,
1071					      ib_port_info_get_mtu_cap
1072					      (p_old_pi));
1073		if (ib_port_info_get_neighbor_mtu(p_pi) !=
1074		    ib_port_info_get_neighbor_mtu(p_old_pi))
1075			send_set = TRUE;
1076
1077		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1078			"Updating neighbor_mtu on switch GUID 0x%016" PRIx64
1079			" port 0 to:%u\n",
1080			cl_ntoh64(osm_physp_get_port_guid(p_physp)),
1081			ib_port_info_get_neighbor_mtu(p_pi));
1082
1083		/* Determine if enhanced switch port 0 and if so set LMC */
1084		if (osm_switch_sp0_is_lmc_capable(p_node->sw, p_mgr->p_subn)) {
1085			/* M_KeyProtectBits are always zero */
1086			p_pi->mkey_lmc = p_mgr->p_subn->opt.lmc;
1087			if (memcmp(&p_pi->mkey_lmc, &p_old_pi->mkey_lmc,
1088				   sizeof(p_pi->mkey_lmc)))
1089				send_set = TRUE;
1090		}
1091	}
1092
1093	context.pi_context.node_guid = osm_node_get_node_guid(p_node);
1094	context.pi_context.port_guid = osm_physp_get_port_guid(p_physp);
1095	context.pi_context.set_method = TRUE;
1096	context.pi_context.light_sweep = FALSE;
1097	context.pi_context.active_transition = FALSE;
1098
1099	/*
1100	   We need to set the cli_rereg bit when we are in first_time_master_sweep
1101	   for ports supporting the ClientReregistration Vol1 (v1.2) p811 14.4.11
1102	   Also, if this port was just now discovered, then we should also set
1103	   the cli_rereg bit. We know that the port was just discovered if its
1104	   is_new field is set.
1105	 */
1106	if ((p_mgr->p_subn->first_time_master_sweep == TRUE || p_port->is_new)
1107	    && !p_mgr->p_subn->opt.no_clients_rereg
1108	    && (p_old_pi->capability_mask & IB_PORT_CAP_HAS_CLIENT_REREG)) {
1109		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1110			"Seting client rereg on %s, port %d\n",
1111			p_port->p_node->print_desc, p_port->p_physp->port_num);
1112		ib_port_info_set_client_rereg(p_pi, 1);
1113		send_set = TRUE;
1114	} else
1115		ib_port_info_set_client_rereg(p_pi, 0);
1116
1117	/* We need to send the PortInfo Set request with the new sm_lid
1118	   in the following cases:
1119	   1. There is a change in the values (send_set == TRUE)
1120	   2. first_time_master_sweep flag on the subnet is TRUE. This means the
1121	   SM just became master, and it then needs to send a PortInfo Set to
1122	   every port.
1123	 */
1124	if (p_mgr->p_subn->first_time_master_sweep == TRUE)
1125		send_set = TRUE;
1126
1127	if (send_set) {
1128		p_mgr->send_set_reqs = TRUE;
1129		status = osm_req_set(p_mgr->sm,
1130				     osm_physp_get_dr_path_ptr(p_physp),
1131				     payload,
1132				     sizeof(payload),
1133				     IB_MAD_ATTR_PORT_INFO,
1134				     cl_hton32(osm_physp_get_port_num(p_physp)),
1135				     CL_DISP_MSGID_NONE, &context);
1136	}
1137
1138Exit:
1139	OSM_LOG_EXIT(p_mgr->p_log);
1140	return send_set;
1141}
1142
1143/**********************************************************************
1144 Processes our own node
1145 Lock must already be held.
1146**********************************************************************/
1147static boolean_t
1148__osm_lid_mgr_process_our_sm_node(IN osm_lid_mgr_t * const p_mgr)
1149{
1150	osm_port_t *p_port;
1151	uint16_t min_lid_ho;
1152	uint16_t max_lid_ho;
1153	boolean_t res = TRUE;
1154
1155	OSM_LOG_ENTER(p_mgr->p_log);
1156
1157	/*
1158	   Acquire our own port object.
1159	 */
1160	p_port =
1161	    osm_get_port_by_guid(p_mgr->p_subn, p_mgr->p_subn->sm_port_guid);
1162	if (!p_port) {
1163		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0308: "
1164			"Can't acquire SM's port object, GUID 0x%016" PRIx64
1165			"\n", cl_ntoh64(p_mgr->p_subn->sm_port_guid));
1166		res = FALSE;
1167		goto Exit;
1168	}
1169
1170	/*
1171	   Determine the LID this SM will use for its own port.
1172	   Be careful.  With an LMC > 0, the bottom of the LID range becomes
1173	   unusable, since port hardware will mask off least significant bits,
1174	   leaving a LID of 0 (invalid).  Therefore, make sure that we always
1175	   configure the SM with a LID that has non-zero bits, even after
1176	   LMC masking by hardware.
1177	 */
1178	__osm_lid_mgr_get_port_lid(p_mgr, p_port, &min_lid_ho, &max_lid_ho);
1179	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1180		"Current base LID is %u\n", min_lid_ho);
1181	/*
1182	   Update subnet object.
1183	 */
1184	p_mgr->p_subn->master_sm_base_lid = cl_hton16(min_lid_ho);
1185	p_mgr->p_subn->sm_base_lid = cl_hton16(min_lid_ho);
1186
1187	OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
1188		"Assigning SM's port 0x%016" PRIx64
1189		"\n\t\t\t\tto LID range [%u,%u]\n",
1190		cl_ntoh64(osm_port_get_guid(p_port)), min_lid_ho, max_lid_ho);
1191
1192	/*
1193	   Set the PortInfo the Physical Port associated with this Port.
1194	 */
1195	__osm_lid_mgr_set_physp_pi(p_mgr, p_port, p_port->p_physp,
1196				   cl_hton16(min_lid_ho));
1197
1198Exit:
1199	OSM_LOG_EXIT(p_mgr->p_log);
1200	return res;
1201}
1202
1203/**********************************************************************
1204 **********************************************************************/
1205osm_signal_t osm_lid_mgr_process_sm(IN osm_lid_mgr_t * const p_mgr)
1206{
1207	osm_signal_t signal = OSM_SIGNAL_DONE_PENDING;
1208
1209	OSM_LOG_ENTER(p_mgr->p_log);
1210
1211	CL_ASSERT(p_mgr->p_subn->sm_port_guid);
1212
1213	CL_PLOCK_EXCL_ACQUIRE(p_mgr->p_lock);
1214
1215	/* initialize the port_lid_tbl and empty ranges list following the
1216	   persistent db */
1217	__osm_lid_mgr_init_sweep(p_mgr);
1218
1219	/* Set the send_set_reqs of the p_mgr to FALSE, and
1220	   we'll see if any set requests were sent. If not -
1221	   can signal OSM_SIGNAL_DONE */
1222	p_mgr->send_set_reqs = FALSE;
1223	if (__osm_lid_mgr_process_our_sm_node(p_mgr) == FALSE)
1224		/* The initialization failed */
1225		signal = OSM_SIGNAL_DONE;
1226
1227	if (p_mgr->send_set_reqs == FALSE)
1228		signal = OSM_SIGNAL_DONE;
1229
1230	CL_PLOCK_RELEASE(p_mgr->p_lock);
1231
1232	OSM_LOG_EXIT(p_mgr->p_log);
1233	return (signal);
1234}
1235
1236/**********************************************************************
1237 1 go through all ports in the subnet.
1238 1.1 call __osm_lid_mgr_get_port_min_lid
1239 1.2 if a change is required send the port info
1240 2 if any change send the signal PENDING...
1241**********************************************************************/
1242osm_signal_t osm_lid_mgr_process_subnet(IN osm_lid_mgr_t * const p_mgr)
1243{
1244	osm_signal_t signal;
1245	cl_qmap_t *p_port_guid_tbl;
1246	osm_port_t *p_port;
1247	ib_net64_t port_guid;
1248	uint16_t min_lid_ho, max_lid_ho;
1249	int lid_changed;
1250
1251	CL_ASSERT(p_mgr);
1252
1253	OSM_LOG_ENTER(p_mgr->p_log);
1254
1255	CL_PLOCK_EXCL_ACQUIRE(p_mgr->p_lock);
1256
1257	CL_ASSERT(p_mgr->p_subn->sm_port_guid);
1258
1259	/* Set the send_set_reqs of the p_mgr to FALSE, and
1260	   we'll see if any set requests were sent. If not -
1261	   can signal OSM_SIGNAL_DONE */
1262	p_mgr->send_set_reqs = FALSE;
1263
1264	p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl;
1265
1266	for (p_port = (osm_port_t *) cl_qmap_head(p_port_guid_tbl);
1267	     p_port != (osm_port_t *) cl_qmap_end(p_port_guid_tbl);
1268	     p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) {
1269		port_guid = osm_port_get_guid(p_port);
1270
1271		/*
1272		   Our own port is a special case in that we want to
1273		   assign a LID to ourselves first, since we have to
1274		   advertise that LID value to the other ports.
1275
1276		   For that reason, our node is treated separately and
1277		   we will not add it to any of these lists.
1278		 */
1279		if (port_guid == p_mgr->p_subn->sm_port_guid) {
1280			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1281				"Skipping our own port 0x%016" PRIx64 "\n",
1282				cl_ntoh64(port_guid));
1283			continue;
1284		}
1285
1286		/*
1287		   get the port lid range - we need to send it on first active
1288		   sweep or if there was a change (the result of
1289		   __osm_lid_mgr_get_port_lid)
1290		 */
1291		lid_changed =
1292		    __osm_lid_mgr_get_port_lid(p_mgr, p_port, &min_lid_ho,
1293					       &max_lid_ho);
1294
1295		/* we can call the function to update the port info as it known
1296		   to look for any field change and will only send an updated
1297		   if required */
1298		OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
1299			"Assigned port 0x%016" PRIx64
1300			", LID [%u,%u]\n", cl_ntoh64(port_guid),
1301			min_lid_ho, max_lid_ho);
1302
1303		/* the proc returns the fact it sent a set port info */
1304		if (__osm_lid_mgr_set_physp_pi
1305		    (p_mgr, p_port, p_port->p_physp, cl_hton16(min_lid_ho)))
1306			p_mgr->send_set_reqs = TRUE;
1307	}			/* all ports */
1308
1309	/* store the guid to lid table in persistent db */
1310	osm_db_store(p_mgr->p_g2l);
1311
1312	if (p_mgr->send_set_reqs == FALSE)
1313		signal = OSM_SIGNAL_DONE;
1314	else
1315		signal = OSM_SIGNAL_DONE_PENDING;
1316
1317	CL_PLOCK_RELEASE(p_mgr->p_lock);
1318
1319	OSM_LOG_EXIT(p_mgr->p_log);
1320	return (signal);
1321}
1322