1155153Smarius/*
2155153Smarius * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3155153Smarius * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved.
4155153Smarius * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5155153Smarius *
6155153Smarius * This software is available to you under a choice of one of two
7155153Smarius * licenses.  You may choose to be licensed under the terms of the GNU
8155153Smarius * General Public License (GPL) Version 2, available from the file
9155153Smarius * COPYING in the main directory of this source tree, or the
10155153Smarius * OpenIB.org BSD license below:
11155153Smarius *
12155153Smarius *     Redistribution and use in source and binary forms, with or
13155153Smarius *     without modification, are permitted provided that the following
14155153Smarius *     conditions are met:
15155153Smarius *
16155153Smarius *      - Redistributions of source code must retain the above
17155153Smarius *        copyright notice, this list of conditions and the following
18155153Smarius *        disclaimer.
19155153Smarius *
20155153Smarius *      - Redistributions in binary form must reproduce the above
21155153Smarius *        copyright notice, this list of conditions and the following
22155153Smarius *        disclaimer in the documentation and/or other materials
23155153Smarius *        provided with the distribution.
24155153Smarius *
25155153Smarius * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26155153Smarius * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27155153Smarius * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28155153Smarius * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29155153Smarius * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30155153Smarius * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31155153Smarius * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32155153Smarius * SOFTWARE.
33155153Smarius *
34155153Smarius */
35155153Smarius
36155153Smarius/*
37155153Smarius * Abstract:
38155153Smarius *    Implementation of osm_pi_rcv_t.
39166145Smarius * This object represents the PortInfo Receiver object.
40155153Smarius * This object is part of the opensm family of objects.
41155153Smarius */
42155153Smarius
43155153Smarius#if HAVE_CONFIG_H
44166145Smarius#  include <config.h>
45155153Smarius#endif				/* HAVE_CONFIG_H */
46155153Smarius
47155153Smarius#include <string.h>
48155153Smarius#include <iba/ib_types.h>
49155153Smarius#include <complib/cl_qmap.h>
50155153Smarius#include <complib/cl_passivelock.h>
51155153Smarius#include <complib/cl_debug.h>
52155153Smarius#include <vendor/osm_vendor_api.h>
53155153Smarius#include <opensm/osm_madw.h>
54155153Smarius#include <opensm/osm_log.h>
55155153Smarius#include <opensm/osm_node.h>
56155153Smarius#include <opensm/osm_subnet.h>
57155153Smarius#include <opensm/osm_mad_pool.h>
58155153Smarius#include <opensm/osm_msgdef.h>
59162005Smarius#include <opensm/osm_helper.h>
60166145Smarius#include <opensm/osm_pkey.h>
61162005Smarius#include <opensm/osm_remote_sm.h>
62162005Smarius#include <opensm/osm_opensm.h>
63162005Smarius#include <opensm/osm_ucast_mgr.h>
64162005Smarius
65162005Smarius/**********************************************************************
66162005Smarius **********************************************************************/
67166145Smariusstatic void
68162005Smarius__osm_pi_rcv_set_sm(IN osm_sm_t * sm,
69162005Smarius		    IN osm_physp_t * const p_physp)
70162005Smarius{
71162005Smarius	osm_bind_handle_t h_bind;
72162005Smarius	osm_dr_path_t *p_dr_path;
73162005Smarius
74155153Smarius	OSM_LOG_ENTER(sm->p_log);
75155153Smarius
76155153Smarius	OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
77155153Smarius		"Setting IS_SM bit in port attributes\n");
78166145Smarius
79166145Smarius	p_dr_path = osm_physp_get_dr_path_ptr(p_physp);
80166145Smarius	h_bind = osm_dr_path_get_bind_handle(p_dr_path);
81166145Smarius
82155153Smarius	/*
83155153Smarius	   The 'IS_SM' bit isn't already set, so set it.
84162005Smarius	 */
85155153Smarius	osm_vendor_set_sm(h_bind, TRUE);
86155153Smarius
87155153Smarius	OSM_LOG_EXIT(sm->p_log);
88162005Smarius}
89166145Smarius
90166145Smarius/**********************************************************************
91166145Smarius **********************************************************************/
92166145Smariusstatic void pi_rcv_check_and_fix_lid(osm_log_t *log, ib_port_info_t * const pi,
93166145Smarius				     osm_physp_t * p)
94155153Smarius{
95155153Smarius	if (cl_ntoh16(pi->base_lid) > IB_LID_UCAST_END_HO) {
96155220Smarius		OSM_LOG(log, OSM_LOG_ERROR, "ERR 0F04: "
97155220Smarius			"Got invalid base LID %u from the network. "
98155153Smarius			"Corrected to %u.\n", cl_ntoh16(pi->base_lid),
99162005Smarius			cl_ntoh16(p->port_info.base_lid));
100155153Smarius		pi->base_lid = p->port_info.base_lid;
101155153Smarius	}
102155153Smarius}
103155153Smarius
104155220Smarius/**********************************************************************
105155220Smarius **********************************************************************/
106162005Smariusstatic void
107155220Smarius__osm_pi_rcv_process_endport(IN osm_sm_t * sm,
108155220Smarius			     IN osm_physp_t * const p_physp,
109155220Smarius			     IN const ib_port_info_t * const p_pi)
110162005Smarius{
111155220Smarius	osm_madw_context_t context;
112155153Smarius	ib_api_status_t status;
113155220Smarius	ib_net64_t port_guid;
114155153Smarius	uint8_t rate, mtu;
115162005Smarius	cl_qmap_t *p_sm_tbl;
116162005Smarius	osm_remote_sm_t *p_sm;
117162005Smarius
118162005Smarius	OSM_LOG_ENTER(sm->p_log);
119162005Smarius
120162005Smarius	port_guid = osm_physp_get_port_guid(p_physp);
121155153Smarius
122155153Smarius	/* HACK extended port 0 should be handled too! */
123155153Smarius	if (osm_physp_get_port_num(p_physp) != 0) {
124155153Smarius		/* track the minimal endport MTU and rate */
125155153Smarius		mtu = ib_port_info_get_mtu_cap(p_pi);
126155153Smarius		if (mtu < sm->p_subn->min_ca_mtu) {
127155153Smarius			OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
128155153Smarius				"Setting endport minimal MTU to:%u defined by port:0x%"
129162005Smarius				PRIx64 "\n", mtu, cl_ntoh64(port_guid));
130162005Smarius			sm->p_subn->min_ca_mtu = mtu;
131162005Smarius		}
132162005Smarius
133162005Smarius		rate = ib_port_info_compute_rate(p_pi);
134162005Smarius		if (rate < sm->p_subn->min_ca_rate) {
135162005Smarius			OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
136162005Smarius				"Setting endport minimal rate to:%u defined by port:0x%"
137162005Smarius				PRIx64 "\n", rate, cl_ntoh64(port_guid));
138162005Smarius			sm->p_subn->min_ca_rate = rate;
139162005Smarius		}
140162005Smarius	}
141162005Smarius
142162005Smarius	if (port_guid == sm->p_subn->sm_port_guid) {
143162005Smarius		/*
144162005Smarius		   We received the PortInfo for our own port.
145162005Smarius		 */
146162005Smarius		if (!(p_pi->capability_mask & IB_PORT_CAP_IS_SM))
147162005Smarius			/*
148162005Smarius			   Set the IS_SM bit to indicate our port hosts an SM.
149162005Smarius			 */
150162005Smarius			__osm_pi_rcv_set_sm(sm, p_physp);
151162005Smarius	} else {
152162005Smarius		p_sm_tbl = &sm->p_subn->sm_guid_tbl;
153162005Smarius		if (p_pi->capability_mask & IB_PORT_CAP_IS_SM) {
154162005Smarius			/*
155162005Smarius			 * Before querying the SM - we want to make sure we
156162005Smarius			 * clean its state, so if the querying fails we
157162005Smarius			 * recognize that this SM is not active.
158162005Smarius			 */
159162005Smarius			p_sm = (osm_remote_sm_t *) cl_qmap_get(p_sm_tbl, port_guid);
160162005Smarius			if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl))
161162005Smarius				/* clean it up */
162162005Smarius				p_sm->smi.pri_state = 0xF0 & p_sm->smi.pri_state;
163155153Smarius			if (sm->p_subn->opt.ignore_other_sm)
164155153Smarius				OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
165162005Smarius					"Ignoring SM on port 0x%" PRIx64 "\n",
166162005Smarius					cl_ntoh64(port_guid));
167162005Smarius			else {
168162005Smarius				OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
169162005Smarius					"Detected another SM. Requesting SMInfo"
170162005Smarius					"\n\t\t\t\tPort 0x%" PRIx64 "\n",
171162005Smarius					cl_ntoh64(port_guid));
172162005Smarius
173162005Smarius				/*
174162005Smarius				   This port indicates it's an SM and
175162005Smarius				   it's not our own port.
176162005Smarius				   Acquire the SMInfo Attribute.
177162005Smarius				 */
178162005Smarius				memset(&context, 0, sizeof(context));
179164125Smarius				context.smi_context.set_method = FALSE;
180164125Smarius				context.smi_context.port_guid = port_guid;
181162005Smarius				status = osm_req_get(sm,
182162005Smarius						     osm_physp_get_dr_path_ptr
183162005Smarius						     (p_physp),
184162005Smarius						     IB_MAD_ATTR_SM_INFO, 0,
185162005Smarius						     CL_DISP_MSGID_NONE,
186162005Smarius						     &context);
187162005Smarius
188162005Smarius				if (status != IB_SUCCESS)
189162005Smarius					OSM_LOG(sm->p_log, OSM_LOG_ERROR,
190162005Smarius						"ERR 0F05: "
191162005Smarius						"Failure requesting SMInfo (%s)\n",
192162005Smarius						ib_get_err_str(status));
193162005Smarius			}
194162005Smarius		} else {
195162005Smarius			p_sm = (osm_remote_sm_t *) cl_qmap_remove(p_sm_tbl, port_guid);
196162005Smarius			if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl))
197162005Smarius				free(p_sm);
198162005Smarius		}
199162005Smarius	}
200162005Smarius
201162005Smarius	OSM_LOG_EXIT(sm->p_log);
202162005Smarius}
203155153Smarius
204155153Smarius/**********************************************************************
205155153Smarius The plock must be held before calling this function.
206155153Smarius**********************************************************************/
207155153Smariusstatic void
208155153Smarius__osm_pi_rcv_process_switch_port(IN osm_sm_t * sm,
209155153Smarius				 IN osm_node_t * const p_node,
210155153Smarius				 IN osm_physp_t * const p_physp,
211155153Smarius				 IN ib_port_info_t * const p_pi)
212155153Smarius{
213155153Smarius	ib_api_status_t status = IB_SUCCESS;
214155153Smarius	osm_madw_context_t context;
215155153Smarius	osm_physp_t *p_remote_physp;
216155153Smarius	osm_node_t *p_remote_node;
217155153Smarius	uint8_t port_num;
218155153Smarius	uint8_t remote_port_num;
219155153Smarius	osm_dr_path_t path;
220155153Smarius
221155153Smarius	OSM_LOG_ENTER(sm->p_log);
222155153Smarius
223155153Smarius	/*
224155153Smarius	   Check the state of the physical port.
225155153Smarius	   If there appears to be something on the other end of the wire,
226155153Smarius	   then ask for NodeInfo.  Ignore the switch management port.
227155153Smarius	 */
228155153Smarius	port_num = osm_physp_get_port_num(p_physp);
229155153Smarius	/* if in_sweep_hop_0 is TRUE, then this means the SM is on the switch,
230162005Smarius	   and we got switchInfo of our local switch. Do not continue
231155153Smarius	   probing through the switch. */
232155153Smarius	if (port_num != 0 && sm->p_subn->in_sweep_hop_0 == FALSE) {
233155153Smarius		switch (ib_port_info_get_port_state(p_pi)) {
234155153Smarius		case IB_LINK_DOWN:
235155153Smarius			p_remote_physp = osm_physp_get_remote(p_physp);
236155153Smarius			if (p_remote_physp) {
237155153Smarius				p_remote_node =
238155153Smarius				    osm_physp_get_node_ptr(p_remote_physp);
239155153Smarius				remote_port_num =
240155153Smarius				    osm_physp_get_port_num(p_remote_physp);
241155153Smarius
242155153Smarius				OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
243155153Smarius					"Unlinking local node 0x%" PRIx64
244155153Smarius					", port %u"
245155153Smarius					"\n\t\t\t\tand remote node 0x%" PRIx64
246155153Smarius					", port %u\n",
247155153Smarius					cl_ntoh64(osm_node_get_node_guid
248155153Smarius						  (p_node)), port_num,
249155153Smarius					cl_ntoh64(osm_node_get_node_guid
250155153Smarius						  (p_remote_node)),
251166145Smarius					remote_port_num);
252166145Smarius
253166145Smarius				if (sm->ucast_mgr.cache_valid)
254166145Smarius					osm_ucast_cache_add_link(&sm->ucast_mgr,
255166145Smarius								 p_physp,
256166145Smarius								 p_remote_physp);
257166145Smarius
258166145Smarius				osm_node_unlink(p_node, (uint8_t) port_num,
259166145Smarius						p_remote_node,
260166145Smarius						(uint8_t) remote_port_num);
261166145Smarius
262155153Smarius			}
263155153Smarius			break;
264166145Smarius
265166145Smarius		case IB_LINK_INIT:
266166145Smarius		case IB_LINK_ARMED:
267166145Smarius		case IB_LINK_ACTIVE:
268166145Smarius			/*
269162871Sru			   To avoid looping forever, only probe the port if it
270162871Sru			   is NOT the port that responded to the SMP.
271155153Smarius
272162871Sru			   Request node info from the other end of this link:
273155153Smarius			   1) Copy the current path from the parent node.
274162871Sru			   2) Extend the path to the next hop thru this port.
275155153Smarius			   3) Request node info with the new path
276155153Smarius
277155153Smarius			 */
278155153Smarius			if (p_pi->local_port_num !=
279162871Sru			    osm_physp_get_port_num(p_physp)) {
280162871Sru				path = *osm_physp_get_dr_path_ptr(p_physp);
281155153Smarius
282155153Smarius				osm_dr_path_extend(&path,
283155153Smarius						   osm_physp_get_port_num
284155153Smarius						   (p_physp));
285155153Smarius
286155153Smarius				memset(&context, 0, sizeof(context));
287155153Smarius				context.ni_context.node_guid =
288155153Smarius				    osm_node_get_node_guid(p_node);
289155153Smarius				context.ni_context.port_num =
290155153Smarius				    osm_physp_get_port_num(p_physp);
291155153Smarius
292155153Smarius				status = osm_req_get(sm,
293155153Smarius						     &path,
294155153Smarius						     IB_MAD_ATTR_NODE_INFO,
295155153Smarius						     0,
296155153Smarius						     CL_DISP_MSGID_NONE,
297166145Smarius						     &context);
298166145Smarius
299166145Smarius				if (status != IB_SUCCESS)
300166145Smarius					OSM_LOG(sm->p_log, OSM_LOG_ERROR,
301166145Smarius						"ERR 0F02: "
302162871Sru						"Failure initiating NodeInfo request (%s)\n",
303162871Sru						ib_get_err_str(status));
304155153Smarius			} else
305162871Sru				OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
306155153Smarius					"Skipping SMP responder port %u\n",
307162871Sru					p_pi->local_port_num);
308155153Smarius			break;
309155153Smarius
310155153Smarius		default:
311155153Smarius			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F03: "
312155153Smarius				"Unknown link state = %u, port = %u\n",
313155153Smarius				ib_port_info_get_port_state(p_pi),
314155153Smarius				p_pi->local_port_num);
315155153Smarius			break;
316155153Smarius		}
317166145Smarius	}
318166145Smarius
319166145Smarius	if (ib_port_info_get_port_state(p_pi) > IB_LINK_INIT && p_node->sw &&
320166145Smarius	    p_node->sw->need_update == 1)
321166145Smarius		p_node->sw->need_update = 0;
322166145Smarius
323166145Smarius	if (p_physp->need_update)
324166145Smarius		sm->p_subn->ignore_existing_lfts = TRUE;
325166145Smarius
326166145Smarius	if (port_num == 0)
327166145Smarius		pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp);
328166145Smarius
329166145Smarius	/*
330166145Smarius	   Update the PortInfo attribute.
331166145Smarius	 */
332166145Smarius	osm_physp_set_port_info(p_physp, p_pi);
333166145Smarius
334166145Smarius	if (port_num == 0) {
335166145Smarius		/* Determine if base switch port 0 */
336166145Smarius		if (p_node->sw &&
337166145Smarius		    !ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info))
338166145Smarius			/* PortState is not used on BSP0 but just in case it is DOWN */
339166145Smarius			p_physp->port_info = *p_pi;
340155153Smarius		__osm_pi_rcv_process_endport(sm, p_physp, p_pi);
341155153Smarius	}
342155153Smarius
343155153Smarius	OSM_LOG_EXIT(sm->p_log);
344155153Smarius}
345155153Smarius
346155153Smarius/**********************************************************************
347155153Smarius **********************************************************************/
348155153Smariusstatic void
349155153Smarius__osm_pi_rcv_process_ca_or_router_port(IN osm_sm_t * sm,
350155153Smarius				       IN osm_node_t * const p_node,
351155153Smarius				       IN osm_physp_t * const p_physp,
352155153Smarius				       IN ib_port_info_t * const p_pi)
353155153Smarius{
354155153Smarius	OSM_LOG_ENTER(sm->p_log);
355155153Smarius
356155153Smarius	UNUSED_PARAM(p_node);
357155153Smarius
358155153Smarius	pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp);
359155153Smarius
360155153Smarius	osm_physp_set_port_info(p_physp, p_pi);
361155153Smarius
362155153Smarius	__osm_pi_rcv_process_endport(sm, p_physp, p_pi);
363155153Smarius
364155153Smarius	OSM_LOG_EXIT(sm->p_log);
365155153Smarius}
366155153Smarius
367155153Smarius#define IBM_VENDOR_ID  (0x5076)
368155153Smarius/**********************************************************************
369155153Smarius **********************************************************************/
370155153Smariusstatic void get_pkey_table(IN osm_log_t * p_log,
371155153Smarius			   IN osm_sm_t * sm,
372155153Smarius			   IN osm_node_t * const p_node,
373155153Smarius			   IN osm_physp_t * const p_physp)
374155153Smarius{
375155153Smarius
376155153Smarius	osm_madw_context_t context;
377155153Smarius	ib_api_status_t status;
378155153Smarius	osm_dr_path_t path;
379155153Smarius	uint8_t port_num;
380155153Smarius	uint16_t block_num, max_blocks;
381155153Smarius	uint32_t attr_mod_ho;
382155153Smarius
383155153Smarius	OSM_LOG_ENTER(p_log);
384155153Smarius
385155153Smarius	path = *osm_physp_get_dr_path_ptr(p_physp);
386155153Smarius
387155153Smarius	context.pkey_context.node_guid = osm_node_get_node_guid(p_node);
388155153Smarius	context.pkey_context.port_guid = osm_physp_get_port_guid(p_physp);
389155153Smarius	context.pkey_context.set_method = FALSE;
390155153Smarius
391155153Smarius	port_num = p_physp->port_num;
392155153Smarius
393155153Smarius	if (!p_node->sw || port_num == 0)
394155153Smarius		/* The maximum blocks is defined by the node info partition cap for CA,
395155153Smarius		   router, and switch management ports. */
396155153Smarius		max_blocks =
397155153Smarius		    (cl_ntoh16(p_node->node_info.partition_cap) +
398155153Smarius		     IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1)
399155153Smarius		    / IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
400155153Smarius	else {
401155153Smarius		/* This is a switch, and not a management port. The maximum blocks
402155153Smarius		   is defined in the switch info partition enforcement cap. */
403155153Smarius
404155153Smarius		/* Check for IBM eHCA firmware defect in reporting partition enforcement cap */
405155153Smarius		if (cl_ntoh32(ib_node_info_get_vendor_id(&p_node->node_info)) ==
406166346Sbrueffer		    IBM_VENDOR_ID)
407155153Smarius			p_node->sw->switch_info.enforce_cap = 0;
408155153Smarius
409155153Smarius		/* Bail out if this is a switch with no partition enforcement capability */
410155153Smarius		if (cl_ntoh16(p_node->sw->switch_info.enforce_cap) == 0)
411155153Smarius			goto Exit;
412155153Smarius
413155153Smarius		max_blocks = (cl_ntoh16(p_node->sw->switch_info.enforce_cap) +
414155153Smarius			      IB_NUM_PKEY_ELEMENTS_IN_BLOCK -
415155153Smarius			      1) / IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
416155153Smarius	}
417155153Smarius
418155153Smarius	for (block_num = 0; block_num < max_blocks; block_num++) {
419155153Smarius		if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH)
420155153Smarius			attr_mod_ho = block_num;
421155153Smarius		else
422155153Smarius			attr_mod_ho = block_num | (port_num << 16);
423155153Smarius		status = osm_req_get(sm, &path, IB_MAD_ATTR_P_KEY_TABLE,
424155153Smarius				     cl_hton32(attr_mod_ho),
425155153Smarius				     CL_DISP_MSGID_NONE, &context);
426155153Smarius
427155153Smarius		if (status != IB_SUCCESS) {
428155153Smarius			OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0F12: "
429155153Smarius				"Failure initiating PKeyTable request (%s)\n",
430267938Sbapt				ib_get_err_str(status));
431155153Smarius			goto Exit;
432155153Smarius		}
433155153Smarius	}
434155153Smarius
435155153SmariusExit:
436155153Smarius	OSM_LOG_EXIT(p_log);
437155153Smarius}
438155153Smarius
439155153Smarius/**********************************************************************
440155153Smarius **********************************************************************/
441155153Smariusstatic void
442155153Smarius__osm_pi_rcv_get_pkey_slvl_vla_tables(IN osm_sm_t * sm,
443155153Smarius				      IN osm_node_t * const p_node,
444155153Smarius				      IN osm_physp_t * const p_physp)
445155153Smarius{
446155153Smarius	OSM_LOG_ENTER(sm->p_log);
447155153Smarius
448155153Smarius	get_pkey_table(sm->p_log, sm, p_node, p_physp);
449155153Smarius
450155153Smarius	OSM_LOG_EXIT(sm->p_log);
451155153Smarius}
452155153Smarius
453155153Smarius/**********************************************************************
454155153Smarius **********************************************************************/
455155153Smariusstatic void
456155153Smariusosm_pi_rcv_process_set(IN osm_sm_t * sm, IN osm_node_t * const p_node,
457155153Smarius		       IN const uint8_t port_num, IN osm_madw_t * const p_madw)
458155153Smarius{
459155153Smarius	osm_physp_t *p_physp;
460155153Smarius	ib_net64_t port_guid;
461155153Smarius	ib_smp_t *p_smp;
462155153Smarius	ib_port_info_t *p_pi;
463155153Smarius	osm_pi_context_t *p_context;
464155153Smarius	osm_log_level_t level;
465155153Smarius
466155153Smarius	OSM_LOG_ENTER(sm->p_log);
467155153Smarius
468155153Smarius	p_context = osm_madw_get_pi_context_ptr(p_madw);
469155153Smarius
470155153Smarius	CL_ASSERT(p_node);
471155153Smarius
472155153Smarius	p_physp = osm_node_get_physp_ptr(p_node, port_num);
473155153Smarius	CL_ASSERT(p_physp);
474155153Smarius
475155153Smarius	port_guid = osm_physp_get_port_guid(p_physp);
476155153Smarius
477	p_smp = osm_madw_get_smp_ptr(p_madw);
478	p_pi = (ib_port_info_t *) ib_smp_get_payload_ptr(p_smp);
479
480	/* check for error */
481	if (cl_ntoh16(p_smp->status) & 0x7fff) {
482		/* If port already ACTIVE, don't treat status 7 as error */
483		if (p_context->active_transition &&
484		    (cl_ntoh16(p_smp->status) & 0x7fff) == 0x1c) {
485			level = OSM_LOG_INFO;
486			OSM_LOG(sm->p_log, OSM_LOG_INFO,
487				"Received error status 0x%x for SetResp() during ACTIVE transition\n",
488				cl_ntoh16(p_smp->status) & 0x7fff);
489			/* Should there be a subsequent Get to validate that port is ACTIVE ? */
490		} else {
491			level = OSM_LOG_ERROR;
492			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F10: "
493				"Received error status for SetResp()\n");
494		}
495		osm_dump_port_info(sm->p_log,
496				   osm_node_get_node_guid(p_node),
497				   port_guid, port_num, p_pi, level);
498	}
499
500	OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
501		"Received logical SetResp() for GUID 0x%" PRIx64
502		", port num %u"
503		"\n\t\t\t\tfor parent node GUID 0x%" PRIx64
504		" TID 0x%" PRIx64 "\n",
505		cl_ntoh64(port_guid), port_num,
506		cl_ntoh64(osm_node_get_node_guid(p_node)),
507		cl_ntoh64(p_smp->trans_id));
508
509	osm_physp_set_port_info(p_physp, p_pi);
510
511	OSM_LOG_EXIT(sm->p_log);
512}
513
514/**********************************************************************
515 **********************************************************************/
516void osm_pi_rcv_process(IN void *context, IN void *data)
517{
518	osm_sm_t *sm = context;
519	osm_madw_t *p_madw = data;
520	ib_port_info_t *p_pi;
521	ib_smp_t *p_smp;
522	osm_port_t *p_port;
523	osm_physp_t *p_physp;
524	osm_dr_path_t *p_dr_path;
525	osm_node_t *p_node;
526	osm_pi_context_t *p_context;
527	ib_net64_t port_guid;
528	ib_net64_t node_guid;
529	uint8_t port_num;
530
531	OSM_LOG_ENTER(sm->p_log);
532
533	CL_ASSERT(sm);
534	CL_ASSERT(p_madw);
535
536	p_smp = osm_madw_get_smp_ptr(p_madw);
537	p_context = osm_madw_get_pi_context_ptr(p_madw);
538	p_pi = (ib_port_info_t *) ib_smp_get_payload_ptr(p_smp);
539
540	CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_PORT_INFO);
541
542	port_num = (uint8_t) cl_ntoh32(p_smp->attr_mod);
543
544	port_guid = p_context->port_guid;
545	node_guid = p_context->node_guid;
546
547	osm_dump_port_info(sm->p_log,
548			   node_guid, port_guid, port_num, p_pi, OSM_LOG_DEBUG);
549
550	/* On receipt of client reregister, clear the reregister bit so
551	   reregistering won't be sent again and again */
552	if (ib_port_info_get_client_rereg(p_pi)) {
553		OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
554			"Client reregister received on response\n");
555		ib_port_info_set_client_rereg(p_pi, 0);
556	}
557
558	/*
559	   we might get a response during a light sweep looking for a change in
560	   the status of a remote port that did not respond in earlier sweeps.
561	   So if the context of the Get was light_sweep - we do not need to
562	   do anything with the response - just flag that we need a heavy sweep
563	 */
564	if (p_context->light_sweep == TRUE) {
565		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
566			"Got light sweep response from remote port of parent node "
567			"GUID 0x%" PRIx64 " port 0x%016" PRIx64
568			", Commencing heavy sweep\n",
569			cl_ntoh64(node_guid), cl_ntoh64(port_guid));
570		sm->p_subn->force_heavy_sweep = TRUE;
571		sm->p_subn->ignore_existing_lfts = TRUE;
572		goto Exit;
573	}
574
575	CL_PLOCK_EXCL_ACQUIRE(sm->p_lock);
576	p_port = osm_get_port_by_guid(sm->p_subn, port_guid);
577	if (!p_port) {
578		CL_PLOCK_RELEASE(sm->p_lock);
579		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F06: "
580			"No port object for port with GUID 0x%" PRIx64
581			"\n\t\t\t\tfor parent node GUID 0x%" PRIx64
582			", TID 0x%" PRIx64 "\n",
583			cl_ntoh64(port_guid),
584			cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id));
585		goto Exit;
586	}
587
588	p_node = p_port->p_node;
589	CL_ASSERT(p_node);
590
591	/*
592	   If we were setting the PortInfo, then receiving
593	   this attribute was not part of sweeping the subnet.
594	   In this case, just update the PortInfo attribute.
595
596	   In an unfortunate blunder, the IB spec defines the
597	   return method for Set() as a GetResp().  Thus, we can't
598	   use the method (what would have been SetResp()) to determine
599	   our course of action.  So, we have to carry this extra
600	   boolean around to determine if we were doing Get() or Set().
601	 */
602	if (p_context->set_method)
603		osm_pi_rcv_process_set(sm, p_node, port_num, p_madw);
604	else {
605		p_port->discovery_count++;
606
607		/*
608		   This PortInfo arrived because we did a Get() method,
609		   most likely due to a subnet sweep in progress.
610		 */
611		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
612			"Discovered port num %u with GUID 0x%" PRIx64
613			" for parent node GUID 0x%" PRIx64
614			", TID 0x%" PRIx64 "\n",
615			port_num, cl_ntoh64(port_guid),
616			cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id));
617
618		p_physp = osm_node_get_physp_ptr(p_node, port_num);
619
620		/*
621		   Determine if we encountered a new Physical Port.
622		   If so, initialize the new Physical Port then
623		   continue processing as normal.
624		 */
625		if (!p_physp) {
626			OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
627				"Initializing port number %u\n", port_num);
628			p_physp = &p_node->physp_table[port_num];
629			osm_physp_init(p_physp,
630				       port_guid,
631				       port_num,
632				       p_node,
633				       osm_madw_get_bind_handle(p_madw),
634				       p_smp->hop_count, p_smp->initial_path);
635		} else {
636			/*
637			   Update the directed route path to this port
638			   in case the old path is no longer usable.
639			 */
640			p_dr_path = osm_physp_get_dr_path_ptr(p_physp);
641			osm_dr_path_init(p_dr_path,
642					 osm_madw_get_bind_handle(p_madw),
643					 p_smp->hop_count, p_smp->initial_path);
644		}
645
646		/* if port just inited or reached INIT state (external reset)
647		   request update for port related tables */
648		p_physp->need_update =
649		    (ib_port_info_get_port_state(p_pi) == IB_LINK_INIT ||
650		     p_physp->need_update > 1) ? 1 : 0;
651
652		switch (osm_node_get_type(p_node)) {
653		case IB_NODE_TYPE_CA:
654		case IB_NODE_TYPE_ROUTER:
655			__osm_pi_rcv_process_ca_or_router_port(sm,
656							       p_node, p_physp,
657							       p_pi);
658			break;
659		case IB_NODE_TYPE_SWITCH:
660			__osm_pi_rcv_process_switch_port(sm,
661							 p_node, p_physp, p_pi);
662			break;
663		default:
664			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F07: "
665				"Unknown node type %u with GUID 0x%" PRIx64
666				"\n", osm_node_get_type(p_node),
667				cl_ntoh64(node_guid));
668			break;
669		}
670
671		/*
672		   Get the tables on the physp.
673		 */
674		if (p_physp->need_update || sm->p_subn->need_update)
675			__osm_pi_rcv_get_pkey_slvl_vla_tables(sm, p_node,
676							      p_physp);
677
678	}
679
680	CL_PLOCK_RELEASE(sm->p_lock);
681
682Exit:
683	/*
684	   Release the lock before jumping here!!
685	 */
686	OSM_LOG_EXIT(sm->p_log);
687}
688