ibcm_path.c revision 4703:bb31c50bb3ab
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. */
38typedef 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. */
47typedef 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
56typedef 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. */
68static ibt_status_t ibcm_get_path_rec(ibcm_path_tqargs_t *, ibcm_dinfo_t *,
69    uint8_t *, ibt_path_info_t *);
70
71static ibt_status_t ibcm_saa_path_rec(ibcm_path_tqargs_t *,
72    ibtl_cm_port_list_t *, ibcm_dinfo_t *, uint8_t *);
73
74static 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
77static ibt_status_t ibcm_fillin_loopbackinfo(ibtl_cm_port_list_t *,
78    uint8_t index, ibcm_dinfo_t *, ibt_path_info_t *);
79
80static ibt_status_t ibcm_saa_service_rec(ibcm_path_tqargs_t *,
81    ibtl_cm_port_list_t *, ibcm_dinfo_t *);
82
83static 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
87static 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
91static ibt_status_t ibcm_validate_path_attributes(ibt_path_attr_t *attrp,
92    ibt_path_flags_t flags, uint8_t max_paths);
93
94static 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
98static void ibcm_process_async_get_paths(void *tq_arg);
99
100static ibt_status_t ibcm_process_get_paths(void *tq_arg);
101
102static 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 */
127ibt_status_t
128ibt_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
168typedef 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
175kmutex_t ibcm_path_cache_mutex;
176int ibcm_path_cache_invalidate;	/* invalidate cache on next ibt_get_paths */
177clock_t ibcm_path_cache_timeout = IBCM_PATH_CACHE_TIMEOUT; /* tunable */
178timeout_id_t ibcm_path_cache_timeout_id;
179int ibcm_path_cache_size_init = IBCM_PATH_CACHE_SIZE;	/* tunable */
180int ibcm_path_cache_size;
181ibcm_path_cache_t *ibcm_path_cachep;
182
183struct 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*/
194static void
195ibcm_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
209void
210ibcm_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
227void
228ibcm_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
248static ibcm_status_t
249ibcm_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
311static void
312ibcm_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
358void
359ibcm_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 */
396ibt_status_t
397ibt_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
430static ibt_status_t
431ibcm_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
503static void
504ibcm_process_async_get_paths(void *tq_arg)
505{
506	(void) ibcm_process_get_paths(tq_arg);
507}
508
509
510static ibt_status_t
511ibcm_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
654static ibt_status_t
655ibcm_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
833path_error1:
834	ibcm_dec_hca_acc_cnt(hcap);
835
836path_error:
837	if (slistp)
838		ibtl_cm_free_active_plist(slistp);
839
840	if (dinfo)
841		kmem_free(dinfo, len);
842
843path_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 */
897static ibt_status_t
898ibcm_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
1052ibt_status_t
1053ibcm_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
1090static ibt_status_t
1091ibcm_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
1134static ibt_status_t
1135ibcm_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
1405static ibt_status_t
1406ibcm_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		}
1852get_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 */
1886static ibt_status_t
1887ibcm_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 */
1968static ibt_status_t
1969ibcm_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 conversion failed: %d", retval);
2004			return (ibt_get_module_failure(IBT_FAILURE_IBSM, 0));
2005		}
2006		cep_p->cep_adds_vect.av_sgid_ix = hport->hp_sgid_ix;
2007		cep_p->cep_adds_vect.av_src_path =
2008		    prec_resp->SLID - hport->hp_base_lid;
2009		cep_p->cep_adds_vect.av_port_num = cep_p->cep_hca_port_num =
2010		    hport->hp_port;
2011	} else if (sl != NULL) {
2012		for (i = 0; i < sl->p_count; i++) {
2013			if (prec_resp->SGID.gid_guid == sl[i].p_sgid.gid_guid) {
2014				/* Convert P_Key to P_Key_Index */
2015				retval = ibt_pkey2index_byguid(sl[i].p_hca_guid,
2016				    sl[i].p_port_num, prec_resp->P_Key,
2017				    &cep_p->cep_pkey_ix);
2018				if (retval != IBT_SUCCESS) {
2019					/* Failed to get pkey_index from pkey */
2020					IBTF_DPRINTF_L2(cmlog,
2021					    "ibcm_update_cep_info: Pkey2Index "
2022					    "conversion failed: %d", retval);
2023					return (ibt_get_module_failure(
2024					    IBT_FAILURE_IBSM, 0));
2025				}
2026
2027				cep_p->cep_adds_vect.av_sgid_ix =
2028				    sl[i].p_sgid_ix;
2029				cep_p->cep_adds_vect.av_src_path =
2030				    prec_resp->SLID - sl[i].p_base_lid;
2031				cep_p->cep_adds_vect.av_port_num =
2032				    sl[i].p_port_num;
2033				cep_p->cep_hca_port_num = sl[i].p_port_num;
2034
2035				break;
2036			}
2037		}
2038	} else {
2039		IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: Sl or Hport "
2040		    "must be non-null");
2041		return (IBT_INVALID_PARAM);
2042	}
2043
2044	if (prec_resp->Rate) {
2045		cep_p->cep_adds_vect.av_srate = prec_resp->Rate;
2046	} else {
2047		IBTF_DPRINTF_L2(cmlog, "ibcm_update_cep_info: SRate (%d) from "
2048		    "pathrecord is invalid, reject it.", prec_resp->Rate);
2049		return (ibt_get_module_failure(IBT_FAILURE_IBSM, 0));
2050	}
2051	/*
2052	 * If both Source and Destination GID prefix are same, then GRH is not
2053	 * valid, so make it as false, else set this field as true.
2054	 */
2055	if (prec_resp->SGID.gid_prefix == prec_resp->DGID.gid_prefix)
2056		cep_p->cep_adds_vect.av_send_grh = B_FALSE;
2057	else
2058		cep_p->cep_adds_vect.av_send_grh = B_TRUE;
2059
2060	/* SGID and SGID Index. */
2061	cep_p->cep_adds_vect.av_sgid = prec_resp->SGID;
2062	cep_p->cep_adds_vect.av_flow = prec_resp->FlowLabel;
2063	cep_p->cep_adds_vect.av_tclass = prec_resp->TClass;
2064	cep_p->cep_adds_vect.av_hop = prec_resp->HopLimit;
2065
2066	/* Address Vector Definition. */
2067	cep_p->cep_adds_vect.av_dlid = prec_resp->DLID;
2068	cep_p->cep_adds_vect.av_srvl = prec_resp->SL;
2069
2070	/* DGID */
2071	cep_p->cep_adds_vect.av_dgid = prec_resp->DGID;
2072
2073	/* CEP Timeout is NOT filled in by PATH routines. */
2074	cep_p->cep_timeout = 0;
2075
2076	IBTF_DPRINTF_L3(cmlog, "ibcm_update_cep_info: Done.  Port[%d]\n"
2077	    "SGID=%llX:%llX DGID=%llX:%llX",
2078	    cep_p->cep_adds_vect.av_port_num,
2079	    prec_resp->SGID.gid_prefix, prec_resp->SGID.gid_guid,
2080	    prec_resp->DGID.gid_prefix, prec_resp->DGID.gid_guid);
2081
2082	return (IBT_SUCCESS);
2083}
2084
2085
2086static void
2087ibcm_fill_svcinfo(sa_service_record_t *sr_resp, ibcm_dest_t *dest)
2088{
2089	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dest))
2090
2091	dest->d_gid = sr_resp->ServiceGID;
2092	dest->d_sid = sr_resp->ServiceID;
2093	ibcm_swizzle_to_srv(sr_resp->ServiceData, &dest->d_sdata);
2094	dest->d_pkey = sr_resp->ServiceP_Key;
2095
2096	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*dest))
2097
2098	IBTF_DPRINTF_L3(cmlog, "ibcm_fill_svcinfo: SID(%llX), GID(%llX:%llX)"
2099	    "\n\tSvcPKey 0x%X", dest->d_sid, dest->d_gid.gid_prefix,
2100	    dest->d_gid.gid_guid, dest->d_pkey);
2101}
2102
2103
2104static ib_gid_t
2105ibcm_saa_get_agid(ibtl_cm_port_list_t *sl, ib_gid_t *gidp, uint_t ngid)
2106{
2107	int		k, l;
2108	ib_gid_t	a_gid;
2109
2110	a_gid.gid_prefix = a_gid.gid_guid = 0;
2111
2112	for (k = 0; k < sl->p_count; k++) {
2113		for (l = 0; l < ngid; l++) {
2114
2115			if (gidp->gid_prefix == sl->p_sgid.gid_prefix) {
2116				a_gid = *gidp;
2117				break;
2118			}
2119			if (a_gid.gid_guid && a_gid.gid_prefix)
2120				break;
2121			gidp++;
2122		}
2123		if (a_gid.gid_guid && a_gid.gid_prefix)
2124			break;
2125		sl++;
2126	}
2127	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_get_agid: AltGID = %llX:%llX",
2128	    a_gid.gid_prefix, a_gid.gid_guid);
2129
2130	return (a_gid);
2131}
2132
2133/*
2134 * Perform SA Access to retrieve Service Records.
2135 * On Success, returns ServiceID and ServiceGID info in '*dinfo'.
2136 */
2137static ibt_status_t
2138ibcm_saa_service_rec(ibcm_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
2139    ibcm_dinfo_t *dinfo)
2140{
2141	sa_service_record_t	svcrec_req;
2142	sa_service_record_t	*svcrec_resp;
2143	void			*results_p;
2144	uint64_t		component_mask = 0;
2145	size_t			length;
2146	uint8_t			i, j, k, rec_found, s;
2147	ibmf_saa_access_args_t	access_args;
2148	ibt_status_t		retval;
2149	ibt_path_attr_t		*attrp = &p_arg->attr;
2150	uint64_t		tmp_sd_flag = attrp->pa_sd_flags;
2151	uint8_t			num_req;
2152
2153	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec(%p, %p)", p_arg, sl);
2154
2155	bzero(&svcrec_req, sizeof (svcrec_req));
2156
2157	/* Service Name */
2158	if ((attrp->pa_sname != NULL) && (strlen(attrp->pa_sname) != 0)) {
2159		(void) strncpy((char *)(svcrec_req.ServiceName),
2160		    attrp->pa_sname, IB_SVC_NAME_LEN);
2161
2162		component_mask |= SA_SR_COMPMASK_NAME;
2163	}
2164
2165	/* Service ID */
2166	if (attrp->pa_sid) {
2167		svcrec_req.ServiceID = attrp->pa_sid;
2168		component_mask |= SA_SR_COMPMASK_ID;
2169	}
2170
2171	/* Is P_Key Specified. */
2172	if (p_arg->flags & IBT_PATH_PKEY) {
2173		svcrec_req.ServiceP_Key = attrp->pa_pkey;
2174		component_mask |= SA_SR_COMPMASK_PKEY;
2175	}
2176
2177	/* Is ServiceData Specified. */
2178	if (attrp->pa_sd_flags != IBT_NO_SDATA) {
2179		/* Handle endianess for service data. */
2180		ibcm_swizzle_from_srv(&attrp->pa_sdata, svcrec_req.ServiceData);
2181
2182		/*
2183		 * Lets not interpret each and every ServiceData flags,
2184		 * just pass it on to SAA. Shift the flag, to suit
2185		 * SA_SR_COMPMASK_ALL_DATA definition.
2186		 */
2187		component_mask |= (tmp_sd_flag << 7);
2188	}
2189
2190	if (dinfo->num_dest == 1) {
2191
2192		/* If a single DGID is specified, provide it */
2193		svcrec_req.ServiceGID = dinfo->dest->d_gid;
2194		component_mask |= SA_SR_COMPMASK_GID;
2195
2196		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec:%llX:%llX",
2197		    svcrec_req.ServiceGID.gid_prefix,
2198		    svcrec_req.ServiceGID.gid_guid);
2199	}
2200
2201	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2202	    "Perform SA Access: Mask: 0x%X", component_mask);
2203
2204	/*
2205	 * Call in SA Access retrieve routine to get Service Records.
2206	 *
2207	 * SA Access framework allocated memory for the "results_p".
2208	 * Make sure to deallocate once we are done with the results_p.
2209	 * The size of the buffer allocated will be as returned in
2210	 * "length" field.
2211	 */
2212	access_args.sq_attr_id = SA_SERVICERECORD_ATTRID;
2213	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
2214	access_args.sq_component_mask = component_mask;
2215	access_args.sq_template = &svcrec_req;
2216	access_args.sq_template_length = sizeof (sa_service_record_t);
2217	access_args.sq_callback = NULL;
2218	access_args.sq_callback_arg = NULL;
2219
2220	for (s = 0; s < sl->p_count; s++) {
2221		retval = ibcm_contact_sa_access(sl[s].p_saa_hdl, &access_args,
2222		    &length, &results_p);
2223		if (retval != IBT_SUCCESS)
2224			if (sl[s].p_multi & IBTL_CM_MULTI_SM)
2225				continue;
2226			else
2227				return (retval);
2228
2229		if ((results_p == NULL) || (length == 0)) {
2230			IBTF_DPRINTF_L2(cmlog, "ibcm_saa_service_rec: SvcRec "
2231			    "Not Found: res_p %p, len %d", results_p, length);
2232			if (sl[s].p_multi & IBTL_CM_MULTI_SM) {
2233				retval = IBT_SERVICE_RECORDS_NOT_FOUND;
2234				continue;
2235			} else
2236				return (IBT_SERVICE_RECORDS_NOT_FOUND);
2237		}
2238
2239		/* if we are here, we got some records. so break. */
2240		break;
2241	}
2242
2243	if (retval != IBT_SUCCESS)
2244		return (retval);
2245
2246	num_req = length / sizeof (sa_service_record_t);
2247
2248	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Got %d Service Records.",
2249	    num_req);
2250
2251	svcrec_resp = (sa_service_record_t *)results_p;
2252	rec_found = 0;
2253
2254	/* Update the return values. */
2255	if (dinfo->num_dest) {
2256		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Get ServiceRec "
2257		    "for Specified DGID: %d", dinfo->num_dest);
2258
2259		for (i = 0; i < num_req; i++, svcrec_resp++) {
2260			/* Limited P_Key is NOT supported as of now!. */
2261			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2262				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2263				    "SvcPkey 0x%X limited, reject the record.",
2264				    svcrec_resp->ServiceP_Key);
2265				continue;
2266			}
2267
2268			for (j = 0; j < dinfo->num_dest; j++) {
2269				if (dinfo->dest[j].d_gid.gid_guid ==
2270				    svcrec_resp->ServiceGID.gid_guid) {
2271					ibcm_fill_svcinfo(svcrec_resp,
2272					    &dinfo->dest[j]);
2273					rec_found++;
2274				}
2275				if (rec_found == dinfo->num_dest)
2276					break;
2277			}
2278			if (rec_found == dinfo->num_dest)
2279				break;
2280		}
2281		if (rec_found != dinfo->num_dest) {
2282			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Did NOT "
2283			    "find ServiceRec for all DGIDs: (%d/%d)", rec_found,
2284			    dinfo->num_dest);
2285			retval = IBT_INSUFF_DATA;
2286		}
2287	} else if (p_arg->flags & IBT_PATH_APM) {
2288		ib_gid_t		p_gid, a_gid, last_p_gid;
2289		ib_gid_t		*gidp = NULL;
2290		uint_t			n_gids;
2291		sa_service_record_t	*stmp;
2292		boolean_t		pri_fill_done = B_FALSE;
2293		boolean_t		alt_fill_done = B_FALSE;
2294		ib_pkey_t		p_pkey = 0, a_pkey = 0;
2295
2296		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: Need to "
2297		    "find ServiceRec that can satisfy APM");
2298
2299		p_gid.gid_prefix = p_gid.gid_guid = 0;
2300		a_gid.gid_prefix = a_gid.gid_guid = 0;
2301		last_p_gid.gid_prefix = last_p_gid.gid_guid = 0;
2302
2303		for (i = 0; i < num_req; i++, svcrec_resp++) {
2304			ibt_status_t	ret;
2305			boolean_t	is_this_on_local_node = B_FALSE;
2306
2307			/* Limited P_Key is NOT supported as of now!. */
2308			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2309				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2310				    "SvcPkey 0x%X limited, reject the record.",
2311				    svcrec_resp->ServiceP_Key);
2312				continue;
2313			}
2314
2315			p_gid = svcrec_resp->ServiceGID;
2316
2317			/* Let's avoid LoopBack Nodes. */
2318			for (j = 0; j < sl->p_count; j++) {
2319				if (p_gid.gid_guid == sl[j].p_sgid.gid_guid) {
2320					is_this_on_local_node = B_TRUE;
2321
2322					IBTF_DPRINTF_L3(cmlog,
2323					    "ibcm_saa_service_rec: ServiceGID "
2324					    "%llX:%llX is on Local Node, "
2325					    "search for remote.",
2326					    p_gid.gid_prefix, p_gid.gid_guid);
2327				}
2328			}
2329
2330			if (is_this_on_local_node == B_TRUE) {
2331				if ((i + 1) < num_req) {
2332					p_gid.gid_prefix = 0;
2333					p_gid.gid_guid = 0;
2334					continue;
2335				} else if (last_p_gid.gid_prefix != 0) {
2336					p_gid = last_p_gid;
2337					break;
2338				}
2339			}
2340
2341			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2342			    "Finally let Primary DGID = %llX:%llX",
2343			    p_gid.gid_prefix, p_gid.gid_guid);
2344
2345			ret = ibt_get_companion_port_gids(p_gid, 0, 0,
2346			    &gidp, &n_gids);
2347			if (ret == IBT_SUCCESS) {
2348				IBTF_DPRINTF_L3(cmlog,
2349				    "ibcm_saa_service_rec: Found %d "
2350				    "CompGID for %llX:%llX", n_gids,
2351				    p_gid.gid_prefix, p_gid.gid_guid);
2352
2353				stmp = (sa_service_record_t *)results_p;
2354				a_gid.gid_prefix = a_gid.gid_guid = 0;
2355
2356				if (sl->p_multi & IBTL_CM_MULTI_SM) {
2357					/* validate sn_pfx */
2358					a_gid = ibcm_saa_get_agid(sl,
2359					    gidp, n_gids);
2360				} else {
2361					for (k = 0; k < num_req; k++) {
2362						ib_gid_t sg = stmp->ServiceGID;
2363
2364						IBTF_DPRINTF_L3(cmlog,
2365						    "ibcm_saa_service_rec: "
2366						    "SvcGID[%d] = %llX:%llX", k,
2367						    sg.gid_prefix, sg.gid_guid);
2368
2369						for (j = 0; j < n_gids; j++) {
2370							if (gidp[j].gid_guid ==
2371							    sg.gid_guid) {
2372								a_gid = gidp[j];
2373								break;
2374							}
2375						}
2376						if (a_gid.gid_guid)
2377							break;
2378						stmp++;
2379					}
2380					if (a_gid.gid_guid == 0) {
2381						/* Rec not found for Alt. */
2382						for (j = 0; j < n_gids; j++) {
2383							if (gidp[j].gid_prefix
2384							    == p_gid.
2385							    gid_prefix) {
2386								a_gid = gidp[j];
2387								break;
2388							}
2389						}
2390					}
2391				}
2392				kmem_free(gidp,
2393				    n_gids * sizeof (ib_gid_t));
2394
2395				if (a_gid.gid_guid)
2396					break;
2397			} else if (ret == IBT_GIDS_NOT_FOUND) {
2398				last_p_gid = p_gid;
2399				IBTF_DPRINTF_L3(cmlog,
2400				    "ibcm_saa_service_rec: Didn't find "
2401				    "CompGID for %llX:%llX, ret=%d",
2402				    p_gid.gid_prefix, p_gid.gid_guid,
2403				    ret);
2404			} else {
2405				IBTF_DPRINTF_L3(cmlog,
2406				    "ibcm_saa_service_rec: Call to "
2407				    "ibt_get_companion_port_gids(%llX:"
2408				    "%llX) Failed = %d",
2409				    p_gid.gid_prefix, p_gid.gid_guid,
2410				    ret);
2411			}
2412		}
2413
2414		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: \n\t"
2415		    "Pri DGID(%llX:%llX), Alt DGID(%llX:%llX)",
2416		    p_gid.gid_prefix, p_gid.gid_guid, a_gid.gid_prefix,
2417		    a_gid.gid_guid);
2418
2419		svcrec_resp = (sa_service_record_t *)results_p;
2420
2421		for (i = 0, j = 0; i < num_req; i++, svcrec_resp++) {
2422			/* Limited P_Key is NOT supported as of now!. */
2423			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2424				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2425				    "SvcPkey 0x%X limited, reject the record.",
2426				    svcrec_resp->ServiceP_Key);
2427				continue;
2428			}
2429
2430			if ((pri_fill_done == B_FALSE) &&
2431			    (p_gid.gid_guid ==
2432			    svcrec_resp->ServiceGID.gid_guid)) {
2433				p_pkey = svcrec_resp->ServiceP_Key;
2434				if ((a_pkey != 0) &&
2435				    (a_pkey != p_pkey)) {
2436					IBTF_DPRINTF_L3(cmlog,
2437					    "ibcm_saa_service_rec: "
2438					    "Pri(0x%X) & Alt (0x%X) "
2439					    "PKey must match.",
2440					    p_pkey, a_pkey);
2441					p_pkey = 0;
2442					continue;
2443				}
2444				ibcm_fill_svcinfo(svcrec_resp,
2445				    &dinfo->dest[j++]);
2446				rec_found++;
2447				pri_fill_done = B_TRUE;
2448			} else if ((alt_fill_done == B_FALSE) &&
2449			    (a_gid.gid_guid ==
2450			    svcrec_resp->ServiceGID.gid_guid)) {
2451				a_pkey = svcrec_resp->ServiceP_Key;
2452				if ((p_pkey != 0) &&
2453				    (a_pkey != p_pkey)) {
2454					IBTF_DPRINTF_L3(cmlog,
2455					    "ibcm_saa_service_rec: "
2456					    "Pri(0x%X) & Alt (0x%X) "
2457					    "PKey must match.",
2458					    p_pkey, a_pkey);
2459					a_pkey = 0;
2460					continue;
2461				}
2462				ibcm_fill_svcinfo(svcrec_resp,
2463				    &dinfo->dest[j++]);
2464				rec_found++;
2465				alt_fill_done = B_TRUE;
2466			}
2467
2468			if (rec_found == 2)
2469				break;
2470		}
2471		if ((alt_fill_done == B_FALSE) && (a_gid.gid_guid)) {
2472			dinfo->dest[j].d_gid = a_gid;
2473			dinfo->dest[j].d_pkey = p_pkey;
2474			rec_found++;
2475			IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2476			    "Let Alt Pkey=%X, DGID=%llX:%llX", p_pkey,
2477			    a_gid.gid_prefix, a_gid.gid_guid);
2478		}
2479
2480		if (rec_found == 1)
2481			retval = IBT_INSUFF_DATA;
2482	} else if (p_arg->flags & IBT_PATH_MULTI_SVC_DEST) {
2483		for (i = 0; i < num_req; i++, svcrec_resp++) {
2484			ib_gid_t	p_gid;
2485			boolean_t	is_this_on_local_node = B_FALSE;
2486
2487			/* Limited P_Key is NOT supported as of now!. */
2488			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2489				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2490				    "SvcPkey 0x%X limited, reject the record.",
2491				    svcrec_resp->ServiceP_Key);
2492				continue;
2493			}
2494
2495			p_gid = svcrec_resp->ServiceGID;
2496
2497			/* Let's avoid LoopBack Nodes. */
2498			for (j = 0; j < sl->p_count; j++) {
2499				if (p_gid.gid_guid == sl[j].p_sgid.gid_guid) {
2500					is_this_on_local_node = B_TRUE;
2501					IBTF_DPRINTF_L3(cmlog,
2502					    "ibcm_saa_service_rec: ServiceGID "
2503					    "%llX:%llX is on Local Node, "
2504					    "search for remote.",
2505					    p_gid.gid_prefix, p_gid.gid_guid);
2506				}
2507			}
2508
2509			if (is_this_on_local_node == B_TRUE)
2510				if ((i + 1) < num_req)
2511					continue;
2512
2513			IBTF_DPRINTF_L4(cmlog, "ibcm_saa_service_rec: "
2514			    "Found ServiceGID = %llX:%llX",
2515			    p_gid.gid_prefix, p_gid.gid_guid);
2516
2517			ibcm_fill_svcinfo(svcrec_resp,
2518			    &dinfo->dest[rec_found]);
2519			rec_found++;
2520			if (rec_found == p_arg->max_paths)
2521				break;
2522		}
2523
2524		if (rec_found < p_arg->max_paths)
2525			retval = IBT_INSUFF_DATA;
2526	} else {
2527		for (i = 0; i < num_req; i++) {
2528			/* Limited P_Key is NOT supported as of now!. */
2529			if ((svcrec_resp->ServiceP_Key & 0x8000) == 0) {
2530				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2531				    "SvcPkey 0x%X limited, reject the record.",
2532				    svcrec_resp->ServiceP_Key);
2533				svcrec_resp++;
2534				continue;
2535			}
2536
2537			ibcm_fill_svcinfo(svcrec_resp, &dinfo->dest[0]);
2538			rec_found = 1;
2539
2540			/* Avoid having loopback node */
2541			if (svcrec_resp->ServiceGID.gid_guid !=
2542			    sl->p_sgid.gid_guid) {
2543				break;
2544			} else {
2545				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2546				    "avoid LoopBack node.");
2547				svcrec_resp++;
2548			}
2549		}
2550	}
2551
2552	/* Deallocate the memory for results_p. */
2553	kmem_free(results_p, length);
2554	if (dinfo->num_dest == 0)
2555		dinfo->num_dest = rec_found;
2556
2557	/*
2558	 * Check out whether all Service Path we looking for are on the same
2559	 * P_key. If yes, then set the global p_key field with that value,
2560	 * to make it easy during SA Path Query.
2561	 */
2562	if ((dinfo->num_dest) && (dinfo->p_key == 0)) {
2563		ib_pkey_t	pk = dinfo->dest[0].d_pkey;
2564
2565		if (dinfo->num_dest == 1) {
2566			dinfo->p_key = pk;
2567		} else {
2568			for (i = 1; i < (dinfo->num_dest - 1); i++) {
2569				IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: "
2570				    "pk= 0x%X, pk[%d]= 0x%X", pk, i,
2571				    dinfo->dest[i].d_pkey);
2572				if (pk != dinfo->dest[i].d_pkey) {
2573					dinfo->p_key = 0;
2574					break;
2575				} else {
2576					dinfo->p_key = pk;
2577				}
2578			}
2579		}
2580	}
2581
2582	if (rec_found == 0) {
2583		IBTF_DPRINTF_L2(cmlog, "ibcm_saa_service_rec: "
2584		    "ServiceRec NOT Found");
2585		retval = IBT_SERVICE_RECORDS_NOT_FOUND;
2586	}
2587
2588	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_service_rec: done. Status %d, "
2589	    "PKey 0x%X, Found %d SvcRec", retval, dinfo->p_key, rec_found);
2590
2591	return (retval);
2592}
2593
2594
2595static boolean_t
2596ibcm_compare_paths(sa_path_record_t *pr_resp, ibt_cep_path_t *rc_path,
2597    ibtl_cm_hca_port_t *c_hp)
2598{
2599	if ((rc_path->cep_hca_port_num == c_hp->hp_port) &&
2600	    (rc_path->cep_adds_vect.av_src_path ==
2601	    (pr_resp->SLID - c_hp->hp_base_lid)) &&
2602	    (rc_path->cep_adds_vect.av_dlid == pr_resp->DLID) &&
2603	    (rc_path->cep_adds_vect.av_srate == pr_resp->Rate)) {
2604		return (B_TRUE);
2605	} else {
2606		return (B_FALSE);
2607	}
2608}
2609
2610/*
2611 * ibcm_get_comp_pgids() routine gets the companion port for 'gid'.
2612 *
2613 * On success:
2614 *	If 'n_gid' is specified, then verify whether 'n_gid' is indeed a
2615 *	companion portgid of 'gid'.  If matches return success or else error.
2616 *
2617 *	If 'n_gid' is NOT specified, then return back SUCCESS along with
2618 *	obtained Companion PortGids 'gid_p', where 'num' indicated number
2619 *	of companion portgids returned in 'gid_p'.
2620 */
2621
2622static ibt_status_t
2623ibcm_get_comp_pgids(ib_gid_t gid, ib_gid_t n_gid, ib_guid_t hca_guid,
2624    ib_gid_t **gid_p, uint_t *num)
2625{
2626	ibt_status_t    ret;
2627	int		i;
2628
2629	ret = ibt_get_companion_port_gids(gid, hca_guid, 0, gid_p, num);
2630	if ((ret != IBT_SUCCESS) && (ret != IBT_GIDS_NOT_FOUND)) {
2631		IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: "
2632		    "ibt_get_companion_port_gids(%llX:%llX) Failed: %d",
2633		    gid.gid_prefix, gid.gid_guid, ret);
2634	} else if ((ret == IBT_GIDS_NOT_FOUND) && (n_gid.gid_guid != 0)) {
2635		IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: Specified GID "
2636		    "(%llX:%llX) is NOT a Companion \n\t to current channel's "
2637		    "GID(%llX:%llX)", n_gid.gid_prefix, n_gid.gid_guid,
2638		    gid.gid_prefix, gid.gid_guid);
2639		ret = IBT_INVALID_PARAM;
2640	} else if (n_gid.gid_guid != 0) {
2641		/*
2642		 * We found some Comp GIDs and n_gid is specified. Validate
2643		 * whether the 'n_gid' specified is indeed the companion port
2644		 * GID of 'gid'.
2645		 */
2646		for (i = 0; i < *num; i++) {
2647			if ((n_gid.gid_prefix == gid_p[i]->gid_prefix) &&
2648			    (n_gid.gid_guid == gid_p[i]->gid_guid)) {
2649				IBTF_DPRINTF_L3(cmlog, "ibcm_get_comp_pgids: "
2650				    "Matching Found!. Done.");
2651				return (IBT_SUCCESS);
2652			}
2653		}
2654		IBTF_DPRINTF_L2(cmlog, "ibcm_get_comp_pgids: GID (%llX:%llX)\n"
2655		    "\t and (%llX:%llX) are NOT Companion Port GIDS",
2656		    n_gid.gid_prefix, n_gid.gid_guid, gid.gid_prefix,
2657		    gid.gid_guid);
2658		ret = IBT_INVALID_PARAM;
2659	} else {
2660		ret = IBT_SUCCESS;
2661	}
2662
2663	IBTF_DPRINTF_L3(cmlog, "ibcm_get_comp_pgids: done. Status = %d", ret);
2664	return (ret);
2665}
2666
2667/*
2668 * Function:
2669 *	ibt_get_alt_path
2670 * Input:
2671 *	rc_chan		An RC channel handle returned in a previous call
2672 *			ibt_alloc_rc_channel(9F), specifies the channel to open.
2673 *	flags		Path flags.
2674 *	attrp		A pointer to an ibt_alt_path_attr_t(9S) structure that
2675 *			specifies required attributes of the selected path(s).
2676 * Output:
2677 *	api_p		An ibt_alt_path_info_t(9S) struct filled in as output
2678 *			parameters.
2679 * Returns:
2680 *	IBT_SUCCESS on Success else appropriate error.
2681 * Description:
2682 *      Finds the best alternate path to a specified channel (as determined by
2683 *      the IBTL) that satisfies the requirements specified in an
2684 *      ibt_alt_path_attr_t struct.  The specified channel must have been
2685 *      previously opened successfully using ibt_open_rc_channel.
2686 *      This function also ensures that the service being accessed by the
2687 *      channel is available at the selected alternate port.
2688 *
2689 *      Note: The apa_dgid must be on the same destination channel adapter,
2690 *      if specified.
2691 *	This routine can not be called from interrupt context.
2692 */
2693ibt_status_t
2694ibt_get_alt_path(ibt_channel_hdl_t rc_chan, ibt_path_flags_t flags,
2695    ibt_alt_path_attr_t *attrp, ibt_alt_path_info_t *api_p)
2696{
2697	sa_multipath_record_t	*mpr_req;
2698	sa_path_record_t	*pr_resp;
2699	ibmf_saa_access_args_t	access_args;
2700	ibt_qp_query_attr_t	qp_attr;
2701	ibtl_cm_hca_port_t	c_hp, n_hp;
2702	ibcm_hca_info_t		*hcap;
2703	void			*results_p;
2704	uint64_t		c_mask = 0;
2705	ib_gid_t		*gid_ptr = NULL;
2706	ib_gid_t		*sgids_p = NULL,  *dgids_p = NULL;
2707	ib_gid_t		cur_dgid, cur_sgid;
2708	ib_gid_t		new_dgid, new_sgid;
2709	ibmf_saa_handle_t	saa_handle;
2710	size_t			length;
2711	int			i, j, template_len, rec_found;
2712	uint_t			snum = 0, dnum = 0, num_rec;
2713	ibt_status_t		retval;
2714	ib_mtu_t		prim_mtu;
2715
2716	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path(%p, %x, %p, %p)",
2717	    rc_chan, flags, attrp, api_p);
2718
2719	/* validate channel */
2720	if (IBCM_INVALID_CHANNEL(rc_chan)) {
2721		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: invalid channel");
2722		return (IBT_CHAN_HDL_INVALID);
2723	}
2724
2725	if (api_p == NULL) {
2726		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: invalid attribute: "
2727		    " AltPathInfo can't be NULL");
2728		return (IBT_INVALID_PARAM);
2729	}
2730
2731	retval = ibt_query_qp(rc_chan, &qp_attr);
2732	if (retval != IBT_SUCCESS) {
2733		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: ibt_query_qp(%p) "
2734		    "failed %d", rc_chan, retval);
2735		return (retval);
2736	}
2737
2738	if (qp_attr.qp_info.qp_trans != IBT_RC_SRV) {
2739		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2740		    "Invalid Channel type: Applicable only to RC Channel");
2741		return (IBT_CHAN_SRV_TYPE_INVALID);
2742	}
2743
2744	cur_dgid =
2745	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dgid;
2746	cur_sgid =
2747	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_sgid;
2748	prim_mtu = qp_attr.qp_info.qp_transport.rc.rc_path_mtu;
2749
2750	/* If optional attributes are specified, validate them. */
2751	if (attrp) {
2752		new_dgid = attrp->apa_dgid;
2753		new_sgid = attrp->apa_sgid;
2754	} else {
2755		new_dgid.gid_prefix = 0;
2756		new_dgid.gid_guid = 0;
2757		new_sgid.gid_prefix = 0;
2758		new_sgid.gid_guid = 0;
2759	}
2760
2761	if ((new_dgid.gid_prefix != 0) && (new_sgid.gid_prefix != 0) &&
2762	    (new_dgid.gid_prefix != new_sgid.gid_prefix)) {
2763		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: Specified SGID's "
2764		    "SNprefix (%llX) doesn't match with \n specified DGID's "
2765		    "SNprefix: %llX", new_sgid.gid_prefix, new_dgid.gid_prefix);
2766		return (IBT_INVALID_PARAM);
2767	}
2768
2769	/* For the specified SGID, get HCA information. */
2770	retval = ibtl_cm_get_hca_port(cur_sgid, 0, &c_hp);
2771	if (retval != IBT_SUCCESS) {
2772		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2773		    "Get HCA Port Failed: %d", retval);
2774		return (retval);
2775	}
2776
2777	hcap = ibcm_find_hca_entry(c_hp.hp_hca_guid);
2778	if (hcap == NULL) {
2779		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: NO HCA found");
2780		return (IBT_HCA_BUSY_DETACHING);
2781	}
2782
2783	/* Validate whether this HCA support APM */
2784	if (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG)) {
2785		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2786		    "HCA (%llX) - APM NOT SUPPORTED ", c_hp.hp_hca_guid);
2787		retval = IBT_APM_NOT_SUPPORTED;
2788		goto get_alt_path_done;
2789	}
2790
2791	/* Get Companion Port GID of the current Channel's SGID */
2792	if ((new_sgid.gid_guid == 0) || ((new_sgid.gid_guid != 0) &&
2793	    (new_sgid.gid_guid != cur_sgid.gid_guid))) {
2794		IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: SRC: "
2795		    "Get Companion PortGids for - %llX:%llX",
2796		    cur_sgid.gid_prefix, cur_sgid.gid_guid);
2797
2798		retval = ibcm_get_comp_pgids(cur_sgid, new_sgid,
2799		    c_hp.hp_hca_guid, &sgids_p, &snum);
2800		if (retval != IBT_SUCCESS)
2801			goto get_alt_path_done;
2802	}
2803
2804	/* Get Companion Port GID of the current Channel's DGID */
2805	if ((new_dgid.gid_guid == 0) || ((new_dgid.gid_guid != 0) &&
2806	    (new_dgid.gid_guid != cur_dgid.gid_guid))) {
2807
2808		IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: DEST: "
2809		    "Get Companion PortGids for - %llX:%llX",
2810		    cur_dgid.gid_prefix, cur_dgid.gid_guid);
2811
2812		retval = ibcm_get_comp_pgids(cur_dgid, new_dgid, 0, &dgids_p,
2813		    &dnum);
2814		if (retval != IBT_SUCCESS)
2815			goto get_alt_path_done;
2816	}
2817
2818	if ((new_dgid.gid_guid == 0) || (new_sgid.gid_guid == 0)) {
2819		if (new_sgid.gid_guid == 0) {
2820			for (i = 0; i < snum; i++) {
2821				if (new_dgid.gid_guid == 0) {
2822					for (j = 0; j < dnum; j++) {
2823						if (sgids_p[i].gid_prefix ==
2824						    dgids_p[j].gid_prefix) {
2825							new_dgid = dgids_p[j];
2826							new_sgid = sgids_p[i];
2827
2828							goto get_alt_proceed;
2829						}
2830					}
2831					/*  Current DGID */
2832					if (sgids_p[i].gid_prefix ==
2833					    cur_dgid.gid_prefix) {
2834						new_sgid = sgids_p[i];
2835						goto get_alt_proceed;
2836					}
2837				} else {
2838					if (sgids_p[i].gid_prefix ==
2839					    new_dgid.gid_prefix) {
2840						new_sgid = sgids_p[i];
2841						goto get_alt_proceed;
2842					}
2843				}
2844			}
2845			/* Current SGID */
2846			if (new_dgid.gid_guid == 0) {
2847				for (j = 0; j < dnum; j++) {
2848					if (cur_sgid.gid_prefix ==
2849					    dgids_p[j].gid_prefix) {
2850						new_dgid = dgids_p[j];
2851
2852						goto get_alt_proceed;
2853					}
2854				}
2855			}
2856		} else if (new_dgid.gid_guid == 0) {
2857			for (i = 0; i < dnum; i++) {
2858				if (dgids_p[i].gid_prefix ==
2859				    new_sgid.gid_prefix) {
2860					new_dgid = dgids_p[i];
2861					goto get_alt_proceed;
2862				}
2863			}
2864			/* Current DGID */
2865			if (cur_dgid.gid_prefix == new_sgid.gid_prefix) {
2866				goto get_alt_proceed;
2867			}
2868		}
2869		/*
2870		 * hmm... No Companion Ports available.
2871		 * so we will be using current or specified attributes only.
2872		 */
2873	}
2874
2875get_alt_proceed:
2876
2877	if (new_sgid.gid_guid != 0) {
2878		retval = ibtl_cm_get_hca_port(new_sgid, 0, &n_hp);
2879		if (retval != IBT_SUCCESS) {
2880			IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
2881			    "Get HCA Port Failed: %d", retval);
2882			goto get_alt_path_done;
2883		}
2884	}
2885
2886	/* Calculate the size for multi-path records template */
2887	template_len = (2 * sizeof (ib_gid_t)) + sizeof (sa_multipath_record_t);
2888
2889	mpr_req = kmem_zalloc(template_len, KM_SLEEP);
2890
2891	ASSERT(mpr_req != NULL);
2892
2893	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
2894
2895	gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
2896	    sizeof (sa_multipath_record_t));
2897
2898	/* SGID */
2899	if (new_sgid.gid_guid == 0)
2900		*gid_ptr = cur_sgid;
2901	else
2902		*gid_ptr = new_sgid;
2903
2904	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Get Path Between "
2905	    " SGID : %llX:%llX", gid_ptr->gid_prefix, gid_ptr->gid_guid);
2906
2907	gid_ptr++;
2908
2909	/* DGID */
2910	if (new_dgid.gid_guid == 0)
2911		*gid_ptr = cur_dgid;
2912	else
2913		*gid_ptr = new_dgid;
2914
2915	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path:\t\t    DGID : %llX:%llX",
2916	    gid_ptr->gid_prefix, gid_ptr->gid_guid);
2917
2918	mpr_req->SGIDCount = 1;
2919	c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
2920
2921	mpr_req->DGIDCount = 1;
2922	c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
2923
2924	/* Is Flow Label Specified. */
2925	if (attrp) {
2926		if (attrp->apa_flow) {
2927			mpr_req->FlowLabel = attrp->apa_flow;
2928			c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
2929		}
2930
2931		/* Is HopLimit Specified. */
2932		if (flags & IBT_PATH_HOP) {
2933			mpr_req->HopLimit = attrp->apa_hop;
2934			c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
2935		}
2936
2937		/* Is TClass Specified. */
2938		if (attrp->apa_tclass) {
2939			mpr_req->TClass = attrp->apa_tclass;
2940			c_mask |= SA_MPR_COMPMASK_TCLASS;
2941		}
2942
2943		/* Is SL specified. */
2944		if (attrp->apa_sl) {
2945			mpr_req->SL = attrp->apa_sl;
2946			c_mask |= SA_MPR_COMPMASK_SL;
2947		}
2948
2949		if (flags & IBT_PATH_PERF) {
2950			mpr_req->PacketLifeTimeSelector = IBT_BEST;
2951			mpr_req->RateSelector = IBT_BEST;
2952
2953			c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
2954			    SA_MPR_COMPMASK_RATESELECTOR;
2955		} else {
2956			if (attrp->apa_pkt_lt.p_selector == IBT_BEST) {
2957				mpr_req->PacketLifeTimeSelector = IBT_BEST;
2958				c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
2959			}
2960
2961			if (attrp->apa_srate.r_selector == IBT_BEST) {
2962				mpr_req->RateSelector = IBT_BEST;
2963				c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
2964			}
2965		}
2966
2967		/*
2968		 * Honor individual selection of these attributes,
2969		 * even if IBT_PATH_PERF is set.
2970		 */
2971		/* Check out whether Packet Life Time is specified. */
2972		if (attrp->apa_pkt_lt.p_pkt_lt) {
2973			mpr_req->PacketLifeTime =
2974			    ibt_usec2ib(attrp->apa_pkt_lt.p_pkt_lt);
2975			mpr_req->PacketLifeTimeSelector =
2976			    attrp->apa_pkt_lt.p_selector;
2977
2978			c_mask |= SA_MPR_COMPMASK_PKTLT |
2979			    SA_MPR_COMPMASK_PKTLTSELECTOR;
2980		}
2981
2982		/* Is SRATE specified. */
2983		if (attrp->apa_srate.r_srate) {
2984			mpr_req->Rate = attrp->apa_srate.r_srate;
2985			mpr_req->RateSelector = attrp->apa_srate.r_selector;
2986
2987			c_mask |= SA_MPR_COMPMASK_RATE |
2988			    SA_MPR_COMPMASK_RATESELECTOR;
2989		}
2990	}
2991
2992	/* Alt PathMTU can be GT or EQU to current channel's Pri PathMTU */
2993
2994	/* P_Key must be same as that of primary path */
2995	retval = ibt_index2pkey_byguid(c_hp.hp_hca_guid, c_hp.hp_port,
2996	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix,
2997	    &mpr_req->P_Key);
2998	if (retval != IBT_SUCCESS) {
2999		IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: Idx2Pkey Failed: %d",
3000		    retval);
3001		goto get_alt_path_done;
3002	}
3003	c_mask |= SA_MPR_COMPMASK_PKEY;
3004
3005	mpr_req->Reversible = 1;	/* We always get REVERSIBLE paths. */
3006	mpr_req->IndependenceSelector = 1;
3007	c_mask |= SA_MPR_COMPMASK_REVERSIBLE | SA_MPR_COMPMASK_INDEPSEL;
3008
3009	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
3010
3011	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: CMask: 0x%llX", c_mask);
3012
3013	/* NOTE: We will **NOT** specify how many records we want. */
3014
3015	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Primary: MTU %d, PKey[%d]="
3016	    "0x%X\n\tSGID = %llX:%llX, DGID = %llX:%llX", prim_mtu,
3017	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix, mpr_req->P_Key,
3018	    cur_sgid.gid_prefix, cur_sgid.gid_guid, cur_dgid.gid_prefix,
3019	    cur_dgid.gid_guid);
3020
3021	/* Get SA Access Handle. */
3022	if (new_sgid.gid_guid != 0)
3023		saa_handle = ibcm_get_saa_handle(hcap, n_hp.hp_port);
3024	else
3025		saa_handle = ibcm_get_saa_handle(hcap, c_hp.hp_port);
3026	if (saa_handle == NULL) {
3027		retval = IBT_HCA_PORT_NOT_ACTIVE;
3028		goto get_alt_path_done;
3029	}
3030
3031	/* Contact SA Access to retrieve Path Records. */
3032	access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
3033	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
3034	access_args.sq_component_mask = c_mask;
3035	access_args.sq_template = mpr_req;
3036	access_args.sq_template_length = sizeof (sa_multipath_record_t);
3037	access_args.sq_callback = NULL;
3038	access_args.sq_callback_arg = NULL;
3039
3040	retval = ibcm_contact_sa_access(saa_handle, &access_args, &length,
3041	    &results_p);
3042	if (retval != IBT_SUCCESS) {
3043		goto get_alt_path_done;
3044	}
3045
3046	num_rec = length / sizeof (sa_path_record_t);
3047
3048	kmem_free(mpr_req, template_len);
3049
3050	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Found %d Paths", num_rec);
3051
3052	rec_found = 0;
3053	if ((results_p != NULL) && (num_rec > 0)) {
3054		/* Update the PathInfo with the response Path Records */
3055		pr_resp = (sa_path_record_t *)results_p;
3056		for (i = 0; i < num_rec; i++, pr_resp++) {
3057			if (prim_mtu > pr_resp->Mtu) {
3058				IBTF_DPRINTF_L2(cmlog, "ibt_get_alt_path: "
3059				    "Alt PathMTU(%d) must be GT or EQU to Pri "
3060				    "PathMTU(%d). Ignore this rec",
3061				    pr_resp->Mtu, prim_mtu);
3062				continue;
3063			}
3064
3065			if ((new_sgid.gid_guid == 0) &&
3066			    (new_dgid.gid_guid == 0)) {
3067				/* Reject PathRec if it same as Primary Path. */
3068				if (ibcm_compare_paths(pr_resp,
3069				    &qp_attr.qp_info.qp_transport.rc.rc_path,
3070				    &c_hp) == B_TRUE) {
3071					IBTF_DPRINTF_L3(cmlog,
3072					    "ibt_get_alt_path: PathRec obtained"
3073					    " is similar to Prim Path, ignore "
3074					    "this record");
3075					continue;
3076				}
3077			}
3078
3079			if (new_sgid.gid_guid == 0) {
3080				retval = ibcm_update_cep_info(pr_resp, NULL,
3081				    &c_hp, &api_p->ap_alt_cep_path);
3082			} else {
3083				retval = ibcm_update_cep_info(pr_resp, NULL,
3084				    &n_hp, &api_p->ap_alt_cep_path);
3085			}
3086			if (retval != IBT_SUCCESS)
3087				continue;
3088
3089			/* Update some leftovers */
3090			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*api_p))
3091
3092			api_p->ap_alt_pkt_lt = pr_resp->PacketLifeTime;
3093
3094			_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*api_p))
3095
3096			rec_found = 1;
3097			break;
3098		}
3099		kmem_free(results_p, length);
3100	}
3101
3102	if (rec_found == 0) {
3103		IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Alternate Path cannot"
3104		    " be established");
3105		retval = IBT_PATH_RECORDS_NOT_FOUND;
3106	} else
3107		retval = IBT_SUCCESS;
3108
3109get_alt_path_done:
3110	if ((snum) && (sgids_p))
3111		kmem_free(sgids_p, snum * sizeof (ib_gid_t));
3112
3113	if ((dnum) && (dgids_p))
3114		kmem_free(dgids_p, dnum * sizeof (ib_gid_t));
3115
3116	ibcm_dec_hca_acc_cnt(hcap);
3117
3118	IBTF_DPRINTF_L3(cmlog, "ibt_get_alt_path: Done (status %d).", retval);
3119
3120	return (retval);
3121}
3122
3123
3124
3125/*
3126 * IP Path API
3127 */
3128
3129typedef struct ibcm_ip_path_tqargs_s {
3130	ibt_ip_path_attr_t	attr;
3131	ibt_path_info_t		*paths;
3132	ibt_path_ip_src_t	*src_ip_p;
3133	uint8_t			*num_paths_p;
3134	ibt_ip_path_handler_t	func;
3135	void			*arg;
3136	ibt_path_flags_t	flags;
3137	ibt_clnt_hdl_t		ibt_hdl;
3138	kmutex_t		ip_lock;
3139	kcondvar_t		ip_cv;
3140	ibt_status_t		retval;
3141	uint_t			len;
3142} ibcm_ip_path_tqargs_t;
3143
3144typedef struct ibcm_ip_dest_s {
3145	ib_gid_t	d_gid;
3146	uint_t		d_tag;	/* 0 = Unicast, 2 = LoopBack */
3147	ibt_ip_addr_t	d_ip;
3148} ibcm_ip_dest_t;
3149
3150/* Holds destination information needed to fill in ibt_path_info_t. */
3151typedef struct ibcm_ip_dinfo_s {
3152	uint8_t		num_dest;
3153	ibcm_ip_dest_t	dest[1];
3154} ibcm_ip_dinfo_t;
3155
3156_NOTE(SCHEME_PROTECTS_DATA("Temporary path storage", ibcm_ip_dinfo_s))
3157
3158/* Prototype Declarations. */
3159static void ibcm_process_get_ip_paths(void *tq_arg);
3160static ibt_status_t ibcm_get_ip_spr(ibcm_ip_path_tqargs_t *,
3161    ibtl_cm_port_list_t *, ibcm_ip_dinfo_t *, uint8_t *, ibt_path_info_t *);
3162static ibt_status_t ibcm_get_ip_mpr(ibcm_ip_path_tqargs_t *,
3163    ibtl_cm_port_list_t *, ibcm_ip_dinfo_t *dinfo,
3164    uint8_t *, ibt_path_info_t *);
3165static ibt_status_t ibcm_fillin_ip_lbpr(ibtl_cm_port_list_t *, uint8_t index,
3166    ibcm_ip_dinfo_t *, ibt_path_info_t *);
3167
3168/*
3169 * Perform SA Access to retrieve Path Records.
3170 */
3171static ibt_status_t
3172ibcm_saa_ip_pr(ibcm_ip_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
3173    ibcm_ip_dinfo_t *dinfo, uint8_t *max_count)
3174{
3175	uint8_t		num_path = *max_count;
3176	uint8_t		num_path_plus;
3177	uint_t		extra, idx, rec_found = 0;
3178	ibt_status_t	retval = IBT_SUCCESS;
3179	int		dgid_present = 0;
3180	uint8_t		i, j;
3181
3182	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_ip_pr(%p, %p, %p, 0x%X, %d)",
3183	    p_arg, sl, dinfo, p_arg->flags, *max_count);
3184
3185	if ((dinfo->num_dest == 0) || (num_path == 0) || (sl == NULL)) {
3186		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_ip_pr: Invalid Counters");
3187		return (IBT_INVALID_PARAM);
3188	}
3189
3190	/*
3191	 * Of the total needed "X" number of paths to "Y" number of destination
3192	 * we need to get X/Y plus X%Y extra paths to each destination,
3193	 * We do this so that we can choose the required number of path records
3194	 * for the specific destination.
3195	 */
3196	num_path /= dinfo->num_dest;
3197	extra = (*max_count % dinfo->num_dest);
3198
3199	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_ip_pr: numpath %d extra %d dest %d",
3200	    num_path, extra, dinfo->num_dest);
3201
3202	/*
3203	 * Find out whether we need to get PathRecord that qualifies for a
3204	 * LoopBack.
3205	 */
3206	for (idx = 0; idx < dinfo->num_dest; idx++) {
3207		ib_gid_t	dgid = dinfo->dest[idx].d_gid;
3208
3209		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_ip_pr: DGID[%d]: %llX:%llX",
3210		    idx, dgid.gid_prefix, dgid.gid_guid);
3211
3212		/*
3213		 * For loop-back path record, we should NOT contact SA Access.
3214		 * But instead we need to "synthesize" a loop back path record.
3215		 */
3216		for (i = 0; i < sl->p_count; i++) {
3217			if ((sl[i].p_sgid.gid_prefix == dgid.gid_prefix) &&
3218			    (sl[i].p_sgid.gid_guid == dgid.gid_guid)) {
3219
3220				dinfo->dest[idx].d_tag = 2;
3221
3222				/* Yes, it's loop back case. */
3223				retval = ibcm_fillin_ip_lbpr(&sl[i], idx,
3224				    dinfo, &p_arg->paths[rec_found]);
3225				if (retval != IBT_SUCCESS)
3226					break;
3227
3228				/*
3229				 * We update only one record for loop-back case.
3230				 */
3231				rec_found++;
3232				if (rec_found == *max_count)
3233					break;
3234			}
3235		}
3236		if (rec_found == *max_count)
3237			break;
3238	}
3239
3240	for (i = 0; i < dinfo->num_dest; i++)
3241		if (dinfo->dest[i].d_tag == 0)
3242			dgid_present++;
3243
3244	num_path_plus = *max_count - rec_found;
3245
3246	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_ip_pr: Recfound: %d, need to find "
3247	    "%d, GID present %d", rec_found, num_path_plus, dgid_present);
3248
3249	if ((dgid_present != 0) && (num_path_plus > 0)) {
3250		IBTF_DPRINTF_L3(cmlog, "ibcm_saa_ip_pr: MultiSM=%X, #SRC=%d, "
3251		    "Dest=%d", sl->p_multi, sl->p_count, dgid_present);
3252
3253		if ((sl->p_multi != IBTL_CM_SIMPLE_SETUP) ||
3254		    ((dgid_present == 1) && (sl->p_count == 1))) {
3255			/*
3256			 * Use SinglePathRec if we are dealing w/ MultiSM or
3257			 * request is for one SGID to one DGID.
3258			 */
3259			retval = ibcm_get_ip_spr(p_arg, sl, dinfo,
3260			    &num_path_plus, &p_arg->paths[rec_found]);
3261		} else {
3262			/* MultiPathRec will be used for other queries. */
3263			retval = ibcm_get_ip_mpr(p_arg, sl, dinfo,
3264			    &num_path_plus, &p_arg->paths[rec_found]);
3265		}
3266
3267		if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA))
3268			IBTF_DPRINTF_L2(cmlog, "ibcm_saa_ip_pr: "
3269			    "Failed to get PathRec: Status %d", retval);
3270		else
3271			rec_found += num_path_plus;
3272	}
3273
3274	if (rec_found == 0)  {
3275		if (retval == IBT_SUCCESS)
3276			retval = IBT_PATH_RECORDS_NOT_FOUND;
3277	} else if (rec_found != *max_count)
3278		retval = IBT_INSUFF_DATA;
3279	else if (rec_found != 0)
3280		retval = IBT_SUCCESS;
3281
3282	if ((p_arg->src_ip_p != NULL) && (rec_found != 0)) {
3283		for (i = 0; i < rec_found; i++) {
3284			for (j = 0; j < sl->p_count; j++) {
3285				if (sl[j].p_sgid.gid_guid == p_arg->paths[i].
3286				    pi_prim_cep_path.cep_adds_vect.
3287				    av_sgid.gid_guid) {
3288					bcopy(&sl[j].p_src_ip,
3289					    &p_arg->src_ip_p[i].ip_primary,
3290					    sizeof (ibt_ip_addr_t));
3291				}
3292				/* Is Alt Path present */
3293				if (p_arg->paths[i].pi_alt_cep_path.
3294				    cep_hca_port_num) {
3295					if (sl[j].p_sgid.gid_guid ==
3296					    p_arg->paths[i].pi_alt_cep_path.
3297					    cep_adds_vect.av_sgid.gid_guid) {
3298						bcopy(&sl[j].p_src_ip,
3299						    &p_arg->src_ip_p[i].
3300						    ip_alternate,
3301						    sizeof (ibt_ip_addr_t));
3302					}
3303				}
3304			}
3305		}
3306	}
3307	IBTF_DPRINTF_L3(cmlog, "ibcm_saa_ip_pr: done. Status = %d, "
3308	    "Found %d/%d Paths", retval, rec_found, *max_count);
3309
3310	*max_count = rec_found; /* Update the return count. */
3311
3312	return (retval);
3313}
3314
3315static ibt_status_t
3316ibcm_ip_update_pri(sa_path_record_t *pr_resp, ibtl_cm_port_list_t *sl,
3317    ibt_path_info_t *paths)
3318{
3319	ibt_status_t	retval = IBT_SUCCESS;
3320	int		s;
3321
3322	retval = ibcm_update_cep_info(pr_resp, sl, NULL,
3323	    &paths->pi_prim_cep_path);
3324	if (retval != IBT_SUCCESS)
3325		return (retval);
3326
3327	/* Update some leftovers */
3328	paths->pi_prim_pkt_lt = pr_resp->PacketLifeTime;
3329	paths->pi_path_mtu = pr_resp->Mtu;
3330
3331	for (s = 0; s < sl->p_count; s++) {
3332		if (pr_resp->SGID.gid_guid == sl[s].p_sgid.gid_guid)
3333			paths->pi_hca_guid = sl[s].p_hca_guid;
3334	}
3335
3336	/* Set Alternate Path to invalid state. */
3337	paths->pi_alt_cep_path.cep_hca_port_num = 0;
3338	paths->pi_alt_cep_path.cep_adds_vect.av_dlid = 0;
3339
3340	IBTF_DPRINTF_L5(cmlog, "ibcm_ip_update_pri: Path HCA GUID 0x%llX",
3341	    paths->pi_hca_guid);
3342
3343	return (retval);
3344}
3345
3346
3347static ibt_status_t
3348ibcm_get_ip_spr(ibcm_ip_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
3349    ibcm_ip_dinfo_t *dinfo, uint8_t *num_path, ibt_path_info_t *paths)
3350{
3351	sa_path_record_t	pathrec_req;
3352	sa_path_record_t	*pr_resp;
3353	ibmf_saa_access_args_t	access_args;
3354	uint64_t		c_mask = 0;
3355	void			*results_p;
3356	uint8_t			num_rec;
3357	size_t			length;
3358	ibt_status_t		retval;
3359	int			i, j, k;
3360	int			found, p_fnd;
3361	ibt_ip_path_attr_t	*attrp = &p_arg->attr;
3362	ibmf_saa_handle_t	saa_handle;
3363
3364	IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr(%p, %p, %p, %d)",
3365	    p_arg, sl, dinfo, *num_path);
3366
3367	bzero(&pathrec_req, sizeof (sa_path_record_t));
3368
3369	/* Is Flow Label Specified. */
3370	if (attrp->ipa_flow) {
3371		pathrec_req.FlowLabel = attrp->ipa_flow;
3372		c_mask |= SA_PR_COMPMASK_FLOWLABEL;
3373	}
3374
3375	/* Is HopLimit Specified. */
3376	if (p_arg->flags & IBT_PATH_HOP) {
3377		pathrec_req.HopLimit = attrp->ipa_hop;
3378		c_mask |= SA_PR_COMPMASK_HOPLIMIT;
3379	}
3380
3381	/* Is TClass Specified. */
3382	if (attrp->ipa_tclass) {
3383		pathrec_req.TClass = attrp->ipa_tclass;
3384		c_mask |= SA_PR_COMPMASK_TCLASS;
3385	}
3386
3387	/* Is SL specified. */
3388	if (attrp->ipa_sl) {
3389		pathrec_req.SL = attrp->ipa_sl;
3390		c_mask |= SA_PR_COMPMASK_SL;
3391	}
3392
3393	/* If IBT_PATH_PERF is set, then mark all selectors to BEST. */
3394	if (p_arg->flags & IBT_PATH_PERF) {
3395		pathrec_req.PacketLifeTimeSelector = IBT_BEST;
3396		pathrec_req.MtuSelector = IBT_BEST;
3397		pathrec_req.RateSelector = IBT_BEST;
3398
3399		c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR |
3400		    SA_PR_COMPMASK_RATESELECTOR | SA_PR_COMPMASK_MTUSELECTOR;
3401	} else {
3402		if (attrp->ipa_pkt_lt.p_selector == IBT_BEST) {
3403			pathrec_req.PacketLifeTimeSelector = IBT_BEST;
3404			c_mask |= SA_PR_COMPMASK_PKTLTSELECTOR;
3405		}
3406
3407		if (attrp->ipa_srate.r_selector == IBT_BEST) {
3408			pathrec_req.RateSelector = IBT_BEST;
3409			c_mask |= SA_PR_COMPMASK_RATESELECTOR;
3410		}
3411
3412		if (attrp->ipa_mtu.r_selector == IBT_BEST) {
3413			pathrec_req.MtuSelector = IBT_BEST;
3414			c_mask |= SA_PR_COMPMASK_MTUSELECTOR;
3415		}
3416	}
3417
3418	/*
3419	 * Honor individual selection of these attributes,
3420	 * even if IBT_PATH_PERF is set.
3421	 */
3422	/* Check out whether Packet Life Time is specified. */
3423	if (attrp->ipa_pkt_lt.p_pkt_lt) {
3424		pathrec_req.PacketLifeTime =
3425		    ibt_usec2ib(attrp->ipa_pkt_lt.p_pkt_lt);
3426		pathrec_req.PacketLifeTimeSelector =
3427		    attrp->ipa_pkt_lt.p_selector;
3428
3429		c_mask |= SA_PR_COMPMASK_PKTLT | SA_PR_COMPMASK_PKTLTSELECTOR;
3430	}
3431
3432	/* Is SRATE specified. */
3433	if (attrp->ipa_srate.r_srate) {
3434		pathrec_req.Rate = attrp->ipa_srate.r_srate;
3435		pathrec_req.RateSelector = attrp->ipa_srate.r_selector;
3436
3437		c_mask |= SA_PR_COMPMASK_RATE | SA_PR_COMPMASK_RATESELECTOR;
3438	}
3439
3440	/* Is MTU specified. */
3441	if (attrp->ipa_mtu.r_mtu) {
3442		pathrec_req.Mtu = attrp->ipa_mtu.r_mtu;
3443		pathrec_req.MtuSelector = attrp->ipa_mtu.r_selector;
3444
3445		c_mask |= SA_PR_COMPMASK_MTU | SA_PR_COMPMASK_MTUSELECTOR;
3446	}
3447
3448	/* We always get REVERSIBLE paths. */
3449	pathrec_req.Reversible = 1;
3450	c_mask |= SA_PR_COMPMASK_REVERSIBLE;
3451
3452	pathrec_req.NumbPath = *num_path;
3453	c_mask |= SA_PR_COMPMASK_NUMBPATH;
3454
3455	p_fnd = found = 0;
3456
3457	for (i = 0; i < sl->p_count; i++) {
3458		/* SGID */
3459		pathrec_req.SGID = sl[i].p_sgid;
3460		c_mask |= SA_PR_COMPMASK_SGID;
3461		saa_handle = sl[i].p_saa_hdl;
3462
3463		for (k = 0; k < dinfo->num_dest; k++) {
3464			if (dinfo->dest[k].d_tag != 0)
3465				continue;
3466
3467			if (pathrec_req.SGID.gid_prefix !=
3468			    dinfo->dest[k].d_gid.gid_prefix) {
3469				IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: "
3470				    "SGID_pfx=%llX DGID_pfx=%llX doesn't match",
3471				    pathrec_req.SGID.gid_prefix,
3472				    dinfo->dest[k].d_gid.gid_prefix);
3473				continue;
3474			} else if (pathrec_req.SGID.gid_guid ==
3475			    pathrec_req.DGID.gid_guid) {
3476				IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: Why "
3477				    "LoopBack request came here! GID %llX:%llX",
3478				    pathrec_req.SGID.gid_prefix,
3479				    pathrec_req.SGID.gid_guid);
3480				continue;
3481			}
3482
3483			pathrec_req.DGID = dinfo->dest[k].d_gid;
3484			c_mask |= SA_PR_COMPMASK_DGID;
3485
3486			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: "
3487			    "Get %d Path(s) between\n SGID %llX:%llX "
3488			    "DGID %llX:%llX", pathrec_req.NumbPath,
3489			    pathrec_req.SGID.gid_prefix,
3490			    pathrec_req.SGID.gid_guid,
3491			    pathrec_req.DGID.gid_prefix,
3492			    pathrec_req.DGID.gid_guid);
3493
3494			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: CMask=0x%llX, "
3495			    "PKey=0x%X", c_mask, pathrec_req.P_Key);
3496
3497			/* Contact SA Access to retrieve Path Records. */
3498			access_args.sq_attr_id = SA_PATHRECORD_ATTRID;
3499			access_args.sq_template = &pathrec_req;
3500			access_args.sq_access_type = IBMF_SAA_RETRIEVE;
3501			access_args.sq_template_length =
3502			    sizeof (sa_path_record_t);
3503			access_args.sq_component_mask = c_mask;
3504			access_args.sq_callback = NULL;
3505			access_args.sq_callback_arg = NULL;
3506
3507			retval = ibcm_contact_sa_access(saa_handle,
3508			    &access_args, &length, &results_p);
3509			if (retval != IBT_SUCCESS) {
3510				*num_path = 0;
3511				return (retval);
3512			}
3513
3514			num_rec = length / sizeof (sa_path_record_t);
3515
3516			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: "
3517			    "FOUND %d/%d path requested", num_rec, *num_path);
3518
3519			if ((results_p == NULL) || (num_rec == 0))
3520				continue;
3521
3522			/* Update the PathInfo from the response. */
3523			pr_resp = (sa_path_record_t *)results_p;
3524			for (j = 0; j < num_rec; j++, pr_resp++) {
3525				if ((p_fnd != 0) &&
3526				    (p_arg->flags & IBT_PATH_APM)) {
3527					IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr"
3528					    ": Fill Alternate Path");
3529					retval = ibcm_update_cep_info(pr_resp,
3530					    sl, NULL,
3531					    &paths[found - 1].pi_alt_cep_path);
3532					if (retval != IBT_SUCCESS)
3533						continue;
3534
3535					/* Update some leftovers */
3536					paths[found - 1].pi_alt_pkt_lt =
3537					    pr_resp->PacketLifeTime;
3538					p_fnd = 0;
3539				} else {
3540					IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr"
3541					    ": Fill Primary Path");
3542
3543					if (found == *num_path)
3544						break;
3545
3546					retval = ibcm_ip_update_pri(pr_resp, sl,
3547					    &paths[found]);
3548					if (retval != IBT_SUCCESS)
3549						continue;
3550					p_fnd = 1;
3551					found++;
3552				}
3553
3554			}
3555			/* Deallocate the memory for results_p. */
3556			kmem_free(results_p, length);
3557		}
3558	}
3559
3560	if (found == 0)
3561		retval = IBT_PATH_RECORDS_NOT_FOUND;
3562	else if (found != *num_path)
3563		retval = IBT_INSUFF_DATA;
3564	else
3565		retval = IBT_SUCCESS;
3566
3567	IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_spr: done. Status %d, "
3568	    "Found %d/%d Paths", retval, found, *num_path);
3569
3570	*num_path = found;
3571
3572	return (retval);
3573}
3574
3575
3576static ibt_status_t
3577ibcm_get_ip_mpr(ibcm_ip_path_tqargs_t *p_arg, ibtl_cm_port_list_t *sl,
3578    ibcm_ip_dinfo_t *dinfo, uint8_t *num_path, ibt_path_info_t *paths)
3579{
3580	sa_multipath_record_t	*mpr_req;
3581	sa_path_record_t	*pr_resp;
3582	ibmf_saa_access_args_t	access_args;
3583	void			*results_p;
3584	uint64_t		c_mask = 0;
3585	ib_gid_t		*gid_ptr, *gid_s_ptr;
3586	size_t			length;
3587	int			template_len, found, num_rec;
3588	int			i;
3589	ibt_status_t		retval;
3590	uint8_t			sgid_cnt, dgid_cnt;
3591	ibt_ip_path_attr_t	*attrp = &p_arg->attr;
3592
3593	IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr(%p, %p, %p, %d)",
3594	    attrp, sl, dinfo, *num_path);
3595
3596	for (i = 0, dgid_cnt = 0; i < dinfo->num_dest; i++) {
3597		if (dinfo->dest[i].d_tag == 0)
3598			dgid_cnt++;
3599	}
3600
3601	sgid_cnt = sl->p_count;
3602
3603	if ((sgid_cnt == 0) || (dgid_cnt == 0)) {
3604		IBTF_DPRINTF_L2(cmlog, "ibcm_get_ip_mpr: sgid_cnt(%d) or"
3605		    " dgid_cnt(%d) is zero", sgid_cnt, dgid_cnt);
3606		return (IBT_INVALID_PARAM);
3607	}
3608
3609	IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: Get %d records between "
3610	    "%d Src(s) <=> %d Dest(s)", *num_path, sgid_cnt, dgid_cnt);
3611
3612	/*
3613	 * Calculate the size for multi-path records template, which includes
3614	 * constant portion of the multipath record, plus variable size for
3615	 * SGID (sgid_cnt) and DGID (dgid_cnt).
3616	 */
3617	template_len = ((dgid_cnt + sgid_cnt) * sizeof (ib_gid_t)) +
3618	    sizeof (sa_multipath_record_t);
3619
3620	mpr_req = kmem_zalloc(template_len, KM_SLEEP);
3621
3622	ASSERT(mpr_req != NULL);
3623
3624	gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
3625	    sizeof (sa_multipath_record_t));
3626
3627	/* Get the starting pointer where GIDs are stored. */
3628	gid_s_ptr = gid_ptr;
3629
3630	/* SGID */
3631	for (i = 0; i < sl->p_count; i++) {
3632		*gid_ptr = sl[i].p_sgid;
3633
3634		IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: SGID[%d] = %llX:%llX",
3635		    i, gid_ptr->gid_prefix, gid_ptr->gid_guid);
3636
3637		gid_ptr++;
3638	}
3639
3640	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
3641
3642	mpr_req->SGIDCount = sgid_cnt;
3643	c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
3644
3645	/* DGIDs */
3646	for (i = 0; i < dinfo->num_dest; i++) {
3647		if (dinfo->dest[i].d_tag == 0) {
3648			*gid_ptr = dinfo->dest[i].d_gid;
3649
3650			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: DGID[%d] = "
3651			    "%llX:%llX", i, gid_ptr->gid_prefix,
3652			    gid_ptr->gid_guid);
3653			gid_ptr++;
3654		}
3655	}
3656
3657	mpr_req->DGIDCount = dgid_cnt;
3658	c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
3659
3660	/* Is Flow Label Specified. */
3661	if (attrp->ipa_flow) {
3662		mpr_req->FlowLabel = attrp->ipa_flow;
3663		c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
3664	}
3665
3666	/* Is HopLimit Specified. */
3667	if (p_arg->flags & IBT_PATH_HOP) {
3668		mpr_req->HopLimit = attrp->ipa_hop;
3669		c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
3670	}
3671
3672	/* Is TClass Specified. */
3673	if (attrp->ipa_tclass) {
3674		mpr_req->TClass = attrp->ipa_tclass;
3675		c_mask |= SA_MPR_COMPMASK_TCLASS;
3676	}
3677
3678	/* Is SL specified. */
3679	if (attrp->ipa_sl) {
3680		mpr_req->SL = attrp->ipa_sl;
3681		c_mask |= SA_MPR_COMPMASK_SL;
3682	}
3683
3684	if (p_arg->flags & IBT_PATH_PERF) {
3685		mpr_req->PacketLifeTimeSelector = IBT_BEST;
3686		mpr_req->RateSelector = IBT_BEST;
3687		mpr_req->MtuSelector = IBT_BEST;
3688
3689		c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
3690		    SA_MPR_COMPMASK_RATESELECTOR | SA_MPR_COMPMASK_MTUSELECTOR;
3691	} else {
3692		if (attrp->ipa_pkt_lt.p_selector == IBT_BEST) {
3693			mpr_req->PacketLifeTimeSelector = IBT_BEST;
3694			c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
3695		}
3696
3697		if (attrp->ipa_srate.r_selector == IBT_BEST) {
3698			mpr_req->RateSelector = IBT_BEST;
3699			c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
3700		}
3701
3702		if (attrp->ipa_mtu.r_selector == IBT_BEST) {
3703			mpr_req->MtuSelector = IBT_BEST;
3704			c_mask |= SA_MPR_COMPMASK_MTUSELECTOR;
3705		}
3706	}
3707
3708	/*
3709	 * Honor individual selection of these attributes,
3710	 * even if IBT_PATH_PERF is set.
3711	 */
3712	/* Check out whether Packet Life Time is specified. */
3713	if (attrp->ipa_pkt_lt.p_pkt_lt) {
3714		mpr_req->PacketLifeTime =
3715		    ibt_usec2ib(attrp->ipa_pkt_lt.p_pkt_lt);
3716		mpr_req->PacketLifeTimeSelector =
3717		    attrp->ipa_pkt_lt.p_selector;
3718
3719		c_mask |= SA_MPR_COMPMASK_PKTLT |
3720		    SA_MPR_COMPMASK_PKTLTSELECTOR;
3721	}
3722
3723	/* Is SRATE specified. */
3724	if (attrp->ipa_srate.r_srate) {
3725		mpr_req->Rate = attrp->ipa_srate.r_srate;
3726		mpr_req->RateSelector = attrp->ipa_srate.r_selector;
3727
3728		c_mask |= SA_MPR_COMPMASK_RATE |
3729		    SA_MPR_COMPMASK_RATESELECTOR;
3730	}
3731
3732	/* Is MTU specified. */
3733	if (attrp->ipa_mtu.r_mtu) {
3734		mpr_req->Mtu = attrp->ipa_mtu.r_mtu;
3735		mpr_req->MtuSelector = attrp->ipa_mtu.r_selector;
3736
3737		c_mask |= SA_MPR_COMPMASK_MTU |
3738		    SA_MPR_COMPMASK_MTUSELECTOR;
3739	}
3740
3741	/* We always get REVERSIBLE paths. */
3742	mpr_req->Reversible = 1;
3743	c_mask |= SA_MPR_COMPMASK_REVERSIBLE;
3744
3745	if (p_arg->flags & IBT_PATH_AVAIL) {
3746		mpr_req->IndependenceSelector = 1;
3747		c_mask |= SA_MPR_COMPMASK_INDEPSEL;
3748	}
3749
3750	/* we will not specify how many records we want. */
3751
3752	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
3753
3754	IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: CMask: %llX Pkey: %X",
3755	    c_mask, mpr_req->P_Key);
3756
3757	/* Contact SA Access to retrieve Path Records. */
3758	access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
3759	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
3760	access_args.sq_component_mask = c_mask;
3761	access_args.sq_template = mpr_req;
3762	access_args.sq_template_length = sizeof (sa_multipath_record_t);
3763	access_args.sq_callback = NULL;
3764	access_args.sq_callback_arg = NULL;
3765
3766	retval = ibcm_contact_sa_access(sl->p_saa_hdl, &access_args, &length,
3767	    &results_p);
3768	if (retval != IBT_SUCCESS) {
3769		*num_path = 0;  /* Update the return count. */
3770		kmem_free(mpr_req, template_len);
3771		return (retval);
3772	}
3773
3774	num_rec = length / sizeof (sa_path_record_t);
3775
3776	IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: Found %d Paths", num_rec);
3777
3778	found = 0;
3779	if ((results_p != NULL) && (num_rec > 0)) {
3780		/* Update the PathInfo with the response Path Records */
3781		pr_resp = (sa_path_record_t *)results_p;
3782
3783		for (i = 0; i < num_rec; i++) {
3784			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: "
3785			    "P[%d]: SG %llX, DG %llX", i,
3786			    pr_resp[i].SGID.gid_guid, pr_resp[i].DGID.gid_guid);
3787		}
3788
3789		if (p_arg->flags & IBT_PATH_APM) {
3790			sa_path_record_t *p_resp = NULL, *a_resp = NULL;
3791			int		p_found = 0, a_found = 0;
3792			ib_gid_t	p_sg, a_sg, p_dg, a_dg;
3793			int		s_spec;
3794
3795			s_spec =
3796			    p_arg->attr.ipa_src_ip.family != AF_UNSPEC ? 1 : 0;
3797
3798			p_sg = gid_s_ptr[0];
3799			if (sgid_cnt > 1)
3800				a_sg = gid_s_ptr[1];
3801			else
3802				a_sg = p_sg;
3803
3804			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: P_SG: %llX, "
3805			    "A_SG: %llX", p_sg.gid_guid, a_sg.gid_guid);
3806
3807			p_dg = gid_s_ptr[sgid_cnt];
3808			if (dgid_cnt > 1)
3809				a_dg = gid_s_ptr[sgid_cnt + 1];
3810			else
3811				a_dg = p_dg;
3812
3813			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: P_DG: %llX, "
3814			    "A_DG: %llX", p_dg.gid_guid, a_dg.gid_guid);
3815
3816			/*
3817			 * If SGID and/or DGID is specified by user, make sure
3818			 * he gets his primary-path on those node points.
3819			 */
3820			for (i = 0; i < num_rec; i++, pr_resp++) {
3821				IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: "
3822				    "PF %d, AF %d,\n\t\t P[%d] = SG: %llX, "
3823				    "DG: %llX", p_found, a_found, i,
3824				    pr_resp->SGID.gid_guid,
3825				    pr_resp->DGID.gid_guid);
3826
3827				if ((!p_found) &&
3828				    (p_dg.gid_guid == pr_resp->DGID.gid_guid)) {
3829					IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr"
3830					    ": Pri DGID Match.. ");
3831					if ((s_spec == 0) || (p_sg.gid_guid ==
3832					    pr_resp->SGID.gid_guid)) {
3833						p_found = 1;
3834						p_resp = pr_resp;
3835						IBTF_DPRINTF_L3(cmlog,
3836						    "ibcm_get_ip_mpr: "
3837						    "Primary Path Found");
3838
3839						if (a_found)
3840							break;
3841						else
3842							continue;
3843					}
3844					IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr"
3845					    ": Pri SGID Don't Match.. ");
3846				}
3847
3848				if ((!a_found) &&
3849				    (a_dg.gid_guid == pr_resp->DGID.gid_guid)) {
3850					IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr"
3851					    ": Alt DGID Match.. ");
3852					if ((s_spec == 0) || (a_sg.gid_guid ==
3853					    pr_resp->SGID.gid_guid)) {
3854						a_found = 1;
3855						a_resp = pr_resp;
3856
3857						IBTF_DPRINTF_L3(cmlog,
3858						    "ibcm_get_ip_mpr:"
3859						    "Alternate Path Found ");
3860
3861						if (p_found)
3862							break;
3863						else
3864							continue;
3865					}
3866					IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr"
3867					    ": Alt SGID Don't Match.. ");
3868				}
3869			}
3870
3871			if ((p_found == 0) && (a_found == 0)) {
3872				IBTF_DPRINTF_L2(cmlog, "ibcm_get_ip_mpr: Path "
3873				    "to desired node points NOT Available.");
3874				retval = IBT_PATH_RECORDS_NOT_FOUND;
3875				goto get_ip_mpr_end;
3876			}
3877
3878			if ((p_resp == NULL) && (a_resp != NULL)) {
3879				p_resp = a_resp;
3880				a_resp = NULL;
3881			}
3882
3883			/* Fill in Primary Path */
3884			retval = ibcm_ip_update_pri(p_resp, sl, &paths[found]);
3885			if (retval != IBT_SUCCESS)
3886				goto get_ip_mpr_end;
3887
3888			/* Fill in Alternate Path */
3889			if (a_resp != NULL) {
3890				/* a_resp will point to AltPathInfo buffer. */
3891				retval = ibcm_update_cep_info(a_resp, sl,
3892				    NULL, &paths[found].pi_alt_cep_path);
3893				if (retval != IBT_SUCCESS)
3894					goto get_ip_mpr_end;
3895
3896				/* Update some leftovers */
3897				paths[found].pi_alt_pkt_lt =
3898				    a_resp->PacketLifeTime;
3899			} else {
3900				IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: "
3901				    "Alternate Path NOT Available.");
3902				retval = IBT_INSUFF_DATA;
3903			}
3904			found++;
3905		} else {	/* If NOT APM */
3906			for (i = 0; i < num_rec; i++, pr_resp++) {
3907				IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: "
3908				    "DGID(%llX)", pr_resp->DGID.gid_guid);
3909
3910				/* Fill in Primary Path */
3911				retval = ibcm_ip_update_pri(pr_resp, sl,
3912				    &paths[found]);
3913				if (retval != IBT_SUCCESS)
3914					continue;
3915
3916				if (++found == *num_path)
3917					break;
3918			}
3919		}
3920get_ip_mpr_end:
3921		kmem_free(results_p, length);
3922	}
3923	kmem_free(mpr_req, template_len);
3924
3925	if (found == 0)
3926		retval = IBT_PATH_RECORDS_NOT_FOUND;
3927	else if (found != *num_path)
3928		retval = IBT_INSUFF_DATA;
3929	else
3930		retval = IBT_SUCCESS;
3931
3932	IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_mpr: Done (status %d). "
3933	    "Found %d/%d Paths", retval, found, *num_path);
3934
3935	*num_path = found;	/* Update the return count. */
3936
3937	return (retval);
3938}
3939
3940
3941/*
3942 * Here we "synthesize" loop back path record information.
3943 *
3944 * Currently the synthesize values are assumed as follows:
3945 *    SLID, DLID = Base LID from Query HCA Port.
3946 *    FlowLabel, HopLimit, TClass = 0, as GRH is False.
3947 *    RawTraffic = 0.
3948 *    P_Key = first valid one in P_Key table as obtained from Query HCA Port.
3949 *    SL = as from Query HCA Port.
3950 *    MTU = from Query HCA Port.
3951 *    Rate = 2 (arbitrary).
3952 *    PacketLifeTime = 0 (4.096 usec).
3953 */
3954static ibt_status_t
3955ibcm_fillin_ip_lbpr(ibtl_cm_port_list_t *sl, uint8_t idx,
3956    ibcm_ip_dinfo_t *dinfo, ibt_path_info_t *paths)
3957{
3958	IBTF_DPRINTF_L3(cmlog, "ibcm_fillin_ip_lbpr(%p, %p)", sl, dinfo);
3959
3960	/* Synthesize path record with appropriate loop back information. */
3961	paths->pi_prim_cep_path.cep_pkey_ix =
3962	    ibtl_cm_get_1st_full_pkey_ix(sl->p_hca_guid, sl->p_port_num);
3963	paths->pi_hca_guid = sl->p_hca_guid;
3964	paths->pi_prim_cep_path.cep_adds_vect.av_dgid = dinfo->dest[idx].d_gid;
3965	paths->pi_prim_cep_path.cep_adds_vect.av_sgid = sl->p_sgid;
3966	paths->pi_prim_cep_path.cep_adds_vect.av_srate	= IBT_SRATE_1X;
3967	paths->pi_prim_cep_path.cep_adds_vect.av_srvl	= 0; /* SL */
3968
3969	paths->pi_prim_cep_path.cep_adds_vect.av_send_grh = B_FALSE;
3970	paths->pi_prim_cep_path.cep_adds_vect.av_flow	= 0;
3971	paths->pi_prim_cep_path.cep_adds_vect.av_tclass	= 0;
3972	paths->pi_prim_cep_path.cep_adds_vect.av_hop 	= 0;
3973
3974	/* SLID and DLID will be equal to BLID. */
3975	paths->pi_prim_cep_path.cep_adds_vect.av_dlid = sl->p_base_lid;
3976	paths->pi_prim_cep_path.cep_adds_vect.av_src_path = 0;
3977	paths->pi_prim_cep_path.cep_adds_vect.av_sgid_ix = sl->p_sgid_ix;
3978	paths->pi_prim_cep_path.cep_adds_vect.av_port_num = sl->p_port_num;
3979	paths->pi_prim_cep_path.cep_hca_port_num = sl->p_port_num;
3980	paths->pi_prim_cep_path.cep_timeout = 0; /* To be filled in by CM. */
3981	paths->pi_path_mtu = sl->p_mtu;		/* MTU */
3982	paths->pi_prim_pkt_lt = 0;		/* Packet Life Time. */
3983	paths->pi_alt_pkt_lt = 0;		/* Packet Life Time. */
3984
3985	IBTF_DPRINTF_L3(cmlog, "ibcm_fillin_ip_lbpr: HCA %llX:%d \n "
3986	    "SGID %llX:%llX DGID %llX:%llX", paths->pi_hca_guid,
3987	    paths->pi_prim_cep_path.cep_hca_port_num, sl->p_sgid.gid_prefix,
3988	    sl->p_sgid.gid_guid, dinfo->dest[idx].d_gid.gid_prefix,
3989	    dinfo->dest[idx].d_gid.gid_guid);
3990
3991	/* Set Alternate Path to invalid state. */
3992	paths->pi_alt_cep_path.cep_hca_port_num = 0;
3993	paths->pi_alt_cep_path.cep_adds_vect.av_dlid = 0;
3994
3995	return (IBT_SUCCESS);
3996}
3997
3998static void
3999ibcm_process_get_ip_paths(void *tq_arg)
4000{
4001	ibcm_ip_path_tqargs_t	*p_arg = (ibcm_ip_path_tqargs_t *)tq_arg;
4002	ibcm_ip_dinfo_t		*dinfo = NULL;
4003	int			len = 0;
4004	uint8_t			max_paths, num_path;
4005	ib_gid_t		*d_gids_p = NULL;
4006	ib_gid_t		sgid, dgid1, dgid2;
4007	ibt_status_t		retval = IBT_SUCCESS;
4008	ibtl_cm_port_list_t	*sl = NULL;
4009	uint_t			dnum = 0;
4010	uint_t			i;
4011	ibcm_hca_info_t		*hcap;
4012	ibmf_saa_handle_t	saa_handle;
4013
4014	IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_ip_paths(%p, 0x%X) ",
4015	    p_arg, p_arg->flags);
4016
4017	max_paths = num_path = p_arg->attr.ipa_max_paths;
4018
4019	/*
4020	 * Prepare the Source and Destination GID list based on the input
4021	 * attributes.  We contact ARP module to perform IP to MAC
4022	 * i.e. GID conversion.  We use this GID for path look-up.
4023	 *
4024	 * If APM is requested and if multiple Dest IPs are specified, check
4025	 * out whether they are companion to each other.  But, if only one
4026	 * Dest IP is specified, then it is beyond our scope to verify that
4027	 * the companion port GID obtained has IP-Service enabled.
4028	 */
4029	dgid1.gid_prefix = dgid1.gid_guid = 0;
4030	sgid.gid_prefix = sgid.gid_guid = 0;
4031	if ((p_arg->attr.ipa_src_ip.family != AF_UNSPEC) &&
4032	    (!(p_arg->flags & IBT_PATH_APM))) {
4033		ibt_path_attr_t		attr;
4034
4035		retval = ibcm_arp_get_ibaddr(p_arg->attr.ipa_src_ip.un.ip4addr,
4036		    p_arg->attr.ipa_dst_ip[0].un.ip4addr, &sgid, &dgid1);
4037		if (retval) {
4038			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: "
4039			    "ibcm_arp_get_ibaddr() failed: %d", retval);
4040			goto ippath_error;
4041		}
4042
4043		bzero(&attr, sizeof (ibt_path_attr_t));
4044		attr.pa_hca_guid = p_arg->attr.ipa_hca_guid;
4045		attr.pa_hca_port_num = p_arg->attr.ipa_hca_port_num;
4046		attr.pa_sgid = sgid;
4047		bcopy(&p_arg->attr.ipa_mtu, &attr.pa_mtu,
4048		    sizeof (ibt_mtu_req_t));
4049		bcopy(&p_arg->attr.ipa_srate, &attr.pa_srate,
4050		    sizeof (ibt_srate_req_t));
4051		bcopy(&p_arg->attr.ipa_pkt_lt, &attr.pa_pkt_lt,
4052		    sizeof (ibt_pkt_lt_req_t));
4053		retval = ibtl_cm_get_active_plist(&attr, p_arg->flags, &sl);
4054		if (retval == IBT_SUCCESS) {
4055			bcopy(&p_arg->attr.ipa_src_ip, &sl->p_src_ip,
4056			    sizeof (ibt_ip_addr_t));
4057		} else {
4058			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: "
4059			    "ibtl_cm_get_active_plist: Failed %d", retval);
4060			goto ippath_error;
4061		}
4062	} else {
4063		/*
4064		 * Get list of active HCA-Port list, that matches input
4065		 * specified attr.
4066		 */
4067		retval = ibcm_arp_get_srcip_plist(&p_arg->attr, p_arg->flags,
4068		    &sl);
4069		if (retval != IBT_SUCCESS) {
4070			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: "
4071			    "ibcm_arp_get_srcip_plist: Failed %d", retval);
4072			goto ippath_error;
4073		}
4074
4075		sl->p_src_ip.un.ip4addr = htonl(sl->p_src_ip.un.ip4addr);
4076		/*
4077		 * Accumulate all destination information.
4078		 * Get GID info for the specified input ip-addr.
4079		 */
4080		retval = ibcm_arp_get_ibaddr(sl->p_src_ip.un.ip4addr,
4081		    p_arg->attr.ipa_dst_ip[0].un.ip4addr, NULL, &dgid1);
4082		if (retval) {
4083			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: "
4084			    "ibcm_arp_get_ibaddr() failed: %d", retval);
4085			goto ippath_error1;
4086		}
4087	}
4088	IBTF_DPRINTF_L4(cmlog, "ibcm_process_get_ip_paths: SrcIP %lX DstIP %lX",
4089	    sl->p_src_ip.un.ip4addr,
4090	    htonl(p_arg->attr.ipa_dst_ip[0].un.ip4addr));
4091
4092	IBTF_DPRINTF_L4(cmlog, "ibcm_process_get_ip_paths: SGID %llX:%llX, "
4093	    "DGID0: %llX:%llX", sl->p_sgid.gid_prefix, sl->p_sgid.gid_guid,
4094	    dgid1.gid_prefix, dgid1.gid_guid);
4095
4096	len = p_arg->attr.ipa_ndst + 1;
4097	len = (len * sizeof (ibcm_ip_dest_t)) + sizeof (ibcm_ip_dinfo_t);
4098	dinfo = kmem_zalloc(len, KM_SLEEP);
4099
4100	dinfo->dest[0].d_gid = dgid1;
4101	bcopy(&p_arg->attr.ipa_dst_ip[0], &dinfo->dest[0].d_ip,
4102	    sizeof (ibt_ip_addr_t));
4103
4104	i = 1;
4105	if (p_arg->attr.ipa_ndst > 1) {
4106		/* Get DGID for all specified Dest IP Addr */
4107		for (; i < p_arg->attr.ipa_ndst; i++) {
4108			retval = ibcm_arp_get_ibaddr(sl->p_src_ip.un.ip4addr,
4109			    p_arg->attr.ipa_dst_ip[i].un.ip4addr, NULL, &dgid2);
4110			if (retval) {
4111				IBTF_DPRINTF_L2(cmlog,
4112				    "ibcm_process_get_ip_paths: "
4113				    "ibcm_arp_get_ibaddr failed: %d", retval);
4114				goto ippath_error2;
4115			}
4116			dinfo->dest[i].d_gid = dgid2;
4117
4118			IBTF_DPRINTF_L4(cmlog, "ibcm_process_get_ip_paths: "
4119			    "DGID%d: %llX:%llX", i, dgid2.gid_prefix,
4120			    dgid2.gid_guid);
4121			bcopy(&p_arg->attr.ipa_dst_ip[i], &dinfo->dest[i].d_ip,
4122			    sizeof (ibt_ip_addr_t));
4123		}
4124
4125		if (p_arg->flags & IBT_PATH_APM) {
4126			dgid2 = dinfo->dest[1].d_gid;
4127
4128			retval = ibcm_get_comp_pgids(dgid1, dgid2, 0,
4129			    &d_gids_p, &dnum);
4130			if ((retval != IBT_SUCCESS) &&
4131			    (retval != IBT_GIDS_NOT_FOUND)) {
4132				IBTF_DPRINTF_L2(cmlog,
4133				    "ibcm_process_get_ip_paths: "
4134				    "Invalid DGIDs specified w/ APM Flag");
4135				goto ippath_error2;
4136			}
4137			IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_ip_paths: "
4138			    "Found %d Comp DGID", dnum);
4139
4140			if (dnum) {
4141				dinfo->dest[i].d_gid = d_gids_p[0];
4142				dinfo->dest[i].d_ip.family = AF_UNSPEC;
4143				i++;
4144			}
4145		}
4146	}
4147
4148	/* "i" will get us num_dest count. */
4149	dinfo->num_dest = i;
4150
4151	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*p_arg))
4152
4153	/*
4154	 * IBTF allocates memory for path_info & src_ip in case of
4155	 * Async Get IP Paths
4156	 */
4157	if (p_arg->func) {   /* Do these only for Async Get Paths */
4158		p_arg->paths = kmem_zalloc(sizeof (ibt_path_info_t) * max_paths,
4159		    KM_SLEEP);
4160		if (p_arg->src_ip_p == NULL)
4161			p_arg->src_ip_p = kmem_zalloc(
4162			    sizeof (ibt_path_ip_src_t) * max_paths, KM_SLEEP);
4163	}
4164
4165	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*p_arg))
4166
4167	IBTF_DPRINTF_L3(cmlog, "ibcm_process_get_ip_paths: HCA (%llX, %d)",
4168	    sl->p_hca_guid, sl->p_port_num);
4169
4170	hcap = ibcm_find_hca_entry(sl->p_hca_guid);
4171	if (hcap == NULL) {
4172		IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: "
4173		    "NO HCA found");
4174		retval = IBT_HCA_BUSY_DETACHING;
4175		goto ippath_error2;
4176	}
4177
4178	/* Get SA Access Handle. */
4179	for (i = 0; i < sl->p_count; i++) {
4180		if (i == 0) {
4181			/* Validate whether this HCA supports APM */
4182			if ((p_arg->flags & IBT_PATH_APM) &&
4183			    (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG))) {
4184				IBTF_DPRINTF_L2(cmlog,
4185				    "ibcm_process_get_ip_paths: HCA (%llX): "
4186				    "APM NOT SUPPORTED", sl[i].p_hca_guid);
4187				retval = IBT_APM_NOT_SUPPORTED;
4188				goto ippath_error3;
4189			}
4190		}
4191
4192		saa_handle = ibcm_get_saa_handle(hcap, sl[i].p_port_num);
4193		if (saa_handle == NULL) {
4194			IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: "
4195			    "SAA HDL NULL, HCA (%llX:%d) NOT ACTIVE",
4196			    sl[i].p_hca_guid, sl[i].p_port_num);
4197			retval = IBT_HCA_PORT_NOT_ACTIVE;
4198			goto ippath_error3;
4199		}
4200		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sl))
4201		sl[i].p_saa_hdl = saa_handle;
4202		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*sl))
4203	}
4204
4205	/* Get Path Records. */
4206	retval = ibcm_saa_ip_pr(p_arg, sl, dinfo, &num_path);
4207
4208ippath_error3:
4209	ibcm_dec_hca_acc_cnt(hcap);
4210
4211ippath_error2:
4212	if (dinfo && len)
4213		kmem_free(dinfo, len);
4214
4215ippath_error1:
4216	if (sl)
4217		ibtl_cm_free_active_plist(sl);
4218
4219ippath_error:
4220	if ((retval != IBT_SUCCESS) && (retval != IBT_INSUFF_DATA))
4221		num_path = 0;
4222
4223	if (p_arg->num_paths_p != NULL)
4224		*p_arg->num_paths_p = num_path;
4225
4226	if (p_arg->func) {   /* Do these only for Async Get Paths */
4227		ibt_path_info_t *tmp_path_p;
4228
4229		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*p_arg))
4230		p_arg->retval = retval;
4231		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*p_arg))
4232
4233		if (retval == IBT_INSUFF_DATA) {
4234			/*
4235			 * We allocated earlier memory based on "max_paths",
4236			 * but we got lesser path-records, so re-adjust that
4237			 * buffer so that caller can free the correct memory.
4238			 */
4239			tmp_path_p = kmem_alloc(
4240			    sizeof (ibt_path_info_t) * num_path, KM_SLEEP);
4241
4242			bcopy(p_arg->paths, tmp_path_p,
4243			    num_path * sizeof (ibt_path_info_t));
4244
4245			kmem_free(p_arg->paths,
4246			    sizeof (ibt_path_info_t) * max_paths);
4247		} else if (retval != IBT_SUCCESS) {
4248			if (p_arg->paths)
4249				kmem_free(p_arg->paths,
4250				    sizeof (ibt_path_info_t) * max_paths);
4251			if (p_arg->src_ip_p)
4252				kmem_free(p_arg->src_ip_p,
4253				    sizeof (ibt_path_ip_src_t) * max_paths);
4254			tmp_path_p = NULL;
4255		} else {
4256			tmp_path_p = p_arg->paths;
4257		}
4258		(*(p_arg->func))(p_arg->arg, retval, tmp_path_p, num_path,
4259		    p_arg->src_ip_p);
4260
4261		cv_destroy(&p_arg->ip_cv);
4262		mutex_destroy(&p_arg->ip_lock);
4263		len = p_arg->len;
4264		if (p_arg && len)
4265			kmem_free(p_arg, len);
4266	} else {
4267		mutex_enter(&p_arg->ip_lock);
4268		p_arg->retval = retval;
4269		cv_signal(&p_arg->ip_cv);
4270		mutex_exit(&p_arg->ip_lock);
4271	}
4272
4273	IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_ip_paths: done: status %d, "
4274	    "Found %d/%d Path Records", retval, num_path, max_paths);
4275}
4276
4277
4278static ibt_status_t
4279ibcm_val_ipattr(ibt_ip_path_attr_t *attrp, ibt_path_flags_t flags)
4280{
4281	uint_t			i;
4282
4283	if (attrp == NULL) {
4284		IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: IP Path Attr is NULL");
4285		return (IBT_INVALID_PARAM);
4286	}
4287
4288	IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: Inputs are: HCA %llX:%d, "
4289	    "Maxpath= %d, Flags= 0x%X, #Dest %d", attrp->ipa_hca_guid,
4290	    attrp->ipa_hca_port_num, attrp->ipa_max_paths, flags,
4291	    attrp->ipa_ndst);
4292
4293	/*
4294	 * Validate Path Flags.
4295	 * IBT_PATH_AVAIL & IBT_PATH_PERF are mutually exclusive.
4296	 */
4297	if ((flags & IBT_PATH_AVAIL) && (flags & IBT_PATH_PERF)) {
4298		IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: Invalid Flags: 0x%X,"
4299		    "\n\t AVAIL and PERF flags specified together", flags);
4300		return (IBT_INVALID_PARAM);
4301	}
4302
4303	/*
4304	 * Validate number of records requested.
4305	 *
4306	 * Max_paths of "0" is invalid.
4307	 * Max_paths <= IBT_MAX_SPECIAL_PATHS, if AVAIL or PERF is set.
4308	 */
4309	if (attrp->ipa_max_paths == 0) {
4310		IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: Invalid max_paths %d",
4311		    attrp->ipa_max_paths);
4312		return (IBT_INVALID_PARAM);
4313	}
4314
4315	if ((flags & (IBT_PATH_AVAIL | IBT_PATH_PERF)) &&
4316	    (attrp->ipa_max_paths > IBT_MAX_SPECIAL_PATHS)) {
4317		IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: MaxPaths that can be "
4318		    "requested is <%d> \n when IBT_PATH_AVAIL or IBT_PATH_PERF"
4319		    " flag is specified.", IBT_MAX_SPECIAL_PATHS);
4320		return (IBT_INVALID_PARAM);
4321	}
4322
4323	/* Only 2 destinations can be specified w/ APM flag. */
4324	if ((flags & IBT_PATH_APM) && (attrp->ipa_ndst > 2)) {
4325		IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: Max #Dest is 2, with "
4326		    "APM flag");
4327		return (IBT_INVALID_PARAM);
4328	}
4329
4330	/* Validate the destination info */
4331	if ((attrp->ipa_ndst == 0) || (attrp->ipa_ndst == NULL)) {
4332		IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: DstIP Not provided "
4333		    "dst_ip %p, ndst %d", attrp->ipa_dst_ip, attrp->ipa_ndst);
4334		return (IBT_INVALID_PARAM);
4335	}
4336
4337	/* Validate destination IP */
4338	for (i = 0; i < attrp->ipa_ndst; i++) {
4339		ibt_ip_addr_t	dst_ip = attrp->ipa_dst_ip[i];
4340
4341		IBTF_DPRINTF_L3(cmlog, "ibcm_val_ipattr: DstIP[%d]:= family %d "
4342		    "IP %lX", i, dst_ip.family, htonl(dst_ip.un.ip4addr));
4343
4344		if (dst_ip.family == AF_UNSPEC) {
4345			IBTF_DPRINTF_L2(cmlog, "ibcm_val_ipattr: ERROR: "
4346			    "Invalid DstIP specified");
4347			return (IBT_INVALID_PARAM);
4348		}
4349	}
4350
4351	IBTF_DPRINTF_L4(cmlog, "ibcm_val_ipattr: SrcIP: family %d, IP %lX",
4352	    attrp->ipa_src_ip.family, htonl(attrp->ipa_src_ip.un.ip4addr));
4353
4354	return (IBT_SUCCESS);
4355}
4356
4357
4358static ibt_status_t
4359ibcm_get_ip_path(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags,
4360    ibt_ip_path_attr_t *attrp, ibt_path_info_t *paths, uint8_t *num_path_p,
4361    ibt_path_ip_src_t *src_ip_p, ibt_ip_path_handler_t func, void  *arg)
4362{
4363	ibcm_ip_path_tqargs_t	*path_tq;
4364	int		sleep_flag = ((func == NULL) ? KM_SLEEP : KM_NOSLEEP);
4365	uint_t		len, ret;
4366	ibt_status_t	retval;
4367
4368	IBTF_DPRINTF_L4(cmlog, "ibcm_get_ip_path(%p, %X, %p, %p, %p %p %p %p)",
4369	    ibt_hdl, flags, attrp, paths, num_path_p, src_ip_p, func, arg);
4370
4371	retval = ibcm_val_ipattr(attrp, flags);
4372	if (retval != IBT_SUCCESS)
4373		return (retval);
4374
4375	len = (attrp->ipa_ndst * sizeof (ibt_ip_addr_t)) +
4376	    sizeof (ibcm_ip_path_tqargs_t);
4377	path_tq = kmem_zalloc(len, sleep_flag);
4378	if (path_tq == NULL) {
4379		IBTF_DPRINTF_L2(cmlog, "ibcm_get_ip_path: "
4380		    "Unable to allocate memory for local usage.");
4381		return (IBT_INSUFF_KERNEL_RESOURCE);
4382	}
4383
4384	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*path_tq))
4385	mutex_init(&path_tq->ip_lock, NULL, MUTEX_DEFAULT, NULL);
4386	cv_init(&path_tq->ip_cv, NULL, CV_DRIVER, NULL);
4387	bcopy(attrp, &path_tq->attr, sizeof (ibt_ip_path_attr_t));
4388
4389	path_tq->attr.ipa_dst_ip = (ibt_ip_addr_t *)(((uchar_t *)path_tq) +
4390	    sizeof (ibcm_ip_path_tqargs_t));
4391	bcopy(attrp->ipa_dst_ip, path_tq->attr.ipa_dst_ip,
4392	    sizeof (ibt_ip_addr_t) * attrp->ipa_ndst);
4393
4394	/* Ignore IBT_PATH_AVAIL flag, if only one path is requested. */
4395	if ((flags & IBT_PATH_AVAIL) && (attrp->ipa_max_paths == 1)) {
4396		flags &= ~IBT_PATH_AVAIL;
4397
4398		IBTF_DPRINTF_L4(cmlog, "ibcm_get_ip_path: Ignoring "
4399		    "IBT_PATH_AVAIL flag, as only ONE path info is requested.");
4400	}
4401
4402	path_tq->flags = flags;
4403	path_tq->ibt_hdl = ibt_hdl;
4404	path_tq->paths = paths;
4405	path_tq->src_ip_p = src_ip_p;
4406	path_tq->num_paths_p = num_path_p;
4407	path_tq->func = func;
4408	path_tq->arg = arg;
4409	path_tq->len = len;
4410
4411	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*path_tq))
4412
4413	sleep_flag = ((func == NULL) ? TQ_SLEEP : TQ_NOSLEEP);
4414	mutex_enter(&path_tq->ip_lock);
4415	ret = taskq_dispatch(ibcm_taskq, ibcm_process_get_ip_paths, path_tq,
4416	    sleep_flag);
4417	if (ret == 0) {
4418		IBTF_DPRINTF_L2(cmlog, "ibcm_get_ip_path: Failed to dispatch "
4419		    "the TaskQ");
4420		mutex_exit(&path_tq->ip_lock);
4421		cv_destroy(&path_tq->ip_cv);
4422		mutex_destroy(&path_tq->ip_lock);
4423		kmem_free(path_tq, len);
4424		retval = IBT_INSUFF_KERNEL_RESOURCE;
4425	} else {
4426		if (func != NULL) {		/* Non-Blocking */
4427			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_path: NonBlocking");
4428			retval = IBT_SUCCESS;
4429			mutex_exit(&path_tq->ip_lock);
4430		} else {		/* Blocking */
4431			IBTF_DPRINTF_L3(cmlog, "ibcm_get_ip_path: Blocking");
4432			cv_wait(&path_tq->ip_cv, &path_tq->ip_lock);
4433			retval = path_tq->retval;
4434			mutex_exit(&path_tq->ip_lock);
4435			cv_destroy(&path_tq->ip_cv);
4436			mutex_destroy(&path_tq->ip_lock);
4437			kmem_free(path_tq, len);
4438		}
4439	}
4440
4441	return (retval);
4442}
4443
4444
4445ibt_status_t
4446ibt_aget_ip_paths(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags,
4447    ibt_ip_path_attr_t *attrp, ibt_ip_path_handler_t func, void  *arg)
4448{
4449	IBTF_DPRINTF_L3(cmlog, "ibt_aget_ip_paths(%p, 0x%X, %p, %p, %p)",
4450	    ibt_hdl, flags, attrp, func, arg);
4451
4452	if (func == NULL) {
4453		IBTF_DPRINTF_L2(cmlog, "ibt_aget_ip_paths: Function Pointer is "
4454		    "NULL - ERROR ");
4455		return (IBT_INVALID_PARAM);
4456	}
4457
4458	/* path info will be allocated in ibcm_process_get_ip_paths() */
4459	return (ibcm_get_ip_path(ibt_hdl, flags, attrp, NULL, NULL,
4460	    NULL, func, arg));
4461}
4462
4463
4464ibt_status_t
4465ibt_get_ip_paths(ibt_clnt_hdl_t ibt_hdl, ibt_path_flags_t flags,
4466    ibt_ip_path_attr_t *attrp, ibt_path_info_t *paths, uint8_t *num_paths_p,
4467    ibt_path_ip_src_t *src_ip_p)
4468{
4469	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_paths(%p, 0x%X, %p, %p, %p, %p)",
4470	    ibt_hdl, flags, attrp, paths, num_paths_p, src_ip_p);
4471
4472	if (paths == NULL) {
4473		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_paths: Path Info Pointer is "
4474		    "NULL - ERROR ");
4475		return (IBT_INVALID_PARAM);
4476	}
4477
4478	if (num_paths_p != NULL)
4479		*num_paths_p = 0;
4480
4481	return (ibcm_get_ip_path(ibt_hdl, flags, attrp, paths, num_paths_p,
4482	    src_ip_p, NULL, NULL));
4483}
4484
4485
4486ibt_status_t
4487ibt_get_ip_alt_path(ibt_channel_hdl_t rc_chan, ibt_path_flags_t flags,
4488    ibt_alt_ip_path_attr_t *attrp, ibt_alt_path_info_t *api_p)
4489{
4490	sa_multipath_record_t	*mpr_req;
4491	sa_path_record_t	*pr_resp;
4492	ibmf_saa_access_args_t	access_args;
4493	ibt_qp_query_attr_t	qp_attr;
4494	ibtl_cm_hca_port_t	c_hp, n_hp;
4495	ibcm_hca_info_t		*hcap;
4496	void			*results_p;
4497	uint64_t		c_mask = 0;
4498	ib_gid_t		*gid_ptr = NULL;
4499	ib_gid_t		*sgids_p = NULL,  *dgids_p = NULL;
4500	ib_gid_t		cur_dgid, cur_sgid;
4501	ib_gid_t		new_dgid, new_sgid;
4502	ibmf_saa_handle_t	saa_handle;
4503	size_t			length;
4504	int			i, j, template_len, rec_found;
4505	uint_t			snum = 0, dnum = 0, num_rec;
4506	ibt_status_t		retval;
4507	ib_mtu_t		prim_mtu;
4508
4509	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path(%p, %x, %p, %p)",
4510	    rc_chan, flags, attrp, api_p);
4511
4512	/* validate channel */
4513	if (IBCM_INVALID_CHANNEL(rc_chan)) {
4514		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: invalid channel");
4515		return (IBT_CHAN_HDL_INVALID);
4516	}
4517
4518	if (api_p == NULL) {
4519		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: invalid attribute:"
4520		    " AltPathInfo can't be NULL");
4521		return (IBT_INVALID_PARAM);
4522	}
4523
4524	retval = ibt_query_qp(rc_chan, &qp_attr);
4525	if (retval != IBT_SUCCESS) {
4526		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: ibt_query_qp(%p) "
4527		    "failed %d", rc_chan, retval);
4528		return (retval);
4529	}
4530
4531	if (qp_attr.qp_info.qp_trans != IBT_RC_SRV) {
4532		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4533		    "Invalid Channel type: Applicable only to RC Channel");
4534		return (IBT_CHAN_SRV_TYPE_INVALID);
4535	}
4536
4537	cur_dgid =
4538	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dgid;
4539	cur_sgid =
4540	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_sgid;
4541	prim_mtu = qp_attr.qp_info.qp_transport.rc.rc_path_mtu;
4542
4543	/* If optional attributes are specified, validate them. */
4544	if (attrp) {
4545		/* Get SGID and DGID for the specified input ip-addr */
4546		retval = ibcm_arp_get_ibaddr(attrp->apa_src_ip.un.ip4addr,
4547		    attrp->apa_dst_ip.un.ip4addr, &new_sgid, &new_dgid);
4548		if (retval) {
4549			IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4550			    "ibcm_arp_get_ibaddr() failed: %d", retval);
4551			return (retval);
4552		}
4553	} else {
4554		new_dgid.gid_prefix = 0;
4555		new_dgid.gid_guid = 0;
4556		new_sgid.gid_prefix = 0;
4557		new_sgid.gid_guid = 0;
4558	}
4559
4560	if ((new_dgid.gid_prefix != 0) && (new_sgid.gid_prefix != 0) &&
4561	    (new_dgid.gid_prefix != new_sgid.gid_prefix)) {
4562		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: Specified SGID's "
4563		    "SNprefix (%llX) doesn't match with \n specified DGID's "
4564		    "SNprefix: %llX", new_sgid.gid_prefix, new_dgid.gid_prefix);
4565		return (IBT_INVALID_PARAM);
4566	}
4567
4568	/* For the specified SGID, get HCA information. */
4569	retval = ibtl_cm_get_hca_port(cur_sgid, 0, &c_hp);
4570	if (retval != IBT_SUCCESS) {
4571		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4572		    "Get HCA Port Failed: %d", retval);
4573		return (retval);
4574	}
4575
4576	hcap = ibcm_find_hca_entry(c_hp.hp_hca_guid);
4577	if (hcap == NULL) {
4578		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: NO HCA found");
4579		return (IBT_HCA_BUSY_DETACHING);
4580	}
4581
4582	/* Validate whether this HCA support APM */
4583	if (!(hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG)) {
4584		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4585		    "HCA (%llX) - APM NOT SUPPORTED ", c_hp.hp_hca_guid);
4586		retval = IBT_APM_NOT_SUPPORTED;
4587		goto get_ip_alt_path_done;
4588	}
4589
4590	/* Get Companion Port GID of the current Channel's SGID */
4591	if ((new_sgid.gid_guid == 0) || ((new_sgid.gid_guid != 0) &&
4592	    (new_sgid.gid_guid != cur_sgid.gid_guid))) {
4593		IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: SRC: "
4594		    "Get Companion PortGids for - %llX:%llX",
4595		    cur_sgid.gid_prefix, cur_sgid.gid_guid);
4596
4597		retval = ibcm_get_comp_pgids(cur_sgid, new_sgid,
4598		    c_hp.hp_hca_guid, &sgids_p, &snum);
4599		if (retval != IBT_SUCCESS)
4600			goto get_ip_alt_path_done;
4601	}
4602
4603	/* Get Companion Port GID of the current Channel's DGID */
4604	if ((new_dgid.gid_guid == 0) || ((new_dgid.gid_guid != 0) &&
4605	    (new_dgid.gid_guid != cur_dgid.gid_guid))) {
4606
4607		IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: DEST: "
4608		    "Get Companion PortGids for - %llX:%llX",
4609		    cur_dgid.gid_prefix, cur_dgid.gid_guid);
4610
4611		retval = ibcm_get_comp_pgids(cur_dgid, new_dgid, 0, &dgids_p,
4612		    &dnum);
4613		if (retval != IBT_SUCCESS)
4614			goto get_ip_alt_path_done;
4615	}
4616
4617	if ((new_dgid.gid_guid == 0) || (new_sgid.gid_guid == 0)) {
4618		if (new_sgid.gid_guid == 0) {
4619			for (i = 0; i < snum; i++) {
4620				if (new_dgid.gid_guid == 0) {
4621					for (j = 0; j < dnum; j++) {
4622						if (sgids_p[i].gid_prefix ==
4623						    dgids_p[j].gid_prefix) {
4624							new_dgid = dgids_p[j];
4625							new_sgid = sgids_p[i];
4626
4627							goto get_ip_alt_proceed;
4628						}
4629					}
4630					/*  Current DGID */
4631					if (sgids_p[i].gid_prefix ==
4632					    cur_dgid.gid_prefix) {
4633						new_sgid = sgids_p[i];
4634						goto get_ip_alt_proceed;
4635					}
4636				} else {
4637					if (sgids_p[i].gid_prefix ==
4638					    new_dgid.gid_prefix) {
4639						new_sgid = sgids_p[i];
4640						goto get_ip_alt_proceed;
4641					}
4642				}
4643			}
4644			/* Current SGID */
4645			if (new_dgid.gid_guid == 0) {
4646				for (j = 0; j < dnum; j++) {
4647					if (cur_sgid.gid_prefix ==
4648					    dgids_p[j].gid_prefix) {
4649						new_dgid = dgids_p[j];
4650
4651						goto get_ip_alt_proceed;
4652					}
4653				}
4654			}
4655		} else if (new_dgid.gid_guid == 0) {
4656			for (i = 0; i < dnum; i++) {
4657				if (dgids_p[i].gid_prefix ==
4658				    new_sgid.gid_prefix) {
4659					new_dgid = dgids_p[i];
4660					goto get_ip_alt_proceed;
4661				}
4662			}
4663			/* Current DGID */
4664			if (cur_dgid.gid_prefix == new_sgid.gid_prefix) {
4665				goto get_ip_alt_proceed;
4666			}
4667		}
4668		/*
4669		 * hmm... No Companion Ports available.
4670		 * so we will be using current or specified attributes only.
4671		 */
4672	}
4673
4674get_ip_alt_proceed:
4675	if (new_sgid.gid_guid != 0) {
4676		retval = ibtl_cm_get_hca_port(new_sgid, 0, &n_hp);
4677		if (retval != IBT_SUCCESS) {
4678			IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4679			    "Get HCA Port Failed: %d", retval);
4680			goto get_ip_alt_path_done;
4681		}
4682	}
4683
4684	/* Calculate the size for multi-path records template */
4685	template_len = (2 * sizeof (ib_gid_t)) + sizeof (sa_multipath_record_t);
4686
4687	mpr_req = kmem_zalloc(template_len, KM_SLEEP);
4688
4689	ASSERT(mpr_req != NULL);
4690
4691	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpr_req))
4692
4693	gid_ptr = (ib_gid_t *)(((uchar_t *)mpr_req) +
4694	    sizeof (sa_multipath_record_t));
4695
4696	/* SGID */
4697	if (new_sgid.gid_guid == 0)
4698		*gid_ptr = cur_sgid;
4699	else
4700		*gid_ptr = new_sgid;
4701
4702	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: Get Path Between "
4703	    " SGID : %llX:%llX", gid_ptr->gid_prefix, gid_ptr->gid_guid);
4704
4705	gid_ptr++;
4706
4707	/* DGID */
4708	if (new_dgid.gid_guid == 0)
4709		*gid_ptr = cur_dgid;
4710	else
4711		*gid_ptr = new_dgid;
4712
4713	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path:\t\t    DGID : %llX:%llX",
4714	    gid_ptr->gid_prefix, gid_ptr->gid_guid);
4715
4716	mpr_req->SGIDCount = 1;
4717	c_mask = SA_MPR_COMPMASK_SGIDCOUNT;
4718
4719	mpr_req->DGIDCount = 1;
4720	c_mask |= SA_MPR_COMPMASK_DGIDCOUNT;
4721
4722	/* Is Flow Label Specified. */
4723	if (attrp) {
4724		if (attrp->apa_flow) {
4725			mpr_req->FlowLabel = attrp->apa_flow;
4726			c_mask |= SA_MPR_COMPMASK_FLOWLABEL;
4727		}
4728
4729		/* Is HopLimit Specified. */
4730		if (flags & IBT_PATH_HOP) {
4731			mpr_req->HopLimit = attrp->apa_hop;
4732			c_mask |= SA_MPR_COMPMASK_HOPLIMIT;
4733		}
4734
4735		/* Is TClass Specified. */
4736		if (attrp->apa_tclass) {
4737			mpr_req->TClass = attrp->apa_tclass;
4738			c_mask |= SA_MPR_COMPMASK_TCLASS;
4739		}
4740
4741		/* Is SL specified. */
4742		if (attrp->apa_sl) {
4743			mpr_req->SL = attrp->apa_sl;
4744			c_mask |= SA_MPR_COMPMASK_SL;
4745		}
4746
4747		if (flags & IBT_PATH_PERF) {
4748			mpr_req->PacketLifeTimeSelector = IBT_BEST;
4749			mpr_req->RateSelector = IBT_BEST;
4750
4751			c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR |
4752			    SA_MPR_COMPMASK_RATESELECTOR;
4753		} else {
4754			if (attrp->apa_pkt_lt.p_selector == IBT_BEST) {
4755				mpr_req->PacketLifeTimeSelector = IBT_BEST;
4756				c_mask |= SA_MPR_COMPMASK_PKTLTSELECTOR;
4757			}
4758
4759			if (attrp->apa_srate.r_selector == IBT_BEST) {
4760				mpr_req->RateSelector = IBT_BEST;
4761				c_mask |= SA_MPR_COMPMASK_RATESELECTOR;
4762			}
4763		}
4764
4765		/*
4766		 * Honor individual selection of these attributes,
4767		 * even if IBT_PATH_PERF is set.
4768		 */
4769		/* Check out whether Packet Life Time is specified. */
4770		if (attrp->apa_pkt_lt.p_pkt_lt) {
4771			mpr_req->PacketLifeTime =
4772			    ibt_usec2ib(attrp->apa_pkt_lt.p_pkt_lt);
4773			mpr_req->PacketLifeTimeSelector =
4774			    attrp->apa_pkt_lt.p_selector;
4775
4776			c_mask |= SA_MPR_COMPMASK_PKTLT |
4777			    SA_MPR_COMPMASK_PKTLTSELECTOR;
4778		}
4779
4780		/* Is SRATE specified. */
4781		if (attrp->apa_srate.r_srate) {
4782			mpr_req->Rate = attrp->apa_srate.r_srate;
4783			mpr_req->RateSelector = attrp->apa_srate.r_selector;
4784
4785			c_mask |= SA_MPR_COMPMASK_RATE |
4786			    SA_MPR_COMPMASK_RATESELECTOR;
4787		}
4788	}
4789
4790	/* Alt PathMTU can be GT or EQU to current channel's Pri PathMTU */
4791
4792	/* P_Key must be same as that of primary path */
4793	retval = ibt_index2pkey_byguid(c_hp.hp_hca_guid, c_hp.hp_port,
4794	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix,
4795	    &mpr_req->P_Key);
4796	if (retval != IBT_SUCCESS) {
4797		IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: PKeyIdx2Pkey "
4798		    "Failed: %d", retval);
4799		goto get_ip_alt_path_done;
4800	}
4801	c_mask |= SA_MPR_COMPMASK_PKEY;
4802
4803	mpr_req->Reversible = 1;	/* We always get REVERSIBLE paths. */
4804	mpr_req->IndependenceSelector = 1;
4805	c_mask |= SA_MPR_COMPMASK_REVERSIBLE | SA_MPR_COMPMASK_INDEPSEL;
4806
4807	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mpr_req))
4808
4809	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: CMask: 0x%llX", c_mask);
4810
4811	/* NOTE: We will **NOT** specify how many records we want. */
4812
4813	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: Primary: MTU %d, PKey[%d]="
4814	    "0x%X\n\tSGID = %llX:%llX, DGID = %llX:%llX", prim_mtu,
4815	    qp_attr.qp_info.qp_transport.rc.rc_path.cep_pkey_ix, mpr_req->P_Key,
4816	    cur_sgid.gid_prefix, cur_sgid.gid_guid, cur_dgid.gid_prefix,
4817	    cur_dgid.gid_guid);
4818
4819	/* Get SA Access Handle. */
4820	if (new_sgid.gid_guid != 0)
4821		saa_handle = ibcm_get_saa_handle(hcap, n_hp.hp_port);
4822	else
4823		saa_handle = ibcm_get_saa_handle(hcap, c_hp.hp_port);
4824	if (saa_handle == NULL) {
4825		retval = IBT_HCA_PORT_NOT_ACTIVE;
4826		goto get_ip_alt_path_done;
4827	}
4828
4829	/* Contact SA Access to retrieve Path Records. */
4830	access_args.sq_attr_id = SA_MULTIPATHRECORD_ATTRID;
4831	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
4832	access_args.sq_component_mask = c_mask;
4833	access_args.sq_template = mpr_req;
4834	access_args.sq_template_length = sizeof (sa_multipath_record_t);
4835	access_args.sq_callback = NULL;
4836	access_args.sq_callback_arg = NULL;
4837
4838	retval = ibcm_contact_sa_access(saa_handle, &access_args, &length,
4839	    &results_p);
4840	if (retval != IBT_SUCCESS) {
4841		goto get_ip_alt_path_done;
4842	}
4843
4844	num_rec = length / sizeof (sa_path_record_t);
4845
4846	kmem_free(mpr_req, template_len);
4847
4848	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: Found %d Paths", num_rec);
4849
4850	rec_found = 0;
4851	if ((results_p != NULL) && (num_rec > 0)) {
4852		/* Update the PathInfo with the response Path Records */
4853		pr_resp = (sa_path_record_t *)results_p;
4854		for (i = 0; i < num_rec; i++, pr_resp++) {
4855			if (prim_mtu > pr_resp->Mtu) {
4856				IBTF_DPRINTF_L2(cmlog, "ibt_get_ip_alt_path: "
4857				    "Alt PathMTU(%d) must be GT or EQU to Pri "
4858				    "PathMTU(%d). Ignore this rec",
4859				    pr_resp->Mtu, prim_mtu);
4860				continue;
4861			}
4862
4863			if ((new_sgid.gid_guid == 0) &&
4864			    (new_dgid.gid_guid == 0)) {
4865				/* Reject PathRec if it same as Primary Path. */
4866				if (ibcm_compare_paths(pr_resp,
4867				    &qp_attr.qp_info.qp_transport.rc.rc_path,
4868				    &c_hp) == B_TRUE) {
4869					IBTF_DPRINTF_L3(cmlog,
4870					    "ibt_get_ip_alt_path: PathRec "
4871					    "obtained is similar to Prim Path, "
4872					    "ignore this record");
4873					continue;
4874				}
4875			}
4876
4877			if (new_sgid.gid_guid == 0) {
4878				retval = ibcm_update_cep_info(pr_resp, NULL,
4879				    &c_hp, &api_p->ap_alt_cep_path);
4880			} else {
4881				retval = ibcm_update_cep_info(pr_resp, NULL,
4882				    &n_hp, &api_p->ap_alt_cep_path);
4883			}
4884			if (retval != IBT_SUCCESS)
4885				continue;
4886
4887			/* Update some leftovers */
4888			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*api_p))
4889
4890			api_p->ap_alt_pkt_lt = pr_resp->PacketLifeTime;
4891
4892			_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*api_p))
4893
4894			rec_found = 1;
4895			break;
4896		}
4897		kmem_free(results_p, length);
4898	}
4899
4900	if (rec_found == 0) {
4901		IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: AltPath cannot"
4902		    " be established");
4903		retval = IBT_PATH_RECORDS_NOT_FOUND;
4904	} else
4905		retval = IBT_SUCCESS;
4906
4907get_ip_alt_path_done:
4908	if ((snum) && (sgids_p))
4909		kmem_free(sgids_p, snum * sizeof (ib_gid_t));
4910
4911	if ((dnum) && (dgids_p))
4912		kmem_free(dgids_p, dnum * sizeof (ib_gid_t));
4913
4914	ibcm_dec_hca_acc_cnt(hcap);
4915
4916	IBTF_DPRINTF_L3(cmlog, "ibt_get_ip_alt_path: Done (status %d)", retval);
4917
4918	return (retval);
4919}
4920
4921
4922/* Routines for warlock */
4923
4924/* ARGSUSED */
4925static void
4926ibcm_dummy_path_handler(void *arg, ibt_status_t retval, ibt_path_info_t *paths,
4927    uint8_t num_path)
4928{
4929	ibcm_path_tqargs_t	dummy_path;
4930
4931	dummy_path.func = ibcm_dummy_path_handler;
4932
4933	IBTF_DPRINTF_L5(cmlog, "ibcm_dummy_path_handler: "
4934	    "dummy_path.func %p", dummy_path.func);
4935}
4936
4937/* ARGSUSED */
4938static void
4939ibcm_dummy_ip_path_handler(void *arg, ibt_status_t retval,
4940    ibt_path_info_t *paths, uint8_t num_path, ibt_path_ip_src_t *src_ip)
4941{
4942	ibcm_ip_path_tqargs_t	dummy_path;
4943
4944	dummy_path.func = ibcm_dummy_ip_path_handler;
4945
4946	IBTF_DPRINTF_L5(cmlog, "ibcm_dummy_ip_path_handler: "
4947	    "dummy_path.func %p", dummy_path.func);
4948}
4949