xref: /illumos-gate/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_path.c (revision 24b28d0419f5763eb5a6bad72f99ae67fa2a8921)
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 			else
803 				num_path_plus = num_path;
804 
805 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: Get %d Paths"
806 			    "- MGID(%016llX%016llX)", num_path_plus,
807 			    dgid.gid_prefix, dgid.gid_guid);
808 
809 			dinfo->dest[idx].d_tag = 1; /* MultiCast */
810 
811 			/* Yes, it's Single PathRec query for MGID as DGID. */
812 			retval = ibcm_get_single_pathrec(p_arg, sl, dinfo, idx,
813 			    &num_path_plus, &p_arg->paths[rec_found]);
814 			if ((retval != IBT_SUCCESS) &&
815 			    (retval != IBT_INSUFF_DATA)) {
816 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: "
817 				    "Failed to get PathRec for MGID %d",
818 				    retval);
819 				continue;
820 			}
821 			if (extra)
822 				extra--;
823 
824 			rec_found += num_path_plus;
825 		} else {
826 			/*
827 			 * Check out whether we are looking for loop-back path
828 			 * info. In this case, we should not contact SA Access
829 			 * for Path Records, but instead we need to "synthesize"
830 			 * a loop back path record.
831 			 */
832 			for (i = 0; i < sl->p_count; i++) {
833 				if ((sl[i].p_sgid.gid_prefix ==
834 				    dgid.gid_prefix) &&
835 				    (sl[i].p_sgid.gid_guid == dgid.gid_guid)) {
836 
837 					dinfo->dest[idx].d_tag = 2;
838 
839 					/* Yes, it's loop back case. */
840 					retval = ibcm_fillin_loopbackinfo(
841 					    &sl[i], idx, dinfo,
842 					    &p_arg->paths[rec_found]);
843 					if (retval != IBT_SUCCESS)
844 						break;
845 
846 					/*
847 					 * We update only one record for
848 					 * loop-back case.
849 					 */
850 					rec_found++;
851 					if (rec_found == *max_count)
852 						break;
853 				}
854 			}
855 		}
856 		if (rec_found == *max_count)
857 			break;
858 	}
859 
860 	for (i = 0; i < dinfo->num_dest; i++) {
861 		if (dinfo->dest[i].d_tag == 0) {
862 			unicast_dgid_present++;
863 		}
864 	}
865 
866 	num_path_plus = *max_count - rec_found;
867 
868 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: Recfound: %d, need to find "
869 	    "%d, UniCastGID present %d", rec_found, num_path_plus,
870 	    unicast_dgid_present);
871 
872 	if ((unicast_dgid_present != 0) && (num_path_plus > 0)) {
873 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: MultiSM=%X, #SRC=%d,"
874 		    "Dest%d", sl->p_multi, sl->p_count, unicast_dgid_present);
875 
876 		if ((sl->p_multi != IBTL_CM_SIMPLE_SETUP) ||
877 		    ((unicast_dgid_present == 1) && (sl->p_count == 1))) {
878 			/*
879 			 * Use SinglePathRec if we are dealing w/ MultiSM or
880 			 * request is for one SGID to one DGID.
881 			 */
882 			retval = ibcm_get_single_pathrec(p_arg, sl, dinfo, 0xFF,
883 			    &num_path_plus, &p_arg->paths[rec_found]);
884 		} else {
885 			/* MultiPathRec will be used for other queries. */
886 			retval = ibcm_get_multi_pathrec(p_arg, sl, dinfo,
887 			    &num_path_plus, &p_arg->paths[rec_found]);
888 		}
889 		if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA)) {
890 			IBTF_DPRINTF_L2(cmlog, "ibcm_saa_path_rec: "
891 			    "Failed to get PathRec: Status %d", retval);
892 		} else {
893 			rec_found += num_path_plus;
894 		}
895 	}
896 
897 	if ((rec_found == 0) && (retval == IBT_SUCCESS))
898 		retval = IBT_PATH_RECORDS_NOT_FOUND;
899 	else if (rec_found != *max_count)
900 		retval = IBT_INSUFF_DATA;
901 	else if (rec_found != 0)
902 		retval = IBT_SUCCESS;
903 
904 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: done. Status = %d, "
905 	    "Found %d/%d Paths", retval, rec_found, *max_count);
906 
907 	*max_count = rec_found; /* Update the return count. */
908 
909 	return (retval);
910 }
911 
912 ibt_status_t
913 ibcm_contact_sa_access(ibmf_saa_handle_t saa_handle,
914     ibmf_saa_access_args_t *access_args, size_t *length, void **results_p)
915 {
916 	int	retry;
917 	int	sa_retval;
918 
919 	IBTF_DPRINTF_L3(cmlog, "ibcm_contact_sa_access(%p, %p)",
920 	    saa_handle, access_args);
921 
922 	ibcm_sa_access_enter();
923 
924 	for (retry = 0; retry < ibcm_max_sa_retries; retry++) {
925 		sa_retval = ibmf_sa_access(saa_handle, access_args, 0,
926 		    length, results_p);
927 		if (sa_retval != IBMF_TRANS_TIMEOUT)
928 			break;
929 
930 		IBTF_DPRINTF_L2(cmlog, "ibcm_contact_sa_access: "
931 		    "ibmf_sa_access() - Timed Out (%d)", sa_retval);
932 		delay(ibcm_sa_timeout_delay);
933 	}
934 
935 	ibcm_sa_access_exit();
936 
937 	if ((sa_retval == IBMF_SUCCESS) || (sa_retval == IBMF_NO_RECORDS) ||
938 	    (sa_retval == IBMF_REQ_INVALID)) {
939 		IBTF_DPRINTF_L3(cmlog, "ibcm_contact_sa_access: "
940 		    "ibmf_sa_access() returned (%d)", sa_retval);
941 		return (IBT_SUCCESS);
942 	} else  {
943 		IBTF_DPRINTF_L2(cmlog, "ibcm_contact_sa_access: "
944 		    "ibmf_sa_access(): Failed (%d)", sa_retval);
945 		return (ibcm_ibmf_analyze_error(sa_retval));
946 	}
947 }
948 
949 
950 static ibt_status_t
951 ibcm_update_pri(sa_path_record_t *pr_resp, ibtl_cm_port_list_t *sl,
952     ibcm_dinfo_t *dinfo, ibt_path_info_t *paths)
953 {
954 	ibt_status_t	retval = IBT_SUCCESS;
955 	int		d, s;
956 
957 	retval = ibcm_update_cep_info(pr_resp, sl, NULL,
958 	    &paths->pi_prim_cep_path);
959 	if (retval != IBT_SUCCESS)
960 		return (retval);
961 
962 	/* Update some leftovers */
963 	paths->pi_prim_pkt_lt = pr_resp->PacketLifeTime;
964 	paths->pi_path_mtu = pr_resp->Mtu;
965 
966 	for (d = 0; d < dinfo->num_dest; d++) {
967 		if (pr_resp->DGID.gid_guid == dinfo->dest[d].d_gid.gid_guid) {
968 			paths->pi_sid = dinfo->dest[d].d_sid;
969 			if (paths->pi_sid != 0) {
970 				bcopy(&dinfo->dest[d].d_sdata,
971 				    &paths->pi_sdata, sizeof (ibt_srv_data_t));
972 			}
973 			break;
974 		}
975 	}
976 
977 	for (s = 0; s < sl->p_count; s++) {
978 		if (pr_resp->SGID.gid_guid == sl[s].p_sgid.gid_guid) {
979 			paths->pi_hca_guid = sl[s].p_hca_guid;
980 		}
981 	}
982 
983 	/* Set Alternate Path to invalid state. */
984 	paths->pi_alt_cep_path.cep_hca_port_num = 0;
985 	paths->pi_alt_cep_path.cep_adds_vect.av_dlid = 0;
986 
987 	IBTF_DPRINTF_L5(cmlog, "Path: HCA GUID  = 0x%llX", paths->pi_hca_guid);
988 	IBTF_DPRINTF_L5(cmlog, "Path: ServiceID = 0x%llX", paths->pi_sid);
989 
990 	return (retval);
991 }
992 
993 
994 static ibt_status_t
995 ibcm_get_single_pathrec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
996     ibcm_dinfo_t *dinfo, uint8_t idx, uint8_t *num_path, ibt_path_info_t *paths)
997 {
998 	sa_path_record_t	pathrec_req;
999 	sa_path_record_t	*pr_resp;
1000 	ibmf_saa_access_args_t	access_args;
1001 	uint64_t		c_mask = 0;
1002 	void			*results_p;
1003 	uint8_t			num_rec;
1004 	size_t			length;
1005 	ibt_status_t		retval;
1006 	int			i, j, k;
1007 	int			found, p_fnd;
1008 	ibt_path_attr_t		*attrp = &p_arg->attr;
1009 	ibmf_saa_handle_t	saa_handle;
1010 
1011 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec(%p, %p, %p, %d)",
1012 	    p_arg, sl, dinfo, *num_path);
1013 
1014 	bzero(&pathrec_req, sizeof (sa_path_record_t));
1015 
1016 	/* Is Flow Label Specified. */
1017 	if (attrp->pa_flow) {
1018 		pathrec_req.FlowLabel = attrp->pa_flow;
1019 		c_mask |= SA_PR_COMPMASK_FLOWLABEL;
1020 	}
1021 
1022 	/* Is HopLimit Specified. */
1023 	if (p_arg->flags & IBT_PATH_HOP) {
1024 		pathrec_req.HopLimit = attrp->pa_hop;
1025 		c_mask |= SA_PR_COMPMASK_HOPLIMIT;
1026 	}
1027 
1028 	/* Is P_Key Specified. */
1029 	if (dinfo->p_key) {
1030 		IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: "
1031 		    "Specified or Global PKEY 0x%X", dinfo->p_key);
1032 		pathrec_req.P_Key = dinfo->p_key;
1033 		c_mask |= SA_PR_COMPMASK_PKEY;
1034 	}
1035 
1036 	/* Is TClass Specified. */
1037 	if (attrp->pa_tclass) {
1038 		pathrec_req.TClass = attrp->pa_tclass;
1039 		c_mask |= SA_PR_COMPMASK_TCLASS;
1040 	}
1041 
1042 	/* Is SL specified. */
1043 	if (attrp->pa_sl) {
1044 		pathrec_req.SL = attrp->pa_sl;
1045 		c_mask |= SA_PR_COMPMASK_SL;
1046 	}
1047 
1048 	/* If IBT_PATH_PERF is set, then mark all selectors to BEST. */
1049 	if (p_arg->flags & IBT_PATH_PERF) {
1050 		pathrec_req.PacketLifeTimeSelector = IBT_BEST;
1051 		pathrec_req.MtuSelector = IBT_BEST;
1052 		pathrec_req.RateSelector = IBT_BEST;
1053 
1054 		c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR |
1055 		    SA_PR_COMPMASK_RATESELECTOR | SA_PR_COMPMASK_MTUSELECTOR;
1056 	} else {
1057 		if (attrp->pa_pkt_lt.p_selector == IBT_BEST) {
1058 			pathrec_req.PacketLifeTimeSelector = IBT_BEST;
1059 			c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR;
1060 		}
1061 
1062 		if (attrp->pa_srate.r_selector == IBT_BEST) {
1063 			pathrec_req.RateSelector = IBT_BEST;
1064 			c_mask |= SA_PR_COMPMASK_RATESELECTOR;
1065 		}
1066 
1067 		if (attrp->pa_mtu.r_selector == IBT_BEST) {
1068 			pathrec_req.MtuSelector = IBT_BEST;
1069 			c_mask |= SA_PR_COMPMASK_MTUSELECTOR;
1070 		}
1071 	}
1072 
1073 	/*
1074 	 * Honor individual selection of these attributes,
1075 	 * even if IBT_PATH_PERF is set.
1076 	 */
1077 	/* Check out whether Packet Life Time is specified. */
1078 	if (attrp->pa_pkt_lt.p_pkt_lt) {
1079 		pathrec_req.PacketLifeTime =
1080 		    ibt_usec2ib(attrp->pa_pkt_lt.p_pkt_lt);
1081 		pathrec_req.PacketLifeTimeSelector =
1082 		    attrp->pa_pkt_lt.p_selector;
1083 
1084 		c_mask |= SA_PR_COMPMASK_PKTLT | SA_PR_COMPMASK_PKTLTSELECTOR;
1085 	}
1086 
1087 	/* Is SRATE specified. */
1088 	if (attrp->pa_srate.r_srate) {
1089 		pathrec_req.Rate = attrp->pa_srate.r_srate;
1090 		pathrec_req.RateSelector = attrp->pa_srate.r_selector;
1091 
1092 		c_mask |= SA_PR_COMPMASK_RATE | SA_PR_COMPMASK_RATESELECTOR;
1093 	}
1094 
1095 	/* Is MTU specified. */
1096 	if (attrp->pa_mtu.r_mtu) {
1097 		pathrec_req.Mtu = attrp->pa_mtu.r_mtu;
1098 		pathrec_req.MtuSelector = attrp->pa_mtu.r_selector;
1099 
1100 		c_mask |= SA_PR_COMPMASK_MTU | SA_PR_COMPMASK_MTUSELECTOR;
1101 	}
1102 
1103 	/* We always get REVERSIBLE paths. */
1104 	pathrec_req.Reversible = 1;
1105 	c_mask |= SA_PR_COMPMASK_REVERSIBLE;
1106 
1107 	pathrec_req.NumbPath = *num_path;
1108 	c_mask |= SA_PR_COMPMASK_NUMBPATH;
1109 
1110 	if (idx != 0xFF) {
1111 		/* MGID */
1112 		pathrec_req.DGID = dinfo->dest[idx].d_gid;
1113 		c_mask |= SA_PR_COMPMASK_DGID;
1114 	}
1115 
1116 	p_fnd = found = 0;
1117 
1118 	for (i = 0; i < sl->p_count; i++) {
1119 		/* SGID */
1120 		pathrec_req.SGID = sl[i].p_sgid;
1121 		c_mask |= SA_PR_COMPMASK_SGID;
1122 		saa_handle = sl[i].p_saa_hdl;
1123 
1124 		for (k = 0; k < dinfo->num_dest; k++) {
1125 			if (idx == 0xFF) {		/* DGID */
1126 				if (dinfo->dest[k].d_tag != 0)
1127 					continue;
1128 
1129 				if (pathrec_req.SGID.gid_prefix !=
1130 				    dinfo->dest[k].d_gid.gid_prefix) {
1131 					IBTF_DPRINTF_L3(cmlog,
1132 					    "ibcm_get_single_pathrec: SGID_pfx="
1133 					    "%llX, DGID_pfx=%llX doesn't match",
1134 					    pathrec_req.SGID.gid_prefix,
1135 					    dinfo->dest[k].d_gid.gid_prefix);
1136 					continue;
1137 				} else if (pathrec_req.SGID.gid_guid ==
1138 				    pathrec_req.DGID.gid_guid) {
1139 					IBTF_DPRINTF_L3(cmlog,
1140 					    "ibcm_get_single_pathrec: Why "
1141 					    "LoopBack request came here!!!! "
1142 					    "GID(%llX:%llX)",
1143 					    pathrec_req.SGID.gid_prefix,
1144 					    pathrec_req.SGID.gid_guid);
1145 					continue;
1146 				}
1147 
1148 				pathrec_req.DGID = dinfo->dest[k].d_gid;
1149 				c_mask |= SA_PR_COMPMASK_DGID;
1150 
1151 				/*
1152 				 * If we had performed Service Look-up, then we
1153 				 * got P_Key from ServiceRecord, so get path
1154 				 * records that satisfy this particular P_Key.
1155 				 */
1156 				if ((dinfo->p_key == 0) &&
1157 				    (dinfo->dest[k].d_pkey != 0)) {
1158 					pathrec_req.P_Key =
1159 					    dinfo->dest[k].d_pkey;
1160 					c_mask |= SA_PR_COMPMASK_PKEY;
1161 				}
1162 			}
1163 
1164 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: "
1165 			    "Get %d Path(s) between\n\tSGID(%llX:%llX) "
1166 			    "DGID(%llX:%llX)", pathrec_req.NumbPath,
1167 			    pathrec_req.SGID.gid_prefix,
1168 			    pathrec_req.SGID.gid_guid,
1169 			    pathrec_req.DGID.gid_prefix,
1170 			    pathrec_req.DGID.gid_guid);
1171 
1172 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: CMask"
1173 			    "=0x%llX, PKey=0x%X", c_mask, pathrec_req.P_Key);
1174 
1175 			/* Contact SA Access to retrieve Path Records. */
1176 			access_args.sq_attr_id = SA_PATHRECORD_ATTRID;
1177 			access_args.sq_template = &pathrec_req;
1178 			access_args.sq_access_type = IBMF_SAA_RETRIEVE;
1179 			access_args.sq_template_length =
1180 			    sizeof (sa_path_record_t);
1181 			access_args.sq_component_mask = c_mask;
1182 			access_args.sq_callback = NULL;
1183 			access_args.sq_callback_arg = NULL;
1184 
1185 			retval = ibcm_contact_sa_access(saa_handle,
1186 			    &access_args, &length, &results_p);
1187 			if (retval != IBT_SUCCESS) {
1188 				*num_path = 0;
1189 				return (retval);
1190 			}
1191 
1192 			num_rec = length / sizeof (sa_path_record_t);
1193 
1194 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: "
1195 			    "FOUND %d/%d path requested", num_rec, *num_path);
1196 
1197 			if ((results_p == NULL) || (num_rec == 0)) {
1198 				if (idx != 0xFF)
1199 					break;
1200 				else
1201 					continue;
1202 			}
1203 
1204 			/* Update the PathInfo from the response. */
1205 			pr_resp = (sa_path_record_t *)results_p;
1206 			for (j = 0; j < num_rec; j++, pr_resp++) {
1207 				if ((p_fnd != 0) &&
1208 				    (p_arg->flags & IBT_PATH_APM)) {
1209 					IBTF_DPRINTF_L3(cmlog,
1210 					    "ibcm_get_single_pathrec: "
1211 					    "Fill Alternate Path");
1212 					retval = ibcm_update_cep_info(pr_resp,
1213 					    sl, NULL,
1214 					    &paths[found - 1].pi_alt_cep_path);
1215 					if (retval != IBT_SUCCESS)
1216 						continue;
1217 
1218 					/* Update some leftovers */
1219 					paths[found - 1].pi_alt_pkt_lt =
1220 					    pr_resp->PacketLifeTime;
1221 					p_fnd = 0;
1222 				} else {
1223 					IBTF_DPRINTF_L3(cmlog,
1224 					    "ibcm_get_single_pathrec: "
1225 					    "Fill Primary Path");
1226 
1227 					if (found == *num_path)
1228 						break;
1229 
1230 					retval = ibcm_update_pri(pr_resp, sl,
1231 					    dinfo, &paths[found]);
1232 					if (retval != IBT_SUCCESS)
1233 						continue;
1234 					p_fnd = 1;
1235 					found++;
1236 				}
1237 
1238 			}
1239 			/* Deallocate the memory for results_p. */
1240 			kmem_free(results_p, length);
1241 
1242 			if (idx != 0xFF)
1243 				break;		/* We r here for MGID */
1244 		}
1245 		if ((idx != 0xFF) && (found == *num_path))
1246 			break;		/* We r here for MGID */
1247 	}
1248 
1249 	if (found == 0)
1250 		retval = IBT_PATH_RECORDS_NOT_FOUND;
1251 	else if (found != *num_path)
1252 		retval = IBT_INSUFF_DATA;
1253 	else
1254 		retval = IBT_SUCCESS;
1255 
1256 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: done. Status %d, "
1257 	    "Found %d/%d Paths", retval, found, *num_path);
1258 
1259 	*num_path = found;
1260 
1261 	return (retval);
1262 }
1263 
1264 
1265 static ibt_status_t
1266 ibcm_get_multi_pathrec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
1267     ibcm_dinfo_t *dinfo, uint8_t *num_path, ibt_path_info_t *paths)
1268 {
1269 	sa_multipath_record_t	*mpr_req;
1270 	sa_path_record_t	*pr_resp;
1271 	ibmf_saa_access_args_t	access_args;
1272 	void			*results_p;
1273 	uint64_t		c_mask = 0;
1274 	ib_gid_t		*gid_ptr, *gid_s_ptr;
1275 	size_t			length;
1276 	int			template_len, found, num_rec;
1277 	int			i, k;
1278 	ibt_status_t		retval;
1279 	uint8_t			sgid_cnt, dgid_cnt;
1280 	ibt_path_attr_t		*attrp = &p_arg->attr;
1281 
1282 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec(%p, %p, %p, %d)",
1283 	    attrp, sl, dinfo, *num_path);
1284 
1285 	for (i = 0, dgid_cnt = 0; i < dinfo->num_dest; i++) {
1286 		if (dinfo->dest[i].d_tag == 0)
1287 			dgid_cnt++;
1288 	}
1289 
1290 	sgid_cnt = sl->p_count;
1291 
1292 	if ((sgid_cnt == 0) || (dgid_cnt == 0)) {
1293 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_multi_pathrec: sgid_cnt(%d) or"
1294 		    " dgid_cnt(%d) is zero", sgid_cnt, dgid_cnt);
1295 		return (IBT_INVALID_PARAM);
1296 	}
1297 
1298 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: Get %d records between "
1299 	    "%d Src(s) <=> %d Dest(s)", *num_path, sgid_cnt, dgid_cnt);
1300 
1301 	/*
1302 	 * Calculate the size for multi-path records template, which includes
1303 	 * constant portion of the multipath record, plus variable size for
1304 	 * SGID (sgid_cnt) and DGID (dgid_cnt).
1305 	 */
1306 	template_len = ((dgid_cnt + sgid_cnt) * sizeof (ib_gid_t)) +
1307 	    sizeof (sa_multipath_record_t);
1308 
1309 	mpr_req = kmem_zalloc(template_len, KM_SLEEP);
1310 
1311 	ASSERT(mpr_req != NULL);
1312 
1313 	gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
1314 	    sizeof (sa_multipath_record_t));
1315 
1316 	/* Get the starting pointer where GIDs are stored. */
1317 	gid_s_ptr = gid_ptr;
1318 
1319 	/* SGID */
1320 	for (i = 0; i < sl->p_count; i++) {
1321 		*gid_ptr = sl[i].p_sgid;
1322 
1323 		IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: SGID[%d] = "
1324 		    "(%llX:%llX)", i, gid_ptr->gid_prefix, gid_ptr->gid_guid);
1325 
1326 		gid_ptr++;
1327 	}
1328 
1329 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
1330 
1331 	mpr_req->SGIDCount = sgid_cnt;
1332 	c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
1333 
1334 	/* DGIDs */
1335 	for (i = 0; i < dinfo->num_dest; i++) {
1336 		if (dinfo->dest[i].d_tag == 0) {
1337 			*gid_ptr = dinfo->dest[i].d_gid;
1338 
1339 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1340 			    "DGID[%d] = (%llX:%llX)", i, gid_ptr->gid_prefix,
1341 			    gid_ptr->gid_guid);
1342 			gid_ptr++;
1343 		}
1344 	}
1345 
1346 	mpr_req->DGIDCount = dgid_cnt;
1347 	c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
1348 
1349 	/* Is Flow Label Specified. */
1350 	if (attrp->pa_flow) {
1351 		mpr_req->FlowLabel = attrp->pa_flow;
1352 		c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
1353 	}
1354 
1355 	/* Is HopLimit Specified. */
1356 	if (p_arg->flags & IBT_PATH_HOP) {
1357 		mpr_req->HopLimit = attrp->pa_hop;
1358 		c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
1359 	}
1360 
1361 	/* Is TClass Specified. */
1362 	if (attrp->pa_tclass) {
1363 		mpr_req->TClass = attrp->pa_tclass;
1364 		c_mask |= SA_MPR_COMPMASK_TCLASS;
1365 	}
1366 
1367 	/* Is SL specified. */
1368 	if (attrp->pa_sl) {
1369 		mpr_req->SL = attrp->pa_sl;
1370 		c_mask |= SA_MPR_COMPMASK_SL;
1371 	}
1372 
1373 	if (p_arg->flags & IBT_PATH_PERF) {
1374 		mpr_req->PacketLifeTimeSelector = IBT_BEST;
1375 		mpr_req->RateSelector = IBT_BEST;
1376 		mpr_req->MtuSelector = IBT_BEST;
1377 
1378 		c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
1379 		    SA_MPR_COMPMASK_RATESELECTOR | SA_MPR_COMPMASK_MTUSELECTOR;
1380 	} else {
1381 		if (attrp->pa_pkt_lt.p_selector == IBT_BEST) {
1382 			mpr_req->PacketLifeTimeSelector = IBT_BEST;
1383 			c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
1384 		}
1385 
1386 		if (attrp->pa_srate.r_selector == IBT_BEST) {
1387 			mpr_req->RateSelector = IBT_BEST;
1388 			c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
1389 		}
1390 
1391 		if (attrp->pa_mtu.r_selector == IBT_BEST) {
1392 			mpr_req->MtuSelector = IBT_BEST;
1393 			c_mask |= SA_MPR_COMPMASK_MTUSELECTOR;
1394 		}
1395 	}
1396 
1397 	/*
1398 	 * Honor individual selection of these attributes,
1399 	 * even if IBT_PATH_PERF is set.
1400 	 */
1401 	/* Check out whether Packet Life Time is specified. */
1402 	if (attrp->pa_pkt_lt.p_pkt_lt) {
1403 		mpr_req->PacketLifeTime =
1404 		    ibt_usec2ib(attrp->pa_pkt_lt.p_pkt_lt);
1405 		mpr_req->PacketLifeTimeSelector =
1406 		    attrp->pa_pkt_lt.p_selector;
1407 
1408 		c_mask |= SA_MPR_COMPMASK_PKTLT |
1409 		    SA_MPR_COMPMASK_PKTLTSELECTOR;
1410 	}
1411 
1412 	/* Is SRATE specified. */
1413 	if (attrp->pa_srate.r_srate) {
1414 		mpr_req->Rate = attrp->pa_srate.r_srate;
1415 		mpr_req->RateSelector = attrp->pa_srate.r_selector;
1416 
1417 		c_mask |= SA_MPR_COMPMASK_RATE |
1418 		    SA_MPR_COMPMASK_RATESELECTOR;
1419 	}
1420 
1421 	/* Is MTU specified. */
1422 	if (attrp->pa_mtu.r_mtu) {
1423 		mpr_req->Mtu = attrp->pa_mtu.r_mtu;
1424 		mpr_req->MtuSelector = attrp->pa_mtu.r_selector;
1425 
1426 		c_mask |= SA_MPR_COMPMASK_MTU |
1427 		    SA_MPR_COMPMASK_MTUSELECTOR;
1428 	}
1429 
1430 	/* Is P_Key Specified or obtained during Service Look-up. */
1431 	if (dinfo->p_key) {
1432 		mpr_req->P_Key = dinfo->p_key;
1433 		c_mask |= SA_MPR_COMPMASK_PKEY;
1434 	}
1435 
1436 	/* We always get REVERSIBLE paths. */
1437 	mpr_req->Reversible = 1;
1438 	c_mask |= SA_MPR_COMPMASK_REVERSIBLE;
1439 
1440 	if (p_arg->flags & IBT_PATH_AVAIL) {
1441 		mpr_req->IndependenceSelector = 1;
1442 		c_mask |= SA_MPR_COMPMASK_INDEPSEL;
1443 	}
1444 
1445 	/* we will not specify how many records we want. */
1446 
1447 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
1448 
1449 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: CMask: %llX Pkey: %X",
1450 	    c_mask, mpr_req->P_Key);
1451 
1452 	/* Contact SA Access to retrieve Path Records. */
1453 	access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
1454 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
1455 	access_args.sq_component_mask = c_mask;
1456 	access_args.sq_template = mpr_req;
1457 	access_args.sq_template_length = sizeof (sa_multipath_record_t);
1458 	access_args.sq_callback = NULL;
1459 	access_args.sq_callback_arg = NULL;
1460 
1461 	retval = ibcm_contact_sa_access(sl->p_saa_hdl, &access_args, &length,
1462 	    &results_p);
1463 	if (retval != IBT_SUCCESS) {
1464 		*num_path = 0;  /* Update the return count. */
1465 		kmem_free(mpr_req, template_len);
1466 		return (retval);
1467 	}
1468 
1469 	num_rec = length / sizeof (sa_path_record_t);
1470 
1471 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: Found %d Paths",
1472 	    num_rec);
1473 
1474 	found = 0;
1475 	if ((results_p != NULL) && (num_rec > 0)) {
1476 		/* Update the PathInfo with the response Path Records */
1477 		pr_resp = (sa_path_record_t *)results_p;
1478 
1479 		for (i = 0; i < num_rec; i++) {
1480 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1481 			    "P[%d]: SG %llX, DG %llX", i,
1482 			    pr_resp[i].SGID.gid_guid, pr_resp[i].DGID.gid_guid);
1483 		}
1484 
1485 		if (p_arg->flags & IBT_PATH_APM) {
1486 			sa_path_record_t *p_resp = NULL, *a_resp = NULL;
1487 			int		p_found = 0, a_found = 0;
1488 			ib_gid_t	p_sg, a_sg, p_dg, a_dg;
1489 			int		s_spec;
1490 
1491 			s_spec = p_arg->attr.pa_sgid.gid_guid != 0 ? 1 : 0;
1492 
1493 			p_sg = gid_s_ptr[0];
1494 			if (sgid_cnt > 1)
1495 				a_sg = gid_s_ptr[1];
1496 			else
1497 				a_sg = p_sg;
1498 
1499 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1500 			    "REQ: P_SG: %llX, A_SG: %llX",
1501 			    p_sg.gid_guid, a_sg.gid_guid);
1502 
1503 			p_dg = gid_s_ptr[sgid_cnt];
1504 			if (dgid_cnt > 1)
1505 				a_dg = gid_s_ptr[sgid_cnt + 1];
1506 			else
1507 				a_dg = p_dg;
1508 
1509 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1510 			    "REQ: P_DG: %llX, A_DG: %llX",
1511 			    p_dg.gid_guid, a_dg.gid_guid);
1512 
1513 			/*
1514 			 * If SGID and/or DGID is specified by user, make sure
1515 			 * he gets his primary-path on those node points.
1516 			 */
1517 			for (i = 0; i < num_rec; i++, pr_resp++) {
1518 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec:"
1519 				    " PF %d, AF %d,\n\t\t P[%d] = SG: %llX, "
1520 				    "DG: %llX", p_found, a_found, i,
1521 				    pr_resp->SGID.gid_guid,
1522 				    pr_resp->DGID.gid_guid);
1523 
1524 				if ((!p_found) &&
1525 				    (p_dg.gid_guid == pr_resp->DGID.gid_guid)) {
1526 					IBTF_DPRINTF_L3(cmlog,
1527 					    "ibcm_get_multi_pathrec: "
1528 					    "Pri DGID Match.. ");
1529 					if ((s_spec == 0) || (p_sg.gid_guid ==
1530 					    pr_resp->SGID.gid_guid)) {
1531 						p_found = 1;
1532 						p_resp = pr_resp;
1533 						IBTF_DPRINTF_L3(cmlog,
1534 						    "ibcm_get_multi_pathrec: "
1535 						    "Primary Path Found");
1536 
1537 						if (a_found)
1538 							break;
1539 						else
1540 							continue;
1541 					}
1542 					IBTF_DPRINTF_L3(cmlog,
1543 					    "ibcm_get_multi_pathrec:"
1544 					    "Pri SGID Don't Match.. ");
1545 				}
1546 
1547 				if ((!a_found) &&
1548 				    (a_dg.gid_guid == pr_resp->DGID.gid_guid)) {
1549 					IBTF_DPRINTF_L3(cmlog,
1550 					    "ibcm_get_multi_pathrec:"
1551 					    "Alt DGID Match.. ");
1552 					if ((s_spec == 0) || (a_sg.gid_guid ==
1553 					    pr_resp->SGID.gid_guid)) {
1554 						a_found = 1;
1555 						a_resp = pr_resp;
1556 
1557 						IBTF_DPRINTF_L3(cmlog,
1558 						    "ibcm_get_multi_pathrec:"
1559 						    "Alternate Path Found ");
1560 
1561 						if (p_found)
1562 							break;
1563 						else
1564 							continue;
1565 					}
1566 					IBTF_DPRINTF_L3(cmlog,
1567 					    "ibcm_get_multi_pathrec:"
1568 					    "Alt SGID Don't Match.. ");
1569 				}
1570 			}
1571 
1572 			if ((p_found == 0) && (a_found == 0)) {
1573 				IBTF_DPRINTF_L2(cmlog, "ibcm_get_multi_pathrec:"
1574 				    " Path to desired node points NOT "
1575 				    "Available.");
1576 				retval = IBT_PATH_RECORDS_NOT_FOUND;
1577 				goto get_multi_pathrec_end;
1578 			}
1579 
1580 			if ((p_resp == NULL) && (a_resp != NULL)) {
1581 				p_resp = a_resp;
1582 				a_resp = NULL;
1583 			}
1584 
1585 			/* Fill in Primary Path */
1586 			retval = ibcm_update_pri(p_resp, sl, dinfo,
1587 			    &paths[found]);
1588 			if (retval != IBT_SUCCESS)
1589 				goto get_multi_pathrec_end;
1590 
1591 			/* Fill in Alternate Path */
1592 			if (a_resp != NULL) {
1593 				/* a_resp will point to AltPathInfo buffer. */
1594 				retval = ibcm_update_cep_info(a_resp, sl,
1595 				    NULL, &paths[found].pi_alt_cep_path);
1596 				if (retval != IBT_SUCCESS)
1597 					goto get_multi_pathrec_end;
1598 
1599 				/* Update some leftovers */
1600 				paths[found].pi_alt_pkt_lt =
1601 				    a_resp->PacketLifeTime;
1602 			} else {
1603 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec:"
1604 				    " Alternate Path NOT Available.");
1605 				retval = IBT_INSUFF_DATA;
1606 			}
1607 			found++;
1608 		} else {	/* If NOT APM */
1609 			boolean_t	check_pkey = B_FALSE;
1610 
1611 			/* mark flag whether to validate PKey or not. */
1612 			if ((dinfo->p_key == 0) && (dinfo->dest[0].d_pkey != 0))
1613 				check_pkey = B_TRUE;
1614 
1615 			for (i = 0; i < num_rec; i++, pr_resp++) {
1616 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec:"
1617 				    " PKeyCheck - %s, PKey=0x%X, DGID(%llX)",
1618 				    ((check_pkey == B_TRUE)?"REQD":"NOT_REQD"),
1619 				    pr_resp->P_Key, pr_resp->DGID.gid_guid);
1620 
1621 				if (check_pkey == B_TRUE) {
1622 					boolean_t	match_found = B_FALSE;
1623 
1624 					/* For all DGIDs */
1625 					for (k = 0; k < dinfo->num_dest; k++) {
1626 						if (dinfo->dest[k].d_tag != 0)
1627 							continue;
1628 
1629 						if ((dinfo->dest[k].d_gid.
1630 						    gid_guid ==
1631 						    pr_resp->DGID.gid_guid) &&
1632 						    (dinfo->dest[k].d_pkey ==
1633 						    pr_resp->P_Key)) {
1634 							match_found = B_TRUE;
1635 							break;
1636 						}
1637 					}
1638 					if (match_found == B_FALSE)
1639 						continue;
1640 				}
1641 				/* Fill in Primary Path */
1642 				retval = ibcm_update_pri(pr_resp, sl, dinfo,
1643 				    &paths[found]);
1644 				if (retval != IBT_SUCCESS)
1645 					continue;
1646 
1647 				if (++found == *num_path)
1648 					break;
1649 			}
1650 		}
1651 get_multi_pathrec_end:
1652 		kmem_free(results_p, length);
1653 	}
1654 	kmem_free(mpr_req, template_len);
1655 
1656 	if (found == 0)
1657 		retval = IBT_PATH_RECORDS_NOT_FOUND;
1658 	else if (found != *num_path)
1659 		retval = IBT_INSUFF_DATA;
1660 	else
1661 		retval = IBT_SUCCESS;
1662 
1663 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: Done (status %d). "
1664 	    "Found %d/%d Paths", retval, found, *num_path);
1665 
1666 	*num_path = found;	/* Update the return count. */
1667 
1668 	return (retval);
1669 }
1670 
1671 
1672 /*
1673  * Here we "synthesize" loop back path record information.
1674  *
1675  * Currently the synthesize values are assumed as follows:
1676  *    SLID, DLID = Base LID from Query HCA Port.
1677  *    FlowLabel, HopLimit, TClass = 0, as GRH is False.
1678  *    RawTraffic = 0.
1679  *    P_Key = first valid one in P_Key table as obtained from Query HCA Port.
1680  *    SL = as from Query HCA Port.
1681  *    MTU = from Query HCA Port.
1682  *    Rate = 2 (arbitrary).
1683  *    PacketLifeTime = 0 (4.096 usec).
1684  */
1685 static ibt_status_t
1686 ibcm_fillin_loopbackinfo(ibtl_cm_port_list_t *sl, uint8_t index,
1687     ibcm_dinfo_t *dinfo, ibt_path_info_t *paths)
1688 {
1689 	ibt_status_t	retval;
1690 	ib_pkey_t	pkey = 0;
1691 
1692 	IBTF_DPRINTF_L3(cmlog, "ibcm_fillin_loopbackinfo(%p, %p)", sl, dinfo);
1693 
1694 	/* Synthesize path record with appropriate loop back information. */
1695 	if (dinfo->p_key)
1696 		pkey = dinfo->p_key;
1697 	else
1698 		pkey = dinfo->dest[index].d_pkey;
1699 	if (pkey) {
1700 		/* Convert P_Key to P_Key_Index */
1701 		retval = ibt_pkey2index_byguid(sl->p_hca_guid, sl->p_port_num,
1702 		    pkey, &paths->pi_prim_cep_path.cep_pkey_ix);
1703 		if (retval != IBT_SUCCESS) {
1704 			/* Failed to get pkey_index from pkey */
1705 			IBTF_DPRINTF_L2(cmlog, "ibcm_fillin_loopbackinfo: "
1706 			    "Pkey2Index (P_Key = %X) conversion failed: %d",
1707 			    pkey, retval);
1708 			return (retval);
1709 		}
1710 	} else {
1711 		paths->pi_prim_cep_path.cep_pkey_ix =
1712 		    ibtl_cm_get_1st_full_pkey_ix(sl->p_hca_guid,
1713 		    sl->p_port_num);
1714 		IBTF_DPRINTF_L3(cmlog, "ibcm_fillin_loopbackinfo: "
1715 		    "1st Full Member P_Key_ix = %d",
1716 		    paths->pi_prim_cep_path.cep_pkey_ix);
1717 	}
1718 
1719 	paths->pi_hca_guid = sl->p_hca_guid;
1720 	paths->pi_prim_cep_path.cep_adds_vect.av_dgid =
1721 	    dinfo->dest[index].d_gid;
1722 	paths->pi_prim_cep_path.cep_adds_vect.av_sgid = sl->p_sgid;
1723 	paths->pi_prim_cep_path.cep_adds_vect.av_srate	= IBT_SRATE_1X;
1724 	paths->pi_prim_cep_path.cep_adds_vect.av_srvl	= 0; /* SL */
1725 
1726 	paths->pi_prim_cep_path.cep_adds_vect.av_send_grh = B_FALSE;
1727 	paths->pi_prim_cep_path.cep_adds_vect.av_flow	= 0;
1728 	paths->pi_prim_cep_path.cep_adds_vect.av_tclass	= 0;
1729 	paths->pi_prim_cep_path.cep_adds_vect.av_hop 	= 0;
1730 
1731 	/* SLID and DLID will be equal to BLID. */
1732 	paths->pi_prim_cep_path.cep_adds_vect.av_dlid = sl->p_base_lid;
1733 	paths->pi_prim_cep_path.cep_adds_vect.av_src_path = 0;
1734 	paths->pi_prim_cep_path.cep_adds_vect.av_sgid_ix = sl->p_sgid_ix;
1735 	paths->pi_prim_cep_path.cep_adds_vect.av_port_num =
1736 	paths->pi_prim_cep_path.cep_hca_port_num = sl->p_port_num;
1737 	paths->pi_prim_cep_path.cep_timeout = 0; /* To be filled in by CM. */
1738 	paths->pi_path_mtu = sl->p_mtu;		/* MTU */
1739 	paths->pi_prim_pkt_lt = 0;		/* Packet Life Time. */
1740 	paths->pi_alt_pkt_lt = 0;		/* Packet Life Time. */
1741 
1742 	paths->pi_sid = dinfo->dest[index].d_sid;
1743 
1744 	if (paths->pi_sid != 0)
1745 		bcopy(&dinfo->dest[index].d_sdata, &paths->pi_sdata,
1746 		    sizeof (ibt_srv_data_t));
1747 
1748 	IBTF_DPRINTF_L3(cmlog, "ibcm_fillin_loopbackinfo: HCA %llX:%d SID %llX"
1749 	    "\n\t SGID %llX:%llX DGID %llX:%llX", paths->pi_hca_guid,
1750 	    paths->pi_prim_cep_path.cep_hca_port_num, paths->pi_sid,
1751 	    sl->p_sgid.gid_prefix, sl->p_sgid.gid_guid,
1752 	    dinfo->dest[index].d_gid.gid_prefix,
1753 	    dinfo->dest[index].d_gid.gid_guid);
1754 
1755 	/* Set Alternate Path to invalid state. */
1756 	paths->pi_alt_cep_path.cep_hca_port_num = 0;
1757 	paths->pi_alt_cep_path.cep_adds_vect.av_dlid = 0;
1758 
1759 	return (IBT_SUCCESS);
1760 }
1761 
1762 
1763 /*
1764  * Update the output path records buffer with the values as obtained from
1765  * SA Access retrieve call results for Path Records.
1766  */
1767 static ibt_status_t
1768 ibcm_update_cep_info(sa_path_record_t *prec_resp, ibtl_cm_port_list_t *sl,
1769     ibtl_cm_hca_port_t *hport, ibt_cep_path_t *cep_p)
1770 {
1771 	ibt_status_t	retval;
1772 	int		i;
1773 
1774 	IBCM_DUMP_PATH_REC(prec_resp);
1775 
1776 	/*
1777 	 * If path's packet life time is more than 4 seconds, IBCM cannot
1778 	 * handle this path connection, so discard this path record.
1779 	 */
1780 	if (prec_resp->PacketLifeTime > ibcm_max_ib_pkt_lt) {
1781 		IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: Path's Packet "
1782 		    "LifeTime too high %d, Maximum allowed %d IB Time (4 sec)",
1783 		    prec_resp->PacketLifeTime, ibcm_max_ib_pkt_lt);
1784 		return (IBT_PATH_PKT_LT_TOO_HIGH);
1785 	}
1786 
1787 	if ((prec_resp->Mtu > IB_MTU_4K) || (prec_resp->Mtu < IB_MTU_256)) {
1788 		IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: MTU (%d) from "
1789 		    "pathrecord is invalid, reject it.", prec_resp->Mtu);
1790 		return (ibt_get_module_failure(IBT_FAILURE_IBCM, 0));
1791 	}
1792 
1793 	/* Source Node Information. */
1794 	cep_p->cep_adds_vect.av_sgid = prec_resp->SGID;
1795 	if (hport != NULL) {
1796 		/* Convert P_Key to P_Key_Index */
1797 		retval = ibt_pkey2index_byguid(hport->hp_hca_guid,
1798 		    hport->hp_port, prec_resp->P_Key, &cep_p->cep_pkey_ix);
1799 		if (retval != IBT_SUCCESS) {
1800 			/* Failed to get pkey_index from pkey */
1801 			IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: "
1802 			    "Pkey2Index conversion failed: %d", retval);
1803 			return (retval);
1804 		}
1805 		cep_p->cep_adds_vect.av_sgid_ix = hport->hp_sgid_ix;
1806 		cep_p->cep_adds_vect.av_src_path =
1807 		    prec_resp->SLID - hport->hp_base_lid;
1808 		cep_p->cep_adds_vect.av_port_num = cep_p->cep_hca_port_num =
1809 		    hport->hp_port;
1810 	} else if (sl != NULL) {
1811 		for (i = 0; i < sl->p_count; i++) {
1812 			if (prec_resp->SGID.gid_guid == sl[i].p_sgid.gid_guid) {
1813 				/* Convert P_Key to P_Key_Index */
1814 				retval = ibt_pkey2index_byguid(sl[i].p_hca_guid,
1815 				    sl[i].p_port_num, prec_resp->P_Key,
1816 				    &cep_p->cep_pkey_ix);
1817 				if (retval != IBT_SUCCESS) {
1818 					/* Failed to get pkey_index from pkey */
1819 					IBTF_DPRINTF_L2(cmlog,
1820 					    "ibcm_update_cep_info: Pkey2Index "
1821 					    "conversion failed: %d", retval);
1822 					return (retval);
1823 				}
1824 
1825 				cep_p->cep_adds_vect.av_sgid_ix =
1826 				    sl[i].p_sgid_ix;
1827 				cep_p->cep_adds_vect.av_src_path =
1828 				    prec_resp->SLID - sl[i].p_base_lid;
1829 				cep_p->cep_adds_vect.av_port_num =
1830 				    sl[i].p_port_num;
1831 				cep_p->cep_hca_port_num = sl[i].p_port_num;
1832 
1833 				break;
1834 			}
1835 		}
1836 	} else {
1837 		IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: Sl or Hport "
1838 		    "must be non-null");
1839 		return (IBT_INVALID_PARAM);
1840 	}
1841 
1842 	switch (prec_resp->Rate) {
1843 	case IBT_SRATE_1X:
1844 	case IBT_SRATE_4X:
1845 	case IBT_SRATE_12X:
1846 		cep_p->cep_adds_vect.av_srate = prec_resp->Rate;
1847 		break;
1848 	default:
1849 		IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: SRate (%d) from "
1850 		    "pathrecord is invalid, reject it.", prec_resp->Rate);
1851 		return (IBT_STATIC_RATE_INVALID);
1852 	}
1853 	/*
1854 	 * If both Source and Destination GID prefix are same, then GRH is not
1855 	 * valid, so make it as false, else set this field as true.
1856 	 */
1857 	if (prec_resp->SGID.gid_prefix == prec_resp->DGID.gid_prefix)
1858 		cep_p->cep_adds_vect.av_send_grh = B_FALSE;
1859 	else
1860 		cep_p->cep_adds_vect.av_send_grh = B_TRUE;
1861 
1862 	/* SGID and SGID Index. */
1863 	cep_p->cep_adds_vect.av_sgid = prec_resp->SGID;
1864 	cep_p->cep_adds_vect.av_flow = prec_resp->FlowLabel;
1865 	cep_p->cep_adds_vect.av_tclass = prec_resp->TClass;
1866 	cep_p->cep_adds_vect.av_hop = prec_resp->HopLimit;
1867 
1868 	/* Address Vector Definition. */
1869 	cep_p->cep_adds_vect.av_dlid = prec_resp->DLID;
1870 	cep_p->cep_adds_vect.av_srvl = prec_resp->SL;
1871 
1872 	/* DGID */
1873 	cep_p->cep_adds_vect.av_dgid = prec_resp->DGID;
1874 
1875 	/* CEP Timeout is NOT filled in by PATH routines. */
1876 	cep_p->cep_timeout = 0;
1877 
1878 	IBTF_DPRINTF_L3(cmlog, "ibcm_update_cep_info: Done.  Port[%d]\n"
1879 	    "SGID=%llX:%llX DGID=%llX:%llX",
1880 	    cep_p->cep_adds_vect.av_port_num,
1881 	    prec_resp->SGID.gid_prefix, prec_resp->SGID.gid_guid,
1882 	    prec_resp->DGID.gid_prefix, prec_resp->DGID.gid_guid);
1883 
1884 	return (IBT_SUCCESS);
1885 }
1886 
1887 
1888 static void
1889 ibcm_fill_svcinfo(sa_service_record_t *sr_resp, ibcm_dest_t *dest)
1890 {
1891 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dest))
1892 
1893 	dest->d_gid = sr_resp->ServiceGID;
1894 	dest->d_sid = sr_resp->ServiceID;
1895 	ibcm_swizzle_to_srv(sr_resp->ServiceData, &dest->d_sdata);
1896 	dest->d_pkey = sr_resp->ServiceP_Key;
1897 
1898 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*dest))
1899 
1900 	IBTF_DPRINTF_L3(cmlog, "ibcm_fill_svcinfo: SID(%llX), GID(%llX:%llX)"
1901 	    "\n\tSvcPKey 0x%X", dest->d_sid, dest->d_gid.gid_prefix,
1902 	    dest->d_gid.gid_guid, dest->d_pkey);
1903 }
1904 
1905 
1906 static ib_gid_t
1907 ibcm_saa_get_agid(ibtl_cm_port_list_t *sl, ib_gid_t *gidp, uint_t ngid)
1908 {
1909 	int		k, l;
1910 	ib_gid_t	a_gid;
1911 
1912 	a_gid.gid_prefix = a_gid.gid_guid = 0;
1913 
1914 	for (k = 0; k < sl->p_count; k++) {
1915 		for (l = 0; l < ngid; l++) {
1916 
1917 			if (gidp->gid_prefix == sl->p_sgid.gid_prefix) {
1918 				a_gid = *gidp;
1919 				break;
1920 			}
1921 			if (a_gid.gid_guid && a_gid.gid_prefix)
1922 				break;
1923 			gidp++;
1924 		}
1925 		if (a_gid.gid_guid && a_gid.gid_prefix)
1926 			break;
1927 		sl++;
1928 	}
1929 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_get_agid: AltGID = %llX:%llX",
1930 	    a_gid.gid_prefix, a_gid.gid_guid);
1931 
1932 	return (a_gid);
1933 }
1934 
1935 /*
1936  * Perform SA Access to retrieve Service Records.
1937  * On Success, returns ServiceID and ServiceGID info in '*dinfo'.
1938  */
1939 static ibt_status_t
1940 ibcm_saa_service_rec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
1941     ibcm_dinfo_t *dinfo)
1942 {
1943 	sa_service_record_t	svcrec_req;
1944 	sa_service_record_t	*svcrec_resp;
1945 	void			*results_p;
1946 	uint64_t		component_mask = 0;
1947 	size_t			length;
1948 	uint8_t			i, j, k, rec_found, s;
1949 	ibmf_saa_access_args_t	access_args;
1950 	ibt_status_t		retval;
1951 	ibt_path_attr_t		*attrp = &p_arg->attr;
1952 	uint64_t		tmp_sd_flag = attrp->pa_sd_flags;
1953 	uint8_t			num_req;
1954 
1955 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec(%p, %p)", p_arg, sl);
1956 
1957 	bzero(&svcrec_req, sizeof (svcrec_req));
1958 
1959 	/* Service Name */
1960 	if ((attrp->pa_sname != NULL) && (strlen(attrp->pa_sname) != 0)) {
1961 		(void) strncpy((char *)(svcrec_req.ServiceName),
1962 		    attrp->pa_sname, IB_SVC_NAME_LEN);
1963 
1964 		component_mask |= SA_SR_COMPMASK_NAME;
1965 	}
1966 
1967 	/* Service ID */
1968 	if (attrp->pa_sid) {
1969 		svcrec_req.ServiceID = attrp->pa_sid;
1970 		component_mask |= SA_SR_COMPMASK_ID;
1971 	}
1972 
1973 	/* Is P_Key Specified. */
1974 	if (p_arg->flags & IBT_PATH_PKEY) {
1975 		svcrec_req.ServiceP_Key = attrp->pa_pkey;
1976 		component_mask |= SA_SR_COMPMASK_PKEY;
1977 	}
1978 
1979 	/* Is ServiceData Specified. */
1980 	if (attrp->pa_sd_flags != IBT_NO_SDATA) {
1981 		/* Handle endianess for service data. */
1982 		ibcm_swizzle_from_srv(&attrp->pa_sdata, svcrec_req.ServiceData);
1983 
1984 		/*
1985 		 * Lets not interpret each and every ServiceData flags,
1986 		 * just pass it on to SAA. Shift the flag, to suit
1987 		 * SA_SR_COMPMASK_ALL_DATA definition.
1988 		 */
1989 		component_mask |= (tmp_sd_flag << 7);
1990 	}
1991 
1992 	if (dinfo->num_dest == 1) {
1993 
1994 		/* If a single DGID is specified, provide it */
1995 		svcrec_req.ServiceGID = dinfo->dest->d_gid;
1996 		component_mask |= SA_SR_COMPMASK_GID;
1997 
1998 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec:%llX:%llX",
1999 		    svcrec_req.ServiceGID.gid_prefix,
2000 		    svcrec_req.ServiceGID.gid_guid);
2001 	}
2002 
2003 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2004 	    "Perform SA Access: Mask: 0x%X", component_mask);
2005 
2006 	/*
2007 	 * Call in SA Access retrieve routine to get Service Records.
2008 	 *
2009 	 * SA Access framework allocated memory for the "results_p".
2010 	 * Make sure to deallocate once we are done with the results_p.
2011 	 * The size of the buffer allocated will be as returned in
2012 	 * "length" field.
2013 	 */
2014 	access_args.sq_attr_id = SA_SERVICERECORD_ATTRID;
2015 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
2016 	access_args.sq_component_mask = component_mask;
2017 	access_args.sq_template = &svcrec_req;
2018 	access_args.sq_template_length = sizeof (sa_service_record_t);
2019 	access_args.sq_callback = NULL;
2020 	access_args.sq_callback_arg = NULL;
2021 
2022 	for (s = 0; s < sl->p_count; s++) {
2023 		retval = ibcm_contact_sa_access(sl[s].p_saa_hdl, &access_args,
2024 		    &length, &results_p);
2025 		if (retval != IBT_SUCCESS)
2026 			if (sl[s].p_multi & IBTL_CM_MULTI_SM)
2027 				continue;
2028 			else
2029 				return (retval);
2030 
2031 		if ((results_p == NULL) || (length == 0)) {
2032 			IBTF_DPRINTF_L2(cmlog, "ibcm_saa_service_rec: SvcRec "
2033 			    "Not Found: res_p %p, len %d", results_p, length);
2034 			if (sl[s].p_multi & IBTL_CM_MULTI_SM) {
2035 				retval = IBT_SERVICE_RECORDS_NOT_FOUND;
2036 				continue;
2037 			} else
2038 				return (IBT_SERVICE_RECORDS_NOT_FOUND);
2039 		}
2040 
2041 		/* if we are here, we got some records. so break. */
2042 		break;
2043 	}
2044 
2045 	if (retval != IBT_SUCCESS)
2046 		return (retval);
2047 
2048 	num_req = length / sizeof (sa_service_record_t);
2049 
2050 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Got %d Service Records.",
2051 	    num_req);
2052 
2053 	svcrec_resp = (sa_service_record_t *)results_p;
2054 	rec_found = 0;
2055 
2056 	/* Update the return values. */
2057 	if (dinfo->num_dest) {
2058 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Get ServiceRec "
2059 		    "for Specified DGID: %d", dinfo->num_dest);
2060 
2061 		for (i = 0; i < num_req; i++, svcrec_resp++) {
2062 			/* Limited P_Key is NOT supported as of now!. */
2063 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2064 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2065 				    "SvcPkey 0x%X limited, reject the record.",
2066 				    svcrec_resp->ServiceP_Key);
2067 				continue;
2068 			}
2069 
2070 			for (j = 0; j < dinfo->num_dest; j++) {
2071 				if (dinfo->dest[j].d_gid.gid_guid ==
2072 				    svcrec_resp->ServiceGID.gid_guid) {
2073 					ibcm_fill_svcinfo(svcrec_resp,
2074 					    &dinfo->dest[j]);
2075 					rec_found++;
2076 				}
2077 				if (rec_found == dinfo->num_dest)
2078 					break;
2079 			}
2080 			if (rec_found == dinfo->num_dest)
2081 				break;
2082 		}
2083 		if (rec_found != dinfo->num_dest) {
2084 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Did NOT "
2085 			    "find ServiceRec for all DGIDs: (%d/%d)", rec_found,
2086 			    dinfo->num_dest);
2087 			retval = IBT_INSUFF_DATA;
2088 		}
2089 	} else if (p_arg->flags & IBT_PATH_APM) {
2090 		ib_gid_t		p_gid, a_gid, last_p_gid;
2091 		ib_gid_t		*gidp = NULL;
2092 		uint_t			n_gids;
2093 		sa_service_record_t	*stmp;
2094 		boolean_t		pri_fill_done = B_FALSE;
2095 		boolean_t		alt_fill_done = B_FALSE;
2096 		ib_pkey_t		p_pkey = 0, a_pkey = 0;
2097 
2098 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Need to "
2099 		    "find ServiceRec that can satisfy APM");
2100 
2101 		p_gid.gid_prefix = p_gid.gid_guid = 0;
2102 		a_gid.gid_prefix = a_gid.gid_guid = 0;
2103 		last_p_gid.gid_prefix = last_p_gid.gid_guid = 0;
2104 
2105 		for (i = 0; i < num_req; i++, svcrec_resp++) {
2106 			ibt_status_t	ret;
2107 			boolean_t	local_node_check_done = B_FALSE;
2108 
2109 			/* Limited P_Key is NOT supported as of now!. */
2110 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2111 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2112 				    "SvcPkey 0x%X limited, reject the record.",
2113 				    svcrec_resp->ServiceP_Key);
2114 				continue;
2115 			}
2116 
2117 			p_gid = svcrec_resp->ServiceGID;
2118 
2119 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2120 			    "Let DGID(%llX:%llX) be Primary",
2121 			    p_gid.gid_prefix, p_gid.gid_guid);
2122 
2123 			/* Let's avoid LoopBack Nodes. */
2124 			if (p_gid.gid_guid == sl->p_sgid.gid_guid) {
2125 				local_node_check_done = B_TRUE;
2126 
2127 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2128 				    "Lets Avoid Local Node, "
2129 				    "search for remote node.");
2130 			}
2131 
2132 			if (local_node_check_done == B_TRUE) {
2133 				if ((i + 1) < num_req) {
2134 					p_gid.gid_prefix = 0;
2135 					p_gid.gid_guid = 0;
2136 					continue;
2137 				} else if (last_p_gid.gid_prefix != 0) {
2138 					p_gid = last_p_gid;
2139 					break;
2140 				}
2141 			}
2142 
2143 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2144 			    "Finally let Primary DGID = %llX:%llX",
2145 			    p_gid.gid_prefix, p_gid.gid_guid);
2146 
2147 			ret = ibt_get_companion_port_gids(p_gid, 0, 0,
2148 			    &gidp, &n_gids);
2149 			if (ret == IBT_SUCCESS) {
2150 				IBTF_DPRINTF_L3(cmlog,
2151 				    "ibcm_saa_service_rec: Found %d "
2152 				    "CompGID for %llX:%llX", n_gids,
2153 				    p_gid.gid_prefix, p_gid.gid_guid);
2154 
2155 				stmp = (sa_service_record_t *)results_p;
2156 				a_gid.gid_prefix = a_gid.gid_guid = 0;
2157 
2158 				if (sl->p_multi & IBTL_CM_MULTI_SM) {
2159 					/* validate sn_pfx */
2160 					a_gid = ibcm_saa_get_agid(sl,
2161 					    gidp, n_gids);
2162 				} else {
2163 					for (k = 0; k < num_req; k++) {
2164 						ib_gid_t sg = stmp->ServiceGID;
2165 
2166 						IBTF_DPRINTF_L3(cmlog,
2167 						    "ibcm_saa_service_rec: "
2168 						    "SvcGID[%d] = %llX:%llX", k,
2169 						    sg.gid_prefix, sg.gid_guid);
2170 
2171 						for (j = 0; j < n_gids; j++) {
2172 							if (gidp[j].gid_guid ==
2173 							    sg.gid_guid) {
2174 								a_gid = gidp[j];
2175 								break;
2176 							}
2177 						}
2178 						if (a_gid.gid_guid)
2179 							break;
2180 						stmp++;
2181 					}
2182 					if (a_gid.gid_guid == 0) {
2183 						/* Rec not found for Alt. */
2184 						for (j = 0; j < n_gids; j++) {
2185 							if (gidp[j].gid_prefix
2186 							== p_gid.gid_prefix) {
2187 								a_gid = gidp[j];
2188 								break;
2189 							}
2190 						}
2191 					}
2192 				}
2193 				kmem_free(gidp,
2194 				    n_gids * sizeof (ib_gid_t));
2195 
2196 				if (a_gid.gid_guid)
2197 					break;
2198 			} else if (ret == IBT_GIDS_NOT_FOUND) {
2199 				last_p_gid = p_gid;
2200 				IBTF_DPRINTF_L3(cmlog,
2201 				    "ibcm_saa_service_rec: Didn't find "
2202 				    "CompGID for %llX:%llX, ret=%d",
2203 				    p_gid.gid_prefix, p_gid.gid_guid,
2204 				    ret);
2205 			} else {
2206 				IBTF_DPRINTF_L3(cmlog,
2207 				    "ibcm_saa_service_rec: Call to "
2208 				    "ibt_get_companion_port_gids(%llX:"
2209 				    "%llX) Failed = %d",
2210 				    p_gid.gid_prefix, p_gid.gid_guid,
2211 				    ret);
2212 			}
2213 		}
2214 
2215 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: \n\t"
2216 		    "Pri DGID(%llX:%llX), Alt DGID(%llX:%llX)",
2217 		    p_gid.gid_prefix, p_gid.gid_guid, a_gid.gid_prefix,
2218 		    a_gid.gid_guid);
2219 
2220 		svcrec_resp = (sa_service_record_t *)results_p;
2221 
2222 		for (i = 0, j = 0; i < num_req; i++, svcrec_resp++) {
2223 			/* Limited P_Key is NOT supported as of now!. */
2224 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2225 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2226 				    "SvcPkey 0x%X limited, reject the record.",
2227 				    svcrec_resp->ServiceP_Key);
2228 				continue;
2229 			}
2230 
2231 			if ((pri_fill_done == B_FALSE) &&
2232 			    (p_gid.gid_guid ==
2233 			    svcrec_resp->ServiceGID.gid_guid)) {
2234 				p_pkey = svcrec_resp->ServiceP_Key;
2235 				if ((a_pkey != 0) &&
2236 				    (a_pkey != p_pkey)) {
2237 					IBTF_DPRINTF_L3(cmlog,
2238 					    "ibcm_saa_service_rec: "
2239 					    "Pri(0x%X) & Alt (0x%X) "
2240 					    "PKey must match.",
2241 					    p_pkey, a_pkey);
2242 					p_pkey = 0;
2243 					continue;
2244 				}
2245 				ibcm_fill_svcinfo(svcrec_resp,
2246 				    &dinfo->dest[j++]);
2247 				rec_found++;
2248 				pri_fill_done = B_TRUE;
2249 			} else if ((alt_fill_done == B_FALSE) &&
2250 			    (a_gid.gid_guid ==
2251 			    svcrec_resp->ServiceGID.gid_guid)) {
2252 				a_pkey = svcrec_resp->ServiceP_Key;
2253 				if ((p_pkey != 0) &&
2254 				    (a_pkey != p_pkey)) {
2255 					IBTF_DPRINTF_L3(cmlog,
2256 					    "ibcm_saa_service_rec: "
2257 					    "Pri(0x%X) & Alt (0x%X) "
2258 					    "PKey must match.",
2259 					    p_pkey, a_pkey);
2260 					a_pkey = 0;
2261 					continue;
2262 				}
2263 				ibcm_fill_svcinfo(svcrec_resp,
2264 				    &dinfo->dest[j++]);
2265 				rec_found++;
2266 				alt_fill_done = B_TRUE;
2267 			}
2268 
2269 			if (rec_found == 2)
2270 				break;
2271 		}
2272 		if ((alt_fill_done == B_FALSE) && (a_gid.gid_guid)) {
2273 			dinfo->dest[j].d_gid = a_gid;
2274 			dinfo->dest[j].d_pkey = p_pkey;
2275 			rec_found++;
2276 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2277 			    "Let Alt Pkey=%X, DGID=%llX:%llX", p_pkey,
2278 			    a_gid.gid_prefix, a_gid.gid_guid);
2279 		}
2280 
2281 		if (rec_found == 1)
2282 			retval = IBT_INSUFF_DATA;
2283 	} else if (p_arg->flags & IBT_PATH_MULTI_SVC_DEST) {
2284 		for (i = 0; i < num_req; i++, svcrec_resp++) {
2285 			/* Limited P_Key is NOT supported as of now!. */
2286 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2287 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2288 				    "SvcPkey 0x%X limited, reject the record.",
2289 				    svcrec_resp->ServiceP_Key);
2290 				continue;
2291 			}
2292 			ibcm_fill_svcinfo(svcrec_resp,
2293 			    &dinfo->dest[rec_found]);
2294 			rec_found++;
2295 			if (rec_found == p_arg->max_paths)
2296 				break;
2297 		}
2298 
2299 		if (rec_found < p_arg->max_paths)
2300 			retval = IBT_INSUFF_DATA;
2301 	} else {
2302 		for (i = 0; i < num_req; i++) {
2303 			/* Limited P_Key is NOT supported as of now!. */
2304 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2305 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2306 				    "SvcPkey 0x%X limited, reject the record.",
2307 				    svcrec_resp->ServiceP_Key);
2308 				svcrec_resp++;
2309 				continue;
2310 			}
2311 
2312 			ibcm_fill_svcinfo(svcrec_resp, &dinfo->dest[0]);
2313 			rec_found = 1;
2314 
2315 			/* Avoid having loopback node */
2316 			if (svcrec_resp->ServiceGID.gid_guid !=
2317 			    sl->p_sgid.gid_guid) {
2318 				break;
2319 			} else {
2320 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2321 				    "avoid LoopBack node.");
2322 				svcrec_resp++;
2323 			}
2324 		}
2325 	}
2326 
2327 	/* Deallocate the memory for results_p. */
2328 	kmem_free(results_p, length);
2329 	if (dinfo->num_dest == 0)
2330 		dinfo->num_dest = rec_found;
2331 
2332 	/*
2333 	 * Check out whether all Service Path we looking for are on the same
2334 	 * P_key. If yes, then set the global p_key field with that value,
2335 	 * to make it easy during SA Path Query.
2336 	 */
2337 	if ((dinfo->num_dest) && (dinfo->p_key == 0)) {
2338 		ib_pkey_t	pk = dinfo->dest[0].d_pkey;
2339 
2340 		if (dinfo->num_dest == 1) {
2341 			dinfo->p_key = pk;
2342 		} else {
2343 			for (i = 1; i < (dinfo->num_dest - 1); i++) {
2344 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2345 				    "pk= 0x%X, pk[%d]= 0x%X", pk, i,
2346 				    dinfo->dest[i].d_pkey);
2347 				if (pk != dinfo->dest[i].d_pkey) {
2348 					dinfo->p_key = 0;
2349 					break;
2350 				} else {
2351 					dinfo->p_key = pk;
2352 				}
2353 			}
2354 		}
2355 	}
2356 
2357 	if (rec_found == 0) {
2358 		IBTF_DPRINTF_L2(cmlog, "ibcm_saa_service_rec: "
2359 		    "ServiceRec NOT Found");
2360 		retval = IBT_SERVICE_RECORDS_NOT_FOUND;
2361 	}
2362 
2363 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: done. Status %d, "
2364 	    "PKey 0x%X, Found %d SvcRec", retval, dinfo->p_key, rec_found);
2365 
2366 	return (retval);
2367 }
2368 
2369 
2370 static boolean_t
2371 ibcm_compare_paths(sa_path_record_t *pr_resp, ibt_cep_path_t *rc_path,
2372     ibtl_cm_hca_port_t *c_hp)
2373 {
2374 	if ((rc_path->cep_hca_port_num == c_hp->hp_port) &&
2375 	    (rc_path->cep_adds_vect.av_src_path ==
2376 	    (pr_resp->SLID - c_hp->hp_base_lid)) &&
2377 	    (rc_path->cep_adds_vect.av_dlid == pr_resp->DLID) &&
2378 	    (rc_path->cep_adds_vect.av_srate == pr_resp->Rate)) {
2379 		return (B_TRUE);
2380 	} else {
2381 		return (B_FALSE);
2382 	}
2383 }
2384 
2385 /*
2386  * ibcm_get_comp_pgids() routine gets the companion port for 'gid'.
2387  *
2388  * On success:
2389  *	If 'n_gid' is specified, then verify whether 'n_gid' is indeed a
2390  *	companion portgid of 'gid'.  If matches return success or else error.
2391  *
2392  *	If 'n_gid' is NOT specified, then return back SUCCESS along with
2393  *	obtained Companion PortGids 'gid_p', where 'num' indicated number
2394  *	of companion portgids returned in 'gid_p'.
2395  */
2396 
2397 static ibt_status_t
2398 ibcm_get_comp_pgids(ib_gid_t gid, ib_gid_t n_gid, ib_guid_t hca_guid,
2399     ib_gid_t **gid_p, uint_t *num)
2400 {
2401 	ibt_status_t    ret;
2402 	int		i;
2403 
2404 	ret = ibt_get_companion_port_gids(gid, hca_guid, 0, gid_p, num);
2405 	if ((ret != IBT_SUCCESS) && (ret != IBT_GIDS_NOT_FOUND)) {
2406 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: "
2407 		    "ibt_get_companion_port_gids(%llX:%llX) Failed: %d",
2408 		    gid.gid_prefix, gid.gid_guid, ret);
2409 	} else if ((ret == IBT_GIDS_NOT_FOUND) && (n_gid.gid_guid != 0)) {
2410 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: Specified GID "
2411 		    "(%llX:%llX) is NOT a Companion \n\t to current channel's "
2412 		    "GID(%llX:%llX)", n_gid.gid_prefix, n_gid.gid_guid,
2413 		    gid.gid_prefix, gid.gid_guid);
2414 		ret = IBT_INVALID_PARAM;
2415 	} else if (n_gid.gid_guid != 0) {
2416 		/*
2417 		 * We found some Comp GIDs and n_gid is specified. Validate
2418 		 * whether the 'n_gid' specified is indeed the companion port
2419 		 * GID of 'gid'.
2420 		 */
2421 		for (i = 0; i < *num; i++) {
2422 			if ((n_gid.gid_prefix == gid_p[i]->gid_prefix) &&
2423 			    (n_gid.gid_guid == gid_p[i]->gid_guid)) {
2424 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_comp_pgids: "
2425 				    "Matching Found!. Done.");
2426 				return (IBT_SUCCESS);
2427 			}
2428 		}
2429 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: GID (%llX:%llX)\n"
2430 		    "\t and (%llX:%llX) are NOT Companion Port GIDS",
2431 		    n_gid.gid_prefix, n_gid.gid_guid, gid.gid_prefix,
2432 		    gid.gid_guid);
2433 		ret = IBT_INVALID_PARAM;
2434 	} else {
2435 		ret = IBT_SUCCESS;
2436 	}
2437 
2438 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_comp_pgids: done. Status = %d", ret);
2439 	return (ret);
2440 }
2441 
2442 /*
2443  * Function:
2444  *	ibt_get_alt_path
2445  * Input:
2446  *	rc_chan		An RC channel handle returned in a previous call
2447  *			ibt_alloc_rc_channel(9F), specifies the channel to open.
2448  *	flags		Path flags.
2449  *	attrp		A pointer to an ibt_alt_path_attr_t(9S) structure that
2450  *			specifies required attributes of the selected path(s).
2451  * Output:
2452  *	api_p		An ibt_alt_path_info_t(9S) struct filled in as output
2453  *			parameters.
2454  * Returns:
2455  *	IBT_SUCCESS on Success else appropriate error.
2456  * Description:
2457  *      Finds the best alternate path to a specified channel (as determined by
2458  *      the IBTL) that satisfies the requirements specified in an
2459  *      ibt_alt_path_attr_t struct.  The specified channel must have been
2460  *      previously opened successfully using ibt_open_rc_channel.
2461  *      This function also ensures that the service being accessed by the
2462  *      channel is available at the selected alternate port.
2463  *
2464  *      Note: The apa_dgid must be on the same destination channel adapter,
2465  *      if specified.
2466  *	This routine can not be called from interrupt context.
2467  */
2468 ibt_status_t
2469 ibt_get_alt_path(ibt_channel_hdl_t rc_chan, ibt_path_flags_t flags,
2470     ibt_alt_path_attr_t *attrp, ibt_alt_path_info_t *api_p)
2471 {
2472 	sa_multipath_record_t	*mpr_req;
2473 	sa_path_record_t	*pr_resp;
2474 	ibmf_saa_access_args_t	access_args;
2475 	ibt_qp_query_attr_t	qp_attr;
2476 	ibtl_cm_hca_port_t	c_hp, n_hp;
2477 	ibcm_hca_info_t		*hcap;
2478 	void			*results_p;
2479 	uint64_t		c_mask = 0;
2480 	ib_gid_t		*gid_ptr = NULL;
2481 	ib_gid_t		*sgids_p = NULL,  *dgids_p = NULL;
2482 	ib_gid_t		cur_dgid, cur_sgid;
2483 	ib_gid_t		new_dgid, new_sgid;
2484 	ibmf_saa_handle_t	saa_handle;
2485 	size_t			length;
2486 	int			i, j, template_len, rec_found;
2487 	uint_t			snum = 0, dnum = 0, num_rec;
2488 	ibt_status_t		retval;
2489 	ib_mtu_t		prim_mtu;
2490 
2491 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path(%p, %x, %p, %p)",
2492 	    rc_chan, flags, attrp, api_p);
2493 
2494 	/* validate channel */
2495 	if (IBCM_INVALID_CHANNEL(rc_chan)) {
2496 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: invalid channel");
2497 		return (IBT_CHAN_HDL_INVALID);
2498 	}
2499 
2500 	if (api_p == NULL) {
2501 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: invalid attribute: "
2502 		    " AltPathInfo can't be NULL");
2503 		return (IBT_INVALID_PARAM);
2504 	}
2505 
2506 	retval = ibt_query_qp(rc_chan, &qp_attr);
2507 	if (retval != IBT_SUCCESS) {
2508 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: ibt_query_qp(%p) "
2509 		    "failed %d", rc_chan, retval);
2510 		return (retval);
2511 	}
2512 
2513 	if (qp_attr.qp_info.qp_trans != IBT_RC_SRV) {
2514 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2515 		    "Invalid Channel type: Applicable only to RC Channel");
2516 		return (IBT_CHAN_SRV_TYPE_INVALID);
2517 	}
2518 
2519 	cur_dgid =
2520 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dgid;
2521 	cur_sgid =
2522 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_sgid;
2523 	prim_mtu = qp_attr.qp_info.qp_transport.rc.rc_path_mtu;
2524 
2525 	/* If optional attributes are specified, validate them. */
2526 	if (attrp) {
2527 		new_dgid = attrp->apa_dgid;
2528 		new_sgid = attrp->apa_sgid;
2529 	} else {
2530 		new_dgid.gid_prefix = 0;
2531 		new_dgid.gid_guid = 0;
2532 		new_sgid.gid_prefix = 0;
2533 		new_sgid.gid_guid = 0;
2534 	}
2535 
2536 	if ((new_dgid.gid_prefix != 0) && (new_sgid.gid_prefix != 0) &&
2537 	    (new_dgid.gid_prefix != new_sgid.gid_prefix)) {
2538 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: Specified SGID's "
2539 		    "SNprefix (%llX) doesn't match with \n specified DGID's "
2540 		    "SNprefix: %llX", new_sgid.gid_prefix, new_dgid.gid_prefix);
2541 		return (IBT_INVALID_PARAM);
2542 	}
2543 
2544 	/* For the specified SGID, get HCA information. */
2545 	retval = ibtl_cm_get_hca_port(cur_sgid, 0, &c_hp);
2546 	if (retval != IBT_SUCCESS) {
2547 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2548 		    "Get HCA Port Failed: %d", retval);
2549 		return (retval);
2550 	}
2551 
2552 	hcap = ibcm_find_hca_entry(c_hp.hp_hca_guid);
2553 	if (hcap == NULL) {
2554 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: NO HCA found");
2555 		return (IBT_HCA_BUSY_DETACHING);
2556 	}
2557 
2558 	/* Validate whether this HCA support APM */
2559 	if (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG)) {
2560 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2561 		    "HCA (%llX) - APM NOT SUPPORTED ", c_hp.hp_hca_guid);
2562 		retval = IBT_APM_NOT_SUPPORTED;
2563 		goto get_alt_path_done;
2564 	}
2565 
2566 	/* Get Companion Port GID of the current Channel's SGID */
2567 	if ((new_sgid.gid_guid == 0) || ((new_sgid.gid_guid != 0) &&
2568 	    (new_sgid.gid_guid != cur_sgid.gid_guid))) {
2569 		IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: SRC: "
2570 		    "Get Companion PortGids for - %llX:%llX",
2571 		    cur_sgid.gid_prefix, cur_sgid.gid_guid);
2572 
2573 		retval = ibcm_get_comp_pgids(cur_sgid, new_sgid,
2574 		    c_hp.hp_hca_guid, &sgids_p, &snum);
2575 		if (retval != IBT_SUCCESS)
2576 			goto get_alt_path_done;
2577 	}
2578 
2579 	/* Get Companion Port GID of the current Channel's DGID */
2580 	if ((new_dgid.gid_guid == 0) || ((new_dgid.gid_guid != 0) &&
2581 	    (new_dgid.gid_guid != cur_dgid.gid_guid))) {
2582 
2583 		IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: DEST: "
2584 		    "Get Companion PortGids for - %llX:%llX",
2585 		    cur_dgid.gid_prefix, cur_dgid.gid_guid);
2586 
2587 		retval = ibcm_get_comp_pgids(cur_dgid, new_dgid, 0, &dgids_p,
2588 		    &dnum);
2589 		if (retval != IBT_SUCCESS)
2590 			goto get_alt_path_done;
2591 	}
2592 
2593 	if ((new_dgid.gid_guid == 0) || (new_sgid.gid_guid == 0)) {
2594 		if (new_sgid.gid_guid == 0) {
2595 			for (i = 0; i < snum; i++) {
2596 				if (new_dgid.gid_guid == 0) {
2597 					for (j = 0; j < dnum; j++) {
2598 						if (sgids_p[i].gid_prefix ==
2599 						    dgids_p[j].gid_prefix) {
2600 							new_dgid = dgids_p[j];
2601 							new_sgid = sgids_p[i];
2602 
2603 							goto get_alt_proceed;
2604 						}
2605 					}
2606 					/*  Current DGID */
2607 					if (sgids_p[i].gid_prefix ==
2608 					    cur_dgid.gid_prefix) {
2609 						new_sgid = sgids_p[i];
2610 						goto get_alt_proceed;
2611 					}
2612 				} else {
2613 					if (sgids_p[i].gid_prefix ==
2614 					    new_dgid.gid_prefix) {
2615 						new_sgid = sgids_p[i];
2616 						goto get_alt_proceed;
2617 					}
2618 				}
2619 			}
2620 			/* Current SGID */
2621 			if (new_dgid.gid_guid == 0) {
2622 				for (j = 0; j < dnum; j++) {
2623 					if (cur_sgid.gid_prefix ==
2624 					    dgids_p[j].gid_prefix) {
2625 						new_dgid = dgids_p[j];
2626 
2627 						goto get_alt_proceed;
2628 					}
2629 				}
2630 			}
2631 		} else if (new_dgid.gid_guid == 0) {
2632 			for (i = 0; i < dnum; i++) {
2633 				if (dgids_p[i].gid_prefix ==
2634 				    new_sgid.gid_prefix) {
2635 					new_dgid = dgids_p[i];
2636 					goto get_alt_proceed;
2637 				}
2638 			}
2639 			/* Current DGID */
2640 			if (cur_dgid.gid_prefix == new_sgid.gid_prefix) {
2641 				goto get_alt_proceed;
2642 			}
2643 		}
2644 		/*
2645 		 * hmm... No Companion Ports available.
2646 		 * so we will be using current or specified attributes only.
2647 		 */
2648 	}
2649 
2650 get_alt_proceed:
2651 
2652 	if (new_sgid.gid_guid != 0) {
2653 		retval = ibtl_cm_get_hca_port(new_sgid, 0, &n_hp);
2654 		if (retval != IBT_SUCCESS) {
2655 			IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2656 			    "Get HCA Port Failed: %d", retval);
2657 			goto get_alt_path_done;
2658 		}
2659 	}
2660 
2661 	/* Calculate the size for multi-path records template */
2662 	template_len = (2 * sizeof (ib_gid_t)) + sizeof (sa_multipath_record_t);
2663 
2664 	mpr_req = kmem_zalloc(template_len, KM_SLEEP);
2665 
2666 	ASSERT(mpr_req != NULL);
2667 
2668 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
2669 
2670 	gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
2671 	    sizeof (sa_multipath_record_t));
2672 
2673 	/* SGID */
2674 	if (new_sgid.gid_guid == 0)
2675 		*gid_ptr = cur_sgid;
2676 	else
2677 		*gid_ptr = new_sgid;
2678 
2679 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Get Path Between "
2680 	    " SGID : %llX:%llX", gid_ptr->gid_prefix, gid_ptr->gid_guid);
2681 
2682 	gid_ptr++;
2683 
2684 	/* DGID */
2685 	if (new_dgid.gid_guid == 0)
2686 		*gid_ptr = cur_dgid;
2687 	else
2688 		*gid_ptr = new_dgid;
2689 
2690 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path:\t\t    DGID : %llX:%llX",
2691 	    gid_ptr->gid_prefix, gid_ptr->gid_guid);
2692 
2693 	mpr_req->SGIDCount = 1;
2694 	c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
2695 
2696 	mpr_req->DGIDCount = 1;
2697 	c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
2698 
2699 	/* Is Flow Label Specified. */
2700 	if (attrp) {
2701 		if (attrp->apa_flow) {
2702 			mpr_req->FlowLabel = attrp->apa_flow;
2703 			c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
2704 		}
2705 
2706 		/* Is HopLimit Specified. */
2707 		if (flags & IBT_PATH_HOP) {
2708 			mpr_req->HopLimit = attrp->apa_hop;
2709 			c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
2710 		}
2711 
2712 		/* Is TClass Specified. */
2713 		if (attrp->apa_tclass) {
2714 			mpr_req->TClass = attrp->apa_tclass;
2715 			c_mask |= SA_MPR_COMPMASK_TCLASS;
2716 		}
2717 
2718 		/* Is SL specified. */
2719 		if (attrp->apa_sl) {
2720 			mpr_req->SL = attrp->apa_sl;
2721 			c_mask |= SA_MPR_COMPMASK_SL;
2722 		}
2723 
2724 		if (flags & IBT_PATH_PERF) {
2725 			mpr_req->PacketLifeTimeSelector = IBT_BEST;
2726 			mpr_req->RateSelector = IBT_BEST;
2727 
2728 			c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
2729 			    SA_MPR_COMPMASK_RATESELECTOR;
2730 		} else {
2731 			if (attrp->apa_pkt_lt.p_selector == IBT_BEST) {
2732 				mpr_req->PacketLifeTimeSelector = IBT_BEST;
2733 				c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
2734 			}
2735 
2736 			if (attrp->apa_srate.r_selector == IBT_BEST) {
2737 				mpr_req->RateSelector = IBT_BEST;
2738 				c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
2739 			}
2740 		}
2741 
2742 		/*
2743 		 * Honor individual selection of these attributes,
2744 		 * even if IBT_PATH_PERF is set.
2745 		 */
2746 		/* Check out whether Packet Life Time is specified. */
2747 		if (attrp->apa_pkt_lt.p_pkt_lt) {
2748 			mpr_req->PacketLifeTime =
2749 			    ibt_usec2ib(attrp->apa_pkt_lt.p_pkt_lt);
2750 			mpr_req->PacketLifeTimeSelector =
2751 			    attrp->apa_pkt_lt.p_selector;
2752 
2753 			c_mask |= SA_MPR_COMPMASK_PKTLT |
2754 			    SA_MPR_COMPMASK_PKTLTSELECTOR;
2755 		}
2756 
2757 		/* Is SRATE specified. */
2758 		if (attrp->apa_srate.r_srate) {
2759 			mpr_req->Rate = attrp->apa_srate.r_srate;
2760 			mpr_req->RateSelector = attrp->apa_srate.r_selector;
2761 
2762 			c_mask |= SA_MPR_COMPMASK_RATE |
2763 			    SA_MPR_COMPMASK_RATESELECTOR;
2764 		}
2765 	}
2766 
2767 	/* Alt PathMTU can be GT or EQU to current channel's Pri PathMTU */
2768 
2769 	/* P_Key must be same as that of primary path */
2770 	retval = ibt_index2pkey_byguid(c_hp.hp_hca_guid, c_hp.hp_port,
2771 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix,
2772 	    &mpr_req->P_Key);
2773 	if (retval != IBT_SUCCESS) {
2774 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: Idx2Pkey Failed: %d",
2775 		    retval);
2776 		goto get_alt_path_done;
2777 	}
2778 	c_mask |= SA_MPR_COMPMASK_PKEY;
2779 
2780 	mpr_req->Reversible = 1;	/* We always get REVERSIBLE paths. */
2781 	mpr_req->IndependenceSelector = 1;
2782 	c_mask |= SA_MPR_COMPMASK_REVERSIBLE | SA_MPR_COMPMASK_INDEPSEL;
2783 
2784 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
2785 
2786 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: CMask: 0x%llX", c_mask);
2787 
2788 	/* NOTE: We will **NOT** specify how many records we want. */
2789 
2790 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Primary: MTU %d, PKey[%d]="
2791 	    "0x%X\n\tSGID = %llX:%llX, DGID = %llX:%llX", prim_mtu,
2792 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix, mpr_req->P_Key,
2793 	    cur_sgid.gid_prefix, cur_sgid.gid_guid, cur_dgid.gid_prefix,
2794 	    cur_dgid.gid_guid);
2795 
2796 	/* Get SA Access Handle. */
2797 	if (new_sgid.gid_guid != 0)
2798 		saa_handle = ibcm_get_saa_handle(hcap, n_hp.hp_port);
2799 	else
2800 		saa_handle = ibcm_get_saa_handle(hcap, c_hp.hp_port);
2801 	if (saa_handle == NULL) {
2802 		retval = IBT_HCA_PORT_NOT_ACTIVE;
2803 		goto get_alt_path_done;
2804 	}
2805 
2806 	/* Contact SA Access to retrieve Path Records. */
2807 	access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
2808 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
2809 	access_args.sq_component_mask = c_mask;
2810 	access_args.sq_template = mpr_req;
2811 	access_args.sq_template_length = sizeof (sa_multipath_record_t);
2812 	access_args.sq_callback = NULL;
2813 	access_args.sq_callback_arg = NULL;
2814 
2815 	retval = ibcm_contact_sa_access(saa_handle, &access_args, &length,
2816 	    &results_p);
2817 	if (retval != IBT_SUCCESS) {
2818 		goto get_alt_path_done;
2819 	}
2820 
2821 	num_rec = length / sizeof (sa_path_record_t);
2822 
2823 	kmem_free(mpr_req, template_len);
2824 
2825 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Found %d Paths", num_rec);
2826 
2827 	rec_found = 0;
2828 	if ((results_p != NULL) && (num_rec > 0)) {
2829 		/* Update the PathInfo with the response Path Records */
2830 		pr_resp = (sa_path_record_t *)results_p;
2831 		for (i = 0; i < num_rec; i++, pr_resp++) {
2832 			if (prim_mtu > pr_resp->Mtu) {
2833 				IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2834 				    "Alt PathMTU(%d) must be GT or EQU to Pri "
2835 				    "PathMTU(%d). Ignore this rec",
2836 				    pr_resp->Mtu, prim_mtu);
2837 				continue;
2838 			}
2839 
2840 			if ((new_sgid.gid_guid == 0) &&
2841 			    (new_dgid.gid_guid == 0)) {
2842 				/* Reject PathRec if it same as Primary Path. */
2843 				if (ibcm_compare_paths(pr_resp,
2844 				    &qp_attr.qp_info.qp_transport.rc.rc_path,
2845 				    &c_hp) == B_TRUE) {
2846 					IBTF_DPRINTF_L3(cmlog,
2847 					    "ibt_get_alt_path: PathRec obtained"
2848 					    " is similar to Prim Path, ignore "
2849 					    "this record");
2850 					continue;
2851 				}
2852 			}
2853 
2854 			if (new_sgid.gid_guid == 0) {
2855 				retval = ibcm_update_cep_info(pr_resp, NULL,
2856 				    &c_hp, &api_p->ap_alt_cep_path);
2857 			} else {
2858 				retval = ibcm_update_cep_info(pr_resp, NULL,
2859 				    &n_hp, &api_p->ap_alt_cep_path);
2860 			}
2861 			if (retval != IBT_SUCCESS)
2862 				continue;
2863 
2864 			/* Update some leftovers */
2865 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*api_p))
2866 
2867 			api_p->ap_alt_pkt_lt = pr_resp->PacketLifeTime;
2868 
2869 			_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*api_p))
2870 
2871 			rec_found = 1;
2872 			break;
2873 		}
2874 		kmem_free(results_p, length);
2875 	}
2876 
2877 	if (rec_found == 0) {
2878 		IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Alternate Path cannot"
2879 		    " be established");
2880 		retval = IBT_PATH_RECORDS_NOT_FOUND;
2881 	} else
2882 		retval = IBT_SUCCESS;
2883 
2884 get_alt_path_done:
2885 	if ((snum) && (sgids_p))
2886 		kmem_free(sgids_p, snum * sizeof (ib_gid_t));
2887 
2888 	if ((dnum) && (dgids_p))
2889 		kmem_free(dgids_p, dnum * sizeof (ib_gid_t));
2890 
2891 	ibcm_dec_hca_acc_cnt(hcap);
2892 
2893 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Done (status %d).", retval);
2894 
2895 	return (retval);
2896 }
2897 
2898 
2899 /* Routines for warlock */
2900 
2901 /* ARGSUSED */
2902 static void
2903 ibcm_dummy_path_handler(void *arg, ibt_status_t retval, ibt_path_info_t *paths,
2904     uint8_t num_path)
2905 {
2906 	ibcm_path_tqargs_t	dummy_path;
2907 
2908 	dummy_path.func = ibcm_dummy_path_handler;
2909 
2910 	IBTF_DPRINTF_L5(cmlog, "ibcm_dummy_path_handler: "
2911 	    "dummy_path.func %p", dummy_path.func);
2912 }
2913