Blame opensm/osm_sa_multipath_record.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2006-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) 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_mpr_rcv_t.
Packit 13e616
 *	This object represents the MultiPath Record 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
#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
Packit 13e616
Packit 13e616
#include <string.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 <complib/cl_qlist.h>
Packit 13e616
#include <opensm/osm_file_ids.h>
Packit 13e616
#define FILE_ID OSM_FILE_SA_MULTIPATH_RECORD_C
Packit 13e616
#include <vendor/osm_vendor_api.h>
Packit 13e616
#include <opensm/osm_port.h>
Packit 13e616
#include <opensm/osm_node.h>
Packit 13e616
#include <opensm/osm_switch.h>
Packit 13e616
#include <opensm/osm_partition.h>
Packit 13e616
#include <opensm/osm_helper.h>
Packit 13e616
#include <opensm/osm_qos_policy.h>
Packit 13e616
#include <opensm/osm_sa.h>
Packit 13e616
Packit 13e616
#define OSM_SA_MPR_MAX_NUM_PATH        127
Packit 13e616
#define MAX_HOPS 64
Packit 13e616
Packit 13e616
#define SA_MPR_RESP_SIZE SA_ITEM_RESP_SIZE(mpr_rec)
Packit 13e616
Packit 13e616
static boolean_t sa_multipath_rec_is_tavor_port(IN const osm_port_t * p_port)
Packit 13e616
{
Packit 13e616
	osm_node_t const *p_node;
Packit 13e616
	ib_net32_t vend_id;
Packit 13e616
Packit 13e616
	p_node = p_port->p_node;
Packit 13e616
	vend_id = ib_node_info_get_vendor_id(&p_node->node_info);
Packit 13e616
Packit 13e616
	return ((p_node->node_info.device_id == CL_HTON16(23108)) &&
Packit 13e616
		((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) ||
Packit 13e616
		 (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) ||
Packit 13e616
		 (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) ||
Packit 13e616
		 (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE))));
Packit 13e616
}
Packit 13e616
Packit 13e616
static boolean_t
Packit 13e616
sa_multipath_rec_apply_tavor_mtu_limit(IN const ib_multipath_rec_t * p_mpr,
Packit 13e616
				       IN const osm_port_t * p_src_port,
Packit 13e616
				       IN const osm_port_t * p_dest_port,
Packit 13e616
				       IN const ib_net64_t comp_mask)
Packit 13e616
{
Packit 13e616
	uint8_t required_mtu;
Packit 13e616
Packit 13e616
	/* only if at least one of the ports is a Tavor device */
Packit 13e616
	if (!sa_multipath_rec_is_tavor_port(p_src_port) &&
Packit 13e616
	    !sa_multipath_rec_is_tavor_port(p_dest_port))
Packit 13e616
		return FALSE;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   we can apply the patch if either:
Packit 13e616
	   1. No MTU required
Packit 13e616
	   2. Required MTU <
Packit 13e616
	   3. Required MTU = 1K or 512 or 256
Packit 13e616
	   4. Required MTU > 256 or 512
Packit 13e616
	 */
Packit 13e616
	required_mtu = ib_multipath_rec_mtu(p_mpr);
Packit 13e616
	if ((comp_mask & IB_MPR_COMPMASK_MTUSELEC) &&
Packit 13e616
	    (comp_mask & IB_MPR_COMPMASK_MTU)) {
Packit 13e616
		switch (ib_multipath_rec_mtu_sel(p_mpr)) {
Packit 13e616
		case 0:	/* must be greater than */
Packit 13e616
		case 2:	/* exact match */
Packit 13e616
			if (IB_MTU_LEN_1024 < required_mtu)
Packit 13e616
				return FALSE;
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 1:	/* must be less than */
Packit 13e616
			/* can't be disqualified by this one */
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 3:	/* largest available */
Packit 13e616
			/* the ULP intentionally requested */
Packit 13e616
			/* the largest MTU possible */
Packit 13e616
			return FALSE;
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		default:
Packit 13e616
			/* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */
Packit 13e616
			CL_ASSERT(FALSE);
Packit 13e616
			break;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	return TRUE;
Packit 13e616
}
Packit 13e616
Packit 13e616
static ib_api_status_t mpr_rcv_get_path_parms(IN osm_sa_t * sa,
Packit 13e616
					      IN const ib_multipath_rec_t *
Packit 13e616
					      p_mpr,
Packit 13e616
					      IN const osm_alias_guid_t * p_src_alias_guid,
Packit 13e616
					      IN const osm_alias_guid_t * p_dest_alias_guid,
Packit 13e616
					      IN const uint16_t src_lid_ho,
Packit 13e616
					      IN const uint16_t dest_lid_ho,
Packit 13e616
					      IN const ib_net64_t comp_mask,
Packit 13e616
					      OUT osm_path_parms_t * p_parms)
Packit 13e616
{
Packit 13e616
	const osm_node_t *p_node;
Packit 13e616
	const osm_physp_t *p_physp, *p_physp0;
Packit 13e616
	const osm_physp_t *p_src_physp;
Packit 13e616
	const osm_physp_t *p_dest_physp;
Packit 13e616
	const osm_prtn_t *p_prtn = NULL;
Packit 13e616
	const ib_port_info_t *p_pi, *p_pi0;
Packit 13e616
	ib_slvl_table_t *p_slvl_tbl;
Packit 13e616
	ib_api_status_t status = IB_SUCCESS;
Packit 13e616
	uint8_t mtu;
Packit 13e616
	uint8_t rate, p0_extended_rate, dest_rate;
Packit 13e616
	uint8_t pkt_life;
Packit 13e616
	uint8_t required_mtu;
Packit 13e616
	uint8_t required_rate;
Packit 13e616
	ib_net16_t required_pkey;
Packit 13e616
	uint8_t required_sl;
Packit 13e616
	uint8_t required_pkt_life;
Packit 13e616
	ib_net16_t dest_lid;
Packit 13e616
	int hops = 0;
Packit 13e616
	int in_port_num = 0;
Packit 13e616
	uint8_t i;
Packit 13e616
	osm_qos_level_t *p_qos_level = NULL;
Packit 13e616
	uint16_t valid_sl_mask = 0xffff;
Packit 13e616
	int extended, p0_extended;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	dest_lid = cl_hton16(dest_lid_ho);
Packit 13e616
Packit 13e616
	p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
Packit 13e616
	p_physp = p_src_alias_guid->p_base_port->p_physp;
Packit 13e616
	p_src_physp = p_physp;
Packit 13e616
	p_pi = &p_physp->port_info;
Packit 13e616
Packit 13e616
	mtu = ib_port_info_get_mtu_cap(p_pi);
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
Packit 13e616
	/*
Packit 13e616
	   Mellanox Tavor device performance is better using 1K MTU.
Packit 13e616
	   If required MTU and MTU selector are such that 1K is OK
Packit 13e616
	   and at least one end of the path is Tavor we override the
Packit 13e616
	   port MTU with 1K.
Packit 13e616
	 */
Packit 13e616
	if (sa->p_subn->opt.enable_quirks &&
Packit 13e616
	    sa_multipath_rec_apply_tavor_mtu_limit(p_mpr,
Packit 13e616
						   p_src_alias_guid->p_base_port,
Packit 13e616
						   p_dest_alias_guid->p_base_port,
Packit 13e616
						   comp_mask))
Packit 13e616
		if (mtu > IB_MTU_LEN_1024) {
Packit 13e616
			mtu = IB_MTU_LEN_1024;
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Optimized Path MTU to 1K for Mellanox Tavor device\n");
Packit 13e616
		}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Walk the subnet object from source to destination,
Packit 13e616
	   tracking the most restrictive rate and mtu values along the way...
Packit 13e616
Packit 13e616
	   If source port node is a switch, then p_physp should
Packit 13e616
	   point to the port that routes the destination lid
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	p_node = osm_physp_get_node_ptr(p_physp);
Packit 13e616
Packit 13e616
	if (p_node->sw) {
Packit 13e616
		/*
Packit 13e616
		 * Source node is a switch.
Packit 13e616
		 * Make sure that p_physp points to the out port of the
Packit 13e616
		 * switch that routes to the destination lid (dest_lid_ho)
Packit 13e616
		 */
Packit 13e616
		p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
Packit 13e616
		if (p_physp == 0) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4514: "
Packit 13e616
				"Can't find routing from LID %u to LID %u on "
Packit 13e616
				"switch %s (GUID 0x%016" PRIx64 ")\n",
Packit 13e616
				src_lid_ho, dest_lid_ho, p_node->print_desc,
Packit 13e616
				cl_ntoh64(osm_node_get_node_guid(p_node)));
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (sa->p_subn->opt.qos) {
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		 * Whether this node is switch or CA, the IN port for
Packit 13e616
		 * the sl2vl table is 0, because this is a source node.
Packit 13e616
		 */
Packit 13e616
		p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, 0);
Packit 13e616
Packit 13e616
		/* update valid SLs that still exist on this route */
Packit 13e616
		for (i = 0; i < IB_MAX_NUM_VLS; i++) {
Packit 13e616
			if (valid_sl_mask & (1 << i) &&
Packit 13e616
			    ib_slvl_table_get(p_slvl_tbl, i) == IB_DROP_VL)
Packit 13e616
				valid_sl_mask &= ~(1 << i);
Packit 13e616
		}
Packit 13e616
		if (!valid_sl_mask) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"All the SLs lead to VL15 on this path\n");
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * Same as above
Packit 13e616
	 */
Packit 13e616
	p_node = osm_physp_get_node_ptr(p_dest_physp);
Packit 13e616
Packit 13e616
	if (p_node->sw) {
Packit 13e616
		/*
Packit 13e616
		 * if destination is switch, we want p_dest_physp to point to port 0
Packit 13e616
		 */
Packit 13e616
		p_dest_physp =
Packit 13e616
		    osm_switch_get_route_by_lid(p_node->sw, dest_lid);
Packit 13e616
Packit 13e616
		if (p_dest_physp == 0) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4515: "
Packit 13e616
				"Can't find routing from LID %u to LID %u on "
Packit 13e616
				"switch %s (GUID 0x%016" PRIx64 ")\n",
Packit 13e616
				src_lid_ho, dest_lid_ho, p_node->print_desc,
Packit 13e616
				cl_ntoh64(osm_node_get_node_guid(p_node)));
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * Now go through the path step by step
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	while (p_physp != p_dest_physp) {
Packit 13e616
Packit 13e616
		int tmp_pnum = p_physp->port_num;
Packit 13e616
		p_node = osm_physp_get_node_ptr(p_physp);
Packit 13e616
		p_physp = osm_physp_get_remote(p_physp);
Packit 13e616
Packit 13e616
		if (p_physp == 0) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4505: "
Packit 13e616
				"Can't find remote phys port of %s (GUID "
Packit 13e616
				"0x%016" PRIx64 ") port %d "
Packit 13e616
				"while routing from LID %u to LID %u",
Packit 13e616
				p_node->print_desc,
Packit 13e616
				cl_ntoh64(osm_node_get_node_guid(p_node)),
Packit 13e616
				tmp_pnum, src_lid_ho, dest_lid_ho);
Packit 13e616
			status = IB_ERROR;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/* update number of hops traversed */
Packit 13e616
		hops++;
Packit 13e616
		if (hops > MAX_HOPS) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4520: "
Packit 13e616
				"Path from GUID 0x%016" PRIx64 " (%s) to"
Packit 13e616
				" lid %u GUID 0x%016" PRIx64 " (%s) needs"
Packit 13e616
				" more than %d hops, max %d hops allowed\n",
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
Packit 13e616
				p_src_physp->p_node->print_desc, dest_lid_ho,
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid
Packit 13e616
					  (p_dest_physp)),
Packit 13e616
				p_dest_physp->p_node->print_desc, hops,
Packit 13e616
				MAX_HOPS);
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		in_port_num = osm_physp_get_port_num(p_physp);
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   This is point to point case (no switch in between)
Packit 13e616
		 */
Packit 13e616
		if (p_physp == p_dest_physp)
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		p_node = osm_physp_get_node_ptr(p_physp);
Packit 13e616
Packit 13e616
		if (!p_node->sw) {
Packit 13e616
			/*
Packit 13e616
			   There is some sort of problem in the subnet object!
Packit 13e616
			   If this isn't a switch, we should have reached
Packit 13e616
			   the destination by now!
Packit 13e616
			 */
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4503: "
Packit 13e616
				"Internal error, bad path while routing "
Packit 13e616
				"from %s (GUID: 0x%016"PRIx64") port %d "
Packit 13e616
				"to %s (GUID: 0x%016"PRIx64") port %d; "
Packit 13e616
				"ended at %s port %d\n",
Packit 13e616
				p_src_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
				cl_ntoh64(p_src_alias_guid->p_base_port->p_node->node_info.node_guid),
Packit 13e616
				p_src_alias_guid->p_base_port->p_physp->port_num,
Packit 13e616
				p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
				cl_ntoh64(p_dest_alias_guid->p_base_port->p_node->node_info.node_guid),
Packit 13e616
				p_dest_alias_guid->p_base_port->p_physp->port_num,
Packit 13e616
				p_node->print_desc,
Packit 13e616
				p_physp->port_num);
Packit 13e616
			status = IB_ERROR;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   Check parameters for the ingress port in this switch.
Packit 13e616
		 */
Packit 13e616
		p_pi = &p_physp->port_info;
Packit 13e616
Packit 13e616
		if (mtu > ib_port_info_get_mtu_cap(p_pi))
Packit 13e616
			mtu = ib_port_info_get_mtu_cap(p_pi);
Packit 13e616
Packit 13e616
		p_physp0 = osm_node_get_physp_ptr((osm_node_t *)p_node, 0);
Packit 13e616
		p_pi0 = &p_physp0->port_info;
Packit 13e616
		p0_extended = p_pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
Packit 13e616
		p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
Packit 13e616
		if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
Packit 13e616
			rate = p0_extended_rate;
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   Continue with the egress port on this switch.
Packit 13e616
		 */
Packit 13e616
		p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
Packit 13e616
		if (p_physp == 0) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4516: "
Packit 13e616
				"Dead end path on switch "
Packit 13e616
				"%s (GUID: 0x%016"PRIx64") to LID %u\n",
Packit 13e616
				p_node->print_desc,
Packit 13e616
				cl_ntoh64(osm_node_get_node_guid(p_node)),
Packit 13e616
				dest_lid_ho);
Packit 13e616
			status = IB_ERROR;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		p_pi = &p_physp->port_info;
Packit 13e616
Packit 13e616
		if (mtu > ib_port_info_get_mtu_cap(p_pi))
Packit 13e616
			mtu = ib_port_info_get_mtu_cap(p_pi);
Packit 13e616
Packit 13e616
		p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
Packit 13e616
		if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
Packit 13e616
			rate = p0_extended_rate;
Packit 13e616
Packit 13e616
		if (sa->p_subn->opt.qos) {
Packit 13e616
			/*
Packit 13e616
			 * Check SL2VL table of the switch and update valid SLs
Packit 13e616
			 */
Packit 13e616
			p_slvl_tbl =
Packit 13e616
			    osm_physp_get_slvl_tbl(p_physp, in_port_num);
Packit 13e616
			for (i = 0; i < IB_MAX_NUM_VLS; i++) {
Packit 13e616
				if (valid_sl_mask & (1 << i) &&
Packit 13e616
				    ib_slvl_table_get(p_slvl_tbl,
Packit 13e616
						      i) == IB_DROP_VL)
Packit 13e616
					valid_sl_mask &= ~(1 << i);
Packit 13e616
			}
Packit 13e616
			if (!valid_sl_mask) {
Packit 13e616
				OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
					"All the SLs lead to VL15 "
Packit 13e616
					"on this path\n");
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   p_physp now points to the destination
Packit 13e616
	 */
Packit 13e616
	p_pi = &p_physp->port_info;
Packit 13e616
Packit 13e616
	if (mtu > ib_port_info_get_mtu_cap(p_pi))
Packit 13e616
		mtu = ib_port_info_get_mtu_cap(p_pi);
Packit 13e616
Packit 13e616
	extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
Packit 13e616
	dest_rate = ib_port_info_compute_rate(p_pi, extended);
Packit 13e616
	if (ib_path_compare_rates(rate, dest_rate) > 0)
Packit 13e616
		rate = dest_rate;
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Path min MTU = %u, min rate = %u\n", mtu, rate);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * Get QoS Level object according to the MultiPath request
Packit 13e616
	 * and adjust MultiPath parameters according to QoS settings
Packit 13e616
	 */
Packit 13e616
	if (sa->p_subn->opt.qos && sa->p_subn->p_qos_policy &&
Packit 13e616
	    (p_qos_level =
Packit 13e616
	     osm_qos_policy_get_qos_level_by_mpr(sa->p_subn->p_qos_policy,
Packit 13e616
						 p_mpr, p_src_physp,
Packit 13e616
						 p_dest_physp, comp_mask))) {
Packit 13e616
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"MultiPathRecord request matches QoS Level '%s' (%s)\n",
Packit 13e616
			p_qos_level->name,
Packit 13e616
			p_qos_level->use ? p_qos_level->use : "no description");
Packit 13e616
Packit 13e616
		if (p_qos_level->mtu_limit_set
Packit 13e616
		    && (mtu > p_qos_level->mtu_limit))
Packit 13e616
			mtu = p_qos_level->mtu_limit;
Packit 13e616
Packit 13e616
		if (p_qos_level->rate_limit_set
Packit 13e616
		    && (ib_path_compare_rates(rate, p_qos_level->rate_limit) > 0))
Packit 13e616
			rate = p_qos_level->rate_limit;
Packit 13e616
Packit 13e616
		if (p_qos_level->sl_set) {
Packit 13e616
			required_sl = p_qos_level->sl;
Packit 13e616
			if (!(valid_sl_mask & (1 << required_sl))) {
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Determine if these values meet the user criteria
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	/* we silently ignore cases where only the MTU selector is defined */
Packit 13e616
	if ((comp_mask & IB_MPR_COMPMASK_MTUSELEC) &&
Packit 13e616
	    (comp_mask & IB_MPR_COMPMASK_MTU)) {
Packit 13e616
		required_mtu = ib_multipath_rec_mtu(p_mpr);
Packit 13e616
		switch (ib_multipath_rec_mtu_sel(p_mpr)) {
Packit 13e616
		case 0:	/* must be greater than */
Packit 13e616
			if (mtu <= required_mtu)
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 1:	/* must be less than */
Packit 13e616
			if (mtu >= required_mtu) {
Packit 13e616
				/* adjust to use the highest mtu
Packit 13e616
				   lower then the required one */
Packit 13e616
				if (required_mtu > 1)
Packit 13e616
					mtu = required_mtu - 1;
Packit 13e616
				else
Packit 13e616
					status = IB_NOT_FOUND;
Packit 13e616
			}
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 2:	/* exact match */
Packit 13e616
			if (mtu < required_mtu)
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
			else
Packit 13e616
				mtu = required_mtu;
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 3:	/* largest available */
Packit 13e616
			/* can't be disqualified by this one */
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		default:
Packit 13e616
			/* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */
Packit 13e616
			CL_ASSERT(FALSE);
Packit 13e616
			status = IB_ERROR;
Packit 13e616
			break;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	if (status != IB_SUCCESS)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	/* we silently ignore cases where only the Rate selector is defined */
Packit 13e616
	if ((comp_mask & IB_MPR_COMPMASK_RATESELEC) &&
Packit 13e616
	    (comp_mask & IB_MPR_COMPMASK_RATE)) {
Packit 13e616
		required_rate = ib_multipath_rec_rate(p_mpr);
Packit 13e616
		switch (ib_multipath_rec_rate_sel(p_mpr)) {
Packit 13e616
		case 0:	/* must be greater than */
Packit 13e616
			if (ib_path_compare_rates(rate, required_rate) <= 0)
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 1:	/* must be less than */
Packit 13e616
			if (ib_path_compare_rates(rate, required_rate) >= 0) {
Packit 13e616
				/* adjust the rate to use the highest rate
Packit 13e616
				   lower then the required one */
Packit 13e616
				rate = ib_path_rate_get_prev(required_rate);
Packit 13e616
				if (!rate)
Packit 13e616
					status = IB_NOT_FOUND;
Packit 13e616
			}
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 2:	/* exact match */
Packit 13e616
			if (ib_path_compare_rates(rate, required_rate))
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
			else
Packit 13e616
				rate = required_rate;
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 3:	/* largest available */
Packit 13e616
			/* can't be disqualified by this one */
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		default:
Packit 13e616
			/* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */
Packit 13e616
			CL_ASSERT(FALSE);
Packit 13e616
			status = IB_ERROR;
Packit 13e616
			break;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	if (status != IB_SUCCESS)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	/* Verify the pkt_life_time */
Packit 13e616
	/* According to spec definition IBA 1.2 Table 205 PacketLifeTime description,
Packit 13e616
	   for loopback paths, packetLifeTime shall be zero. */
Packit 13e616
	if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
Packit 13e616
		pkt_life = 0;	/* loopback */
Packit 13e616
	else if (p_qos_level && p_qos_level->pkt_life_set)
Packit 13e616
		pkt_life = p_qos_level->pkt_life;
Packit 13e616
	else
Packit 13e616
		pkt_life = sa->p_subn->opt.subnet_timeout;
Packit 13e616
Packit 13e616
	/* we silently ignore cases where only the PktLife selector is defined */
Packit 13e616
	if ((comp_mask & IB_MPR_COMPMASK_PKTLIFETIMESELEC) &&
Packit 13e616
	    (comp_mask & IB_MPR_COMPMASK_PKTLIFETIME)) {
Packit 13e616
		required_pkt_life = ib_multipath_rec_pkt_life(p_mpr);
Packit 13e616
		switch (ib_multipath_rec_pkt_life_sel(p_mpr)) {
Packit 13e616
		case 0:	/* must be greater than */
Packit 13e616
			if (pkt_life <= required_pkt_life)
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 1:	/* must be less than */
Packit 13e616
			if (pkt_life >= required_pkt_life) {
Packit 13e616
				/* adjust the lifetime to use the highest possible
Packit 13e616
				   lower then the required one */
Packit 13e616
				if (required_pkt_life > 1)
Packit 13e616
					pkt_life = required_pkt_life - 1;
Packit 13e616
				else
Packit 13e616
					status = IB_NOT_FOUND;
Packit 13e616
			}
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 2:	/* exact match */
Packit 13e616
			if (pkt_life < required_pkt_life)
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
			else
Packit 13e616
				pkt_life = required_pkt_life;
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 3:	/* smallest available */
Packit 13e616
			/* can't be disqualified by this one */
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		default:
Packit 13e616
			/* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */
Packit 13e616
			CL_ASSERT(FALSE);
Packit 13e616
			status = IB_ERROR;
Packit 13e616
			break;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (status != IB_SUCCESS)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * set Pkey for this MultiPath record request
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	if (comp_mask & IB_MPR_COMPMASK_RAWTRAFFIC &&
Packit 13e616
	    cl_ntoh32(p_mpr->hop_flow_raw) & (1 << 31))
Packit 13e616
		required_pkey =
Packit 13e616
		    osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
Packit 13e616
					       sa->p_subn->opt.allow_both_pkeys);
Packit 13e616
Packit 13e616
	else if (comp_mask & IB_MPR_COMPMASK_PKEY) {
Packit 13e616
		/*
Packit 13e616
		 * MPR request has a specific pkey:
Packit 13e616
		 * Check that source and destination share this pkey.
Packit 13e616
		 * If QoS level has pkeys, check that this pkey exists
Packit 13e616
		 * in the QoS level pkeys.
Packit 13e616
		 * MPR returned pkey is the requested pkey.
Packit 13e616
		 */
Packit 13e616
		required_pkey = p_mpr->pkey;
Packit 13e616
		if (!osm_physp_share_this_pkey
Packit 13e616
		    (p_src_physp, p_dest_physp, required_pkey,
Packit 13e616
		     sa->p_subn->opt.allow_both_pkeys)) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4518: "
Packit 13e616
				"Ports src 0x%016"PRIx64" (%s port %d) "
Packit 13e616
				"and dst 0x%016"PRIx64" (%s port %d) "
Packit 13e616
				"do not share the specified PKey 0x%04x\n",
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
Packit 13e616
				p_src_physp->p_node->print_desc,
Packit 13e616
				p_src_physp->port_num,
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid
Packit 13e616
					  (p_dest_physp)),
Packit 13e616
				p_dest_physp->p_node->print_desc,
Packit 13e616
				p_dest_physp->port_num,
Packit 13e616
				cl_ntoh16(required_pkey));
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
		if (p_qos_level && p_qos_level->pkey_range_len &&
Packit 13e616
		    !osm_qos_level_has_pkey(p_qos_level, required_pkey)) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451C: "
Packit 13e616
				"Ports src 0x%016"PRIx64" (%s port %d) "
Packit 13e616
				"and dst 0x%016"PRIx64" (%s port %d) "
Packit 13e616
				"do not share specified PKey (0x%04x) as "
Packit 13e616
				"defined by QoS level \"%s\"\n",
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
Packit 13e616
				p_src_physp->p_node->print_desc,
Packit 13e616
				p_src_physp->port_num,
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid
Packit 13e616
					  (p_dest_physp)),
Packit 13e616
				p_dest_physp->p_node->print_desc,
Packit 13e616
				p_dest_physp->port_num,
Packit 13e616
				cl_ntoh16(required_pkey),
Packit 13e616
				p_qos_level->name);
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
	} else if (p_qos_level && p_qos_level->pkey_range_len) {
Packit 13e616
		/*
Packit 13e616
		 * MPR request doesn't have a specific pkey, but QoS level
Packit 13e616
		 * has pkeys - get shared pkey from QoS level pkeys
Packit 13e616
		 */
Packit 13e616
		required_pkey = osm_qos_level_get_shared_pkey(p_qos_level,
Packit 13e616
							      p_src_physp,
Packit 13e616
							      p_dest_physp,
Packit 13e616
							      sa->p_subn->opt.allow_both_pkeys);
Packit 13e616
		if (!required_pkey) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451D: "
Packit 13e616
				"Ports src 0x%016"PRIx64" (%s port %d) "
Packit 13e616
				"and dst 0x%016"PRIx64" (%s port %d) "
Packit 13e616
				"do not share a PKey as defined by QoS "
Packit 13e616
				"level \"%s\"\n",
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
Packit 13e616
				p_src_physp->p_node->print_desc,
Packit 13e616
				p_src_physp->port_num,
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid
Packit 13e616
					  (p_dest_physp)),
Packit 13e616
				p_dest_physp->p_node->print_desc,
Packit 13e616
				p_dest_physp->port_num,
Packit 13e616
				p_qos_level->name);
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
	} else {
Packit 13e616
		/*
Packit 13e616
		 * Neither MPR request nor QoS level have pkey.
Packit 13e616
		 * Just get any shared pkey.
Packit 13e616
		 */
Packit 13e616
		required_pkey =
Packit 13e616
		    osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
Packit 13e616
					       sa->p_subn->opt.allow_both_pkeys);
Packit 13e616
		if (!required_pkey) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4519: "
Packit 13e616
				"Ports src 0x%016"PRIx64" (%s port %d) "
Packit 13e616
				"and dst 0x%016"PRIx64" (%s port %d) "
Packit 13e616
				"do not have any shared PKeys\n",
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
Packit 13e616
				p_src_physp->p_node->print_desc,
Packit 13e616
				p_src_physp->port_num,
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid
Packit 13e616
					  (p_dest_physp)),
Packit 13e616
				p_dest_physp->p_node->print_desc,
Packit 13e616
				p_dest_physp->port_num);
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (required_pkey) {
Packit 13e616
		p_prtn =
Packit 13e616
		    (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl,
Packit 13e616
					       required_pkey &
Packit 13e616
					       cl_ntoh16((uint16_t) ~ 0x8000));
Packit 13e616
		if (p_prtn ==
Packit 13e616
		    (osm_prtn_t *) cl_qmap_end(&sa->p_subn->prtn_pkey_tbl))
Packit 13e616
			p_prtn = NULL;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * Set MultiPathRecord SL.
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	if (comp_mask & IB_MPR_COMPMASK_SL) {
Packit 13e616
		/*
Packit 13e616
		 * Specific SL was requested
Packit 13e616
		 */
Packit 13e616
		required_sl = ib_multipath_rec_sl(p_mpr);
Packit 13e616
Packit 13e616
		if (p_qos_level && p_qos_level->sl_set &&
Packit 13e616
		    p_qos_level->sl != required_sl) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451E: "
Packit 13e616
				"QoS constraints: required MultiPathRecord SL "
Packit 13e616
				"(%u) doesn't match QoS policy \"%s\" SL (%u) "
Packit 13e616
				"[%s port %d <-> %s port %d]\n", required_sl,
Packit 13e616
				p_qos_level->name,
Packit 13e616
				p_qos_level->sl,
Packit 13e616
				p_src_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
				p_src_alias_guid->p_base_port->p_physp->port_num,
Packit 13e616
				p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
				p_dest_alias_guid->p_base_port->p_physp->port_num);
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
	} else if (p_qos_level && p_qos_level->sl_set) {
Packit 13e616
		/*
Packit 13e616
		 * No specific SL was requested,
Packit 13e616
		 * but there is an SL in QoS level.
Packit 13e616
		 */
Packit 13e616
		required_sl = p_qos_level->sl;
Packit 13e616
Packit 13e616
		if (required_pkey && p_prtn && p_prtn->sl != p_qos_level->sl)
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"QoS level SL (%u) overrides partition SL (%u)\n",
Packit 13e616
				p_qos_level->sl, p_prtn->sl);
Packit 13e616
Packit 13e616
	} else if (required_pkey) {
Packit 13e616
		/*
Packit 13e616
		 * No specific SL in request or in QoS level - use partition SL
Packit 13e616
		 */
Packit 13e616
		p_prtn =
Packit 13e616
		    (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl,
Packit 13e616
					       required_pkey &
Packit 13e616
					       cl_ntoh16((uint16_t) ~ 0x8000));
Packit 13e616
		if (!p_prtn) {
Packit 13e616
			required_sl = OSM_DEFAULT_SL;
Packit 13e616
			/* this may be possible when pkey tables are created somehow in
Packit 13e616
			   previous runs or things are going wrong here */
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451A: "
Packit 13e616
				"No partition found for PKey 0x%04x - "
Packit 13e616
				"using default SL %d "
Packit 13e616
				"[%s port %d <-> %s port %d]\n",
Packit 13e616
				cl_ntoh16(required_pkey), required_sl,
Packit 13e616
				p_src_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
				p_src_alias_guid->p_base_port->p_physp->port_num,
Packit 13e616
				p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
				p_dest_alias_guid->p_base_port->p_physp->port_num);
Packit 13e616
		} else
Packit 13e616
			required_sl = p_prtn->sl;
Packit 13e616
Packit 13e616
	} else if (sa->p_subn->opt.qos) {
Packit 13e616
		if (valid_sl_mask & (1 << OSM_DEFAULT_SL))
Packit 13e616
			required_sl = OSM_DEFAULT_SL;
Packit 13e616
		else {
Packit 13e616
			for (i = 0; i < IB_MAX_NUM_VLS; i++)
Packit 13e616
				if (valid_sl_mask & (1 << i))
Packit 13e616
					break;
Packit 13e616
			required_sl = i;
Packit 13e616
		}
Packit 13e616
	} else
Packit 13e616
		required_sl = OSM_DEFAULT_SL;
Packit 13e616
Packit 13e616
	if (sa->p_subn->opt.qos && !(valid_sl_mask & (1 << required_sl))) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451F: "
Packit 13e616
			"Selected SL (%u) leads to VL15 "
Packit 13e616
			"[%s port %d <-> %s port %d]\n",
Packit 13e616
			required_sl,
Packit 13e616
			p_src_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
			p_src_alias_guid->p_base_port->p_physp->port_num,
Packit 13e616
			p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
			p_dest_alias_guid->p_base_port->p_physp->port_num);
Packit 13e616
		status = IB_NOT_FOUND;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* reset pkey when raw traffic */
Packit 13e616
	if (comp_mask & IB_MPR_COMPMASK_RAWTRAFFIC &&
Packit 13e616
	    cl_ntoh32(p_mpr->hop_flow_raw) & (1 << 31))
Packit 13e616
		required_pkey = 0;
Packit 13e616
Packit 13e616
	p_parms->mtu = mtu;
Packit 13e616
	p_parms->rate = rate;
Packit 13e616
	p_parms->pkey = required_pkey;
Packit 13e616
	p_parms->pkt_life = pkt_life;
Packit 13e616
	p_parms->sl = required_sl;
Packit 13e616
	p_parms->hops = hops;
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "MultiPath params:"
Packit 13e616
		" mtu = %u, rate = %u, packet lifetime = %u,"
Packit 13e616
		" pkey = 0x%04X, sl = %u, hops = %u\n", mtu, rate,
Packit 13e616
		pkt_life, cl_ntoh16(required_pkey), required_sl, hops);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
	return status;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void mpr_rcv_build_pr(IN osm_sa_t * sa,
Packit 13e616
			     IN const osm_alias_guid_t * p_src_alias_guid,
Packit 13e616
			     IN const osm_alias_guid_t * p_dest_alias_guid,
Packit 13e616
			     IN uint16_t src_lid_ho, IN uint16_t dest_lid_ho,
Packit 13e616
			     IN uint8_t preference,
Packit 13e616
			     IN const osm_path_parms_t * p_parms,
Packit 13e616
			     OUT ib_path_rec_t * p_pr)
Packit 13e616
{
Packit 13e616
	const osm_physp_t *p_src_physp, *p_dest_physp;
Packit 13e616
	uint8_t rate, new_rate;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	p_src_physp = p_src_alias_guid->p_base_port->p_physp;
Packit 13e616
	p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
Packit 13e616
Packit 13e616
	p_pr->dgid.unicast.prefix = osm_physp_get_subnet_prefix(p_dest_physp);
Packit 13e616
	p_pr->dgid.unicast.interface_id = p_dest_alias_guid->alias_guid;
Packit 13e616
Packit 13e616
	p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix(p_src_physp);
Packit 13e616
	p_pr->sgid.unicast.interface_id = p_src_alias_guid->alias_guid;
Packit 13e616
Packit 13e616
	p_pr->dlid = cl_hton16(dest_lid_ho);
Packit 13e616
	p_pr->slid = cl_hton16(src_lid_ho);
Packit 13e616
Packit 13e616
	p_pr->hop_flow_raw &= cl_hton32(1 << 31);
Packit 13e616
Packit 13e616
	p_pr->pkey = p_parms->pkey;
Packit 13e616
	ib_path_rec_set_qos_class(p_pr, 0);
Packit 13e616
	ib_path_rec_set_sl(p_pr, p_parms->sl);
Packit 13e616
	p_pr->mtu = (uint8_t) (p_parms->mtu | 0x80);
Packit 13e616
	rate = p_parms->rate;
Packit 13e616
	if (sa->p_subn->opt.use_original_extended_sa_rates_only) {
Packit 13e616
		new_rate = ib_path_rate_max_12xedr(rate);
Packit 13e616
		if (new_rate != rate) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit 13e616
				"Rate decreased from %u to %u\n",
Packit 13e616
				rate, new_rate);
Packit 13e616
			rate = new_rate;
Packit 13e616
		}
Packit 13e616
	} else if (rate >= IB_PATH_RECORD_RATE_28_GBS) {
Packit 13e616
		/*
Packit 13e616
		 * If one of the new 2x or HDR rates, make sure that
Packit 13e616
		 * src (and dest if reversible) ports support this
Packit 13e616
		 */
Packit 13e616
		rate = ib_path_rate_2x_hdr_fixups(&p_src_physp->port_info, rate);
Packit 13e616
		if (p_parms->reversible)
Packit 13e616
			 rate = ib_path_rate_2x_hdr_fixups(&p_dest_physp->port_info, rate);
Packit 13e616
	}
Packit 13e616
	p_pr->rate = (uint8_t) (rate | 0x80);
Packit 13e616
Packit 13e616
	/* According to 1.2 spec definition Table 205 PacketLifeTime description,
Packit 13e616
	   for loopback paths, packetLifeTime shall be zero. */
Packit 13e616
	if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
Packit 13e616
		p_pr->pkt_life = 0x80;	/* loopback */
Packit 13e616
	else
Packit 13e616
		p_pr->pkt_life = (uint8_t) (p_parms->pkt_life | 0x80);
Packit 13e616
Packit 13e616
	p_pr->preference = preference;
Packit 13e616
Packit 13e616
	/* always return num_path = 0 so this is only the reversible component */
Packit 13e616
	if (p_parms->reversible)
Packit 13e616
		p_pr->num_path = 0x80;
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static osm_sa_item_t *mpr_rcv_get_lid_pair_path(IN osm_sa_t * sa,
Packit 13e616
						IN const ib_multipath_rec_t *
Packit 13e616
						p_mpr,
Packit 13e616
						IN const osm_alias_guid_t *
Packit 13e616
						p_src_alias_guid,
Packit 13e616
						IN const osm_alias_guid_t *
Packit 13e616
						p_dest_alias_guid,
Packit 13e616
						IN const uint16_t src_lid_ho,
Packit 13e616
						IN const uint16_t dest_lid_ho,
Packit 13e616
						IN const ib_net64_t comp_mask,
Packit 13e616
						IN const uint8_t preference)
Packit 13e616
{
Packit 13e616
	osm_path_parms_t path_parms;
Packit 13e616
	osm_path_parms_t rev_path_parms;
Packit 13e616
	osm_sa_item_t *p_pr_item;
Packit 13e616
	ib_api_status_t status, rev_path_status;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID %u, Dest LID %u\n",
Packit 13e616
		src_lid_ho, dest_lid_ho);
Packit 13e616
Packit 13e616
	p_pr_item = malloc(SA_MPR_RESP_SIZE);
Packit 13e616
	if (p_pr_item == NULL) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4501: "
Packit 13e616
			"Unable to allocate path record\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
	memset(p_pr_item, 0, SA_MPR_RESP_SIZE);
Packit 13e616
Packit 13e616
	status = mpr_rcv_get_path_parms(sa, p_mpr, p_src_alias_guid,
Packit 13e616
					p_dest_alias_guid,
Packit 13e616
					src_lid_ho, dest_lid_ho,
Packit 13e616
					comp_mask, &path_parms);
Packit 13e616
Packit 13e616
	if (status != IB_SUCCESS) {
Packit 13e616
		free(p_pr_item);
Packit 13e616
		p_pr_item = NULL;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* now try the reversible path */
Packit 13e616
	rev_path_status = mpr_rcv_get_path_parms(sa, p_mpr, p_dest_alias_guid,
Packit 13e616
						 p_src_alias_guid,
Packit 13e616
						 dest_lid_ho, src_lid_ho,
Packit 13e616
						 comp_mask, &rev_path_parms);
Packit 13e616
	path_parms.reversible = (rev_path_status == IB_SUCCESS);
Packit 13e616
Packit 13e616
	/* did we get a Reversible Path compmask ? */
Packit 13e616
	/*
Packit 13e616
	   NOTE that if the reversible component = 0, it is a don't care
Packit 13e616
	   rather then requiring non-reversible paths ...
Packit 13e616
	   see Vol1 Ver1.2 p900 l16
Packit 13e616
	 */
Packit 13e616
	if (comp_mask & IB_MPR_COMPMASK_REVERSIBLE) {
Packit 13e616
		if ((!path_parms.reversible && (p_mpr->num_path & 0x80))) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Requested reversible path but failed to get one\n");
Packit 13e616
Packit 13e616
			free(p_pr_item);
Packit 13e616
			p_pr_item = NULL;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_pr_item->resp.mpr_rec.p_src_port = p_src_alias_guid->p_base_port;
Packit 13e616
	p_pr_item->resp.mpr_rec.p_dest_port = p_dest_alias_guid->p_base_port;
Packit 13e616
	p_pr_item->resp.mpr_rec.hops = path_parms.hops;
Packit 13e616
Packit 13e616
	mpr_rcv_build_pr(sa, p_src_alias_guid, p_dest_alias_guid, src_lid_ho,
Packit 13e616
			 dest_lid_ho, preference, &path_parms,
Packit 13e616
			 &p_pr_item->resp.mpr_rec.path_rec);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
	return p_pr_item;
Packit 13e616
}
Packit 13e616
Packit 13e616
static uint32_t mpr_rcv_get_port_pair_paths(IN osm_sa_t * sa,
Packit 13e616
					    IN const ib_multipath_rec_t * p_mpr,
Packit 13e616
					    IN const osm_port_t * p_req_port,
Packit 13e616
					    IN const osm_alias_guid_t * p_src_alias_guid,
Packit 13e616
					    IN const osm_alias_guid_t * p_dest_alias_guid,
Packit 13e616
					    IN const uint32_t rem_paths,
Packit 13e616
					    IN const ib_net64_t comp_mask,
Packit 13e616
					    IN cl_qlist_t * p_list)
Packit 13e616
{
Packit 13e616
	osm_sa_item_t *p_pr_item;
Packit 13e616
	uint16_t src_lid_min_ho;
Packit 13e616
	uint16_t src_lid_max_ho;
Packit 13e616
	uint16_t dest_lid_min_ho;
Packit 13e616
	uint16_t dest_lid_max_ho;
Packit 13e616
	uint16_t src_lid_ho;
Packit 13e616
	uint16_t dest_lid_ho;
Packit 13e616
	uint32_t path_num = 0;
Packit 13e616
	uint8_t preference;
Packit 13e616
	unsigned src_offset, dest_offset;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Src port 0x%016" PRIx64 ", Dst port 0x%016" PRIx64 "\n",
Packit 13e616
		cl_ntoh64(p_src_alias_guid->alias_guid),
Packit 13e616
		cl_ntoh64(p_dest_alias_guid->alias_guid));
Packit 13e616
Packit 13e616
	/* Check that the req_port, src_port and dest_port all share a
Packit 13e616
	   pkey. The check is done on the default physical port of the ports. */
Packit 13e616
	if (osm_port_share_pkey(sa->p_log, p_req_port,
Packit 13e616
				p_src_alias_guid->p_base_port,
Packit 13e616
				sa->p_subn->opt.allow_both_pkeys) == FALSE
Packit 13e616
	    || osm_port_share_pkey(sa->p_log, p_req_port,
Packit 13e616
				   p_dest_alias_guid->p_base_port,
Packit 13e616
				   sa->p_subn->opt.allow_both_pkeys) == FALSE
Packit 13e616
	    || osm_port_share_pkey(sa->p_log, p_src_alias_guid->p_base_port,
Packit 13e616
				   p_dest_alias_guid->p_base_port,
Packit 13e616
				   sa->p_subn->opt.allow_both_pkeys) == FALSE)
Packit 13e616
		/* One of the pairs doesn't share a pkey so the path is disqualified. */
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   We shouldn't be here if the paths are disqualified in some way...
Packit 13e616
	   Thus, we assume every possible connection is valid.
Packit 13e616
Packit 13e616
	   We desire to return high-quality paths first.
Packit 13e616
	   In OpenSM, higher quality mean least overlap with other paths.
Packit 13e616
	   This is acheived in practice by returning paths with
Packit 13e616
	   different LID value on each end, which means these
Packit 13e616
	   paths are more redundant that paths with the same LID repeated
Packit 13e616
	   on one side.  For example, in OpenSM the paths between two
Packit 13e616
	   endpoints with LMC = 1 might be as follows:
Packit 13e616
Packit 13e616
	   Port A, LID 1 <-> Port B, LID 3
Packit 13e616
	   Port A, LID 1 <-> Port B, LID 4
Packit 13e616
	   Port A, LID 2 <-> Port B, LID 3
Packit 13e616
	   Port A, LID 2 <-> Port B, LID 4
Packit 13e616
Packit 13e616
	   The OpenSM unicast routing algorithms attempt to disperse each path
Packit 13e616
	   to as varied a physical path as is reasonable.  1<->3 and 1<->4 have
Packit 13e616
	   more physical overlap (hence less redundancy) than 1<->3 and 2<->4.
Packit 13e616
Packit 13e616
	   OpenSM ranks paths in three preference groups:
Packit 13e616
Packit 13e616
	   Preference Value           Description
Packit 13e616
	   ----------------           -------------------------------------------
Packit 13e616
	   0                  Redundant in both directions with other
Packit 13e616
	   pref value = 0 paths
Packit 13e616
Packit 13e616
	   1                  Redundant in one direction with other
Packit 13e616
	   pref value = 0 and pref value = 1 paths
Packit 13e616
Packit 13e616
	   2                  Not redundant in either direction with
Packit 13e616
	   other paths
Packit 13e616
Packit 13e616
	   3-FF                       Unused
Packit 13e616
Packit 13e616
	   SA clients don't need to know these details, only that the lower
Packit 13e616
	   preference paths are preferred, as stated in the spec.  The paths
Packit 13e616
	   may not actually be physically redundant depending on the topology
Packit 13e616
	   of the subnet, but the point of LMC > 0 is to offer redundancy,
Packit 13e616
	   so I assume the subnet is physically appropriate for the specified
Packit 13e616
	   LMC value.  A more advanced implementation could inspect for physical
Packit 13e616
	   redundancy, but I'm not going to bother with that now.
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	osm_port_get_lid_range_ho(p_src_alias_guid->p_base_port,
Packit 13e616
				  &src_lid_min_ho, &src_lid_max_ho);
Packit 13e616
	osm_port_get_lid_range_ho(p_dest_alias_guid->p_base_port,
Packit 13e616
				  &dest_lid_min_ho, &dest_lid_max_ho);
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID [%u-%u], Dest LID [%u-%u]\n",
Packit 13e616
		src_lid_min_ho, src_lid_max_ho,
Packit 13e616
		dest_lid_min_ho, dest_lid_max_ho);
Packit 13e616
Packit 13e616
	src_lid_ho = src_lid_min_ho;
Packit 13e616
	dest_lid_ho = dest_lid_min_ho;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Preferred paths come first in OpenSM
Packit 13e616
	 */
Packit 13e616
	preference = 0;
Packit 13e616
Packit 13e616
	while (path_num < rem_paths) {
Packit 13e616
		/*
Packit 13e616
		   These paths are "fully redundant"
Packit 13e616
		 */
Packit 13e616
		p_pr_item = mpr_rcv_get_lid_pair_path(sa, p_mpr,
Packit 13e616
						      p_src_alias_guid,
Packit 13e616
						      p_dest_alias_guid,
Packit 13e616
						      src_lid_ho, dest_lid_ho,
Packit 13e616
						      comp_mask, preference);
Packit 13e616
Packit 13e616
		if (p_pr_item) {
Packit 13e616
			cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
Packit 13e616
			++path_num;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if (++src_lid_ho > src_lid_max_ho)
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		if (++dest_lid_ho > dest_lid_max_ho)
Packit 13e616
			break;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Check if we've accumulated all the paths that the user cares to see
Packit 13e616
	 */
Packit 13e616
	if (path_num == rem_paths)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Don't bother reporting preference 1 paths for now.
Packit 13e616
	   It's more trouble than it's worth and can only occur
Packit 13e616
	   if ports have different LMC values, which isn't supported
Packit 13e616
	   by OpenSM right now anyway.
Packit 13e616
	 */
Packit 13e616
	preference = 2;
Packit 13e616
	src_lid_ho = src_lid_min_ho;
Packit 13e616
	dest_lid_ho = dest_lid_min_ho;
Packit 13e616
	src_offset = 0;
Packit 13e616
	dest_offset = 0;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Iterate over the remaining paths
Packit 13e616
	 */
Packit 13e616
	while (path_num < rem_paths) {
Packit 13e616
		dest_offset++;
Packit 13e616
		dest_lid_ho++;
Packit 13e616
Packit 13e616
		if (dest_lid_ho > dest_lid_max_ho) {
Packit 13e616
			src_offset++;
Packit 13e616
			src_lid_ho++;
Packit 13e616
Packit 13e616
			if (src_lid_ho > src_lid_max_ho)
Packit 13e616
				break;	/* done */
Packit 13e616
Packit 13e616
			dest_offset = 0;
Packit 13e616
			dest_lid_ho = dest_lid_min_ho;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   These paths are "fully non-redundant" with paths already
Packit 13e616
		   identified above and consequently not of much value.
Packit 13e616
Packit 13e616
		   Don't return paths we already identified above, as indicated
Packit 13e616
		   by the offset values being equal.
Packit 13e616
		 */
Packit 13e616
		if (src_offset == dest_offset)
Packit 13e616
			continue;	/* already reported */
Packit 13e616
Packit 13e616
		p_pr_item = mpr_rcv_get_lid_pair_path(sa, p_mpr,
Packit 13e616
						      p_src_alias_guid,
Packit 13e616
						      p_dest_alias_guid,
Packit 13e616
						      src_lid_ho, dest_lid_ho,
Packit 13e616
						      comp_mask, preference);
Packit 13e616
Packit 13e616
		if (p_pr_item) {
Packit 13e616
			cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
Packit 13e616
			++path_num;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
	return path_num;
Packit 13e616
}
Packit 13e616
Packit 13e616
#undef min
Packit 13e616
#define min(x,y)	(((x) < (y)) ? (x) : (y))
Packit 13e616
Packit 13e616
static osm_sa_item_t *mpr_rcv_get_apm_port_pair_paths(IN osm_sa_t * sa,
Packit 13e616
						      IN const
Packit 13e616
						      ib_multipath_rec_t *
Packit 13e616
						      p_mpr,
Packit 13e616
						      IN const osm_alias_guid_t *
Packit 13e616
						      p_src_alias_guid,
Packit 13e616
						      IN const osm_alias_guid_t *
Packit 13e616
						      p_dest_alias_guid,
Packit 13e616
						      IN int base_offs,
Packit 13e616
						      IN const ib_net64_t
Packit 13e616
						      comp_mask,
Packit 13e616
						      IN cl_qlist_t * p_list)
Packit 13e616
{
Packit 13e616
	osm_sa_item_t *p_pr_item = 0;
Packit 13e616
	uint16_t src_lid_min_ho;
Packit 13e616
	uint16_t src_lid_max_ho;
Packit 13e616
	uint16_t dest_lid_min_ho;
Packit 13e616
	uint16_t dest_lid_max_ho;
Packit 13e616
	uint16_t src_lid_ho;
Packit 13e616
	uint16_t dest_lid_ho;
Packit 13e616
	unsigned iterations;
Packit 13e616
	int src_lids, dest_lids;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src port 0x%016" PRIx64 ", "
Packit 13e616
		"Dst port 0x%016" PRIx64 ", base offs %d\n",
Packit 13e616
		cl_ntoh64(p_src_alias_guid->alias_guid),
Packit 13e616
		cl_ntoh64(p_dest_alias_guid->alias_guid),
Packit 13e616
		base_offs);
Packit 13e616
Packit 13e616
	osm_port_get_lid_range_ho(p_src_alias_guid->p_base_port,
Packit 13e616
				  &src_lid_min_ho, &src_lid_max_ho);
Packit 13e616
	osm_port_get_lid_range_ho(p_dest_alias_guid->p_base_port,
Packit 13e616
				  &dest_lid_min_ho, &dest_lid_max_ho);
Packit 13e616
Packit 13e616
	src_lid_ho = src_lid_min_ho;
Packit 13e616
	dest_lid_ho = dest_lid_min_ho;
Packit 13e616
Packit 13e616
	src_lids = src_lid_max_ho - src_lid_min_ho + 1;
Packit 13e616
	dest_lids = dest_lid_max_ho - dest_lid_min_ho + 1;
Packit 13e616
Packit 13e616
	src_lid_ho += base_offs % src_lids;
Packit 13e616
	dest_lid_ho += base_offs % dest_lids;
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Src LIDs [%u-%u] hashed %u, "
Packit 13e616
		"Dest LIDs [%u-%u] hashed %u\n",
Packit 13e616
		src_lid_min_ho, src_lid_max_ho, src_lid_ho,
Packit 13e616
		dest_lid_min_ho, dest_lid_max_ho, dest_lid_ho);
Packit 13e616
Packit 13e616
	iterations = min(src_lids, dest_lids);
Packit 13e616
Packit 13e616
	while (iterations--) {
Packit 13e616
		/*
Packit 13e616
		   These paths are "fully redundant"
Packit 13e616
		 */
Packit 13e616
		p_pr_item = mpr_rcv_get_lid_pair_path(sa, p_mpr,
Packit 13e616
						      p_src_alias_guid,
Packit 13e616
						      p_dest_alias_guid,
Packit 13e616
						      src_lid_ho, dest_lid_ho,
Packit 13e616
						      comp_mask, 0);
Packit 13e616
Packit 13e616
		if (p_pr_item) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Found matching path from Src LID %u to Dest LID %u with %d hops\n",
Packit 13e616
				src_lid_ho, dest_lid_ho, p_pr_item->resp.mpr_rec.hops);
Packit 13e616
			break;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if (++src_lid_ho > src_lid_max_ho)
Packit 13e616
			src_lid_ho = src_lid_min_ho;
Packit 13e616
Packit 13e616
		if (++dest_lid_ho > dest_lid_max_ho)
Packit 13e616
			dest_lid_ho = dest_lid_min_ho;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
	return p_pr_item;
Packit 13e616
}
Packit 13e616
Packit 13e616
static ib_net16_t mpr_rcv_get_gids(IN osm_sa_t * sa, IN const ib_gid_t * gids,
Packit 13e616
				   IN int ngids, IN int is_sgid,
Packit 13e616
				   OUT osm_alias_guid_t ** pp_alias_guid)
Packit 13e616
{
Packit 13e616
	osm_alias_guid_t *p_alias_guid;
Packit 13e616
	ib_net16_t ib_status = IB_SUCCESS;
Packit 13e616
	int i;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	for (i = 0; i < ngids; i++, gids++) {
Packit 13e616
		if (!ib_gid_is_link_local(gids)) {
Packit 13e616
			if ((is_sgid && ib_gid_is_multicast(gids)) ||
Packit 13e616
			    (ib_gid_get_subnet_prefix(gids) !=
Packit 13e616
			     sa->p_subn->opt.subnet_prefix)) {
Packit 13e616
				/*
Packit 13e616
				   This 'error' is the client's fault (bad gid)
Packit 13e616
				   so don't enter it as an error in our own log.
Packit 13e616
				   Return an error response to the client.
Packit 13e616
				 */
Packit 13e616
				OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "ERR 451B: "
Packit 13e616
					"%sGID 0x%016" PRIx64
Packit 13e616
					" is multicast or non local subnet prefix\n",
Packit 13e616
					is_sgid ? "S" : "D",
Packit 13e616
					cl_ntoh64(gids->unicast.prefix));
Packit 13e616
Packit 13e616
				ib_status = IB_SA_MAD_STATUS_INVALID_GID;
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
Packit 13e616
		p_alias_guid =
Packit 13e616
		    osm_get_alias_guid_by_guid(sa->p_subn,
Packit 13e616
					       gids->unicast.interface_id);
Packit 13e616
		if (!p_alias_guid) {
Packit 13e616
			/*
Packit 13e616
			   This 'error' is the client's fault (bad gid) so
Packit 13e616
			   don't enter it as an error in our own log.
Packit 13e616
			   Return an error response to the client.
Packit 13e616
			 */
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4506: "
Packit 13e616
				"No port with GUID 0x%016" PRIx64 "\n",
Packit 13e616
				cl_ntoh64(gids->unicast.interface_id));
Packit 13e616
Packit 13e616
			ib_status = IB_SA_MAD_STATUS_INVALID_GID;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		pp_alias_guid[i] = p_alias_guid;
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
Packit 13e616
	return ib_status;
Packit 13e616
}
Packit 13e616
Packit 13e616
static ib_net16_t mpr_rcv_get_end_points(IN osm_sa_t * sa,
Packit 13e616
					 IN const osm_madw_t * p_madw,
Packit 13e616
					 OUT osm_alias_guid_t ** pp_alias_guids,
Packit 13e616
					 OUT int *nsrc, OUT int *ndest)
Packit 13e616
{
Packit 13e616
	const ib_multipath_rec_t *p_mpr;
Packit 13e616
	const ib_sa_mad_t *p_sa_mad;
Packit 13e616
	ib_net64_t comp_mask;
Packit 13e616
	ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
Packit 13e616
	ib_gid_t *gids;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Determine what fields are valid and then get a pointer
Packit 13e616
	   to the source and destination port objects, if possible.
Packit 13e616
	 */
Packit 13e616
	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
Packit 13e616
	p_mpr = (ib_multipath_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
Packit 13e616
	gids = (ib_gid_t *) p_mpr->gids;
Packit 13e616
Packit 13e616
	comp_mask = p_sa_mad->comp_mask;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Check a few easy disqualifying cases up front before getting
Packit 13e616
	   into the endpoints.
Packit 13e616
	 */
Packit 13e616
	*nsrc = *ndest = 0;
Packit 13e616
Packit 13e616
	if (comp_mask & IB_MPR_COMPMASK_SGIDCOUNT) {
Packit 13e616
		*nsrc = p_mpr->sgid_count;
Packit 13e616
		if (*nsrc > IB_MULTIPATH_MAX_GIDS)
Packit 13e616
			*nsrc = IB_MULTIPATH_MAX_GIDS;
Packit 13e616
		sa_status = mpr_rcv_get_gids(sa, gids, *nsrc, 1, pp_alias_guids);
Packit 13e616
		if (sa_status != IB_SUCCESS)
Packit 13e616
			goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (comp_mask & IB_MPR_COMPMASK_DGIDCOUNT) {
Packit 13e616
		*ndest = p_mpr->dgid_count;
Packit 13e616
		if (*ndest + *nsrc > IB_MULTIPATH_MAX_GIDS)
Packit 13e616
			*ndest = IB_MULTIPATH_MAX_GIDS - *nsrc;
Packit 13e616
		sa_status =
Packit 13e616
		    mpr_rcv_get_gids(sa, gids + *nsrc, *ndest, 0,
Packit 13e616
				     pp_alias_guids + *nsrc);
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
	return sa_status;
Packit 13e616
}
Packit 13e616
Packit 13e616
#define hash_lids(a, b, lmc)	\
Packit 13e616
	(((((a) >> (lmc)) << 4) | ((b) >> (lmc))) % 103)
Packit 13e616
Packit 13e616
static void mpr_rcv_get_apm_paths(IN osm_sa_t * sa,
Packit 13e616
				  IN const ib_multipath_rec_t * p_mpr,
Packit 13e616
				  IN const osm_port_t * p_req_port,
Packit 13e616
				  IN osm_alias_guid_t ** _pp_alias_guids,
Packit 13e616
				  IN const ib_net64_t comp_mask,
Packit 13e616
				  IN cl_qlist_t * p_list)
Packit 13e616
{
Packit 13e616
	osm_alias_guid_t *pp_alias_guids[4];
Packit 13e616
	osm_sa_item_t *matrix[2][2];
Packit 13e616
	int base_offs, src_lid_ho, dest_lid_ho;
Packit 13e616
	int sumA, sumB, minA, minB;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * We want to:
Packit 13e616
	 *    1. use different lid offsets (from base) for the resultant paths
Packit 13e616
	 *    to increase the probability of redundant paths or in case
Packit 13e616
	 *    of Clos - to ensure it (different offset => different spine!)
Packit 13e616
	 *    2. keep consistent paths no matter of direction and order of ports
Packit 13e616
	 *    3. distibute the lid offsets to balance the load
Packit 13e616
	 * So, we sort the ports (within the srcs, and within the dests),
Packit 13e616
	 * hash the lids of S0, D0 (after the sort), and call mpr_rcv_get_apm_port_pair_paths
Packit 13e616
	 * with base_lid for S0, D0 and base_lid + 1 for S1, D1. This way we will get
Packit 13e616
	 * always the same offsets - order independent, and make sure different spines are used.
Packit 13e616
	 * Note that the diagonals on a Clos have the same number of hops, so it doesn't
Packit 13e616
	 * really matter which diagonal we use.
Packit 13e616
	 */
Packit 13e616
	if (_pp_alias_guids[0]->p_base_port->guid <
Packit 13e616
	    _pp_alias_guids[1]->p_base_port->guid) {
Packit 13e616
		pp_alias_guids[0] = _pp_alias_guids[0];
Packit 13e616
		pp_alias_guids[1] = _pp_alias_guids[1];
Packit 13e616
	} else {
Packit 13e616
		pp_alias_guids[0] = _pp_alias_guids[1];
Packit 13e616
		pp_alias_guids[1] = _pp_alias_guids[0];
Packit 13e616
	}
Packit 13e616
	if (_pp_alias_guids[2]->p_base_port->guid <
Packit 13e616
	    _pp_alias_guids[3]->p_base_port->guid) {
Packit 13e616
		pp_alias_guids[2] = _pp_alias_guids[2];
Packit 13e616
		pp_alias_guids[3] = _pp_alias_guids[3];
Packit 13e616
	} else {
Packit 13e616
		pp_alias_guids[2] = _pp_alias_guids[3];
Packit 13e616
		pp_alias_guids[3] = _pp_alias_guids[2];
Packit 13e616
	}
Packit 13e616
Packit 13e616
	src_lid_ho = osm_port_get_base_lid(pp_alias_guids[0]->p_base_port);
Packit 13e616
	dest_lid_ho = osm_port_get_base_lid(pp_alias_guids[2]->p_base_port);
Packit 13e616
Packit 13e616
	base_offs = src_lid_ho < dest_lid_ho ?
Packit 13e616
	    hash_lids(src_lid_ho, dest_lid_ho, sa->p_subn->opt.lmc) :
Packit 13e616
	    hash_lids(dest_lid_ho, src_lid_ho, sa->p_subn->opt.lmc);
Packit 13e616
Packit 13e616
	matrix[0][0] =
Packit 13e616
	    mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[0],
Packit 13e616
					    pp_alias_guids[2], base_offs,
Packit 13e616
					    comp_mask, p_list);
Packit 13e616
	matrix[0][1] =
Packit 13e616
	    mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[0],
Packit 13e616
					    pp_alias_guids[3], base_offs,
Packit 13e616
					    comp_mask, p_list);
Packit 13e616
	matrix[1][0] =
Packit 13e616
	    mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[1],
Packit 13e616
					    pp_alias_guids[2], base_offs + 1,
Packit 13e616
					    comp_mask, p_list);
Packit 13e616
	matrix[1][1] =
Packit 13e616
	    mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[1],
Packit 13e616
					    pp_alias_guids[3], base_offs + 1,
Packit 13e616
					    comp_mask, p_list);
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "APM matrix:\n"
Packit 13e616
		"\t{0,0} 0x%X->0x%X (%d)\t| {0,1} 0x%X->0x%X (%d)\n"
Packit 13e616
		"\t{1,0} 0x%X->0x%X (%d)\t| {1,1} 0x%X->0x%X (%d)\n",
Packit 13e616
		matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.slid : 0,
Packit 13e616
		matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.dlid : 0,
Packit 13e616
		matrix[0][0] ? matrix[0][0]->resp.mpr_rec.hops : 0,
Packit 13e616
		matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.slid : 0,
Packit 13e616
		matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.dlid : 0,
Packit 13e616
		matrix[0][1] ? matrix[0][1]->resp.mpr_rec.hops : 0,
Packit 13e616
		matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.slid : 0,
Packit 13e616
		matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.dlid : 0,
Packit 13e616
		matrix[1][0] ? matrix[1][0]->resp.mpr_rec.hops : 0,
Packit 13e616
		matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.slid : 0,
Packit 13e616
		matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.dlid : 0,
Packit 13e616
		matrix[1][1] ? matrix[1][1]->resp.mpr_rec.hops : 0);
Packit 13e616
Packit 13e616
	sumA = minA = sumB = minB = 0;
Packit 13e616
Packit 13e616
	/* check diagonal A {(0,0), (1,1)} */
Packit 13e616
	if (matrix[0][0]) {
Packit 13e616
		sumA += matrix[0][0]->resp.mpr_rec.hops;
Packit 13e616
		minA = matrix[0][0]->resp.mpr_rec.hops;
Packit 13e616
	}
Packit 13e616
	if (matrix[1][1]) {
Packit 13e616
		sumA += matrix[1][1]->resp.mpr_rec.hops;
Packit 13e616
		if (minA)
Packit 13e616
			minA = min(minA, matrix[1][1]->resp.mpr_rec.hops);
Packit 13e616
		else
Packit 13e616
			minA = matrix[1][1]->resp.mpr_rec.hops;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* check diagonal B {(0,1), (1,0)} */
Packit 13e616
	if (matrix[0][1]) {
Packit 13e616
		sumB += matrix[0][1]->resp.mpr_rec.hops;
Packit 13e616
		minB = matrix[0][1]->resp.mpr_rec.hops;
Packit 13e616
	}
Packit 13e616
	if (matrix[1][0]) {
Packit 13e616
		sumB += matrix[1][0]->resp.mpr_rec.hops;
Packit 13e616
		if (minB)
Packit 13e616
			minB = min(minB, matrix[1][0]->resp.mpr_rec.hops);
Packit 13e616
		else
Packit 13e616
			minB = matrix[1][0]->resp.mpr_rec.hops;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* and the winner is... */
Packit 13e616
	if (minA <= minB || (minA == minB && sumA < sumB)) {
Packit 13e616
		/* Diag A */
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Diag {0,0} & {1,1} is the best:\n"
Packit 13e616
			"\t{0,0} 0x%X->0x%X (%d)\t & {1,1} 0x%X->0x%X (%d)\n",
Packit 13e616
			matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.slid : 0,
Packit 13e616
			matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.dlid : 0,
Packit 13e616
			matrix[0][0] ? matrix[0][0]->resp.mpr_rec.hops : 0,
Packit 13e616
			matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.slid : 0,
Packit 13e616
			matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.dlid : 0,
Packit 13e616
			matrix[1][1] ? matrix[1][1]->resp.mpr_rec.hops : 0);
Packit 13e616
		if (matrix[0][0])
Packit 13e616
			cl_qlist_insert_tail(p_list, &matrix[0][0]->list_item);
Packit 13e616
		if (matrix[1][1])
Packit 13e616
			cl_qlist_insert_tail(p_list, &matrix[1][1]->list_item);
Packit 13e616
		free(matrix[0][1]);
Packit 13e616
		free(matrix[1][0]);
Packit 13e616
	} else {
Packit 13e616
		/* Diag B */
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Diag {0,1} & {1,0} is the best:\n"
Packit 13e616
			"\t{0,1} 0x%X->0x%X (%d)\t & {1,0} 0x%X->0x%X (%d)\n",
Packit 13e616
			matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.slid : 0,
Packit 13e616
			matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.dlid : 0,
Packit 13e616
			matrix[0][1] ? matrix[0][1]->resp.mpr_rec.hops : 0,
Packit 13e616
			matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.slid : 0,
Packit 13e616
			matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.dlid: 0,
Packit 13e616
			matrix[1][0] ? matrix[1][0]->resp.mpr_rec.hops : 0);
Packit 13e616
		if (matrix[0][1])
Packit 13e616
			cl_qlist_insert_tail(p_list, &matrix[0][1]->list_item);
Packit 13e616
		if (matrix[1][0])
Packit 13e616
			cl_qlist_insert_tail(p_list, &matrix[1][0]->list_item);
Packit 13e616
		free(matrix[0][0]);
Packit 13e616
		free(matrix[1][1]);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void mpr_rcv_process_pairs(IN osm_sa_t * sa,
Packit 13e616
				  IN const ib_multipath_rec_t * p_mpr,
Packit 13e616
				  IN osm_port_t * p_req_port,
Packit 13e616
				  IN osm_alias_guid_t ** pp_alias_guids,
Packit 13e616
				  IN const int nsrc, IN int ndest,
Packit 13e616
				  IN ib_net64_t comp_mask,
Packit 13e616
				  IN cl_qlist_t * p_list)
Packit 13e616
{
Packit 13e616
	osm_alias_guid_t **pp_src_alias_guid, **pp_es;
Packit 13e616
	osm_alias_guid_t **pp_dest_alias_guid, **pp_ed;
Packit 13e616
	uint32_t max_paths, num_paths, total_paths = 0;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	if (comp_mask & IB_MPR_COMPMASK_NUMBPATH)
Packit 13e616
		max_paths = p_mpr->num_path & 0x7F;
Packit 13e616
	else
Packit 13e616
		max_paths = OSM_SA_MPR_MAX_NUM_PATH;
Packit 13e616
Packit 13e616
	for (pp_src_alias_guid = pp_alias_guids, pp_es = pp_alias_guids + nsrc;
Packit 13e616
	     pp_src_alias_guid < pp_es; pp_src_alias_guid++) {
Packit 13e616
		for (pp_dest_alias_guid = pp_es, pp_ed = pp_es + ndest;
Packit 13e616
		     pp_dest_alias_guid < pp_ed; pp_dest_alias_guid++) {
Packit 13e616
			num_paths =
Packit 13e616
			    mpr_rcv_get_port_pair_paths(sa, p_mpr, p_req_port,
Packit 13e616
							*pp_src_alias_guid,
Packit 13e616
							*pp_dest_alias_guid,
Packit 13e616
							max_paths - total_paths,
Packit 13e616
							comp_mask, p_list);
Packit 13e616
			total_paths += num_paths;
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"%d paths %d total paths %d max paths\n",
Packit 13e616
				num_paths, total_paths, max_paths);
Packit 13e616
			/* Just take first NumbPaths found */
Packit 13e616
			if (total_paths >= max_paths)
Packit 13e616
				goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_mpr_rcv_process(IN void *context, IN void *data)
Packit 13e616
{
Packit 13e616
	osm_sa_t *sa = context;
Packit 13e616
	osm_madw_t *p_madw = data;
Packit 13e616
	const ib_multipath_rec_t *p_mpr;
Packit 13e616
	ib_sa_mad_t *p_sa_mad;
Packit 13e616
	osm_port_t *requester_port;
Packit 13e616
	osm_alias_guid_t *pp_alias_guids[IB_MULTIPATH_MAX_GIDS];
Packit 13e616
	cl_qlist_t pr_list;
Packit 13e616
	ib_net16_t sa_status;
Packit 13e616
	int nsrc, ndest;
Packit 13e616
	uint8_t rate, mtu;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_madw);
Packit 13e616
Packit 13e616
	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
Packit 13e616
	p_mpr = (ib_multipath_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_MULTIPATH_RECORD);
Packit 13e616
Packit 13e616
	if ((p_sa_mad->rmpp_flags & IB_RMPP_FLAG_ACTIVE) != IB_RMPP_FLAG_ACTIVE) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4510: "
Packit 13e616
			"Invalid request since RMPP_FLAG_ACTIVE is not set\n");
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* we only support SubnAdmGetMulti method */
Packit 13e616
	if (p_sa_mad->method != IB_MAD_METHOD_GETMULTI) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4513: "
Packit 13e616
			"Unsupported Method (%s) for MultiPathRecord request\n",
Packit 13e616
			ib_get_sa_method_str(p_sa_mad->method));
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG))
Packit 13e616
		osm_dump_multipath_record_v2(sa->p_log, p_mpr, FILE_ID, OSM_LOG_DEBUG);
Packit 13e616
Packit 13e616
	/* Make sure required components (S/DGIDCount) are supplied */
Packit 13e616
	if (!(p_sa_mad->comp_mask & IB_MPR_COMPMASK_SGIDCOUNT) ||
Packit 13e616
	    !(p_sa_mad->comp_mask & IB_MPR_COMPMASK_DGIDCOUNT)) {
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INSUF_COMPS);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Validate rate if supplied */
Packit 13e616
	if ((p_sa_mad->comp_mask & IB_MPR_COMPMASK_RATESELEC) &&
Packit 13e616
	    (p_sa_mad->comp_mask & IB_MPR_COMPMASK_RATE)) {
Packit 13e616
		rate = ib_multipath_rec_rate(p_mpr);
Packit 13e616
		if (!ib_rate_is_valid(rate)) {
Packit 13e616
			osm_sa_send_error(sa, p_madw,
Packit 13e616
					  IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	/* Validate MTU if supplied */
Packit 13e616
	if ((p_sa_mad->comp_mask & IB_MPR_COMPMASK_MTUSELEC) &&
Packit 13e616
	    (p_sa_mad->comp_mask & IB_MPR_COMPMASK_MTU)) {
Packit 13e616
		mtu = ib_multipath_rec_mtu(p_mpr);
Packit 13e616
		if (!ib_mtu_is_valid(mtu)) {
Packit 13e616
			osm_sa_send_error(sa, p_madw,
Packit 13e616
					  IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Make sure either none or both ServiceID parameters are supplied */
Packit 13e616
	if ((p_sa_mad->comp_mask & IB_MPR_COMPMASK_SERVICEID) != 0 &&
Packit 13e616
	    (p_sa_mad->comp_mask & IB_MPR_COMPMASK_SERVICEID) !=
Packit 13e616
	     IB_MPR_COMPMASK_SERVICEID) {
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INSUF_COMPS);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	cl_qlist_init(&pr_list);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Most SA functions (including this one) are read-only on the
Packit 13e616
	   subnet object, so we grab the lock non-exclusively.
Packit 13e616
	 */
Packit 13e616
	cl_plock_acquire(sa->p_lock);
Packit 13e616
Packit 13e616
	/* update the requester physical port */
Packit 13e616
	requester_port = osm_get_port_by_mad_addr(sa->p_log, sa->p_subn,
Packit 13e616
						  osm_madw_get_mad_addr_ptr
Packit 13e616
						  (p_madw));
Packit 13e616
	if (requester_port == NULL) {
Packit 13e616
		cl_plock_release(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4517: "
Packit 13e616
			"Cannot find requester physical port\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Requester port GUID 0x%" PRIx64 "\n",
Packit 13e616
		cl_ntoh64(osm_port_get_guid(requester_port)));
Packit 13e616
Packit 13e616
	sa_status = mpr_rcv_get_end_points(sa, p_madw, pp_alias_guids,
Packit 13e616
					   &nsrc, &ndest);
Packit 13e616
Packit 13e616
	if (sa_status != IB_SA_MAD_STATUS_SUCCESS || !nsrc || !ndest) {
Packit 13e616
		cl_plock_release(sa->p_lock);
Packit 13e616
		if (sa_status == IB_SA_MAD_STATUS_SUCCESS && (!nsrc || !ndest))
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4512: "
Packit 13e616
				"mpr_rcv_get_end_points failed, # GIDs found; "
Packit 13e616
				"src %d; dest %d)\n", nsrc, ndest);
Packit 13e616
		if (sa_status == IB_SA_MAD_STATUS_SUCCESS)
Packit 13e616
			osm_sa_send_error(sa, p_madw,
Packit 13e616
					  IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
		else
Packit 13e616
			osm_sa_send_error(sa, p_madw, sa_status);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* APM request */
Packit 13e616
	if (nsrc == 2 && ndest == 2 && (p_mpr->num_path & 0x7F) == 2)
Packit 13e616
		mpr_rcv_get_apm_paths(sa, p_mpr, requester_port, pp_alias_guids,
Packit 13e616
				      p_sa_mad->comp_mask, &pr_list);
Packit 13e616
	else
Packit 13e616
		mpr_rcv_process_pairs(sa, p_mpr, requester_port, pp_alias_guids,
Packit 13e616
				      nsrc, ndest, p_sa_mad->comp_mask,
Packit 13e616
				      &pr_list);
Packit 13e616
Packit 13e616
	cl_plock_release(sa->p_lock);
Packit 13e616
Packit 13e616
	/* o15-0.2.7: If MultiPath is supported, then SA shall respond to a
Packit 13e616
	   SubnAdmGetMulti() containing a valid MultiPathRecord attribute with
Packit 13e616
	   a set of zero or more PathRecords satisfying the constraints
Packit 13e616
	   indicated in the MultiPathRecord received. The PathRecord Attribute
Packit 13e616
	   ID shall be used in the response.
Packit 13e616
	 */
Packit 13e616
	p_sa_mad->attr_id = IB_MAD_ATTR_PATH_RECORD;
Packit 13e616
	osm_sa_respond(sa, p_madw, sizeof(ib_path_rec_t), &pr_list);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
#endif