1/*
2 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2012 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 opensm pkey manipulation functions.
39 */
40
41#if HAVE_CONFIG_H
42#  include <config.h>
43#endif				/* HAVE_CONFIG_H */
44
45#include <stdlib.h>
46#include <stdio.h>
47#include <string.h>
48#include <complib/cl_debug.h>
49#include <iba/ib_types.h>
50#include <opensm/osm_file_ids.h>
51#define FILE_ID OSM_FILE_PKEY_C
52#include <opensm/osm_pkey.h>
53#include <opensm/osm_log.h>
54#include <opensm/osm_port.h>
55#include <opensm/osm_node.h>
56#include <opensm/osm_switch.h>
57#include <opensm/osm_helper.h>
58
59void osm_pkey_tbl_construct(IN osm_pkey_tbl_t * p_pkey_tbl)
60{
61	cl_map_construct(&p_pkey_tbl->accum_pkeys);
62	cl_ptr_vector_construct(&p_pkey_tbl->blocks);
63	cl_ptr_vector_construct(&p_pkey_tbl->new_blocks);
64	cl_map_construct(&p_pkey_tbl->keys);
65}
66
67void osm_pkey_tbl_destroy(IN osm_pkey_tbl_t * p_pkey_tbl)
68{
69	ib_pkey_table_t *p_block;
70	uint16_t num_blocks, i;
71
72	num_blocks = (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->blocks));
73	for (i = 0; i < num_blocks; i++)
74		if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, i)))
75			free(p_block);
76	cl_ptr_vector_destroy(&p_pkey_tbl->blocks);
77
78	num_blocks =
79	    (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks));
80	for (i = 0; i < num_blocks; i++)
81		if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, i)))
82			free(p_block);
83	cl_ptr_vector_destroy(&p_pkey_tbl->new_blocks);
84
85	cl_map_remove_all(&p_pkey_tbl->accum_pkeys);
86	cl_map_destroy(&p_pkey_tbl->accum_pkeys);
87
88	cl_map_remove_all(&p_pkey_tbl->keys);
89	cl_map_destroy(&p_pkey_tbl->keys);
90}
91
92ib_api_status_t osm_pkey_tbl_init(IN osm_pkey_tbl_t * p_pkey_tbl)
93{
94	cl_map_init(&p_pkey_tbl->accum_pkeys, 1);
95	cl_ptr_vector_init(&p_pkey_tbl->blocks, 0, 1);
96	cl_ptr_vector_init(&p_pkey_tbl->new_blocks, 0, 1);
97	cl_map_init(&p_pkey_tbl->keys, 1);
98	cl_qlist_init(&p_pkey_tbl->pending);
99	p_pkey_tbl->last_pkey_idx = 0;
100	p_pkey_tbl->used_blocks = 0;
101	p_pkey_tbl->max_blocks = 0;
102	p_pkey_tbl->rcv_blocks_cnt = 0;
103	p_pkey_tbl->indx0_pkey = 0;
104	return IB_SUCCESS;
105}
106
107void osm_pkey_tbl_init_new_blocks(IN const osm_pkey_tbl_t * p_pkey_tbl)
108{
109	ib_pkey_table_t *p_block;
110	size_t b, num_blocks = cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks);
111
112	for (b = 0; b < num_blocks; b++)
113		if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, b)))
114			memset(p_block, 0, sizeof(*p_block));
115}
116
117ib_api_status_t osm_pkey_tbl_set(IN osm_pkey_tbl_t * p_pkey_tbl,
118				 IN uint16_t block, IN ib_pkey_table_t * p_tbl,
119				 IN boolean_t allow_both_pkeys)
120{
121	uint16_t b, i;
122	ib_pkey_table_t *p_pkey_block;
123	uint16_t *p_prev_pkey;
124	ib_net16_t pkey, pkey_base;
125
126	/* make sure the block is allocated */
127	if (cl_ptr_vector_get_size(&p_pkey_tbl->blocks) > block)
128		p_pkey_block =
129		    (ib_pkey_table_t *) cl_ptr_vector_get(&p_pkey_tbl->blocks,
130							  block);
131	else
132		p_pkey_block = NULL;
133
134	if (!p_pkey_block) {
135		p_pkey_block =
136		    (ib_pkey_table_t *) malloc(sizeof(ib_pkey_table_t));
137		if (!p_pkey_block)
138			return IB_ERROR;
139		memset(p_pkey_block, 0, sizeof(ib_pkey_table_t));
140		cl_ptr_vector_set(&p_pkey_tbl->blocks, block, p_pkey_block);
141	}
142
143	/* sets the block values */
144	memcpy(p_pkey_block, p_tbl, sizeof(ib_pkey_table_t));
145
146	/*
147	   NOTE: as the spec does not require uniqueness of PKeys in
148	   tables there is no other way but to refresh the entire keys map.
149
150	   Moreover, if the same key exists but with full membership it should
151	   have precedence over the key with limited membership !
152	 */
153	cl_map_remove_all(&p_pkey_tbl->keys);
154
155	for (b = 0; b < cl_ptr_vector_get_size(&p_pkey_tbl->blocks); b++) {
156
157		p_pkey_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, b);
158		if (!p_pkey_block)
159			continue;
160
161		for (i = 0; i < IB_NUM_PKEY_ELEMENTS_IN_BLOCK; i++) {
162			pkey = p_pkey_block->pkey_entry[i];
163			if (ib_pkey_is_invalid(pkey))
164				continue;
165
166			if (allow_both_pkeys)
167				pkey_base = pkey;
168			else
169				pkey_base = ib_pkey_get_base(pkey);
170
171			/*
172			   If allow_both_pkeys is FALSE,
173			   ignore the PKey Full Member bit in the key but store
174			   the pointer to the table element as the map value
175			 */
176			p_prev_pkey = cl_map_get(&p_pkey_tbl->keys, pkey_base);
177
178			/* we only insert if no previous or it is not full member and allow_both_pkeys is FALSE */
179			if ((p_prev_pkey == NULL) ||
180			    (allow_both_pkeys == FALSE &&
181			     cl_ntoh16(*p_prev_pkey) < cl_ntoh16(pkey)))
182				cl_map_insert(&p_pkey_tbl->keys, pkey_base,
183					      &(p_pkey_block->pkey_entry[i])
184				    );
185		}
186	}
187	return IB_SUCCESS;
188}
189
190/*
191  Store the given pkey (along with it's overall index) in the accum_pkeys array.
192*/
193cl_status_t osm_pkey_tbl_set_accum_pkeys(IN osm_pkey_tbl_t * p_pkey_tbl,
194					 IN uint16_t pkey,
195					 IN uint16_t pkey_idx)
196{
197	uintptr_t ptr = pkey_idx + 1; /* 0 means not found so bias by 1 */
198	uint16_t *p_prev_pkey_idx;
199	cl_status_t status = CL_SUCCESS;
200
201	if (pkey_idx >= p_pkey_tbl->last_pkey_idx)
202		p_pkey_tbl->last_pkey_idx = pkey_idx + 1;
203
204	p_prev_pkey_idx = (uint16_t *) cl_map_get(&p_pkey_tbl->accum_pkeys, pkey);
205
206	if (p_prev_pkey_idx != NULL)
207		cl_map_remove(&p_pkey_tbl->accum_pkeys, pkey);
208
209	if (cl_map_insert(&p_pkey_tbl->accum_pkeys, pkey, (void *) ptr) == NULL)
210		status = CL_INSUFFICIENT_MEMORY;
211
212	return status;
213
214}
215
216/*
217+ * Find the next last pkey index
218+*/
219void osm_pkey_find_last_accum_pkey_index(IN osm_pkey_tbl_t * p_pkey_tbl)
220{
221	void *ptr;
222	uintptr_t pkey_idx_ptr;
223	uint16_t pkey_idx, last_pkey_idx = 0;
224	cl_map_iterator_t map_iter = cl_map_head(&p_pkey_tbl->accum_pkeys);
225
226	while (map_iter != cl_map_end(&p_pkey_tbl->accum_pkeys)) {
227		ptr = (uint16_t *) cl_map_obj(map_iter);
228		CL_ASSERT(ptr);
229		pkey_idx_ptr = (uintptr_t) ptr;
230		pkey_idx = pkey_idx_ptr;
231		if (pkey_idx > last_pkey_idx)
232			last_pkey_idx = pkey_idx;
233		map_iter = cl_map_next(map_iter);
234	}
235	p_pkey_tbl->last_pkey_idx = last_pkey_idx;
236}
237
238/*
239  Store the given pkey in the "new" blocks array.
240  Also, make sure the regular block exists.
241*/
242ib_api_status_t osm_pkey_tbl_set_new_entry(IN osm_pkey_tbl_t * p_pkey_tbl,
243					   IN uint16_t block_idx,
244					   IN uint8_t pkey_idx,
245					   IN uint16_t pkey)
246{
247	ib_pkey_table_t *p_block;
248
249	if (!(p_block = osm_pkey_tbl_new_block_get(p_pkey_tbl, block_idx))) {
250		p_block = (ib_pkey_table_t *) malloc(sizeof(ib_pkey_table_t));
251		if (!p_block)
252			return IB_ERROR;
253		memset(p_block, 0, sizeof(ib_pkey_table_t));
254		cl_ptr_vector_set(&p_pkey_tbl->new_blocks, block_idx, p_block);
255	}
256
257	p_block->pkey_entry[pkey_idx] = pkey;
258	if (p_pkey_tbl->used_blocks <= block_idx)
259		p_pkey_tbl->used_blocks = block_idx + 1;
260
261	return IB_SUCCESS;
262}
263
264boolean_t osm_pkey_find_next_free_entry(IN osm_pkey_tbl_t * p_pkey_tbl,
265					OUT uint16_t * p_block_idx,
266					OUT uint8_t * p_pkey_idx)
267{
268	ib_pkey_table_t *p_new_block;
269
270	CL_ASSERT(p_block_idx);
271	CL_ASSERT(p_pkey_idx);
272
273	while (*p_block_idx < p_pkey_tbl->max_blocks) {
274		if (*p_pkey_idx > IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) {
275			*p_pkey_idx = 0;
276			(*p_block_idx)++;
277			if (*p_block_idx >= p_pkey_tbl->max_blocks)
278				return FALSE;
279		}
280
281		p_new_block =
282		    osm_pkey_tbl_new_block_get(p_pkey_tbl, *p_block_idx);
283
284		if (!p_new_block ||
285		    ib_pkey_is_invalid(p_new_block->pkey_entry[*p_pkey_idx]))
286			return TRUE;
287		else
288			(*p_pkey_idx)++;
289	}
290	return FALSE;
291}
292
293ib_api_status_t osm_pkey_tbl_get_block_and_idx(IN osm_pkey_tbl_t * p_pkey_tbl,
294					       IN uint16_t * p_pkey,
295					       OUT uint16_t * p_block_idx,
296					       OUT uint8_t * p_pkey_idx)
297{
298	uint16_t num_of_blocks;
299	uint16_t block_index;
300	ib_pkey_table_t *block;
301
302	CL_ASSERT(p_block_idx != NULL);
303	CL_ASSERT(p_pkey_idx != NULL);
304
305	num_of_blocks = (uint16_t) cl_ptr_vector_get_size(&p_pkey_tbl->blocks);
306	for (block_index = 0; block_index < num_of_blocks; block_index++) {
307		block = osm_pkey_tbl_block_get(p_pkey_tbl, block_index);
308		if ((block->pkey_entry <= p_pkey) &&
309		    (p_pkey <
310		     block->pkey_entry + IB_NUM_PKEY_ELEMENTS_IN_BLOCK)) {
311			*p_block_idx = block_index;
312			*p_pkey_idx = (uint8_t) (p_pkey - block->pkey_entry);
313			return IB_SUCCESS;
314		}
315	}
316	return IB_NOT_FOUND;
317}
318
319static boolean_t match_pkey(IN const ib_net16_t * pkey1,
320			    IN const ib_net16_t * pkey2)
321{
322
323	/* if both pkeys are not full member - this is not a match */
324	if (!(ib_pkey_is_full_member(*pkey1) || ib_pkey_is_full_member(*pkey2)))
325		return FALSE;
326
327	/* compare if the bases are the same. if they are - then
328	   this is a match */
329	if (ib_pkey_get_base(*pkey1) != ib_pkey_get_base(*pkey2))
330		return FALSE;
331
332	return TRUE;
333}
334
335boolean_t osm_physp_share_this_pkey(IN const osm_physp_t * p_physp1,
336				    IN const osm_physp_t * p_physp2,
337				    IN ib_net16_t pkey,
338				    IN boolean_t allow_both_pkeys)
339{
340	ib_net16_t *pkey1, *pkey2;
341	ib_net16_t full_pkey, limited_pkey;
342
343	if (allow_both_pkeys) {
344		full_pkey = pkey | IB_PKEY_TYPE_MASK;
345		limited_pkey = pkey & ~IB_PKEY_TYPE_MASK;
346		pkey1 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp1))->keys,
347				   full_pkey);
348		if (!pkey1)
349			pkey1 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp1))->keys,
350					   limited_pkey);
351		pkey2 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp2))->keys,
352				   full_pkey);
353		if (!pkey2)
354			pkey2 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp2))->keys,
355					   limited_pkey);
356	} else {
357		pkey1 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp1))->keys,
358				   ib_pkey_get_base(pkey));
359		pkey2 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp2))->keys,
360				   ib_pkey_get_base(pkey));
361	}
362	return (pkey1 && pkey2 && match_pkey(pkey1, pkey2));
363}
364
365ib_net16_t osm_physp_find_common_pkey(IN const osm_physp_t * p_physp1,
366				      IN const osm_physp_t * p_physp2,
367				      IN boolean_t allow_both_pkeys)
368{
369	ib_net16_t *pkey1, *pkey2;
370	uint64_t pkey1_base, pkey2_base;
371	const osm_pkey_tbl_t *pkey_tbl1, *pkey_tbl2;
372	cl_map_iterator_t map_iter1, map_iter2;
373
374	pkey_tbl1 = osm_physp_get_pkey_tbl(p_physp1);
375	pkey_tbl2 = osm_physp_get_pkey_tbl(p_physp2);
376
377	map_iter1 = cl_map_head(&pkey_tbl1->keys);
378	map_iter2 = cl_map_head(&pkey_tbl2->keys);
379
380	/* we rely on the fact the map are sorted by pkey */
381	while ((map_iter1 != cl_map_end(&pkey_tbl1->keys)) &&
382	       (map_iter2 != cl_map_end(&pkey_tbl2->keys))) {
383		pkey1 = (ib_net16_t *) cl_map_obj(map_iter1);
384		pkey2 = (ib_net16_t *) cl_map_obj(map_iter2);
385
386		if (match_pkey(pkey1, pkey2))
387			return *pkey1;
388
389		/* advance the lower value if they are not equal */
390		pkey1_base = cl_map_key(map_iter1);
391		pkey2_base = cl_map_key(map_iter2);
392		if (pkey2_base == pkey1_base) {
393			map_iter1 = cl_map_next(map_iter1);
394			map_iter2 = cl_map_next(map_iter2);
395		} else if (pkey2_base < pkey1_base)
396			map_iter2 = cl_map_next(map_iter2);
397		else
398			map_iter1 = cl_map_next(map_iter1);
399	}
400
401	if (!allow_both_pkeys)
402		return 0;
403
404	/*
405	   When using allow_both_pkeys, the keys in pkey tables are the
406	   pkey value including membership bit.
407	   Therefore, in order to complete the search, we also need to
408	   compare port\s 1 full pkeys with port 2 limited pkeys, and
409	   port 2 full pkeys with port 1 full pkeys.
410	*/
411
412	map_iter1 = cl_map_head(&pkey_tbl1->keys);
413	map_iter2 = cl_map_head(&pkey_tbl2->keys);
414
415	/* comparing pkey_tbl1 full with pkey_tbl2 limited */
416	while ((map_iter1 != cl_map_end(&pkey_tbl1->keys)) &&
417	       (map_iter2 != cl_map_end(&pkey_tbl2->keys))) {
418		pkey1 = (ib_net16_t *) cl_map_obj(map_iter1);
419		pkey2 = (ib_net16_t *) cl_map_obj(map_iter2);
420
421		if (!ib_pkey_is_full_member(*pkey1)) {
422			map_iter1 = cl_map_next(map_iter1);
423			continue;
424		}
425		if (ib_pkey_is_full_member(*pkey2)) {
426			map_iter2 = cl_map_next(map_iter2);
427			continue;
428		}
429
430		if (match_pkey(pkey1, pkey2))
431			return *pkey1;
432
433		/* advance the lower value if they are not equal */
434		pkey1_base = ib_pkey_get_base(cl_map_key(map_iter1));
435		pkey2_base = ib_pkey_get_base(cl_map_key(map_iter2));
436		if (pkey2_base == pkey1_base) {
437			map_iter1 = cl_map_next(map_iter1);
438			map_iter2 = cl_map_next(map_iter2);
439		} else if (pkey2_base < pkey1_base)
440			map_iter2 = cl_map_next(map_iter2);
441		else
442			map_iter1 = cl_map_next(map_iter1);
443	}
444
445	map_iter1 = cl_map_head(&pkey_tbl1->keys);
446	map_iter2 = cl_map_head(&pkey_tbl2->keys);
447
448	/* comparing pkey_tbl1 limited with pkey_tbl2 full */
449	while ((map_iter1 != cl_map_end(&pkey_tbl1->keys)) &&
450	       (map_iter2 != cl_map_end(&pkey_tbl2->keys))) {
451		pkey1 = (ib_net16_t *) cl_map_obj(map_iter1);
452		pkey2 = (ib_net16_t *) cl_map_obj(map_iter2);
453
454		if (ib_pkey_is_full_member(*pkey1)) {
455			map_iter1 = cl_map_next(map_iter1);
456			continue;
457		}
458		if (!ib_pkey_is_full_member(*pkey2)) {
459			map_iter2 = cl_map_next(map_iter2);
460			continue;
461		}
462
463		if (match_pkey(pkey1, pkey2))
464			return *pkey1;
465
466		/* advance the lower value if they are not equal */
467		pkey1_base = ib_pkey_get_base(cl_map_key(map_iter1));
468		pkey2_base = ib_pkey_get_base(cl_map_key(map_iter2));
469		if (pkey2_base == pkey1_base) {
470			map_iter1 = cl_map_next(map_iter1);
471			map_iter2 = cl_map_next(map_iter2);
472		} else if (pkey2_base < pkey1_base)
473			map_iter2 = cl_map_next(map_iter2);
474		else
475			map_iter1 = cl_map_next(map_iter1);
476	}
477
478	return 0;
479}
480
481boolean_t osm_physp_share_pkey(IN osm_log_t * p_log,
482			       IN const osm_physp_t * p_physp_1,
483			       IN const osm_physp_t * p_physp_2,
484			       IN boolean_t allow_both_pkeys)
485{
486	const osm_pkey_tbl_t *pkey_tbl1, *pkey_tbl2;
487
488	if (p_physp_1 == p_physp_2)
489		return TRUE;
490
491	pkey_tbl1 = osm_physp_get_pkey_tbl(p_physp_1);
492	pkey_tbl2 = osm_physp_get_pkey_tbl(p_physp_2);
493
494	/*
495	   The spec: 10.9.2 does not require each phys port to have PKey Table.
496	   So actually if it does not, we need to use the default port instead.
497
498	   HACK: meanwhile we will ignore the check
499	 */
500	if (cl_is_map_empty(&pkey_tbl1->keys)
501	    || cl_is_map_empty(&pkey_tbl2->keys))
502		return TRUE;
503
504	return
505	    !ib_pkey_is_invalid(osm_physp_find_common_pkey
506				(p_physp_1, p_physp_2, allow_both_pkeys));
507}
508
509boolean_t osm_port_share_pkey(IN osm_log_t * p_log,
510			      IN const osm_port_t * p_port_1,
511			      IN const osm_port_t * p_port_2,
512			      IN boolean_t allow_both_pkeys)
513{
514
515	osm_physp_t *p_physp1, *p_physp2;
516	boolean_t ret;
517
518	OSM_LOG_ENTER(p_log);
519
520	if (!p_port_1 || !p_port_2) {
521		ret = FALSE;
522		goto Exit;
523	}
524
525	p_physp1 = p_port_1->p_physp;
526	p_physp2 = p_port_2->p_physp;
527
528	if (!p_physp1 || !p_physp2) {
529		ret = FALSE;
530		goto Exit;
531	}
532
533	ret = osm_physp_share_pkey(p_log, p_physp1, p_physp2, allow_both_pkeys);
534
535Exit:
536	OSM_LOG_EXIT(p_log);
537	return ret;
538}
539
540boolean_t osm_physp_has_pkey(IN osm_log_t * p_log, IN ib_net16_t pkey,
541			     IN const osm_physp_t * p_physp)
542{
543	ib_net16_t *p_pkey, pkey_base;
544	const osm_pkey_tbl_t *pkey_tbl;
545	boolean_t res = FALSE;
546
547	OSM_LOG_ENTER(p_log);
548
549	OSM_LOG(p_log, OSM_LOG_DEBUG,
550		"Search for PKey: 0x%04x\n", cl_ntoh16(pkey));
551
552	/* if the pkey given is an invalid pkey - return TRUE. */
553	if (ib_pkey_is_invalid(pkey)) {
554		OSM_LOG(p_log, OSM_LOG_DEBUG,
555			"Given invalid PKey - we treat it loosely and allow it\n");
556		res = TRUE;
557		goto Exit;
558	}
559
560	pkey_base = ib_pkey_get_base(pkey);
561
562	pkey_tbl = osm_physp_get_pkey_tbl(p_physp);
563
564	p_pkey = cl_map_get(&pkey_tbl->keys, pkey_base);
565	if (p_pkey) {
566		res = TRUE;
567		OSM_LOG(p_log, OSM_LOG_DEBUG,
568			"PKey 0x%04x was found\n", cl_ntoh16(pkey));
569	} else
570		OSM_LOG(p_log, OSM_LOG_DEBUG,
571			"PKey 0x%04x was not found\n", cl_ntoh16(pkey));
572
573Exit:
574	OSM_LOG_EXIT(p_log);
575	return res;
576}
577
578void osm_pkey_tbl_set_indx0_pkey(IN osm_log_t * p_log, IN ib_net16_t pkey,
579				 IN boolean_t full,
580				 OUT osm_pkey_tbl_t * p_pkey_tbl)
581{
582	p_pkey_tbl->indx0_pkey = (full == TRUE) ?
583				 pkey | cl_hton16(0x8000) : pkey;
584	OSM_LOG(p_log, OSM_LOG_DEBUG, "pkey 0x%04x set at indx0\n",
585		cl_ntoh16(p_pkey_tbl->indx0_pkey));
586}
587