46d630d63927b2bf8dd433d017ac6887a70cc6d6
[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 range 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 acording 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       osm_log( p_mgr->p_log, OSM_LOG_ERROR,
305                "osm_lid_mgr_init: ERR 0317: " 
306                "Error restoring Guid-to-Lid persistent database.\n");
307       status = IB_ERROR;
308       goto Exit;
309     }
310
311     /* we need to make sure we did not get duplicates with
312        current lmc */
313     __osm_lid_mgr_validate_db(p_mgr);
314   }
315
316  Exit:
317   OSM_LOG_EXIT( p_mgr->p_log );
318   return( status );
319 }
320
321 /**********************************************************************
322  initialize the manager for a new sweep:
323  scans the known persistent assignment and port_lid_tbl
324  re-calculate all empty ranges.
325  cleanup invalid port_lid_tbl entries
326 **********************************************************************/
327 int
328 __osm_lid_mgr_init_sweep(
329   IN osm_lid_mgr_t* const p_mgr )
330 {
331
332   cl_ptr_vector_t     *p_discovered_vec = &p_mgr->p_subn->port_lid_tbl;
333   cl_ptr_vector_t     *p_persistent_vec = &p_mgr->used_lids;
334   uint16_t             max_defined_lid;
335   uint16_t             max_persistent_lid;
336   uint16_t             max_discovered_lid;
337   uint16_t             lid;
338   uint16_t             disc_min_lid;
339   uint16_t             disc_max_lid;
340   uint16_t             db_min_lid;
341   uint16_t             db_max_lid;
342   int                  status = 0;
343   cl_list_item_t      *p_item;
344   boolean_t            is_free;
345   osm_lid_mgr_range_t *p_range = NULL;
346   osm_port_t          *p_port;
347   cl_qmap_t           *p_port_guid_tbl;
348   uint8_t              lmc_num_lids = (uint8_t)(1 << p_mgr->p_subn->opt.lmc);
349   uint16_t             lmc_mask;
350   uint16_t             req_lid, num_lids;
351   
352   OSM_LOG_ENTER( p_mgr->p_log, __osm_lid_mgr_init_sweep );
353
354   if (p_mgr->p_subn->opt.lmc)
355     lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
356   else
357     lmc_mask = 0xffff;
358
359   /* if we came out of standby we need to discard any previous guid 2 lid
360      info we might have */
361   if ( p_mgr->p_subn->coming_out_of_standby == TRUE )
362   {
363     osm_db_clear( p_mgr->p_g2l );
364     for (lid = 0; lid < cl_ptr_vector_get_size(&p_mgr->used_lids); lid++)
365       cl_ptr_vector_set(p_persistent_vec, lid, NULL);
366   }
367
368   /* we need to cleanup the empty ranges list */
369   p_item = cl_qlist_remove_head( &p_mgr->free_ranges );
370   while ( p_item != cl_qlist_end( &p_mgr->free_ranges ) )
371   {
372     cl_free( (osm_lid_mgr_range_t *)p_item );
373     p_item = cl_qlist_remove_head( &p_mgr->free_ranges );
374   }
375
376   /* first clean up the port_by_lid_tbl */
377   for (lid = 0; lid < cl_ptr_vector_get_size(p_discovered_vec); lid++)
378     cl_ptr_vector_set(p_discovered_vec, lid, NULL);
379
380   /* we if are in the first sweep and in re-assign lids mode 
381      we should ignore all the available info and simply define one 
382      huge empty range */
383   if ((p_mgr->p_subn->first_time_master_sweep == TRUE) &&
384       (p_mgr->p_subn->opt.reassign_lids == TRUE ))
385   {
386     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
387              "__osm_lid_mgr_init_sweep: "
388              "Skipping all lids - as we are reassigning them.\n");
389     p_range =
390       (osm_lid_mgr_range_t *)cl_malloc(sizeof(osm_lid_mgr_range_t));
391     p_range->min_lid = 1;
392     goto AfterScanningLids;
393   }
394
395   /* go over all discovered ports and mark their entries */
396   p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl;
397
398   for( p_port = (osm_port_t*)cl_qmap_head( p_port_guid_tbl );
399        p_port != (osm_port_t*)cl_qmap_end( p_port_guid_tbl );
400        p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item ) )
401   {
402     osm_port_get_lid_range_ho(p_port, &disc_min_lid, &disc_max_lid);
403     for (lid = disc_min_lid; lid <= disc_max_lid; lid++)
404       cl_ptr_vector_set(p_discovered_vec, lid, p_port );
405     /* make sure the guid2lid entry is valid. If not - clean it. */
406     if (!osm_db_guid2lid_get( p_mgr->p_g2l,
407                               cl_ntoh64(osm_port_get_guid(p_port)),
408                               &db_min_lid, &db_max_lid))
409     {
410       if ( osm_node_get_type( osm_port_get_parent_node( p_port ) ) !=
411            IB_NODE_TYPE_SWITCH)
412         num_lids = lmc_num_lids;
413       else
414         num_lids = 1;
415
416       if ((num_lids != 1) &&
417           (((db_min_lid & lmc_mask) != db_min_lid) ||
418            (db_max_lid - db_min_lid + 1 < num_lids)) )
419       {
420         /* Not aligned, or not wide enough - remove the entry */
421         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
422                  "__osm_lid_mgr_init_sweep: "
423                  "Cleaning persistent entry for guid:0x%016" PRIx64
424                  " illegal range:[0x%x:0x%x] \n",
425                  cl_ntoh64(osm_port_get_guid(p_port)), db_min_lid,
426                  db_max_lid );
427         osm_db_guid2lid_delete( p_mgr->p_g2l,
428                                 cl_ntoh64(osm_port_get_guid(p_port)));
429         for ( lid = db_min_lid ; lid <= db_max_lid ; lid++ )
430           cl_ptr_vector_set(p_persistent_vec, lid, NULL);
431       }
432     }
433   }
434
435   /* 
436      Our task is to find free lid ranges.
437      A lid can be used if
438      1. a persistent assignment exists
439      2. the lid is used by a discovered port that does not have a persistent 
440      assignment.
441      
442      scan through all lid values of both the persistent table and
443      discovered table. 
444      If the lid has an assigned port in the discovered table:
445      * make sure the lid matches the persistent table, or 
446      * there is no other persistent assignment for that lid.
447      * else cleanup the port_by_lid_tbl, mark this as empty range.
448      Else if the lid does not have an entry in the persistent table
449      mark it as free.
450   */
451
452   /* find the range of lids to scan */
453   max_discovered_lid = (uint16_t)cl_ptr_vector_get_size(p_discovered_vec);
454   max_persistent_lid = (uint16_t)cl_ptr_vector_get_size(p_persistent_vec);
455
456   /* but the vectors have one extra entry for lid=0 */
457   if (max_discovered_lid) max_discovered_lid--;
458   if (max_persistent_lid) max_persistent_lid--;
459
460   if (max_persistent_lid > max_discovered_lid)
461     max_defined_lid = max_persistent_lid;
462   else
463     max_defined_lid = max_discovered_lid;
464
465   for (lid = 1; lid <= max_defined_lid ; lid++)
466   {
467     is_free = TRUE;
468     /* first check to see if the lid is used by a persistent assignment */
469     if ((lid <= max_persistent_lid) && cl_ptr_vector_get(p_persistent_vec, lid))
470     {
471       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
472                "__osm_lid_mgr_init_sweep: "
473                "0x%04x is not free as its mapped by the persistent db.\n",
474                lid);
475       is_free = FALSE;
476     }
477     else
478     {
479       /* check this is a discovered port */
480       if (lid <= max_discovered_lid && (p_port = (osm_port_t *)cl_ptr_vector_get(p_discovered_vec, lid)))
481       {
482         /* we have a port. Now lets see if we can preserve its lid range. */
483         /* For that - we need to make sure:
484            1. The port has a (legal) persistency entry. Then the local lid
485            is free (we will use the persistency value).
486            2. Can the port keep its local assignment?
487            a. Make sure the lid a aligned.
488            b. Make sure all needed lids (for the lmc) are free according
489            to persistency table.
490         */
491         /* qualify the guid of the port is not persistently mapped to 
492            another range */
493         if (!osm_db_guid2lid_get( p_mgr->p_g2l,
494                                   cl_ntoh64(osm_port_get_guid(p_port)),
495                                   &db_min_lid, &db_max_lid))
496         {
497           osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
498                    "__osm_lid_mgr_init_sweep: "
499                    "0x%04x is free as it was discovered "
500                    "but mapped by the persistent db to [0x%04x:0x%04x].\n",
501                    lid, db_min_lid, db_max_lid);
502         }
503         else
504         {
505           /* can the port keep its assignment ? */
506           /* get the lid range of that port, and the required number
507              of lids we are about to assign to it */
508           osm_port_get_lid_range_ho(p_port, &disc_min_lid, &disc_max_lid);
509           if ( osm_node_get_type( osm_port_get_parent_node( p_port ) ) !=
510                IB_NODE_TYPE_SWITCH)
511           {
512             disc_max_lid = disc_min_lid + lmc_num_lids - 1;
513             num_lids = lmc_num_lids;
514           }
515           else
516           {
517             num_lids = 1;
518           }
519           /* Make sure the lid is aligned */
520           if ((num_lids != 1) && ((disc_min_lid & lmc_mask) != disc_min_lid))
521           {
522             /* The lid cannot be used */
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 not aligned. \n",
527                      lid );
528           }
529           else
530           {
531             /* check that all needed lids are not persistently mapped */
532             is_free = FALSE;
533             for ( req_lid = disc_min_lid + 1 ; req_lid <= disc_max_lid ; req_lid++ )
534             {
535               if ((req_lid <= max_persistent_lid) && cl_ptr_vector_get(p_persistent_vec, req_lid))
536               {
537                 osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
538                          "__osm_lid_mgr_init_sweep: "
539                          "0x%04x is free as it was discovered "
540                          "but mapped. \n",
541                          lid);
542                 is_free = TRUE;
543                 break;
544               }
545             }
546             if (is_free == FALSE)
547             {
548               /* This port will use its local lid, and consume the entire required lid range.
549                  Thus we can skip that range. */
550               /* If the disc_max_lid is greater then lid - we can skip right to it, 
551                  since we've done all neccessary checks on the lids in between. */
552               if (disc_max_lid > lid)
553                 lid = disc_max_lid;
554             }
555           }
556         }
557       }
558     }
559
560     if (is_free)
561     {
562       if (p_range)
563       {
564         p_range->max_lid = lid;
565       }
566       else
567       {
568         p_range =
569           (osm_lid_mgr_range_t *)cl_malloc(sizeof(osm_lid_mgr_range_t));
570         p_range->min_lid = lid;
571         p_range->max_lid = lid;
572       }
573     }
574     else
575     {
576       /* this lid is used so we need to finalize the previous free range */
577       if (p_range)
578       {
579         cl_qlist_insert_tail( &p_mgr->free_ranges, &p_range->item );
580         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
581                  "__osm_lid_mgr_init_sweep: "
582                  "new free lid range [0x%x:0x%x]\n",
583                  p_range->min_lid, p_range->max_lid);
584         p_range = NULL;
585       }
586     }
587   }
588
589  AfterScanningLids:
590   /* after scanning all known lids we need to extend the last range 
591      to the max allowed lid */
592   if (!p_range)
593   {
594     p_range =
595       (osm_lid_mgr_range_t *)cl_malloc(sizeof(osm_lid_mgr_range_t));
596     /* 
597        The p_range can be NULL in one of 2 cases:
598        1. If max_defined_lid == 0. In this case, we want the entire range.
599        2. If all lids discovered in the loop where mapped. In this case
600           no free range exists, and we want to define it after the last 
601           mapped lid.
602     */
603     p_range->min_lid = lid;
604   }
605   p_range->max_lid = p_mgr->p_subn->max_unicast_lid_ho - 1;
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            "final free lid range [0x%x:0x%x]\n",
610            p_range->min_lid, p_range->max_lid);
611
612   OSM_LOG_EXIT( p_mgr->p_log );
613   return status;
614 }
615
616 /**********************************************************************
617  check if the given range of lids is free 
618 **********************************************************************/
619 static boolean_t
620 __osm_lid_mgr_is_range_not_persistent(
621   IN osm_lid_mgr_t* const p_mgr,
622   IN const uint16_t lid,
623   IN const uint16_t num_lids )
624 {
625   uint16_t        i;
626   cl_status_t     status;
627   osm_port_t     *p_port;
628   const uint8_t   start_lid = (uint8_t)(1 << p_mgr->p_subn->opt.lmc);
629   const cl_ptr_vector_t* const p_tbl = &p_mgr->used_lids;
630
631   if( lid < start_lid )
632     return( FALSE );
633
634   for( i = lid; i < lid + num_lids; i++ )
635   {
636     status = cl_ptr_vector_at( p_tbl, i, (void*)&p_port );
637     if( status == CL_SUCCESS )
638     {
639       if(p_port != NULL)
640         return( FALSE );
641     }
642     else
643     {
644       /*
645         We are out of range in the array.
646         Consider all further entries "free".
647       */
648       return( TRUE );
649     }
650   }
651
652   return( TRUE );
653 }
654
655 /**********************************************************************
656 find a free lid range
657 **********************************************************************/
658 static void
659 __osm_lid_mgr_find_free_lid_range(
660   IN osm_lid_mgr_t* const p_mgr,
661   IN const uint8_t num_lids,
662   OUT uint16_t* const p_min_lid,
663   OUT uint16_t* const p_max_lid )
664 {
665   uint16_t             lid;
666   cl_list_item_t      *p_item;
667   cl_list_item_t      *p_next_item;
668   osm_lid_mgr_range_t *p_range = NULL;
669   uint8_t              lmc_num_lids;
670   uint16_t             lmc_mask;
671
672
673   osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
674            "__osm_lid_mgr_find_free_lid_range: "
675            "LMC = %u, number LIDs = %u.\n",
676            p_mgr->p_subn->opt.lmc, num_lids );
677
678   lmc_num_lids = (1 << p_mgr->p_subn->opt.lmc );
679   if (p_mgr->p_subn->opt.lmc)
680     lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
681   else
682     lmc_mask = 0xffff;
683
684   /*
685     Search the list of free lid ranges for a range which is big enough
686   */
687   p_item = cl_qlist_head( &p_mgr->free_ranges );
688   while( p_item != cl_qlist_end( &p_mgr->free_ranges ) )
689   {
690     p_next_item = cl_qlist_next( p_item );
691     p_range = (osm_lid_mgr_range_t *)p_item;
692
693     lid = p_range->min_lid;
694
695     /* if we require more then one lid we must align to LMC */
696     if (num_lids > 1)
697     {
698       if ((lid & lmc_mask) != lid)
699         lid = (lid + lmc_num_lids) & lmc_mask;
700     }
701
702     /* but we can be out of the range */
703     if (lid + num_lids - 1 <= p_range->max_lid)
704     {
705       /* ok let us use that range */
706       if (lid + num_lids - 1 == p_range->max_lid)
707       {
708         /* we consumed the entire range */
709         cl_qlist_remove_item( &p_mgr->free_ranges, p_item );
710       }
711       else
712       {
713         /* only update the available range */
714         p_range->min_lid = lid + num_lids;
715       }
716
717       *p_min_lid = lid;
718       *p_max_lid = (uint16_t)(lid + num_lids - 1);
719       return;
720     }
721     p_item = p_next_item;
722   }
723
724   /*
725     Couldn't find a free range of lids.
726   */
727   *p_min_lid = *p_max_lid = 0;
728   /* if we run out of lids - give an error and abort! */
729   osm_log( p_mgr->p_log, OSM_LOG_ERROR,
730            "__osm_lid_mgr_find_free_lid_range: ERR 0307: "
731            "OPENSM RAN OUT OF LIDS!!!\n");
732   CL_ASSERT( 0 );
733 }
734
735 /**********************************************************************
736  **********************************************************************/
737 void
738 __osm_lid_mgr_cleanup_discovered_port_lid_range(
739   IN osm_lid_mgr_t* p_mgr,
740   IN osm_port_t *p_port )
741 {
742   cl_ptr_vector_t *p_discovered_vec = &p_mgr->p_subn->port_lid_tbl;
743   uint16_t         lid, min_lid, max_lid;
744   uint16_t         max_tbl_lid = (uint16_t)(cl_ptr_vector_get_size( p_discovered_vec ));
745
746   osm_port_get_lid_range_ho(p_port, &min_lid, &max_lid);
747   for (lid = min_lid; lid <= max_lid; lid++)
748   {
749     if ((lid < max_tbl_lid ) &&
750         (p_port == (osm_port_t*)cl_ptr_vector_get(p_discovered_vec, lid)))
751       cl_ptr_vector_set(p_discovered_vec, lid, NULL );
752   }
753 }
754
755 /**********************************************************************
756  0.1 if the port info lid matches the guid2lid return 0
757  0.2 if the port info has a lid and that range is empty in
758      port_lid_tbl - return 0 and update the port_lid_tbl and
759      guid2lid
760  0.3 else find an empty space in port_lid_tbl,  update the
761  port_lid_tbl and guid2lid, return 1 - to flag a change required.
762 **********************************************************************/
763 int
764 __osm_lid_mgr_get_port_lid(
765   IN osm_lid_mgr_t* const p_mgr,
766   IN osm_port_t * const p_port,
767   OUT uint16_t* const p_min_lid,
768   OUT uint16_t* const p_max_lid)
769 {
770   uint16_t lid, min_lid, max_lid;
771   uint64_t guid;
772   uint8_t  num_lids = (1 << p_mgr->p_subn->opt.lmc);
773   int      lid_changed = 0;
774   uint16_t lmc_mask;
775
776   OSM_LOG_ENTER( p_mgr->p_log, __osm_lid_mgr_get_port_lid );
777
778   if (p_mgr->p_subn->opt.lmc)
779     lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
780   else
781     lmc_mask = 0xffff;
782
783   /* get the lid from the guid2lid */
784   guid = cl_ntoh64( osm_port_get_guid( p_port ) );
785
786   /* if the port is a switch then we only need one lid */
787   if( osm_node_get_type( osm_port_get_parent_node( p_port ) ) ==
788       IB_NODE_TYPE_SWITCH )
789     num_lids = 1;
790
791   /* if the port matches the guid2lid */
792   if (!osm_db_guid2lid_get( p_mgr->p_g2l, guid, &min_lid, &max_lid))
793   {
794     *p_min_lid = min_lid;
795     *p_max_lid = min_lid + num_lids - 1;
796     if (min_lid == cl_ntoh16(osm_port_get_base_lid(p_port)))
797     {
798       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
799                "__osm_lid_mgr_get_port_lid: "
800                "0x%016" PRIx64" matches its known lid:0x%04x\n",
801                guid, min_lid);
802       goto Exit;
803     }
804     else
805     {
806       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
807                "__osm_lid_mgr_get_port_lid: "
808                "0x%016" PRIx64
809                " with lid:0x%04x does not matches its known lid:0x%04x\n",
810                guid, cl_ntoh16(osm_port_get_base_lid(p_port)), min_lid);
811       __osm_lid_mgr_cleanup_discovered_port_lid_range( p_mgr, p_port );
812       /* we still need to send the setting to the target port */
813       lid_changed = 1;
814       goto Exit;
815     }
816   }
817   else
818   {
819     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
820              "__osm_lid_mgr_get_port_lid: "
821              "0x%016" PRIx64" has no persistent lid assigned.\n",
822              guid);
823   }
824
825   /* if the port info carries a lid it must be lmc aligned and not mapped
826      by the pesistent storage  */
827   min_lid = cl_ntoh16(osm_port_get_base_lid(p_port));
828   
829   /* we want to ignore the discovered lid if we are also on first sweep of
830      re-assign lids flow */
831   if (min_lid &&
832       ! ((p_mgr->p_subn->first_time_master_sweep == TRUE) &&
833          (p_mgr->p_subn->opt.reassign_lids == TRUE )))
834   {
835     /* make sure lid is valid */
836     if ((num_lids == 1) || ((min_lid & lmc_mask) == min_lid))
837     {
838       /* is it free */
839       if (__osm_lid_mgr_is_range_not_persistent(p_mgr, min_lid, num_lids))
840       {
841         *p_min_lid = min_lid;
842         *p_max_lid = min_lid + num_lids - 1;
843         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
844                  "__osm_lid_mgr_get_port_lid: "
845                  "0x%016" PRIx64" lid range:[0x%x-0x%x] is free\n",
846                  guid, *p_min_lid, *p_max_lid);
847         goto NewLidSet;
848       }
849       else
850       {
851         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
852                  "__osm_lid_mgr_get_port_lid: "
853                  "0x%016" PRIx64
854                  " existing lid range:[0x%x:0x%x] is not free.\n",
855                  guid, min_lid, min_lid + num_lids - 1);
856       }
857     }
858     else
859     {
860       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
861                "__osm_lid_mgr_get_port_lid: "
862                "0x%016" PRIx64
863                " existing lid range:[0x%x:0x%x] is not lmc aligned.\n",
864                guid, min_lid, min_lid + num_lids - 1);
865     }
866   }
867
868   /* first cleanup the existing discovered lid range */
869   __osm_lid_mgr_cleanup_discovered_port_lid_range( p_mgr, p_port );
870
871   /* find an empty space */
872   __osm_lid_mgr_find_free_lid_range(p_mgr, num_lids, p_min_lid, p_max_lid);
873   osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
874            "__osm_lid_mgr_get_port_lid: "
875            "0x%016" PRIx64" assigned a new lid range:[0x%x-0x%x]\n",
876            guid, *p_min_lid, *p_max_lid);
877   lid_changed = 1;
878
879  NewLidSet:
880   /* update the guid2lid db and used_lids */
881   osm_db_guid2lid_set(p_mgr->p_g2l, guid, *p_min_lid, *p_max_lid);
882   for (lid = *p_min_lid; lid <= *p_max_lid; lid++)
883     cl_ptr_vector_set(&p_mgr->used_lids, lid, (void*)1);
884
885  Exit:
886   /* make sure the assigned lids are marked in port_lid_tbl */
887   for (lid = *p_min_lid; lid <= *p_max_lid; lid++)
888     cl_ptr_vector_set(&p_mgr->p_subn->port_lid_tbl, lid, p_port);
889
890   OSM_LOG_EXIT( p_mgr->p_log );
891   return lid_changed;
892 }
893
894 /**********************************************************************
895  **********************************************************************/
896 static boolean_t
897 __osm_lid_mgr_set_physp_pi(
898   IN osm_lid_mgr_t *       const p_mgr,
899   IN osm_physp_t*          const p_physp,
900   IN ib_net16_t               const lid )
901 {
902   uint8_t               payload[IB_SMP_DATA_SIZE];
903   ib_port_info_t*       p_pi = (ib_port_info_t*)payload;
904   const ib_port_info_t* p_old_pi;
905   osm_madw_context_t    context;
906   osm_node_t*           p_node;
907   ib_api_status_t       status;
908   uint8_t               mtu;
909   uint8_t               op_vls;
910   uint8_t               port_num;
911   boolean_t             send_set = FALSE;
912
913   OSM_LOG_ENTER( p_mgr->p_log, __osm_lid_mgr_set_physp_pi );
914
915   /*
916     Don't bother doing anything if this Physical Port is not valid.
917     This allows simplified code in the caller.
918   */
919   if( p_physp == NULL )
920     goto Exit;
921
922   if( !osm_physp_is_valid( p_physp ) )
923     goto Exit;
924
925   port_num = osm_physp_get_port_num( p_physp );
926   p_node = osm_physp_get_node_ptr( p_physp );
927
928   if( (osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH) &&
929       (port_num != 0) )
930   {
931     /*
932       Switch ports that are not numbered 0 - should not be set with the
933       following attributes set later (during NO_CHANGE state in link mgr).
934     */
935     if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
936     {
937       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
938                "__osm_lid_mgr_set_physp_pi: "
939                "Skipping switch port %u, GUID = 0x%016" PRIx64 ".\n",
940                port_num,
941                cl_ntoh64( osm_physp_get_port_guid( p_physp ) ) );
942     }
943     goto Exit;
944   }
945
946   p_old_pi = osm_physp_get_port_info_ptr( p_physp );
947
948   /*
949     First, copy existing parameters from the PortInfo attribute we
950     already have for this node.
951
952     Second, update with default values that we know must be set for
953     every Physical Port and the LID and set the neighbor MTU field
954     appropriately.
955
956     Third, send the SMP to this physical port.
957   */
958
959   cl_memclr( payload, IB_SMP_DATA_SIZE );
960
961   /* Correction by FUJITSU */
962   if( port_num != 0 )
963   {
964     cl_memcpy( payload, p_old_pi, sizeof(ib_port_info_t) );
965   }
966
967   /*
968     Correction following a bug injected by the previous
969     FUJITSU line:
970
971     Should never write back a value that is bigger then 3 in
972     the PortPhysicalState field - so can not simply copy!
973
974     Actually we want to write there:
975     port physical state - no change,
976     link down default state = polling
977     port state - no change
978   */
979   /* these values can be set only for hca ports, so if we are
980      on a switch node - set these values to zero */
981   if ( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH )
982     p_pi->state_info2 = 0x0;
983   else
984   {
985     p_pi->state_info2 = 0x02;
986     /* Check to see if the value we are setting is different than
987        the value in the port_info. If it is - turn on send_set flag */
988     if ( ib_port_info_get_link_down_def_state(p_pi) !=
989          ib_port_info_get_link_down_def_state(p_old_pi) )
990       send_set = TRUE;
991   }
992
993   ib_port_info_set_port_state( p_pi, IB_LINK_NO_CHANGE );
994
995   p_pi->m_key = p_mgr->p_subn->opt.m_key;
996   /* Check to see if the value we are setting is different than
997      the value in the port_info. If it is - turn on send_set flag */
998   if (cl_memcmp( &p_pi->m_key, &p_old_pi->m_key, sizeof(p_pi->m_key) ))
999     send_set = TRUE;
1000
1001   p_pi->subnet_prefix = p_mgr->p_subn->opt.subnet_prefix;
1002   /* Check to see if the value we are setting is different than
1003      the value in the port_info. If it is - turn on send_set flag */
1004   if (cl_memcmp( &p_pi->subnet_prefix, &p_old_pi->subnet_prefix,
1005                  sizeof(p_pi->subnet_prefix) ))
1006     send_set = TRUE;
1007
1008   p_pi->base_lid = lid;
1009   /* Check to see if the value we are setting is different than
1010      the value in the port_info. If it is - turn on send_set flag */
1011   if (cl_memcmp( &p_pi->base_lid, &p_old_pi->base_lid,
1012                  sizeof(p_pi->base_lid) ))
1013     send_set = TRUE;
1014
1015   /* we are updating the ports with our local sm_base_lid */
1016   p_pi->master_sm_base_lid = p_mgr->p_subn->sm_base_lid;
1017   /* Check to see if the value we are setting is different than
1018      the value in the port_info. If it is - turn on send_set flag */
1019   if (cl_memcmp( &p_pi->master_sm_base_lid, &p_old_pi->master_sm_base_lid,
1020                  sizeof(p_pi->master_sm_base_lid) ))
1021     send_set = TRUE;
1022
1023   p_pi->m_key_lease_period = p_mgr->p_subn->opt.m_key_lease_period;
1024   /* Check to see if the value we are setting is different than
1025      the value in the port_info. If it is - turn on send_set flag */
1026   if (cl_memcmp( &p_pi->m_key_lease_period, &p_old_pi->m_key_lease_period,
1027                  sizeof(p_pi->m_key_lease_period) ))
1028     send_set = TRUE;
1029
1030   /*
1031     we want to set the timeout for both the switch port 0
1032     and the HCA ports
1033   */
1034   ib_port_info_set_timeout( p_pi, p_mgr->p_subn->opt.subnet_timeout );
1035   /* Check to see if the value we are setting is different than
1036      the value in the port_info. If it is - turn on send_set flag */
1037   if (ib_port_info_get_timeout( p_pi ) != ib_port_info_get_timeout( p_old_pi ))
1038     send_set = TRUE;
1039
1040   if( port_num != 0 )
1041   {
1042     /*
1043       HCA's don't have a port 0, and for switch port 0,
1044       the state bits are ignored.
1045       This is not the switch management port
1046     */
1047     p_pi->link_width_enabled = p_old_pi->link_width_supported;
1048     /* Check to see if the value we are setting is different than
1049        the value in the port_info. If it is - turn on send_set flag */
1050     if (cl_memcmp( &p_pi->link_width_enabled, &p_old_pi->link_width_enabled,
1051                    sizeof(p_pi->link_width_enabled) ))
1052       send_set = TRUE;
1053
1054     /* M_KeyProtectBits are always zero */
1055     p_pi->mkey_lmc = p_mgr->p_subn->opt.lmc;
1056     /* Check to see if the value we are setting is different than
1057        the value in the port_info. If it is - turn on send_set flag */
1058     if (cl_memcmp( &p_pi->mkey_lmc, &p_old_pi->mkey_lmc, sizeof(p_pi->mkey_lmc) ))
1059       send_set = TRUE;
1060
1061     /* calc new op_vls and mtu */
1062     op_vls = osm_physp_calc_link_op_vls(
1063       p_mgr->p_log, p_mgr->p_subn, p_physp );
1064     mtu =  osm_physp_calc_link_mtu(p_mgr->p_log, p_physp );
1065
1066     ib_port_info_set_neighbor_mtu( p_pi, mtu );
1067
1068     if ( ib_port_info_get_neighbor_mtu(p_pi) !=
1069          ib_port_info_get_neighbor_mtu(p_old_pi) )
1070       send_set = TRUE;
1071
1072     ib_port_info_set_op_vls( p_pi, op_vls );
1073     if ( ib_port_info_get_op_vls(p_pi) !=
1074          ib_port_info_get_op_vls(p_old_pi) )
1075       send_set = TRUE;
1076
1077     /*
1078       Several timeout mechanisms:
1079     */
1080     ib_port_info_set_phy_and_overrun_err_thd(
1081       p_pi,
1082       p_mgr->p_subn->opt.local_phy_errors_threshold,
1083       p_mgr->p_subn->opt.overrun_errors_threshold);
1084
1085     if (cl_memcmp( &p_pi->error_threshold, &p_old_pi->error_threshold,
1086                    sizeof(p_pi->error_threshold) ))
1087       send_set = TRUE;
1088
1089     /*
1090       TO DO -
1091       If the subnet is being reconfigured, should we force the link
1092       to the INIT state?
1093
1094       To reset the port state machine we can send PortInfo.State = DOWN.
1095       (see: 7.2.7 p161 lines:10-19.)
1096     */
1097     if ( (mtu != ib_port_info_get_mtu_cap( p_old_pi )) ||
1098          (op_vls !=  ib_port_info_get_op_vls(p_old_pi)))
1099     {
1100       if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
1101       {
1102         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1103                  "__osm_lid_mgr_set_physp_pi: "
1104                  "Sending Link Down due to op_vls or mtu change. MTU:%u,%u VL_CAP:%u,%u \n",
1105                  mtu, ib_port_info_get_mtu_cap( p_old_pi ),
1106                  op_vls, ib_port_info_get_op_vls(p_old_pi)
1107                  );
1108       }
1109       ib_port_info_set_port_state( p_pi, IB_LINK_DOWN );
1110       if ( ib_port_info_get_port_state(p_pi) !=
1111            ib_port_info_get_port_state(p_old_pi) )
1112         send_set = TRUE;
1113     }
1114   }
1115   else
1116   {
1117     /*
1118       For Port 0 - NeighborMTU is relevant only for Enh. SP0.
1119       In this case we'll set the MTU according to the mtu_cap
1120     */
1121     ib_port_info_set_neighbor_mtu( p_pi, ib_port_info_get_mtu_cap( p_old_pi ) );
1122     if ( ib_port_info_get_neighbor_mtu(p_pi) !=
1123          ib_port_info_get_neighbor_mtu(p_old_pi) )
1124       send_set = TRUE;
1125
1126     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1127              "__osm_lid_mgr_set_physp_pi: "
1128              "Updating neighbor_mtu on sw. port 0 to:%u\n",
1129              ib_port_info_get_neighbor_mtu( p_pi ) );
1130   }
1131
1132   context.pi_context.node_guid = osm_node_get_node_guid( p_node );
1133   context.pi_context.port_guid = osm_physp_get_port_guid( p_physp );
1134   context.pi_context.set_method = TRUE;
1135   context.pi_context.update_master_sm_base_lid = FALSE;
1136   context.pi_context.ignore_errors = FALSE;
1137   context.pi_context.light_sweep = FALSE;
1138
1139   /*
1140     We need to set the cli_rereg bit when we are in first_time_master_sweep for
1141     ports supporting the ClientReregistration Vol1 (v1.2) p811 14.4.11
1142   */
1143   if ( ( p_mgr->p_subn->first_time_master_sweep == TRUE ) &&
1144        ( (p_old_pi->capability_mask & IB_PORT_CAP_HAS_CLIENT_REREG) != 0 ) )
1145     ib_port_info_set_client_rereg( p_pi, 1 );
1146
1147   /* We need to send the PortInfoSet request with the new sm_lid
1148      in the following cases:
1149      1. There is a change in the values (send_set == TRUE)
1150      2. first_time_master_sweep flag on the subnet is TRUE. This means the
1151      SM just became master, and it then needs to send at PortInfoSet to
1152      every port.
1153      3. got_set_resp on the physical port is FALSE. This means we haven't seen
1154      this port before - need to send Set of PortInfo to it.
1155   */
1156   if (send_set || p_mgr->p_subn->first_time_master_sweep == TRUE ||
1157       p_physp->got_set_resp == FALSE)
1158   {
1159
1160     p_mgr->send_set_reqs = TRUE;
1161     status = osm_req_set( p_mgr->p_req,
1162                           osm_physp_get_dr_path_ptr( p_physp ),
1163                           payload,
1164                           sizeof(payload),
1165                           IB_MAD_ATTR_PORT_INFO,
1166                           cl_hton32(osm_physp_get_port_num( p_physp )),
1167                           CL_DISP_MSGID_NONE,
1168                           &context );
1169   }
1170
1171  Exit:
1172   OSM_LOG_EXIT( p_mgr->p_log );
1173   return (send_set || p_mgr->p_subn->first_time_master_sweep == TRUE ||
1174           p_physp->got_set_resp == FALSE);
1175 }
1176
1177 /**********************************************************************
1178  Processes our own node
1179  Lock must already be held.
1180 **********************************************************************/
1181 static boolean_t
1182 __osm_lid_mgr_process_our_sm_node(
1183   IN osm_lid_mgr_t* const p_mgr )
1184 {
1185   osm_port_t     *p_port;
1186   uint16_t        min_lid_ho;
1187   uint16_t        max_lid_ho;
1188   osm_physp_t    *p_physp;
1189   boolean_t       res = TRUE;
1190
1191   OSM_LOG_ENTER( p_mgr->p_log, __osm_lid_mgr_process_our_sm_node );
1192
1193   /*
1194     Acquire our own port object.
1195   */
1196   p_port = (osm_port_t*)cl_qmap_get( &p_mgr->p_subn->port_guid_tbl,
1197                                      p_mgr->p_subn->sm_port_guid );
1198
1199   if( p_port == (osm_port_t*)cl_qmap_end( &p_mgr->p_subn->port_guid_tbl ) )
1200   {
1201     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
1202              "__osm_lid_mgr_process_our_sm_node: ERR 0308: "
1203              "Can't acquire SM's Port object, GUID = 0x%016" PRIx64 ".\n",
1204              cl_ntoh64( p_mgr->p_subn->sm_port_guid ) );
1205     res = FALSE;
1206     goto Exit;
1207   }
1208
1209   /*
1210     Determine the LID this SM will use for its own port.
1211     Be careful.  With an LMC > 0, the bottom of the LID range becomes
1212     unusable, since port hardware will mask off least significant bits,
1213     leaving a LID of 0 (invalid).  Therefore, make sure that we always
1214     configure the SM with a LID that has non-zero bits, even after
1215     LMC masking by hardware.
1216   */
1217   __osm_lid_mgr_get_port_lid(p_mgr, p_port, &min_lid_ho, &max_lid_ho);
1218   osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1219            "__osm_lid_mgr_process_our_sm_node: "
1220            "Current base LID is 0x%X.\n", min_lid_ho );
1221   /*
1222     Update subnet object.
1223   */
1224   p_mgr->p_subn->master_sm_base_lid = cl_hton16( min_lid_ho );
1225   p_mgr->p_subn->sm_base_lid = cl_hton16( min_lid_ho );
1226
1227   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) )
1228   {
1229     osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
1230              "__osm_lid_mgr_process_our_sm_node: "
1231              "Assigning SM's port 0x%016" PRIx64
1232              "\n\t\t\t\tto LID range [0x%X,0x%X].\n",
1233              cl_ntoh64( osm_port_get_guid( p_port ) ),
1234              min_lid_ho, max_lid_ho );
1235   }
1236
1237   /*
1238     Set the PortInfo the Physical Port associated
1239     with this Port.
1240   */
1241   p_physp = osm_port_get_default_phys_ptr( p_port );
1242
1243   __osm_lid_mgr_set_physp_pi( p_mgr, p_physp, cl_hton16( min_lid_ho ) );
1244
1245  Exit:
1246   OSM_LOG_EXIT( p_mgr->p_log );
1247   return res;
1248 }
1249
1250 /**********************************************************************
1251  **********************************************************************/
1252 osm_signal_t
1253 osm_lid_mgr_process_sm(
1254   IN osm_lid_mgr_t*        const p_mgr )
1255 {
1256   osm_signal_t          signal = OSM_SIGNAL_DONE_PENDING;
1257
1258   OSM_LOG_ENTER( p_mgr->p_log, osm_lid_mgr_process_sm );
1259
1260   CL_ASSERT( p_mgr->p_subn->sm_port_guid );
1261
1262   CL_PLOCK_EXCL_ACQUIRE( p_mgr->p_lock );
1263
1264   /* initialize the port_lid_tbl and empty ranges list following the
1265      persistent db */
1266   __osm_lid_mgr_init_sweep( p_mgr );
1267
1268   if (p_mgr->p_subn->opt.pfn_ui_pre_lid_assign)
1269   {
1270     osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
1271              "osm_lid_mgr_process_sm: "
1272              "Invoking UI function pfn_ui_pre_lid_assign\n");
1273     p_mgr->p_subn->opt.pfn_ui_pre_lid_assign(
1274       p_mgr->p_subn->opt.ui_pre_lid_assign_ctx);
1275   }
1276
1277   /* Set the send_set_reqs of the p_mgr to FALSE, and
1278      we'll see if any set requests were sent. If not -
1279      can signal OSM_SIGNAL_DONE */
1280   p_mgr->send_set_reqs = FALSE;
1281   if ( __osm_lid_mgr_process_our_sm_node( p_mgr ) == FALSE )
1282     /* The initialization failed */
1283     signal = OSM_SIGNAL_DONE;
1284
1285   if ( p_mgr->send_set_reqs == FALSE )
1286     signal = OSM_SIGNAL_DONE;
1287
1288   CL_PLOCK_RELEASE( p_mgr->p_lock );
1289
1290   OSM_LOG_EXIT( p_mgr->p_log );
1291   return( signal );
1292 }
1293
1294 /**********************************************************************
1295  1 go through all ports in the subnet.
1296  1.1 call __osm_lid_mgr_get_port_min_lid
1297  1.2 if a change is required send the port info
1298  2 if any change send the signal PENDING...
1299 **********************************************************************/
1300 osm_signal_t
1301 osm_lid_mgr_process_subnet(
1302   IN osm_lid_mgr_t*        const p_mgr )
1303 {
1304   osm_signal_t    signal;
1305   cl_qmap_t      *p_port_guid_tbl;
1306   osm_port_t     *p_port;
1307   ib_net64_t      port_guid;
1308   uint16_t        min_lid_ho, max_lid_ho;
1309   osm_physp_t    *p_physp;
1310   int             lid_changed;
1311
1312   OSM_LOG_ENTER( p_mgr->p_log, osm_lid_mgr_process_subnet );
1313
1314   CL_ASSERT( p_mgr );
1315
1316   CL_PLOCK_EXCL_ACQUIRE( p_mgr->p_lock );
1317
1318   CL_ASSERT( p_mgr->p_subn->sm_port_guid );
1319
1320   /* Set the send_set_reqs of the p_mgr to FALSE, and
1321      we'll see if any set requests were sent. If not -
1322      can signal OSM_SIGNAL_DONE */
1323   p_mgr->send_set_reqs = FALSE;
1324
1325   p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl;
1326
1327   for( p_port = (osm_port_t*)cl_qmap_head( p_port_guid_tbl );
1328        p_port != (osm_port_t*)cl_qmap_end( p_port_guid_tbl );
1329        p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item ) )
1330   {
1331     port_guid = osm_port_get_guid( p_port );
1332
1333     /*
1334       Our own port is a special case in that we want to
1335       assign a LID to ourselves first, since we have to
1336       advertise that LID value to the other ports.
1337
1338       For that reason, our node is treated separately and
1339       we will not add it to any of these lists.
1340     */
1341     if( port_guid == p_mgr->p_subn->sm_port_guid )
1342     {
1343       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1344                "osm_lid_mgr_process_subnet: "
1345                "Skipping our own port 0x%016" PRIx64 ".\n",
1346                cl_ntoh64( port_guid ) );
1347     }
1348     else
1349     {
1350       /*
1351         get the port lid range - we need to send it on first active sweep or
1352         if there was a change (the result of the __osm_lid_mgr_get_port_lid)
1353       */
1354       lid_changed =
1355         __osm_lid_mgr_get_port_lid(p_mgr, p_port, &min_lid_ho, &max_lid_ho);
1356
1357       /* we can call the function to update the port info as it known to 
1358          look for any field change and will only send an updated if required */
1359       osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
1360                "osm_lid_mgr_process_subnet: "
1361                "Assigned port 0x%016" PRIx64
1362                ", LID [0x%X,0x%X]\n", cl_ntoh64( port_guid ),
1363                min_lid_ho, max_lid_ho );
1364       
1365       p_physp = osm_port_get_default_phys_ptr( p_port );
1366       /* the proc returns the fact it sent a set port info */
1367       if (__osm_lid_mgr_set_physp_pi( p_mgr, p_physp, cl_hton16( min_lid_ho )))
1368         p_mgr->send_set_reqs = TRUE;
1369     }
1370   } /* all ports */
1371
1372   /* store the guid to lid table in persistent db */
1373   osm_db_store( p_mgr->p_g2l );
1374
1375   if ( p_mgr->send_set_reqs == FALSE )
1376     signal = OSM_SIGNAL_DONE;
1377   else
1378     signal = OSM_SIGNAL_DONE_PENDING;
1379
1380   CL_PLOCK_RELEASE( p_mgr->p_lock );
1381
1382   OSM_LOG_EXIT( p_mgr->p_log );
1383   return( signal );
1384 }