Blame opensm/osm_link_mgr.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2002-2011 Mellanox Technologies LTD. All rights reserved.
Packit 13e616
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit 13e616
 * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2009-2011 ZIH, TU Dresden, Federal Republic of Germany. 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_link_mgr_t.
Packit 13e616
 * This file implements the Link Manager object.
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 <iba/ib_types.h>
Packit 13e616
#include <complib/cl_debug.h>
Packit 13e616
#include <opensm/osm_file_ids.h>
Packit 13e616
#define FILE_ID OSM_FILE_LINK_MGR_C
Packit 13e616
#include <opensm/osm_sm.h>
Packit 13e616
#include <opensm/osm_node.h>
Packit 13e616
#include <opensm/osm_switch.h>
Packit 13e616
#include <opensm/osm_helper.h>
Packit 13e616
#include <opensm/osm_msgdef.h>
Packit 13e616
#include <opensm/osm_opensm.h>
Packit 13e616
#include <opensm/osm_db_pack.h>
Packit 13e616
Packit 13e616
static uint8_t link_mgr_get_smsl(IN osm_sm_t * sm, IN osm_physp_t * p_physp)
Packit 13e616
{
Packit 13e616
	osm_opensm_t *p_osm = sm->p_subn->p_osm;
Packit 13e616
	struct osm_routing_engine *re = p_osm->routing_engine_used;
Packit 13e616
	ib_net16_t slid;
Packit 13e616
	ib_net16_t smlid;
Packit 13e616
	uint8_t sl;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	if (!(re && re->path_sl &&
Packit 13e616
	      (slid = osm_physp_get_base_lid(p_physp)))) {
Packit 13e616
		/*
Packit 13e616
		 * Use default SL if routing engine does not provide a
Packit 13e616
		 * path SL lookup callback.
Packit 13e616
		 */
Packit 13e616
		OSM_LOG_EXIT(sm->p_log);
Packit 13e616
		return sm->p_subn->opt.sm_sl;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	smlid = sm->p_subn->sm_base_lid;
Packit 13e616
Packit 13e616
	/* Call into routing engine to find proper SL */
Packit 13e616
	sl = re->path_sl(re->context, sm->p_subn->opt.sm_sl,
Packit 13e616
			 slid, smlid);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
	return sl;
Packit 13e616
}
Packit 13e616
Packit 13e616
static int link_mgr_set_physp_pi(osm_sm_t * sm, IN osm_physp_t * p_physp,
Packit 13e616
				 IN uint8_t port_state)
Packit 13e616
{
Packit 13e616
	uint8_t payload[IB_SMP_DATA_SIZE], payload2[IB_SMP_DATA_SIZE];
Packit 13e616
	ib_port_info_t *p_pi = (ib_port_info_t *) payload;
Packit 13e616
	ib_mlnx_ext_port_info_t *p_epi = (ib_mlnx_ext_port_info_t *) payload2;
Packit 13e616
	const ib_port_info_t *p_old_pi;
Packit 13e616
	const ib_mlnx_ext_port_info_t *p_old_epi;
Packit 13e616
	osm_madw_context_t context;
Packit 13e616
	osm_node_t *p_node;
Packit 13e616
	ib_api_status_t status;
Packit 13e616
	uint8_t port_num, mtu, op_vls, smsl = OSM_DEFAULT_SL;
Packit 13e616
	boolean_t esp0 = FALSE, send_set = FALSE, send_set2 = FALSE;
Packit 13e616
	osm_physp_t *p_remote_physp, *physp0 = NULL;
Packit 13e616
	int issue_ext = 0, fdr10_change = 0;
Packit 13e616
	int ret = 0;
Packit 13e616
	ib_net32_t attr_mod, cap_mask;
Packit 13e616
	boolean_t update_mkey = FALSE;
Packit 13e616
	ib_net64_t m_key = 0;
Packit Service 5cdc0c
	ib_net16_t capability_mask2;
Packit 13e616
	osm_port_t *p_port;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	p_node = osm_physp_get_node_ptr(p_physp);
Packit 13e616
	CL_ASSERT(p_node);
Packit 13e616
Packit 13e616
	p_old_pi = &p_physp->port_info;
Packit 13e616
Packit 13e616
	port_num = osm_physp_get_port_num(p_physp);
Packit 13e616
Packit 13e616
	memcpy(payload, p_old_pi, sizeof(ib_port_info_t));
Packit 13e616
Packit 13e616
	if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH ||
Packit 13e616
	    port_num == 0) {
Packit 13e616
		/* Need to make sure LID and SMLID fields in PortInfo are not 0 */
Packit 13e616
		if (!p_pi->base_lid) {
Packit 13e616
			p_port = osm_get_port_by_guid(sm->p_subn,
Packit 13e616
						      osm_physp_get_port_guid(p_physp));
Packit 13e616
			CL_ASSERT(p_port);
Packit 13e616
			p_pi->base_lid = p_port->lid;
Packit 13e616
			sm->lid_mgr.dirty = TRUE;
Packit 13e616
			send_set = TRUE;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/* we are initializing the ports with our local sm_base_lid */
Packit 13e616
		p_pi->master_sm_base_lid = sm->p_subn->sm_base_lid;
Packit 13e616
		if (p_pi->master_sm_base_lid != p_old_pi->master_sm_base_lid)
Packit 13e616
			send_set = TRUE;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH)
Packit 13e616
		physp0 = osm_node_get_physp_ptr(p_node, 0);
Packit 13e616
Packit 13e616
	if (port_num == 0) {
Packit 13e616
		/*
Packit 13e616
		   CAs don't have a port 0, and for switch port 0,
Packit 13e616
		   we need to check if this is enhanced or base port 0.
Packit 13e616
		   For base port 0 the following parameters are not valid
Packit 13e616
		   (IBA 1.2.1 p.830 table 146).
Packit 13e616
		 */
Packit 13e616
		if (!p_node->sw) {
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 4201: "
Packit 13e616
				"Cannot find switch by guid: 0x%" PRIx64 "\n",
Packit 13e616
				cl_ntoh64(p_node->node_info.node_guid));
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if (ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info)
Packit 13e616
		    == FALSE) {
Packit 13e616
Packit 13e616
			/* Even for base port 0 we might have to set smsl
Packit 13e616
			   (if we are using lash routing) */
Packit 13e616
			smsl = link_mgr_get_smsl(sm, p_physp);
Packit 13e616
			if (smsl != ib_port_info_get_master_smsl(p_old_pi)) {
Packit 13e616
				send_set = TRUE;
Packit 13e616
				OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
Packit 13e616
					"Setting SMSL to %d on port 0 GUID 0x%016"
Packit 13e616
					PRIx64 "\n", smsl,
Packit 13e616
					cl_ntoh64(osm_physp_get_port_guid
Packit 13e616
						  (p_physp)));
Packit 13e616
			/* Enter if base lid and master_sm_lid didn't change */
Packit 13e616
			} else if (send_set == FALSE) {
Packit 13e616
				/* This means the switch doesn't support
Packit 13e616
				   enhanced port 0 and we don't need to
Packit 13e616
				   change SMSL. Can skip it. */
Packit 13e616
				OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
Packit 13e616
					"Skipping port 0, GUID 0x%016" PRIx64
Packit 13e616
					"\n",
Packit 13e616
					cl_ntoh64(osm_physp_get_port_guid
Packit 13e616
						  (p_physp)));
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
		} else
Packit 13e616
			esp0 = TRUE;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Should never write back a value that is bigger then 3 in
Packit 13e616
	   the PortPhysicalState field - so can not simply copy!
Packit 13e616
Packit 13e616
	   Actually we want to write there:
Packit 13e616
	   port physical state - no change,
Packit 13e616
	   link down default state = polling
Packit 13e616
	   port state - as requested.
Packit 13e616
	 */
Packit 13e616
	p_pi->state_info2 = 0x02;
Packit 13e616
	ib_port_info_set_port_state(p_pi, port_state);
Packit 13e616
Packit Service 5cdc0c
	/* Determine ports' M_Key and CapabilityMask2 */
Packit 13e616
	if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH &&
Packit Service 5cdc0c
	    osm_physp_get_port_num(p_physp) != 0) {
Packit 13e616
		m_key = ib_port_info_get_m_key(&physp0->port_info);
Packit Service 5cdc0c
		capability_mask2 = physp0->port_info.capability_mask2;
Packit Service 5cdc0c
	} else {
Packit 13e616
		m_key = ib_port_info_get_m_key(p_pi);
Packit Service 5cdc0c
		capability_mask2 = p_pi->capability_mask2;
Packit Service 5cdc0c
	}
Packit 13e616
Packit 13e616
	/* Check whether this is base port0 smsl handling only */
Packit 13e616
	if (port_num == 0 && esp0 == FALSE) {
Packit 13e616
		ib_port_info_set_master_smsl(p_pi, smsl);
Packit 13e616
		goto Send;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   PAST THIS POINT WE ARE HANDLING EITHER A NON PORT 0 OR ENHANCED PORT 0
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	if (ib_port_info_get_link_down_def_state(p_pi) !=
Packit 13e616
	    ib_port_info_get_link_down_def_state(p_old_pi))
Packit 13e616
		send_set = TRUE;
Packit 13e616
Packit 13e616
	/* didn't get PortInfo before */
Packit 13e616
	if (!ib_port_info_get_port_state(p_old_pi))
Packit 13e616
		send_set = TRUE;
Packit 13e616
Packit 13e616
	/* we only change port fields if we do not change state */
Packit 13e616
	if (port_state == IB_LINK_NO_CHANGE) {
Packit 13e616
		/* The following fields are relevant only for CA port, router, or Enh. SP0 */
Packit 13e616
		if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH ||
Packit 13e616
		    port_num == 0) {
Packit 13e616
			p_pi->m_key = sm->p_subn->opt.m_key;
Packit 13e616
			if (memcmp(&p_pi->m_key, &p_old_pi->m_key,
Packit 13e616
				   sizeof(p_pi->m_key))) {
Packit 13e616
				update_mkey = TRUE;
Packit 13e616
				send_set = TRUE;
Packit 13e616
			}
Packit 13e616
Packit 13e616
			p_pi->subnet_prefix = sm->p_subn->opt.subnet_prefix;
Packit 13e616
			if (memcmp(&p_pi->subnet_prefix,
Packit 13e616
				   &p_old_pi->subnet_prefix,
Packit 13e616
				   sizeof(p_pi->subnet_prefix)))
Packit 13e616
				send_set = TRUE;
Packit 13e616
Packit 13e616
			smsl = link_mgr_get_smsl(sm, p_physp);
Packit 13e616
			if (smsl != ib_port_info_get_master_smsl(p_old_pi)) {
Packit 13e616
Packit 13e616
				ib_port_info_set_master_smsl(p_pi, smsl);
Packit 13e616
Packit 13e616
				OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
Packit 13e616
					"Setting SMSL to %d on GUID 0x%016"
Packit 13e616
					PRIx64 ", port %d\n", smsl,
Packit 13e616
					cl_ntoh64(osm_physp_get_port_guid
Packit 13e616
						  (p_physp)), port_num);
Packit 13e616
Packit 13e616
				send_set = TRUE;
Packit 13e616
			}
Packit 13e616
Packit 13e616
			p_pi->m_key_lease_period =
Packit 13e616
			    sm->p_subn->opt.m_key_lease_period;
Packit 13e616
			if (memcmp(&p_pi->m_key_lease_period,
Packit 13e616
				   &p_old_pi->m_key_lease_period,
Packit 13e616
				   sizeof(p_pi->m_key_lease_period)))
Packit 13e616
				send_set = TRUE;
Packit 13e616
Packit 13e616
			p_pi->mkey_lmc = 0;
Packit 13e616
			ib_port_info_set_mpb(p_pi, sm->p_subn->opt.m_key_protect_bits);
Packit 13e616
			if (esp0 == FALSE || sm->p_subn->opt.lmc_esp0)
Packit 13e616
				ib_port_info_set_lmc(p_pi, sm->p_subn->opt.lmc);
Packit 13e616
			if (ib_port_info_get_lmc(p_old_pi) !=
Packit 13e616
			    ib_port_info_get_lmc(p_pi) ||
Packit 13e616
			    ib_port_info_get_mpb(p_old_pi) !=
Packit 13e616
			    ib_port_info_get_mpb(p_pi))
Packit 13e616
				send_set = TRUE;
Packit 13e616
Packit 13e616
			ib_port_info_set_timeout(p_pi,
Packit 13e616
						 sm->p_subn->opt.
Packit 13e616
						 subnet_timeout);
Packit 13e616
			if (ib_port_info_get_timeout(p_pi) !=
Packit 13e616
			    ib_port_info_get_timeout(p_old_pi))
Packit 13e616
				send_set = TRUE;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   Several timeout mechanisms:
Packit 13e616
		 */
Packit 13e616
		p_remote_physp = osm_physp_get_remote(p_physp);
Packit 13e616
		if (port_num != 0 && p_remote_physp) {
Packit 13e616
			if (osm_node_get_type(osm_physp_get_node_ptr(p_physp))
Packit 13e616
			    == IB_NODE_TYPE_ROUTER) {
Packit 13e616
				ib_port_info_set_hoq_lifetime(p_pi,
Packit 13e616
							      sm->p_subn->
Packit 13e616
							      opt.
Packit 13e616
							      leaf_head_of_queue_lifetime);
Packit 13e616
			} else
Packit 13e616
			    if (osm_node_get_type
Packit 13e616
				(osm_physp_get_node_ptr(p_physp)) ==
Packit 13e616
				IB_NODE_TYPE_SWITCH) {
Packit 13e616
				/* Is remote end CA or router (a leaf port) ? */
Packit 13e616
				if (osm_node_get_type
Packit 13e616
				    (osm_physp_get_node_ptr(p_remote_physp)) !=
Packit 13e616
				    IB_NODE_TYPE_SWITCH) {
Packit 13e616
					ib_port_info_set_hoq_lifetime(p_pi,
Packit 13e616
								      sm->
Packit 13e616
								      p_subn->
Packit 13e616
								      opt.
Packit 13e616
								      leaf_head_of_queue_lifetime);
Packit 13e616
					ib_port_info_set_vl_stall_count(p_pi,
Packit 13e616
									sm->
Packit 13e616
									p_subn->
Packit 13e616
									opt.
Packit 13e616
									leaf_vl_stall_count);
Packit 13e616
				} else {
Packit 13e616
					ib_port_info_set_hoq_lifetime(p_pi,
Packit 13e616
								      sm->
Packit 13e616
								      p_subn->
Packit 13e616
								      opt.
Packit 13e616
								      head_of_queue_lifetime);
Packit 13e616
					ib_port_info_set_vl_stall_count(p_pi,
Packit 13e616
									sm->
Packit 13e616
									p_subn->
Packit 13e616
									opt.
Packit 13e616
									vl_stall_count);
Packit 13e616
				}
Packit 13e616
			}
Packit 13e616
			if (ib_port_info_get_hoq_lifetime(p_pi) !=
Packit 13e616
			    ib_port_info_get_hoq_lifetime(p_old_pi) ||
Packit 13e616
			    ib_port_info_get_vl_stall_count(p_pi) !=
Packit 13e616
			    ib_port_info_get_vl_stall_count(p_old_pi))
Packit 13e616
				send_set = TRUE;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		ib_port_info_set_phy_and_overrun_err_thd(p_pi,
Packit 13e616
							 sm->p_subn->opt.
Packit 13e616
							 local_phy_errors_threshold,
Packit 13e616
							 sm->p_subn->opt.
Packit 13e616
							 overrun_errors_threshold);
Packit 13e616
		if (p_pi->error_threshold != p_old_pi->error_threshold)
Packit 13e616
			send_set = TRUE;
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   Set the easy common parameters for all port types,
Packit 13e616
		   then determine the neighbor MTU.
Packit 13e616
		 */
Packit 13e616
		if (sm->p_subn->opt.force_link_width &&
Packit 13e616
		    (sm->p_subn->opt.force_link_width < IB_LINK_WIDTH_ACTIVE_2X ||
Packit Service 5cdc0c
		     (capability_mask2 &
Packit 13e616
		      IB_PORT_CAP2_IS_LINK_WIDTH_2X_SUPPORTED)) &&
Packit 13e616
		    (sm->p_subn->opt.force_link_width != IB_LINK_WIDTH_SET_LWS ||
Packit 13e616
		     p_pi->link_width_enabled != p_pi->link_width_supported)) {
Packit 13e616
			p_pi->link_width_enabled = sm->p_subn->opt.force_link_width;
Packit 13e616
			if (p_pi->link_width_enabled != p_old_pi->link_width_enabled)
Packit 13e616
				send_set = TRUE;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if (sm->p_subn->opt.force_link_speed &&
Packit 13e616
		    (sm->p_subn->opt.force_link_speed != IB_LINK_SPEED_SET_LSS ||
Packit 13e616
		     ib_port_info_get_link_speed_enabled(p_pi) !=
Packit 13e616
		     ib_port_info_get_link_speed_sup(p_pi))) {
Packit 13e616
			ib_port_info_set_link_speed_enabled(p_pi,
Packit 13e616
							    sm->p_subn->opt.
Packit 13e616
							    force_link_speed);
Packit 13e616
			if (p_pi->link_speed != p_old_pi->link_speed)
Packit 13e616
				send_set = TRUE;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if (sm->p_subn->opt.fdr10 &&
Packit 13e616
		    p_physp->ext_port_info.link_speed_supported & FDR10) {
Packit 13e616
			if (sm->p_subn->opt.fdr10 == 1) { /* enable */
Packit 13e616
				if (!(p_physp->ext_port_info.link_speed_enabled & FDR10))
Packit 13e616
					fdr10_change = 1;
Packit 13e616
			} else {	/* disable */
Packit 13e616
				if (p_physp->ext_port_info.link_speed_enabled & FDR10)
Packit 13e616
					fdr10_change = 1;
Packit 13e616
			}
Packit 13e616
			if (fdr10_change) {
Packit 13e616
				p_old_epi = &p_physp->ext_port_info;
Packit 13e616
				memcpy(payload2, p_old_epi,
Packit 13e616
				       sizeof(ib_mlnx_ext_port_info_t));
Packit 13e616
				p_epi->state_change_enable = 0x01;
Packit 13e616
				if (sm->p_subn->opt.fdr10 == 1)
Packit 13e616
					p_epi->link_speed_enabled = FDR10;
Packit 13e616
				else
Packit 13e616
					p_epi->link_speed_enabled = 0;
Packit 13e616
				send_set2 = TRUE;
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if (osm_node_get_type(p_physp->p_node) == IB_NODE_TYPE_SWITCH &&
Packit 13e616
		    osm_physp_get_port_num(p_physp) != 0) {
Packit 13e616
			cap_mask = physp0->port_info.capability_mask;
Packit 13e616
		} else
Packit 13e616
			cap_mask = p_pi->capability_mask;
Packit 13e616
Packit 13e616
		if (cap_mask & IB_PORT_CAP_HAS_EXT_SPEEDS)
Packit 13e616
			issue_ext = 1;
Packit 13e616
Packit 13e616
		/* Do peer ports support extended link speeds ? */
Packit 13e616
		if (port_num != 0 && p_remote_physp) {
Packit 13e616
			osm_physp_t *rphysp0;
Packit 13e616
			ib_net32_t rem_cap_mask;
Packit 13e616
Packit 13e616
			if (osm_node_get_type(p_remote_physp->p_node) ==
Packit 13e616
			    IB_NODE_TYPE_SWITCH) {
Packit 13e616
				rphysp0 = osm_node_get_physp_ptr(p_remote_physp->p_node, 0);
Packit 13e616
				rem_cap_mask = rphysp0->port_info.capability_mask;
Packit 13e616
			} else
Packit 13e616
				rem_cap_mask = p_remote_physp->port_info.capability_mask;
Packit 13e616
Packit 13e616
			if (cap_mask & IB_PORT_CAP_HAS_EXT_SPEEDS &&
Packit 13e616
			    rem_cap_mask & IB_PORT_CAP_HAS_EXT_SPEEDS) {
Packit 13e616
				if (sm->p_subn->opt.force_link_speed_ext &&
Packit 13e616
				    (sm->p_subn->opt.force_link_speed_ext != IB_LINK_SPEED_EXT_SET_LSES ||
Packit 13e616
				     p_pi->link_speed_ext_enabled !=
Packit 13e616
				     ib_port_info_get_link_speed_ext_sup(p_pi))) {
Packit 13e616
					p_pi->link_speed_ext_enabled = sm->p_subn->opt.force_link_speed_ext;
Packit 13e616
					if (p_pi->link_speed_ext_enabled !=
Packit 13e616
					    p_old_pi->link_speed_ext_enabled)
Packit 13e616
						send_set = TRUE;
Packit 13e616
				}
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/* calc new op_vls and mtu */
Packit 13e616
		op_vls =
Packit 13e616
		    osm_physp_calc_link_op_vls(sm->p_log, sm->p_subn, p_physp,
Packit 13e616
					       ib_port_info_get_op_vls(p_old_pi));
Packit 13e616
		mtu = osm_physp_calc_link_mtu(sm->p_log, p_physp,
Packit 13e616
					      ib_port_info_get_neighbor_mtu(p_old_pi));
Packit 13e616
Packit 13e616
		ib_port_info_set_neighbor_mtu(p_pi, mtu);
Packit 13e616
		if (ib_port_info_get_neighbor_mtu(p_pi) !=
Packit 13e616
		    ib_port_info_get_neighbor_mtu(p_old_pi))
Packit 13e616
			send_set = TRUE;
Packit 13e616
Packit 13e616
		ib_port_info_set_op_vls(p_pi, op_vls);
Packit 13e616
		if (ib_port_info_get_op_vls(p_pi) !=
Packit 13e616
		    ib_port_info_get_op_vls(p_old_pi))
Packit 13e616
			send_set = TRUE;
Packit 13e616
Packit 13e616
		/* provide the vl_high_limit from the qos mgr */
Packit 13e616
		if (sm->p_subn->opt.qos &&
Packit 13e616
		    p_physp->vl_high_limit != p_old_pi->vl_high_limit) {
Packit 13e616
			send_set = TRUE;
Packit 13e616
			p_pi->vl_high_limit = p_physp->vl_high_limit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
Send:
Packit 13e616
	context.pi_context.active_transition = FALSE;
Packit 13e616
	if (port_state != IB_LINK_NO_CHANGE &&
Packit 13e616
	    port_state != ib_port_info_get_port_state(p_old_pi)) {
Packit 13e616
		send_set = TRUE;
Packit 13e616
		if (port_state == IB_LINK_ACTIVE)
Packit 13e616
			context.pi_context.active_transition = TRUE;
Packit 13e616
	}
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 = TRUE;
Packit 13e616
	context.pi_context.light_sweep = FALSE;
Packit 13e616
	context.pi_context.client_rereg = FALSE;
Packit 13e616
Packit 13e616
	/* We need to send the PortInfoSet request with the new sm_lid
Packit 13e616
	   in the following cases:
Packit 13e616
	   1. There is a change in the values (send_set == TRUE)
Packit 13e616
	   2. This is a switch external port (so it wasn't handled yet by
Packit 13e616
	   osm_lid_mgr) and first_time_master_sweep flag on the subnet is TRUE,
Packit 13e616
	   which means the SM just became master, and it then needs to send at
Packit 13e616
	   PortInfoSet to every port.
Packit 13e616
	 */
Packit 13e616
	if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH && port_num
Packit 13e616
	    && sm->p_subn->first_time_master_sweep == TRUE)
Packit 13e616
		send_set = TRUE;
Packit 13e616
Packit 13e616
	if (!send_set)
Packit 13e616
		goto SEND_EPI;
Packit 13e616
Packit 13e616
	attr_mod = cl_hton32(port_num);
Packit 13e616
	if (issue_ext)
Packit 13e616
		attr_mod |= cl_hton32(1 << 31);	/* AM SMSupportExtendedSpeeds */
Packit 13e616
	status = osm_req_set(sm, osm_physp_get_dr_path_ptr(p_physp),
Packit 13e616
			     payload, sizeof(payload), IB_MAD_ATTR_PORT_INFO,
Packit 13e616
			     attr_mod, FALSE, m_key,
Packit 13e616
			     0, CL_DISP_MSGID_NONE, &context);
Packit 13e616
	if (status)
Packit 13e616
		ret = -1;
Packit 13e616
Packit 13e616
	/* If we sent a new mkey above, update our guid2mkey map
Packit 13e616
	   now, on the assumption that the SubnSet succeeds
Packit 13e616
	 */
Packit 13e616
	if (update_mkey)
Packit 13e616
		osm_db_guid2mkey_set(sm->p_subn->p_g2m,
Packit 13e616
				     cl_ntoh64(p_physp->port_guid),
Packit 13e616
				     cl_ntoh64(p_pi->m_key));
Packit 13e616
Packit 13e616
SEND_EPI:
Packit 13e616
	if (send_set2) {
Packit 13e616
		status = osm_req_set(sm, osm_physp_get_dr_path_ptr(p_physp),
Packit 13e616
				     payload2, sizeof(payload2),
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)
Packit 13e616
			ret = -1;
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
	return ret;
Packit 13e616
}
Packit 13e616
Packit 13e616
static int link_mgr_process_node(osm_sm_t * sm, IN osm_node_t * p_node,
Packit 13e616
				 IN const uint8_t link_state)
Packit 13e616
{
Packit 13e616
	osm_physp_t *p_physp, *p_physp_remote;
Packit 13e616
	uint32_t i, num_physp;
Packit 13e616
	int ret = 0;
Packit 13e616
	uint8_t current_state;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Node 0x%" PRIx64 " going to %s\n",
Packit 13e616
		cl_ntoh64(osm_node_get_node_guid(p_node)),
Packit 13e616
		ib_get_port_state_str(link_state));
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Set the PortInfo for every Physical Port associated
Packit 13e616
	   with this Port.  Start iterating with port 1, since the linkstate
Packit 13e616
	   is not applicable to the management port on switches.
Packit 13e616
	 */
Packit 13e616
	num_physp = osm_node_get_num_physp(p_node);
Packit 13e616
	for (i = 0; i < num_physp; i++) {
Packit 13e616
		/*
Packit 13e616
		   Don't bother doing anything if this Physical Port is not valid.
Packit 13e616
		   or if the state of the port is already better then the
Packit 13e616
		   specified state.
Packit 13e616
		 */
Packit 13e616
		p_physp = osm_node_get_physp_ptr(p_node, (uint8_t) i);
Packit 13e616
		if (!p_physp)
Packit 13e616
			continue;
Packit 13e616
Packit 13e616
		current_state = osm_physp_get_port_state(p_physp);
Packit 13e616
		if (current_state == IB_LINK_DOWN)
Packit 13e616
			continue;
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		    Set PortState to DOWN in case Remote Physical Port is
Packit 13e616
		    unreachable. We have to check this for all ports, except
Packit 13e616
		    port zero.
Packit 13e616
		 */
Packit 13e616
		p_physp_remote = osm_physp_get_remote(p_physp);
Packit 13e616
		if ((i != 0) && (!p_physp_remote ||
Packit 13e616
		    !osm_physp_is_valid(p_physp_remote))) {
Packit 13e616
			if (current_state != IB_LINK_INIT)
Packit 13e616
				link_mgr_set_physp_pi(sm, p_physp, IB_LINK_DOWN);
Packit 13e616
			continue;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   Normally we only send state update if state is lower
Packit 13e616
		   then required state. However, we need to send update if
Packit 13e616
		   no state change required.
Packit 13e616
		 */
Packit 13e616
		if (link_state != IB_LINK_NO_CHANGE &&
Packit 13e616
		    link_state <= current_state)
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Physical port %u already %s. Skipping\n",
Packit 13e616
				p_physp->port_num,
Packit 13e616
				ib_get_port_state_str(current_state));
Packit 13e616
		else if (link_mgr_set_physp_pi(sm, p_physp, link_state))
Packit 13e616
			ret = -1;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
	return ret;
Packit 13e616
}
Packit 13e616
Packit 13e616
int osm_link_mgr_process(osm_sm_t * sm, IN const uint8_t link_state)
Packit 13e616
{
Packit 13e616
	cl_qmap_t *p_node_guid_tbl;
Packit 13e616
	osm_node_t *p_node;
Packit 13e616
	int ret = 0;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	p_node_guid_tbl = &sm->p_subn->node_guid_tbl;
Packit 13e616
Packit 13e616
	CL_PLOCK_EXCL_ACQUIRE(sm->p_lock);
Packit 13e616
Packit 13e616
	for (p_node = (osm_node_t *) cl_qmap_head(p_node_guid_tbl);
Packit 13e616
	     p_node != (osm_node_t *) cl_qmap_end(p_node_guid_tbl);
Packit 13e616
	     p_node = (osm_node_t *) cl_qmap_next(&p_node->map_item))
Packit 13e616
		if (link_mgr_process_node(sm, p_node, link_state))
Packit 13e616
			ret = -1;
Packit 13e616
Packit 13e616
	CL_PLOCK_RELEASE(sm->p_lock);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
	return ret;
Packit 13e616
}