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