Blame opensm/osm_pkey.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2002-2012 Mellanox Technologies LTD. All rights reserved.
Packit 13e616
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit 13e616
 *
Packit 13e616
 * This software is available to you under a choice of one of two
Packit 13e616
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit 13e616
 * General Public License (GPL) Version 2, available from the file
Packit 13e616
 * COPYING in the main directory of this source tree, or the
Packit 13e616
 * OpenIB.org BSD license below:
Packit 13e616
 *
Packit 13e616
 *     Redistribution and use in source and binary forms, with or
Packit 13e616
 *     without modification, are permitted provided that the following
Packit 13e616
 *     conditions are met:
Packit 13e616
 *
Packit 13e616
 *      - Redistributions of source code must retain the above
Packit 13e616
 *        copyright notice, this list of conditions and the following
Packit 13e616
 *        disclaimer.
Packit 13e616
 *
Packit 13e616
 *      - Redistributions in binary form must reproduce the above
Packit 13e616
 *        copyright notice, this list of conditions and the following
Packit 13e616
 *        disclaimer in the documentation and/or other materials
Packit 13e616
 *        provided with the distribution.
Packit 13e616
 *
Packit 13e616
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit 13e616
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit 13e616
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit 13e616
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit 13e616
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit 13e616
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit 13e616
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit 13e616
 * SOFTWARE.
Packit 13e616
 *
Packit 13e616
 */
Packit 13e616
Packit 13e616
/*
Packit 13e616
 * Abstract:
Packit 13e616
 *    Implementation of opensm pkey manipulation functions.
Packit 13e616
 */
Packit 13e616
Packit 13e616
#if HAVE_CONFIG_H
Packit 13e616
#  include <config.h>
Packit 13e616
#endif				/* HAVE_CONFIG_H */
Packit 13e616
Packit 13e616
#include <stdlib.h>
Packit 13e616
#include <stdio.h>
Packit 13e616
#include <string.h>
Packit 13e616
#include <complib/cl_debug.h>
Packit 13e616
#include <iba/ib_types.h>
Packit 13e616
#include <opensm/osm_file_ids.h>
Packit 13e616
#define FILE_ID OSM_FILE_PKEY_C
Packit 13e616
#include <opensm/osm_pkey.h>
Packit 13e616
#include <opensm/osm_log.h>
Packit 13e616
#include <opensm/osm_port.h>
Packit 13e616
#include <opensm/osm_node.h>
Packit 13e616
#include <opensm/osm_switch.h>
Packit 13e616
#include <opensm/osm_helper.h>
Packit 13e616
Packit 13e616
void osm_pkey_tbl_construct(IN osm_pkey_tbl_t * p_pkey_tbl)
Packit 13e616
{
Packit 13e616
	cl_map_construct(&p_pkey_tbl->accum_pkeys);
Packit 13e616
	cl_ptr_vector_construct(&p_pkey_tbl->blocks);
Packit 13e616
	cl_ptr_vector_construct(&p_pkey_tbl->new_blocks);
Packit 13e616
	cl_map_construct(&p_pkey_tbl->keys);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_pkey_tbl_destroy(IN osm_pkey_tbl_t * p_pkey_tbl)
Packit 13e616
{
Packit 13e616
	ib_pkey_table_t *p_block;
Packit 13e616
	uint16_t num_blocks, i;
Packit 13e616
Packit 13e616
	num_blocks = (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->blocks));
Packit 13e616
	for (i = 0; i < num_blocks; i++)
Packit 13e616
		if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, i)))
Packit 13e616
			free(p_block);
Packit 13e616
	cl_ptr_vector_destroy(&p_pkey_tbl->blocks);
Packit 13e616
Packit 13e616
	num_blocks =
Packit 13e616
	    (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks));
Packit 13e616
	for (i = 0; i < num_blocks; i++)
Packit 13e616
		if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, i)))
Packit 13e616
			free(p_block);
Packit 13e616
	cl_ptr_vector_destroy(&p_pkey_tbl->new_blocks);
Packit 13e616
Packit 13e616
	cl_map_remove_all(&p_pkey_tbl->accum_pkeys);
Packit 13e616
	cl_map_destroy(&p_pkey_tbl->accum_pkeys);
Packit 13e616
Packit 13e616
	cl_map_remove_all(&p_pkey_tbl->keys);
Packit 13e616
	cl_map_destroy(&p_pkey_tbl->keys);
Packit 13e616
}
Packit 13e616
Packit 13e616
ib_api_status_t osm_pkey_tbl_init(IN osm_pkey_tbl_t * p_pkey_tbl)
Packit 13e616
{
Packit 13e616
	cl_map_init(&p_pkey_tbl->accum_pkeys, 1);
Packit 13e616
	cl_ptr_vector_init(&p_pkey_tbl->blocks, 0, 1);
Packit 13e616
	cl_ptr_vector_init(&p_pkey_tbl->new_blocks, 0, 1);
Packit 13e616
	cl_map_init(&p_pkey_tbl->keys, 1);
Packit 13e616
	cl_qlist_init(&p_pkey_tbl->pending);
Packit 13e616
	p_pkey_tbl->last_pkey_idx = 0;
Packit 13e616
	p_pkey_tbl->used_blocks = 0;
Packit 13e616
	p_pkey_tbl->max_blocks = 0;
Packit 13e616
	p_pkey_tbl->rcv_blocks_cnt = 0;
Packit 13e616
	p_pkey_tbl->indx0_pkey = 0;
Packit 13e616
	return IB_SUCCESS;
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_pkey_tbl_init_new_blocks(IN const osm_pkey_tbl_t * p_pkey_tbl)
Packit 13e616
{
Packit 13e616
	ib_pkey_table_t *p_block;
Packit 13e616
	size_t b, num_blocks = cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks);
Packit 13e616
Packit 13e616
	for (b = 0; b < num_blocks; b++)
Packit 13e616
		if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, b)))
Packit 13e616
			memset(p_block, 0, sizeof(*p_block));
Packit 13e616
}
Packit 13e616
Packit 13e616
ib_api_status_t osm_pkey_tbl_set(IN osm_pkey_tbl_t * p_pkey_tbl,
Packit 13e616
				 IN uint16_t block, IN ib_pkey_table_t * p_tbl,
Packit 13e616
				 IN boolean_t allow_both_pkeys)
Packit 13e616
{
Packit 13e616
	uint16_t b, i;
Packit 13e616
	ib_pkey_table_t *p_pkey_block;
Packit 13e616
	uint16_t *p_prev_pkey;
Packit 13e616
	ib_net16_t pkey, pkey_base;
Packit 13e616
Packit 13e616
	/* make sure the block is allocated */
Packit 13e616
	if (cl_ptr_vector_get_size(&p_pkey_tbl->blocks) > block)
Packit 13e616
		p_pkey_block =
Packit 13e616
		    (ib_pkey_table_t *) cl_ptr_vector_get(&p_pkey_tbl->blocks,
Packit 13e616
							  block);
Packit 13e616
	else
Packit 13e616
		p_pkey_block = NULL;
Packit 13e616
Packit 13e616
	if (!p_pkey_block) {
Packit 13e616
		p_pkey_block =
Packit 13e616
		    (ib_pkey_table_t *) malloc(sizeof(ib_pkey_table_t));
Packit 13e616
		if (!p_pkey_block)
Packit 13e616
			return IB_ERROR;
Packit 13e616
		memset(p_pkey_block, 0, sizeof(ib_pkey_table_t));
Packit 13e616
		cl_ptr_vector_set(&p_pkey_tbl->blocks, block, p_pkey_block);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* sets the block values */
Packit 13e616
	memcpy(p_pkey_block, p_tbl, sizeof(ib_pkey_table_t));
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   NOTE: as the spec does not require uniqueness of PKeys in
Packit 13e616
	   tables there is no other way but to refresh the entire keys map.
Packit 13e616
Packit 13e616
	   Moreover, if the same key exists but with full membership it should
Packit 13e616
	   have precedence over the key with limited membership !
Packit 13e616
	 */
Packit 13e616
	cl_map_remove_all(&p_pkey_tbl->keys);
Packit 13e616
Packit 13e616
	for (b = 0; b < cl_ptr_vector_get_size(&p_pkey_tbl->blocks); b++) {
Packit 13e616
Packit 13e616
		p_pkey_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, b);
Packit 13e616
		if (!p_pkey_block)
Packit 13e616
			continue;
Packit 13e616
Packit 13e616
		for (i = 0; i < IB_NUM_PKEY_ELEMENTS_IN_BLOCK; i++) {
Packit 13e616
			pkey = p_pkey_block->pkey_entry[i];
Packit 13e616
			if (ib_pkey_is_invalid(pkey))
Packit 13e616
				continue;
Packit 13e616
Packit 13e616
			if (allow_both_pkeys)
Packit 13e616
				pkey_base = pkey;
Packit 13e616
			else
Packit 13e616
				pkey_base = ib_pkey_get_base(pkey);
Packit 13e616
Packit 13e616
			/*
Packit 13e616
			   If allow_both_pkeys is FALSE,
Packit 13e616
			   ignore the PKey Full Member bit in the key but store
Packit 13e616
			   the pointer to the table element as the map value
Packit 13e616
			 */
Packit 13e616
			p_prev_pkey = cl_map_get(&p_pkey_tbl->keys, pkey_base);
Packit 13e616
Packit 13e616
			/* we only insert if no previous or it is not full member and allow_both_pkeys is FALSE */
Packit 13e616
			if ((p_prev_pkey == NULL) ||
Packit 13e616
			    (allow_both_pkeys == FALSE &&
Packit 13e616
			     cl_ntoh16(*p_prev_pkey) < cl_ntoh16(pkey)))
Packit 13e616
				cl_map_insert(&p_pkey_tbl->keys, pkey_base,
Packit 13e616
					      &(p_pkey_block->pkey_entry[i])
Packit 13e616
				    );
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	return IB_SUCCESS;
Packit 13e616
}
Packit 13e616
Packit 13e616
/*
Packit 13e616
  Store the given pkey (along with it's overall index) in the accum_pkeys array.
Packit 13e616
*/
Packit 13e616
cl_status_t osm_pkey_tbl_set_accum_pkeys(IN osm_pkey_tbl_t * p_pkey_tbl,
Packit 13e616
					 IN uint16_t pkey,
Packit 13e616
					 IN uint16_t pkey_idx)
Packit 13e616
{
Packit 13e616
	uintptr_t ptr = pkey_idx + 1; /* 0 means not found so bias by 1 */
Packit 13e616
	uint16_t *p_prev_pkey_idx;
Packit 13e616
	cl_status_t status = CL_SUCCESS;
Packit 13e616
Packit 13e616
	if (pkey_idx >= p_pkey_tbl->last_pkey_idx)
Packit 13e616
		p_pkey_tbl->last_pkey_idx = pkey_idx + 1;
Packit 13e616
Packit 13e616
	p_prev_pkey_idx = (uint16_t *) cl_map_get(&p_pkey_tbl->accum_pkeys, pkey);
Packit 13e616
Packit 13e616
	if (p_prev_pkey_idx != NULL)
Packit 13e616
		cl_map_remove(&p_pkey_tbl->accum_pkeys, pkey);
Packit 13e616
Packit 13e616
	if (cl_map_insert(&p_pkey_tbl->accum_pkeys, pkey, (void *) ptr) == NULL)
Packit 13e616
		status = CL_INSUFFICIENT_MEMORY;
Packit 13e616
Packit 13e616
	return status;
Packit 13e616
Packit 13e616
}
Packit 13e616
Packit 13e616
/*
Packit 13e616
+ * Find the next last pkey index
Packit 13e616
+*/
Packit 13e616
void osm_pkey_find_last_accum_pkey_index(IN osm_pkey_tbl_t * p_pkey_tbl)
Packit 13e616
{
Packit 13e616
	void *ptr;
Packit 13e616
	uintptr_t pkey_idx_ptr;
Packit 13e616
	uint16_t pkey_idx, last_pkey_idx = 0;
Packit 13e616
	cl_map_iterator_t map_iter = cl_map_head(&p_pkey_tbl->accum_pkeys);
Packit 13e616
Packit 13e616
	while (map_iter != cl_map_end(&p_pkey_tbl->accum_pkeys)) {
Packit 13e616
		ptr = (uint16_t *) cl_map_obj(map_iter);
Packit 13e616
		CL_ASSERT(ptr);
Packit 13e616
		pkey_idx_ptr = (uintptr_t) ptr;
Packit 13e616
		pkey_idx = pkey_idx_ptr;
Packit 13e616
		if (pkey_idx > last_pkey_idx)
Packit 13e616
			last_pkey_idx = pkey_idx;
Packit 13e616
		map_iter = cl_map_next(map_iter);
Packit 13e616
	}
Packit 13e616
	p_pkey_tbl->last_pkey_idx = last_pkey_idx;
Packit 13e616
}
Packit 13e616
Packit 13e616
/*
Packit 13e616
  Store the given pkey in the "new" blocks array.
Packit 13e616
  Also, make sure the regular block exists.
Packit 13e616
*/
Packit 13e616
ib_api_status_t osm_pkey_tbl_set_new_entry(IN osm_pkey_tbl_t * p_pkey_tbl,
Packit 13e616
					   IN uint16_t block_idx,
Packit 13e616
					   IN uint8_t pkey_idx,
Packit 13e616
					   IN uint16_t pkey)
Packit 13e616
{
Packit 13e616
	ib_pkey_table_t *p_block;
Packit 13e616
Packit 13e616
	if (!(p_block = osm_pkey_tbl_new_block_get(p_pkey_tbl, block_idx))) {
Packit 13e616
		p_block = (ib_pkey_table_t *) malloc(sizeof(ib_pkey_table_t));
Packit 13e616
		if (!p_block)
Packit 13e616
			return IB_ERROR;
Packit 13e616
		memset(p_block, 0, sizeof(ib_pkey_table_t));
Packit 13e616
		cl_ptr_vector_set(&p_pkey_tbl->new_blocks, block_idx, p_block);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_block->pkey_entry[pkey_idx] = pkey;
Packit 13e616
	if (p_pkey_tbl->used_blocks <= block_idx)
Packit 13e616
		p_pkey_tbl->used_blocks = block_idx + 1;
Packit 13e616
Packit 13e616
	return IB_SUCCESS;
Packit 13e616
}
Packit 13e616
Packit 13e616
boolean_t osm_pkey_find_next_free_entry(IN osm_pkey_tbl_t * p_pkey_tbl,
Packit 13e616
					OUT uint16_t * p_block_idx,
Packit 13e616
					OUT uint8_t * p_pkey_idx)
Packit 13e616
{
Packit 13e616
	ib_pkey_table_t *p_new_block;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_block_idx);
Packit 13e616
	CL_ASSERT(p_pkey_idx);
Packit 13e616
Packit 13e616
	while (*p_block_idx < p_pkey_tbl->max_blocks) {
Packit 13e616
		if (*p_pkey_idx > IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) {
Packit 13e616
			*p_pkey_idx = 0;
Packit 13e616
			(*p_block_idx)++;
Packit 13e616
			if (*p_block_idx >= p_pkey_tbl->max_blocks)
Packit 13e616
				return FALSE;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		p_new_block =
Packit 13e616
		    osm_pkey_tbl_new_block_get(p_pkey_tbl, *p_block_idx);
Packit 13e616
Packit 13e616
		if (!p_new_block ||
Packit 13e616
		    ib_pkey_is_invalid(p_new_block->pkey_entry[*p_pkey_idx]))
Packit 13e616
			return TRUE;
Packit 13e616
		else
Packit 13e616
			(*p_pkey_idx)++;
Packit 13e616
	}
Packit 13e616
	return FALSE;
Packit 13e616
}
Packit 13e616
Packit 13e616
ib_api_status_t osm_pkey_tbl_get_block_and_idx(IN osm_pkey_tbl_t * p_pkey_tbl,
Packit 13e616
					       IN uint16_t * p_pkey,
Packit 13e616
					       OUT uint16_t * p_block_idx,
Packit 13e616
					       OUT uint8_t * p_pkey_idx)
Packit 13e616
{
Packit 13e616
	uint16_t num_of_blocks;
Packit 13e616
	uint16_t block_index;
Packit 13e616
	ib_pkey_table_t *block;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_block_idx != NULL);
Packit 13e616
	CL_ASSERT(p_pkey_idx != NULL);
Packit 13e616
Packit 13e616
	num_of_blocks = (uint16_t) cl_ptr_vector_get_size(&p_pkey_tbl->blocks);
Packit 13e616
	for (block_index = 0; block_index < num_of_blocks; block_index++) {
Packit 13e616
		block = osm_pkey_tbl_block_get(p_pkey_tbl, block_index);
Packit 13e616
		if ((block->pkey_entry <= p_pkey) &&
Packit 13e616
		    (p_pkey <
Packit 13e616
		     block->pkey_entry + IB_NUM_PKEY_ELEMENTS_IN_BLOCK)) {
Packit 13e616
			*p_block_idx = block_index;
Packit 13e616
			*p_pkey_idx = (uint8_t) (p_pkey - block->pkey_entry);
Packit 13e616
			return IB_SUCCESS;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	return IB_NOT_FOUND;
Packit 13e616
}
Packit 13e616
Packit 13e616
static boolean_t match_pkey(IN const ib_net16_t * pkey1,
Packit 13e616
			    IN const ib_net16_t * pkey2)
Packit 13e616
{
Packit 13e616
Packit 13e616
	/* if neither pkey is full member - this is not a match */
Packit 13e616
	if (!(ib_pkey_is_full_member(*pkey1) || ib_pkey_is_full_member(*pkey2)))
Packit 13e616
		return FALSE;
Packit 13e616
Packit 13e616
	/* compare if the bases are the same. if they are - then
Packit 13e616
	   this is a match */
Packit 13e616
	if (ib_pkey_get_base(*pkey1) != ib_pkey_get_base(*pkey2))
Packit 13e616
		return FALSE;
Packit 13e616
Packit 13e616
	return TRUE;
Packit 13e616
}
Packit 13e616
Packit 13e616
boolean_t osm_physp_share_this_pkey(IN const osm_physp_t * p_physp1,
Packit 13e616
				    IN const osm_physp_t * p_physp2,
Packit 13e616
				    IN ib_net16_t pkey,
Packit 13e616
				    IN boolean_t allow_both_pkeys)
Packit 13e616
{
Packit 13e616
	ib_net16_t *pkey1, *pkey2;
Packit 13e616
	ib_net16_t full_pkey, limited_pkey;
Packit 13e616
Packit 13e616
	if (allow_both_pkeys) {
Packit 13e616
		full_pkey = pkey | IB_PKEY_TYPE_MASK;
Packit 13e616
		limited_pkey = pkey & ~IB_PKEY_TYPE_MASK;
Packit 13e616
		pkey1 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp1))->keys,
Packit 13e616
				   full_pkey);
Packit 13e616
		if (!pkey1)
Packit 13e616
			pkey1 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp1))->keys,
Packit 13e616
					   limited_pkey);
Packit 13e616
		pkey2 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp2))->keys,
Packit 13e616
				   full_pkey);
Packit 13e616
		if (!pkey2)
Packit 13e616
			pkey2 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp2))->keys,
Packit 13e616
					   limited_pkey);
Packit 13e616
	} else {
Packit 13e616
		pkey1 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp1))->keys,
Packit 13e616
				   ib_pkey_get_base(pkey));
Packit 13e616
		pkey2 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp2))->keys,
Packit 13e616
				   ib_pkey_get_base(pkey));
Packit 13e616
	}
Packit 13e616
	return (pkey1 && pkey2 && match_pkey(pkey1, pkey2));
Packit 13e616
}
Packit 13e616
Packit 13e616
ib_net16_t osm_physp_find_common_pkey(IN const osm_physp_t * p_physp1,
Packit 13e616
				      IN const osm_physp_t * p_physp2,
Packit 13e616
				      IN boolean_t allow_both_pkeys)
Packit 13e616
{
Packit 13e616
	ib_net16_t *pkey1, *pkey2;
Packit 13e616
	uint64_t pkey1_base, pkey2_base;
Packit 13e616
	const osm_pkey_tbl_t *pkey_tbl1, *pkey_tbl2;
Packit 13e616
	cl_map_iterator_t map_iter1, map_iter2;
Packit 13e616
Packit 13e616
	pkey_tbl1 = osm_physp_get_pkey_tbl(p_physp1);
Packit 13e616
	pkey_tbl2 = osm_physp_get_pkey_tbl(p_physp2);
Packit 13e616
Packit 13e616
	map_iter1 = cl_map_head(&pkey_tbl1->keys);
Packit 13e616
	map_iter2 = cl_map_head(&pkey_tbl2->keys);
Packit 13e616
Packit 13e616
	/* we rely on the fact the map are sorted by pkey */
Packit 13e616
	while ((map_iter1 != cl_map_end(&pkey_tbl1->keys)) &&
Packit 13e616
	       (map_iter2 != cl_map_end(&pkey_tbl2->keys))) {
Packit 13e616
		pkey1 = (ib_net16_t *) cl_map_obj(map_iter1);
Packit 13e616
		pkey2 = (ib_net16_t *) cl_map_obj(map_iter2);
Packit 13e616
Packit 13e616
		if (match_pkey(pkey1, pkey2))
Packit 13e616
			return *pkey1;
Packit 13e616
Packit 13e616
		/* advance the lower value if they are not equal */
Packit 13e616
		pkey1_base = cl_map_key(map_iter1);
Packit 13e616
		pkey2_base = cl_map_key(map_iter2);
Packit 13e616
		if (pkey2_base == pkey1_base) {
Packit 13e616
			map_iter1 = cl_map_next(map_iter1);
Packit 13e616
			map_iter2 = cl_map_next(map_iter2);
Packit 13e616
		} else if (pkey2_base < pkey1_base)
Packit 13e616
			map_iter2 = cl_map_next(map_iter2);
Packit 13e616
		else
Packit 13e616
			map_iter1 = cl_map_next(map_iter1);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (!allow_both_pkeys)
Packit 13e616
		return 0;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   When using allow_both_pkeys, the keys in pkey tables are the
Packit 13e616
	   pkey value including membership bit.
Packit 13e616
	   Therefore, in order to complete the search, we also need to
Packit 13e616
	   compare port\s 1 full pkeys with port 2 limited pkeys, and
Packit 13e616
	   port 2 full pkeys with port 1 full pkeys.
Packit 13e616
	*/
Packit 13e616
Packit 13e616
	map_iter1 = cl_map_head(&pkey_tbl1->keys);
Packit 13e616
	map_iter2 = cl_map_head(&pkey_tbl2->keys);
Packit 13e616
Packit 13e616
	/* comparing pkey_tbl1 full with pkey_tbl2 limited */
Packit 13e616
	while ((map_iter1 != cl_map_end(&pkey_tbl1->keys)) &&
Packit 13e616
	       (map_iter2 != cl_map_end(&pkey_tbl2->keys))) {
Packit 13e616
		pkey1 = (ib_net16_t *) cl_map_obj(map_iter1);
Packit 13e616
		pkey2 = (ib_net16_t *) cl_map_obj(map_iter2);
Packit 13e616
Packit 13e616
		if (!ib_pkey_is_full_member(*pkey1)) {
Packit 13e616
			map_iter1 = cl_map_next(map_iter1);
Packit 13e616
			continue;
Packit 13e616
		}
Packit 13e616
		if (ib_pkey_is_full_member(*pkey2)) {
Packit 13e616
			map_iter2 = cl_map_next(map_iter2);
Packit 13e616
			continue;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if (match_pkey(pkey1, pkey2))
Packit 13e616
			return *pkey1;
Packit 13e616
Packit 13e616
		/* advance the lower value if they are not equal */
Packit 13e616
		pkey1_base = ib_pkey_get_base(cl_map_key(map_iter1));
Packit 13e616
		pkey2_base = ib_pkey_get_base(cl_map_key(map_iter2));
Packit 13e616
		if (pkey2_base == pkey1_base) {
Packit 13e616
			map_iter1 = cl_map_next(map_iter1);
Packit 13e616
			map_iter2 = cl_map_next(map_iter2);
Packit 13e616
		} else if (pkey2_base < pkey1_base)
Packit 13e616
			map_iter2 = cl_map_next(map_iter2);
Packit 13e616
		else
Packit 13e616
			map_iter1 = cl_map_next(map_iter1);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	map_iter1 = cl_map_head(&pkey_tbl1->keys);
Packit 13e616
	map_iter2 = cl_map_head(&pkey_tbl2->keys);
Packit 13e616
Packit 13e616
	/* comparing pkey_tbl1 limited with pkey_tbl2 full */
Packit 13e616
	while ((map_iter1 != cl_map_end(&pkey_tbl1->keys)) &&
Packit 13e616
	       (map_iter2 != cl_map_end(&pkey_tbl2->keys))) {
Packit 13e616
		pkey1 = (ib_net16_t *) cl_map_obj(map_iter1);
Packit 13e616
		pkey2 = (ib_net16_t *) cl_map_obj(map_iter2);
Packit 13e616
Packit 13e616
		if (ib_pkey_is_full_member(*pkey1)) {
Packit 13e616
			map_iter1 = cl_map_next(map_iter1);
Packit 13e616
			continue;
Packit 13e616
		}
Packit 13e616
		if (!ib_pkey_is_full_member(*pkey2)) {
Packit 13e616
			map_iter2 = cl_map_next(map_iter2);
Packit 13e616
			continue;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if (match_pkey(pkey1, pkey2))
Packit 13e616
			return *pkey1;
Packit 13e616
Packit 13e616
		/* advance the lower value if they are not equal */
Packit 13e616
		pkey1_base = ib_pkey_get_base(cl_map_key(map_iter1));
Packit 13e616
		pkey2_base = ib_pkey_get_base(cl_map_key(map_iter2));
Packit 13e616
		if (pkey2_base == pkey1_base) {
Packit 13e616
			map_iter1 = cl_map_next(map_iter1);
Packit 13e616
			map_iter2 = cl_map_next(map_iter2);
Packit 13e616
		} else if (pkey2_base < pkey1_base)
Packit 13e616
			map_iter2 = cl_map_next(map_iter2);
Packit 13e616
		else
Packit 13e616
			map_iter1 = cl_map_next(map_iter1);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
boolean_t osm_physp_share_pkey(IN osm_log_t * p_log,
Packit 13e616
			       IN const osm_physp_t * p_physp_1,
Packit 13e616
			       IN const osm_physp_t * p_physp_2,
Packit 13e616
			       IN boolean_t allow_both_pkeys)
Packit 13e616
{
Packit 13e616
	const osm_pkey_tbl_t *pkey_tbl1, *pkey_tbl2;
Packit 13e616
Packit 13e616
	if (p_physp_1 == p_physp_2)
Packit 13e616
		return TRUE;
Packit 13e616
Packit 13e616
	pkey_tbl1 = osm_physp_get_pkey_tbl(p_physp_1);
Packit 13e616
	pkey_tbl2 = osm_physp_get_pkey_tbl(p_physp_2);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   The spec: 10.9.2 does not require each phys port to have PKey Table.
Packit 13e616
	   So actually if it does not, we need to use the default port instead.
Packit 13e616
Packit 13e616
	   HACK: meanwhile we will ignore the check
Packit 13e616
	 */
Packit 13e616
	if (cl_is_map_empty(&pkey_tbl1->keys)
Packit 13e616
	    || cl_is_map_empty(&pkey_tbl2->keys))
Packit 13e616
		return TRUE;
Packit 13e616
Packit 13e616
	return
Packit 13e616
	    !ib_pkey_is_invalid(osm_physp_find_common_pkey
Packit 13e616
				(p_physp_1, p_physp_2, allow_both_pkeys));
Packit 13e616
}
Packit 13e616
Packit 13e616
boolean_t osm_port_share_pkey(IN osm_log_t * p_log,
Packit 13e616
			      IN const osm_port_t * p_port_1,
Packit 13e616
			      IN const osm_port_t * p_port_2,
Packit 13e616
			      IN boolean_t allow_both_pkeys)
Packit 13e616
{
Packit 13e616
Packit 13e616
	osm_physp_t *p_physp1, *p_physp2;
Packit 13e616
	boolean_t ret;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_log);
Packit 13e616
Packit 13e616
	if (!p_port_1 || !p_port_2) {
Packit 13e616
		ret = FALSE;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_physp1 = p_port_1->p_physp;
Packit 13e616
	p_physp2 = p_port_2->p_physp;
Packit 13e616
Packit 13e616
	if (!p_physp1 || !p_physp2) {
Packit 13e616
		ret = FALSE;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	ret = osm_physp_share_pkey(p_log, p_physp1, p_physp2, allow_both_pkeys);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(p_log);
Packit 13e616
	return ret;
Packit 13e616
}
Packit 13e616
Packit 13e616
boolean_t osm_physp_has_pkey(IN osm_log_t * p_log, IN ib_net16_t pkey,
Packit 13e616
			     IN const osm_physp_t * p_physp)
Packit 13e616
{
Packit 13e616
	ib_net16_t *p_pkey, pkey_base;
Packit 13e616
	const osm_pkey_tbl_t *pkey_tbl;
Packit 13e616
	boolean_t res = FALSE;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_log);
Packit 13e616
Packit 13e616
	OSM_LOG(p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Search for PKey: 0x%04x\n", cl_ntoh16(pkey));
Packit 13e616
Packit 13e616
	/* if the pkey given is an invalid pkey - return TRUE. */
Packit 13e616
	if (ib_pkey_is_invalid(pkey)) {
Packit 13e616
		OSM_LOG(p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Given invalid PKey - we treat it loosely and allow it\n");
Packit 13e616
		res = TRUE;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	pkey_base = ib_pkey_get_base(pkey);
Packit 13e616
Packit 13e616
	pkey_tbl = osm_physp_get_pkey_tbl(p_physp);
Packit 13e616
Packit 13e616
	p_pkey = cl_map_get(&pkey_tbl->keys, pkey_base);
Packit 13e616
	if (p_pkey) {
Packit 13e616
		res = TRUE;
Packit 13e616
		OSM_LOG(p_log, OSM_LOG_DEBUG,
Packit 13e616
			"PKey 0x%04x was found\n", cl_ntoh16(pkey));
Packit 13e616
	} else
Packit 13e616
		OSM_LOG(p_log, OSM_LOG_DEBUG,
Packit 13e616
			"PKey 0x%04x was not found\n", cl_ntoh16(pkey));
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(p_log);
Packit 13e616
	return res;
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_pkey_tbl_set_indx0_pkey(IN osm_log_t * p_log, IN ib_net16_t pkey,
Packit 13e616
				 IN boolean_t full,
Packit 13e616
				 OUT osm_pkey_tbl_t * p_pkey_tbl)
Packit 13e616
{
Packit 13e616
	p_pkey_tbl->indx0_pkey = (full == TRUE) ?
Packit 13e616
				 pkey | cl_hton16(0x8000) : pkey;
Packit 13e616
	OSM_LOG(p_log, OSM_LOG_DEBUG, "pkey 0x%04x set at indx0\n",
Packit 13e616
		cl_ntoh16(p_pkey_tbl->indx0_pkey));
Packit 13e616
}