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