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