1 /*
2  * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2011 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved.
6  * Copyright (c) 2009 HNR Consulting. All rights reserved.
7  * Copyright (c) 2010 Sun Microsystems, Inc. All rights reserved.
8  * Copyright (c) 2009-2011 ZIH, TU Dresden, Federal Republic of Germany. All rights reserved.
9  * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
10  *
11  * This software is available to you under a choice of one of two
12  * licenses.  You may choose to be licensed under the terms of the GNU
13  * General Public License (GPL) Version 2, available from the file
14  * COPYING in the main directory of this source tree, or the
15  * OpenIB.org BSD license below:
16  *
17  *     Redistribution and use in source and binary forms, with or
18  *     without modification, are permitted provided that the following
19  *     conditions are met:
20  *
21  *      - Redistributions of source code must retain the above
22  *        copyright notice, this list of conditions and the following
23  *        disclaimer.
24  *
25  *      - Redistributions in binary form must reproduce the above
26  *        copyright notice, this list of conditions and the following
27  *        disclaimer in the documentation and/or other materials
28  *        provided with the distribution.
29  *
30  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
34  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
35  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
36  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37  * SOFTWARE.
38  *
39  */
40 
41 /*
42  * Abstract:
43  *    Implementation of osm_pr_rcv_t.
44  * This object represents the PathRecord Receiver object.
45  * This object is part of the opensm family of objects.
46  */
47 
48 #if HAVE_CONFIG_H
49 #  include <config.h>
50 #endif				/* HAVE_CONFIG_H */
51 
52 #include <string.h>
53 #include <arpa/inet.h>
54 #include <sys/socket.h>
55 #include <iba/ib_types.h>
56 #include <complib/cl_qmap.h>
57 #include <complib/cl_passivelock.h>
58 #include <complib/cl_debug.h>
59 #include <complib/cl_qlist.h>
60 #include <opensm/osm_file_ids.h>
61 #define FILE_ID OSM_FILE_SA_PATH_RECORD_C
62 #include <vendor/osm_vendor_api.h>
63 #include <opensm/osm_base.h>
64 #include <opensm/osm_port.h>
65 #include <opensm/osm_node.h>
66 #include <opensm/osm_switch.h>
67 #include <opensm/osm_helper.h>
68 #include <opensm/osm_pkey.h>
69 #include <opensm/osm_multicast.h>
70 #include <opensm/osm_partition.h>
71 #include <opensm/osm_opensm.h>
72 #include <opensm/osm_qos_policy.h>
73 #include <opensm/osm_sa.h>
74 #include <opensm/osm_router.h>
75 #include <opensm/osm_prefix_route.h>
76 #include <opensm/osm_ucast_lash.h>
77 
78 #define SA_PR_RESP_SIZE SA_ITEM_RESP_SIZE(path_rec)
79 
80 #define MAX_HOPS 64
81 
82 static inline boolean_t sa_path_rec_is_tavor_port(IN const osm_port_t * p_port)
83 {
84 	osm_node_t const *p_node;
85 	ib_net32_t vend_id;
86 
87 	p_node = p_port->p_node;
88 	vend_id = ib_node_info_get_vendor_id(&p_node->node_info);
89 
90 	return ((p_node->node_info.device_id == CL_HTON16(23108)) &&
91 		((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) ||
92 		 (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) ||
93 		 (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) ||
94 		 (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE))));
95 }
96 
97 static boolean_t
98 sa_path_rec_apply_tavor_mtu_limit(IN const ib_path_rec_t * p_pr,
99 				  IN const osm_port_t * p_src_port,
100 				  IN const osm_port_t * p_dest_port,
101 				  IN const ib_net64_t comp_mask)
102 {
103 	uint8_t required_mtu;
104 
105 	/* only if at least one of the ports is a Tavor device */
106 	if (!sa_path_rec_is_tavor_port(p_src_port) &&
107 	    !sa_path_rec_is_tavor_port(p_dest_port))
108 		return FALSE;
109 
110 	/*
111 	   we can apply the patch if either:
112 	   1. No MTU required
113 	   2. Required MTU <
114 	   3. Required MTU = 1K or 512 or 256
115 	   4. Required MTU > 256 or 512
116 	 */
117 	required_mtu = ib_path_rec_mtu(p_pr);
118 	if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
119 	    (comp_mask & IB_PR_COMPMASK_MTU)) {
120 		switch (ib_path_rec_mtu_sel(p_pr)) {
121 		case 0:	/* must be greater than */
122 		case 2:	/* exact match */
123 			if (IB_MTU_LEN_1024 < required_mtu)
124 				return FALSE;
125 			break;
126 
127 		case 1:	/* must be less than */
128 			/* can't be disqualified by this one */
129 			break;
130 
131 		case 3:	/* largest available */
132 			/* the ULP intentionally requested */
133 			/* the largest MTU possible */
134 			return FALSE;
135 
136 		default:
137 			/* if we're here, there's a bug in ib_path_rec_mtu_sel() */
138 			CL_ASSERT(FALSE);
139 			break;
140 		}
141 	}
142 
143 	return TRUE;
144 }
145 
146 static ib_api_status_t pr_rcv_get_path_parms(IN osm_sa_t * sa,
147 					     IN const ib_path_rec_t * p_pr,
148 					     IN const osm_alias_guid_t * p_src_alias_guid,
149 					     IN const uint16_t src_lid_ho,
150 					     IN const osm_alias_guid_t * p_dest_alias_guid,
151 					     IN const uint16_t dest_lid_ho,
152 					     IN const ib_net64_t comp_mask,
153 					     OUT osm_path_parms_t * p_parms)
154 {
155 	const osm_node_t *p_node;
156 	const osm_physp_t *p_physp, *p_physp0;
157 	const osm_physp_t *p_src_physp;
158 	const osm_physp_t *p_dest_physp;
159 	const osm_prtn_t *p_prtn = NULL;
160 	osm_opensm_t *p_osm;
161 	struct osm_routing_engine *p_re;
162 	const ib_port_info_t *p_pi, *p_pi0;
163 	ib_api_status_t status = IB_SUCCESS;
164 	ib_net16_t pkey;
165 	uint8_t mtu;
166 	uint8_t rate, p0_extended_rate, dest_rate;
167 	uint8_t pkt_life;
168 	uint8_t required_mtu;
169 	uint8_t required_rate;
170 	uint8_t required_pkt_life;
171 	uint8_t sl;
172 	uint8_t in_port_num;
173 	ib_net16_t dest_lid;
174 	uint8_t i;
175 	ib_slvl_table_t *p_slvl_tbl = NULL;
176 	osm_qos_level_t *p_qos_level = NULL;
177 	uint16_t valid_sl_mask = 0xffff;
178 	int hops = 0;
179 	int extended, p0_extended;
180 
181 	OSM_LOG_ENTER(sa->p_log);
182 
183 	dest_lid = cl_hton16(dest_lid_ho);
184 
185 	p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
186 	p_physp = p_src_alias_guid->p_base_port->p_physp;
187 	p_src_physp = p_physp;
188 	p_pi = &p_physp->port_info;
189 	p_osm = sa->p_subn->p_osm;
190 	p_re = p_osm->routing_engine_used;
191 
192 	mtu = ib_port_info_get_mtu_cap(p_pi);
193 	extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
194 	rate = ib_port_info_compute_rate(p_pi, extended);
195 
196 	/*
197 	   Mellanox Tavor device performance is better using 1K MTU.
198 	   If required MTU and MTU selector are such that 1K is OK
199 	   and at least one end of the path is Tavor we override the
200 	   port MTU with 1K.
201 	 */
202 	if (sa->p_subn->opt.enable_quirks &&
203 	    sa_path_rec_apply_tavor_mtu_limit(p_pr,
204 					      p_src_alias_guid->p_base_port,
205 					      p_dest_alias_guid->p_base_port,
206 					      comp_mask))
207 		if (mtu > IB_MTU_LEN_1024) {
208 			mtu = IB_MTU_LEN_1024;
209 			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
210 				"Optimized Path MTU to 1K for Mellanox Tavor device\n");
211 		}
212 
213 	/*
214 	   Walk the subnet object from source to destination,
215 	   tracking the most restrictive rate and mtu values along the way...
216 
217 	   If source port node is a switch, then p_physp should
218 	   point to the port that routes the destination lid
219 	 */
220 
221 	p_node = osm_physp_get_node_ptr(p_physp);
222 
223 	if (p_node->sw) {
224 		/*
225 		 * Source node is a switch.
226 		 * Make sure that p_physp points to the out port of the
227 		 * switch that routes to the destination lid (dest_lid_ho)
228 		 */
229 		p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
230 		if (p_physp == 0) {
231 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F02: "
232 				"Cannot find routing from LID %u to LID %u on "
233 				"switch %s (GUID: 0x%016" PRIx64 ")\n",
234 				src_lid_ho, dest_lid_ho, p_node->print_desc,
235 				cl_ntoh64(osm_node_get_node_guid(p_node)));
236 			status = IB_NOT_FOUND;
237 			goto Exit;
238 		}
239 	}
240 
241 	if (sa->p_subn->opt.qos) {
242 		/*
243 		 * Whether this node is switch or CA, the IN port for
244 		 * the sl2vl table is 0, because this is a source node.
245 		 */
246 		p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, 0);
247 
248 		/* update valid SLs that still exist on this route */
249 		for (i = 0; i < IB_MAX_NUM_VLS; i++) {
250 			if (valid_sl_mask & (1 << i) &&
251 			    ib_slvl_table_get(p_slvl_tbl, i) == IB_DROP_VL)
252 				valid_sl_mask &= ~(1 << i);
253 		}
254 		if (!valid_sl_mask) {
255 			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
256 				"All the SLs lead to VL15 on this path\n");
257 			status = IB_NOT_FOUND;
258 			goto Exit;
259 		}
260 	}
261 
262 	/*
263 	 * Same as above
264 	 */
265 	p_node = osm_physp_get_node_ptr(p_dest_physp);
266 
267 	if (p_node->sw) {
268 		/*
269 		 * if destination is switch, we want p_dest_physp to point to port 0
270 		 */
271 		p_dest_physp =
272 		    osm_switch_get_route_by_lid(p_node->sw, dest_lid);
273 
274 		if (p_dest_physp == 0) {
275 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F03: "
276 				"Can't find routing from LID %u to LID %u on "
277 				"switch %s (GUID: 0x%016" PRIx64 ")\n",
278 				src_lid_ho, dest_lid_ho, p_node->print_desc,
279 				cl_ntoh64(osm_node_get_node_guid(p_node)));
280 			status = IB_NOT_FOUND;
281 			goto Exit;
282 		}
283 
284 	}
285 
286 	/*
287 	 * Now go through the path step by step
288 	 */
289 
290 	while (p_physp != p_dest_physp) {
291 
292 		int tmp_pnum = p_physp->port_num;
293 		p_node = osm_physp_get_node_ptr(p_physp);
294 		p_physp = osm_physp_get_remote(p_physp);
295 
296 		if (p_physp == 0) {
297 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F05: "
298 				"Can't find remote phys port of %s (GUID: "
299 				"0x%016"PRIx64") port %d "
300 				"while routing from LID %u to LID %u\n",
301 				p_node->print_desc,
302 				cl_ntoh64(osm_node_get_node_guid(p_node)),
303 				tmp_pnum, src_lid_ho, dest_lid_ho);
304 			status = IB_ERROR;
305 			goto Exit;
306 		}
307 
308 		in_port_num = osm_physp_get_port_num(p_physp);
309 
310 		/*
311 		   This is point to point case (no switch in between)
312 		 */
313 		if (p_physp == p_dest_physp)
314 			break;
315 
316 		p_node = osm_physp_get_node_ptr(p_physp);
317 
318 		if (!p_node->sw) {
319 			/*
320 			   There is some sort of problem in the subnet object!
321 			   If this isn't a switch, we should have reached
322 			   the destination by now!
323 			 */
324 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F06: "
325 				"Internal error, bad path while routing "
326 				"%s (GUID: 0x%016"PRIx64") port %d to "
327 				"%s (GUID: 0x%016"PRIx64") port %d; "
328 				"ended at %s port %d\n",
329 				p_src_alias_guid->p_base_port->p_node->print_desc,
330 				cl_ntoh64(p_src_alias_guid->p_base_port->p_node->node_info.node_guid),
331 				p_src_alias_guid->p_base_port->p_physp->port_num,
332 				p_dest_alias_guid->p_base_port->p_node->print_desc,
333 				cl_ntoh64(p_dest_alias_guid->p_base_port->p_node->node_info.node_guid),
334 				p_dest_alias_guid->p_base_port->p_physp->port_num,
335 				p_node->print_desc,
336 				p_physp->port_num);
337 			status = IB_ERROR;
338 			goto Exit;
339 		}
340 
341 		/*
342 		   Check parameters for the ingress port in this switch.
343 		 */
344 		p_pi = &p_physp->port_info;
345 
346 		if (mtu > ib_port_info_get_mtu_cap(p_pi))
347 			mtu = ib_port_info_get_mtu_cap(p_pi);
348 
349 		p_physp0 = osm_node_get_physp_ptr((osm_node_t *)p_node, 0);
350 		p_pi0 = &p_physp0->port_info;
351 		p0_extended = p_pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
352 		p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
353 		if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
354 			rate = p0_extended_rate;
355 
356 		/*
357 		   Continue with the egress port on this switch.
358 		 */
359 		p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
360 		if (p_physp == 0) {
361 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F07: "
362 				"Dead end path on switch "
363 				"%s (GUID: 0x%016"PRIx64") to LID %u\n",
364 				p_node->print_desc,
365 				cl_ntoh64(osm_node_get_node_guid(p_node)),
366 				dest_lid_ho);
367 			status = IB_ERROR;
368 			goto Exit;
369 		}
370 
371 		p_pi = &p_physp->port_info;
372 
373 		if (mtu > ib_port_info_get_mtu_cap(p_pi))
374 			mtu = ib_port_info_get_mtu_cap(p_pi);
375 
376 		p_physp0 = osm_node_get_physp_ptr((osm_node_t *)p_node, 0);
377 		p_pi0 = &p_physp0->port_info;
378 		p0_extended = p_pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
379 		p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
380 		if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
381 			rate = p0_extended_rate;
382 
383 		if (sa->p_subn->opt.qos) {
384 			/*
385 			 * Check SL2VL table of the switch and update valid SLs
386 			 */
387 			p_slvl_tbl =
388 			    osm_physp_get_slvl_tbl(p_physp, in_port_num);
389 			for (i = 0; i < IB_MAX_NUM_VLS; i++) {
390 				if (valid_sl_mask & (1 << i) &&
391 				    ib_slvl_table_get(p_slvl_tbl,
392 						      i) == IB_DROP_VL)
393 					valid_sl_mask &= ~(1 << i);
394 			}
395 			if (!valid_sl_mask) {
396 				OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "All the SLs "
397 					"lead to VL15 on this path\n");
398 				status = IB_NOT_FOUND;
399 				goto Exit;
400 			}
401 		}
402 
403 		/* update number of hops traversed */
404 		hops++;
405 		if (hops > MAX_HOPS) {
406 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F25: "
407 				"Path from GUID 0x%016" PRIx64 " (%s port %d) "
408 				"to lid %u GUID 0x%016" PRIx64 " (%s port %d) "
409 				"needs more than %d hops, max %d hops allowed\n",
410 				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
411 				p_src_physp->p_node->print_desc,
412 				p_src_physp->port_num,
413 				dest_lid_ho,
414 				cl_ntoh64(osm_physp_get_port_guid
415 					  (p_dest_physp)),
416 				p_dest_physp->p_node->print_desc,
417 				p_dest_physp->port_num,
418 				hops,
419 				MAX_HOPS);
420 			status = IB_NOT_FOUND;
421 			goto Exit;
422 		}
423 	}
424 
425 	/*
426 	   p_physp now points to the destination
427 	 */
428 	p_pi = &p_physp->port_info;
429 
430 	if (mtu > ib_port_info_get_mtu_cap(p_pi))
431 		mtu = ib_port_info_get_mtu_cap(p_pi);
432 
433 	extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
434 	dest_rate = ib_port_info_compute_rate(p_pi, extended);
435 	if (ib_path_compare_rates(rate, dest_rate) > 0)
436 		rate = dest_rate;
437 
438 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
439 		"Path min MTU = %u, min rate = %u\n", mtu, rate);
440 
441 	/*
442 	 * Get QoS Level object according to the path request
443 	 * and adjust path parameters according to QoS settings
444 	 */
445 	if (sa->p_subn->opt.qos &&
446 	    sa->p_subn->p_qos_policy &&
447 	    (p_qos_level =
448 	     osm_qos_policy_get_qos_level_by_pr(sa->p_subn->p_qos_policy,
449 						p_pr, p_src_physp, p_dest_physp,
450 						comp_mask))) {
451 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
452 			"PathRecord request matches QoS Level '%s' (%s)\n",
453 			p_qos_level->name, p_qos_level->use ?
454 			p_qos_level->use : "no description");
455 
456 		if (p_qos_level->mtu_limit_set
457 		    && (mtu > p_qos_level->mtu_limit))
458 			mtu = p_qos_level->mtu_limit;
459 
460 		if (p_qos_level->rate_limit_set
461 		    && (ib_path_compare_rates(rate, p_qos_level->rate_limit) > 0))
462 			rate = p_qos_level->rate_limit;
463 
464 		if (p_qos_level->sl_set) {
465 			sl = p_qos_level->sl;
466 			if (!(valid_sl_mask & (1 << sl))) {
467 				status = IB_NOT_FOUND;
468 				goto Exit;
469 			}
470 		}
471 	}
472 
473 	/*
474 	 * Set packet lifetime.
475 	 * According to spec definition IBA 1.2 Table 205
476 	 * PacketLifeTime description, for loopback paths,
477 	 * packetLifeTime shall be zero.
478 	 */
479 	if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
480 		pkt_life = 0;
481 	else if (p_qos_level && p_qos_level->pkt_life_set)
482 		pkt_life = p_qos_level->pkt_life;
483 	else
484 		pkt_life = sa->p_subn->opt.subnet_timeout;
485 
486 	/*
487 	   Determine if these values meet the user criteria
488 	   and adjust appropriately
489 	 */
490 
491 	/* we silently ignore cases where only the MTU selector is defined */
492 	if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
493 	    (comp_mask & IB_PR_COMPMASK_MTU)) {
494 		required_mtu = ib_path_rec_mtu(p_pr);
495 		switch (ib_path_rec_mtu_sel(p_pr)) {
496 		case 0:	/* must be greater than */
497 			if (mtu <= required_mtu)
498 				status = IB_NOT_FOUND;
499 			break;
500 
501 		case 1:	/* must be less than */
502 			if (mtu >= required_mtu) {
503 				/* adjust to use the highest mtu
504 				   lower than the required one */
505 				if (required_mtu > 1)
506 					mtu = required_mtu - 1;
507 				else
508 					status = IB_NOT_FOUND;
509 			}
510 			break;
511 
512 		case 2:	/* exact match */
513 			if (mtu < required_mtu)
514 				status = IB_NOT_FOUND;
515 			else
516 				mtu = required_mtu;
517 			break;
518 
519 		case 3:	/* largest available */
520 			/* can't be disqualified by this one */
521 			break;
522 
523 		default:
524 			/* if we're here, there's a bug in ib_path_rec_mtu_sel() */
525 			CL_ASSERT(FALSE);
526 			status = IB_ERROR;
527 			break;
528 		}
529 	}
530 	if (status != IB_SUCCESS)
531 		goto Exit;
532 
533 	/* we silently ignore cases where only the Rate selector is defined */
534 	if ((comp_mask & IB_PR_COMPMASK_RATESELEC) &&
535 	    (comp_mask & IB_PR_COMPMASK_RATE)) {
536 		required_rate = ib_path_rec_rate(p_pr);
537 		switch (ib_path_rec_rate_sel(p_pr)) {
538 		case 0:	/* must be greater than */
539 			if (ib_path_compare_rates(rate, required_rate) <= 0)
540 				status = IB_NOT_FOUND;
541 			break;
542 
543 		case 1:	/* must be less than */
544 			if (ib_path_compare_rates(rate, required_rate) >= 0) {
545 				/* adjust the rate to use the highest rate
546 				   lower than the required one */
547 				rate = ib_path_rate_get_prev(required_rate);
548 				if (!rate)
549 					status = IB_NOT_FOUND;
550 			}
551 			break;
552 
553 		case 2:	/* exact match */
554 			if (ib_path_compare_rates(rate, required_rate))
555 				status = IB_NOT_FOUND;
556 			else
557 				rate = required_rate;
558 			break;
559 
560 		case 3:	/* largest available */
561 			/* can't be disqualified by this one */
562 			break;
563 
564 		default:
565 			/* if we're here, there's a bug in ib_path_rec_mtu_sel() */
566 			CL_ASSERT(FALSE);
567 			status = IB_ERROR;
568 			break;
569 		}
570 	}
571 	if (status != IB_SUCCESS)
572 		goto Exit;
573 
574 	/* we silently ignore cases where only the PktLife selector is defined */
575 	if ((comp_mask & IB_PR_COMPMASK_PKTLIFETIMESELEC) &&
576 	    (comp_mask & IB_PR_COMPMASK_PKTLIFETIME)) {
577 		required_pkt_life = ib_path_rec_pkt_life(p_pr);
578 		switch (ib_path_rec_pkt_life_sel(p_pr)) {
579 		case 0:	/* must be greater than */
580 			if (pkt_life <= required_pkt_life)
581 				status = IB_NOT_FOUND;
582 			break;
583 
584 		case 1:	/* must be less than */
585 			if (pkt_life >= required_pkt_life) {
586 				/* adjust the lifetime to use the highest possible
587 				   lower than the required one */
588 				if (required_pkt_life > 1)
589 					pkt_life = required_pkt_life - 1;
590 				else
591 					status = IB_NOT_FOUND;
592 			}
593 			break;
594 
595 		case 2:	/* exact match */
596 			if (pkt_life < required_pkt_life)
597 				status = IB_NOT_FOUND;
598 			else
599 				pkt_life = required_pkt_life;
600 			break;
601 
602 		case 3:	/* smallest available */
603 			/* can't be disqualified by this one */
604 			break;
605 
606 		default:
607 			/* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */
608 			CL_ASSERT(FALSE);
609 			status = IB_ERROR;
610 			break;
611 		}
612 	}
613 
614 	if (status != IB_SUCCESS)
615 		goto Exit;
616 
617 	/*
618 	 * set Pkey for this path record request
619 	 */
620 
621 	if ((comp_mask & IB_PR_COMPMASK_RAWTRAFFIC) &&
622 	    (cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31)))
623 		pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
624 						  sa->p_subn->opt.allow_both_pkeys);
625 
626 	else if (comp_mask & IB_PR_COMPMASK_PKEY) {
627 		/*
628 		 * PR request has a specific pkey:
629 		 * Check that source and destination share this pkey.
630 		 * If QoS level has pkeys, check that this pkey exists
631 		 * in the QoS level pkeys.
632 		 * PR returned pkey is the requested pkey.
633 		 */
634 		pkey = p_pr->pkey;
635 		if (!osm_physp_share_this_pkey(p_src_physp, p_dest_physp, pkey,
636 					       sa->p_subn->opt.allow_both_pkeys)) {
637 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1A: "
638 				"Ports 0x%016" PRIx64 " (%s port %d) and "
639 				"0x%016" PRIx64 " (%s port %d) "
640 				"do not share specified PKey 0x%04x\n",
641 				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
642 				p_src_physp->p_node->print_desc,
643 				p_src_physp->port_num,
644 				cl_ntoh64(osm_physp_get_port_guid
645 					  (p_dest_physp)),
646 				p_dest_physp->p_node->print_desc,
647 				p_dest_physp->port_num,
648 				cl_ntoh16(pkey));
649 			status = IB_NOT_FOUND;
650 			goto Exit;
651 		}
652 		if (p_qos_level && p_qos_level->pkey_range_len &&
653 		    !osm_qos_level_has_pkey(p_qos_level, pkey)) {
654 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1D: "
655 				"QoS level \"%s\" doesn't define specified PKey 0x%04x "
656 				"for ports 0x%016" PRIx64 " (%s port %d) and "
657 				"0x%016"PRIx64" (%s port %d)\n",
658 				p_qos_level->name,
659 				cl_ntoh16(pkey),
660 				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
661 				p_src_physp->p_node->print_desc,
662 				p_src_alias_guid->p_base_port->p_physp->port_num,
663 				cl_ntoh64(osm_physp_get_port_guid
664 					  (p_dest_physp)),
665 				p_dest_physp->p_node->print_desc,
666 				p_dest_alias_guid->p_base_port->p_physp->port_num);
667 			status = IB_NOT_FOUND;
668 			goto Exit;
669 		}
670 
671 	} else if (p_qos_level && p_qos_level->pkey_range_len) {
672 		/*
673 		 * PR request doesn't have a specific pkey, but QoS level
674 		 * has pkeys - get shared pkey from QoS level pkeys
675 		 */
676 		pkey = osm_qos_level_get_shared_pkey(p_qos_level,
677 						     p_src_physp, p_dest_physp,
678 						     sa->p_subn->opt.allow_both_pkeys);
679 		if (!pkey) {
680 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1E: "
681 				"Ports 0x%016" PRIx64 " (%s) and "
682 				"0x%016" PRIx64 " (%s) do not share "
683 				"PKeys defined by QoS level \"%s\"\n",
684 				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
685 				p_src_physp->p_node->print_desc,
686 				cl_ntoh64(osm_physp_get_port_guid
687 					  (p_dest_physp)),
688 				p_dest_physp->p_node->print_desc,
689 				p_qos_level->name);
690 			status = IB_NOT_FOUND;
691 			goto Exit;
692 		}
693 	} else {
694 		/*
695 		 * Neither PR request nor QoS level have pkey.
696 		 * Just get any shared pkey.
697 		 */
698 		pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
699 						  sa->p_subn->opt.allow_both_pkeys);
700 		if (!pkey) {
701 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1B: "
702 				"Ports src 0x%016"PRIx64" (%s port %d) and "
703 				"dst 0x%016"PRIx64" (%s port %d) do not have "
704 				"any shared PKeys\n",
705 				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
706 				p_src_physp->p_node->print_desc,
707 				p_src_physp->port_num,
708 				cl_ntoh64(osm_physp_get_port_guid
709 					  (p_dest_physp)),
710 				p_dest_physp->p_node->print_desc,
711 				p_dest_physp->port_num);
712 			status = IB_NOT_FOUND;
713 			goto Exit;
714 		}
715 	}
716 
717 	if (pkey) {
718 		p_prtn =
719 		    (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl,
720 					       pkey & cl_hton16((uint16_t) ~
721 								0x8000));
722 		if (p_prtn ==
723 		    (osm_prtn_t *) cl_qmap_end(&sa->p_subn->prtn_pkey_tbl))
724 			p_prtn = NULL;
725 	}
726 
727 	/*
728 	 * Set PathRecord SL
729 	 */
730 
731 	if (comp_mask & IB_PR_COMPMASK_SL) {
732 		/*
733 		 * Specific SL was requested
734 		 */
735 		sl = ib_path_rec_sl(p_pr);
736 
737 		if (p_qos_level && p_qos_level->sl_set
738 		    && (p_qos_level->sl != sl)) {
739 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1F: "
740 				"QoS constraints: required PathRecord SL (%u) "
741 				"doesn't match QoS policy \"%s\" SL (%u) "
742 				"[%s port %d <-> %s port %d]\n", sl,
743 				p_qos_level->name,
744 				p_qos_level->sl,
745 				p_src_alias_guid->p_base_port->p_node->print_desc,
746 				p_src_alias_guid->p_base_port->p_physp->port_num,
747 				p_dest_alias_guid->p_base_port->p_node->print_desc,
748 				p_dest_alias_guid->p_base_port->p_physp->port_num);
749 			status = IB_NOT_FOUND;
750 			goto Exit;
751 		}
752 
753 	} else if (p_qos_level && p_qos_level->sl_set) {
754 		/*
755 		 * No specific SL was requested, but there is an SL in
756 		 * QoS level.
757 		 */
758 		sl = p_qos_level->sl;
759 
760 		if (pkey && p_prtn && p_prtn->sl != p_qos_level->sl)
761 			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
762 				"QoS level SL (%u) overrides partition SL (%u)\n",
763 				p_qos_level->sl, p_prtn->sl);
764 
765 	} else if (pkey) {
766 		/*
767 		 * No specific SL in request or in QoS level - use partition SL
768 		 */
769 		if (!p_prtn) {
770 			sl = OSM_DEFAULT_SL;
771 			/* this may be possible when pkey tables are created somehow in
772 			   previous runs or things are going wrong here */
773 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1C: "
774 				"No partition found for PKey 0x%04x - "
775 				"using default SL %d "
776 				"[%s port %d <-> %s port %d]\n",
777 				cl_ntoh16(pkey), sl,
778 				p_src_alias_guid->p_base_port->p_node->print_desc,
779 				p_src_alias_guid->p_base_port->p_physp->port_num,
780 				p_dest_alias_guid->p_base_port->p_node->print_desc,
781 				p_dest_alias_guid->p_base_port->p_physp->port_num);
782 		} else
783 			sl = p_prtn->sl;
784 	} else if (sa->p_subn->opt.qos) {
785 		if (valid_sl_mask & (1 << OSM_DEFAULT_SL))
786 			sl = OSM_DEFAULT_SL;
787 		else {
788 			for (i = 0; i < IB_MAX_NUM_VLS; i++)
789 				if (valid_sl_mask & (1 << i))
790 					break;
791 			sl = i;
792 		}
793 	} else
794 		sl = OSM_DEFAULT_SL;
795 
796 	if (sa->p_subn->opt.qos && !(valid_sl_mask & (1 << sl))) {
797 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F24: "
798 			"Selected SL (%u) leads to VL15 "
799 			"[%s port %d <-> %s port %d]\n",
800 			sl,
801 			p_src_alias_guid->p_base_port->p_node->print_desc,
802 			p_src_alias_guid->p_base_port->p_physp->port_num,
803 			p_dest_alias_guid->p_base_port->p_node->print_desc,
804 			p_dest_alias_guid->p_base_port->p_physp->port_num);
805 		status = IB_NOT_FOUND;
806 		goto Exit;
807 	}
808 
809 	/*
810 	 * If the routing engine wants to have a say in path SL selection,
811 	 * send the currently computed SL value as a hint and let the routing
812 	 * engine override it.
813 	 */
814 	if (p_re && p_re->path_sl) {
815 		uint8_t pr_sl;
816 		pr_sl = sl;
817 
818 		sl = p_re->path_sl(p_re->context, sl,
819 				   cl_hton16(src_lid_ho), cl_hton16(dest_lid_ho));
820 
821 		if ((comp_mask & IB_PR_COMPMASK_SL) && (sl != pr_sl)) {
822 			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F2A: "
823 				"Requested SL (%u) doesn't match SL calculated"
824 				"by routing engine (%u) "
825 				"[%s port %d <-> %s port %d]\n",
826 				pr_sl,
827 				sl,
828 				p_src_alias_guid->p_base_port->p_node->print_desc,
829 				p_src_alias_guid->p_base_port->p_physp->port_num,
830 				p_dest_alias_guid->p_base_port->p_node->print_desc,
831 				p_dest_alias_guid->p_base_port->p_physp->port_num);
832 			status = IB_NOT_FOUND;
833 			goto Exit;
834 		}
835 	}
836 	/* reset pkey when raw traffic */
837 	if (comp_mask & IB_PR_COMPMASK_RAWTRAFFIC &&
838 	    cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31))
839 		pkey = 0;
840 
841 	p_parms->mtu = mtu;
842 	p_parms->rate = rate;
843 	p_parms->pkt_life = pkt_life;
844 	p_parms->pkey = pkey;
845 	p_parms->sl = sl;
846 
847 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Path params: mtu = %u, rate = %u,"
848 		" packet lifetime = %u, pkey = 0x%04X, sl = %u\n",
849 		mtu, rate, pkt_life, cl_ntoh16(pkey), sl);
850 Exit:
851 	OSM_LOG_EXIT(sa->p_log);
852 	return status;
853 }
854 
855 ib_api_status_t osm_get_path_params(IN osm_sa_t * sa,
856 				    IN const osm_port_t * p_src_port,
857 				    IN const uint16_t slid_ho,
858 				    IN const osm_port_t * p_dest_port,
859 				    IN const uint16_t dlid_ho,
860 				    OUT osm_path_parms_t * p_parms)
861 {
862 	osm_alias_guid_t *p_src_alias_guid, *p_dest_alias_guid;
863 	ib_path_rec_t pr;
864 
865 	if (!p_src_port || !slid_ho || !p_dest_port || !dlid_ho)
866 		return IB_INVALID_PARAMETER;
867 
868 	memset(&pr, 0, sizeof(ib_path_rec_t));
869 
870 	p_src_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
871 						      osm_port_get_guid(p_src_port));
872 	p_dest_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
873 						       osm_port_get_guid(p_dest_port));
874 	return pr_rcv_get_path_parms(sa, &pr,
875 				     p_src_alias_guid, slid_ho,
876 				     p_dest_alias_guid, dlid_ho, 0, p_parms);
877 }
878 
879 static void pr_rcv_build_pr(IN osm_sa_t * sa,
880 			    IN const osm_alias_guid_t * p_src_alias_guid,
881 			    IN const osm_alias_guid_t * p_dest_alias_guid,
882 			    IN const ib_gid_t * p_sgid,
883 			    IN const ib_gid_t * p_dgid,
884 			    IN const uint16_t src_lid_ho,
885 			    IN const uint16_t dest_lid_ho,
886 			    IN const uint8_t preference,
887 			    IN const osm_path_parms_t * p_parms,
888 			    OUT ib_path_rec_t * p_pr)
889 {
890 	const osm_physp_t *p_src_physp, *p_dest_physp;
891 
892 	OSM_LOG_ENTER(sa->p_log);
893 
894 	if (p_dgid)
895 		p_pr->dgid = *p_dgid;
896 	else {
897 		p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
898 
899 		p_pr->dgid.unicast.prefix =
900 		    osm_physp_get_subnet_prefix(p_dest_physp);
901 		p_pr->dgid.unicast.interface_id = p_dest_alias_guid->alias_guid;
902 	}
903 	if (p_sgid)
904 		p_pr->sgid = *p_sgid;
905 	else {
906 		p_src_physp = p_src_alias_guid->p_base_port->p_physp;
907 
908 		p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix(p_src_physp);
909 		p_pr->sgid.unicast.interface_id = p_src_alias_guid->alias_guid;
910 	}
911 
912 	p_pr->dlid = cl_hton16(dest_lid_ho);
913 	p_pr->slid = cl_hton16(src_lid_ho);
914 
915 	p_pr->hop_flow_raw &= cl_hton32(1 << 31);
916 
917 	/* Only set HopLimit if going through a router */
918 	if (p_dgid)
919 		p_pr->hop_flow_raw |= cl_hton32(IB_HOPLIMIT_MAX);
920 
921 	p_pr->pkey = p_parms->pkey;
922 	ib_path_rec_set_sl(p_pr, p_parms->sl);
923 	ib_path_rec_set_qos_class(p_pr, 0);
924 	p_pr->mtu = (uint8_t) (p_parms->mtu | 0x80);
925 	p_pr->rate = (uint8_t) (p_parms->rate | 0x80);
926 
927 	/* According to 1.2 spec definition Table 205 PacketLifeTime description,
928 	   for loopback paths, packetLifeTime shall be zero. */
929 	if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
930 		p_pr->pkt_life = 0x80;	/* loopback */
931 	else
932 		p_pr->pkt_life = (uint8_t) (p_parms->pkt_life | 0x80);
933 
934 	p_pr->preference = preference;
935 
936 	/* always return num_path = 0 so this is only the reversible component */
937 	if (p_parms->reversible)
938 		p_pr->num_path = 0x80;
939 
940 	OSM_LOG_EXIT(sa->p_log);
941 }
942 
943 static osm_sa_item_t *pr_rcv_get_lid_pair_path(IN osm_sa_t * sa,
944 					       IN const ib_path_rec_t * p_pr,
945 					       IN const osm_alias_guid_t * p_src_alias_guid,
946 					       IN const osm_alias_guid_t * p_dest_alias_guid,
947 					       IN const ib_gid_t * p_sgid,
948 					       IN const ib_gid_t * p_dgid,
949 					       IN const uint16_t src_lid_ho,
950 					       IN const uint16_t dest_lid_ho,
951 					       IN const ib_net64_t comp_mask,
952 					       IN const uint8_t preference)
953 {
954 	osm_path_parms_t path_parms;
955 	osm_path_parms_t rev_path_parms;
956 	osm_sa_item_t *p_pr_item;
957 	ib_api_status_t status, rev_path_status;
958 
959 	OSM_LOG_ENTER(sa->p_log);
960 
961 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID %u, Dest LID %u\n",
962 		src_lid_ho, dest_lid_ho);
963 
964 	p_pr_item = malloc(SA_PR_RESP_SIZE);
965 	if (p_pr_item == NULL) {
966 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F01: "
967 			"Unable to allocate path record\n");
968 		goto Exit;
969 	}
970 	memset(p_pr_item, 0, SA_PR_RESP_SIZE);
971 
972 	status = pr_rcv_get_path_parms(sa, p_pr, p_src_alias_guid, src_lid_ho,
973 				       p_dest_alias_guid, dest_lid_ho,
974 				       comp_mask, &path_parms);
975 
976 	if (status != IB_SUCCESS) {
977 		free(p_pr_item);
978 		p_pr_item = NULL;
979 		goto Exit;
980 	}
981 
982 	/* now try the reversible path */
983 	rev_path_status = pr_rcv_get_path_parms(sa, p_pr, p_dest_alias_guid,
984 						dest_lid_ho, p_src_alias_guid,
985 						src_lid_ho, comp_mask,
986 						&rev_path_parms);
987 
988 	path_parms.reversible = (rev_path_status == IB_SUCCESS);
989 
990 	/* did we get a Reversible Path compmask ? */
991 	/*
992 	   NOTE that if the reversible component = 0, it is a don't care
993 	   rather than requiring non-reversible paths ...
994 	   see Vol1 Ver1.2 p900 l16
995 	 */
996 	if ((comp_mask & IB_PR_COMPMASK_REVERSIBLE) &&
997 	    !path_parms.reversible && (p_pr->num_path & 0x80)) {
998 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
999 			"Requested reversible path but failed to get one\n");
1000 		free(p_pr_item);
1001 		p_pr_item = NULL;
1002 		goto Exit;
1003 	}
1004 
1005 	pr_rcv_build_pr(sa, p_src_alias_guid, p_dest_alias_guid, p_sgid, p_dgid,
1006 			src_lid_ho, dest_lid_ho, preference, &path_parms,
1007 			&p_pr_item->resp.path_rec);
1008 
1009 Exit:
1010 	OSM_LOG_EXIT(sa->p_log);
1011 	return p_pr_item;
1012 }
1013 
1014 static void pr_rcv_get_port_pair_paths(IN osm_sa_t * sa,
1015 				       IN const ib_sa_mad_t *sa_mad,
1016 				       IN const osm_port_t * p_req_port,
1017 				       IN const osm_alias_guid_t * p_src_alias_guid,
1018 				       IN const osm_alias_guid_t * p_dest_alias_guid,
1019 				       IN const ib_gid_t * p_sgid,
1020 				       IN const ib_gid_t * p_dgid,
1021 				       IN cl_qlist_t * p_list)
1022 {
1023 	const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
1024 	ib_net64_t comp_mask = sa_mad->comp_mask;
1025 	osm_sa_item_t *p_pr_item;
1026 	uint16_t src_lid_min_ho;
1027 	uint16_t src_lid_max_ho;
1028 	uint16_t dest_lid_min_ho;
1029 	uint16_t dest_lid_max_ho;
1030 	uint16_t src_lid_ho;
1031 	uint16_t dest_lid_ho;
1032 	uint32_t path_num;
1033 	uint8_t preference;
1034 	unsigned iterations, src_offset, dest_offset;
1035 
1036 	OSM_LOG_ENTER(sa->p_log);
1037 
1038 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1039 		"Src port 0x%016" PRIx64 ", Dst port 0x%016" PRIx64 "\n",
1040 		cl_ntoh64(p_src_alias_guid->alias_guid),
1041 		cl_ntoh64(p_dest_alias_guid->alias_guid));
1042 
1043 	/* Check that the req_port, src_port and dest_port all share a
1044 	   pkey. The check is done on the default physical port of the ports. */
1045 	if (osm_port_share_pkey(sa->p_log, p_req_port,
1046 				p_src_alias_guid->p_base_port,
1047 				sa->p_subn->opt.allow_both_pkeys) == FALSE
1048 	    || osm_port_share_pkey(sa->p_log, p_req_port,
1049 				   p_dest_alias_guid->p_base_port,
1050 				   sa->p_subn->opt.allow_both_pkeys) == FALSE
1051 	    || osm_port_share_pkey(sa->p_log, p_src_alias_guid->p_base_port,
1052 				   p_dest_alias_guid->p_base_port,
1053 				   sa->p_subn->opt.allow_both_pkeys) == FALSE)
1054 		/* One of the pairs doesn't share a pkey so the path is disqualified. */
1055 		goto Exit;
1056 
1057 	/*
1058 	   We shouldn't be here if the paths are disqualified in some way...
1059 	   Thus, we assume every possible connection is valid.
1060 
1061 	   We desire to return high-quality paths first.
1062 	   In OpenSM, higher quality means least overlap with other paths.
1063 	   This is acheived in practice by returning paths with
1064 	   different LID value on each end, which means these
1065 	   paths are more redundant that paths with the same LID repeated
1066 	   on one side.  For example, in OpenSM the paths between two
1067 	   endpoints with LMC = 1 might be as follows:
1068 
1069 	   Port A, LID 1 <-> Port B, LID 3
1070 	   Port A, LID 1 <-> Port B, LID 4
1071 	   Port A, LID 2 <-> Port B, LID 3
1072 	   Port A, LID 2 <-> Port B, LID 4
1073 
1074 	   The OpenSM unicast routing algorithms attempt to disperse each path
1075 	   to as varied a physical path as is reasonable.  1<->3 and 1<->4 have
1076 	   more physical overlap (hence less redundancy) than 1<->3 and 2<->4.
1077 
1078 	   OpenSM ranks paths in three preference groups:
1079 
1080 	   Preference Value    Description
1081 	   ----------------    -------------------------------------------
1082 	   0             Redundant in both directions with other
1083 	   pref value = 0 paths
1084 
1085 	   1             Redundant in one direction with other
1086 	   pref value = 0 and pref value = 1 paths
1087 
1088 	   2             Not redundant in either direction with
1089 	   other paths
1090 
1091 	   3-FF          Unused
1092 
1093 	   SA clients don't need to know these details, only that the lower
1094 	   preference paths are preferred, as stated in the spec.  The paths
1095 	   may not actually be physically redundant depending on the topology
1096 	   of the subnet, but the point of LMC > 0 is to offer redundancy,
1097 	   so it is assumed that the subnet is physically appropriate for the
1098 	   specified LMC value.  A more advanced implementation would inspect for
1099 	   physical redundancy, but I'm not going to bother with that now.
1100 	 */
1101 
1102 	/*
1103 	   Refine our search if the client specified end-point LIDs
1104 	 */
1105 	if (comp_mask & IB_PR_COMPMASK_DLID)
1106 		dest_lid_max_ho = dest_lid_min_ho = cl_ntoh16(p_pr->dlid);
1107 	else
1108 		osm_port_get_lid_range_ho(p_dest_alias_guid->p_base_port,
1109 					  &dest_lid_min_ho, &dest_lid_max_ho);
1110 
1111 	if (comp_mask & IB_PR_COMPMASK_SLID)
1112 		src_lid_max_ho = src_lid_min_ho = cl_ntoh16(p_pr->slid);
1113 	else
1114 		osm_port_get_lid_range_ho(p_src_alias_guid->p_base_port,
1115 					  &src_lid_min_ho, &src_lid_max_ho);
1116 
1117 	if (src_lid_min_ho == 0) {
1118 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1119 			"Obtained source LID of 0. No such LID possible "
1120 			"(%s port %d)\n",
1121 			p_src_alias_guid->p_base_port->p_node->print_desc,
1122 			p_src_alias_guid->p_base_port->p_physp->port_num);
1123 		goto Exit;
1124 	}
1125 
1126 	if (dest_lid_min_ho == 0) {
1127 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1128 			"Obtained destination LID of 0. No such LID possible "
1129 			"(%s port %d)\n",
1130 			p_dest_alias_guid->p_base_port->p_node->print_desc,
1131 			p_dest_alias_guid->p_base_port->p_physp->port_num);
1132 		goto Exit;
1133 	}
1134 
1135 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1136 		"Src LIDs [%u-%u], Dest LIDs [%u-%u]\n",
1137 		src_lid_min_ho, src_lid_max_ho,
1138 		dest_lid_min_ho, dest_lid_max_ho);
1139 
1140 	src_lid_ho = src_lid_min_ho;
1141 	dest_lid_ho = dest_lid_min_ho;
1142 
1143 	/*
1144 	   Preferred paths come first in OpenSM
1145 	 */
1146 	preference = 0;
1147 	path_num = 0;
1148 
1149 	/* If SubnAdmGet, assume NumbPaths 1 (1.2 erratum) */
1150 	if (sa_mad->method == IB_MAD_METHOD_GET)
1151 		iterations = 1;
1152 	else if (comp_mask & IB_PR_COMPMASK_NUMBPATH)
1153 		iterations = ib_path_rec_num_path(p_pr);
1154 	else
1155 		iterations = (unsigned) (-1);
1156 
1157 	while (path_num < iterations) {
1158 		/*
1159 		   These paths are "fully redundant"
1160 		 */
1161 
1162 		p_pr_item = pr_rcv_get_lid_pair_path(sa, p_pr, p_src_alias_guid,
1163 						     p_dest_alias_guid,
1164 						     p_sgid, p_dgid,
1165 						     src_lid_ho, dest_lid_ho,
1166 						     comp_mask, preference);
1167 
1168 		if (p_pr_item) {
1169 			cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
1170 			++path_num;
1171 		}
1172 
1173 		if (++src_lid_ho > src_lid_max_ho)
1174 			break;
1175 
1176 		if (++dest_lid_ho > dest_lid_max_ho)
1177 			break;
1178 	}
1179 
1180 	/*
1181 	   Check if we've accumulated all the paths that the user cares to see
1182 	 */
1183 	if (path_num == iterations)
1184 		goto Exit;
1185 
1186 	/*
1187 	   Don't bother reporting preference 1 paths for now.
1188 	   It's more trouble than it's worth and can only occur
1189 	   if ports have different LMC values, which isn't supported
1190 	   by OpenSM right now anyway.
1191 	 */
1192 	preference = 2;
1193 	src_lid_ho = src_lid_min_ho;
1194 	dest_lid_ho = dest_lid_min_ho;
1195 	src_offset = 0;
1196 	dest_offset = 0;
1197 
1198 	/*
1199 	   Iterate over the remaining paths
1200 	 */
1201 	while (path_num < iterations) {
1202 		dest_offset++;
1203 		dest_lid_ho++;
1204 
1205 		if (dest_lid_ho > dest_lid_max_ho) {
1206 			src_offset++;
1207 			src_lid_ho++;
1208 
1209 			if (src_lid_ho > src_lid_max_ho)
1210 				break;	/* done */
1211 
1212 			dest_offset = 0;
1213 			dest_lid_ho = dest_lid_min_ho;
1214 		}
1215 
1216 		/*
1217 		   These paths are "fully non-redundant" with paths already
1218 		   identified above and consequently not of much value.
1219 
1220 		   Don't return paths we already identified above, as indicated
1221 		   by the offset values being equal.
1222 		 */
1223 		if (src_offset == dest_offset)
1224 			continue;	/* already reported */
1225 
1226 		p_pr_item = pr_rcv_get_lid_pair_path(sa, p_pr, p_src_alias_guid,
1227 						     p_dest_alias_guid, p_sgid,
1228 						     p_dgid, src_lid_ho,
1229 						     dest_lid_ho, comp_mask,
1230 						     preference);
1231 
1232 		if (p_pr_item) {
1233 			cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
1234 			++path_num;
1235 		}
1236 	}
1237 
1238 Exit:
1239 	OSM_LOG_EXIT(sa->p_log);
1240 }
1241 
1242 /* Find the router port that is configured to handle this prefix, if any */
1243 static ib_net64_t find_router(const osm_sa_t *sa, ib_net64_t prefix)
1244 {
1245 	osm_prefix_route_t *route = NULL;
1246 	osm_router_t *rtr;
1247 	cl_qlist_t *l = &sa->p_subn->prefix_routes_list;
1248 	cl_list_item_t *i;
1249 
1250 	OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "Non local DGID subnet prefix "
1251 		"0x%016" PRIx64 "\n", cl_ntoh64(prefix));
1252 
1253 	for (i = cl_qlist_head(l); i != cl_qlist_end(l); i = cl_qlist_next(i)) {
1254 		osm_prefix_route_t *r = (osm_prefix_route_t *)i;
1255 		if (!r->prefix || r->prefix == prefix) {
1256 			route = r;
1257 			break;
1258 		}
1259 	}
1260 	if (!route)
1261 		return 0;
1262 
1263 	if (route->guid == 0) /* first router */
1264 		rtr = (osm_router_t *) cl_qmap_head(&sa->p_subn->rtr_guid_tbl);
1265 	else
1266 		rtr = (osm_router_t *) cl_qmap_get(&sa->p_subn->rtr_guid_tbl,
1267 						   route->guid);
1268 
1269 	if (rtr == (osm_router_t *) cl_qmap_end(&sa->p_subn->rtr_guid_tbl))
1270 		return 0;
1271 
1272 	return osm_port_get_guid(osm_router_get_port_ptr(rtr));
1273 }
1274 
1275 ib_net16_t osm_pr_get_end_points(IN osm_sa_t * sa,
1276 				 IN const ib_sa_mad_t *sa_mad,
1277 				 OUT const osm_alias_guid_t ** pp_src_alias_guid,
1278 				 OUT const osm_alias_guid_t ** pp_dest_alias_guid,
1279 				 OUT const osm_port_t ** pp_src_port,
1280 				 OUT const osm_port_t ** pp_dest_port,
1281 				 OUT const ib_gid_t ** pp_sgid,
1282 				 OUT const ib_gid_t ** pp_dgid)
1283 {
1284 	const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
1285 	ib_net64_t comp_mask = sa_mad->comp_mask;
1286 	ib_net64_t dest_guid;
1287 	ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
1288 
1289 	OSM_LOG_ENTER(sa->p_log);
1290 
1291 	/*
1292 	   Determine what fields are valid and then get a pointer
1293 	   to the source and destination port objects, if possible.
1294 	 */
1295 
1296 	/*
1297 	   Check a few easy disqualifying cases up front before getting
1298 	   into the endpoints.
1299 	 */
1300 
1301 	*pp_src_alias_guid = NULL;
1302 	*pp_src_port = NULL;
1303 	if (comp_mask & IB_PR_COMPMASK_SGID) {
1304 		if (!ib_gid_is_link_local(&p_pr->sgid)) {
1305 			if (ib_gid_get_subnet_prefix(&p_pr->sgid) !=
1306 			    sa->p_subn->opt.subnet_prefix) {
1307 				/*
1308 				   This 'error' is the client's fault (bad gid)
1309 				   so don't enter it as an error in our own log.
1310 				   Return an error response to the client.
1311 				 */
1312 				OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1313 					"Non local SGID subnet prefix 0x%016"
1314 					PRIx64 "\n",
1315 					cl_ntoh64(p_pr->sgid.unicast.prefix));
1316 				sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1317 				goto Exit;
1318 			}
1319 		}
1320 
1321 		*pp_src_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
1322 								p_pr->sgid.unicast.interface_id);
1323 		if (!*pp_src_alias_guid) {
1324 			/*
1325 			   This 'error' is the client's fault (bad gid) so
1326 			   don't enter it as an error in our own log.
1327 			   Return an error response to the client.
1328 			 */
1329 			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1330 				"No source port with GUID 0x%016" PRIx64 "\n",
1331 				cl_ntoh64(p_pr->sgid.unicast.interface_id));
1332 			sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1333 			goto Exit;
1334 		}
1335 		if (pp_sgid)
1336 			*pp_sgid = &p_pr->sgid;
1337 	}
1338 
1339 	if (comp_mask & IB_PR_COMPMASK_SLID) {
1340 		*pp_src_port = osm_get_port_by_lid(sa->p_subn, p_pr->slid);
1341 		if (!*pp_src_port) {
1342 			/*
1343 			   This 'error' is the client's fault (bad lid) so
1344 			   don't enter it as an error in our own log.
1345 			   Return an error response to the client.
1346 			 */
1347 			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "No source port "
1348 				"with LID %u\n", cl_ntoh16(p_pr->slid));
1349 			sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
1350 			goto Exit;
1351 		}
1352 	}
1353 
1354 	*pp_dest_alias_guid = NULL;
1355 	*pp_dest_port = NULL;
1356 	if (comp_mask & IB_PR_COMPMASK_DGID) {
1357 		if (!ib_gid_is_link_local(&p_pr->dgid) &&
1358 		    !ib_gid_is_multicast(&p_pr->dgid) &&
1359 		    ib_gid_get_subnet_prefix(&p_pr->dgid) !=
1360 		    sa->p_subn->opt.subnet_prefix) {
1361 			dest_guid = find_router(sa, p_pr->dgid.unicast.prefix);
1362 			if (!dest_guid) {
1363 				char gid_str[INET6_ADDRSTRLEN];
1364 				OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1365 					"Off subnet DGID %s, but router not "
1366 					"found\n",
1367 					inet_ntop(AF_INET6, p_pr->dgid.raw,
1368 						  gid_str, sizeof(gid_str)));
1369 				sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1370 				goto Exit;
1371 			}
1372 			if (pp_dgid)
1373 				*pp_dgid = &p_pr->dgid;
1374 		} else
1375 			dest_guid = p_pr->dgid.unicast.interface_id;
1376 
1377 		*pp_dest_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
1378 								 dest_guid);
1379 		if (!*pp_dest_alias_guid) {
1380 			/*
1381 			   This 'error' is the client's fault (bad gid) so
1382 			   don't enter it as an error in our own log.
1383 			   Return an error response to the client.
1384 			 */
1385 			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1386 				"No dest port with GUID 0x%016" PRIx64 "\n",
1387 				cl_ntoh64(dest_guid));
1388 			sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1389 			goto Exit;
1390 		}
1391 	}
1392 
1393 	if (comp_mask & IB_PR_COMPMASK_DLID) {
1394 		*pp_dest_port = osm_get_port_by_lid(sa->p_subn, p_pr->dlid);
1395 		if (!*pp_dest_port) {
1396 			/*
1397 			   This 'error' is the client's fault (bad lid)
1398 			   so don't enter it as an error in our own log.
1399 			   Return an error response to the client.
1400 			 */
1401 			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "No dest port "
1402 				"with LID %u\n", cl_ntoh16(p_pr->dlid));
1403 			sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
1404 			goto Exit;
1405 		}
1406 	}
1407 
1408 Exit:
1409 	OSM_LOG_EXIT(sa->p_log);
1410 	return sa_status;
1411 }
1412 
1413 static void pr_rcv_process_world(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
1414 				 IN const osm_port_t * requester_port,
1415 				 IN const ib_gid_t * p_sgid,
1416 				 IN const ib_gid_t * p_dgid,
1417 				 IN cl_qlist_t * p_list)
1418 {
1419 	const cl_qmap_t *p_tbl;
1420 	const osm_alias_guid_t *p_dest_alias_guid, *p_src_alias_guid;
1421 
1422 	OSM_LOG_ENTER(sa->p_log);
1423 
1424 	/*
1425 	   Iterate the entire port space over itself.
1426 	   A path record from a port to itself is legit, so no
1427 	   need for a special case there.
1428 
1429 	   We compute both A -> B and B -> A, since we don't have
1430 	   any check to determine the reversability of the paths.
1431 	 */
1432 	p_tbl = &sa->p_subn->alias_port_guid_tbl;
1433 
1434 	p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
1435 	while (p_dest_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
1436 		p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
1437 		while (p_src_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
1438 			pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
1439 						   p_src_alias_guid,
1440 						   p_dest_alias_guid,
1441 						   p_sgid, p_dgid, p_list);
1442 			if (sa_mad->method == IB_MAD_METHOD_GET &&
1443 			    cl_qlist_count(p_list) > 0)
1444 				goto Exit;
1445 
1446 			p_src_alias_guid =
1447 			    (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
1448 		}
1449 
1450 		p_dest_alias_guid =
1451 		    (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
1452 	}
1453 
1454 Exit:
1455 	OSM_LOG_EXIT(sa->p_log);
1456 }
1457 
1458 void osm_pr_process_half(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
1459 				IN const osm_port_t * requester_port,
1460 				IN const osm_alias_guid_t * p_src_alias_guid,
1461 				IN const osm_alias_guid_t * p_dest_alias_guid,
1462 				IN const ib_gid_t * p_sgid,
1463 				IN const ib_gid_t * p_dgid,
1464 				IN cl_qlist_t * p_list)
1465 {
1466 	const cl_qmap_t *p_tbl;
1467 	const osm_alias_guid_t *p_alias_guid;
1468 
1469 	OSM_LOG_ENTER(sa->p_log);
1470 
1471 	/*
1472 	   Iterate over every port, looking for matches...
1473 	   A path record from a port to itself is legit, so no
1474 	   need to special case that one.
1475 	 */
1476 	p_tbl = &sa->p_subn->alias_port_guid_tbl;
1477 
1478 	if (p_src_alias_guid) {
1479 		/*
1480 		   The src port if fixed, so iterate over destination ports.
1481 		 */
1482 		p_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
1483 		while (p_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
1484 			pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
1485 						   p_src_alias_guid,
1486 						   p_alias_guid,
1487 						   p_sgid, p_dgid, p_list);
1488 			if (sa_mad->method == IB_MAD_METHOD_GET &&
1489 			    cl_qlist_count(p_list) > 0)
1490 				break;
1491 			p_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_alias_guid->map_item);
1492 		}
1493 	} else {
1494 		/*
1495 		   The dest port if fixed, so iterate over source ports.
1496 		 */
1497 		p_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
1498 		while (p_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
1499 			pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
1500 						   p_alias_guid,
1501 						   p_dest_alias_guid, p_sgid,
1502 						   p_dgid, p_list);
1503 			if (sa_mad->method == IB_MAD_METHOD_GET &&
1504 			    cl_qlist_count(p_list) > 0)
1505 				break;
1506 			p_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_alias_guid->map_item);
1507 		}
1508 	}
1509 
1510 	OSM_LOG_EXIT(sa->p_log);
1511 }
1512 
1513 void osm_pr_process_pair(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
1514 				IN const osm_port_t * requester_port,
1515 				IN const osm_alias_guid_t * p_src_alias_guid,
1516 				IN const osm_alias_guid_t * p_dest_alias_guid,
1517 				IN const ib_gid_t * p_sgid,
1518 				IN const ib_gid_t * p_dgid,
1519 				IN cl_qlist_t * p_list)
1520 {
1521 	OSM_LOG_ENTER(sa->p_log);
1522 
1523 	pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port, p_src_alias_guid,
1524 				   p_dest_alias_guid, p_sgid, p_dgid, p_list);
1525 
1526 	OSM_LOG_EXIT(sa->p_log);
1527 }
1528 
1529 static ib_api_status_t pr_match_mgrp_attributes(IN osm_sa_t * sa,
1530 						IN const ib_sa_mad_t * sa_mad,
1531 						IN const osm_mgrp_t * p_mgrp)
1532 {
1533 	const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
1534 	ib_net64_t comp_mask = sa_mad->comp_mask;
1535 	const osm_port_t *port;
1536 	ib_api_status_t status = IB_ERROR;
1537 	uint32_t flow_label;
1538 	uint8_t sl, hop_limit;
1539 
1540 	OSM_LOG_ENTER(sa->p_log);
1541 
1542 	/* check that MLID of the MC group matches the PathRecord DLID */
1543 	if ((comp_mask & IB_PR_COMPMASK_DLID) && p_mgrp->mlid != p_pr->dlid) {
1544 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1545 			"DLID 0x%x is not MLID 0x%x for MC group\n",
1546 			 cl_ntoh16(p_pr->dlid), cl_ntoh16(p_mgrp->mlid));
1547 		goto Exit;
1548 	}
1549 
1550 	/* If SGID and/or SLID specified, should validate as member of MC group */
1551 	if (comp_mask & IB_PR_COMPMASK_SGID) {
1552 		if (!osm_mgrp_get_mcm_alias_guid(p_mgrp,
1553 						 p_pr->sgid.unicast.interface_id)) {
1554 			char gid_str[INET6_ADDRSTRLEN];
1555 			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1556 				"SGID %s is not a member of MC group\n",
1557 				inet_ntop(AF_INET6, p_pr->sgid.raw,
1558 					  gid_str, sizeof gid_str));
1559 			goto Exit;
1560 		}
1561 	}
1562 
1563 	if (comp_mask & IB_PR_COMPMASK_SLID) {
1564 		port = osm_get_port_by_lid(sa->p_subn, p_pr->slid);
1565 		if (!port || !osm_mgrp_get_mcm_port(p_mgrp, port->guid)) {
1566 			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1567 				"Either no port with SLID %u found or "
1568 				"SLID not a member of MC group\n",
1569 				cl_ntoh16(p_pr->slid));
1570 			goto Exit;
1571 		}
1572 	}
1573 
1574 	/* Also, MTU, rate, packet lifetime, and raw traffic requested are not currently checked */
1575 	if ((comp_mask & IB_PR_COMPMASK_PKEY) &&
1576 	    p_pr->pkey != p_mgrp->mcmember_rec.pkey) {
1577 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1578 			"Pkey 0x%x doesn't match MC group Pkey 0x%x\n",
1579 			cl_ntoh16(p_pr->pkey),
1580 			cl_ntoh16(p_mgrp->mcmember_rec.pkey));
1581 		goto Exit;
1582 	}
1583 
1584 	ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop,
1585 				  &sl, &flow_label, &hop_limit);
1586 
1587 	if ((comp_mask & IB_PR_COMPMASK_SL) && ib_path_rec_sl(p_pr) != sl) {
1588 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1589 			"SL %d doesn't match MC group SL %d\n",
1590 			ib_path_rec_sl(p_pr), sl);
1591 		goto Exit;
1592 	}
1593 
1594 	/* If SubnAdmGet, assume NumbPaths of 1 (1.2 erratum) */
1595 	if ((comp_mask & IB_PR_COMPMASK_NUMBPATH) &&
1596 	    sa_mad->method != IB_MAD_METHOD_GET &&
1597 	    ib_path_rec_num_path(p_pr) == 0) {
1598 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1599 			"Number of paths requested is 0\n");
1600 		goto Exit;
1601 	}
1602 
1603 	if ((comp_mask & IB_PR_COMPMASK_FLOWLABEL) &&
1604 	    ib_path_rec_flow_lbl(p_pr) != flow_label) {
1605 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1606 			"Flow label 0x%x doesn't match MC group "
1607 			" flow label 0x%x\n",
1608 			ib_path_rec_flow_lbl(p_pr), flow_label);
1609 		goto Exit;
1610 	}
1611 
1612 	if ((comp_mask & IB_PR_COMPMASK_HOPLIMIT) &&
1613 	    ib_path_rec_hop_limit(p_pr) != hop_limit) {
1614 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1615 			"Hop limit %u doesn't match MC group hop limit %u\n",
1616 			ib_path_rec_hop_limit(p_pr), hop_limit);
1617 		goto Exit;
1618 	}
1619 
1620 
1621 	if ((comp_mask & IB_PR_COMPMASK_TCLASS) &&
1622 	    p_pr->tclass != p_mgrp->mcmember_rec.tclass) {
1623 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1624 			"TClass 0x%02x doesn't match MC group TClass 0x%02x\n",
1625 			p_pr->tclass, p_mgrp->mcmember_rec.tclass);
1626 		goto Exit;
1627 	}
1628 
1629 	status = IB_SUCCESS;
1630 
1631 Exit:
1632 	OSM_LOG_EXIT(sa->p_log);
1633 	return status;
1634 }
1635 
1636 static void pr_process_multicast(osm_sa_t * sa, const ib_sa_mad_t *sa_mad,
1637 				 cl_qlist_t *list)
1638 {
1639 	ib_path_rec_t *pr = ib_sa_mad_get_payload_ptr(sa_mad);
1640 	osm_mgrp_t *mgrp;
1641 	ib_api_status_t status;
1642 	osm_sa_item_t *pr_item;
1643 	uint32_t flow_label;
1644 	uint8_t sl, hop_limit;
1645 
1646 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Multicast destination requested\n");
1647 
1648 	mgrp = osm_get_mgrp_by_mgid(sa->p_subn, &pr->dgid);
1649 	if (!mgrp) {
1650 		char gid_str[INET6_ADDRSTRLEN];
1651 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F09: "
1652 			"No MC group found for PathRecord destination GID %s\n",
1653 			inet_ntop(AF_INET6, pr->dgid.raw, gid_str,
1654 				  sizeof gid_str));
1655 		return;
1656 	}
1657 
1658 	/* Make sure the rest of the PathRecord matches the MC group attributes */
1659 	status = pr_match_mgrp_attributes(sa, sa_mad, mgrp);
1660 	if (status != IB_SUCCESS) {
1661 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F19: "
1662 			"MC group attributes don't match PathRecord request\n");
1663 		return;
1664 	}
1665 
1666 	pr_item = malloc(SA_PR_RESP_SIZE);
1667 	if (pr_item == NULL) {
1668 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F18: "
1669 			"Unable to allocate path record for MC group\n");
1670 		return;
1671 	}
1672 	memset(pr_item, 0, sizeof(cl_list_item_t));
1673 
1674 	/* Copy PathRecord request into response */
1675 	pr_item->resp.path_rec = *pr;
1676 
1677 	/* Now, use the MC info to cruft up the PathRecord response */
1678 	pr_item->resp.path_rec.dgid = mgrp->mcmember_rec.mgid;
1679 	pr_item->resp.path_rec.dlid = mgrp->mcmember_rec.mlid;
1680 	pr_item->resp.path_rec.tclass = mgrp->mcmember_rec.tclass;
1681 	pr_item->resp.path_rec.num_path = 1;
1682 	pr_item->resp.path_rec.pkey = mgrp->mcmember_rec.pkey;
1683 
1684 	/* MTU, rate, and packet lifetime should be exactly */
1685 	pr_item->resp.path_rec.mtu = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.mtu;
1686 	pr_item->resp.path_rec.rate = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.rate;
1687 	pr_item->resp.path_rec.pkt_life = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.pkt_life;
1688 
1689 	/* SL, Hop Limit, and Flow Label */
1690 	ib_member_get_sl_flow_hop(mgrp->mcmember_rec.sl_flow_hop,
1691 				  &sl, &flow_label, &hop_limit);
1692 	ib_path_rec_set_sl(&pr_item->resp.path_rec, sl);
1693 	ib_path_rec_set_qos_class(&pr_item->resp.path_rec, 0);
1694 
1695 	/* HopLimit is not yet set in non link local MC groups */
1696 	/* If it were, this would not be needed */
1697 	if (ib_mgid_get_scope(&mgrp->mcmember_rec.mgid) !=
1698 	    IB_MC_SCOPE_LINK_LOCAL)
1699 		hop_limit = IB_HOPLIMIT_MAX;
1700 
1701 	pr_item->resp.path_rec.hop_flow_raw =
1702 	    cl_hton32(hop_limit) | (flow_label << 8);
1703 
1704 	cl_qlist_insert_tail(list, &pr_item->list_item);
1705 }
1706 
1707 void osm_pr_rcv_process(IN void *context, IN void *data)
1708 {
1709 	osm_sa_t *sa = context;
1710 	osm_madw_t *p_madw = data;
1711 	const ib_sa_mad_t *p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1712 	ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(p_sa_mad);
1713 	cl_qlist_t pr_list;
1714 	const ib_gid_t *p_sgid = NULL, *p_dgid = NULL;
1715 	const osm_alias_guid_t *p_src_alias_guid, *p_dest_alias_guid;
1716 	const osm_port_t *p_src_port, *p_dest_port;
1717 	osm_port_t *requester_port;
1718 	uint8_t rate, mtu;
1719 
1720 	OSM_LOG_ENTER(sa->p_log);
1721 
1722 	CL_ASSERT(p_madw);
1723 
1724 	CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD);
1725 
1726 	/* we only support SubnAdmGet and SubnAdmGetTable methods */
1727 	if (p_sa_mad->method != IB_MAD_METHOD_GET &&
1728 	    p_sa_mad->method != IB_MAD_METHOD_GETTABLE) {
1729 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F17: "
1730 			"Unsupported Method (%s) for PathRecord request\n",
1731 			ib_get_sa_method_str(p_sa_mad->method));
1732 		osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
1733 		goto Exit;
1734 	}
1735 
1736 	/* Validate rate if supplied */
1737 	if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_RATESELEC) &&
1738 	    (p_sa_mad->comp_mask & IB_PR_COMPMASK_RATE)) {
1739 		rate = ib_path_rec_rate(p_pr);
1740 		if (!ib_rate_is_valid(rate)) {
1741 			osm_sa_send_error(sa, p_madw,
1742 					  IB_SA_MAD_STATUS_REQ_INVALID);
1743 			goto Exit;
1744 		}
1745 	}
1746 	/* Validate MTU if supplied */
1747 	if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
1748 	    (p_sa_mad->comp_mask & IB_PR_COMPMASK_MTU)) {
1749 		mtu = ib_path_rec_mtu(p_pr);
1750 		if (!ib_mtu_is_valid(mtu)) {
1751 			osm_sa_send_error(sa, p_madw,
1752 					  IB_SA_MAD_STATUS_REQ_INVALID);
1753 			goto Exit;
1754 		}
1755 	}
1756 
1757 	/* Make sure either none or both ServiceID parameters are supplied */
1758 	if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_SERVICEID) != 0 &&
1759 	    (p_sa_mad->comp_mask & IB_PR_COMPMASK_SERVICEID) !=
1760 	     IB_PR_COMPMASK_SERVICEID) {
1761 		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INSUF_COMPS);
1762 		goto Exit;
1763 	}
1764 
1765 	cl_qlist_init(&pr_list);
1766 
1767 	/*
1768 	   Most SA functions (including this one) are read-only on the
1769 	   subnet object, so we grab the lock non-exclusively.
1770 	 */
1771 	cl_plock_acquire(sa->p_lock);
1772 
1773 	/* update the requester physical port */
1774 	requester_port = osm_get_port_by_mad_addr(sa->p_log, sa->p_subn,
1775 						  osm_madw_get_mad_addr_ptr
1776 						  (p_madw));
1777 	if (requester_port == NULL) {
1778 		cl_plock_release(sa->p_lock);
1779 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F16: "
1780 			"Cannot find requester physical port\n");
1781 		goto Exit;
1782 	}
1783 
1784 	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
1785 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1786 			"Requester port GUID 0x%" PRIx64 "\n",
1787 			cl_ntoh64(osm_port_get_guid(requester_port)));
1788 		osm_dump_path_record_v2(sa->p_log, p_pr, FILE_ID, OSM_LOG_DEBUG);
1789 	}
1790 
1791 	/* Handle multicast destinations separately */
1792 	if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_DGID) &&
1793 	    ib_gid_is_multicast(&p_pr->dgid)) {
1794 		pr_process_multicast(sa, p_sa_mad, &pr_list);
1795 		goto Unlock;
1796 	}
1797 
1798 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Unicast destination requested\n");
1799 
1800 	if (osm_pr_get_end_points(sa, p_sa_mad,
1801 				  &p_src_alias_guid, &p_dest_alias_guid,
1802 				  &p_src_port, &p_dest_port,
1803 				  &p_sgid, &p_dgid) != IB_SA_MAD_STATUS_SUCCESS)
1804 		goto Unlock;
1805 
1806 	if (p_src_alias_guid && p_src_port &&
1807 	    p_src_alias_guid->p_base_port != p_src_port) {
1808 		cl_plock_release(sa->p_lock);
1809 		OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1810 			"Requester port GUID 0x%" PRIx64 ": Port for SGUID "
1811 			"0x%" PRIx64 " not same as port for SLID %u\n",
1812 			cl_ntoh64(osm_port_get_guid(requester_port)),
1813 			cl_ntoh64(p_pr->sgid.unicast.interface_id),
1814 			cl_ntoh16(p_pr->slid));
1815 		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1816 		goto Exit;
1817 	}
1818 
1819 	if (p_dest_alias_guid && p_dest_port &&
1820 	    p_dest_alias_guid->p_base_port != p_dest_port) {
1821 		cl_plock_release(sa->p_lock);
1822 		OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1823 			"Requester port GUID 0x%" PRIx64 ": Port for DGUID "
1824 			"0x%" PRIx64 " not same as port for DLID %u\n",
1825 			cl_ntoh64(osm_port_get_guid(requester_port)),
1826 			cl_ntoh64(p_pr->dgid.unicast.interface_id),
1827 			cl_ntoh16(p_pr->dlid));
1828 		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1829 		goto Exit;
1830 	}
1831 
1832 	/*
1833 	   What happens next depends on the type of endpoint information
1834 	   that was specified....
1835 	 */
1836 	if (p_src_alias_guid) {
1837 		if (p_dest_alias_guid)
1838 			osm_pr_process_pair(sa, p_sa_mad, requester_port,
1839 					    p_src_alias_guid, p_dest_alias_guid,
1840 					    p_sgid, p_dgid, &pr_list);
1841 		else if (!p_dest_port)
1842 			osm_pr_process_half(sa, p_sa_mad, requester_port,
1843 					    p_src_alias_guid, NULL, p_sgid,
1844 					    p_dgid, &pr_list);
1845 		else {
1846 			/* Get all alias GUIDs for the dest port */
1847 			p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1848 			while (p_dest_alias_guid !=
1849 			       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1850 				if (osm_get_port_by_alias_guid(sa->p_subn, p_dest_alias_guid->alias_guid) ==
1851 				    p_dest_port)
1852 					osm_pr_process_pair(sa, p_sa_mad,
1853 							    requester_port,
1854 							    p_src_alias_guid,
1855 							    p_dest_alias_guid,
1856 							    p_sgid, p_dgid,
1857 							    &pr_list);
1858 				if (p_sa_mad->method == IB_MAD_METHOD_GET &&
1859 				    cl_qlist_count(&pr_list) > 0)
1860 					break;
1861 
1862 				p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
1863 			}
1864 		}
1865 	} else {
1866 		if (p_dest_alias_guid && !p_src_port)
1867 			osm_pr_process_half(sa, p_sa_mad, requester_port,
1868 					    NULL, p_dest_alias_guid, p_sgid,
1869 					    p_dgid, &pr_list);
1870 		else if (!p_src_port && !p_dest_port)
1871 			/*
1872 			   Katie, bar the door!
1873 			 */
1874 			pr_rcv_process_world(sa, p_sa_mad, requester_port,
1875 					     p_sgid, p_dgid, &pr_list);
1876 		else if (p_dest_alias_guid && p_src_port) {
1877 			/* Get all alias GUIDs for the src port */
1878 			p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1879 			while (p_src_alias_guid !=
1880 			       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1881 				if (osm_get_port_by_alias_guid(sa->p_subn,
1882 							       p_src_alias_guid->alias_guid) ==
1883 				    p_src_port)
1884 					osm_pr_process_pair(sa, p_sa_mad,
1885 							    requester_port,
1886 							    p_src_alias_guid,
1887 							    p_dest_alias_guid,
1888 							    p_sgid, p_dgid,
1889 							    &pr_list);
1890 				if (p_sa_mad->method == IB_MAD_METHOD_GET &&
1891 				    cl_qlist_count(&pr_list) > 0)
1892 					break;
1893 				p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
1894 			}
1895 		} else if (p_src_port && !p_dest_port) {
1896 			/* Get all alias GUIDs for the src port */
1897 			p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1898 			while (p_src_alias_guid !=
1899 			       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1900 				if (osm_get_port_by_alias_guid(sa->p_subn,
1901 							       p_src_alias_guid->alias_guid) ==
1902 				    p_src_port)
1903 					osm_pr_process_half(sa, p_sa_mad,
1904 							    requester_port,
1905 							    p_src_alias_guid,
1906 							    NULL, p_sgid,
1907 							    p_dgid, &pr_list);
1908 				p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
1909 			}
1910 		} else if (p_dest_port && !p_src_port) {
1911 			/* Get all alias GUIDs for the dest port */
1912 			p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1913 			while (p_dest_alias_guid !=
1914 			       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1915 				if (osm_get_port_by_alias_guid(sa->p_subn,
1916 							       p_dest_alias_guid->alias_guid) ==
1917 				    p_dest_port)
1918 					osm_pr_process_half(sa, p_sa_mad,
1919 							    requester_port,
1920 							    NULL,
1921 							    p_dest_alias_guid,
1922 							    p_sgid, p_dgid,
1923 							    &pr_list);
1924 				p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
1925 			}
1926 		} else {
1927 			/* Get all alias GUIDs for the src port */
1928 			p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1929 			while (p_src_alias_guid !=
1930 			       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1931 				if (osm_get_port_by_alias_guid(sa->p_subn,
1932 							       p_src_alias_guid->alias_guid) ==
1933 				    p_src_port) {
1934 					/* Get all alias GUIDs for the dest port */
1935 					p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1936 					while (p_dest_alias_guid !=
1937 					       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1938 						if (osm_get_port_by_alias_guid(sa->p_subn,
1939 									       p_dest_alias_guid->alias_guid) ==
1940 						    p_dest_port)
1941 						osm_pr_process_pair(sa,
1942 								    p_sa_mad,
1943 								    requester_port,
1944 								    p_src_alias_guid,
1945 								    p_dest_alias_guid,
1946 								    p_sgid,
1947 								    p_dgid,
1948 								    &pr_list);
1949 						if (p_sa_mad->method == IB_MAD_METHOD_GET &&
1950 						    cl_qlist_count(&pr_list) > 0)
1951 							break;
1952 						p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
1953 					}
1954 				}
1955 				if (p_sa_mad->method == IB_MAD_METHOD_GET &&
1956 				    cl_qlist_count(&pr_list) > 0)
1957 					break;
1958 				p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
1959 			}
1960 		}
1961 	}
1962 
1963 Unlock:
1964 	cl_plock_release(sa->p_lock);
1965 
1966 	/* Now, (finally) respond to the PathRecord request */
1967 	osm_sa_respond(sa, p_madw, sizeof(ib_path_rec_t), &pr_list);
1968 
1969 Exit:
1970 	OSM_LOG_EXIT(sa->p_log);
1971 }
1972