[OPENSM] When trying to set to INIT the remote port of the given physical port
[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 database\n" );
308         status = IB_ERROR;
309         goto Exit;
310       }
311       else
312       {
313        osm_log( p_mgr->p_log, OSM_LOG_ERROR,
314                 "osm_lid_mgr_init: ERR 0317: "
315                 "Error restoring Guid-to-Lid persistent database\n");
316       }
317     }
318
319     /* we need to make sure we did not get duplicates with
320        current lmc */
321     __osm_lid_mgr_validate_db(p_mgr);
322   }
323
324 Exit:
325   OSM_LOG_EXIT( p_mgr->p_log );
326   return( status );
327 }
328
329 /**********************************************************************
330  initialize the manager for a new sweep:
331  scans the known persistent assignment and port_lid_tbl
332  re-calculate all empty ranges.
333  cleanup invalid port_lid_tbl entries
334 **********************************************************************/
335 int
336 __osm_lid_mgr_init_sweep(
337   IN osm_lid_mgr_t* const p_mgr )
338 {
339   cl_ptr_vector_t     *p_discovered_vec = &p_mgr->p_subn->port_lid_tbl;
340   cl_ptr_vector_t     *p_persistent_vec = &p_mgr->used_lids;
341   uint16_t             max_defined_lid;
342   uint16_t             max_persistent_lid;
343   uint16_t             max_discovered_lid;
344   uint16_t             lid;
345   uint16_t             disc_min_lid;
346   uint16_t             disc_max_lid;
347   uint16_t             db_min_lid;
348   uint16_t             db_max_lid;
349   int                  status = 0;
350   cl_list_item_t      *p_item;
351   boolean_t            is_free;
352   osm_lid_mgr_range_t *p_range = NULL;
353   osm_port_t          *p_port;
354   cl_qmap_t           *p_port_guid_tbl;
355   uint8_t              lmc_num_lids = (uint8_t)(1 << p_mgr->p_subn->opt.lmc);
356   uint16_t             lmc_mask;
357   uint16_t             req_lid, num_lids;
358
359   OSM_LOG_ENTER( p_mgr->p_log, __osm_lid_mgr_init_sweep );
360
361   if (p_mgr->p_subn->opt.lmc)
362     lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
363   else
364     lmc_mask = 0xffff;
365
366   /* if we came out of standby we need to discard any previous guid2lid
367      info we might have. 
368      Do this only if the honor_guid2lid_file option is FALSE. If not, then
369      need to honor this file. */
370   if ( p_mgr->p_subn->coming_out_of_standby == TRUE )
371   {
372     if ( p_mgr->p_subn->opt.honor_guid2lid_file == FALSE )
373     {
374       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
375                "__osm_lid_mgr_init_sweep: "
376                "Ignore guid2lid file when coming out of standby\n");
377       osm_db_clear( p_mgr->p_g2l );
378       for (lid = 0; lid < cl_ptr_vector_get_size(&p_mgr->used_lids); lid++)
379         cl_ptr_vector_set(p_persistent_vec, lid, NULL);
380     }
381     else
382     {
383       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
384                "__osm_lid_mgr_init_sweep: "
385                "Honor current guid2lid file when coming out of standby\n");
386       osm_db_clear( p_mgr->p_g2l );
387       if (osm_db_restore(p_mgr->p_g2l))
388         osm_log( p_mgr->p_log, OSM_LOG_ERROR,
389                  "osm_lid_mgr_init_sweep: ERR 0306: " 
390                  "Error restoring Guid-to-Lid persistant database. Ignoring it\n");
391     }
392   }
393
394   /* we need to cleanup the empty ranges list */
395   p_item = cl_qlist_remove_head( &p_mgr->free_ranges );
396   while ( p_item != cl_qlist_end( &p_mgr->free_ranges ) )
397   {
398     cl_free( (osm_lid_mgr_range_t *)p_item );
399     p_item = cl_qlist_remove_head( &p_mgr->free_ranges );
400   }
401
402   /* first clean up the port_by_lid_tbl */
403   for (lid = 0; lid < cl_ptr_vector_get_size(p_discovered_vec); lid++)
404     cl_ptr_vector_set(p_discovered_vec, lid, NULL);
405
406   /* we if are in the first sweep and in re-assign lids mode
407      we should ignore all the available info and simply define one
408      huge empty range */
409   if ((p_mgr->p_subn->first_time_master_sweep == TRUE) &&
410       (p_mgr->p_subn->opt.reassign_lids == TRUE ))
411   {
412     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
413              "__osm_lid_mgr_init_sweep: "
414              "Skipping all lids as we are reassigning them\n");
415     p_range =
416       (osm_lid_mgr_range_t *)cl_malloc(sizeof(osm_lid_mgr_range_t));
417     p_range->min_lid = 1;
418     goto AfterScanningLids;
419   }
420
421   /* go over all discovered ports and mark their entries */
422   p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl;
423
424   for( p_port = (osm_port_t*)cl_qmap_head( p_port_guid_tbl );
425        p_port != (osm_port_t*)cl_qmap_end( p_port_guid_tbl );
426        p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item ) )
427   {
428     osm_port_get_lid_range_ho(p_port, &disc_min_lid, &disc_max_lid);
429     for (lid = disc_min_lid; lid <= disc_max_lid; lid++)
430       cl_ptr_vector_set(p_discovered_vec, lid, p_port );
431     /* make sure the guid2lid entry is valid. If not, clean it. */
432     if (!osm_db_guid2lid_get( p_mgr->p_g2l,
433                               cl_ntoh64(osm_port_get_guid(p_port)),
434                               &db_min_lid, &db_max_lid))
435     {
436       if ( osm_node_get_type( osm_port_get_parent_node( p_port ) ) !=
437            IB_NODE_TYPE_SWITCH)
438         num_lids = lmc_num_lids;
439       else
440         num_lids = 1;
441
442       if ((num_lids != 1) &&
443           (((db_min_lid & lmc_mask) != db_min_lid) ||
444            (db_max_lid - db_min_lid + 1 < num_lids)) )
445       {
446         /* Not aligned, or not wide enough, then remove the entry */
447         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
448                  "__osm_lid_mgr_init_sweep: "
449                  "Cleaning persistent entry for guid:0x%016" PRIx64
450                  " illegal range:[0x%x:0x%x]\n",
451                  cl_ntoh64(osm_port_get_guid(p_port)), db_min_lid,
452                  db_max_lid );
453         osm_db_guid2lid_delete( p_mgr->p_g2l,
454                                 cl_ntoh64(osm_port_get_guid(p_port)));
455         for ( lid = db_min_lid ; lid <= db_max_lid ; lid++ )
456           cl_ptr_vector_set(p_persistent_vec, lid, NULL);
457       }
458     }
459   }
460
461   /* 
462      Our task is to find free lid ranges.
463      A lid can be used if
464      1. a persistent assignment exists
465      2. the lid is used by a discovered port that does not have a persistent
466         assignment.
467      
468      scan through all lid values of both the persistent table and
469      discovered table. 
470      If the lid has an assigned port in the discovered table:
471      * make sure the lid matches the persistent table, or 
472      * there is no other persistent assignment for that lid.
473      * else cleanup the port_by_lid_tbl, mark this as empty range.
474      Else if the lid does not have an entry in the persistent table
475      mark it as free.
476   */
477
478   /* find the range of lids to scan */
479   max_discovered_lid = (uint16_t)cl_ptr_vector_get_size(p_discovered_vec);
480   max_persistent_lid = (uint16_t)cl_ptr_vector_get_size(p_persistent_vec);
481
482   /* but the vectors have one extra entry for lid=0 */
483   if (max_discovered_lid) max_discovered_lid--;
484   if (max_persistent_lid) max_persistent_lid--;
485
486   if (max_persistent_lid > max_discovered_lid)
487     max_defined_lid = max_persistent_lid;
488   else
489     max_defined_lid = max_discovered_lid;
490
491   for (lid = 1; lid <= max_defined_lid ; lid++)
492   {
493     is_free = TRUE;
494     /* first check to see if the lid is used by a persistent assignment */
495     if ((lid <= max_persistent_lid) && cl_ptr_vector_get(p_persistent_vec, lid))
496     {
497       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
498                "__osm_lid_mgr_init_sweep: "
499                "0x%04x is not free as its mapped by the persistent db\n",
500                lid);
501       is_free = FALSE;
502     }
503     else
504     {
505       /* check this is a discovered port */
506       if (lid <= max_discovered_lid && (p_port = (osm_port_t *)cl_ptr_vector_get(p_discovered_vec, lid)))
507       {
508         /* we have a port. Now lets see if we can preserve its lid range. */
509         /* For that, we need to make sure:
510            1. The port has a (legal) persistency entry. Then the local lid
511               is free (we will use the persistency value).
512            2. Can the port keep its local assignment?
513               a. Make sure the lid a aligned.
514               b. Make sure all needed lids (for the lmc) are free according
515                  to persistency table.
516         */
517       /* qualify the guid of the port is not persistently mapped to 
518          another range */
519       if (!osm_db_guid2lid_get( p_mgr->p_g2l,
520                                 cl_ntoh64(osm_port_get_guid(p_port)),
521                                 &db_min_lid, &db_max_lid))
522       {
523           osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
524                    "__osm_lid_mgr_init_sweep: "
525                    "0x%04x is free as it was discovered "
526                    "but mapped by the persistent db to [0x%04x:0x%04x]\n",
527                    lid, db_min_lid, db_max_lid);
528         }
529         else
530         {
531           /* can the port keep its assignment ? */
532           /* get the lid range of that port, and the required number
533              of lids we are about to assign to it */
534           osm_port_get_lid_range_ho(p_port, &disc_min_lid, &disc_max_lid);
535           if ( osm_node_get_type( osm_port_get_parent_node( p_port ) ) !=
536                IB_NODE_TYPE_SWITCH)
537           {
538             disc_max_lid = disc_min_lid + lmc_num_lids - 1;
539             num_lids = lmc_num_lids;
540         }
541         else
542         {
543             num_lids = 1;
544           }
545           /* Make sure the lid is aligned */
546           if ((num_lids != 1) && ((disc_min_lid & lmc_mask) != disc_min_lid))
547           {
548             /* The lid cannot be used */
549           osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
550                    "__osm_lid_mgr_init_sweep: "
551                      "0x%04x is free as it was discovered "
552                      "but not aligned\n",
553                      lid );
554       }
555       else
556       {
557             /* check that all needed lids are not persistently mapped */
558             is_free = FALSE;
559             for ( req_lid = disc_min_lid + 1 ; req_lid <= disc_max_lid ; req_lid++ )
560             {
561               if ((req_lid <= max_persistent_lid) && cl_ptr_vector_get(p_persistent_vec, req_lid))
562               {
563         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
564                  "__osm_lid_mgr_init_sweep: "
565                          "0x%04x is free as it was discovered "
566                          "but mapped\n",
567                  lid);
568                 is_free = TRUE;
569                 break;
570               }
571       }
572       if (is_free == FALSE)
573       {
574               /* This port will use its local lid, and consume the entire required lid range.
575                  Thus we can skip that range. */
576               /* If the disc_max_lid is greater then lid, we can skip right to it, 
577                  since we've done all neccessary checks on the lids in between. */
578               if (disc_max_lid > lid)
579                 lid = disc_max_lid;
580       }
581     }
582         }
583       }
584     }
585
586     if (is_free)
587     {
588       if (p_range)
589       {
590         p_range->max_lid = lid;
591       }
592       else
593       {
594         p_range =
595           (osm_lid_mgr_range_t *)cl_malloc(sizeof(osm_lid_mgr_range_t));
596         p_range->min_lid = lid;
597         p_range->max_lid = lid;
598       }
599     }
600     else
601     {
602       /* this lid is used so we need to finalize the previous free range */
603       if (p_range)
604       {
605         cl_qlist_insert_tail( &p_mgr->free_ranges, &p_range->item );
606         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
607                  "__osm_lid_mgr_init_sweep: "
608                  "new free lid range [0x%x:0x%x]\n",
609                  p_range->min_lid, p_range->max_lid);
610         p_range = NULL;
611       }
612     }
613   }
614
615  AfterScanningLids:
616   /* after scanning all known lids we need to extend the last range 
617      to the max allowed lid */
618   if (!p_range)
619   {
620     p_range =
621       (osm_lid_mgr_range_t *)cl_malloc(sizeof(osm_lid_mgr_range_t));
622     /* 
623        The p_range can be NULL in one of 2 cases:
624        1. If max_defined_lid == 0. In this case, we want the entire range.
625        2. If all lids discovered in the loop where mapped. In this case
626           no free range exists, and we want to define it after the last 
627           mapped lid.
628     */
629     p_range->min_lid = lid;
630   }
631   p_range->max_lid = p_mgr->p_subn->max_unicast_lid_ho - 1;
632   cl_qlist_insert_tail( &p_mgr->free_ranges, &p_range->item );
633   osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
634            "__osm_lid_mgr_init_sweep: "
635            "final free lid range [0x%x:0x%x]\n",
636            p_range->min_lid, p_range->max_lid);
637
638   OSM_LOG_EXIT( p_mgr->p_log );
639   return status;
640 }
641
642 /**********************************************************************
643  check if the given range of lids is free 
644 **********************************************************************/
645 static boolean_t
646 __osm_lid_mgr_is_range_not_persistent(
647   IN osm_lid_mgr_t* const p_mgr,
648   IN const uint16_t lid,
649   IN const uint16_t num_lids )
650 {
651   uint16_t        i;
652   cl_status_t     status;
653   osm_port_t     *p_port;
654   const uint8_t   start_lid = (uint8_t)(1 << p_mgr->p_subn->opt.lmc);
655   const cl_ptr_vector_t* const p_tbl = &p_mgr->used_lids;
656
657   if( lid < start_lid )
658     return( FALSE );
659
660   for( i = lid; i < lid + num_lids; i++ )
661   {
662     status = cl_ptr_vector_at( p_tbl, i, (void*)&p_port );
663     if( status == CL_SUCCESS )
664     {
665       if(p_port != NULL)
666         return( FALSE );
667     }
668     else
669     {
670       /*
671         We are out of range in the array.
672         Consider all further entries "free".
673       */
674       return( TRUE );
675     }
676   }
677
678   return( TRUE );
679 }
680
681 /**********************************************************************
682 find a free lid range
683 **********************************************************************/
684 static void
685 __osm_lid_mgr_find_free_lid_range(
686   IN osm_lid_mgr_t* const p_mgr,
687   IN const uint8_t num_lids,
688   OUT uint16_t* const p_min_lid,
689   OUT uint16_t* const p_max_lid )
690 {
691   uint16_t             lid;
692   cl_list_item_t      *p_item;
693   cl_list_item_t      *p_next_item;
694   osm_lid_mgr_range_t *p_range = NULL;
695   uint8_t              lmc_num_lids;
696   uint16_t             lmc_mask;
697
698   osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
699            "__osm_lid_mgr_find_free_lid_range: "
700            "LMC = %u, number LIDs = %u\n",
701            p_mgr->p_subn->opt.lmc, num_lids );
702
703   lmc_num_lids = (1 << p_mgr->p_subn->opt.lmc );
704   if (p_mgr->p_subn->opt.lmc)
705     lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
706   else
707     lmc_mask = 0xffff;
708
709   /*
710     Search the list of free lid ranges for a range which is big enough
711   */
712   p_item = cl_qlist_head( &p_mgr->free_ranges );
713   while( p_item != cl_qlist_end( &p_mgr->free_ranges ) )
714   {
715     p_next_item = cl_qlist_next( p_item );
716     p_range = (osm_lid_mgr_range_t *)p_item;
717
718     lid = p_range->min_lid;
719
720     /* if we require more then one lid we must align to LMC */
721     if (num_lids > 1)
722     {
723       if ((lid & lmc_mask) != lid)
724         lid = (lid + lmc_num_lids) & lmc_mask;
725     }
726
727     /* but we can be out of the range */
728     if (lid + num_lids - 1 <= p_range->max_lid)
729     {
730       /* ok let us use that range */
731       if (lid + num_lids - 1 == p_range->max_lid)
732       {
733         /* we consumed the entire range */
734         cl_qlist_remove_item( &p_mgr->free_ranges, p_item );
735       }
736       else
737       {
738         /* only update the available range */
739         p_range->min_lid = lid + num_lids;
740       }
741
742       *p_min_lid = lid;
743       *p_max_lid = (uint16_t)(lid + num_lids - 1);
744       return;
745     }
746     p_item = p_next_item;
747   }
748
749   /*
750     Couldn't find a free range of lids.
751   */
752   *p_min_lid = *p_max_lid = 0;
753   /* if we run out of lids, give an error and abort! */
754   osm_log( p_mgr->p_log, OSM_LOG_ERROR,
755            "__osm_lid_mgr_find_free_lid_range: ERR 0307: "
756            "OPENSM RAN OUT OF LIDS!!!\n");
757   CL_ASSERT( 0 );
758 }
759
760 /**********************************************************************
761  **********************************************************************/
762 void
763  __osm_lid_mgr_cleanup_discovered_port_lid_range(
764    IN osm_lid_mgr_t* p_mgr,
765    IN osm_port_t *p_port )
766 {
767   cl_ptr_vector_t *p_discovered_vec = &p_mgr->p_subn->port_lid_tbl;
768   uint16_t         lid, min_lid, max_lid;
769   uint16_t         max_tbl_lid = (uint16_t)(cl_ptr_vector_get_size( p_discovered_vec ));
770
771   osm_port_get_lid_range_ho(p_port, &min_lid, &max_lid);
772   for (lid = min_lid; lid <= max_lid; lid++)
773   {
774     if ((lid < max_tbl_lid ) &&
775         (p_port == (osm_port_t*)cl_ptr_vector_get(p_discovered_vec, lid)))
776       cl_ptr_vector_set(p_discovered_vec, lid, NULL );
777   }
778 }
779
780 /**********************************************************************
781  0.1 if the port info lid matches the guid2lid return 0
782  0.2 if the port info has a lid and that range is empty in
783      port_lid_tbl, return 0 and update the port_lid_tbl and
784      guid2lid
785  0.3 else find an empty space in port_lid_tbl,  update the
786  port_lid_tbl and guid2lid, return 1 to flag a change required.
787 **********************************************************************/
788 int
789 __osm_lid_mgr_get_port_lid(
790   IN osm_lid_mgr_t* const p_mgr,
791   IN osm_port_t * const p_port,
792   OUT uint16_t* const p_min_lid,
793   OUT uint16_t* const p_max_lid)
794 {
795   uint16_t lid, min_lid, max_lid;
796   uint64_t guid;
797   uint8_t  num_lids = (1 << p_mgr->p_subn->opt.lmc);
798   int      lid_changed = 0;
799   uint16_t lmc_mask;
800
801   OSM_LOG_ENTER( p_mgr->p_log, __osm_lid_mgr_get_port_lid );
802
803   if (p_mgr->p_subn->opt.lmc)
804     lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
805   else
806     lmc_mask = 0xffff;
807
808   /* get the lid from the guid2lid */
809   guid = cl_ntoh64( osm_port_get_guid( p_port ) );
810
811   /* if the port is a switch then we only need one lid */
812   if( osm_node_get_type( osm_port_get_parent_node( p_port ) ) ==
813       IB_NODE_TYPE_SWITCH )
814     num_lids = 1;
815
816   /* if the port matches the guid2lid */
817   if (!osm_db_guid2lid_get( p_mgr->p_g2l, guid, &min_lid, &max_lid))
818   {
819     *p_min_lid = min_lid;
820     *p_max_lid = min_lid + num_lids - 1;
821     if (min_lid == cl_ntoh16(osm_port_get_base_lid(p_port)))
822     {
823       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
824                "__osm_lid_mgr_get_port_lid: "
825                "0x%016" PRIx64" matches its known lid:0x%04x\n",
826                guid, min_lid);
827       goto Exit;
828     }
829     else
830     {
831       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
832                "__osm_lid_mgr_get_port_lid: "
833                "0x%016" PRIx64
834                " with lid:0x%04x does not match its known lid:0x%04x\n",
835                guid, cl_ntoh16(osm_port_get_base_lid(p_port)), min_lid);
836       __osm_lid_mgr_cleanup_discovered_port_lid_range( p_mgr, p_port );
837       /* we still need to send the setting to the target port */
838       lid_changed = 1;
839       goto Exit;
840     }
841   }
842   else
843   {
844     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
845              "__osm_lid_mgr_get_port_lid: "
846              "0x%016" PRIx64" has no persistent lid assigned\n",
847              guid);
848   }
849
850   /* if the port info carries a lid it must be lmc aligned and not mapped
851      by the pesistent storage  */
852   min_lid = cl_ntoh16(osm_port_get_base_lid(p_port));
853   
854   /* we want to ignore the discovered lid if we are also on first sweep of
855      re-assign lids flow */
856   if (min_lid &&
857       ! ((p_mgr->p_subn->first_time_master_sweep == TRUE) &&
858          (p_mgr->p_subn->opt.reassign_lids == TRUE )))
859   {
860     /* make sure lid is valid */
861     if ((num_lids == 1) || ((min_lid & lmc_mask) == min_lid))
862     {
863       /* is it free */
864       if (__osm_lid_mgr_is_range_not_persistent(p_mgr, min_lid, num_lids))
865       {
866         *p_min_lid = min_lid;
867         *p_max_lid = min_lid + num_lids - 1;
868         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
869                  "__osm_lid_mgr_get_port_lid: "
870                  "0x%016" PRIx64" lid range:[0x%x-0x%x] is free\n",
871                  guid, *p_min_lid, *p_max_lid);
872         goto NewLidSet;
873       }
874       else
875       {
876         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
877                  "__osm_lid_mgr_get_port_lid: "
878                  "0x%016" PRIx64
879                  " existing lid range:[0x%x:0x%x] is not free\n",
880                  guid, min_lid, min_lid + num_lids - 1);
881       }
882     }
883     else
884     {
885       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
886                "__osm_lid_mgr_get_port_lid: "
887                "0x%016" PRIx64
888                " existing lid range:[0x%x:0x%x] is not lmc aligned\n",
889                guid, min_lid, min_lid + num_lids - 1);
890     }
891   }
892
893   /* first cleanup the existing discovered lid range */
894   __osm_lid_mgr_cleanup_discovered_port_lid_range( p_mgr, p_port );
895
896   /* find an empty space */
897   __osm_lid_mgr_find_free_lid_range(p_mgr, num_lids, p_min_lid, p_max_lid);
898   osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
899            "__osm_lid_mgr_get_port_lid: "
900            "0x%016" PRIx64" assigned a new lid range:[0x%x-0x%x]\n",
901            guid, *p_min_lid, *p_max_lid);
902   lid_changed = 1;
903
904  NewLidSet:
905   /* update the guid2lid db and used_lids */
906   osm_db_guid2lid_set(p_mgr->p_g2l, guid, *p_min_lid, *p_max_lid);
907   for (lid = *p_min_lid; lid <= *p_max_lid; lid++)
908     cl_ptr_vector_set(&p_mgr->used_lids, lid, (void*)1);
909
910  Exit:
911   /* make sure the assigned lids are marked in port_lid_tbl */
912   for (lid = *p_min_lid; lid <= *p_max_lid; lid++)
913     cl_ptr_vector_set(&p_mgr->p_subn->port_lid_tbl, lid, p_port);
914
915   OSM_LOG_EXIT( p_mgr->p_log );
916   return lid_changed;
917 }
918
919 /**********************************************************************
920  Set to INIT the remote port of the given physical port
921  **********************************************************************/
922 static void
923 __osm_lid_mgr_set_remote_pi_state_to_init(
924   IN osm_lid_mgr_t *       const p_mgr,
925   IN osm_physp_t*          const p_physp)
926 {
927   ib_port_info_t *p_pi;
928   osm_physp_t *p_rem_physp = osm_physp_get_remote(p_physp);
929
930   if ( p_rem_physp == NULL )
931     return;
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 }