1/* 2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2002-2006 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_pkey.h> 51#include <opensm/osm_log.h> 52#include <opensm/osm_port.h> 53#include <opensm/osm_node.h> 54#include <opensm/osm_switch.h> 55#include <opensm/osm_helper.h> 56 57/********************************************************************** 58 **********************************************************************/ 59void osm_pkey_tbl_construct(IN osm_pkey_tbl_t * p_pkey_tbl) 60{ 61 cl_ptr_vector_construct(&p_pkey_tbl->blocks); 62 cl_ptr_vector_construct(&p_pkey_tbl->new_blocks); 63 cl_map_construct(&p_pkey_tbl->keys); 64} 65 66/********************************************************************** 67 **********************************************************************/ 68void osm_pkey_tbl_destroy(IN osm_pkey_tbl_t * p_pkey_tbl) 69{ 70 ib_pkey_table_t *p_block; 71 uint16_t num_blocks, i; 72 73 num_blocks = (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->blocks)); 74 for (i = 0; i < num_blocks; i++) 75 if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, i))) 76 free(p_block); 77 cl_ptr_vector_destroy(&p_pkey_tbl->blocks); 78 79 num_blocks = 80 (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks)); 81 for (i = 0; i < num_blocks; i++) 82 if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, i))) 83 free(p_block); 84 cl_ptr_vector_destroy(&p_pkey_tbl->new_blocks); 85 86 cl_map_remove_all(&p_pkey_tbl->keys); 87 cl_map_destroy(&p_pkey_tbl->keys); 88} 89 90/********************************************************************** 91 **********************************************************************/ 92ib_api_status_t osm_pkey_tbl_init(IN osm_pkey_tbl_t * p_pkey_tbl) 93{ 94 cl_ptr_vector_init(&p_pkey_tbl->blocks, 0, 1); 95 cl_ptr_vector_init(&p_pkey_tbl->new_blocks, 0, 1); 96 cl_map_init(&p_pkey_tbl->keys, 1); 97 cl_qlist_init(&p_pkey_tbl->pending); 98 p_pkey_tbl->used_blocks = 0; 99 p_pkey_tbl->max_blocks = 0; 100 return (IB_SUCCESS); 101} 102 103/********************************************************************** 104 **********************************************************************/ 105void osm_pkey_tbl_init_new_blocks(IN const osm_pkey_tbl_t * p_pkey_tbl) 106{ 107 ib_pkey_table_t *p_block; 108 size_t b, num_blocks = cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks); 109 110 for (b = 0; b < num_blocks; b++) 111 if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, b))) 112 memset(p_block, 0, sizeof(*p_block)); 113} 114 115/********************************************************************** 116 **********************************************************************/ 117void osm_pkey_tbl_cleanup_pending(IN osm_pkey_tbl_t * p_pkey_tbl) 118{ 119 cl_list_item_t *p_item; 120 121 p_item = cl_qlist_remove_head(&p_pkey_tbl->pending); 122 while (p_item != cl_qlist_end(&p_pkey_tbl->pending)) { 123 free((osm_pending_pkey_t *) p_item); 124 } 125} 126 127/********************************************************************** 128 **********************************************************************/ 129ib_api_status_t 130osm_pkey_tbl_set(IN osm_pkey_tbl_t * p_pkey_tbl, 131 IN uint16_t block, IN ib_pkey_table_t * p_tbl) 132{ 133 uint16_t b, i; 134 ib_pkey_table_t *p_pkey_block; 135 uint16_t *p_prev_pkey; 136 ib_net16_t pkey; 137 138 /* make sure the block is allocated */ 139 if (cl_ptr_vector_get_size(&p_pkey_tbl->blocks) > block) 140 p_pkey_block = 141 (ib_pkey_table_t *) cl_ptr_vector_get(&p_pkey_tbl->blocks, 142 block); 143 else 144 p_pkey_block = NULL; 145 146 if (!p_pkey_block) { 147 p_pkey_block = 148 (ib_pkey_table_t *) malloc(sizeof(ib_pkey_table_t)); 149 if (!p_pkey_block) 150 return (IB_ERROR); 151 memset(p_pkey_block, 0, sizeof(ib_pkey_table_t)); 152 cl_ptr_vector_set(&p_pkey_tbl->blocks, block, p_pkey_block); 153 } 154 155 /* sets the block values */ 156 memcpy(p_pkey_block, p_tbl, sizeof(ib_pkey_table_t)); 157 158 /* 159 NOTE: as the spec does not require uniqueness of PKeys in 160 tables there is no other way but to refresh the entire keys map. 161 162 Moreover, if the same key exists but with full membership it should 163 have precedence on the key with limited membership ! 164 */ 165 cl_map_remove_all(&p_pkey_tbl->keys); 166 167 for (b = 0; b < cl_ptr_vector_get_size(&p_pkey_tbl->blocks); b++) { 168 169 p_pkey_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, b); 170 if (!p_pkey_block) 171 continue; 172 173 for (i = 0; i < IB_NUM_PKEY_ELEMENTS_IN_BLOCK; i++) { 174 pkey = p_pkey_block->pkey_entry[i]; 175 if (ib_pkey_is_invalid(pkey)) 176 continue; 177 178 /* 179 ignore the PKey Full Member bit in the key but store 180 the pointer to the table element as the map value 181 */ 182 p_prev_pkey = 183 cl_map_get(&p_pkey_tbl->keys, 184 ib_pkey_get_base(pkey)); 185 186 /* we only insert if no previous or it is not full member */ 187 if ((p_prev_pkey == NULL) || 188 (cl_ntoh16(*p_prev_pkey) < cl_ntoh16(pkey))) 189 cl_map_insert(&p_pkey_tbl->keys, 190 ib_pkey_get_base(pkey), 191 &(p_pkey_block->pkey_entry[i]) 192 ); 193 } 194 } 195 return (IB_SUCCESS); 196} 197 198/********************************************************************** 199 **********************************************************************/ 200/* 201 Store the given pkey in the "new" blocks array. 202 Also, make sure the regular block exists. 203*/ 204ib_api_status_t 205osm_pkey_tbl_set_new_entry(IN osm_pkey_tbl_t * p_pkey_tbl, 206 IN uint16_t block_idx, 207 IN uint8_t pkey_idx, IN uint16_t pkey) 208{ 209 ib_pkey_table_t *p_block; 210 211 if (!(p_block = osm_pkey_tbl_new_block_get(p_pkey_tbl, block_idx))) { 212 p_block = (ib_pkey_table_t *) malloc(sizeof(ib_pkey_table_t)); 213 if (!p_block) 214 return (IB_ERROR); 215 memset(p_block, 0, sizeof(ib_pkey_table_t)); 216 cl_ptr_vector_set(&p_pkey_tbl->new_blocks, block_idx, p_block); 217 } 218 219 p_block->pkey_entry[pkey_idx] = pkey; 220 if (p_pkey_tbl->used_blocks <= block_idx) 221 p_pkey_tbl->used_blocks = block_idx + 1; 222 223 return (IB_SUCCESS); 224} 225 226/********************************************************************** 227 **********************************************************************/ 228boolean_t 229osm_pkey_find_next_free_entry(IN osm_pkey_tbl_t * p_pkey_tbl, 230 OUT uint16_t * p_block_idx, 231 OUT uint8_t * p_pkey_idx) 232{ 233 ib_pkey_table_t *p_new_block; 234 235 CL_ASSERT(p_block_idx); 236 CL_ASSERT(p_pkey_idx); 237 238 while (*p_block_idx < p_pkey_tbl->max_blocks) { 239 if (*p_pkey_idx > IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) { 240 *p_pkey_idx = 0; 241 (*p_block_idx)++; 242 if (*p_block_idx >= p_pkey_tbl->max_blocks) 243 return FALSE; 244 } 245 246 p_new_block = 247 osm_pkey_tbl_new_block_get(p_pkey_tbl, *p_block_idx); 248 249 if (!p_new_block || 250 ib_pkey_is_invalid(p_new_block->pkey_entry[*p_pkey_idx])) 251 return TRUE; 252 else 253 (*p_pkey_idx)++; 254 } 255 return FALSE; 256} 257 258/********************************************************************** 259 **********************************************************************/ 260ib_api_status_t 261osm_pkey_tbl_get_block_and_idx(IN osm_pkey_tbl_t * p_pkey_tbl, 262 IN uint16_t * p_pkey, 263 OUT uint16_t * p_block_idx, 264 OUT uint8_t * p_pkey_idx) 265{ 266 uint16_t num_of_blocks; 267 uint16_t block_index; 268 ib_pkey_table_t *block; 269 270 CL_ASSERT(p_block_idx != NULL); 271 CL_ASSERT(p_pkey_idx != NULL); 272 273 num_of_blocks = (uint16_t) cl_ptr_vector_get_size(&p_pkey_tbl->blocks); 274 for (block_index = 0; block_index < num_of_blocks; block_index++) { 275 block = osm_pkey_tbl_block_get(p_pkey_tbl, block_index); 276 if ((block->pkey_entry <= p_pkey) && 277 (p_pkey < 278 block->pkey_entry + IB_NUM_PKEY_ELEMENTS_IN_BLOCK)) { 279 *p_block_idx = block_index; 280 *p_pkey_idx = (uint8_t) (p_pkey - block->pkey_entry); 281 return (IB_SUCCESS); 282 } 283 } 284 return (IB_NOT_FOUND); 285} 286 287/********************************************************************** 288 **********************************************************************/ 289static boolean_t 290__osm_match_pkey(IN const ib_net16_t * pkey1, IN const ib_net16_t * pkey2) 291{ 292 293 /* if both pkeys are not full member - this is not a match */ 294 if (!(ib_pkey_is_full_member(*pkey1) || ib_pkey_is_full_member(*pkey2))) 295 return (FALSE); 296 297 /* compare if the bases are the same. if they are - then 298 this is a match */ 299 if (ib_pkey_get_base(*pkey1) != ib_pkey_get_base(*pkey2)) 300 return (FALSE); 301 302 return (TRUE); 303} 304 305/********************************************************************** 306 **********************************************************************/ 307boolean_t 308osm_physp_share_this_pkey(IN const osm_physp_t * const p_physp1, 309 IN const osm_physp_t * const p_physp2, 310 IN const ib_net16_t pkey) 311{ 312 ib_net16_t *pkey1, *pkey2; 313 314 pkey1 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp1))->keys, 315 ib_pkey_get_base(pkey)); 316 pkey2 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp2))->keys, 317 ib_pkey_get_base(pkey)); 318 return (pkey1 && pkey2 && __osm_match_pkey(pkey1, pkey2)); 319} 320 321/********************************************************************** 322 **********************************************************************/ 323ib_net16_t 324osm_physp_find_common_pkey(IN const osm_physp_t * const p_physp1, 325 IN const osm_physp_t * const p_physp2) 326{ 327 ib_net16_t *pkey1, *pkey2; 328 uint64_t pkey1_base, pkey2_base; 329 const osm_pkey_tbl_t *pkey_tbl1, *pkey_tbl2; 330 cl_map_iterator_t map_iter1, map_iter2; 331 332 pkey_tbl1 = osm_physp_get_pkey_tbl(p_physp1); 333 pkey_tbl2 = osm_physp_get_pkey_tbl(p_physp2); 334 335 map_iter1 = cl_map_head(&pkey_tbl1->keys); 336 map_iter2 = cl_map_head(&pkey_tbl2->keys); 337 338 /* we rely on the fact the map are sorted by pkey */ 339 while ((map_iter1 != cl_map_end(&pkey_tbl1->keys)) && 340 (map_iter2 != cl_map_end(&pkey_tbl2->keys))) { 341 pkey1 = (ib_net16_t *) cl_map_obj(map_iter1); 342 pkey2 = (ib_net16_t *) cl_map_obj(map_iter2); 343 344 if (__osm_match_pkey(pkey1, pkey2)) 345 return *pkey1; 346 347 /* advance the lower value if they are not equal */ 348 pkey1_base = cl_map_key(map_iter1); 349 pkey2_base = cl_map_key(map_iter2); 350 if (pkey2_base == pkey1_base) { 351 map_iter1 = cl_map_next(map_iter1); 352 map_iter2 = cl_map_next(map_iter2); 353 } else if (pkey2_base < pkey1_base) 354 map_iter2 = cl_map_next(map_iter2); 355 else 356 map_iter1 = cl_map_next(map_iter1); 357 } 358 359 return 0; 360} 361 362/********************************************************************** 363 **********************************************************************/ 364boolean_t 365osm_physp_share_pkey(IN osm_log_t * p_log, 366 IN const osm_physp_t * const p_physp_1, 367 IN const osm_physp_t * const p_physp_2) 368{ 369 const osm_pkey_tbl_t *pkey_tbl1, *pkey_tbl2; 370 371 if (p_physp_1 == p_physp_2) 372 return TRUE; 373 374 pkey_tbl1 = osm_physp_get_pkey_tbl(p_physp_1); 375 pkey_tbl2 = osm_physp_get_pkey_tbl(p_physp_2); 376 377 /* 378 The spec: 10.9.2 does not require each phys port to have PKey Table. 379 So actually if it does not, we need to use the default port instead. 380 381 HACK: meanwhile we will ignore the check 382 */ 383 if (cl_is_map_empty(&pkey_tbl1->keys) 384 || cl_is_map_empty(&pkey_tbl2->keys)) 385 return TRUE; 386 387 return 388 !ib_pkey_is_invalid(osm_physp_find_common_pkey 389 (p_physp_1, p_physp_2)); 390} 391 392/********************************************************************** 393 **********************************************************************/ 394boolean_t 395osm_port_share_pkey(IN osm_log_t * p_log, 396 IN const osm_port_t * const p_port_1, 397 IN const osm_port_t * const p_port_2) 398{ 399 400 osm_physp_t *p_physp1, *p_physp2; 401 boolean_t ret; 402 403 OSM_LOG_ENTER(p_log); 404 405 if (!p_port_1 || !p_port_2) { 406 ret = FALSE; 407 goto Exit; 408 } 409 410 p_physp1 = p_port_1->p_physp; 411 p_physp2 = p_port_2->p_physp; 412 413 if (!p_physp1 || !p_physp2) { 414 ret = FALSE; 415 goto Exit; 416 } 417 418 ret = osm_physp_share_pkey(p_log, p_physp1, p_physp2); 419 420Exit: 421 OSM_LOG_EXIT(p_log); 422 return ret; 423} 424 425/********************************************************************** 426 **********************************************************************/ 427boolean_t 428osm_physp_has_pkey(IN osm_log_t * p_log, 429 IN const ib_net16_t pkey, 430 IN const osm_physp_t * const p_physp) 431{ 432 433 ib_net16_t *p_pkey, pkey_base; 434 const osm_pkey_tbl_t *pkey_tbl; 435 boolean_t res = FALSE; 436 437 OSM_LOG_ENTER(p_log); 438 439 OSM_LOG(p_log, OSM_LOG_DEBUG, 440 "Search for PKey: 0x%04x\n", cl_ntoh16(pkey)); 441 442 /* if the pkey given is an invalid pkey - return TRUE. */ 443 if (ib_pkey_is_invalid(pkey)) { 444 OSM_LOG(p_log, OSM_LOG_DEBUG, 445 "Given invalid PKey - we treat it loosely and allow it\n"); 446 res = TRUE; 447 goto Exit; 448 } 449 450 pkey_base = ib_pkey_get_base(pkey); 451 452 pkey_tbl = osm_physp_get_pkey_tbl(p_physp); 453 454 p_pkey = cl_map_get(&pkey_tbl->keys, pkey_base); 455 if (p_pkey) { 456 res = TRUE; 457 OSM_LOG(p_log, OSM_LOG_DEBUG, 458 "PKey 0x%04x was found\n", cl_ntoh16(pkey)); 459 } else { 460 OSM_LOG(p_log, OSM_LOG_DEBUG, 461 "PKey 0x%04x was not found\n", cl_ntoh16(pkey)); 462 } 463 464Exit: 465 OSM_LOG_EXIT(p_log); 466 return res; 467} 468