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