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