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