xref: /illumos-gate/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_path.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/ib/mgt/ibcm/ibcm_impl.h>
30 #include <sys/ib/ibtl/ibti.h>
31 
32 /*
33  * ibcm_path.c
34  *
35  * ibt_get_paths() implement the Path Informations related functionality.
36  */
37 
38 /* Externs. */
39 extern char	cmlog[];
40 
41 /* ibcm_saa_service_rec() fills in ServiceID and DGID. */
42 typedef struct ibcm_dest_s {
43 	ib_gid_t	d_gid;
44 	ib_svc_id_t	d_sid;
45 	ibt_srv_data_t	d_sdata;
46 	ib_pkey_t	d_pkey;
47 	uint_t		d_tag;	/* 0 = Unicast, 1 = Multicast, 2 = LoopBack */
48 } ibcm_dest_t;
49 
50 /* Holds Destination information needed to fill in ibt_path_info_t. */
51 typedef struct ibcm_dinfo_s {
52 	uint8_t		num_dest;
53 	ib_pkey_t	p_key;
54 	ibcm_dest_t	dest[1];
55 } ibcm_dinfo_t;
56 
57 _NOTE(SCHEME_PROTECTS_DATA("Temporary path storage", ibcm_dinfo_s))
58 _NOTE(READ_ONLY_DATA(ibt_path_attr_s))
59 
60 typedef struct ibcm_path_tqargs_s {
61 	ibt_path_attr_t		attr;
62 	ibt_path_info_t		*paths;
63 	uint8_t			*num_paths_p;
64 	ibt_path_handler_t	func;
65 	void			*arg;
66 	ibt_path_flags_t	flags;
67 	uint8_t			max_paths;
68 } ibcm_path_tqargs_t;
69 
70 
71 /* Prototype Declarations. */
72 static ibt_status_t ibcm_get_path_rec(ibcm_path_tqargs_t *, ibcm_dinfo_t *,
73     uint8_t *, ibt_path_info_t *);
74 
75 static ibt_status_t ibcm_saa_path_rec(ibcm_path_tqargs_t *,
76     ibtl_cm_port_list_t *, ibcm_dinfo_t *, uint8_t *);
77 
78 static ibt_status_t ibcm_update_cep_info(sa_path_record_t *,
79     ibtl_cm_port_list_t *, ibtl_cm_hca_port_t *, ibt_cep_path_t *);
80 
81 static ibt_status_t ibcm_fillin_loopbackinfo(ibtl_cm_port_list_t *,
82     uint8_t index, ibcm_dinfo_t *, ibt_path_info_t *);
83 
84 static ibt_status_t ibcm_saa_service_rec(ibcm_path_tqargs_t *,
85     ibtl_cm_port_list_t *, ibcm_dinfo_t *);
86 
87 static ibt_status_t ibcm_get_single_pathrec(ibcm_path_tqargs_t *,
88     ibtl_cm_port_list_t *, ibcm_dinfo_t *, uint8_t,
89     uint8_t *, ibt_path_info_t *);
90 
91 static ibt_status_t ibcm_get_multi_pathrec(ibcm_path_tqargs_t *,
92     ibtl_cm_port_list_t *, ibcm_dinfo_t *dinfo,
93     uint8_t *, ibt_path_info_t *);
94 
95 static ibt_status_t ibcm_validate_path_attributes(ibt_path_attr_t *attrp,
96     ibt_path_flags_t flags, uint8_t max_paths);
97 
98 static ibt_status_t ibcm_handle_get_path(ibt_path_attr_t *attrp,
99     ibt_path_flags_t flags, uint8_t max_paths, ibt_path_info_t *paths,
100     uint8_t *num_path_p, ibt_path_handler_t func, void  *arg);
101 
102 static void ibcm_process_async_get_paths(void *tq_arg);
103 
104 static ibt_status_t ibcm_process_get_paths(void *tq_arg);
105 
106 static ibt_status_t ibcm_get_comp_pgids(ib_gid_t, ib_gid_t, ib_guid_t,
107     ib_gid_t **, uint_t *);
108 
109 
110 /*
111  * Function:
112  *	ibt_aget_paths
113  * Input:
114  *	ibt_hdl		The handle returned to the client by the IBTF from an
115  *			ibt_attach() call. Can be used by the IBTF Policy module
116  *			and CM in the determination of the "best" path to the
117  *			specified destination for this class of driver.
118  *	flags		Path flags.
119  *	attrp		Points to an ibt_path_attr_t struct that contains
120  *			required and optional attributes.
121  *	func		A pointer to an ibt_path_handler_t function to call
122  *			when ibt_aget_paths() completes.
123  *	arg		The argument to 'func'.
124  * Returns:
125  *	IBT_SUCCESS on early validation of attributes else appropriate error.
126  * Description:
127  *	Finds the best path to a specified destination or service
128  *	asynchronously (as determined by the IBTL) that satisfies the
129  *	requirements specified in an ibt_path_attr_t struct.
130  *	ibt_aget_paths() is a Non-Blocking version of ibt_get_paths().
131  */
132 ibt_status_t
133 ibt_aget_paths(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags,
134     ibt_path_attr_t *attrp, uint8_t max_paths, ibt_path_handler_t func,
135     void  *arg)
136 {
137 	IBTF_DPRINTF_L3(cmlog, "ibt_aget_paths(%p, 0x%lX, %p, %d, %p)",
138 	    ibt_hdl, flags, attrp, max_paths, func);
139 
140 	if (func == NULL) {
141 		IBTF_DPRINTF_L2(cmlog, "ibt_aget_paths: Function Pointer is "
142 		    "NULL - ERROR ");
143 		return (IBT_INVALID_PARAM);
144 	}
145 
146 	/* Memory for path info will be allocated in ibcm_process_get_paths() */
147 	return (ibcm_handle_get_path(attrp, flags, max_paths, NULL, NULL,
148 	    func, arg));
149 }
150 
151 
152 /*
153  * Function:
154  *	ibt_get_paths
155  * Input:
156  *	ibt_hdl		The handle returned to the client by the IBTF from an
157  *			ibt_attach() call. Can be used by the IBTF Policy module
158  *			and CM in the determination of the "best" path to the
159  *			specified destination for this class of driver.
160  *	flags		Path flags.
161  *	attrp		Points to an ibt_path_attr_t struct that contains
162  *			required and optional attributes.
163  *	max_paths	The size of the "paths" array argument. Also, this
164  *			is the limit on the number of paths returned.
165  *			max_paths indicates the number of requested paths to
166  *			the specified destination(s).
167  * Output:
168  *	paths		An array of ibt_path_info_t structs filled in by
169  *			ibt_get_paths() as output parameters. Upon return,
170  *			array elements with non-NULL HCA GUIDs are valid.
171  *	num_paths_p	If non-NULL, return the actual number of paths found.
172  * Returns:
173  *	IBT_SUCCESS on Success else appropriate error.
174  * Description:
175  *	Finds the best path to a specified destination (as determined by the
176  *	IBTL) that satisfies the requirements specified in an ibt_path_attr_t
177  *	struct.
178  *
179  *	This routine can not be called from interrupt context.
180  */
181 ibt_status_t
182 ibt_get_paths(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags,
183     ibt_path_attr_t *attrp, uint8_t max_paths, ibt_path_info_t *paths,
184     uint8_t *num_paths_p)
185 {
186 	ASSERT(paths != NULL);
187 
188 	IBTF_DPRINTF_L3(cmlog, "ibt_get_paths(%p, 0x%lX, %p, %d)",
189 	    ibt_hdl, flags, attrp, max_paths);
190 
191 	if (paths == NULL) {
192 		IBTF_DPRINTF_L2(cmlog, "ibt_get_paths: Path Info Pointer is "
193 		    "NULL - ERROR ");
194 		return (IBT_INVALID_PARAM);
195 	}
196 
197 	if (num_paths_p != NULL)
198 		*num_paths_p = 0;
199 
200 	return (ibcm_handle_get_path(attrp, flags, max_paths, paths,
201 	    num_paths_p, NULL, NULL));
202 }
203 
204 
205 static ibt_status_t
206 ibcm_handle_get_path(ibt_path_attr_t *attrp, ibt_path_flags_t flags,
207     uint8_t max_paths, ibt_path_info_t *paths, uint8_t *num_path_p,
208     ibt_path_handler_t func, void  *arg)
209 {
210 	ibcm_path_tqargs_t	*path_tq;
211 	int		sleep_flag = ((func == NULL) ? KM_SLEEP : KM_NOSLEEP);
212 	int		len;
213 	ibt_status_t	retval;
214 
215 	retval = ibcm_validate_path_attributes(attrp, flags, max_paths);
216 	if (retval != IBT_SUCCESS)
217 		return (retval);
218 
219 	len = (attrp->pa_num_dgids * sizeof (ib_gid_t)) +
220 	    sizeof (ibcm_path_tqargs_t);
221 
222 	path_tq = kmem_alloc(len, sleep_flag);
223 	if (path_tq == NULL) {
224 		IBTF_DPRINTF_L2(cmlog, "ibcm_handle_get_path: "
225 		    "Unable to allocate memory for local usage.");
226 		return (IBT_INSUFF_KERNEL_RESOURCE);
227 	}
228 
229 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*path_tq))
230 
231 	bcopy(attrp, &path_tq->attr, sizeof (ibt_path_attr_t));
232 
233 	if (attrp->pa_num_dgids) {
234 		path_tq->attr.pa_dgids = (ib_gid_t *)(((uchar_t *)path_tq) +
235 		    sizeof (ibcm_path_tqargs_t));
236 
237 		bcopy(attrp->pa_dgids, path_tq->attr.pa_dgids,
238 		    sizeof (ib_gid_t) * attrp->pa_num_dgids);
239 	} else {
240 		path_tq->attr.pa_dgids = NULL;
241 	}
242 
243 	/* Ignore IBT_PATH_AVAIL flag, if only one path is requested. */
244 	if ((flags & IBT_PATH_AVAIL) && (max_paths == 1)) {
245 		flags &= ~IBT_PATH_AVAIL;
246 
247 		IBTF_DPRINTF_L4(cmlog, "ibcm_handle_get_path: "
248 		    "Ignoring IBT_PATH_AVAIL flag, as only ONE path "
249 		    "information is requested.");
250 	}
251 
252 	path_tq->flags = flags;
253 	path_tq->max_paths = max_paths;
254 	path_tq->paths = paths;
255 	path_tq->num_paths_p = num_path_p;
256 	path_tq->func = func;
257 	path_tq->arg = arg;
258 
259 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*path_tq))
260 
261 	if (func != NULL) {		/* Non-Blocking */
262 		IBTF_DPRINTF_L3(cmlog, "ibcm_handle_get_path: Non Blocking");
263 		if (taskq_dispatch(ibcm_taskq, ibcm_process_async_get_paths,
264 		    path_tq, TQ_NOSLEEP) == 0) {
265 			IBTF_DPRINTF_L2(cmlog, "ibcm_handle_get_path: "
266 			    "Failed to dispatch the TaskQ");
267 			kmem_free(path_tq, len);
268 			return (IBT_INSUFF_KERNEL_RESOURCE);
269 		} else
270 			return (IBT_SUCCESS);
271 	} else {		/* Blocking */
272 		IBTF_DPRINTF_L3(cmlog, "ibcm_handle_get_path: Blocking");
273 		return (ibcm_process_get_paths(path_tq));
274 	}
275 }
276 
277 
278 static void
279 ibcm_process_async_get_paths(void *tq_arg)
280 {
281 	(void) ibcm_process_get_paths(tq_arg);
282 }
283 
284 
285 static ibt_status_t
286 ibcm_validate_path_attributes(ibt_path_attr_t *attrp, ibt_path_flags_t flags,
287     uint8_t max_paths)
288 {
289 	uint_t			i;
290 
291 	IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: Inputs are: "
292 	    "HCA (%llX, %d),\n\tSGID(%llX:%llX), SName=\"%s\",\n\tSID= %llX, "
293 	    "Maxpath= %d, Flags= 0x%X, #Dgid= %d, SDFlag= 0x%llX",
294 	    attrp->pa_hca_guid, attrp->pa_hca_port_num,
295 	    attrp->pa_sgid.gid_prefix, attrp->pa_sgid.gid_guid,
296 	    ((attrp->pa_sname != NULL) ? attrp->pa_sname : ""), attrp->pa_sid,
297 	    max_paths, flags, attrp->pa_num_dgids, attrp->pa_sd_flags);
298 
299 	/*
300 	 * Validate Path Flags.
301 	 * IBT_PATH_AVAIL & IBT_PATH_PERF are mutually exclusive.
302 	 */
303 	if ((flags & IBT_PATH_AVAIL) && (flags & IBT_PATH_PERF)) {
304 		IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
305 		    "Invalid Flags: 0x%X,\n\t AVAIL and PERF flags cannot "
306 		    "specified together.", flags);
307 		return (IBT_INVALID_PARAM);
308 	}
309 
310 	/* Validate number of records requested. */
311 	if ((flags & (IBT_PATH_AVAIL | IBT_PATH_PERF)) &&
312 	    (max_paths > IBT_MAX_SPECIAL_PATHS)) {
313 		IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
314 		    "Max records that can be requested is <%d> \n"
315 		    "when IBT_PATH_AVAIL or IBT_PATH_PERF flag is specified.",
316 		    IBT_MAX_SPECIAL_PATHS);
317 		return (IBT_INVALID_PARAM);
318 	}
319 
320 	/* Only 2 destinations can be specified w/ APM flag. */
321 	if ((flags & IBT_PATH_APM) && (attrp->pa_num_dgids > 2)) {
322 		IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes:\n\t Max "
323 		    "number of DGIDs that can be specified w/APM flag is 2");
324 		return (IBT_INVALID_PARAM);
325 	}
326 
327 	/*
328 	 * Max_paths of "0" is invalid.
329 	 * w/ IBT_PATH_MULTI_SVC_DEST flag, max_paths must be greater than "1".
330 	 */
331 	if ((max_paths == 0) ||
332 	    ((flags & IBT_PATH_MULTI_SVC_DEST) && (max_paths < 2))) {
333 		IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
334 		    "Invalid number of records requested:\n flags 0x%X, "
335 		    "max_paths %d", flags, max_paths);
336 		return (IBT_INVALID_PARAM);
337 	}
338 
339 	/*
340 	 * If IBT_PATH_MULTI_SVC_DEST is set, then ServiceName and/or Service ID
341 	 * must be specified and DGIDs SHOULD NOT be specified.
342 	 */
343 	if ((flags & IBT_PATH_MULTI_SVC_DEST) && ((attrp->pa_num_dgids > 0) ||
344 	    ((attrp->pa_sid == 0) && ((attrp->pa_sname == NULL) ||
345 	    ((attrp->pa_sname != NULL) && (strlen(attrp->pa_sname) == 0)))))) {
346 		IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
347 		    "Invalid Flags: 0x%X, IBT_PATH_MULTI_SVC_DEST flag set "
348 		    "but Service Name \n or Service ID NOT specified or DGIDs "
349 		    "are specified.", flags);
350 		return (IBT_INVALID_PARAM);
351 	}
352 
353 	/*
354 	 * User need to specify the destination information, which can be
355 	 * provided as one or more of the following.
356 	 *	o ServiceName
357 	 *	o ServiceID
358 	 *	o Array of DGIDs w/Num of DGIDs, (max of 2)
359 	 */
360 	if ((attrp->pa_sid == 0) && (attrp->pa_num_dgids == 0) &&
361 	    ((attrp->pa_sname == NULL) || ((attrp->pa_sname != NULL) &&
362 	    (strlen(attrp->pa_sname) == 0)))) {
363 		/* Destination information not provided, bail out. */
364 		IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
365 		    "Client's MUST supply DestInfo.");
366 		return (IBT_INVALID_PARAM);
367 	}
368 
369 	/* If DGIDs are provided, validate them. */
370 	if (attrp->pa_num_dgids > 0) {
371 		if (attrp->pa_dgids == NULL) {
372 			IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
373 			    "pa_dgids NULL, but pa_num_dgids : %d",
374 			    attrp->pa_num_dgids);
375 			return (IBT_INVALID_PARAM);
376 		}
377 
378 		/* Validate DGIDs */
379 		for (i = 0; i < attrp->pa_num_dgids; i++) {
380 			ib_gid_t	gid = attrp->pa_dgids[i];
381 
382 			IBTF_DPRINTF_L3(cmlog, "ibcm_validate_path_attributes: "
383 			    "DGID[%d] = %llX:%llX", i, gid.gid_prefix,
384 			    gid.gid_guid);
385 
386 			/* APM request for MultiCast destination is invalid. */
387 			if ((gid.gid_prefix >> 56ULL & 0xFF) == 0xFF) {
388 				if (flags & IBT_PATH_APM) {
389 					IBTF_DPRINTF_L2(cmlog,
390 					    "ibcm_validate_path_attributes: "
391 					    "APM for MGIDs not supported.");
392 					return (IBT_INVALID_PARAM);
393 				}
394 			} else if ((gid.gid_prefix == 0) ||
395 			    (gid.gid_guid == 0)) {
396 				IBTF_DPRINTF_L2(cmlog,
397 				    "ibcm_validate_path_attributes: ERROR: "
398 				    "Invalid DGIDs specified");
399 				return (IBT_INVALID_PARAM);
400 			}
401 		}
402 	}
403 
404 	/* Check for valid Service Name length. */
405 	if ((attrp->pa_sname != NULL) &&
406 	    (strlen(attrp->pa_sname) >= IB_SVC_NAME_LEN)) {
407 		IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
408 		    "ServiceName too long");
409 		return (IBT_INVALID_PARAM);
410 	}
411 
412 	/* If P_Key is specified, check for invalid p_key's */
413 	if (flags & IBT_PATH_PKEY) {
414 		/* Limited P_Key is NOT supported as of now!. */
415 		if ((attrp->pa_pkey == IB_PKEY_INVALID_FULL) ||
416 		    (attrp->pa_pkey & 0x8000) == 0) {
417 			IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
418 			    "Specified P_Key is invalid: 0x%X", attrp->pa_pkey);
419 			return (IBT_INVALID_PARAM);
420 		}
421 		IBTF_DPRINTF_L3(cmlog, "ibcm_validate_path_attributes: "
422 		    "P_Key= 0x%X", attrp->pa_pkey);
423 	}
424 
425 	return (IBT_SUCCESS);
426 }
427 
428 
429 static ibt_status_t
430 ibcm_process_get_paths(void *tq_arg)
431 {
432 	ibcm_path_tqargs_t	*p_arg = (ibcm_path_tqargs_t *)tq_arg;
433 	ibcm_dinfo_t		*dinfo;
434 	int			len;
435 	uint8_t			max_paths, num_path;
436 	ibt_status_t		retval;
437 	ib_gid_t		*d_gids_p = NULL;
438 	ibtl_cm_port_list_t	*slistp = NULL;
439 	uint_t			dnum = 0, num_dest;
440 	uint_t			i, j;
441 	ibcm_hca_info_t		*hcap;
442 	ibmf_saa_handle_t	saa_handle;
443 
444 	IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths(%p, 0x%X, %d) ",
445 	    p_arg, p_arg->flags, p_arg->max_paths);
446 
447 	max_paths = num_path = p_arg->max_paths;
448 
449 	/*
450 	 * Prepare the Destination list based on the input DGIDs and
451 	 * other attributes.
452 	 *
453 	 * APM is requested and pa_dgids are specified.  If multiple DGIDs are
454 	 * specified, check out whether they are companion to each other or if
455 	 * only one DGID is specified, then get the companion port GID for that.
456 	 */
457 	if (p_arg->attr.pa_num_dgids) {
458 		if (p_arg->flags & IBT_PATH_APM) {
459 			ib_gid_t	c_gid, n_gid;
460 
461 			IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: "
462 			    "DGIDs specified w/ APM Flag");
463 
464 			c_gid = p_arg->attr.pa_dgids[0];
465 			if (p_arg->attr.pa_num_dgids > 1)
466 				n_gid = p_arg->attr.pa_dgids[1];
467 			else
468 				n_gid.gid_prefix = n_gid.gid_guid = 0;
469 
470 			retval = ibcm_get_comp_pgids(c_gid, n_gid, 0, &d_gids_p,
471 			    &dnum);
472 			if ((retval != IBT_SUCCESS) &&
473 			    (retval != IBT_GIDS_NOT_FOUND)) {
474 				IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths:"
475 				    " Invalid DGIDs specified w/ APM Flag");
476 				    goto path_error2;
477 			}
478 			IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: "
479 			    "Found %d Comp DGID", dnum);
480 		}
481 
482 		if (dnum) {
483 			len = 1;
484 		} else {
485 			len = p_arg->attr.pa_num_dgids - 1;
486 		}
487 		num_dest = len + 1;
488 
489 		IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: #dgid %d, dnum "
490 		    "%d, #dest %d", p_arg->attr.pa_num_dgids, dnum, num_dest);
491 	} else {
492 		if (p_arg->flags & IBT_PATH_MULTI_SVC_DEST) {
493 			IBTF_DPRINTF_L4(cmlog, "ibcm_process_get_paths: "
494 			    "IBT_PATH_MULTI_SVC_DEST flags set");
495 			len = max_paths - 1;
496 		} else if (p_arg->flags & IBT_PATH_APM) {
497 			len = 1;
498 		} else {
499 			len = 0;
500 		}
501 		num_dest = 0;
502 	}
503 
504 	/* Allocate memory and accumulate all destination information */
505 	len = (len * sizeof (ibcm_dest_t)) + sizeof (ibcm_dinfo_t);
506 
507 	dinfo = kmem_zalloc(len, KM_SLEEP);
508 	dinfo->num_dest = num_dest;
509 	if (p_arg->flags & IBT_PATH_PKEY)
510 		dinfo->p_key = p_arg->attr.pa_pkey;
511 
512 	for (i = 0, j = 0; i < num_dest; i++) {
513 		if (i < p_arg->attr.pa_num_dgids)
514 			dinfo->dest[i].d_gid = p_arg->attr.pa_dgids[i];
515 		else
516 			dinfo->dest[i].d_gid = d_gids_p[j++];
517 	}
518 
519 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*p_arg))
520 
521 	/* IBTF allocates memory for path_info in case of Async Get Paths */
522 	if (p_arg->paths == NULL)
523 		p_arg->paths = kmem_zalloc(sizeof (ibt_path_info_t) * max_paths,
524 		    KM_SLEEP);
525 
526 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*p_arg))
527 
528 	/* Checkout whether user has specified SGID. */
529 	if (p_arg->attr.pa_sgid.gid_prefix && p_arg->attr.pa_sgid.gid_guid) {
530 		ibtl_cm_hca_port_t	hport;
531 
532 		IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: SGID %llX:%llX",
533 		    p_arg->attr.pa_sgid.gid_prefix,
534 		    p_arg->attr.pa_sgid.gid_guid);
535 
536 		/* For the specified SGID, get HCA information. */
537 		retval = ibtl_cm_get_hca_port(p_arg->attr.pa_sgid,
538 		    p_arg->attr.pa_hca_guid, &hport);
539 		if (retval != IBT_SUCCESS) {
540 			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: "
541 			    "Get HCA Port Failed: %d", retval);
542 			goto path_error;
543 		}
544 
545 		if ((p_arg->attr.pa_hca_port_num != 0) &&
546 		    (p_arg->attr.pa_hca_port_num != hport.hp_port)) {
547 			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: "
548 			    "Mis-match input HCA PortNum v/s SGID");
549 			retval = IBT_HCA_PORT_INVALID;
550 			goto path_error;
551 		}
552 
553 		/*
554 		 * If a specific MTU is desired, then first check out whether
555 		 * this source port is capable of this MTU.
556 		 */
557 		if (p_arg->attr.pa_mtu.r_mtu) {
558 			if ((p_arg->attr.pa_mtu.r_selector == IBT_GT) &&
559 			    (p_arg->attr.pa_mtu.r_mtu >= hport.hp_mtu)) {
560 
561 				IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths:"
562 				    " Required MTU not available on this Port. "
563 				    "Requested IBT_GT 0x%x but avail 0x%x",
564 				    p_arg->attr.pa_mtu.r_mtu, hport.hp_mtu);
565 
566 				retval = IBT_INVALID_PARAM;
567 				goto path_error;
568 			} else if ((p_arg->attr.pa_mtu.r_selector == IBT_EQU) &&
569 			    (p_arg->attr.pa_mtu.r_mtu > hport.hp_mtu)) {
570 				IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths:"
571 				    " Required MTU not available on this Port "
572 				    "Requested IBT_EQU to 0x%x but avail 0x%x",
573 				    p_arg->attr.pa_mtu.r_mtu, hport.hp_mtu);
574 
575 				retval = IBT_INVALID_PARAM;
576 				goto path_error;
577 			}
578 		}
579 
580 		if (p_arg->flags & IBT_PATH_APM) {
581 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*p_arg))
582 			p_arg->attr.pa_hca_guid = hport.hp_hca_guid;
583 			_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*p_arg))
584 
585 			retval = ibtl_cm_get_active_plist(&p_arg->attr,
586 			    p_arg->flags, &slistp);
587 			if (retval != IBT_SUCCESS) {
588 				IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths:"
589 				    " ibtl_cm_get_active_plist returned error "
590 				    " %d", retval);
591 				goto path_error;
592 			}
593 		} else {
594 			slistp = kmem_zalloc(sizeof (ibtl_cm_port_list_t),
595 			    KM_SLEEP);
596 
597 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*slistp))
598 			slistp->p_hca_guid = hport.hp_hca_guid;
599 			slistp->p_mtu = hport.hp_mtu;
600 			slistp->p_port_num = hport.hp_port;
601 			slistp->p_base_lid = hport.hp_base_lid;
602 			slistp->p_sgid = p_arg->attr.pa_sgid;
603 			slistp->p_sgid_ix = hport.hp_sgid_ix;
604 			slistp->p_count = 1;
605 			_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*slistp))
606 		}
607 	} else {
608 		/* Source GID is not specified, but so let's find them. */
609 		if (p_arg->attr.pa_hca_guid)
610 			IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: Get "
611 			    "Paths from HCA (%llX)", p_arg->attr.pa_hca_guid);
612 		else
613 			IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: SRC "
614 			    "Point not specified, flags(%X)", p_arg->flags);
615 		/*
616 		 * Get list of active HCA<->Port list, that matches input
617 		 * specified attr.
618 		 */
619 		retval = ibtl_cm_get_active_plist(&p_arg->attr, p_arg->flags,
620 		    &slistp);
621 		if (retval != IBT_SUCCESS) {
622 			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: "
623 			    "HCA capable of requested source attributes NOT "
624 			    "available.");
625 			goto path_error;
626 		}
627 	}
628 
629 	IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: HCA (%llX, %d)",
630 	    slistp->p_hca_guid, slistp->p_port_num);
631 
632 	hcap = ibcm_find_hca_entry(slistp->p_hca_guid);
633 	if (hcap == NULL) {
634 		IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: "
635 		    "NO HCA found");
636 		retval = IBT_HCA_BUSY_DETACHING;
637 		goto path_error;
638 	}
639 
640 	/* Get SA Access Handle. */
641 	for (i = 0; i < slistp->p_count; i++) {
642 		if (i == 0) {
643 			/* Validate whether this HCA supports APM */
644 			if ((p_arg->flags & IBT_PATH_APM) &&
645 			    (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG))) {
646 				IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths:"
647 				    " HCA (%llX): APM NOT SUPPORTED ",
648 				    slistp[i].p_hca_guid);
649 				retval = IBT_APM_NOT_SUPPORTED;
650 				goto path_error1;
651 			}
652 		}
653 
654 		saa_handle = ibcm_get_saa_handle(hcap, slistp[i].p_port_num);
655 		if (saa_handle == NULL) {
656 			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: "
657 			    "SAA HDL NULL, HCA (%llX:%d) NOT ACTIVE",
658 			    slistp[i].p_hca_guid, slistp[i].p_port_num);
659 			retval = IBT_HCA_PORT_NOT_ACTIVE;
660 			goto path_error1;
661 		}
662 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*slistp))
663 		slistp[i].p_saa_hdl = saa_handle;
664 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*slistp))
665 	}
666 
667 	/*
668 	 * If Service Name or Service ID are specified, first retrieve
669 	 * Service Records.
670 	 */
671 	if ((p_arg->attr.pa_sid != 0) || ((p_arg->attr.pa_sname != NULL) &&
672 	    (strlen(p_arg->attr.pa_sname) != 0))) {
673 
674 		IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: Get Service "
675 		    "Record for \n\t(%llX, \"%s\")", p_arg->attr.pa_sid,
676 		    ((p_arg->attr.pa_sname != NULL) ?
677 		    p_arg->attr.pa_sname : ""));
678 
679 		/* Get Service Records. */
680 		retval = ibcm_saa_service_rec(p_arg, slistp, dinfo);
681 		if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA)) {
682 			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: Status="
683 			    "%d, Failed to get Service Record for \n\t"
684 			    "(%llX, \"%s\")", retval, p_arg->attr.pa_sid,
685 			    ((p_arg->attr.pa_sname != NULL) ?
686 			    p_arg->attr.pa_sname : ""));
687 			goto path_error1;
688 		}
689 	}
690 
691 	/* Get Path Records. */
692 	retval = ibcm_saa_path_rec(p_arg, slistp, dinfo, &num_path);
693 
694 path_error1:
695 	ibcm_dec_hca_acc_cnt(hcap);
696 
697 path_error:
698 	if (slistp)
699 		ibtl_cm_free_active_plist(slistp);
700 
701 	if (dinfo)
702 		kmem_free(dinfo, len);
703 
704 path_error2:
705 	if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA))
706 		num_path = 0;
707 
708 	if (p_arg->num_paths_p != NULL)
709 		*p_arg->num_paths_p = num_path;
710 
711 	if ((dnum) && (d_gids_p))
712 		kmem_free(d_gids_p, dnum * sizeof (ib_gid_t));
713 
714 	if (p_arg->func) {   /* Do these only for Async Get Paths */
715 		ibt_path_info_t *tmp_path_p;
716 
717 		if (retval == IBT_INSUFF_DATA) {
718 			/*
719 			 * We allocated earlier memory based on "max_paths",
720 			 * but we got lesser path-records, so re-adjust that
721 			 * buffer so that caller can free the correct memory.
722 			 */
723 			tmp_path_p = kmem_alloc(
724 			    sizeof (ibt_path_info_t) * num_path, KM_SLEEP);
725 
726 			bcopy(p_arg->paths, tmp_path_p,
727 			    num_path * sizeof (ibt_path_info_t));
728 
729 			kmem_free(p_arg->paths,
730 			    sizeof (ibt_path_info_t) * max_paths);
731 		} else if (retval != IBT_SUCCESS) {
732 			if (p_arg->paths)
733 				kmem_free(p_arg->paths,
734 				    sizeof (ibt_path_info_t) * max_paths);
735 			tmp_path_p = NULL;
736 		} else {
737 			tmp_path_p = p_arg->paths;
738 		}
739 		(*(p_arg->func))(p_arg->arg, retval, tmp_path_p, num_path);
740 	}
741 
742 	len = (sizeof (ib_gid_t) * p_arg->attr.pa_num_dgids) +
743 	    sizeof (ibcm_path_tqargs_t);
744 
745 	if (p_arg && len)
746 		kmem_free(p_arg, len);
747 
748 	IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: done: status %d, "
749 	    "Found %d/%d Path Records", retval, num_path, max_paths);
750 
751 	return (retval);
752 }
753 
754 
755 /*
756  * Perform SA Access to retrieve Path Records.
757  */
758 static ibt_status_t
759 ibcm_saa_path_rec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
760     ibcm_dinfo_t *dinfo, uint8_t *max_count)
761 {
762 	uint8_t		num_path = *max_count;
763 	uint8_t		num_path_plus;
764 	uint_t		extra, idx, rec_found = 0;
765 	ibt_status_t	retval = IBT_SUCCESS;
766 	int		unicast_dgid_present = 0;
767 	uint8_t		i;
768 
769 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec(%p, %p, %p, 0x%X, %d)",
770 	    p_arg, sl, dinfo, p_arg->flags, *max_count);
771 
772 	if ((dinfo->num_dest == 0) || (num_path == 0) || (sl == NULL)) {
773 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: Invalid Counters");
774 		return (IBT_INVALID_PARAM);
775 	}
776 
777 	/*
778 	 * Of the total needed "X" number of paths to "Y" number of destination
779 	 * we need to get X/Y plus X%Y extra paths to each destination,
780 	 * We do this so that we can choose the required number of path records
781 	 * for the specific destination.
782 	 */
783 	num_path /= dinfo->num_dest;
784 	extra = (*max_count % dinfo->num_dest);
785 
786 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: numpath %d extra %d dest %d",
787 	    num_path, extra, dinfo->num_dest);
788 
789 	/*
790 	 * Find out whether we need to get PathRecord for a MGID as DGID or
791 	 * qualifies for a LoopBack.
792 	 */
793 	for (idx = 0; idx < dinfo->num_dest; idx++) {
794 		ib_gid_t	dgid = dinfo->dest[idx].d_gid;
795 
796 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: DGID[%d]: %llX:%llX",
797 		    idx, dgid.gid_prefix, dgid.gid_guid);
798 
799 		if ((dgid.gid_prefix >> 56ULL & 0xFF) == 0xFF) {
800 			if (extra) {
801 				num_path_plus = num_path + 1;
802 				extra--;
803 			} else
804 				num_path_plus = num_path;
805 
806 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: Get %d Paths"
807 			    "- MGID(%016llX%016llX)", num_path_plus,
808 			    dgid.gid_prefix, dgid.gid_guid);
809 
810 			dinfo->dest[idx].d_tag = 1; /* MultiCast */
811 
812 			/* Yes, it's Single PathRec query for MGID as DGID. */
813 			retval = ibcm_get_single_pathrec(p_arg, sl, dinfo, idx,
814 			    &num_path_plus, &p_arg->paths[rec_found]);
815 			if ((retval != IBT_SUCCESS) &&
816 			    (retval != IBT_INSUFF_DATA)) {
817 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: "
818 				    "Failed to get PathRec for MGID %d",
819 				    retval);
820 				continue;
821 			}
822 
823 			rec_found += num_path_plus;
824 		} else {
825 			/*
826 			 * Check out whether we are looking for loop-back path
827 			 * info. In this case, we should not contact SA Access
828 			 * for Path Records, but instead we need to "synthesize"
829 			 * a loop back path record.
830 			 */
831 			for (i = 0; i < sl->p_count; i++) {
832 				if ((sl[i].p_sgid.gid_prefix ==
833 				    dgid.gid_prefix) &&
834 				    (sl[i].p_sgid.gid_guid == dgid.gid_guid)) {
835 
836 					dinfo->dest[idx].d_tag = 2;
837 
838 					/* Yes, it's loop back case. */
839 					retval = ibcm_fillin_loopbackinfo(
840 					    &sl[i], idx, dinfo,
841 					    &p_arg->paths[rec_found]);
842 					if (retval != IBT_SUCCESS)
843 						break;
844 
845 					/*
846 					 * We update only one record for
847 					 * loop-back case.
848 					 */
849 					rec_found++;
850 					if (rec_found == *max_count)
851 						break;
852 				}
853 			}
854 		}
855 		if (rec_found == *max_count)
856 			break;
857 	}
858 
859 	for (i = 0; i < dinfo->num_dest; i++) {
860 		if (dinfo->dest[i].d_tag == 0) {
861 			unicast_dgid_present++;
862 		}
863 	}
864 
865 	num_path_plus = *max_count - rec_found;
866 
867 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: Recfound: %d, need to find "
868 	    "%d, UniCastGID present %d", rec_found, num_path_plus,
869 	    unicast_dgid_present);
870 
871 	if ((unicast_dgid_present != 0) && (num_path_plus > 0)) {
872 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: MultiSM=%d, #SRC=%d,"
873 		    "Dest%d", sl->p_multism, sl->p_count, unicast_dgid_present);
874 
875 		if ((sl->p_multism == 1) ||
876 		    ((unicast_dgid_present == 1) && (sl->p_count == 1))) {
877 			/*
878 			 * Use SinglePathRec if we are dealing w/ MultiSM or
879 			 * request is for one SGID to one DGID.
880 			 */
881 			retval = ibcm_get_single_pathrec(p_arg, sl, dinfo, 0xFF,
882 			    &num_path_plus, &p_arg->paths[rec_found]);
883 		} else {
884 			/* MultiPathRec will be used for other queries. */
885 			retval = ibcm_get_multi_pathrec(p_arg, sl, dinfo,
886 			    &num_path_plus, &p_arg->paths[rec_found]);
887 		}
888 		if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA)) {
889 			IBTF_DPRINTF_L2(cmlog, "ibcm_saa_path_rec: "
890 			    "Failed to get PathRec: Status %d", retval);
891 		} else {
892 			rec_found += num_path_plus;
893 		}
894 	}
895 
896 	if (rec_found == 0) {
897 		if (retval == IBT_SUCCESS)
898 			retval = IBT_PATH_RECORDS_NOT_FOUND;
899 	} else if (rec_found != *max_count)
900 		retval = IBT_INSUFF_DATA;
901 
902 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: done. Status = %d, "
903 	    "Found %d/%d Paths", retval, rec_found, *max_count);
904 
905 	*max_count = rec_found; /* Update the return count. */
906 
907 	return (retval);
908 }
909 
910 ibt_status_t
911 ibcm_contact_sa_access(ibmf_saa_handle_t saa_handle,
912     ibmf_saa_access_args_t *access_args, size_t *length, void **results_p)
913 {
914 	int	retry;
915 	int	sa_retval;
916 
917 	IBTF_DPRINTF_L3(cmlog, "ibcm_contact_sa_access(%p, %p)",
918 	    saa_handle, access_args);
919 
920 	ibcm_sa_access_enter();
921 
922 	for (retry = 0; retry < ibcm_max_sa_retries; retry++) {
923 		sa_retval = ibmf_sa_access(saa_handle, access_args, 0,
924 		    length, results_p);
925 		if (sa_retval != IBMF_TRANS_TIMEOUT)
926 			break;
927 
928 		IBTF_DPRINTF_L2(cmlog, "ibcm_contact_sa_access: "
929 		    "ibmf_sa_access() - Timed Out (%d)", sa_retval);
930 		delay(ibcm_sa_timeout_delay);
931 	}
932 
933 	ibcm_sa_access_exit();
934 
935 	if ((sa_retval == IBMF_SUCCESS) || (sa_retval == IBMF_NO_RECORDS) ||
936 	    (sa_retval == IBMF_REQ_INVALID)) {
937 		IBTF_DPRINTF_L3(cmlog, "ibcm_contact_sa_access: "
938 		    "ibmf_sa_access() returned (%d)", sa_retval);
939 		return (IBT_SUCCESS);
940 	} else  {
941 		IBTF_DPRINTF_L2(cmlog, "ibcm_contact_sa_access: "
942 		    "ibmf_sa_access(): Failed (%d)", sa_retval);
943 		return (ibcm_ibmf_analyze_error(sa_retval));
944 	}
945 }
946 
947 
948 static ibt_status_t
949 ibcm_update_pri(sa_path_record_t *pr_resp, ibtl_cm_port_list_t *sl,
950     ibcm_dinfo_t *dinfo, ibt_path_info_t *paths)
951 {
952 	ibt_status_t	retval = IBT_SUCCESS;
953 	int		d, s;
954 
955 	retval = ibcm_update_cep_info(pr_resp, sl, NULL,
956 	    &paths->pi_prim_cep_path);
957 	if (retval != IBT_SUCCESS)
958 		return (retval);
959 
960 	/* Update some leftovers */
961 	paths->pi_prim_pkt_lt = pr_resp->PacketLifeTime;
962 	paths->pi_path_mtu = pr_resp->Mtu;
963 
964 	for (d = 0; d < dinfo->num_dest; d++) {
965 		if (pr_resp->DGID.gid_guid == dinfo->dest[d].d_gid.gid_guid) {
966 			paths->pi_sid = dinfo->dest[d].d_sid;
967 			if (paths->pi_sid != 0) {
968 				bcopy(&dinfo->dest[d].d_sdata,
969 				    &paths->pi_sdata, sizeof (ibt_srv_data_t));
970 			}
971 			break;
972 		}
973 	}
974 
975 	for (s = 0; s < sl->p_count; s++) {
976 		if (pr_resp->SGID.gid_guid == sl[s].p_sgid.gid_guid) {
977 			paths->pi_hca_guid = sl[s].p_hca_guid;
978 		}
979 	}
980 
981 	/* Set Alternate Path to invalid state. */
982 	paths->pi_alt_cep_path.cep_hca_port_num = 0;
983 	paths->pi_alt_cep_path.cep_adds_vect.av_dlid = 0;
984 
985 	IBTF_DPRINTF_L5(cmlog, "Path: HCA GUID  = 0x%llX", paths->pi_hca_guid);
986 	IBTF_DPRINTF_L5(cmlog, "Path: ServiceID = 0x%llX", paths->pi_sid);
987 
988 	return (retval);
989 }
990 
991 
992 static ibt_status_t
993 ibcm_get_single_pathrec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
994     ibcm_dinfo_t *dinfo, uint8_t idx, uint8_t *num_path, ibt_path_info_t *paths)
995 {
996 	sa_path_record_t	pathrec_req;
997 	sa_path_record_t	*pr_resp;
998 	ibmf_saa_access_args_t	access_args;
999 	uint64_t		c_mask = 0;
1000 	void			*results_p;
1001 	uint8_t			num_rec;
1002 	size_t			length;
1003 	ibt_status_t		retval;
1004 	int			i, j, k;
1005 	int			found, p_fnd, a_fnd;
1006 	ibt_path_attr_t		*attrp = &p_arg->attr;
1007 	ibmf_saa_handle_t	saa_handle;
1008 
1009 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec(%p, %p, %p, %d)",
1010 	    p_arg, sl, dinfo, *num_path);
1011 
1012 	bzero(&pathrec_req, sizeof (sa_path_record_t));
1013 
1014 	/* Is Flow Label Specified. */
1015 	if (attrp->pa_flow) {
1016 		pathrec_req.FlowLabel = attrp->pa_flow;
1017 		c_mask |= SA_PR_COMPMASK_FLOWLABEL;
1018 	}
1019 
1020 	/* Is HopLimit Specified. */
1021 	if (p_arg->flags & IBT_PATH_HOP) {
1022 		pathrec_req.HopLimit = attrp->pa_hop;
1023 		c_mask |= SA_PR_COMPMASK_HOPLIMIT;
1024 	}
1025 
1026 	/* Is P_Key Specified. */
1027 	if (dinfo->p_key) {
1028 		IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: "
1029 		    "Specified or Global PKEY 0x%X", dinfo->p_key);
1030 		pathrec_req.P_Key = dinfo->p_key;
1031 		c_mask |= SA_PR_COMPMASK_PKEY;
1032 	}
1033 
1034 	/* Is TClass Specified. */
1035 	if (attrp->pa_tclass) {
1036 		pathrec_req.TClass = attrp->pa_tclass;
1037 		c_mask |= SA_PR_COMPMASK_TCLASS;
1038 	}
1039 
1040 	/* Is SL specified. */
1041 	if (attrp->pa_sl) {
1042 		pathrec_req.SL = attrp->pa_sl;
1043 		c_mask |= SA_PR_COMPMASK_SL;
1044 	}
1045 
1046 	/* If IBT_PATH_PERF is set, then mark all selectors to BEST. */
1047 	if (p_arg->flags & IBT_PATH_PERF) {
1048 		pathrec_req.PacketLifeTimeSelector = IBT_BEST;
1049 		pathrec_req.MtuSelector = IBT_BEST;
1050 		pathrec_req.RateSelector = IBT_BEST;
1051 
1052 		c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR |
1053 		    SA_PR_COMPMASK_RATESELECTOR | SA_PR_COMPMASK_MTUSELECTOR;
1054 	} else {
1055 		if (attrp->pa_pkt_lt.p_selector == IBT_BEST) {
1056 			pathrec_req.PacketLifeTimeSelector = IBT_BEST;
1057 			c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR;
1058 		}
1059 
1060 		if (attrp->pa_srate.r_selector == IBT_BEST) {
1061 			pathrec_req.RateSelector = IBT_BEST;
1062 			c_mask |= SA_PR_COMPMASK_RATESELECTOR;
1063 		}
1064 
1065 		if (attrp->pa_mtu.r_selector == IBT_BEST) {
1066 			pathrec_req.MtuSelector = IBT_BEST;
1067 			c_mask |= SA_PR_COMPMASK_MTUSELECTOR;
1068 		}
1069 	}
1070 
1071 	/*
1072 	 * Honor individual selection of these attributes,
1073 	 * even if IBT_PATH_PERF is set.
1074 	 */
1075 	/* Check out whether Packet Life Time is specified. */
1076 	if (attrp->pa_pkt_lt.p_pkt_lt) {
1077 		pathrec_req.PacketLifeTime =
1078 		    ibt_usec2ib(attrp->pa_pkt_lt.p_pkt_lt);
1079 		pathrec_req.PacketLifeTimeSelector =
1080 		    attrp->pa_pkt_lt.p_selector;
1081 
1082 		c_mask |= SA_PR_COMPMASK_PKTLT | SA_PR_COMPMASK_PKTLTSELECTOR;
1083 	}
1084 
1085 	/* Is SRATE specified. */
1086 	if (attrp->pa_srate.r_srate) {
1087 		pathrec_req.Rate = attrp->pa_srate.r_srate;
1088 		pathrec_req.RateSelector = attrp->pa_srate.r_selector;
1089 
1090 		c_mask |= SA_PR_COMPMASK_RATE | SA_PR_COMPMASK_RATESELECTOR;
1091 	}
1092 
1093 	/* Is MTU specified. */
1094 	if (attrp->pa_mtu.r_mtu) {
1095 		pathrec_req.Mtu = attrp->pa_mtu.r_mtu;
1096 		pathrec_req.MtuSelector = attrp->pa_mtu.r_selector;
1097 
1098 		c_mask |= SA_PR_COMPMASK_MTU | SA_PR_COMPMASK_MTUSELECTOR;
1099 	}
1100 
1101 	/* We always get REVERSIBLE paths. */
1102 	pathrec_req.Reversible = 1;
1103 	c_mask |= SA_PR_COMPMASK_REVERSIBLE;
1104 
1105 	pathrec_req.NumbPath = *num_path;
1106 	c_mask |= SA_PR_COMPMASK_NUMBPATH;
1107 
1108 	if (idx != 0xFF) {
1109 		/* MGID */
1110 		pathrec_req.DGID = dinfo->dest[idx].d_gid;
1111 		c_mask |= SA_PR_COMPMASK_DGID;
1112 	}
1113 
1114 	p_fnd = a_fnd = found = 0;
1115 
1116 	for (i = 0; i < sl->p_count; i++) {
1117 		/* SGID */
1118 		pathrec_req.SGID = sl[i].p_sgid;
1119 		c_mask |= SA_PR_COMPMASK_SGID;
1120 		saa_handle = sl[i].p_saa_hdl;
1121 
1122 		for (k = 0; k < dinfo->num_dest; k++) {
1123 			if (idx == 0xFF) {		/* DGID */
1124 				if (dinfo->dest[k].d_tag != 0)
1125 					continue;
1126 
1127 				pathrec_req.DGID = dinfo->dest[k].d_gid;
1128 				c_mask |= SA_PR_COMPMASK_DGID;
1129 
1130 				/*
1131 				 * If we had performed Service Look-up, then we
1132 				 * got P_Key from ServiceRecord, so get path
1133 				 * records that satisfy this particular P_Key.
1134 				 */
1135 				if ((dinfo->p_key == 0) &&
1136 				    (dinfo->dest[k].d_pkey != 0)) {
1137 					pathrec_req.P_Key =
1138 					    dinfo->dest[k].d_pkey;
1139 					c_mask |= SA_PR_COMPMASK_PKEY;
1140 				}
1141 			}
1142 
1143 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: "
1144 			    "Get %d Path(s) between\n\tSGID(%llX:%llX) "
1145 			    "DGID(%llX:%llX)", pathrec_req.NumbPath,
1146 			    pathrec_req.SGID.gid_prefix,
1147 			    pathrec_req.SGID.gid_guid,
1148 			    pathrec_req.DGID.gid_prefix,
1149 			    pathrec_req.DGID.gid_guid);
1150 
1151 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: CMask"
1152 			    "=0x%llX, PKey=0x%X", c_mask, pathrec_req.P_Key);
1153 
1154 			if ((idx == 0xFF) && (pathrec_req.SGID.gid_prefix !=
1155 			    pathrec_req.DGID.gid_prefix)) {
1156 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec"
1157 				    ": SGID_pfx=%llX, DGID_pfx=%llX doesn't "
1158 				    "match", pathrec_req.SGID.gid_prefix,
1159 				    pathrec_req.DGID.gid_prefix);
1160 				continue;
1161 			} else if ((pathrec_req.SGID.gid_prefix ==
1162 			    pathrec_req.DGID.gid_prefix) &&
1163 			    (pathrec_req.SGID.gid_guid ==
1164 			    pathrec_req.DGID.gid_guid)) {
1165 				IBTF_DPRINTF_L2(cmlog, "ibcm_get_single_pathrec"
1166 				    ": Why LoopBack request came here!!!! "
1167 				    "GID(%llX:%llX)",
1168 				    pathrec_req.SGID.gid_prefix,
1169 				    pathrec_req.SGID.gid_guid);
1170 				continue;
1171 			}
1172 
1173 			/* Contact SA Access to retrieve Path Records. */
1174 			access_args.sq_attr_id = SA_PATHRECORD_ATTRID;
1175 			access_args.sq_template = &pathrec_req;
1176 			access_args.sq_access_type = IBMF_SAA_RETRIEVE;
1177 			access_args.sq_template_length =
1178 			    sizeof (sa_path_record_t);
1179 			access_args.sq_component_mask = c_mask;
1180 			access_args.sq_callback = NULL;
1181 			access_args.sq_callback_arg = NULL;
1182 
1183 			retval = ibcm_contact_sa_access(saa_handle,
1184 			    &access_args, &length, &results_p);
1185 			if (retval != IBT_SUCCESS) {
1186 				*num_path = 0;
1187 				return (retval);
1188 			}
1189 
1190 			num_rec = length / sizeof (sa_path_record_t);
1191 
1192 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: "
1193 			    "FOUND %d/%d path requested", num_rec, *num_path);
1194 
1195 			if ((results_p == NULL) || (num_rec == 0)) {
1196 				retval = IBT_PATH_RECORDS_NOT_FOUND;
1197 				if (idx != 0xFF)
1198 					break;
1199 				else
1200 					continue;
1201 			}
1202 
1203 			/* Update the PathInfo from the response. */
1204 			pr_resp = (sa_path_record_t *)results_p;
1205 			for (j = 0; j < num_rec; j++, pr_resp++) {
1206 				if ((p_fnd != 0) &&
1207 				    (p_arg->flags & IBT_PATH_APM)) {
1208 					IBTF_DPRINTF_L3(cmlog,
1209 					    "ibcm_get_single_pathrec: "
1210 					    "Fill Alternate Path");
1211 					retval = ibcm_update_cep_info(pr_resp,
1212 					    sl, NULL,
1213 					    &paths[found].pi_alt_cep_path);
1214 					if (retval != IBT_SUCCESS)
1215 						continue;
1216 
1217 					/* Update some leftovers */
1218 					paths[found].pi_alt_pkt_lt =
1219 					    pr_resp->PacketLifeTime;
1220 				} else {
1221 					IBTF_DPRINTF_L3(cmlog,
1222 					    "ibcm_get_single_pathrec: "
1223 					    "Fill Primary Path");
1224 					retval = ibcm_update_pri(pr_resp, sl,
1225 					    dinfo, &paths[p_fnd]);
1226 					if (retval != IBT_SUCCESS)
1227 						continue;
1228 				}
1229 
1230 				if (++found == *num_path)
1231 					break;
1232 			}
1233 			/* Deallocate the memory for results_p. */
1234 			kmem_free(results_p, length);
1235 
1236 			if (idx != 0xFF)
1237 				break;		/* We r here for MGID */
1238 		}
1239 
1240 		if (p_fnd == 0)
1241 			p_fnd = found;
1242 		else if ((p_arg->flags & IBT_PATH_APM) && (a_fnd == 0))
1243 			a_fnd = found;
1244 		else
1245 			p_fnd += found;
1246 
1247 		if ((found == *num_path) && (idx != 0xFF))
1248 			break;
1249 		else
1250 			found = 0;
1251 	}
1252 
1253 	found = (p_fnd > a_fnd) ? p_fnd : a_fnd;
1254 
1255 	if ((found != 0) && (found != *num_path)) {
1256 		IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: Status %d, "
1257 		    "Found %d", retval, found);
1258 		retval = IBT_INSUFF_DATA;
1259 	}
1260 
1261 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: done. Status %d, "
1262 	    "Found %d/%d Paths", retval, found, *num_path);
1263 
1264 	*num_path = found;
1265 
1266 	return (retval);
1267 }
1268 
1269 
1270 static ibt_status_t
1271 ibcm_get_multi_pathrec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
1272     ibcm_dinfo_t *dinfo, uint8_t *num_path, ibt_path_info_t *paths)
1273 {
1274 	sa_multipath_record_t	*mpr_req;
1275 	sa_path_record_t	*pr_resp;
1276 	ibmf_saa_access_args_t	access_args;
1277 	void			*results_p;
1278 	uint64_t		c_mask = 0;
1279 	ib_gid_t		*gid_ptr, *gid_s_ptr;
1280 	size_t			length;
1281 	int			template_len, found, num_rec;
1282 	int			i, k;
1283 	ibt_status_t		retval;
1284 	uint8_t			sgid_cnt, dgid_cnt;
1285 	ibt_path_attr_t		*attrp = &p_arg->attr;
1286 
1287 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec(%p, %p, %p, %d)",
1288 	    attrp, sl, dinfo, *num_path);
1289 
1290 	for (i = 0, dgid_cnt = 0; i < dinfo->num_dest; i++) {
1291 		if (dinfo->dest[i].d_tag == 0)
1292 			dgid_cnt++;
1293 	}
1294 
1295 	sgid_cnt = sl->p_count;
1296 
1297 	if ((sgid_cnt == 0) || (dgid_cnt == 0)) {
1298 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_multi_pathrec: sgid_cnt(%d) or"
1299 		    " dgid_cnt(%d) is zero", sgid_cnt, dgid_cnt);
1300 		return (IBT_INVALID_PARAM);
1301 	}
1302 
1303 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: Get %d records between "
1304 	    "%d Src(s) <=> %d Dest(s)", *num_path, sgid_cnt, dgid_cnt);
1305 
1306 	/*
1307 	 * Calculate the size for multi-path records template, which includes
1308 	 * constant portion of the multipath record, plus variable size for
1309 	 * SGID (sgid_cnt) and DGID (dgid_cnt).
1310 	 */
1311 	template_len = ((dgid_cnt + sgid_cnt) * sizeof (ib_gid_t)) +
1312 	    sizeof (sa_multipath_record_t);
1313 
1314 	mpr_req = kmem_zalloc(template_len, KM_SLEEP);
1315 
1316 	ASSERT(mpr_req != NULL);
1317 
1318 	gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
1319 	    sizeof (sa_multipath_record_t));
1320 
1321 	/* Get the starting pointer where GIDs are stored. */
1322 	gid_s_ptr = gid_ptr;
1323 
1324 	/* SGID */
1325 	for (i = 0; i < sl->p_count; i++) {
1326 		*gid_ptr = sl[i].p_sgid;
1327 
1328 		IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: SGID[%d] = "
1329 		    "(%llX:%llX)", i, gid_ptr->gid_prefix, gid_ptr->gid_guid);
1330 
1331 		gid_ptr++;
1332 	}
1333 
1334 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
1335 
1336 	mpr_req->SGIDCount = sgid_cnt;
1337 	c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
1338 
1339 	/* DGIDs */
1340 	for (i = 0; i < dinfo->num_dest; i++) {
1341 		if (dinfo->dest[i].d_tag == 0) {
1342 			*gid_ptr = dinfo->dest[i].d_gid;
1343 
1344 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1345 			    "DGID[%d] = (%llX:%llX)", i, gid_ptr->gid_prefix,
1346 			    gid_ptr->gid_guid);
1347 			gid_ptr++;
1348 		}
1349 	}
1350 
1351 	mpr_req->DGIDCount = dgid_cnt;
1352 	c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
1353 
1354 	/* Is Flow Label Specified. */
1355 	if (attrp->pa_flow) {
1356 		mpr_req->FlowLabel = attrp->pa_flow;
1357 		c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
1358 	}
1359 
1360 	/* Is HopLimit Specified. */
1361 	if (p_arg->flags & IBT_PATH_HOP) {
1362 		mpr_req->HopLimit = attrp->pa_hop;
1363 		c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
1364 	}
1365 
1366 	/* Is TClass Specified. */
1367 	if (attrp->pa_tclass) {
1368 		mpr_req->TClass = attrp->pa_tclass;
1369 		c_mask |= SA_MPR_COMPMASK_TCLASS;
1370 	}
1371 
1372 	/* Is SL specified. */
1373 	if (attrp->pa_sl) {
1374 		mpr_req->SL = attrp->pa_sl;
1375 		c_mask |= SA_MPR_COMPMASK_SL;
1376 	}
1377 
1378 	if (p_arg->flags & IBT_PATH_PERF) {
1379 		mpr_req->PacketLifeTimeSelector = IBT_BEST;
1380 		mpr_req->RateSelector = IBT_BEST;
1381 		mpr_req->MtuSelector = IBT_BEST;
1382 
1383 		c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
1384 		    SA_MPR_COMPMASK_RATESELECTOR | SA_MPR_COMPMASK_MTUSELECTOR;
1385 	} else {
1386 		if (attrp->pa_pkt_lt.p_selector == IBT_BEST) {
1387 			mpr_req->PacketLifeTimeSelector = IBT_BEST;
1388 			c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
1389 		}
1390 
1391 		if (attrp->pa_srate.r_selector == IBT_BEST) {
1392 			mpr_req->RateSelector = IBT_BEST;
1393 			c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
1394 		}
1395 
1396 		if (attrp->pa_mtu.r_selector == IBT_BEST) {
1397 			mpr_req->MtuSelector = IBT_BEST;
1398 			c_mask |= SA_MPR_COMPMASK_MTUSELECTOR;
1399 		}
1400 	}
1401 
1402 	/*
1403 	 * Honor individual selection of these attributes,
1404 	 * even if IBT_PATH_PERF is set.
1405 	 */
1406 	/* Check out whether Packet Life Time is specified. */
1407 	if (attrp->pa_pkt_lt.p_pkt_lt) {
1408 		mpr_req->PacketLifeTime =
1409 		    ibt_usec2ib(attrp->pa_pkt_lt.p_pkt_lt);
1410 		mpr_req->PacketLifeTimeSelector =
1411 		    attrp->pa_pkt_lt.p_selector;
1412 
1413 		c_mask |= SA_MPR_COMPMASK_PKTLT |
1414 		    SA_MPR_COMPMASK_PKTLTSELECTOR;
1415 	}
1416 
1417 	/* Is SRATE specified. */
1418 	if (attrp->pa_srate.r_srate) {
1419 		mpr_req->Rate = attrp->pa_srate.r_srate;
1420 		mpr_req->RateSelector = attrp->pa_srate.r_selector;
1421 
1422 		c_mask |= SA_MPR_COMPMASK_RATE |
1423 		    SA_MPR_COMPMASK_RATESELECTOR;
1424 	}
1425 
1426 	/* Is MTU specified. */
1427 	if (attrp->pa_mtu.r_mtu) {
1428 		mpr_req->Mtu = attrp->pa_mtu.r_mtu;
1429 		mpr_req->MtuSelector = attrp->pa_mtu.r_selector;
1430 
1431 		c_mask |= SA_MPR_COMPMASK_MTU |
1432 		    SA_MPR_COMPMASK_MTUSELECTOR;
1433 	}
1434 
1435 	/* Is P_Key Specified or obtained during Service Look-up. */
1436 	if (dinfo->p_key) {
1437 		mpr_req->P_Key = dinfo->p_key;
1438 		c_mask |= SA_MPR_COMPMASK_PKEY;
1439 	}
1440 
1441 	/* We always get REVERSIBLE paths. */
1442 	mpr_req->Reversible = 1;
1443 	c_mask |= SA_MPR_COMPMASK_REVERSIBLE;
1444 
1445 	if (p_arg->flags & IBT_PATH_AVAIL) {
1446 		mpr_req->IndependenceSelector = 1;
1447 		c_mask |= SA_MPR_COMPMASK_INDEPSEL;
1448 	}
1449 
1450 	/* we will not specify how many records we want. */
1451 
1452 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
1453 
1454 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: CMask: %llX Pkey: %X",
1455 	    c_mask, mpr_req->P_Key);
1456 
1457 	/* Contact SA Access to retrieve Path Records. */
1458 	access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
1459 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
1460 	access_args.sq_component_mask = c_mask;
1461 	access_args.sq_template = mpr_req;
1462 	access_args.sq_template_length = sizeof (sa_multipath_record_t);
1463 	access_args.sq_callback = NULL;
1464 	access_args.sq_callback_arg = NULL;
1465 
1466 	retval = ibcm_contact_sa_access(sl->p_saa_hdl, &access_args, &length,
1467 	    &results_p);
1468 	if (retval != IBT_SUCCESS) {
1469 		*num_path = 0;  /* Update the return count. */
1470 		kmem_free(mpr_req, template_len);
1471 		return (retval);
1472 	}
1473 
1474 	num_rec = length / sizeof (sa_path_record_t);
1475 
1476 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: Found %d Paths",
1477 	    num_rec);
1478 
1479 	found = 0;
1480 	if ((results_p != NULL) && (num_rec > 0)) {
1481 		/* Update the PathInfo with the response Path Records */
1482 		pr_resp = (sa_path_record_t *)results_p;
1483 
1484 		for (i = 0; i < num_rec; i++) {
1485 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1486 			    "P[%d]: SG %llX, DG %llX", i,
1487 			    pr_resp[i].SGID.gid_guid, pr_resp[i].DGID.gid_guid);
1488 		}
1489 
1490 		if (p_arg->flags & IBT_PATH_APM) {
1491 			sa_path_record_t *p_resp = NULL, *a_resp = NULL;
1492 			int		p_found = 0, a_found = 0;
1493 			ib_gid_t	p_sg, a_sg, p_dg, a_dg;
1494 			int		s_spec;
1495 
1496 			s_spec = p_arg->attr.pa_sgid.gid_guid != 0 ? 1 : 0;
1497 
1498 			p_sg = gid_s_ptr[0];
1499 			if (sgid_cnt > 1)
1500 				a_sg = gid_s_ptr[1];
1501 			else
1502 				a_sg = p_sg;
1503 
1504 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1505 			    "REQ: P_SG: %llX, A_SG: %llX",
1506 			    p_sg.gid_guid, a_sg.gid_guid);
1507 
1508 			p_dg = gid_s_ptr[sgid_cnt];
1509 			if (dgid_cnt > 1)
1510 				a_dg = gid_s_ptr[sgid_cnt + 1];
1511 			else
1512 				a_dg = p_dg;
1513 
1514 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1515 			    "REQ: P_DG: %llX, A_DG: %llX",
1516 			    p_dg.gid_guid, a_dg.gid_guid);
1517 
1518 			/*
1519 			 * If SGID and/or DGID is specified by user, make sure
1520 			 * he gets his primary-path on those node points.
1521 			 */
1522 			for (i = 0; i < num_rec; i++, pr_resp++) {
1523 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec:"
1524 				    " PF %d, AF %d,\n\t\t P[%d] = SG: %llX, "
1525 				    "DG: %llX", p_found, a_found, i,
1526 				    pr_resp->SGID.gid_guid,
1527 				    pr_resp->DGID.gid_guid);
1528 
1529 				if ((!p_found) &&
1530 				    (p_dg.gid_guid == pr_resp->DGID.gid_guid)) {
1531 					IBTF_DPRINTF_L3(cmlog,
1532 					    "ibcm_get_multi_pathrec: "
1533 					    "Pri DGID Match.. ");
1534 					if ((s_spec == 0) || (p_sg.gid_guid ==
1535 					    pr_resp->SGID.gid_guid)) {
1536 						p_found = 1;
1537 						p_resp = pr_resp;
1538 						IBTF_DPRINTF_L3(cmlog,
1539 						    "ibcm_get_multi_pathrec: "
1540 						    "Primary Path Found");
1541 
1542 						if (a_found)
1543 							break;
1544 						else
1545 							continue;
1546 					}
1547 					IBTF_DPRINTF_L3(cmlog,
1548 					    "ibcm_get_multi_pathrec:"
1549 					    "Pri SGID Don't Match.. ");
1550 				}
1551 
1552 				if ((!a_found) &&
1553 				    (a_dg.gid_guid == pr_resp->DGID.gid_guid)) {
1554 					IBTF_DPRINTF_L3(cmlog,
1555 					    "ibcm_get_multi_pathrec:"
1556 					    "Alt DGID Match.. ");
1557 					if ((s_spec == 0) || (a_sg.gid_guid ==
1558 					    pr_resp->SGID.gid_guid)) {
1559 						a_found = 1;
1560 						a_resp = pr_resp;
1561 
1562 						IBTF_DPRINTF_L3(cmlog,
1563 						    "ibcm_get_multi_pathrec:"
1564 						    "Alternate Path Found ");
1565 
1566 						if (p_found)
1567 							break;
1568 						else
1569 							continue;
1570 					}
1571 					IBTF_DPRINTF_L3(cmlog,
1572 					    "ibcm_get_multi_pathrec:"
1573 					    "Alt SGID Don't Match.. ");
1574 				}
1575 			}
1576 
1577 			if ((p_found == 0) && (a_found == 0)) {
1578 				IBTF_DPRINTF_L2(cmlog, "ibcm_get_multi_pathrec:"
1579 				    " Path to desired node points NOT "
1580 				    "Available.");
1581 				retval = IBT_PATH_RECORDS_NOT_FOUND;
1582 				goto get_multi_pathrec_end;
1583 			}
1584 
1585 			if ((p_resp == NULL) && (a_resp != NULL)) {
1586 				p_resp = a_resp;
1587 				a_resp = NULL;
1588 			}
1589 
1590 			/* Fill in Primary Path */
1591 			retval = ibcm_update_pri(p_resp, sl, dinfo,
1592 			    &paths[found]);
1593 			if (retval != IBT_SUCCESS)
1594 				goto get_multi_pathrec_end;
1595 
1596 			/* Fill in Alternate Path */
1597 			if (a_resp != NULL) {
1598 				/* a_resp will point to AltPathInfo buffer. */
1599 				retval = ibcm_update_cep_info(a_resp, sl,
1600 				    NULL, &paths[found].pi_alt_cep_path);
1601 				if (retval != IBT_SUCCESS)
1602 					goto get_multi_pathrec_end;
1603 
1604 				/* Update some leftovers */
1605 				paths[found].pi_alt_pkt_lt =
1606 				    a_resp->PacketLifeTime;
1607 			} else {
1608 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec:"
1609 				    " Alternate Path NOT Available.");
1610 				retval = IBT_INSUFF_DATA;
1611 			}
1612 			found++;
1613 		} else {	/* If NOT APM */
1614 			boolean_t	check_pkey = B_FALSE;
1615 
1616 			/* mark flag whether to validate PKey or not. */
1617 			if ((dinfo->p_key == 0) && (dinfo->dest[0].d_pkey != 0))
1618 				check_pkey = B_TRUE;
1619 
1620 			for (i = 0; i < num_rec; i++, pr_resp++) {
1621 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec:"
1622 				    " PKeyCheck - %s, PKey=0x%X, DGID(%llX)",
1623 				    ((check_pkey == B_TRUE)?"REQD":"NOT_REQD"),
1624 				    pr_resp->P_Key, pr_resp->DGID.gid_guid);
1625 
1626 				if (check_pkey == B_TRUE) {
1627 					boolean_t	match_found = B_FALSE;
1628 
1629 					/* For all DGIDs */
1630 					for (k = 0; k < dinfo->num_dest; k++) {
1631 						if (dinfo->dest[k].d_tag != 0)
1632 							continue;
1633 
1634 						if ((dinfo->dest[k].d_gid.
1635 						    gid_guid ==
1636 						    pr_resp->DGID.gid_guid) &&
1637 						    (dinfo->dest[k].d_pkey ==
1638 						    pr_resp->P_Key)) {
1639 							match_found = B_TRUE;
1640 							break;
1641 						}
1642 					}
1643 					if (match_found == B_FALSE)
1644 						continue;
1645 				}
1646 				/* Fill in Primary Path */
1647 				retval = ibcm_update_pri(pr_resp, sl, dinfo,
1648 				    &paths[found]);
1649 				if (retval != IBT_SUCCESS)
1650 					continue;
1651 
1652 				if (++found == *num_path)
1653 					break;
1654 			}
1655 		}
1656 get_multi_pathrec_end:
1657 		kmem_free(results_p, length);
1658 	}
1659 	kmem_free(mpr_req, template_len);
1660 
1661 	if (retval == IBT_SUCCESS) {
1662 		if (found == 0)
1663 			retval = IBT_PATH_RECORDS_NOT_FOUND;
1664 		else if (found != *num_path)
1665 			retval = IBT_INSUFF_DATA;
1666 	}
1667 
1668 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: Done (status %d). "
1669 	    "Found %d/%d Paths", retval, found, *num_path);
1670 
1671 	*num_path = found;	/* Update the return count. */
1672 
1673 	return (retval);
1674 }
1675 
1676 
1677 /*
1678  * Here we "synthesize" loop back path record information.
1679  *
1680  * Currently the synthesize values are assumed as follows:
1681  *    SLID, DLID = Base LID from Query HCA Port.
1682  *    FlowLabel, HopLimit, TClass = 0, as GRH is False.
1683  *    RawTraffic = 0.
1684  *    P_Key = first valid one in P_Key table as obtained from Query HCA Port.
1685  *    SL = as from Query HCA Port.
1686  *    MTU = from Query HCA Port.
1687  *    Rate = 2 (arbitrary).
1688  *    PacketLifeTime = 0 (4.096 usec).
1689  */
1690 static ibt_status_t
1691 ibcm_fillin_loopbackinfo(ibtl_cm_port_list_t *sl, uint8_t index,
1692     ibcm_dinfo_t *dinfo, ibt_path_info_t *paths)
1693 {
1694 	ibt_status_t	retval;
1695 	ib_pkey_t	pkey = 0;
1696 
1697 	IBTF_DPRINTF_L3(cmlog, "ibcm_fillin_loopbackinfo(%p, %p)", sl, dinfo);
1698 
1699 	/* Synthesize path record with appropriate loop back information. */
1700 	if (dinfo->p_key)
1701 		pkey = dinfo->p_key;
1702 	else
1703 		pkey = dinfo->dest[index].d_pkey;
1704 	if (pkey) {
1705 		/* Convert P_Key to P_Key_Index */
1706 		retval = ibt_pkey2index_byguid(sl->p_hca_guid, sl->p_port_num,
1707 		    pkey, &paths->pi_prim_cep_path.cep_pkey_ix);
1708 		if (retval != IBT_SUCCESS) {
1709 			/* Failed to get pkey_index from pkey */
1710 			IBTF_DPRINTF_L2(cmlog, "ibcm_fillin_loopbackinfo: "
1711 			    "Pkey2Index (P_Key = %X) conversion failed: %d",
1712 			    pkey, retval);
1713 			return (retval);
1714 		}
1715 	} else {
1716 		paths->pi_prim_cep_path.cep_pkey_ix =
1717 		    ibtl_cm_get_1st_full_pkey_ix(sl->p_hca_guid,
1718 		    sl->p_port_num);
1719 		IBTF_DPRINTF_L3(cmlog, "ibcm_fillin_loopbackinfo: "
1720 		    "1st Full Member P_Key_ix = %d",
1721 		    paths->pi_prim_cep_path.cep_pkey_ix);
1722 	}
1723 
1724 	paths->pi_hca_guid = sl->p_hca_guid;
1725 	paths->pi_prim_cep_path.cep_adds_vect.av_dgid =
1726 	    dinfo->dest[index].d_gid;
1727 	paths->pi_prim_cep_path.cep_adds_vect.av_sgid = sl->p_sgid;
1728 	paths->pi_prim_cep_path.cep_adds_vect.av_srate	= IBT_SRATE_1X;
1729 	paths->pi_prim_cep_path.cep_adds_vect.av_srvl	= 0; /* SL */
1730 
1731 	paths->pi_prim_cep_path.cep_adds_vect.av_send_grh = B_FALSE;
1732 	paths->pi_prim_cep_path.cep_adds_vect.av_flow	= 0;
1733 	paths->pi_prim_cep_path.cep_adds_vect.av_tclass	= 0;
1734 	paths->pi_prim_cep_path.cep_adds_vect.av_hop 	= 0;
1735 
1736 	/* SLID and DLID will be equal to BLID. */
1737 	paths->pi_prim_cep_path.cep_adds_vect.av_dlid = sl->p_base_lid;
1738 	paths->pi_prim_cep_path.cep_adds_vect.av_src_path = 0;
1739 	paths->pi_prim_cep_path.cep_adds_vect.av_sgid_ix = sl->p_sgid_ix;
1740 	paths->pi_prim_cep_path.cep_adds_vect.av_port_num =
1741 	paths->pi_prim_cep_path.cep_hca_port_num = sl->p_port_num;
1742 	paths->pi_prim_cep_path.cep_timeout = 0; /* To be filled in by CM. */
1743 	paths->pi_path_mtu = sl->p_mtu;		/* MTU */
1744 	paths->pi_prim_pkt_lt = 0;		/* Packet Life Time. */
1745 	paths->pi_alt_pkt_lt = 0;		/* Packet Life Time. */
1746 
1747 	paths->pi_sid = dinfo->dest[index].d_sid;
1748 
1749 	if (paths->pi_sid != 0)
1750 		bcopy(&dinfo->dest[index].d_sdata, &paths->pi_sdata,
1751 		    sizeof (ibt_srv_data_t));
1752 
1753 	IBTF_DPRINTF_L3(cmlog, "ibcm_fillin_loopbackinfo: HCA %llX:%d SID %llX"
1754 	    "\n\t SGID %llX:%llX DGID %llX:%llX", paths->pi_hca_guid,
1755 	    paths->pi_prim_cep_path.cep_hca_port_num, paths->pi_sid,
1756 	    sl->p_sgid.gid_prefix, sl->p_sgid.gid_guid,
1757 	    dinfo->dest[index].d_gid.gid_prefix,
1758 	    dinfo->dest[index].d_gid.gid_guid);
1759 
1760 	/* Set Alternate Path to invalid state. */
1761 	paths->pi_alt_cep_path.cep_hca_port_num = 0;
1762 	paths->pi_alt_cep_path.cep_adds_vect.av_dlid = 0;
1763 
1764 	return (IBT_SUCCESS);
1765 }
1766 
1767 
1768 /*
1769  * Update the output path records buffer with the values as obtained from
1770  * SA Access retrieve call results for Path Records.
1771  */
1772 static ibt_status_t
1773 ibcm_update_cep_info(sa_path_record_t *prec_resp, ibtl_cm_port_list_t *sl,
1774     ibtl_cm_hca_port_t *hport, ibt_cep_path_t *cep_p)
1775 {
1776 	ibt_status_t	retval;
1777 	int		i;
1778 
1779 	IBCM_DUMP_PATH_REC(prec_resp);
1780 
1781 	/*
1782 	 * If path's packet life time is more than 4 seconds, IBCM cannot
1783 	 * handle this path connection, so discard this path record.
1784 	 */
1785 	if (prec_resp->PacketLifeTime > ibcm_max_ib_pkt_lt) {
1786 		IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: Path's Packet "
1787 		    "LifeTime too high %d, Maximum allowed %d IB Time (4 sec)",
1788 		    prec_resp->PacketLifeTime, ibcm_max_ib_pkt_lt);
1789 		return (IBT_PATH_PKT_LT_TOO_HIGH);
1790 	}
1791 
1792 	if ((prec_resp->Mtu > IB_MTU_4K) || (prec_resp->Mtu < IB_MTU_256)) {
1793 		IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: MTU (%d) from "
1794 		    "pathrecord is invalid, reject it.", prec_resp->Mtu);
1795 		return (ibt_get_module_failure(IBT_FAILURE_IBCM, 0));
1796 	}
1797 
1798 	/* Source Node Information. */
1799 	cep_p->cep_adds_vect.av_sgid = prec_resp->SGID;
1800 	if (hport != NULL) {
1801 		/* Convert P_Key to P_Key_Index */
1802 		retval = ibt_pkey2index_byguid(hport->hp_hca_guid,
1803 		    hport->hp_port, prec_resp->P_Key, &cep_p->cep_pkey_ix);
1804 		if (retval != IBT_SUCCESS) {
1805 			/* Failed to get pkey_index from pkey */
1806 			IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: "
1807 			    "Pkey2Index conversion failed: %d", retval);
1808 			return (retval);
1809 		}
1810 		cep_p->cep_adds_vect.av_sgid_ix = hport->hp_sgid_ix;
1811 		cep_p->cep_adds_vect.av_src_path =
1812 		    prec_resp->SLID - hport->hp_base_lid;
1813 		cep_p->cep_adds_vect.av_port_num = cep_p->cep_hca_port_num =
1814 		    hport->hp_port;
1815 	} else if (sl != NULL) {
1816 		for (i = 0; i < sl->p_count; i++) {
1817 			if (prec_resp->SGID.gid_guid == sl[i].p_sgid.gid_guid) {
1818 				/* Convert P_Key to P_Key_Index */
1819 				retval = ibt_pkey2index_byguid(sl[i].p_hca_guid,
1820 				    sl[i].p_port_num, prec_resp->P_Key,
1821 				    &cep_p->cep_pkey_ix);
1822 				if (retval != IBT_SUCCESS) {
1823 					/* Failed to get pkey_index from pkey */
1824 					IBTF_DPRINTF_L2(cmlog,
1825 					    "ibcm_update_cep_info: Pkey2Index "
1826 					    "conversion failed: %d", retval);
1827 					return (retval);
1828 				}
1829 
1830 				cep_p->cep_adds_vect.av_sgid_ix =
1831 				    sl[i].p_sgid_ix;
1832 				cep_p->cep_adds_vect.av_src_path =
1833 				    prec_resp->SLID - sl[i].p_base_lid;
1834 				cep_p->cep_adds_vect.av_port_num =
1835 				    sl[i].p_port_num;
1836 				cep_p->cep_hca_port_num = sl[i].p_port_num;
1837 
1838 				break;
1839 			}
1840 		}
1841 	} else {
1842 		IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: Sl or Hport "
1843 		    "must be non-null");
1844 		return (IBT_INVALID_PARAM);
1845 	}
1846 
1847 	switch (prec_resp->Rate) {
1848 	case IBT_SRATE_1X:
1849 	case IBT_SRATE_4X:
1850 	case IBT_SRATE_12X:
1851 		cep_p->cep_adds_vect.av_srate = prec_resp->Rate;
1852 		break;
1853 	default:
1854 		IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: SRate (%d) from "
1855 		    "pathrecord is invalid, reject it.", prec_resp->Rate);
1856 		return (IBT_STATIC_RATE_INVALID);
1857 	}
1858 	/*
1859 	 * If both Source and Destination GID prefix are same, then GRH is not
1860 	 * valid, so make it as false, else set this field as true.
1861 	 */
1862 	if (prec_resp->SGID.gid_prefix == prec_resp->DGID.gid_prefix)
1863 		cep_p->cep_adds_vect.av_send_grh = B_FALSE;
1864 	else
1865 		cep_p->cep_adds_vect.av_send_grh = B_TRUE;
1866 
1867 	/* SGID and SGID Index. */
1868 	cep_p->cep_adds_vect.av_sgid = prec_resp->SGID;
1869 	cep_p->cep_adds_vect.av_flow = prec_resp->FlowLabel;
1870 	cep_p->cep_adds_vect.av_tclass = prec_resp->TClass;
1871 	cep_p->cep_adds_vect.av_hop = prec_resp->HopLimit;
1872 
1873 	/* Address Vector Definition. */
1874 	cep_p->cep_adds_vect.av_dlid = prec_resp->DLID;
1875 	cep_p->cep_adds_vect.av_srvl = prec_resp->SL;
1876 
1877 	/* DGID */
1878 	cep_p->cep_adds_vect.av_dgid = prec_resp->DGID;
1879 
1880 	/* CEP Timeout is NOT filled in by PATH routines. */
1881 	cep_p->cep_timeout = 0;
1882 
1883 	IBTF_DPRINTF_L3(cmlog, "ibcm_update_cep_info: Done.  Port[%d]\n"
1884 	    "SGID=%llX:%llX DGID=%llX:%llX",
1885 	    cep_p->cep_adds_vect.av_port_num,
1886 	    prec_resp->SGID.gid_prefix, prec_resp->SGID.gid_guid,
1887 	    prec_resp->DGID.gid_prefix, prec_resp->DGID.gid_guid);
1888 
1889 	return (IBT_SUCCESS);
1890 }
1891 
1892 
1893 static void
1894 ibcm_fill_svcinfo(sa_service_record_t *sr_resp, ibcm_dest_t *dest)
1895 {
1896 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dest))
1897 
1898 	dest->d_gid = sr_resp->ServiceGID;
1899 	dest->d_sid = sr_resp->ServiceID;
1900 	ibcm_swizzle_to_srv(sr_resp->ServiceData, &dest->d_sdata);
1901 	dest->d_pkey = sr_resp->ServiceP_Key;
1902 
1903 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*dest))
1904 
1905 	IBTF_DPRINTF_L3(cmlog, "ibcm_fill_svcinfo: SID(%llX), GID(%llX:%llX)"
1906 	    "\n\tSvcPKey 0x%X", dest->d_sid, dest->d_gid.gid_prefix,
1907 	    dest->d_gid.gid_guid, dest->d_pkey);
1908 }
1909 
1910 
1911 static ib_gid_t
1912 ibcm_saa_get_agid(ibtl_cm_port_list_t *sl, ib_gid_t *gidp, uint_t ngid)
1913 {
1914 	int		k, l;
1915 	ib_gid_t	a_gid;
1916 
1917 	a_gid.gid_prefix = a_gid.gid_guid = 0;
1918 
1919 	for (k = 0; k < sl->p_count; k++) {
1920 		for (l = 0; l < ngid; l++) {
1921 
1922 			if (gidp->gid_prefix == sl->p_sgid.gid_prefix) {
1923 				a_gid = *gidp;
1924 				break;
1925 			}
1926 			if (a_gid.gid_guid && a_gid.gid_prefix)
1927 				break;
1928 			gidp++;
1929 		}
1930 		if (a_gid.gid_guid && a_gid.gid_prefix)
1931 			break;
1932 		sl++;
1933 	}
1934 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_get_agid: AltGID = %llX:%llX",
1935 	    a_gid.gid_prefix, a_gid.gid_guid);
1936 
1937 	return (a_gid);
1938 }
1939 
1940 /*
1941  * Perform SA Access to retrieve Service Records.
1942  * On Success, returns ServiceID and ServiceGID info in '*dinfo'.
1943  */
1944 static ibt_status_t
1945 ibcm_saa_service_rec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
1946     ibcm_dinfo_t *dinfo)
1947 {
1948 	sa_service_record_t	svcrec_req;
1949 	sa_service_record_t	*svcrec_resp;
1950 	void			*results_p;
1951 	uint64_t		component_mask = 0;
1952 	size_t			length;
1953 	uint8_t			i, j, k, rec_found;
1954 	ibmf_saa_access_args_t	access_args;
1955 	ibt_status_t		retval;
1956 	ibt_path_attr_t		*attrp = &p_arg->attr;
1957 	uint64_t		tmp_sd_flag = attrp->pa_sd_flags;
1958 	uint8_t			num_req;
1959 
1960 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec(%p, %p)", p_arg, sl);
1961 
1962 	bzero(&svcrec_req, sizeof (svcrec_req));
1963 
1964 	/* Service Name */
1965 	if ((attrp->pa_sname != NULL) && (strlen(attrp->pa_sname) != 0)) {
1966 		(void) strncpy((char *)(svcrec_req.ServiceName),
1967 		    attrp->pa_sname, IB_SVC_NAME_LEN);
1968 
1969 		component_mask |= SA_SR_COMPMASK_NAME;
1970 	}
1971 
1972 	/* Service ID */
1973 	if (attrp->pa_sid) {
1974 		svcrec_req.ServiceID = attrp->pa_sid;
1975 		component_mask |= SA_SR_COMPMASK_ID;
1976 	}
1977 
1978 	/* Is P_Key Specified. */
1979 	if (p_arg->flags & IBT_PATH_PKEY) {
1980 		svcrec_req.ServiceP_Key = attrp->pa_pkey;
1981 		component_mask |= SA_SR_COMPMASK_PKEY;
1982 	}
1983 
1984 	/* Is ServiceData Specified. */
1985 	if (attrp->pa_sd_flags != IBT_NO_SDATA) {
1986 		/* Handle endianess for service data. */
1987 		ibcm_swizzle_from_srv(&attrp->pa_sdata, svcrec_req.ServiceData);
1988 
1989 		/*
1990 		 * Lets not interpret each and every ServiceData flags,
1991 		 * just pass it on to SAA. Shift the flag, to suit
1992 		 * SA_SR_COMPMASK_ALL_DATA definition.
1993 		 */
1994 		component_mask |= (tmp_sd_flag << 7);
1995 	}
1996 
1997 	if (dinfo->num_dest == 1) {
1998 
1999 		/* If a single DGID is specified, provide it */
2000 		svcrec_req.ServiceGID = dinfo->dest->d_gid;
2001 		component_mask |= SA_SR_COMPMASK_GID;
2002 
2003 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec:%llX:%llX",
2004 		    svcrec_req.ServiceGID.gid_prefix,
2005 		    svcrec_req.ServiceGID.gid_guid);
2006 	}
2007 
2008 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2009 	    "Perform SA Access: Mask: 0x%X", component_mask);
2010 
2011 	/*
2012 	 * Call in SA Access retrieve routine to get Service Records.
2013 	 *
2014 	 * SA Access framework allocated memory for the "results_p".
2015 	 * Make sure to deallocate once we are done with the results_p.
2016 	 * The size of the buffer allocated will be as returned in
2017 	 * "length" field.
2018 	 */
2019 	access_args.sq_attr_id = SA_SERVICERECORD_ATTRID;
2020 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
2021 	access_args.sq_component_mask = component_mask;
2022 	access_args.sq_template = &svcrec_req;
2023 	access_args.sq_template_length = sizeof (sa_service_record_t);
2024 	access_args.sq_callback = NULL;
2025 	access_args.sq_callback_arg = NULL;
2026 
2027 	retval = ibcm_contact_sa_access(sl->p_saa_hdl, &access_args,
2028 	    &length, &results_p);
2029 	if (retval != IBT_SUCCESS)
2030 		return (retval);
2031 
2032 	if ((results_p == NULL) || (length == 0)) {
2033 		IBTF_DPRINTF_L2(cmlog, "ibcm_saa_service_rec: SvcRec Not Found:"
2034 		    " res_p %p, len %d", results_p, length);
2035 		return (IBT_SERVICE_RECORDS_NOT_FOUND);
2036 	}
2037 
2038 	num_req = length / sizeof (sa_service_record_t);
2039 
2040 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Got %d Service Records.",
2041 	    num_req);
2042 
2043 	svcrec_resp = (sa_service_record_t *)results_p;
2044 	rec_found = 0;
2045 
2046 	/* Update the return values. */
2047 	if (dinfo->num_dest) {
2048 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Get ServiceRec "
2049 		    "for Specified DGID: %d", dinfo->num_dest);
2050 
2051 		for (i = 0; i < num_req; i++, svcrec_resp++) {
2052 			/* Limited P_Key is NOT supported as of now!. */
2053 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2054 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2055 				    "SvcPkey 0x%X limited, reject the record.",
2056 				    svcrec_resp->ServiceP_Key);
2057 				continue;
2058 			}
2059 
2060 			for (j = 0; j < dinfo->num_dest; j++) {
2061 				if (dinfo->dest[j].d_gid.gid_guid ==
2062 				    svcrec_resp->ServiceGID.gid_guid) {
2063 					ibcm_fill_svcinfo(svcrec_resp,
2064 					    &dinfo->dest[j]);
2065 					rec_found++;
2066 				}
2067 				if (rec_found == dinfo->num_dest)
2068 					break;
2069 			}
2070 			if (rec_found == dinfo->num_dest)
2071 				break;
2072 		}
2073 		if (rec_found != dinfo->num_dest) {
2074 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Did NOT "
2075 			    "find ServiceRec for all DGIDs: (%d/%d)", rec_found,
2076 			    dinfo->num_dest);
2077 			retval = IBT_INSUFF_DATA;
2078 		}
2079 	} else if (p_arg->flags & IBT_PATH_APM) {
2080 		ib_gid_t		p_gid, a_gid, last_p_gid;
2081 		ib_gid_t		*gidp = NULL;
2082 		uint_t			n_gids;
2083 		sa_service_record_t	*stmp;
2084 		boolean_t		pri_fill_done = B_FALSE;
2085 		boolean_t		alt_fill_done = B_FALSE;
2086 		ib_pkey_t		p_pkey = 0, a_pkey = 0;
2087 
2088 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Need to "
2089 		    "find ServiceRec that can satisfy APM");
2090 
2091 		p_gid.gid_prefix = p_gid.gid_guid = 0;
2092 		a_gid.gid_prefix = a_gid.gid_guid = 0;
2093 		last_p_gid.gid_prefix = last_p_gid.gid_guid = 0;
2094 
2095 		for (i = 0; i < num_req; i++, svcrec_resp++) {
2096 			ibt_status_t	ret;
2097 			boolean_t	local_node_check_done = B_FALSE;
2098 
2099 			/* Limited P_Key is NOT supported as of now!. */
2100 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2101 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2102 				    "SvcPkey 0x%X limited, reject the record.",
2103 				    svcrec_resp->ServiceP_Key);
2104 				continue;
2105 			}
2106 
2107 			p_gid = svcrec_resp->ServiceGID;
2108 
2109 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2110 			    "Let DGID(%llX:%llX) be Primary",
2111 			    p_gid.gid_prefix, p_gid.gid_guid);
2112 
2113 			/* Let's avoid LoopBack Nodes. */
2114 			if (p_gid.gid_guid == sl->p_sgid.gid_guid) {
2115 				local_node_check_done = B_TRUE;
2116 
2117 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2118 				    "Lets Avoid Local Node, "
2119 				    "search for remote node.");
2120 			}
2121 
2122 			if (local_node_check_done == B_TRUE) {
2123 				if ((i + 1) < num_req) {
2124 					p_gid.gid_prefix = 0;
2125 					p_gid.gid_guid = 0;
2126 					continue;
2127 				} else if (last_p_gid.gid_prefix != 0) {
2128 					p_gid = last_p_gid;
2129 					break;
2130 				}
2131 			}
2132 
2133 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2134 			    "Finally let Primary DGID = %llX:%llX",
2135 			    p_gid.gid_prefix, p_gid.gid_guid);
2136 
2137 			ret = ibt_get_companion_port_gids(p_gid, 0, 0,
2138 			    &gidp, &n_gids);
2139 			if (ret == IBT_SUCCESS) {
2140 				IBTF_DPRINTF_L3(cmlog,
2141 				    "ibcm_saa_service_rec: Found %d "
2142 				    "CompGID for %llX:%llX", n_gids,
2143 				    p_gid.gid_prefix, p_gid.gid_guid);
2144 
2145 				stmp = (sa_service_record_t *)results_p;
2146 				a_gid.gid_prefix = a_gid.gid_guid = 0;
2147 
2148 				if (sl->p_multism) {
2149 					/* validate sn_pfx */
2150 					a_gid = ibcm_saa_get_agid(sl,
2151 					    gidp, n_gids);
2152 				} else {
2153 					for (k = 0; k < num_req; k++) {
2154 						ib_gid_t sg = stmp->ServiceGID;
2155 
2156 						IBTF_DPRINTF_L3(cmlog,
2157 						    "ibcm_saa_service_rec: "
2158 						    "SvcGID[%d] = %llX:%llX", k,
2159 						    sg.gid_prefix, sg.gid_guid);
2160 
2161 						for (j = 0; j < n_gids; j++) {
2162 							if (gidp[j].gid_guid ==
2163 							    sg.gid_guid) {
2164 								a_gid = gidp[j];
2165 								break;
2166 							}
2167 						}
2168 						if (a_gid.gid_guid)
2169 							break;
2170 						stmp++;
2171 					}
2172 					if (a_gid.gid_guid == 0) {
2173 						/* Rec not found for Alt. */
2174 						for (j = 0; j < n_gids; j++) {
2175 							if (gidp[j].gid_prefix
2176 							== p_gid.gid_prefix) {
2177 								a_gid = gidp[j];
2178 								break;
2179 							}
2180 						}
2181 					}
2182 				}
2183 				kmem_free(gidp,
2184 				    n_gids * sizeof (ib_gid_t));
2185 
2186 				if (a_gid.gid_guid)
2187 					break;
2188 			} else if (ret == IBT_GIDS_NOT_FOUND) {
2189 				last_p_gid = p_gid;
2190 				IBTF_DPRINTF_L3(cmlog,
2191 				    "ibcm_saa_service_rec: Didn't find "
2192 				    "CompGID for %llX:%llX, ret=%d",
2193 				    p_gid.gid_prefix, p_gid.gid_guid,
2194 				    ret);
2195 			} else {
2196 				IBTF_DPRINTF_L3(cmlog,
2197 				    "ibcm_saa_service_rec: Call to "
2198 				    "ibt_get_companion_port_gids(%llX:"
2199 				    "%llX) Failed = %d",
2200 				    p_gid.gid_prefix, p_gid.gid_guid,
2201 				    ret);
2202 			}
2203 		}
2204 
2205 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: \n\t"
2206 		    "Pri DGID(%llX:%llX), Alt DGID(%llX:%llX)",
2207 		    p_gid.gid_prefix, p_gid.gid_guid, a_gid.gid_prefix,
2208 		    a_gid.gid_guid);
2209 
2210 		svcrec_resp = (sa_service_record_t *)results_p;
2211 
2212 		for (i = 0, j = 0; i < num_req; i++, svcrec_resp++) {
2213 			/* Limited P_Key is NOT supported as of now!. */
2214 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2215 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2216 				    "SvcPkey 0x%X limited, reject the record.",
2217 				    svcrec_resp->ServiceP_Key);
2218 				continue;
2219 			}
2220 
2221 			if ((pri_fill_done == B_FALSE) &&
2222 			    (p_gid.gid_guid ==
2223 			    svcrec_resp->ServiceGID.gid_guid)) {
2224 				p_pkey = svcrec_resp->ServiceP_Key;
2225 				if ((a_pkey != 0) &&
2226 				    (a_pkey != p_pkey)) {
2227 					IBTF_DPRINTF_L3(cmlog,
2228 					    "ibcm_saa_service_rec: "
2229 					    "Pri(0x%X) & Alt (0x%X) "
2230 					    "PKey must match.",
2231 					    p_pkey, a_pkey);
2232 					p_pkey = 0;
2233 					continue;
2234 				}
2235 				ibcm_fill_svcinfo(svcrec_resp,
2236 				    &dinfo->dest[j++]);
2237 				rec_found++;
2238 				pri_fill_done = B_TRUE;
2239 			} else if ((alt_fill_done == B_FALSE) &&
2240 			    (a_gid.gid_guid ==
2241 			    svcrec_resp->ServiceGID.gid_guid)) {
2242 				a_pkey = svcrec_resp->ServiceP_Key;
2243 				if ((p_pkey != 0) &&
2244 				    (a_pkey != p_pkey)) {
2245 					IBTF_DPRINTF_L3(cmlog,
2246 					    "ibcm_saa_service_rec: "
2247 					    "Pri(0x%X) & Alt (0x%X) "
2248 					    "PKey must match.",
2249 					    p_pkey, a_pkey);
2250 					a_pkey = 0;
2251 					continue;
2252 				}
2253 				ibcm_fill_svcinfo(svcrec_resp,
2254 				    &dinfo->dest[j++]);
2255 				rec_found++;
2256 				alt_fill_done = B_TRUE;
2257 			}
2258 
2259 			if (rec_found == 2)
2260 				break;
2261 		}
2262 		if ((alt_fill_done == B_FALSE) && (a_gid.gid_guid)) {
2263 			dinfo->dest[j].d_gid = a_gid;
2264 			dinfo->dest[j].d_pkey = p_pkey;
2265 			rec_found++;
2266 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2267 			    "Let Alt Pkey=%X, DGID=%llX:%llX", p_pkey,
2268 			    a_gid.gid_prefix, a_gid.gid_guid);
2269 		}
2270 
2271 		if (rec_found == 1)
2272 			retval = IBT_INSUFF_DATA;
2273 	} else if (p_arg->flags & IBT_PATH_MULTI_SVC_DEST) {
2274 		for (i = 0; i < num_req; i++, svcrec_resp++) {
2275 			/* Limited P_Key is NOT supported as of now!. */
2276 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2277 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2278 				    "SvcPkey 0x%X limited, reject the record.",
2279 				    svcrec_resp->ServiceP_Key);
2280 				continue;
2281 			}
2282 			ibcm_fill_svcinfo(svcrec_resp,
2283 			    &dinfo->dest[rec_found]);
2284 			rec_found++;
2285 			if (rec_found == p_arg->max_paths)
2286 				break;
2287 		}
2288 
2289 		if (rec_found < p_arg->max_paths)
2290 			retval = IBT_INSUFF_DATA;
2291 	} else {
2292 		for (i = 0; i < num_req; i++) {
2293 			/* Limited P_Key is NOT supported as of now!. */
2294 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2295 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2296 				    "SvcPkey 0x%X limited, reject the record.",
2297 				    svcrec_resp->ServiceP_Key);
2298 				svcrec_resp++;
2299 				continue;
2300 			}
2301 
2302 			ibcm_fill_svcinfo(svcrec_resp, &dinfo->dest[0]);
2303 			rec_found = 1;
2304 
2305 			/* Avoid having loopback node */
2306 			if (svcrec_resp->ServiceGID.gid_guid !=
2307 			    sl->p_sgid.gid_guid) {
2308 				break;
2309 			} else {
2310 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2311 				    "avoid LoopBack node.");
2312 				svcrec_resp++;
2313 			}
2314 		}
2315 	}
2316 
2317 	/* Deallocate the memory for results_p. */
2318 	kmem_free(results_p, length);
2319 	if (dinfo->num_dest == 0)
2320 		dinfo->num_dest = rec_found;
2321 
2322 	/*
2323 	 * Check out whether all Service Path we looking for are on the same
2324 	 * P_key. If yes, then set the global p_key field with that value,
2325 	 * to make it easy during SA Path Query.
2326 	 */
2327 	if ((dinfo->num_dest) && (dinfo->p_key == 0)) {
2328 		ib_pkey_t	pk = dinfo->dest[0].d_pkey;
2329 
2330 		if (dinfo->num_dest == 1) {
2331 			dinfo->p_key = pk;
2332 		} else {
2333 			for (i = 1; i < (dinfo->num_dest - 1); i++) {
2334 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2335 				    "pk= 0x%X, pk[%d]= 0x%X", pk, i,
2336 				    dinfo->dest[i].d_pkey);
2337 				if (pk != dinfo->dest[i].d_pkey) {
2338 					dinfo->p_key = 0;
2339 					break;
2340 				} else {
2341 					dinfo->p_key = pk;
2342 				}
2343 			}
2344 		}
2345 	}
2346 
2347 	if (rec_found == 0) {
2348 		IBTF_DPRINTF_L2(cmlog, "ibcm_saa_service_rec: "
2349 		    "ServiceRec NOT Found");
2350 		retval = IBT_SERVICE_RECORDS_NOT_FOUND;
2351 	}
2352 
2353 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: done. Status %d, "
2354 	    "PKey 0x%X, Found %d SvcRec", retval, dinfo->p_key, rec_found);
2355 
2356 	return (retval);
2357 }
2358 
2359 
2360 static boolean_t
2361 ibcm_compare_paths(sa_path_record_t *pr_resp, ibt_cep_path_t *rc_path,
2362     ibtl_cm_hca_port_t *c_hp)
2363 {
2364 	if ((rc_path->cep_hca_port_num == c_hp->hp_port) &&
2365 	    (rc_path->cep_adds_vect.av_src_path ==
2366 	    (pr_resp->SLID - c_hp->hp_base_lid)) &&
2367 	    (rc_path->cep_adds_vect.av_dlid == pr_resp->DLID) &&
2368 	    (rc_path->cep_adds_vect.av_srate == pr_resp->Rate)) {
2369 		return (B_TRUE);
2370 	} else {
2371 		return (B_FALSE);
2372 	}
2373 }
2374 
2375 /*
2376  * ibcm_get_comp_pgids() routine gets the companion port for 'gid'.
2377  *
2378  * On success:
2379  *	If 'n_gid' is specified, then verify whether 'n_gid' is indeed a
2380  *	companion portgid of 'gid'.  If matches return success or else error.
2381  *
2382  *	If 'n_gid' is NOT specified, then return back SUCCESS along with
2383  *	obtained Companion PortGids 'gid_p', where 'num' indicated number
2384  *	of companion portgids returned in 'gid_p'.
2385  */
2386 
2387 static ibt_status_t
2388 ibcm_get_comp_pgids(ib_gid_t gid, ib_gid_t n_gid, ib_guid_t hca_guid,
2389     ib_gid_t **gid_p, uint_t *num)
2390 {
2391 	ibt_status_t    ret;
2392 	int		i;
2393 
2394 	ret = ibt_get_companion_port_gids(gid, hca_guid, 0, gid_p, num);
2395 	if ((ret != IBT_SUCCESS) && (ret != IBT_GIDS_NOT_FOUND)) {
2396 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: "
2397 		    "ibt_get_companion_port_gids(%llX:%llX) Failed: %d",
2398 		    gid.gid_prefix, gid.gid_guid, ret);
2399 	} else if ((ret == IBT_GIDS_NOT_FOUND) && (n_gid.gid_guid != 0)) {
2400 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: Specified GID "
2401 		    "(%llX:%llX) is NOT a Companion \n\t to current channel's "
2402 		    "GID(%llX:%llX)", n_gid.gid_prefix, n_gid.gid_guid,
2403 		    gid.gid_prefix, gid.gid_guid);
2404 		ret = IBT_INVALID_PARAM;
2405 	} else if (n_gid.gid_guid != 0) {
2406 		/*
2407 		 * We found some Comp GIDs and n_gid is specified. Validate
2408 		 * whether the 'n_gid' specified is indeed the companion port
2409 		 * GID of 'gid'.
2410 		 */
2411 		for (i = 0; i < *num; i++) {
2412 			if ((n_gid.gid_prefix == gid_p[i]->gid_prefix) &&
2413 			    (n_gid.gid_guid == gid_p[i]->gid_guid)) {
2414 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_comp_pgids: "
2415 				    "Matching Found!. Done.");
2416 				return (IBT_SUCCESS);
2417 			}
2418 		}
2419 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: GID (%llX:%llX)\n"
2420 		    "\t and (%llX:%llX) are NOT Companion Port GIDS",
2421 		    n_gid.gid_prefix, n_gid.gid_guid, gid.gid_prefix,
2422 		    gid.gid_guid);
2423 		ret = IBT_INVALID_PARAM;
2424 	} else {
2425 		ret = IBT_SUCCESS;
2426 	}
2427 
2428 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_comp_pgids: done. Status = %d", ret);
2429 	return (ret);
2430 }
2431 
2432 /*
2433  * Function:
2434  *	ibt_get_alt_path
2435  * Input:
2436  *	rc_chan		An RC channel handle returned in a previous call
2437  *			ibt_alloc_rc_channel(9F), specifies the channel to open.
2438  *	flags		Path flags.
2439  *	attrp		A pointer to an ibt_alt_path_attr_t(9S) structure that
2440  *			specifies required attributes of the selected path(s).
2441  * Output:
2442  *	api_p		An ibt_alt_path_info_t(9S) struct filled in as output
2443  *			parameters.
2444  * Returns:
2445  *	IBT_SUCCESS on Success else appropriate error.
2446  * Description:
2447  *      Finds the best alternate path to a specified channel (as determined by
2448  *      the IBTL) that satisfies the requirements specified in an
2449  *      ibt_alt_path_attr_t struct.  The specified channel must have been
2450  *      previously opened successfully using ibt_open_rc_channel.
2451  *      This function also ensures that the service being accessed by the
2452  *      channel is available at the selected alternate port.
2453  *
2454  *      Note: The apa_dgid must be on the same destination channel adapter,
2455  *      if specified.
2456  *	This routine can not be called from interrupt context.
2457  */
2458 ibt_status_t
2459 ibt_get_alt_path(ibt_channel_hdl_t rc_chan, ibt_path_flags_t flags,
2460     ibt_alt_path_attr_t *attrp, ibt_alt_path_info_t *api_p)
2461 {
2462 	sa_multipath_record_t	*mpr_req;
2463 	sa_path_record_t	*pr_resp;
2464 	ibmf_saa_access_args_t	access_args;
2465 	ibt_qp_query_attr_t	qp_attr;
2466 	ibtl_cm_hca_port_t	c_hp, n_hp;
2467 	ibcm_hca_info_t		*hcap;
2468 	void			*results_p;
2469 	uint64_t		c_mask = 0;
2470 	ib_gid_t		*gid_ptr = NULL;
2471 	ib_gid_t		*sgids_p = NULL,  *dgids_p = NULL;
2472 	ib_gid_t		cur_dgid, cur_sgid;
2473 	ib_gid_t		new_dgid, new_sgid;
2474 	ibmf_saa_handle_t	saa_handle;
2475 	size_t			length;
2476 	int			i, j, template_len, rec_found;
2477 	uint_t			snum = 0, dnum = 0, num_rec;
2478 	ibt_status_t		retval;
2479 	ib_mtu_t		prim_mtu;
2480 
2481 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path(%p, %x, %p, %p)",
2482 	    rc_chan, flags, attrp, api_p);
2483 
2484 	/* validate channel */
2485 	if (IBCM_INVALID_CHANNEL(rc_chan)) {
2486 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: invalid channel");
2487 		return (IBT_CHAN_HDL_INVALID);
2488 	}
2489 
2490 	if (api_p == NULL) {
2491 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: invalid attribute: "
2492 		    " AltPathInfo can't be NULL");
2493 		return (IBT_INVALID_PARAM);
2494 	}
2495 
2496 	retval = ibt_query_qp(rc_chan, &qp_attr);
2497 	if (retval != IBT_SUCCESS) {
2498 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: ibt_query_qp(%p) "
2499 		    "failed %d", rc_chan, retval);
2500 		return (retval);
2501 	}
2502 
2503 	if (qp_attr.qp_info.qp_trans != IBT_RC_SRV) {
2504 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2505 		    "Invalid Channel type: Applicable only to RC Channel");
2506 		return (IBT_CHAN_SRV_TYPE_INVALID);
2507 	}
2508 
2509 	cur_dgid =
2510 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dgid;
2511 	cur_sgid =
2512 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_sgid;
2513 	prim_mtu = qp_attr.qp_info.qp_transport.rc.rc_path_mtu;
2514 
2515 	/* If optional attributes are specified, validate them. */
2516 	if (attrp) {
2517 		new_dgid = attrp->apa_dgid;
2518 		new_sgid = attrp->apa_sgid;
2519 	} else {
2520 		new_dgid.gid_prefix = 0;
2521 		new_dgid.gid_guid = 0;
2522 		new_sgid.gid_prefix = 0;
2523 		new_sgid.gid_guid = 0;
2524 	}
2525 
2526 	if ((new_dgid.gid_prefix != 0) && (new_sgid.gid_prefix != 0) &&
2527 	    (new_dgid.gid_prefix != new_sgid.gid_prefix)) {
2528 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: Specified SGID's "
2529 		    "SNprefix (%llX) doesn't match with \n specified DGID's "
2530 		    "SNprefix: %llX", new_sgid.gid_prefix, new_dgid.gid_prefix);
2531 		return (IBT_INVALID_PARAM);
2532 	}
2533 
2534 	/* For the specified SGID, get HCA information. */
2535 	retval = ibtl_cm_get_hca_port(cur_sgid, 0, &c_hp);
2536 	if (retval != IBT_SUCCESS) {
2537 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2538 		    "Get HCA Port Failed: %d", retval);
2539 		return (retval);
2540 	}
2541 
2542 	hcap = ibcm_find_hca_entry(c_hp.hp_hca_guid);
2543 	if (hcap == NULL) {
2544 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: NO HCA found");
2545 		return (IBT_HCA_BUSY_DETACHING);
2546 	}
2547 
2548 	/* Validate whether this HCA support APM */
2549 	if (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG)) {
2550 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2551 		    "HCA (%llX) - APM NOT SUPPORTED ", c_hp.hp_hca_guid);
2552 		retval = IBT_APM_NOT_SUPPORTED;
2553 		goto get_alt_path_done;
2554 	}
2555 
2556 	/* Get Companion Port GID of the current Channel's SGID */
2557 	if ((new_sgid.gid_guid == 0) || ((new_sgid.gid_guid != 0) &&
2558 	    (new_sgid.gid_guid != cur_sgid.gid_guid))) {
2559 		IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: SRC: "
2560 		    "Get Companion PortGids for - %llX:%llX",
2561 		    cur_sgid.gid_prefix, cur_sgid.gid_guid);
2562 
2563 		retval = ibcm_get_comp_pgids(cur_sgid, new_sgid,
2564 		    c_hp.hp_hca_guid, &sgids_p, &snum);
2565 		if (retval != IBT_SUCCESS)
2566 			goto get_alt_path_done;
2567 	}
2568 
2569 	/* Get Companion Port GID of the current Channel's DGID */
2570 	if ((new_dgid.gid_guid == 0) || ((new_dgid.gid_guid != 0) &&
2571 	    (new_dgid.gid_guid != cur_dgid.gid_guid))) {
2572 
2573 		IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: DEST: "
2574 		    "Get Companion PortGids for - %llX:%llX",
2575 		    cur_dgid.gid_prefix, cur_dgid.gid_guid);
2576 
2577 		retval = ibcm_get_comp_pgids(cur_dgid, new_dgid, 0, &dgids_p,
2578 		    &dnum);
2579 		if (retval != IBT_SUCCESS)
2580 			goto get_alt_path_done;
2581 	}
2582 
2583 	if ((new_dgid.gid_guid == 0) || (new_sgid.gid_guid == 0)) {
2584 		if (new_sgid.gid_guid == 0) {
2585 			for (i = 0; i < snum; i++) {
2586 				if (new_dgid.gid_guid == 0) {
2587 					for (j = 0; j < dnum; j++) {
2588 						if (sgids_p[i].gid_prefix ==
2589 						    dgids_p[j].gid_prefix) {
2590 							new_dgid = dgids_p[j];
2591 							new_sgid = sgids_p[i];
2592 
2593 							goto get_alt_proceed;
2594 						}
2595 					}
2596 					/*  Current DGID */
2597 					if (sgids_p[i].gid_prefix ==
2598 					    cur_dgid.gid_prefix) {
2599 						new_sgid = sgids_p[i];
2600 						goto get_alt_proceed;
2601 					}
2602 				} else {
2603 					if (sgids_p[i].gid_prefix ==
2604 					    new_dgid.gid_prefix) {
2605 						new_sgid = sgids_p[i];
2606 						goto get_alt_proceed;
2607 					}
2608 				}
2609 			}
2610 			/* Current SGID */
2611 			if (new_dgid.gid_guid == 0) {
2612 				for (j = 0; j < dnum; j++) {
2613 					if (cur_sgid.gid_prefix ==
2614 					    dgids_p[j].gid_prefix) {
2615 						new_dgid = dgids_p[j];
2616 
2617 						goto get_alt_proceed;
2618 					}
2619 				}
2620 			}
2621 		} else if (new_dgid.gid_guid == 0) {
2622 			for (i = 0; i < dnum; i++) {
2623 				if (dgids_p[i].gid_prefix ==
2624 				    new_sgid.gid_prefix) {
2625 					new_dgid = dgids_p[i];
2626 					goto get_alt_proceed;
2627 				}
2628 			}
2629 			/* Current DGID */
2630 			if (cur_dgid.gid_prefix == new_sgid.gid_prefix) {
2631 				goto get_alt_proceed;
2632 			}
2633 		}
2634 		/*
2635 		 * hmm... No Companion Ports available.
2636 		 * so we will be using current or specified attributes only.
2637 		 */
2638 	}
2639 
2640 get_alt_proceed:
2641 
2642 	if (new_sgid.gid_guid != 0) {
2643 		retval = ibtl_cm_get_hca_port(new_sgid, 0, &n_hp);
2644 		if (retval != IBT_SUCCESS) {
2645 			IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2646 			    "Get HCA Port Failed: %d", retval);
2647 			goto get_alt_path_done;
2648 		}
2649 	}
2650 
2651 	/* Calculate the size for multi-path records template */
2652 	template_len = (2 * sizeof (ib_gid_t)) + sizeof (sa_multipath_record_t);
2653 
2654 	mpr_req = kmem_zalloc(template_len, KM_SLEEP);
2655 
2656 	ASSERT(mpr_req != NULL);
2657 
2658 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
2659 
2660 	gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
2661 	    sizeof (sa_multipath_record_t));
2662 
2663 	/* SGID */
2664 	if (new_sgid.gid_guid == 0)
2665 		*gid_ptr = cur_sgid;
2666 	else
2667 		*gid_ptr = new_sgid;
2668 
2669 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Get Path Between "
2670 	    " SGID : %llX:%llX", gid_ptr->gid_prefix, gid_ptr->gid_guid);
2671 
2672 	gid_ptr++;
2673 
2674 	/* DGID */
2675 	if (new_dgid.gid_guid == 0)
2676 		*gid_ptr = cur_dgid;
2677 	else
2678 		*gid_ptr = new_dgid;
2679 
2680 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path:\t\t    DGID : %llX:%llX",
2681 	    gid_ptr->gid_prefix, gid_ptr->gid_guid);
2682 
2683 	mpr_req->SGIDCount = 1;
2684 	c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
2685 
2686 	mpr_req->DGIDCount = 1;
2687 	c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
2688 
2689 	/* Is Flow Label Specified. */
2690 	if (attrp) {
2691 		if (attrp->apa_flow) {
2692 			mpr_req->FlowLabel = attrp->apa_flow;
2693 			c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
2694 		}
2695 
2696 		/* Is HopLimit Specified. */
2697 		if (flags & IBT_PATH_HOP) {
2698 			mpr_req->HopLimit = attrp->apa_hop;
2699 			c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
2700 		}
2701 
2702 		/* Is TClass Specified. */
2703 		if (attrp->apa_tclass) {
2704 			mpr_req->TClass = attrp->apa_tclass;
2705 			c_mask |= SA_MPR_COMPMASK_TCLASS;
2706 		}
2707 
2708 		/* Is SL specified. */
2709 		if (attrp->apa_sl) {
2710 			mpr_req->SL = attrp->apa_sl;
2711 			c_mask |= SA_MPR_COMPMASK_SL;
2712 		}
2713 
2714 		if (flags & IBT_PATH_PERF) {
2715 			mpr_req->PacketLifeTimeSelector = IBT_BEST;
2716 			mpr_req->RateSelector = IBT_BEST;
2717 
2718 			c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
2719 			    SA_MPR_COMPMASK_RATESELECTOR;
2720 		} else {
2721 			if (attrp->apa_pkt_lt.p_selector == IBT_BEST) {
2722 				mpr_req->PacketLifeTimeSelector = IBT_BEST;
2723 				c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
2724 			}
2725 
2726 			if (attrp->apa_srate.r_selector == IBT_BEST) {
2727 				mpr_req->RateSelector = IBT_BEST;
2728 				c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
2729 			}
2730 		}
2731 
2732 		/*
2733 		 * Honor individual selection of these attributes,
2734 		 * even if IBT_PATH_PERF is set.
2735 		 */
2736 		/* Check out whether Packet Life Time is specified. */
2737 		if (attrp->apa_pkt_lt.p_pkt_lt) {
2738 			mpr_req->PacketLifeTime =
2739 			    ibt_usec2ib(attrp->apa_pkt_lt.p_pkt_lt);
2740 			mpr_req->PacketLifeTimeSelector =
2741 			    attrp->apa_pkt_lt.p_selector;
2742 
2743 			c_mask |= SA_MPR_COMPMASK_PKTLT |
2744 			    SA_MPR_COMPMASK_PKTLTSELECTOR;
2745 		}
2746 
2747 		/* Is SRATE specified. */
2748 		if (attrp->apa_srate.r_srate) {
2749 			mpr_req->Rate = attrp->apa_srate.r_srate;
2750 			mpr_req->RateSelector = attrp->apa_srate.r_selector;
2751 
2752 			c_mask |= SA_MPR_COMPMASK_RATE |
2753 			    SA_MPR_COMPMASK_RATESELECTOR;
2754 		}
2755 	}
2756 
2757 	/* Alt PathMTU can be GT or EQU to current channel's Pri PathMTU */
2758 
2759 	/* P_Key must be same as that of primary path */
2760 	retval = ibt_index2pkey_byguid(c_hp.hp_hca_guid, c_hp.hp_port,
2761 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix,
2762 	    &mpr_req->P_Key);
2763 	if (retval != IBT_SUCCESS) {
2764 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: Idx2Pkey Failed: %d",
2765 		    retval);
2766 		goto get_alt_path_done;
2767 	}
2768 	c_mask |= SA_MPR_COMPMASK_PKEY;
2769 
2770 	mpr_req->Reversible = 1;	/* We always get REVERSIBLE paths. */
2771 	mpr_req->IndependenceSelector = 1;
2772 	c_mask |= SA_MPR_COMPMASK_REVERSIBLE | SA_MPR_COMPMASK_INDEPSEL;
2773 
2774 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
2775 
2776 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: CMask: 0x%llX", c_mask);
2777 
2778 	/* NOTE: We will **NOT** specify how many records we want. */
2779 
2780 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Primary: MTU %d, PKey[%d]="
2781 	    "0x%X\n\tSGID = %llX:%llX, DGID = %llX:%llX", prim_mtu,
2782 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix, mpr_req->P_Key,
2783 	    cur_sgid.gid_prefix, cur_sgid.gid_guid, cur_dgid.gid_prefix,
2784 	    cur_dgid.gid_guid);
2785 
2786 	/* Get SA Access Handle. */
2787 	if (new_sgid.gid_guid != 0)
2788 		saa_handle = ibcm_get_saa_handle(hcap, n_hp.hp_port);
2789 	else
2790 		saa_handle = ibcm_get_saa_handle(hcap, c_hp.hp_port);
2791 	if (saa_handle == NULL) {
2792 		retval = IBT_HCA_PORT_NOT_ACTIVE;
2793 		goto get_alt_path_done;
2794 	}
2795 
2796 	/* Contact SA Access to retrieve Path Records. */
2797 	access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
2798 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
2799 	access_args.sq_component_mask = c_mask;
2800 	access_args.sq_template = mpr_req;
2801 	access_args.sq_template_length = sizeof (sa_multipath_record_t);
2802 	access_args.sq_callback = NULL;
2803 	access_args.sq_callback_arg = NULL;
2804 
2805 	retval = ibcm_contact_sa_access(saa_handle, &access_args, &length,
2806 	    &results_p);
2807 	if (retval != IBT_SUCCESS) {
2808 		goto get_alt_path_done;
2809 	}
2810 
2811 	num_rec = length / sizeof (sa_path_record_t);
2812 
2813 	kmem_free(mpr_req, template_len);
2814 
2815 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Found %d Paths", num_rec);
2816 
2817 	rec_found = 0;
2818 	if ((results_p != NULL) && (num_rec > 0)) {
2819 		/* Update the PathInfo with the response Path Records */
2820 		pr_resp = (sa_path_record_t *)results_p;
2821 		for (i = 0; i < num_rec; i++, pr_resp++) {
2822 			if (prim_mtu > pr_resp->Mtu) {
2823 				IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2824 				    "Alt PathMTU(%d) must be GT or EQU to Pri "
2825 				    "PathMTU(%d). Ignore this rec",
2826 				    pr_resp->Mtu, prim_mtu);
2827 				continue;
2828 			}
2829 
2830 			if ((new_sgid.gid_guid == 0) &&
2831 			    (new_dgid.gid_guid == 0)) {
2832 				/* Reject PathRec if it same as Primary Path. */
2833 				if (ibcm_compare_paths(pr_resp,
2834 				    &qp_attr.qp_info.qp_transport.rc.rc_path,
2835 				    &c_hp) == B_TRUE) {
2836 					IBTF_DPRINTF_L3(cmlog,
2837 					    "ibt_get_alt_path: PathRec obtained"
2838 					    " is similar to Prim Path, ignore "
2839 					    "this record");
2840 					continue;
2841 				}
2842 			}
2843 
2844 			if (new_sgid.gid_guid == 0) {
2845 				retval = ibcm_update_cep_info(pr_resp, NULL,
2846 				    &c_hp, &api_p->ap_alt_cep_path);
2847 			} else {
2848 				retval = ibcm_update_cep_info(pr_resp, NULL,
2849 				    &n_hp, &api_p->ap_alt_cep_path);
2850 			}
2851 			if (retval != IBT_SUCCESS)
2852 				continue;
2853 
2854 			/* Update some leftovers */
2855 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*api_p))
2856 
2857 			api_p->ap_alt_pkt_lt = pr_resp->PacketLifeTime;
2858 
2859 			_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*api_p))
2860 
2861 			rec_found = 1;
2862 			break;
2863 		}
2864 		kmem_free(results_p, length);
2865 	}
2866 
2867 	if (rec_found == 0) {
2868 		IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Alternate Path cannot"
2869 		    " be established");
2870 		retval = IBT_PATH_RECORDS_NOT_FOUND;
2871 	} else
2872 		retval = IBT_SUCCESS;
2873 
2874 get_alt_path_done:
2875 	if ((snum) && (sgids_p))
2876 		kmem_free(sgids_p, snum * sizeof (ib_gid_t));
2877 
2878 	if ((dnum) && (dgids_p))
2879 		kmem_free(dgids_p, dnum * sizeof (ib_gid_t));
2880 
2881 	ibcm_dec_hca_acc_cnt(hcap);
2882 
2883 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Done (status %d).", retval);
2884 
2885 	return (retval);
2886 }
2887 
2888 
2889 /* Routines for warlock */
2890 
2891 /* ARGSUSED */
2892 static void
2893 ibcm_dummy_path_handler(void *arg, ibt_status_t retval, ibt_path_info_t *paths,
2894     uint8_t num_path)
2895 {
2896 	ibcm_path_tqargs_t	dummy_path;
2897 
2898 	dummy_path.func = ibcm_dummy_path_handler;
2899 
2900 	IBTF_DPRINTF_L5(cmlog, "ibcm_dummy_path_handler: "
2901 	    "dummy_path.func %p", dummy_path.func);
2902 }
2903