Blame opensm/osm_sa_path_record.c

Packit Service 54dbc3
/*
Packit Service 54dbc3
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 2002-2011 Mellanox Technologies LTD. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 2009 HNR Consulting. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 2010 Sun Microsystems, Inc. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 2009-2011 ZIH, TU Dresden, Federal Republic of Germany. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 * This software is available to you under a choice of one of two
Packit Service 54dbc3
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit Service 54dbc3
 * General Public License (GPL) Version 2, available from the file
Packit Service 54dbc3
 * COPYING in the main directory of this source tree, or the
Packit Service 54dbc3
 * OpenIB.org BSD license below:
Packit Service 54dbc3
 *
Packit Service 54dbc3
 *     Redistribution and use in source and binary forms, with or
Packit Service 54dbc3
 *     without modification, are permitted provided that the following
Packit Service 54dbc3
 *     conditions are met:
Packit Service 54dbc3
 *
Packit Service 54dbc3
 *      - Redistributions of source code must retain the above
Packit Service 54dbc3
 *        copyright notice, this list of conditions and the following
Packit Service 54dbc3
 *        disclaimer.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 *      - Redistributions in binary form must reproduce the above
Packit Service 54dbc3
 *        copyright notice, this list of conditions and the following
Packit Service 54dbc3
 *        disclaimer in the documentation and/or other materials
Packit Service 54dbc3
 *        provided with the distribution.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit Service 54dbc3
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit Service 54dbc3
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit Service 54dbc3
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit Service 54dbc3
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit Service 54dbc3
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit Service 54dbc3
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit Service 54dbc3
 * SOFTWARE.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 */
Packit Service 54dbc3
Packit Service 54dbc3
/*
Packit Service 54dbc3
 * Abstract:
Packit Service 54dbc3
 *    Implementation of osm_pr_rcv_t.
Packit Service 54dbc3
 * This object represents the PathRecord Receiver object.
Packit Service 54dbc3
 * This object is part of the opensm family of objects.
Packit Service 54dbc3
 */
Packit Service 54dbc3
Packit Service 54dbc3
#if HAVE_CONFIG_H
Packit Service 54dbc3
#  include <config.h>
Packit Service 54dbc3
#endif				/* HAVE_CONFIG_H */
Packit Service 54dbc3
Packit Service 54dbc3
#include <string.h>
Packit Service 54dbc3
#include <arpa/inet.h>
Packit Service 54dbc3
#include <iba/ib_types.h>
Packit Service 54dbc3
#include <complib/cl_qmap.h>
Packit Service 54dbc3
#include <complib/cl_passivelock.h>
Packit Service 54dbc3
#include <complib/cl_debug.h>
Packit Service 54dbc3
#include <complib/cl_qlist.h>
Packit Service 54dbc3
#include <opensm/osm_file_ids.h>
Packit Service 54dbc3
#define FILE_ID OSM_FILE_SA_PATH_RECORD_C
Packit Service 54dbc3
#include <vendor/osm_vendor_api.h>
Packit Service 54dbc3
#include <opensm/osm_base.h>
Packit Service 54dbc3
#include <opensm/osm_port.h>
Packit Service 54dbc3
#include <opensm/osm_node.h>
Packit Service 54dbc3
#include <opensm/osm_switch.h>
Packit Service 54dbc3
#include <opensm/osm_helper.h>
Packit Service 54dbc3
#include <opensm/osm_pkey.h>
Packit Service 54dbc3
#include <opensm/osm_multicast.h>
Packit Service 54dbc3
#include <opensm/osm_partition.h>
Packit Service 54dbc3
#include <opensm/osm_opensm.h>
Packit Service 54dbc3
#include <opensm/osm_qos_policy.h>
Packit Service 54dbc3
#include <opensm/osm_sa.h>
Packit Service 54dbc3
#include <opensm/osm_router.h>
Packit Service 54dbc3
#include <opensm/osm_prefix_route.h>
Packit Service 54dbc3
#include <opensm/osm_ucast_lash.h>
Packit Service 54dbc3
Packit Service 54dbc3
#define SA_PR_RESP_SIZE SA_ITEM_RESP_SIZE(path_rec)
Packit Service 54dbc3
Packit Service 54dbc3
#define MAX_HOPS 64
Packit Service 54dbc3
Packit Service 54dbc3
static inline boolean_t sa_path_rec_is_tavor_port(IN const osm_port_t * p_port)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_node_t const *p_node;
Packit Service 54dbc3
	ib_net32_t vend_id;
Packit Service 54dbc3
Packit Service 54dbc3
	p_node = p_port->p_node;
Packit Service 54dbc3
	vend_id = ib_node_info_get_vendor_id(&p_node->node_info);
Packit Service 54dbc3
Packit Service 54dbc3
	return ((p_node->node_info.device_id == CL_HTON16(23108)) &&
Packit Service 54dbc3
		((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) ||
Packit Service 54dbc3
		 (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) ||
Packit Service 54dbc3
		 (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) ||
Packit Service 54dbc3
		 (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE))));
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static boolean_t
Packit Service 54dbc3
sa_path_rec_apply_tavor_mtu_limit(IN const ib_path_rec_t * p_pr,
Packit Service 54dbc3
				  IN const osm_port_t * p_src_port,
Packit Service 54dbc3
				  IN const osm_port_t * p_dest_port,
Packit Service 54dbc3
				  IN const ib_net64_t comp_mask)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint8_t required_mtu;
Packit Service 54dbc3
Packit Service 54dbc3
	/* only if at least one of the ports is a Tavor device */
Packit Service 54dbc3
	if (!sa_path_rec_is_tavor_port(p_src_port) &&
Packit Service 54dbc3
	    !sa_path_rec_is_tavor_port(p_dest_port))
Packit Service 54dbc3
		return FALSE;
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   we can apply the patch if either:
Packit Service 54dbc3
	   1. No MTU required
Packit Service 54dbc3
	   2. Required MTU <
Packit Service 54dbc3
	   3. Required MTU = 1K or 512 or 256
Packit Service 54dbc3
	   4. Required MTU > 256 or 512
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	required_mtu = ib_path_rec_mtu(p_pr);
Packit Service 54dbc3
	if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
Packit Service 54dbc3
	    (comp_mask & IB_PR_COMPMASK_MTU)) {
Packit Service 54dbc3
		switch (ib_path_rec_mtu_sel(p_pr)) {
Packit Service 54dbc3
		case 0:	/* must be greater than */
Packit Service 54dbc3
		case 2:	/* exact match */
Packit Service 54dbc3
			if (IB_MTU_LEN_1024 < required_mtu)
Packit Service 54dbc3
				return FALSE;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		case 1:	/* must be less than */
Packit Service 54dbc3
			/* can't be disqualified by this one */
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		case 3:	/* largest available */
Packit Service 54dbc3
			/* the ULP intentionally requested */
Packit Service 54dbc3
			/* the largest MTU possible */
Packit Service 54dbc3
			return FALSE;
Packit Service 54dbc3
Packit Service 54dbc3
		default:
Packit Service 54dbc3
			/* if we're here, there's a bug in ib_path_rec_mtu_sel() */
Packit Service 54dbc3
			CL_ASSERT(FALSE);
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	return TRUE;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static ib_api_status_t pr_rcv_get_path_parms(IN osm_sa_t * sa,
Packit Service 54dbc3
					     IN const ib_path_rec_t * p_pr,
Packit Service 54dbc3
					     IN const osm_alias_guid_t * p_src_alias_guid,
Packit Service 54dbc3
					     IN const uint16_t src_lid_ho,
Packit Service 54dbc3
					     IN const osm_alias_guid_t * p_dest_alias_guid,
Packit Service 54dbc3
					     IN const uint16_t dest_lid_ho,
Packit Service 54dbc3
					     IN const ib_net64_t comp_mask,
Packit Service 54dbc3
					     OUT osm_path_parms_t * p_parms)
Packit Service 54dbc3
{
Packit Service 54dbc3
	const osm_node_t *p_node;
Packit Service 54dbc3
	const osm_physp_t *p_physp, *p_physp0;
Packit Service 54dbc3
	const osm_physp_t *p_src_physp;
Packit Service 54dbc3
	const osm_physp_t *p_dest_physp;
Packit Service 54dbc3
	const osm_prtn_t *p_prtn = NULL;
Packit Service 54dbc3
	osm_opensm_t *p_osm;
Packit Service 54dbc3
	struct osm_routing_engine *p_re;
Packit Service 54dbc3
	const ib_port_info_t *p_pi, *p_pi0;
Packit Service 54dbc3
	ib_api_status_t status = IB_SUCCESS;
Packit Service 54dbc3
	ib_net16_t pkey;
Packit Service 54dbc3
	uint8_t mtu;
Packit Service 54dbc3
	uint8_t rate, p0_extended_rate, dest_rate;
Packit Service 54dbc3
	uint8_t pkt_life;
Packit Service 54dbc3
	uint8_t required_mtu;
Packit Service 54dbc3
	uint8_t required_rate;
Packit Service 54dbc3
	uint8_t required_pkt_life;
Packit Service 54dbc3
	uint8_t sl;
Packit Service 54dbc3
	uint8_t in_port_num;
Packit Service 54dbc3
	ib_net16_t dest_lid;
Packit Service 54dbc3
	uint8_t i;
Packit Service 54dbc3
	ib_slvl_table_t *p_slvl_tbl = NULL;
Packit Service 54dbc3
	osm_qos_level_t *p_qos_level = NULL;
Packit Service 54dbc3
	uint16_t valid_sl_mask = 0xffff;
Packit Service 54dbc3
	int hops = 0;
Packit Service 54dbc3
	int extended, p0_extended;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sa->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	dest_lid = cl_hton16(dest_lid_ho);
Packit Service 54dbc3
Packit Service 54dbc3
	p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
Packit Service 54dbc3
	p_physp = p_src_alias_guid->p_base_port->p_physp;
Packit Service 54dbc3
	p_src_physp = p_physp;
Packit Service 54dbc3
	p_pi = &p_physp->port_info;
Packit Service 54dbc3
	p_osm = sa->p_subn->p_osm;
Packit Service 54dbc3
	p_re = p_osm->routing_engine_used;
Packit Service 54dbc3
Packit Service 54dbc3
	mtu = ib_port_info_get_mtu_cap(p_pi);
Packit Service 54dbc3
	extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
Packit Service 54dbc3
	rate = ib_port_info_compute_rate(p_pi, extended);
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   Mellanox Tavor device performance is better using 1K MTU.
Packit Service 54dbc3
	   If required MTU and MTU selector are such that 1K is OK
Packit Service 54dbc3
	   and at least one end of the path is Tavor we override the
Packit Service 54dbc3
	   port MTU with 1K.
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	if (sa->p_subn->opt.enable_quirks &&
Packit Service 54dbc3
	    sa_path_rec_apply_tavor_mtu_limit(p_pr,
Packit Service 54dbc3
					      p_src_alias_guid->p_base_port,
Packit Service 54dbc3
					      p_dest_alias_guid->p_base_port,
Packit Service 54dbc3
					      comp_mask))
Packit Service 54dbc3
		if (mtu > IB_MTU_LEN_1024) {
Packit Service 54dbc3
			mtu = IB_MTU_LEN_1024;
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
				"Optimized Path MTU to 1K for Mellanox Tavor device\n");
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   Walk the subnet object from source to destination,
Packit Service 54dbc3
	   tracking the most restrictive rate and mtu values along the way...
Packit Service 54dbc3
Packit Service 54dbc3
	   If source port node is a switch, then p_physp should
Packit Service 54dbc3
	   point to the port that routes the destination lid
Packit Service 54dbc3
	 */
Packit Service 54dbc3
Packit Service 54dbc3
	p_node = osm_physp_get_node_ptr(p_physp);
Packit Service 54dbc3
Packit Service 54dbc3
	if (p_node->sw) {
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		 * Source node is a switch.
Packit Service 54dbc3
		 * Make sure that p_physp points to the out port of the
Packit Service 54dbc3
		 * switch that routes to the destination lid (dest_lid_ho)
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
Packit Service 54dbc3
		if (p_physp == 0) {
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F02: "
Packit Service 54dbc3
				"Cannot find routing from LID %u to LID %u on "
Packit Service 54dbc3
				"switch %s (GUID: 0x%016" PRIx64 ")\n",
Packit Service 54dbc3
				src_lid_ho, dest_lid_ho, p_node->print_desc,
Packit Service 54dbc3
				cl_ntoh64(osm_node_get_node_guid(p_node)));
Packit Service 54dbc3
			status = IB_NOT_FOUND;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (sa->p_subn->opt.qos) {
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		 * Whether this node is switch or CA, the IN port for
Packit Service 54dbc3
		 * the sl2vl table is 0, because this is a source node.
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, 0);
Packit Service 54dbc3
Packit Service 54dbc3
		/* update valid SLs that still exist on this route */
Packit Service 54dbc3
		for (i = 0; i < IB_MAX_NUM_VLS; i++) {
Packit Service 54dbc3
			if (valid_sl_mask & (1 << i) &&
Packit Service 54dbc3
			    ib_slvl_table_get(p_slvl_tbl, i) == IB_DROP_VL)
Packit Service 54dbc3
				valid_sl_mask &= ~(1 << i);
Packit Service 54dbc3
		}
Packit Service 54dbc3
		if (!valid_sl_mask) {
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
				"All the SLs lead to VL15 on this path\n");
Packit Service 54dbc3
			status = IB_NOT_FOUND;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	 * Same as above
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	p_node = osm_physp_get_node_ptr(p_dest_physp);
Packit Service 54dbc3
Packit Service 54dbc3
	if (p_node->sw) {
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		 * if destination is switch, we want p_dest_physp to point to port 0
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		p_dest_physp =
Packit Service 54dbc3
		    osm_switch_get_route_by_lid(p_node->sw, dest_lid);
Packit Service 54dbc3
Packit Service 54dbc3
		if (p_dest_physp == 0) {
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F03: "
Packit Service 54dbc3
				"Can't find routing from LID %u to LID %u on "
Packit Service 54dbc3
				"switch %s (GUID: 0x%016" PRIx64 ")\n",
Packit Service 54dbc3
				src_lid_ho, dest_lid_ho, p_node->print_desc,
Packit Service 54dbc3
				cl_ntoh64(osm_node_get_node_guid(p_node)));
Packit Service 54dbc3
			status = IB_NOT_FOUND;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	 * Now go through the path step by step
Packit Service 54dbc3
	 */
Packit Service 54dbc3
Packit Service 54dbc3
	while (p_physp != p_dest_physp) {
Packit Service 54dbc3
Packit Service 54dbc3
		int tmp_pnum = p_physp->port_num;
Packit Service 54dbc3
		p_node = osm_physp_get_node_ptr(p_physp);
Packit Service 54dbc3
		p_physp = osm_physp_get_remote(p_physp);
Packit Service 54dbc3
Packit Service 54dbc3
		if (p_physp == 0) {
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F05: "
Packit Service 54dbc3
				"Can't find remote phys port of %s (GUID: "
Packit Service 54dbc3
				"0x%016"PRIx64") port %d "
Packit Service 54dbc3
				"while routing from LID %u to LID %u\n",
Packit Service 54dbc3
				p_node->print_desc,
Packit Service 54dbc3
				cl_ntoh64(osm_node_get_node_guid(p_node)),
Packit Service 54dbc3
				tmp_pnum, src_lid_ho, dest_lid_ho);
Packit Service 54dbc3
			status = IB_ERROR;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		in_port_num = osm_physp_get_port_num(p_physp);
Packit Service 54dbc3
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		   This is point to point case (no switch in between)
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		if (p_physp == p_dest_physp)
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		p_node = osm_physp_get_node_ptr(p_physp);
Packit Service 54dbc3
Packit Service 54dbc3
		if (!p_node->sw) {
Packit Service 54dbc3
			/*
Packit Service 54dbc3
			   There is some sort of problem in the subnet object!
Packit Service 54dbc3
			   If this isn't a switch, we should have reached
Packit Service 54dbc3
			   the destination by now!
Packit Service 54dbc3
			 */
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F06: "
Packit Service 54dbc3
				"Internal error, bad path while routing "
Packit Service 54dbc3
				"%s (GUID: 0x%016"PRIx64") port %d to "
Packit Service 54dbc3
				"%s (GUID: 0x%016"PRIx64") port %d; "
Packit Service 54dbc3
				"ended at %s port %d\n",
Packit Service 54dbc3
				p_src_alias_guid->p_base_port->p_node->print_desc,
Packit Service 54dbc3
				cl_ntoh64(p_src_alias_guid->p_base_port->p_node->node_info.node_guid),
Packit Service 54dbc3
				p_src_alias_guid->p_base_port->p_physp->port_num,
Packit Service 54dbc3
				p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit Service 54dbc3
				cl_ntoh64(p_dest_alias_guid->p_base_port->p_node->node_info.node_guid),
Packit Service 54dbc3
				p_dest_alias_guid->p_base_port->p_physp->port_num,
Packit Service 54dbc3
				p_node->print_desc,
Packit Service 54dbc3
				p_physp->port_num);
Packit Service 54dbc3
			status = IB_ERROR;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		   Check parameters for the ingress port in this switch.
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		p_pi = &p_physp->port_info;
Packit Service 54dbc3
Packit Service 54dbc3
		if (mtu > ib_port_info_get_mtu_cap(p_pi))
Packit Service 54dbc3
			mtu = ib_port_info_get_mtu_cap(p_pi);
Packit Service 54dbc3
Packit Service 54dbc3
		p_physp0 = osm_node_get_physp_ptr((osm_node_t *)p_node, 0);
Packit Service 54dbc3
		p_pi0 = &p_physp0->port_info;
Packit Service 54dbc3
		p0_extended = p_pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
Packit Service 54dbc3
		p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
Packit Service 54dbc3
		if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
Packit Service 54dbc3
			rate = p0_extended_rate;
Packit Service 54dbc3
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		   Continue with the egress port on this switch.
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
Packit Service 54dbc3
		if (p_physp == 0) {
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F07: "
Packit Service 54dbc3
				"Dead end path on switch "
Packit Service 54dbc3
				"%s (GUID: 0x%016"PRIx64") to LID %u\n",
Packit Service 54dbc3
				p_node->print_desc,
Packit Service 54dbc3
				cl_ntoh64(osm_node_get_node_guid(p_node)),
Packit Service 54dbc3
				dest_lid_ho);
Packit Service 54dbc3
			status = IB_ERROR;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		p_pi = &p_physp->port_info;
Packit Service 54dbc3
Packit Service 54dbc3
		if (mtu > ib_port_info_get_mtu_cap(p_pi))
Packit Service 54dbc3
			mtu = ib_port_info_get_mtu_cap(p_pi);
Packit Service 54dbc3
Packit Service 54dbc3
		p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
Packit Service 54dbc3
		if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
Packit Service 54dbc3
			rate = p0_extended_rate;
Packit Service 54dbc3
Packit Service 54dbc3
		if (sa->p_subn->opt.qos) {
Packit Service 54dbc3
			/*
Packit Service 54dbc3
			 * Check SL2VL table of the switch and update valid SLs
Packit Service 54dbc3
			 */
Packit Service 54dbc3
			p_slvl_tbl =
Packit Service 54dbc3
			    osm_physp_get_slvl_tbl(p_physp, in_port_num);
Packit Service 54dbc3
			for (i = 0; i < IB_MAX_NUM_VLS; i++) {
Packit Service 54dbc3
				if (valid_sl_mask & (1 << i) &&
Packit Service 54dbc3
				    ib_slvl_table_get(p_slvl_tbl,
Packit Service 54dbc3
						      i) == IB_DROP_VL)
Packit Service 54dbc3
					valid_sl_mask &= ~(1 << i);
Packit Service 54dbc3
			}
Packit Service 54dbc3
			if (!valid_sl_mask) {
Packit Service 54dbc3
				OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "All the SLs "
Packit Service 54dbc3
					"lead to VL15 on this path\n");
Packit Service 54dbc3
				status = IB_NOT_FOUND;
Packit Service 54dbc3
				goto Exit;
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		/* update number of hops traversed */
Packit Service 54dbc3
		hops++;
Packit Service 54dbc3
		if (hops > MAX_HOPS) {
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F25: "
Packit Service 54dbc3
				"Path from GUID 0x%016" PRIx64 " (%s port %d) "
Packit Service 54dbc3
				"to lid %u GUID 0x%016" PRIx64 " (%s port %d) "
Packit Service 54dbc3
				"needs more than %d hops, max %d hops allowed\n",
Packit Service 54dbc3
				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
Packit Service 54dbc3
				p_src_physp->p_node->print_desc,
Packit Service 54dbc3
				p_src_physp->port_num,
Packit Service 54dbc3
				dest_lid_ho,
Packit Service 54dbc3
				cl_ntoh64(osm_physp_get_port_guid
Packit Service 54dbc3
					  (p_dest_physp)),
Packit Service 54dbc3
				p_dest_physp->p_node->print_desc,
Packit Service 54dbc3
				p_dest_physp->port_num,
Packit Service 54dbc3
				hops,
Packit Service 54dbc3
				MAX_HOPS);
Packit Service 54dbc3
			status = IB_NOT_FOUND;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   p_physp now points to the destination
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	p_pi = &p_physp->port_info;
Packit Service 54dbc3
Packit Service 54dbc3
	if (mtu > ib_port_info_get_mtu_cap(p_pi))
Packit Service 54dbc3
		mtu = ib_port_info_get_mtu_cap(p_pi);
Packit Service 54dbc3
Packit Service 54dbc3
	extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
Packit Service 54dbc3
	dest_rate = ib_port_info_compute_rate(p_pi, extended);
Packit Service 54dbc3
	if (ib_path_compare_rates(rate, dest_rate) > 0)
Packit Service 54dbc3
		rate = dest_rate;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
		"Path min MTU = %u, min rate = %u\n", mtu, rate);
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	 * Get QoS Level object according to the path request
Packit Service 54dbc3
	 * and adjust path parameters according to QoS settings
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	if (sa->p_subn->opt.qos &&
Packit Service 54dbc3
	    sa->p_subn->p_qos_policy &&
Packit Service 54dbc3
	    (p_qos_level =
Packit Service 54dbc3
	     osm_qos_policy_get_qos_level_by_pr(sa->p_subn->p_qos_policy,
Packit Service 54dbc3
						p_pr, p_src_physp, p_dest_physp,
Packit Service 54dbc3
						comp_mask))) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"PathRecord request matches QoS Level '%s' (%s)\n",
Packit Service 54dbc3
			p_qos_level->name, p_qos_level->use ?
Packit Service 54dbc3
			p_qos_level->use : "no description");
Packit Service 54dbc3
Packit Service 54dbc3
		if (p_qos_level->mtu_limit_set
Packit Service 54dbc3
		    && (mtu > p_qos_level->mtu_limit))
Packit Service 54dbc3
			mtu = p_qos_level->mtu_limit;
Packit Service 54dbc3
Packit Service 54dbc3
		if (p_qos_level->rate_limit_set
Packit Service 54dbc3
		    && (ib_path_compare_rates(rate, p_qos_level->rate_limit) > 0))
Packit Service 54dbc3
			rate = p_qos_level->rate_limit;
Packit Service 54dbc3
Packit Service 54dbc3
		if (p_qos_level->sl_set) {
Packit Service 54dbc3
			sl = p_qos_level->sl;
Packit Service 54dbc3
			if (!(valid_sl_mask & (1 << sl))) {
Packit Service 54dbc3
				status = IB_NOT_FOUND;
Packit Service 54dbc3
				goto Exit;
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	 * Set packet lifetime.
Packit Service 54dbc3
	 * According to spec definition IBA 1.2 Table 205
Packit Service 54dbc3
	 * PacketLifeTime description, for loopback paths,
Packit Service 54dbc3
	 * packetLifeTime shall be zero.
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
Packit Service 54dbc3
		pkt_life = 0;
Packit Service 54dbc3
	else if (p_qos_level && p_qos_level->pkt_life_set)
Packit Service 54dbc3
		pkt_life = p_qos_level->pkt_life;
Packit Service 54dbc3
	else
Packit Service 54dbc3
		pkt_life = sa->p_subn->opt.subnet_timeout;
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   Determine if these values meet the user criteria
Packit Service 54dbc3
	   and adjust appropriately
Packit Service 54dbc3
	 */
Packit Service 54dbc3
Packit Service 54dbc3
	/* we silently ignore cases where only the MTU selector is defined */
Packit Service 54dbc3
	if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
Packit Service 54dbc3
	    (comp_mask & IB_PR_COMPMASK_MTU)) {
Packit Service 54dbc3
		required_mtu = ib_path_rec_mtu(p_pr);
Packit Service 54dbc3
		switch (ib_path_rec_mtu_sel(p_pr)) {
Packit Service 54dbc3
		case 0:	/* must be greater than */
Packit Service 54dbc3
			if (mtu <= required_mtu)
Packit Service 54dbc3
				status = IB_NOT_FOUND;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		case 1:	/* must be less than */
Packit Service 54dbc3
			if (mtu >= required_mtu) {
Packit Service 54dbc3
				/* adjust to use the highest mtu
Packit Service 54dbc3
				   lower than the required one */
Packit Service 54dbc3
				if (required_mtu > 1)
Packit Service 54dbc3
					mtu = required_mtu - 1;
Packit Service 54dbc3
				else
Packit Service 54dbc3
					status = IB_NOT_FOUND;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		case 2:	/* exact match */
Packit Service 54dbc3
			if (mtu < required_mtu)
Packit Service 54dbc3
				status = IB_NOT_FOUND;
Packit Service 54dbc3
			else
Packit Service 54dbc3
				mtu = required_mtu;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		case 3:	/* largest available */
Packit Service 54dbc3
			/* can't be disqualified by this one */
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		default:
Packit Service 54dbc3
			/* if we're here, there's a bug in ib_path_rec_mtu_sel() */
Packit Service 54dbc3
			CL_ASSERT(FALSE);
Packit Service 54dbc3
			status = IB_ERROR;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
	if (status != IB_SUCCESS)
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
Packit Service 54dbc3
	/* we silently ignore cases where only the Rate selector is defined */
Packit Service 54dbc3
	if ((comp_mask & IB_PR_COMPMASK_RATESELEC) &&
Packit Service 54dbc3
	    (comp_mask & IB_PR_COMPMASK_RATE)) {
Packit Service 54dbc3
		required_rate = ib_path_rec_rate(p_pr);
Packit Service 54dbc3
		switch (ib_path_rec_rate_sel(p_pr)) {
Packit Service 54dbc3
		case 0:	/* must be greater than */
Packit Service 54dbc3
			if (ib_path_compare_rates(rate, required_rate) <= 0)
Packit Service 54dbc3
				status = IB_NOT_FOUND;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		case 1:	/* must be less than */
Packit Service 54dbc3
			if (ib_path_compare_rates(rate, required_rate) >= 0) {
Packit Service 54dbc3
				/* adjust the rate to use the highest rate
Packit Service 54dbc3
				   lower than the required one */
Packit Service 54dbc3
				rate = ib_path_rate_get_prev(required_rate);
Packit Service 54dbc3
				if (!rate)
Packit Service 54dbc3
					status = IB_NOT_FOUND;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		case 2:	/* exact match */
Packit Service 54dbc3
			if (ib_path_compare_rates(rate, required_rate))
Packit Service 54dbc3
				status = IB_NOT_FOUND;
Packit Service 54dbc3
			else
Packit Service 54dbc3
				rate = required_rate;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		case 3:	/* largest available */
Packit Service 54dbc3
			/* can't be disqualified by this one */
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		default:
Packit Service 54dbc3
			/* if we're here, there's a bug in ib_path_rec_mtu_sel() */
Packit Service 54dbc3
			CL_ASSERT(FALSE);
Packit Service 54dbc3
			status = IB_ERROR;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
	if (status != IB_SUCCESS)
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
Packit Service 54dbc3
	/* we silently ignore cases where only the PktLife selector is defined */
Packit Service 54dbc3
	if ((comp_mask & IB_PR_COMPMASK_PKTLIFETIMESELEC) &&
Packit Service 54dbc3
	    (comp_mask & IB_PR_COMPMASK_PKTLIFETIME)) {
Packit Service 54dbc3
		required_pkt_life = ib_path_rec_pkt_life(p_pr);
Packit Service 54dbc3
		switch (ib_path_rec_pkt_life_sel(p_pr)) {
Packit Service 54dbc3
		case 0:	/* must be greater than */
Packit Service 54dbc3
			if (pkt_life <= required_pkt_life)
Packit Service 54dbc3
				status = IB_NOT_FOUND;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		case 1:	/* must be less than */
Packit Service 54dbc3
			if (pkt_life >= required_pkt_life) {
Packit Service 54dbc3
				/* adjust the lifetime to use the highest possible
Packit Service 54dbc3
				   lower than the required one */
Packit Service 54dbc3
				if (required_pkt_life > 1)
Packit Service 54dbc3
					pkt_life = required_pkt_life - 1;
Packit Service 54dbc3
				else
Packit Service 54dbc3
					status = IB_NOT_FOUND;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		case 2:	/* exact match */
Packit Service 54dbc3
			if (pkt_life < required_pkt_life)
Packit Service 54dbc3
				status = IB_NOT_FOUND;
Packit Service 54dbc3
			else
Packit Service 54dbc3
				pkt_life = required_pkt_life;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		case 3:	/* smallest available */
Packit Service 54dbc3
			/* can't be disqualified by this one */
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		default:
Packit Service 54dbc3
			/* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */
Packit Service 54dbc3
			CL_ASSERT(FALSE);
Packit Service 54dbc3
			status = IB_ERROR;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (status != IB_SUCCESS)
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	 * set Pkey for this path record request
Packit Service 54dbc3
	 */
Packit Service 54dbc3
Packit Service 54dbc3
	if ((comp_mask & IB_PR_COMPMASK_RAWTRAFFIC) &&
Packit Service 54dbc3
	    (cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31)))
Packit Service 54dbc3
		pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
Packit Service 54dbc3
						  sa->p_subn->opt.allow_both_pkeys);
Packit Service 54dbc3
Packit Service 54dbc3
	else if (comp_mask & IB_PR_COMPMASK_PKEY) {
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		 * PR request has a specific pkey:
Packit Service 54dbc3
		 * Check that source and destination share this pkey.
Packit Service 54dbc3
		 * If QoS level has pkeys, check that this pkey exists
Packit Service 54dbc3
		 * in the QoS level pkeys.
Packit Service 54dbc3
		 * PR returned pkey is the requested pkey.
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		pkey = p_pr->pkey;
Packit Service 54dbc3
		if (!osm_physp_share_this_pkey(p_src_physp, p_dest_physp, pkey,
Packit Service 54dbc3
					       sa->p_subn->opt.allow_both_pkeys)) {
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1A: "
Packit Service 54dbc3
				"Ports 0x%016" PRIx64 " (%s port %d) and "
Packit Service 54dbc3
				"0x%016" PRIx64 " (%s port %d) "
Packit Service 54dbc3
				"do not share specified PKey 0x%04x\n",
Packit Service 54dbc3
				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
Packit Service 54dbc3
				p_src_physp->p_node->print_desc,
Packit Service 54dbc3
				p_src_physp->port_num,
Packit Service 54dbc3
				cl_ntoh64(osm_physp_get_port_guid
Packit Service 54dbc3
					  (p_dest_physp)),
Packit Service 54dbc3
				p_dest_physp->p_node->print_desc,
Packit Service 54dbc3
				p_dest_physp->port_num,
Packit Service 54dbc3
				cl_ntoh16(pkey));
Packit Service 54dbc3
			status = IB_NOT_FOUND;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
		if (p_qos_level && p_qos_level->pkey_range_len &&
Packit Service 54dbc3
		    !osm_qos_level_has_pkey(p_qos_level, pkey)) {
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1D: "
Packit Service 54dbc3
				"QoS level \"%s\" doesn't define specified PKey 0x%04x "
Packit Service 54dbc3
				"for ports 0x%016" PRIx64 " (%s port %d) and "
Packit Service 54dbc3
				"0x%016"PRIx64" (%s port %d)\n",
Packit Service 54dbc3
				p_qos_level->name,
Packit Service 54dbc3
				cl_ntoh16(pkey),
Packit Service 54dbc3
				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
Packit Service 54dbc3
				p_src_physp->p_node->print_desc,
Packit Service 54dbc3
				p_src_alias_guid->p_base_port->p_physp->port_num,
Packit Service 54dbc3
				cl_ntoh64(osm_physp_get_port_guid
Packit Service 54dbc3
					  (p_dest_physp)),
Packit Service 54dbc3
				p_dest_physp->p_node->print_desc,
Packit Service 54dbc3
				p_dest_alias_guid->p_base_port->p_physp->port_num);
Packit Service 54dbc3
			status = IB_NOT_FOUND;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
	} else if (p_qos_level && p_qos_level->pkey_range_len) {
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		 * PR request doesn't have a specific pkey, but QoS level
Packit Service 54dbc3
		 * has pkeys - get shared pkey from QoS level pkeys
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		pkey = osm_qos_level_get_shared_pkey(p_qos_level,
Packit Service 54dbc3
						     p_src_physp, p_dest_physp,
Packit Service 54dbc3
						     sa->p_subn->opt.allow_both_pkeys);
Packit Service 54dbc3
		if (!pkey) {
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1E: "
Packit Service 54dbc3
				"Ports 0x%016" PRIx64 " (%s) and "
Packit Service 54dbc3
				"0x%016" PRIx64 " (%s) do not share "
Packit Service 54dbc3
				"PKeys defined by QoS level \"%s\"\n",
Packit Service 54dbc3
				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
Packit Service 54dbc3
				p_src_physp->p_node->print_desc,
Packit Service 54dbc3
				cl_ntoh64(osm_physp_get_port_guid
Packit Service 54dbc3
					  (p_dest_physp)),
Packit Service 54dbc3
				p_dest_physp->p_node->print_desc,
Packit Service 54dbc3
				p_qos_level->name);
Packit Service 54dbc3
			status = IB_NOT_FOUND;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	} else {
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		 * Neither PR request nor QoS level have pkey.
Packit Service 54dbc3
		 * Just get any shared pkey.
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
Packit Service 54dbc3
						  sa->p_subn->opt.allow_both_pkeys);
Packit Service 54dbc3
		if (!pkey) {
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1B: "
Packit Service 54dbc3
				"Ports src 0x%016"PRIx64" (%s port %d) and "
Packit Service 54dbc3
				"dst 0x%016"PRIx64" (%s port %d) do not have "
Packit Service 54dbc3
				"any shared PKeys\n",
Packit Service 54dbc3
				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
Packit Service 54dbc3
				p_src_physp->p_node->print_desc,
Packit Service 54dbc3
				p_src_physp->port_num,
Packit Service 54dbc3
				cl_ntoh64(osm_physp_get_port_guid
Packit Service 54dbc3
					  (p_dest_physp)),
Packit Service 54dbc3
				p_dest_physp->p_node->print_desc,
Packit Service 54dbc3
				p_dest_physp->port_num);
Packit Service 54dbc3
			status = IB_NOT_FOUND;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (pkey) {
Packit Service 54dbc3
		p_prtn =
Packit Service 54dbc3
		    (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl,
Packit Service 54dbc3
					       pkey & cl_hton16((uint16_t) ~
Packit Service 54dbc3
								0x8000));
Packit Service 54dbc3
		if (p_prtn ==
Packit Service 54dbc3
		    (osm_prtn_t *) cl_qmap_end(&sa->p_subn->prtn_pkey_tbl))
Packit Service 54dbc3
			p_prtn = NULL;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	 * Set PathRecord SL
Packit Service 54dbc3
	 */
Packit Service 54dbc3
Packit Service 54dbc3
	if (comp_mask & IB_PR_COMPMASK_SL) {
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		 * Specific SL was requested
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		sl = ib_path_rec_sl(p_pr);
Packit Service 54dbc3
Packit Service 54dbc3
		if (p_qos_level && p_qos_level->sl_set
Packit Service 54dbc3
		    && (p_qos_level->sl != sl)) {
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1F: "
Packit Service 54dbc3
				"QoS constraints: required PathRecord SL (%u) "
Packit Service 54dbc3
				"doesn't match QoS policy \"%s\" SL (%u) "
Packit Service 54dbc3
				"[%s port %d <-> %s port %d]\n", sl,
Packit Service 54dbc3
				p_qos_level->name,
Packit Service 54dbc3
				p_qos_level->sl,
Packit Service 54dbc3
				p_src_alias_guid->p_base_port->p_node->print_desc,
Packit Service 54dbc3
				p_src_alias_guid->p_base_port->p_physp->port_num,
Packit Service 54dbc3
				p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit Service 54dbc3
				p_dest_alias_guid->p_base_port->p_physp->port_num);
Packit Service 54dbc3
			status = IB_NOT_FOUND;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
	} else if (p_qos_level && p_qos_level->sl_set) {
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		 * No specific SL was requested, but there is an SL in
Packit Service 54dbc3
		 * QoS level.
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		sl = p_qos_level->sl;
Packit Service 54dbc3
Packit Service 54dbc3
		if (pkey && p_prtn && p_prtn->sl != p_qos_level->sl)
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
				"QoS level SL (%u) overrides partition SL (%u)\n",
Packit Service 54dbc3
				p_qos_level->sl, p_prtn->sl);
Packit Service 54dbc3
Packit Service 54dbc3
	} else if (pkey) {
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		 * No specific SL in request or in QoS level - use partition SL
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		if (!p_prtn) {
Packit Service 54dbc3
			sl = OSM_DEFAULT_SL;
Packit Service 54dbc3
			/* this may be possible when pkey tables are created somehow in
Packit Service 54dbc3
			   previous runs or things are going wrong here */
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1C: "
Packit Service 54dbc3
				"No partition found for PKey 0x%04x - "
Packit Service 54dbc3
				"using default SL %d "
Packit Service 54dbc3
				"[%s port %d <-> %s port %d]\n",
Packit Service 54dbc3
				cl_ntoh16(pkey), sl,
Packit Service 54dbc3
				p_src_alias_guid->p_base_port->p_node->print_desc,
Packit Service 54dbc3
				p_src_alias_guid->p_base_port->p_physp->port_num,
Packit Service 54dbc3
				p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit Service 54dbc3
				p_dest_alias_guid->p_base_port->p_physp->port_num);
Packit Service 54dbc3
		} else
Packit Service 54dbc3
			sl = p_prtn->sl;
Packit Service 54dbc3
	} else if (sa->p_subn->opt.qos) {
Packit Service 54dbc3
		if (valid_sl_mask & (1 << OSM_DEFAULT_SL))
Packit Service 54dbc3
			sl = OSM_DEFAULT_SL;
Packit Service 54dbc3
		else {
Packit Service 54dbc3
			for (i = 0; i < IB_MAX_NUM_VLS; i++)
Packit Service 54dbc3
				if (valid_sl_mask & (1 << i))
Packit Service 54dbc3
					break;
Packit Service 54dbc3
			sl = i;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	} else
Packit Service 54dbc3
		sl = OSM_DEFAULT_SL;
Packit Service 54dbc3
Packit Service 54dbc3
	if (sa->p_subn->opt.qos && !(valid_sl_mask & (1 << sl))) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F24: "
Packit Service 54dbc3
			"Selected SL (%u) leads to VL15 "
Packit Service 54dbc3
			"[%s port %d <-> %s port %d]\n",
Packit Service 54dbc3
			sl,
Packit Service 54dbc3
			p_src_alias_guid->p_base_port->p_node->print_desc,
Packit Service 54dbc3
			p_src_alias_guid->p_base_port->p_physp->port_num,
Packit Service 54dbc3
			p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit Service 54dbc3
			p_dest_alias_guid->p_base_port->p_physp->port_num);
Packit Service 54dbc3
		status = IB_NOT_FOUND;
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	 * If the routing engine wants to have a say in path SL selection,
Packit Service 54dbc3
	 * send the currently computed SL value as a hint and let the routing
Packit Service 54dbc3
	 * engine override it.
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	if (p_re && p_re->path_sl) {
Packit Service 54dbc3
		uint8_t pr_sl;
Packit Service 54dbc3
		pr_sl = sl;
Packit Service 54dbc3
Packit Service 54dbc3
		sl = p_re->path_sl(p_re->context, sl,
Packit Service 54dbc3
				   cl_hton16(src_lid_ho), cl_hton16(dest_lid_ho));
Packit Service 54dbc3
Packit Service 54dbc3
		if ((comp_mask & IB_PR_COMPMASK_SL) && (sl != pr_sl)) {
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F2A: "
Packit Service 54dbc3
				"Requested SL (%u) doesn't match SL calculated"
Packit Service 54dbc3
				"by routing engine (%u) "
Packit Service 54dbc3
				"[%s port %d <-> %s port %d]\n",
Packit Service 54dbc3
				pr_sl,
Packit Service 54dbc3
				sl,
Packit Service 54dbc3
				p_src_alias_guid->p_base_port->p_node->print_desc,
Packit Service 54dbc3
				p_src_alias_guid->p_base_port->p_physp->port_num,
Packit Service 54dbc3
				p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit Service 54dbc3
				p_dest_alias_guid->p_base_port->p_physp->port_num);
Packit Service 54dbc3
			status = IB_NOT_FOUND;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
	/* reset pkey when raw traffic */
Packit Service 54dbc3
	if (comp_mask & IB_PR_COMPMASK_RAWTRAFFIC &&
Packit Service 54dbc3
	    cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31))
Packit Service 54dbc3
		pkey = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	p_parms->mtu = mtu;
Packit Service 54dbc3
	p_parms->rate = rate;
Packit Service 54dbc3
	p_parms->pkt_life = pkt_life;
Packit Service 54dbc3
	p_parms->pkey = pkey;
Packit Service 54dbc3
	p_parms->sl = sl;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Path params: mtu = %u, rate = %u,"
Packit Service 54dbc3
		" packet lifetime = %u, pkey = 0x%04X, sl = %u\n",
Packit Service 54dbc3
		mtu, rate, pkt_life, cl_ntoh16(pkey), sl);
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	OSM_LOG_EXIT(sa->p_log);
Packit Service 54dbc3
	return status;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
ib_api_status_t osm_get_path_params(IN osm_sa_t * sa,
Packit Service 54dbc3
				    IN const osm_port_t * p_src_port,
Packit Service 54dbc3
				    IN const uint16_t slid_ho,
Packit Service 54dbc3
				    IN const osm_port_t * p_dest_port,
Packit Service 54dbc3
				    IN const uint16_t dlid_ho,
Packit Service 54dbc3
				    OUT osm_path_parms_t * p_parms)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_alias_guid_t *p_src_alias_guid, *p_dest_alias_guid;
Packit Service 54dbc3
	ib_path_rec_t pr;
Packit Service 54dbc3
Packit Service 54dbc3
	if (!p_src_port || !slid_ho || !p_dest_port || !dlid_ho)
Packit Service 54dbc3
		return IB_INVALID_PARAMETER;
Packit Service 54dbc3
Packit Service 54dbc3
	memset(&pr, 0, sizeof(ib_path_rec_t));
Packit Service 54dbc3
Packit Service 54dbc3
	p_src_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
Packit Service 54dbc3
						      osm_port_get_guid(p_src_port));
Packit Service 54dbc3
	p_dest_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
Packit Service 54dbc3
						       osm_port_get_guid(p_dest_port));
Packit Service 54dbc3
	return pr_rcv_get_path_parms(sa, &pr,
Packit Service 54dbc3
				     p_src_alias_guid, slid_ho,
Packit Service 54dbc3
				     p_dest_alias_guid, dlid_ho, 0, p_parms);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void pr_rcv_build_pr(IN osm_sa_t * sa,
Packit Service 54dbc3
			    IN const osm_alias_guid_t * p_src_alias_guid,
Packit Service 54dbc3
			    IN const osm_alias_guid_t * p_dest_alias_guid,
Packit Service 54dbc3
			    IN const ib_gid_t * p_sgid,
Packit Service 54dbc3
			    IN const ib_gid_t * p_dgid,
Packit Service 54dbc3
			    IN const uint16_t src_lid_ho,
Packit Service 54dbc3
			    IN const uint16_t dest_lid_ho,
Packit Service 54dbc3
			    IN const uint8_t preference,
Packit Service 54dbc3
			    IN const osm_path_parms_t * p_parms,
Packit Service 54dbc3
			    OUT ib_path_rec_t * p_pr)
Packit Service 54dbc3
{
Packit Service 54dbc3
	const osm_physp_t *p_src_physp = NULL, *p_dest_physp = NULL;
Packit Service 54dbc3
	osm_port_t *p_port;
Packit Service 54dbc3
	uint8_t rate, new_rate;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sa->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	if (p_dgid)
Packit Service 54dbc3
		p_pr->dgid = *p_dgid;
Packit Service 54dbc3
	else {
Packit Service 54dbc3
		p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
Packit Service 54dbc3
Packit Service 54dbc3
		p_pr->dgid.unicast.prefix =
Packit Service 54dbc3
		    osm_physp_get_subnet_prefix(p_dest_physp);
Packit Service 54dbc3
		p_pr->dgid.unicast.interface_id = p_dest_alias_guid->alias_guid;
Packit Service 54dbc3
	}
Packit Service 54dbc3
	if (p_sgid)
Packit Service 54dbc3
		p_pr->sgid = *p_sgid;
Packit Service 54dbc3
	else {
Packit Service 54dbc3
		p_src_physp = p_src_alias_guid->p_base_port->p_physp;
Packit Service 54dbc3
Packit Service 54dbc3
		p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix(p_src_physp);
Packit Service 54dbc3
		p_pr->sgid.unicast.interface_id = p_src_alias_guid->alias_guid;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	p_pr->dlid = cl_hton16(dest_lid_ho);
Packit Service 54dbc3
	p_pr->slid = cl_hton16(src_lid_ho);
Packit Service 54dbc3
Packit Service 54dbc3
	p_pr->hop_flow_raw &= cl_hton32(1 << 31);
Packit Service 54dbc3
Packit Service 54dbc3
	/* Only set HopLimit if going through a router */
Packit Service 54dbc3
	if (p_dgid)
Packit Service 54dbc3
		p_pr->hop_flow_raw |= cl_hton32(IB_HOPLIMIT_MAX);
Packit Service 54dbc3
Packit Service 54dbc3
	p_pr->pkey = p_parms->pkey;
Packit Service 54dbc3
	ib_path_rec_set_sl(p_pr, p_parms->sl);
Packit Service 54dbc3
	ib_path_rec_set_qos_class(p_pr, 0);
Packit Service 54dbc3
	p_pr->mtu = (uint8_t) (p_parms->mtu | 0x80);
Packit Service 54dbc3
	rate = p_parms->rate;
Packit Service 54dbc3
	if (sa->p_subn->opt.use_original_extended_sa_rates_only) {
Packit Service 54dbc3
		new_rate = ib_path_rate_max_12xedr(rate);
Packit Service 54dbc3
		if (new_rate != rate) {
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
				"Rate decreased from %u to %u\n",
Packit Service 54dbc3
				rate, new_rate);
Packit Service 54dbc3
			rate = new_rate;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	} else if (rate >= IB_PATH_RECORD_RATE_28_GBS) {
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		 * If one of the new 2x or HDR rates, make sure that
Packit Service 54dbc3
		 * src (and dest if reversible) ports support this
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		if (p_src_physp == NULL) {
Packit Service 54dbc3
			p_port = osm_get_port_by_lid_ho(sa->p_subn, src_lid_ho);
Packit Service 54dbc3
			if (p_port)
Packit Service 54dbc3
				p_src_physp = p_port->p_physp;
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		if (p_src_physp)
Packit Service 54dbc3
			rate = ib_path_rate_2x_hdr_fixups(&p_src_physp->port_info, rate);
Packit Service 54dbc3
		if (p_parms->reversible) {
Packit Service 54dbc3
			if (p_dest_physp == NULL) {
Packit Service 54dbc3
				p_port = osm_get_port_by_lid_ho(sa->p_subn,
Packit Service 54dbc3
								dest_lid_ho);
Packit Service 54dbc3
				if (p_port)
Packit Service 54dbc3
					p_dest_physp = p_port->p_physp;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			if (p_dest_physp)
Packit Service 54dbc3
				rate = ib_path_rate_2x_hdr_fixups(&p_dest_physp->port_info, rate);
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
	p_pr->rate = (uint8_t) (rate | 0x80);
Packit Service 54dbc3
Packit Service 54dbc3
	/* According to 1.2 spec definition Table 205 PacketLifeTime description,
Packit Service 54dbc3
	   for loopback paths, packetLifeTime shall be zero. */
Packit Service 54dbc3
	if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
Packit Service 54dbc3
		p_pr->pkt_life = 0x80;	/* loopback */
Packit Service 54dbc3
	else
Packit Service 54dbc3
		p_pr->pkt_life = (uint8_t) (p_parms->pkt_life | 0x80);
Packit Service 54dbc3
Packit Service 54dbc3
	p_pr->preference = preference;
Packit Service 54dbc3
Packit Service 54dbc3
	/* always return num_path = 0 so this is only the reversible component */
Packit Service 54dbc3
	if (p_parms->reversible)
Packit Service 54dbc3
		p_pr->num_path = 0x80;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_EXIT(sa->p_log);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static osm_sa_item_t *pr_rcv_get_lid_pair_path(IN osm_sa_t * sa,
Packit Service 54dbc3
					       IN const ib_path_rec_t * p_pr,
Packit Service 54dbc3
					       IN const osm_alias_guid_t * p_src_alias_guid,
Packit Service 54dbc3
					       IN const osm_alias_guid_t * p_dest_alias_guid,
Packit Service 54dbc3
					       IN const ib_gid_t * p_sgid,
Packit Service 54dbc3
					       IN const ib_gid_t * p_dgid,
Packit Service 54dbc3
					       IN const uint16_t src_lid_ho,
Packit Service 54dbc3
					       IN const uint16_t dest_lid_ho,
Packit Service 54dbc3
					       IN const ib_net64_t comp_mask,
Packit Service 54dbc3
					       IN const uint8_t preference)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_path_parms_t path_parms;
Packit Service 54dbc3
	osm_path_parms_t rev_path_parms;
Packit Service 54dbc3
	osm_sa_item_t *p_pr_item;
Packit Service 54dbc3
	ib_api_status_t status, rev_path_status;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sa->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID %u, Dest LID %u\n",
Packit Service 54dbc3
		src_lid_ho, dest_lid_ho);
Packit Service 54dbc3
Packit Service 54dbc3
	p_pr_item = malloc(SA_PR_RESP_SIZE);
Packit Service 54dbc3
	if (p_pr_item == NULL) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F01: "
Packit Service 54dbc3
			"Unable to allocate path record\n");
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
	memset(p_pr_item, 0, SA_PR_RESP_SIZE);
Packit Service 54dbc3
Packit Service 54dbc3
	status = pr_rcv_get_path_parms(sa, p_pr, p_src_alias_guid, src_lid_ho,
Packit Service 54dbc3
				       p_dest_alias_guid, dest_lid_ho,
Packit Service 54dbc3
				       comp_mask, &path_parms);
Packit Service 54dbc3
Packit Service 54dbc3
	if (status != IB_SUCCESS) {
Packit Service 54dbc3
		free(p_pr_item);
Packit Service 54dbc3
		p_pr_item = NULL;
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* now try the reversible path */
Packit Service 54dbc3
	rev_path_status = pr_rcv_get_path_parms(sa, p_pr, p_dest_alias_guid,
Packit Service 54dbc3
						dest_lid_ho, p_src_alias_guid,
Packit Service 54dbc3
						src_lid_ho, comp_mask,
Packit Service 54dbc3
						&rev_path_parms);
Packit Service 54dbc3
Packit Service 54dbc3
	path_parms.reversible = (rev_path_status == IB_SUCCESS);
Packit Service 54dbc3
Packit Service 54dbc3
	/* did we get a Reversible Path compmask ? */
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   NOTE that if the reversible component = 0, it is a don't care
Packit Service 54dbc3
	   rather than requiring non-reversible paths ...
Packit Service 54dbc3
	   see Vol1 Ver1.2 p900 l16
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	if ((comp_mask & IB_PR_COMPMASK_REVERSIBLE) &&
Packit Service 54dbc3
	    !path_parms.reversible && (p_pr->num_path & 0x80)) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"Requested reversible path but failed to get one\n");
Packit Service 54dbc3
		free(p_pr_item);
Packit Service 54dbc3
		p_pr_item = NULL;
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	pr_rcv_build_pr(sa, p_src_alias_guid, p_dest_alias_guid, p_sgid, p_dgid,
Packit Service 54dbc3
			src_lid_ho, dest_lid_ho, preference, &path_parms,
Packit Service 54dbc3
			&p_pr_item->resp.path_rec);
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	OSM_LOG_EXIT(sa->p_log);
Packit Service 54dbc3
	return p_pr_item;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void pr_rcv_get_port_pair_paths(IN osm_sa_t * sa,
Packit Service 54dbc3
				       IN const ib_sa_mad_t *sa_mad,
Packit Service 54dbc3
				       IN const osm_port_t * p_req_port,
Packit Service 54dbc3
				       IN const osm_alias_guid_t * p_src_alias_guid,
Packit Service 54dbc3
				       IN const osm_alias_guid_t * p_dest_alias_guid,
Packit Service 54dbc3
				       IN const ib_gid_t * p_sgid,
Packit Service 54dbc3
				       IN const ib_gid_t * p_dgid,
Packit Service 54dbc3
				       IN cl_qlist_t * p_list)
Packit Service 54dbc3
{
Packit Service 54dbc3
	const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
Packit Service 54dbc3
	ib_net64_t comp_mask = sa_mad->comp_mask;
Packit Service 54dbc3
	osm_sa_item_t *p_pr_item;
Packit Service 54dbc3
	uint16_t src_lid_min_ho;
Packit Service 54dbc3
	uint16_t src_lid_max_ho;
Packit Service 54dbc3
	uint16_t dest_lid_min_ho;
Packit Service 54dbc3
	uint16_t dest_lid_max_ho;
Packit Service 54dbc3
	uint16_t src_lid_ho;
Packit Service 54dbc3
	uint16_t dest_lid_ho;
Packit Service 54dbc3
	uint32_t path_num;
Packit Service 54dbc3
	uint8_t preference;
Packit Service 54dbc3
	unsigned iterations, src_offset, dest_offset;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sa->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
		"Src port 0x%016" PRIx64 ", Dst port 0x%016" PRIx64 "\n",
Packit Service 54dbc3
		cl_ntoh64(p_src_alias_guid->alias_guid),
Packit Service 54dbc3
		cl_ntoh64(p_dest_alias_guid->alias_guid));
Packit Service 54dbc3
Packit Service 54dbc3
	/* Check that the req_port, src_port and dest_port all share a
Packit Service 54dbc3
	   pkey. The check is done on the default physical port of the ports. */
Packit Service 54dbc3
	if (osm_port_share_pkey(sa->p_log, p_req_port,
Packit Service 54dbc3
				p_src_alias_guid->p_base_port,
Packit Service 54dbc3
				sa->p_subn->opt.allow_both_pkeys) == FALSE
Packit Service 54dbc3
	    || osm_port_share_pkey(sa->p_log, p_req_port,
Packit Service 54dbc3
				   p_dest_alias_guid->p_base_port,
Packit Service 54dbc3
				   sa->p_subn->opt.allow_both_pkeys) == FALSE
Packit Service 54dbc3
	    || osm_port_share_pkey(sa->p_log, p_src_alias_guid->p_base_port,
Packit Service 54dbc3
				   p_dest_alias_guid->p_base_port,
Packit Service 54dbc3
				   sa->p_subn->opt.allow_both_pkeys) == FALSE)
Packit Service 54dbc3
		/* One of the pairs doesn't share a pkey so the path is disqualified. */
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   We shouldn't be here if the paths are disqualified in some way...
Packit Service 54dbc3
	   Thus, we assume every possible connection is valid.
Packit Service 54dbc3
Packit Service 54dbc3
	   We desire to return high-quality paths first.
Packit Service 54dbc3
	   In OpenSM, higher quality means least overlap with other paths.
Packit Service 54dbc3
	   This is acheived in practice by returning paths with
Packit Service 54dbc3
	   different LID value on each end, which means these
Packit Service 54dbc3
	   paths are more redundant that paths with the same LID repeated
Packit Service 54dbc3
	   on one side.  For example, in OpenSM the paths between two
Packit Service 54dbc3
	   endpoints with LMC = 1 might be as follows:
Packit Service 54dbc3
Packit Service 54dbc3
	   Port A, LID 1 <-> Port B, LID 3
Packit Service 54dbc3
	   Port A, LID 1 <-> Port B, LID 4
Packit Service 54dbc3
	   Port A, LID 2 <-> Port B, LID 3
Packit Service 54dbc3
	   Port A, LID 2 <-> Port B, LID 4
Packit Service 54dbc3
Packit Service 54dbc3
	   The OpenSM unicast routing algorithms attempt to disperse each path
Packit Service 54dbc3
	   to as varied a physical path as is reasonable.  1<->3 and 1<->4 have
Packit Service 54dbc3
	   more physical overlap (hence less redundancy) than 1<->3 and 2<->4.
Packit Service 54dbc3
Packit Service 54dbc3
	   OpenSM ranks paths in three preference groups:
Packit Service 54dbc3
Packit Service 54dbc3
	   Preference Value    Description
Packit Service 54dbc3
	   ----------------    -------------------------------------------
Packit Service 54dbc3
	   0             Redundant in both directions with other
Packit Service 54dbc3
	   pref value = 0 paths
Packit Service 54dbc3
Packit Service 54dbc3
	   1             Redundant in one direction with other
Packit Service 54dbc3
	   pref value = 0 and pref value = 1 paths
Packit Service 54dbc3
Packit Service 54dbc3
	   2             Not redundant in either direction with
Packit Service 54dbc3
	   other paths
Packit Service 54dbc3
Packit Service 54dbc3
	   3-FF          Unused
Packit Service 54dbc3
Packit Service 54dbc3
	   SA clients don't need to know these details, only that the lower
Packit Service 54dbc3
	   preference paths are preferred, as stated in the spec.  The paths
Packit Service 54dbc3
	   may not actually be physically redundant depending on the topology
Packit Service 54dbc3
	   of the subnet, but the point of LMC > 0 is to offer redundancy,
Packit Service 54dbc3
	   so it is assumed that the subnet is physically appropriate for the
Packit Service 54dbc3
	   specified LMC value.  A more advanced implementation would inspect for
Packit Service 54dbc3
	   physical redundancy, but I'm not going to bother with that now.
Packit Service 54dbc3
	 */
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   Refine our search if the client specified end-point LIDs
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	if (comp_mask & IB_PR_COMPMASK_DLID)
Packit Service 54dbc3
		dest_lid_max_ho = dest_lid_min_ho = cl_ntoh16(p_pr->dlid);
Packit Service 54dbc3
	else
Packit Service 54dbc3
		osm_port_get_lid_range_ho(p_dest_alias_guid->p_base_port,
Packit Service 54dbc3
					  &dest_lid_min_ho, &dest_lid_max_ho);
Packit Service 54dbc3
Packit Service 54dbc3
	if (comp_mask & IB_PR_COMPMASK_SLID)
Packit Service 54dbc3
		src_lid_max_ho = src_lid_min_ho = cl_ntoh16(p_pr->slid);
Packit Service 54dbc3
	else
Packit Service 54dbc3
		osm_port_get_lid_range_ho(p_src_alias_guid->p_base_port,
Packit Service 54dbc3
					  &src_lid_min_ho, &src_lid_max_ho);
Packit Service 54dbc3
Packit Service 54dbc3
	if (src_lid_min_ho == 0) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"Obtained source LID of 0. No such LID possible "
Packit Service 54dbc3
			"(%s port %d)\n",
Packit Service 54dbc3
			p_src_alias_guid->p_base_port->p_node->print_desc,
Packit Service 54dbc3
			p_src_alias_guid->p_base_port->p_physp->port_num);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (dest_lid_min_ho == 0) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"Obtained destination LID of 0. No such LID possible "
Packit Service 54dbc3
			"(%s port %d)\n",
Packit Service 54dbc3
			p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit Service 54dbc3
			p_dest_alias_guid->p_base_port->p_physp->port_num);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
		"Src LIDs [%u-%u], Dest LIDs [%u-%u]\n",
Packit Service 54dbc3
		src_lid_min_ho, src_lid_max_ho,
Packit Service 54dbc3
		dest_lid_min_ho, dest_lid_max_ho);
Packit Service 54dbc3
Packit Service 54dbc3
	src_lid_ho = src_lid_min_ho;
Packit Service 54dbc3
	dest_lid_ho = dest_lid_min_ho;
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   Preferred paths come first in OpenSM
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	preference = 0;
Packit Service 54dbc3
	path_num = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	/* If SubnAdmGet, assume NumbPaths 1 (1.2 erratum) */
Packit Service 54dbc3
	if (sa_mad->method == IB_MAD_METHOD_GET)
Packit Service 54dbc3
		iterations = 1;
Packit Service 54dbc3
	else if (comp_mask & IB_PR_COMPMASK_NUMBPATH)
Packit Service 54dbc3
		iterations = ib_path_rec_num_path(p_pr);
Packit Service 54dbc3
	else
Packit Service 54dbc3
		iterations = (unsigned) (-1);
Packit Service 54dbc3
Packit Service 54dbc3
	while (path_num < iterations) {
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		   These paths are "fully redundant"
Packit Service 54dbc3
		 */
Packit Service 54dbc3
Packit Service 54dbc3
		p_pr_item = pr_rcv_get_lid_pair_path(sa, p_pr, p_src_alias_guid,
Packit Service 54dbc3
						     p_dest_alias_guid,
Packit Service 54dbc3
						     p_sgid, p_dgid,
Packit Service 54dbc3
						     src_lid_ho, dest_lid_ho,
Packit Service 54dbc3
						     comp_mask, preference);
Packit Service 54dbc3
Packit Service 54dbc3
		if (p_pr_item) {
Packit Service 54dbc3
			cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
Packit Service 54dbc3
			++path_num;
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		if (++src_lid_ho > src_lid_max_ho)
Packit Service 54dbc3
			break;
Packit Service 54dbc3
Packit Service 54dbc3
		if (++dest_lid_ho > dest_lid_max_ho)
Packit Service 54dbc3
			break;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   Check if we've accumulated all the paths that the user cares to see
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	if (path_num == iterations)
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   Don't bother reporting preference 1 paths for now.
Packit Service 54dbc3
	   It's more trouble than it's worth and can only occur
Packit Service 54dbc3
	   if ports have different LMC values, which isn't supported
Packit Service 54dbc3
	   by OpenSM right now anyway.
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	preference = 2;
Packit Service 54dbc3
	src_lid_ho = src_lid_min_ho;
Packit Service 54dbc3
	dest_lid_ho = dest_lid_min_ho;
Packit Service 54dbc3
	src_offset = 0;
Packit Service 54dbc3
	dest_offset = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   Iterate over the remaining paths
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	while (path_num < iterations) {
Packit Service 54dbc3
		dest_offset++;
Packit Service 54dbc3
		dest_lid_ho++;
Packit Service 54dbc3
Packit Service 54dbc3
		if (dest_lid_ho > dest_lid_max_ho) {
Packit Service 54dbc3
			src_offset++;
Packit Service 54dbc3
			src_lid_ho++;
Packit Service 54dbc3
Packit Service 54dbc3
			if (src_lid_ho > src_lid_max_ho)
Packit Service 54dbc3
				break;	/* done */
Packit Service 54dbc3
Packit Service 54dbc3
			dest_offset = 0;
Packit Service 54dbc3
			dest_lid_ho = dest_lid_min_ho;
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		   These paths are "fully non-redundant" with paths already
Packit Service 54dbc3
		   identified above and consequently not of much value.
Packit Service 54dbc3
Packit Service 54dbc3
		   Don't return paths we already identified above, as indicated
Packit Service 54dbc3
		   by the offset values being equal.
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		if (src_offset == dest_offset)
Packit Service 54dbc3
			continue;	/* already reported */
Packit Service 54dbc3
Packit Service 54dbc3
		p_pr_item = pr_rcv_get_lid_pair_path(sa, p_pr, p_src_alias_guid,
Packit Service 54dbc3
						     p_dest_alias_guid, p_sgid,
Packit Service 54dbc3
						     p_dgid, src_lid_ho,
Packit Service 54dbc3
						     dest_lid_ho, comp_mask,
Packit Service 54dbc3
						     preference);
Packit Service 54dbc3
Packit Service 54dbc3
		if (p_pr_item) {
Packit Service 54dbc3
			cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
Packit Service 54dbc3
			++path_num;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	OSM_LOG_EXIT(sa->p_log);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* Find the router port that is configured to handle this prefix, if any */
Packit Service 54dbc3
static ib_net64_t find_router(const osm_sa_t *sa, ib_net64_t prefix)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_prefix_route_t *route = NULL;
Packit Service 54dbc3
	osm_router_t *rtr;
Packit Service 54dbc3
	cl_qlist_t *l = &sa->p_subn->prefix_routes_list;
Packit Service 54dbc3
	cl_list_item_t *i;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "Non local DGID subnet prefix "
Packit Service 54dbc3
		"0x%016" PRIx64 "\n", cl_ntoh64(prefix));
Packit Service 54dbc3
Packit Service 54dbc3
	for (i = cl_qlist_head(l); i != cl_qlist_end(l); i = cl_qlist_next(i)) {
Packit Service 54dbc3
		osm_prefix_route_t *r = (osm_prefix_route_t *)i;
Packit Service 54dbc3
		if (!r->prefix || r->prefix == prefix) {
Packit Service 54dbc3
			route = r;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
	if (!route)
Packit Service 54dbc3
		return 0;
Packit Service 54dbc3
Packit Service 54dbc3
	if (route->guid == 0) /* first router */
Packit Service 54dbc3
		rtr = (osm_router_t *) cl_qmap_head(&sa->p_subn->rtr_guid_tbl);
Packit Service 54dbc3
	else
Packit Service 54dbc3
		rtr = (osm_router_t *) cl_qmap_get(&sa->p_subn->rtr_guid_tbl,
Packit Service 54dbc3
						   route->guid);
Packit Service 54dbc3
Packit Service 54dbc3
	if (rtr == (osm_router_t *) cl_qmap_end(&sa->p_subn->rtr_guid_tbl))
Packit Service 54dbc3
		return 0;
Packit Service 54dbc3
Packit Service 54dbc3
	return osm_port_get_guid(osm_router_get_port_ptr(rtr));
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
ib_net16_t osm_pr_get_end_points(IN osm_sa_t * sa,
Packit Service 54dbc3
				 IN const ib_sa_mad_t *sa_mad,
Packit Service 54dbc3
				 OUT const osm_alias_guid_t ** pp_src_alias_guid,
Packit Service 54dbc3
				 OUT const osm_alias_guid_t ** pp_dest_alias_guid,
Packit Service 54dbc3
				 OUT const osm_port_t ** pp_src_port,
Packit Service 54dbc3
				 OUT const osm_port_t ** pp_dest_port,
Packit Service 54dbc3
				 OUT const ib_gid_t ** pp_sgid,
Packit Service 54dbc3
				 OUT const ib_gid_t ** pp_dgid)
Packit Service 54dbc3
{
Packit Service 54dbc3
	const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
Packit Service 54dbc3
	ib_net64_t comp_mask = sa_mad->comp_mask;
Packit Service 54dbc3
	ib_net64_t dest_guid;
Packit Service 54dbc3
	ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sa->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   Determine what fields are valid and then get a pointer
Packit Service 54dbc3
	   to the source and destination port objects, if possible.
Packit Service 54dbc3
	 */
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   Check a few easy disqualifying cases up front before getting
Packit Service 54dbc3
	   into the endpoints.
Packit Service 54dbc3
	 */
Packit Service 54dbc3
Packit Service 54dbc3
	*pp_src_alias_guid = NULL;
Packit Service 54dbc3
	*pp_src_port = NULL;
Packit Service 54dbc3
	if (comp_mask & IB_PR_COMPMASK_SGID) {
Packit Service 54dbc3
		if (!ib_gid_is_link_local(&p_pr->sgid)) {
Packit Service 54dbc3
			if (ib_gid_get_subnet_prefix(&p_pr->sgid) !=
Packit Service 54dbc3
			    sa->p_subn->opt.subnet_prefix) {
Packit Service 54dbc3
				/*
Packit Service 54dbc3
				   This 'error' is the client's fault (bad gid)
Packit Service 54dbc3
				   so don't enter it as an error in our own log.
Packit Service 54dbc3
				   Return an error response to the client.
Packit Service 54dbc3
				 */
Packit Service 54dbc3
				OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
					"Non local SGID subnet prefix 0x%016"
Packit Service 54dbc3
					PRIx64 "\n",
Packit Service 54dbc3
					cl_ntoh64(p_pr->sgid.unicast.prefix));
Packit Service 54dbc3
				sa_status = IB_SA_MAD_STATUS_INVALID_GID;
Packit Service 54dbc3
				goto Exit;
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		*pp_src_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
Packit Service 54dbc3
								p_pr->sgid.unicast.interface_id);
Packit Service 54dbc3
		if (!*pp_src_alias_guid) {
Packit Service 54dbc3
			/*
Packit Service 54dbc3
			   This 'error' is the client's fault (bad gid) so
Packit Service 54dbc3
			   don't enter it as an error in our own log.
Packit Service 54dbc3
			   Return an error response to the client.
Packit Service 54dbc3
			 */
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
				"No source port with GUID 0x%016" PRIx64 "\n",
Packit Service 54dbc3
				cl_ntoh64(p_pr->sgid.unicast.interface_id));
Packit Service 54dbc3
			sa_status = IB_SA_MAD_STATUS_INVALID_GID;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
		if (pp_sgid)
Packit Service 54dbc3
			*pp_sgid = &p_pr->sgid;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (comp_mask & IB_PR_COMPMASK_SLID) {
Packit Service 54dbc3
		*pp_src_port = osm_get_port_by_lid(sa->p_subn, p_pr->slid);
Packit Service 54dbc3
		if (!*pp_src_port) {
Packit Service 54dbc3
			/*
Packit Service 54dbc3
			   This 'error' is the client's fault (bad lid) so
Packit Service 54dbc3
			   don't enter it as an error in our own log.
Packit Service 54dbc3
			   Return an error response to the client.
Packit Service 54dbc3
			 */
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "No source port "
Packit Service 54dbc3
				"with LID %u\n", cl_ntoh16(p_pr->slid));
Packit Service 54dbc3
			sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	*pp_dest_alias_guid = NULL;
Packit Service 54dbc3
	*pp_dest_port = NULL;
Packit Service 54dbc3
	if (comp_mask & IB_PR_COMPMASK_DGID) {
Packit Service 54dbc3
		if (!ib_gid_is_link_local(&p_pr->dgid) &&
Packit Service 54dbc3
		    !ib_gid_is_multicast(&p_pr->dgid) &&
Packit Service 54dbc3
		    ib_gid_get_subnet_prefix(&p_pr->dgid) !=
Packit Service 54dbc3
		    sa->p_subn->opt.subnet_prefix) {
Packit Service 54dbc3
			dest_guid = find_router(sa, p_pr->dgid.unicast.prefix);
Packit Service 54dbc3
			if (!dest_guid) {
Packit Service 54dbc3
				char gid_str[INET6_ADDRSTRLEN];
Packit Service 54dbc3
				OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
					"Off subnet DGID %s, but router not "
Packit Service 54dbc3
					"found\n",
Packit Service 54dbc3
					inet_ntop(AF_INET6, p_pr->dgid.raw,
Packit Service 54dbc3
						  gid_str, sizeof(gid_str)));
Packit Service 54dbc3
				sa_status = IB_SA_MAD_STATUS_INVALID_GID;
Packit Service 54dbc3
				goto Exit;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			if (pp_dgid)
Packit Service 54dbc3
				*pp_dgid = &p_pr->dgid;
Packit Service 54dbc3
		} else
Packit Service 54dbc3
			dest_guid = p_pr->dgid.unicast.interface_id;
Packit Service 54dbc3
Packit Service 54dbc3
		*pp_dest_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
Packit Service 54dbc3
								 dest_guid);
Packit Service 54dbc3
		if (!*pp_dest_alias_guid) {
Packit Service 54dbc3
			/*
Packit Service 54dbc3
			   This 'error' is the client's fault (bad gid) so
Packit Service 54dbc3
			   don't enter it as an error in our own log.
Packit Service 54dbc3
			   Return an error response to the client.
Packit Service 54dbc3
			 */
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
				"No dest port with GUID 0x%016" PRIx64 "\n",
Packit Service 54dbc3
				cl_ntoh64(dest_guid));
Packit Service 54dbc3
			sa_status = IB_SA_MAD_STATUS_INVALID_GID;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (comp_mask & IB_PR_COMPMASK_DLID) {
Packit Service 54dbc3
		*pp_dest_port = osm_get_port_by_lid(sa->p_subn, p_pr->dlid);
Packit Service 54dbc3
		if (!*pp_dest_port) {
Packit Service 54dbc3
			/*
Packit Service 54dbc3
			   This 'error' is the client's fault (bad lid)
Packit Service 54dbc3
			   so don't enter it as an error in our own log.
Packit Service 54dbc3
			   Return an error response to the client.
Packit Service 54dbc3
			 */
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "No dest port "
Packit Service 54dbc3
				"with LID %u\n", cl_ntoh16(p_pr->dlid));
Packit Service 54dbc3
			sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	OSM_LOG_EXIT(sa->p_log);
Packit Service 54dbc3
	return sa_status;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void pr_rcv_process_world(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
Packit Service 54dbc3
				 IN const osm_port_t * requester_port,
Packit Service 54dbc3
				 IN const ib_gid_t * p_sgid,
Packit Service 54dbc3
				 IN const ib_gid_t * p_dgid,
Packit Service 54dbc3
				 IN cl_qlist_t * p_list)
Packit Service 54dbc3
{
Packit Service 54dbc3
	const cl_qmap_t *p_tbl;
Packit Service 54dbc3
	const osm_alias_guid_t *p_dest_alias_guid, *p_src_alias_guid;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sa->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   Iterate the entire port space over itself.
Packit Service 54dbc3
	   A path record from a port to itself is legit, so no
Packit Service 54dbc3
	   need for a special case there.
Packit Service 54dbc3
Packit Service 54dbc3
	   We compute both A -> B and B -> A, since we don't have
Packit Service 54dbc3
	   any check to determine the reversability of the paths.
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	p_tbl = &sa->p_subn->alias_port_guid_tbl;
Packit Service 54dbc3
Packit Service 54dbc3
	p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
Packit Service 54dbc3
	while (p_dest_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
Packit Service 54dbc3
		p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
Packit Service 54dbc3
		while (p_src_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
Packit Service 54dbc3
			pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
Packit Service 54dbc3
						   p_src_alias_guid,
Packit Service 54dbc3
						   p_dest_alias_guid,
Packit Service 54dbc3
						   p_sgid, p_dgid, p_list);
Packit Service 54dbc3
			if (sa_mad->method == IB_MAD_METHOD_GET &&
Packit Service 54dbc3
			    cl_qlist_count(p_list) > 0)
Packit Service 54dbc3
				goto Exit;
Packit Service 54dbc3
Packit Service 54dbc3
			p_src_alias_guid =
Packit Service 54dbc3
			    (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		p_dest_alias_guid =
Packit Service 54dbc3
		    (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	OSM_LOG_EXIT(sa->p_log);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
void osm_pr_process_half(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
Packit Service 54dbc3
				IN const osm_port_t * requester_port,
Packit Service 54dbc3
				IN const osm_alias_guid_t * p_src_alias_guid,
Packit Service 54dbc3
				IN const osm_alias_guid_t * p_dest_alias_guid,
Packit Service 54dbc3
				IN const ib_gid_t * p_sgid,
Packit Service 54dbc3
				IN const ib_gid_t * p_dgid,
Packit Service 54dbc3
				IN cl_qlist_t * p_list)
Packit Service 54dbc3
{
Packit Service 54dbc3
	const cl_qmap_t *p_tbl;
Packit Service 54dbc3
	const osm_alias_guid_t *p_alias_guid;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sa->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   Iterate over every port, looking for matches...
Packit Service 54dbc3
	   A path record from a port to itself is legit, so no
Packit Service 54dbc3
	   need to special case that one.
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	p_tbl = &sa->p_subn->alias_port_guid_tbl;
Packit Service 54dbc3
Packit Service 54dbc3
	if (p_src_alias_guid) {
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		   The src port if fixed, so iterate over destination ports.
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		p_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
Packit Service 54dbc3
		while (p_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
Packit Service 54dbc3
			pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
Packit Service 54dbc3
						   p_src_alias_guid,
Packit Service 54dbc3
						   p_alias_guid,
Packit Service 54dbc3
						   p_sgid, p_dgid, p_list);
Packit Service 54dbc3
			if (sa_mad->method == IB_MAD_METHOD_GET &&
Packit Service 54dbc3
			    cl_qlist_count(p_list) > 0)
Packit Service 54dbc3
				break;
Packit Service 54dbc3
			p_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_alias_guid->map_item);
Packit Service 54dbc3
		}
Packit Service 54dbc3
	} else {
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		   The dest port if fixed, so iterate over source ports.
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		p_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
Packit Service 54dbc3
		while (p_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
Packit Service 54dbc3
			pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
Packit Service 54dbc3
						   p_alias_guid,
Packit Service 54dbc3
						   p_dest_alias_guid, p_sgid,
Packit Service 54dbc3
						   p_dgid, p_list);
Packit Service 54dbc3
			if (sa_mad->method == IB_MAD_METHOD_GET &&
Packit Service 54dbc3
			    cl_qlist_count(p_list) > 0)
Packit Service 54dbc3
				break;
Packit Service 54dbc3
			p_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_alias_guid->map_item);
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_EXIT(sa->p_log);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
void osm_pr_process_pair(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
Packit Service 54dbc3
				IN const osm_port_t * requester_port,
Packit Service 54dbc3
				IN const osm_alias_guid_t * p_src_alias_guid,
Packit Service 54dbc3
				IN const osm_alias_guid_t * p_dest_alias_guid,
Packit Service 54dbc3
				IN const ib_gid_t * p_sgid,
Packit Service 54dbc3
				IN const ib_gid_t * p_dgid,
Packit Service 54dbc3
				IN cl_qlist_t * p_list)
Packit Service 54dbc3
{
Packit Service 54dbc3
	OSM_LOG_ENTER(sa->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port, p_src_alias_guid,
Packit Service 54dbc3
				   p_dest_alias_guid, p_sgid, p_dgid, p_list);
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_EXIT(sa->p_log);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static ib_api_status_t pr_match_mgrp_attributes(IN osm_sa_t * sa,
Packit Service 54dbc3
						IN const ib_sa_mad_t * sa_mad,
Packit Service 54dbc3
						IN const osm_mgrp_t * p_mgrp)
Packit Service 54dbc3
{
Packit Service 54dbc3
	const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
Packit Service 54dbc3
	ib_net64_t comp_mask = sa_mad->comp_mask;
Packit Service 54dbc3
	const osm_port_t *port;
Packit Service 54dbc3
	ib_api_status_t status = IB_ERROR;
Packit Service 54dbc3
	uint32_t flow_label;
Packit Service 54dbc3
	uint8_t sl, hop_limit;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sa->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	/* check that MLID of the MC group matches the PathRecord DLID */
Packit Service 54dbc3
	if ((comp_mask & IB_PR_COMPMASK_DLID) && p_mgrp->mlid != p_pr->dlid) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"DLID 0x%x is not MLID 0x%x for MC group\n",
Packit Service 54dbc3
			 cl_ntoh16(p_pr->dlid), cl_ntoh16(p_mgrp->mlid));
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* If SGID and/or SLID specified, should validate as member of MC group */
Packit Service 54dbc3
	if (comp_mask & IB_PR_COMPMASK_SGID) {
Packit Service 54dbc3
		if (!osm_mgrp_get_mcm_alias_guid(p_mgrp,
Packit Service 54dbc3
						 p_pr->sgid.unicast.interface_id)) {
Packit Service 54dbc3
			char gid_str[INET6_ADDRSTRLEN];
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
				"SGID %s is not a member of MC group\n",
Packit Service 54dbc3
				inet_ntop(AF_INET6, p_pr->sgid.raw,
Packit Service 54dbc3
					  gid_str, sizeof gid_str));
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (comp_mask & IB_PR_COMPMASK_SLID) {
Packit Service 54dbc3
		port = osm_get_port_by_lid(sa->p_subn, p_pr->slid);
Packit Service 54dbc3
		if (!port || !osm_mgrp_get_mcm_port(p_mgrp, port->guid)) {
Packit Service 54dbc3
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
				"Either no port with SLID %u found or "
Packit Service 54dbc3
				"SLID not a member of MC group\n",
Packit Service 54dbc3
				cl_ntoh16(p_pr->slid));
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* Also, MTU, rate, packet lifetime, and raw traffic requested are not currently checked */
Packit Service 54dbc3
	if ((comp_mask & IB_PR_COMPMASK_PKEY) &&
Packit Service 54dbc3
	    p_pr->pkey != p_mgrp->mcmember_rec.pkey) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"Pkey 0x%x doesn't match MC group Pkey 0x%x\n",
Packit Service 54dbc3
			cl_ntoh16(p_pr->pkey),
Packit Service 54dbc3
			cl_ntoh16(p_mgrp->mcmember_rec.pkey));
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop,
Packit Service 54dbc3
				  &sl, &flow_label, &hop_limit);
Packit Service 54dbc3
Packit Service 54dbc3
	if ((comp_mask & IB_PR_COMPMASK_SL) && ib_path_rec_sl(p_pr) != sl) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"SL %d doesn't match MC group SL %d\n",
Packit Service 54dbc3
			ib_path_rec_sl(p_pr), sl);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* If SubnAdmGet, assume NumbPaths of 1 (1.2 erratum) */
Packit Service 54dbc3
	if ((comp_mask & IB_PR_COMPMASK_NUMBPATH) &&
Packit Service 54dbc3
	    sa_mad->method != IB_MAD_METHOD_GET &&
Packit Service 54dbc3
	    ib_path_rec_num_path(p_pr) == 0) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"Number of paths requested is 0\n");
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if ((comp_mask & IB_PR_COMPMASK_FLOWLABEL) &&
Packit Service 54dbc3
	    ib_path_rec_flow_lbl(p_pr) != flow_label) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"Flow label 0x%x doesn't match MC group "
Packit Service 54dbc3
			" flow label 0x%x\n",
Packit Service 54dbc3
			ib_path_rec_flow_lbl(p_pr), flow_label);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if ((comp_mask & IB_PR_COMPMASK_HOPLIMIT) &&
Packit Service 54dbc3
	    ib_path_rec_hop_limit(p_pr) != hop_limit) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"Hop limit %u doesn't match MC group hop limit %u\n",
Packit Service 54dbc3
			ib_path_rec_hop_limit(p_pr), hop_limit);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
Packit Service 54dbc3
	if ((comp_mask & IB_PR_COMPMASK_TCLASS) &&
Packit Service 54dbc3
	    p_pr->tclass != p_mgrp->mcmember_rec.tclass) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"TClass 0x%02x doesn't match MC group TClass 0x%02x\n",
Packit Service 54dbc3
			p_pr->tclass, p_mgrp->mcmember_rec.tclass);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	status = IB_SUCCESS;
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	OSM_LOG_EXIT(sa->p_log);
Packit Service 54dbc3
	return status;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void pr_process_multicast(osm_sa_t * sa, const ib_sa_mad_t *sa_mad,
Packit Service 54dbc3
				 cl_qlist_t *list)
Packit Service 54dbc3
{
Packit Service 54dbc3
	ib_path_rec_t *pr = ib_sa_mad_get_payload_ptr(sa_mad);
Packit Service 54dbc3
	osm_mgrp_t *mgrp;
Packit Service 54dbc3
	ib_api_status_t status;
Packit Service 54dbc3
	osm_sa_item_t *pr_item;
Packit Service 54dbc3
	uint32_t flow_label;
Packit Service 54dbc3
	uint8_t sl, hop_limit;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Multicast destination requested\n");
Packit Service 54dbc3
Packit Service 54dbc3
	mgrp = osm_get_mgrp_by_mgid(sa->p_subn, &pr->dgid);
Packit Service 54dbc3
	if (!mgrp) {
Packit Service 54dbc3
		char gid_str[INET6_ADDRSTRLEN];
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F09: "
Packit Service 54dbc3
			"No MC group found for PathRecord destination GID %s\n",
Packit Service 54dbc3
			inet_ntop(AF_INET6, pr->dgid.raw, gid_str,
Packit Service 54dbc3
				  sizeof gid_str));
Packit Service 54dbc3
		return;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* Make sure the rest of the PathRecord matches the MC group attributes */
Packit Service 54dbc3
	status = pr_match_mgrp_attributes(sa, sa_mad, mgrp);
Packit Service 54dbc3
	if (status != IB_SUCCESS) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F19: "
Packit Service 54dbc3
			"MC group attributes don't match PathRecord request\n");
Packit Service 54dbc3
		return;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	pr_item = malloc(SA_PR_RESP_SIZE);
Packit Service 54dbc3
	if (pr_item == NULL) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F18: "
Packit Service 54dbc3
			"Unable to allocate path record for MC group\n");
Packit Service 54dbc3
		return;
Packit Service 54dbc3
	}
Packit Service 54dbc3
	memset(pr_item, 0, sizeof(cl_list_item_t));
Packit Service 54dbc3
Packit Service 54dbc3
	/* Copy PathRecord request into response */
Packit Service 54dbc3
	pr_item->resp.path_rec = *pr;
Packit Service 54dbc3
Packit Service 54dbc3
	/* Now, use the MC info to cruft up the PathRecord response */
Packit Service 54dbc3
	pr_item->resp.path_rec.dgid = mgrp->mcmember_rec.mgid;
Packit Service 54dbc3
	pr_item->resp.path_rec.dlid = mgrp->mcmember_rec.mlid;
Packit Service 54dbc3
	pr_item->resp.path_rec.tclass = mgrp->mcmember_rec.tclass;
Packit Service 54dbc3
	pr_item->resp.path_rec.num_path = 1;
Packit Service 54dbc3
	pr_item->resp.path_rec.pkey = mgrp->mcmember_rec.pkey;
Packit Service 54dbc3
Packit Service 54dbc3
	/* MTU, rate, and packet lifetime should be exactly */
Packit Service 54dbc3
	pr_item->resp.path_rec.mtu = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.mtu;
Packit Service 54dbc3
	pr_item->resp.path_rec.rate = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.rate;
Packit Service 54dbc3
	pr_item->resp.path_rec.pkt_life = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.pkt_life;
Packit Service 54dbc3
Packit Service 54dbc3
	/* SL, Hop Limit, and Flow Label */
Packit Service 54dbc3
	ib_member_get_sl_flow_hop(mgrp->mcmember_rec.sl_flow_hop,
Packit Service 54dbc3
				  &sl, &flow_label, &hop_limit);
Packit Service 54dbc3
	ib_path_rec_set_sl(&pr_item->resp.path_rec, sl);
Packit Service 54dbc3
	ib_path_rec_set_qos_class(&pr_item->resp.path_rec, 0);
Packit Service 54dbc3
Packit Service 54dbc3
	/* HopLimit is not yet set in non link local MC groups */
Packit Service 54dbc3
	/* If it were, this would not be needed */
Packit Service 54dbc3
	if (ib_mgid_get_scope(&mgrp->mcmember_rec.mgid) !=
Packit Service 54dbc3
	    IB_MC_SCOPE_LINK_LOCAL)
Packit Service 54dbc3
		hop_limit = IB_HOPLIMIT_MAX;
Packit Service 54dbc3
Packit Service 54dbc3
	pr_item->resp.path_rec.hop_flow_raw =
Packit Service 54dbc3
	    cl_hton32(hop_limit) | (flow_label << 8);
Packit Service 54dbc3
Packit Service 54dbc3
	cl_qlist_insert_tail(list, &pr_item->list_item);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
void osm_pr_rcv_process(IN void *context, IN void *data)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_sa_t *sa = context;
Packit Service 54dbc3
	osm_madw_t *p_madw = data;
Packit Service 54dbc3
	const ib_sa_mad_t *p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
Packit Service 54dbc3
	ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(p_sa_mad);
Packit Service 54dbc3
	cl_qlist_t pr_list;
Packit Service 54dbc3
	const ib_gid_t *p_sgid = NULL, *p_dgid = NULL;
Packit Service 54dbc3
	const osm_alias_guid_t *p_src_alias_guid, *p_dest_alias_guid;
Packit Service 54dbc3
	const osm_port_t *p_src_port, *p_dest_port;
Packit Service 54dbc3
	osm_port_t *requester_port;
Packit Service 54dbc3
	uint8_t rate, mtu;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sa->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(p_madw);
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD);
Packit Service 54dbc3
Packit Service 54dbc3
	/* we only support SubnAdmGet and SubnAdmGetTable methods */
Packit Service 54dbc3
	if (p_sa_mad->method != IB_MAD_METHOD_GET &&
Packit Service 54dbc3
	    p_sa_mad->method != IB_MAD_METHOD_GETTABLE) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F17: "
Packit Service 54dbc3
			"Unsupported Method (%s) for PathRecord request\n",
Packit Service 54dbc3
			ib_get_sa_method_str(p_sa_mad->method));
Packit Service 54dbc3
		osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* Validate rate if supplied */
Packit Service 54dbc3
	if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_RATESELEC) &&
Packit Service 54dbc3
	    (p_sa_mad->comp_mask & IB_PR_COMPMASK_RATE)) {
Packit Service 54dbc3
		rate = ib_path_rec_rate(p_pr);
Packit Service 54dbc3
		if (!ib_rate_is_valid(rate)) {
Packit Service 54dbc3
			osm_sa_send_error(sa, p_madw,
Packit Service 54dbc3
					  IB_SA_MAD_STATUS_REQ_INVALID);
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
	/* Validate MTU if supplied */
Packit Service 54dbc3
	if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
Packit Service 54dbc3
	    (p_sa_mad->comp_mask & IB_PR_COMPMASK_MTU)) {
Packit Service 54dbc3
		mtu = ib_path_rec_mtu(p_pr);
Packit Service 54dbc3
		if (!ib_mtu_is_valid(mtu)) {
Packit Service 54dbc3
			osm_sa_send_error(sa, p_madw,
Packit Service 54dbc3
					  IB_SA_MAD_STATUS_REQ_INVALID);
Packit Service 54dbc3
			goto Exit;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* Make sure either none or both ServiceID parameters are supplied */
Packit Service 54dbc3
	if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_SERVICEID) != 0 &&
Packit Service 54dbc3
	    (p_sa_mad->comp_mask & IB_PR_COMPMASK_SERVICEID) !=
Packit Service 54dbc3
	     IB_PR_COMPMASK_SERVICEID) {
Packit Service 54dbc3
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INSUF_COMPS);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	cl_qlist_init(&pr_list);
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   Most SA functions (including this one) are read-only on the
Packit Service 54dbc3
	   subnet object, so we grab the lock non-exclusively.
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	cl_plock_acquire(sa->p_lock);
Packit Service 54dbc3
Packit Service 54dbc3
	/* update the requester physical port */
Packit Service 54dbc3
	requester_port = osm_get_port_by_mad_addr(sa->p_log, sa->p_subn,
Packit Service 54dbc3
						  osm_madw_get_mad_addr_ptr
Packit Service 54dbc3
						  (p_madw));
Packit Service 54dbc3
	if (requester_port == NULL) {
Packit Service 54dbc3
		cl_plock_release(sa->p_lock);
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F16: "
Packit Service 54dbc3
			"Cannot find requester physical port\n");
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"Requester port GUID 0x%" PRIx64 "\n",
Packit Service 54dbc3
			cl_ntoh64(osm_port_get_guid(requester_port)));
Packit Service 54dbc3
		osm_dump_path_record_v2(sa->p_log, p_pr, FILE_ID, OSM_LOG_DEBUG);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* Handle multicast destinations separately */
Packit Service 54dbc3
	if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_DGID) &&
Packit Service 54dbc3
	    ib_gid_is_multicast(&p_pr->dgid)) {
Packit Service 54dbc3
		pr_process_multicast(sa, p_sa_mad, &pr_list);
Packit Service 54dbc3
		goto Unlock;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Unicast destination requested\n");
Packit Service 54dbc3
Packit Service 54dbc3
	if (osm_pr_get_end_points(sa, p_sa_mad,
Packit Service 54dbc3
				  &p_src_alias_guid, &p_dest_alias_guid,
Packit Service 54dbc3
				  &p_src_port, &p_dest_port,
Packit Service 54dbc3
				  &p_sgid, &p_dgid) != IB_SA_MAD_STATUS_SUCCESS)
Packit Service 54dbc3
		goto Unlock;
Packit Service 54dbc3
Packit Service 54dbc3
	if (p_src_alias_guid && p_src_port &&
Packit Service 54dbc3
	    p_src_alias_guid->p_base_port != p_src_port) {
Packit Service 54dbc3
		cl_plock_release(sa->p_lock);
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
			"Requester port GUID 0x%" PRIx64 ": Port for SGUID "
Packit Service 54dbc3
			"0x%" PRIx64 " not same as port for SLID %u\n",
Packit Service 54dbc3
			cl_ntoh64(osm_port_get_guid(requester_port)),
Packit Service 54dbc3
			cl_ntoh64(p_pr->sgid.unicast.interface_id),
Packit Service 54dbc3
			cl_ntoh16(p_pr->slid));
Packit Service 54dbc3
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (p_dest_alias_guid && p_dest_port &&
Packit Service 54dbc3
	    p_dest_alias_guid->p_base_port != p_dest_port) {
Packit Service 54dbc3
		cl_plock_release(sa->p_lock);
Packit Service 54dbc3
		OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
			"Requester port GUID 0x%" PRIx64 ": Port for DGUID "
Packit Service 54dbc3
			"0x%" PRIx64 " not same as port for DLID %u\n",
Packit Service 54dbc3
			cl_ntoh64(osm_port_get_guid(requester_port)),
Packit Service 54dbc3
			cl_ntoh64(p_pr->dgid.unicast.interface_id),
Packit Service 54dbc3
			cl_ntoh16(p_pr->dlid));
Packit Service 54dbc3
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   What happens next depends on the type of endpoint information
Packit Service 54dbc3
	   that was specified....
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	if (p_src_alias_guid) {
Packit Service 54dbc3
		if (p_dest_alias_guid)
Packit Service 54dbc3
			osm_pr_process_pair(sa, p_sa_mad, requester_port,
Packit Service 54dbc3
					    p_src_alias_guid, p_dest_alias_guid,
Packit Service 54dbc3
					    p_sgid, p_dgid, &pr_list);
Packit Service 54dbc3
		else if (!p_dest_port)
Packit Service 54dbc3
			osm_pr_process_half(sa, p_sa_mad, requester_port,
Packit Service 54dbc3
					    p_src_alias_guid, NULL, p_sgid,
Packit Service 54dbc3
					    p_dgid, &pr_list);
Packit Service 54dbc3
		else {
Packit Service 54dbc3
			/* Get all alias GUIDs for the dest port */
Packit Service 54dbc3
			p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
Packit Service 54dbc3
			while (p_dest_alias_guid !=
Packit Service 54dbc3
			       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
Packit Service 54dbc3
				if (osm_get_port_by_alias_guid(sa->p_subn, p_dest_alias_guid->alias_guid) ==
Packit Service 54dbc3
				    p_dest_port)
Packit Service 54dbc3
					osm_pr_process_pair(sa, p_sa_mad,
Packit Service 54dbc3
							    requester_port,
Packit Service 54dbc3
							    p_src_alias_guid,
Packit Service 54dbc3
							    p_dest_alias_guid,
Packit Service 54dbc3
							    p_sgid, p_dgid,
Packit Service 54dbc3
							    &pr_list);
Packit Service 54dbc3
				if (p_sa_mad->method == IB_MAD_METHOD_GET &&
Packit Service 54dbc3
				    cl_qlist_count(&pr_list) > 0)
Packit Service 54dbc3
					break;
Packit Service 54dbc3
Packit Service 54dbc3
				p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
	} else {
Packit Service 54dbc3
		if (p_dest_alias_guid && !p_src_port)
Packit Service 54dbc3
			osm_pr_process_half(sa, p_sa_mad, requester_port,
Packit Service 54dbc3
					    NULL, p_dest_alias_guid, p_sgid,
Packit Service 54dbc3
					    p_dgid, &pr_list);
Packit Service 54dbc3
		else if (!p_src_port && !p_dest_port)
Packit Service 54dbc3
			/*
Packit Service 54dbc3
			   Katie, bar the door!
Packit Service 54dbc3
			 */
Packit Service 54dbc3
			pr_rcv_process_world(sa, p_sa_mad, requester_port,
Packit Service 54dbc3
					     p_sgid, p_dgid, &pr_list);
Packit Service 54dbc3
		else if (p_dest_alias_guid && p_src_port) {
Packit Service 54dbc3
			/* Get all alias GUIDs for the src port */
Packit Service 54dbc3
			p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
Packit Service 54dbc3
			while (p_src_alias_guid !=
Packit Service 54dbc3
			       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
Packit Service 54dbc3
				if (osm_get_port_by_alias_guid(sa->p_subn,
Packit Service 54dbc3
							       p_src_alias_guid->alias_guid) ==
Packit Service 54dbc3
				    p_src_port)
Packit Service 54dbc3
					osm_pr_process_pair(sa, p_sa_mad,
Packit Service 54dbc3
							    requester_port,
Packit Service 54dbc3
							    p_src_alias_guid,
Packit Service 54dbc3
							    p_dest_alias_guid,
Packit Service 54dbc3
							    p_sgid, p_dgid,
Packit Service 54dbc3
							    &pr_list);
Packit Service 54dbc3
				if (p_sa_mad->method == IB_MAD_METHOD_GET &&
Packit Service 54dbc3
				    cl_qlist_count(&pr_list) > 0)
Packit Service 54dbc3
					break;
Packit Service 54dbc3
				p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
Packit Service 54dbc3
			}
Packit Service 54dbc3
		} else if (p_src_port && !p_dest_port) {
Packit Service 54dbc3
			/* Get all alias GUIDs for the src port */
Packit Service 54dbc3
			p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
Packit Service 54dbc3
			while (p_src_alias_guid !=
Packit Service 54dbc3
			       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
Packit Service 54dbc3
				if (osm_get_port_by_alias_guid(sa->p_subn,
Packit Service 54dbc3
							       p_src_alias_guid->alias_guid) ==
Packit Service 54dbc3
				    p_src_port)
Packit Service 54dbc3
					osm_pr_process_half(sa, p_sa_mad,
Packit Service 54dbc3
							    requester_port,
Packit Service 54dbc3
							    p_src_alias_guid,
Packit Service 54dbc3
							    NULL, p_sgid,
Packit Service 54dbc3
							    p_dgid, &pr_list);
Packit Service 54dbc3
				p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
Packit Service 54dbc3
			}
Packit Service 54dbc3
		} else if (p_dest_port && !p_src_port) {
Packit Service 54dbc3
			/* Get all alias GUIDs for the dest port */
Packit Service 54dbc3
			p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
Packit Service 54dbc3
			while (p_dest_alias_guid !=
Packit Service 54dbc3
			       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
Packit Service 54dbc3
				if (osm_get_port_by_alias_guid(sa->p_subn,
Packit Service 54dbc3
							       p_dest_alias_guid->alias_guid) ==
Packit Service 54dbc3
				    p_dest_port)
Packit Service 54dbc3
					osm_pr_process_half(sa, p_sa_mad,
Packit Service 54dbc3
							    requester_port,
Packit Service 54dbc3
							    NULL,
Packit Service 54dbc3
							    p_dest_alias_guid,
Packit Service 54dbc3
							    p_sgid, p_dgid,
Packit Service 54dbc3
							    &pr_list);
Packit Service 54dbc3
				p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
Packit Service 54dbc3
			}
Packit Service 54dbc3
		} else {
Packit Service 54dbc3
			/* Get all alias GUIDs for the src port */
Packit Service 54dbc3
			p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
Packit Service 54dbc3
			while (p_src_alias_guid !=
Packit Service 54dbc3
			       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
Packit Service 54dbc3
				if (osm_get_port_by_alias_guid(sa->p_subn,
Packit Service 54dbc3
							       p_src_alias_guid->alias_guid) ==
Packit Service 54dbc3
				    p_src_port) {
Packit Service 54dbc3
					/* Get all alias GUIDs for the dest port */
Packit Service 54dbc3
					p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
Packit Service 54dbc3
					while (p_dest_alias_guid !=
Packit Service 54dbc3
					       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
Packit Service 54dbc3
						if (osm_get_port_by_alias_guid(sa->p_subn,
Packit Service 54dbc3
									       p_dest_alias_guid->alias_guid) ==
Packit Service 54dbc3
						    p_dest_port)
Packit Service 54dbc3
						osm_pr_process_pair(sa,
Packit Service 54dbc3
								    p_sa_mad,
Packit Service 54dbc3
								    requester_port,
Packit Service 54dbc3
								    p_src_alias_guid,
Packit Service 54dbc3
								    p_dest_alias_guid,
Packit Service 54dbc3
								    p_sgid,
Packit Service 54dbc3
								    p_dgid,
Packit Service 54dbc3
								    &pr_list);
Packit Service 54dbc3
						if (p_sa_mad->method == IB_MAD_METHOD_GET &&
Packit Service 54dbc3
						    cl_qlist_count(&pr_list) > 0)
Packit Service 54dbc3
							break;
Packit Service 54dbc3
						p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
Packit Service 54dbc3
					}
Packit Service 54dbc3
				}
Packit Service 54dbc3
				if (p_sa_mad->method == IB_MAD_METHOD_GET &&
Packit Service 54dbc3
				    cl_qlist_count(&pr_list) > 0)
Packit Service 54dbc3
					break;
Packit Service 54dbc3
				p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
Unlock:
Packit Service 54dbc3
	cl_plock_release(sa->p_lock);
Packit Service 54dbc3
Packit Service 54dbc3
	/* Now, (finally) respond to the PathRecord request */
Packit Service 54dbc3
	osm_sa_respond(sa, p_madw, sizeof(ib_path_rec_t), &pr_list);
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	OSM_LOG_EXIT(sa->p_log);
Packit Service 54dbc3
}