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