1d6b92ffaSHans Petter Selasky /*
2d6b92ffaSHans Petter Selasky  * Copyright (c) 2006-2009 Voltaire, Inc. All rights reserved.
3d6b92ffaSHans Petter Selasky  * Copyright (c) 2002-2011 Mellanox Technologies LTD. All rights reserved.
4d6b92ffaSHans Petter Selasky  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5d6b92ffaSHans Petter Selasky  * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
6d6b92ffaSHans Petter Selasky  *
7d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
8d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
9d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
10d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
11d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
12d6b92ffaSHans Petter Selasky  *
13d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
14d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
15d6b92ffaSHans Petter Selasky  *     conditions are met:
16d6b92ffaSHans Petter Selasky  *
17d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
18d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
19d6b92ffaSHans Petter Selasky  *        disclaimer.
20d6b92ffaSHans Petter Selasky  *
21d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
22d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
23d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
24d6b92ffaSHans Petter Selasky  *        provided with the distribution.
25d6b92ffaSHans Petter Selasky  *
26d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33d6b92ffaSHans Petter Selasky  * SOFTWARE.
34d6b92ffaSHans Petter Selasky  *
35d6b92ffaSHans Petter Selasky  */
36d6b92ffaSHans Petter Selasky 
37d6b92ffaSHans Petter Selasky /*
38d6b92ffaSHans Petter Selasky  * Abstract:
39d6b92ffaSHans Petter Selasky  * 	Implementation of osm_mpr_rcv_t.
40d6b92ffaSHans Petter Selasky  *	This object represents the MultiPath Record Receiver object.
41d6b92ffaSHans Petter Selasky  *	This object is part of the opensm family of objects.
42d6b92ffaSHans Petter Selasky  */
43d6b92ffaSHans Petter Selasky 
44d6b92ffaSHans Petter Selasky #if HAVE_CONFIG_H
45d6b92ffaSHans Petter Selasky #  include <config.h>
46d6b92ffaSHans Petter Selasky #endif				/* HAVE_CONFIG_H */
47d6b92ffaSHans Petter Selasky 
48d6b92ffaSHans Petter Selasky #if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
49d6b92ffaSHans Petter Selasky 
50d6b92ffaSHans Petter Selasky #include <string.h>
51d6b92ffaSHans Petter Selasky #include <iba/ib_types.h>
52d6b92ffaSHans Petter Selasky #include <complib/cl_qmap.h>
53d6b92ffaSHans Petter Selasky #include <complib/cl_passivelock.h>
54d6b92ffaSHans Petter Selasky #include <complib/cl_debug.h>
55d6b92ffaSHans Petter Selasky #include <complib/cl_qlist.h>
56d6b92ffaSHans Petter Selasky #include <opensm/osm_file_ids.h>
57d6b92ffaSHans Petter Selasky #define FILE_ID OSM_FILE_SA_MULTIPATH_RECORD_C
58d6b92ffaSHans Petter Selasky #include <vendor/osm_vendor_api.h>
59d6b92ffaSHans Petter Selasky #include <opensm/osm_port.h>
60d6b92ffaSHans Petter Selasky #include <opensm/osm_node.h>
61d6b92ffaSHans Petter Selasky #include <opensm/osm_switch.h>
62d6b92ffaSHans Petter Selasky #include <opensm/osm_partition.h>
63d6b92ffaSHans Petter Selasky #include <opensm/osm_helper.h>
64d6b92ffaSHans Petter Selasky #include <opensm/osm_qos_policy.h>
65d6b92ffaSHans Petter Selasky #include <opensm/osm_sa.h>
66d6b92ffaSHans Petter Selasky 
67d6b92ffaSHans Petter Selasky #define OSM_SA_MPR_MAX_NUM_PATH        127
68d6b92ffaSHans Petter Selasky #define MAX_HOPS 64
69d6b92ffaSHans Petter Selasky 
70d6b92ffaSHans Petter Selasky #define SA_MPR_RESP_SIZE SA_ITEM_RESP_SIZE(mpr_rec)
71d6b92ffaSHans Petter Selasky 
sa_multipath_rec_is_tavor_port(IN const osm_port_t * p_port)72d6b92ffaSHans Petter Selasky static boolean_t sa_multipath_rec_is_tavor_port(IN const osm_port_t * p_port)
73d6b92ffaSHans Petter Selasky {
74d6b92ffaSHans Petter Selasky 	osm_node_t const *p_node;
75d6b92ffaSHans Petter Selasky 	ib_net32_t vend_id;
76d6b92ffaSHans Petter Selasky 
77d6b92ffaSHans Petter Selasky 	p_node = p_port->p_node;
78d6b92ffaSHans Petter Selasky 	vend_id = ib_node_info_get_vendor_id(&p_node->node_info);
79d6b92ffaSHans Petter Selasky 
80d6b92ffaSHans Petter Selasky 	return ((p_node->node_info.device_id == CL_HTON16(23108)) &&
81d6b92ffaSHans Petter Selasky 		((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) ||
82d6b92ffaSHans Petter Selasky 		 (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) ||
83d6b92ffaSHans Petter Selasky 		 (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) ||
84d6b92ffaSHans Petter Selasky 		 (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE))));
85d6b92ffaSHans Petter Selasky }
86d6b92ffaSHans Petter Selasky 
87d6b92ffaSHans Petter Selasky static boolean_t
sa_multipath_rec_apply_tavor_mtu_limit(IN const ib_multipath_rec_t * p_mpr,IN const osm_port_t * p_src_port,IN const osm_port_t * p_dest_port,IN const ib_net64_t comp_mask)88d6b92ffaSHans Petter Selasky sa_multipath_rec_apply_tavor_mtu_limit(IN const ib_multipath_rec_t * p_mpr,
89d6b92ffaSHans Petter Selasky 				       IN const osm_port_t * p_src_port,
90d6b92ffaSHans Petter Selasky 				       IN const osm_port_t * p_dest_port,
91d6b92ffaSHans Petter Selasky 				       IN const ib_net64_t comp_mask)
92d6b92ffaSHans Petter Selasky {
93d6b92ffaSHans Petter Selasky 	uint8_t required_mtu;
94d6b92ffaSHans Petter Selasky 
95d6b92ffaSHans Petter Selasky 	/* only if at least one of the ports is a Tavor device */
96d6b92ffaSHans Petter Selasky 	if (!sa_multipath_rec_is_tavor_port(p_src_port) &&
97d6b92ffaSHans Petter Selasky 	    !sa_multipath_rec_is_tavor_port(p_dest_port))
98d6b92ffaSHans Petter Selasky 		return FALSE;
99d6b92ffaSHans Petter Selasky 
100d6b92ffaSHans Petter Selasky 	/*
101d6b92ffaSHans Petter Selasky 	   we can apply the patch if either:
102d6b92ffaSHans Petter Selasky 	   1. No MTU required
103d6b92ffaSHans Petter Selasky 	   2. Required MTU <
104d6b92ffaSHans Petter Selasky 	   3. Required MTU = 1K or 512 or 256
105d6b92ffaSHans Petter Selasky 	   4. Required MTU > 256 or 512
106d6b92ffaSHans Petter Selasky 	 */
107d6b92ffaSHans Petter Selasky 	required_mtu = ib_multipath_rec_mtu(p_mpr);
108d6b92ffaSHans Petter Selasky 	if ((comp_mask & IB_MPR_COMPMASK_MTUSELEC) &&
109d6b92ffaSHans Petter Selasky 	    (comp_mask & IB_MPR_COMPMASK_MTU)) {
110d6b92ffaSHans Petter Selasky 		switch (ib_multipath_rec_mtu_sel(p_mpr)) {
111d6b92ffaSHans Petter Selasky 		case 0:	/* must be greater than */
112d6b92ffaSHans Petter Selasky 		case 2:	/* exact match */
113d6b92ffaSHans Petter Selasky 			if (IB_MTU_LEN_1024 < required_mtu)
114d6b92ffaSHans Petter Selasky 				return FALSE;
115d6b92ffaSHans Petter Selasky 			break;
116d6b92ffaSHans Petter Selasky 
117d6b92ffaSHans Petter Selasky 		case 1:	/* must be less than */
118d6b92ffaSHans Petter Selasky 			/* can't be disqualified by this one */
119d6b92ffaSHans Petter Selasky 			break;
120d6b92ffaSHans Petter Selasky 
121d6b92ffaSHans Petter Selasky 		case 3:	/* largest available */
122d6b92ffaSHans Petter Selasky 			/* the ULP intentionally requested */
123d6b92ffaSHans Petter Selasky 			/* the largest MTU possible */
124d6b92ffaSHans Petter Selasky 			return FALSE;
125d6b92ffaSHans Petter Selasky 			break;
126d6b92ffaSHans Petter Selasky 
127d6b92ffaSHans Petter Selasky 		default:
128d6b92ffaSHans Petter Selasky 			/* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */
129d6b92ffaSHans Petter Selasky 			CL_ASSERT(FALSE);
130d6b92ffaSHans Petter Selasky 			break;
131d6b92ffaSHans Petter Selasky 		}
132d6b92ffaSHans Petter Selasky 	}
133d6b92ffaSHans Petter Selasky 
134d6b92ffaSHans Petter Selasky 	return TRUE;
135d6b92ffaSHans Petter Selasky }
136d6b92ffaSHans Petter Selasky 
mpr_rcv_get_path_parms(IN osm_sa_t * sa,IN const ib_multipath_rec_t * p_mpr,IN const osm_alias_guid_t * p_src_alias_guid,IN const osm_alias_guid_t * p_dest_alias_guid,IN const uint16_t src_lid_ho,IN const uint16_t dest_lid_ho,IN const ib_net64_t comp_mask,OUT osm_path_parms_t * p_parms)137d6b92ffaSHans Petter Selasky static ib_api_status_t mpr_rcv_get_path_parms(IN osm_sa_t * sa,
138d6b92ffaSHans Petter Selasky 					      IN const ib_multipath_rec_t *
139d6b92ffaSHans Petter Selasky 					      p_mpr,
140d6b92ffaSHans Petter Selasky 					      IN const osm_alias_guid_t * p_src_alias_guid,
141d6b92ffaSHans Petter Selasky 					      IN const osm_alias_guid_t * p_dest_alias_guid,
142d6b92ffaSHans Petter Selasky 					      IN const uint16_t src_lid_ho,
143d6b92ffaSHans Petter Selasky 					      IN const uint16_t dest_lid_ho,
144d6b92ffaSHans Petter Selasky 					      IN const ib_net64_t comp_mask,
145d6b92ffaSHans Petter Selasky 					      OUT osm_path_parms_t * p_parms)
146d6b92ffaSHans Petter Selasky {
147d6b92ffaSHans Petter Selasky 	const osm_node_t *p_node;
148d6b92ffaSHans Petter Selasky 	const osm_physp_t *p_physp, *p_physp0;
149d6b92ffaSHans Petter Selasky 	const osm_physp_t *p_src_physp;
150d6b92ffaSHans Petter Selasky 	const osm_physp_t *p_dest_physp;
151d6b92ffaSHans Petter Selasky 	const osm_prtn_t *p_prtn = NULL;
152d6b92ffaSHans Petter Selasky 	const ib_port_info_t *p_pi, *p_pi0;
153d6b92ffaSHans Petter Selasky 	ib_slvl_table_t *p_slvl_tbl;
154d6b92ffaSHans Petter Selasky 	ib_api_status_t status = IB_SUCCESS;
155d6b92ffaSHans Petter Selasky 	uint8_t mtu;
156d6b92ffaSHans Petter Selasky 	uint8_t rate, p0_extended_rate, dest_rate;
157d6b92ffaSHans Petter Selasky 	uint8_t pkt_life;
158d6b92ffaSHans Petter Selasky 	uint8_t required_mtu;
159d6b92ffaSHans Petter Selasky 	uint8_t required_rate;
160d6b92ffaSHans Petter Selasky 	ib_net16_t required_pkey;
161d6b92ffaSHans Petter Selasky 	uint8_t required_sl;
162d6b92ffaSHans Petter Selasky 	uint8_t required_pkt_life;
163d6b92ffaSHans Petter Selasky 	ib_net16_t dest_lid;
164d6b92ffaSHans Petter Selasky 	int hops = 0;
165d6b92ffaSHans Petter Selasky 	int in_port_num = 0;
166d6b92ffaSHans Petter Selasky 	uint8_t i;
167d6b92ffaSHans Petter Selasky 	osm_qos_level_t *p_qos_level = NULL;
168d6b92ffaSHans Petter Selasky 	uint16_t valid_sl_mask = 0xffff;
169d6b92ffaSHans Petter Selasky 	int extended, p0_extended;
170d6b92ffaSHans Petter Selasky 
171d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(sa->p_log);
172d6b92ffaSHans Petter Selasky 
173d6b92ffaSHans Petter Selasky 	dest_lid = cl_hton16(dest_lid_ho);
174d6b92ffaSHans Petter Selasky 
175d6b92ffaSHans Petter Selasky 	p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
176d6b92ffaSHans Petter Selasky 	p_physp = p_src_alias_guid->p_base_port->p_physp;
177d6b92ffaSHans Petter Selasky 	p_src_physp = p_physp;
178d6b92ffaSHans Petter Selasky 	p_pi = &p_physp->port_info;
179d6b92ffaSHans Petter Selasky 
180d6b92ffaSHans Petter Selasky 	mtu = ib_port_info_get_mtu_cap(p_pi);
181d6b92ffaSHans Petter Selasky 	extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
182d6b92ffaSHans Petter Selasky 	rate = ib_port_info_compute_rate(p_pi, extended);
183d6b92ffaSHans Petter Selasky 
184d6b92ffaSHans Petter Selasky 	/*
185d6b92ffaSHans Petter Selasky 	   Mellanox Tavor device performance is better using 1K MTU.
186d6b92ffaSHans Petter Selasky 	   If required MTU and MTU selector are such that 1K is OK
187d6b92ffaSHans Petter Selasky 	   and at least one end of the path is Tavor we override the
188d6b92ffaSHans Petter Selasky 	   port MTU with 1K.
189d6b92ffaSHans Petter Selasky 	 */
190d6b92ffaSHans Petter Selasky 	if (sa->p_subn->opt.enable_quirks &&
191d6b92ffaSHans Petter Selasky 	    sa_multipath_rec_apply_tavor_mtu_limit(p_mpr,
192d6b92ffaSHans Petter Selasky 						   p_src_alias_guid->p_base_port,
193d6b92ffaSHans Petter Selasky 						   p_dest_alias_guid->p_base_port,
194d6b92ffaSHans Petter Selasky 						   comp_mask))
195d6b92ffaSHans Petter Selasky 		if (mtu > IB_MTU_LEN_1024) {
196d6b92ffaSHans Petter Selasky 			mtu = IB_MTU_LEN_1024;
197d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
198d6b92ffaSHans Petter Selasky 				"Optimized Path MTU to 1K for Mellanox Tavor device\n");
199d6b92ffaSHans Petter Selasky 		}
200d6b92ffaSHans Petter Selasky 
201d6b92ffaSHans Petter Selasky 	/*
202d6b92ffaSHans Petter Selasky 	   Walk the subnet object from source to destination,
203d6b92ffaSHans Petter Selasky 	   tracking the most restrictive rate and mtu values along the way...
204d6b92ffaSHans Petter Selasky 
205d6b92ffaSHans Petter Selasky 	   If source port node is a switch, then p_physp should
206d6b92ffaSHans Petter Selasky 	   point to the port that routes the destination lid
207d6b92ffaSHans Petter Selasky 	 */
208d6b92ffaSHans Petter Selasky 
209d6b92ffaSHans Petter Selasky 	p_node = osm_physp_get_node_ptr(p_physp);
210d6b92ffaSHans Petter Selasky 
211d6b92ffaSHans Petter Selasky 	if (p_node->sw) {
212d6b92ffaSHans Petter Selasky 		/*
213d6b92ffaSHans Petter Selasky 		 * Source node is a switch.
214d6b92ffaSHans Petter Selasky 		 * Make sure that p_physp points to the out port of the
215d6b92ffaSHans Petter Selasky 		 * switch that routes to the destination lid (dest_lid_ho)
216d6b92ffaSHans Petter Selasky 		 */
217d6b92ffaSHans Petter Selasky 		p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
218d6b92ffaSHans Petter Selasky 		if (p_physp == 0) {
219d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4514: "
220d6b92ffaSHans Petter Selasky 				"Can't find routing from LID %u to LID %u on "
221d6b92ffaSHans Petter Selasky 				"switch %s (GUID 0x%016" PRIx64 ")\n",
222d6b92ffaSHans Petter Selasky 				src_lid_ho, dest_lid_ho, p_node->print_desc,
223d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_node_get_node_guid(p_node)));
224d6b92ffaSHans Petter Selasky 			status = IB_NOT_FOUND;
225d6b92ffaSHans Petter Selasky 			goto Exit;
226d6b92ffaSHans Petter Selasky 		}
227d6b92ffaSHans Petter Selasky 	}
228d6b92ffaSHans Petter Selasky 
229d6b92ffaSHans Petter Selasky 	if (sa->p_subn->opt.qos) {
230d6b92ffaSHans Petter Selasky 
231d6b92ffaSHans Petter Selasky 		/*
232d6b92ffaSHans Petter Selasky 		 * Whether this node is switch or CA, the IN port for
233d6b92ffaSHans Petter Selasky 		 * the sl2vl table is 0, because this is a source node.
234d6b92ffaSHans Petter Selasky 		 */
235d6b92ffaSHans Petter Selasky 		p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, 0);
236d6b92ffaSHans Petter Selasky 
237d6b92ffaSHans Petter Selasky 		/* update valid SLs that still exist on this route */
238d6b92ffaSHans Petter Selasky 		for (i = 0; i < IB_MAX_NUM_VLS; i++) {
239d6b92ffaSHans Petter Selasky 			if (valid_sl_mask & (1 << i) &&
240d6b92ffaSHans Petter Selasky 			    ib_slvl_table_get(p_slvl_tbl, i) == IB_DROP_VL)
241d6b92ffaSHans Petter Selasky 				valid_sl_mask &= ~(1 << i);
242d6b92ffaSHans Petter Selasky 		}
243d6b92ffaSHans Petter Selasky 		if (!valid_sl_mask) {
244d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
245d6b92ffaSHans Petter Selasky 				"All the SLs lead to VL15 on this path\n");
246d6b92ffaSHans Petter Selasky 			status = IB_NOT_FOUND;
247d6b92ffaSHans Petter Selasky 			goto Exit;
248d6b92ffaSHans Petter Selasky 		}
249d6b92ffaSHans Petter Selasky 	}
250d6b92ffaSHans Petter Selasky 
251d6b92ffaSHans Petter Selasky 	/*
252d6b92ffaSHans Petter Selasky 	 * Same as above
253d6b92ffaSHans Petter Selasky 	 */
254d6b92ffaSHans Petter Selasky 	p_node = osm_physp_get_node_ptr(p_dest_physp);
255d6b92ffaSHans Petter Selasky 
256d6b92ffaSHans Petter Selasky 	if (p_node->sw) {
257d6b92ffaSHans Petter Selasky 		/*
258d6b92ffaSHans Petter Selasky 		 * if destination is switch, we want p_dest_physp to point to port 0
259d6b92ffaSHans Petter Selasky 		 */
260d6b92ffaSHans Petter Selasky 		p_dest_physp =
261d6b92ffaSHans Petter Selasky 		    osm_switch_get_route_by_lid(p_node->sw, dest_lid);
262d6b92ffaSHans Petter Selasky 
263d6b92ffaSHans Petter Selasky 		if (p_dest_physp == 0) {
264d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4515: "
265d6b92ffaSHans Petter Selasky 				"Can't find routing from LID %u to LID %u on "
266d6b92ffaSHans Petter Selasky 				"switch %s (GUID 0x%016" PRIx64 ")\n",
267d6b92ffaSHans Petter Selasky 				src_lid_ho, dest_lid_ho, p_node->print_desc,
268d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_node_get_node_guid(p_node)));
269d6b92ffaSHans Petter Selasky 			status = IB_NOT_FOUND;
270d6b92ffaSHans Petter Selasky 			goto Exit;
271d6b92ffaSHans Petter Selasky 		}
272d6b92ffaSHans Petter Selasky 
273d6b92ffaSHans Petter Selasky 	}
274d6b92ffaSHans Petter Selasky 
275d6b92ffaSHans Petter Selasky 	/*
276d6b92ffaSHans Petter Selasky 	 * Now go through the path step by step
277d6b92ffaSHans Petter Selasky 	 */
278d6b92ffaSHans Petter Selasky 
279d6b92ffaSHans Petter Selasky 	while (p_physp != p_dest_physp) {
280d6b92ffaSHans Petter Selasky 
281d6b92ffaSHans Petter Selasky 		int tmp_pnum = p_physp->port_num;
282d6b92ffaSHans Petter Selasky 		p_node = osm_physp_get_node_ptr(p_physp);
283d6b92ffaSHans Petter Selasky 		p_physp = osm_physp_get_remote(p_physp);
284d6b92ffaSHans Petter Selasky 
285d6b92ffaSHans Petter Selasky 		if (p_physp == 0) {
286d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4505: "
287d6b92ffaSHans Petter Selasky 				"Can't find remote phys port of %s (GUID "
288d6b92ffaSHans Petter Selasky 				"0x%016" PRIx64 ") port %d "
289d6b92ffaSHans Petter Selasky 				"while routing from LID %u to LID %u",
290d6b92ffaSHans Petter Selasky 				p_node->print_desc,
291d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_node_get_node_guid(p_node)),
292d6b92ffaSHans Petter Selasky 				tmp_pnum, src_lid_ho, dest_lid_ho);
293d6b92ffaSHans Petter Selasky 			status = IB_ERROR;
294d6b92ffaSHans Petter Selasky 			goto Exit;
295d6b92ffaSHans Petter Selasky 		}
296d6b92ffaSHans Petter Selasky 
297d6b92ffaSHans Petter Selasky 		/* update number of hops traversed */
298d6b92ffaSHans Petter Selasky 		hops++;
299d6b92ffaSHans Petter Selasky 		if (hops > MAX_HOPS) {
300d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4520: "
301d6b92ffaSHans Petter Selasky 				"Path from GUID 0x%016" PRIx64 " (%s) to"
302d6b92ffaSHans Petter Selasky 				" lid %u GUID 0x%016" PRIx64 " (%s) needs"
303d6b92ffaSHans Petter Selasky 				" more than %d hops, max %d hops allowed\n",
304d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
305d6b92ffaSHans Petter Selasky 				p_src_physp->p_node->print_desc, dest_lid_ho,
306d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_physp_get_port_guid
307d6b92ffaSHans Petter Selasky 					  (p_dest_physp)),
308d6b92ffaSHans Petter Selasky 				p_dest_physp->p_node->print_desc, hops,
309d6b92ffaSHans Petter Selasky 				MAX_HOPS);
310d6b92ffaSHans Petter Selasky 			status = IB_NOT_FOUND;
311d6b92ffaSHans Petter Selasky 			goto Exit;
312d6b92ffaSHans Petter Selasky 		}
313d6b92ffaSHans Petter Selasky 
314d6b92ffaSHans Petter Selasky 		in_port_num = osm_physp_get_port_num(p_physp);
315d6b92ffaSHans Petter Selasky 
316d6b92ffaSHans Petter Selasky 		/*
317d6b92ffaSHans Petter Selasky 		   This is point to point case (no switch in between)
318d6b92ffaSHans Petter Selasky 		 */
319d6b92ffaSHans Petter Selasky 		if (p_physp == p_dest_physp)
320d6b92ffaSHans Petter Selasky 			break;
321d6b92ffaSHans Petter Selasky 
322d6b92ffaSHans Petter Selasky 		p_node = osm_physp_get_node_ptr(p_physp);
323d6b92ffaSHans Petter Selasky 
324d6b92ffaSHans Petter Selasky 		if (!p_node->sw) {
325d6b92ffaSHans Petter Selasky 			/*
326d6b92ffaSHans Petter Selasky 			   There is some sort of problem in the subnet object!
327d6b92ffaSHans Petter Selasky 			   If this isn't a switch, we should have reached
328d6b92ffaSHans Petter Selasky 			   the destination by now!
329d6b92ffaSHans Petter Selasky 			 */
330d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4503: "
331d6b92ffaSHans Petter Selasky 				"Internal error, bad path while routing "
332d6b92ffaSHans Petter Selasky 				"from %s (GUID: 0x%016"PRIx64") port %d "
333d6b92ffaSHans Petter Selasky 				"to %s (GUID: 0x%016"PRIx64") port %d; "
334d6b92ffaSHans Petter Selasky 				"ended at %s port %d\n",
335d6b92ffaSHans Petter Selasky 				p_src_alias_guid->p_base_port->p_node->print_desc,
336d6b92ffaSHans Petter Selasky 				cl_ntoh64(p_src_alias_guid->p_base_port->p_node->node_info.node_guid),
337d6b92ffaSHans Petter Selasky 				p_src_alias_guid->p_base_port->p_physp->port_num,
338d6b92ffaSHans Petter Selasky 				p_dest_alias_guid->p_base_port->p_node->print_desc,
339d6b92ffaSHans Petter Selasky 				cl_ntoh64(p_dest_alias_guid->p_base_port->p_node->node_info.node_guid),
340d6b92ffaSHans Petter Selasky 				p_dest_alias_guid->p_base_port->p_physp->port_num,
341d6b92ffaSHans Petter Selasky 				p_node->print_desc,
342d6b92ffaSHans Petter Selasky 				p_physp->port_num);
343d6b92ffaSHans Petter Selasky 			status = IB_ERROR;
344d6b92ffaSHans Petter Selasky 			goto Exit;
345d6b92ffaSHans Petter Selasky 		}
346d6b92ffaSHans Petter Selasky 
347d6b92ffaSHans Petter Selasky 		/*
348d6b92ffaSHans Petter Selasky 		   Check parameters for the ingress port in this switch.
349d6b92ffaSHans Petter Selasky 		 */
350d6b92ffaSHans Petter Selasky 		p_pi = &p_physp->port_info;
351d6b92ffaSHans Petter Selasky 
352d6b92ffaSHans Petter Selasky 		if (mtu > ib_port_info_get_mtu_cap(p_pi))
353d6b92ffaSHans Petter Selasky 			mtu = ib_port_info_get_mtu_cap(p_pi);
354d6b92ffaSHans Petter Selasky 
355d6b92ffaSHans Petter Selasky 		p_physp0 = osm_node_get_physp_ptr((osm_node_t *)p_node, 0);
356d6b92ffaSHans Petter Selasky 		p_pi0 = &p_physp0->port_info;
357d6b92ffaSHans Petter Selasky 		p0_extended = p_pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
358d6b92ffaSHans Petter Selasky 		p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
359d6b92ffaSHans Petter Selasky 		if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
360d6b92ffaSHans Petter Selasky 			rate = p0_extended_rate;
361d6b92ffaSHans Petter Selasky 
362d6b92ffaSHans Petter Selasky 		/*
363d6b92ffaSHans Petter Selasky 		   Continue with the egress port on this switch.
364d6b92ffaSHans Petter Selasky 		 */
365d6b92ffaSHans Petter Selasky 		p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
366d6b92ffaSHans Petter Selasky 		if (p_physp == 0) {
367d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4516: "
368d6b92ffaSHans Petter Selasky 				"Dead end path on switch "
369d6b92ffaSHans Petter Selasky 				"%s (GUID: 0x%016"PRIx64") to LID %u\n",
370d6b92ffaSHans Petter Selasky 				p_node->print_desc,
371d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_node_get_node_guid(p_node)),
372d6b92ffaSHans Petter Selasky 				dest_lid_ho);
373d6b92ffaSHans Petter Selasky 			status = IB_ERROR;
374d6b92ffaSHans Petter Selasky 			goto Exit;
375d6b92ffaSHans Petter Selasky 		}
376d6b92ffaSHans Petter Selasky 
377d6b92ffaSHans Petter Selasky 		p_pi = &p_physp->port_info;
378d6b92ffaSHans Petter Selasky 
379d6b92ffaSHans Petter Selasky 		if (mtu > ib_port_info_get_mtu_cap(p_pi))
380d6b92ffaSHans Petter Selasky 			mtu = ib_port_info_get_mtu_cap(p_pi);
381d6b92ffaSHans Petter Selasky 
382d6b92ffaSHans Petter Selasky 		p_physp0 = osm_node_get_physp_ptr((osm_node_t *)p_node, 0);
383d6b92ffaSHans Petter Selasky 		p_pi0 = &p_physp0->port_info;
384d6b92ffaSHans Petter Selasky 		p0_extended = p_pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
385d6b92ffaSHans Petter Selasky 		p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
386d6b92ffaSHans Petter Selasky 		if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
387d6b92ffaSHans Petter Selasky 			rate = p0_extended_rate;
388d6b92ffaSHans Petter Selasky 
389d6b92ffaSHans Petter Selasky 		if (sa->p_subn->opt.qos) {
390d6b92ffaSHans Petter Selasky 			/*
391d6b92ffaSHans Petter Selasky 			 * Check SL2VL table of the switch and update valid SLs
392d6b92ffaSHans Petter Selasky 			 */
393d6b92ffaSHans Petter Selasky 			p_slvl_tbl =
394d6b92ffaSHans Petter Selasky 			    osm_physp_get_slvl_tbl(p_physp, in_port_num);
395d6b92ffaSHans Petter Selasky 			for (i = 0; i < IB_MAX_NUM_VLS; i++) {
396d6b92ffaSHans Petter Selasky 				if (valid_sl_mask & (1 << i) &&
397d6b92ffaSHans Petter Selasky 				    ib_slvl_table_get(p_slvl_tbl,
398d6b92ffaSHans Petter Selasky 						      i) == IB_DROP_VL)
399d6b92ffaSHans Petter Selasky 					valid_sl_mask &= ~(1 << i);
400d6b92ffaSHans Petter Selasky 			}
401d6b92ffaSHans Petter Selasky 			if (!valid_sl_mask) {
402d6b92ffaSHans Petter Selasky 				OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
403d6b92ffaSHans Petter Selasky 					"All the SLs lead to VL15 "
404d6b92ffaSHans Petter Selasky 					"on this path\n");
405d6b92ffaSHans Petter Selasky 				status = IB_NOT_FOUND;
406d6b92ffaSHans Petter Selasky 				goto Exit;
407d6b92ffaSHans Petter Selasky 			}
408d6b92ffaSHans Petter Selasky 		}
409d6b92ffaSHans Petter Selasky 	}
410d6b92ffaSHans Petter Selasky 
411d6b92ffaSHans Petter Selasky 	/*
412d6b92ffaSHans Petter Selasky 	   p_physp now points to the destination
413d6b92ffaSHans Petter Selasky 	 */
414d6b92ffaSHans Petter Selasky 	p_pi = &p_physp->port_info;
415d6b92ffaSHans Petter Selasky 
416d6b92ffaSHans Petter Selasky 	if (mtu > ib_port_info_get_mtu_cap(p_pi))
417d6b92ffaSHans Petter Selasky 		mtu = ib_port_info_get_mtu_cap(p_pi);
418d6b92ffaSHans Petter Selasky 
419d6b92ffaSHans Petter Selasky 	extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
420d6b92ffaSHans Petter Selasky 	dest_rate = ib_port_info_compute_rate(p_pi, extended);
421d6b92ffaSHans Petter Selasky 	if (ib_path_compare_rates(rate, dest_rate) > 0)
422d6b92ffaSHans Petter Selasky 		rate = dest_rate;
423d6b92ffaSHans Petter Selasky 
424d6b92ffaSHans Petter Selasky 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
425d6b92ffaSHans Petter Selasky 		"Path min MTU = %u, min rate = %u\n", mtu, rate);
426d6b92ffaSHans Petter Selasky 
427d6b92ffaSHans Petter Selasky 	/*
428d6b92ffaSHans Petter Selasky 	 * Get QoS Level object according to the MultiPath request
429d6b92ffaSHans Petter Selasky 	 * and adjust MultiPath parameters according to QoS settings
430d6b92ffaSHans Petter Selasky 	 */
431d6b92ffaSHans Petter Selasky 	if (sa->p_subn->opt.qos && sa->p_subn->p_qos_policy &&
432d6b92ffaSHans Petter Selasky 	    (p_qos_level =
433d6b92ffaSHans Petter Selasky 	     osm_qos_policy_get_qos_level_by_mpr(sa->p_subn->p_qos_policy,
434d6b92ffaSHans Petter Selasky 						 p_mpr, p_src_physp,
435d6b92ffaSHans Petter Selasky 						 p_dest_physp, comp_mask))) {
436d6b92ffaSHans Petter Selasky 
437d6b92ffaSHans Petter Selasky 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
438d6b92ffaSHans Petter Selasky 			"MultiPathRecord request matches QoS Level '%s' (%s)\n",
439d6b92ffaSHans Petter Selasky 			p_qos_level->name,
440d6b92ffaSHans Petter Selasky 			p_qos_level->use ? p_qos_level->use : "no description");
441d6b92ffaSHans Petter Selasky 
442d6b92ffaSHans Petter Selasky 		if (p_qos_level->mtu_limit_set
443d6b92ffaSHans Petter Selasky 		    && (mtu > p_qos_level->mtu_limit))
444d6b92ffaSHans Petter Selasky 			mtu = p_qos_level->mtu_limit;
445d6b92ffaSHans Petter Selasky 
446d6b92ffaSHans Petter Selasky 		if (p_qos_level->rate_limit_set
447d6b92ffaSHans Petter Selasky 		    && (ib_path_compare_rates(rate, p_qos_level->rate_limit) > 0))
448d6b92ffaSHans Petter Selasky 			rate = p_qos_level->rate_limit;
449d6b92ffaSHans Petter Selasky 
450d6b92ffaSHans Petter Selasky 		if (p_qos_level->sl_set) {
451d6b92ffaSHans Petter Selasky 			required_sl = p_qos_level->sl;
452d6b92ffaSHans Petter Selasky 			if (!(valid_sl_mask & (1 << required_sl))) {
453d6b92ffaSHans Petter Selasky 				status = IB_NOT_FOUND;
454d6b92ffaSHans Petter Selasky 				goto Exit;
455d6b92ffaSHans Petter Selasky 			}
456d6b92ffaSHans Petter Selasky 		}
457d6b92ffaSHans Petter Selasky 	}
458d6b92ffaSHans Petter Selasky 
459d6b92ffaSHans Petter Selasky 	/*
460d6b92ffaSHans Petter Selasky 	   Determine if these values meet the user criteria
461d6b92ffaSHans Petter Selasky 	 */
462d6b92ffaSHans Petter Selasky 
463d6b92ffaSHans Petter Selasky 	/* we silently ignore cases where only the MTU selector is defined */
464d6b92ffaSHans Petter Selasky 	if ((comp_mask & IB_MPR_COMPMASK_MTUSELEC) &&
465d6b92ffaSHans Petter Selasky 	    (comp_mask & IB_MPR_COMPMASK_MTU)) {
466d6b92ffaSHans Petter Selasky 		required_mtu = ib_multipath_rec_mtu(p_mpr);
467d6b92ffaSHans Petter Selasky 		switch (ib_multipath_rec_mtu_sel(p_mpr)) {
468d6b92ffaSHans Petter Selasky 		case 0:	/* must be greater than */
469d6b92ffaSHans Petter Selasky 			if (mtu <= required_mtu)
470d6b92ffaSHans Petter Selasky 				status = IB_NOT_FOUND;
471d6b92ffaSHans Petter Selasky 			break;
472d6b92ffaSHans Petter Selasky 
473d6b92ffaSHans Petter Selasky 		case 1:	/* must be less than */
474d6b92ffaSHans Petter Selasky 			if (mtu >= required_mtu) {
475d6b92ffaSHans Petter Selasky 				/* adjust to use the highest mtu
476d6b92ffaSHans Petter Selasky 				   lower then the required one */
477d6b92ffaSHans Petter Selasky 				if (required_mtu > 1)
478d6b92ffaSHans Petter Selasky 					mtu = required_mtu - 1;
479d6b92ffaSHans Petter Selasky 				else
480d6b92ffaSHans Petter Selasky 					status = IB_NOT_FOUND;
481d6b92ffaSHans Petter Selasky 			}
482d6b92ffaSHans Petter Selasky 			break;
483d6b92ffaSHans Petter Selasky 
484d6b92ffaSHans Petter Selasky 		case 2:	/* exact match */
485d6b92ffaSHans Petter Selasky 			if (mtu < required_mtu)
486d6b92ffaSHans Petter Selasky 				status = IB_NOT_FOUND;
487d6b92ffaSHans Petter Selasky 			else
488d6b92ffaSHans Petter Selasky 				mtu = required_mtu;
489d6b92ffaSHans Petter Selasky 			break;
490d6b92ffaSHans Petter Selasky 
491d6b92ffaSHans Petter Selasky 		case 3:	/* largest available */
492d6b92ffaSHans Petter Selasky 			/* can't be disqualified by this one */
493d6b92ffaSHans Petter Selasky 			break;
494d6b92ffaSHans Petter Selasky 
495d6b92ffaSHans Petter Selasky 		default:
496d6b92ffaSHans Petter Selasky 			/* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */
497d6b92ffaSHans Petter Selasky 			CL_ASSERT(FALSE);
498d6b92ffaSHans Petter Selasky 			status = IB_ERROR;
499d6b92ffaSHans Petter Selasky 			break;
500d6b92ffaSHans Petter Selasky 		}
501d6b92ffaSHans Petter Selasky 	}
502d6b92ffaSHans Petter Selasky 	if (status != IB_SUCCESS)
503d6b92ffaSHans Petter Selasky 		goto Exit;
504d6b92ffaSHans Petter Selasky 
505d6b92ffaSHans Petter Selasky 	/* we silently ignore cases where only the Rate selector is defined */
506d6b92ffaSHans Petter Selasky 	if ((comp_mask & IB_MPR_COMPMASK_RATESELEC) &&
507d6b92ffaSHans Petter Selasky 	    (comp_mask & IB_MPR_COMPMASK_RATE)) {
508d6b92ffaSHans Petter Selasky 		required_rate = ib_multipath_rec_rate(p_mpr);
509d6b92ffaSHans Petter Selasky 		switch (ib_multipath_rec_rate_sel(p_mpr)) {
510d6b92ffaSHans Petter Selasky 		case 0:	/* must be greater than */
511d6b92ffaSHans Petter Selasky 			if (ib_path_compare_rates(rate, required_rate) <= 0)
512d6b92ffaSHans Petter Selasky 				status = IB_NOT_FOUND;
513d6b92ffaSHans Petter Selasky 			break;
514d6b92ffaSHans Petter Selasky 
515d6b92ffaSHans Petter Selasky 		case 1:	/* must be less than */
516d6b92ffaSHans Petter Selasky 			if (ib_path_compare_rates(rate, required_rate) >= 0) {
517d6b92ffaSHans Petter Selasky 				/* adjust the rate to use the highest rate
518d6b92ffaSHans Petter Selasky 				   lower then the required one */
519d6b92ffaSHans Petter Selasky 				rate = ib_path_rate_get_prev(required_rate);
520d6b92ffaSHans Petter Selasky 				if (!rate)
521d6b92ffaSHans Petter Selasky 					status = IB_NOT_FOUND;
522d6b92ffaSHans Petter Selasky 			}
523d6b92ffaSHans Petter Selasky 			break;
524d6b92ffaSHans Petter Selasky 
525d6b92ffaSHans Petter Selasky 		case 2:	/* exact match */
526d6b92ffaSHans Petter Selasky 			if (ib_path_compare_rates(rate, required_rate))
527d6b92ffaSHans Petter Selasky 				status = IB_NOT_FOUND;
528d6b92ffaSHans Petter Selasky 			else
529d6b92ffaSHans Petter Selasky 				rate = required_rate;
530d6b92ffaSHans Petter Selasky 			break;
531d6b92ffaSHans Petter Selasky 
532d6b92ffaSHans Petter Selasky 		case 3:	/* largest available */
533d6b92ffaSHans Petter Selasky 			/* can't be disqualified by this one */
534d6b92ffaSHans Petter Selasky 			break;
535d6b92ffaSHans Petter Selasky 
536d6b92ffaSHans Petter Selasky 		default:
537d6b92ffaSHans Petter Selasky 			/* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */
538d6b92ffaSHans Petter Selasky 			CL_ASSERT(FALSE);
539d6b92ffaSHans Petter Selasky 			status = IB_ERROR;
540d6b92ffaSHans Petter Selasky 			break;
541d6b92ffaSHans Petter Selasky 		}
542d6b92ffaSHans Petter Selasky 	}
543d6b92ffaSHans Petter Selasky 	if (status != IB_SUCCESS)
544d6b92ffaSHans Petter Selasky 		goto Exit;
545d6b92ffaSHans Petter Selasky 
546d6b92ffaSHans Petter Selasky 	/* Verify the pkt_life_time */
547d6b92ffaSHans Petter Selasky 	/* According to spec definition IBA 1.2 Table 205 PacketLifeTime description,
548d6b92ffaSHans Petter Selasky 	   for loopback paths, packetLifeTime shall be zero. */
549d6b92ffaSHans Petter Selasky 	if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
550d6b92ffaSHans Petter Selasky 		pkt_life = 0;	/* loopback */
551d6b92ffaSHans Petter Selasky 	else if (p_qos_level && p_qos_level->pkt_life_set)
552d6b92ffaSHans Petter Selasky 		pkt_life = p_qos_level->pkt_life;
553d6b92ffaSHans Petter Selasky 	else
554d6b92ffaSHans Petter Selasky 		pkt_life = sa->p_subn->opt.subnet_timeout;
555d6b92ffaSHans Petter Selasky 
556d6b92ffaSHans Petter Selasky 	/* we silently ignore cases where only the PktLife selector is defined */
557d6b92ffaSHans Petter Selasky 	if ((comp_mask & IB_MPR_COMPMASK_PKTLIFETIMESELEC) &&
558d6b92ffaSHans Petter Selasky 	    (comp_mask & IB_MPR_COMPMASK_PKTLIFETIME)) {
559d6b92ffaSHans Petter Selasky 		required_pkt_life = ib_multipath_rec_pkt_life(p_mpr);
560d6b92ffaSHans Petter Selasky 		switch (ib_multipath_rec_pkt_life_sel(p_mpr)) {
561d6b92ffaSHans Petter Selasky 		case 0:	/* must be greater than */
562d6b92ffaSHans Petter Selasky 			if (pkt_life <= required_pkt_life)
563d6b92ffaSHans Petter Selasky 				status = IB_NOT_FOUND;
564d6b92ffaSHans Petter Selasky 			break;
565d6b92ffaSHans Petter Selasky 
566d6b92ffaSHans Petter Selasky 		case 1:	/* must be less than */
567d6b92ffaSHans Petter Selasky 			if (pkt_life >= required_pkt_life) {
568d6b92ffaSHans Petter Selasky 				/* adjust the lifetime to use the highest possible
569d6b92ffaSHans Petter Selasky 				   lower then the required one */
570d6b92ffaSHans Petter Selasky 				if (required_pkt_life > 1)
571d6b92ffaSHans Petter Selasky 					pkt_life = required_pkt_life - 1;
572d6b92ffaSHans Petter Selasky 				else
573d6b92ffaSHans Petter Selasky 					status = IB_NOT_FOUND;
574d6b92ffaSHans Petter Selasky 			}
575d6b92ffaSHans Petter Selasky 			break;
576d6b92ffaSHans Petter Selasky 
577d6b92ffaSHans Petter Selasky 		case 2:	/* exact match */
578d6b92ffaSHans Petter Selasky 			if (pkt_life < required_pkt_life)
579d6b92ffaSHans Petter Selasky 				status = IB_NOT_FOUND;
580d6b92ffaSHans Petter Selasky 			else
581d6b92ffaSHans Petter Selasky 				pkt_life = required_pkt_life;
582d6b92ffaSHans Petter Selasky 			break;
583d6b92ffaSHans Petter Selasky 
584d6b92ffaSHans Petter Selasky 		case 3:	/* smallest available */
585d6b92ffaSHans Petter Selasky 			/* can't be disqualified by this one */
586d6b92ffaSHans Petter Selasky 			break;
587d6b92ffaSHans Petter Selasky 
588d6b92ffaSHans Petter Selasky 		default:
589d6b92ffaSHans Petter Selasky 			/* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */
590d6b92ffaSHans Petter Selasky 			CL_ASSERT(FALSE);
591d6b92ffaSHans Petter Selasky 			status = IB_ERROR;
592d6b92ffaSHans Petter Selasky 			break;
593d6b92ffaSHans Petter Selasky 		}
594d6b92ffaSHans Petter Selasky 	}
595d6b92ffaSHans Petter Selasky 
596d6b92ffaSHans Petter Selasky 	if (status != IB_SUCCESS)
597d6b92ffaSHans Petter Selasky 		goto Exit;
598d6b92ffaSHans Petter Selasky 
599d6b92ffaSHans Petter Selasky 	/*
600d6b92ffaSHans Petter Selasky 	 * set Pkey for this MultiPath record request
601d6b92ffaSHans Petter Selasky 	 */
602d6b92ffaSHans Petter Selasky 
603d6b92ffaSHans Petter Selasky 	if (comp_mask & IB_MPR_COMPMASK_RAWTRAFFIC &&
604d6b92ffaSHans Petter Selasky 	    cl_ntoh32(p_mpr->hop_flow_raw) & (1 << 31))
605d6b92ffaSHans Petter Selasky 		required_pkey =
606d6b92ffaSHans Petter Selasky 		    osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
607d6b92ffaSHans Petter Selasky 					       sa->p_subn->opt.allow_both_pkeys);
608d6b92ffaSHans Petter Selasky 
609d6b92ffaSHans Petter Selasky 	else if (comp_mask & IB_MPR_COMPMASK_PKEY) {
610d6b92ffaSHans Petter Selasky 		/*
611d6b92ffaSHans Petter Selasky 		 * MPR request has a specific pkey:
612d6b92ffaSHans Petter Selasky 		 * Check that source and destination share this pkey.
613d6b92ffaSHans Petter Selasky 		 * If QoS level has pkeys, check that this pkey exists
614d6b92ffaSHans Petter Selasky 		 * in the QoS level pkeys.
615d6b92ffaSHans Petter Selasky 		 * MPR returned pkey is the requested pkey.
616d6b92ffaSHans Petter Selasky 		 */
617d6b92ffaSHans Petter Selasky 		required_pkey = p_mpr->pkey;
618d6b92ffaSHans Petter Selasky 		if (!osm_physp_share_this_pkey
619d6b92ffaSHans Petter Selasky 		    (p_src_physp, p_dest_physp, required_pkey,
620d6b92ffaSHans Petter Selasky 		     sa->p_subn->opt.allow_both_pkeys)) {
621d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4518: "
622d6b92ffaSHans Petter Selasky 				"Ports src 0x%016"PRIx64" (%s port %d) "
623d6b92ffaSHans Petter Selasky 				"and dst 0x%016"PRIx64" (%s port %d) "
624d6b92ffaSHans Petter Selasky 				"do not share the specified PKey 0x%04x\n",
625d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
626d6b92ffaSHans Petter Selasky 				p_src_physp->p_node->print_desc,
627d6b92ffaSHans Petter Selasky 				p_src_physp->port_num,
628d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_physp_get_port_guid
629d6b92ffaSHans Petter Selasky 					  (p_dest_physp)),
630d6b92ffaSHans Petter Selasky 				p_dest_physp->p_node->print_desc,
631d6b92ffaSHans Petter Selasky 				p_dest_physp->port_num,
632d6b92ffaSHans Petter Selasky 				cl_ntoh16(required_pkey));
633d6b92ffaSHans Petter Selasky 			status = IB_NOT_FOUND;
634d6b92ffaSHans Petter Selasky 			goto Exit;
635d6b92ffaSHans Petter Selasky 		}
636d6b92ffaSHans Petter Selasky 		if (p_qos_level && p_qos_level->pkey_range_len &&
637d6b92ffaSHans Petter Selasky 		    !osm_qos_level_has_pkey(p_qos_level, required_pkey)) {
638d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451C: "
639d6b92ffaSHans Petter Selasky 				"Ports src 0x%016"PRIx64" (%s port %d) "
640d6b92ffaSHans Petter Selasky 				"and dst 0x%016"PRIx64" (%s port %d) "
641d6b92ffaSHans Petter Selasky 				"do not share specified PKey (0x%04x) as "
642d6b92ffaSHans Petter Selasky 				"defined by QoS level \"%s\"\n",
643d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
644d6b92ffaSHans Petter Selasky 				p_src_physp->p_node->print_desc,
645d6b92ffaSHans Petter Selasky 				p_src_physp->port_num,
646d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_physp_get_port_guid
647d6b92ffaSHans Petter Selasky 					  (p_dest_physp)),
648d6b92ffaSHans Petter Selasky 				p_dest_physp->p_node->print_desc,
649d6b92ffaSHans Petter Selasky 				p_dest_physp->port_num,
650d6b92ffaSHans Petter Selasky 				cl_ntoh16(required_pkey),
651d6b92ffaSHans Petter Selasky 				p_qos_level->name);
652d6b92ffaSHans Petter Selasky 			status = IB_NOT_FOUND;
653d6b92ffaSHans Petter Selasky 			goto Exit;
654d6b92ffaSHans Petter Selasky 		}
655d6b92ffaSHans Petter Selasky 
656d6b92ffaSHans Petter Selasky 	} else if (p_qos_level && p_qos_level->pkey_range_len) {
657d6b92ffaSHans Petter Selasky 		/*
658d6b92ffaSHans Petter Selasky 		 * MPR request doesn't have a specific pkey, but QoS level
659d6b92ffaSHans Petter Selasky 		 * has pkeys - get shared pkey from QoS level pkeys
660d6b92ffaSHans Petter Selasky 		 */
661d6b92ffaSHans Petter Selasky 		required_pkey = osm_qos_level_get_shared_pkey(p_qos_level,
662d6b92ffaSHans Petter Selasky 							      p_src_physp,
663d6b92ffaSHans Petter Selasky 							      p_dest_physp,
664d6b92ffaSHans Petter Selasky 							      sa->p_subn->opt.allow_both_pkeys);
665d6b92ffaSHans Petter Selasky 		if (!required_pkey) {
666d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451D: "
667d6b92ffaSHans Petter Selasky 				"Ports src 0x%016"PRIx64" (%s port %d) "
668d6b92ffaSHans Petter Selasky 				"and dst 0x%016"PRIx64" (%s port %d) "
669d6b92ffaSHans Petter Selasky 				"do not share a PKey as defined by QoS "
670d6b92ffaSHans Petter Selasky 				"level \"%s\"\n",
671d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
672d6b92ffaSHans Petter Selasky 				p_src_physp->p_node->print_desc,
673d6b92ffaSHans Petter Selasky 				p_src_physp->port_num,
674d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_physp_get_port_guid
675d6b92ffaSHans Petter Selasky 					  (p_dest_physp)),
676d6b92ffaSHans Petter Selasky 				p_dest_physp->p_node->print_desc,
677d6b92ffaSHans Petter Selasky 				p_dest_physp->port_num,
678d6b92ffaSHans Petter Selasky 				p_qos_level->name);
679d6b92ffaSHans Petter Selasky 			status = IB_NOT_FOUND;
680d6b92ffaSHans Petter Selasky 			goto Exit;
681d6b92ffaSHans Petter Selasky 		}
682d6b92ffaSHans Petter Selasky 
683d6b92ffaSHans Petter Selasky 	} else {
684d6b92ffaSHans Petter Selasky 		/*
685d6b92ffaSHans Petter Selasky 		 * Neither MPR request nor QoS level have pkey.
686d6b92ffaSHans Petter Selasky 		 * Just get any shared pkey.
687d6b92ffaSHans Petter Selasky 		 */
688d6b92ffaSHans Petter Selasky 		required_pkey =
689d6b92ffaSHans Petter Selasky 		    osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
690d6b92ffaSHans Petter Selasky 					       sa->p_subn->opt.allow_both_pkeys);
691d6b92ffaSHans Petter Selasky 		if (!required_pkey) {
692d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4519: "
693d6b92ffaSHans Petter Selasky 				"Ports src 0x%016"PRIx64" (%s port %d) "
694d6b92ffaSHans Petter Selasky 				"and dst 0x%016"PRIx64" (%s port %d) "
695d6b92ffaSHans Petter Selasky 				"do not have any shared PKeys\n",
696d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
697d6b92ffaSHans Petter Selasky 				p_src_physp->p_node->print_desc,
698d6b92ffaSHans Petter Selasky 				p_src_physp->port_num,
699d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_physp_get_port_guid
700d6b92ffaSHans Petter Selasky 					  (p_dest_physp)),
701d6b92ffaSHans Petter Selasky 				p_dest_physp->p_node->print_desc,
702d6b92ffaSHans Petter Selasky 				p_dest_physp->port_num);
703d6b92ffaSHans Petter Selasky 			status = IB_NOT_FOUND;
704d6b92ffaSHans Petter Selasky 			goto Exit;
705d6b92ffaSHans Petter Selasky 		}
706d6b92ffaSHans Petter Selasky 	}
707d6b92ffaSHans Petter Selasky 
708d6b92ffaSHans Petter Selasky 	if (required_pkey) {
709d6b92ffaSHans Petter Selasky 		p_prtn =
710d6b92ffaSHans Petter Selasky 		    (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl,
711d6b92ffaSHans Petter Selasky 					       required_pkey &
712d6b92ffaSHans Petter Selasky 					       cl_ntoh16((uint16_t) ~ 0x8000));
713d6b92ffaSHans Petter Selasky 		if (p_prtn ==
714d6b92ffaSHans Petter Selasky 		    (osm_prtn_t *) cl_qmap_end(&sa->p_subn->prtn_pkey_tbl))
715d6b92ffaSHans Petter Selasky 			p_prtn = NULL;
716d6b92ffaSHans Petter Selasky 	}
717d6b92ffaSHans Petter Selasky 
718d6b92ffaSHans Petter Selasky 	/*
719d6b92ffaSHans Petter Selasky 	 * Set MultiPathRecord SL.
720d6b92ffaSHans Petter Selasky 	 */
721d6b92ffaSHans Petter Selasky 
722d6b92ffaSHans Petter Selasky 	if (comp_mask & IB_MPR_COMPMASK_SL) {
723d6b92ffaSHans Petter Selasky 		/*
724d6b92ffaSHans Petter Selasky 		 * Specific SL was requested
725d6b92ffaSHans Petter Selasky 		 */
726d6b92ffaSHans Petter Selasky 		required_sl = ib_multipath_rec_sl(p_mpr);
727d6b92ffaSHans Petter Selasky 
728d6b92ffaSHans Petter Selasky 		if (p_qos_level && p_qos_level->sl_set &&
729d6b92ffaSHans Petter Selasky 		    p_qos_level->sl != required_sl) {
730d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451E: "
731d6b92ffaSHans Petter Selasky 				"QoS constraints: required MultiPathRecord SL "
732d6b92ffaSHans Petter Selasky 				"(%u) doesn't match QoS policy \"%s\" SL (%u) "
733d6b92ffaSHans Petter Selasky 				"[%s port %d <-> %s port %d]\n", required_sl,
734d6b92ffaSHans Petter Selasky 				p_qos_level->name,
735d6b92ffaSHans Petter Selasky 				p_qos_level->sl,
736d6b92ffaSHans Petter Selasky 				p_src_alias_guid->p_base_port->p_node->print_desc,
737d6b92ffaSHans Petter Selasky 				p_src_alias_guid->p_base_port->p_physp->port_num,
738d6b92ffaSHans Petter Selasky 				p_dest_alias_guid->p_base_port->p_node->print_desc,
739d6b92ffaSHans Petter Selasky 				p_dest_alias_guid->p_base_port->p_physp->port_num);
740d6b92ffaSHans Petter Selasky 			status = IB_NOT_FOUND;
741d6b92ffaSHans Petter Selasky 			goto Exit;
742d6b92ffaSHans Petter Selasky 		}
743d6b92ffaSHans Petter Selasky 
744d6b92ffaSHans Petter Selasky 	} else if (p_qos_level && p_qos_level->sl_set) {
745d6b92ffaSHans Petter Selasky 		/*
746d6b92ffaSHans Petter Selasky 		 * No specific SL was requested,
747d6b92ffaSHans Petter Selasky 		 * but there is an SL in QoS level.
748d6b92ffaSHans Petter Selasky 		 */
749d6b92ffaSHans Petter Selasky 		required_sl = p_qos_level->sl;
750d6b92ffaSHans Petter Selasky 
751d6b92ffaSHans Petter Selasky 		if (required_pkey && p_prtn && p_prtn->sl != p_qos_level->sl)
752d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
753d6b92ffaSHans Petter Selasky 				"QoS level SL (%u) overrides partition SL (%u)\n",
754d6b92ffaSHans Petter Selasky 				p_qos_level->sl, p_prtn->sl);
755d6b92ffaSHans Petter Selasky 
756d6b92ffaSHans Petter Selasky 	} else if (required_pkey) {
757d6b92ffaSHans Petter Selasky 		/*
758d6b92ffaSHans Petter Selasky 		 * No specific SL in request or in QoS level - use partition SL
759d6b92ffaSHans Petter Selasky 		 */
760d6b92ffaSHans Petter Selasky 		p_prtn =
761d6b92ffaSHans Petter Selasky 		    (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl,
762d6b92ffaSHans Petter Selasky 					       required_pkey &
763d6b92ffaSHans Petter Selasky 					       cl_ntoh16((uint16_t) ~ 0x8000));
764d6b92ffaSHans Petter Selasky 		if (!p_prtn) {
765d6b92ffaSHans Petter Selasky 			required_sl = OSM_DEFAULT_SL;
766d6b92ffaSHans Petter Selasky 			/* this may be possible when pkey tables are created somehow in
767d6b92ffaSHans Petter Selasky 			   previous runs or things are going wrong here */
768d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451A: "
769d6b92ffaSHans Petter Selasky 				"No partition found for PKey 0x%04x - "
770d6b92ffaSHans Petter Selasky 				"using default SL %d "
771d6b92ffaSHans Petter Selasky 				"[%s port %d <-> %s port %d]\n",
772d6b92ffaSHans Petter Selasky 				cl_ntoh16(required_pkey), required_sl,
773d6b92ffaSHans Petter Selasky 				p_src_alias_guid->p_base_port->p_node->print_desc,
774d6b92ffaSHans Petter Selasky 				p_src_alias_guid->p_base_port->p_physp->port_num,
775d6b92ffaSHans Petter Selasky 				p_dest_alias_guid->p_base_port->p_node->print_desc,
776d6b92ffaSHans Petter Selasky 				p_dest_alias_guid->p_base_port->p_physp->port_num);
777d6b92ffaSHans Petter Selasky 		} else
778d6b92ffaSHans Petter Selasky 			required_sl = p_prtn->sl;
779d6b92ffaSHans Petter Selasky 
780d6b92ffaSHans Petter Selasky 	} else if (sa->p_subn->opt.qos) {
781d6b92ffaSHans Petter Selasky 		if (valid_sl_mask & (1 << OSM_DEFAULT_SL))
782d6b92ffaSHans Petter Selasky 			required_sl = OSM_DEFAULT_SL;
783d6b92ffaSHans Petter Selasky 		else {
784d6b92ffaSHans Petter Selasky 			for (i = 0; i < IB_MAX_NUM_VLS; i++)
785d6b92ffaSHans Petter Selasky 				if (valid_sl_mask & (1 << i))
786d6b92ffaSHans Petter Selasky 					break;
787d6b92ffaSHans Petter Selasky 			required_sl = i;
788d6b92ffaSHans Petter Selasky 		}
789d6b92ffaSHans Petter Selasky 	} else
790d6b92ffaSHans Petter Selasky 		required_sl = OSM_DEFAULT_SL;
791d6b92ffaSHans Petter Selasky 
792d6b92ffaSHans Petter Selasky 	if (sa->p_subn->opt.qos && !(valid_sl_mask & (1 << required_sl))) {
793d6b92ffaSHans Petter Selasky 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451F: "
794d6b92ffaSHans Petter Selasky 			"Selected SL (%u) leads to VL15 "
795d6b92ffaSHans Petter Selasky 			"[%s port %d <-> %s port %d]\n",
796d6b92ffaSHans Petter Selasky 			required_sl,
797d6b92ffaSHans Petter Selasky 			p_src_alias_guid->p_base_port->p_node->print_desc,
798d6b92ffaSHans Petter Selasky 			p_src_alias_guid->p_base_port->p_physp->port_num,
799d6b92ffaSHans Petter Selasky 			p_dest_alias_guid->p_base_port->p_node->print_desc,
800d6b92ffaSHans Petter Selasky 			p_dest_alias_guid->p_base_port->p_physp->port_num);
801d6b92ffaSHans Petter Selasky 		status = IB_NOT_FOUND;
802d6b92ffaSHans Petter Selasky 		goto Exit;
803d6b92ffaSHans Petter Selasky 	}
804d6b92ffaSHans Petter Selasky 
805d6b92ffaSHans Petter Selasky 	/* reset pkey when raw traffic */
806d6b92ffaSHans Petter Selasky 	if (comp_mask & IB_MPR_COMPMASK_RAWTRAFFIC &&
807d6b92ffaSHans Petter Selasky 	    cl_ntoh32(p_mpr->hop_flow_raw) & (1 << 31))
808d6b92ffaSHans Petter Selasky 		required_pkey = 0;
809d6b92ffaSHans Petter Selasky 
810d6b92ffaSHans Petter Selasky 	p_parms->mtu = mtu;
811d6b92ffaSHans Petter Selasky 	p_parms->rate = rate;
812d6b92ffaSHans Petter Selasky 	p_parms->pkey = required_pkey;
813d6b92ffaSHans Petter Selasky 	p_parms->pkt_life = pkt_life;
814d6b92ffaSHans Petter Selasky 	p_parms->sl = required_sl;
815d6b92ffaSHans Petter Selasky 	p_parms->hops = hops;
816d6b92ffaSHans Petter Selasky 
817d6b92ffaSHans Petter Selasky 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "MultiPath params:"
818d6b92ffaSHans Petter Selasky 		" mtu = %u, rate = %u, packet lifetime = %u,"
819d6b92ffaSHans Petter Selasky 		" pkey = 0x%04X, sl = %u, hops = %u\n", mtu, rate,
820d6b92ffaSHans Petter Selasky 		pkt_life, cl_ntoh16(required_pkey), required_sl, hops);
821d6b92ffaSHans Petter Selasky 
822d6b92ffaSHans Petter Selasky Exit:
823d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(sa->p_log);
824d6b92ffaSHans Petter Selasky 	return status;
825d6b92ffaSHans Petter Selasky }
826d6b92ffaSHans Petter Selasky 
mpr_rcv_build_pr(IN osm_sa_t * sa,IN const osm_alias_guid_t * p_src_alias_guid,IN const osm_alias_guid_t * p_dest_alias_guid,IN uint16_t src_lid_ho,IN uint16_t dest_lid_ho,IN uint8_t preference,IN const osm_path_parms_t * p_parms,OUT ib_path_rec_t * p_pr)827d6b92ffaSHans Petter Selasky static void mpr_rcv_build_pr(IN osm_sa_t * sa,
828d6b92ffaSHans Petter Selasky 			     IN const osm_alias_guid_t * p_src_alias_guid,
829d6b92ffaSHans Petter Selasky 			     IN const osm_alias_guid_t * p_dest_alias_guid,
830d6b92ffaSHans Petter Selasky 			     IN uint16_t src_lid_ho, IN uint16_t dest_lid_ho,
831d6b92ffaSHans Petter Selasky 			     IN uint8_t preference,
832d6b92ffaSHans Petter Selasky 			     IN const osm_path_parms_t * p_parms,
833d6b92ffaSHans Petter Selasky 			     OUT ib_path_rec_t * p_pr)
834d6b92ffaSHans Petter Selasky {
835d6b92ffaSHans Petter Selasky 	const osm_physp_t *p_src_physp, *p_dest_physp;
836d6b92ffaSHans Petter Selasky 
837d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(sa->p_log);
838d6b92ffaSHans Petter Selasky 
839d6b92ffaSHans Petter Selasky 	p_src_physp = p_src_alias_guid->p_base_port->p_physp;
840d6b92ffaSHans Petter Selasky 	p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
841d6b92ffaSHans Petter Selasky 
842d6b92ffaSHans Petter Selasky 	p_pr->dgid.unicast.prefix = osm_physp_get_subnet_prefix(p_dest_physp);
843d6b92ffaSHans Petter Selasky 	p_pr->dgid.unicast.interface_id = p_dest_alias_guid->alias_guid;
844d6b92ffaSHans Petter Selasky 
845d6b92ffaSHans Petter Selasky 	p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix(p_src_physp);
846d6b92ffaSHans Petter Selasky 	p_pr->sgid.unicast.interface_id = p_src_alias_guid->alias_guid;
847d6b92ffaSHans Petter Selasky 
848d6b92ffaSHans Petter Selasky 	p_pr->dlid = cl_hton16(dest_lid_ho);
849d6b92ffaSHans Petter Selasky 	p_pr->slid = cl_hton16(src_lid_ho);
850d6b92ffaSHans Petter Selasky 
851d6b92ffaSHans Petter Selasky 	p_pr->hop_flow_raw &= cl_hton32(1 << 31);
852d6b92ffaSHans Petter Selasky 
853d6b92ffaSHans Petter Selasky 	p_pr->pkey = p_parms->pkey;
854d6b92ffaSHans Petter Selasky 	ib_path_rec_set_qos_class(p_pr, 0);
855d6b92ffaSHans Petter Selasky 	ib_path_rec_set_sl(p_pr, p_parms->sl);
856d6b92ffaSHans Petter Selasky 	p_pr->mtu = (uint8_t) (p_parms->mtu | 0x80);
857d6b92ffaSHans Petter Selasky 	p_pr->rate = (uint8_t) (p_parms->rate | 0x80);
858d6b92ffaSHans Petter Selasky 
859d6b92ffaSHans Petter Selasky 	/* According to 1.2 spec definition Table 205 PacketLifeTime description,
860d6b92ffaSHans Petter Selasky 	   for loopback paths, packetLifeTime shall be zero. */
861d6b92ffaSHans Petter Selasky 	if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
862d6b92ffaSHans Petter Selasky 		p_pr->pkt_life = 0x80;	/* loopback */
863d6b92ffaSHans Petter Selasky 	else
864d6b92ffaSHans Petter Selasky 		p_pr->pkt_life = (uint8_t) (p_parms->pkt_life | 0x80);
865d6b92ffaSHans Petter Selasky 
866d6b92ffaSHans Petter Selasky 	p_pr->preference = preference;
867d6b92ffaSHans Petter Selasky 
868d6b92ffaSHans Petter Selasky 	/* always return num_path = 0 so this is only the reversible component */
869d6b92ffaSHans Petter Selasky 	if (p_parms->reversible)
870d6b92ffaSHans Petter Selasky 		p_pr->num_path = 0x80;
871d6b92ffaSHans Petter Selasky 
872d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(sa->p_log);
873d6b92ffaSHans Petter Selasky }
874d6b92ffaSHans Petter Selasky 
mpr_rcv_get_lid_pair_path(IN osm_sa_t * sa,IN const ib_multipath_rec_t * p_mpr,IN const osm_alias_guid_t * p_src_alias_guid,IN const osm_alias_guid_t * p_dest_alias_guid,IN const uint16_t src_lid_ho,IN const uint16_t dest_lid_ho,IN const ib_net64_t comp_mask,IN const uint8_t preference)875d6b92ffaSHans Petter Selasky static osm_sa_item_t *mpr_rcv_get_lid_pair_path(IN osm_sa_t * sa,
876d6b92ffaSHans Petter Selasky 						IN const ib_multipath_rec_t *
877d6b92ffaSHans Petter Selasky 						p_mpr,
878d6b92ffaSHans Petter Selasky 						IN const osm_alias_guid_t *
879d6b92ffaSHans Petter Selasky 						p_src_alias_guid,
880d6b92ffaSHans Petter Selasky 						IN const osm_alias_guid_t *
881d6b92ffaSHans Petter Selasky 						p_dest_alias_guid,
882d6b92ffaSHans Petter Selasky 						IN const uint16_t src_lid_ho,
883d6b92ffaSHans Petter Selasky 						IN const uint16_t dest_lid_ho,
884d6b92ffaSHans Petter Selasky 						IN const ib_net64_t comp_mask,
885d6b92ffaSHans Petter Selasky 						IN const uint8_t preference)
886d6b92ffaSHans Petter Selasky {
887d6b92ffaSHans Petter Selasky 	osm_path_parms_t path_parms;
888d6b92ffaSHans Petter Selasky 	osm_path_parms_t rev_path_parms;
889d6b92ffaSHans Petter Selasky 	osm_sa_item_t *p_pr_item;
890d6b92ffaSHans Petter Selasky 	ib_api_status_t status, rev_path_status;
891d6b92ffaSHans Petter Selasky 
892d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(sa->p_log);
893d6b92ffaSHans Petter Selasky 
894d6b92ffaSHans Petter Selasky 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID %u, Dest LID %u\n",
895d6b92ffaSHans Petter Selasky 		src_lid_ho, dest_lid_ho);
896d6b92ffaSHans Petter Selasky 
897d6b92ffaSHans Petter Selasky 	p_pr_item = malloc(SA_MPR_RESP_SIZE);
898d6b92ffaSHans Petter Selasky 	if (p_pr_item == NULL) {
899d6b92ffaSHans Petter Selasky 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4501: "
900d6b92ffaSHans Petter Selasky 			"Unable to allocate path record\n");
901d6b92ffaSHans Petter Selasky 		goto Exit;
902d6b92ffaSHans Petter Selasky 	}
903d6b92ffaSHans Petter Selasky 	memset(p_pr_item, 0, SA_MPR_RESP_SIZE);
904d6b92ffaSHans Petter Selasky 
905d6b92ffaSHans Petter Selasky 	status = mpr_rcv_get_path_parms(sa, p_mpr, p_src_alias_guid,
906d6b92ffaSHans Petter Selasky 					p_dest_alias_guid,
907d6b92ffaSHans Petter Selasky 					src_lid_ho, dest_lid_ho,
908d6b92ffaSHans Petter Selasky 					comp_mask, &path_parms);
909d6b92ffaSHans Petter Selasky 
910d6b92ffaSHans Petter Selasky 	if (status != IB_SUCCESS) {
911d6b92ffaSHans Petter Selasky 		free(p_pr_item);
912d6b92ffaSHans Petter Selasky 		p_pr_item = NULL;
913d6b92ffaSHans Petter Selasky 		goto Exit;
914d6b92ffaSHans Petter Selasky 	}
915d6b92ffaSHans Petter Selasky 
916d6b92ffaSHans Petter Selasky 	/* now try the reversible path */
917d6b92ffaSHans Petter Selasky 	rev_path_status = mpr_rcv_get_path_parms(sa, p_mpr, p_dest_alias_guid,
918d6b92ffaSHans Petter Selasky 						 p_src_alias_guid,
919d6b92ffaSHans Petter Selasky 						 dest_lid_ho, src_lid_ho,
920d6b92ffaSHans Petter Selasky 						 comp_mask, &rev_path_parms);
921d6b92ffaSHans Petter Selasky 	path_parms.reversible = (rev_path_status == IB_SUCCESS);
922d6b92ffaSHans Petter Selasky 
923d6b92ffaSHans Petter Selasky 	/* did we get a Reversible Path compmask ? */
924d6b92ffaSHans Petter Selasky 	/*
925d6b92ffaSHans Petter Selasky 	   NOTE that if the reversible component = 0, it is a don't care
926d6b92ffaSHans Petter Selasky 	   rather then requiring non-reversible paths ...
927d6b92ffaSHans Petter Selasky 	   see Vol1 Ver1.2 p900 l16
928d6b92ffaSHans Petter Selasky 	 */
929d6b92ffaSHans Petter Selasky 	if (comp_mask & IB_MPR_COMPMASK_REVERSIBLE) {
930d6b92ffaSHans Petter Selasky 		if ((!path_parms.reversible && (p_mpr->num_path & 0x80))) {
931d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
932d6b92ffaSHans Petter Selasky 				"Requested reversible path but failed to get one\n");
933d6b92ffaSHans Petter Selasky 
934d6b92ffaSHans Petter Selasky 			free(p_pr_item);
935d6b92ffaSHans Petter Selasky 			p_pr_item = NULL;
936d6b92ffaSHans Petter Selasky 			goto Exit;
937d6b92ffaSHans Petter Selasky 		}
938d6b92ffaSHans Petter Selasky 	}
939d6b92ffaSHans Petter Selasky 
940d6b92ffaSHans Petter Selasky 	p_pr_item->resp.mpr_rec.p_src_port = p_src_alias_guid->p_base_port;
941d6b92ffaSHans Petter Selasky 	p_pr_item->resp.mpr_rec.p_dest_port = p_dest_alias_guid->p_base_port;
942d6b92ffaSHans Petter Selasky 	p_pr_item->resp.mpr_rec.hops = path_parms.hops;
943d6b92ffaSHans Petter Selasky 
944d6b92ffaSHans Petter Selasky 	mpr_rcv_build_pr(sa, p_src_alias_guid, p_dest_alias_guid, src_lid_ho,
945d6b92ffaSHans Petter Selasky 			 dest_lid_ho, preference, &path_parms,
946d6b92ffaSHans Petter Selasky 			 &p_pr_item->resp.mpr_rec.path_rec);
947d6b92ffaSHans Petter Selasky 
948d6b92ffaSHans Petter Selasky Exit:
949d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(sa->p_log);
950d6b92ffaSHans Petter Selasky 	return p_pr_item;
951d6b92ffaSHans Petter Selasky }
952d6b92ffaSHans Petter Selasky 
mpr_rcv_get_port_pair_paths(IN osm_sa_t * sa,IN const ib_multipath_rec_t * p_mpr,IN const osm_port_t * p_req_port,IN const osm_alias_guid_t * p_src_alias_guid,IN const osm_alias_guid_t * p_dest_alias_guid,IN const uint32_t rem_paths,IN const ib_net64_t comp_mask,IN cl_qlist_t * p_list)953d6b92ffaSHans Petter Selasky static uint32_t mpr_rcv_get_port_pair_paths(IN osm_sa_t * sa,
954d6b92ffaSHans Petter Selasky 					    IN const ib_multipath_rec_t * p_mpr,
955d6b92ffaSHans Petter Selasky 					    IN const osm_port_t * p_req_port,
956d6b92ffaSHans Petter Selasky 					    IN const osm_alias_guid_t * p_src_alias_guid,
957d6b92ffaSHans Petter Selasky 					    IN const osm_alias_guid_t * p_dest_alias_guid,
958d6b92ffaSHans Petter Selasky 					    IN const uint32_t rem_paths,
959d6b92ffaSHans Petter Selasky 					    IN const ib_net64_t comp_mask,
960d6b92ffaSHans Petter Selasky 					    IN cl_qlist_t * p_list)
961d6b92ffaSHans Petter Selasky {
962d6b92ffaSHans Petter Selasky 	osm_sa_item_t *p_pr_item;
963d6b92ffaSHans Petter Selasky 	uint16_t src_lid_min_ho;
964d6b92ffaSHans Petter Selasky 	uint16_t src_lid_max_ho;
965d6b92ffaSHans Petter Selasky 	uint16_t dest_lid_min_ho;
966d6b92ffaSHans Petter Selasky 	uint16_t dest_lid_max_ho;
967d6b92ffaSHans Petter Selasky 	uint16_t src_lid_ho;
968d6b92ffaSHans Petter Selasky 	uint16_t dest_lid_ho;
969d6b92ffaSHans Petter Selasky 	uint32_t path_num = 0;
970d6b92ffaSHans Petter Selasky 	uint8_t preference;
971d6b92ffaSHans Petter Selasky 	unsigned src_offset, dest_offset;
972d6b92ffaSHans Petter Selasky 
973d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(sa->p_log);
974d6b92ffaSHans Petter Selasky 
975d6b92ffaSHans Petter Selasky 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
976d6b92ffaSHans Petter Selasky 		"Src port 0x%016" PRIx64 ", Dst port 0x%016" PRIx64 "\n",
977d6b92ffaSHans Petter Selasky 		cl_ntoh64(p_src_alias_guid->alias_guid),
978d6b92ffaSHans Petter Selasky 		cl_ntoh64(p_dest_alias_guid->alias_guid));
979d6b92ffaSHans Petter Selasky 
980d6b92ffaSHans Petter Selasky 	/* Check that the req_port, src_port and dest_port all share a
981d6b92ffaSHans Petter Selasky 	   pkey. The check is done on the default physical port of the ports. */
982d6b92ffaSHans Petter Selasky 	if (osm_port_share_pkey(sa->p_log, p_req_port,
983d6b92ffaSHans Petter Selasky 				p_src_alias_guid->p_base_port,
984d6b92ffaSHans Petter Selasky 				sa->p_subn->opt.allow_both_pkeys) == FALSE
985d6b92ffaSHans Petter Selasky 	    || osm_port_share_pkey(sa->p_log, p_req_port,
986d6b92ffaSHans Petter Selasky 				   p_dest_alias_guid->p_base_port,
987d6b92ffaSHans Petter Selasky 				   sa->p_subn->opt.allow_both_pkeys) == FALSE
988d6b92ffaSHans Petter Selasky 	    || osm_port_share_pkey(sa->p_log, p_src_alias_guid->p_base_port,
989d6b92ffaSHans Petter Selasky 				   p_dest_alias_guid->p_base_port,
990d6b92ffaSHans Petter Selasky 				   sa->p_subn->opt.allow_both_pkeys) == FALSE)
991d6b92ffaSHans Petter Selasky 		/* One of the pairs doesn't share a pkey so the path is disqualified. */
992d6b92ffaSHans Petter Selasky 		goto Exit;
993d6b92ffaSHans Petter Selasky 
994d6b92ffaSHans Petter Selasky 	/*
995d6b92ffaSHans Petter Selasky 	   We shouldn't be here if the paths are disqualified in some way...
996d6b92ffaSHans Petter Selasky 	   Thus, we assume every possible connection is valid.
997d6b92ffaSHans Petter Selasky 
998d6b92ffaSHans Petter Selasky 	   We desire to return high-quality paths first.
999d6b92ffaSHans Petter Selasky 	   In OpenSM, higher quality mean least overlap with other paths.
1000d6b92ffaSHans Petter Selasky 	   This is acheived in practice by returning paths with
1001d6b92ffaSHans Petter Selasky 	   different LID value on each end, which means these
1002d6b92ffaSHans Petter Selasky 	   paths are more redundant that paths with the same LID repeated
1003d6b92ffaSHans Petter Selasky 	   on one side.  For example, in OpenSM the paths between two
1004d6b92ffaSHans Petter Selasky 	   endpoints with LMC = 1 might be as follows:
1005d6b92ffaSHans Petter Selasky 
1006d6b92ffaSHans Petter Selasky 	   Port A, LID 1 <-> Port B, LID 3
1007d6b92ffaSHans Petter Selasky 	   Port A, LID 1 <-> Port B, LID 4
1008d6b92ffaSHans Petter Selasky 	   Port A, LID 2 <-> Port B, LID 3
1009d6b92ffaSHans Petter Selasky 	   Port A, LID 2 <-> Port B, LID 4
1010d6b92ffaSHans Petter Selasky 
1011d6b92ffaSHans Petter Selasky 	   The OpenSM unicast routing algorithms attempt to disperse each path
1012d6b92ffaSHans Petter Selasky 	   to as varied a physical path as is reasonable.  1<->3 and 1<->4 have
1013d6b92ffaSHans Petter Selasky 	   more physical overlap (hence less redundancy) than 1<->3 and 2<->4.
1014d6b92ffaSHans Petter Selasky 
1015d6b92ffaSHans Petter Selasky 	   OpenSM ranks paths in three preference groups:
1016d6b92ffaSHans Petter Selasky 
1017d6b92ffaSHans Petter Selasky 	   Preference Value           Description
1018d6b92ffaSHans Petter Selasky 	   ----------------           -------------------------------------------
1019d6b92ffaSHans Petter Selasky 	   0                  Redundant in both directions with other
1020d6b92ffaSHans Petter Selasky 	   pref value = 0 paths
1021d6b92ffaSHans Petter Selasky 
1022d6b92ffaSHans Petter Selasky 	   1                  Redundant in one direction with other
1023d6b92ffaSHans Petter Selasky 	   pref value = 0 and pref value = 1 paths
1024d6b92ffaSHans Petter Selasky 
1025d6b92ffaSHans Petter Selasky 	   2                  Not redundant in either direction with
1026d6b92ffaSHans Petter Selasky 	   other paths
1027d6b92ffaSHans Petter Selasky 
1028d6b92ffaSHans Petter Selasky 	   3-FF                       Unused
1029d6b92ffaSHans Petter Selasky 
1030d6b92ffaSHans Petter Selasky 	   SA clients don't need to know these details, only that the lower
1031d6b92ffaSHans Petter Selasky 	   preference paths are preferred, as stated in the spec.  The paths
1032d6b92ffaSHans Petter Selasky 	   may not actually be physically redundant depending on the topology
1033d6b92ffaSHans Petter Selasky 	   of the subnet, but the point of LMC > 0 is to offer redundancy,
1034d6b92ffaSHans Petter Selasky 	   so I assume the subnet is physically appropriate for the specified
1035d6b92ffaSHans Petter Selasky 	   LMC value.  A more advanced implementation could inspect for physical
1036d6b92ffaSHans Petter Selasky 	   redundancy, but I'm not going to bother with that now.
1037d6b92ffaSHans Petter Selasky 	 */
1038d6b92ffaSHans Petter Selasky 
1039d6b92ffaSHans Petter Selasky 	osm_port_get_lid_range_ho(p_src_alias_guid->p_base_port,
1040d6b92ffaSHans Petter Selasky 				  &src_lid_min_ho, &src_lid_max_ho);
1041d6b92ffaSHans Petter Selasky 	osm_port_get_lid_range_ho(p_dest_alias_guid->p_base_port,
1042d6b92ffaSHans Petter Selasky 				  &dest_lid_min_ho, &dest_lid_max_ho);
1043d6b92ffaSHans Petter Selasky 
1044d6b92ffaSHans Petter Selasky 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID [%u-%u], Dest LID [%u-%u]\n",
1045d6b92ffaSHans Petter Selasky 		src_lid_min_ho, src_lid_max_ho,
1046d6b92ffaSHans Petter Selasky 		dest_lid_min_ho, dest_lid_max_ho);
1047d6b92ffaSHans Petter Selasky 
1048d6b92ffaSHans Petter Selasky 	src_lid_ho = src_lid_min_ho;
1049d6b92ffaSHans Petter Selasky 	dest_lid_ho = dest_lid_min_ho;
1050d6b92ffaSHans Petter Selasky 
1051d6b92ffaSHans Petter Selasky 	/*
1052d6b92ffaSHans Petter Selasky 	   Preferred paths come first in OpenSM
1053d6b92ffaSHans Petter Selasky 	 */
1054d6b92ffaSHans Petter Selasky 	preference = 0;
1055d6b92ffaSHans Petter Selasky 
1056d6b92ffaSHans Petter Selasky 	while (path_num < rem_paths) {
1057d6b92ffaSHans Petter Selasky 		/*
1058d6b92ffaSHans Petter Selasky 		   These paths are "fully redundant"
1059d6b92ffaSHans Petter Selasky 		 */
1060d6b92ffaSHans Petter Selasky 		p_pr_item = mpr_rcv_get_lid_pair_path(sa, p_mpr,
1061d6b92ffaSHans Petter Selasky 						      p_src_alias_guid,
1062d6b92ffaSHans Petter Selasky 						      p_dest_alias_guid,
1063d6b92ffaSHans Petter Selasky 						      src_lid_ho, dest_lid_ho,
1064d6b92ffaSHans Petter Selasky 						      comp_mask, preference);
1065d6b92ffaSHans Petter Selasky 
1066d6b92ffaSHans Petter Selasky 		if (p_pr_item) {
1067d6b92ffaSHans Petter Selasky 			cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
1068d6b92ffaSHans Petter Selasky 			++path_num;
1069d6b92ffaSHans Petter Selasky 		}
1070d6b92ffaSHans Petter Selasky 
1071d6b92ffaSHans Petter Selasky 		if (++src_lid_ho > src_lid_max_ho)
1072d6b92ffaSHans Petter Selasky 			break;
1073d6b92ffaSHans Petter Selasky 
1074d6b92ffaSHans Petter Selasky 		if (++dest_lid_ho > dest_lid_max_ho)
1075d6b92ffaSHans Petter Selasky 			break;
1076d6b92ffaSHans Petter Selasky 	}
1077d6b92ffaSHans Petter Selasky 
1078d6b92ffaSHans Petter Selasky 	/*
1079d6b92ffaSHans Petter Selasky 	   Check if we've accumulated all the paths that the user cares to see
1080d6b92ffaSHans Petter Selasky 	 */
1081d6b92ffaSHans Petter Selasky 	if (path_num == rem_paths)
1082d6b92ffaSHans Petter Selasky 		goto Exit;
1083d6b92ffaSHans Petter Selasky 
1084d6b92ffaSHans Petter Selasky 	/*
1085d6b92ffaSHans Petter Selasky 	   Don't bother reporting preference 1 paths for now.
1086d6b92ffaSHans Petter Selasky 	   It's more trouble than it's worth and can only occur
1087d6b92ffaSHans Petter Selasky 	   if ports have different LMC values, which isn't supported
1088d6b92ffaSHans Petter Selasky 	   by OpenSM right now anyway.
1089d6b92ffaSHans Petter Selasky 	 */
1090d6b92ffaSHans Petter Selasky 	preference = 2;
1091d6b92ffaSHans Petter Selasky 	src_lid_ho = src_lid_min_ho;
1092d6b92ffaSHans Petter Selasky 	dest_lid_ho = dest_lid_min_ho;
1093d6b92ffaSHans Petter Selasky 	src_offset = 0;
1094d6b92ffaSHans Petter Selasky 	dest_offset = 0;
1095d6b92ffaSHans Petter Selasky 
1096d6b92ffaSHans Petter Selasky 	/*
1097d6b92ffaSHans Petter Selasky 	   Iterate over the remaining paths
1098d6b92ffaSHans Petter Selasky 	 */
1099d6b92ffaSHans Petter Selasky 	while (path_num < rem_paths) {
1100d6b92ffaSHans Petter Selasky 		dest_offset++;
1101d6b92ffaSHans Petter Selasky 		dest_lid_ho++;
1102d6b92ffaSHans Petter Selasky 
1103d6b92ffaSHans Petter Selasky 		if (dest_lid_ho > dest_lid_max_ho) {
1104d6b92ffaSHans Petter Selasky 			src_offset++;
1105d6b92ffaSHans Petter Selasky 			src_lid_ho++;
1106d6b92ffaSHans Petter Selasky 
1107d6b92ffaSHans Petter Selasky 			if (src_lid_ho > src_lid_max_ho)
1108d6b92ffaSHans Petter Selasky 				break;	/* done */
1109d6b92ffaSHans Petter Selasky 
1110d6b92ffaSHans Petter Selasky 			dest_offset = 0;
1111d6b92ffaSHans Petter Selasky 			dest_lid_ho = dest_lid_min_ho;
1112d6b92ffaSHans Petter Selasky 		}
1113d6b92ffaSHans Petter Selasky 
1114d6b92ffaSHans Petter Selasky 		/*
1115d6b92ffaSHans Petter Selasky 		   These paths are "fully non-redundant" with paths already
1116d6b92ffaSHans Petter Selasky 		   identified above and consequently not of much value.
1117d6b92ffaSHans Petter Selasky 
1118d6b92ffaSHans Petter Selasky 		   Don't return paths we already identified above, as indicated
1119d6b92ffaSHans Petter Selasky 		   by the offset values being equal.
1120d6b92ffaSHans Petter Selasky 		 */
1121d6b92ffaSHans Petter Selasky 		if (src_offset == dest_offset)
1122d6b92ffaSHans Petter Selasky 			continue;	/* already reported */
1123d6b92ffaSHans Petter Selasky 
1124d6b92ffaSHans Petter Selasky 		p_pr_item = mpr_rcv_get_lid_pair_path(sa, p_mpr,
1125d6b92ffaSHans Petter Selasky 						      p_src_alias_guid,
1126d6b92ffaSHans Petter Selasky 						      p_dest_alias_guid,
1127d6b92ffaSHans Petter Selasky 						      src_lid_ho, dest_lid_ho,
1128d6b92ffaSHans Petter Selasky 						      comp_mask, preference);
1129d6b92ffaSHans Petter Selasky 
1130d6b92ffaSHans Petter Selasky 		if (p_pr_item) {
1131d6b92ffaSHans Petter Selasky 			cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
1132d6b92ffaSHans Petter Selasky 			++path_num;
1133d6b92ffaSHans Petter Selasky 		}
1134d6b92ffaSHans Petter Selasky 	}
1135d6b92ffaSHans Petter Selasky 
1136d6b92ffaSHans Petter Selasky Exit:
1137d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(sa->p_log);
1138d6b92ffaSHans Petter Selasky 	return path_num;
1139d6b92ffaSHans Petter Selasky }
1140d6b92ffaSHans Petter Selasky 
1141d6b92ffaSHans Petter Selasky #undef min
1142d6b92ffaSHans Petter Selasky #define min(x,y)	(((x) < (y)) ? (x) : (y))
1143d6b92ffaSHans Petter Selasky 
mpr_rcv_get_apm_port_pair_paths(IN osm_sa_t * sa,IN const ib_multipath_rec_t * p_mpr,IN const osm_alias_guid_t * p_src_alias_guid,IN const osm_alias_guid_t * p_dest_alias_guid,IN int base_offs,IN const ib_net64_t comp_mask,IN cl_qlist_t * p_list)1144d6b92ffaSHans Petter Selasky static osm_sa_item_t *mpr_rcv_get_apm_port_pair_paths(IN osm_sa_t * sa,
1145d6b92ffaSHans Petter Selasky 						      IN const
1146d6b92ffaSHans Petter Selasky 						      ib_multipath_rec_t *
1147d6b92ffaSHans Petter Selasky 						      p_mpr,
1148d6b92ffaSHans Petter Selasky 						      IN const osm_alias_guid_t *
1149d6b92ffaSHans Petter Selasky 						      p_src_alias_guid,
1150d6b92ffaSHans Petter Selasky 						      IN const osm_alias_guid_t *
1151d6b92ffaSHans Petter Selasky 						      p_dest_alias_guid,
1152d6b92ffaSHans Petter Selasky 						      IN int base_offs,
1153d6b92ffaSHans Petter Selasky 						      IN const ib_net64_t
1154d6b92ffaSHans Petter Selasky 						      comp_mask,
1155d6b92ffaSHans Petter Selasky 						      IN cl_qlist_t * p_list)
1156d6b92ffaSHans Petter Selasky {
1157d6b92ffaSHans Petter Selasky 	osm_sa_item_t *p_pr_item = 0;
1158d6b92ffaSHans Petter Selasky 	uint16_t src_lid_min_ho;
1159d6b92ffaSHans Petter Selasky 	uint16_t src_lid_max_ho;
1160d6b92ffaSHans Petter Selasky 	uint16_t dest_lid_min_ho;
1161d6b92ffaSHans Petter Selasky 	uint16_t dest_lid_max_ho;
1162d6b92ffaSHans Petter Selasky 	uint16_t src_lid_ho;
1163d6b92ffaSHans Petter Selasky 	uint16_t dest_lid_ho;
1164d6b92ffaSHans Petter Selasky 	unsigned iterations;
1165d6b92ffaSHans Petter Selasky 	int src_lids, dest_lids;
1166d6b92ffaSHans Petter Selasky 
1167d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(sa->p_log);
1168d6b92ffaSHans Petter Selasky 
1169d6b92ffaSHans Petter Selasky 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src port 0x%016" PRIx64 ", "
1170d6b92ffaSHans Petter Selasky 		"Dst port 0x%016" PRIx64 ", base offs %d\n",
1171d6b92ffaSHans Petter Selasky 		cl_ntoh64(p_src_alias_guid->alias_guid),
1172d6b92ffaSHans Petter Selasky 		cl_ntoh64(p_dest_alias_guid->alias_guid),
1173d6b92ffaSHans Petter Selasky 		base_offs);
1174d6b92ffaSHans Petter Selasky 
1175d6b92ffaSHans Petter Selasky 	osm_port_get_lid_range_ho(p_src_alias_guid->p_base_port,
1176d6b92ffaSHans Petter Selasky 				  &src_lid_min_ho, &src_lid_max_ho);
1177d6b92ffaSHans Petter Selasky 	osm_port_get_lid_range_ho(p_dest_alias_guid->p_base_port,
1178d6b92ffaSHans Petter Selasky 				  &dest_lid_min_ho, &dest_lid_max_ho);
1179d6b92ffaSHans Petter Selasky 
1180d6b92ffaSHans Petter Selasky 	src_lid_ho = src_lid_min_ho;
1181d6b92ffaSHans Petter Selasky 	dest_lid_ho = dest_lid_min_ho;
1182d6b92ffaSHans Petter Selasky 
1183d6b92ffaSHans Petter Selasky 	src_lids = src_lid_max_ho - src_lid_min_ho + 1;
1184d6b92ffaSHans Petter Selasky 	dest_lids = dest_lid_max_ho - dest_lid_min_ho + 1;
1185d6b92ffaSHans Petter Selasky 
1186d6b92ffaSHans Petter Selasky 	src_lid_ho += base_offs % src_lids;
1187d6b92ffaSHans Petter Selasky 	dest_lid_ho += base_offs % dest_lids;
1188d6b92ffaSHans Petter Selasky 
1189d6b92ffaSHans Petter Selasky 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1190d6b92ffaSHans Petter Selasky 		"Src LIDs [%u-%u] hashed %u, "
1191d6b92ffaSHans Petter Selasky 		"Dest LIDs [%u-%u] hashed %u\n",
1192d6b92ffaSHans Petter Selasky 		src_lid_min_ho, src_lid_max_ho, src_lid_ho,
1193d6b92ffaSHans Petter Selasky 		dest_lid_min_ho, dest_lid_max_ho, dest_lid_ho);
1194d6b92ffaSHans Petter Selasky 
1195d6b92ffaSHans Petter Selasky 	iterations = min(src_lids, dest_lids);
1196d6b92ffaSHans Petter Selasky 
1197d6b92ffaSHans Petter Selasky 	while (iterations--) {
1198d6b92ffaSHans Petter Selasky 		/*
1199d6b92ffaSHans Petter Selasky 		   These paths are "fully redundant"
1200d6b92ffaSHans Petter Selasky 		 */
1201d6b92ffaSHans Petter Selasky 		p_pr_item = mpr_rcv_get_lid_pair_path(sa, p_mpr,
1202d6b92ffaSHans Petter Selasky 						      p_src_alias_guid,
1203d6b92ffaSHans Petter Selasky 						      p_dest_alias_guid,
1204d6b92ffaSHans Petter Selasky 						      src_lid_ho, dest_lid_ho,
1205d6b92ffaSHans Petter Selasky 						      comp_mask, 0);
1206d6b92ffaSHans Petter Selasky 
1207d6b92ffaSHans Petter Selasky 		if (p_pr_item) {
1208d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1209d6b92ffaSHans Petter Selasky 				"Found matching path from Src LID %u to Dest LID %u with %d hops\n",
1210d6b92ffaSHans Petter Selasky 				src_lid_ho, dest_lid_ho, p_pr_item->resp.mpr_rec.hops);
1211d6b92ffaSHans Petter Selasky 			break;
1212d6b92ffaSHans Petter Selasky 		}
1213d6b92ffaSHans Petter Selasky 
1214d6b92ffaSHans Petter Selasky 		if (++src_lid_ho > src_lid_max_ho)
1215d6b92ffaSHans Petter Selasky 			src_lid_ho = src_lid_min_ho;
1216d6b92ffaSHans Petter Selasky 
1217d6b92ffaSHans Petter Selasky 		if (++dest_lid_ho > dest_lid_max_ho)
1218d6b92ffaSHans Petter Selasky 			dest_lid_ho = dest_lid_min_ho;
1219d6b92ffaSHans Petter Selasky 	}
1220d6b92ffaSHans Petter Selasky 
1221d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(sa->p_log);
1222d6b92ffaSHans Petter Selasky 	return p_pr_item;
1223d6b92ffaSHans Petter Selasky }
1224d6b92ffaSHans Petter Selasky 
mpr_rcv_get_gids(IN osm_sa_t * sa,IN const ib_gid_t * gids,IN int ngids,IN int is_sgid,OUT osm_alias_guid_t ** pp_alias_guid)1225d6b92ffaSHans Petter Selasky static ib_net16_t mpr_rcv_get_gids(IN osm_sa_t * sa, IN const ib_gid_t * gids,
1226d6b92ffaSHans Petter Selasky 				   IN int ngids, IN int is_sgid,
1227d6b92ffaSHans Petter Selasky 				   OUT osm_alias_guid_t ** pp_alias_guid)
1228d6b92ffaSHans Petter Selasky {
1229d6b92ffaSHans Petter Selasky 	osm_alias_guid_t *p_alias_guid;
1230d6b92ffaSHans Petter Selasky 	ib_net16_t ib_status = IB_SUCCESS;
1231d6b92ffaSHans Petter Selasky 	int i;
1232d6b92ffaSHans Petter Selasky 
1233d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(sa->p_log);
1234d6b92ffaSHans Petter Selasky 
1235d6b92ffaSHans Petter Selasky 	for (i = 0; i < ngids; i++, gids++) {
1236d6b92ffaSHans Petter Selasky 		if (!ib_gid_is_link_local(gids)) {
1237d6b92ffaSHans Petter Selasky 			if ((is_sgid && ib_gid_is_multicast(gids)) ||
1238d6b92ffaSHans Petter Selasky 			    (ib_gid_get_subnet_prefix(gids) !=
1239d6b92ffaSHans Petter Selasky 			     sa->p_subn->opt.subnet_prefix)) {
1240d6b92ffaSHans Petter Selasky 				/*
1241d6b92ffaSHans Petter Selasky 				   This 'error' is the client's fault (bad gid)
1242d6b92ffaSHans Petter Selasky 				   so don't enter it as an error in our own log.
1243d6b92ffaSHans Petter Selasky 				   Return an error response to the client.
1244d6b92ffaSHans Petter Selasky 				 */
1245d6b92ffaSHans Petter Selasky 				OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "ERR 451B: "
1246d6b92ffaSHans Petter Selasky 					"%sGID 0x%016" PRIx64
1247d6b92ffaSHans Petter Selasky 					" is multicast or non local subnet prefix\n",
1248d6b92ffaSHans Petter Selasky 					is_sgid ? "S" : "D",
1249d6b92ffaSHans Petter Selasky 					cl_ntoh64(gids->unicast.prefix));
1250d6b92ffaSHans Petter Selasky 
1251d6b92ffaSHans Petter Selasky 				ib_status = IB_SA_MAD_STATUS_INVALID_GID;
1252d6b92ffaSHans Petter Selasky 				goto Exit;
1253d6b92ffaSHans Petter Selasky 			}
1254d6b92ffaSHans Petter Selasky 		}
1255d6b92ffaSHans Petter Selasky 
1256d6b92ffaSHans Petter Selasky 		p_alias_guid =
1257d6b92ffaSHans Petter Selasky 		    osm_get_alias_guid_by_guid(sa->p_subn,
1258d6b92ffaSHans Petter Selasky 					       gids->unicast.interface_id);
1259d6b92ffaSHans Petter Selasky 		if (!p_alias_guid) {
1260d6b92ffaSHans Petter Selasky 			/*
1261d6b92ffaSHans Petter Selasky 			   This 'error' is the client's fault (bad gid) so
1262d6b92ffaSHans Petter Selasky 			   don't enter it as an error in our own log.
1263d6b92ffaSHans Petter Selasky 			   Return an error response to the client.
1264d6b92ffaSHans Petter Selasky 			 */
1265d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4506: "
1266d6b92ffaSHans Petter Selasky 				"No port with GUID 0x%016" PRIx64 "\n",
1267d6b92ffaSHans Petter Selasky 				cl_ntoh64(gids->unicast.interface_id));
1268d6b92ffaSHans Petter Selasky 
1269d6b92ffaSHans Petter Selasky 			ib_status = IB_SA_MAD_STATUS_INVALID_GID;
1270d6b92ffaSHans Petter Selasky 			goto Exit;
1271d6b92ffaSHans Petter Selasky 		}
1272d6b92ffaSHans Petter Selasky 
1273d6b92ffaSHans Petter Selasky 		pp_alias_guid[i] = p_alias_guid;
1274d6b92ffaSHans Petter Selasky 	}
1275d6b92ffaSHans Petter Selasky 
1276d6b92ffaSHans Petter Selasky Exit:
1277d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(sa->p_log);
1278d6b92ffaSHans Petter Selasky 
1279d6b92ffaSHans Petter Selasky 	return ib_status;
1280d6b92ffaSHans Petter Selasky }
1281d6b92ffaSHans Petter Selasky 
mpr_rcv_get_end_points(IN osm_sa_t * sa,IN const osm_madw_t * p_madw,OUT osm_alias_guid_t ** pp_alias_guids,OUT int * nsrc,OUT int * ndest)1282d6b92ffaSHans Petter Selasky static ib_net16_t mpr_rcv_get_end_points(IN osm_sa_t * sa,
1283d6b92ffaSHans Petter Selasky 					 IN const osm_madw_t * p_madw,
1284d6b92ffaSHans Petter Selasky 					 OUT osm_alias_guid_t ** pp_alias_guids,
1285d6b92ffaSHans Petter Selasky 					 OUT int *nsrc, OUT int *ndest)
1286d6b92ffaSHans Petter Selasky {
1287d6b92ffaSHans Petter Selasky 	const ib_multipath_rec_t *p_mpr;
1288d6b92ffaSHans Petter Selasky 	const ib_sa_mad_t *p_sa_mad;
1289d6b92ffaSHans Petter Selasky 	ib_net64_t comp_mask;
1290d6b92ffaSHans Petter Selasky 	ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
1291d6b92ffaSHans Petter Selasky 	ib_gid_t *gids;
1292d6b92ffaSHans Petter Selasky 
1293d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(sa->p_log);
1294d6b92ffaSHans Petter Selasky 
1295d6b92ffaSHans Petter Selasky 	/*
1296d6b92ffaSHans Petter Selasky 	   Determine what fields are valid and then get a pointer
1297d6b92ffaSHans Petter Selasky 	   to the source and destination port objects, if possible.
1298d6b92ffaSHans Petter Selasky 	 */
1299d6b92ffaSHans Petter Selasky 	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1300d6b92ffaSHans Petter Selasky 	p_mpr = (ib_multipath_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
1301d6b92ffaSHans Petter Selasky 	gids = (ib_gid_t *) p_mpr->gids;
1302d6b92ffaSHans Petter Selasky 
1303d6b92ffaSHans Petter Selasky 	comp_mask = p_sa_mad->comp_mask;
1304d6b92ffaSHans Petter Selasky 
1305d6b92ffaSHans Petter Selasky 	/*
1306d6b92ffaSHans Petter Selasky 	   Check a few easy disqualifying cases up front before getting
1307d6b92ffaSHans Petter Selasky 	   into the endpoints.
1308d6b92ffaSHans Petter Selasky 	 */
1309d6b92ffaSHans Petter Selasky 	*nsrc = *ndest = 0;
1310d6b92ffaSHans Petter Selasky 
1311d6b92ffaSHans Petter Selasky 	if (comp_mask & IB_MPR_COMPMASK_SGIDCOUNT) {
1312d6b92ffaSHans Petter Selasky 		*nsrc = p_mpr->sgid_count;
1313d6b92ffaSHans Petter Selasky 		if (*nsrc > IB_MULTIPATH_MAX_GIDS)
1314d6b92ffaSHans Petter Selasky 			*nsrc = IB_MULTIPATH_MAX_GIDS;
1315d6b92ffaSHans Petter Selasky 		sa_status = mpr_rcv_get_gids(sa, gids, *nsrc, 1, pp_alias_guids);
1316d6b92ffaSHans Petter Selasky 		if (sa_status != IB_SUCCESS)
1317d6b92ffaSHans Petter Selasky 			goto Exit;
1318d6b92ffaSHans Petter Selasky 	}
1319d6b92ffaSHans Petter Selasky 
1320d6b92ffaSHans Petter Selasky 	if (comp_mask & IB_MPR_COMPMASK_DGIDCOUNT) {
1321d6b92ffaSHans Petter Selasky 		*ndest = p_mpr->dgid_count;
1322d6b92ffaSHans Petter Selasky 		if (*ndest + *nsrc > IB_MULTIPATH_MAX_GIDS)
1323d6b92ffaSHans Petter Selasky 			*ndest = IB_MULTIPATH_MAX_GIDS - *nsrc;
1324d6b92ffaSHans Petter Selasky 		sa_status =
1325d6b92ffaSHans Petter Selasky 		    mpr_rcv_get_gids(sa, gids + *nsrc, *ndest, 0,
1326d6b92ffaSHans Petter Selasky 				     pp_alias_guids + *nsrc);
1327d6b92ffaSHans Petter Selasky 	}
1328d6b92ffaSHans Petter Selasky 
1329d6b92ffaSHans Petter Selasky Exit:
1330d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(sa->p_log);
1331d6b92ffaSHans Petter Selasky 	return sa_status;
1332d6b92ffaSHans Petter Selasky }
1333d6b92ffaSHans Petter Selasky 
1334d6b92ffaSHans Petter Selasky #define hash_lids(a, b, lmc)	\
1335d6b92ffaSHans Petter Selasky 	(((((a) >> (lmc)) << 4) | ((b) >> (lmc))) % 103)
1336d6b92ffaSHans Petter Selasky 
mpr_rcv_get_apm_paths(IN osm_sa_t * sa,IN const ib_multipath_rec_t * p_mpr,IN const osm_port_t * p_req_port,IN osm_alias_guid_t ** _pp_alias_guids,IN const ib_net64_t comp_mask,IN cl_qlist_t * p_list)1337d6b92ffaSHans Petter Selasky static void mpr_rcv_get_apm_paths(IN osm_sa_t * sa,
1338d6b92ffaSHans Petter Selasky 				  IN const ib_multipath_rec_t * p_mpr,
1339d6b92ffaSHans Petter Selasky 				  IN const osm_port_t * p_req_port,
1340d6b92ffaSHans Petter Selasky 				  IN osm_alias_guid_t ** _pp_alias_guids,
1341d6b92ffaSHans Petter Selasky 				  IN const ib_net64_t comp_mask,
1342d6b92ffaSHans Petter Selasky 				  IN cl_qlist_t * p_list)
1343d6b92ffaSHans Petter Selasky {
1344d6b92ffaSHans Petter Selasky 	osm_alias_guid_t *pp_alias_guids[4];
1345d6b92ffaSHans Petter Selasky 	osm_sa_item_t *matrix[2][2];
1346d6b92ffaSHans Petter Selasky 	int base_offs, src_lid_ho, dest_lid_ho;
1347d6b92ffaSHans Petter Selasky 	int sumA, sumB, minA, minB;
1348d6b92ffaSHans Petter Selasky 
1349d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(sa->p_log);
1350d6b92ffaSHans Petter Selasky 
1351d6b92ffaSHans Petter Selasky 	/*
1352d6b92ffaSHans Petter Selasky 	 * We want to:
1353d6b92ffaSHans Petter Selasky 	 *    1. use different lid offsets (from base) for the resultant paths
1354d6b92ffaSHans Petter Selasky 	 *    to increase the probability of redundant paths or in case
1355d6b92ffaSHans Petter Selasky 	 *    of Clos - to ensure it (different offset => different spine!)
1356d6b92ffaSHans Petter Selasky 	 *    2. keep consistent paths no matter of direction and order of ports
1357d6b92ffaSHans Petter Selasky 	 *    3. distibute the lid offsets to balance the load
1358d6b92ffaSHans Petter Selasky 	 * So, we sort the ports (within the srcs, and within the dests),
1359d6b92ffaSHans Petter Selasky 	 * hash the lids of S0, D0 (after the sort), and call mpr_rcv_get_apm_port_pair_paths
1360d6b92ffaSHans Petter Selasky 	 * with base_lid for S0, D0 and base_lid + 1 for S1, D1. This way we will get
1361d6b92ffaSHans Petter Selasky 	 * always the same offsets - order independent, and make sure different spines are used.
1362d6b92ffaSHans Petter Selasky 	 * Note that the diagonals on a Clos have the same number of hops, so it doesn't
1363d6b92ffaSHans Petter Selasky 	 * really matter which diagonal we use.
1364d6b92ffaSHans Petter Selasky 	 */
1365d6b92ffaSHans Petter Selasky 	if (_pp_alias_guids[0]->p_base_port->guid <
1366d6b92ffaSHans Petter Selasky 	    _pp_alias_guids[1]->p_base_port->guid) {
1367d6b92ffaSHans Petter Selasky 		pp_alias_guids[0] = _pp_alias_guids[0];
1368d6b92ffaSHans Petter Selasky 		pp_alias_guids[1] = _pp_alias_guids[1];
1369d6b92ffaSHans Petter Selasky 	} else {
1370d6b92ffaSHans Petter Selasky 		pp_alias_guids[0] = _pp_alias_guids[1];
1371d6b92ffaSHans Petter Selasky 		pp_alias_guids[1] = _pp_alias_guids[0];
1372d6b92ffaSHans Petter Selasky 	}
1373d6b92ffaSHans Petter Selasky 	if (_pp_alias_guids[2]->p_base_port->guid <
1374d6b92ffaSHans Petter Selasky 	    _pp_alias_guids[3]->p_base_port->guid) {
1375d6b92ffaSHans Petter Selasky 		pp_alias_guids[2] = _pp_alias_guids[2];
1376d6b92ffaSHans Petter Selasky 		pp_alias_guids[3] = _pp_alias_guids[3];
1377d6b92ffaSHans Petter Selasky 	} else {
1378d6b92ffaSHans Petter Selasky 		pp_alias_guids[2] = _pp_alias_guids[3];
1379d6b92ffaSHans Petter Selasky 		pp_alias_guids[3] = _pp_alias_guids[2];
1380d6b92ffaSHans Petter Selasky 	}
1381d6b92ffaSHans Petter Selasky 
1382d6b92ffaSHans Petter Selasky 	src_lid_ho = osm_port_get_base_lid(pp_alias_guids[0]->p_base_port);
1383d6b92ffaSHans Petter Selasky 	dest_lid_ho = osm_port_get_base_lid(pp_alias_guids[2]->p_base_port);
1384d6b92ffaSHans Petter Selasky 
1385d6b92ffaSHans Petter Selasky 	base_offs = src_lid_ho < dest_lid_ho ?
1386d6b92ffaSHans Petter Selasky 	    hash_lids(src_lid_ho, dest_lid_ho, sa->p_subn->opt.lmc) :
1387d6b92ffaSHans Petter Selasky 	    hash_lids(dest_lid_ho, src_lid_ho, sa->p_subn->opt.lmc);
1388d6b92ffaSHans Petter Selasky 
1389d6b92ffaSHans Petter Selasky 	matrix[0][0] =
1390d6b92ffaSHans Petter Selasky 	    mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[0],
1391d6b92ffaSHans Petter Selasky 					    pp_alias_guids[2], base_offs,
1392d6b92ffaSHans Petter Selasky 					    comp_mask, p_list);
1393d6b92ffaSHans Petter Selasky 	matrix[0][1] =
1394d6b92ffaSHans Petter Selasky 	    mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[0],
1395d6b92ffaSHans Petter Selasky 					    pp_alias_guids[3], base_offs,
1396d6b92ffaSHans Petter Selasky 					    comp_mask, p_list);
1397d6b92ffaSHans Petter Selasky 	matrix[1][0] =
1398d6b92ffaSHans Petter Selasky 	    mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[1],
1399d6b92ffaSHans Petter Selasky 					    pp_alias_guids[2], base_offs + 1,
1400d6b92ffaSHans Petter Selasky 					    comp_mask, p_list);
1401d6b92ffaSHans Petter Selasky 	matrix[1][1] =
1402d6b92ffaSHans Petter Selasky 	    mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[1],
1403d6b92ffaSHans Petter Selasky 					    pp_alias_guids[3], base_offs + 1,
1404d6b92ffaSHans Petter Selasky 					    comp_mask, p_list);
1405d6b92ffaSHans Petter Selasky 
1406d6b92ffaSHans Petter Selasky 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "APM matrix:\n"
1407d6b92ffaSHans Petter Selasky 		"\t{0,0} 0x%X->0x%X (%d)\t| {0,1} 0x%X->0x%X (%d)\n"
1408d6b92ffaSHans Petter Selasky 		"\t{1,0} 0x%X->0x%X (%d)\t| {1,1} 0x%X->0x%X (%d)\n",
1409d6b92ffaSHans Petter Selasky 		matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.slid : 0,
1410d6b92ffaSHans Petter Selasky 		matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.dlid : 0,
1411d6b92ffaSHans Petter Selasky 		matrix[0][0] ? matrix[0][0]->resp.mpr_rec.hops : 0,
1412d6b92ffaSHans Petter Selasky 		matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.slid : 0,
1413d6b92ffaSHans Petter Selasky 		matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.dlid : 0,
1414d6b92ffaSHans Petter Selasky 		matrix[0][1] ? matrix[0][1]->resp.mpr_rec.hops : 0,
1415d6b92ffaSHans Petter Selasky 		matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.slid : 0,
1416d6b92ffaSHans Petter Selasky 		matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.dlid : 0,
1417d6b92ffaSHans Petter Selasky 		matrix[1][0] ? matrix[1][0]->resp.mpr_rec.hops : 0,
1418d6b92ffaSHans Petter Selasky 		matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.slid : 0,
1419d6b92ffaSHans Petter Selasky 		matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.dlid : 0,
1420d6b92ffaSHans Petter Selasky 		matrix[1][1] ? matrix[1][1]->resp.mpr_rec.hops : 0);
1421d6b92ffaSHans Petter Selasky 
1422d6b92ffaSHans Petter Selasky 	sumA = minA = sumB = minB = 0;
1423d6b92ffaSHans Petter Selasky 
1424d6b92ffaSHans Petter Selasky 	/* check diagonal A {(0,0), (1,1)} */
1425d6b92ffaSHans Petter Selasky 	if (matrix[0][0]) {
1426d6b92ffaSHans Petter Selasky 		sumA += matrix[0][0]->resp.mpr_rec.hops;
1427d6b92ffaSHans Petter Selasky 		minA = matrix[0][0]->resp.mpr_rec.hops;
1428d6b92ffaSHans Petter Selasky 	}
1429d6b92ffaSHans Petter Selasky 	if (matrix[1][1]) {
1430d6b92ffaSHans Petter Selasky 		sumA += matrix[1][1]->resp.mpr_rec.hops;
1431d6b92ffaSHans Petter Selasky 		if (minA)
1432d6b92ffaSHans Petter Selasky 			minA = min(minA, matrix[1][1]->resp.mpr_rec.hops);
1433d6b92ffaSHans Petter Selasky 		else
1434d6b92ffaSHans Petter Selasky 			minA = matrix[1][1]->resp.mpr_rec.hops;
1435d6b92ffaSHans Petter Selasky 	}
1436d6b92ffaSHans Petter Selasky 
1437d6b92ffaSHans Petter Selasky 	/* check diagonal B {(0,1), (1,0)} */
1438d6b92ffaSHans Petter Selasky 	if (matrix[0][1]) {
1439d6b92ffaSHans Petter Selasky 		sumB += matrix[0][1]->resp.mpr_rec.hops;
1440d6b92ffaSHans Petter Selasky 		minB = matrix[0][1]->resp.mpr_rec.hops;
1441d6b92ffaSHans Petter Selasky 	}
1442d6b92ffaSHans Petter Selasky 	if (matrix[1][0]) {
1443d6b92ffaSHans Petter Selasky 		sumB += matrix[1][0]->resp.mpr_rec.hops;
1444d6b92ffaSHans Petter Selasky 		if (minB)
1445d6b92ffaSHans Petter Selasky 			minB = min(minB, matrix[1][0]->resp.mpr_rec.hops);
1446d6b92ffaSHans Petter Selasky 		else
1447d6b92ffaSHans Petter Selasky 			minB = matrix[1][0]->resp.mpr_rec.hops;
1448d6b92ffaSHans Petter Selasky 	}
1449d6b92ffaSHans Petter Selasky 
1450d6b92ffaSHans Petter Selasky 	/* and the winner is... */
1451d6b92ffaSHans Petter Selasky 	if (minA <= minB || (minA == minB && sumA < sumB)) {
1452d6b92ffaSHans Petter Selasky 		/* Diag A */
1453d6b92ffaSHans Petter Selasky 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1454d6b92ffaSHans Petter Selasky 			"Diag {0,0} & {1,1} is the best:\n"
1455d6b92ffaSHans Petter Selasky 			"\t{0,0} 0x%X->0x%X (%d)\t & {1,1} 0x%X->0x%X (%d)\n",
1456d6b92ffaSHans Petter Selasky 			matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.slid : 0,
1457d6b92ffaSHans Petter Selasky 			matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.dlid : 0,
1458d6b92ffaSHans Petter Selasky 			matrix[0][0] ? matrix[0][0]->resp.mpr_rec.hops : 0,
1459d6b92ffaSHans Petter Selasky 			matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.slid : 0,
1460d6b92ffaSHans Petter Selasky 			matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.dlid : 0,
1461d6b92ffaSHans Petter Selasky 			matrix[1][1] ? matrix[1][1]->resp.mpr_rec.hops : 0);
1462d6b92ffaSHans Petter Selasky 		if (matrix[0][0])
1463d6b92ffaSHans Petter Selasky 			cl_qlist_insert_tail(p_list, &matrix[0][0]->list_item);
1464d6b92ffaSHans Petter Selasky 		if (matrix[1][1])
1465d6b92ffaSHans Petter Selasky 			cl_qlist_insert_tail(p_list, &matrix[1][1]->list_item);
1466d6b92ffaSHans Petter Selasky 		free(matrix[0][1]);
1467d6b92ffaSHans Petter Selasky 		free(matrix[1][0]);
1468d6b92ffaSHans Petter Selasky 	} else {
1469d6b92ffaSHans Petter Selasky 		/* Diag B */
1470d6b92ffaSHans Petter Selasky 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1471d6b92ffaSHans Petter Selasky 			"Diag {0,1} & {1,0} is the best:\n"
1472d6b92ffaSHans Petter Selasky 			"\t{0,1} 0x%X->0x%X (%d)\t & {1,0} 0x%X->0x%X (%d)\n",
1473d6b92ffaSHans Petter Selasky 			matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.slid : 0,
1474d6b92ffaSHans Petter Selasky 			matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.dlid : 0,
1475d6b92ffaSHans Petter Selasky 			matrix[0][1] ? matrix[0][1]->resp.mpr_rec.hops : 0,
1476d6b92ffaSHans Petter Selasky 			matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.slid : 0,
1477d6b92ffaSHans Petter Selasky 			matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.dlid: 0,
1478d6b92ffaSHans Petter Selasky 			matrix[1][0] ? matrix[1][0]->resp.mpr_rec.hops : 0);
1479d6b92ffaSHans Petter Selasky 		if (matrix[0][1])
1480d6b92ffaSHans Petter Selasky 			cl_qlist_insert_tail(p_list, &matrix[0][1]->list_item);
1481d6b92ffaSHans Petter Selasky 		if (matrix[1][0])
1482d6b92ffaSHans Petter Selasky 			cl_qlist_insert_tail(p_list, &matrix[1][0]->list_item);
1483d6b92ffaSHans Petter Selasky 		free(matrix[0][0]);
1484d6b92ffaSHans Petter Selasky 		free(matrix[1][1]);
1485d6b92ffaSHans Petter Selasky 	}
1486d6b92ffaSHans Petter Selasky 
1487d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(sa->p_log);
1488d6b92ffaSHans Petter Selasky }
1489d6b92ffaSHans Petter Selasky 
mpr_rcv_process_pairs(IN osm_sa_t * sa,IN const ib_multipath_rec_t * p_mpr,IN osm_port_t * p_req_port,IN osm_alias_guid_t ** pp_alias_guids,IN const int nsrc,IN int ndest,IN ib_net64_t comp_mask,IN cl_qlist_t * p_list)1490d6b92ffaSHans Petter Selasky static void mpr_rcv_process_pairs(IN osm_sa_t * sa,
1491d6b92ffaSHans Petter Selasky 				  IN const ib_multipath_rec_t * p_mpr,
1492d6b92ffaSHans Petter Selasky 				  IN osm_port_t * p_req_port,
1493d6b92ffaSHans Petter Selasky 				  IN osm_alias_guid_t ** pp_alias_guids,
1494d6b92ffaSHans Petter Selasky 				  IN const int nsrc, IN int ndest,
1495d6b92ffaSHans Petter Selasky 				  IN ib_net64_t comp_mask,
1496d6b92ffaSHans Petter Selasky 				  IN cl_qlist_t * p_list)
1497d6b92ffaSHans Petter Selasky {
1498d6b92ffaSHans Petter Selasky 	osm_alias_guid_t **pp_src_alias_guid, **pp_es;
1499d6b92ffaSHans Petter Selasky 	osm_alias_guid_t **pp_dest_alias_guid, **pp_ed;
1500d6b92ffaSHans Petter Selasky 	uint32_t max_paths, num_paths, total_paths = 0;
1501d6b92ffaSHans Petter Selasky 
1502d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(sa->p_log);
1503d6b92ffaSHans Petter Selasky 
1504d6b92ffaSHans Petter Selasky 	if (comp_mask & IB_MPR_COMPMASK_NUMBPATH)
1505d6b92ffaSHans Petter Selasky 		max_paths = p_mpr->num_path & 0x7F;
1506d6b92ffaSHans Petter Selasky 	else
1507d6b92ffaSHans Petter Selasky 		max_paths = OSM_SA_MPR_MAX_NUM_PATH;
1508d6b92ffaSHans Petter Selasky 
1509d6b92ffaSHans Petter Selasky 	for (pp_src_alias_guid = pp_alias_guids, pp_es = pp_alias_guids + nsrc;
1510d6b92ffaSHans Petter Selasky 	     pp_src_alias_guid < pp_es; pp_src_alias_guid++) {
1511d6b92ffaSHans Petter Selasky 		for (pp_dest_alias_guid = pp_es, pp_ed = pp_es + ndest;
1512d6b92ffaSHans Petter Selasky 		     pp_dest_alias_guid < pp_ed; pp_dest_alias_guid++) {
1513d6b92ffaSHans Petter Selasky 			num_paths =
1514d6b92ffaSHans Petter Selasky 			    mpr_rcv_get_port_pair_paths(sa, p_mpr, p_req_port,
1515d6b92ffaSHans Petter Selasky 							*pp_src_alias_guid,
1516d6b92ffaSHans Petter Selasky 							*pp_dest_alias_guid,
1517d6b92ffaSHans Petter Selasky 							max_paths - total_paths,
1518d6b92ffaSHans Petter Selasky 							comp_mask, p_list);
1519d6b92ffaSHans Petter Selasky 			total_paths += num_paths;
1520d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1521d6b92ffaSHans Petter Selasky 				"%d paths %d total paths %d max paths\n",
1522d6b92ffaSHans Petter Selasky 				num_paths, total_paths, max_paths);
1523d6b92ffaSHans Petter Selasky 			/* Just take first NumbPaths found */
1524d6b92ffaSHans Petter Selasky 			if (total_paths >= max_paths)
1525d6b92ffaSHans Petter Selasky 				goto Exit;
1526d6b92ffaSHans Petter Selasky 		}
1527d6b92ffaSHans Petter Selasky 	}
1528d6b92ffaSHans Petter Selasky 
1529d6b92ffaSHans Petter Selasky Exit:
1530d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(sa->p_log);
1531d6b92ffaSHans Petter Selasky }
1532d6b92ffaSHans Petter Selasky 
osm_mpr_rcv_process(IN void * context,IN void * data)1533d6b92ffaSHans Petter Selasky void osm_mpr_rcv_process(IN void *context, IN void *data)
1534d6b92ffaSHans Petter Selasky {
1535d6b92ffaSHans Petter Selasky 	osm_sa_t *sa = context;
1536d6b92ffaSHans Petter Selasky 	osm_madw_t *p_madw = data;
1537d6b92ffaSHans Petter Selasky 	const ib_multipath_rec_t *p_mpr;
1538d6b92ffaSHans Petter Selasky 	ib_sa_mad_t *p_sa_mad;
1539d6b92ffaSHans Petter Selasky 	osm_port_t *requester_port;
1540d6b92ffaSHans Petter Selasky 	osm_alias_guid_t *pp_alias_guids[IB_MULTIPATH_MAX_GIDS];
1541d6b92ffaSHans Petter Selasky 	cl_qlist_t pr_list;
1542d6b92ffaSHans Petter Selasky 	ib_net16_t sa_status;
1543d6b92ffaSHans Petter Selasky 	int nsrc, ndest;
1544d6b92ffaSHans Petter Selasky 	uint8_t rate, mtu;
1545d6b92ffaSHans Petter Selasky 
1546d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(sa->p_log);
1547d6b92ffaSHans Petter Selasky 
1548d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_madw);
1549d6b92ffaSHans Petter Selasky 
1550d6b92ffaSHans Petter Selasky 	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1551d6b92ffaSHans Petter Selasky 	p_mpr = (ib_multipath_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
1552d6b92ffaSHans Petter Selasky 
1553d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_MULTIPATH_RECORD);
1554d6b92ffaSHans Petter Selasky 
1555d6b92ffaSHans Petter Selasky 	if ((p_sa_mad->rmpp_flags & IB_RMPP_FLAG_ACTIVE) != IB_RMPP_FLAG_ACTIVE) {
1556d6b92ffaSHans Petter Selasky 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4510: "
1557d6b92ffaSHans Petter Selasky 			"Invalid request since RMPP_FLAG_ACTIVE is not set\n");
1558d6b92ffaSHans Petter Selasky 		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1559d6b92ffaSHans Petter Selasky 		goto Exit;
1560d6b92ffaSHans Petter Selasky 	}
1561d6b92ffaSHans Petter Selasky 
1562d6b92ffaSHans Petter Selasky 	/* we only support SubnAdmGetMulti method */
1563d6b92ffaSHans Petter Selasky 	if (p_sa_mad->method != IB_MAD_METHOD_GETMULTI) {
1564d6b92ffaSHans Petter Selasky 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4513: "
1565d6b92ffaSHans Petter Selasky 			"Unsupported Method (%s) for MultiPathRecord request\n",
1566d6b92ffaSHans Petter Selasky 			ib_get_sa_method_str(p_sa_mad->method));
1567d6b92ffaSHans Petter Selasky 		osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
1568d6b92ffaSHans Petter Selasky 		goto Exit;
1569d6b92ffaSHans Petter Selasky 	}
1570d6b92ffaSHans Petter Selasky 
1571d6b92ffaSHans Petter Selasky 	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG))
1572d6b92ffaSHans Petter Selasky 		osm_dump_multipath_record_v2(sa->p_log, p_mpr, FILE_ID, OSM_LOG_DEBUG);
1573d6b92ffaSHans Petter Selasky 
1574d6b92ffaSHans Petter Selasky 	/* Make sure required components (S/DGIDCount) are supplied */
1575d6b92ffaSHans Petter Selasky 	if (!(p_sa_mad->comp_mask & IB_MPR_COMPMASK_SGIDCOUNT) ||
1576d6b92ffaSHans Petter Selasky 	    !(p_sa_mad->comp_mask & IB_MPR_COMPMASK_DGIDCOUNT)) {
1577d6b92ffaSHans Petter Selasky 		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INSUF_COMPS);
1578d6b92ffaSHans Petter Selasky 		goto Exit;
1579d6b92ffaSHans Petter Selasky 	}
1580d6b92ffaSHans Petter Selasky 
1581d6b92ffaSHans Petter Selasky 	/* Validate rate if supplied */
1582d6b92ffaSHans Petter Selasky 	if ((p_sa_mad->comp_mask & IB_MPR_COMPMASK_RATESELEC) &&
1583d6b92ffaSHans Petter Selasky 	    (p_sa_mad->comp_mask & IB_MPR_COMPMASK_RATE)) {
1584d6b92ffaSHans Petter Selasky 		rate = ib_multipath_rec_rate(p_mpr);
1585d6b92ffaSHans Petter Selasky 		if (!ib_rate_is_valid(rate)) {
1586d6b92ffaSHans Petter Selasky 			osm_sa_send_error(sa, p_madw,
1587d6b92ffaSHans Petter Selasky 					  IB_SA_MAD_STATUS_REQ_INVALID);
1588d6b92ffaSHans Petter Selasky 			goto Exit;
1589d6b92ffaSHans Petter Selasky 		}
1590d6b92ffaSHans Petter Selasky 	}
1591d6b92ffaSHans Petter Selasky 	/* Validate MTU if supplied */
1592d6b92ffaSHans Petter Selasky 	if ((p_sa_mad->comp_mask & IB_MPR_COMPMASK_MTUSELEC) &&
1593d6b92ffaSHans Petter Selasky 	    (p_sa_mad->comp_mask & IB_MPR_COMPMASK_MTU)) {
1594d6b92ffaSHans Petter Selasky 		mtu = ib_multipath_rec_mtu(p_mpr);
1595d6b92ffaSHans Petter Selasky 		if (!ib_mtu_is_valid(mtu)) {
1596d6b92ffaSHans Petter Selasky 			osm_sa_send_error(sa, p_madw,
1597d6b92ffaSHans Petter Selasky 					  IB_SA_MAD_STATUS_REQ_INVALID);
1598d6b92ffaSHans Petter Selasky 			goto Exit;
1599d6b92ffaSHans Petter Selasky 		}
1600d6b92ffaSHans Petter Selasky 	}
1601d6b92ffaSHans Petter Selasky 
1602d6b92ffaSHans Petter Selasky 	/* Make sure either none or both ServiceID parameters are supplied */
1603d6b92ffaSHans Petter Selasky 	if ((p_sa_mad->comp_mask & IB_MPR_COMPMASK_SERVICEID) != 0 &&
1604d6b92ffaSHans Petter Selasky 	    (p_sa_mad->comp_mask & IB_MPR_COMPMASK_SERVICEID) !=
1605d6b92ffaSHans Petter Selasky 	     IB_MPR_COMPMASK_SERVICEID) {
1606d6b92ffaSHans Petter Selasky 		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INSUF_COMPS);
1607d6b92ffaSHans Petter Selasky 		goto Exit;
1608d6b92ffaSHans Petter Selasky 	}
1609d6b92ffaSHans Petter Selasky 
1610d6b92ffaSHans Petter Selasky 	cl_qlist_init(&pr_list);
1611d6b92ffaSHans Petter Selasky 
1612d6b92ffaSHans Petter Selasky 	/*
1613d6b92ffaSHans Petter Selasky 	   Most SA functions (including this one) are read-only on the
1614d6b92ffaSHans Petter Selasky 	   subnet object, so we grab the lock non-exclusively.
1615d6b92ffaSHans Petter Selasky 	 */
1616d6b92ffaSHans Petter Selasky 	cl_plock_acquire(sa->p_lock);
1617d6b92ffaSHans Petter Selasky 
1618d6b92ffaSHans Petter Selasky 	/* update the requester physical port */
1619d6b92ffaSHans Petter Selasky 	requester_port = osm_get_port_by_mad_addr(sa->p_log, sa->p_subn,
1620d6b92ffaSHans Petter Selasky 						  osm_madw_get_mad_addr_ptr
1621d6b92ffaSHans Petter Selasky 						  (p_madw));
1622d6b92ffaSHans Petter Selasky 	if (requester_port == NULL) {
1623d6b92ffaSHans Petter Selasky 		cl_plock_release(sa->p_lock);
1624d6b92ffaSHans Petter Selasky 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4517: "
1625d6b92ffaSHans Petter Selasky 			"Cannot find requester physical port\n");
1626d6b92ffaSHans Petter Selasky 		goto Exit;
1627d6b92ffaSHans Petter Selasky 	}
1628d6b92ffaSHans Petter Selasky 
1629d6b92ffaSHans Petter Selasky 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1630d6b92ffaSHans Petter Selasky 		"Requester port GUID 0x%" PRIx64 "\n",
1631d6b92ffaSHans Petter Selasky 		cl_ntoh64(osm_port_get_guid(requester_port)));
1632d6b92ffaSHans Petter Selasky 
1633d6b92ffaSHans Petter Selasky 	sa_status = mpr_rcv_get_end_points(sa, p_madw, pp_alias_guids,
1634d6b92ffaSHans Petter Selasky 					   &nsrc, &ndest);
1635d6b92ffaSHans Petter Selasky 
1636d6b92ffaSHans Petter Selasky 	if (sa_status != IB_SA_MAD_STATUS_SUCCESS || !nsrc || !ndest) {
1637d6b92ffaSHans Petter Selasky 		cl_plock_release(sa->p_lock);
1638d6b92ffaSHans Petter Selasky 		if (sa_status == IB_SA_MAD_STATUS_SUCCESS && (!nsrc || !ndest))
1639d6b92ffaSHans Petter Selasky 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4512: "
1640d6b92ffaSHans Petter Selasky 				"mpr_rcv_get_end_points failed, # GIDs found; "
1641d6b92ffaSHans Petter Selasky 				"src %d; dest %d)\n", nsrc, ndest);
1642d6b92ffaSHans Petter Selasky 		if (sa_status == IB_SA_MAD_STATUS_SUCCESS)
1643d6b92ffaSHans Petter Selasky 			osm_sa_send_error(sa, p_madw,
1644d6b92ffaSHans Petter Selasky 					  IB_SA_MAD_STATUS_REQ_INVALID);
1645d6b92ffaSHans Petter Selasky 		else
1646d6b92ffaSHans Petter Selasky 			osm_sa_send_error(sa, p_madw, sa_status);
1647d6b92ffaSHans Petter Selasky 		goto Exit;
1648d6b92ffaSHans Petter Selasky 	}
1649d6b92ffaSHans Petter Selasky 
1650d6b92ffaSHans Petter Selasky 	/* APM request */
1651d6b92ffaSHans Petter Selasky 	if (nsrc == 2 && ndest == 2 && (p_mpr->num_path & 0x7F) == 2)
1652d6b92ffaSHans Petter Selasky 		mpr_rcv_get_apm_paths(sa, p_mpr, requester_port, pp_alias_guids,
1653d6b92ffaSHans Petter Selasky 				      p_sa_mad->comp_mask, &pr_list);
1654d6b92ffaSHans Petter Selasky 	else
1655d6b92ffaSHans Petter Selasky 		mpr_rcv_process_pairs(sa, p_mpr, requester_port, pp_alias_guids,
1656d6b92ffaSHans Petter Selasky 				      nsrc, ndest, p_sa_mad->comp_mask,
1657d6b92ffaSHans Petter Selasky 				      &pr_list);
1658d6b92ffaSHans Petter Selasky 
1659d6b92ffaSHans Petter Selasky 	cl_plock_release(sa->p_lock);
1660d6b92ffaSHans Petter Selasky 
1661d6b92ffaSHans Petter Selasky 	/* o15-0.2.7: If MultiPath is supported, then SA shall respond to a
1662d6b92ffaSHans Petter Selasky 	   SubnAdmGetMulti() containing a valid MultiPathRecord attribute with
1663d6b92ffaSHans Petter Selasky 	   a set of zero or more PathRecords satisfying the constraints
1664d6b92ffaSHans Petter Selasky 	   indicated in the MultiPathRecord received. The PathRecord Attribute
1665d6b92ffaSHans Petter Selasky 	   ID shall be used in the response.
1666d6b92ffaSHans Petter Selasky 	 */
1667d6b92ffaSHans Petter Selasky 	p_sa_mad->attr_id = IB_MAD_ATTR_PATH_RECORD;
1668d6b92ffaSHans Petter Selasky 	osm_sa_respond(sa, p_madw, sizeof(ib_path_rec_t), &pr_list);
1669d6b92ffaSHans Petter Selasky 
1670d6b92ffaSHans Petter Selasky Exit:
1671d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(sa->p_log);
1672d6b92ffaSHans Petter Selasky }
1673d6b92ffaSHans Petter Selasky #endif
1674