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