xref: /NextBSD/contrib/ofed/management/opensm/opensm/osm_port.c (revision eb1a5f8de9f7ea602c373a710f531abbf81141c4)
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  **********************************************************************/
osm_physp_construct(IN osm_physp_t * const p_physp)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  **********************************************************************/
osm_physp_destroy(IN osm_physp_t * const p_physp)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
osm_physp_init(IN osm_physp_t * const p_physp,IN const ib_net64_t port_guid,IN const uint8_t port_num,IN const struct osm_node * const p_node,IN const osm_bind_handle_t h_bind,IN const uint8_t hop_count,IN const uint8_t * const p_initial_path)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  **********************************************************************/
osm_port_delete(IN OUT osm_port_t ** const pp_port)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
osm_port_init(IN osm_port_t * const p_port,IN const ib_node_info_t * p_ni,IN osm_node_t * const p_parent_node)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  **********************************************************************/
osm_port_new(IN const ib_node_info_t * p_ni,IN osm_node_t * const p_parent_node)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
osm_port_get_lid_range_ho(IN const osm_port_t * const p_port,IN uint16_t * const p_min_lid,IN uint16_t * const p_max_lid)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
osm_get_port_by_base_lid(IN const osm_subn_t * const p_subn,IN const ib_net16_t lid,IN OUT const osm_port_t ** const pp_port)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
osm_port_add_mgrp(IN osm_port_t * const p_port,IN const ib_net16_t mlid)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
__osm_port_mgrp_find_func(IN const cl_list_item_t * const p_list_item,IN void * context)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
osm_port_remove_mgrp(IN osm_port_t * const p_port,IN const ib_net16_t mlid)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  **********************************************************************/
osm_port_remove_all_mgrp(IN osm_port_t * const p_port)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
osm_physp_calc_link_mtu(IN osm_log_t * p_log,IN const osm_physp_t * p_physp)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
osm_physp_calc_link_op_vls(IN osm_log_t * p_log,IN const osm_subn_t * p_subn,IN const osm_physp_t * p_physp)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 
__osm_ptr_to_key(void const * p)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 
__osm_key_to_ptr(uint64_t k)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
__osm_physp_get_dr_physp_set(IN osm_log_t * p_log,IN osm_subn_t const * p_subn,IN osm_dr_path_t const * p_path,OUT cl_map_t * p_physp_map)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
__osm_physp_update_new_dr_path(IN osm_physp_t const * p_dest_physp,IN cl_map_t * p_visited_map,IN osm_bind_handle_t * h_bind)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
osm_physp_replace_dr_path_with_alternate_dr_path(IN osm_log_t * p_log,IN osm_subn_t const * p_subn,IN osm_physp_t const * p_dest_physp,IN osm_bind_handle_t * h_bind)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  **********************************************************************/
osm_link_is_healthy(IN const osm_physp_t * const p_physp)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
osm_physp_set_pkey_tbl(IN osm_log_t * p_log,IN const osm_subn_t * p_subn,IN osm_physp_t * const p_physp,IN ib_pkey_table_t * p_pkey_tbl,IN uint16_t block_num)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 }
781