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