Blame opensm/osm_port.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2002-2015 Mellanox Technologies LTD. All rights reserved.
Packit 13e616
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit 13e616
 * Copyright (C) 2012-2017 Tokyo Institute of Technology. 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_physp_t.
Packit 13e616
 * This object represents an Infiniband Port.
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 <stdlib.h>
Packit 13e616
#include <string.h>
Packit 13e616
#include <complib/cl_debug.h>
Packit 13e616
#include <iba/ib_types.h>
Packit 13e616
#include <opensm/osm_file_ids.h>
Packit 13e616
#define FILE_ID OSM_FILE_PORT_C
Packit 13e616
#include <opensm/osm_port.h>
Packit 13e616
#include <opensm/osm_node.h>
Packit 13e616
#include <opensm/osm_madw.h>
Packit 13e616
#include <opensm/osm_switch.h>
Packit 13e616
#include <opensm/osm_db_pack.h>
Packit 13e616
#include <opensm/osm_sm.h>
Packit 13e616
Packit 13e616
void osm_physp_construct(IN osm_physp_t * p_physp)
Packit 13e616
{
Packit 13e616
	memset(p_physp, 0, sizeof(*p_physp));
Packit 13e616
	osm_dr_path_construct(&p_physp->dr_path);
Packit 13e616
	cl_ptr_vector_construct(&p_physp->slvl_by_port);
Packit 13e616
	osm_pkey_tbl_construct(&p_physp->pkeys);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_physp_destroy(IN osm_physp_t * p_physp)
Packit 13e616
{
Packit 13e616
	size_t num_slvl, i;
Packit 13e616
Packit 13e616
	/* the physp might be uninitialized */
Packit 13e616
	if (p_physp->port_guid) {
Packit 13e616
		if (p_physp->p_guids)
Packit 13e616
			free(p_physp->p_guids);
Packit 13e616
Packit 13e616
		/* free the SL2VL Tables */
Packit 13e616
		num_slvl = cl_ptr_vector_get_size(&p_physp->slvl_by_port);
Packit 13e616
		for (i = 0; i < num_slvl; i++)
Packit 13e616
			free(cl_ptr_vector_get(&p_physp->slvl_by_port, i));
Packit 13e616
		cl_ptr_vector_destroy(&p_physp->slvl_by_port);
Packit 13e616
Packit 13e616
		/* free the P_Key Tables */
Packit 13e616
		osm_pkey_tbl_destroy(&p_physp->pkeys);
Packit 13e616
Packit 13e616
		memset(p_physp, 0, sizeof(*p_physp));
Packit 13e616
		osm_dr_path_construct(&p_physp->dr_path);	/* clear dr_path */
Packit 13e616
	}
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_physp_init(IN osm_physp_t * p_physp, IN ib_net64_t port_guid,
Packit 13e616
		    IN uint8_t port_num, IN const struct osm_node *p_node,
Packit 13e616
		    IN osm_bind_handle_t h_bind, IN uint8_t hop_count,
Packit 13e616
		    IN const uint8_t * p_initial_path)
Packit 13e616
{
Packit 13e616
	uint16_t num_slvl, i;
Packit 13e616
	ib_slvl_table_t *p_slvl;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_node);
Packit 13e616
Packit 13e616
	osm_physp_construct(p_physp);
Packit 13e616
	p_physp->port_guid = port_guid;
Packit 13e616
	p_physp->port_num = port_num;
Packit 13e616
	p_physp->healthy = TRUE;
Packit 13e616
	p_physp->need_update = 2;
Packit 13e616
	p_physp->p_node = (struct osm_node *)p_node;
Packit 13e616
Packit 13e616
	osm_dr_path_init(&p_physp->dr_path, hop_count, p_initial_path);
Packit 13e616
Packit 13e616
	/* allocate enough SL2VL tables */
Packit 13e616
	if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH)
Packit 13e616
		/* we need node num ports + 1 SL2VL tables */
Packit 13e616
		num_slvl = osm_node_get_num_physp(p_node) + 1;
Packit 13e616
	else
Packit 13e616
		/* An end node - we need only one SL2VL */
Packit 13e616
		num_slvl = 1;
Packit 13e616
Packit 13e616
	cl_ptr_vector_init(&p_physp->slvl_by_port, num_slvl, 1);
Packit 13e616
	for (i = 0; i < num_slvl; i++) {
Packit 13e616
		p_slvl = (ib_slvl_table_t *) malloc(sizeof(ib_slvl_table_t));
Packit 13e616
		if (!p_slvl)
Packit 13e616
			break;
Packit 13e616
		memset(p_slvl, 0, sizeof(ib_slvl_table_t));
Packit 13e616
		cl_ptr_vector_set(&p_physp->slvl_by_port, i, p_slvl);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* initialize the pkey table */
Packit 13e616
	osm_pkey_tbl_init(&p_physp->pkeys);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_port_delete(IN OUT osm_port_t ** pp_port)
Packit 13e616
{
Packit 13e616
	free(*pp_port);
Packit 13e616
	*pp_port = NULL;
Packit 13e616
}
Packit 13e616
Packit 13e616
osm_port_t *osm_port_new(IN const ib_node_info_t * p_ni,
Packit 13e616
			 IN osm_node_t * p_parent_node)
Packit 13e616
{
Packit 13e616
	osm_port_t *p_port;
Packit 13e616
	ib_net64_t port_guid;
Packit 13e616
	osm_physp_t *p_physp;
Packit 13e616
	uint8_t port_num;
Packit 13e616
Packit 13e616
	p_port = malloc(sizeof(*p_port));
Packit 13e616
	if (!p_port)
Packit 13e616
		return NULL;
Packit 13e616
Packit 13e616
	memset(p_port, 0, sizeof(*p_port));
Packit 13e616
	cl_qlist_init(&p_port->mcm_list);
Packit 13e616
	p_port->p_node = (struct osm_node *)p_parent_node;
Packit 13e616
	port_guid = p_ni->port_guid;
Packit 13e616
	p_port->guid = port_guid;
Packit 13e616
	port_num = p_ni->node_type == IB_NODE_TYPE_SWITCH ?
Packit 13e616
	    0 : ib_node_info_get_local_port_num(p_ni);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Get the pointers to the physical node objects "owned" by this
Packit 13e616
	   logical port GUID.
Packit 13e616
	   For switches, port '0' is owned; for HCA's and routers,
Packit 13e616
	   only the singular part that has this GUID is owned.
Packit 13e616
	 */
Packit 13e616
	p_physp = osm_node_get_physp_ptr(p_parent_node, port_num);
Packit 13e616
	if (!p_physp) {
Packit 13e616
		free(p_port);
Packit 13e616
		return NULL;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	CL_ASSERT(port_guid == osm_physp_get_port_guid(p_physp));
Packit 13e616
	p_port->p_physp = p_physp;
Packit 13e616
Packit 13e616
	return p_port;
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_port_get_lid_range_ho(IN const osm_port_t * p_port,
Packit 13e616
			       IN uint16_t * p_min_lid, IN uint16_t * p_max_lid)
Packit 13e616
{
Packit 13e616
	uint8_t lmc;
Packit 13e616
Packit 13e616
	*p_min_lid = cl_ntoh16(osm_port_get_base_lid(p_port));
Packit 13e616
	lmc = osm_port_get_lmc(p_port);
Packit 13e616
	*p_max_lid = (uint16_t) (*p_min_lid + (1 << lmc) - 1);
Packit 13e616
}
Packit 13e616
Packit 13e616
uint8_t osm_physp_calc_link_mtu(IN osm_log_t * p_log,
Packit 13e616
				IN const osm_physp_t * p_physp,
Packit 13e616
				IN uint8_t current_mtu)
Packit 13e616
{
Packit 13e616
	const osm_physp_t *p_remote_physp;
Packit 13e616
	uint8_t mtu;
Packit 13e616
	uint8_t remote_mtu;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_log);
Packit 13e616
Packit 13e616
	p_remote_physp = osm_physp_get_remote(p_physp);
Packit 13e616
	if (p_remote_physp) {
Packit 13e616
		/* use the available MTU */
Packit 13e616
		mtu = ib_port_info_get_mtu_cap(&p_physp->port_info);
Packit 13e616
Packit 13e616
		remote_mtu =
Packit 13e616
		    ib_port_info_get_mtu_cap(&p_remote_physp->port_info);
Packit 13e616
Packit 13e616
		OSM_LOG(p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Remote port 0x%016" PRIx64 " port = %u : "
Packit 13e616
			"MTU = %u. This Port MTU: %u\n",
Packit 13e616
			cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)),
Packit 13e616
			osm_physp_get_port_num(p_remote_physp),
Packit 13e616
			remote_mtu, mtu);
Packit 13e616
Packit 13e616
		if (mtu != remote_mtu) {
Packit 13e616
			if (mtu > remote_mtu)
Packit 13e616
				mtu = remote_mtu;
Packit 13e616
			if (mtu != current_mtu)
Packit 13e616
				OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
					"MTU mismatch between ports."
Packit 13e616
					"\n\t\t\t\tPort 0x%016" PRIx64 ", port %u"
Packit 13e616
					" and port 0x%016" PRIx64 ", port %u."
Packit 13e616
					"\n\t\t\t\tUsing lower MTU of %u\n",
Packit 13e616
					cl_ntoh64(osm_physp_get_port_guid(p_physp)),
Packit 13e616
					osm_physp_get_port_num(p_physp),
Packit 13e616
					cl_ntoh64(osm_physp_get_port_guid
Packit 13e616
						  (p_remote_physp)),
Packit 13e616
					osm_physp_get_port_num(p_remote_physp), mtu);
Packit 13e616
		}
Packit 13e616
	} else
Packit 13e616
		mtu = ib_port_info_get_neighbor_mtu(&p_physp->port_info);
Packit 13e616
Packit 13e616
	if (mtu == 0) {
Packit 13e616
		OSM_LOG(p_log, OSM_LOG_DEBUG, "ERR 4101: "
Packit 13e616
			"Invalid MTU = 0. Forcing correction to 256\n");
Packit 13e616
		mtu = 1;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_log);
Packit 13e616
	return mtu;
Packit 13e616
}
Packit 13e616
Packit 13e616
uint8_t osm_physp_calc_link_op_vls(IN osm_log_t * p_log,
Packit 13e616
				   IN const osm_subn_t * p_subn,
Packit 13e616
				   IN const osm_physp_t * p_physp,
Packit 13e616
				   IN uint8_t current_op_vls)
Packit 13e616
{
Packit 13e616
	const osm_physp_t *p_remote_physp;
Packit 13e616
	uint8_t op_vls;
Packit 13e616
	uint8_t remote_op_vls;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_log);
Packit 13e616
Packit 13e616
	p_remote_physp = osm_physp_get_remote(p_physp);
Packit 13e616
	if (p_remote_physp) {
Packit 13e616
		/* use the available VLCap */
Packit 13e616
		op_vls = ib_port_info_get_vl_cap(&p_physp->port_info);
Packit 13e616
Packit 13e616
		remote_op_vls =
Packit 13e616
		    ib_port_info_get_vl_cap(&p_remote_physp->port_info);
Packit 13e616
Packit 13e616
		OSM_LOG(p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Remote port 0x%016" PRIx64 " port = 0x%X : "
Packit 13e616
			"VL_CAP = %u. This port VL_CAP = %u\n",
Packit 13e616
			cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)),
Packit 13e616
			osm_physp_get_port_num(p_remote_physp),
Packit 13e616
			remote_op_vls, op_vls);
Packit 13e616
Packit 13e616
		if (op_vls != remote_op_vls) {
Packit 13e616
			if (op_vls > remote_op_vls)
Packit 13e616
				op_vls = remote_op_vls;
Packit 13e616
			if (op_vls != current_op_vls)
Packit 13e616
				OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
					"OP_VLS mismatch between ports."
Packit 13e616
					"\n\t\t\t\tPort 0x%016" PRIx64 ", port 0x%X"
Packit 13e616
					" and port 0x%016" PRIx64 ", port 0x%X."
Packit 13e616
					"\n\t\t\t\tUsing lower OP_VLS of %u\n",
Packit 13e616
					cl_ntoh64(osm_physp_get_port_guid(p_physp)),
Packit 13e616
					osm_physp_get_port_num(p_physp),
Packit 13e616
					cl_ntoh64(osm_physp_get_port_guid
Packit 13e616
						  (p_remote_physp)),
Packit 13e616
					osm_physp_get_port_num(p_remote_physp), op_vls);
Packit 13e616
		}
Packit 13e616
	} else
Packit 13e616
		op_vls = ib_port_info_get_op_vls(&p_physp->port_info);
Packit 13e616
Packit 13e616
	if (op_vls == 0) {
Packit 13e616
		/* for non compliant implementations */
Packit 13e616
		OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
			"Invalid OP_VLS = 0. Forcing correction to 1 (VL0)\n");
Packit 13e616
		op_vls = 1;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* support user limitation of max_op_vls */
Packit 13e616
	if (op_vls > p_subn->opt.max_op_vls)
Packit 13e616
		op_vls = p_subn->opt.max_op_vls;
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_log);
Packit 13e616
	return op_vls;
Packit 13e616
}
Packit 13e616
Packit 13e616
static inline uint64_t ptr_to_key(void const *p)
Packit 13e616
{
Packit 13e616
	uint64_t k = 0;
Packit 13e616
Packit 13e616
	memcpy(&k, p, sizeof(void *));
Packit 13e616
	return k;
Packit 13e616
}
Packit 13e616
Packit 13e616
#if 0
Packit 13e616
static inline void *key_to_ptr(uint64_t k)
Packit 13e616
{
Packit 13e616
	void *p = 0;
Packit 13e616
Packit 13e616
	memcpy(&p, &k, sizeof(void *));
Packit 13e616
	return p;
Packit 13e616
}
Packit 13e616
#endif
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 Traverse the fabric from the SM node following the DR path given and
Packit 13e616
 add every phys port traversed to the map. Avoid tracking the first and
Packit 13e616
 last phys ports (going into the first switch and into the target port).
Packit 13e616
 **********************************************************************/
Packit 13e616
static cl_status_t physp_get_dr_physp_set(IN osm_log_t * p_log,
Packit 13e616
					  IN osm_subn_t const *p_subn,
Packit 13e616
					  IN osm_dr_path_t const *p_path,
Packit 13e616
					  OUT cl_map_t * p_physp_map)
Packit 13e616
{
Packit 13e616
	osm_port_t *p_port;
Packit 13e616
	osm_physp_t *p_physp;
Packit 13e616
	osm_node_t *p_node;
Packit 13e616
	uint8_t hop;
Packit 13e616
	cl_status_t status = CL_SUCCESS;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_log);
Packit 13e616
Packit 13e616
	/* find the OSM node */
Packit 13e616
	p_port = osm_get_port_by_guid(p_subn, p_subn->sm_port_guid);
Packit 13e616
	if (!p_port) {
Packit 13e616
		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4103: "
Packit 13e616
			"Failed to find the SM own port by guid\n");
Packit 13e616
		status = CL_ERROR;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* get the node of the SM */
Packit 13e616
	p_node = p_port->p_node;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   traverse the path adding the nodes to the table
Packit 13e616
	   start after the first dummy hop and stop just before the
Packit 13e616
	   last one
Packit 13e616
	 */
Packit 13e616
	for (hop = 1; hop < p_path->hop_count - 1; hop++) {
Packit 13e616
		/* go out using the phys port of the path */
Packit 13e616
		p_physp = osm_node_get_physp_ptr(p_node, p_path->path[hop]);
Packit 13e616
Packit 13e616
		/* make sure we got a valid port and it has a remote port */
Packit 13e616
		if (!p_physp) {
Packit 13e616
			OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4104: "
Packit 13e616
				"DR Traversal stopped on invalid port at hop:%u\n",
Packit 13e616
				hop);
Packit 13e616
			status = CL_ERROR;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/* we track the ports we go out along the path */
Packit 13e616
		if (hop > 1)
Packit 13e616
			cl_map_insert(p_physp_map, ptr_to_key(p_physp), NULL);
Packit 13e616
Packit 13e616
		OSM_LOG(p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Traversed through node: 0x%016" PRIx64
Packit 13e616
			" port:%u\n",
Packit 13e616
			cl_ntoh64(p_node->node_info.node_guid),
Packit 13e616
			p_path->path[hop]);
Packit 13e616
Packit 13e616
		if (!(p_physp = osm_physp_get_remote(p_physp))) {
Packit 13e616
			OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4106: "
Packit 13e616
				"DR Traversal stopped on missing remote physp at hop:%u\n",
Packit 13e616
				hop);
Packit 13e616
			status = CL_ERROR;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		p_node = osm_physp_get_node_ptr(p_physp);
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(p_log);
Packit 13e616
	return status;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void physp_update_new_dr_path(IN osm_physp_t const *p_dest_physp,
Packit 13e616
				     IN cl_map_t * p_visited_map,
Packit 13e616
				     IN osm_bind_handle_t * h_bind)
Packit 13e616
{
Packit 13e616
	cl_list_t tmpPortsList;
Packit 13e616
	osm_physp_t *p_physp, *p_src_physp = NULL;
Packit 13e616
	uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX];
Packit 13e616
	uint8_t i = 0;
Packit 13e616
	osm_dr_path_t *p_dr_path;
Packit 13e616
Packit 13e616
	cl_list_construct(&tmpPortsList);
Packit 13e616
	cl_list_init(&tmpPortsList, 10);
Packit 13e616
Packit 13e616
	cl_list_insert_head(&tmpPortsList, p_dest_physp);
Packit 13e616
	/* get the output port where we need to come from */
Packit 13e616
	p_physp = (osm_physp_t *) cl_map_get(p_visited_map,
Packit 13e616
					     ptr_to_key(p_dest_physp));
Packit 13e616
	while (p_physp != NULL) {
Packit 13e616
		cl_list_insert_head(&tmpPortsList, p_physp);
Packit 13e616
		/* get the input port through where we reached the output port */
Packit 13e616
		p_src_physp = p_physp;
Packit 13e616
		p_physp = (osm_physp_t *) cl_map_get(p_visited_map,
Packit 13e616
						     ptr_to_key(p_physp));
Packit 13e616
		/* if we reached a null p_physp - this means we are at the begining
Packit 13e616
		   of the path. Break. */
Packit 13e616
		if (p_physp == NULL)
Packit 13e616
			break;
Packit 13e616
		/* get the output port */
Packit 13e616
		p_physp = (osm_physp_t *) cl_map_get(p_visited_map,
Packit 13e616
						     ptr_to_key(p_physp));
Packit 13e616
	}
Packit 13e616
Packit 13e616
	memset(path_array, 0, sizeof(path_array));
Packit 13e616
	p_physp = (osm_physp_t *) cl_list_remove_head(&tmpPortsList);
Packit 13e616
	while (p_physp != NULL) {
Packit 13e616
		i++;
Packit 13e616
		path_array[i] = p_physp->port_num;
Packit 13e616
		p_physp = (osm_physp_t *) cl_list_remove_head(&tmpPortsList);
Packit 13e616
	}
Packit 13e616
	if (p_src_physp) {
Packit 13e616
		p_dr_path = osm_physp_get_dr_path_ptr(p_src_physp);
Packit 13e616
		osm_dr_path_init(p_dr_path, i, path_array);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	cl_list_destroy(&tmpPortsList);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_physp_replace_dr_path_with_alternate_dr_path(IN osm_log_t * p_log,
Packit 13e616
						      IN osm_subn_t const
Packit 13e616
						      *p_subn, IN osm_physp_t const
Packit 13e616
						      *p_dest_physp,
Packit 13e616
						      IN osm_bind_handle_t *
Packit 13e616
						      h_bind)
Packit 13e616
{
Packit 13e616
	cl_map_t physp_map;
Packit 13e616
	cl_map_t visited_map;
Packit 13e616
	osm_dr_path_t *p_dr_path;
Packit 13e616
	cl_list_t *p_currPortsList;
Packit 13e616
	cl_list_t *p_nextPortsList;
Packit 13e616
	osm_port_t *p_port;
Packit 13e616
	osm_physp_t *p_physp, *p_remote_physp;
Packit 13e616
	ib_net64_t port_guid;
Packit 13e616
	boolean_t next_list_is_full = TRUE, reached_dest = FALSE;
Packit 13e616
	uint8_t num_ports, port_num;
Packit 13e616
Packit 13e616
	p_nextPortsList = (cl_list_t *) malloc(sizeof(cl_list_t));
Packit 13e616
	if (!p_nextPortsList)
Packit 13e616
		return;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   initialize the map of all port participating in current dr path
Packit 13e616
	   not including first and last switches
Packit 13e616
	 */
Packit 13e616
	cl_map_construct(&physp_map);
Packit 13e616
	cl_map_init(&physp_map, 4);
Packit 13e616
	cl_map_construct(&visited_map);
Packit 13e616
	cl_map_init(&visited_map, 4);
Packit 13e616
	p_dr_path = osm_physp_get_dr_path_ptr(p_dest_physp);
Packit 13e616
	physp_get_dr_physp_set(p_log, p_subn, p_dr_path, &physp_map);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   BFS from OSM port until we find the target physp but avoid
Packit 13e616
	   going through mapped ports
Packit 13e616
	 */
Packit 13e616
	cl_list_construct(p_nextPortsList);
Packit 13e616
	cl_list_init(p_nextPortsList, 10);
Packit 13e616
Packit 13e616
	port_guid = p_subn->sm_port_guid;
Packit 13e616
Packit 13e616
	CL_ASSERT(port_guid);
Packit 13e616
Packit 13e616
	p_port = osm_get_port_by_guid(p_subn, port_guid);
Packit 13e616
	if (!p_port) {
Packit 13e616
		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4105: No SM port object\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   HACK: We are assuming SM is running on HCA, so when getting the default
Packit 13e616
	   port we'll get the port connected to the rest of the subnet. If SM is
Packit 13e616
	   running on SWITCH - we should try to get a dr path from all switch ports.
Packit 13e616
	 */
Packit 13e616
	p_physp = p_port->p_physp;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_physp);
Packit 13e616
Packit 13e616
	cl_list_insert_tail(p_nextPortsList, p_physp);
Packit 13e616
Packit 13e616
	while (next_list_is_full == TRUE) {
Packit 13e616
		next_list_is_full = FALSE;
Packit 13e616
		p_currPortsList = p_nextPortsList;
Packit 13e616
		p_nextPortsList = (cl_list_t *) malloc(sizeof(cl_list_t));
Packit 13e616
		if (!p_nextPortsList) {
Packit 13e616
			p_nextPortsList = p_currPortsList;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
		cl_list_construct(p_nextPortsList);
Packit 13e616
		cl_list_init(p_nextPortsList, 10);
Packit 13e616
		p_physp = (osm_physp_t *) cl_list_remove_head(p_currPortsList);
Packit 13e616
		while (p_physp != NULL) {
Packit 13e616
			/* If we are in a switch - need to go out through all
Packit 13e616
			   the other physical ports of the switch */
Packit 13e616
			num_ports = osm_node_get_num_physp(p_physp->p_node);
Packit 13e616
Packit 13e616
			for (port_num = 1; port_num < num_ports; port_num++) {
Packit 13e616
				if (osm_node_get_type(p_physp->p_node) ==
Packit 13e616
				    IB_NODE_TYPE_SWITCH)
Packit 13e616
					p_remote_physp =
Packit 13e616
					    osm_node_get_physp_ptr(p_physp->
Packit 13e616
								   p_node,
Packit 13e616
								   port_num);
Packit 13e616
				else
Packit 13e616
					/* this is HCA or router - the remote port is just the port connected
Packit 13e616
					   on the other side */
Packit 13e616
					p_remote_physp =
Packit 13e616
					    p_physp->p_remote_physp;
Packit 13e616
Packit 13e616
				/*
Packit 13e616
				   make sure that all of the following occurred:
Packit 13e616
				   1. The port isn't NULL
Packit 13e616
				   2. This is not the port we came from
Packit 13e616
				   3. The port is not in the physp_map
Packit 13e616
				   4. This port haven't been visited before
Packit 13e616
				 */
Packit 13e616
				if (p_remote_physp &&
Packit 13e616
				    p_remote_physp != p_physp &&
Packit 13e616
				    cl_map_get(&physp_map,
Packit 13e616
					       ptr_to_key(p_remote_physp))
Packit 13e616
				    == NULL
Packit 13e616
				    && cl_map_get(&visited_map,
Packit 13e616
						  ptr_to_key
Packit 13e616
						  (p_remote_physp)) == NULL) {
Packit 13e616
					/* Insert the port into the visited_map, and save its source port */
Packit 13e616
					cl_map_insert(&visited_map,
Packit 13e616
						      ptr_to_key
Packit 13e616
						      (p_remote_physp),
Packit 13e616
						      p_physp);
Packit 13e616
Packit 13e616
					/* Is this the p_dest_physp? */
Packit 13e616
					if (p_remote_physp == p_dest_physp) {
Packit 13e616
						/* update the new dr path */
Packit 13e616
						physp_update_new_dr_path
Packit 13e616
						    (p_dest_physp, &visited_map,
Packit 13e616
						     h_bind);
Packit 13e616
						reached_dest = TRUE;
Packit 13e616
						break;
Packit 13e616
					}
Packit 13e616
Packit 13e616
					/* add the p_remote_physp to the nextPortsList */
Packit 13e616
					cl_list_insert_tail(p_nextPortsList,
Packit 13e616
							    p_remote_physp);
Packit 13e616
					next_list_is_full = TRUE;
Packit 13e616
				}
Packit 13e616
			}
Packit 13e616
Packit 13e616
			p_physp = (osm_physp_t *)
Packit 13e616
			    cl_list_remove_head(p_currPortsList);
Packit 13e616
			if (reached_dest == TRUE) {
Packit 13e616
				/* free the rest of the currPortsList */
Packit 13e616
				while (p_physp != NULL)
Packit 13e616
					p_physp = (osm_physp_t *)
Packit 13e616
					    cl_list_remove_head
Packit 13e616
					    (p_currPortsList);
Packit 13e616
				/* free the nextPortsList, if items were added to it */
Packit 13e616
				p_physp = (osm_physp_t *)
Packit 13e616
				    cl_list_remove_head(p_nextPortsList);
Packit 13e616
				while (p_physp != NULL)
Packit 13e616
					p_physp = (osm_physp_t *)
Packit 13e616
					    cl_list_remove_head
Packit 13e616
					    (p_nextPortsList);
Packit 13e616
				next_list_is_full = FALSE;
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
		cl_list_destroy(p_currPortsList);
Packit 13e616
		free(p_currPortsList);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* cleanup */
Packit 13e616
Exit:
Packit 13e616
	cl_list_destroy(p_nextPortsList);
Packit 13e616
	free(p_nextPortsList);
Packit 13e616
	cl_map_destroy(&physp_map);
Packit 13e616
	cl_map_destroy(&visited_map);
Packit 13e616
}
Packit 13e616
Packit 13e616
boolean_t osm_link_is_healthy(IN const osm_physp_t * p_physp)
Packit 13e616
{
Packit 13e616
	osm_physp_t *p_remote_physp;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_physp);
Packit 13e616
	p_remote_physp = p_physp->p_remote_physp;
Packit 13e616
	if (p_remote_physp != NULL)
Packit 13e616
		return ((p_physp->healthy) & (p_remote_physp->healthy));
Packit 13e616
	/* the other side is not known - consider the link as healthy */
Packit 13e616
	return TRUE;
Packit 13e616
}
Packit 13e616
Packit 13e616
boolean_t osm_link_is_throttled(IN osm_physp_t * p_physp,
Packit 13e616
				IN const boolean_t subn_has_fdr10_enabled)
Packit 13e616
{
Packit 13e616
	osm_physp_t *p_remote;
Packit 13e616
	uint8_t speed_physp, speed_remote, width_physp, width_remote;
Packit 13e616
	uint8_t highest_speed, highest_width;
Packit 13e616
	boolean_t physp_has_extended_speeds_capability;
Packit 13e616
	boolean_t remote_has_extended_speeds_capability;
Packit 13e616
	ib_port_info_t *p_physp_info, *p_remote_info;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_physp);
Packit 13e616
	p_remote = p_physp->p_remote_physp;
Packit 13e616
Packit 13e616
	/* the other side is not known - consider the link as unthrottled */
Packit 13e616
	if (!p_remote)
Packit 13e616
		return FALSE;
Packit 13e616
Packit 13e616
	/* only SP0 (and not Sw Ext.) have a valid CapabilityMask */
Packit 13e616
	if (osm_node_get_type(p_physp->p_node) == IB_NODE_TYPE_SWITCH)
Packit 13e616
		p_physp_info =
Packit 13e616
		    &(osm_node_get_physp_ptr(p_physp->p_node, 0)->port_info);
Packit 13e616
	else
Packit 13e616
		p_physp_info = &p_physp->port_info;
Packit 13e616
	if (osm_node_get_type(p_remote->p_node) == IB_NODE_TYPE_SWITCH)
Packit 13e616
		p_remote_info =
Packit 13e616
		    &(osm_node_get_physp_ptr(p_remote->p_node, 0)->port_info);
Packit 13e616
	else
Packit 13e616
		p_remote_info = &p_remote->port_info;
Packit 13e616
Packit 13e616
	physp_has_extended_speeds_capability =
Packit 13e616
	    p_physp_info->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
Packit 13e616
	remote_has_extended_speeds_capability =
Packit 13e616
	    p_remote_info->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
Packit 13e616
Packit 13e616
	/* reset again to the original port_info */
Packit 13e616
	p_physp_info = &p_physp->port_info;
Packit 13e616
	p_remote_info = &p_remote->port_info;
Packit 13e616
Packit 13e616
	/* first determine the enabled link speed/width of both sides */
Packit 13e616
	speed_physp =
Packit 13e616
	    (physp_has_extended_speeds_capability ?
Packit 13e616
	     ib_port_info_get_link_speed_ext_enabled(p_physp_info) << 4 : 0)
Packit 13e616
	    + (subn_has_fdr10_enabled ?
Packit 13e616
	       (p_physp->ext_port_info.link_speed_enabled & FDR10) << 3 : 0)
Packit 13e616
	    + ib_port_info_get_link_speed_enabled(p_physp_info);
Packit 13e616
	width_physp = p_physp_info->link_width_enabled;
Packit 13e616
Packit 13e616
	speed_remote =
Packit 13e616
	    (remote_has_extended_speeds_capability ?
Packit 13e616
	     ib_port_info_get_link_speed_ext_enabled(p_remote_info) << 4 : 0)
Packit 13e616
	    + (subn_has_fdr10_enabled ?
Packit 13e616
	       (p_remote->ext_port_info.link_speed_enabled & FDR10) << 3 : 0)
Packit 13e616
	    + ib_port_info_get_link_speed_enabled(p_remote_info);
Packit 13e616
	width_remote = p_remote_info->link_width_enabled;
Packit 13e616
Packit 13e616
	highest_speed = ib_get_highest_link_speed(speed_physp & speed_remote);
Packit 13e616
	highest_width = ib_get_highest_link_width(width_physp & width_remote);
Packit 13e616
Packit 13e616
	/* and now determine the currently active link speed/width */
Packit 13e616
	speed_physp =
Packit 13e616
	    (physp_has_extended_speeds_capability ?
Packit 13e616
	     ib_port_info_get_link_speed_ext_active(p_physp_info) << 4 : 0)
Packit 13e616
	    + (subn_has_fdr10_enabled ?
Packit 13e616
	       (p_physp->ext_port_info.link_speed_active & FDR10) << 3 : 0)
Packit 13e616
	    + ib_port_info_get_link_speed_active(p_physp_info);
Packit 13e616
	speed_physp = ib_get_highest_link_speed(speed_physp);
Packit 13e616
	width_physp = p_physp_info->link_width_active;
Packit 13e616
Packit 13e616
	speed_remote =
Packit 13e616
	    (remote_has_extended_speeds_capability ?
Packit 13e616
	     ib_port_info_get_link_speed_ext_active(p_remote_info) << 4 : 0)
Packit 13e616
	    + (subn_has_fdr10_enabled ?
Packit 13e616
	       (p_remote->ext_port_info.link_speed_active & FDR10) << 3 : 0)
Packit 13e616
	    + ib_port_info_get_link_speed_active(p_remote_info);
Packit 13e616
	speed_remote = ib_get_highest_link_speed(speed_remote);
Packit 13e616
	width_remote = p_remote_info->link_width_active;
Packit 13e616
Packit 13e616
	/* check if the link supports same speed in both directions
Packit 13e616
	   and whether or not it runs at maximum speed/width which is
Packit 13e616
	   enabled by both ends (if not then its considered 'throttled')
Packit 13e616
	 */
Packit 13e616
	if (speed_physp != speed_remote || speed_physp != highest_speed ||
Packit 13e616
	    width_physp != width_remote || width_physp != highest_width)
Packit 13e616
		return TRUE;
Packit 13e616
Packit 13e616
	return FALSE;
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_physp_set_pkey_tbl(IN osm_log_t * p_log, IN const osm_subn_t * p_subn,
Packit 13e616
			    IN osm_physp_t * p_physp,
Packit 13e616
			    IN ib_pkey_table_t * p_pkey_tbl,
Packit 13e616
			    IN uint16_t block_num,
Packit 13e616
			    IN boolean_t is_set)
Packit 13e616
{
Packit 13e616
	uint16_t max_blocks;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_pkey_tbl);
Packit 13e616
	/*
Packit 13e616
	   (14.2.5.7) - the block number valid values are 0-2047, and are
Packit 13e616
	   further limited by the size of the P_Key table specified by
Packit 13e616
	   the PartitionCap on the node.
Packit 13e616
	 */
Packit 13e616
	if (!p_physp->p_node->sw || p_physp->port_num == 0)
Packit 13e616
		/*
Packit 13e616
		   The maximum blocks is defined in the node info: partition cap
Packit 13e616
		   for CA, router, and switch management ports.
Packit 13e616
		 */
Packit 13e616
		max_blocks =
Packit 13e616
		    (cl_ntoh16(p_physp->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
		/*
Packit 13e616
		   This is a switch, and not a management port. The maximum
Packit 13e616
		   blocks is defined in the switch info: partition enforcement
Packit 13e616
		   cap.
Packit 13e616
		 */
Packit 13e616
		max_blocks =
Packit 13e616
		    (cl_ntoh16(p_physp->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
	if (block_num >= max_blocks) {
Packit 13e616
		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4108: "
Packit 13e616
			"Got illegal update for block number:%u max:%u "
Packit 13e616
			"for GUID: %" PRIx64 " port number:%u\n",
Packit 13e616
			block_num, max_blocks,
Packit 13e616
			cl_ntoh64(p_physp->p_node->node_info.node_guid),
Packit 13e616
			p_physp->port_num);
Packit 13e616
		return;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* decrement block received counter */
Packit 13e616
	if(!is_set)
Packit 13e616
		p_physp->pkeys.rcv_blocks_cnt--;
Packit 13e616
	osm_pkey_tbl_set(&p_physp->pkeys, block_num, p_pkey_tbl,
Packit 13e616
			 p_subn->opt.allow_both_pkeys);
Packit 13e616
}
Packit 13e616
Packit 13e616
osm_alias_guid_t *osm_alias_guid_new(IN const ib_net64_t alias_guid,
Packit 13e616
				     IN osm_port_t *p_base_port)
Packit 13e616
{
Packit 13e616
	osm_alias_guid_t *p_alias_guid;
Packit 13e616
Packit 13e616
	p_alias_guid = calloc(1, sizeof(*p_alias_guid));
Packit 13e616
	if (p_alias_guid) {
Packit 13e616
		p_alias_guid->alias_guid = alias_guid;
Packit 13e616
		p_alias_guid->p_base_port = p_base_port;
Packit 13e616
	}
Packit 13e616
	return p_alias_guid;
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_alias_guid_delete(IN OUT osm_alias_guid_t ** pp_alias_guid)
Packit 13e616
{
Packit 13e616
	free(*pp_alias_guid);
Packit 13e616
	*pp_alias_guid = NULL;
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_physp_set_port_info(IN osm_physp_t * p_physp,
Packit 13e616
					   IN const ib_port_info_t * p_pi,
Packit 13e616
					   IN const struct osm_sm * p_sm)
Packit 13e616
{
Packit 13e616
	CL_ASSERT(p_pi);
Packit 13e616
	CL_ASSERT(osm_physp_is_valid(p_physp));
Packit 13e616
Packit 13e616
	if (ib_port_info_get_port_state(p_pi) == IB_LINK_DOWN) {
Packit 13e616
		/* If PortState is down, only copy PortState */
Packit 13e616
		/* and PortPhysicalState per C14-24-2.1 */
Packit 13e616
		ib_port_info_set_port_state(&p_physp->port_info, IB_LINK_DOWN);
Packit 13e616
		ib_port_info_set_port_phys_state
Packit 13e616
		    (ib_port_info_get_port_phys_state(p_pi),
Packit 13e616
		     &p_physp->port_info);
Packit 13e616
	} else {
Packit 13e616
		p_physp->port_info = *p_pi;
Packit 13e616
Packit 13e616
		/* The MKey in p_pi can only be considered valid if it's
Packit 13e616
		 * for a HCA/router or switch port 0, and it's either
Packit 13e616
		 * non-zero or the MKeyProtect bits are also zero.
Packit 13e616
		 */
Packit 13e616
		if ((osm_node_get_type(p_physp->p_node) !=
Packit 13e616
		     IB_NODE_TYPE_SWITCH || p_physp->port_num == 0) &&
Packit 13e616
		    (p_pi->m_key != 0 || ib_port_info_get_mpb(p_pi) == 0))
Packit 13e616
			osm_db_guid2mkey_set(p_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
}