xref: /trueos/contrib/ofed/management/opensm/opensm/osm_lid_mgr.c (revision 8fe640108653f13042f1b15213769e338aa524f6)
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  **********************************************************************/
101 typedef 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  **********************************************************************/
osm_lid_mgr_construct(IN osm_lid_mgr_t * const p_mgr)109 void 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  **********************************************************************/
osm_lid_mgr_destroy(IN osm_lid_mgr_t * const p_mgr)117 void 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 /**********************************************************************
133 Validate the guid to lid data by making sure that under the current
134 LMC we did not get duplicates. If we do flag them as errors and remove
135 the entry.
136 **********************************************************************/
__osm_lid_mgr_validate_db(IN osm_lid_mgr_t * p_mgr)137 static 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 */
228 Exit:
229 	OSM_LOG_EXIT(p_mgr->p_log);
230 }
231 
232 /**********************************************************************
233  **********************************************************************/
234 ib_api_status_t
osm_lid_mgr_init(IN osm_lid_mgr_t * const p_mgr,IN osm_sm_t * sm)235 osm_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 
288 Exit:
289 	OSM_LOG_EXIT(p_mgr->p_log);
290 	return (status);
291 }
292 
__osm_trim_lid(IN uint16_t lid)293 static 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 **********************************************************************/
__osm_lid_mgr_init_sweep(IN osm_lid_mgr_t * const p_mgr)306 static 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 
588 AfterScanningLids:
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 **********************************************************************/
620 static boolean_t
__osm_lid_mgr_is_range_not_persistent(IN osm_lid_mgr_t * const p_mgr,IN const uint16_t lid,IN const uint16_t num_lids)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 /**********************************************************************
651 find a free lid range
652 **********************************************************************/
653 static void
__osm_lid_mgr_find_free_lid_range(IN osm_lid_mgr_t * const p_mgr,IN const uint8_t num_lids,OUT uint16_t * const p_min_lid,OUT uint16_t * const p_max_lid)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  **********************************************************************/
721 static void
__osm_lid_mgr_cleanup_discovered_port_lid_range(IN osm_lid_mgr_t * p_mgr,IN osm_port_t * p_port)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 **********************************************************************/
749 static int
__osm_lid_mgr_get_port_lid(IN osm_lid_mgr_t * const p_mgr,IN osm_port_t * const p_port,OUT uint16_t * const p_min_lid,OUT uint16_t * const p_max_lid)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 
845 NewLidSet:
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 
851 Exit:
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  **********************************************************************/
863 static void
__osm_lid_mgr_set_remote_pi_state_to_init(IN osm_lid_mgr_t * const p_mgr,IN osm_physp_t * const p_physp)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  **********************************************************************/
878 static boolean_t
__osm_lid_mgr_set_physp_pi(IN osm_lid_mgr_t * const p_mgr,IN osm_port_t * const p_port,IN osm_physp_t * const p_physp,IN ib_net16_t const lid)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 
1138 Exit:
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 **********************************************************************/
1147 static boolean_t
__osm_lid_mgr_process_our_sm_node(IN osm_lid_mgr_t * const p_mgr)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 
1198 Exit:
1199 	OSM_LOG_EXIT(p_mgr->p_log);
1200 	return res;
1201 }
1202 
1203 /**********************************************************************
1204  **********************************************************************/
osm_lid_mgr_process_sm(IN osm_lid_mgr_t * const p_mgr)1205 osm_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 **********************************************************************/
osm_lid_mgr_process_subnet(IN osm_lid_mgr_t * const p_mgr)1242 osm_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