]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ofed/management/opensm/opensm/osm_port.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ofed / management / opensm / opensm / osm_port.c
1 /*
2  * Copyright (c) 2004-2008 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 a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  *
34  */
35
36 /*
37  * Abstract:
38  *    Implementation of osm_physp_t.
39  * This object represents an Infiniband Port.
40  * This object is part of the opensm family of objects.
41  */
42
43 #if HAVE_CONFIG_H
44 #  include <config.h>
45 #endif                          /* HAVE_CONFIG_H */
46
47 #include <stdlib.h>
48 #include <string.h>
49 #include <complib/cl_debug.h>
50 #include <iba/ib_types.h>
51 #include <opensm/osm_port.h>
52 #include <opensm/osm_node.h>
53 #include <opensm/osm_madw.h>
54 #include <opensm/osm_mcm_info.h>
55 #include <opensm/osm_switch.h>
56
57 /**********************************************************************
58  **********************************************************************/
59 void osm_physp_construct(IN osm_physp_t * const p_physp)
60 {
61         memset(p_physp, 0, sizeof(*p_physp));
62         osm_dr_path_construct(&p_physp->dr_path);
63         cl_ptr_vector_construct(&p_physp->slvl_by_port);
64         osm_pkey_tbl_construct(&p_physp->pkeys);
65 }
66
67 /**********************************************************************
68  **********************************************************************/
69 void osm_physp_destroy(IN osm_physp_t * const p_physp)
70 {
71         size_t num_slvl, i;
72
73         /* the physp might be uninitialized */
74         if (p_physp->port_guid) {
75                 /* free the SL2VL Tables */
76                 num_slvl = cl_ptr_vector_get_size(&p_physp->slvl_by_port);
77                 for (i = 0; i < num_slvl; i++)
78                         free(cl_ptr_vector_get(&p_physp->slvl_by_port, i));
79                 cl_ptr_vector_destroy(&p_physp->slvl_by_port);
80
81                 /* free the P_Key Tables */
82                 osm_pkey_tbl_destroy(&p_physp->pkeys);
83
84                 memset(p_physp, 0, sizeof(*p_physp));
85                 osm_dr_path_construct(&p_physp->dr_path);       /* clear dr_path */
86         }
87 }
88
89 /**********************************************************************
90  **********************************************************************/
91 void
92 osm_physp_init(IN osm_physp_t * const p_physp,
93                IN const ib_net64_t port_guid,
94                IN const uint8_t port_num,
95                IN const struct osm_node *const p_node,
96                IN const osm_bind_handle_t h_bind,
97                IN const uint8_t hop_count,
98                IN const uint8_t * const p_initial_path)
99 {
100         uint16_t num_slvl, i;
101         ib_slvl_table_t *p_slvl;
102
103         CL_ASSERT(p_node);
104
105         osm_physp_construct(p_physp);
106         p_physp->port_guid = port_guid;
107         p_physp->port_num = port_num;
108         p_physp->healthy = TRUE;
109         p_physp->need_update = 2;
110         p_physp->p_node = (struct osm_node *)p_node;
111
112         osm_dr_path_init(&p_physp->dr_path, h_bind, hop_count, p_initial_path);
113
114         /* allocate enough SL2VL tables */
115         if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH)
116                 /* we need node num ports + 1 SL2VL tables */
117                 num_slvl = osm_node_get_num_physp(p_node) + 1;
118         else
119                 /* An end node - we need only one SL2VL */
120                 num_slvl = 1;
121
122         cl_ptr_vector_init(&p_physp->slvl_by_port, num_slvl, 1);
123         for (i = 0; i < num_slvl; i++) {
124                 p_slvl = (ib_slvl_table_t *) malloc(sizeof(ib_slvl_table_t));
125                 if (!p_slvl)
126                         break;
127                 memset(p_slvl, 0, sizeof(ib_slvl_table_t));
128                 cl_ptr_vector_set(&p_physp->slvl_by_port, i, p_slvl);
129         }
130
131         /* initialize the pkey table */
132         osm_pkey_tbl_init(&p_physp->pkeys);
133 }
134
135 /**********************************************************************
136  **********************************************************************/
137 void osm_port_delete(IN OUT osm_port_t ** const pp_port)
138 {
139         /* cleanup all mcm recs attached */
140         osm_port_remove_all_mgrp(*pp_port);
141         free(*pp_port);
142         *pp_port = NULL;
143 }
144
145 /**********************************************************************
146  **********************************************************************/
147 static void
148 osm_port_init(IN osm_port_t * const p_port,
149               IN const ib_node_info_t * p_ni,
150               IN osm_node_t * const p_parent_node)
151 {
152         ib_net64_t port_guid;
153         osm_physp_t *p_physp;
154         uint8_t port_num;
155
156         CL_ASSERT(p_port);
157         CL_ASSERT(p_ni);
158         CL_ASSERT(p_parent_node);
159
160         memset(p_port, 0, sizeof(*p_port));
161         cl_qlist_init(&p_port->mcm_list);
162         p_port->p_node = (struct osm_node *)p_parent_node;
163         port_guid = p_ni->port_guid;
164         p_port->guid = port_guid;
165         port_num = p_ni->node_type == IB_NODE_TYPE_SWITCH ?
166                 0 : ib_node_info_get_local_port_num(p_ni);
167
168         /*
169            Get the pointers to the physical node objects "owned" by this
170            logical port GUID.
171            For switches, port '0' is owned; for HCA's and routers,
172            only the singular part that has this GUID is owned.
173          */
174         p_physp = osm_node_get_physp_ptr(p_parent_node, port_num);
175         CL_ASSERT(port_guid == osm_physp_get_port_guid(p_physp));
176         p_port->p_physp = p_physp;
177 }
178
179 /**********************************************************************
180  **********************************************************************/
181 osm_port_t *osm_port_new(IN const ib_node_info_t * p_ni,
182                          IN osm_node_t * const p_parent_node)
183 {
184         osm_port_t *p_port;
185
186         p_port = malloc(sizeof(*p_port));
187         if (p_port != NULL) {
188                 memset(p_port, 0, sizeof(*p_port));
189                 osm_port_init(p_port, p_ni, p_parent_node);
190         }
191
192         return (p_port);
193 }
194
195 /**********************************************************************
196  **********************************************************************/
197 void
198 osm_port_get_lid_range_ho(IN const osm_port_t * const p_port,
199                           IN uint16_t * const p_min_lid,
200                           IN uint16_t * const p_max_lid)
201 {
202         uint8_t lmc;
203
204         *p_min_lid = cl_ntoh16(osm_port_get_base_lid(p_port));
205         lmc = osm_port_get_lmc(p_port);
206         *p_max_lid = (uint16_t) (*p_min_lid + (1 << lmc) - 1);
207 }
208
209 /**********************************************************************
210  **********************************************************************/
211 ib_api_status_t
212 osm_get_port_by_base_lid(IN const osm_subn_t * const p_subn,
213                          IN const ib_net16_t lid,
214                          IN OUT const osm_port_t ** const pp_port)
215 {
216         ib_api_status_t status;
217         uint16_t base_lid;
218         uint8_t lmc;
219
220         *pp_port = NULL;
221
222         /* Loop on lmc from 0 up through max LMC possible */
223         for (lmc = 0; lmc <= IB_PORT_LMC_MAX; lmc++) {
224                 /* Calculate a base LID assuming this is the real LMC */
225                 base_lid = cl_ntoh16(lid) & ~((1 << lmc) - 1);
226
227                 /* Look for a match */
228                 status = cl_ptr_vector_at(&p_subn->port_lid_tbl,
229                                           base_lid, (void **)pp_port);
230                 if ((status == CL_SUCCESS) && (*pp_port != NULL)) {
231                         /* Determine if base LID "tested" is the real base LID */
232                         /* This is true if the LMC "tested" is the port's actual LMC */
233                         if (lmc == osm_port_get_lmc(*pp_port)) {
234                                 status = IB_SUCCESS;
235                                 goto Found;
236                         }
237                 }
238         }
239         *pp_port = NULL;
240         status = IB_NOT_FOUND;
241
242 Found:
243         return status;
244 }
245
246 /**********************************************************************
247  **********************************************************************/
248 ib_api_status_t
249 osm_port_add_mgrp(IN osm_port_t * const p_port, IN const ib_net16_t mlid)
250 {
251         ib_api_status_t status = IB_SUCCESS;
252         osm_mcm_info_t *p_mcm;
253
254         p_mcm = osm_mcm_info_new(mlid);
255         if (p_mcm)
256                 cl_qlist_insert_tail(&p_port->mcm_list,
257                                      (cl_list_item_t *) p_mcm);
258         else
259                 status = IB_INSUFFICIENT_MEMORY;
260
261         return (status);
262 }
263
264 /**********************************************************************
265  **********************************************************************/
266 static cl_status_t
267 __osm_port_mgrp_find_func(IN const cl_list_item_t * const p_list_item,
268                           IN void *context)
269 {
270         if (*((ib_net16_t *) context) == ((osm_mcm_info_t *) p_list_item)->mlid)
271                 return (CL_SUCCESS);
272         else
273                 return (CL_NOT_FOUND);
274 }
275
276 /**********************************************************************
277  **********************************************************************/
278 void
279 osm_port_remove_mgrp(IN osm_port_t * const p_port, IN const ib_net16_t mlid)
280 {
281         cl_list_item_t *p_mcm;
282
283         p_mcm = cl_qlist_find_from_head(&p_port->mcm_list,
284                                         __osm_port_mgrp_find_func, &mlid);
285
286         if (p_mcm != cl_qlist_end(&p_port->mcm_list)) {
287                 cl_qlist_remove_item(&p_port->mcm_list, p_mcm);
288                 osm_mcm_info_delete((osm_mcm_info_t *) p_mcm);
289         }
290 }
291
292 /**********************************************************************
293  **********************************************************************/
294 void osm_port_remove_all_mgrp(IN osm_port_t * const p_port)
295 {
296         cl_list_item_t *p_mcm;
297
298         p_mcm = cl_qlist_remove_head(&p_port->mcm_list);
299         while (p_mcm != cl_qlist_end(&p_port->mcm_list)) {
300                 osm_mcm_info_delete((osm_mcm_info_t *) p_mcm);
301                 p_mcm = cl_qlist_remove_head(&p_port->mcm_list);
302         }
303 }
304
305 /**********************************************************************
306  **********************************************************************/
307 uint8_t
308 osm_physp_calc_link_mtu(IN osm_log_t * p_log, IN const osm_physp_t * p_physp)
309 {
310         const osm_physp_t *p_remote_physp;
311         uint8_t mtu;
312         uint8_t remote_mtu;
313
314         OSM_LOG_ENTER(p_log);
315
316         p_remote_physp = osm_physp_get_remote(p_physp);
317         if (p_remote_physp) {
318                 /* use the available MTU */
319                 mtu = ib_port_info_get_mtu_cap(&p_physp->port_info);
320
321                 remote_mtu =
322                     ib_port_info_get_mtu_cap(&p_remote_physp->port_info);
323
324                 OSM_LOG(p_log, OSM_LOG_DEBUG,
325                         "Remote port 0x%016" PRIx64 " port = %u : "
326                         "MTU = %u. This Port MTU: %u\n",
327                         cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)),
328                         osm_physp_get_port_num(p_remote_physp),
329                         remote_mtu, mtu);
330
331                 if (mtu != remote_mtu) {
332                         if (mtu > remote_mtu)
333                                 mtu = remote_mtu;
334
335                         OSM_LOG(p_log, OSM_LOG_VERBOSE,
336                                 "MTU mismatch between ports."
337                                 "\n\t\t\t\tPort 0x%016" PRIx64 ", port %u"
338                                 " and port 0x%016" PRIx64 ", port %u."
339                                 "\n\t\t\t\tUsing lower MTU of %u\n",
340                                 cl_ntoh64(osm_physp_get_port_guid(p_physp)),
341                                 osm_physp_get_port_num(p_physp),
342                                 cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)),
343                                 osm_physp_get_port_num(p_remote_physp),mtu);
344                 }
345         } else
346                 mtu = ib_port_info_get_neighbor_mtu(&p_physp->port_info);
347
348         if (mtu == 0) {
349                 OSM_LOG(p_log, OSM_LOG_DEBUG, "ERR 4101: "
350                         "Invalid MTU = 0. Forcing correction to 256\n");
351                 mtu = 1;
352         }
353
354         OSM_LOG_EXIT(p_log);
355         return (mtu);
356 }
357
358 /**********************************************************************
359  **********************************************************************/
360 uint8_t
361 osm_physp_calc_link_op_vls(IN osm_log_t * p_log,
362                            IN const osm_subn_t * p_subn,
363                            IN const osm_physp_t * p_physp)
364 {
365         const osm_physp_t *p_remote_physp;
366         uint8_t op_vls;
367         uint8_t remote_op_vls;
368
369         OSM_LOG_ENTER(p_log);
370
371         p_remote_physp = osm_physp_get_remote(p_physp);
372         if (p_remote_physp) {
373                 /* use the available VLCap */
374                 op_vls = ib_port_info_get_vl_cap(&p_physp->port_info);
375
376                 remote_op_vls =
377                     ib_port_info_get_vl_cap(&p_remote_physp->port_info);
378
379                 OSM_LOG(p_log, OSM_LOG_DEBUG,
380                         "Remote port 0x%016" PRIx64 " port = 0x%X : "
381                         "VL_CAP = %u. This port VL_CAP = %u\n",
382                         cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)),
383                         osm_physp_get_port_num(p_remote_physp),
384                         remote_op_vls, op_vls);
385
386                 if (op_vls != remote_op_vls) {
387                         if (op_vls > remote_op_vls)
388                                 op_vls = remote_op_vls;
389
390                         OSM_LOG(p_log, OSM_LOG_VERBOSE,
391                                 "OP_VLS mismatch between ports."
392                                 "\n\t\t\t\tPort 0x%016" PRIx64 ", port 0x%X"
393                                 " and port 0x%016" PRIx64 ", port 0x%X."
394                                 "\n\t\t\t\tUsing lower OP_VLS of %u\n",
395                                 cl_ntoh64(osm_physp_get_port_guid(p_physp)),
396                                 osm_physp_get_port_num(p_physp),
397                                 cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)),
398                                 osm_physp_get_port_num(p_remote_physp), op_vls);
399                 }
400         } else
401                 op_vls = ib_port_info_get_op_vls(&p_physp->port_info);
402
403         /* support user limitation of max_op_vls */
404         if (op_vls > p_subn->opt.max_op_vls)
405                 op_vls = p_subn->opt.max_op_vls;
406
407         if (op_vls == 0) {
408                 OSM_LOG(p_log, OSM_LOG_DEBUG, "ERR 4102: "
409                         "Invalid OP_VLS = 0. Forcing correction to 1 (VL0)\n");
410                 op_vls = 1;
411         }
412
413         OSM_LOG_EXIT(p_log);
414         return (op_vls);
415 }
416
417 static inline uint64_t __osm_ptr_to_key(void const *p)
418 {
419         uint64_t k = 0;
420
421         memcpy(&k, p, sizeof(void *));
422         return k;
423 }
424
425 static inline void *__osm_key_to_ptr(uint64_t k)
426 {
427         void *p = 0;
428
429         memcpy(&p, &k, sizeof(void *));
430         return p;
431 }
432
433 /**********************************************************************
434  Traverse the fabric from the SM node following the DR path given and
435  add every phys port traversed to the map. Avoid tracking the first and
436  last phys ports (going into the first switch and into the target port).
437  **********************************************************************/
438 static cl_status_t
439 __osm_physp_get_dr_physp_set(IN osm_log_t * p_log,
440                              IN osm_subn_t const *p_subn,
441                              IN osm_dr_path_t const *p_path,
442                              OUT cl_map_t * p_physp_map)
443 {
444         osm_port_t *p_port;
445         osm_physp_t *p_physp;
446         osm_node_t *p_node;
447         uint8_t hop;
448         cl_status_t status = CL_SUCCESS;
449
450         OSM_LOG_ENTER(p_log);
451
452         /* find the OSM node */
453         p_port = osm_get_port_by_guid(p_subn, p_subn->sm_port_guid);
454         if (!p_port) {
455                 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4103: "
456                         "Failed to find the SM own port by guid\n");
457                 status = CL_ERROR;
458                 goto Exit;
459         }
460
461         /* get the node of the SM */
462         p_node = p_port->p_node;
463
464         /*
465            traverse the path adding the nodes to the table
466            start after the first dummy hop and stop just before the
467            last one
468          */
469         for (hop = 1; hop < p_path->hop_count - 1; hop++) {
470                 /* go out using the phys port of the path */
471                 p_physp = osm_node_get_physp_ptr(p_node, p_path->path[hop]);
472
473                 /* make sure we got a valid port and it has a remote port */
474                 if (!p_physp) {
475                         OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4104: "
476                                 "DR Traversal stopped on invalid port at hop:%u\n",
477                                 hop);
478                         status = CL_ERROR;
479                         goto Exit;
480                 }
481
482                 /* we track the ports we go out along the path */
483                 if (hop > 1)
484                         cl_map_insert(p_physp_map, __osm_ptr_to_key(p_physp),
485                                       NULL);
486
487                 OSM_LOG(p_log, OSM_LOG_DEBUG,
488                         "Traversed through node: 0x%016" PRIx64
489                         " port:%u\n",
490                         cl_ntoh64(p_node->node_info.node_guid),
491                         p_path->path[hop]);
492
493                 if (!(p_physp = osm_physp_get_remote(p_physp))) {
494                         OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4106: "
495                                 "DR Traversal stopped on missing remote physp at hop:%u\n",
496                                 hop);
497                         status = CL_ERROR;
498                         goto Exit;
499                 }
500
501                 p_node = osm_physp_get_node_ptr(p_physp);
502         }
503
504 Exit:
505         OSM_LOG_EXIT(p_log);
506         return status;
507 }
508
509 /**********************************************************************
510  **********************************************************************/
511 static void
512 __osm_physp_update_new_dr_path(IN osm_physp_t const *p_dest_physp,
513                                IN cl_map_t * p_visited_map,
514                                IN osm_bind_handle_t * h_bind)
515 {
516         cl_list_t tmpPortsList;
517         osm_physp_t *p_physp, *p_src_physp = NULL;
518         uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX];
519         uint8_t i = 0;
520         osm_dr_path_t *p_dr_path;
521
522         cl_list_construct(&tmpPortsList);
523         cl_list_init(&tmpPortsList, 10);
524
525         cl_list_insert_head(&tmpPortsList, p_dest_physp);
526         /* get the output port where we need to come from */
527         p_physp = (osm_physp_t *) cl_map_get(p_visited_map,
528                                              __osm_ptr_to_key(p_dest_physp));
529         while (p_physp != NULL) {
530                 cl_list_insert_head(&tmpPortsList, p_physp);
531                 /* get the input port through where we reached the output port */
532                 p_src_physp = p_physp;
533                 p_physp = (osm_physp_t *) cl_map_get(p_visited_map,
534                                                      __osm_ptr_to_key(p_physp));
535                 /* if we reached a null p_physp - this means we are at the begining
536                    of the path. Break. */
537                 if (p_physp == NULL)
538                         break;
539                 /* get the output port */
540                 p_physp = (osm_physp_t *) cl_map_get(p_visited_map,
541                                                      __osm_ptr_to_key(p_physp));
542         }
543
544         memset(path_array, 0, sizeof(path_array));
545         p_physp = (osm_physp_t *) cl_list_remove_head(&tmpPortsList);
546         while (p_physp != NULL) {
547                 i++;
548                 path_array[i] = p_physp->port_num;
549                 p_physp = (osm_physp_t *) cl_list_remove_head(&tmpPortsList);
550         }
551         if (p_src_physp) {
552                 p_dr_path = osm_physp_get_dr_path_ptr(p_src_physp);
553                 osm_dr_path_init(p_dr_path, h_bind, i, path_array);
554         }
555
556         cl_list_destroy(&tmpPortsList);
557 }
558
559 /**********************************************************************
560  **********************************************************************/
561 void
562 osm_physp_replace_dr_path_with_alternate_dr_path(IN osm_log_t * p_log,
563                                                  IN osm_subn_t const *p_subn,
564                                                  IN osm_physp_t const
565                                                  *p_dest_physp,
566                                                  IN osm_bind_handle_t * h_bind)
567 {
568         cl_map_t physp_map;
569         cl_map_t visited_map;
570         osm_dr_path_t *p_dr_path;
571         cl_list_t *p_currPortsList;
572         cl_list_t *p_nextPortsList;
573         osm_port_t *p_port;
574         osm_physp_t *p_physp, *p_remote_physp;
575         ib_net64_t port_guid;
576         boolean_t next_list_is_full = TRUE, reached_dest = FALSE;
577         uint8_t num_ports, port_num;
578
579         p_nextPortsList = (cl_list_t *) malloc(sizeof(cl_list_t));
580         if (!p_nextPortsList)
581                 return;
582
583         /*
584            initialize the map of all port participating in current dr path
585            not including first and last switches
586          */
587         cl_map_construct(&physp_map);
588         cl_map_init(&physp_map, 4);
589         cl_map_construct(&visited_map);
590         cl_map_init(&visited_map, 4);
591         p_dr_path = osm_physp_get_dr_path_ptr(p_dest_physp);
592         __osm_physp_get_dr_physp_set(p_log, p_subn, p_dr_path, &physp_map);
593
594         /*
595            BFS from OSM port until we find the target physp but avoid
596            going through mapped ports
597          */
598         cl_list_construct(p_nextPortsList);
599         cl_list_init(p_nextPortsList, 10);
600
601         port_guid = p_subn->sm_port_guid;
602
603         CL_ASSERT(port_guid);
604
605         p_port = osm_get_port_by_guid(p_subn, port_guid);
606         if (!p_port) {
607                 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4105: No SM port object\n");
608                 goto Exit;
609         }
610
611         /*
612            HACK: We are assuming SM is running on HCA, so when getting the default
613            port we'll get the port connected to the rest of the subnet. If SM is
614            running on SWITCH - we should try to get a dr path from all switch ports.
615          */
616         p_physp = p_port->p_physp;
617
618         CL_ASSERT(p_physp);
619
620         cl_list_insert_tail(p_nextPortsList, p_physp);
621
622         while (next_list_is_full == TRUE) {
623                 next_list_is_full = FALSE;
624                 p_currPortsList = p_nextPortsList;
625                 p_nextPortsList = (cl_list_t *) malloc(sizeof(cl_list_t));
626                 if (!p_nextPortsList) {
627                         p_nextPortsList = p_currPortsList;
628                         goto Exit;
629                 }
630                 cl_list_construct(p_nextPortsList);
631                 cl_list_init(p_nextPortsList, 10);
632                 p_physp = (osm_physp_t *) cl_list_remove_head(p_currPortsList);
633                 while (p_physp != NULL) {
634                         /* If we are in a switch - need to go out through all
635                            the other physical ports of the switch */
636                         num_ports = osm_node_get_num_physp(p_physp->p_node);
637
638                         for (port_num = 1; port_num < num_ports; port_num++) {
639                                 if (osm_node_get_type(p_physp->p_node) ==
640                                     IB_NODE_TYPE_SWITCH)
641                                         p_remote_physp =
642                                             osm_node_get_physp_ptr(p_physp->
643                                                                    p_node,
644                                                                    port_num);
645                                 else
646                                         /* this is HCA or router - the remote port is just the port connected
647                                            on the other side */
648                                         p_remote_physp =
649                                             p_physp->p_remote_physp;
650
651                                 /*
652                                    make sure that all of the following occurred:
653                                    1. The port isn't NULL
654                                    2. This is not the port we came from
655                                    3. The port is not in the physp_map
656                                    4. This port haven't been visited before
657                                  */
658                                 if (p_remote_physp &&
659                                     p_remote_physp != p_physp &&
660                                     cl_map_get(&physp_map,
661                                                __osm_ptr_to_key(p_remote_physp))
662                                     == NULL
663                                     && cl_map_get(&visited_map,
664                                                   __osm_ptr_to_key
665                                                   (p_remote_physp)) == NULL) {
666                                         /* Insert the port into the visited_map, and save its source port */
667                                         cl_map_insert(&visited_map,
668                                                       __osm_ptr_to_key
669                                                       (p_remote_physp),
670                                                       p_physp);
671
672                                         /* Is this the p_dest_physp? */
673                                         if (p_remote_physp == p_dest_physp) {
674                                                 /* update the new dr path */
675                                                 __osm_physp_update_new_dr_path
676                                                     (p_dest_physp, &visited_map,
677                                                      h_bind);
678                                                 reached_dest = TRUE;
679                                                 break;
680                                         }
681
682                                         /* add the p_remote_physp to the nextPortsList */
683                                         cl_list_insert_tail(p_nextPortsList,
684                                                             p_remote_physp);
685                                         next_list_is_full = TRUE;
686                                 }
687                         }
688
689                         p_physp = (osm_physp_t *)
690                             cl_list_remove_head(p_currPortsList);
691                         if (reached_dest == TRUE) {
692                                 /* free the rest of the currPortsList */
693                                 while (p_physp != NULL)
694                                         p_physp = (osm_physp_t *)
695                                             cl_list_remove_head
696                                             (p_currPortsList);
697                                 /* free the nextPortsList, if items were added to it */
698                                 p_physp = (osm_physp_t *)
699                                     cl_list_remove_head(p_nextPortsList);
700                                 while (p_physp != NULL)
701                                         p_physp = (osm_physp_t *)
702                                             cl_list_remove_head
703                                             (p_nextPortsList);
704                                 next_list_is_full = FALSE;
705                         }
706                 }
707                 cl_list_destroy(p_currPortsList);
708                 free(p_currPortsList);
709         }
710
711         /* cleanup */
712 Exit:
713         cl_list_destroy(p_nextPortsList);
714         free(p_nextPortsList);
715         cl_map_destroy(&physp_map);
716         cl_map_destroy(&visited_map);
717 }
718
719 /**********************************************************************
720  **********************************************************************/
721 boolean_t osm_link_is_healthy(IN const osm_physp_t * const p_physp)
722 {
723         osm_physp_t *p_remote_physp;
724
725         CL_ASSERT(p_physp);
726         p_remote_physp = p_physp->p_remote_physp;
727         if (p_remote_physp != NULL)
728                 return ((p_physp->healthy) & (p_remote_physp->healthy));
729         /* the other side is not known - consider the link as healthy */
730         return (TRUE);
731 }
732
733 /**********************************************************************
734  **********************************************************************/
735 void
736 osm_physp_set_pkey_tbl(IN osm_log_t * p_log,
737                        IN const osm_subn_t * p_subn,
738                        IN osm_physp_t * const p_physp,
739                        IN ib_pkey_table_t * p_pkey_tbl, IN uint16_t block_num)
740 {
741         uint16_t max_blocks;
742
743         CL_ASSERT(p_pkey_tbl);
744         /*
745            (14.2.5.7) - the block number valid values are 0-2047, and are
746            further limited by the size of the P_Key table specified by
747            the PartitionCap on the node.
748          */
749         if (!p_physp->p_node->sw || p_physp->port_num == 0)
750                 /*
751                    The maximum blocks is defined in the node info: partition cap
752                    for CA, router, and switch management ports.
753                  */
754                 max_blocks =
755                     (cl_ntoh16(p_physp->p_node->node_info.partition_cap) +
756                      IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1)
757                     / IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
758         else
759                 /*
760                    This is a switch, and not a management port. The maximum
761                    blocks is defined in the switch info: partition enforcement
762                    cap.
763                  */
764                 max_blocks =
765                     (cl_ntoh16(p_physp->p_node->sw->switch_info.enforce_cap) +
766                      IB_NUM_PKEY_ELEMENTS_IN_BLOCK -
767                      1) / IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
768
769         if (block_num >= max_blocks) {
770                 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4108: "
771                         "Got illegal set for block number:%u "
772                         "For GUID: %" PRIx64 " port number:%u\n",
773                         block_num,
774                         cl_ntoh64(p_physp->p_node->node_info.node_guid),
775                         p_physp->port_num);
776                 return;
777         }
778
779         osm_pkey_tbl_set(&p_physp->pkeys, block_num, p_pkey_tbl);
780 }