2 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2011 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
7 * This software is available to you under a choice of one of two
8 * licenses. You may choose to be licensed under the terms of the GNU
9 * General Public License (GPL) Version 2, available from the file
10 * COPYING in the main directory of this source tree, or the
11 * OpenIB.org BSD license below:
13 * Redistribution and use in source and binary forms, with or
14 * without modification, are permitted provided that the following
17 * - Redistributions of source code must retain the above
18 * copyright notice, this list of conditions and the following
21 * - Redistributions in binary form must reproduce the above
22 * copyright notice, this list of conditions and the following
23 * disclaimer in the documentation and/or other materials
24 * provided with the distribution.
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 * Implementation of the P_Key Manager (Partition Manager).
40 * This is part of the OpenSM.
45 #endif /* HAVE_CONFIG_H */
48 #include <iba/ib_types.h>
49 #include <complib/cl_qmap.h>
50 #include <complib/cl_debug.h>
51 #include <opensm/osm_file_ids.h>
52 #define FILE_ID OSM_FILE_PKEY_MGR_C
53 #include <opensm/osm_node.h>
54 #include <opensm/osm_switch.h>
55 #include <opensm/osm_partition.h>
56 #include <opensm/osm_opensm.h>
58 static void clear_accum_pkey_index(osm_pkey_tbl_t * p_pkey_tbl,
62 The max number of pkeys/pkey blocks for a physical port is located
63 in a different place for switch external ports (SwitchInfo) and the
64 rest of the ports (NodeInfo).
67 pkey_mgr_get_physp_max_pkeys(IN const osm_physp_t * p_physp)
69 osm_node_t *p_node = osm_physp_get_node_ptr(p_physp);
70 uint16_t num_pkeys = 0;
72 if (!p_node->sw || (osm_physp_get_port_num(p_physp) == 0))
73 num_pkeys = cl_ntoh16(p_node->node_info.partition_cap);
75 num_pkeys = cl_ntoh16(p_node->sw->switch_info.enforce_cap);
80 pkey_mgr_get_physp_max_blocks(IN const osm_physp_t * p_physp)
82 return ((pkey_mgr_get_physp_max_pkeys(p_physp) + 31) / 32);
86 * Insert new pending pkey entry to the specific port pkey table
87 * pending pkeys. New entries are inserted at the back.
90 pkey_mgr_process_physical_port(IN osm_log_t * p_log,
92 IN const ib_net16_t pkey,
93 IN osm_physp_t * p_physp)
95 osm_node_t *p_node = osm_physp_get_node_ptr(p_physp);
96 osm_pkey_tbl_t *p_pkey_tbl;
97 ib_net16_t *p_orig_pkey;
98 osm_pending_pkey_t *p_pending;
100 p_pkey_tbl = &p_physp->pkeys;
101 p_pending = (osm_pending_pkey_t *) calloc(1, sizeof(osm_pending_pkey_t));
103 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0502: "
104 "Failed to allocate new pending pkey entry for node "
105 "0x%016" PRIx64 " port %u\n",
106 cl_ntoh64(osm_node_get_node_guid(p_node)),
107 osm_physp_get_port_num(p_physp));
110 p_pending->pkey = pkey;
111 if (sm->p_subn->opt.allow_both_pkeys)
112 p_orig_pkey = cl_map_get(&p_pkey_tbl->keys, pkey);
114 p_orig_pkey = cl_map_get(&p_pkey_tbl->keys,
115 ib_pkey_get_base(pkey));
118 p_pending->is_new = TRUE;
120 CL_ASSERT(ib_pkey_get_base(*p_orig_pkey) ==
121 ib_pkey_get_base(pkey));
122 p_pending->is_new = FALSE;
123 if (osm_pkey_tbl_get_block_and_idx(p_pkey_tbl, p_orig_pkey,
125 &p_pending->index) !=
127 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0503: "
128 "Failed to obtain P_Key 0x%04x block and index "
129 "for node 0x%016" PRIx64 " port %u\n",
130 cl_ntoh16(ib_pkey_get_base(pkey)),
131 cl_ntoh64(osm_node_get_node_guid(p_node)),
132 osm_physp_get_port_num(p_physp));
136 if (p_physp->pkeys.indx0_pkey) {
138 * Remove the pkey that should be at index 0 from
139 * accum pkey if current position is not index 0
141 if (((sm->p_subn->opt.allow_both_pkeys &&
142 pkey == p_physp->pkeys.indx0_pkey) ||
143 (!sm->p_subn->opt.allow_both_pkeys &&
144 ib_pkey_get_base(pkey) == ib_pkey_get_base(p_physp->pkeys.indx0_pkey))) &&
145 (p_pending->block != 0 || p_pending->index != 0)) {
146 p_pending->is_new = TRUE;
147 clear_accum_pkey_index(p_pkey_tbl,
149 IB_NUM_PKEY_ELEMENTS_IN_BLOCK +
153 if (p_pending->block == 0 && p_pending->index == 0) {
154 /* Move the pkey away from index 0 */
155 if ((sm->p_subn->opt.allow_both_pkeys &&
156 pkey != p_physp->pkeys.indx0_pkey) ||
157 (!sm->p_subn->opt.allow_both_pkeys &&
158 ib_pkey_get_base(pkey) != ib_pkey_get_base(p_physp->pkeys.indx0_pkey))) {
159 p_pending->is_new = TRUE;
160 clear_accum_pkey_index(p_pkey_tbl, 0);
164 /* If index 0 is occupied by non-default, it should reoccupied by pkey 0x7FFF */
165 if (p_pending->block == 0 && p_pending->index == 0) {
166 if (ib_pkey_get_base(pkey) != IB_DEFAULT_PARTIAL_PKEY) {
167 p_pending->is_new = TRUE;
168 clear_accum_pkey_index(p_pkey_tbl, 0);
170 /* Need to move default pkey to index 0 */
171 } else if ((sm->p_subn->opt.allow_both_pkeys &&
172 pkey == IB_DEFAULT_PKEY) ||
173 (!sm->p_subn->opt.allow_both_pkeys &&
174 ib_pkey_get_base(pkey) == IB_DEFAULT_PARTIAL_PKEY)) {
175 p_pending->is_new = TRUE;
176 clear_accum_pkey_index(p_pkey_tbl,
178 IB_NUM_PKEY_ELEMENTS_IN_BLOCK +
184 if (p_pending->is_new == TRUE)
185 cl_qlist_insert_tail(&p_pkey_tbl->pending,
186 (cl_list_item_t *) p_pending);
188 cl_qlist_insert_head(&p_pkey_tbl->pending,
189 (cl_list_item_t *) p_pending);
191 OSM_LOG(p_log, OSM_LOG_DEBUG,
192 "pkey 0x%04x was %s for node 0x%016" PRIx64 " port %u\n",
193 cl_ntoh16(pkey), p_pending->is_new ? "inserted" : "updated",
194 cl_ntoh64(osm_node_get_node_guid(p_node)),
195 osm_physp_get_port_num(p_physp));
199 pkey_mgr_process_partition_table(osm_log_t * p_log, osm_sm_t * sm,
200 const osm_prtn_t * p_prtn,
201 const boolean_t full)
203 const cl_map_t *p_tbl =
204 full ? &p_prtn->full_guid_tbl : &p_prtn->part_guid_tbl;
205 cl_map_iterator_t i, i_next;
206 ib_net16_t pkey = p_prtn->pkey;
207 osm_physp_t *p_physp;
210 pkey |= cl_hton16(0x8000);
212 i_next = cl_map_head(p_tbl);
213 while (i_next != cl_map_end(p_tbl)) {
215 i_next = cl_map_next(i);
216 p_physp = cl_map_obj(i);
218 pkey_mgr_process_physical_port(p_log, sm, pkey,
223 static ib_api_status_t
224 pkey_mgr_update_pkey_entry(IN osm_sm_t * sm,
225 IN const osm_physp_t * p_physp,
226 IN const ib_pkey_table_t * block,
227 IN const uint16_t block_index)
229 osm_madw_context_t context;
230 osm_node_t *p_node = osm_physp_get_node_ptr(p_physp);
235 context.pkey_context.node_guid = osm_node_get_node_guid(p_node);
236 context.pkey_context.port_guid = osm_physp_get_port_guid(p_physp);
237 context.pkey_context.set_method = TRUE;
238 attr_mod = block_index;
239 if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH &&
240 osm_physp_get_port_num(p_physp) != 0) {
241 attr_mod |= osm_physp_get_port_num(p_physp) << 16;
242 physp0 = osm_node_get_physp_ptr(p_node, 0);
243 m_key = ib_port_info_get_m_key(&physp0->port_info);
245 m_key = ib_port_info_get_m_key(&p_physp->port_info);
246 return osm_req_set(sm, osm_physp_get_dr_path_ptr(p_physp),
247 (uint8_t *) block, sizeof(*block),
248 IB_MAD_ATTR_P_KEY_TABLE,
249 cl_hton32(attr_mod), FALSE, m_key,
250 CL_DISP_MSGID_NONE, &context);
253 static ib_api_status_t
254 pkey_mgr_enforce_partition(IN osm_log_t * p_log, osm_sm_t * sm,
255 IN osm_physp_t * p_physp,
256 IN osm_partition_enforce_type_enum enforce_type)
258 osm_madw_context_t context;
259 uint8_t payload[IB_SMP_DATA_SIZE];
260 ib_port_info_t *p_pi;
263 ib_api_status_t status;
264 uint8_t enforce_bits;
266 p_pi = &p_physp->port_info;
268 if (enforce_type == OSM_PARTITION_ENFORCE_TYPE_BOTH)
270 else if (enforce_type == OSM_PARTITION_ENFORCE_TYPE_IN)
275 if ((p_pi->vl_enforce & 0xc) == enforce_bits *
276 (enforce_type != OSM_PARTITION_ENFORCE_TYPE_OFF)) {
277 OSM_LOG(p_log, OSM_LOG_DEBUG,
278 "No need to update PortInfo for "
279 "node 0x%016" PRIx64 " port %u (%s)\n",
280 cl_ntoh64(osm_node_get_node_guid
281 (osm_physp_get_node_ptr(p_physp))),
282 osm_physp_get_port_num(p_physp),
283 p_physp->p_node->print_desc);
287 memcpy(payload, p_pi, sizeof(ib_port_info_t));
289 p_pi = (ib_port_info_t *) payload;
290 p_pi->vl_enforce &= ~0xc;
291 if (enforce_type != OSM_PARTITION_ENFORCE_TYPE_OFF)
292 p_pi->vl_enforce |= enforce_bits;
294 p_pi->state_info2 = 0;
295 ib_port_info_set_port_state(p_pi, IB_LINK_NO_CHANGE);
297 physp0 = osm_node_get_physp_ptr(p_physp->p_node, 0);
298 m_key = ib_port_info_get_m_key(&physp0->port_info);
300 context.pi_context.node_guid =
301 osm_node_get_node_guid(osm_physp_get_node_ptr(p_physp));
302 context.pi_context.port_guid = osm_physp_get_port_guid(p_physp);
303 context.pi_context.set_method = TRUE;
304 context.pi_context.light_sweep = FALSE;
305 context.pi_context.active_transition = FALSE;
306 context.pi_context.client_rereg = FALSE;
308 status = osm_req_set(sm, osm_physp_get_dr_path_ptr(p_physp),
309 payload, sizeof(payload),
310 IB_MAD_ATTR_PORT_INFO,
311 cl_hton32(osm_physp_get_port_num(p_physp)),
313 CL_DISP_MSGID_NONE, &context);
314 if (status != IB_SUCCESS)
315 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0511: "
316 "Failed to set PortInfo for "
317 "node 0x%016" PRIx64 " port %u (%s)\n",
318 cl_ntoh64(osm_node_get_node_guid
319 (osm_physp_get_node_ptr(p_physp))),
320 osm_physp_get_port_num(p_physp),
321 p_physp->p_node->print_desc);
323 OSM_LOG(p_log, OSM_LOG_DEBUG,
324 "Set PortInfo for node 0x%016" PRIx64 " port %u (%s)\n",
325 cl_ntoh64(osm_node_get_node_guid
326 (osm_physp_get_node_ptr(p_physp))),
327 osm_physp_get_port_num(p_physp),
328 p_physp->p_node->print_desc);
332 static void clear_accum_pkey_index(osm_pkey_tbl_t * p_pkey_tbl,
335 uint16_t pkey_idx_bias, pkey_idx;
337 uintptr_t pkey_idx_ptr;
338 cl_map_iterator_t map_iter, map_iter_temp;
340 map_iter = cl_map_head(&p_pkey_tbl->accum_pkeys);
342 pkey_idx_bias = pkey_index + 1; // adjust for pkey index bias in accum_pkeys
344 while (map_iter != cl_map_end(&p_pkey_tbl->accum_pkeys)) {
345 map_iter_temp = cl_map_next(map_iter);
346 ptr = (uint16_t *) cl_map_obj(map_iter);
348 pkey_idx_ptr = (uintptr_t) ptr;
349 pkey_idx = pkey_idx_ptr;
350 if (pkey_idx == pkey_idx_bias) {
351 cl_map_remove_item(&p_pkey_tbl->accum_pkeys, map_iter);
352 if (p_pkey_tbl->last_pkey_idx == pkey_idx)
353 osm_pkey_find_last_accum_pkey_index(p_pkey_tbl);
356 map_iter = map_iter_temp;
360 static int last_accum_pkey_index(osm_pkey_tbl_t * p_pkey_tbl,
361 uint16_t * p_block_idx,
362 uint8_t * p_pkey_idx)
364 if (p_pkey_tbl->last_pkey_idx) {
365 *p_block_idx = (p_pkey_tbl->last_pkey_idx - 1) / IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
366 *p_pkey_idx = (p_pkey_tbl->last_pkey_idx - 1) % IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
373 static int pkey_mgr_update_port(osm_log_t * p_log, osm_sm_t * sm,
374 const osm_port_t * const p_port)
376 osm_physp_t *p_physp;
378 ib_pkey_table_t *block, *new_block;
379 osm_pkey_tbl_t *p_pkey_tbl;
380 uint16_t block_index;
382 uint16_t last_free_block_index = 0;
383 uint8_t last_free_pkey_index = 0;
384 uint16_t num_of_blocks;
385 uint16_t max_num_of_blocks;
386 ib_api_status_t status;
387 osm_pending_pkey_t *p_pending;
389 ib_pkey_table_t empty_block;
390 int ret = 0, full = 0;
392 uintptr_t pkey_idx_ptr;
395 p_physp = p_port->p_physp;
399 memset(&empty_block, 0, sizeof(ib_pkey_table_t));
401 p_node = osm_physp_get_node_ptr(p_physp);
402 p_pkey_tbl = &p_physp->pkeys;
403 num_of_blocks = osm_pkey_tbl_get_num_blocks(p_pkey_tbl);
404 max_num_of_blocks = pkey_mgr_get_physp_max_blocks(p_physp);
405 if (p_pkey_tbl->max_blocks > max_num_of_blocks) {
406 OSM_LOG(p_log, OSM_LOG_INFO,
407 "Max number of blocks reduced from %u to %u "
408 "for node 0x%016" PRIx64 " port %u (%s)\n",
409 p_pkey_tbl->max_blocks, max_num_of_blocks,
410 cl_ntoh64(osm_node_get_node_guid(p_node)),
411 osm_physp_get_port_num(p_physp),
412 p_physp->p_node->print_desc);
414 p_pkey_tbl->max_blocks = max_num_of_blocks;
416 osm_pkey_tbl_init_new_blocks(p_pkey_tbl);
417 p_pkey_tbl->used_blocks = 0;
420 process every pending pkey in order -
421 first must be "updated" last are "new"
424 (osm_pending_pkey_t *) cl_qlist_remove_head(&p_pkey_tbl->pending);
426 (osm_pending_pkey_t *) cl_qlist_end(&p_pkey_tbl->pending)) {
431 if (p_pending->is_new == FALSE) {
432 block_index = p_pending->block;
433 pkey_index = p_pending->index;
436 ptr = cl_map_get(&p_pkey_tbl->accum_pkeys,p_pending->pkey);
438 pkey_idx_ptr = (uintptr_t) ptr;
439 pkey_idx = pkey_idx_ptr;
440 pkey_idx--; /* adjust pkey index for bias */
441 block_index = pkey_idx / IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
442 pkey_index = pkey_idx % IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
444 if (((sm->p_subn->opt.allow_both_pkeys &&
445 p_pending->pkey == p_physp->pkeys.indx0_pkey) ||
446 (!sm->p_subn->opt.allow_both_pkeys &&
447 ib_pkey_get_base(p_pending->pkey) == ib_pkey_get_base(p_physp->pkeys.indx0_pkey))) ||
448 ((p_pending->pkey != p_physp->pkeys.indx0_pkey &&
450 clear_accum_pkey_index(p_pkey_tbl, pkey_idx);
451 cl_qlist_insert_tail(&p_pkey_tbl->pending,
452 (cl_list_item_t *)p_pending);
454 (osm_pending_pkey_t *) cl_qlist_remove_head(&p_pkey_tbl->pending);
461 if (!p_pkey_tbl->indx0_pkey &&
462 ((sm->p_subn->opt.allow_both_pkeys &&
463 p_pending->pkey == IB_DEFAULT_PKEY) ||
464 (!sm->p_subn->opt.allow_both_pkeys &&
465 ib_pkey_get_base(p_pending->pkey) == IB_DEFAULT_PARTIAL_PKEY))) {
468 } else if ((sm->p_subn->opt.allow_both_pkeys &&
469 p_pending->pkey == p_pkey_tbl->indx0_pkey) ||
470 (!sm->p_subn->opt.allow_both_pkeys &&
471 ib_pkey_get_base(p_pending->pkey) ==
472 ib_pkey_get_base(p_pkey_tbl->indx0_pkey))) {
475 } else if (last_accum_pkey_index(p_pkey_tbl,
476 &last_free_block_index,
477 &last_free_pkey_index)) {
478 block_index = last_free_block_index;
479 pkey_index = last_free_pkey_index + 1;
480 if (pkey_index >= IB_NUM_PKEY_ELEMENTS_IN_BLOCK) {
482 pkey_index -= IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
489 if (block_index * IB_NUM_PKEY_ELEMENTS_IN_BLOCK + pkey_index >= pkey_mgr_get_physp_max_pkeys(p_physp)) {
490 if ((sm->p_subn->opt.allow_both_pkeys &&
491 p_pending->pkey != IB_DEFAULT_PKEY) ||
492 (!sm->p_subn->opt.allow_both_pkeys &&
493 ib_pkey_get_base(p_pending->pkey) != IB_DEFAULT_PARTIAL_PKEY)) {
494 last_free_block_index = 0;
495 last_free_pkey_index = 1;
496 found = osm_pkey_find_next_free_entry(p_pkey_tbl, &last_free_block_index, &last_free_pkey_index);
502 block_index = last_free_block_index;
503 pkey_index = last_free_pkey_index;
504 if (block_index * IB_NUM_PKEY_ELEMENTS_IN_BLOCK + pkey_index >= pkey_mgr_get_physp_max_pkeys(p_physp)) {
508 OSM_LOG(p_log, OSM_LOG_INFO,
509 "Reusing PKeyTable block index %u pkey index %u "
510 "for pkey 0x%x on 0x%016" PRIx64 " port %u (%s)\n",
513 cl_ntoh16(p_pending->pkey),
514 cl_ntoh64(osm_node_get_node_guid(p_node)),
515 osm_physp_get_port_num(p_physp),
516 p_physp->p_node->print_desc);
518 clear_accum_pkey_index(p_pkey_tbl, block_index * IB_NUM_PKEY_ELEMENTS_IN_BLOCK + pkey_index);
522 OSM_LOG(p_log, OSM_LOG_ERROR,
524 "Failed to set PKey 0x%04x because Pkey table is full "
525 "for node 0x%016" PRIx64 " port %u (%s)\n",
526 cl_ntoh16(p_pending->pkey),
527 cl_ntoh64(osm_node_get_node_guid(p_node)),
528 osm_physp_get_port_num(p_physp),
529 p_physp->p_node->print_desc);
537 osm_pkey_tbl_set_new_entry(p_pkey_tbl, block_index,
540 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0505: "
541 "Failed to set PKey 0x%04x in block %u idx %u "
542 "for node 0x%016" PRIx64 " port %u (%s)\n",
543 cl_ntoh16(p_pending->pkey), block_index,
545 cl_ntoh64(osm_node_get_node_guid
547 osm_physp_get_port_num(p_physp),
548 p_physp->p_node->print_desc);
552 osm_pkey_tbl_set_accum_pkeys(p_pkey_tbl,
554 block_index * IB_NUM_PKEY_ELEMENTS_IN_BLOCK + pkey_index)) {
555 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0508: "
556 "Failed to set accum_pkeys PKey 0x%04x "
557 "in block %u idx %u for node 0x%016"
558 PRIx64 " port %u (%s)\n",
559 cl_ntoh16(p_pending->pkey), block_index,
561 cl_ntoh64(osm_node_get_node_guid(p_node)),
562 osm_physp_get_port_num(p_physp),
563 p_physp->p_node->print_desc);
568 (osm_pending_pkey_t *) cl_qlist_remove_head(&p_pkey_tbl->
572 p_pkey_tbl->indx0_pkey = 0;
573 /* now look for changes and store */
574 for (block_index = 0; block_index < num_of_blocks; block_index++) {
575 block = osm_pkey_tbl_block_get(p_pkey_tbl, block_index);
576 new_block = osm_pkey_tbl_new_block_get(p_pkey_tbl, block_index);
578 new_block = &empty_block;
579 if (block && !memcmp(new_block, block, sizeof(*block)))
583 pkey_mgr_update_pkey_entry(sm, p_physp, new_block,
585 if (status == IB_SUCCESS)
586 OSM_LOG(p_log, OSM_LOG_DEBUG,
587 "Updated pkey table block %u for node 0x%016"
588 PRIx64 " port %u (%s)\n", block_index,
589 cl_ntoh64(osm_node_get_node_guid(p_node)),
590 osm_physp_get_port_num(p_physp),
591 p_physp->p_node->print_desc);
593 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0506: "
594 "pkey_mgr_update_pkey_entry() failed to update "
595 "pkey table block %u for node 0x%016" PRIx64
596 " port %u (%s)\n", block_index,
597 cl_ntoh64(osm_node_get_node_guid(p_node)),
598 osm_physp_get_port_num(p_physp),
599 p_physp->p_node->print_desc);
607 static int last_used_pkey_index(const osm_port_t * const p_port,
608 const osm_pkey_tbl_t * p_pkey_tbl,
609 uint16_t * p_last_index)
611 ib_pkey_table_t *last_block;
612 uint16_t index, last_index = 0;
614 CL_ASSERT(p_last_index);
616 last_block = osm_pkey_tbl_new_block_get(p_pkey_tbl,
617 p_pkey_tbl->used_blocks - 1);
621 if (p_pkey_tbl->used_blocks == p_pkey_tbl->max_blocks)
622 last_index = cl_ntoh16(p_port->p_node->node_info.partition_cap) % IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
624 last_index = IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
628 if (!ib_pkey_is_invalid(last_block->pkey_entry[index]))
630 } while (index != 0);
632 *p_last_index = index;
636 static int update_peer_block(osm_log_t * p_log, osm_sm_t * sm,
638 osm_pkey_tbl_t * p_peer_pkey_tbl,
639 ib_pkey_table_t * new_peer_block,
640 uint16_t peer_block_idx, osm_node_t * p_node)
643 ib_pkey_table_t *peer_block;
645 peer_block = osm_pkey_tbl_block_get(p_peer_pkey_tbl, peer_block_idx);
647 memcmp(peer_block, new_peer_block, sizeof(*peer_block))) {
648 if (pkey_mgr_update_pkey_entry(sm, peer, new_peer_block,
649 peer_block_idx) != IB_SUCCESS) {
650 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0509: "
651 "pkey_mgr_update_pkey_entry() failed to update "
652 "pkey table block %u for node 0x%016"
653 PRIx64 " port %u (%s)\n",
655 cl_ntoh64(osm_node_get_node_guid(p_node)),
656 osm_physp_get_port_num(peer),
665 static int new_pkey_exists(osm_pkey_tbl_t * p_pkey_tbl, ib_net16_t pkey)
668 uint16_t block_index;
669 ib_pkey_table_t *block;
672 num_blocks = (uint16_t) cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks);
673 for (block_index = 0; block_index < num_blocks; block_index++) {
674 block = osm_pkey_tbl_new_block_get(p_pkey_tbl, block_index);
678 for (pkey_idx = 0; pkey_idx < IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
680 if (block->pkey_entry[pkey_idx] == pkey)
687 static int pkey_mgr_update_peer_port(osm_log_t * p_log, osm_sm_t * sm,
688 const osm_subn_t * p_subn,
689 const osm_port_t * const p_port,
690 osm_partition_enforce_type_enum enforce_type)
692 osm_physp_t *p_physp, *peer;
694 ib_pkey_table_t *block;
695 const osm_pkey_tbl_t *p_pkey_tbl;
696 osm_pkey_tbl_t *p_peer_pkey_tbl;
697 uint16_t block_index, peer_block_idx;
698 uint16_t peer_max_blocks;
700 ib_pkey_table_t new_peer_block;
701 uint16_t pkey_idx, peer_pkey_idx;
702 ib_net16_t pkey, full_pkey;
703 int ret = 0, loop_exit = 0;
705 p_physp = p_port->p_physp;
708 peer = osm_physp_get_remote(p_physp);
711 p_node = osm_physp_get_node_ptr(peer);
712 if (!p_node->sw || !p_node->sw->switch_info.enforce_cap)
715 if (enforce_type == OSM_PARTITION_ENFORCE_TYPE_OFF) {
716 pkey_mgr_enforce_partition(p_log, sm, peer, OSM_PARTITION_ENFORCE_TYPE_OFF);
720 p_pkey_tbl = osm_physp_get_pkey_tbl(p_physp);
721 peer_max_blocks = pkey_mgr_get_physp_max_blocks(peer);
722 p_peer_pkey_tbl = &peer->pkeys;
725 for (block_index = 0; block_index < p_pkey_tbl->used_blocks;
729 block = osm_pkey_tbl_new_block_get(p_pkey_tbl, block_index);
732 for (pkey_idx = 0; pkey_idx < IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
734 pkey = block->pkey_entry[pkey_idx];
735 if (ib_pkey_is_invalid(pkey))
737 if (!ib_pkey_is_full_member(pkey)) {
738 full_pkey = pkey | IB_PKEY_TYPE_MASK;
739 if (new_pkey_exists(&p_physp->pkeys, full_pkey))
742 new_peer_block.pkey_entry[peer_pkey_idx] = pkey;
743 if (peer_block_idx >= peer_max_blocks) {
747 if (++peer_pkey_idx == IB_NUM_PKEY_ELEMENTS_IN_BLOCK) {
748 if (update_peer_block(p_log, sm, peer,
751 peer_block_idx, p_node))
759 if (peer_block_idx < peer_max_blocks) {
761 /* Handle partial last block */
762 for (; peer_pkey_idx < IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
764 new_peer_block.pkey_entry[peer_pkey_idx] = 0;
765 if (update_peer_block(p_log, sm, peer, p_peer_pkey_tbl,
766 &new_peer_block, peer_block_idx,
772 p_peer_pkey_tbl->used_blocks = peer_block_idx + 1;
773 if (p_peer_pkey_tbl->used_blocks == peer_max_blocks) {
774 /* Is last used pkey index beyond switch peer port capacity ? */
775 if (!last_used_pkey_index(p_port, p_peer_pkey_tbl,
777 last_index += peer_block_idx * IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
778 if (cl_ntoh16(p_node->sw->switch_info.enforce_cap) <= last_index) {
779 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0507: "
780 "Not enough pkey entries (%u <= %u) on switch 0x%016"
781 PRIx64 " port %u (%s). Clearing Enforcement bit\n",
782 cl_ntoh16(p_node->sw->switch_info.enforce_cap),
784 cl_ntoh64(osm_node_get_node_guid(p_node)),
785 osm_physp_get_port_num(peer),
787 enforce_type = OSM_PARTITION_ENFORCE_TYPE_OFF;
793 p_peer_pkey_tbl->used_blocks = peer_max_blocks;
794 enforce_type = OSM_PARTITION_ENFORCE_TYPE_OFF;
798 OSM_LOG(p_log, OSM_LOG_DEBUG,
799 "Pkey table was successfully updated for node 0x%016"
800 PRIx64 " port %u (%s)\n",
801 cl_ntoh64(osm_node_get_node_guid(p_node)),
802 osm_physp_get_port_num(peer), p_node->print_desc);
804 if (pkey_mgr_enforce_partition(p_log, sm, peer, enforce_type))
810 int osm_pkey_mgr_process(IN osm_opensm_t * p_osm)
813 cl_map_item_t *p_next;
817 osm_physp_t *p_physp;
818 osm_node_t *p_remote_node;
824 OSM_LOG_ENTER(&p_osm->log);
826 CL_PLOCK_EXCL_ACQUIRE(&p_osm->lock);
828 if (osm_prtn_make_partitions(&p_osm->log, &p_osm->subn) != IB_SUCCESS) {
829 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 0510: "
830 "osm_prtn_make_partitions() failed\n");
835 /* populate the pending pkey entries by scanning all partitions */
836 p_tbl = &p_osm->subn.prtn_pkey_tbl;
837 p_next = cl_qmap_head(p_tbl);
838 while (p_next != cl_qmap_end(p_tbl)) {
839 p_prtn = (osm_prtn_t *) p_next;
840 p_next = cl_qmap_next(p_next);
841 pkey_mgr_process_partition_table(&p_osm->log, &p_osm->sm,
843 pkey_mgr_process_partition_table(&p_osm->log, &p_osm->sm,
847 /* calculate and set new pkey tables */
848 p_tbl = &p_osm->subn.port_guid_tbl;
849 p_next = cl_qmap_head(p_tbl);
850 while (p_next != cl_qmap_end(p_tbl)) {
851 p_port = (osm_port_t *) p_next;
852 p_next = cl_qmap_next(p_next);
853 if (pkey_mgr_update_port(&p_osm->log, &p_osm->sm, p_port))
855 if ((osm_node_get_type(p_port->p_node) != IB_NODE_TYPE_SWITCH)
856 && pkey_mgr_update_peer_port(&p_osm->log, &p_osm->sm,
857 &p_osm->subn, p_port,
858 p_osm->subn.opt.part_enforce_enum))
862 /* clear partition enforcement on inter-switch links */
863 p_tbl = &p_osm->subn.sw_guid_tbl;
864 p_next = cl_qmap_head(p_tbl);
865 while (p_next != cl_qmap_end(p_tbl)) {
866 p_sw = (osm_switch_t *) p_next;
867 p_next = cl_qmap_next(p_next);
868 for (i = 1; i < p_sw->num_ports; i++) {
869 p_physp = osm_node_get_physp_ptr(p_sw->p_node, i);
870 if (p_physp && p_physp->p_remote_physp)
871 p_remote_node = p_physp->p_remote_physp->p_node;
875 if (osm_node_get_type(p_remote_node) != IB_NODE_TYPE_SWITCH)
878 if(! (p_physp->port_info.vl_enforce & 0xc ))
881 /* clear partition enforcement */
882 if (pkey_mgr_enforce_partition(&p_osm->log, &p_osm->sm, p_physp, OSM_PARTITION_ENFORCE_TYPE_OFF))
887 CL_PLOCK_RELEASE(&p_osm->lock);
888 OSM_LOG_EXIT(&p_osm->log);