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