xref: /freebsd/contrib/ofed/opensm/opensm/osm_port.c (revision d13def78)
1 /*
2  * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2015 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_file_ids.h>
52 #define FILE_ID OSM_FILE_PORT_C
53 #include <opensm/osm_port.h>
54 #include <opensm/osm_node.h>
55 #include <opensm/osm_madw.h>
56 #include <opensm/osm_switch.h>
57 #include <opensm/osm_db_pack.h>
58 #include <opensm/osm_sm.h>
59 
osm_physp_construct(IN osm_physp_t * p_physp)60 void osm_physp_construct(IN osm_physp_t * p_physp)
61 {
62 	memset(p_physp, 0, sizeof(*p_physp));
63 	osm_dr_path_construct(&p_physp->dr_path);
64 	cl_ptr_vector_construct(&p_physp->slvl_by_port);
65 	osm_pkey_tbl_construct(&p_physp->pkeys);
66 }
67 
osm_physp_destroy(IN osm_physp_t * p_physp)68 void osm_physp_destroy(IN osm_physp_t * p_physp)
69 {
70 	size_t num_slvl, i;
71 
72 	/* the physp might be uninitialized */
73 	if (p_physp->port_guid) {
74 		if (p_physp->p_guids)
75 			free(p_physp->p_guids);
76 
77 		/* free the SL2VL Tables */
78 		num_slvl = cl_ptr_vector_get_size(&p_physp->slvl_by_port);
79 		for (i = 0; i < num_slvl; i++)
80 			free(cl_ptr_vector_get(&p_physp->slvl_by_port, i));
81 		cl_ptr_vector_destroy(&p_physp->slvl_by_port);
82 
83 		/* free the P_Key Tables */
84 		osm_pkey_tbl_destroy(&p_physp->pkeys);
85 
86 		memset(p_physp, 0, sizeof(*p_physp));
87 		osm_dr_path_construct(&p_physp->dr_path);	/* clear dr_path */
88 	}
89 }
90 
osm_physp_init(IN osm_physp_t * p_physp,IN ib_net64_t port_guid,IN uint8_t port_num,IN const struct osm_node * p_node,IN osm_bind_handle_t h_bind,IN uint8_t hop_count,IN const uint8_t * p_initial_path)91 void osm_physp_init(IN osm_physp_t * p_physp, IN ib_net64_t port_guid,
92 		    IN uint8_t port_num, IN const struct osm_node *p_node,
93 		    IN osm_bind_handle_t h_bind, IN uint8_t hop_count,
94 		    IN const uint8_t * p_initial_path)
95 {
96 	uint16_t num_slvl, i;
97 	ib_slvl_table_t *p_slvl;
98 
99 	CL_ASSERT(p_node);
100 
101 	osm_physp_construct(p_physp);
102 	p_physp->port_guid = port_guid;
103 	p_physp->port_num = port_num;
104 	p_physp->healthy = TRUE;
105 	p_physp->need_update = 2;
106 	p_physp->p_node = (struct osm_node *)p_node;
107 
108 	osm_dr_path_init(&p_physp->dr_path, hop_count, p_initial_path);
109 
110 	/* allocate enough SL2VL tables */
111 	if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH)
112 		/* we need node num ports + 1 SL2VL tables */
113 		num_slvl = osm_node_get_num_physp(p_node) + 1;
114 	else
115 		/* An end node - we need only one SL2VL */
116 		num_slvl = 1;
117 
118 	cl_ptr_vector_init(&p_physp->slvl_by_port, num_slvl, 1);
119 	for (i = 0; i < num_slvl; i++) {
120 		p_slvl = (ib_slvl_table_t *) malloc(sizeof(ib_slvl_table_t));
121 		if (!p_slvl)
122 			break;
123 		memset(p_slvl, 0, sizeof(ib_slvl_table_t));
124 		cl_ptr_vector_set(&p_physp->slvl_by_port, i, p_slvl);
125 	}
126 
127 	/* initialize the pkey table */
128 	osm_pkey_tbl_init(&p_physp->pkeys);
129 }
130 
osm_port_delete(IN OUT osm_port_t ** pp_port)131 void osm_port_delete(IN OUT osm_port_t ** pp_port)
132 {
133 	free(*pp_port);
134 	*pp_port = NULL;
135 }
136 
osm_port_new(IN const ib_node_info_t * p_ni,IN osm_node_t * p_parent_node)137 osm_port_t *osm_port_new(IN const ib_node_info_t * p_ni,
138 			 IN osm_node_t * p_parent_node)
139 {
140 	osm_port_t *p_port;
141 	ib_net64_t port_guid;
142 	osm_physp_t *p_physp;
143 	uint8_t port_num;
144 
145 	p_port = malloc(sizeof(*p_port));
146 	if (!p_port)
147 		return NULL;
148 
149 	memset(p_port, 0, sizeof(*p_port));
150 	cl_qlist_init(&p_port->mcm_list);
151 	p_port->p_node = (struct osm_node *)p_parent_node;
152 	port_guid = p_ni->port_guid;
153 	p_port->guid = port_guid;
154 	port_num = p_ni->node_type == IB_NODE_TYPE_SWITCH ?
155 	    0 : ib_node_info_get_local_port_num(p_ni);
156 
157 	/*
158 	   Get the pointers to the physical node objects "owned" by this
159 	   logical port GUID.
160 	   For switches, port '0' is owned; for HCA's and routers,
161 	   only the singular part that has this GUID is owned.
162 	 */
163 	p_physp = osm_node_get_physp_ptr(p_parent_node, port_num);
164 	if (!p_physp) {
165 		osm_port_delete(&p_port);
166 		return NULL;
167 	}
168 
169 	CL_ASSERT(port_guid == osm_physp_get_port_guid(p_physp));
170 	p_port->p_physp = p_physp;
171 
172 	return p_port;
173 }
174 
osm_port_get_lid_range_ho(IN const osm_port_t * p_port,IN uint16_t * p_min_lid,IN uint16_t * p_max_lid)175 void osm_port_get_lid_range_ho(IN const osm_port_t * p_port,
176 			       IN uint16_t * p_min_lid, IN uint16_t * p_max_lid)
177 {
178 	uint8_t lmc;
179 
180 	*p_min_lid = cl_ntoh16(osm_port_get_base_lid(p_port));
181 	lmc = osm_port_get_lmc(p_port);
182 	*p_max_lid = (uint16_t) (*p_min_lid + (1 << lmc) - 1);
183 }
184 
osm_physp_calc_link_mtu(IN osm_log_t * p_log,IN const osm_physp_t * p_physp,IN uint8_t current_mtu)185 uint8_t osm_physp_calc_link_mtu(IN osm_log_t * p_log,
186 				IN const osm_physp_t * p_physp,
187 				IN uint8_t current_mtu)
188 {
189 	const osm_physp_t *p_remote_physp;
190 	uint8_t mtu;
191 	uint8_t remote_mtu;
192 
193 	OSM_LOG_ENTER(p_log);
194 
195 	p_remote_physp = osm_physp_get_remote(p_physp);
196 	if (p_remote_physp) {
197 		/* use the available MTU */
198 		mtu = ib_port_info_get_mtu_cap(&p_physp->port_info);
199 
200 		remote_mtu =
201 		    ib_port_info_get_mtu_cap(&p_remote_physp->port_info);
202 
203 		OSM_LOG(p_log, OSM_LOG_DEBUG,
204 			"Remote port 0x%016" PRIx64 " port = %u : "
205 			"MTU = %u. This Port MTU: %u\n",
206 			cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)),
207 			osm_physp_get_port_num(p_remote_physp),
208 			remote_mtu, mtu);
209 
210 		if (mtu != remote_mtu) {
211 			if (mtu > remote_mtu)
212 				mtu = remote_mtu;
213 			if (mtu != current_mtu)
214 				OSM_LOG(p_log, OSM_LOG_VERBOSE,
215 					"MTU mismatch between ports."
216 					"\n\t\t\t\tPort 0x%016" PRIx64 ", port %u"
217 					" and port 0x%016" PRIx64 ", port %u."
218 					"\n\t\t\t\tUsing lower MTU of %u\n",
219 					cl_ntoh64(osm_physp_get_port_guid(p_physp)),
220 					osm_physp_get_port_num(p_physp),
221 					cl_ntoh64(osm_physp_get_port_guid
222 						  (p_remote_physp)),
223 					osm_physp_get_port_num(p_remote_physp), mtu);
224 		}
225 	} else
226 		mtu = ib_port_info_get_neighbor_mtu(&p_physp->port_info);
227 
228 	if (mtu == 0) {
229 		OSM_LOG(p_log, OSM_LOG_DEBUG, "ERR 4101: "
230 			"Invalid MTU = 0. Forcing correction to 256\n");
231 		mtu = 1;
232 	}
233 
234 	OSM_LOG_EXIT(p_log);
235 	return mtu;
236 }
237 
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,IN uint8_t current_op_vls)238 uint8_t osm_physp_calc_link_op_vls(IN osm_log_t * p_log,
239 				   IN const osm_subn_t * p_subn,
240 				   IN const osm_physp_t * p_physp,
241 				   IN uint8_t current_op_vls)
242 {
243 	const osm_physp_t *p_remote_physp;
244 	uint8_t op_vls;
245 	uint8_t remote_op_vls;
246 
247 	OSM_LOG_ENTER(p_log);
248 
249 	p_remote_physp = osm_physp_get_remote(p_physp);
250 	if (p_remote_physp) {
251 		/* use the available VLCap */
252 		op_vls = ib_port_info_get_vl_cap(&p_physp->port_info);
253 
254 		remote_op_vls =
255 		    ib_port_info_get_vl_cap(&p_remote_physp->port_info);
256 
257 		OSM_LOG(p_log, OSM_LOG_DEBUG,
258 			"Remote port 0x%016" PRIx64 " port = 0x%X : "
259 			"VL_CAP = %u. This port VL_CAP = %u\n",
260 			cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)),
261 			osm_physp_get_port_num(p_remote_physp),
262 			remote_op_vls, op_vls);
263 
264 		if (op_vls != remote_op_vls) {
265 			if (op_vls > remote_op_vls)
266 				op_vls = remote_op_vls;
267 			if (op_vls != current_op_vls)
268 				OSM_LOG(p_log, OSM_LOG_VERBOSE,
269 					"OP_VLS mismatch between ports."
270 					"\n\t\t\t\tPort 0x%016" PRIx64 ", port 0x%X"
271 					" and port 0x%016" PRIx64 ", port 0x%X."
272 					"\n\t\t\t\tUsing lower OP_VLS of %u\n",
273 					cl_ntoh64(osm_physp_get_port_guid(p_physp)),
274 					osm_physp_get_port_num(p_physp),
275 					cl_ntoh64(osm_physp_get_port_guid
276 						  (p_remote_physp)),
277 					osm_physp_get_port_num(p_remote_physp), op_vls);
278 		}
279 	} else
280 		op_vls = ib_port_info_get_op_vls(&p_physp->port_info);
281 
282 	if (op_vls == 0) {
283 		/* for non compliant implementations */
284 		OSM_LOG(p_log, OSM_LOG_VERBOSE,
285 			"Invalid OP_VLS = 0. Forcing correction to 1 (VL0)\n");
286 		op_vls = 1;
287 	}
288 
289 	/* support user limitation of max_op_vls */
290 	if (op_vls > p_subn->opt.max_op_vls)
291 		op_vls = p_subn->opt.max_op_vls;
292 
293 	OSM_LOG_EXIT(p_log);
294 	return op_vls;
295 }
296 
ptr_to_key(void const * p)297 static inline uint64_t ptr_to_key(void const *p)
298 {
299 	uint64_t k = 0;
300 
301 	memcpy(&k, p, sizeof(void *));
302 	return k;
303 }
304 
key_to_ptr(uint64_t k)305 static inline void *key_to_ptr(uint64_t k)
306 {
307 	void *p = 0;
308 
309 	memcpy(&p, &k, sizeof(void *));
310 	return p;
311 }
312 
313 /**********************************************************************
314  Traverse the fabric from the SM node following the DR path given and
315  add every phys port traversed to the map. Avoid tracking the first and
316  last phys ports (going into the first switch and into the target port).
317  **********************************************************************/
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)318 static cl_status_t physp_get_dr_physp_set(IN osm_log_t * p_log,
319 					  IN osm_subn_t const *p_subn,
320 					  IN osm_dr_path_t const *p_path,
321 					  OUT cl_map_t * p_physp_map)
322 {
323 	osm_port_t *p_port;
324 	osm_physp_t *p_physp;
325 	osm_node_t *p_node;
326 	uint8_t hop;
327 	cl_status_t status = CL_SUCCESS;
328 
329 	OSM_LOG_ENTER(p_log);
330 
331 	/* find the OSM node */
332 	p_port = osm_get_port_by_guid(p_subn, p_subn->sm_port_guid);
333 	if (!p_port) {
334 		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4103: "
335 			"Failed to find the SM own port by guid\n");
336 		status = CL_ERROR;
337 		goto Exit;
338 	}
339 
340 	/* get the node of the SM */
341 	p_node = p_port->p_node;
342 
343 	/*
344 	   traverse the path adding the nodes to the table
345 	   start after the first dummy hop and stop just before the
346 	   last one
347 	 */
348 	for (hop = 1; hop < p_path->hop_count - 1; hop++) {
349 		/* go out using the phys port of the path */
350 		p_physp = osm_node_get_physp_ptr(p_node, p_path->path[hop]);
351 
352 		/* make sure we got a valid port and it has a remote port */
353 		if (!p_physp) {
354 			OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4104: "
355 				"DR Traversal stopped on invalid port at hop:%u\n",
356 				hop);
357 			status = CL_ERROR;
358 			goto Exit;
359 		}
360 
361 		/* we track the ports we go out along the path */
362 		if (hop > 1)
363 			cl_map_insert(p_physp_map, ptr_to_key(p_physp), NULL);
364 
365 		OSM_LOG(p_log, OSM_LOG_DEBUG,
366 			"Traversed through node: 0x%016" PRIx64
367 			" port:%u\n",
368 			cl_ntoh64(p_node->node_info.node_guid),
369 			p_path->path[hop]);
370 
371 		if (!(p_physp = osm_physp_get_remote(p_physp))) {
372 			OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4106: "
373 				"DR Traversal stopped on missing remote physp at hop:%u\n",
374 				hop);
375 			status = CL_ERROR;
376 			goto Exit;
377 		}
378 
379 		p_node = osm_physp_get_node_ptr(p_physp);
380 	}
381 
382 Exit:
383 	OSM_LOG_EXIT(p_log);
384 	return status;
385 }
386 
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)387 static void physp_update_new_dr_path(IN osm_physp_t const *p_dest_physp,
388 				     IN cl_map_t * p_visited_map,
389 				     IN osm_bind_handle_t * h_bind)
390 {
391 	cl_list_t tmpPortsList;
392 	osm_physp_t *p_physp, *p_src_physp = NULL;
393 	uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX];
394 	uint8_t i = 0;
395 	osm_dr_path_t *p_dr_path;
396 
397 	cl_list_construct(&tmpPortsList);
398 	cl_list_init(&tmpPortsList, 10);
399 
400 	cl_list_insert_head(&tmpPortsList, p_dest_physp);
401 	/* get the output port where we need to come from */
402 	p_physp = (osm_physp_t *) cl_map_get(p_visited_map,
403 					     ptr_to_key(p_dest_physp));
404 	while (p_physp != NULL) {
405 		cl_list_insert_head(&tmpPortsList, p_physp);
406 		/* get the input port through where we reached the output port */
407 		p_src_physp = p_physp;
408 		p_physp = (osm_physp_t *) cl_map_get(p_visited_map,
409 						     ptr_to_key(p_physp));
410 		/* if we reached a null p_physp - this means we are at the begining
411 		   of the path. Break. */
412 		if (p_physp == NULL)
413 			break;
414 		/* get the output port */
415 		p_physp = (osm_physp_t *) cl_map_get(p_visited_map,
416 						     ptr_to_key(p_physp));
417 	}
418 
419 	memset(path_array, 0, sizeof(path_array));
420 	p_physp = (osm_physp_t *) cl_list_remove_head(&tmpPortsList);
421 	while (p_physp != NULL) {
422 		i++;
423 		path_array[i] = p_physp->port_num;
424 		p_physp = (osm_physp_t *) cl_list_remove_head(&tmpPortsList);
425 	}
426 	if (p_src_physp) {
427 		p_dr_path = osm_physp_get_dr_path_ptr(p_src_physp);
428 		osm_dr_path_init(p_dr_path, i, path_array);
429 	}
430 
431 	cl_list_destroy(&tmpPortsList);
432 }
433 
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)434 void osm_physp_replace_dr_path_with_alternate_dr_path(IN osm_log_t * p_log,
435 						      IN osm_subn_t const
436 						      *p_subn, IN osm_physp_t const
437 						      *p_dest_physp,
438 						      IN osm_bind_handle_t *
439 						      h_bind)
440 {
441 	cl_map_t physp_map;
442 	cl_map_t visited_map;
443 	osm_dr_path_t *p_dr_path;
444 	cl_list_t *p_currPortsList;
445 	cl_list_t *p_nextPortsList;
446 	osm_port_t *p_port;
447 	osm_physp_t *p_physp, *p_remote_physp;
448 	ib_net64_t port_guid;
449 	boolean_t next_list_is_full = TRUE, reached_dest = FALSE;
450 	uint8_t num_ports, port_num;
451 
452 	p_nextPortsList = (cl_list_t *) malloc(sizeof(cl_list_t));
453 	if (!p_nextPortsList)
454 		return;
455 
456 	/*
457 	   initialize the map of all port participating in current dr path
458 	   not including first and last switches
459 	 */
460 	cl_map_construct(&physp_map);
461 	cl_map_init(&physp_map, 4);
462 	cl_map_construct(&visited_map);
463 	cl_map_init(&visited_map, 4);
464 	p_dr_path = osm_physp_get_dr_path_ptr(p_dest_physp);
465 	physp_get_dr_physp_set(p_log, p_subn, p_dr_path, &physp_map);
466 
467 	/*
468 	   BFS from OSM port until we find the target physp but avoid
469 	   going through mapped ports
470 	 */
471 	cl_list_construct(p_nextPortsList);
472 	cl_list_init(p_nextPortsList, 10);
473 
474 	port_guid = p_subn->sm_port_guid;
475 
476 	CL_ASSERT(port_guid);
477 
478 	p_port = osm_get_port_by_guid(p_subn, port_guid);
479 	if (!p_port) {
480 		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4105: No SM port object\n");
481 		goto Exit;
482 	}
483 
484 	/*
485 	   HACK: We are assuming SM is running on HCA, so when getting the default
486 	   port we'll get the port connected to the rest of the subnet. If SM is
487 	   running on SWITCH - we should try to get a dr path from all switch ports.
488 	 */
489 	p_physp = p_port->p_physp;
490 
491 	CL_ASSERT(p_physp);
492 
493 	cl_list_insert_tail(p_nextPortsList, p_physp);
494 
495 	while (next_list_is_full == TRUE) {
496 		next_list_is_full = FALSE;
497 		p_currPortsList = p_nextPortsList;
498 		p_nextPortsList = (cl_list_t *) malloc(sizeof(cl_list_t));
499 		if (!p_nextPortsList) {
500 			p_nextPortsList = p_currPortsList;
501 			goto Exit;
502 		}
503 		cl_list_construct(p_nextPortsList);
504 		cl_list_init(p_nextPortsList, 10);
505 		p_physp = (osm_physp_t *) cl_list_remove_head(p_currPortsList);
506 		while (p_physp != NULL) {
507 			/* If we are in a switch - need to go out through all
508 			   the other physical ports of the switch */
509 			num_ports = osm_node_get_num_physp(p_physp->p_node);
510 
511 			for (port_num = 1; port_num < num_ports; port_num++) {
512 				if (osm_node_get_type(p_physp->p_node) ==
513 				    IB_NODE_TYPE_SWITCH)
514 					p_remote_physp =
515 					    osm_node_get_physp_ptr(p_physp->
516 								   p_node,
517 								   port_num);
518 				else
519 					/* this is HCA or router - the remote port is just the port connected
520 					   on the other side */
521 					p_remote_physp =
522 					    p_physp->p_remote_physp;
523 
524 				/*
525 				   make sure that all of the following occurred:
526 				   1. The port isn't NULL
527 				   2. This is not the port we came from
528 				   3. The port is not in the physp_map
529 				   4. This port haven't been visited before
530 				 */
531 				if (p_remote_physp &&
532 				    p_remote_physp != p_physp &&
533 				    cl_map_get(&physp_map,
534 					       ptr_to_key(p_remote_physp))
535 				    == NULL
536 				    && cl_map_get(&visited_map,
537 						  ptr_to_key
538 						  (p_remote_physp)) == NULL) {
539 					/* Insert the port into the visited_map, and save its source port */
540 					cl_map_insert(&visited_map,
541 						      ptr_to_key
542 						      (p_remote_physp),
543 						      p_physp);
544 
545 					/* Is this the p_dest_physp? */
546 					if (p_remote_physp == p_dest_physp) {
547 						/* update the new dr path */
548 						physp_update_new_dr_path
549 						    (p_dest_physp, &visited_map,
550 						     h_bind);
551 						reached_dest = TRUE;
552 						break;
553 					}
554 
555 					/* add the p_remote_physp to the nextPortsList */
556 					cl_list_insert_tail(p_nextPortsList,
557 							    p_remote_physp);
558 					next_list_is_full = TRUE;
559 				}
560 			}
561 
562 			p_physp = (osm_physp_t *)
563 			    cl_list_remove_head(p_currPortsList);
564 			if (reached_dest == TRUE) {
565 				/* free the rest of the currPortsList */
566 				while (p_physp != NULL)
567 					p_physp = (osm_physp_t *)
568 					    cl_list_remove_head
569 					    (p_currPortsList);
570 				/* free the nextPortsList, if items were added to it */
571 				p_physp = (osm_physp_t *)
572 				    cl_list_remove_head(p_nextPortsList);
573 				while (p_physp != NULL)
574 					p_physp = (osm_physp_t *)
575 					    cl_list_remove_head
576 					    (p_nextPortsList);
577 				next_list_is_full = FALSE;
578 			}
579 		}
580 		cl_list_destroy(p_currPortsList);
581 		free(p_currPortsList);
582 	}
583 
584 	/* cleanup */
585 Exit:
586 	cl_list_destroy(p_nextPortsList);
587 	free(p_nextPortsList);
588 	cl_map_destroy(&physp_map);
589 	cl_map_destroy(&visited_map);
590 }
591 
osm_link_is_healthy(IN const osm_physp_t * p_physp)592 boolean_t osm_link_is_healthy(IN const osm_physp_t * p_physp)
593 {
594 	osm_physp_t *p_remote_physp;
595 
596 	CL_ASSERT(p_physp);
597 	p_remote_physp = p_physp->p_remote_physp;
598 	if (p_remote_physp != NULL)
599 		return ((p_physp->healthy) & (p_remote_physp->healthy));
600 	/* the other side is not known - consider the link as healthy */
601 	return TRUE;
602 }
603 
osm_physp_set_pkey_tbl(IN osm_log_t * p_log,IN const osm_subn_t * p_subn,IN osm_physp_t * p_physp,IN ib_pkey_table_t * p_pkey_tbl,IN uint16_t block_num,IN boolean_t is_set)604 void osm_physp_set_pkey_tbl(IN osm_log_t * p_log, IN const osm_subn_t * p_subn,
605 			    IN osm_physp_t * p_physp,
606 			    IN ib_pkey_table_t * p_pkey_tbl,
607 			    IN uint16_t block_num,
608 			    IN boolean_t is_set)
609 {
610 	uint16_t max_blocks;
611 
612 	CL_ASSERT(p_pkey_tbl);
613 	/*
614 	   (14.2.5.7) - the block number valid values are 0-2047, and are
615 	   further limited by the size of the P_Key table specified by
616 	   the PartitionCap on the node.
617 	 */
618 	if (!p_physp->p_node->sw || p_physp->port_num == 0)
619 		/*
620 		   The maximum blocks is defined in the node info: partition cap
621 		   for CA, router, and switch management ports.
622 		 */
623 		max_blocks =
624 		    (cl_ntoh16(p_physp->p_node->node_info.partition_cap) +
625 		     IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1)
626 		    / IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
627 	else
628 		/*
629 		   This is a switch, and not a management port. The maximum
630 		   blocks is defined in the switch info: partition enforcement
631 		   cap.
632 		 */
633 		max_blocks =
634 		    (cl_ntoh16(p_physp->p_node->sw->switch_info.enforce_cap) +
635 		     IB_NUM_PKEY_ELEMENTS_IN_BLOCK -
636 		     1) / IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
637 
638 	if (block_num >= max_blocks) {
639 		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4108: "
640 			"Got illegal update for block number:%u max:%u "
641 			"for GUID: %" PRIx64 " port number:%u\n",
642 			block_num, max_blocks,
643 			cl_ntoh64(p_physp->p_node->node_info.node_guid),
644 			p_physp->port_num);
645 		return;
646 	}
647 
648 	/* decrement block received counter */
649 	if(!is_set)
650 		p_physp->pkeys.rcv_blocks_cnt--;
651 	osm_pkey_tbl_set(&p_physp->pkeys, block_num, p_pkey_tbl,
652 			 p_subn->opt.allow_both_pkeys);
653 }
654 
osm_alias_guid_new(IN const ib_net64_t alias_guid,IN osm_port_t * p_base_port)655 osm_alias_guid_t *osm_alias_guid_new(IN const ib_net64_t alias_guid,
656 				     IN osm_port_t *p_base_port)
657 {
658 	osm_alias_guid_t *p_alias_guid;
659 
660 	p_alias_guid = calloc(1, sizeof(*p_alias_guid));
661 	if (p_alias_guid) {
662 		p_alias_guid->alias_guid = alias_guid;
663 		p_alias_guid->p_base_port = p_base_port;
664 	}
665 	return p_alias_guid;
666 }
667 
osm_alias_guid_delete(IN OUT osm_alias_guid_t ** pp_alias_guid)668 void osm_alias_guid_delete(IN OUT osm_alias_guid_t ** pp_alias_guid)
669 {
670 	free(*pp_alias_guid);
671 	*pp_alias_guid = NULL;
672 }
673 
osm_physp_set_port_info(IN osm_physp_t * p_physp,IN const ib_port_info_t * p_pi,IN const struct osm_sm * p_sm)674 void osm_physp_set_port_info(IN osm_physp_t * p_physp,
675 					   IN const ib_port_info_t * p_pi,
676 					   IN const struct osm_sm * p_sm)
677 {
678 	CL_ASSERT(p_pi);
679 	CL_ASSERT(osm_physp_is_valid(p_physp));
680 
681 	if (ib_port_info_get_port_state(p_pi) == IB_LINK_DOWN) {
682 		/* If PortState is down, only copy PortState */
683 		/* and PortPhysicalState per C14-24-2.1 */
684 		ib_port_info_set_port_state(&p_physp->port_info, IB_LINK_DOWN);
685 		ib_port_info_set_port_phys_state
686 		    (ib_port_info_get_port_phys_state(p_pi),
687 		     &p_physp->port_info);
688 	} else {
689 		p_physp->port_info = *p_pi;
690 
691 		/* The MKey in p_pi can only be considered valid if it's
692 		 * for a HCA/router or switch port 0, and it's either
693 		 * non-zero or the MKeyProtect bits are also zero.
694 		 */
695 		if ((osm_node_get_type(p_physp->p_node) !=
696 		     IB_NODE_TYPE_SWITCH || p_physp->port_num == 0) &&
697 		    (p_pi->m_key != 0 || ib_port_info_get_mpb(p_pi) == 0))
698 			osm_db_guid2mkey_set(p_sm->p_subn->p_g2m,
699 					     cl_ntoh64(p_physp->port_guid),
700 					     cl_ntoh64(p_pi->m_key));
701 	}
702 }
703