1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3219820Sjeff * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved.
4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5219820Sjeff *
6219820Sjeff * This software is available to you under a choice of one of two
7219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
8219820Sjeff * General Public License (GPL) Version 2, available from the file
9219820Sjeff * COPYING in the main directory of this source tree, or the
10219820Sjeff * OpenIB.org BSD license below:
11219820Sjeff *
12219820Sjeff *     Redistribution and use in source and binary forms, with or
13219820Sjeff *     without modification, are permitted provided that the following
14219820Sjeff *     conditions are met:
15219820Sjeff *
16219820Sjeff *      - Redistributions of source code must retain the above
17219820Sjeff *        copyright notice, this list of conditions and the following
18219820Sjeff *        disclaimer.
19219820Sjeff *
20219820Sjeff *      - Redistributions in binary form must reproduce the above
21219820Sjeff *        copyright notice, this list of conditions and the following
22219820Sjeff *        disclaimer in the documentation and/or other materials
23219820Sjeff *        provided with the distribution.
24219820Sjeff *
25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32219820Sjeff * SOFTWARE.
33219820Sjeff *
34219820Sjeff */
35219820Sjeff
36219820Sjeff/*
37219820Sjeff * Abstract:
38219820Sjeff * Implementation of the P_Key Manager (Partititon Manager).
39219820Sjeff * This is part of the OpenSM.
40219820Sjeff */
41219820Sjeff
42219820Sjeff#if HAVE_CONFIG_H
43219820Sjeff#  include <config.h>
44219820Sjeff#endif				/* HAVE_CONFIG_H */
45219820Sjeff
46219820Sjeff#include <string.h>
47219820Sjeff#include <iba/ib_types.h>
48219820Sjeff#include <complib/cl_qmap.h>
49219820Sjeff#include <complib/cl_debug.h>
50219820Sjeff#include <opensm/osm_node.h>
51219820Sjeff#include <opensm/osm_switch.h>
52219820Sjeff#include <opensm/osm_partition.h>
53219820Sjeff#include <opensm/osm_opensm.h>
54219820Sjeff
55219820Sjeff/**********************************************************************
56219820Sjeff **********************************************************************/
57219820Sjeff/*
58219820Sjeff  The max number of pkey blocks for a physical port is located in
59219820Sjeff  a different place for switch external ports (SwitchInfo) and the
60219820Sjeff  rest of the ports (NodeInfo).
61219820Sjeff*/
62219820Sjeffstatic uint16_t
63219820Sjeffpkey_mgr_get_physp_max_blocks(IN const osm_subn_t * p_subn,
64219820Sjeff			      IN const osm_physp_t * p_physp)
65219820Sjeff{
66219820Sjeff	osm_node_t *p_node = osm_physp_get_node_ptr(p_physp);
67219820Sjeff	uint16_t num_pkeys = 0;
68219820Sjeff
69219820Sjeff	if (!p_node->sw || (osm_physp_get_port_num(p_physp) == 0))
70219820Sjeff		num_pkeys = cl_ntoh16(p_node->node_info.partition_cap);
71219820Sjeff	else
72219820Sjeff		num_pkeys = cl_ntoh16(p_node->sw->switch_info.enforce_cap);
73219820Sjeff	return ((num_pkeys + 31) / 32);
74219820Sjeff}
75219820Sjeff
76219820Sjeff/**********************************************************************
77219820Sjeff **********************************************************************/
78219820Sjeff/*
79219820Sjeff * Insert new pending pkey entry to the specific port pkey table
80219820Sjeff * pending pkeys. New entries are inserted at the back.
81219820Sjeff */
82219820Sjeffstatic void
83219820Sjeffpkey_mgr_process_physical_port(IN osm_log_t * p_log,
84219820Sjeff			       IN osm_sm_t * sm,
85219820Sjeff			       IN const ib_net16_t pkey,
86219820Sjeff			       IN osm_physp_t * p_physp)
87219820Sjeff{
88219820Sjeff	osm_node_t *p_node = osm_physp_get_node_ptr(p_physp);
89219820Sjeff	osm_pkey_tbl_t *p_pkey_tbl;
90219820Sjeff	ib_net16_t *p_orig_pkey;
91219820Sjeff	char *stat = NULL;
92219820Sjeff	osm_pending_pkey_t *p_pending;
93219820Sjeff
94219820Sjeff	p_pkey_tbl = &p_physp->pkeys;
95219820Sjeff	p_pending = (osm_pending_pkey_t *) malloc(sizeof(osm_pending_pkey_t));
96219820Sjeff	if (!p_pending) {
97219820Sjeff		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0502: "
98219820Sjeff			"Failed to allocate new pending pkey entry for node "
99219820Sjeff			"0x%016" PRIx64 " port %u\n",
100219820Sjeff			cl_ntoh64(osm_node_get_node_guid(p_node)),
101219820Sjeff			osm_physp_get_port_num(p_physp));
102219820Sjeff		return;
103219820Sjeff	}
104219820Sjeff	p_pending->pkey = pkey;
105219820Sjeff	p_orig_pkey = cl_map_get(&p_pkey_tbl->keys, ib_pkey_get_base(pkey));
106219820Sjeff	if (!p_orig_pkey) {
107219820Sjeff		p_pending->is_new = TRUE;
108219820Sjeff		cl_qlist_insert_tail(&p_pkey_tbl->pending,
109219820Sjeff				     (cl_list_item_t *) p_pending);
110219820Sjeff		stat = "inserted";
111219820Sjeff	} else {
112219820Sjeff		CL_ASSERT(ib_pkey_get_base(*p_orig_pkey) ==
113219820Sjeff			  ib_pkey_get_base(pkey));
114219820Sjeff		p_pending->is_new = FALSE;
115219820Sjeff		if (osm_pkey_tbl_get_block_and_idx(p_pkey_tbl, p_orig_pkey,
116219820Sjeff						   &p_pending->block,
117219820Sjeff						   &p_pending->index) !=
118219820Sjeff		    IB_SUCCESS) {
119219820Sjeff			OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0503: "
120219820Sjeff				"Failed to obtain P_Key 0x%04x block and index for node "
121219820Sjeff				"0x%016" PRIx64 " port %u\n",
122219820Sjeff				ib_pkey_get_base(pkey),
123219820Sjeff				cl_ntoh64(osm_node_get_node_guid(p_node)),
124219820Sjeff				osm_physp_get_port_num(p_physp));
125219820Sjeff			return;
126219820Sjeff		}
127219820Sjeff		cl_qlist_insert_head(&p_pkey_tbl->pending,
128219820Sjeff				     (cl_list_item_t *) p_pending);
129219820Sjeff		stat = "updated";
130219820Sjeff	}
131219820Sjeff
132219820Sjeff	OSM_LOG(p_log, OSM_LOG_DEBUG,
133219820Sjeff		"pkey 0x%04x was %s for node 0x%016" PRIx64 " port %u\n",
134219820Sjeff		cl_ntoh16(pkey), stat,
135219820Sjeff		cl_ntoh64(osm_node_get_node_guid(p_node)),
136219820Sjeff		osm_physp_get_port_num(p_physp));
137219820Sjeff}
138219820Sjeff
139219820Sjeff/**********************************************************************
140219820Sjeff **********************************************************************/
141219820Sjeffstatic void
142219820Sjeffpkey_mgr_process_partition_table(osm_log_t * p_log, osm_sm_t * sm,
143219820Sjeff				 const osm_prtn_t * p_prtn,
144219820Sjeff				 const boolean_t full)
145219820Sjeff{
146219820Sjeff	const cl_map_t *p_tbl =
147219820Sjeff	    full ? &p_prtn->full_guid_tbl : &p_prtn->part_guid_tbl;
148219820Sjeff	cl_map_iterator_t i, i_next;
149219820Sjeff	ib_net16_t pkey = p_prtn->pkey;
150219820Sjeff	osm_physp_t *p_physp;
151219820Sjeff
152219820Sjeff	if (full)
153219820Sjeff		pkey |= cl_hton16(0x8000);
154219820Sjeff
155219820Sjeff	i_next = cl_map_head(p_tbl);
156219820Sjeff	while (i_next != cl_map_end(p_tbl)) {
157219820Sjeff		i = i_next;
158219820Sjeff		i_next = cl_map_next(i);
159219820Sjeff		p_physp = cl_map_obj(i);
160219820Sjeff		if (p_physp)
161219820Sjeff			pkey_mgr_process_physical_port(p_log, sm, pkey,
162219820Sjeff						       p_physp);
163219820Sjeff	}
164219820Sjeff}
165219820Sjeff
166219820Sjeff/**********************************************************************
167219820Sjeff **********************************************************************/
168219820Sjeffstatic ib_api_status_t
169219820Sjeffpkey_mgr_update_pkey_entry(IN osm_sm_t * sm,
170219820Sjeff			   IN const osm_physp_t * p_physp,
171219820Sjeff			   IN const ib_pkey_table_t * block,
172219820Sjeff			   IN const uint16_t block_index)
173219820Sjeff{
174219820Sjeff	osm_madw_context_t context;
175219820Sjeff	osm_node_t *p_node = osm_physp_get_node_ptr(p_physp);
176219820Sjeff	uint32_t attr_mod;
177219820Sjeff
178219820Sjeff	context.pkey_context.node_guid = osm_node_get_node_guid(p_node);
179219820Sjeff	context.pkey_context.port_guid = osm_physp_get_port_guid(p_physp);
180219820Sjeff	context.pkey_context.set_method = TRUE;
181219820Sjeff	attr_mod = block_index;
182219820Sjeff	if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH)
183219820Sjeff		attr_mod |= osm_physp_get_port_num(p_physp) << 16;
184219820Sjeff	return osm_req_set(sm, osm_physp_get_dr_path_ptr(p_physp),
185219820Sjeff			   (uint8_t *) block, sizeof(*block),
186219820Sjeff			   IB_MAD_ATTR_P_KEY_TABLE,
187219820Sjeff			   cl_hton32(attr_mod), CL_DISP_MSGID_NONE, &context);
188219820Sjeff}
189219820Sjeff
190219820Sjeff/**********************************************************************
191219820Sjeff **********************************************************************/
192219820Sjeffstatic boolean_t
193219820Sjeffpkey_mgr_enforce_partition(IN osm_log_t * p_log, osm_sm_t * sm,
194219820Sjeff			   IN osm_physp_t * p_physp, IN const boolean_t enforce)
195219820Sjeff{
196219820Sjeff	osm_madw_context_t context;
197219820Sjeff	uint8_t payload[IB_SMP_DATA_SIZE];
198219820Sjeff	ib_port_info_t *p_pi;
199219820Sjeff	ib_api_status_t status;
200219820Sjeff
201219820Sjeff	p_pi = &p_physp->port_info;
202219820Sjeff
203219820Sjeff	if ((p_pi->vl_enforce & 0xc) == (0xc) * (enforce == TRUE)) {
204219820Sjeff		OSM_LOG(p_log, OSM_LOG_DEBUG,
205219820Sjeff			"No need to update PortInfo for "
206219820Sjeff			"node 0x%016" PRIx64 " port %u\n",
207219820Sjeff			cl_ntoh64(osm_node_get_node_guid
208219820Sjeff				  (osm_physp_get_node_ptr(p_physp))),
209219820Sjeff			osm_physp_get_port_num(p_physp));
210219820Sjeff		return FALSE;
211219820Sjeff	}
212219820Sjeff
213219820Sjeff	memset(payload, 0, IB_SMP_DATA_SIZE);
214219820Sjeff	memcpy(payload, p_pi, sizeof(ib_port_info_t));
215219820Sjeff
216219820Sjeff	p_pi = (ib_port_info_t *) payload;
217219820Sjeff	if (enforce == TRUE)
218219820Sjeff		p_pi->vl_enforce |= 0xc;
219219820Sjeff	else
220219820Sjeff		p_pi->vl_enforce &= ~0xc;
221219820Sjeff	p_pi->state_info2 = 0;
222219820Sjeff	ib_port_info_set_port_state(p_pi, IB_LINK_NO_CHANGE);
223219820Sjeff
224219820Sjeff	context.pi_context.node_guid =
225219820Sjeff	    osm_node_get_node_guid(osm_physp_get_node_ptr(p_physp));
226219820Sjeff	context.pi_context.port_guid = osm_physp_get_port_guid(p_physp);
227219820Sjeff	context.pi_context.set_method = TRUE;
228219820Sjeff	context.pi_context.light_sweep = FALSE;
229219820Sjeff	context.pi_context.active_transition = FALSE;
230219820Sjeff
231219820Sjeff	status = osm_req_set(sm, osm_physp_get_dr_path_ptr(p_physp),
232219820Sjeff			     payload, sizeof(payload),
233219820Sjeff			     IB_MAD_ATTR_PORT_INFO,
234219820Sjeff			     cl_hton32(osm_physp_get_port_num(p_physp)),
235219820Sjeff			     CL_DISP_MSGID_NONE, &context);
236219820Sjeff	if (status != IB_SUCCESS) {
237219820Sjeff		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0511: "
238219820Sjeff			"Failed to set PortInfo for "
239219820Sjeff			"node 0x%016" PRIx64 " port %u\n",
240219820Sjeff			cl_ntoh64(osm_node_get_node_guid
241219820Sjeff				  (osm_physp_get_node_ptr(p_physp))),
242219820Sjeff			osm_physp_get_port_num(p_physp));
243219820Sjeff		return FALSE;
244219820Sjeff	} else {
245219820Sjeff		OSM_LOG(p_log, OSM_LOG_DEBUG,
246219820Sjeff			"Set PortInfo for node 0x%016" PRIx64 " port %u\n",
247219820Sjeff			cl_ntoh64(osm_node_get_node_guid
248219820Sjeff				  (osm_physp_get_node_ptr(p_physp))),
249219820Sjeff			osm_physp_get_port_num(p_physp));
250219820Sjeff		return TRUE;
251219820Sjeff	}
252219820Sjeff}
253219820Sjeff
254219820Sjeff/**********************************************************************
255219820Sjeff **********************************************************************/
256219820Sjeffstatic boolean_t pkey_mgr_update_port(osm_log_t * p_log, osm_sm_t * sm,
257219820Sjeff				      const osm_port_t * const p_port)
258219820Sjeff{
259219820Sjeff	osm_physp_t *p_physp;
260219820Sjeff	osm_node_t *p_node;
261219820Sjeff	ib_pkey_table_t *block, *new_block;
262219820Sjeff	osm_pkey_tbl_t *p_pkey_tbl;
263219820Sjeff	uint16_t block_index;
264219820Sjeff	uint8_t pkey_index;
265219820Sjeff	uint16_t last_free_block_index = 0;
266219820Sjeff	uint8_t last_free_pkey_index = 0;
267219820Sjeff	uint16_t num_of_blocks;
268219820Sjeff	uint16_t max_num_of_blocks;
269219820Sjeff	ib_api_status_t status;
270219820Sjeff	boolean_t ret_val = FALSE;
271219820Sjeff	osm_pending_pkey_t *p_pending;
272219820Sjeff	boolean_t found;
273219820Sjeff	ib_pkey_table_t empty_block;
274219820Sjeff
275219820Sjeff	memset(&empty_block, 0, sizeof(ib_pkey_table_t));
276219820Sjeff
277219820Sjeff	p_physp = p_port->p_physp;
278219820Sjeff	if (!p_physp)
279219820Sjeff		return FALSE;
280219820Sjeff
281219820Sjeff	p_node = osm_physp_get_node_ptr(p_physp);
282219820Sjeff	p_pkey_tbl = &p_physp->pkeys;
283219820Sjeff	num_of_blocks = osm_pkey_tbl_get_num_blocks(p_pkey_tbl);
284219820Sjeff	max_num_of_blocks =
285219820Sjeff	    pkey_mgr_get_physp_max_blocks(sm->p_subn, p_physp);
286219820Sjeff	if (p_pkey_tbl->max_blocks > max_num_of_blocks) {
287219820Sjeff		OSM_LOG(p_log, OSM_LOG_INFO,
288219820Sjeff			"Max number of blocks reduced from %u to %u "
289219820Sjeff			"for node 0x%016" PRIx64 " port %u\n",
290219820Sjeff			p_pkey_tbl->max_blocks, max_num_of_blocks,
291219820Sjeff			cl_ntoh64(osm_node_get_node_guid(p_node)),
292219820Sjeff			osm_physp_get_port_num(p_physp));
293219820Sjeff	}
294219820Sjeff	p_pkey_tbl->max_blocks = max_num_of_blocks;
295219820Sjeff
296219820Sjeff	osm_pkey_tbl_init_new_blocks(p_pkey_tbl);
297219820Sjeff	p_pkey_tbl->used_blocks = 0;
298219820Sjeff
299219820Sjeff	/*
300219820Sjeff	   process every pending pkey in order -
301219820Sjeff	   first must be "updated" last are "new"
302219820Sjeff	 */
303219820Sjeff	p_pending =
304219820Sjeff	    (osm_pending_pkey_t *) cl_qlist_remove_head(&p_pkey_tbl->pending);
305219820Sjeff	while (p_pending !=
306219820Sjeff	       (osm_pending_pkey_t *) cl_qlist_end(&p_pkey_tbl->pending)) {
307219820Sjeff		if (p_pending->is_new == FALSE) {
308219820Sjeff			block_index = p_pending->block;
309219820Sjeff			pkey_index = p_pending->index;
310219820Sjeff			found = TRUE;
311219820Sjeff		} else {
312219820Sjeff			found = osm_pkey_find_next_free_entry(p_pkey_tbl,
313219820Sjeff							      &last_free_block_index,
314219820Sjeff							      &last_free_pkey_index);
315219820Sjeff			if (!found) {
316219820Sjeff				OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0504: "
317219820Sjeff					"Failed to find empty space for new pkey 0x%04x "
318219820Sjeff					"for node 0x%016" PRIx64 " port %u\n",
319219820Sjeff					cl_ntoh16(p_pending->pkey),
320219820Sjeff					cl_ntoh64(osm_node_get_node_guid
321219820Sjeff						  (p_node)),
322219820Sjeff					osm_physp_get_port_num(p_physp));
323219820Sjeff			} else {
324219820Sjeff				block_index = last_free_block_index;
325219820Sjeff				pkey_index = last_free_pkey_index++;
326219820Sjeff			}
327219820Sjeff		}
328219820Sjeff
329219820Sjeff		if (found) {
330219820Sjeff			if (IB_SUCCESS !=
331219820Sjeff			    osm_pkey_tbl_set_new_entry(p_pkey_tbl, block_index,
332219820Sjeff						       pkey_index,
333219820Sjeff						       p_pending->pkey)) {
334219820Sjeff				OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0505: "
335219820Sjeff					"Failed to set PKey 0x%04x in block %u idx %u "
336219820Sjeff					"for node 0x%016" PRIx64 " port %u\n",
337219820Sjeff					cl_ntoh16(p_pending->pkey), block_index,
338219820Sjeff					pkey_index,
339219820Sjeff					cl_ntoh64(osm_node_get_node_guid
340219820Sjeff						  (p_node)),
341219820Sjeff					osm_physp_get_port_num(p_physp));
342219820Sjeff			}
343219820Sjeff		}
344219820Sjeff
345219820Sjeff		free(p_pending);
346219820Sjeff		p_pending =
347219820Sjeff		    (osm_pending_pkey_t *) cl_qlist_remove_head(&p_pkey_tbl->
348219820Sjeff								pending);
349219820Sjeff	}
350219820Sjeff
351219820Sjeff	/* now look for changes and store */
352219820Sjeff	for (block_index = 0; block_index < num_of_blocks; block_index++) {
353219820Sjeff		block = osm_pkey_tbl_block_get(p_pkey_tbl, block_index);
354219820Sjeff		new_block = osm_pkey_tbl_new_block_get(p_pkey_tbl, block_index);
355219820Sjeff		if (!new_block)
356219820Sjeff			new_block = &empty_block;
357219820Sjeff		if (block && !memcmp(new_block, block, sizeof(*block)))
358219820Sjeff			continue;
359219820Sjeff
360219820Sjeff		status =
361219820Sjeff		    pkey_mgr_update_pkey_entry(sm, p_physp, new_block,
362219820Sjeff					       block_index);
363219820Sjeff		if (status == IB_SUCCESS) {
364219820Sjeff			OSM_LOG(p_log, OSM_LOG_DEBUG,
365219820Sjeff				"Updated pkey table block %d for node 0x%016"
366219820Sjeff				PRIx64 " port %u\n", block_index,
367219820Sjeff				cl_ntoh64(osm_node_get_node_guid(p_node)),
368219820Sjeff				osm_physp_get_port_num(p_physp));
369219820Sjeff			ret_val = TRUE;
370219820Sjeff		} else {
371219820Sjeff			OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0506: "
372219820Sjeff				"pkey_mgr_update_pkey_entry() failed to update "
373219820Sjeff				"pkey table block %d for node 0x%016" PRIx64
374219820Sjeff				" port %u\n", block_index,
375219820Sjeff				cl_ntoh64(osm_node_get_node_guid(p_node)),
376219820Sjeff				osm_physp_get_port_num(p_physp));
377219820Sjeff		}
378219820Sjeff	}
379219820Sjeff
380219820Sjeff	return ret_val;
381219820Sjeff}
382219820Sjeff
383219820Sjeff/**********************************************************************
384219820Sjeff **********************************************************************/
385219820Sjeffstatic boolean_t
386219820Sjeffpkey_mgr_update_peer_port(osm_log_t * p_log, osm_sm_t * sm,
387219820Sjeff			  const osm_subn_t * p_subn,
388219820Sjeff			  const osm_port_t * const p_port, boolean_t enforce)
389219820Sjeff{
390219820Sjeff	osm_physp_t *p_physp, *peer;
391219820Sjeff	osm_node_t *p_node;
392219820Sjeff	ib_pkey_table_t *block, *peer_block;
393219820Sjeff	const osm_pkey_tbl_t *p_pkey_tbl;
394219820Sjeff	osm_pkey_tbl_t *p_peer_pkey_tbl;
395219820Sjeff	uint16_t block_index;
396219820Sjeff	uint16_t num_of_blocks;
397219820Sjeff	uint16_t peer_max_blocks;
398219820Sjeff	ib_api_status_t status = IB_SUCCESS;
399219820Sjeff	boolean_t ret_val = FALSE;
400219820Sjeff	boolean_t port_info_set = FALSE;
401219820Sjeff	ib_pkey_table_t empty_block;
402219820Sjeff
403219820Sjeff	memset(&empty_block, 0, sizeof(ib_pkey_table_t));
404219820Sjeff
405219820Sjeff	p_physp = p_port->p_physp;
406219820Sjeff	if (!p_physp)
407219820Sjeff		return FALSE;
408219820Sjeff	peer = osm_physp_get_remote(p_physp);
409219820Sjeff	if (!peer)
410219820Sjeff		return FALSE;
411219820Sjeff	p_node = osm_physp_get_node_ptr(peer);
412219820Sjeff	if (!p_node->sw || !p_node->sw->switch_info.enforce_cap)
413219820Sjeff		return FALSE;
414219820Sjeff
415219820Sjeff	p_pkey_tbl = osm_physp_get_pkey_tbl(p_physp);
416219820Sjeff	p_peer_pkey_tbl = &peer->pkeys;
417219820Sjeff	num_of_blocks = osm_pkey_tbl_get_num_blocks(p_pkey_tbl);
418219820Sjeff	peer_max_blocks = pkey_mgr_get_physp_max_blocks(p_subn, peer);
419219820Sjeff	if (peer_max_blocks < p_pkey_tbl->used_blocks) {
420219820Sjeff		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0508: "
421219820Sjeff			"Not enough pkey entries (%u < %u) on switch 0x%016"
422219820Sjeff			PRIx64 " port %u. Clearing Enforcement bit\n",
423219820Sjeff			peer_max_blocks, num_of_blocks,
424219820Sjeff			cl_ntoh64(osm_node_get_node_guid(p_node)),
425219820Sjeff			osm_physp_get_port_num(peer));
426219820Sjeff		enforce = FALSE;
427219820Sjeff	}
428219820Sjeff
429219820Sjeff	if (pkey_mgr_enforce_partition(p_log, sm, peer, enforce))
430219820Sjeff		port_info_set = TRUE;
431219820Sjeff
432219820Sjeff	if (enforce == FALSE)
433219820Sjeff		return port_info_set;
434219820Sjeff
435219820Sjeff	p_peer_pkey_tbl->used_blocks = p_pkey_tbl->used_blocks;
436219820Sjeff	for (block_index = 0; block_index < p_pkey_tbl->used_blocks;
437219820Sjeff	     block_index++) {
438219820Sjeff		block = osm_pkey_tbl_new_block_get(p_pkey_tbl, block_index);
439219820Sjeff		if (!block)
440219820Sjeff			block = &empty_block;
441219820Sjeff
442219820Sjeff		peer_block =
443219820Sjeff		    osm_pkey_tbl_block_get(p_peer_pkey_tbl, block_index);
444219820Sjeff		if (!peer_block
445219820Sjeff		    || memcmp(peer_block, block, sizeof(*peer_block))) {
446219820Sjeff			status =
447219820Sjeff			    pkey_mgr_update_pkey_entry(sm, peer, block,
448219820Sjeff						       block_index);
449219820Sjeff			if (status == IB_SUCCESS)
450219820Sjeff				ret_val = TRUE;
451219820Sjeff			else
452219820Sjeff				OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0509: "
453219820Sjeff					"pkey_mgr_update_pkey_entry() failed to update "
454219820Sjeff					"pkey table block %d for node 0x%016"
455219820Sjeff					PRIx64 " port %u\n", block_index,
456219820Sjeff					cl_ntoh64(osm_node_get_node_guid
457219820Sjeff						  (p_node)),
458219820Sjeff					osm_physp_get_port_num(peer));
459219820Sjeff		}
460219820Sjeff	}
461219820Sjeff
462219820Sjeff	if (ret_val)
463219820Sjeff		OSM_LOG(p_log, OSM_LOG_DEBUG,
464219820Sjeff			"Pkey table was updated for node 0x%016" PRIx64
465219820Sjeff			" port %u\n",
466219820Sjeff			cl_ntoh64(osm_node_get_node_guid(p_node)),
467219820Sjeff			osm_physp_get_port_num(peer));
468219820Sjeff
469219820Sjeff	if (port_info_set)
470219820Sjeff		return TRUE;
471219820Sjeff	return ret_val;
472219820Sjeff}
473219820Sjeff
474219820Sjeff/**********************************************************************
475219820Sjeff **********************************************************************/
476219820Sjeffosm_signal_t osm_pkey_mgr_process(IN osm_opensm_t * p_osm)
477219820Sjeff{
478219820Sjeff	cl_qmap_t *p_tbl;
479219820Sjeff	cl_map_item_t *p_next;
480219820Sjeff	osm_prtn_t *p_prtn;
481219820Sjeff	osm_port_t *p_port;
482219820Sjeff	osm_signal_t signal = OSM_SIGNAL_DONE;
483219820Sjeff
484219820Sjeff	CL_ASSERT(p_osm);
485219820Sjeff
486219820Sjeff	OSM_LOG_ENTER(&p_osm->log);
487219820Sjeff
488219820Sjeff	CL_PLOCK_EXCL_ACQUIRE(&p_osm->lock);
489219820Sjeff
490219820Sjeff	if (osm_prtn_make_partitions(&p_osm->log, &p_osm->subn) != IB_SUCCESS) {
491219820Sjeff		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 0510: "
492219820Sjeff			"osm_prtn_make_partitions() failed\n");
493219820Sjeff		goto _err;
494219820Sjeff	}
495219820Sjeff
496219820Sjeff	/* populate the pending pkey entries by scanning all partitions */
497219820Sjeff	p_tbl = &p_osm->subn.prtn_pkey_tbl;
498219820Sjeff	p_next = cl_qmap_head(p_tbl);
499219820Sjeff	while (p_next != cl_qmap_end(p_tbl)) {
500219820Sjeff		p_prtn = (osm_prtn_t *) p_next;
501219820Sjeff		p_next = cl_qmap_next(p_next);
502219820Sjeff		pkey_mgr_process_partition_table(&p_osm->log, &p_osm->sm,
503219820Sjeff						 p_prtn, FALSE);
504219820Sjeff		pkey_mgr_process_partition_table(&p_osm->log, &p_osm->sm,
505219820Sjeff						 p_prtn, TRUE);
506219820Sjeff	}
507219820Sjeff
508219820Sjeff	/* calculate and set new pkey tables */
509219820Sjeff	p_tbl = &p_osm->subn.port_guid_tbl;
510219820Sjeff	p_next = cl_qmap_head(p_tbl);
511219820Sjeff	while (p_next != cl_qmap_end(p_tbl)) {
512219820Sjeff		p_port = (osm_port_t *) p_next;
513219820Sjeff		p_next = cl_qmap_next(p_next);
514219820Sjeff		if (pkey_mgr_update_port(&p_osm->log, &p_osm->sm, p_port))
515219820Sjeff			signal = OSM_SIGNAL_DONE_PENDING;
516219820Sjeff		if ((osm_node_get_type(p_port->p_node) != IB_NODE_TYPE_SWITCH)
517219820Sjeff		    && pkey_mgr_update_peer_port(&p_osm->log, &p_osm->sm,
518219820Sjeff						 &p_osm->subn, p_port,
519219820Sjeff						 !p_osm->subn.opt.
520219820Sjeff						 no_partition_enforcement))
521219820Sjeff			signal = OSM_SIGNAL_DONE_PENDING;
522219820Sjeff	}
523219820Sjeff
524219820Sjeff_err:
525219820Sjeff	CL_PLOCK_RELEASE(&p_osm->lock);
526219820Sjeff	OSM_LOG_EXIT(&p_osm->log);
527219820Sjeff	return (signal);
528219820Sjeff}
529