]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/opensm/opensm/osm_lid_mgr.c
MFV r353623: 10473 zfs(1M) missing cross-reference to zfs-program(1M)
[FreeBSD/FreeBSD.git] / contrib / ofed / opensm / opensm / osm_lid_mgr.c
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
109 void osm_lid_mgr_construct(IN osm_lid_mgr_t * p_mgr)
110 {
111         memset(p_mgr, 0, sizeof(*p_mgr));
112 }
113
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 **********************************************************************/
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
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
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 **********************************************************************/
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 **********************************************************************/
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 **********************************************************************/
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
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 **********************************************************************/
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  **********************************************************************/
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
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 **********************************************************************/
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
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 **********************************************************************/
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 }