xref: /illumos-gate/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_path.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/ib/mgt/ibcm/ibcm_impl.h>
27 #include <sys/ib/mgt/ibcm/ibcm_arp.h>
28 
29 /*
30  * ibcm_path.c
31  *
32  * ibt_get_paths() implement the Path Informations related functionality.
33  */
34 
35 /* ibcm_saa_service_rec() fills in ServiceID and DGID. */
36 typedef struct ibcm_dest_s {
37 	ib_gid_t	d_gid;
38 	ib_svc_id_t	d_sid;
39 	ibt_srv_data_t	d_sdata;
40 	ib_pkey_t	d_pkey;
41 	uint_t		d_tag;	/* 0 = Unicast, 1 = Multicast */
42 } ibcm_dest_t;
43 
44 /* Holds Destination information needed to fill in ibt_path_info_t. */
45 typedef struct ibcm_dinfo_s {
46 	uint8_t		num_dest;
47 	ib_pkey_t	p_key;
48 	ibcm_dest_t	dest[1];
49 } ibcm_dinfo_t;
50 
51 _NOTE(SCHEME_PROTECTS_DATA("Temporary path storage", ibcm_dinfo_s))
52 _NOTE(READ_ONLY_DATA(ibt_path_attr_s))
53 
54 typedef struct ibcm_path_tqargs_s {
55 	ibt_path_attr_t		attr;
56 	ibt_path_info_t		*paths;
57 	uint8_t			*num_paths_p;
58 	ibt_path_handler_t	func;
59 	void			*arg;
60 	ibt_path_flags_t	flags;
61 	uint8_t			max_paths;
62 } ibcm_path_tqargs_t;
63 
64 
65 /* Prototype Declarations. */
66 static ibt_status_t ibcm_get_path_rec(ibcm_path_tqargs_t *, ibcm_dinfo_t *,
67     uint8_t *, ibt_path_info_t *);
68 
69 static ibt_status_t ibcm_saa_path_rec(ibcm_path_tqargs_t *,
70     ibtl_cm_port_list_t *, ibcm_dinfo_t *, uint8_t *);
71 
72 static ibt_status_t ibcm_update_cep_info(sa_path_record_t *,
73     ibtl_cm_port_list_t *, ibtl_cm_hca_port_t *, ibt_cep_path_t *);
74 
75 static ibt_status_t ibcm_saa_service_rec(ibcm_path_tqargs_t *,
76     ibtl_cm_port_list_t *, ibcm_dinfo_t *);
77 
78 static ibt_status_t ibcm_get_single_pathrec(ibcm_path_tqargs_t *,
79     ibtl_cm_port_list_t *, ibcm_dinfo_t *, uint8_t,
80     uint8_t *, ibt_path_info_t *);
81 
82 static ibt_status_t ibcm_get_multi_pathrec(ibcm_path_tqargs_t *,
83     ibtl_cm_port_list_t *, ibcm_dinfo_t *dinfo,
84     uint8_t *, ibt_path_info_t *);
85 
86 static ibt_status_t ibcm_validate_path_attributes(ibt_path_attr_t *attrp,
87     ibt_path_flags_t flags, uint8_t max_paths);
88 
89 static ibt_status_t ibcm_handle_get_path(ibt_path_attr_t *attrp,
90     ibt_path_flags_t flags, uint8_t max_paths, ibt_path_info_t *paths,
91     uint8_t *num_path_p, ibt_path_handler_t func, void  *arg);
92 
93 static void ibcm_process_async_get_paths(void *tq_arg);
94 
95 static ibt_status_t ibcm_process_get_paths(void *tq_arg);
96 
97 static ibt_status_t ibcm_get_comp_pgids(ib_gid_t, ib_gid_t, ib_guid_t,
98     ib_gid_t **, uint_t *);
99 
100 /*
101  * Function:
102  *	ibt_aget_paths
103  * Input:
104  *	ibt_hdl		The handle returned to the client by the IBTF from an
105  *			ibt_attach() call. Can be used by the IBTF Policy module
106  *			and CM in the determination of the "best" path to the
107  *			specified destination for this class of driver.
108  *	flags		Path flags.
109  *	attrp		Points to an ibt_path_attr_t struct that contains
110  *			required and optional attributes.
111  *	func		A pointer to an ibt_path_handler_t function to call
112  *			when ibt_aget_paths() completes.
113  *	arg		The argument to 'func'.
114  * Returns:
115  *	IBT_SUCCESS on early validation of attributes else appropriate error.
116  * Description:
117  *	Finds the best path to a specified destination or service
118  *	asynchronously (as determined by the IBTL) that satisfies the
119  *	requirements specified in an ibt_path_attr_t struct.
120  *	ibt_aget_paths() is a Non-Blocking version of ibt_get_paths().
121  */
122 ibt_status_t
123 ibt_aget_paths(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags,
124     ibt_path_attr_t *attrp, uint8_t max_paths, ibt_path_handler_t func,
125     void  *arg)
126 {
127 	IBTF_DPRINTF_L3(cmlog, "ibt_aget_paths(%p(%s), 0x%X, %p, %d, %p)",
128 	    ibt_hdl, ibtl_cm_get_clnt_name(ibt_hdl), flags, attrp, max_paths,
129 	    func);
130 
131 	if (func == NULL) {
132 		IBTF_DPRINTF_L2(cmlog, "ibt_aget_paths: Function Pointer is "
133 		    "NULL - ERROR ");
134 		return (IBT_INVALID_PARAM);
135 	}
136 
137 	/* Memory for path info will be allocated in ibcm_process_get_paths() */
138 	return (ibcm_handle_get_path(attrp, flags, max_paths, NULL, NULL,
139 	    func, arg));
140 }
141 
142 
143 /*
144  * ibt_get_paths() cache consists of one or more of:
145  *
146  *	ib_gid_t dgid (attrp->pa_dgids[0])
147  *	ibt_path_attr_t attr
148  *	ibt_path_flags_t flags
149  *	ibt_path_info_t path
150  *
151  * If the first 3 match, max_paths is 1, sname is NULL, and sid is 0,
152  * then the path is returned immediately.
153  *
154  * Note that a compare of "attr" is non-trivial.  Only accept ones
155  * that memcmp() succeeds, i.e., basically assume a bzero was done.
156  *
157  * Cache must be invalidated if PORT_DOWN event or GID_UNAVAIL occurs.
158  * Cache must be freed as part of _fini.
159  */
160 
161 #define	IBCM_PATH_CACHE_SIZE	16	/* keep small for linear search */
162 #define	IBCM_PATH_CACHE_TIMEOUT	60	/* purge cache after 60 seconds */
163 
164 typedef struct ibcm_path_cache_s {
165 	ib_gid_t		dgid;
166 	ibt_path_attr_t		attr;
167 	ibt_path_flags_t	flags;
168 	ibt_path_info_t		path;
169 } ibcm_path_cache_t;
170 
171 kmutex_t ibcm_path_cache_mutex;
172 int ibcm_path_cache_invalidate;	/* invalidate cache on next ibt_get_paths */
173 clock_t ibcm_path_cache_timeout = IBCM_PATH_CACHE_TIMEOUT; /* tunable */
174 timeout_id_t ibcm_path_cache_timeout_id;
175 int ibcm_path_cache_size_init = IBCM_PATH_CACHE_SIZE;	/* tunable */
176 int ibcm_path_cache_size;
177 ibcm_path_cache_t *ibcm_path_cachep;
178 
179 /* tunable, set to 1 to not allow link-local address */
180 int	ibcm_ip6_linklocal_addr_ok = 0;
181 
182 struct ibcm_path_cache_stat_s {
183 	int hits;
184 	int misses;
185 	int adds;
186 	int already_in_cache;
187 	int bad_path_for_cache;
188 	int purges;
189 	int timeouts;
190 } ibcm_path_cache_stats;
191 
192 /*ARGSUSED*/
193 static void
194 ibcm_path_cache_timeout_cb(void *arg)
195 {
196 	clock_t timeout_in_hz;
197 
198 	timeout_in_hz = drv_usectohz(ibcm_path_cache_timeout * 1000000);
199 	mutex_enter(&ibcm_path_cache_mutex);
200 	ibcm_path_cache_invalidate = 1;	/* invalidate cache on next check */
201 	if (ibcm_path_cache_timeout_id)
202 		ibcm_path_cache_timeout_id = timeout(ibcm_path_cache_timeout_cb,
203 		    NULL, timeout_in_hz);
204 	/* else we're in _fini */
205 	mutex_exit(&ibcm_path_cache_mutex);
206 }
207 
208 void
209 ibcm_path_cache_init(void)
210 {
211 	clock_t timeout_in_hz;
212 	int cache_size = ibcm_path_cache_size_init;
213 	ibcm_path_cache_t *path_cachep;
214 
215 	timeout_in_hz = drv_usectohz(ibcm_path_cache_timeout * 1000000);
216 	path_cachep = kmem_zalloc(cache_size * sizeof (*path_cachep), KM_SLEEP);
217 	mutex_init(&ibcm_path_cache_mutex, NULL, MUTEX_DEFAULT, NULL);
218 	mutex_enter(&ibcm_path_cache_mutex);
219 	ibcm_path_cache_size = cache_size;
220 	ibcm_path_cachep = path_cachep;
221 	ibcm_path_cache_timeout_id = timeout(ibcm_path_cache_timeout_cb,
222 	    NULL, timeout_in_hz);
223 	mutex_exit(&ibcm_path_cache_mutex);
224 }
225 
226 void
227 ibcm_path_cache_fini(void)
228 {
229 	timeout_id_t tmp_timeout_id;
230 	int cache_size;
231 	ibcm_path_cache_t *path_cachep;
232 
233 	mutex_enter(&ibcm_path_cache_mutex);
234 	if (ibcm_path_cache_timeout_id) {
235 		tmp_timeout_id = ibcm_path_cache_timeout_id;
236 		ibcm_path_cache_timeout_id = 0;	/* no more timeouts */
237 	}
238 	cache_size = ibcm_path_cache_size;
239 	path_cachep = ibcm_path_cachep;
240 	mutex_exit(&ibcm_path_cache_mutex);
241 	if (tmp_timeout_id)
242 		(void) untimeout(tmp_timeout_id);
243 	mutex_destroy(&ibcm_path_cache_mutex);
244 	kmem_free(path_cachep, cache_size * sizeof (*path_cachep));
245 }
246 
247 static ibcm_status_t
248 ibcm_path_cache_check(ibt_path_flags_t flags, ibt_path_attr_t *attrp,
249     uint8_t max_paths, ibt_path_info_t *path, uint8_t *num_paths_p)
250 {
251 	int i;
252 	ib_gid_t dgid;
253 	ibcm_path_cache_t *path_cachep;
254 
255 	if (max_paths != 1 || attrp->pa_num_dgids != 1 ||
256 	    attrp->pa_sname != NULL || attrp->pa_sid != 0) {
257 		mutex_enter(&ibcm_path_cache_mutex);
258 		ibcm_path_cache_stats.bad_path_for_cache++;
259 		mutex_exit(&ibcm_path_cache_mutex);
260 		return (IBCM_FAILURE);
261 	}
262 
263 	dgid = attrp->pa_dgids[0];
264 	if ((dgid.gid_guid | dgid.gid_prefix) == 0ULL)
265 		return (IBCM_FAILURE);
266 
267 	mutex_enter(&ibcm_path_cache_mutex);
268 	if (ibcm_path_cache_invalidate) {	/* invalidate all entries */
269 		ibcm_path_cache_stats.timeouts++;
270 		ibcm_path_cache_invalidate = 0;
271 		path_cachep = ibcm_path_cachep;
272 		for (i = 0; i < ibcm_path_cache_size; i++, path_cachep++) {
273 			path_cachep->dgid.gid_guid = 0ULL;
274 			path_cachep->dgid.gid_prefix = 0ULL;
275 		}
276 		mutex_exit(&ibcm_path_cache_mutex);
277 		return (IBCM_FAILURE);
278 	}
279 
280 	path_cachep = ibcm_path_cachep;
281 	for (i = 0; i < ibcm_path_cache_size; i++, path_cachep++) {
282 		if (path_cachep->dgid.gid_guid == 0ULL)
283 			break;	/* end of search, no more valid cache entries */
284 
285 		/* make pa_dgids pointers match, so we can use memcmp */
286 		path_cachep->attr.pa_dgids = attrp->pa_dgids;
287 		if (path_cachep->flags != flags ||
288 		    path_cachep->dgid.gid_guid != dgid.gid_guid ||
289 		    path_cachep->dgid.gid_prefix != dgid.gid_prefix ||
290 		    memcmp(&(path_cachep->attr), attrp, sizeof (*attrp)) != 0) {
291 			/* make pa_dgids NULL again */
292 			path_cachep->attr.pa_dgids = NULL;
293 			continue;
294 		}
295 		/* else we have a match */
296 		/* make pa_dgids NULL again */
297 		path_cachep->attr.pa_dgids = NULL;
298 		*path = path_cachep->path;	/* retval */
299 		if (num_paths_p)
300 			*num_paths_p = 1;	/* retval */
301 		ibcm_path_cache_stats.hits++;
302 		mutex_exit(&ibcm_path_cache_mutex);
303 		return (IBCM_SUCCESS);
304 	}
305 	ibcm_path_cache_stats.misses++;
306 	mutex_exit(&ibcm_path_cache_mutex);
307 	return (IBCM_FAILURE);
308 }
309 
310 static void
311 ibcm_path_cache_add(ibt_path_flags_t flags,
312     ibt_path_attr_t *attrp, uint8_t max_paths, ibt_path_info_t *path)
313 {
314 	int i;
315 	ib_gid_t dgid;
316 	ibcm_path_cache_t *path_cachep;
317 
318 	if (max_paths != 1 || attrp->pa_num_dgids != 1 ||
319 	    attrp->pa_sname != NULL || attrp->pa_sid != 0)
320 		return;
321 
322 	dgid = attrp->pa_dgids[0];
323 	if ((dgid.gid_guid | dgid.gid_prefix) == 0ULL)
324 		return;
325 
326 	mutex_enter(&ibcm_path_cache_mutex);
327 	path_cachep = ibcm_path_cachep;
328 	for (i = 0; i < ibcm_path_cache_size; i++, path_cachep++) {
329 		path_cachep->attr.pa_dgids = attrp->pa_dgids;
330 		if (path_cachep->flags == flags &&
331 		    path_cachep->dgid.gid_guid == dgid.gid_guid &&
332 		    path_cachep->dgid.gid_prefix == dgid.gid_prefix &&
333 		    memcmp(&(path_cachep->attr), attrp, sizeof (*attrp)) == 0) {
334 			/* already in cache */
335 			ibcm_path_cache_stats.already_in_cache++;
336 			path_cachep->attr.pa_dgids = NULL;
337 			mutex_exit(&ibcm_path_cache_mutex);
338 			return;
339 		}
340 		if (path_cachep->dgid.gid_guid != 0ULL) {
341 			path_cachep->attr.pa_dgids = NULL;
342 			continue;
343 		}
344 		/* else the rest of the entries are free, so use this one */
345 		ibcm_path_cache_stats.adds++;
346 		path_cachep->flags = flags;
347 		path_cachep->attr = *attrp;
348 		path_cachep->attr.pa_dgids = NULL;
349 		path_cachep->dgid = attrp->pa_dgids[0];
350 		path_cachep->path = *path;
351 		mutex_exit(&ibcm_path_cache_mutex);
352 		return;
353 	}
354 	mutex_exit(&ibcm_path_cache_mutex);
355 }
356 
357 void
358 ibcm_path_cache_purge(void)
359 {
360 	mutex_enter(&ibcm_path_cache_mutex);
361 	ibcm_path_cache_invalidate = 1;	/* invalidate cache on next check */
362 	ibcm_path_cache_stats.purges++;
363 	mutex_exit(&ibcm_path_cache_mutex);
364 }
365 
366 /*
367  * Function:
368  *	ibt_get_paths
369  * Input:
370  *	ibt_hdl		The handle returned to the client by the IBTF from an
371  *			ibt_attach() call. Can be used by the IBTF Policy module
372  *			and CM in the determination of the "best" path to the
373  *			specified destination for this class of driver.
374  *	flags		Path flags.
375  *	attrp		Points to an ibt_path_attr_t struct that contains
376  *			required and optional attributes.
377  *	max_paths	The size of the "paths" array argument. Also, this
378  *			is the limit on the number of paths returned.
379  *			max_paths indicates the number of requested paths to
380  *			the specified destination(s).
381  * Output:
382  *	paths		An array of ibt_path_info_t structs filled in by
383  *			ibt_get_paths() as output parameters. Upon return,
384  *			array elements with non-NULL HCA GUIDs are valid.
385  *	num_paths_p	If non-NULL, return the actual number of paths found.
386  * Returns:
387  *	IBT_SUCCESS on Success else appropriate error.
388  * Description:
389  *	Finds the best path to a specified destination (as determined by the
390  *	IBTL) that satisfies the requirements specified in an ibt_path_attr_t
391  *	struct.
392  *
393  *	This routine can not be called from interrupt context.
394  */
395 ibt_status_t
396 ibt_get_paths(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags,
397     ibt_path_attr_t *attrp, uint8_t max_paths, ibt_path_info_t *paths,
398     uint8_t *num_paths_p)
399 {
400 	ibt_status_t	retval;
401 
402 	ASSERT(paths != NULL);
403 
404 	IBTF_DPRINTF_L3(cmlog, "ibt_get_paths(%p(%s), 0x%X, %p, %d)",
405 	    ibt_hdl, ibtl_cm_get_clnt_name(ibt_hdl), flags, attrp, max_paths);
406 
407 	if (paths == NULL) {
408 		IBTF_DPRINTF_L2(cmlog, "ibt_get_paths: Path Info Pointer is "
409 		    "NULL - ERROR ");
410 		return (IBT_INVALID_PARAM);
411 	}
412 
413 	if (num_paths_p != NULL)
414 		*num_paths_p = 0;
415 
416 	if (ibcm_path_cache_check(flags, attrp, max_paths, paths,
417 	    num_paths_p) == IBCM_SUCCESS)
418 		return (IBT_SUCCESS);
419 
420 	retval = ibcm_handle_get_path(attrp, flags, max_paths, paths,
421 	    num_paths_p, NULL, NULL);
422 
423 	if (retval == IBT_SUCCESS)
424 		ibcm_path_cache_add(flags, attrp, max_paths, paths);
425 	return (retval);
426 }
427 
428 
429 static ibt_status_t
430 ibcm_handle_get_path(ibt_path_attr_t *attrp, ibt_path_flags_t flags,
431     uint8_t max_paths, ibt_path_info_t *paths, uint8_t *num_path_p,
432     ibt_path_handler_t func, void  *arg)
433 {
434 	ibcm_path_tqargs_t	*path_tq;
435 	int		sleep_flag = ((func == NULL) ? KM_SLEEP : KM_NOSLEEP);
436 	int		len;
437 	ibt_status_t	retval;
438 
439 	retval = ibcm_validate_path_attributes(attrp, flags, max_paths);
440 	if (retval != IBT_SUCCESS)
441 		return (retval);
442 
443 	len = (attrp->pa_num_dgids * sizeof (ib_gid_t)) +
444 	    sizeof (ibcm_path_tqargs_t);
445 
446 	path_tq = kmem_alloc(len, sleep_flag);
447 	if (path_tq == NULL) {
448 		IBTF_DPRINTF_L2(cmlog, "ibcm_handle_get_path: "
449 		    "Unable to allocate memory for local usage.");
450 		return (IBT_INSUFF_KERNEL_RESOURCE);
451 	}
452 
453 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*path_tq))
454 
455 	bcopy(attrp, &path_tq->attr, sizeof (ibt_path_attr_t));
456 
457 	if (attrp->pa_num_dgids) {
458 		path_tq->attr.pa_dgids = (ib_gid_t *)(((uchar_t *)path_tq) +
459 		    sizeof (ibcm_path_tqargs_t));
460 
461 		bcopy(attrp->pa_dgids, path_tq->attr.pa_dgids,
462 		    sizeof (ib_gid_t) * attrp->pa_num_dgids);
463 	} else {
464 		path_tq->attr.pa_dgids = NULL;
465 	}
466 
467 	/* Ignore IBT_PATH_AVAIL flag, if only one path is requested. */
468 	if ((flags & IBT_PATH_AVAIL) && (max_paths == 1)) {
469 		flags &= ~IBT_PATH_AVAIL;
470 
471 		IBTF_DPRINTF_L4(cmlog, "ibcm_handle_get_path: "
472 		    "Ignoring IBT_PATH_AVAIL flag, as only ONE path "
473 		    "information is requested.");
474 	}
475 
476 	path_tq->flags = flags;
477 	path_tq->max_paths = max_paths;
478 	path_tq->paths = paths;
479 	path_tq->num_paths_p = num_path_p;
480 	path_tq->func = func;
481 	path_tq->arg = arg;
482 
483 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*path_tq))
484 
485 	if (func != NULL) {		/* Non-Blocking */
486 		IBTF_DPRINTF_L3(cmlog, "ibcm_handle_get_path: Non Blocking");
487 		if (taskq_dispatch(ibcm_taskq, ibcm_process_async_get_paths,
488 		    path_tq, TQ_NOSLEEP) == 0) {
489 			IBTF_DPRINTF_L2(cmlog, "ibcm_handle_get_path: "
490 			    "Failed to dispatch the TaskQ");
491 			kmem_free(path_tq, len);
492 			return (IBT_INSUFF_KERNEL_RESOURCE);
493 		} else
494 			return (IBT_SUCCESS);
495 	} else {		/* Blocking */
496 		IBTF_DPRINTF_L3(cmlog, "ibcm_handle_get_path: Blocking");
497 		return (ibcm_process_get_paths(path_tq));
498 	}
499 }
500 
501 
502 static void
503 ibcm_process_async_get_paths(void *tq_arg)
504 {
505 	(void) ibcm_process_get_paths(tq_arg);
506 }
507 
508 
509 static ibt_status_t
510 ibcm_validate_path_attributes(ibt_path_attr_t *attrp, ibt_path_flags_t flags,
511     uint8_t max_paths)
512 {
513 	uint_t			i;
514 
515 	IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: Inputs are: "
516 	    "HCA (%llX, %d),\n\tSGID(%llX:%llX), SName=\"%s\",\n\tSID= %llX, "
517 	    "Maxpath= %d, Flags= 0x%X, #Dgid= %d, SDFlag= 0x%llX",
518 	    attrp->pa_hca_guid, attrp->pa_hca_port_num,
519 	    attrp->pa_sgid.gid_prefix, attrp->pa_sgid.gid_guid,
520 	    ((attrp->pa_sname != NULL) ? attrp->pa_sname : ""), attrp->pa_sid,
521 	    max_paths, flags, attrp->pa_num_dgids, attrp->pa_sd_flags);
522 
523 	/*
524 	 * Validate Path Flags.
525 	 * IBT_PATH_AVAIL & IBT_PATH_PERF are mutually exclusive.
526 	 */
527 	if ((flags & IBT_PATH_AVAIL) && (flags & IBT_PATH_PERF)) {
528 		IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
529 		    "Invalid Flags: 0x%X,\n\t AVAIL and PERF flags cannot "
530 		    "specified together.", flags);
531 		return (IBT_INVALID_PARAM);
532 	}
533 
534 	/* Validate number of records requested. */
535 	if ((flags & (IBT_PATH_AVAIL | IBT_PATH_PERF)) &&
536 	    (max_paths > IBT_MAX_SPECIAL_PATHS)) {
537 		IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
538 		    "Max records that can be requested is <%d> \n"
539 		    "when IBT_PATH_AVAIL or IBT_PATH_PERF flag is specified.",
540 		    IBT_MAX_SPECIAL_PATHS);
541 		return (IBT_INVALID_PARAM);
542 	}
543 
544 	/* Only 2 destinations can be specified w/ APM flag. */
545 	if ((flags & IBT_PATH_APM) && (attrp->pa_num_dgids > 2)) {
546 		IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes:\n\t Max "
547 		    "number of DGIDs that can be specified w/APM flag is 2");
548 		return (IBT_INVALID_PARAM);
549 	}
550 
551 	/*
552 	 * Max_paths of "0" is invalid.
553 	 * w/ IBT_PATH_MULTI_SVC_DEST flag, max_paths must be greater than "1".
554 	 */
555 	if ((max_paths == 0) ||
556 	    ((flags & IBT_PATH_MULTI_SVC_DEST) && (max_paths < 2))) {
557 		IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
558 		    "Invalid number of records requested:\n flags 0x%X, "
559 		    "max_paths %d", flags, max_paths);
560 		return (IBT_INVALID_PARAM);
561 	}
562 
563 	/*
564 	 * If IBT_PATH_MULTI_SVC_DEST is set, then ServiceName and/or Service ID
565 	 * must be specified and DGIDs SHOULD NOT be specified.
566 	 */
567 	if ((flags & IBT_PATH_MULTI_SVC_DEST) && ((attrp->pa_num_dgids > 0) ||
568 	    ((attrp->pa_sid == 0) && ((attrp->pa_sname == NULL) ||
569 	    ((attrp->pa_sname != NULL) && (strlen(attrp->pa_sname) == 0)))))) {
570 		IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
571 		    "Invalid Flags: 0x%X, IBT_PATH_MULTI_SVC_DEST flag set "
572 		    "but Service Name \n or Service ID NOT specified or DGIDs "
573 		    "are specified.", flags);
574 		return (IBT_INVALID_PARAM);
575 	}
576 
577 	/*
578 	 * User need to specify the destination information, which can be
579 	 * provided as one or more of the following.
580 	 *	o ServiceName
581 	 *	o ServiceID
582 	 *	o Array of DGIDs w/Num of DGIDs, (max of 2)
583 	 */
584 	if ((attrp->pa_sid == 0) && (attrp->pa_num_dgids == 0) &&
585 	    ((attrp->pa_sname == NULL) || ((attrp->pa_sname != NULL) &&
586 	    (strlen(attrp->pa_sname) == 0)))) {
587 		/* Destination information not provided, bail out. */
588 		IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
589 		    "Client's MUST supply DestInfo.");
590 		return (IBT_INVALID_PARAM);
591 	}
592 
593 	/* If DGIDs are provided, validate them. */
594 	if (attrp->pa_num_dgids > 0) {
595 		if (attrp->pa_dgids == NULL) {
596 			IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
597 			    "pa_dgids NULL, but pa_num_dgids : %d",
598 			    attrp->pa_num_dgids);
599 			return (IBT_INVALID_PARAM);
600 		}
601 
602 		/* Validate DGIDs */
603 		for (i = 0; i < attrp->pa_num_dgids; i++) {
604 			ib_gid_t	gid = attrp->pa_dgids[i];
605 
606 			IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
607 			    "DGID[%d] = %llX:%llX", i, gid.gid_prefix,
608 			    gid.gid_guid);
609 
610 			/* APM request for MultiCast destination is invalid. */
611 			if ((gid.gid_prefix >> 56ULL & 0xFF) == 0xFF) {
612 				if (flags & IBT_PATH_APM) {
613 					IBTF_DPRINTF_L2(cmlog,
614 					    "ibcm_validate_path_attributes: "
615 					    "APM for MGIDs not supported.");
616 					return (IBT_INVALID_PARAM);
617 				}
618 			} else if ((gid.gid_prefix == 0) ||
619 			    (gid.gid_guid == 0)) {
620 				IBTF_DPRINTF_L2(cmlog,
621 				    "ibcm_validate_path_attributes: ERROR: "
622 				    "Invalid DGIDs specified");
623 				return (IBT_INVALID_PARAM);
624 			}
625 		}
626 	}
627 
628 	/* Check for valid Service Name length. */
629 	if ((attrp->pa_sname != NULL) &&
630 	    (strlen(attrp->pa_sname) >= IB_SVC_NAME_LEN)) {
631 		IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
632 		    "ServiceName too long");
633 		return (IBT_INVALID_PARAM);
634 	}
635 
636 	/* If P_Key is specified, check for invalid p_key's */
637 	if (flags & IBT_PATH_PKEY) {
638 		/* Limited P_Key is NOT supported as of now!. */
639 		if ((attrp->pa_pkey == IB_PKEY_INVALID_FULL) ||
640 		    (attrp->pa_pkey & 0x8000) == 0) {
641 			IBTF_DPRINTF_L2(cmlog, "ibcm_validate_path_attributes: "
642 			    "Specified P_Key is invalid: 0x%X", attrp->pa_pkey);
643 			return (IBT_INVALID_PARAM);
644 		}
645 		IBTF_DPRINTF_L3(cmlog, "ibcm_validate_path_attributes: "
646 		    "P_Key= 0x%X", attrp->pa_pkey);
647 	}
648 
649 	return (IBT_SUCCESS);
650 }
651 
652 
653 static ibt_status_t
654 ibcm_process_get_paths(void *tq_arg)
655 {
656 	ibcm_path_tqargs_t	*p_arg = (ibcm_path_tqargs_t *)tq_arg;
657 	ibcm_dinfo_t		*dinfo;
658 	int			len;
659 	uint8_t			max_paths, num_path;
660 	ibt_status_t		retval;
661 	ib_gid_t		*d_gids_p = NULL;
662 	ibtl_cm_port_list_t	*slistp = NULL;
663 	uint_t			dnum = 0, num_dest;
664 	uint_t			i, j;
665 	ibcm_hca_info_t		*hcap;
666 	ibmf_saa_handle_t	saa_handle;
667 
668 	IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths(%p, 0x%X, %d) ",
669 	    p_arg, p_arg->flags, p_arg->max_paths);
670 
671 	max_paths = num_path = p_arg->max_paths;
672 
673 	/*
674 	 * Prepare the Destination list based on the input DGIDs and
675 	 * other attributes.
676 	 *
677 	 * APM is requested and pa_dgids are specified.  If multiple DGIDs are
678 	 * specified, check out whether they are companion to each other or if
679 	 * only one DGID is specified, then get the companion port GID for that.
680 	 */
681 	if (p_arg->attr.pa_num_dgids) {
682 		if (p_arg->flags & IBT_PATH_APM) {
683 			ib_gid_t	c_gid, n_gid;
684 
685 			IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: "
686 			    "DGIDs specified w/ APM Flag");
687 
688 			c_gid = p_arg->attr.pa_dgids[0];
689 			if (p_arg->attr.pa_num_dgids > 1)
690 				n_gid = p_arg->attr.pa_dgids[1];
691 			else
692 				n_gid.gid_prefix = n_gid.gid_guid = 0;
693 
694 			retval = ibcm_get_comp_pgids(c_gid, n_gid, 0, &d_gids_p,
695 			    &dnum);
696 			if ((retval != IBT_SUCCESS) &&
697 			    (retval != IBT_GIDS_NOT_FOUND)) {
698 				IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths:"
699 				    " Invalid DGIDs specified w/ APM Flag");
700 				goto path_error2;
701 			}
702 			IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: "
703 			    "Found %d Comp DGID", dnum);
704 		}
705 
706 		if (dnum) {
707 			len = 1;
708 		} else {
709 			len = p_arg->attr.pa_num_dgids - 1;
710 		}
711 		num_dest = len + 1;
712 
713 		IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: #dgid %d, dnum "
714 		    "%d, #dest %d", p_arg->attr.pa_num_dgids, dnum, num_dest);
715 	} else {
716 		if (p_arg->flags & IBT_PATH_MULTI_SVC_DEST) {
717 			IBTF_DPRINTF_L4(cmlog, "ibcm_process_get_paths: "
718 			    "IBT_PATH_MULTI_SVC_DEST flags set");
719 			len = max_paths - 1;
720 		} else if (p_arg->flags & IBT_PATH_APM) {
721 			len = 1;
722 		} else {
723 			len = 0;
724 		}
725 		num_dest = 0;
726 	}
727 
728 	/* Allocate memory and accumulate all destination information */
729 	len = (len * sizeof (ibcm_dest_t)) + sizeof (ibcm_dinfo_t);
730 
731 	dinfo = kmem_zalloc(len, KM_SLEEP);
732 	dinfo->num_dest = num_dest;
733 	if (p_arg->flags & IBT_PATH_PKEY)
734 		dinfo->p_key = p_arg->attr.pa_pkey;
735 
736 	for (i = 0, j = 0; i < num_dest; i++) {
737 		if (i < p_arg->attr.pa_num_dgids)
738 			dinfo->dest[i].d_gid = p_arg->attr.pa_dgids[i];
739 		else
740 			dinfo->dest[i].d_gid = d_gids_p[j++];
741 	}
742 
743 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*p_arg))
744 
745 	/* IBTF allocates memory for path_info in case of Async Get Paths */
746 	if (p_arg->paths == NULL)
747 		p_arg->paths = kmem_zalloc(sizeof (ibt_path_info_t) * max_paths,
748 		    KM_SLEEP);
749 
750 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*p_arg))
751 
752 	/*
753 	 * Get list of active HCA<->Port list, that matches input specified attr
754 	 */
755 	IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: Get Paths from \n HCA "
756 	    "(%llX:%d), SGID  %llX:%llX", p_arg->attr.pa_hca_guid,
757 	    p_arg->attr.pa_hca_port_num, p_arg->attr.pa_sgid.gid_prefix,
758 	    p_arg->attr.pa_sgid.gid_guid);
759 
760 	retval = ibtl_cm_get_active_plist(&p_arg->attr, p_arg->flags, &slistp);
761 	if (retval != IBT_SUCCESS) {
762 		IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: HCA capable of "
763 		    "requested source attributes NOT available.");
764 		goto path_error;
765 	}
766 
767 	IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: HCA (%llX, %d)",
768 	    slistp->p_hca_guid, slistp->p_port_num);
769 
770 	hcap = ibcm_find_hca_entry(slistp->p_hca_guid);
771 	if (hcap == NULL) {
772 		IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: "
773 		    "NO HCA found");
774 		retval = IBT_HCA_BUSY_DETACHING;
775 		goto path_error;
776 	}
777 
778 	/* Get SA Access Handle. */
779 	for (i = 0; i < slistp->p_count; i++) {
780 		if (i == 0) {
781 			/* Validate whether this HCA supports APM */
782 			if ((p_arg->flags & IBT_PATH_APM) &&
783 			    (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG))) {
784 				IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths:"
785 				    " HCA (%llX): APM NOT SUPPORTED ",
786 				    slistp[i].p_hca_guid);
787 				retval = IBT_APM_NOT_SUPPORTED;
788 				goto path_error1;
789 			}
790 		}
791 
792 		saa_handle = ibcm_get_saa_handle(hcap, slistp[i].p_port_num);
793 		if (saa_handle == NULL) {
794 			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: "
795 			    "SAA HDL NULL, HCA (%llX:%d) NOT ACTIVE",
796 			    slistp[i].p_hca_guid, slistp[i].p_port_num);
797 			retval = IBT_HCA_PORT_NOT_ACTIVE;
798 			goto path_error1;
799 		}
800 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*slistp))
801 		slistp[i].p_saa_hdl = saa_handle;
802 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*slistp))
803 	}
804 
805 	/*
806 	 * If Service Name or Service ID are specified, first retrieve
807 	 * Service Records.
808 	 */
809 	if ((p_arg->attr.pa_sid != 0) || ((p_arg->attr.pa_sname != NULL) &&
810 	    (strlen(p_arg->attr.pa_sname) != 0))) {
811 
812 		IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_paths: Get Service "
813 		    "Record for \n\t(%llX, \"%s\")", p_arg->attr.pa_sid,
814 		    ((p_arg->attr.pa_sname != NULL) ?
815 		    p_arg->attr.pa_sname : ""));
816 
817 		/* Get Service Records. */
818 		retval = ibcm_saa_service_rec(p_arg, slistp, dinfo);
819 		if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA)) {
820 			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: Status="
821 			    "%d, Failed to get Service Record for \n\t"
822 			    "(%llX, \"%s\")", retval, p_arg->attr.pa_sid,
823 			    ((p_arg->attr.pa_sname != NULL) ?
824 			    p_arg->attr.pa_sname : ""));
825 			goto path_error1;
826 		}
827 	}
828 
829 	/* Get Path Records. */
830 	retval = ibcm_saa_path_rec(p_arg, slistp, dinfo, &num_path);
831 
832 path_error1:
833 	ibcm_dec_hca_acc_cnt(hcap);
834 
835 path_error:
836 	if (slistp)
837 		ibtl_cm_free_active_plist(slistp);
838 
839 	if (dinfo)
840 		kmem_free(dinfo, len);
841 
842 path_error2:
843 	if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA))
844 		num_path = 0;
845 
846 	if (p_arg->num_paths_p != NULL)
847 		*p_arg->num_paths_p = num_path;
848 
849 	if ((dnum) && (d_gids_p))
850 		kmem_free(d_gids_p, dnum * sizeof (ib_gid_t));
851 
852 	if (p_arg->func) {   /* Do these only for Async Get Paths */
853 		ibt_path_info_t *tmp_path_p;
854 
855 		if (retval == IBT_INSUFF_DATA) {
856 			/*
857 			 * We allocated earlier memory based on "max_paths",
858 			 * but we got lesser path-records, so re-adjust that
859 			 * buffer so that caller can free the correct memory.
860 			 */
861 			tmp_path_p = kmem_alloc(
862 			    sizeof (ibt_path_info_t) * num_path, KM_SLEEP);
863 
864 			bcopy(p_arg->paths, tmp_path_p,
865 			    num_path * sizeof (ibt_path_info_t));
866 
867 			kmem_free(p_arg->paths,
868 			    sizeof (ibt_path_info_t) * max_paths);
869 		} else if (retval != IBT_SUCCESS) {
870 			if (p_arg->paths)
871 				kmem_free(p_arg->paths,
872 				    sizeof (ibt_path_info_t) * max_paths);
873 			tmp_path_p = NULL;
874 		} else {
875 			tmp_path_p = p_arg->paths;
876 		}
877 		(*(p_arg->func))(p_arg->arg, retval, tmp_path_p, num_path);
878 	}
879 
880 	len = (sizeof (ib_gid_t) * p_arg->attr.pa_num_dgids) +
881 	    sizeof (ibcm_path_tqargs_t);
882 
883 	if (p_arg && len)
884 		kmem_free(p_arg, len);
885 
886 	IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_paths: done: status %d, "
887 	    "Found %d/%d Path Records", retval, num_path, max_paths);
888 
889 	return (retval);
890 }
891 
892 
893 /*
894  * Perform SA Access to retrieve Path Records.
895  */
896 static ibt_status_t
897 ibcm_saa_path_rec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
898     ibcm_dinfo_t *dinfo, uint8_t *max_count)
899 {
900 	uint8_t		num_path = *max_count;
901 	uint8_t		num_path_plus;
902 	uint_t		extra, idx, rec_found = 0;
903 	ibt_status_t	retval = IBT_SUCCESS;
904 	int		unicast_dgid_present = 0;
905 	uint8_t		i;
906 
907 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec(%p, %p, %p, 0x%X, %d)",
908 	    p_arg, sl, dinfo, p_arg->flags, *max_count);
909 
910 	if ((dinfo->num_dest == 0) || (num_path == 0) || (sl == NULL)) {
911 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: Invalid Counters");
912 		return (IBT_INVALID_PARAM);
913 	}
914 
915 	/*
916 	 * Of the total needed "X" number of paths to "Y" number of destination
917 	 * we need to get X/Y plus X%Y extra paths to each destination,
918 	 * We do this so that we can choose the required number of path records
919 	 * for the specific destination.
920 	 */
921 	num_path /= dinfo->num_dest;
922 	extra = (*max_count % dinfo->num_dest);
923 
924 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: numpath %d extra %d dest %d",
925 	    num_path, extra, dinfo->num_dest);
926 
927 	/* Find out whether we need to get PathRecord for a MGID as DGID. */
928 	for (idx = 0; idx < dinfo->num_dest; idx++) {
929 		ib_gid_t	dgid = dinfo->dest[idx].d_gid;
930 
931 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: DGID[%d]: %llX:%llX",
932 		    idx, dgid.gid_prefix, dgid.gid_guid);
933 
934 		if ((dgid.gid_prefix >> 56ULL & 0xFF) == 0xFF) {
935 			if (extra)
936 				num_path_plus = num_path + 1;
937 			else
938 				num_path_plus = num_path;
939 
940 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: Get %d Paths"
941 			    "- MGID(%016llX%016llX)", num_path_plus,
942 			    dgid.gid_prefix, dgid.gid_guid);
943 
944 			dinfo->dest[idx].d_tag = 1; /* MultiCast */
945 
946 			/* Yes, it's Single PathRec query for MGID as DGID. */
947 			retval = ibcm_get_single_pathrec(p_arg, sl, dinfo, idx,
948 			    &num_path_plus, &p_arg->paths[rec_found]);
949 			if ((retval != IBT_SUCCESS) &&
950 			    (retval != IBT_INSUFF_DATA)) {
951 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: "
952 				    "Failed to get PathRec for MGID %d",
953 				    retval);
954 				continue;
955 			}
956 			if (extra)
957 				extra--;
958 
959 			rec_found += num_path_plus;
960 		}
961 		if (rec_found == *max_count)
962 			break;
963 	}
964 
965 	for (i = 0; i < dinfo->num_dest; i++) {
966 		if (dinfo->dest[i].d_tag == 0) {
967 			unicast_dgid_present++;
968 		}
969 	}
970 
971 	num_path_plus = *max_count - rec_found;
972 
973 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: Recfound: %d, need to find "
974 	    "%d, UniCastGID present %d", rec_found, num_path_plus,
975 	    unicast_dgid_present);
976 
977 	if ((unicast_dgid_present != 0) && (num_path_plus > 0)) {
978 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: MultiSM=%X, #SRC=%d,"
979 		    "Dest%d", sl->p_multi, sl->p_count, unicast_dgid_present);
980 
981 		if ((sl->p_multi != IBTL_CM_SIMPLE_SETUP) ||
982 		    ((unicast_dgid_present == 1) && (sl->p_count == 1))) {
983 			/*
984 			 * Use SinglePathRec if we are dealing w/ MultiSM or
985 			 * request is for one SGID to one DGID.
986 			 */
987 			retval = ibcm_get_single_pathrec(p_arg, sl, dinfo, 0xFF,
988 			    &num_path_plus, &p_arg->paths[rec_found]);
989 		} else {
990 			uint8_t old_num_path_plus = num_path_plus;
991 
992 			/* MultiPathRec will be used for other queries. */
993 			retval = ibcm_get_multi_pathrec(p_arg, sl, dinfo,
994 			    &num_path_plus, &p_arg->paths[rec_found]);
995 			if ((retval != IBT_SUCCESS) &&
996 			    (retval != IBT_INSUFF_DATA) &&
997 			    (sl->p_count > 0) &&
998 			    (dinfo->num_dest > 0)) {
999 				ibtl_cm_port_list_t sl_tmp = *sl;
1000 				ibcm_dinfo_t dinfo_tmp = *dinfo;
1001 
1002 				sl_tmp.p_count = 1;
1003 				dinfo_tmp.num_dest = 1;
1004 				num_path_plus = old_num_path_plus;
1005 				retval = ibcm_get_single_pathrec(p_arg, &sl_tmp,
1006 				    &dinfo_tmp, 0xFF, &num_path_plus,
1007 				    &p_arg->paths[rec_found]);
1008 			}
1009 		}
1010 		if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA)) {
1011 			IBTF_DPRINTF_L2(cmlog, "ibcm_saa_path_rec: "
1012 			    "Failed to get PathRec: Status %d", retval);
1013 		} else {
1014 			rec_found += num_path_plus;
1015 		}
1016 	}
1017 
1018 	if (rec_found == 0)  {
1019 		if (retval == IBT_SUCCESS)
1020 			retval = IBT_PATH_RECORDS_NOT_FOUND;
1021 	} else if (rec_found != *max_count)
1022 		retval = IBT_INSUFF_DATA;
1023 	else if (rec_found != 0)
1024 		retval = IBT_SUCCESS;
1025 
1026 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_path_rec: done. Status = %d, "
1027 	    "Found %d/%d Paths", retval, rec_found, *max_count);
1028 
1029 	*max_count = rec_found; /* Update the return count. */
1030 
1031 	return (retval);
1032 }
1033 
1034 ibt_status_t
1035 ibcm_contact_sa_access(ibmf_saa_handle_t saa_handle,
1036     ibmf_saa_access_args_t *access_args, size_t *length, void **results_p)
1037 {
1038 	int	retry;
1039 	int	sa_retval;
1040 
1041 	IBTF_DPRINTF_L3(cmlog, "ibcm_contact_sa_access(%p, %p)",
1042 	    saa_handle, access_args);
1043 
1044 	ibcm_sa_access_enter();
1045 
1046 	for (retry = 0; retry < ibcm_max_sa_retries; retry++) {
1047 		sa_retval = ibmf_sa_access(saa_handle, access_args, 0,
1048 		    length, results_p);
1049 		if (sa_retval != IBMF_TRANS_TIMEOUT)
1050 			break;
1051 
1052 		IBTF_DPRINTF_L2(cmlog, "ibcm_contact_sa_access: "
1053 		    "ibmf_sa_access() - Timed Out (%d)", sa_retval);
1054 		delay(ibcm_sa_timeout_delay);
1055 	}
1056 
1057 	ibcm_sa_access_exit();
1058 
1059 	if ((sa_retval == IBMF_SUCCESS) || (sa_retval == IBMF_NO_RECORDS) ||
1060 	    (sa_retval == IBMF_REQ_INVALID)) {
1061 		IBTF_DPRINTF_L3(cmlog, "ibcm_contact_sa_access: "
1062 		    "ibmf_sa_access() returned (%d)", sa_retval);
1063 		return (IBT_SUCCESS);
1064 	} else  {
1065 		IBTF_DPRINTF_L2(cmlog, "ibcm_contact_sa_access: "
1066 		    "ibmf_sa_access(): Failed (%d)", sa_retval);
1067 		return (ibcm_ibmf_analyze_error(sa_retval));
1068 	}
1069 }
1070 
1071 
1072 static ibt_status_t
1073 ibcm_update_pri(sa_path_record_t *pr_resp, ibtl_cm_port_list_t *sl,
1074     ibcm_dinfo_t *dinfo, ibt_path_info_t *paths)
1075 {
1076 	ibt_status_t	retval = IBT_SUCCESS;
1077 	int		d, s;
1078 
1079 	retval = ibcm_update_cep_info(pr_resp, sl, NULL,
1080 	    &paths->pi_prim_cep_path);
1081 	if (retval != IBT_SUCCESS)
1082 		return (retval);
1083 
1084 	/* Update some leftovers */
1085 	paths->pi_prim_pkt_lt = pr_resp->PacketLifeTime;
1086 	paths->pi_path_mtu = pr_resp->Mtu;
1087 
1088 	for (d = 0; d < dinfo->num_dest; d++) {
1089 		if (pr_resp->DGID.gid_guid == dinfo->dest[d].d_gid.gid_guid) {
1090 			paths->pi_sid = dinfo->dest[d].d_sid;
1091 			if (paths->pi_sid != 0) {
1092 				bcopy(&dinfo->dest[d].d_sdata,
1093 				    &paths->pi_sdata, sizeof (ibt_srv_data_t));
1094 			}
1095 			break;
1096 		}
1097 	}
1098 
1099 	for (s = 0; s < sl->p_count; s++) {
1100 		if (pr_resp->SGID.gid_guid == sl[s].p_sgid.gid_guid) {
1101 			paths->pi_hca_guid = sl[s].p_hca_guid;
1102 		}
1103 	}
1104 
1105 	/* Set Alternate Path to invalid state. */
1106 	paths->pi_alt_cep_path.cep_hca_port_num = 0;
1107 	paths->pi_alt_cep_path.cep_adds_vect.av_dlid = 0;
1108 
1109 	IBTF_DPRINTF_L5(cmlog, "Path: HCA GUID  = 0x%llX", paths->pi_hca_guid);
1110 	IBTF_DPRINTF_L5(cmlog, "Path: ServiceID = 0x%llX", paths->pi_sid);
1111 
1112 	return (retval);
1113 }
1114 
1115 
1116 static ibt_status_t
1117 ibcm_get_single_pathrec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
1118     ibcm_dinfo_t *dinfo, uint8_t idx, uint8_t *num_path, ibt_path_info_t *paths)
1119 {
1120 	sa_path_record_t	pathrec_req;
1121 	sa_path_record_t	*pr_resp;
1122 	ibmf_saa_access_args_t	access_args;
1123 	uint64_t		c_mask = 0;
1124 	void			*results_p;
1125 	uint8_t			num_rec;
1126 	size_t			length;
1127 	ibt_status_t		retval;
1128 	int			i, j, k;
1129 	int			found, p_fnd;
1130 	ibt_path_attr_t		*attrp = &p_arg->attr;
1131 	ibmf_saa_handle_t	saa_handle;
1132 
1133 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec(%p, %p, %p, %d)",
1134 	    p_arg, sl, dinfo, *num_path);
1135 
1136 	bzero(&pathrec_req, sizeof (sa_path_record_t));
1137 
1138 	/* Is Flow Label Specified. */
1139 	if (attrp->pa_flow) {
1140 		pathrec_req.FlowLabel = attrp->pa_flow;
1141 		c_mask |= SA_PR_COMPMASK_FLOWLABEL;
1142 	}
1143 
1144 	/* Is HopLimit Specified. */
1145 	if (p_arg->flags & IBT_PATH_HOP) {
1146 		pathrec_req.HopLimit = attrp->pa_hop;
1147 		c_mask |= SA_PR_COMPMASK_HOPLIMIT;
1148 	}
1149 
1150 	/* Is P_Key Specified. */
1151 	if (dinfo->p_key) {
1152 		IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: "
1153 		    "Specified or Global PKEY 0x%X", dinfo->p_key);
1154 		pathrec_req.P_Key = dinfo->p_key;
1155 		c_mask |= SA_PR_COMPMASK_PKEY;
1156 	}
1157 
1158 	/* Is TClass Specified. */
1159 	if (attrp->pa_tclass) {
1160 		pathrec_req.TClass = attrp->pa_tclass;
1161 		c_mask |= SA_PR_COMPMASK_TCLASS;
1162 	}
1163 
1164 	/* Is SL specified. */
1165 	if (attrp->pa_sl) {
1166 		pathrec_req.SL = attrp->pa_sl;
1167 		c_mask |= SA_PR_COMPMASK_SL;
1168 	}
1169 
1170 	/* If IBT_PATH_PERF is set, then mark all selectors to BEST. */
1171 	if (p_arg->flags & IBT_PATH_PERF) {
1172 		pathrec_req.PacketLifeTimeSelector = IBT_BEST;
1173 		pathrec_req.MtuSelector = IBT_BEST;
1174 		pathrec_req.RateSelector = IBT_BEST;
1175 
1176 		c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR |
1177 		    SA_PR_COMPMASK_RATESELECTOR | SA_PR_COMPMASK_MTUSELECTOR;
1178 	} else {
1179 		if (attrp->pa_pkt_lt.p_selector == IBT_BEST) {
1180 			pathrec_req.PacketLifeTimeSelector = IBT_BEST;
1181 			c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR;
1182 		}
1183 
1184 		if (attrp->pa_srate.r_selector == IBT_BEST) {
1185 			pathrec_req.RateSelector = IBT_BEST;
1186 			c_mask |= SA_PR_COMPMASK_RATESELECTOR;
1187 		}
1188 
1189 		if (attrp->pa_mtu.r_selector == IBT_BEST) {
1190 			pathrec_req.MtuSelector = IBT_BEST;
1191 			c_mask |= SA_PR_COMPMASK_MTUSELECTOR;
1192 		}
1193 	}
1194 
1195 	/*
1196 	 * Honor individual selection of these attributes,
1197 	 * even if IBT_PATH_PERF is set.
1198 	 */
1199 	/* Check out whether Packet Life Time is specified. */
1200 	if (attrp->pa_pkt_lt.p_pkt_lt) {
1201 		pathrec_req.PacketLifeTime =
1202 		    ibt_usec2ib(attrp->pa_pkt_lt.p_pkt_lt);
1203 		pathrec_req.PacketLifeTimeSelector =
1204 		    attrp->pa_pkt_lt.p_selector;
1205 
1206 		c_mask |= SA_PR_COMPMASK_PKTLT | SA_PR_COMPMASK_PKTLTSELECTOR;
1207 	}
1208 
1209 	/* Is SRATE specified. */
1210 	if (attrp->pa_srate.r_srate) {
1211 		pathrec_req.Rate = attrp->pa_srate.r_srate;
1212 		pathrec_req.RateSelector = attrp->pa_srate.r_selector;
1213 
1214 		c_mask |= SA_PR_COMPMASK_RATE | SA_PR_COMPMASK_RATESELECTOR;
1215 	}
1216 
1217 	/* Is MTU specified. */
1218 	if (attrp->pa_mtu.r_mtu) {
1219 		pathrec_req.Mtu = attrp->pa_mtu.r_mtu;
1220 		pathrec_req.MtuSelector = attrp->pa_mtu.r_selector;
1221 
1222 		c_mask |= SA_PR_COMPMASK_MTU | SA_PR_COMPMASK_MTUSELECTOR;
1223 	}
1224 
1225 	/* We always get REVERSIBLE paths. */
1226 	pathrec_req.Reversible = 1;
1227 	c_mask |= SA_PR_COMPMASK_REVERSIBLE;
1228 
1229 	pathrec_req.NumbPath = *num_path;
1230 	c_mask |= SA_PR_COMPMASK_NUMBPATH;
1231 
1232 	if (idx != 0xFF) {
1233 		/* MGID */
1234 		pathrec_req.DGID = dinfo->dest[idx].d_gid;
1235 		c_mask |= SA_PR_COMPMASK_DGID;
1236 	}
1237 
1238 	p_fnd = found = 0;
1239 
1240 	for (i = 0; i < sl->p_count; i++) {
1241 		/* SGID */
1242 		pathrec_req.SGID = sl[i].p_sgid;
1243 		c_mask |= SA_PR_COMPMASK_SGID;
1244 		saa_handle = sl[i].p_saa_hdl;
1245 
1246 		for (k = 0; k < dinfo->num_dest; k++) {
1247 			if (idx == 0xFF) {		/* DGID */
1248 				if (dinfo->dest[k].d_tag != 0)
1249 					continue;
1250 
1251 				if (pathrec_req.SGID.gid_prefix !=
1252 				    dinfo->dest[k].d_gid.gid_prefix) {
1253 					IBTF_DPRINTF_L3(cmlog,
1254 					    "ibcm_get_single_pathrec: SGID_pfx="
1255 					    "%llX, DGID_pfx=%llX doesn't match",
1256 					    pathrec_req.SGID.gid_prefix,
1257 					    dinfo->dest[k].d_gid.gid_prefix);
1258 					continue;
1259 				}
1260 
1261 				pathrec_req.DGID = dinfo->dest[k].d_gid;
1262 				c_mask |= SA_PR_COMPMASK_DGID;
1263 
1264 				/*
1265 				 * If we had performed Service Look-up, then we
1266 				 * got P_Key from ServiceRecord, so get path
1267 				 * records that satisfy this particular P_Key.
1268 				 */
1269 				if ((dinfo->p_key == 0) &&
1270 				    (dinfo->dest[k].d_pkey != 0)) {
1271 					pathrec_req.P_Key =
1272 					    dinfo->dest[k].d_pkey;
1273 					c_mask |= SA_PR_COMPMASK_PKEY;
1274 				}
1275 			}
1276 
1277 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: "
1278 			    "Get %d Path(s) between\nSGID %llX:%llX "
1279 			    "DGID %llX:%llX", pathrec_req.NumbPath,
1280 			    pathrec_req.SGID.gid_prefix,
1281 			    pathrec_req.SGID.gid_guid,
1282 			    pathrec_req.DGID.gid_prefix,
1283 			    pathrec_req.DGID.gid_guid);
1284 
1285 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: CMask"
1286 			    "=0x%llX, PKey=0x%X", c_mask, pathrec_req.P_Key);
1287 
1288 			/* Contact SA Access to retrieve Path Records. */
1289 			access_args.sq_attr_id = SA_PATHRECORD_ATTRID;
1290 			access_args.sq_template = &pathrec_req;
1291 			access_args.sq_access_type = IBMF_SAA_RETRIEVE;
1292 			access_args.sq_template_length =
1293 			    sizeof (sa_path_record_t);
1294 			access_args.sq_component_mask = c_mask;
1295 			access_args.sq_callback = NULL;
1296 			access_args.sq_callback_arg = NULL;
1297 
1298 			retval = ibcm_contact_sa_access(saa_handle,
1299 			    &access_args, &length, &results_p);
1300 			if (retval != IBT_SUCCESS) {
1301 				*num_path = 0;
1302 				return (retval);
1303 			}
1304 
1305 			num_rec = length / sizeof (sa_path_record_t);
1306 
1307 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: "
1308 			    "FOUND %d/%d path requested", num_rec, *num_path);
1309 
1310 			if ((results_p == NULL) || (num_rec == 0)) {
1311 				if (idx != 0xFF)
1312 					break;
1313 				else
1314 					continue;
1315 			}
1316 
1317 			/* Update the PathInfo from the response. */
1318 			pr_resp = (sa_path_record_t *)results_p;
1319 			for (j = 0; j < num_rec; j++, pr_resp++) {
1320 				if ((p_fnd != 0) &&
1321 				    (p_arg->flags & IBT_PATH_APM)) {
1322 					IBTF_DPRINTF_L3(cmlog,
1323 					    "ibcm_get_single_pathrec: "
1324 					    "Fill Alternate Path");
1325 					retval = ibcm_update_cep_info(pr_resp,
1326 					    sl, NULL,
1327 					    &paths[found - 1].pi_alt_cep_path);
1328 					if (retval != IBT_SUCCESS)
1329 						continue;
1330 
1331 					/* Update some leftovers */
1332 					paths[found - 1].pi_alt_pkt_lt =
1333 					    pr_resp->PacketLifeTime;
1334 					p_fnd = 0;
1335 				} else {
1336 					IBTF_DPRINTF_L3(cmlog,
1337 					    "ibcm_get_single_pathrec: "
1338 					    "Fill Primary Path");
1339 
1340 					if (found == *num_path)
1341 						break;
1342 
1343 					retval = ibcm_update_pri(pr_resp, sl,
1344 					    dinfo, &paths[found]);
1345 					if (retval != IBT_SUCCESS)
1346 						continue;
1347 					p_fnd = 1;
1348 					found++;
1349 				}
1350 
1351 			}
1352 			/* Deallocate the memory for results_p. */
1353 			kmem_free(results_p, length);
1354 
1355 			if (idx != 0xFF)
1356 				break;		/* We r here for MGID */
1357 		}
1358 		if ((idx != 0xFF) && (found == *num_path))
1359 			break;		/* We r here for MGID */
1360 	}
1361 
1362 	if (found == 0)
1363 		retval = IBT_PATH_RECORDS_NOT_FOUND;
1364 	else if (found != *num_path)
1365 		retval = IBT_INSUFF_DATA;
1366 	else
1367 		retval = IBT_SUCCESS;
1368 
1369 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_single_pathrec: done. Status %d, "
1370 	    "Found %d/%d Paths", retval, found, *num_path);
1371 
1372 	*num_path = found;
1373 
1374 	return (retval);
1375 }
1376 
1377 
1378 static ibt_status_t
1379 ibcm_get_multi_pathrec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
1380     ibcm_dinfo_t *dinfo, uint8_t *num_path, ibt_path_info_t *paths)
1381 {
1382 	sa_multipath_record_t	*mpr_req;
1383 	sa_path_record_t	*pr_resp;
1384 	ibmf_saa_access_args_t	access_args;
1385 	void			*results_p;
1386 	uint64_t		c_mask = 0;
1387 	ib_gid_t		*gid_ptr, *gid_s_ptr;
1388 	size_t			length;
1389 	int			template_len, found, num_rec;
1390 	int			i, k;
1391 	ibt_status_t		retval;
1392 	uint8_t			sgid_cnt, dgid_cnt;
1393 	ibt_path_attr_t		*attrp = &p_arg->attr;
1394 
1395 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec(%p, %p, %p, %d)",
1396 	    attrp, sl, dinfo, *num_path);
1397 
1398 	for (i = 0, dgid_cnt = 0; i < dinfo->num_dest; i++) {
1399 		if (dinfo->dest[i].d_tag == 0)
1400 			dgid_cnt++;
1401 	}
1402 
1403 	sgid_cnt = sl->p_count;
1404 
1405 	if ((sgid_cnt == 0) || (dgid_cnt == 0)) {
1406 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_multi_pathrec: sgid_cnt(%d) or"
1407 		    " dgid_cnt(%d) is zero", sgid_cnt, dgid_cnt);
1408 		return (IBT_INVALID_PARAM);
1409 	}
1410 
1411 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: Get %d records between "
1412 	    "%d Src(s) <=> %d Dest(s)", *num_path, sgid_cnt, dgid_cnt);
1413 
1414 	/*
1415 	 * Calculate the size for multi-path records template, which includes
1416 	 * constant portion of the multipath record, plus variable size for
1417 	 * SGID (sgid_cnt) and DGID (dgid_cnt).
1418 	 */
1419 	template_len = ((dgid_cnt + sgid_cnt) * sizeof (ib_gid_t)) +
1420 	    sizeof (sa_multipath_record_t);
1421 
1422 	mpr_req = kmem_zalloc(template_len, KM_SLEEP);
1423 
1424 	ASSERT(mpr_req != NULL);
1425 
1426 	gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
1427 	    sizeof (sa_multipath_record_t));
1428 
1429 	/* Get the starting pointer where GIDs are stored. */
1430 	gid_s_ptr = gid_ptr;
1431 
1432 	/* SGID */
1433 	for (i = 0; i < sgid_cnt; i++) {
1434 		*gid_ptr = sl[i].p_sgid;
1435 
1436 		IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: SGID[%d] = "
1437 		    "(%llX:%llX)", i, gid_ptr->gid_prefix, gid_ptr->gid_guid);
1438 
1439 		gid_ptr++;
1440 	}
1441 
1442 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
1443 
1444 	mpr_req->SGIDCount = sgid_cnt;
1445 	c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
1446 
1447 	/* DGIDs */
1448 	for (i = 0; i < dinfo->num_dest; i++) {
1449 		if (dinfo->dest[i].d_tag == 0) {
1450 			*gid_ptr = dinfo->dest[i].d_gid;
1451 
1452 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1453 			    "DGID[%d] = (%llX:%llX)", i, gid_ptr->gid_prefix,
1454 			    gid_ptr->gid_guid);
1455 			gid_ptr++;
1456 		}
1457 	}
1458 
1459 	mpr_req->DGIDCount = dgid_cnt;
1460 	c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
1461 
1462 	/* Is Flow Label Specified. */
1463 	if (attrp->pa_flow) {
1464 		mpr_req->FlowLabel = attrp->pa_flow;
1465 		c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
1466 	}
1467 
1468 	/* Is HopLimit Specified. */
1469 	if (p_arg->flags & IBT_PATH_HOP) {
1470 		mpr_req->HopLimit = attrp->pa_hop;
1471 		c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
1472 	}
1473 
1474 	/* Is TClass Specified. */
1475 	if (attrp->pa_tclass) {
1476 		mpr_req->TClass = attrp->pa_tclass;
1477 		c_mask |= SA_MPR_COMPMASK_TCLASS;
1478 	}
1479 
1480 	/* Is SL specified. */
1481 	if (attrp->pa_sl) {
1482 		mpr_req->SL = attrp->pa_sl;
1483 		c_mask |= SA_MPR_COMPMASK_SL;
1484 	}
1485 
1486 	if (p_arg->flags & IBT_PATH_PERF) {
1487 		mpr_req->PacketLifeTimeSelector = IBT_BEST;
1488 		mpr_req->RateSelector = IBT_BEST;
1489 		mpr_req->MtuSelector = IBT_BEST;
1490 
1491 		c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
1492 		    SA_MPR_COMPMASK_RATESELECTOR | SA_MPR_COMPMASK_MTUSELECTOR;
1493 	} else {
1494 		if (attrp->pa_pkt_lt.p_selector == IBT_BEST) {
1495 			mpr_req->PacketLifeTimeSelector = IBT_BEST;
1496 			c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
1497 		}
1498 
1499 		if (attrp->pa_srate.r_selector == IBT_BEST) {
1500 			mpr_req->RateSelector = IBT_BEST;
1501 			c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
1502 		}
1503 
1504 		if (attrp->pa_mtu.r_selector == IBT_BEST) {
1505 			mpr_req->MtuSelector = IBT_BEST;
1506 			c_mask |= SA_MPR_COMPMASK_MTUSELECTOR;
1507 		}
1508 	}
1509 
1510 	/*
1511 	 * Honor individual selection of these attributes,
1512 	 * even if IBT_PATH_PERF is set.
1513 	 */
1514 	/* Check out whether Packet Life Time is specified. */
1515 	if (attrp->pa_pkt_lt.p_pkt_lt) {
1516 		mpr_req->PacketLifeTime =
1517 		    ibt_usec2ib(attrp->pa_pkt_lt.p_pkt_lt);
1518 		mpr_req->PacketLifeTimeSelector =
1519 		    attrp->pa_pkt_lt.p_selector;
1520 
1521 		c_mask |= SA_MPR_COMPMASK_PKTLT |
1522 		    SA_MPR_COMPMASK_PKTLTSELECTOR;
1523 	}
1524 
1525 	/* Is SRATE specified. */
1526 	if (attrp->pa_srate.r_srate) {
1527 		mpr_req->Rate = attrp->pa_srate.r_srate;
1528 		mpr_req->RateSelector = attrp->pa_srate.r_selector;
1529 
1530 		c_mask |= SA_MPR_COMPMASK_RATE |
1531 		    SA_MPR_COMPMASK_RATESELECTOR;
1532 	}
1533 
1534 	/* Is MTU specified. */
1535 	if (attrp->pa_mtu.r_mtu) {
1536 		mpr_req->Mtu = attrp->pa_mtu.r_mtu;
1537 		mpr_req->MtuSelector = attrp->pa_mtu.r_selector;
1538 
1539 		c_mask |= SA_MPR_COMPMASK_MTU |
1540 		    SA_MPR_COMPMASK_MTUSELECTOR;
1541 	}
1542 
1543 	/* Is P_Key Specified or obtained during Service Look-up. */
1544 	if (dinfo->p_key) {
1545 		mpr_req->P_Key = dinfo->p_key;
1546 		c_mask |= SA_MPR_COMPMASK_PKEY;
1547 	}
1548 
1549 	/* We always get REVERSIBLE paths. */
1550 	mpr_req->Reversible = 1;
1551 	c_mask |= SA_MPR_COMPMASK_REVERSIBLE;
1552 
1553 	if (p_arg->flags & IBT_PATH_AVAIL) {
1554 		mpr_req->IndependenceSelector = 1;
1555 		c_mask |= SA_MPR_COMPMASK_INDEPSEL;
1556 	}
1557 
1558 	/* we will not specify how many records we want. */
1559 
1560 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
1561 
1562 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: CMask: %llX Pkey: %X",
1563 	    c_mask, mpr_req->P_Key);
1564 
1565 	/* Contact SA Access to retrieve Path Records. */
1566 	access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
1567 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
1568 	access_args.sq_component_mask = c_mask;
1569 	access_args.sq_template = mpr_req;
1570 	access_args.sq_template_length = sizeof (sa_multipath_record_t);
1571 	access_args.sq_callback = NULL;
1572 	access_args.sq_callback_arg = NULL;
1573 
1574 	retval = ibcm_contact_sa_access(sl->p_saa_hdl, &access_args, &length,
1575 	    &results_p);
1576 	if (retval != IBT_SUCCESS) {
1577 		*num_path = 0;  /* Update the return count. */
1578 		kmem_free(mpr_req, template_len);
1579 		return (retval);
1580 	}
1581 
1582 	num_rec = length / sizeof (sa_path_record_t);
1583 
1584 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: Found %d Paths",
1585 	    num_rec);
1586 
1587 	found = 0;
1588 	if ((results_p != NULL) && (num_rec > 0)) {
1589 		/* Update the PathInfo with the response Path Records */
1590 		pr_resp = (sa_path_record_t *)results_p;
1591 
1592 		for (i = 0; i < num_rec; i++) {
1593 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1594 			    "P[%d]: SG %llX, DG %llX", i,
1595 			    pr_resp[i].SGID.gid_guid, pr_resp[i].DGID.gid_guid);
1596 		}
1597 
1598 		if (p_arg->flags & (IBT_PATH_APM | IBT_PATH_AVAIL)) {
1599 			sa_path_record_t *p_resp = NULL, *a_resp = NULL;
1600 			sa_path_record_t *p_tmp = NULL, *a_tmp = NULL;
1601 			int		p_found = 0, a_found = 0;
1602 			ib_gid_t	p_sg, a_sg, p_dg, a_dg;
1603 			int		p_tmp_found = 0, a_tmp_found = 0;
1604 
1605 			p_sg = gid_s_ptr[0];
1606 			if (sgid_cnt > 1)
1607 				a_sg = gid_s_ptr[1];
1608 			else
1609 				a_sg = p_sg;
1610 
1611 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1612 			    "REQ: P_SG: %llX, A_SG: %llX",
1613 			    p_sg.gid_guid, a_sg.gid_guid);
1614 
1615 			p_dg = gid_s_ptr[sgid_cnt];
1616 			if (dgid_cnt > 1)
1617 				a_dg = gid_s_ptr[sgid_cnt + 1];
1618 			else
1619 				a_dg = p_dg;
1620 
1621 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: "
1622 			    "REQ: P_DG: %llX, A_DG: %llX",
1623 			    p_dg.gid_guid, a_dg.gid_guid);
1624 
1625 			/*
1626 			 * If SGID and/or DGID is specified by user, make sure
1627 			 * he gets his primary-path on those node points.
1628 			 */
1629 			for (i = 0; i < num_rec; i++, pr_resp++) {
1630 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec:"
1631 				    " PF %d, AF %d,\n\t\t P[%d] = SG: %llX, "
1632 				    "DG: %llX", p_found, a_found, i,
1633 				    pr_resp->SGID.gid_guid,
1634 				    pr_resp->DGID.gid_guid);
1635 
1636 				if ((!p_found) &&
1637 				    (p_dg.gid_guid == pr_resp->DGID.gid_guid)) {
1638 					IBTF_DPRINTF_L3(cmlog,
1639 					    "ibcm_get_multi_pathrec: "
1640 					    "Pri DGID Match.. ");
1641 					if (p_sg.gid_guid ==
1642 					    pr_resp->SGID.gid_guid) {
1643 						p_found = 1;
1644 						p_resp = pr_resp;
1645 						IBTF_DPRINTF_L3(cmlog,
1646 						    "ibcm_get_multi_pathrec: "
1647 						    "Primary Path Found");
1648 
1649 						if (a_found)
1650 							break;
1651 						else
1652 							continue;
1653 					} else if ((!p_tmp_found) &&
1654 					    (a_sg.gid_guid ==
1655 					    pr_resp->SGID.gid_guid)) {
1656 						p_tmp_found = 1;
1657 						p_tmp = pr_resp;
1658 						IBTF_DPRINTF_L3(cmlog,
1659 						    "ibcm_get_multi_pathrec: "
1660 						    "Tmp Pri Path Found");
1661 					}
1662 					IBTF_DPRINTF_L3(cmlog,
1663 					    "ibcm_get_multi_pathrec:"
1664 					    "Pri SGID Don't Match.. ");
1665 				}
1666 
1667 				if ((!a_found) &&
1668 				    (a_dg.gid_guid == pr_resp->DGID.gid_guid)) {
1669 					IBTF_DPRINTF_L3(cmlog,
1670 					    "ibcm_get_multi_pathrec:"
1671 					    "Alt DGID Match.. ");
1672 					if (a_sg.gid_guid ==
1673 					    pr_resp->SGID.gid_guid) {
1674 						a_found = 1;
1675 						a_resp = pr_resp;
1676 
1677 						IBTF_DPRINTF_L3(cmlog,
1678 						    "ibcm_get_multi_pathrec:"
1679 						    "Alternate Path Found ");
1680 
1681 						if (p_found)
1682 							break;
1683 						else
1684 							continue;
1685 					} else if ((!a_tmp_found) &&
1686 					    (p_sg.gid_guid ==
1687 					    pr_resp->SGID.gid_guid)) {
1688 						a_tmp_found = 1;
1689 						a_tmp = pr_resp;
1690 
1691 						IBTF_DPRINTF_L3(cmlog,
1692 						    "ibcm_get_multi_pathrec:"
1693 						    "Tmp Alt Path Found ");
1694 					}
1695 					IBTF_DPRINTF_L3(cmlog,
1696 					    "ibcm_get_multi_pathrec:"
1697 					    "Alt SGID Don't Match.. ");
1698 				}
1699 			}
1700 
1701 			if ((p_found == 0) && (a_found == 0) &&
1702 			    (p_tmp_found == 0) && (a_tmp_found == 0)) {
1703 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec:"
1704 				    " Path to desired node points NOT "
1705 				    "Available.");
1706 				retval = IBT_PATH_RECORDS_NOT_FOUND;
1707 				goto get_mpr_end;
1708 			}
1709 
1710 			if (p_resp == NULL) {
1711 				if (a_resp != NULL) {
1712 					p_resp = a_resp;
1713 					a_resp = NULL;
1714 				} else if (p_tmp != NULL) {
1715 					p_resp = p_tmp;
1716 					p_tmp = NULL;
1717 				} else if (a_tmp != NULL) {
1718 					p_resp = a_tmp;
1719 					a_tmp = NULL;
1720 				}
1721 			}
1722 			if (a_resp == NULL) {
1723 				if (a_tmp != NULL) {
1724 					a_resp = a_tmp;
1725 					a_tmp = NULL;
1726 				} else if (p_tmp != NULL) {
1727 					a_resp = p_tmp;
1728 					p_tmp = NULL;
1729 				}
1730 			}
1731 
1732 			/* Fill in Primary Path */
1733 			retval = ibcm_update_pri(p_resp, sl, dinfo,
1734 			    &paths[found]);
1735 			if (retval != IBT_SUCCESS)
1736 				goto get_mpr_end;
1737 
1738 			if (p_arg->flags & IBT_PATH_APM) {
1739 				/* Fill in Alternate Path */
1740 				if (a_resp != NULL) {
1741 					/*
1742 					 * a_resp will point to AltPathInfo
1743 					 * buffer.
1744 					 */
1745 					retval = ibcm_update_cep_info(a_resp,
1746 					    sl, NULL,
1747 					    &paths[found].pi_alt_cep_path);
1748 					if (retval != IBT_SUCCESS)
1749 						goto get_mpr_end;
1750 
1751 					/* Update some leftovers */
1752 					paths[found].pi_alt_pkt_lt =
1753 					    a_resp->PacketLifeTime;
1754 				} else {
1755 					IBTF_DPRINTF_L3(cmlog,
1756 					    "ibcm_get_multi_pathrec:"
1757 					    " Alternate Path NOT Available.");
1758 					retval = IBT_INSUFF_DATA;
1759 				}
1760 				found++;
1761 			} else if (p_arg->flags & IBT_PATH_AVAIL) {
1762 				found++;
1763 
1764 				if (found < *num_path) {
1765 
1766 					/* Fill in second Path */
1767 					if (a_resp != NULL) {
1768 						retval = ibcm_update_pri(a_resp,
1769 						    sl, dinfo, &paths[found]);
1770 						if (retval != IBT_SUCCESS)
1771 							goto get_mpr_end;
1772 						else
1773 							found++;
1774 					} else {
1775 						IBTF_DPRINTF_L3(cmlog,
1776 						    "ibcm_get_multi_pathrec: "
1777 						    "SecondPath NOT Available");
1778 						retval = IBT_INSUFF_DATA;
1779 					}
1780 				}
1781 			}
1782 		} else {	/* If NOT APM */
1783 			boolean_t	check_pkey = B_FALSE;
1784 
1785 			/* mark flag whether to validate PKey or not. */
1786 			if ((dinfo->p_key == 0) && (dinfo->dest[0].d_pkey != 0))
1787 				check_pkey = B_TRUE;
1788 
1789 			for (i = 0; i < num_rec; i++, pr_resp++) {
1790 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec:"
1791 				    " PKeyCheck - %s, PKey=0x%X, DGID(%llX)",
1792 				    ((check_pkey == B_TRUE)?"REQD":"NOT_REQD"),
1793 				    pr_resp->P_Key, pr_resp->DGID.gid_guid);
1794 
1795 				if (check_pkey) {
1796 					boolean_t	match_found = B_FALSE;
1797 
1798 					/* For all DGIDs */
1799 					for (k = 0; k < dinfo->num_dest; k++) {
1800 						if (dinfo->dest[k].d_tag != 0)
1801 							continue;
1802 
1803 						if ((dinfo->dest[k].d_gid.
1804 						    gid_guid ==
1805 						    pr_resp->DGID.gid_guid) &&
1806 						    (dinfo->dest[k].d_pkey ==
1807 						    pr_resp->P_Key)) {
1808 							match_found = B_TRUE;
1809 							break;
1810 						}
1811 					}
1812 					if (!match_found)
1813 						continue;
1814 				}
1815 				/* Fill in Primary Path */
1816 				retval = ibcm_update_pri(pr_resp, sl, dinfo,
1817 				    &paths[found]);
1818 				if (retval != IBT_SUCCESS)
1819 					continue;
1820 
1821 				if (++found == *num_path)
1822 					break;
1823 			}
1824 		}
1825 get_mpr_end:
1826 		kmem_free(results_p, length);
1827 	}
1828 	kmem_free(mpr_req, template_len);
1829 
1830 	if (found == 0)
1831 		retval = IBT_PATH_RECORDS_NOT_FOUND;
1832 	else if (found != *num_path)
1833 		retval = IBT_INSUFF_DATA;
1834 	else
1835 		retval = IBT_SUCCESS;
1836 
1837 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_multi_pathrec: Done (status %d). "
1838 	    "Found %d/%d Paths", retval, found, *num_path);
1839 
1840 	*num_path = found;	/* Update the return count. */
1841 
1842 	return (retval);
1843 }
1844 
1845 
1846 /*
1847  * Update the output path records buffer with the values as obtained from
1848  * SA Access retrieve call results for Path Records.
1849  */
1850 static ibt_status_t
1851 ibcm_update_cep_info(sa_path_record_t *prec_resp, ibtl_cm_port_list_t *sl,
1852     ibtl_cm_hca_port_t *hport, ibt_cep_path_t *cep_p)
1853 {
1854 	ibt_status_t	retval;
1855 	int		i;
1856 
1857 	IBCM_DUMP_PATH_REC(prec_resp);
1858 
1859 	/*
1860 	 * If path's packet life time is more than 4 seconds, IBCM cannot
1861 	 * handle this path connection, so discard this path record.
1862 	 */
1863 	if (prec_resp->PacketLifeTime > ibcm_max_ib_pkt_lt) {
1864 		IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: Path's Packet "
1865 		    "LifeTime too high %d, Maximum allowed %d IB Time (4 sec)",
1866 		    prec_resp->PacketLifeTime, ibcm_max_ib_pkt_lt);
1867 		return (ibt_get_module_failure(IBT_FAILURE_IBSM, 0));
1868 	}
1869 
1870 	if ((prec_resp->Mtu > IB_MTU_4K) || (prec_resp->Mtu < IB_MTU_256)) {
1871 		IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: MTU (%d) from "
1872 		    "pathrecord is invalid, reject it.", prec_resp->Mtu);
1873 		return (ibt_get_module_failure(IBT_FAILURE_IBSM, 0));
1874 	}
1875 
1876 	/* Source Node Information. */
1877 	cep_p->cep_adds_vect.av_sgid = prec_resp->SGID;
1878 	if (hport != NULL) {
1879 		/* Convert P_Key to P_Key_Index */
1880 		retval = ibt_pkey2index_byguid(hport->hp_hca_guid,
1881 		    hport->hp_port, prec_resp->P_Key, &cep_p->cep_pkey_ix);
1882 		if (retval != IBT_SUCCESS) {
1883 			/* Failed to get pkey_index from pkey */
1884 			IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: "
1885 			    "Pkey2Index (PKey = %X) conversion failed: %d",
1886 			    prec_resp->P_Key, retval);
1887 			return (ibt_get_module_failure(IBT_FAILURE_IBSM, 0));
1888 		}
1889 		cep_p->cep_adds_vect.av_sgid_ix = hport->hp_sgid_ix;
1890 		cep_p->cep_adds_vect.av_src_path =
1891 		    prec_resp->SLID - hport->hp_base_lid;
1892 		cep_p->cep_adds_vect.av_port_num = cep_p->cep_hca_port_num =
1893 		    hport->hp_port;
1894 	} else if (sl != NULL) {
1895 		for (i = 0; i < sl->p_count; i++) {
1896 			if (prec_resp->SGID.gid_guid == sl[i].p_sgid.gid_guid) {
1897 				/* Convert P_Key to P_Key_Index */
1898 				retval = ibt_pkey2index_byguid(sl[i].p_hca_guid,
1899 				    sl[i].p_port_num, prec_resp->P_Key,
1900 				    &cep_p->cep_pkey_ix);
1901 				if (retval != IBT_SUCCESS) {
1902 					/* Failed to get pkey_index from pkey */
1903 					IBTF_DPRINTF_L2(cmlog,
1904 					    "ibcm_update_cep_info: Pkey2Index "
1905 					    "(PKey = %X) conversion failed: %d",
1906 					    prec_resp->P_Key, retval);
1907 					return (ibt_get_module_failure(
1908 					    IBT_FAILURE_IBSM, 0));
1909 				}
1910 
1911 				cep_p->cep_adds_vect.av_sgid_ix =
1912 				    sl[i].p_sgid_ix;
1913 				cep_p->cep_adds_vect.av_src_path =
1914 				    prec_resp->SLID - sl[i].p_base_lid;
1915 				cep_p->cep_adds_vect.av_port_num =
1916 				    sl[i].p_port_num;
1917 				cep_p->cep_hca_port_num = sl[i].p_port_num;
1918 
1919 				break;
1920 			}
1921 		}
1922 	} else {
1923 		IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: Sl or Hport "
1924 		    "must be non-null");
1925 		return (IBT_INVALID_PARAM);
1926 	}
1927 
1928 	if (prec_resp->Rate) {
1929 		cep_p->cep_adds_vect.av_srate = prec_resp->Rate;
1930 	} else {
1931 		IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: SRate (%d) from "
1932 		    "pathrecord is invalid, reject it.", prec_resp->Rate);
1933 		return (ibt_get_module_failure(IBT_FAILURE_IBSM, 0));
1934 	}
1935 	/*
1936 	 * If both Source and Destination GID prefix are same, then GRH is not
1937 	 * valid, so make it as false, else set this field as true.
1938 	 */
1939 	if (prec_resp->SGID.gid_prefix == prec_resp->DGID.gid_prefix)
1940 		cep_p->cep_adds_vect.av_send_grh = B_FALSE;
1941 	else
1942 		cep_p->cep_adds_vect.av_send_grh = B_TRUE;
1943 
1944 	/* SGID and SGID Index. */
1945 	cep_p->cep_adds_vect.av_sgid = prec_resp->SGID;
1946 	cep_p->cep_adds_vect.av_flow = prec_resp->FlowLabel;
1947 	cep_p->cep_adds_vect.av_tclass = prec_resp->TClass;
1948 	cep_p->cep_adds_vect.av_hop = prec_resp->HopLimit;
1949 
1950 	/* Address Vector Definition. */
1951 	cep_p->cep_adds_vect.av_dlid = prec_resp->DLID;
1952 	cep_p->cep_adds_vect.av_srvl = prec_resp->SL;
1953 
1954 	/* DGID */
1955 	cep_p->cep_adds_vect.av_dgid = prec_resp->DGID;
1956 
1957 	/* CEP Timeout is NOT filled in by PATH routines. */
1958 	cep_p->cep_timeout = 0;
1959 
1960 	IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: Done. Port=%d, PKey=%X\n"
1961 	    "SGID=%llX:%llX DGID=%llX:%llX", cep_p->cep_adds_vect.av_port_num,
1962 	    prec_resp->P_Key,
1963 	    prec_resp->SGID.gid_prefix, prec_resp->SGID.gid_guid,
1964 	    prec_resp->DGID.gid_prefix, prec_resp->DGID.gid_guid);
1965 
1966 	return (IBT_SUCCESS);
1967 }
1968 
1969 
1970 static void
1971 ibcm_fill_svcinfo(sa_service_record_t *sr_resp, ibcm_dest_t *dest)
1972 {
1973 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dest))
1974 
1975 	dest->d_gid = sr_resp->ServiceGID;
1976 	dest->d_sid = sr_resp->ServiceID;
1977 	ibcm_swizzle_to_srv(sr_resp->ServiceData, &dest->d_sdata);
1978 	dest->d_pkey = sr_resp->ServiceP_Key;
1979 
1980 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*dest))
1981 
1982 	IBTF_DPRINTF_L3(cmlog, "ibcm_fill_svcinfo: SID(%llX), GID(%llX:%llX)"
1983 	    "\n\tSvcPKey 0x%X", dest->d_sid, dest->d_gid.gid_prefix,
1984 	    dest->d_gid.gid_guid, dest->d_pkey);
1985 }
1986 
1987 
1988 static ib_gid_t
1989 ibcm_saa_get_agid(ibtl_cm_port_list_t *sl, ib_gid_t *gidp, uint_t ngid)
1990 {
1991 	int		k, l;
1992 	ib_gid_t	a_gid;
1993 
1994 	a_gid.gid_prefix = a_gid.gid_guid = 0;
1995 
1996 	for (k = 0; k < sl->p_count; k++) {
1997 		for (l = 0; l < ngid; l++) {
1998 
1999 			if (gidp->gid_prefix == sl->p_sgid.gid_prefix) {
2000 				a_gid = *gidp;
2001 				break;
2002 			}
2003 			if (a_gid.gid_guid && a_gid.gid_prefix)
2004 				break;
2005 			gidp++;
2006 		}
2007 		if (a_gid.gid_guid && a_gid.gid_prefix)
2008 			break;
2009 		sl++;
2010 	}
2011 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_get_agid: AltGID = %llX:%llX",
2012 	    a_gid.gid_prefix, a_gid.gid_guid);
2013 
2014 	return (a_gid);
2015 }
2016 
2017 /*
2018  * Perform SA Access to retrieve Service Records.
2019  * On Success, returns ServiceID and ServiceGID info in '*dinfo'.
2020  */
2021 static ibt_status_t
2022 ibcm_saa_service_rec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
2023     ibcm_dinfo_t *dinfo)
2024 {
2025 	sa_service_record_t	svcrec_req;
2026 	sa_service_record_t	*svcrec_resp;
2027 	void			*results_p;
2028 	uint64_t		component_mask = 0;
2029 	size_t			length;
2030 	uint8_t			i, j, k, rec_found, s;
2031 	ibmf_saa_access_args_t	access_args;
2032 	ibt_status_t		retval;
2033 	ibt_path_attr_t		*attrp = &p_arg->attr;
2034 	uint64_t		tmp_sd_flag = attrp->pa_sd_flags;
2035 	uint8_t			num_req;
2036 
2037 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec(%p, %p)", p_arg, sl);
2038 
2039 	bzero(&svcrec_req, sizeof (svcrec_req));
2040 
2041 	/* Service Name */
2042 	if ((attrp->pa_sname != NULL) && (strlen(attrp->pa_sname) != 0)) {
2043 		(void) strncpy((char *)(svcrec_req.ServiceName),
2044 		    attrp->pa_sname, IB_SVC_NAME_LEN);
2045 
2046 		component_mask |= SA_SR_COMPMASK_NAME;
2047 	}
2048 
2049 	/* Service ID */
2050 	if (attrp->pa_sid) {
2051 		svcrec_req.ServiceID = attrp->pa_sid;
2052 		component_mask |= SA_SR_COMPMASK_ID;
2053 	}
2054 
2055 	/* Is P_Key Specified. */
2056 	if (p_arg->flags & IBT_PATH_PKEY) {
2057 		svcrec_req.ServiceP_Key = attrp->pa_pkey;
2058 		component_mask |= SA_SR_COMPMASK_PKEY;
2059 	}
2060 
2061 	/* Is ServiceData Specified. */
2062 	if (attrp->pa_sd_flags != IBT_NO_SDATA) {
2063 		/* Handle endianess for service data. */
2064 		ibcm_swizzle_from_srv(&attrp->pa_sdata, svcrec_req.ServiceData);
2065 
2066 		/*
2067 		 * Lets not interpret each and every ServiceData flags,
2068 		 * just pass it on to SAA. Shift the flag, to suit
2069 		 * SA_SR_COMPMASK_ALL_DATA definition.
2070 		 */
2071 		component_mask |= (tmp_sd_flag << 7);
2072 	}
2073 
2074 	if (dinfo->num_dest == 1) {
2075 
2076 		/* If a single DGID is specified, provide it */
2077 		svcrec_req.ServiceGID = dinfo->dest->d_gid;
2078 		component_mask |= SA_SR_COMPMASK_GID;
2079 
2080 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec:%llX:%llX",
2081 		    svcrec_req.ServiceGID.gid_prefix,
2082 		    svcrec_req.ServiceGID.gid_guid);
2083 	}
2084 
2085 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2086 	    "Perform SA Access: Mask: 0x%X", component_mask);
2087 
2088 	/*
2089 	 * Call in SA Access retrieve routine to get Service Records.
2090 	 *
2091 	 * SA Access framework allocated memory for the "results_p".
2092 	 * Make sure to deallocate once we are done with the results_p.
2093 	 * The size of the buffer allocated will be as returned in
2094 	 * "length" field.
2095 	 */
2096 	access_args.sq_attr_id = SA_SERVICERECORD_ATTRID;
2097 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
2098 	access_args.sq_component_mask = component_mask;
2099 	access_args.sq_template = &svcrec_req;
2100 	access_args.sq_template_length = sizeof (sa_service_record_t);
2101 	access_args.sq_callback = NULL;
2102 	access_args.sq_callback_arg = NULL;
2103 
2104 	for (s = 0; s < sl->p_count; s++) {
2105 		retval = ibcm_contact_sa_access(sl[s].p_saa_hdl, &access_args,
2106 		    &length, &results_p);
2107 		if (retval != IBT_SUCCESS)
2108 			if (sl[s].p_multi & IBTL_CM_MULTI_SM)
2109 				continue;
2110 			else
2111 				return (retval);
2112 
2113 		if ((results_p == NULL) || (length == 0)) {
2114 			IBTF_DPRINTF_L2(cmlog, "ibcm_saa_service_rec: SvcRec "
2115 			    "Not Found: res_p %p, len %d", results_p, length);
2116 			if (sl[s].p_multi & IBTL_CM_MULTI_SM) {
2117 				retval = IBT_SERVICE_RECORDS_NOT_FOUND;
2118 				continue;
2119 			} else
2120 				return (IBT_SERVICE_RECORDS_NOT_FOUND);
2121 		}
2122 
2123 		/* if we are here, we got some records. so break. */
2124 		break;
2125 	}
2126 
2127 	if (retval != IBT_SUCCESS)
2128 		return (retval);
2129 
2130 	num_req = length / sizeof (sa_service_record_t);
2131 
2132 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Got %d Service Records.",
2133 	    num_req);
2134 
2135 	svcrec_resp = (sa_service_record_t *)results_p;
2136 	rec_found = 0;
2137 
2138 	/* Update the return values. */
2139 	if (dinfo->num_dest) {
2140 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Get ServiceRec "
2141 		    "for Specified DGID: %d", dinfo->num_dest);
2142 
2143 		for (i = 0; i < num_req; i++, svcrec_resp++) {
2144 			/* Limited P_Key is NOT supported as of now!. */
2145 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2146 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2147 				    "SvcPkey 0x%X limited, reject the record.",
2148 				    svcrec_resp->ServiceP_Key);
2149 				continue;
2150 			}
2151 
2152 			for (j = 0; j < dinfo->num_dest; j++) {
2153 				if (dinfo->dest[j].d_gid.gid_guid ==
2154 				    svcrec_resp->ServiceGID.gid_guid) {
2155 					ibcm_fill_svcinfo(svcrec_resp,
2156 					    &dinfo->dest[j]);
2157 					rec_found++;
2158 				}
2159 				if (rec_found == dinfo->num_dest)
2160 					break;
2161 			}
2162 			if (rec_found == dinfo->num_dest)
2163 				break;
2164 		}
2165 		if (rec_found != dinfo->num_dest) {
2166 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Did NOT "
2167 			    "find ServiceRec for all DGIDs: (%d/%d)", rec_found,
2168 			    dinfo->num_dest);
2169 			retval = IBT_INSUFF_DATA;
2170 		}
2171 	} else if (p_arg->flags & IBT_PATH_APM) {
2172 		ib_gid_t		p_gid, a_gid, last_p_gid;
2173 		ib_gid_t		*gidp = NULL;
2174 		uint_t			n_gids;
2175 		sa_service_record_t	*stmp;
2176 		boolean_t		pri_fill_done = B_FALSE;
2177 		boolean_t		alt_fill_done = B_FALSE;
2178 		ib_pkey_t		p_pkey = 0, a_pkey = 0;
2179 
2180 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Need to "
2181 		    "find ServiceRec that can satisfy APM");
2182 
2183 		p_gid.gid_prefix = p_gid.gid_guid = 0;
2184 		a_gid.gid_prefix = a_gid.gid_guid = 0;
2185 		last_p_gid.gid_prefix = last_p_gid.gid_guid = 0;
2186 
2187 		for (i = 0; i < num_req; i++, svcrec_resp++) {
2188 			ibt_status_t	ret;
2189 			boolean_t	is_this_on_local_node = B_FALSE;
2190 
2191 			/* Limited P_Key is NOT supported as of now!. */
2192 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2193 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2194 				    "SvcPkey 0x%X limited, reject the record.",
2195 				    svcrec_resp->ServiceP_Key);
2196 				continue;
2197 			}
2198 
2199 			p_gid = svcrec_resp->ServiceGID;
2200 
2201 			/* Let's avoid LoopBack Nodes. */
2202 			for (j = 0; j < sl->p_count; j++) {
2203 				if (p_gid.gid_guid == sl[j].p_sgid.gid_guid) {
2204 					is_this_on_local_node = B_TRUE;
2205 
2206 					IBTF_DPRINTF_L3(cmlog,
2207 					    "ibcm_saa_service_rec: ServiceGID "
2208 					    "%llX:%llX is on Local Node, "
2209 					    "search for remote.",
2210 					    p_gid.gid_prefix, p_gid.gid_guid);
2211 				}
2212 			}
2213 
2214 			if (is_this_on_local_node) {
2215 				if ((i + 1) < num_req) {
2216 					p_gid.gid_prefix = 0;
2217 					p_gid.gid_guid = 0;
2218 					continue;
2219 				} else if (last_p_gid.gid_prefix != 0) {
2220 					p_gid = last_p_gid;
2221 					break;
2222 				}
2223 			}
2224 
2225 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2226 			    "Finally let Primary DGID = %llX:%llX",
2227 			    p_gid.gid_prefix, p_gid.gid_guid);
2228 
2229 			ret = ibt_get_companion_port_gids(p_gid, 0, 0,
2230 			    &gidp, &n_gids);
2231 			if (ret == IBT_SUCCESS) {
2232 				IBTF_DPRINTF_L3(cmlog,
2233 				    "ibcm_saa_service_rec: Found %d "
2234 				    "CompGID for %llX:%llX", n_gids,
2235 				    p_gid.gid_prefix, p_gid.gid_guid);
2236 
2237 				stmp = (sa_service_record_t *)results_p;
2238 				a_gid.gid_prefix = a_gid.gid_guid = 0;
2239 
2240 				if (sl->p_multi & IBTL_CM_MULTI_SM) {
2241 					/* validate sn_pfx */
2242 					a_gid = ibcm_saa_get_agid(sl,
2243 					    gidp, n_gids);
2244 				} else {
2245 					for (k = 0; k < num_req; k++) {
2246 						ib_gid_t sg = stmp->ServiceGID;
2247 
2248 						IBTF_DPRINTF_L3(cmlog,
2249 						    "ibcm_saa_service_rec: "
2250 						    "SvcGID[%d] = %llX:%llX", k,
2251 						    sg.gid_prefix, sg.gid_guid);
2252 
2253 						for (j = 0; j < n_gids; j++) {
2254 							if (gidp[j].gid_guid ==
2255 							    sg.gid_guid) {
2256 								a_gid = gidp[j];
2257 								break;
2258 							}
2259 						}
2260 						if (a_gid.gid_guid)
2261 							break;
2262 						stmp++;
2263 					}
2264 					if (a_gid.gid_guid == 0) {
2265 						/* Rec not found for Alt. */
2266 						for (j = 0; j < n_gids; j++) {
2267 							if (gidp[j].gid_prefix
2268 							    == p_gid.
2269 							    gid_prefix) {
2270 								a_gid = gidp[j];
2271 								break;
2272 							}
2273 						}
2274 					}
2275 				}
2276 				kmem_free(gidp,
2277 				    n_gids * sizeof (ib_gid_t));
2278 
2279 				if (a_gid.gid_guid)
2280 					break;
2281 			} else if (ret == IBT_GIDS_NOT_FOUND) {
2282 				last_p_gid = p_gid;
2283 				IBTF_DPRINTF_L3(cmlog,
2284 				    "ibcm_saa_service_rec: Didn't find "
2285 				    "CompGID for %llX:%llX, ret=%d",
2286 				    p_gid.gid_prefix, p_gid.gid_guid,
2287 				    ret);
2288 			} else {
2289 				IBTF_DPRINTF_L3(cmlog,
2290 				    "ibcm_saa_service_rec: Call to "
2291 				    "ibt_get_companion_port_gids(%llX:"
2292 				    "%llX) Failed = %d",
2293 				    p_gid.gid_prefix, p_gid.gid_guid,
2294 				    ret);
2295 			}
2296 		}
2297 
2298 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: \n\t"
2299 		    "Pri DGID(%llX:%llX), Alt DGID(%llX:%llX)",
2300 		    p_gid.gid_prefix, p_gid.gid_guid, a_gid.gid_prefix,
2301 		    a_gid.gid_guid);
2302 
2303 		svcrec_resp = (sa_service_record_t *)results_p;
2304 
2305 		for (i = 0, j = 0; i < num_req; i++, svcrec_resp++) {
2306 			/* Limited P_Key is NOT supported as of now!. */
2307 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2308 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2309 				    "SvcPkey 0x%X limited, reject the record.",
2310 				    svcrec_resp->ServiceP_Key);
2311 				continue;
2312 			}
2313 
2314 			if ((!pri_fill_done) && (p_gid.gid_guid ==
2315 			    svcrec_resp->ServiceGID.gid_guid)) {
2316 				p_pkey = svcrec_resp->ServiceP_Key;
2317 				if ((a_pkey != 0) &&
2318 				    (a_pkey != p_pkey)) {
2319 					IBTF_DPRINTF_L3(cmlog,
2320 					    "ibcm_saa_service_rec: "
2321 					    "Pri(0x%X) & Alt (0x%X) "
2322 					    "PKey must match.",
2323 					    p_pkey, a_pkey);
2324 					p_pkey = 0;
2325 					continue;
2326 				}
2327 				ibcm_fill_svcinfo(svcrec_resp,
2328 				    &dinfo->dest[j++]);
2329 				rec_found++;
2330 				pri_fill_done = B_TRUE;
2331 			} else if ((!alt_fill_done) && (a_gid.gid_guid ==
2332 			    svcrec_resp->ServiceGID.gid_guid)) {
2333 				a_pkey = svcrec_resp->ServiceP_Key;
2334 				if ((p_pkey != 0) &&
2335 				    (a_pkey != p_pkey)) {
2336 					IBTF_DPRINTF_L3(cmlog,
2337 					    "ibcm_saa_service_rec: "
2338 					    "Pri(0x%X) & Alt (0x%X) "
2339 					    "PKey must match.",
2340 					    p_pkey, a_pkey);
2341 					a_pkey = 0;
2342 					continue;
2343 				}
2344 				ibcm_fill_svcinfo(svcrec_resp,
2345 				    &dinfo->dest[j++]);
2346 				rec_found++;
2347 				alt_fill_done = B_TRUE;
2348 			}
2349 
2350 			if (rec_found == 2)
2351 				break;
2352 		}
2353 		if ((!alt_fill_done) && (a_gid.gid_guid)) {
2354 			dinfo->dest[j].d_gid = a_gid;
2355 			dinfo->dest[j].d_pkey = p_pkey;
2356 			rec_found++;
2357 			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2358 			    "Let Alt Pkey=%X, DGID=%llX:%llX", p_pkey,
2359 			    a_gid.gid_prefix, a_gid.gid_guid);
2360 		}
2361 
2362 		if (rec_found == 1)
2363 			retval = IBT_INSUFF_DATA;
2364 	} else if (p_arg->flags & IBT_PATH_MULTI_SVC_DEST) {
2365 		for (i = 0; i < num_req; i++, svcrec_resp++) {
2366 			ib_gid_t	p_gid;
2367 			boolean_t	is_this_on_local_node = B_FALSE;
2368 
2369 			/* Limited P_Key is NOT supported as of now!. */
2370 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2371 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2372 				    "SvcPkey 0x%X limited, reject the record.",
2373 				    svcrec_resp->ServiceP_Key);
2374 				continue;
2375 			}
2376 
2377 			p_gid = svcrec_resp->ServiceGID;
2378 
2379 			/* Let's avoid LoopBack Nodes. */
2380 			for (j = 0; j < sl->p_count; j++) {
2381 				if (p_gid.gid_guid == sl[j].p_sgid.gid_guid) {
2382 					is_this_on_local_node = B_TRUE;
2383 					IBTF_DPRINTF_L3(cmlog,
2384 					    "ibcm_saa_service_rec: ServiceGID "
2385 					    "%llX:%llX is on Local Node, "
2386 					    "search for remote.",
2387 					    p_gid.gid_prefix, p_gid.gid_guid);
2388 				}
2389 			}
2390 
2391 			if (is_this_on_local_node)
2392 				if ((i + 1) < num_req)
2393 					continue;
2394 
2395 			IBTF_DPRINTF_L4(cmlog, "ibcm_saa_service_rec: "
2396 			    "Found ServiceGID = %llX:%llX",
2397 			    p_gid.gid_prefix, p_gid.gid_guid);
2398 
2399 			ibcm_fill_svcinfo(svcrec_resp,
2400 			    &dinfo->dest[rec_found]);
2401 			rec_found++;
2402 			if (rec_found == p_arg->max_paths)
2403 				break;
2404 		}
2405 
2406 		if (rec_found < p_arg->max_paths)
2407 			retval = IBT_INSUFF_DATA;
2408 	} else {
2409 		for (i = 0; i < num_req; i++) {
2410 			/* Limited P_Key is NOT supported as of now!. */
2411 			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2412 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2413 				    "SvcPkey 0x%X limited, reject the record.",
2414 				    svcrec_resp->ServiceP_Key);
2415 				svcrec_resp++;
2416 				continue;
2417 			}
2418 
2419 			ibcm_fill_svcinfo(svcrec_resp, &dinfo->dest[0]);
2420 			rec_found = 1;
2421 
2422 			/* Avoid having loopback node */
2423 			if (svcrec_resp->ServiceGID.gid_guid !=
2424 			    sl->p_sgid.gid_guid) {
2425 				break;
2426 			} else {
2427 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2428 				    "avoid LoopBack node.");
2429 				svcrec_resp++;
2430 			}
2431 		}
2432 	}
2433 
2434 	/* Deallocate the memory for results_p. */
2435 	kmem_free(results_p, length);
2436 	if (dinfo->num_dest == 0)
2437 		dinfo->num_dest = rec_found;
2438 
2439 	/*
2440 	 * Check out whether all Service Path we looking for are on the same
2441 	 * P_key. If yes, then set the global p_key field with that value,
2442 	 * to make it easy during SA Path Query.
2443 	 */
2444 	if ((dinfo->num_dest) && (dinfo->p_key == 0)) {
2445 		ib_pkey_t	pk = dinfo->dest[0].d_pkey;
2446 
2447 		if (dinfo->num_dest == 1) {
2448 			dinfo->p_key = pk;
2449 		} else {
2450 			for (i = 1; i < (dinfo->num_dest - 1); i++) {
2451 				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2452 				    "pk= 0x%X, pk[%d]= 0x%X", pk, i,
2453 				    dinfo->dest[i].d_pkey);
2454 				if (pk != dinfo->dest[i].d_pkey) {
2455 					dinfo->p_key = 0;
2456 					break;
2457 				} else {
2458 					dinfo->p_key = pk;
2459 				}
2460 			}
2461 		}
2462 	}
2463 
2464 	if (rec_found == 0) {
2465 		IBTF_DPRINTF_L2(cmlog, "ibcm_saa_service_rec: "
2466 		    "ServiceRec NOT Found");
2467 		retval = IBT_SERVICE_RECORDS_NOT_FOUND;
2468 	}
2469 
2470 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: done. Status %d, "
2471 	    "PKey 0x%X, Found %d SvcRec", retval, dinfo->p_key, rec_found);
2472 
2473 	return (retval);
2474 }
2475 
2476 
2477 static boolean_t
2478 ibcm_compare_paths(sa_path_record_t *pr_resp, ibt_cep_path_t *rc_path,
2479     ibtl_cm_hca_port_t *c_hp)
2480 {
2481 	if ((rc_path->cep_hca_port_num == c_hp->hp_port) &&
2482 	    (rc_path->cep_adds_vect.av_src_path ==
2483 	    (pr_resp->SLID - c_hp->hp_base_lid)) &&
2484 	    (rc_path->cep_adds_vect.av_dlid == pr_resp->DLID) &&
2485 	    (rc_path->cep_adds_vect.av_srate == pr_resp->Rate)) {
2486 		return (B_TRUE);
2487 	} else {
2488 		return (B_FALSE);
2489 	}
2490 }
2491 
2492 /*
2493  * ibcm_get_comp_pgids() routine gets the companion port for 'gid'.
2494  *
2495  * On success:
2496  *	If 'n_gid' is specified, then verify whether 'n_gid' is indeed a
2497  *	companion portgid of 'gid'.  If matches return success or else error.
2498  *
2499  *	If 'n_gid' is NOT specified, then return back SUCCESS along with
2500  *	obtained Companion PortGids 'gid_p', where 'num' indicated number
2501  *	of companion portgids returned in 'gid_p'.
2502  */
2503 
2504 static ibt_status_t
2505 ibcm_get_comp_pgids(ib_gid_t gid, ib_gid_t n_gid, ib_guid_t hca_guid,
2506     ib_gid_t **gid_p, uint_t *num)
2507 {
2508 	ibt_status_t    ret;
2509 	int		i;
2510 
2511 	ret = ibt_get_companion_port_gids(gid, hca_guid, 0, gid_p, num);
2512 	if ((ret != IBT_SUCCESS) && (ret != IBT_GIDS_NOT_FOUND)) {
2513 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: "
2514 		    "ibt_get_companion_port_gids(%llX:%llX) Failed: %d",
2515 		    gid.gid_prefix, gid.gid_guid, ret);
2516 	} else if ((ret == IBT_GIDS_NOT_FOUND) && (n_gid.gid_guid != 0)) {
2517 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: Specified GID "
2518 		    "(%llX:%llX) is NOT a Companion \n\t to current channel's "
2519 		    "GID(%llX:%llX)", n_gid.gid_prefix, n_gid.gid_guid,
2520 		    gid.gid_prefix, gid.gid_guid);
2521 		ret = IBT_INVALID_PARAM;
2522 	} else if (n_gid.gid_guid != 0) {
2523 		/*
2524 		 * We found some Comp GIDs and n_gid is specified. Validate
2525 		 * whether the 'n_gid' specified is indeed the companion port
2526 		 * GID of 'gid'.
2527 		 */
2528 		for (i = 0; i < *num; i++) {
2529 			if ((n_gid.gid_prefix == gid_p[i]->gid_prefix) &&
2530 			    (n_gid.gid_guid == gid_p[i]->gid_guid)) {
2531 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_comp_pgids: "
2532 				    "Matching Found!. Done.");
2533 				return (IBT_SUCCESS);
2534 			}
2535 		}
2536 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: GID (%llX:%llX)\n"
2537 		    "\t and (%llX:%llX) are NOT Companion Port GIDS",
2538 		    n_gid.gid_prefix, n_gid.gid_guid, gid.gid_prefix,
2539 		    gid.gid_guid);
2540 		ret = IBT_INVALID_PARAM;
2541 	} else {
2542 		ret = IBT_SUCCESS;
2543 	}
2544 
2545 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_comp_pgids: done. Status = %d", ret);
2546 	return (ret);
2547 }
2548 
2549 /*
2550  * Function:
2551  *	ibt_get_alt_path
2552  * Input:
2553  *	rc_chan		An RC channel handle returned in a previous call
2554  *			ibt_alloc_rc_channel(9F), specifies the channel to open.
2555  *	flags		Path flags.
2556  *	attrp		A pointer to an ibt_alt_path_attr_t(9S) structure that
2557  *			specifies required attributes of the selected path(s).
2558  * Output:
2559  *	api_p		An ibt_alt_path_info_t(9S) struct filled in as output
2560  *			parameters.
2561  * Returns:
2562  *	IBT_SUCCESS on Success else appropriate error.
2563  * Description:
2564  *      Finds the best alternate path to a specified channel (as determined by
2565  *      the IBTL) that satisfies the requirements specified in an
2566  *      ibt_alt_path_attr_t struct.  The specified channel must have been
2567  *      previously opened successfully using ibt_open_rc_channel.
2568  *      This function also ensures that the service being accessed by the
2569  *      channel is available at the selected alternate port.
2570  *
2571  *      Note: The apa_dgid must be on the same destination channel adapter,
2572  *      if specified.
2573  *	This routine can not be called from interrupt context.
2574  */
2575 ibt_status_t
2576 ibt_get_alt_path(ibt_channel_hdl_t rc_chan, ibt_path_flags_t flags,
2577     ibt_alt_path_attr_t *attrp, ibt_alt_path_info_t *api_p)
2578 {
2579 	sa_multipath_record_t	*mpr_req;
2580 	sa_path_record_t	*pr_resp;
2581 	ibmf_saa_access_args_t	access_args;
2582 	ibt_qp_query_attr_t	qp_attr;
2583 	ibtl_cm_hca_port_t	c_hp, n_hp;
2584 	ibcm_hca_info_t		*hcap;
2585 	void			*results_p;
2586 	uint64_t		c_mask = 0;
2587 	ib_gid_t		*gid_ptr = NULL;
2588 	ib_gid_t		*sgids_p = NULL,  *dgids_p = NULL;
2589 	ib_gid_t		cur_dgid, cur_sgid;
2590 	ib_gid_t		new_dgid, new_sgid;
2591 	ibmf_saa_handle_t	saa_handle;
2592 	size_t			length;
2593 	int			i, j, template_len, rec_found;
2594 	uint_t			snum = 0, dnum = 0, num_rec;
2595 	ibt_status_t		retval;
2596 	ib_mtu_t		prim_mtu;
2597 
2598 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path(%p, %x, %p, %p)",
2599 	    rc_chan, flags, attrp, api_p);
2600 
2601 	/* validate channel */
2602 	if (IBCM_INVALID_CHANNEL(rc_chan)) {
2603 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: invalid channel");
2604 		return (IBT_CHAN_HDL_INVALID);
2605 	}
2606 
2607 	if (api_p == NULL) {
2608 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: invalid attribute: "
2609 		    " AltPathInfo can't be NULL");
2610 		return (IBT_INVALID_PARAM);
2611 	}
2612 
2613 	retval = ibt_query_qp(rc_chan, &qp_attr);
2614 	if (retval != IBT_SUCCESS) {
2615 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: ibt_query_qp(%p) "
2616 		    "failed %d", rc_chan, retval);
2617 		return (retval);
2618 	}
2619 
2620 	if (qp_attr.qp_info.qp_trans != IBT_RC_SRV) {
2621 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2622 		    "Invalid Channel type: Applicable only to RC Channel");
2623 		return (IBT_CHAN_SRV_TYPE_INVALID);
2624 	}
2625 
2626 	cur_dgid =
2627 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dgid;
2628 	cur_sgid =
2629 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_sgid;
2630 	prim_mtu = qp_attr.qp_info.qp_transport.rc.rc_path_mtu;
2631 
2632 	/* If optional attributes are specified, validate them. */
2633 	if (attrp) {
2634 		new_dgid = attrp->apa_dgid;
2635 		new_sgid = attrp->apa_sgid;
2636 	} else {
2637 		new_dgid.gid_prefix = 0;
2638 		new_dgid.gid_guid = 0;
2639 		new_sgid.gid_prefix = 0;
2640 		new_sgid.gid_guid = 0;
2641 	}
2642 
2643 	if ((new_dgid.gid_prefix != 0) && (new_sgid.gid_prefix != 0) &&
2644 	    (new_dgid.gid_prefix != new_sgid.gid_prefix)) {
2645 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: Specified SGID's "
2646 		    "SNprefix (%llX) doesn't match with \n specified DGID's "
2647 		    "SNprefix: %llX", new_sgid.gid_prefix, new_dgid.gid_prefix);
2648 		return (IBT_INVALID_PARAM);
2649 	}
2650 
2651 	/* For the specified SGID, get HCA information. */
2652 	retval = ibtl_cm_get_hca_port(cur_sgid, 0, &c_hp);
2653 	if (retval != IBT_SUCCESS) {
2654 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2655 		    "Get HCA Port Failed: %d", retval);
2656 		return (retval);
2657 	}
2658 
2659 	hcap = ibcm_find_hca_entry(c_hp.hp_hca_guid);
2660 	if (hcap == NULL) {
2661 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: NO HCA found");
2662 		return (IBT_HCA_BUSY_DETACHING);
2663 	}
2664 
2665 	/* Validate whether this HCA support APM */
2666 	if (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG)) {
2667 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2668 		    "HCA (%llX) - APM NOT SUPPORTED ", c_hp.hp_hca_guid);
2669 		retval = IBT_APM_NOT_SUPPORTED;
2670 		goto get_alt_path_done;
2671 	}
2672 
2673 	/* Get Companion Port GID of the current Channel's SGID */
2674 	if ((new_sgid.gid_guid == 0) || ((new_sgid.gid_guid != 0) &&
2675 	    (new_sgid.gid_guid != cur_sgid.gid_guid))) {
2676 		IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: SRC: "
2677 		    "Get Companion PortGids for - %llX:%llX",
2678 		    cur_sgid.gid_prefix, cur_sgid.gid_guid);
2679 
2680 		retval = ibcm_get_comp_pgids(cur_sgid, new_sgid,
2681 		    c_hp.hp_hca_guid, &sgids_p, &snum);
2682 		if (retval != IBT_SUCCESS)
2683 			goto get_alt_path_done;
2684 	}
2685 
2686 	/* Get Companion Port GID of the current Channel's DGID */
2687 	if ((new_dgid.gid_guid == 0) || ((new_dgid.gid_guid != 0) &&
2688 	    (new_dgid.gid_guid != cur_dgid.gid_guid))) {
2689 
2690 		IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: DEST: "
2691 		    "Get Companion PortGids for - %llX:%llX",
2692 		    cur_dgid.gid_prefix, cur_dgid.gid_guid);
2693 
2694 		retval = ibcm_get_comp_pgids(cur_dgid, new_dgid, 0, &dgids_p,
2695 		    &dnum);
2696 		if (retval != IBT_SUCCESS)
2697 			goto get_alt_path_done;
2698 	}
2699 
2700 	if ((new_dgid.gid_guid == 0) || (new_sgid.gid_guid == 0)) {
2701 		if (new_sgid.gid_guid == 0) {
2702 			for (i = 0; i < snum; i++) {
2703 				if (new_dgid.gid_guid == 0) {
2704 					for (j = 0; j < dnum; j++) {
2705 						if (sgids_p[i].gid_prefix ==
2706 						    dgids_p[j].gid_prefix) {
2707 							new_dgid = dgids_p[j];
2708 							new_sgid = sgids_p[i];
2709 
2710 							goto get_alt_proceed;
2711 						}
2712 					}
2713 					/*  Current DGID */
2714 					if (sgids_p[i].gid_prefix ==
2715 					    cur_dgid.gid_prefix) {
2716 						new_sgid = sgids_p[i];
2717 						goto get_alt_proceed;
2718 					}
2719 				} else {
2720 					if (sgids_p[i].gid_prefix ==
2721 					    new_dgid.gid_prefix) {
2722 						new_sgid = sgids_p[i];
2723 						goto get_alt_proceed;
2724 					}
2725 				}
2726 			}
2727 			/* Current SGID */
2728 			if (new_dgid.gid_guid == 0) {
2729 				for (j = 0; j < dnum; j++) {
2730 					if (cur_sgid.gid_prefix ==
2731 					    dgids_p[j].gid_prefix) {
2732 						new_dgid = dgids_p[j];
2733 
2734 						goto get_alt_proceed;
2735 					}
2736 				}
2737 			}
2738 		} else if (new_dgid.gid_guid == 0) {
2739 			for (i = 0; i < dnum; i++) {
2740 				if (dgids_p[i].gid_prefix ==
2741 				    new_sgid.gid_prefix) {
2742 					new_dgid = dgids_p[i];
2743 					goto get_alt_proceed;
2744 				}
2745 			}
2746 			/* Current DGID */
2747 			if (cur_dgid.gid_prefix == new_sgid.gid_prefix) {
2748 				goto get_alt_proceed;
2749 			}
2750 		}
2751 		/*
2752 		 * hmm... No Companion Ports available.
2753 		 * so we will be using current or specified attributes only.
2754 		 */
2755 	}
2756 
2757 get_alt_proceed:
2758 
2759 	if (new_sgid.gid_guid != 0) {
2760 		retval = ibtl_cm_get_hca_port(new_sgid, 0, &n_hp);
2761 		if (retval != IBT_SUCCESS) {
2762 			IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2763 			    "Get HCA Port Failed: %d", retval);
2764 			goto get_alt_path_done;
2765 		}
2766 	}
2767 
2768 	/* Calculate the size for multi-path records template */
2769 	template_len = (2 * sizeof (ib_gid_t)) + sizeof (sa_multipath_record_t);
2770 
2771 	mpr_req = kmem_zalloc(template_len, KM_SLEEP);
2772 
2773 	ASSERT(mpr_req != NULL);
2774 
2775 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
2776 
2777 	gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
2778 	    sizeof (sa_multipath_record_t));
2779 
2780 	/* SGID */
2781 	if (new_sgid.gid_guid == 0)
2782 		*gid_ptr = cur_sgid;
2783 	else
2784 		*gid_ptr = new_sgid;
2785 
2786 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Get Path Between "
2787 	    " SGID : %llX:%llX", gid_ptr->gid_prefix, gid_ptr->gid_guid);
2788 
2789 	gid_ptr++;
2790 
2791 	/* DGID */
2792 	if (new_dgid.gid_guid == 0)
2793 		*gid_ptr = cur_dgid;
2794 	else
2795 		*gid_ptr = new_dgid;
2796 
2797 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path:\t\t    DGID : %llX:%llX",
2798 	    gid_ptr->gid_prefix, gid_ptr->gid_guid);
2799 
2800 	mpr_req->SGIDCount = 1;
2801 	c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
2802 
2803 	mpr_req->DGIDCount = 1;
2804 	c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
2805 
2806 	/* Is Flow Label Specified. */
2807 	if (attrp) {
2808 		if (attrp->apa_flow) {
2809 			mpr_req->FlowLabel = attrp->apa_flow;
2810 			c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
2811 		}
2812 
2813 		/* Is HopLimit Specified. */
2814 		if (flags & IBT_PATH_HOP) {
2815 			mpr_req->HopLimit = attrp->apa_hop;
2816 			c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
2817 		}
2818 
2819 		/* Is TClass Specified. */
2820 		if (attrp->apa_tclass) {
2821 			mpr_req->TClass = attrp->apa_tclass;
2822 			c_mask |= SA_MPR_COMPMASK_TCLASS;
2823 		}
2824 
2825 		/* Is SL specified. */
2826 		if (attrp->apa_sl) {
2827 			mpr_req->SL = attrp->apa_sl;
2828 			c_mask |= SA_MPR_COMPMASK_SL;
2829 		}
2830 
2831 		if (flags & IBT_PATH_PERF) {
2832 			mpr_req->PacketLifeTimeSelector = IBT_BEST;
2833 			mpr_req->RateSelector = IBT_BEST;
2834 
2835 			c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
2836 			    SA_MPR_COMPMASK_RATESELECTOR;
2837 		} else {
2838 			if (attrp->apa_pkt_lt.p_selector == IBT_BEST) {
2839 				mpr_req->PacketLifeTimeSelector = IBT_BEST;
2840 				c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
2841 			}
2842 
2843 			if (attrp->apa_srate.r_selector == IBT_BEST) {
2844 				mpr_req->RateSelector = IBT_BEST;
2845 				c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
2846 			}
2847 		}
2848 
2849 		/*
2850 		 * Honor individual selection of these attributes,
2851 		 * even if IBT_PATH_PERF is set.
2852 		 */
2853 		/* Check out whether Packet Life Time is specified. */
2854 		if (attrp->apa_pkt_lt.p_pkt_lt) {
2855 			mpr_req->PacketLifeTime =
2856 			    ibt_usec2ib(attrp->apa_pkt_lt.p_pkt_lt);
2857 			mpr_req->PacketLifeTimeSelector =
2858 			    attrp->apa_pkt_lt.p_selector;
2859 
2860 			c_mask |= SA_MPR_COMPMASK_PKTLT |
2861 			    SA_MPR_COMPMASK_PKTLTSELECTOR;
2862 		}
2863 
2864 		/* Is SRATE specified. */
2865 		if (attrp->apa_srate.r_srate) {
2866 			mpr_req->Rate = attrp->apa_srate.r_srate;
2867 			mpr_req->RateSelector = attrp->apa_srate.r_selector;
2868 
2869 			c_mask |= SA_MPR_COMPMASK_RATE |
2870 			    SA_MPR_COMPMASK_RATESELECTOR;
2871 		}
2872 	}
2873 
2874 	/* Alt PathMTU can be GT or EQU to current channel's Pri PathMTU */
2875 
2876 	/* P_Key must be same as that of primary path */
2877 	retval = ibt_index2pkey_byguid(c_hp.hp_hca_guid, c_hp.hp_port,
2878 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix,
2879 	    &mpr_req->P_Key);
2880 	if (retval != IBT_SUCCESS) {
2881 		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: Idx2Pkey Failed: %d",
2882 		    retval);
2883 		goto get_alt_path_done;
2884 	}
2885 	c_mask |= SA_MPR_COMPMASK_PKEY;
2886 
2887 	mpr_req->Reversible = 1;	/* We always get REVERSIBLE paths. */
2888 	mpr_req->IndependenceSelector = 1;
2889 	c_mask |= SA_MPR_COMPMASK_REVERSIBLE | SA_MPR_COMPMASK_INDEPSEL;
2890 
2891 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
2892 
2893 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: CMask: 0x%llX", c_mask);
2894 
2895 	/* NOTE: We will **NOT** specify how many records we want. */
2896 
2897 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Primary: MTU %d, PKey[%d]="
2898 	    "0x%X\n\tSGID = %llX:%llX, DGID = %llX:%llX", prim_mtu,
2899 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix, mpr_req->P_Key,
2900 	    cur_sgid.gid_prefix, cur_sgid.gid_guid, cur_dgid.gid_prefix,
2901 	    cur_dgid.gid_guid);
2902 
2903 	/* Get SA Access Handle. */
2904 	if (new_sgid.gid_guid != 0)
2905 		saa_handle = ibcm_get_saa_handle(hcap, n_hp.hp_port);
2906 	else
2907 		saa_handle = ibcm_get_saa_handle(hcap, c_hp.hp_port);
2908 	if (saa_handle == NULL) {
2909 		retval = IBT_HCA_PORT_NOT_ACTIVE;
2910 		goto get_alt_path_done;
2911 	}
2912 
2913 	/* Contact SA Access to retrieve Path Records. */
2914 	access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
2915 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
2916 	access_args.sq_component_mask = c_mask;
2917 	access_args.sq_template = mpr_req;
2918 	access_args.sq_template_length = sizeof (sa_multipath_record_t);
2919 	access_args.sq_callback = NULL;
2920 	access_args.sq_callback_arg = NULL;
2921 
2922 	retval = ibcm_contact_sa_access(saa_handle, &access_args, &length,
2923 	    &results_p);
2924 	if (retval != IBT_SUCCESS) {
2925 		goto get_alt_path_done;
2926 	}
2927 
2928 	num_rec = length / sizeof (sa_path_record_t);
2929 
2930 	kmem_free(mpr_req, template_len);
2931 
2932 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Found %d Paths", num_rec);
2933 
2934 	rec_found = 0;
2935 	if ((results_p != NULL) && (num_rec > 0)) {
2936 		/* Update the PathInfo with the response Path Records */
2937 		pr_resp = (sa_path_record_t *)results_p;
2938 		for (i = 0; i < num_rec; i++, pr_resp++) {
2939 			if (prim_mtu > pr_resp->Mtu) {
2940 				IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2941 				    "Alt PathMTU(%d) must be GT or EQU to Pri "
2942 				    "PathMTU(%d). Ignore this rec",
2943 				    pr_resp->Mtu, prim_mtu);
2944 				continue;
2945 			}
2946 
2947 			if ((new_sgid.gid_guid == 0) &&
2948 			    (new_dgid.gid_guid == 0)) {
2949 				/* Reject PathRec if it same as Primary Path. */
2950 				if (ibcm_compare_paths(pr_resp,
2951 				    &qp_attr.qp_info.qp_transport.rc.rc_path,
2952 				    &c_hp)) {
2953 					IBTF_DPRINTF_L3(cmlog,
2954 					    "ibt_get_alt_path: PathRec obtained"
2955 					    " is similar to Prim Path, ignore "
2956 					    "this record");
2957 					continue;
2958 				}
2959 			}
2960 
2961 			if (new_sgid.gid_guid == 0) {
2962 				retval = ibcm_update_cep_info(pr_resp, NULL,
2963 				    &c_hp, &api_p->ap_alt_cep_path);
2964 			} else {
2965 				retval = ibcm_update_cep_info(pr_resp, NULL,
2966 				    &n_hp, &api_p->ap_alt_cep_path);
2967 			}
2968 			if (retval != IBT_SUCCESS)
2969 				continue;
2970 
2971 			/* Update some leftovers */
2972 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*api_p))
2973 
2974 			api_p->ap_alt_pkt_lt = pr_resp->PacketLifeTime;
2975 
2976 			_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*api_p))
2977 
2978 			rec_found = 1;
2979 			break;
2980 		}
2981 		kmem_free(results_p, length);
2982 	}
2983 
2984 	if (rec_found == 0) {
2985 		IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Alternate Path cannot"
2986 		    " be established");
2987 		retval = IBT_PATH_RECORDS_NOT_FOUND;
2988 	} else
2989 		retval = IBT_SUCCESS;
2990 
2991 get_alt_path_done:
2992 	if ((snum) && (sgids_p))
2993 		kmem_free(sgids_p, snum * sizeof (ib_gid_t));
2994 
2995 	if ((dnum) && (dgids_p))
2996 		kmem_free(dgids_p, dnum * sizeof (ib_gid_t));
2997 
2998 	ibcm_dec_hca_acc_cnt(hcap);
2999 
3000 	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Done (status %d).", retval);
3001 
3002 	return (retval);
3003 }
3004 
3005 
3006 
3007 /*
3008  * IP Path API
3009  */
3010 
3011 typedef struct ibcm_ip_path_tqargs_s {
3012 	ibt_ip_path_attr_t	attr;
3013 	ibt_path_info_t		*paths;
3014 	ibt_path_ip_src_t	*src_ip_p;
3015 	uint8_t			*num_paths_p;
3016 	ibt_ip_path_handler_t	func;
3017 	void			*arg;
3018 	ibt_path_flags_t	flags;
3019 	ibt_clnt_hdl_t		ibt_hdl;
3020 	kmutex_t		ip_lock;
3021 	kcondvar_t		ip_cv;
3022 	ibt_status_t		retval;
3023 	uint_t			len;
3024 } ibcm_ip_path_tqargs_t;
3025 
3026 typedef struct ibcm_ip_dest_s {
3027 	ib_gid_t	d_gid;
3028 	ibt_ip_addr_t	d_ip;
3029 } ibcm_ip_dest_t;
3030 
3031 /* Holds destination information needed to fill in ibt_path_info_t. */
3032 typedef struct ibcm_ip_dinfo_s {
3033 	uint8_t		num_dest;
3034 	ibcm_ip_dest_t	dest[1];
3035 } ibcm_ip_dinfo_t;
3036 
3037 _NOTE(SCHEME_PROTECTS_DATA("Temporary path storage", ibcm_ip_dinfo_s))
3038 
3039 /* Prototype Declarations. */
3040 static void ibcm_process_get_ip_paths(void *tq_arg);
3041 static ibt_status_t ibcm_get_ip_spr(ibcm_ip_path_tqargs_t *,
3042     ibtl_cm_port_list_t *, ibcm_ip_dinfo_t *, uint8_t *, ibt_path_info_t *);
3043 static ibt_status_t ibcm_get_ip_mpr(ibcm_ip_path_tqargs_t *,
3044     ibtl_cm_port_list_t *, ibcm_ip_dinfo_t *dinfo,
3045     uint8_t *, ibt_path_info_t *);
3046 
3047 /*
3048  * Perform SA Access to retrieve Path Records.
3049  */
3050 static ibt_status_t
3051 ibcm_saa_ip_pr(ibcm_ip_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
3052     ibcm_ip_dinfo_t *dinfo, uint8_t *max_count)
3053 {
3054 	uint8_t		num_path = *max_count;
3055 	uint_t		rec_found = 0;
3056 	ibt_status_t	retval = IBT_SUCCESS;
3057 	uint8_t		i, j;
3058 
3059 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_ip_pr(%p, %p, %p, 0x%X, %d)",
3060 	    p_arg, sl, dinfo, p_arg->flags, *max_count);
3061 
3062 	if ((dinfo->num_dest == 0) || (num_path == 0) || (sl == NULL)) {
3063 		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_ip_pr: Invalid Counters");
3064 		return (IBT_INVALID_PARAM);
3065 	}
3066 
3067 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_ip_pr: MultiSM=%X, #SRC=%d, "
3068 	    "#Dest=%d, #Path %d", sl->p_multi, sl->p_count, dinfo->num_dest,
3069 	    num_path);
3070 
3071 	if ((sl->p_multi != IBTL_CM_SIMPLE_SETUP) ||
3072 	    ((dinfo->num_dest == 1) && (sl->p_count == 1))) {
3073 		/*
3074 		 * Use SinglePathRec if we are dealing w/ MultiSM or
3075 		 * request is for one SGID to one DGID.
3076 		 */
3077 		retval = ibcm_get_ip_spr(p_arg, sl, dinfo,
3078 		    &num_path, &p_arg->paths[rec_found]);
3079 	} else {
3080 		/* MultiPathRec will be used for other queries. */
3081 		retval = ibcm_get_ip_mpr(p_arg, sl, dinfo,
3082 		    &num_path, &p_arg->paths[rec_found]);
3083 	}
3084 	if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA))
3085 		IBTF_DPRINTF_L2(cmlog, "ibcm_saa_ip_pr: "
3086 		    "Failed to get PathRec: Status %d", retval);
3087 	else
3088 		rec_found += num_path;
3089 
3090 	if (rec_found == 0)  {
3091 		if (retval == IBT_SUCCESS)
3092 			retval = IBT_PATH_RECORDS_NOT_FOUND;
3093 	} else if (rec_found != *max_count)
3094 		retval = IBT_INSUFF_DATA;
3095 	else if (rec_found != 0)
3096 		retval = IBT_SUCCESS;
3097 
3098 	if ((p_arg->src_ip_p != NULL) && (rec_found != 0)) {
3099 		for (i = 0; i < rec_found; i++) {
3100 			for (j = 0; j < sl->p_count; j++) {
3101 				if (sl[j].p_sgid.gid_guid == p_arg->paths[i].
3102 				    pi_prim_cep_path.cep_adds_vect.
3103 				    av_sgid.gid_guid) {
3104 					bcopy(&sl[j].p_src_ip,
3105 					    &p_arg->src_ip_p[i].ip_primary,
3106 					    sizeof (ibt_ip_addr_t));
3107 				}
3108 				/* Is Alt Path present */
3109 				if (p_arg->paths[i].pi_alt_cep_path.
3110 				    cep_hca_port_num) {
3111 					if (sl[j].p_sgid.gid_guid ==
3112 					    p_arg->paths[i].pi_alt_cep_path.
3113 					    cep_adds_vect.av_sgid.gid_guid) {
3114 						bcopy(&sl[j].p_src_ip,
3115 						    &p_arg->src_ip_p[i].
3116 						    ip_alternate,
3117 						    sizeof (ibt_ip_addr_t));
3118 					}
3119 				}
3120 			}
3121 		}
3122 	}
3123 	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_ip_pr: done. Status = %d, "
3124 	    "Found %d/%d Paths", retval, rec_found, *max_count);
3125 
3126 	*max_count = rec_found; /* Update the return count. */
3127 
3128 	return (retval);
3129 }
3130 
3131 static ibt_status_t
3132 ibcm_ip_update_pri(sa_path_record_t *pr_resp, ibtl_cm_port_list_t *sl,
3133     ibt_path_info_t *paths)
3134 {
3135 	ibt_status_t	retval = IBT_SUCCESS;
3136 	int		s;
3137 
3138 	retval = ibcm_update_cep_info(pr_resp, sl, NULL,
3139 	    &paths->pi_prim_cep_path);
3140 	if (retval != IBT_SUCCESS)
3141 		return (retval);
3142 
3143 	/* Update some leftovers */
3144 	paths->pi_prim_pkt_lt = pr_resp->PacketLifeTime;
3145 	paths->pi_path_mtu = pr_resp->Mtu;
3146 
3147 	for (s = 0; s < sl->p_count; s++) {
3148 		if (pr_resp->SGID.gid_guid == sl[s].p_sgid.gid_guid)
3149 			paths->pi_hca_guid = sl[s].p_hca_guid;
3150 	}
3151 
3152 	/* Set Alternate Path to invalid state. */
3153 	paths->pi_alt_cep_path.cep_hca_port_num = 0;
3154 	paths->pi_alt_cep_path.cep_adds_vect.av_dlid = 0;
3155 
3156 	IBTF_DPRINTF_L5(cmlog, "ibcm_ip_update_pri: Path HCA GUID 0x%llX",
3157 	    paths->pi_hca_guid);
3158 
3159 	return (retval);
3160 }
3161 
3162 
3163 static ibt_status_t
3164 ibcm_get_ip_spr(ibcm_ip_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
3165     ibcm_ip_dinfo_t *dinfo, uint8_t *num_path, ibt_path_info_t *paths)
3166 {
3167 	sa_path_record_t	pathrec_req;
3168 	sa_path_record_t	*pr_resp;
3169 	ibmf_saa_access_args_t	access_args;
3170 	uint64_t		c_mask = 0;
3171 	void			*results_p;
3172 	uint8_t			num_rec;
3173 	size_t			length;
3174 	ibt_status_t		retval;
3175 	int			i, j, k;
3176 	int			found, p_fnd;
3177 	ibt_ip_path_attr_t	*attrp = &p_arg->attr;
3178 	ibmf_saa_handle_t	saa_handle;
3179 
3180 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr(%p, %p, %p, %d)",
3181 	    p_arg, sl, dinfo, *num_path);
3182 
3183 	bzero(&pathrec_req, sizeof (sa_path_record_t));
3184 
3185 	/* Is Flow Label Specified. */
3186 	if (attrp->ipa_flow) {
3187 		pathrec_req.FlowLabel = attrp->ipa_flow;
3188 		c_mask |= SA_PR_COMPMASK_FLOWLABEL;
3189 	}
3190 
3191 	/* Is HopLimit Specified. */
3192 	if (p_arg->flags & IBT_PATH_HOP) {
3193 		pathrec_req.HopLimit = attrp->ipa_hop;
3194 		c_mask |= SA_PR_COMPMASK_HOPLIMIT;
3195 	}
3196 
3197 	/* Is TClass Specified. */
3198 	if (attrp->ipa_tclass) {
3199 		pathrec_req.TClass = attrp->ipa_tclass;
3200 		c_mask |= SA_PR_COMPMASK_TCLASS;
3201 	}
3202 
3203 	/* Is SL specified. */
3204 	if (attrp->ipa_sl) {
3205 		pathrec_req.SL = attrp->ipa_sl;
3206 		c_mask |= SA_PR_COMPMASK_SL;
3207 	}
3208 
3209 	/* If IBT_PATH_PERF is set, then mark all selectors to BEST. */
3210 	if (p_arg->flags & IBT_PATH_PERF) {
3211 		pathrec_req.PacketLifeTimeSelector = IBT_BEST;
3212 		pathrec_req.MtuSelector = IBT_BEST;
3213 		pathrec_req.RateSelector = IBT_BEST;
3214 
3215 		c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR |
3216 		    SA_PR_COMPMASK_RATESELECTOR | SA_PR_COMPMASK_MTUSELECTOR;
3217 	} else {
3218 		if (attrp->ipa_pkt_lt.p_selector == IBT_BEST) {
3219 			pathrec_req.PacketLifeTimeSelector = IBT_BEST;
3220 			c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR;
3221 		}
3222 
3223 		if (attrp->ipa_srate.r_selector == IBT_BEST) {
3224 			pathrec_req.RateSelector = IBT_BEST;
3225 			c_mask |= SA_PR_COMPMASK_RATESELECTOR;
3226 		}
3227 
3228 		if (attrp->ipa_mtu.r_selector == IBT_BEST) {
3229 			pathrec_req.MtuSelector = IBT_BEST;
3230 			c_mask |= SA_PR_COMPMASK_MTUSELECTOR;
3231 		}
3232 	}
3233 
3234 	/*
3235 	 * Honor individual selection of these attributes,
3236 	 * even if IBT_PATH_PERF is set.
3237 	 */
3238 	/* Check out whether Packet Life Time is specified. */
3239 	if (attrp->ipa_pkt_lt.p_pkt_lt) {
3240 		pathrec_req.PacketLifeTime =
3241 		    ibt_usec2ib(attrp->ipa_pkt_lt.p_pkt_lt);
3242 		pathrec_req.PacketLifeTimeSelector =
3243 		    attrp->ipa_pkt_lt.p_selector;
3244 
3245 		c_mask |= SA_PR_COMPMASK_PKTLT | SA_PR_COMPMASK_PKTLTSELECTOR;
3246 	}
3247 
3248 	/* Is SRATE specified. */
3249 	if (attrp->ipa_srate.r_srate) {
3250 		pathrec_req.Rate = attrp->ipa_srate.r_srate;
3251 		pathrec_req.RateSelector = attrp->ipa_srate.r_selector;
3252 
3253 		c_mask |= SA_PR_COMPMASK_RATE | SA_PR_COMPMASK_RATESELECTOR;
3254 	}
3255 
3256 	/* Is MTU specified. */
3257 	if (attrp->ipa_mtu.r_mtu) {
3258 		pathrec_req.Mtu = attrp->ipa_mtu.r_mtu;
3259 		pathrec_req.MtuSelector = attrp->ipa_mtu.r_selector;
3260 
3261 		c_mask |= SA_PR_COMPMASK_MTU | SA_PR_COMPMASK_MTUSELECTOR;
3262 	}
3263 
3264 	/* We always get REVERSIBLE paths. */
3265 	pathrec_req.Reversible = 1;
3266 	c_mask |= SA_PR_COMPMASK_REVERSIBLE;
3267 
3268 	pathrec_req.NumbPath = *num_path;
3269 	c_mask |= SA_PR_COMPMASK_NUMBPATH;
3270 
3271 	p_fnd = found = 0;
3272 
3273 	for (i = 0; i < sl->p_count; i++) {
3274 		/* SGID */
3275 		pathrec_req.SGID = sl[i].p_sgid;
3276 		c_mask |= SA_PR_COMPMASK_SGID;
3277 		saa_handle = sl[i].p_saa_hdl;
3278 
3279 		for (k = 0; k < dinfo->num_dest; k++) {
3280 			if (pathrec_req.SGID.gid_prefix !=
3281 			    dinfo->dest[k].d_gid.gid_prefix) {
3282 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: "
3283 				    "SGID_pfx=%llX DGID_pfx=%llX doesn't match",
3284 				    pathrec_req.SGID.gid_prefix,
3285 				    dinfo->dest[k].d_gid.gid_prefix);
3286 				continue;
3287 			}
3288 
3289 			pathrec_req.DGID = dinfo->dest[k].d_gid;
3290 			c_mask |= SA_PR_COMPMASK_DGID;
3291 
3292 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: "
3293 			    "Get %d Path(s) between\n SGID %llX:%llX "
3294 			    "DGID %llX:%llX", pathrec_req.NumbPath,
3295 			    pathrec_req.SGID.gid_prefix,
3296 			    pathrec_req.SGID.gid_guid,
3297 			    pathrec_req.DGID.gid_prefix,
3298 			    pathrec_req.DGID.gid_guid);
3299 
3300 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: CMask=0x%llX, "
3301 			    "PKey=0x%X", c_mask, pathrec_req.P_Key);
3302 
3303 			/* Contact SA Access to retrieve Path Records. */
3304 			access_args.sq_attr_id = SA_PATHRECORD_ATTRID;
3305 			access_args.sq_template = &pathrec_req;
3306 			access_args.sq_access_type = IBMF_SAA_RETRIEVE;
3307 			access_args.sq_template_length =
3308 			    sizeof (sa_path_record_t);
3309 			access_args.sq_component_mask = c_mask;
3310 			access_args.sq_callback = NULL;
3311 			access_args.sq_callback_arg = NULL;
3312 
3313 			retval = ibcm_contact_sa_access(saa_handle,
3314 			    &access_args, &length, &results_p);
3315 			if (retval != IBT_SUCCESS) {
3316 				*num_path = 0;
3317 				return (retval);
3318 			}
3319 
3320 			num_rec = length / sizeof (sa_path_record_t);
3321 
3322 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: "
3323 			    "FOUND %d/%d path requested", num_rec, *num_path);
3324 
3325 			if ((results_p == NULL) || (num_rec == 0))
3326 				continue;
3327 
3328 			/* Update the PathInfo from the response. */
3329 			pr_resp = (sa_path_record_t *)results_p;
3330 			for (j = 0; j < num_rec; j++, pr_resp++) {
3331 				if ((p_fnd != 0) &&
3332 				    (p_arg->flags & IBT_PATH_APM)) {
3333 					IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr"
3334 					    ": Fill Alternate Path");
3335 					retval = ibcm_update_cep_info(pr_resp,
3336 					    sl, NULL,
3337 					    &paths[found - 1].pi_alt_cep_path);
3338 					if (retval != IBT_SUCCESS)
3339 						continue;
3340 
3341 					/* Update some leftovers */
3342 					paths[found - 1].pi_alt_pkt_lt =
3343 					    pr_resp->PacketLifeTime;
3344 					p_fnd = 0;
3345 				} else {
3346 					IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr"
3347 					    ": Fill Primary Path");
3348 
3349 					if (found == *num_path)
3350 						break;
3351 
3352 					retval = ibcm_ip_update_pri(pr_resp, sl,
3353 					    &paths[found]);
3354 					if (retval != IBT_SUCCESS)
3355 						continue;
3356 					p_fnd = 1;
3357 					found++;
3358 				}
3359 
3360 			}
3361 			/* Deallocate the memory for results_p. */
3362 			kmem_free(results_p, length);
3363 		}
3364 	}
3365 
3366 	if (found == 0)
3367 		retval = IBT_PATH_RECORDS_NOT_FOUND;
3368 	else if (found != *num_path)
3369 		retval = IBT_INSUFF_DATA;
3370 	else
3371 		retval = IBT_SUCCESS;
3372 
3373 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: done. Status %d, "
3374 	    "Found %d/%d Paths", retval, found, *num_path);
3375 
3376 	*num_path = found;
3377 
3378 	return (retval);
3379 }
3380 
3381 
3382 static ibt_status_t
3383 ibcm_get_ip_mpr(ibcm_ip_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
3384     ibcm_ip_dinfo_t *dinfo, uint8_t *num_path, ibt_path_info_t *paths)
3385 {
3386 	sa_multipath_record_t	*mpr_req;
3387 	sa_path_record_t	*pr_resp;
3388 	ibmf_saa_access_args_t	access_args;
3389 	void			*results_p;
3390 	uint64_t		c_mask = 0;
3391 	ib_gid_t		*gid_ptr, *gid_s_ptr;
3392 	size_t			length;
3393 	int			template_len, found, num_rec;
3394 	int			i;
3395 	ibt_status_t		retval;
3396 	uint8_t			sgid_cnt, dgid_cnt;
3397 	ibt_ip_path_attr_t	*attrp = &p_arg->attr;
3398 
3399 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr(%p, %p, %p, %d)",
3400 	    attrp, sl, dinfo, *num_path);
3401 
3402 	dgid_cnt = dinfo->num_dest;
3403 	sgid_cnt = sl->p_count;
3404 
3405 	if ((sgid_cnt == 0) || (dgid_cnt == 0)) {
3406 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_ip_mpr: sgid_cnt(%d) or"
3407 		    " dgid_cnt(%d) is zero", sgid_cnt, dgid_cnt);
3408 		return (IBT_INVALID_PARAM);
3409 	}
3410 
3411 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: Get %d records between "
3412 	    "%d Src(s) <=> %d Dest(s)", *num_path, sgid_cnt, dgid_cnt);
3413 
3414 	/*
3415 	 * Calculate the size for multi-path records template, which includes
3416 	 * constant portion of the multipath record, plus variable size for
3417 	 * SGID (sgid_cnt) and DGID (dgid_cnt).
3418 	 */
3419 	template_len = ((dgid_cnt + sgid_cnt) * sizeof (ib_gid_t)) +
3420 	    sizeof (sa_multipath_record_t);
3421 
3422 	mpr_req = kmem_zalloc(template_len, KM_SLEEP);
3423 
3424 	ASSERT(mpr_req != NULL);
3425 
3426 	gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
3427 	    sizeof (sa_multipath_record_t));
3428 
3429 	/* Get the starting pointer where GIDs are stored. */
3430 	gid_s_ptr = gid_ptr;
3431 
3432 	/* SGID */
3433 	for (i = 0; i < sgid_cnt; i++) {
3434 		*gid_ptr = sl[i].p_sgid;
3435 
3436 		IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: SGID[%d] = %llX:%llX",
3437 		    i, gid_ptr->gid_prefix, gid_ptr->gid_guid);
3438 
3439 		gid_ptr++;
3440 	}
3441 
3442 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
3443 
3444 	mpr_req->SGIDCount = sgid_cnt;
3445 	c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
3446 
3447 	/* DGIDs */
3448 	for (i = 0; i < dgid_cnt; i++) {
3449 		*gid_ptr = dinfo->dest[i].d_gid;
3450 
3451 		IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: DGID[%d] = "
3452 		    "%llX:%llX", i, gid_ptr->gid_prefix, gid_ptr->gid_guid);
3453 		gid_ptr++;
3454 	}
3455 
3456 	mpr_req->DGIDCount = dgid_cnt;
3457 	c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
3458 
3459 	/* Is Flow Label Specified. */
3460 	if (attrp->ipa_flow) {
3461 		mpr_req->FlowLabel = attrp->ipa_flow;
3462 		c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
3463 	}
3464 
3465 	/* Is HopLimit Specified. */
3466 	if (p_arg->flags & IBT_PATH_HOP) {
3467 		mpr_req->HopLimit = attrp->ipa_hop;
3468 		c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
3469 	}
3470 
3471 	/* Is TClass Specified. */
3472 	if (attrp->ipa_tclass) {
3473 		mpr_req->TClass = attrp->ipa_tclass;
3474 		c_mask |= SA_MPR_COMPMASK_TCLASS;
3475 	}
3476 
3477 	/* Is SL specified. */
3478 	if (attrp->ipa_sl) {
3479 		mpr_req->SL = attrp->ipa_sl;
3480 		c_mask |= SA_MPR_COMPMASK_SL;
3481 	}
3482 
3483 	if (p_arg->flags & IBT_PATH_PERF) {
3484 		mpr_req->PacketLifeTimeSelector = IBT_BEST;
3485 		mpr_req->RateSelector = IBT_BEST;
3486 		mpr_req->MtuSelector = IBT_BEST;
3487 
3488 		c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
3489 		    SA_MPR_COMPMASK_RATESELECTOR | SA_MPR_COMPMASK_MTUSELECTOR;
3490 	} else {
3491 		if (attrp->ipa_pkt_lt.p_selector == IBT_BEST) {
3492 			mpr_req->PacketLifeTimeSelector = IBT_BEST;
3493 			c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
3494 		}
3495 
3496 		if (attrp->ipa_srate.r_selector == IBT_BEST) {
3497 			mpr_req->RateSelector = IBT_BEST;
3498 			c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
3499 		}
3500 
3501 		if (attrp->ipa_mtu.r_selector == IBT_BEST) {
3502 			mpr_req->MtuSelector = IBT_BEST;
3503 			c_mask |= SA_MPR_COMPMASK_MTUSELECTOR;
3504 		}
3505 	}
3506 
3507 	/*
3508 	 * Honor individual selection of these attributes,
3509 	 * even if IBT_PATH_PERF is set.
3510 	 */
3511 	/* Check out whether Packet Life Time is specified. */
3512 	if (attrp->ipa_pkt_lt.p_pkt_lt) {
3513 		mpr_req->PacketLifeTime =
3514 		    ibt_usec2ib(attrp->ipa_pkt_lt.p_pkt_lt);
3515 		mpr_req->PacketLifeTimeSelector =
3516 		    attrp->ipa_pkt_lt.p_selector;
3517 
3518 		c_mask |= SA_MPR_COMPMASK_PKTLT |
3519 		    SA_MPR_COMPMASK_PKTLTSELECTOR;
3520 	}
3521 
3522 	/* Is SRATE specified. */
3523 	if (attrp->ipa_srate.r_srate) {
3524 		mpr_req->Rate = attrp->ipa_srate.r_srate;
3525 		mpr_req->RateSelector = attrp->ipa_srate.r_selector;
3526 
3527 		c_mask |= SA_MPR_COMPMASK_RATE |
3528 		    SA_MPR_COMPMASK_RATESELECTOR;
3529 	}
3530 
3531 	/* Is MTU specified. */
3532 	if (attrp->ipa_mtu.r_mtu) {
3533 		mpr_req->Mtu = attrp->ipa_mtu.r_mtu;
3534 		mpr_req->MtuSelector = attrp->ipa_mtu.r_selector;
3535 
3536 		c_mask |= SA_MPR_COMPMASK_MTU |
3537 		    SA_MPR_COMPMASK_MTUSELECTOR;
3538 	}
3539 
3540 	/* We always get REVERSIBLE paths. */
3541 	mpr_req->Reversible = 1;
3542 	c_mask |= SA_MPR_COMPMASK_REVERSIBLE;
3543 
3544 	if (p_arg->flags & IBT_PATH_AVAIL) {
3545 		mpr_req->IndependenceSelector = 1;
3546 		c_mask |= SA_MPR_COMPMASK_INDEPSEL;
3547 	}
3548 
3549 	/* we will not specify how many records we want. */
3550 
3551 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
3552 
3553 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: CMask: %llX Pkey: %X",
3554 	    c_mask, mpr_req->P_Key);
3555 
3556 	/* Contact SA Access to retrieve Path Records. */
3557 	access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
3558 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
3559 	access_args.sq_component_mask = c_mask;
3560 	access_args.sq_template = mpr_req;
3561 	access_args.sq_template_length = sizeof (sa_multipath_record_t);
3562 	access_args.sq_callback = NULL;
3563 	access_args.sq_callback_arg = NULL;
3564 
3565 	retval = ibcm_contact_sa_access(sl->p_saa_hdl, &access_args, &length,
3566 	    &results_p);
3567 	if (retval != IBT_SUCCESS) {
3568 		*num_path = 0;  /* Update the return count. */
3569 		kmem_free(mpr_req, template_len);
3570 		return (retval);
3571 	}
3572 
3573 	num_rec = length / sizeof (sa_path_record_t);
3574 
3575 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: Found %d Paths", num_rec);
3576 
3577 	found = 0;
3578 	if ((results_p != NULL) && (num_rec > 0)) {
3579 		/* Update the PathInfo with the response Path Records */
3580 		pr_resp = (sa_path_record_t *)results_p;
3581 
3582 		for (i = 0; i < num_rec; i++) {
3583 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: "
3584 			    "P[%d]: SG %llX, DG %llX", i,
3585 			    pr_resp[i].SGID.gid_guid, pr_resp[i].DGID.gid_guid);
3586 		}
3587 
3588 		if (p_arg->flags & IBT_PATH_APM) {
3589 			sa_path_record_t *p_resp = NULL, *a_resp = NULL;
3590 			int		p_found = 0, a_found = 0;
3591 			ib_gid_t	p_sg, a_sg, p_dg, a_dg;
3592 			int		s_spec;
3593 
3594 			s_spec =
3595 			    p_arg->attr.ipa_src_ip.family != AF_UNSPEC ? 1 : 0;
3596 
3597 			p_sg = gid_s_ptr[0];
3598 			if (sgid_cnt > 1)
3599 				a_sg = gid_s_ptr[1];
3600 			else
3601 				a_sg = p_sg;
3602 
3603 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: P_SG: %llX, "
3604 			    "A_SG: %llX", p_sg.gid_guid, a_sg.gid_guid);
3605 
3606 			p_dg = gid_s_ptr[sgid_cnt];
3607 			if (dgid_cnt > 1)
3608 				a_dg = gid_s_ptr[sgid_cnt + 1];
3609 			else
3610 				a_dg = p_dg;
3611 
3612 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: P_DG: %llX, "
3613 			    "A_DG: %llX", p_dg.gid_guid, a_dg.gid_guid);
3614 
3615 			/*
3616 			 * If SGID and/or DGID is specified by user, make sure
3617 			 * he gets his primary-path on those node points.
3618 			 */
3619 			for (i = 0; i < num_rec; i++, pr_resp++) {
3620 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: "
3621 				    "PF %d, AF %d,\n\t\t P[%d] = SG: %llX, "
3622 				    "DG: %llX", p_found, a_found, i,
3623 				    pr_resp->SGID.gid_guid,
3624 				    pr_resp->DGID.gid_guid);
3625 
3626 				if ((!p_found) &&
3627 				    (p_dg.gid_guid == pr_resp->DGID.gid_guid)) {
3628 					IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr"
3629 					    ": Pri DGID Match.. ");
3630 					if ((s_spec == 0) || (p_sg.gid_guid ==
3631 					    pr_resp->SGID.gid_guid)) {
3632 						p_found = 1;
3633 						p_resp = pr_resp;
3634 						IBTF_DPRINTF_L3(cmlog,
3635 						    "ibcm_get_ip_mpr: "
3636 						    "Primary Path Found");
3637 
3638 						if (a_found)
3639 							break;
3640 						else
3641 							continue;
3642 					}
3643 					IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr"
3644 					    ": Pri SGID Don't Match.. ");
3645 				}
3646 
3647 				if ((!a_found) &&
3648 				    (a_dg.gid_guid == pr_resp->DGID.gid_guid)) {
3649 					IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr"
3650 					    ": Alt DGID Match.. ");
3651 					if ((s_spec == 0) || (a_sg.gid_guid ==
3652 					    pr_resp->SGID.gid_guid)) {
3653 						a_found = 1;
3654 						a_resp = pr_resp;
3655 
3656 						IBTF_DPRINTF_L3(cmlog,
3657 						    "ibcm_get_ip_mpr:"
3658 						    "Alternate Path Found ");
3659 
3660 						if (p_found)
3661 							break;
3662 						else
3663 							continue;
3664 					}
3665 					IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr"
3666 					    ": Alt SGID Don't Match.. ");
3667 				}
3668 			}
3669 
3670 			if ((p_found == 0) && (a_found == 0)) {
3671 				IBTF_DPRINTF_L2(cmlog, "ibcm_get_ip_mpr: Path "
3672 				    "to desired node points NOT Available.");
3673 				retval = IBT_PATH_RECORDS_NOT_FOUND;
3674 				goto get_ip_mpr_end;
3675 			}
3676 
3677 			if ((p_resp == NULL) && (a_resp != NULL)) {
3678 				p_resp = a_resp;
3679 				a_resp = NULL;
3680 			}
3681 
3682 			/* Fill in Primary Path */
3683 			retval = ibcm_ip_update_pri(p_resp, sl, &paths[found]);
3684 			if (retval != IBT_SUCCESS)
3685 				goto get_ip_mpr_end;
3686 
3687 			/* Fill in Alternate Path */
3688 			if (a_resp != NULL) {
3689 				/* a_resp will point to AltPathInfo buffer. */
3690 				retval = ibcm_update_cep_info(a_resp, sl,
3691 				    NULL, &paths[found].pi_alt_cep_path);
3692 				if (retval != IBT_SUCCESS)
3693 					goto get_ip_mpr_end;
3694 
3695 				/* Update some leftovers */
3696 				paths[found].pi_alt_pkt_lt =
3697 				    a_resp->PacketLifeTime;
3698 			} else {
3699 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: "
3700 				    "Alternate Path NOT Available.");
3701 				retval = IBT_INSUFF_DATA;
3702 			}
3703 			found++;
3704 		} else {	/* If NOT APM */
3705 			for (i = 0; i < num_rec; i++, pr_resp++) {
3706 				IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: "
3707 				    "DGID(%llX)", pr_resp->DGID.gid_guid);
3708 
3709 				/* Fill in Primary Path */
3710 				retval = ibcm_ip_update_pri(pr_resp, sl,
3711 				    &paths[found]);
3712 				if (retval != IBT_SUCCESS)
3713 					continue;
3714 
3715 				if (++found == *num_path)
3716 					break;
3717 			}
3718 		}
3719 get_ip_mpr_end:
3720 		kmem_free(results_p, length);
3721 	}
3722 	kmem_free(mpr_req, template_len);
3723 
3724 	if (found == 0)
3725 		retval = IBT_PATH_RECORDS_NOT_FOUND;
3726 	else if (found != *num_path)
3727 		retval = IBT_INSUFF_DATA;
3728 	else
3729 		retval = IBT_SUCCESS;
3730 
3731 	IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: Done (status %d). "
3732 	    "Found %d/%d Paths", retval, found, *num_path);
3733 
3734 	*num_path = found;	/* Update the return count. */
3735 
3736 	return (retval);
3737 }
3738 
3739 
3740 static void
3741 ibcm_process_get_ip_paths(void *tq_arg)
3742 {
3743 	ibcm_ip_path_tqargs_t	*p_arg = (ibcm_ip_path_tqargs_t *)tq_arg;
3744 	ibcm_ip_dinfo_t		*dinfo = NULL;
3745 	int			len = 0;
3746 	uint8_t			max_paths, num_path;
3747 	ib_gid_t		*d_gids_p = NULL;
3748 	ib_gid_t		sgid, dgid1, dgid2;
3749 	ibt_status_t		retval = IBT_SUCCESS;
3750 	ibtl_cm_port_list_t	*sl = NULL;
3751 	uint_t			dnum = 0;
3752 	uint_t			i, j;
3753 	ibcm_hca_info_t		*hcap;
3754 	ibmf_saa_handle_t	saa_handle;
3755 
3756 	IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_ip_paths(%p, 0x%X) ",
3757 	    p_arg, p_arg->flags);
3758 
3759 	max_paths = num_path = p_arg->attr.ipa_max_paths;
3760 
3761 	/*
3762 	 * Prepare the Source and Destination GID list based on the input
3763 	 * attributes.  We contact ARP module to perform IP to MAC
3764 	 * i.e. GID conversion.  We use this GID for path look-up.
3765 	 *
3766 	 * If APM is requested and if multiple Dest IPs are specified, check
3767 	 * out whether they are companion to each other.  But, if only one
3768 	 * Dest IP is specified, then it is beyond our scope to verify that
3769 	 * the companion port GID obtained has IP-Service enabled.
3770 	 */
3771 	dgid1.gid_prefix = dgid1.gid_guid = 0;
3772 	sgid.gid_prefix = sgid.gid_guid = 0;
3773 	if ((p_arg->attr.ipa_src_ip.family != AF_UNSPEC) &&
3774 	    (!(p_arg->flags & IBT_PATH_APM))) {
3775 		ibt_path_attr_t		attr;
3776 
3777 		retval = ibcm_arp_get_ibaddr(p_arg->attr.ipa_src_ip,
3778 		    p_arg->attr.ipa_dst_ip[0], &sgid, &dgid1);
3779 		if (retval) {
3780 			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: "
3781 			    "ibcm_arp_get_ibaddr() failed: %d", retval);
3782 			goto ippath_error;
3783 		}
3784 
3785 		bzero(&attr, sizeof (ibt_path_attr_t));
3786 		attr.pa_hca_guid = p_arg->attr.ipa_hca_guid;
3787 		attr.pa_hca_port_num = p_arg->attr.ipa_hca_port_num;
3788 		attr.pa_sgid = sgid;
3789 		bcopy(&p_arg->attr.ipa_mtu, &attr.pa_mtu,
3790 		    sizeof (ibt_mtu_req_t));
3791 		bcopy(&p_arg->attr.ipa_srate, &attr.pa_srate,
3792 		    sizeof (ibt_srate_req_t));
3793 		bcopy(&p_arg->attr.ipa_pkt_lt, &attr.pa_pkt_lt,
3794 		    sizeof (ibt_pkt_lt_req_t));
3795 		retval = ibtl_cm_get_active_plist(&attr, p_arg->flags, &sl);
3796 		if (retval == IBT_SUCCESS) {
3797 			bcopy(&p_arg->attr.ipa_src_ip, &sl->p_src_ip,
3798 			    sizeof (ibt_ip_addr_t));
3799 		} else {
3800 			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: "
3801 			    "ibtl_cm_get_active_plist: Failed %d", retval);
3802 			goto ippath_error;
3803 		}
3804 	} else {
3805 		boolean_t	arp_nd_lookup = B_FALSE;
3806 
3807 		/*
3808 		 * Get list of active HCA-Port list, that matches input
3809 		 * specified attr.
3810 		 */
3811 		retval = ibcm_arp_get_srcip_plist(&p_arg->attr, p_arg->flags,
3812 		    &sl);
3813 		if (retval != IBT_SUCCESS) {
3814 			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: "
3815 			    "ibcm_arp_get_srcip_plist: Failed %d", retval);
3816 			goto ippath_error;
3817 		}
3818 
3819 		/*
3820 		 * Accumulate all destination information.
3821 		 * Get GID info for the specified input ip-addr.
3822 		 */
3823 		for (j = 0; j < sl->p_count; j++) {
3824 			retval = ibcm_arp_get_ibaddr(sl[j].p_src_ip,
3825 			    p_arg->attr.ipa_dst_ip[0], NULL, &dgid1);
3826 			if (retval == IBT_SUCCESS) {
3827 				arp_nd_lookup = B_TRUE; /* found */
3828 				IBCM_PRINT_IP("ibcm_process_get_ip_paths: "
3829 				    "SrcIP ", &sl[j].p_src_ip);
3830 				IBCM_PRINT_IP("ibcm_process_get_ip_paths: "
3831 				    "DstIP ", &p_arg->attr.ipa_dst_ip[0]);
3832 				break;
3833 			}
3834 			IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_ip_paths: "
3835 			    "ibcm_arp_get_ibaddr() failed: %d", retval);
3836 		}
3837 		if (!arp_nd_lookup)
3838 			goto ippath_error1;
3839 	}
3840 
3841 	IBTF_DPRINTF_L4(cmlog, "ibcm_process_get_ip_paths: SGID %llX:%llX, "
3842 	    "DGID0: %llX:%llX", sl->p_sgid.gid_prefix, sl->p_sgid.gid_guid,
3843 	    dgid1.gid_prefix, dgid1.gid_guid);
3844 
3845 	len = p_arg->attr.ipa_ndst + 1;
3846 	len = (len * sizeof (ibcm_ip_dest_t)) + sizeof (ibcm_ip_dinfo_t);
3847 	dinfo = kmem_zalloc(len, KM_SLEEP);
3848 
3849 	dinfo->dest[0].d_gid = dgid1;
3850 	bcopy(&p_arg->attr.ipa_dst_ip[0], &dinfo->dest[0].d_ip,
3851 	    sizeof (ibt_ip_addr_t));
3852 
3853 	i = 1;
3854 	if (p_arg->attr.ipa_ndst > 1) {
3855 		/* Get DGID for all specified Dest IP Addr */
3856 		for (; i < p_arg->attr.ipa_ndst; i++) {
3857 			retval = ibcm_arp_get_ibaddr(sl->p_src_ip,
3858 			    p_arg->attr.ipa_dst_ip[i], NULL, &dgid2);
3859 			if (retval) {
3860 				IBTF_DPRINTF_L2(cmlog,
3861 				    "ibcm_process_get_ip_paths: "
3862 				    "ibcm_arp_get_ibaddr failed: %d", retval);
3863 				goto ippath_error2;
3864 			}
3865 			dinfo->dest[i].d_gid = dgid2;
3866 
3867 			IBTF_DPRINTF_L4(cmlog, "ibcm_process_get_ip_paths: "
3868 			    "DGID%d: %llX:%llX", i, dgid2.gid_prefix,
3869 			    dgid2.gid_guid);
3870 			bcopy(&p_arg->attr.ipa_dst_ip[i], &dinfo->dest[i].d_ip,
3871 			    sizeof (ibt_ip_addr_t));
3872 		}
3873 
3874 		if (p_arg->flags & IBT_PATH_APM) {
3875 			dgid2 = dinfo->dest[1].d_gid;
3876 
3877 			retval = ibcm_get_comp_pgids(dgid1, dgid2, 0,
3878 			    &d_gids_p, &dnum);
3879 			if ((retval != IBT_SUCCESS) &&
3880 			    (retval != IBT_GIDS_NOT_FOUND)) {
3881 				IBTF_DPRINTF_L2(cmlog,
3882 				    "ibcm_process_get_ip_paths: "
3883 				    "Invalid DGIDs specified w/ APM Flag");
3884 				goto ippath_error2;
3885 			}
3886 			IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_ip_paths: "
3887 			    "Found %d Comp DGID", dnum);
3888 
3889 			if (dnum) {
3890 				dinfo->dest[i].d_gid = d_gids_p[0];
3891 				dinfo->dest[i].d_ip.family = AF_UNSPEC;
3892 				i++;
3893 			}
3894 		}
3895 	}
3896 
3897 	/* "i" will get us num_dest count. */
3898 	dinfo->num_dest = i;
3899 
3900 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*p_arg))
3901 
3902 	/*
3903 	 * IBTF allocates memory for path_info & src_ip in case of
3904 	 * Async Get IP Paths
3905 	 */
3906 	if (p_arg->func) {   /* Do these only for Async Get Paths */
3907 		p_arg->paths = kmem_zalloc(sizeof (ibt_path_info_t) * max_paths,
3908 		    KM_SLEEP);
3909 		if (p_arg->src_ip_p == NULL)
3910 			p_arg->src_ip_p = kmem_zalloc(
3911 			    sizeof (ibt_path_ip_src_t) * max_paths, KM_SLEEP);
3912 	}
3913 
3914 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*p_arg))
3915 
3916 	IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_ip_paths: HCA (%llX, %d)",
3917 	    sl->p_hca_guid, sl->p_port_num);
3918 
3919 	hcap = ibcm_find_hca_entry(sl->p_hca_guid);
3920 	if (hcap == NULL) {
3921 		IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: "
3922 		    "NO HCA found");
3923 		retval = IBT_HCA_BUSY_DETACHING;
3924 		goto ippath_error2;
3925 	}
3926 
3927 	/* Get SA Access Handle. */
3928 	for (i = 0; i < sl->p_count; i++) {
3929 		if (i == 0) {
3930 			/* Validate whether this HCA supports APM */
3931 			if ((p_arg->flags & IBT_PATH_APM) &&
3932 			    (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG))) {
3933 				IBTF_DPRINTF_L2(cmlog,
3934 				    "ibcm_process_get_ip_paths: HCA (%llX): "
3935 				    "APM NOT SUPPORTED", sl[i].p_hca_guid);
3936 				retval = IBT_APM_NOT_SUPPORTED;
3937 				goto ippath_error3;
3938 			}
3939 		}
3940 
3941 		saa_handle = ibcm_get_saa_handle(hcap, sl[i].p_port_num);
3942 		if (saa_handle == NULL) {
3943 			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: "
3944 			    "SAA HDL NULL, HCA (%llX:%d) NOT ACTIVE",
3945 			    sl[i].p_hca_guid, sl[i].p_port_num);
3946 			retval = IBT_HCA_PORT_NOT_ACTIVE;
3947 			goto ippath_error3;
3948 		}
3949 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sl))
3950 		sl[i].p_saa_hdl = saa_handle;
3951 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*sl))
3952 	}
3953 
3954 	/* Get Path Records. */
3955 	retval = ibcm_saa_ip_pr(p_arg, sl, dinfo, &num_path);
3956 
3957 ippath_error3:
3958 	ibcm_dec_hca_acc_cnt(hcap);
3959 
3960 ippath_error2:
3961 	if (dinfo && len)
3962 		kmem_free(dinfo, len);
3963 
3964 ippath_error1:
3965 	if (sl)
3966 		ibtl_cm_free_active_plist(sl);
3967 
3968 ippath_error:
3969 	if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA))
3970 		num_path = 0;
3971 
3972 	if (p_arg->num_paths_p != NULL)
3973 		*p_arg->num_paths_p = num_path;
3974 
3975 	if (p_arg->func) {   /* Do these only for Async Get Paths */
3976 		ibt_path_info_t *tmp_path_p;
3977 
3978 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*p_arg))
3979 		p_arg->retval = retval;
3980 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*p_arg))
3981 
3982 		if (retval == IBT_INSUFF_DATA) {
3983 			/*
3984 			 * We allocated earlier memory based on "max_paths",
3985 			 * but we got lesser path-records, so re-adjust that
3986 			 * buffer so that caller can free the correct memory.
3987 			 */
3988 			tmp_path_p = kmem_alloc(
3989 			    sizeof (ibt_path_info_t) * num_path, KM_SLEEP);
3990 
3991 			bcopy(p_arg->paths, tmp_path_p,
3992 			    num_path * sizeof (ibt_path_info_t));
3993 
3994 			kmem_free(p_arg->paths,
3995 			    sizeof (ibt_path_info_t) * max_paths);
3996 		} else if (retval != IBT_SUCCESS) {
3997 			if (p_arg->paths)
3998 				kmem_free(p_arg->paths,
3999 				    sizeof (ibt_path_info_t) * max_paths);
4000 			if (p_arg->src_ip_p)
4001 				kmem_free(p_arg->src_ip_p,
4002 				    sizeof (ibt_path_ip_src_t) * max_paths);
4003 			tmp_path_p = NULL;
4004 		} else {
4005 			tmp_path_p = p_arg->paths;
4006 		}
4007 		(*(p_arg->func))(p_arg->arg, retval, tmp_path_p, num_path,
4008 		    p_arg->src_ip_p);
4009 
4010 		cv_destroy(&p_arg->ip_cv);
4011 		mutex_destroy(&p_arg->ip_lock);
4012 		len = p_arg->len;
4013 		if (p_arg && len)
4014 			kmem_free(p_arg, len);
4015 	} else {
4016 		mutex_enter(&p_arg->ip_lock);
4017 		p_arg->retval = retval;
4018 		cv_signal(&p_arg->ip_cv);
4019 		mutex_exit(&p_arg->ip_lock);
4020 	}
4021 
4022 	IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: done: status %d, "
4023 	    "Found %d/%d Path Records", retval, num_path, max_paths);
4024 }
4025 
4026 
4027 static ibt_status_t
4028 ibcm_val_ipattr(ibt_ip_path_attr_t *attrp, ibt_path_flags_t flags)
4029 {
4030 	uint_t			i;
4031 
4032 	if (attrp == NULL) {
4033 		IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: IP Path Attr is NULL");
4034 		return (IBT_INVALID_PARAM);
4035 	}
4036 
4037 	IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: Inputs are: HCA %llX:%d, "
4038 	    "Maxpath= %d, \n Flags= 0x%X, #Dest %d", attrp->ipa_hca_guid,
4039 	    attrp->ipa_hca_port_num, attrp->ipa_max_paths, flags,
4040 	    attrp->ipa_ndst);
4041 
4042 	/*
4043 	 * Validate Path Flags.
4044 	 * IBT_PATH_AVAIL & IBT_PATH_PERF are mutually exclusive.
4045 	 */
4046 	if ((flags & IBT_PATH_AVAIL) && (flags & IBT_PATH_PERF)) {
4047 		IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: Invalid Flags: 0x%X,"
4048 		    "\n\t AVAIL and PERF flags specified together", flags);
4049 		return (IBT_INVALID_PARAM);
4050 	}
4051 
4052 	/*
4053 	 * Validate number of records requested.
4054 	 *
4055 	 * Max_paths of "0" is invalid.
4056 	 * Max_paths <= IBT_MAX_SPECIAL_PATHS, if AVAIL or PERF is set.
4057 	 */
4058 	if (attrp->ipa_max_paths == 0) {
4059 		IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: Invalid max_paths %d",
4060 		    attrp->ipa_max_paths);
4061 		return (IBT_INVALID_PARAM);
4062 	}
4063 
4064 	if ((flags & (IBT_PATH_AVAIL | IBT_PATH_PERF)) &&
4065 	    (attrp->ipa_max_paths > IBT_MAX_SPECIAL_PATHS)) {
4066 		IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: MaxPaths that can be "
4067 		    "requested is <%d> \n when IBT_PATH_AVAIL or IBT_PATH_PERF"
4068 		    " flag is specified.", IBT_MAX_SPECIAL_PATHS);
4069 		return (IBT_INVALID_PARAM);
4070 	}
4071 
4072 	/* Only 2 destinations can be specified w/ APM flag. */
4073 	if ((flags & IBT_PATH_APM) && (attrp->ipa_ndst > 2)) {
4074 		IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: Max #Dest is 2, with "
4075 		    "APM flag");
4076 		return (IBT_INVALID_PARAM);
4077 	}
4078 
4079 	/* Validate the destination info */
4080 	if ((attrp->ipa_ndst == 0) || (attrp->ipa_ndst == NULL)) {
4081 		IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: DstIP Not provided "
4082 		    "dst_ip %p, ndst %d", attrp->ipa_dst_ip, attrp->ipa_ndst);
4083 		return (IBT_INVALID_PARAM);
4084 	}
4085 
4086 	/* Basic validation of Source IPADDR (if provided). */
4087 	IBCM_PRINT_IP("ibcm_val_ipattr SrcIP", &attrp->ipa_src_ip);
4088 	if ((attrp->ipa_src_ip.family == AF_INET) &&
4089 	    (attrp->ipa_src_ip.un.ip4addr == htonl(INADDR_LOOPBACK) ||
4090 	    attrp->ipa_src_ip.un.ip4addr == INADDR_ANY)) {
4091 		IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: SrcIP specified is "
4092 		    "LOOPBACK/ZEROs: NOT SUPPORTED");
4093 		return (IBT_NOT_SUPPORTED);
4094 	} else if ((attrp->ipa_src_ip.family == AF_INET6) &&
4095 	    (IN6_IS_ADDR_UNSPECIFIED(&attrp->ipa_src_ip.un.ip6addr) ||
4096 	    IN6_IS_ADDR_LOOPBACK(&attrp->ipa_src_ip.un.ip6addr))) {
4097 		IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: SrcIP specified is "
4098 		    "LOOPBACK/ZEROs: NOT SUPPORTED");
4099 		return (IBT_NOT_SUPPORTED);
4100 	}
4101 
4102 	if (ibcm_ip6_linklocal_addr_ok &&
4103 	    (attrp->ipa_src_ip.family == AF_INET6) &&
4104 	    (IN6_IS_ADDR_LINKLOCAL(&attrp->ipa_src_ip.un.ip6addr))) {
4105 		IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: SrcIP specified is "
4106 		    "Link Local Address: NOT SUPPORTED");
4107 		return (IBT_NOT_SUPPORTED);
4108 	}
4109 
4110 	/* Basic validation of Dest IPADDR. */
4111 	for (i = 0; i < attrp->ipa_ndst; i++) {
4112 		ibt_ip_addr_t	dst_ip = attrp->ipa_dst_ip[i];
4113 
4114 		IBCM_PRINT_IP("ibcm_val_ipattr DstIP", &dst_ip);
4115 
4116 		if (dst_ip.family == AF_UNSPEC) {
4117 			IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: ERROR: "
4118 			    "Invalid DstIP specified");
4119 			return (IBT_INVALID_PARAM);
4120 		} else if ((dst_ip.family == AF_INET) &&
4121 		    (dst_ip.un.ip4addr == htonl(INADDR_LOOPBACK) ||
4122 		    dst_ip.un.ip4addr == INADDR_ANY)) {
4123 			IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: DstIP "
4124 			    "specified is LOOPBACK/ZEROs: NOT SUPPORTED");
4125 			return (IBT_NOT_SUPPORTED);
4126 		} else if ((dst_ip.family == AF_INET6) &&
4127 		    (IN6_IS_ADDR_UNSPECIFIED(&dst_ip.un.ip6addr) ||
4128 		    IN6_IS_ADDR_LOOPBACK(&dst_ip.un.ip6addr))) {
4129 			IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: DstIP "
4130 			    "specified is LOOPBACK/ZEROs: NOT SUPPORTED");
4131 			return (IBT_NOT_SUPPORTED);
4132 		}
4133 
4134 		/*
4135 		 * If SrcIP is specified, make sure that SrcIP and DstIP
4136 		 * belong to same family.
4137 		 */
4138 		if ((attrp->ipa_src_ip.family != AF_UNSPEC) &&
4139 		    (attrp->ipa_src_ip.family != dst_ip.family)) {
4140 			IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: ERROR: "
4141 			    "Specified SrcIP (%d) and DstIP(%d) family diffs.",
4142 			    attrp->ipa_src_ip.family, dst_ip.family);
4143 			return (IBT_INVALID_PARAM);
4144 		}
4145 	}
4146 
4147 	return (IBT_SUCCESS);
4148 }
4149 
4150 
4151 static ibt_status_t
4152 ibcm_get_ip_path(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags,
4153     ibt_ip_path_attr_t *attrp, ibt_path_info_t *paths, uint8_t *num_path_p,
4154     ibt_path_ip_src_t *src_ip_p, ibt_ip_path_handler_t func, void  *arg)
4155 {
4156 	ibcm_ip_path_tqargs_t	*path_tq;
4157 	int		sleep_flag = ((func == NULL) ? KM_SLEEP : KM_NOSLEEP);
4158 	uint_t		len, ret;
4159 	ibt_status_t	retval;
4160 
4161 	retval = ibcm_val_ipattr(attrp, flags);
4162 	if (retval != IBT_SUCCESS)
4163 		return (retval);
4164 
4165 	len = (attrp->ipa_ndst * sizeof (ibt_ip_addr_t)) +
4166 	    sizeof (ibcm_ip_path_tqargs_t);
4167 	path_tq = kmem_zalloc(len, sleep_flag);
4168 	if (path_tq == NULL) {
4169 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_ip_path: "
4170 		    "Unable to allocate memory for local usage.");
4171 		return (IBT_INSUFF_KERNEL_RESOURCE);
4172 	}
4173 
4174 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*path_tq))
4175 	mutex_init(&path_tq->ip_lock, NULL, MUTEX_DEFAULT, NULL);
4176 	cv_init(&path_tq->ip_cv, NULL, CV_DRIVER, NULL);
4177 	bcopy(attrp, &path_tq->attr, sizeof (ibt_ip_path_attr_t));
4178 
4179 	path_tq->attr.ipa_dst_ip = (ibt_ip_addr_t *)(((uchar_t *)path_tq) +
4180 	    sizeof (ibcm_ip_path_tqargs_t));
4181 	bcopy(attrp->ipa_dst_ip, path_tq->attr.ipa_dst_ip,
4182 	    sizeof (ibt_ip_addr_t) * attrp->ipa_ndst);
4183 
4184 	/* Ignore IBT_PATH_AVAIL flag, if only one path is requested. */
4185 	if ((flags & IBT_PATH_AVAIL) && (attrp->ipa_max_paths == 1)) {
4186 		flags &= ~IBT_PATH_AVAIL;
4187 
4188 		IBTF_DPRINTF_L4(cmlog, "ibcm_get_ip_path: Ignoring "
4189 		    "IBT_PATH_AVAIL flag, as only ONE path info is requested.");
4190 	}
4191 
4192 	path_tq->flags = flags;
4193 	path_tq->ibt_hdl = ibt_hdl;
4194 	path_tq->paths = paths;
4195 	path_tq->src_ip_p = src_ip_p;
4196 	path_tq->num_paths_p = num_path_p;
4197 	path_tq->func = func;
4198 	path_tq->arg = arg;
4199 	path_tq->len = len;
4200 
4201 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*path_tq))
4202 
4203 	sleep_flag = ((func == NULL) ? TQ_SLEEP : TQ_NOSLEEP);
4204 	mutex_enter(&path_tq->ip_lock);
4205 	ret = taskq_dispatch(ibcm_taskq, ibcm_process_get_ip_paths, path_tq,
4206 	    sleep_flag);
4207 	if (ret == 0) {
4208 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_ip_path: Failed to dispatch "
4209 		    "the TaskQ");
4210 		mutex_exit(&path_tq->ip_lock);
4211 		cv_destroy(&path_tq->ip_cv);
4212 		mutex_destroy(&path_tq->ip_lock);
4213 		kmem_free(path_tq, len);
4214 		retval = IBT_INSUFF_KERNEL_RESOURCE;
4215 	} else {
4216 		if (func != NULL) {		/* Non-Blocking */
4217 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_path: NonBlocking");
4218 			retval = IBT_SUCCESS;
4219 			mutex_exit(&path_tq->ip_lock);
4220 		} else {		/* Blocking */
4221 			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_path: Blocking");
4222 			cv_wait(&path_tq->ip_cv, &path_tq->ip_lock);
4223 			retval = path_tq->retval;
4224 			mutex_exit(&path_tq->ip_lock);
4225 			cv_destroy(&path_tq->ip_cv);
4226 			mutex_destroy(&path_tq->ip_lock);
4227 			kmem_free(path_tq, len);
4228 		}
4229 	}
4230 
4231 	return (retval);
4232 }
4233 
4234 
4235 ibt_status_t
4236 ibt_aget_ip_paths(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags,
4237     ibt_ip_path_attr_t *attrp, ibt_ip_path_handler_t func, void  *arg)
4238 {
4239 	IBTF_DPRINTF_L3(cmlog, "ibt_aget_ip_paths(%p (%s), 0x%X, %p, %p, %p)",
4240 	    ibt_hdl, ibtl_cm_get_clnt_name(ibt_hdl), flags, attrp, func, arg);
4241 
4242 	if (func == NULL) {
4243 		IBTF_DPRINTF_L2(cmlog, "ibt_aget_ip_paths: Function Pointer is "
4244 		    "NULL - ERROR ");
4245 		return (IBT_INVALID_PARAM);
4246 	}
4247 
4248 	/* path info will be allocated in ibcm_process_get_ip_paths() */
4249 	return (ibcm_get_ip_path(ibt_hdl, flags, attrp, NULL, NULL,
4250 	    NULL, func, arg));
4251 }
4252 
4253 
4254 ibt_status_t
4255 ibt_get_ip_paths(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags,
4256     ibt_ip_path_attr_t *attrp, ibt_path_info_t *paths, uint8_t *num_paths_p,
4257     ibt_path_ip_src_t *src_ip_p)
4258 {
4259 	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_paths(%p(%s), 0x%X, %p, %p, %p, %p)",
4260 	    ibt_hdl, ibtl_cm_get_clnt_name(ibt_hdl), flags, attrp, paths,
4261 	    num_paths_p, src_ip_p);
4262 
4263 	if (paths == NULL) {
4264 		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_paths: Path Info Pointer is "
4265 		    "NULL - ERROR ");
4266 		return (IBT_INVALID_PARAM);
4267 	}
4268 
4269 	if (num_paths_p != NULL)
4270 		*num_paths_p = 0;
4271 
4272 	return (ibcm_get_ip_path(ibt_hdl, flags, attrp, paths, num_paths_p,
4273 	    src_ip_p, NULL, NULL));
4274 }
4275 
4276 
4277 ibt_status_t
4278 ibt_get_ip_alt_path(ibt_channel_hdl_t rc_chan, ibt_path_flags_t flags,
4279     ibt_alt_ip_path_attr_t *attrp, ibt_alt_path_info_t *api_p)
4280 {
4281 	sa_multipath_record_t	*mpr_req;
4282 	sa_path_record_t	*pr_resp;
4283 	ibmf_saa_access_args_t	access_args;
4284 	ibt_qp_query_attr_t	qp_attr;
4285 	ibtl_cm_hca_port_t	c_hp, n_hp;
4286 	ibcm_hca_info_t		*hcap;
4287 	void			*results_p;
4288 	uint64_t		c_mask = 0;
4289 	ib_gid_t		*gid_ptr = NULL;
4290 	ib_gid_t		*sgids_p = NULL,  *dgids_p = NULL;
4291 	ib_gid_t		cur_dgid, cur_sgid;
4292 	ib_gid_t		new_dgid, new_sgid;
4293 	ibmf_saa_handle_t	saa_handle;
4294 	size_t			length;
4295 	int			i, j, template_len, rec_found;
4296 	uint_t			snum = 0, dnum = 0, num_rec;
4297 	ibt_status_t		retval;
4298 	ib_mtu_t		prim_mtu;
4299 
4300 	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path(%p, %x, %p, %p)",
4301 	    rc_chan, flags, attrp, api_p);
4302 
4303 	/* validate channel */
4304 	if (IBCM_INVALID_CHANNEL(rc_chan)) {
4305 		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: invalid channel");
4306 		return (IBT_CHAN_HDL_INVALID);
4307 	}
4308 
4309 	if (api_p == NULL) {
4310 		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: invalid attribute:"
4311 		    " AltPathInfo can't be NULL");
4312 		return (IBT_INVALID_PARAM);
4313 	}
4314 
4315 	retval = ibt_query_qp(rc_chan, &qp_attr);
4316 	if (retval != IBT_SUCCESS) {
4317 		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: ibt_query_qp(%p) "
4318 		    "failed %d", rc_chan, retval);
4319 		return (retval);
4320 	}
4321 
4322 	if (qp_attr.qp_info.qp_trans != IBT_RC_SRV) {
4323 		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4324 		    "Invalid Channel type: Applicable only to RC Channel");
4325 		return (IBT_CHAN_SRV_TYPE_INVALID);
4326 	}
4327 
4328 	cur_dgid =
4329 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dgid;
4330 	cur_sgid =
4331 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_sgid;
4332 	prim_mtu = qp_attr.qp_info.qp_transport.rc.rc_path_mtu;
4333 
4334 	/* If optional attributes are specified, validate them. */
4335 	if (attrp) {
4336 		/* Get SGID and DGID for the specified input ip-addr */
4337 		retval = ibcm_arp_get_ibaddr(attrp->apa_src_ip,
4338 		    attrp->apa_dst_ip, &new_sgid, &new_dgid);
4339 		if (retval) {
4340 			IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4341 			    "ibcm_arp_get_ibaddr() failed: %d", retval);
4342 			return (retval);
4343 		}
4344 	} else {
4345 		new_dgid.gid_prefix = 0;
4346 		new_dgid.gid_guid = 0;
4347 		new_sgid.gid_prefix = 0;
4348 		new_sgid.gid_guid = 0;
4349 	}
4350 
4351 	if ((new_dgid.gid_prefix != 0) && (new_sgid.gid_prefix != 0) &&
4352 	    (new_dgid.gid_prefix != new_sgid.gid_prefix)) {
4353 		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: Specified SGID's "
4354 		    "SNprefix (%llX) doesn't match with \n specified DGID's "
4355 		    "SNprefix: %llX", new_sgid.gid_prefix, new_dgid.gid_prefix);
4356 		return (IBT_INVALID_PARAM);
4357 	}
4358 
4359 	/* For the specified SGID, get HCA information. */
4360 	retval = ibtl_cm_get_hca_port(cur_sgid, 0, &c_hp);
4361 	if (retval != IBT_SUCCESS) {
4362 		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4363 		    "Get HCA Port Failed: %d", retval);
4364 		return (retval);
4365 	}
4366 
4367 	hcap = ibcm_find_hca_entry(c_hp.hp_hca_guid);
4368 	if (hcap == NULL) {
4369 		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: NO HCA found");
4370 		return (IBT_HCA_BUSY_DETACHING);
4371 	}
4372 
4373 	/* Validate whether this HCA support APM */
4374 	if (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG)) {
4375 		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4376 		    "HCA (%llX) - APM NOT SUPPORTED ", c_hp.hp_hca_guid);
4377 		retval = IBT_APM_NOT_SUPPORTED;
4378 		goto get_ip_alt_path_done;
4379 	}
4380 
4381 	/* Get Companion Port GID of the current Channel's SGID */
4382 	if ((new_sgid.gid_guid == 0) || ((new_sgid.gid_guid != 0) &&
4383 	    (new_sgid.gid_guid != cur_sgid.gid_guid))) {
4384 		IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: SRC: "
4385 		    "Get Companion PortGids for - %llX:%llX",
4386 		    cur_sgid.gid_prefix, cur_sgid.gid_guid);
4387 
4388 		retval = ibcm_get_comp_pgids(cur_sgid, new_sgid,
4389 		    c_hp.hp_hca_guid, &sgids_p, &snum);
4390 		if (retval != IBT_SUCCESS)
4391 			goto get_ip_alt_path_done;
4392 	}
4393 
4394 	/* Get Companion Port GID of the current Channel's DGID */
4395 	if ((new_dgid.gid_guid == 0) || ((new_dgid.gid_guid != 0) &&
4396 	    (new_dgid.gid_guid != cur_dgid.gid_guid))) {
4397 
4398 		IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: DEST: "
4399 		    "Get Companion PortGids for - %llX:%llX",
4400 		    cur_dgid.gid_prefix, cur_dgid.gid_guid);
4401 
4402 		retval = ibcm_get_comp_pgids(cur_dgid, new_dgid, 0, &dgids_p,
4403 		    &dnum);
4404 		if (retval != IBT_SUCCESS)
4405 			goto get_ip_alt_path_done;
4406 	}
4407 
4408 	if ((new_dgid.gid_guid == 0) || (new_sgid.gid_guid == 0)) {
4409 		if (new_sgid.gid_guid == 0) {
4410 			for (i = 0; i < snum; i++) {
4411 				if (new_dgid.gid_guid == 0) {
4412 					for (j = 0; j < dnum; j++) {
4413 						if (sgids_p[i].gid_prefix ==
4414 						    dgids_p[j].gid_prefix) {
4415 							new_dgid = dgids_p[j];
4416 							new_sgid = sgids_p[i];
4417 
4418 							goto get_ip_alt_proceed;
4419 						}
4420 					}
4421 					/*  Current DGID */
4422 					if (sgids_p[i].gid_prefix ==
4423 					    cur_dgid.gid_prefix) {
4424 						new_sgid = sgids_p[i];
4425 						goto get_ip_alt_proceed;
4426 					}
4427 				} else {
4428 					if (sgids_p[i].gid_prefix ==
4429 					    new_dgid.gid_prefix) {
4430 						new_sgid = sgids_p[i];
4431 						goto get_ip_alt_proceed;
4432 					}
4433 				}
4434 			}
4435 			/* Current SGID */
4436 			if (new_dgid.gid_guid == 0) {
4437 				for (j = 0; j < dnum; j++) {
4438 					if (cur_sgid.gid_prefix ==
4439 					    dgids_p[j].gid_prefix) {
4440 						new_dgid = dgids_p[j];
4441 
4442 						goto get_ip_alt_proceed;
4443 					}
4444 				}
4445 			}
4446 		} else if (new_dgid.gid_guid == 0) {
4447 			for (i = 0; i < dnum; i++) {
4448 				if (dgids_p[i].gid_prefix ==
4449 				    new_sgid.gid_prefix) {
4450 					new_dgid = dgids_p[i];
4451 					goto get_ip_alt_proceed;
4452 				}
4453 			}
4454 			/* Current DGID */
4455 			if (cur_dgid.gid_prefix == new_sgid.gid_prefix) {
4456 				goto get_ip_alt_proceed;
4457 			}
4458 		}
4459 		/*
4460 		 * hmm... No Companion Ports available.
4461 		 * so we will be using current or specified attributes only.
4462 		 */
4463 	}
4464 
4465 get_ip_alt_proceed:
4466 	if (new_sgid.gid_guid != 0) {
4467 		retval = ibtl_cm_get_hca_port(new_sgid, 0, &n_hp);
4468 		if (retval != IBT_SUCCESS) {
4469 			IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4470 			    "Get HCA Port Failed: %d", retval);
4471 			goto get_ip_alt_path_done;
4472 		}
4473 	}
4474 
4475 	/* Calculate the size for multi-path records template */
4476 	template_len = (2 * sizeof (ib_gid_t)) + sizeof (sa_multipath_record_t);
4477 
4478 	mpr_req = kmem_zalloc(template_len, KM_SLEEP);
4479 
4480 	ASSERT(mpr_req != NULL);
4481 
4482 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
4483 
4484 	gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
4485 	    sizeof (sa_multipath_record_t));
4486 
4487 	/* SGID */
4488 	if (new_sgid.gid_guid == 0)
4489 		*gid_ptr = cur_sgid;
4490 	else
4491 		*gid_ptr = new_sgid;
4492 
4493 	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: Get Path Between "
4494 	    " SGID : %llX:%llX", gid_ptr->gid_prefix, gid_ptr->gid_guid);
4495 
4496 	gid_ptr++;
4497 
4498 	/* DGID */
4499 	if (new_dgid.gid_guid == 0)
4500 		*gid_ptr = cur_dgid;
4501 	else
4502 		*gid_ptr = new_dgid;
4503 
4504 	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path:\t\t    DGID : %llX:%llX",
4505 	    gid_ptr->gid_prefix, gid_ptr->gid_guid);
4506 
4507 	mpr_req->SGIDCount = 1;
4508 	c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
4509 
4510 	mpr_req->DGIDCount = 1;
4511 	c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
4512 
4513 	/* Is Flow Label Specified. */
4514 	if (attrp) {
4515 		if (attrp->apa_flow) {
4516 			mpr_req->FlowLabel = attrp->apa_flow;
4517 			c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
4518 		}
4519 
4520 		/* Is HopLimit Specified. */
4521 		if (flags & IBT_PATH_HOP) {
4522 			mpr_req->HopLimit = attrp->apa_hop;
4523 			c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
4524 		}
4525 
4526 		/* Is TClass Specified. */
4527 		if (attrp->apa_tclass) {
4528 			mpr_req->TClass = attrp->apa_tclass;
4529 			c_mask |= SA_MPR_COMPMASK_TCLASS;
4530 		}
4531 
4532 		/* Is SL specified. */
4533 		if (attrp->apa_sl) {
4534 			mpr_req->SL = attrp->apa_sl;
4535 			c_mask |= SA_MPR_COMPMASK_SL;
4536 		}
4537 
4538 		if (flags & IBT_PATH_PERF) {
4539 			mpr_req->PacketLifeTimeSelector = IBT_BEST;
4540 			mpr_req->RateSelector = IBT_BEST;
4541 
4542 			c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
4543 			    SA_MPR_COMPMASK_RATESELECTOR;
4544 		} else {
4545 			if (attrp->apa_pkt_lt.p_selector == IBT_BEST) {
4546 				mpr_req->PacketLifeTimeSelector = IBT_BEST;
4547 				c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
4548 			}
4549 
4550 			if (attrp->apa_srate.r_selector == IBT_BEST) {
4551 				mpr_req->RateSelector = IBT_BEST;
4552 				c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
4553 			}
4554 		}
4555 
4556 		/*
4557 		 * Honor individual selection of these attributes,
4558 		 * even if IBT_PATH_PERF is set.
4559 		 */
4560 		/* Check out whether Packet Life Time is specified. */
4561 		if (attrp->apa_pkt_lt.p_pkt_lt) {
4562 			mpr_req->PacketLifeTime =
4563 			    ibt_usec2ib(attrp->apa_pkt_lt.p_pkt_lt);
4564 			mpr_req->PacketLifeTimeSelector =
4565 			    attrp->apa_pkt_lt.p_selector;
4566 
4567 			c_mask |= SA_MPR_COMPMASK_PKTLT |
4568 			    SA_MPR_COMPMASK_PKTLTSELECTOR;
4569 		}
4570 
4571 		/* Is SRATE specified. */
4572 		if (attrp->apa_srate.r_srate) {
4573 			mpr_req->Rate = attrp->apa_srate.r_srate;
4574 			mpr_req->RateSelector = attrp->apa_srate.r_selector;
4575 
4576 			c_mask |= SA_MPR_COMPMASK_RATE |
4577 			    SA_MPR_COMPMASK_RATESELECTOR;
4578 		}
4579 	}
4580 
4581 	/* Alt PathMTU can be GT or EQU to current channel's Pri PathMTU */
4582 
4583 	/* P_Key must be same as that of primary path */
4584 	retval = ibt_index2pkey_byguid(c_hp.hp_hca_guid, c_hp.hp_port,
4585 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix,
4586 	    &mpr_req->P_Key);
4587 	if (retval != IBT_SUCCESS) {
4588 		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: PKeyIdx2Pkey "
4589 		    "Failed: %d", retval);
4590 		goto get_ip_alt_path_done;
4591 	}
4592 	c_mask |= SA_MPR_COMPMASK_PKEY;
4593 
4594 	mpr_req->Reversible = 1;	/* We always get REVERSIBLE paths. */
4595 	mpr_req->IndependenceSelector = 1;
4596 	c_mask |= SA_MPR_COMPMASK_REVERSIBLE | SA_MPR_COMPMASK_INDEPSEL;
4597 
4598 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
4599 
4600 	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: CMask: 0x%llX", c_mask);
4601 
4602 	/* NOTE: We will **NOT** specify how many records we want. */
4603 
4604 	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: Primary: MTU %d, PKey[%d]="
4605 	    "0x%X\n\tSGID = %llX:%llX, DGID = %llX:%llX", prim_mtu,
4606 	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix, mpr_req->P_Key,
4607 	    cur_sgid.gid_prefix, cur_sgid.gid_guid, cur_dgid.gid_prefix,
4608 	    cur_dgid.gid_guid);
4609 
4610 	/* Get SA Access Handle. */
4611 	if (new_sgid.gid_guid != 0)
4612 		saa_handle = ibcm_get_saa_handle(hcap, n_hp.hp_port);
4613 	else
4614 		saa_handle = ibcm_get_saa_handle(hcap, c_hp.hp_port);
4615 	if (saa_handle == NULL) {
4616 		retval = IBT_HCA_PORT_NOT_ACTIVE;
4617 		goto get_ip_alt_path_done;
4618 	}
4619 
4620 	/* Contact SA Access to retrieve Path Records. */
4621 	access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
4622 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
4623 	access_args.sq_component_mask = c_mask;
4624 	access_args.sq_template = mpr_req;
4625 	access_args.sq_template_length = sizeof (sa_multipath_record_t);
4626 	access_args.sq_callback = NULL;
4627 	access_args.sq_callback_arg = NULL;
4628 
4629 	retval = ibcm_contact_sa_access(saa_handle, &access_args, &length,
4630 	    &results_p);
4631 	if (retval != IBT_SUCCESS) {
4632 		goto get_ip_alt_path_done;
4633 	}
4634 
4635 	num_rec = length / sizeof (sa_path_record_t);
4636 
4637 	kmem_free(mpr_req, template_len);
4638 
4639 	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: Found %d Paths", num_rec);
4640 
4641 	rec_found = 0;
4642 	if ((results_p != NULL) && (num_rec > 0)) {
4643 		/* Update the PathInfo with the response Path Records */
4644 		pr_resp = (sa_path_record_t *)results_p;
4645 		for (i = 0; i < num_rec; i++, pr_resp++) {
4646 			if (prim_mtu > pr_resp->Mtu) {
4647 				IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4648 				    "Alt PathMTU(%d) must be GT or EQU to Pri "
4649 				    "PathMTU(%d). Ignore this rec",
4650 				    pr_resp->Mtu, prim_mtu);
4651 				continue;
4652 			}
4653 
4654 			if ((new_sgid.gid_guid == 0) &&
4655 			    (new_dgid.gid_guid == 0)) {
4656 				/* Reject PathRec if it same as Primary Path. */
4657 				if (ibcm_compare_paths(pr_resp,
4658 				    &qp_attr.qp_info.qp_transport.rc.rc_path,
4659 				    &c_hp)) {
4660 					IBTF_DPRINTF_L3(cmlog,
4661 					    "ibt_get_ip_alt_path: PathRec "
4662 					    "obtained is similar to Prim Path, "
4663 					    "ignore this record");
4664 					continue;
4665 				}
4666 			}
4667 
4668 			if (new_sgid.gid_guid == 0) {
4669 				retval = ibcm_update_cep_info(pr_resp, NULL,
4670 				    &c_hp, &api_p->ap_alt_cep_path);
4671 			} else {
4672 				retval = ibcm_update_cep_info(pr_resp, NULL,
4673 				    &n_hp, &api_p->ap_alt_cep_path);
4674 			}
4675 			if (retval != IBT_SUCCESS)
4676 				continue;
4677 
4678 			/* Update some leftovers */
4679 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*api_p))
4680 
4681 			api_p->ap_alt_pkt_lt = pr_resp->PacketLifeTime;
4682 
4683 			_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*api_p))
4684 
4685 			rec_found = 1;
4686 			break;
4687 		}
4688 		kmem_free(results_p, length);
4689 	}
4690 
4691 	if (rec_found == 0) {
4692 		IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: AltPath cannot"
4693 		    " be established");
4694 		retval = IBT_PATH_RECORDS_NOT_FOUND;
4695 	} else
4696 		retval = IBT_SUCCESS;
4697 
4698 get_ip_alt_path_done:
4699 	if ((snum) && (sgids_p))
4700 		kmem_free(sgids_p, snum * sizeof (ib_gid_t));
4701 
4702 	if ((dnum) && (dgids_p))
4703 		kmem_free(dgids_p, dnum * sizeof (ib_gid_t));
4704 
4705 	ibcm_dec_hca_acc_cnt(hcap);
4706 
4707 	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: Done (status %d)", retval);
4708 
4709 	return (retval);
4710 }
4711 
4712 
4713 /* Routines for warlock */
4714 
4715 /* ARGSUSED */
4716 static void
4717 ibcm_dummy_path_handler(void *arg, ibt_status_t retval, ibt_path_info_t *paths,
4718     uint8_t num_path)
4719 {
4720 	ibcm_path_tqargs_t	dummy_path;
4721 
4722 	dummy_path.func = ibcm_dummy_path_handler;
4723 
4724 	IBTF_DPRINTF_L5(cmlog, "ibcm_dummy_path_handler: "
4725 	    "dummy_path.func %p", dummy_path.func);
4726 }
4727 
4728 /* ARGSUSED */
4729 static void
4730 ibcm_dummy_ip_path_handler(void *arg, ibt_status_t retval,
4731     ibt_path_info_t *paths, uint8_t num_path, ibt_path_ip_src_t *src_ip)
4732 {
4733 	ibcm_ip_path_tqargs_t	dummy_path;
4734 
4735 	dummy_path.func = ibcm_dummy_ip_path_handler;
4736 
4737 	IBTF_DPRINTF_L5(cmlog, "ibcm_dummy_ip_path_handler: "
4738 	    "dummy_path.func %p", dummy_path.func);
4739 }
4740