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