Blame opensm/osm_port_info_rcv.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2002-2012 Mellanox Technologies LTD. All rights reserved.
Packit 13e616
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit 13e616
 * Copyright (c) 2009 HNR Consulting. All rights reserved.
Packit 13e616
 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
Packit 13e616
 *
Packit 13e616
 * This software is available to you under a choice of one of two
Packit 13e616
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit 13e616
 * General Public License (GPL) Version 2, available from the file
Packit 13e616
 * COPYING in the main directory of this source tree, or the
Packit 13e616
 * OpenIB.org BSD license below:
Packit 13e616
 *
Packit 13e616
 *     Redistribution and use in source and binary forms, with or
Packit 13e616
 *     without modification, are permitted provided that the following
Packit 13e616
 *     conditions are met:
Packit 13e616
 *
Packit 13e616
 *      - Redistributions of source code must retain the above
Packit 13e616
 *        copyright notice, this list of conditions and the following
Packit 13e616
 *        disclaimer.
Packit 13e616
 *
Packit 13e616
 *      - Redistributions in binary form must reproduce the above
Packit 13e616
 *        copyright notice, this list of conditions and the following
Packit 13e616
 *        disclaimer in the documentation and/or other materials
Packit 13e616
 *        provided with the distribution.
Packit 13e616
 *
Packit 13e616
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit 13e616
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit 13e616
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit 13e616
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit 13e616
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit 13e616
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit 13e616
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit 13e616
 * SOFTWARE.
Packit 13e616
 *
Packit 13e616
 */
Packit 13e616
Packit 13e616
/*
Packit 13e616
 * Abstract:
Packit 13e616
 *    Implementation of osm_pi_rcv_t.
Packit 13e616
 * This object represents the PortInfo Receiver object.
Packit 13e616
 * This object is part of the opensm family of objects.
Packit 13e616
 */
Packit 13e616
Packit 13e616
#if HAVE_CONFIG_H
Packit 13e616
#  include <config.h>
Packit 13e616
#endif				/* HAVE_CONFIG_H */
Packit 13e616
Packit 13e616
#include <string.h>
Packit 13e616
#include <stdlib.h>
Packit 13e616
#include <iba/ib_types.h>
Packit 13e616
#include <complib/cl_qmap.h>
Packit 13e616
#include <complib/cl_passivelock.h>
Packit 13e616
#include <complib/cl_debug.h>
Packit 13e616
#include <opensm/osm_file_ids.h>
Packit 13e616
#define FILE_ID OSM_FILE_PORT_INFO_RCV_C
Packit 13e616
#include <vendor/osm_vendor_api.h>
Packit 13e616
#include <opensm/osm_madw.h>
Packit 13e616
#include <opensm/osm_log.h>
Packit 13e616
#include <opensm/osm_node.h>
Packit 13e616
#include <opensm/osm_subnet.h>
Packit 13e616
#include <opensm/osm_mad_pool.h>
Packit 13e616
#include <opensm/osm_msgdef.h>
Packit 13e616
#include <opensm/osm_helper.h>
Packit 13e616
#include <opensm/osm_pkey.h>
Packit 13e616
#include <opensm/osm_remote_sm.h>
Packit 13e616
#include <opensm/osm_opensm.h>
Packit 13e616
#include <opensm/osm_ucast_mgr.h>
Packit 13e616
Packit 13e616
static void pi_rcv_check_and_fix_lid(osm_log_t * log, ib_port_info_t * pi,
Packit 13e616
				     osm_physp_t * p)
Packit 13e616
{
Packit 13e616
	if (PF(cl_ntoh16(pi->base_lid) > IB_LID_UCAST_END_HO)) {
Packit 13e616
		OSM_LOG(log, OSM_LOG_ERROR, "ERR 0F04: "
Packit 13e616
			"Got invalid base LID %u from the network. "
Packit 13e616
			"Corrected to %u\n", cl_ntoh16(pi->base_lid),
Packit 13e616
			cl_ntoh16(p->port_info.base_lid));
Packit 13e616
		pi->base_lid = p->port_info.base_lid;
Packit 13e616
	}
Packit 13e616
}
Packit 13e616
Packit 13e616
static void pi_rcv_process_endport(IN osm_sm_t * sm, IN osm_physp_t * p_physp,
Packit 13e616
				   IN const ib_port_info_t * p_pi)
Packit 13e616
{
Packit 13e616
	osm_madw_context_t context;
Packit 13e616
	ib_api_status_t status;
Packit 13e616
	ib_net64_t port_guid;
Packit 13e616
	int extended;
Packit 13e616
	uint8_t rate, mtu, mpb;
Packit 13e616
	unsigned data_vls;
Packit 13e616
	cl_qmap_t *p_sm_tbl;
Packit 13e616
	osm_remote_sm_t *p_sm;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	port_guid = osm_physp_get_port_guid(p_physp);
Packit 13e616
Packit 13e616
	/* HACK extended port 0 should be handled too! */
Packit 13e616
	if (osm_physp_get_port_num(p_physp) != 0 &&
Packit 13e616
	    ib_port_info_get_port_state(p_pi) != IB_LINK_DOWN) {
Packit 13e616
		/* track the minimal endport MTU, rate, and operational VLs */
Packit 13e616
		mtu = ib_port_info_get_mtu_cap(p_pi);
Packit 13e616
		if (mtu < sm->p_subn->min_ca_mtu) {
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit 13e616
				"Setting endport minimal MTU to:%u defined by port:0x%"
Packit 13e616
				PRIx64 "\n", mtu, cl_ntoh64(port_guid));
Packit 13e616
			sm->p_subn->min_ca_mtu = mtu;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
Packit 13e616
		rate = ib_port_info_compute_rate(p_pi, extended);
Packit 13e616
		if (ib_path_compare_rates(rate, sm->p_subn->min_ca_rate) < 0) {
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit 13e616
				"Setting endport minimal rate to:%u defined by port:0x%"
Packit 13e616
				PRIx64 "\n", rate, cl_ntoh64(port_guid));
Packit 13e616
			sm->p_subn->min_ca_rate = rate;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		data_vls = 1U << (ib_port_info_get_vl_cap(p_pi) - 1);
Packit 13e616
		if (data_vls > 1U << (sm->p_subn->opt.max_op_vls - 1))
Packit 13e616
			data_vls = 1U << (sm->p_subn->opt.max_op_vls - 1);
Packit 13e616
		if (data_vls >= IB_MAX_NUM_VLS)
Packit 13e616
			data_vls = IB_MAX_NUM_VLS - 1;
Packit 13e616
		if ((uint8_t)data_vls < sm->p_subn->min_data_vls) {
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit 13e616
				"Setting endport minimal data VLs to:%u defined by port:0x%"
Packit 13e616
				PRIx64 "\n", data_vls, cl_ntoh64(port_guid));
Packit 13e616
			sm->p_subn->min_data_vls = data_vls;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Check M_Key vs M_Key protect, can we control the port ? */
Packit 13e616
	mpb = ib_port_info_get_mpb(p_pi);
Packit 13e616
	if (mpb > 0 && p_pi->m_key == 0) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_INFO,
Packit 13e616
			"Port 0x%" PRIx64 " has unknown M_Key, protection level %u\n",
Packit 13e616
			cl_ntoh64(port_guid), mpb);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (port_guid != sm->p_subn->sm_port_guid) {
Packit 13e616
		p_sm_tbl = &sm->p_subn->sm_guid_tbl;
Packit 13e616
		if (p_pi->capability_mask & IB_PORT_CAP_IS_SM) {
Packit 13e616
			/*
Packit 13e616
			 * Before querying the SM - we want to make sure we
Packit 13e616
			 * clean its state, so if the querying fails we
Packit 13e616
			 * recognize that this SM is not active.
Packit 13e616
			 */
Packit 13e616
			p_sm =
Packit 13e616
			    (osm_remote_sm_t *) cl_qmap_get(p_sm_tbl,
Packit 13e616
							    port_guid);
Packit 13e616
			if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl))
Packit 13e616
				/* clean it up */
Packit 13e616
				p_sm->smi.pri_state =
Packit 13e616
				    0xF0 & p_sm->smi.pri_state;
Packit 13e616
			if (sm->p_subn->opt.ignore_other_sm)
Packit 13e616
				OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit 13e616
					"Ignoring SM on port 0x%" PRIx64 "\n",
Packit 13e616
					cl_ntoh64(port_guid));
Packit 13e616
			else {
Packit 13e616
				OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit 13e616
					"Detected another SM. Requesting SMInfo "
Packit 13e616
					"from port 0x%" PRIx64 "\n",
Packit 13e616
					cl_ntoh64(port_guid));
Packit 13e616
Packit 13e616
				/*
Packit 13e616
				   This port indicates it's an SM and
Packit 13e616
				   it's not our own port.
Packit 13e616
				   Acquire the SMInfo Attribute.
Packit 13e616
				 */
Packit 13e616
				memset(&context, 0, sizeof(context));
Packit 13e616
				context.smi_context.set_method = FALSE;
Packit 13e616
				context.smi_context.port_guid = port_guid;
Packit 13e616
				status = osm_req_get(sm,
Packit 13e616
						     osm_physp_get_dr_path_ptr
Packit 13e616
						     (p_physp),
Packit 13e616
						     IB_MAD_ATTR_SM_INFO, 0,
Packit 13e616
						     FALSE,
Packit 13e616
						     ib_port_info_get_m_key(&p_physp->port_info),
Packit 13e616
						     0, CL_DISP_MSGID_NONE,
Packit 13e616
						     &context);
Packit 13e616
Packit 13e616
				if (status != IB_SUCCESS)
Packit 13e616
					OSM_LOG(sm->p_log, OSM_LOG_ERROR,
Packit 13e616
						"ERR 0F05: "
Packit 13e616
						"Failure requesting SMInfo (%s) "
Packit 13e616
						"from port 0x%" PRIx64 "\n",
Packit 13e616
						ib_get_err_str(status),
Packit 13e616
						cl_ntoh64(port_guid));
Packit 13e616
			}
Packit 13e616
		} else {
Packit 13e616
			p_sm =
Packit 13e616
			    (osm_remote_sm_t *) cl_qmap_remove(p_sm_tbl,
Packit 13e616
							       port_guid);
Packit 13e616
			if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl))
Packit 13e616
				free(p_sm);
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 The plock must be held before calling this function.
Packit 13e616
**********************************************************************/
Packit 13e616
static void pi_rcv_process_switch_port0(IN osm_sm_t * sm,
Packit 13e616
					IN osm_node_t * p_node,
Packit 13e616
					IN osm_physp_t * p_physp,
Packit 13e616
					IN ib_port_info_t * p_pi)
Packit 13e616
{
Packit 13e616
	ib_api_status_t status;
Packit 13e616
	osm_madw_context_t context;
Packit 13e616
	uint8_t port, num_ports;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	if (p_physp->need_update)
Packit 13e616
		sm->p_subn->ignore_existing_lfts = TRUE;
Packit 13e616
Packit 13e616
	pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp);
Packit 13e616
Packit 13e616
	/* Update the PortInfo attribute */
Packit 13e616
	osm_physp_set_port_info(p_physp, p_pi, sm);
Packit 13e616
Packit 13e616
	/* Determine if base switch port 0 */
Packit 13e616
	if (p_node->sw &&
Packit 13e616
	    !ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info))
Packit 13e616
		/* PortState is not used on BSP0 but just in case it is DOWN */
Packit 13e616
		p_physp->port_info = *p_pi;
Packit 13e616
Packit 13e616
	/* Now, query PortInfo for the switch external ports */
Packit 13e616
	num_ports = osm_node_get_num_physp(p_node);
Packit 13e616
Packit 13e616
	context.pi_context.node_guid = osm_node_get_node_guid(p_node);
Packit 13e616
	context.pi_context.port_guid = osm_physp_get_port_guid(p_physp);
Packit 13e616
	context.pi_context.set_method = FALSE;
Packit 13e616
	context.pi_context.light_sweep = FALSE;
Packit 13e616
	context.pi_context.active_transition = FALSE;
Packit 13e616
	context.pi_context.client_rereg = FALSE;
Packit 13e616
Packit 13e616
	for (port = 1; port < num_ports; port++) {
Packit 13e616
		status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_physp),
Packit 13e616
				     IB_MAD_ATTR_PORT_INFO, cl_hton32(port),
Packit 13e616
				     FALSE,
Packit 13e616
				     ib_port_info_get_m_key(&p_physp->port_info),
Packit 13e616
				     0, CL_DISP_MSGID_NONE, &context);
Packit 13e616
		if (status != IB_SUCCESS)
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F16: "
Packit 13e616
				"Failure initiating PortInfo request (%s)\n",
Packit 13e616
				ib_get_err_str(status));
Packit 13e616
	}
Packit 13e616
Packit 13e616
	pi_rcv_process_endport(sm, p_physp, p_pi);
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 The plock must be held before calling this function.
Packit 13e616
**********************************************************************/
Packit 13e616
static void pi_rcv_process_switch_ext_port(IN osm_sm_t * sm,
Packit 13e616
					   IN osm_node_t * p_node,
Packit 13e616
					   IN osm_physp_t * p_physp,
Packit 13e616
					   IN ib_port_info_t * p_pi)
Packit 13e616
{
Packit 13e616
	ib_api_status_t status = IB_SUCCESS;
Packit 13e616
	osm_madw_context_t context;
Packit 13e616
	osm_physp_t *p_remote_physp, *physp0;
Packit 13e616
	osm_node_t *p_remote_node;
Packit 13e616
	ib_net64_t m_key;
Packit 13e616
	unsigned data_vls;
Packit 13e616
	uint8_t port_num;
Packit 13e616
	uint8_t remote_port_num;
Packit 13e616
	osm_dr_path_t path;
Packit 13e616
	int mlnx_epi_supported = 0;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Check the state of the physical port.
Packit 13e616
	   If there appears to be something on the other end of the wire,
Packit 13e616
	   then ask for NodeInfo.  Ignore the switch management port.
Packit 13e616
	 */
Packit 13e616
	port_num = osm_physp_get_port_num(p_physp);
Packit 13e616
Packit 13e616
	if (sm->p_subn->opt.fdr10)
Packit 13e616
		mlnx_epi_supported = is_mlnx_ext_port_info_supported(
Packit 13e616
						ib_node_info_get_vendor_id(&p_node->node_info),
Packit 13e616
						p_node->node_info.device_id);
Packit 13e616
Packit 13e616
	/* if in_sweep_hop_0 is TRUE, then this means the SM is on the switch,
Packit 13e616
	   and we got switchInfo of our local switch. Do not continue
Packit 13e616
	   probing through the switch. */
Packit 13e616
	switch (ib_port_info_get_port_state(p_pi)) {
Packit 13e616
	case IB_LINK_DOWN:
Packit 13e616
		p_remote_physp = osm_physp_get_remote(p_physp);
Packit 13e616
		if (p_remote_physp) {
Packit 13e616
			p_remote_node =
Packit 13e616
			    osm_physp_get_node_ptr(p_remote_physp);
Packit 13e616
			remote_port_num =
Packit 13e616
			    osm_physp_get_port_num(p_remote_physp);
Packit 13e616
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit 13e616
				"Unlinking local node 0x%" PRIx64
Packit 13e616
				", port %u"
Packit 13e616
				"\n\t\t\t\tand remote node 0x%" PRIx64
Packit 13e616
				", port %u\n",
Packit 13e616
				cl_ntoh64(osm_node_get_node_guid
Packit 13e616
					  (p_node)), port_num,
Packit 13e616
				cl_ntoh64(osm_node_get_node_guid
Packit 13e616
					  (p_remote_node)),
Packit 13e616
				remote_port_num);
Packit 13e616
Packit 13e616
			if (sm->ucast_mgr.cache_valid)
Packit 13e616
				osm_ucast_cache_add_link(&sm->ucast_mgr,
Packit 13e616
							 p_physp,
Packit 13e616
							 p_remote_physp);
Packit 13e616
Packit 13e616
			osm_node_unlink(p_node, (uint8_t) port_num,
Packit 13e616
					p_remote_node,
Packit 13e616
					(uint8_t) remote_port_num);
Packit 13e616
Packit 13e616
		}
Packit 13e616
		break;
Packit 13e616
Packit 13e616
	case IB_LINK_INIT:
Packit 13e616
	case IB_LINK_ARMED:
Packit 13e616
	case IB_LINK_ACTIVE:
Packit 13e616
		physp0 = osm_node_get_physp_ptr(p_node, 0);
Packit 13e616
		if (mlnx_epi_supported) {
Packit 13e616
			m_key = ib_port_info_get_m_key(&physp0->port_info);
Packit 13e616
Packit 13e616
			context.pi_context.node_guid = osm_node_get_node_guid(p_node);
Packit 13e616
			context.pi_context.port_guid = osm_physp_get_port_guid(p_physp);
Packit 13e616
			context.pi_context.set_method = FALSE;
Packit 13e616
			context.pi_context.light_sweep = FALSE;
Packit 13e616
			context.pi_context.active_transition = FALSE;
Packit 13e616
			context.pi_context.client_rereg = FALSE;
Packit 13e616
			status = osm_req_get(sm,
Packit 13e616
					     osm_physp_get_dr_path_ptr(p_physp),
Packit 13e616
					     IB_MAD_ATTR_MLNX_EXTENDED_PORT_INFO,
Packit 13e616
					     cl_hton32(port_num), FALSE, m_key,
Packit 13e616
					     0, CL_DISP_MSGID_NONE, &context);
Packit 13e616
			if (status != IB_SUCCESS)
Packit 13e616
				OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F11: "
Packit 13e616
					"Failure initiating MLNX ExtPortInfo request (%s)\n",
Packit 13e616
					ib_get_err_str(status));
Packit 13e616
		}
Packit 13e616
		if (sm->p_subn->in_sweep_hop_0 == FALSE) {
Packit 13e616
			/*
Packit 13e616
			   To avoid looping forever, only probe the port if it
Packit 13e616
			   is NOT the port that responded to the SMP.
Packit 13e616
Packit 13e616
			   Request node info from the other end of this link:
Packit 13e616
			   1) Copy the current path from the parent node.
Packit 13e616
			   2) Extend the path to the next hop thru this port.
Packit 13e616
			   3) Request node info with the new path
Packit 13e616
Packit 13e616
			 */
Packit 13e616
			if (p_pi->local_port_num !=
Packit 13e616
			    osm_physp_get_port_num(p_physp)) {
Packit 13e616
				path = *osm_physp_get_dr_path_ptr(p_physp);
Packit 13e616
Packit 13e616
				if (osm_dr_path_extend(&path,
Packit 13e616
						       osm_physp_get_port_num
Packit 13e616
						       (p_physp))) {
Packit 13e616
					OSM_LOG(sm->p_log, OSM_LOG_ERROR,
Packit 13e616
						"ERR 0F08: "
Packit 13e616
						"DR path with hop count %d couldn't be extended\n",
Packit 13e616
						path.hop_count);
Packit 13e616
					break;
Packit 13e616
				}
Packit 13e616
Packit 13e616
				memset(&context, 0, sizeof(context));
Packit 13e616
				context.ni_context.node_guid =
Packit 13e616
				    osm_node_get_node_guid(p_node);
Packit 13e616
				context.ni_context.port_num =
Packit 13e616
				    osm_physp_get_port_num(p_physp);
Packit 13e616
Packit 13e616
				status = osm_req_get(sm, &path,
Packit 13e616
						     IB_MAD_ATTR_NODE_INFO, 0,
Packit 13e616
						     TRUE, 0, 0,
Packit 13e616
						     CL_DISP_MSGID_NONE,
Packit 13e616
						     &context);
Packit 13e616
Packit 13e616
				if (status != IB_SUCCESS)
Packit 13e616
					OSM_LOG(sm->p_log, OSM_LOG_ERROR,
Packit 13e616
						"ERR 0F02: "
Packit 13e616
						"Failure initiating NodeInfo request (%s)\n",
Packit 13e616
						ib_get_err_str(status));
Packit 13e616
			} else
Packit 13e616
				OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
Packit 13e616
					"Skipping SMP responder port %u\n",
Packit 13e616
					p_pi->local_port_num);
Packit 13e616
		}
Packit 13e616
		break;
Packit 13e616
Packit 13e616
	default:
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F03: "
Packit 13e616
			"Unknown link state = %u, port = %u\n",
Packit 13e616
			ib_port_info_get_port_state(p_pi),
Packit 13e616
			p_pi->local_port_num);
Packit 13e616
		break;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (ib_port_info_get_port_state(p_pi) > IB_LINK_INIT && p_node->sw &&
Packit 13e616
	    !ib_switch_info_get_state_change(&p_node->sw->switch_info) &&
Packit 13e616
	    p_node->sw->need_update == 1)
Packit 13e616
		p_node->sw->need_update = 0;
Packit 13e616
Packit 13e616
	if (p_physp->need_update)
Packit 13e616
		sm->p_subn->ignore_existing_lfts = TRUE;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Update the PortInfo attribute.
Packit 13e616
	 */
Packit 13e616
	osm_physp_set_port_info(p_physp, p_pi, sm);
Packit 13e616
Packit 13e616
	if (ib_port_info_get_port_state(p_pi) == IB_LINK_DOWN)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	p_remote_physp = osm_physp_get_remote(p_physp);
Packit 13e616
	if (p_remote_physp) {
Packit 13e616
		p_remote_node = osm_physp_get_node_ptr(p_remote_physp);
Packit 13e616
		if (p_remote_node->sw) {
Packit 13e616
			data_vls = 1U << (ib_port_info_get_vl_cap(p_pi) - 1);
Packit 13e616
			if (data_vls > 1U << (sm->p_subn->opt.max_op_vls - 1))
Packit 13e616
				data_vls = 1U << (sm->p_subn->opt.max_op_vls - 1);
Packit 13e616
			if (data_vls >= IB_MAX_NUM_VLS)
Packit 13e616
				data_vls = IB_MAX_NUM_VLS - 1;
Packit 13e616
			if ((uint8_t)data_vls < sm->p_subn->min_sw_data_vls) {
Packit 13e616
				OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit 13e616
					"Setting switch port minimal data VLs "
Packit 13e616
					"to:%u defined by node:0x%"
Packit 13e616
					PRIx64 ", port:%u\n", data_vls,
Packit 13e616
					cl_ntoh64(osm_node_get_node_guid(p_node)),
Packit 13e616
					port_num);
Packit 13e616
				sm->p_subn->min_sw_data_vls = data_vls;
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void pi_rcv_process_ca_or_router_port(IN osm_sm_t * sm,
Packit 13e616
					     IN osm_node_t * p_node,
Packit 13e616
					     IN osm_physp_t * p_physp,
Packit 13e616
					     IN ib_port_info_t * p_pi)
Packit 13e616
{
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	UNUSED_PARAM(p_node);
Packit 13e616
Packit 13e616
	pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp);
Packit 13e616
Packit 13e616
	osm_physp_set_port_info(p_physp, p_pi, sm);
Packit 13e616
Packit 13e616
	pi_rcv_process_endport(sm, p_physp, p_pi);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
#define IBM_VENDOR_ID  (0x5076)
Packit 13e616
static void get_pkey_table(IN osm_log_t * p_log, IN osm_sm_t * sm,
Packit 13e616
			   IN osm_node_t * p_node, IN osm_physp_t * p_physp)
Packit 13e616
{
Packit 13e616
Packit 13e616
	osm_madw_context_t context;
Packit 13e616
	ib_api_status_t status;
Packit 13e616
	osm_dr_path_t path;
Packit 13e616
	osm_physp_t *physp0;
Packit 13e616
	ib_net64_t m_key;
Packit 13e616
	uint8_t port_num;
Packit 13e616
	uint16_t block_num, max_blocks;
Packit 13e616
	uint32_t attr_mod_ho;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_log);
Packit 13e616
Packit 13e616
	path = *osm_physp_get_dr_path_ptr(p_physp);
Packit 13e616
Packit 13e616
	context.pkey_context.node_guid = osm_node_get_node_guid(p_node);
Packit 13e616
	context.pkey_context.port_guid = osm_physp_get_port_guid(p_physp);
Packit 13e616
	context.pkey_context.set_method = FALSE;
Packit 13e616
Packit 13e616
	port_num = p_physp->port_num;
Packit 13e616
Packit 13e616
	if (!p_node->sw || port_num == 0)
Packit 13e616
		/* The maximum blocks is defined by the node info partition cap
Packit 13e616
		   for CA, router, and switch management ports. */
Packit 13e616
		max_blocks =
Packit 13e616
		    (cl_ntoh16(p_node->node_info.partition_cap) +
Packit 13e616
		     IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1)
Packit 13e616
		    / IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
Packit 13e616
	else {
Packit 13e616
		/* This is a switch, and not a management port. The maximum blocks
Packit 13e616
		   is defined in the switch info partition enforcement cap. */
Packit 13e616
Packit 13e616
		/* Check for IBM eHCA firmware defect in reporting partition enforcement cap */
Packit 13e616
		if (cl_ntoh32(ib_node_info_get_vendor_id(&p_node->node_info)) ==
Packit 13e616
		    IBM_VENDOR_ID)
Packit 13e616
			p_node->sw->switch_info.enforce_cap = 0;
Packit 13e616
Packit 13e616
		/* Bail out if this is a switch with no partition enforcement capability */
Packit 13e616
		if (cl_ntoh16(p_node->sw->switch_info.enforce_cap) == 0)
Packit 13e616
			goto Exit;
Packit 13e616
Packit 13e616
		max_blocks = (cl_ntoh16(p_node->sw->switch_info.enforce_cap) +
Packit 13e616
			      IB_NUM_PKEY_ELEMENTS_IN_BLOCK -
Packit 13e616
			      1) / IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_physp->pkeys.rcv_blocks_cnt = max_blocks;
Packit 13e616
	for (block_num = 0; block_num < max_blocks; block_num++) {
Packit 13e616
		if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH ||
Packit 13e616
		    osm_physp_get_port_num(p_physp) == 0) {
Packit 13e616
			attr_mod_ho = block_num;
Packit 13e616
			m_key = ib_port_info_get_m_key(&p_physp->port_info);
Packit 13e616
		} else {
Packit 13e616
			attr_mod_ho = block_num | (port_num << 16);
Packit 13e616
			physp0 = osm_node_get_physp_ptr(p_node, 0);
Packit 13e616
			m_key = ib_port_info_get_m_key(&physp0->port_info);
Packit 13e616
		}
Packit 13e616
		status = osm_req_get(sm, &path, IB_MAD_ATTR_P_KEY_TABLE,
Packit 13e616
				     cl_hton32(attr_mod_ho), FALSE,
Packit 13e616
				     m_key, 0, CL_DISP_MSGID_NONE, &context);
Packit 13e616
Packit 13e616
		if (status != IB_SUCCESS) {
Packit 13e616
			OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0F12: "
Packit 13e616
				"Failure initiating PKeyTable request (%s)\n",
Packit 13e616
				ib_get_err_str(status));
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void pi_rcv_get_pkey_slvl_vla_tables(IN osm_sm_t * sm,
Packit 13e616
					    IN osm_node_t * p_node,
Packit 13e616
					    IN osm_physp_t * p_physp)
Packit 13e616
{
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	get_pkey_table(sm->p_log, sm, p_node, p_physp);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static int osm_pi_rcv_update_self(IN osm_sm_t *sm, IN osm_physp_t *p_physp,
Packit 13e616
				  IN ib_port_info_t *p_pi)
Packit 13e616
{
Packit 13e616
	if (ib_port_info_get_port_state(p_pi) == IB_LINK_DOWN)
Packit 13e616
		return 0;
Packit 13e616
Packit 13e616
	if (sm->p_subn->need_update || p_physp->need_update > 1 ||
Packit 13e616
	    ib_port_info_get_port_state(p_pi) == IB_LINK_INIT)
Packit 13e616
		return 1;
Packit 13e616
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void pi_rcv_process_set(IN osm_sm_t * sm, IN osm_node_t * p_node,
Packit 13e616
			       IN uint8_t port_num, IN osm_madw_t * p_madw)
Packit 13e616
{
Packit 13e616
	osm_physp_t *p_physp;
Packit 13e616
	ib_net64_t port_guid;
Packit 13e616
	ib_smp_t *p_smp;
Packit 13e616
	ib_port_info_t *p_pi;
Packit 13e616
	osm_pi_context_t *p_context;
Packit 13e616
	osm_log_level_t level;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	p_context = osm_madw_get_pi_context_ptr(p_madw);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_node);
Packit 13e616
Packit 13e616
	p_physp = osm_node_get_physp_ptr(p_node, port_num);
Packit 13e616
	CL_ASSERT(p_physp);
Packit 13e616
Packit 13e616
	port_guid = osm_physp_get_port_guid(p_physp);
Packit 13e616
Packit 13e616
	p_smp = osm_madw_get_smp_ptr(p_madw);
Packit 13e616
	p_pi = ib_smp_get_payload_ptr(p_smp);
Packit 13e616
Packit 13e616
	/* check for error */
Packit 13e616
	if (cl_ntoh16(p_smp->status) & 0x7fff) {
Packit 13e616
		/* If port already ACTIVE, don't treat status 7 as error */
Packit 13e616
		if (p_context->active_transition &&
Packit 13e616
		    (cl_ntoh16(p_smp->status) & 0x7fff) == 0x1c) {
Packit 13e616
			level = OSM_LOG_INFO;
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_INFO,
Packit 13e616
				"Received error status 0x%x for SetResp() during ACTIVE transition\n",
Packit 13e616
				cl_ntoh16(p_smp->status) & 0x7fff);
Packit 13e616
			/* Should there be a subsequent Get to validate that port is ACTIVE ? */
Packit 13e616
		} else {
Packit 13e616
			level = OSM_LOG_ERROR;
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F10: "
Packit 13e616
				"Received error status for SetResp()\n");
Packit 13e616
		}
Packit 13e616
		osm_dump_port_info_v2(sm->p_log, osm_node_get_node_guid(p_node),
Packit 13e616
				      port_guid, port_num, p_pi, FILE_ID, level);
Packit 13e616
	} else
Packit 13e616
		osm_physp_set_port_info(p_physp, p_pi, sm);
Packit 13e616
Packit 13e616
	OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Received logical SetResp() for GUID 0x%" PRIx64
Packit 13e616
		", port num %u"
Packit 13e616
		"\n\t\t\t\tfor parent node GUID 0x%" PRIx64
Packit 13e616
		" TID 0x%" PRIx64 "\n",
Packit 13e616
		cl_ntoh64(port_guid), port_num,
Packit 13e616
		cl_ntoh64(osm_node_get_node_guid(p_node)),
Packit 13e616
		cl_ntoh64(p_smp->trans_id));
Packit 13e616
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static int osm_pi_rcv_update_neighbor(IN osm_physp_t *p_physp)
Packit 13e616
{
Packit 13e616
	osm_physp_t *p_rem_physp = p_physp->p_remote_physp;
Packit 13e616
	osm_node_t *p_node;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * Our own port - this is the only case where CA port
Packit 13e616
	 * is discovered before its' neighbor port
Packit 13e616
	 */
Packit 13e616
	if (!p_rem_physp)
Packit 13e616
		return p_physp->need_update;
Packit 13e616
Packit 13e616
	p_node = osm_physp_get_node_ptr(p_rem_physp);
Packit 13e616
	CL_ASSERT(p_node);
Packit 13e616
Packit 13e616
	/* CA/RTR to CA/RTR connection */
Packit 13e616
	if (!p_node->sw)
Packit 13e616
		return p_physp->need_update;
Packit 13e616
Packit 13e616
	return (ib_switch_info_get_state_change(&p_node->sw->switch_info) ? 1 : p_physp->need_update);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_pi_rcv_process(IN void *context, IN void *data)
Packit 13e616
{
Packit 13e616
	osm_sm_t *sm = context;
Packit 13e616
	osm_madw_t *p_madw = data;
Packit 13e616
	ib_port_info_t *p_pi;
Packit 13e616
	ib_smp_t *p_smp;
Packit 13e616
	osm_port_t *p_port;
Packit 13e616
	osm_physp_t *p_physp;
Packit 13e616
	osm_dr_path_t *p_dr_path;
Packit 13e616
	osm_node_t *p_node;
Packit 13e616
	osm_pi_context_t *p_context;
Packit 13e616
	ib_net64_t port_guid, node_guid;
Packit 13e616
	uint8_t port_num;
Packit 13e616
Packit 13e616
	CL_ASSERT(sm);
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_madw);
Packit 13e616
Packit 13e616
	p_smp = osm_madw_get_smp_ptr(p_madw);
Packit 13e616
	p_context = osm_madw_get_pi_context_ptr(p_madw);
Packit 13e616
	p_pi = ib_smp_get_payload_ptr(p_smp);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_PORT_INFO);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * Attribute modifier has already been validated upon MAD receive,
Packit 13e616
	 * which means that port_num has to be valid - it originated from
Packit 13e616
	 * the request attribute modifier.
Packit 13e616
	 */
Packit 13e616
	port_num = (uint8_t) cl_ntoh32(p_smp->attr_mod);
Packit 13e616
Packit 13e616
	port_guid = p_context->port_guid;
Packit 13e616
	node_guid = p_context->node_guid;
Packit 13e616
Packit 13e616
	osm_dump_port_info_v2(sm->p_log, node_guid, port_guid, port_num, p_pi,
Packit 13e616
			      FILE_ID, OSM_LOG_DEBUG);
Packit 13e616
Packit 13e616
	/* On receipt of client reregister, clear the reregister bit so
Packit 13e616
	   reregistering won't be sent again and again */
Packit 13e616
	if (p_context->set_method &&
Packit 13e616
	    (ib_port_info_get_client_rereg(p_pi) || p_context->client_rereg)) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Client reregister received on response\n");
Packit 13e616
		ib_port_info_set_client_rereg(p_pi, 0);
Packit 13e616
		p_context->client_rereg = FALSE;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   we might get a response during a light sweep looking for a change in
Packit 13e616
	   the status of a remote port that did not respond in earlier sweeps.
Packit 13e616
	   So if the context of the Get was light_sweep - we do not need to
Packit 13e616
	   do anything with the response - just flag that we need a heavy sweep
Packit 13e616
	 */
Packit 13e616
	if (p_context->light_sweep == TRUE) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit 13e616
			"Got light sweep response from remote port of parent node "
Packit 13e616
			"GUID 0x%" PRIx64 " port 0x%016" PRIx64
Packit 13e616
			", Commencing heavy sweep\n",
Packit 13e616
			cl_ntoh64(node_guid), cl_ntoh64(port_guid));
Packit 13e616
		sm->p_subn->force_heavy_sweep = TRUE;
Packit 13e616
		sm->p_subn->ignore_existing_lfts = TRUE;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	CL_PLOCK_EXCL_ACQUIRE(sm->p_lock);
Packit 13e616
	p_port = osm_get_port_by_guid(sm->p_subn, port_guid);
Packit 13e616
	if (PF(!p_port)) {
Packit 13e616
		CL_PLOCK_RELEASE(sm->p_lock);
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F06: "
Packit 13e616
			"No port object for port with GUID 0x%" PRIx64
Packit 13e616
			"\n\t\t\t\tfor parent node GUID 0x%" PRIx64
Packit 13e616
			", TID 0x%" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(port_guid),
Packit 13e616
			cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id));
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_node = p_port->p_node;
Packit 13e616
	CL_ASSERT(p_node);
Packit 13e616
Packit 13e616
	if (PF(p_pi->local_port_num > p_node->node_info.num_ports)) {
Packit 13e616
		CL_PLOCK_RELEASE(sm->p_lock);
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F15: "
Packit 13e616
			"Received PortInfo for port GUID 0x%" PRIx64 " is "
Packit 13e616
			"non-compliant and is being ignored since the "
Packit 13e616
			"local port num %u > num ports %u\n",
Packit 13e616
			cl_ntoh64(port_guid), p_pi->local_port_num,
Packit 13e616
			p_node->node_info.num_ports);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   If we were setting the PortInfo, then receiving
Packit 13e616
	   this attribute was not part of sweeping the subnet.
Packit 13e616
	   In this case, just update the PortInfo attribute.
Packit 13e616
Packit 13e616
	   In an unfortunate blunder, the IB spec defines the
Packit 13e616
	   return method for Set() as a GetResp().  Thus, we can't
Packit 13e616
	   use the method (what would have been SetResp()) to determine
Packit 13e616
	   our course of action.  So, we have to carry this extra
Packit 13e616
	   boolean around to determine if we were doing Get() or Set().
Packit 13e616
	 */
Packit 13e616
	if (p_context->set_method)
Packit 13e616
		pi_rcv_process_set(sm, p_node, port_num, p_madw);
Packit 13e616
	else {
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   This PortInfo arrived because we did a Get() method,
Packit 13e616
		   most likely due to a subnet sweep in progress.
Packit 13e616
		 */
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit 13e616
			"Discovered port num %u with GUID 0x%" PRIx64
Packit 13e616
			" for parent node GUID 0x%" PRIx64
Packit 13e616
			", TID 0x%" PRIx64 "\n",
Packit 13e616
			port_num, cl_ntoh64(port_guid),
Packit 13e616
			cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id));
Packit 13e616
Packit 13e616
		p_physp = osm_node_get_physp_ptr(p_node, port_num);
Packit 13e616
Packit 13e616
		CL_ASSERT(p_physp);
Packit 13e616
Packit 13e616
		/* Update the directed route path to this port
Packit 13e616
		   in case the old path is no longer usable. */
Packit 13e616
		p_dr_path = osm_physp_get_dr_path_ptr(p_physp);
Packit 13e616
		osm_dr_path_init(p_dr_path, p_smp->hop_count,
Packit 13e616
				 p_smp->initial_path);
Packit 13e616
Packit 13e616
		p_physp->need_update = osm_pi_rcv_update_self(sm, p_physp, p_pi);
Packit 13e616
Packit 13e616
		switch (osm_node_get_type(p_node)) {
Packit 13e616
		case IB_NODE_TYPE_CA:
Packit 13e616
		case IB_NODE_TYPE_ROUTER:
Packit 13e616
			if (!p_node->physp_discovered[port_num]) {
Packit 13e616
				p_port->discovery_count++;
Packit 13e616
				p_node->physp_discovered[port_num] = 1;
Packit 13e616
			}
Packit 13e616
			p_physp->need_update = osm_pi_rcv_update_neighbor(p_physp);
Packit 13e616
			pi_rcv_process_ca_or_router_port(sm, p_node, p_physp,
Packit 13e616
							 p_pi);
Packit 13e616
			break;
Packit 13e616
		case IB_NODE_TYPE_SWITCH:
Packit 13e616
			if (!p_node->physp_discovered[port_num]) {
Packit 13e616
				p_port->discovery_count++;
Packit 13e616
				p_node->physp_discovered[port_num] = 1;
Packit 13e616
			}
Packit 13e616
			if (port_num == 0)
Packit 13e616
				pi_rcv_process_switch_port0(sm, p_node,
Packit 13e616
							    p_physp, p_pi);
Packit 13e616
			else
Packit 13e616
				pi_rcv_process_switch_ext_port(sm, p_node,
Packit 13e616
							       p_physp, p_pi);
Packit 13e616
Packit 13e616
			if (ib_port_info_get_port_state(p_pi) == IB_LINK_DOWN) {
Packit 13e616
				CL_PLOCK_RELEASE(sm->p_lock);
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
			break;
Packit 13e616
		default:
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F07: "
Packit 13e616
				"Unknown node type %u with GUID 0x%" PRIx64
Packit 13e616
				"\n", osm_node_get_type(p_node),
Packit 13e616
				cl_ntoh64(node_guid));
Packit 13e616
			break;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   Get the tables on the physp.
Packit 13e616
		 */
Packit 13e616
		if (p_physp->need_update || (p_node->sw &&
Packit 13e616
					     p_node->sw->need_update))
Packit 13e616
			pi_rcv_get_pkey_slvl_vla_tables(sm, p_node, p_physp);
Packit 13e616
Packit 13e616
	}
Packit 13e616
Packit 13e616
	CL_PLOCK_RELEASE(sm->p_lock);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	/*
Packit 13e616
	   Release the lock before jumping here!!
Packit 13e616
	 */
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}