1321936Shselasky/*
2321936Shselasky * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3321936Shselasky * Copyright (c) 2002-2012 Mellanox Technologies LTD. All rights reserved.
4321936Shselasky * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5321936Shselasky *
6321936Shselasky * This software is available to you under a choice of one of two
7321936Shselasky * licenses.  You may choose to be licensed under the terms of the GNU
8321936Shselasky * General Public License (GPL) Version 2, available from the file
9321936Shselasky * COPYING in the main directory of this source tree, or the
10321936Shselasky * OpenIB.org BSD license below:
11321936Shselasky *
12321936Shselasky *     Redistribution and use in source and binary forms, with or
13321936Shselasky *     without modification, are permitted provided that the following
14321936Shselasky *     conditions are met:
15321936Shselasky *
16321936Shselasky *      - Redistributions of source code must retain the above
17321936Shselasky *        copyright notice, this list of conditions and the following
18321936Shselasky *        disclaimer.
19321936Shselasky *
20321936Shselasky *      - Redistributions in binary form must reproduce the above
21321936Shselasky *        copyright notice, this list of conditions and the following
22321936Shselasky *        disclaimer in the documentation and/or other materials
23321936Shselasky *        provided with the distribution.
24321936Shselasky *
25321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32321936Shselasky * SOFTWARE.
33321936Shselasky *
34321936Shselasky */
35321936Shselasky
36321936Shselasky/*
37321936Shselasky * Abstract:
38321936Shselasky *    Implementation of opensm pkey manipulation functions.
39321936Shselasky */
40321936Shselasky
41321936Shselasky#if HAVE_CONFIG_H
42321936Shselasky#  include <config.h>
43321936Shselasky#endif				/* HAVE_CONFIG_H */
44321936Shselasky
45321936Shselasky#include <stdlib.h>
46321936Shselasky#include <stdio.h>
47321936Shselasky#include <string.h>
48321936Shselasky#include <complib/cl_debug.h>
49321936Shselasky#include <iba/ib_types.h>
50321936Shselasky#include <opensm/osm_file_ids.h>
51321936Shselasky#define FILE_ID OSM_FILE_PKEY_C
52321936Shselasky#include <opensm/osm_pkey.h>
53321936Shselasky#include <opensm/osm_log.h>
54321936Shselasky#include <opensm/osm_port.h>
55321936Shselasky#include <opensm/osm_node.h>
56321936Shselasky#include <opensm/osm_switch.h>
57321936Shselasky#include <opensm/osm_helper.h>
58321936Shselasky
59321936Shselaskyvoid osm_pkey_tbl_construct(IN osm_pkey_tbl_t * p_pkey_tbl)
60321936Shselasky{
61321936Shselasky	cl_map_construct(&p_pkey_tbl->accum_pkeys);
62321936Shselasky	cl_ptr_vector_construct(&p_pkey_tbl->blocks);
63321936Shselasky	cl_ptr_vector_construct(&p_pkey_tbl->new_blocks);
64321936Shselasky	cl_map_construct(&p_pkey_tbl->keys);
65321936Shselasky}
66321936Shselasky
67321936Shselaskyvoid osm_pkey_tbl_destroy(IN osm_pkey_tbl_t * p_pkey_tbl)
68321936Shselasky{
69321936Shselasky	ib_pkey_table_t *p_block;
70321936Shselasky	uint16_t num_blocks, i;
71321936Shselasky
72321936Shselasky	num_blocks = (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->blocks));
73321936Shselasky	for (i = 0; i < num_blocks; i++)
74321936Shselasky		if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, i)))
75321936Shselasky			free(p_block);
76321936Shselasky	cl_ptr_vector_destroy(&p_pkey_tbl->blocks);
77321936Shselasky
78321936Shselasky	num_blocks =
79321936Shselasky	    (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks));
80321936Shselasky	for (i = 0; i < num_blocks; i++)
81321936Shselasky		if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, i)))
82321936Shselasky			free(p_block);
83321936Shselasky	cl_ptr_vector_destroy(&p_pkey_tbl->new_blocks);
84321936Shselasky
85321936Shselasky	cl_map_remove_all(&p_pkey_tbl->accum_pkeys);
86321936Shselasky	cl_map_destroy(&p_pkey_tbl->accum_pkeys);
87321936Shselasky
88321936Shselasky	cl_map_remove_all(&p_pkey_tbl->keys);
89321936Shselasky	cl_map_destroy(&p_pkey_tbl->keys);
90321936Shselasky}
91321936Shselasky
92321936Shselaskyib_api_status_t osm_pkey_tbl_init(IN osm_pkey_tbl_t * p_pkey_tbl)
93321936Shselasky{
94321936Shselasky	cl_map_init(&p_pkey_tbl->accum_pkeys, 1);
95321936Shselasky	cl_ptr_vector_init(&p_pkey_tbl->blocks, 0, 1);
96321936Shselasky	cl_ptr_vector_init(&p_pkey_tbl->new_blocks, 0, 1);
97321936Shselasky	cl_map_init(&p_pkey_tbl->keys, 1);
98321936Shselasky	cl_qlist_init(&p_pkey_tbl->pending);
99321936Shselasky	p_pkey_tbl->last_pkey_idx = 0;
100321936Shselasky	p_pkey_tbl->used_blocks = 0;
101321936Shselasky	p_pkey_tbl->max_blocks = 0;
102321936Shselasky	p_pkey_tbl->rcv_blocks_cnt = 0;
103321936Shselasky	p_pkey_tbl->indx0_pkey = 0;
104321936Shselasky	return IB_SUCCESS;
105321936Shselasky}
106321936Shselasky
107321936Shselaskyvoid osm_pkey_tbl_init_new_blocks(IN const osm_pkey_tbl_t * p_pkey_tbl)
108321936Shselasky{
109321936Shselasky	ib_pkey_table_t *p_block;
110321936Shselasky	size_t b, num_blocks = cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks);
111321936Shselasky
112321936Shselasky	for (b = 0; b < num_blocks; b++)
113321936Shselasky		if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, b)))
114321936Shselasky			memset(p_block, 0, sizeof(*p_block));
115321936Shselasky}
116321936Shselasky
117321936Shselaskyib_api_status_t osm_pkey_tbl_set(IN osm_pkey_tbl_t * p_pkey_tbl,
118321936Shselasky				 IN uint16_t block, IN ib_pkey_table_t * p_tbl,
119321936Shselasky				 IN boolean_t allow_both_pkeys)
120321936Shselasky{
121321936Shselasky	uint16_t b, i;
122321936Shselasky	ib_pkey_table_t *p_pkey_block;
123321936Shselasky	uint16_t *p_prev_pkey;
124321936Shselasky	ib_net16_t pkey, pkey_base;
125321936Shselasky
126321936Shselasky	/* make sure the block is allocated */
127321936Shselasky	if (cl_ptr_vector_get_size(&p_pkey_tbl->blocks) > block)
128321936Shselasky		p_pkey_block =
129321936Shselasky		    (ib_pkey_table_t *) cl_ptr_vector_get(&p_pkey_tbl->blocks,
130321936Shselasky							  block);
131321936Shselasky	else
132321936Shselasky		p_pkey_block = NULL;
133321936Shselasky
134321936Shselasky	if (!p_pkey_block) {
135321936Shselasky		p_pkey_block =
136321936Shselasky		    (ib_pkey_table_t *) malloc(sizeof(ib_pkey_table_t));
137321936Shselasky		if (!p_pkey_block)
138321936Shselasky			return IB_ERROR;
139321936Shselasky		memset(p_pkey_block, 0, sizeof(ib_pkey_table_t));
140321936Shselasky		cl_ptr_vector_set(&p_pkey_tbl->blocks, block, p_pkey_block);
141321936Shselasky	}
142321936Shselasky
143321936Shselasky	/* sets the block values */
144321936Shselasky	memcpy(p_pkey_block, p_tbl, sizeof(ib_pkey_table_t));
145321936Shselasky
146321936Shselasky	/*
147321936Shselasky	   NOTE: as the spec does not require uniqueness of PKeys in
148321936Shselasky	   tables there is no other way but to refresh the entire keys map.
149321936Shselasky
150321936Shselasky	   Moreover, if the same key exists but with full membership it should
151321936Shselasky	   have precedence over the key with limited membership !
152321936Shselasky	 */
153321936Shselasky	cl_map_remove_all(&p_pkey_tbl->keys);
154321936Shselasky
155321936Shselasky	for (b = 0; b < cl_ptr_vector_get_size(&p_pkey_tbl->blocks); b++) {
156321936Shselasky
157321936Shselasky		p_pkey_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, b);
158321936Shselasky		if (!p_pkey_block)
159321936Shselasky			continue;
160321936Shselasky
161321936Shselasky		for (i = 0; i < IB_NUM_PKEY_ELEMENTS_IN_BLOCK; i++) {
162321936Shselasky			pkey = p_pkey_block->pkey_entry[i];
163321936Shselasky			if (ib_pkey_is_invalid(pkey))
164321936Shselasky				continue;
165321936Shselasky
166321936Shselasky			if (allow_both_pkeys)
167321936Shselasky				pkey_base = pkey;
168321936Shselasky			else
169321936Shselasky				pkey_base = ib_pkey_get_base(pkey);
170321936Shselasky
171321936Shselasky			/*
172321936Shselasky			   If allow_both_pkeys is FALSE,
173321936Shselasky			   ignore the PKey Full Member bit in the key but store
174321936Shselasky			   the pointer to the table element as the map value
175321936Shselasky			 */
176321936Shselasky			p_prev_pkey = cl_map_get(&p_pkey_tbl->keys, pkey_base);
177321936Shselasky
178321936Shselasky			/* we only insert if no previous or it is not full member and allow_both_pkeys is FALSE */
179321936Shselasky			if ((p_prev_pkey == NULL) ||
180321936Shselasky			    (allow_both_pkeys == FALSE &&
181321936Shselasky			     cl_ntoh16(*p_prev_pkey) < cl_ntoh16(pkey)))
182321936Shselasky				cl_map_insert(&p_pkey_tbl->keys, pkey_base,
183321936Shselasky					      &(p_pkey_block->pkey_entry[i])
184321936Shselasky				    );
185321936Shselasky		}
186321936Shselasky	}
187321936Shselasky	return IB_SUCCESS;
188321936Shselasky}
189321936Shselasky
190321936Shselasky/*
191321936Shselasky  Store the given pkey (along with it's overall index) in the accum_pkeys array.
192321936Shselasky*/
193321936Shselaskycl_status_t osm_pkey_tbl_set_accum_pkeys(IN osm_pkey_tbl_t * p_pkey_tbl,
194321936Shselasky					 IN uint16_t pkey,
195321936Shselasky					 IN uint16_t pkey_idx)
196321936Shselasky{
197321936Shselasky	uintptr_t ptr = pkey_idx + 1; /* 0 means not found so bias by 1 */
198321936Shselasky	uint16_t *p_prev_pkey_idx;
199321936Shselasky	cl_status_t status = CL_SUCCESS;
200321936Shselasky
201321936Shselasky	if (pkey_idx >= p_pkey_tbl->last_pkey_idx)
202321936Shselasky		p_pkey_tbl->last_pkey_idx = pkey_idx + 1;
203321936Shselasky
204321936Shselasky	p_prev_pkey_idx = (uint16_t *) cl_map_get(&p_pkey_tbl->accum_pkeys, pkey);
205321936Shselasky
206321936Shselasky	if (p_prev_pkey_idx != NULL)
207321936Shselasky		cl_map_remove(&p_pkey_tbl->accum_pkeys, pkey);
208321936Shselasky
209321936Shselasky	if (cl_map_insert(&p_pkey_tbl->accum_pkeys, pkey, (void *) ptr) == NULL)
210321936Shselasky		status = CL_INSUFFICIENT_MEMORY;
211321936Shselasky
212321936Shselasky	return status;
213321936Shselasky
214321936Shselasky}
215321936Shselasky
216321936Shselasky/*
217321936Shselasky+ * Find the next last pkey index
218321936Shselasky+*/
219321936Shselaskyvoid osm_pkey_find_last_accum_pkey_index(IN osm_pkey_tbl_t * p_pkey_tbl)
220321936Shselasky{
221321936Shselasky	void *ptr;
222321936Shselasky	uintptr_t pkey_idx_ptr;
223321936Shselasky	uint16_t pkey_idx, last_pkey_idx = 0;
224321936Shselasky	cl_map_iterator_t map_iter = cl_map_head(&p_pkey_tbl->accum_pkeys);
225321936Shselasky
226321936Shselasky	while (map_iter != cl_map_end(&p_pkey_tbl->accum_pkeys)) {
227321936Shselasky		ptr = (uint16_t *) cl_map_obj(map_iter);
228321936Shselasky		CL_ASSERT(ptr);
229321936Shselasky		pkey_idx_ptr = (uintptr_t) ptr;
230321936Shselasky		pkey_idx = pkey_idx_ptr;
231321936Shselasky		if (pkey_idx > last_pkey_idx)
232321936Shselasky			last_pkey_idx = pkey_idx;
233321936Shselasky		map_iter = cl_map_next(map_iter);
234321936Shselasky	}
235321936Shselasky	p_pkey_tbl->last_pkey_idx = last_pkey_idx;
236321936Shselasky}
237321936Shselasky
238321936Shselasky/*
239321936Shselasky  Store the given pkey in the "new" blocks array.
240321936Shselasky  Also, make sure the regular block exists.
241321936Shselasky*/
242321936Shselaskyib_api_status_t osm_pkey_tbl_set_new_entry(IN osm_pkey_tbl_t * p_pkey_tbl,
243321936Shselasky					   IN uint16_t block_idx,
244321936Shselasky					   IN uint8_t pkey_idx,
245321936Shselasky					   IN uint16_t pkey)
246321936Shselasky{
247321936Shselasky	ib_pkey_table_t *p_block;
248321936Shselasky
249321936Shselasky	if (!(p_block = osm_pkey_tbl_new_block_get(p_pkey_tbl, block_idx))) {
250321936Shselasky		p_block = (ib_pkey_table_t *) malloc(sizeof(ib_pkey_table_t));
251321936Shselasky		if (!p_block)
252321936Shselasky			return IB_ERROR;
253321936Shselasky		memset(p_block, 0, sizeof(ib_pkey_table_t));
254321936Shselasky		cl_ptr_vector_set(&p_pkey_tbl->new_blocks, block_idx, p_block);
255321936Shselasky	}
256321936Shselasky
257321936Shselasky	p_block->pkey_entry[pkey_idx] = pkey;
258321936Shselasky	if (p_pkey_tbl->used_blocks <= block_idx)
259321936Shselasky		p_pkey_tbl->used_blocks = block_idx + 1;
260321936Shselasky
261321936Shselasky	return IB_SUCCESS;
262321936Shselasky}
263321936Shselasky
264321936Shselaskyboolean_t osm_pkey_find_next_free_entry(IN osm_pkey_tbl_t * p_pkey_tbl,
265321936Shselasky					OUT uint16_t * p_block_idx,
266321936Shselasky					OUT uint8_t * p_pkey_idx)
267321936Shselasky{
268321936Shselasky	ib_pkey_table_t *p_new_block;
269321936Shselasky
270321936Shselasky	CL_ASSERT(p_block_idx);
271321936Shselasky	CL_ASSERT(p_pkey_idx);
272321936Shselasky
273321936Shselasky	while (*p_block_idx < p_pkey_tbl->max_blocks) {
274321936Shselasky		if (*p_pkey_idx > IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) {
275321936Shselasky			*p_pkey_idx = 0;
276321936Shselasky			(*p_block_idx)++;
277321936Shselasky			if (*p_block_idx >= p_pkey_tbl->max_blocks)
278321936Shselasky				return FALSE;
279321936Shselasky		}
280321936Shselasky
281321936Shselasky		p_new_block =
282321936Shselasky		    osm_pkey_tbl_new_block_get(p_pkey_tbl, *p_block_idx);
283321936Shselasky
284321936Shselasky		if (!p_new_block ||
285321936Shselasky		    ib_pkey_is_invalid(p_new_block->pkey_entry[*p_pkey_idx]))
286321936Shselasky			return TRUE;
287321936Shselasky		else
288321936Shselasky			(*p_pkey_idx)++;
289321936Shselasky	}
290321936Shselasky	return FALSE;
291321936Shselasky}
292321936Shselasky
293321936Shselaskyib_api_status_t osm_pkey_tbl_get_block_and_idx(IN osm_pkey_tbl_t * p_pkey_tbl,
294321936Shselasky					       IN uint16_t * p_pkey,
295321936Shselasky					       OUT uint16_t * p_block_idx,
296321936Shselasky					       OUT uint8_t * p_pkey_idx)
297321936Shselasky{
298321936Shselasky	uint16_t num_of_blocks;
299321936Shselasky	uint16_t block_index;
300321936Shselasky	ib_pkey_table_t *block;
301321936Shselasky
302321936Shselasky	CL_ASSERT(p_block_idx != NULL);
303321936Shselasky	CL_ASSERT(p_pkey_idx != NULL);
304321936Shselasky
305321936Shselasky	num_of_blocks = (uint16_t) cl_ptr_vector_get_size(&p_pkey_tbl->blocks);
306321936Shselasky	for (block_index = 0; block_index < num_of_blocks; block_index++) {
307321936Shselasky		block = osm_pkey_tbl_block_get(p_pkey_tbl, block_index);
308321936Shselasky		if ((block->pkey_entry <= p_pkey) &&
309321936Shselasky		    (p_pkey <
310321936Shselasky		     block->pkey_entry + IB_NUM_PKEY_ELEMENTS_IN_BLOCK)) {
311321936Shselasky			*p_block_idx = block_index;
312321936Shselasky			*p_pkey_idx = (uint8_t) (p_pkey - block->pkey_entry);
313321936Shselasky			return IB_SUCCESS;
314321936Shselasky		}
315321936Shselasky	}
316321936Shselasky	return IB_NOT_FOUND;
317321936Shselasky}
318321936Shselasky
319321936Shselaskystatic boolean_t match_pkey(IN const ib_net16_t * pkey1,
320321936Shselasky			    IN const ib_net16_t * pkey2)
321321936Shselasky{
322321936Shselasky
323321936Shselasky	/* if both pkeys are not full member - this is not a match */
324321936Shselasky	if (!(ib_pkey_is_full_member(*pkey1) || ib_pkey_is_full_member(*pkey2)))
325321936Shselasky		return FALSE;
326321936Shselasky
327321936Shselasky	/* compare if the bases are the same. if they are - then
328321936Shselasky	   this is a match */
329321936Shselasky	if (ib_pkey_get_base(*pkey1) != ib_pkey_get_base(*pkey2))
330321936Shselasky		return FALSE;
331321936Shselasky
332321936Shselasky	return TRUE;
333321936Shselasky}
334321936Shselasky
335321936Shselaskyboolean_t osm_physp_share_this_pkey(IN const osm_physp_t * p_physp1,
336321936Shselasky				    IN const osm_physp_t * p_physp2,
337321936Shselasky				    IN ib_net16_t pkey,
338321936Shselasky				    IN boolean_t allow_both_pkeys)
339321936Shselasky{
340321936Shselasky	ib_net16_t *pkey1, *pkey2;
341321936Shselasky	ib_net16_t full_pkey, limited_pkey;
342321936Shselasky
343321936Shselasky	if (allow_both_pkeys) {
344321936Shselasky		full_pkey = pkey | IB_PKEY_TYPE_MASK;
345321936Shselasky		limited_pkey = pkey & ~IB_PKEY_TYPE_MASK;
346321936Shselasky		pkey1 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp1))->keys,
347321936Shselasky				   full_pkey);
348321936Shselasky		if (!pkey1)
349321936Shselasky			pkey1 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp1))->keys,
350321936Shselasky					   limited_pkey);
351321936Shselasky		pkey2 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp2))->keys,
352321936Shselasky				   full_pkey);
353321936Shselasky		if (!pkey2)
354321936Shselasky			pkey2 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp2))->keys,
355321936Shselasky					   limited_pkey);
356321936Shselasky	} else {
357321936Shselasky		pkey1 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp1))->keys,
358321936Shselasky				   ib_pkey_get_base(pkey));
359321936Shselasky		pkey2 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp2))->keys,
360321936Shselasky				   ib_pkey_get_base(pkey));
361321936Shselasky	}
362321936Shselasky	return (pkey1 && pkey2 && match_pkey(pkey1, pkey2));
363321936Shselasky}
364321936Shselasky
365321936Shselaskyib_net16_t osm_physp_find_common_pkey(IN const osm_physp_t * p_physp1,
366321936Shselasky				      IN const osm_physp_t * p_physp2,
367321936Shselasky				      IN boolean_t allow_both_pkeys)
368321936Shselasky{
369321936Shselasky	ib_net16_t *pkey1, *pkey2;
370321936Shselasky	uint64_t pkey1_base, pkey2_base;
371321936Shselasky	const osm_pkey_tbl_t *pkey_tbl1, *pkey_tbl2;
372321936Shselasky	cl_map_iterator_t map_iter1, map_iter2;
373321936Shselasky
374321936Shselasky	pkey_tbl1 = osm_physp_get_pkey_tbl(p_physp1);
375321936Shselasky	pkey_tbl2 = osm_physp_get_pkey_tbl(p_physp2);
376321936Shselasky
377321936Shselasky	map_iter1 = cl_map_head(&pkey_tbl1->keys);
378321936Shselasky	map_iter2 = cl_map_head(&pkey_tbl2->keys);
379321936Shselasky
380321936Shselasky	/* we rely on the fact the map are sorted by pkey */
381321936Shselasky	while ((map_iter1 != cl_map_end(&pkey_tbl1->keys)) &&
382321936Shselasky	       (map_iter2 != cl_map_end(&pkey_tbl2->keys))) {
383321936Shselasky		pkey1 = (ib_net16_t *) cl_map_obj(map_iter1);
384321936Shselasky		pkey2 = (ib_net16_t *) cl_map_obj(map_iter2);
385321936Shselasky
386321936Shselasky		if (match_pkey(pkey1, pkey2))
387321936Shselasky			return *pkey1;
388321936Shselasky
389321936Shselasky		/* advance the lower value if they are not equal */
390321936Shselasky		pkey1_base = cl_map_key(map_iter1);
391321936Shselasky		pkey2_base = cl_map_key(map_iter2);
392321936Shselasky		if (pkey2_base == pkey1_base) {
393321936Shselasky			map_iter1 = cl_map_next(map_iter1);
394321936Shselasky			map_iter2 = cl_map_next(map_iter2);
395321936Shselasky		} else if (pkey2_base < pkey1_base)
396321936Shselasky			map_iter2 = cl_map_next(map_iter2);
397321936Shselasky		else
398321936Shselasky			map_iter1 = cl_map_next(map_iter1);
399321936Shselasky	}
400321936Shselasky
401321936Shselasky	if (!allow_both_pkeys)
402321936Shselasky		return 0;
403321936Shselasky
404321936Shselasky	/*
405321936Shselasky	   When using allow_both_pkeys, the keys in pkey tables are the
406321936Shselasky	   pkey value including membership bit.
407321936Shselasky	   Therefore, in order to complete the search, we also need to
408321936Shselasky	   compare port\s 1 full pkeys with port 2 limited pkeys, and
409321936Shselasky	   port 2 full pkeys with port 1 full pkeys.
410321936Shselasky	*/
411321936Shselasky
412321936Shselasky	map_iter1 = cl_map_head(&pkey_tbl1->keys);
413321936Shselasky	map_iter2 = cl_map_head(&pkey_tbl2->keys);
414321936Shselasky
415321936Shselasky	/* comparing pkey_tbl1 full with pkey_tbl2 limited */
416321936Shselasky	while ((map_iter1 != cl_map_end(&pkey_tbl1->keys)) &&
417321936Shselasky	       (map_iter2 != cl_map_end(&pkey_tbl2->keys))) {
418321936Shselasky		pkey1 = (ib_net16_t *) cl_map_obj(map_iter1);
419321936Shselasky		pkey2 = (ib_net16_t *) cl_map_obj(map_iter2);
420321936Shselasky
421321936Shselasky		if (!ib_pkey_is_full_member(*pkey1)) {
422321936Shselasky			map_iter1 = cl_map_next(map_iter1);
423321936Shselasky			continue;
424321936Shselasky		}
425321936Shselasky		if (ib_pkey_is_full_member(*pkey2)) {
426321936Shselasky			map_iter2 = cl_map_next(map_iter2);
427321936Shselasky			continue;
428321936Shselasky		}
429321936Shselasky
430321936Shselasky		if (match_pkey(pkey1, pkey2))
431321936Shselasky			return *pkey1;
432321936Shselasky
433321936Shselasky		/* advance the lower value if they are not equal */
434321936Shselasky		pkey1_base = ib_pkey_get_base(cl_map_key(map_iter1));
435321936Shselasky		pkey2_base = ib_pkey_get_base(cl_map_key(map_iter2));
436321936Shselasky		if (pkey2_base == pkey1_base) {
437321936Shselasky			map_iter1 = cl_map_next(map_iter1);
438321936Shselasky			map_iter2 = cl_map_next(map_iter2);
439321936Shselasky		} else if (pkey2_base < pkey1_base)
440321936Shselasky			map_iter2 = cl_map_next(map_iter2);
441321936Shselasky		else
442321936Shselasky			map_iter1 = cl_map_next(map_iter1);
443321936Shselasky	}
444321936Shselasky
445321936Shselasky	map_iter1 = cl_map_head(&pkey_tbl1->keys);
446321936Shselasky	map_iter2 = cl_map_head(&pkey_tbl2->keys);
447321936Shselasky
448321936Shselasky	/* comparing pkey_tbl1 limited with pkey_tbl2 full */
449321936Shselasky	while ((map_iter1 != cl_map_end(&pkey_tbl1->keys)) &&
450321936Shselasky	       (map_iter2 != cl_map_end(&pkey_tbl2->keys))) {
451321936Shselasky		pkey1 = (ib_net16_t *) cl_map_obj(map_iter1);
452321936Shselasky		pkey2 = (ib_net16_t *) cl_map_obj(map_iter2);
453321936Shselasky
454321936Shselasky		if (ib_pkey_is_full_member(*pkey1)) {
455321936Shselasky			map_iter1 = cl_map_next(map_iter1);
456321936Shselasky			continue;
457321936Shselasky		}
458321936Shselasky		if (!ib_pkey_is_full_member(*pkey2)) {
459321936Shselasky			map_iter2 = cl_map_next(map_iter2);
460321936Shselasky			continue;
461321936Shselasky		}
462321936Shselasky
463321936Shselasky		if (match_pkey(pkey1, pkey2))
464321936Shselasky			return *pkey1;
465321936Shselasky
466321936Shselasky		/* advance the lower value if they are not equal */
467321936Shselasky		pkey1_base = ib_pkey_get_base(cl_map_key(map_iter1));
468321936Shselasky		pkey2_base = ib_pkey_get_base(cl_map_key(map_iter2));
469321936Shselasky		if (pkey2_base == pkey1_base) {
470321936Shselasky			map_iter1 = cl_map_next(map_iter1);
471321936Shselasky			map_iter2 = cl_map_next(map_iter2);
472321936Shselasky		} else if (pkey2_base < pkey1_base)
473321936Shselasky			map_iter2 = cl_map_next(map_iter2);
474321936Shselasky		else
475321936Shselasky			map_iter1 = cl_map_next(map_iter1);
476321936Shselasky	}
477321936Shselasky
478321936Shselasky	return 0;
479321936Shselasky}
480321936Shselasky
481321936Shselaskyboolean_t osm_physp_share_pkey(IN osm_log_t * p_log,
482321936Shselasky			       IN const osm_physp_t * p_physp_1,
483321936Shselasky			       IN const osm_physp_t * p_physp_2,
484321936Shselasky			       IN boolean_t allow_both_pkeys)
485321936Shselasky{
486321936Shselasky	const osm_pkey_tbl_t *pkey_tbl1, *pkey_tbl2;
487321936Shselasky
488321936Shselasky	if (p_physp_1 == p_physp_2)
489321936Shselasky		return TRUE;
490321936Shselasky
491321936Shselasky	pkey_tbl1 = osm_physp_get_pkey_tbl(p_physp_1);
492321936Shselasky	pkey_tbl2 = osm_physp_get_pkey_tbl(p_physp_2);
493321936Shselasky
494321936Shselasky	/*
495321936Shselasky	   The spec: 10.9.2 does not require each phys port to have PKey Table.
496321936Shselasky	   So actually if it does not, we need to use the default port instead.
497321936Shselasky
498321936Shselasky	   HACK: meanwhile we will ignore the check
499321936Shselasky	 */
500321936Shselasky	if (cl_is_map_empty(&pkey_tbl1->keys)
501321936Shselasky	    || cl_is_map_empty(&pkey_tbl2->keys))
502321936Shselasky		return TRUE;
503321936Shselasky
504321936Shselasky	return
505321936Shselasky	    !ib_pkey_is_invalid(osm_physp_find_common_pkey
506321936Shselasky				(p_physp_1, p_physp_2, allow_both_pkeys));
507321936Shselasky}
508321936Shselasky
509321936Shselaskyboolean_t osm_port_share_pkey(IN osm_log_t * p_log,
510321936Shselasky			      IN const osm_port_t * p_port_1,
511321936Shselasky			      IN const osm_port_t * p_port_2,
512321936Shselasky			      IN boolean_t allow_both_pkeys)
513321936Shselasky{
514321936Shselasky
515321936Shselasky	osm_physp_t *p_physp1, *p_physp2;
516321936Shselasky	boolean_t ret;
517321936Shselasky
518321936Shselasky	OSM_LOG_ENTER(p_log);
519321936Shselasky
520321936Shselasky	if (!p_port_1 || !p_port_2) {
521321936Shselasky		ret = FALSE;
522321936Shselasky		goto Exit;
523321936Shselasky	}
524321936Shselasky
525321936Shselasky	p_physp1 = p_port_1->p_physp;
526321936Shselasky	p_physp2 = p_port_2->p_physp;
527321936Shselasky
528321936Shselasky	if (!p_physp1 || !p_physp2) {
529321936Shselasky		ret = FALSE;
530321936Shselasky		goto Exit;
531321936Shselasky	}
532321936Shselasky
533321936Shselasky	ret = osm_physp_share_pkey(p_log, p_physp1, p_physp2, allow_both_pkeys);
534321936Shselasky
535321936ShselaskyExit:
536321936Shselasky	OSM_LOG_EXIT(p_log);
537321936Shselasky	return ret;
538321936Shselasky}
539321936Shselasky
540321936Shselaskyboolean_t osm_physp_has_pkey(IN osm_log_t * p_log, IN ib_net16_t pkey,
541321936Shselasky			     IN const osm_physp_t * p_physp)
542321936Shselasky{
543321936Shselasky	ib_net16_t *p_pkey, pkey_base;
544321936Shselasky	const osm_pkey_tbl_t *pkey_tbl;
545321936Shselasky	boolean_t res = FALSE;
546321936Shselasky
547321936Shselasky	OSM_LOG_ENTER(p_log);
548321936Shselasky
549321936Shselasky	OSM_LOG(p_log, OSM_LOG_DEBUG,
550321936Shselasky		"Search for PKey: 0x%04x\n", cl_ntoh16(pkey));
551321936Shselasky
552321936Shselasky	/* if the pkey given is an invalid pkey - return TRUE. */
553321936Shselasky	if (ib_pkey_is_invalid(pkey)) {
554321936Shselasky		OSM_LOG(p_log, OSM_LOG_DEBUG,
555321936Shselasky			"Given invalid PKey - we treat it loosely and allow it\n");
556321936Shselasky		res = TRUE;
557321936Shselasky		goto Exit;
558321936Shselasky	}
559321936Shselasky
560321936Shselasky	pkey_base = ib_pkey_get_base(pkey);
561321936Shselasky
562321936Shselasky	pkey_tbl = osm_physp_get_pkey_tbl(p_physp);
563321936Shselasky
564321936Shselasky	p_pkey = cl_map_get(&pkey_tbl->keys, pkey_base);
565321936Shselasky	if (p_pkey) {
566321936Shselasky		res = TRUE;
567321936Shselasky		OSM_LOG(p_log, OSM_LOG_DEBUG,
568321936Shselasky			"PKey 0x%04x was found\n", cl_ntoh16(pkey));
569321936Shselasky	} else
570321936Shselasky		OSM_LOG(p_log, OSM_LOG_DEBUG,
571321936Shselasky			"PKey 0x%04x was not found\n", cl_ntoh16(pkey));
572321936Shselasky
573321936ShselaskyExit:
574321936Shselasky	OSM_LOG_EXIT(p_log);
575321936Shselasky	return res;
576321936Shselasky}
577321936Shselasky
578321936Shselaskyvoid osm_pkey_tbl_set_indx0_pkey(IN osm_log_t * p_log, IN ib_net16_t pkey,
579321936Shselasky				 IN boolean_t full,
580321936Shselasky				 OUT osm_pkey_tbl_t * p_pkey_tbl)
581321936Shselasky{
582321936Shselasky	p_pkey_tbl->indx0_pkey = (full == TRUE) ?
583321936Shselasky				 pkey | cl_hton16(0x8000) : pkey;
584321936Shselasky	OSM_LOG(p_log, OSM_LOG_DEBUG, "pkey 0x%04x set at indx0\n",
585321936Shselasky		cl_ntoh16(p_pkey_tbl->indx0_pkey));
586321936Shselasky}
587