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