xref: /illumos-gate/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_path.c (revision a1e3386ed23bbb4894435257b2006a5f8edcc9ea)
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 	switch (prec_resp->Rate) {
2135 	case IBT_SRATE_1X:
2136 	case IBT_SRATE_4X:
2137 	case IBT_SRATE_12X:
2138 		cep_p->cep_adds_vect.av_srate = prec_resp->Rate;
2139 		break;
2140 	default:
2141 		IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: SRate (%d) from "
2142 		    "pathrecord is invalid, reject it.", prec_resp->Rate);
2143 		return (ibt_get_module_failure(IBT_FAILURE_IBSM, 0));
2144 	}
2145 	/*
2146 	 * If both Source and Destination GID prefix are same, then GRH is not
2147 	 * valid, so make it as false, else set this field as true.
2148 	 */
2149 	if (prec_resp->SGID.gid_prefix == prec_resp->DGID.gid_prefix)
2150 		cep_p->cep_adds_vect.av_send_grh = B_FALSE;
2151 	else
2152 		cep_p->cep_adds_vect.av_send_grh = B_TRUE;
2153 
2154 	/* SGID and SGID Index. */
2155 	cep_p->cep_adds_vect.av_sgid = prec_resp->SGID;
2156 	cep_p->cep_adds_vect.av_flow = prec_resp->FlowLabel;
2157 	cep_p->cep_adds_vect.av_tclass = prec_resp->TClass;
2158 	cep_p->cep_adds_vect.av_hop = prec_resp->HopLimit;
2159 
2160 	/* Address Vector Definition. */
2161 	cep_p->cep_adds_vect.av_dlid = prec_resp->DLID;
2162 	cep_p->cep_adds_vect.av_srvl = prec_resp->SL;
2163 
2164 	/* DGID */
2165 	cep_p->cep_adds_vect.av_dgid = prec_resp->DGID;
2166 
2167 	/* CEP Timeout is NOT filled in by PATH routines. */
2168 	cep_p->cep_timeout = 0;
2169 
2170 	IBTF_DPRINTF_L3(cmlog, "ibcm_update_cep_info: Done.  Port[%d]\n"
2171 	    "SGID=%llX:%llX DGID=%llX:%llX",
2172 	    cep_p->cep_adds_vect.av_port_num,
2173 	    prec_resp->SGID.gid_prefix, prec_resp->SGID.gid_guid,
2174 	    prec_resp->DGID.gid_prefix, prec_resp->DGID.gid_guid);
2175 
2176 	return (IBT_SUCCESS);
2177 }
2178 
2179 
2180 static void
2181 ibcm_fill_svcinfo(sa_service_record_t *sr_resp, ibcm_dest_t *dest)
2182 {
2183 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dest))
2184 
2185 	dest->d_gid = sr_resp->ServiceGID;
2186 	dest->d_sid = sr_resp->ServiceID;
2187 	ibcm_swizzle_to_srv(sr_resp->ServiceData, &dest->d_sdata);
2188 	dest->d_pkey = sr_resp->ServiceP_Key;
2189 
2190 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*dest))
2191 
2192 	IBTF_DPRINTF_L3(cmlog, "ibcm_fill_svcinfo: SID(%llX), GID(%llX:%llX)"
2193 	    "\n\tSvcPKey 0x%X", dest->d_sid, dest->d_gid.gid_prefix,
2194 	    dest->d_gid.gid_guid, dest->d_pkey);
2195 }
2196 
2197 
2198 static ib_gid_t
2199 ibcm_saa_get_agid(ibtl_cm_port_list_t *sl, ib_gid_t *gidp, uint_t ngid)
2200 {
2201 	int		k, l;
2202 	ib_gid_t	a_gid;
2203 
2204 	a_gid.gid_prefix = a_gid.gid_guid = 0;
2205 
2206 	for (k = 0; k < sl->p_count; k++) {
2207 		for (l = 0; l < ngid; l++) {
2208 
2209 			if (gidp->gid_prefix == sl->p_sgid.gid_prefix) {
2210 				a_gid = *gidp;
2211 				break;
2212 			}
2213 			if (a_gid.gid_guid && a_gid.gid_prefix)
2214 				break;
2215 			gidp++;
2216 		}
2217 		if (a_gid.gid_guid && a_gid.gid_prefix)
2218 			break;
2219 		sl++;
2220 	}
2221 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_get_agid: AltGID = %llX:%llX",
2222 	    a_gid.gid_prefix, a_gid.gid_guid);
2223 
2224 	return (a_gid);
2225 }
2226 
2227 /*
2228  * Perform SA Access to retrieve Service Records.
2229  * On Success, returns ServiceID and ServiceGID info in '*dinfo'.
2230  */
2231 static ibt_status_t
2232 ibcm_saa_service_rec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
2233     ibcm_dinfo_t *dinfo)
2234 {
2235 	sa_service_record_t	svcrec_req;
2236 	sa_service_record_t	*svcrec_resp;
2237 	void			*results_p;
2238 	uint64_t		component_mask = 0;
2239 	size_t			length;
2240 	uint8_t			i, j, k, rec_found, s;
2241 	ibmf_saa_access_args_t	access_args;
2242 	ibt_status_t		retval;
2243 	ibt_path_attr_t		*attrp = &p_arg->attr;
2244 	uint64_t		tmp_sd_flag = attrp->pa_sd_flags;
2245 	uint8_t			num_req;
2246 
2247 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec(%p, %p)", p_arg, sl);
2248 
2249 	bzero(&svcrec_req, sizeof (svcrec_req));
2250 
2251 	/* Service Name */
2252 	if ((attrp->pa_sname != NULL) && (strlen(attrp->pa_sname) != 0)) {
2253 		(void) strncpy((char *)(svcrec_req.ServiceName),
2254 		    attrp->pa_sname, IB_SVC_NAME_LEN);
2255 
2256 		component_mask |= SA_SR_COMPMASK_NAME;
2257 	}
2258 
2259 	/* Service ID */
2260 	if (attrp->pa_sid) {
2261 		svcrec_req.ServiceID = attrp->pa_sid;
2262 		component_mask |= SA_SR_COMPMASK_ID;
2263 	}
2264 
2265 	/* Is P_Key Specified. */
2266 	if (p_arg->flags & IBT_PATH_PKEY) {
2267 		svcrec_req.ServiceP_Key = attrp->pa_pkey;
2268 		component_mask |= SA_SR_COMPMASK_PKEY;
2269 	}
2270 
2271 	/* Is ServiceData Specified. */
2272 	if (attrp->pa_sd_flags != IBT_NO_SDATA) {
2273 		/* Handle endianess for service data. */
2274 		ibcm_swizzle_from_srv(&attrp->pa_sdata, svcrec_req.ServiceData);
2275 
2276 		/*
2277 		 * Lets not interpret each and every ServiceData flags,
2278 		 * just pass it on to SAA. Shift the flag, to suit
2279 		 * SA_SR_COMPMASK_ALL_DATA definition.
2280 		 */
2281 		component_mask |= (tmp_sd_flag << 7);
2282 	}
2283 
2284 	if (dinfo->num_dest == 1) {
2285 
2286 		/* If a single DGID is specified, provide it */
2287 		svcrec_req.ServiceGID = dinfo->dest->d_gid;
2288 		component_mask |= SA_SR_COMPMASK_GID;
2289 
2290 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec:%llX:%llX",
2291 		    svcrec_req.ServiceGID.gid_prefix,
2292 		    svcrec_req.ServiceGID.gid_guid);
2293 	}
2294 
2295 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2296 	    "Perform SA Access: Mask: 0x%X", component_mask);
2297 
2298 	/*
2299 	 * Call in SA Access retrieve routine to get Service Records.
2300 	 *
2301 	 * SA Access framework allocated memory for the "results_p".
2302 	 * Make sure to deallocate once we are done with the results_p.
2303 	 * The size of the buffer allocated will be as returned in
2304 	 * "length" field.
2305 	 */
2306 	access_args.sq_attr_id = SA_SERVICERECORD_ATTRID;
2307 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
2308 	access_args.sq_component_mask = component_mask;
2309 	access_args.sq_template = &svcrec_req;
2310 	access_args.sq_template_length = sizeof (sa_service_record_t);
2311 	access_args.sq_callback = NULL;
2312 	access_args.sq_callback_arg = NULL;
2313 
2314 	for (s = 0; s < sl->p_count; s++) {
2315 		retval = ibcm_contact_sa_access(sl[s].p_saa_hdl, &access_args,
2316 		    &length, &results_p);
2317 		if (retval != IBT_SUCCESS)
2318 			if (sl[s].p_multi & IBTL_CM_MULTI_SM)
2319 				continue;
2320 			else
2321 				return (retval);
2322 
2323 		if ((results_p == NULL) || (length == 0)) {
2324 			IBTF_DPRINTF_L2(cmlog, "ibcm_saa_service_rec: SvcRec "
2325 			    "Not Found: res_p %p, len %d", results_p, length);
2326 			if (sl[s].p_multi & IBTL_CM_MULTI_SM) {
2327 				retval = IBT_SERVICE_RECORDS_NOT_FOUND;
2328 				continue;
2329 			} else
2330 				return (IBT_SERVICE_RECORDS_NOT_FOUND);
2331 		}
2332 
2333 		/* if we are here, we got some records. so break. */
2334 		break;
2335 	}
2336 
2337 	if (retval != IBT_SUCCESS)
2338 		return (retval);
2339 
2340 	num_req = length / sizeof (sa_service_record_t);
2341 
2342 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Got %d Service Records.",
2343 	    num_req);
2344 
2345 	svcrec_resp = (sa_service_record_t *)results_p;
2346 	rec_found = 0;
2347 
2348 	/* Update the return values. */
2349 	if (dinfo->num_dest) {
2350 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Get ServiceRec "
2351 		    "for Specified DGID: %d", dinfo->num_dest);
2352 
2353 		for (i = 0; i < num_req; i++, svcrec_resp++) {
2354 			/* Limited P_Key is NOT supported as of now!. */
2355 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2356 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2357 				    "SvcPkey 0x%X limited, reject the record.",
2358 				    svcrec_resp->ServiceP_Key);
2359 				continue;
2360 			}
2361 
2362 			for (j = 0; j < dinfo->num_dest; j++) {
2363 				if (dinfo->dest[j].d_gid.gid_guid ==
2364 				    svcrec_resp->ServiceGID.gid_guid) {
2365 					ibcm_fill_svcinfo(svcrec_resp,
2366 					    &dinfo->dest[j]);
2367 					rec_found++;
2368 				}
2369 				if (rec_found == dinfo->num_dest)
2370 					break;
2371 			}
2372 			if (rec_found == dinfo->num_dest)
2373 				break;
2374 		}
2375 		if (rec_found != dinfo->num_dest) {
2376 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Did NOT "
2377 			    "find ServiceRec for all DGIDs: (%d/%d)", rec_found,
2378 			    dinfo->num_dest);
2379 			retval = IBT_INSUFF_DATA;
2380 		}
2381 	} else if (p_arg->flags & IBT_PATH_APM) {
2382 		ib_gid_t		p_gid, a_gid, last_p_gid;
2383 		ib_gid_t		*gidp = NULL;
2384 		uint_t			n_gids;
2385 		sa_service_record_t	*stmp;
2386 		boolean_t		pri_fill_done = B_FALSE;
2387 		boolean_t		alt_fill_done = B_FALSE;
2388 		ib_pkey_t		p_pkey = 0, a_pkey = 0;
2389 
2390 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Need to "
2391 		    "find ServiceRec that can satisfy APM");
2392 
2393 		p_gid.gid_prefix = p_gid.gid_guid = 0;
2394 		a_gid.gid_prefix = a_gid.gid_guid = 0;
2395 		last_p_gid.gid_prefix = last_p_gid.gid_guid = 0;
2396 
2397 		for (i = 0; i < num_req; i++, svcrec_resp++) {
2398 			ibt_status_t	ret;
2399 			boolean_t	is_this_on_local_node = B_FALSE;
2400 
2401 			/* Limited P_Key is NOT supported as of now!. */
2402 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2403 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2404 				    "SvcPkey 0x%X limited, reject the record.",
2405 				    svcrec_resp->ServiceP_Key);
2406 				continue;
2407 			}
2408 
2409 			p_gid = svcrec_resp->ServiceGID;
2410 
2411 			/* Let's avoid LoopBack Nodes. */
2412 			for (j = 0; j < sl->p_count; j++) {
2413 				if (p_gid.gid_guid == sl[j].p_sgid.gid_guid) {
2414 					is_this_on_local_node = B_TRUE;
2415 
2416 					IBTF_DPRINTF_L3(cmlog,
2417 					    "ibcm_saa_service_rec: ServiceGID "
2418 					    "%llX:%llX is on Local Node, "
2419 					    "search for remote.",
2420 					    p_gid.gid_prefix, p_gid.gid_guid);
2421 				}
2422 			}
2423 
2424 			if (is_this_on_local_node == B_TRUE) {
2425 				if ((i + 1) < num_req) {
2426 					p_gid.gid_prefix = 0;
2427 					p_gid.gid_guid = 0;
2428 					continue;
2429 				} else if (last_p_gid.gid_prefix != 0) {
2430 					p_gid = last_p_gid;
2431 					break;
2432 				}
2433 			}
2434 
2435 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2436 			    "Finally let Primary DGID = %llX:%llX",
2437 			    p_gid.gid_prefix, p_gid.gid_guid);
2438 
2439 			ret = ibt_get_companion_port_gids(p_gid, 0, 0,
2440 			    &gidp, &n_gids);
2441 			if (ret == IBT_SUCCESS) {
2442 				IBTF_DPRINTF_L3(cmlog,
2443 				    "ibcm_saa_service_rec: Found %d "
2444 				    "CompGID for %llX:%llX", n_gids,
2445 				    p_gid.gid_prefix, p_gid.gid_guid);
2446 
2447 				stmp = (sa_service_record_t *)results_p;
2448 				a_gid.gid_prefix = a_gid.gid_guid = 0;
2449 
2450 				if (sl->p_multi & IBTL_CM_MULTI_SM) {
2451 					/* validate sn_pfx */
2452 					a_gid = ibcm_saa_get_agid(sl,
2453 					    gidp, n_gids);
2454 				} else {
2455 					for (k = 0; k < num_req; k++) {
2456 						ib_gid_t sg = stmp->ServiceGID;
2457 
2458 						IBTF_DPRINTF_L3(cmlog,
2459 						    "ibcm_saa_service_rec: "
2460 						    "SvcGID[%d] = %llX:%llX", k,
2461 						    sg.gid_prefix, sg.gid_guid);
2462 
2463 						for (j = 0; j < n_gids; j++) {
2464 							if (gidp[j].gid_guid ==
2465 							    sg.gid_guid) {
2466 								a_gid = gidp[j];
2467 								break;
2468 							}
2469 						}
2470 						if (a_gid.gid_guid)
2471 							break;
2472 						stmp++;
2473 					}
2474 					if (a_gid.gid_guid == 0) {
2475 						/* Rec not found for Alt. */
2476 						for (j = 0; j < n_gids; j++) {
2477 							if (gidp[j].gid_prefix
2478 							== p_gid.gid_prefix) {
2479 								a_gid = gidp[j];
2480 								break;
2481 							}
2482 						}
2483 					}
2484 				}
2485 				kmem_free(gidp,
2486 				    n_gids * sizeof (ib_gid_t));
2487 
2488 				if (a_gid.gid_guid)
2489 					break;
2490 			} else if (ret == IBT_GIDS_NOT_FOUND) {
2491 				last_p_gid = p_gid;
2492 				IBTF_DPRINTF_L3(cmlog,
2493 				    "ibcm_saa_service_rec: Didn't find "
2494 				    "CompGID for %llX:%llX, ret=%d",
2495 				    p_gid.gid_prefix, p_gid.gid_guid,
2496 				    ret);
2497 			} else {
2498 				IBTF_DPRINTF_L3(cmlog,
2499 				    "ibcm_saa_service_rec: Call to "
2500 				    "ibt_get_companion_port_gids(%llX:"
2501 				    "%llX) Failed = %d",
2502 				    p_gid.gid_prefix, p_gid.gid_guid,
2503 				    ret);
2504 			}
2505 		}
2506 
2507 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: \n\t"
2508 		    "Pri DGID(%llX:%llX), Alt DGID(%llX:%llX)",
2509 		    p_gid.gid_prefix, p_gid.gid_guid, a_gid.gid_prefix,
2510 		    a_gid.gid_guid);
2511 
2512 		svcrec_resp = (sa_service_record_t *)results_p;
2513 
2514 		for (i = 0, j = 0; i < num_req; i++, svcrec_resp++) {
2515 			/* Limited P_Key is NOT supported as of now!. */
2516 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2517 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2518 				    "SvcPkey 0x%X limited, reject the record.",
2519 				    svcrec_resp->ServiceP_Key);
2520 				continue;
2521 			}
2522 
2523 			if ((pri_fill_done == B_FALSE) &&
2524 			    (p_gid.gid_guid ==
2525 			    svcrec_resp->ServiceGID.gid_guid)) {
2526 				p_pkey = svcrec_resp->ServiceP_Key;
2527 				if ((a_pkey != 0) &&
2528 				    (a_pkey != p_pkey)) {
2529 					IBTF_DPRINTF_L3(cmlog,
2530 					    "ibcm_saa_service_rec: "
2531 					    "Pri(0x%X) & Alt (0x%X) "
2532 					    "PKey must match.",
2533 					    p_pkey, a_pkey);
2534 					p_pkey = 0;
2535 					continue;
2536 				}
2537 				ibcm_fill_svcinfo(svcrec_resp,
2538 				    &dinfo->dest[j++]);
2539 				rec_found++;
2540 				pri_fill_done = B_TRUE;
2541 			} else if ((alt_fill_done == B_FALSE) &&
2542 			    (a_gid.gid_guid ==
2543 			    svcrec_resp->ServiceGID.gid_guid)) {
2544 				a_pkey = svcrec_resp->ServiceP_Key;
2545 				if ((p_pkey != 0) &&
2546 				    (a_pkey != p_pkey)) {
2547 					IBTF_DPRINTF_L3(cmlog,
2548 					    "ibcm_saa_service_rec: "
2549 					    "Pri(0x%X) & Alt (0x%X) "
2550 					    "PKey must match.",
2551 					    p_pkey, a_pkey);
2552 					a_pkey = 0;
2553 					continue;
2554 				}
2555 				ibcm_fill_svcinfo(svcrec_resp,
2556 				    &dinfo->dest[j++]);
2557 				rec_found++;
2558 				alt_fill_done = B_TRUE;
2559 			}
2560 
2561 			if (rec_found == 2)
2562 				break;
2563 		}
2564 		if ((alt_fill_done == B_FALSE) && (a_gid.gid_guid)) {
2565 			dinfo->dest[j].d_gid = a_gid;
2566 			dinfo->dest[j].d_pkey = p_pkey;
2567 			rec_found++;
2568 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2569 			    "Let Alt Pkey=%X, DGID=%llX:%llX", p_pkey,
2570 			    a_gid.gid_prefix, a_gid.gid_guid);
2571 		}
2572 
2573 		if (rec_found == 1)
2574 			retval = IBT_INSUFF_DATA;
2575 	} else if (p_arg->flags & IBT_PATH_MULTI_SVC_DEST) {
2576 		for (i = 0; i < num_req; i++, svcrec_resp++) {
2577 			ib_gid_t	p_gid;
2578 			boolean_t	is_this_on_local_node = B_FALSE;
2579 
2580 			/* Limited P_Key is NOT supported as of now!. */
2581 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2582 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2583 				    "SvcPkey 0x%X limited, reject the record.",
2584 				    svcrec_resp->ServiceP_Key);
2585 				continue;
2586 			}
2587 
2588 			p_gid = svcrec_resp->ServiceGID;
2589 
2590 			/* Let's avoid LoopBack Nodes. */
2591 			for (j = 0; j < sl->p_count; j++) {
2592 				if (p_gid.gid_guid == sl[j].p_sgid.gid_guid) {
2593 					is_this_on_local_node = B_TRUE;
2594 					IBTF_DPRINTF_L3(cmlog,
2595 					    "ibcm_saa_service_rec: ServiceGID "
2596 					    "%llX:%llX is on Local Node, "
2597 					    "search for remote.",
2598 					    p_gid.gid_prefix, p_gid.gid_guid);
2599 				}
2600 			}
2601 
2602 			if (is_this_on_local_node == B_TRUE)
2603 				if ((i + 1) < num_req)
2604 					continue;
2605 
2606 			IBTF_DPRINTF_L4(cmlog, "ibcm_saa_service_rec: "
2607 			    "Found ServiceGID = %llX:%llX",
2608 			    p_gid.gid_prefix, p_gid.gid_guid);
2609 
2610 			ibcm_fill_svcinfo(svcrec_resp,
2611 			    &dinfo->dest[rec_found]);
2612 			rec_found++;
2613 			if (rec_found == p_arg->max_paths)
2614 				break;
2615 		}
2616 
2617 		if (rec_found < p_arg->max_paths)
2618 			retval = IBT_INSUFF_DATA;
2619 	} else {
2620 		for (i = 0; i < num_req; i++) {
2621 			/* Limited P_Key is NOT supported as of now!. */
2622 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2623 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2624 				    "SvcPkey 0x%X limited, reject the record.",
2625 				    svcrec_resp->ServiceP_Key);
2626 				svcrec_resp++;
2627 				continue;
2628 			}
2629 
2630 			ibcm_fill_svcinfo(svcrec_resp, &dinfo->dest[0]);
2631 			rec_found = 1;
2632 
2633 			/* Avoid having loopback node */
2634 			if (svcrec_resp->ServiceGID.gid_guid !=
2635 			    sl->p_sgid.gid_guid) {
2636 				break;
2637 			} else {
2638 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2639 				    "avoid LoopBack node.");
2640 				svcrec_resp++;
2641 			}
2642 		}
2643 	}
2644 
2645 	/* Deallocate the memory for results_p. */
2646 	kmem_free(results_p, length);
2647 	if (dinfo->num_dest == 0)
2648 		dinfo->num_dest = rec_found;
2649 
2650 	/*
2651 	 * Check out whether all Service Path we looking for are on the same
2652 	 * P_key. If yes, then set the global p_key field with that value,
2653 	 * to make it easy during SA Path Query.
2654 	 */
2655 	if ((dinfo->num_dest) && (dinfo->p_key == 0)) {
2656 		ib_pkey_t	pk = dinfo->dest[0].d_pkey;
2657 
2658 		if (dinfo->num_dest == 1) {
2659 			dinfo->p_key = pk;
2660 		} else {
2661 			for (i = 1; i < (dinfo->num_dest - 1); i++) {
2662 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2663 				    "pk= 0x%X, pk[%d]= 0x%X", pk, i,
2664 				    dinfo->dest[i].d_pkey);
2665 				if (pk != dinfo->dest[i].d_pkey) {
2666 					dinfo->p_key = 0;
2667 					break;
2668 				} else {
2669 					dinfo->p_key = pk;
2670 				}
2671 			}
2672 		}
2673 	}
2674 
2675 	if (rec_found == 0) {
2676 		IBTF_DPRINTF_L2(cmlog, "ibcm_saa_service_rec: "
2677 		    "ServiceRec NOT Found");
2678 		retval = IBT_SERVICE_RECORDS_NOT_FOUND;
2679 	}
2680 
2681 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: done. Status %d, "
2682 	    "PKey 0x%X, Found %d SvcRec", retval, dinfo->p_key, rec_found);
2683 
2684 	return (retval);
2685 }
2686 
2687 
2688 static boolean_t
2689 ibcm_compare_paths(sa_path_record_t *pr_resp, ibt_cep_path_t *rc_path,
2690     ibtl_cm_hca_port_t *c_hp)
2691 {
2692 	if ((rc_path->cep_hca_port_num == c_hp->hp_port) &&
2693 	    (rc_path->cep_adds_vect.av_src_path ==
2694 	    (pr_resp->SLID - c_hp->hp_base_lid)) &&
2695 	    (rc_path->cep_adds_vect.av_dlid == pr_resp->DLID) &&
2696 	    (rc_path->cep_adds_vect.av_srate == pr_resp->Rate)) {
2697 		return (B_TRUE);
2698 	} else {
2699 		return (B_FALSE);
2700 	}
2701 }
2702 
2703 /*
2704  * ibcm_get_comp_pgids() routine gets the companion port for 'gid'.
2705  *
2706  * On success:
2707  *	If 'n_gid' is specified, then verify whether 'n_gid' is indeed a
2708  *	companion portgid of 'gid'.  If matches return success or else error.
2709  *
2710  *	If 'n_gid' is NOT specified, then return back SUCCESS along with
2711  *	obtained Companion PortGids 'gid_p', where 'num' indicated number
2712  *	of companion portgids returned in 'gid_p'.
2713  */
2714 
2715 static ibt_status_t
2716 ibcm_get_comp_pgids(ib_gid_t gid, ib_gid_t n_gid, ib_guid_t hca_guid,
2717     ib_gid_t **gid_p, uint_t *num)
2718 {
2719 	ibt_status_t    ret;
2720 	int		i;
2721 
2722 	ret = ibt_get_companion_port_gids(gid, hca_guid, 0, gid_p, num);
2723 	if ((ret != IBT_SUCCESS) && (ret != IBT_GIDS_NOT_FOUND)) {
2724 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: "
2725 		    "ibt_get_companion_port_gids(%llX:%llX) Failed: %d",
2726 		    gid.gid_prefix, gid.gid_guid, ret);
2727 	} else if ((ret == IBT_GIDS_NOT_FOUND) && (n_gid.gid_guid != 0)) {
2728 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: Specified GID "
2729 		    "(%llX:%llX) is NOT a Companion \n\t to current channel's "
2730 		    "GID(%llX:%llX)", n_gid.gid_prefix, n_gid.gid_guid,
2731 		    gid.gid_prefix, gid.gid_guid);
2732 		ret = IBT_INVALID_PARAM;
2733 	} else if (n_gid.gid_guid != 0) {
2734 		/*
2735 		 * We found some Comp GIDs and n_gid is specified. Validate
2736 		 * whether the 'n_gid' specified is indeed the companion port
2737 		 * GID of 'gid'.
2738 		 */
2739 		for (i = 0; i < *num; i++) {
2740 			if ((n_gid.gid_prefix == gid_p[i]->gid_prefix) &&
2741 			    (n_gid.gid_guid == gid_p[i]->gid_guid)) {
2742 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_comp_pgids: "
2743 				    "Matching Found!. Done.");
2744 				return (IBT_SUCCESS);
2745 			}
2746 		}
2747 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: GID (%llX:%llX)\n"
2748 		    "\t and (%llX:%llX) are NOT Companion Port GIDS",
2749 		    n_gid.gid_prefix, n_gid.gid_guid, gid.gid_prefix,
2750 		    gid.gid_guid);
2751 		ret = IBT_INVALID_PARAM;
2752 	} else {
2753 		ret = IBT_SUCCESS;
2754 	}
2755 
2756 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_comp_pgids: done. Status = %d", ret);
2757 	return (ret);
2758 }
2759 
2760 /*
2761  * Function:
2762  *	ibt_get_alt_path
2763  * Input:
2764  *	rc_chan		An RC channel handle returned in a previous call
2765  *			ibt_alloc_rc_channel(9F), specifies the channel to open.
2766  *	flags		Path flags.
2767  *	attrp		A pointer to an ibt_alt_path_attr_t(9S) structure that
2768  *			specifies required attributes of the selected path(s).
2769  * Output:
2770  *	api_p		An ibt_alt_path_info_t(9S) struct filled in as output
2771  *			parameters.
2772  * Returns:
2773  *	IBT_SUCCESS on Success else appropriate error.
2774  * Description:
2775  *      Finds the best alternate path to a specified channel (as determined by
2776  *      the IBTL) that satisfies the requirements specified in an
2777  *      ibt_alt_path_attr_t struct.  The specified channel must have been
2778  *      previously opened successfully using ibt_open_rc_channel.
2779  *      This function also ensures that the service being accessed by the
2780  *      channel is available at the selected alternate port.
2781  *
2782  *      Note: The apa_dgid must be on the same destination channel adapter,
2783  *      if specified.
2784  *	This routine can not be called from interrupt context.
2785  */
2786 ibt_status_t
2787 ibt_get_alt_path(ibt_channel_hdl_t rc_chan, ibt_path_flags_t flags,
2788     ibt_alt_path_attr_t *attrp, ibt_alt_path_info_t *api_p)
2789 {
2790 	sa_multipath_record_t	*mpr_req;
2791 	sa_path_record_t	*pr_resp;
2792 	ibmf_saa_access_args_t	access_args;
2793 	ibt_qp_query_attr_t	qp_attr;
2794 	ibtl_cm_hca_port_t	c_hp, n_hp;
2795 	ibcm_hca_info_t		*hcap;
2796 	void			*results_p;
2797 	uint64_t		c_mask = 0;
2798 	ib_gid_t		*gid_ptr = NULL;
2799 	ib_gid_t		*sgids_p = NULL,  *dgids_p = NULL;
2800 	ib_gid_t		cur_dgid, cur_sgid;
2801 	ib_gid_t		new_dgid, new_sgid;
2802 	ibmf_saa_handle_t	saa_handle;
2803 	size_t			length;
2804 	int			i, j, template_len, rec_found;
2805 	uint_t			snum = 0, dnum = 0, num_rec;
2806 	ibt_status_t		retval;
2807 	ib_mtu_t		prim_mtu;
2808 
2809 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path(%p, %x, %p, %p)",
2810 	    rc_chan, flags, attrp, api_p);
2811 
2812 	/* validate channel */
2813 	if (IBCM_INVALID_CHANNEL(rc_chan)) {
2814 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: invalid channel");
2815 		return (IBT_CHAN_HDL_INVALID);
2816 	}
2817 
2818 	if (api_p == NULL) {
2819 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: invalid attribute: "
2820 		    " AltPathInfo can't be NULL");
2821 		return (IBT_INVALID_PARAM);
2822 	}
2823 
2824 	retval = ibt_query_qp(rc_chan, &qp_attr);
2825 	if (retval != IBT_SUCCESS) {
2826 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: ibt_query_qp(%p) "
2827 		    "failed %d", rc_chan, retval);
2828 		return (retval);
2829 	}
2830 
2831 	if (qp_attr.qp_info.qp_trans != IBT_RC_SRV) {
2832 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2833 		    "Invalid Channel type: Applicable only to RC Channel");
2834 		return (IBT_CHAN_SRV_TYPE_INVALID);
2835 	}
2836 
2837 	cur_dgid =
2838 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dgid;
2839 	cur_sgid =
2840 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_sgid;
2841 	prim_mtu = qp_attr.qp_info.qp_transport.rc.rc_path_mtu;
2842 
2843 	/* If optional attributes are specified, validate them. */
2844 	if (attrp) {
2845 		new_dgid = attrp->apa_dgid;
2846 		new_sgid = attrp->apa_sgid;
2847 	} else {
2848 		new_dgid.gid_prefix = 0;
2849 		new_dgid.gid_guid = 0;
2850 		new_sgid.gid_prefix = 0;
2851 		new_sgid.gid_guid = 0;
2852 	}
2853 
2854 	if ((new_dgid.gid_prefix != 0) && (new_sgid.gid_prefix != 0) &&
2855 	    (new_dgid.gid_prefix != new_sgid.gid_prefix)) {
2856 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: Specified SGID's "
2857 		    "SNprefix (%llX) doesn't match with \n specified DGID's "
2858 		    "SNprefix: %llX", new_sgid.gid_prefix, new_dgid.gid_prefix);
2859 		return (IBT_INVALID_PARAM);
2860 	}
2861 
2862 	/* For the specified SGID, get HCA information. */
2863 	retval = ibtl_cm_get_hca_port(cur_sgid, 0, &c_hp);
2864 	if (retval != IBT_SUCCESS) {
2865 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2866 		    "Get HCA Port Failed: %d", retval);
2867 		return (retval);
2868 	}
2869 
2870 	hcap = ibcm_find_hca_entry(c_hp.hp_hca_guid);
2871 	if (hcap == NULL) {
2872 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: NO HCA found");
2873 		return (IBT_HCA_BUSY_DETACHING);
2874 	}
2875 
2876 	/* Validate whether this HCA support APM */
2877 	if (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG)) {
2878 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2879 		    "HCA (%llX) - APM NOT SUPPORTED ", c_hp.hp_hca_guid);
2880 		retval = IBT_APM_NOT_SUPPORTED;
2881 		goto get_alt_path_done;
2882 	}
2883 
2884 	/* Get Companion Port GID of the current Channel's SGID */
2885 	if ((new_sgid.gid_guid == 0) || ((new_sgid.gid_guid != 0) &&
2886 	    (new_sgid.gid_guid != cur_sgid.gid_guid))) {
2887 		IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: SRC: "
2888 		    "Get Companion PortGids for - %llX:%llX",
2889 		    cur_sgid.gid_prefix, cur_sgid.gid_guid);
2890 
2891 		retval = ibcm_get_comp_pgids(cur_sgid, new_sgid,
2892 		    c_hp.hp_hca_guid, &sgids_p, &snum);
2893 		if (retval != IBT_SUCCESS)
2894 			goto get_alt_path_done;
2895 	}
2896 
2897 	/* Get Companion Port GID of the current Channel's DGID */
2898 	if ((new_dgid.gid_guid == 0) || ((new_dgid.gid_guid != 0) &&
2899 	    (new_dgid.gid_guid != cur_dgid.gid_guid))) {
2900 
2901 		IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: DEST: "
2902 		    "Get Companion PortGids for - %llX:%llX",
2903 		    cur_dgid.gid_prefix, cur_dgid.gid_guid);
2904 
2905 		retval = ibcm_get_comp_pgids(cur_dgid, new_dgid, 0, &dgids_p,
2906 		    &dnum);
2907 		if (retval != IBT_SUCCESS)
2908 			goto get_alt_path_done;
2909 	}
2910 
2911 	if ((new_dgid.gid_guid == 0) || (new_sgid.gid_guid == 0)) {
2912 		if (new_sgid.gid_guid == 0) {
2913 			for (i = 0; i < snum; i++) {
2914 				if (new_dgid.gid_guid == 0) {
2915 					for (j = 0; j < dnum; j++) {
2916 						if (sgids_p[i].gid_prefix ==
2917 						    dgids_p[j].gid_prefix) {
2918 							new_dgid = dgids_p[j];
2919 							new_sgid = sgids_p[i];
2920 
2921 							goto get_alt_proceed;
2922 						}
2923 					}
2924 					/*  Current DGID */
2925 					if (sgids_p[i].gid_prefix ==
2926 					    cur_dgid.gid_prefix) {
2927 						new_sgid = sgids_p[i];
2928 						goto get_alt_proceed;
2929 					}
2930 				} else {
2931 					if (sgids_p[i].gid_prefix ==
2932 					    new_dgid.gid_prefix) {
2933 						new_sgid = sgids_p[i];
2934 						goto get_alt_proceed;
2935 					}
2936 				}
2937 			}
2938 			/* Current SGID */
2939 			if (new_dgid.gid_guid == 0) {
2940 				for (j = 0; j < dnum; j++) {
2941 					if (cur_sgid.gid_prefix ==
2942 					    dgids_p[j].gid_prefix) {
2943 						new_dgid = dgids_p[j];
2944 
2945 						goto get_alt_proceed;
2946 					}
2947 				}
2948 			}
2949 		} else if (new_dgid.gid_guid == 0) {
2950 			for (i = 0; i < dnum; i++) {
2951 				if (dgids_p[i].gid_prefix ==
2952 				    new_sgid.gid_prefix) {
2953 					new_dgid = dgids_p[i];
2954 					goto get_alt_proceed;
2955 				}
2956 			}
2957 			/* Current DGID */
2958 			if (cur_dgid.gid_prefix == new_sgid.gid_prefix) {
2959 				goto get_alt_proceed;
2960 			}
2961 		}
2962 		/*
2963 		 * hmm... No Companion Ports available.
2964 		 * so we will be using current or specified attributes only.
2965 		 */
2966 	}
2967 
2968 get_alt_proceed:
2969 
2970 	if (new_sgid.gid_guid != 0) {
2971 		retval = ibtl_cm_get_hca_port(new_sgid, 0, &n_hp);
2972 		if (retval != IBT_SUCCESS) {
2973 			IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2974 			    "Get HCA Port Failed: %d", retval);
2975 			goto get_alt_path_done;
2976 		}
2977 	}
2978 
2979 	/* Calculate the size for multi-path records template */
2980 	template_len = (2 * sizeof (ib_gid_t)) + sizeof (sa_multipath_record_t);
2981 
2982 	mpr_req = kmem_zalloc(template_len, KM_SLEEP);
2983 
2984 	ASSERT(mpr_req != NULL);
2985 
2986 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
2987 
2988 	gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
2989 	    sizeof (sa_multipath_record_t));
2990 
2991 	/* SGID */
2992 	if (new_sgid.gid_guid == 0)
2993 		*gid_ptr = cur_sgid;
2994 	else
2995 		*gid_ptr = new_sgid;
2996 
2997 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Get Path Between "
2998 	    " SGID : %llX:%llX", gid_ptr->gid_prefix, gid_ptr->gid_guid);
2999 
3000 	gid_ptr++;
3001 
3002 	/* DGID */
3003 	if (new_dgid.gid_guid == 0)
3004 		*gid_ptr = cur_dgid;
3005 	else
3006 		*gid_ptr = new_dgid;
3007 
3008 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path:\t\t    DGID : %llX:%llX",
3009 	    gid_ptr->gid_prefix, gid_ptr->gid_guid);
3010 
3011 	mpr_req->SGIDCount = 1;
3012 	c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
3013 
3014 	mpr_req->DGIDCount = 1;
3015 	c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
3016 
3017 	/* Is Flow Label Specified. */
3018 	if (attrp) {
3019 		if (attrp->apa_flow) {
3020 			mpr_req->FlowLabel = attrp->apa_flow;
3021 			c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
3022 		}
3023 
3024 		/* Is HopLimit Specified. */
3025 		if (flags & IBT_PATH_HOP) {
3026 			mpr_req->HopLimit = attrp->apa_hop;
3027 			c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
3028 		}
3029 
3030 		/* Is TClass Specified. */
3031 		if (attrp->apa_tclass) {
3032 			mpr_req->TClass = attrp->apa_tclass;
3033 			c_mask |= SA_MPR_COMPMASK_TCLASS;
3034 		}
3035 
3036 		/* Is SL specified. */
3037 		if (attrp->apa_sl) {
3038 			mpr_req->SL = attrp->apa_sl;
3039 			c_mask |= SA_MPR_COMPMASK_SL;
3040 		}
3041 
3042 		if (flags & IBT_PATH_PERF) {
3043 			mpr_req->PacketLifeTimeSelector = IBT_BEST;
3044 			mpr_req->RateSelector = IBT_BEST;
3045 
3046 			c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
3047 			    SA_MPR_COMPMASK_RATESELECTOR;
3048 		} else {
3049 			if (attrp->apa_pkt_lt.p_selector == IBT_BEST) {
3050 				mpr_req->PacketLifeTimeSelector = IBT_BEST;
3051 				c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
3052 			}
3053 
3054 			if (attrp->apa_srate.r_selector == IBT_BEST) {
3055 				mpr_req->RateSelector = IBT_BEST;
3056 				c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
3057 			}
3058 		}
3059 
3060 		/*
3061 		 * Honor individual selection of these attributes,
3062 		 * even if IBT_PATH_PERF is set.
3063 		 */
3064 		/* Check out whether Packet Life Time is specified. */
3065 		if (attrp->apa_pkt_lt.p_pkt_lt) {
3066 			mpr_req->PacketLifeTime =
3067 			    ibt_usec2ib(attrp->apa_pkt_lt.p_pkt_lt);
3068 			mpr_req->PacketLifeTimeSelector =
3069 			    attrp->apa_pkt_lt.p_selector;
3070 
3071 			c_mask |= SA_MPR_COMPMASK_PKTLT |
3072 			    SA_MPR_COMPMASK_PKTLTSELECTOR;
3073 		}
3074 
3075 		/* Is SRATE specified. */
3076 		if (attrp->apa_srate.r_srate) {
3077 			mpr_req->Rate = attrp->apa_srate.r_srate;
3078 			mpr_req->RateSelector = attrp->apa_srate.r_selector;
3079 
3080 			c_mask |= SA_MPR_COMPMASK_RATE |
3081 			    SA_MPR_COMPMASK_RATESELECTOR;
3082 		}
3083 	}
3084 
3085 	/* Alt PathMTU can be GT or EQU to current channel's Pri PathMTU */
3086 
3087 	/* P_Key must be same as that of primary path */
3088 	retval = ibt_index2pkey_byguid(c_hp.hp_hca_guid, c_hp.hp_port,
3089 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix,
3090 	    &mpr_req->P_Key);
3091 	if (retval != IBT_SUCCESS) {
3092 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: Idx2Pkey Failed: %d",
3093 		    retval);
3094 		goto get_alt_path_done;
3095 	}
3096 	c_mask |= SA_MPR_COMPMASK_PKEY;
3097 
3098 	mpr_req->Reversible = 1;	/* We always get REVERSIBLE paths. */
3099 	mpr_req->IndependenceSelector = 1;
3100 	c_mask |= SA_MPR_COMPMASK_REVERSIBLE | SA_MPR_COMPMASK_INDEPSEL;
3101 
3102 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
3103 
3104 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: CMask: 0x%llX", c_mask);
3105 
3106 	/* NOTE: We will **NOT** specify how many records we want. */
3107 
3108 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Primary: MTU %d, PKey[%d]="
3109 	    "0x%X\n\tSGID = %llX:%llX, DGID = %llX:%llX", prim_mtu,
3110 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix, mpr_req->P_Key,
3111 	    cur_sgid.gid_prefix, cur_sgid.gid_guid, cur_dgid.gid_prefix,
3112 	    cur_dgid.gid_guid);
3113 
3114 	/* Get SA Access Handle. */
3115 	if (new_sgid.gid_guid != 0)
3116 		saa_handle = ibcm_get_saa_handle(hcap, n_hp.hp_port);
3117 	else
3118 		saa_handle = ibcm_get_saa_handle(hcap, c_hp.hp_port);
3119 	if (saa_handle == NULL) {
3120 		retval = IBT_HCA_PORT_NOT_ACTIVE;
3121 		goto get_alt_path_done;
3122 	}
3123 
3124 	/* Contact SA Access to retrieve Path Records. */
3125 	access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
3126 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
3127 	access_args.sq_component_mask = c_mask;
3128 	access_args.sq_template = mpr_req;
3129 	access_args.sq_template_length = sizeof (sa_multipath_record_t);
3130 	access_args.sq_callback = NULL;
3131 	access_args.sq_callback_arg = NULL;
3132 
3133 	retval = ibcm_contact_sa_access(saa_handle, &access_args, &length,
3134 	    &results_p);
3135 	if (retval != IBT_SUCCESS) {
3136 		goto get_alt_path_done;
3137 	}
3138 
3139 	num_rec = length / sizeof (sa_path_record_t);
3140 
3141 	kmem_free(mpr_req, template_len);
3142 
3143 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Found %d Paths", num_rec);
3144 
3145 	rec_found = 0;
3146 	if ((results_p != NULL) && (num_rec > 0)) {
3147 		/* Update the PathInfo with the response Path Records */
3148 		pr_resp = (sa_path_record_t *)results_p;
3149 		for (i = 0; i < num_rec; i++, pr_resp++) {
3150 			if (prim_mtu > pr_resp->Mtu) {
3151 				IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
3152 				    "Alt PathMTU(%d) must be GT or EQU to Pri "
3153 				    "PathMTU(%d). Ignore this rec",
3154 				    pr_resp->Mtu, prim_mtu);
3155 				continue;
3156 			}
3157 
3158 			if ((new_sgid.gid_guid == 0) &&
3159 			    (new_dgid.gid_guid == 0)) {
3160 				/* Reject PathRec if it same as Primary Path. */
3161 				if (ibcm_compare_paths(pr_resp,
3162 				    &qp_attr.qp_info.qp_transport.rc.rc_path,
3163 				    &c_hp) == B_TRUE) {
3164 					IBTF_DPRINTF_L3(cmlog,
3165 					    "ibt_get_alt_path: PathRec obtained"
3166 					    " is similar to Prim Path, ignore "
3167 					    "this record");
3168 					continue;
3169 				}
3170 			}
3171 
3172 			if (new_sgid.gid_guid == 0) {
3173 				retval = ibcm_update_cep_info(pr_resp, NULL,
3174 				    &c_hp, &api_p->ap_alt_cep_path);
3175 			} else {
3176 				retval = ibcm_update_cep_info(pr_resp, NULL,
3177 				    &n_hp, &api_p->ap_alt_cep_path);
3178 			}
3179 			if (retval != IBT_SUCCESS)
3180 				continue;
3181 
3182 			/* Update some leftovers */
3183 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*api_p))
3184 
3185 			api_p->ap_alt_pkt_lt = pr_resp->PacketLifeTime;
3186 
3187 			_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*api_p))
3188 
3189 			rec_found = 1;
3190 			break;
3191 		}
3192 		kmem_free(results_p, length);
3193 	}
3194 
3195 	if (rec_found == 0) {
3196 		IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Alternate Path cannot"
3197 		    " be established");
3198 		retval = IBT_PATH_RECORDS_NOT_FOUND;
3199 	} else
3200 		retval = IBT_SUCCESS;
3201 
3202 get_alt_path_done:
3203 	if ((snum) && (sgids_p))
3204 		kmem_free(sgids_p, snum * sizeof (ib_gid_t));
3205 
3206 	if ((dnum) && (dgids_p))
3207 		kmem_free(dgids_p, dnum * sizeof (ib_gid_t));
3208 
3209 	ibcm_dec_hca_acc_cnt(hcap);
3210 
3211 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Done (status %d).", retval);
3212 
3213 	return (retval);
3214 }
3215 
3216 
3217 /* Routines for warlock */
3218 
3219 /* ARGSUSED */
3220 static void
3221 ibcm_dummy_path_handler(void *arg, ibt_status_t retval, ibt_path_info_t *paths,
3222     uint8_t num_path)
3223 {
3224 	ibcm_path_tqargs_t	dummy_path;
3225 
3226 	dummy_path.func = ibcm_dummy_path_handler;
3227 
3228 	IBTF_DPRINTF_L5(cmlog, "ibcm_dummy_path_handler: "
3229 	    "dummy_path.func %p", dummy_path.func);
3230 }
3231