1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <sys/ib/ibtl/impl/ibtl.h>
27#include <sys/ib/ibtl/impl/ibtl_cm.h>
28
29/*
30 * ibtl_cm.c
31 *    These routines tie the Communication Manager into IBTL.
32 */
33
34/*
35 * Globals.
36 */
37static char 		ibtf_cm[] = "ibtl_cm";
38boolean_t		ibtl_fast_gid_cache_valid = B_FALSE;
39
40/*
41 * Function:
42 *	ibtl_cm_set_chan_private
43 * Input:
44 *	chan		Channel Handle.
45 *	cm_private	CM private data.
46 * Output:
47 *	none.
48 * Returns:
49 *	none.
50 * Description:
51 *	A helper function to store CM's Private data in the specified channel.
52 */
53void
54ibtl_cm_set_chan_private(ibt_channel_hdl_t chan, void *cm_private)
55{
56	IBTF_DPRINTF_L3(ibtf_cm, "ibtl_cm_set_chan_private(%p, %p)",
57	    chan, cm_private);
58
59	mutex_enter(&chan->ch_cm_mutex);
60	chan->ch_cm_private = cm_private;
61	if (cm_private == NULL)
62		cv_signal(&chan->ch_cm_cv);
63	mutex_exit(&chan->ch_cm_mutex);
64}
65
66
67/*
68 * Function:
69 *	ibtl_cm_get_chan_private
70 * Input:
71 *	chan		Channel Handle.
72 * Output:
73 *	cm_private_p	The CM private data.
74 * Returns:
75 *	CM private data.
76 * Description:
77 *	A helper function to get CM's Private data for the specified channel.
78 */
79void *
80ibtl_cm_get_chan_private(ibt_channel_hdl_t chan)
81{
82	void *cm_private;
83
84	IBTF_DPRINTF_L3(ibtf_cm, "ibtl_cm_get_chan_private(%p)", chan);
85	mutex_enter(&chan->ch_cm_mutex);
86	cm_private = chan->ch_cm_private;
87#ifndef __lock_lint
88	/* IBCM will call the release function if cm_private is non-NULL */
89	if (cm_private == NULL)
90#endif
91		mutex_exit(&chan->ch_cm_mutex);
92	return (cm_private);
93}
94
95void
96ibtl_cm_release_chan_private(ibt_channel_hdl_t chan)
97{
98#ifndef __lock_lint
99	mutex_exit(&chan->ch_cm_mutex);
100#endif
101}
102
103void
104ibtl_cm_wait_chan_private(ibt_channel_hdl_t chan)
105{
106	mutex_enter(&chan->ch_cm_mutex);
107	if (chan->ch_cm_private != NULL)
108		cv_wait(&chan->ch_cm_cv, &chan->ch_cm_mutex);
109	mutex_exit(&chan->ch_cm_mutex);
110	delay(drv_usectohz(50000));
111}
112
113
114/*
115 * Function:
116 *	ibtl_cm_get_chan_type
117 * Input:
118 *	chan		Channel Handle.
119 * Output:
120 *	none.
121 * Returns:
122 *	Channel transport type.
123 * Description:
124 *	A helper function to get channel transport type.
125 */
126ibt_tran_srv_t
127ibtl_cm_get_chan_type(ibt_channel_hdl_t chan)
128{
129	IBTF_DPRINTF_L3(ibtf_cm, "ibtl_cm_get_chan_type(%p)", chan);
130
131	return (chan->ch_qp.qp_type);
132}
133
134/*
135 * Function:
136 *	ibtl_cm_change_service_cnt
137 * Input:
138 *	ibt_hdl		Client's IBT Handle.
139 *	delta_num_sids	The change in the number of service ids
140 *			(positive for ibt_register_service() and
141 *			negative fo ibt_service_deregister()).
142 */
143void
144ibtl_cm_change_service_cnt(ibt_clnt_hdl_t ibt_hdl, int delta_num_sids)
145{
146	IBTF_DPRINTF_L3(ibtf_cm, "ibtl_cm_change_service_cnt(%p. %d)",
147	    ibt_hdl, delta_num_sids);
148
149	mutex_enter(&ibtl_clnt_list_mutex);
150	if ((delta_num_sids < 0) && (-delta_num_sids > ibt_hdl->clnt_srv_cnt)) {
151		IBTF_DPRINTF_L2(ibtf_cm, "ibtl_cm_change_service_cnt: "
152		    "ERROR: service registration counter underflow\n"
153		    "current count = %d, requested delta = %d",
154		    ibt_hdl->clnt_srv_cnt, delta_num_sids);
155	}
156	ibt_hdl->clnt_srv_cnt += delta_num_sids;
157	mutex_exit(&ibtl_clnt_list_mutex);
158}
159
160
161/*
162 * Function:
163 *	ibtl_cm_get_hca_port
164 * Input:
165 *	gid		Source GID.
166 *	hca_guid	Optional source HCA GUID on which SGID is available.
167 *			Ignored if zero.
168 * Output:
169 *	hca_port	Pointer to ibtl_cm_hca_port_t struct.
170 * Returns:
171 *	IBT_SUCCESS.
172 * Description:
173 *	A helper function to get HCA node GUID, Base LID, SGID Index,
174 *	port number, LMC and MTU for the specified SGID.
175 *	Also filling default SGID, to be used in ibmf_sa_session_open.
176 */
177ibt_status_t
178ibtl_cm_get_hca_port(ib_gid_t gid, ib_guid_t hca_guid,
179    ibtl_cm_hca_port_t *hca_port)
180{
181	ibtl_hca_devinfo_t	*hca_devp;	/* HCA Dev Info */
182	ibt_hca_portinfo_t	*portinfop;
183	uint_t			ports, port;
184	uint_t			i;
185	ib_gid_t		*sgid;
186	static ib_gid_t		fast_gid;	/* fast_gid_cache data */
187	static uint8_t		fast_sgid_ix;
188	static ibt_hca_portinfo_t *fast_portinfop;
189	static ib_guid_t	fast_node_guid;
190	static ib_guid_t	fast_port_guid;
191
192	IBTF_DPRINTF_L3(ibtf_cm, "ibtl_cm_get_hca_port(%llX:%llX, %llX)",
193	    gid.gid_prefix, gid.gid_guid, hca_guid);
194
195	if ((gid.gid_prefix == 0) || (gid.gid_guid == 0)) {
196		IBTF_DPRINTF_L2(ibtf_cm, "ibtl_cm_get_hca_port: "
197		    "NULL SGID specified.");
198		return (IBT_INVALID_PARAM);
199	}
200
201	mutex_enter(&ibtl_clnt_list_mutex);
202
203	if ((ibtl_fast_gid_cache_valid == B_TRUE) &&
204	    (gid.gid_guid == fast_gid.gid_guid) &&
205	    (gid.gid_prefix == fast_gid.gid_prefix)) {
206
207		if ((hca_guid != 0) && (hca_guid != fast_node_guid)) {
208			IBTF_DPRINTF_L3(ibtf_cm, "ibtl_cm_get_hca_port: "
209			    "Mis-match hca_guid v/s sgid combination.");
210			mutex_exit(&ibtl_clnt_list_mutex);
211			return (IBT_INVALID_PARAM);
212		}
213
214		portinfop = fast_portinfop;
215		hca_port->hp_base_lid = portinfop->p_base_lid;
216		hca_port->hp_port = portinfop->p_port_num;
217		hca_port->hp_sgid_ix = fast_sgid_ix;
218		hca_port->hp_lmc = portinfop->p_lmc;
219		hca_port->hp_mtu = portinfop->p_mtu;
220		hca_port->hp_hca_guid = fast_node_guid;
221		hca_port->hp_port_guid = fast_port_guid;
222
223		mutex_exit(&ibtl_clnt_list_mutex);
224
225		return (IBT_SUCCESS);
226	}
227
228	/* If HCA GUID is specified, then lookup in that device only. */
229	if (hca_guid) {
230		hca_devp = ibtl_get_hcadevinfo(hca_guid);
231	} else {
232		hca_devp = ibtl_hca_list;
233	}
234
235	while (hca_devp != NULL) {
236
237		ports = hca_devp->hd_hca_attr->hca_nports;
238		portinfop = hca_devp->hd_portinfop;
239
240		for (port = 0; port < ports; port++, portinfop++) {
241			if (portinfop->p_linkstate != IBT_PORT_ACTIVE)
242				continue;
243			sgid = &portinfop->p_sgid_tbl[0];
244			for (i = 0; i < portinfop->p_sgid_tbl_sz; i++, sgid++) {
245				if ((gid.gid_guid != sgid->gid_guid) ||
246				    (gid.gid_prefix != sgid->gid_prefix))
247					continue;
248
249				/*
250				 * Found the matching GID.
251				 */
252				ibtl_fast_gid_cache_valid = B_TRUE;
253				fast_gid = gid;
254				fast_portinfop = portinfop;
255				fast_node_guid = hca_port->hp_hca_guid =
256				    hca_devp->hd_hca_attr->hca_node_guid;
257				fast_sgid_ix = hca_port->hp_sgid_ix = i;
258				fast_port_guid =
259				    portinfop->p_sgid_tbl[0].gid_guid;
260				hca_port->hp_port_guid = fast_port_guid;
261				hca_port->hp_base_lid = portinfop->p_base_lid;
262				hca_port->hp_port = portinfop->p_port_num;
263				hca_port->hp_lmc = portinfop->p_lmc;
264				hca_port->hp_mtu = portinfop->p_mtu;
265
266				mutex_exit(&ibtl_clnt_list_mutex);
267
268				return (IBT_SUCCESS);
269			}
270		}
271
272		/* Asked to look in the specified HCA device only?. */
273		if (hca_guid)
274			break;
275
276		/* Get next in the list */
277		hca_devp = hca_devp->hd_hca_dev_link;
278	}
279
280	mutex_exit(&ibtl_clnt_list_mutex);
281
282	/* If we are here, then we failed to get a match, so return error. */
283	return (IBT_INVALID_PARAM);
284}
285
286
287static ibt_status_t
288ibtl_cm_get_cnt(ibt_path_attr_t *attr, ibt_path_flags_t flags,
289    ibtl_cm_port_list_t *plistp, uint_t *count)
290{
291	ibtl_hca_devinfo_t	*hdevp;
292	ibt_hca_portinfo_t	*pinfop;
293	ib_guid_t		hca_guid, tmp_hca_guid = 0;
294	ib_gid_t		gid;
295	uint_t			pcount = 0, tmp_pcount = 0;
296	uint_t			cnt = *count;
297	ibt_status_t		retval = IBT_SUCCESS;
298	uint_t			i, j;
299
300	*count = 0;
301
302	/* If HCA GUID is specified, then lookup in that device only. */
303	if (attr->pa_hca_guid) {
304		hdevp = ibtl_get_hcadevinfo(attr->pa_hca_guid);
305	} else {
306		hdevp = ibtl_hca_list;
307	}
308
309	while (hdevp != NULL) {
310		hca_guid = hdevp->hd_hca_attr->hca_node_guid;
311
312		if ((flags & IBT_PATH_APM) &&
313		    (!(hdevp->hd_hca_attr->hca_flags &
314		    IBT_HCA_AUTO_PATH_MIG))) {
315
316			IBTF_DPRINTF_L2(ibtf_cm, "ibtl_cm_get_cnt: "
317			    "HCA (%llX) - APM NOT SUPPORTED ", hca_guid);
318
319			retval = IBT_APM_NOT_SUPPORTED;
320
321			if (attr->pa_hca_guid)
322				break;
323			goto search_next;
324		}
325
326		for (i = 0; i < hdevp->hd_hca_attr->hca_nports; i++) {
327
328			if ((attr->pa_hca_port_num) &&
329			    (attr->pa_hca_port_num != (i + 1))) {
330				IBTF_DPRINTF_L3(ibtf_cm, "ibtl_cm_get_cnt: "
331				    "Asked only on Port# %d, so skip this "
332				    "port(%d)", attr->pa_hca_port_num, (i + 1));
333				continue;
334			}
335			pinfop = hdevp->hd_portinfop + i;
336
337			if (pinfop->p_linkstate != IBT_PORT_ACTIVE) {
338				retval = IBT_HCA_PORT_NOT_ACTIVE;
339				continue;
340			}
341			if (attr->pa_mtu.r_mtu) {
342				if ((attr->pa_mtu.r_selector == IBT_GT) &&
343				    (attr->pa_mtu.r_mtu >= pinfop->p_mtu))
344					continue;
345				else if ((attr->pa_mtu.r_selector == IBT_EQU) &&
346				    (attr->pa_mtu.r_mtu > pinfop->p_mtu))
347					continue;
348			}
349
350			if ((flags & IBT_PATH_APM) && (!attr->pa_hca_guid) &&
351			    attr->pa_sgid.gid_prefix &&
352			    attr->pa_sgid.gid_guid) {
353				for (j = 0; j < pinfop->p_sgid_tbl_sz; j++) {
354					gid = pinfop->p_sgid_tbl[j];
355					if (gid.gid_prefix && gid.gid_guid) {
356						if ((attr->pa_sgid.gid_prefix !=
357						    gid.gid_prefix) ||
358						    (attr->pa_sgid.gid_guid !=
359						    gid.gid_guid)) {
360							continue;
361						} else {
362							attr->pa_hca_guid =
363							    hca_guid;
364							goto got_apm_hca_info;
365						}
366					}
367				}
368				continue;
369			}
370got_apm_hca_info:
371			for (j = 0; j < pinfop->p_sgid_tbl_sz; j++) {
372				gid = pinfop->p_sgid_tbl[j];
373				if (gid.gid_prefix && gid.gid_guid) {
374					if (!(flags & IBT_PATH_APM) &&
375					    attr->pa_sgid.gid_prefix &&
376					    attr->pa_sgid.gid_guid) {
377						if ((attr->pa_sgid.gid_prefix !=
378						    gid.gid_prefix) ||
379						    (attr->pa_sgid.gid_guid !=
380						    gid.gid_guid))
381							continue;
382					}
383					pcount++;
384					if (plistp) {
385						plistp->p_hca_guid = hca_guid;
386						plistp->p_mtu = pinfop->p_mtu;
387						plistp->p_base_lid =
388						    pinfop->p_base_lid;
389						plistp->p_port_num =
390						    pinfop->p_port_num;
391						plistp->p_sgid_ix = j;
392						plistp->p_sgid = gid;
393						plistp->p_count = cnt;
394						if (hdevp->hd_multism)
395							plistp->p_multi |=
396							    IBTL_CM_MULTI_SM;
397
398						IBTF_DPRINTF_L3(ibtf_cm,
399						    "ibtl_cm_get_cnt: HCA"
400						    "(%llX,%d) SGID(%llX:%llX)",
401						    plistp->p_hca_guid,
402						    plistp->p_port_num,
403						    plistp->p_sgid.gid_prefix,
404						    plistp->p_sgid.gid_guid);
405
406						plistp++;
407					}
408				}
409			}
410		}
411		/* Asked to look in the specified HCA device only?. */
412		if (attr->pa_hca_guid)
413			break;
414
415		if (flags & IBT_PATH_APM) {
416			if (pcount == 2) {
417				attr->pa_hca_guid = hca_guid;
418				break;
419			} else if (pcount == 1) {
420				if (hdevp->hd_hca_dev_link) {
421					tmp_hca_guid = hca_guid;
422					tmp_pcount = pcount;
423					pcount = 0;
424				} else if (tmp_hca_guid) {
425					attr->pa_hca_guid = tmp_hca_guid;
426				} else {
427					attr->pa_hca_guid = hca_guid;
428				}
429			} else if ((pcount == 0) && (tmp_hca_guid)) {
430				attr->pa_hca_guid = tmp_hca_guid;
431				pcount = tmp_pcount;
432			}
433		}
434search_next:
435		hdevp = hdevp->hd_hca_dev_link;
436	}
437
438	*count = pcount;
439
440	if (pcount) {
441		retval = IBT_SUCCESS;
442	} else {
443		IBTF_DPRINTF_L2(ibtf_cm, "ibtl_cm_get_cnt: "
444		    "Appropriate Source Points NOT found");
445		if (retval == IBT_SUCCESS)
446			retval = IBT_NO_HCAS_AVAILABLE;
447	}
448
449	return (retval);
450}
451
452
453ibt_status_t
454ibtl_cm_get_active_plist(ibt_path_attr_t *attr, ibt_path_flags_t flags,
455    ibtl_cm_port_list_t **port_list_p)
456{
457	ibtl_cm_port_list_t	*p_listp, tmp;
458	uint_t			i, j;
459	uint_t			count, rcount;
460	boolean_t		multi_hca = B_FALSE;
461	ibt_status_t		retval = IBT_SUCCESS;
462
463	IBTF_DPRINTF_L3(ibtf_cm, "ibtl_cm_get_active_plist(%p, %X)",
464	    attr, flags);
465
466get_plist_start:
467	*port_list_p = NULL;
468
469	/* Get "number of active src points" so that we can allocate memory. */
470	mutex_enter(&ibtl_clnt_list_mutex);
471	retval = ibtl_cm_get_cnt(attr, flags, NULL, &count);
472	mutex_exit(&ibtl_clnt_list_mutex);
473
474	IBTF_DPRINTF_L3(ibtf_cm, "ibtl_cm_get_active_plist: Found %d SrcPoint",
475	    count);
476	if (retval != IBT_SUCCESS)
477		return (retval);
478
479	/* Allocate Memory to hold Src Point information. */
480	p_listp = kmem_zalloc(count * sizeof (ibtl_cm_port_list_t), KM_SLEEP);
481
482	/*
483	 * Verify that the count we got previously is still valid, as we had
484	 * dropped mutex to allocate memory. If not, restart the process.
485	 */
486	mutex_enter(&ibtl_clnt_list_mutex);
487	retval = ibtl_cm_get_cnt(attr, flags, NULL, &rcount);
488	if (retval != IBT_SUCCESS) {
489		mutex_exit(&ibtl_clnt_list_mutex);
490		kmem_free(p_listp, count * sizeof (ibtl_cm_port_list_t));
491		return (retval);
492	} else if (rcount != count) {
493		mutex_exit(&ibtl_clnt_list_mutex);
494		kmem_free(p_listp, count * sizeof (ibtl_cm_port_list_t));
495		goto get_plist_start;
496	}
497
498	*port_list_p = p_listp;
499	/*
500	 * Src count hasn't changed, still holding the lock fill-in the
501	 * required source point information.
502	 */
503	retval = ibtl_cm_get_cnt(attr, flags, p_listp, &rcount);
504	mutex_exit(&ibtl_clnt_list_mutex);
505	if (retval != IBT_SUCCESS) {
506		kmem_free(p_listp, count * sizeof (ibtl_cm_port_list_t));
507		*port_list_p = NULL;
508		return (retval);
509	}
510
511	p_listp = *port_list_p;
512
513	_NOTE(NO_COMPETING_THREADS_NOW)
514
515	for (i = 0; i < count - 1; i++) {
516		for (j = 0; j < count - 1 - i; j++) {
517			if (p_listp[j].p_hca_guid != p_listp[j+1].p_hca_guid) {
518				multi_hca = B_TRUE;
519				break;
520			}
521		}
522		if (multi_hca == B_TRUE)
523			break;
524	}
525
526	if (multi_hca == B_TRUE)
527		for (i = 0; i < count; i++)
528			p_listp[i].p_multi |= IBTL_CM_MULTI_HCA;
529
530	/*
531	 * Sort (bubble sort) the list based on MTU quality (higher on top).
532	 * Sorting is only performed, if IBT_PATH_AVAIL is set.
533	 */
534	if (((attr->pa_mtu.r_selector == IBT_GT) || (flags & IBT_PATH_AVAIL)) &&
535	    (!(flags & IBT_PATH_APM))) {
536		for (i = 0; i < count - 1; i++) {
537			for (j = 0; j < count - 1 - i; j++) {
538				if (p_listp[j].p_mtu < p_listp[j+1].p_mtu) {
539					tmp = p_listp[j];
540					p_listp[j] = p_listp[j+1];
541					p_listp[j+1] = tmp;
542				}
543			}
544		}
545	}
546
547	if ((p_listp->p_multi & IBTL_CM_MULTI_HCA) &&
548	    (flags & IBT_PATH_AVAIL) && (!(flags & IBT_PATH_APM))) {
549		/* Avoid having same HCA next to each other in the list. */
550		for (i = 0; i < count - 1; i++) {
551			for (j = 0; j < (count - 1 - i); j++) {
552				if ((p_listp[j].p_hca_guid ==
553				    p_listp[j+1].p_hca_guid) &&
554				    (j+2 < count)) {
555					tmp = p_listp[j+1];
556					p_listp[j+1] = p_listp[j+2];
557					p_listp[j+2] = tmp;
558				}
559			}
560		}
561	}
562
563	/*
564	 * If SGID is specified, then make sure that SGID info is first
565	 * in the array.
566	 */
567	if (attr->pa_sgid.gid_guid && (p_listp->p_count > 1) &&
568	    (p_listp[0].p_sgid.gid_guid != attr->pa_sgid.gid_guid)) {
569		for (i = 1; i < count; i++) {
570			if (p_listp[i].p_sgid.gid_guid ==
571			    attr->pa_sgid.gid_guid) {
572				tmp = p_listp[i];
573				p_listp[i] = p_listp[0];
574				p_listp[0] = tmp;
575			}
576		}
577	}
578
579#ifndef lint
580	_NOTE(COMPETING_THREADS_NOW)
581#endif
582
583	IBTF_DPRINTF_L3(ibtf_cm, "ibtl_cm_get_active_plist: "
584	    "Returned <%d> entries @0x%p", count, *port_list_p);
585
586	return (retval);
587}
588
589
590void
591ibtl_cm_free_active_plist(ibtl_cm_port_list_t *plist)
592{
593	int count;
594
595	IBTF_DPRINTF_L3(ibtf_cm, "ibtl_cm_free_active_plist(%p)", plist);
596
597	if (plist != NULL) {
598		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*plist))
599		count = plist->p_count;
600		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*plist))
601
602		kmem_free(plist, count * sizeof (ibtl_cm_port_list_t));
603	}
604}
605
606/*
607 * Function:
608 *	ibtl_cm_get_1st_full_pkey_ix
609 * Input:
610 *	hca_guid	HCA GUID.
611 *	port		Port Number.
612 * Output:
613 *	None.
614 * Returns:
615 *	P_Key Index of the first full member available from the P_Key table
616 *	of the specified HCA<->Port.
617 * Description:
618 *	A helper function to get P_Key Index of the first full member P_Key
619 *	available on the specified HCA and Port combination.
620 */
621uint16_t
622ibtl_cm_get_1st_full_pkey_ix(ib_guid_t hca_guid, uint8_t port)
623{
624	ibtl_hca_devinfo_t	*hca_devp;	/* HCA Dev Info */
625	uint16_t		pkey_ix = 0;
626
627	IBTF_DPRINTF_L3(ibtf_cm, "ibtl_cm_get_1st_full_pkey_ix(%llX, %d)",
628	    hca_guid, port);
629
630	mutex_enter(&ibtl_clnt_list_mutex);
631	hca_devp = ibtl_get_hcadevinfo(hca_guid);
632
633	if ((hca_devp != NULL) && (port <= hca_devp->hd_hca_attr->hca_nports) &&
634	    (port != 0)) {
635		pkey_ix = hca_devp->hd_portinfop[port - 1].p_def_pkey_ix;
636	} else {
637		IBTF_DPRINTF_L2(ibtf_cm, "ibtl_cm_get_1st_full_pkey_ix: "
638		    "Invalid HCA (%llX), Port (%d) specified.", hca_guid, port);
639	}
640	mutex_exit(&ibtl_clnt_list_mutex);
641
642	return (pkey_ix);
643}
644
645
646ibt_status_t
647ibtl_cm_get_local_comp_gids(ib_guid_t hca_guid, ib_gid_t gid, ib_gid_t **gids_p,
648    uint_t *num_gids_p)
649{
650	ibtl_hca_devinfo_t	*hdevp;	/* HCA Dev Info */
651	ibt_hca_portinfo_t	*pinfop;
652	ib_gid_t		sgid;
653	ib_gid_t		*gidp = NULL;
654	int			i, j, k;
655	int			count = 0;
656	int			gid_specified;
657
658	IBTF_DPRINTF_L3(ibtf_cm, "ibtl_cm_get_local_comp_gids(%llX, %llX:%llX)",
659	    hca_guid, gid.gid_prefix, gid.gid_guid);
660
661	mutex_enter(&ibtl_clnt_list_mutex);
662	hdevp = ibtl_get_hcadevinfo(hca_guid);
663
664	if (hdevp == NULL) {
665		IBTF_DPRINTF_L3(ibtf_cm, "ibtl_cm_get_local_comp_gids: ",
666		    "NO HCA (%llX) availble", hca_guid);
667		mutex_exit(&ibtl_clnt_list_mutex);
668		return (IBT_NO_HCAS_AVAILABLE);
669	}
670
671	if (gid.gid_prefix && gid.gid_guid)
672		gid_specified = 1;
673	else
674		gid_specified = 0;
675
676	for (i = 0; i < hdevp->hd_hca_attr->hca_nports; i++) {
677		pinfop = hdevp->hd_portinfop + i;
678
679		if (pinfop->p_linkstate != IBT_PORT_ACTIVE)
680			continue;
681
682		for (j = 0; j < pinfop->p_sgid_tbl_sz; j++) {
683			sgid = pinfop->p_sgid_tbl[j];
684			if (sgid.gid_prefix && sgid.gid_guid) {
685				if (gid_specified &&
686				    ((gid.gid_prefix == sgid.gid_prefix) &&
687				    (gid.gid_guid == sgid.gid_guid))) {
688					/*
689					 * Don't return the input specified
690					 * GID
691					 */
692					continue;
693				}
694				count++;
695			}
696		}
697	}
698
699	if (count == 0) {
700		IBTF_DPRINTF_L2(ibtf_cm, "ibtl_cm_get_local_comp_gids: "
701		    "Companion GIDs not available");
702		mutex_exit(&ibtl_clnt_list_mutex);
703		return (IBT_GIDS_NOT_FOUND);
704	}
705
706	gidp = kmem_zalloc(count * sizeof (ib_gid_t), KM_SLEEP);
707	*num_gids_p = count;
708	*gids_p = gidp;
709	k = 0;
710
711	for (i = 0; i < hdevp->hd_hca_attr->hca_nports; i++) {
712		pinfop = hdevp->hd_portinfop + i;
713
714		if (pinfop->p_linkstate != IBT_PORT_ACTIVE)
715			continue;
716
717		for (j = 0; j < pinfop->p_sgid_tbl_sz; j++) {
718			sgid = pinfop->p_sgid_tbl[j];
719			if (sgid.gid_prefix && sgid.gid_guid) {
720				if (gid_specified &&
721				    ((gid.gid_prefix == sgid.gid_prefix) &&
722				    (gid.gid_guid == sgid.gid_guid)))
723					continue;
724
725				gidp[k].gid_prefix = sgid.gid_prefix;
726				gidp[k].gid_guid = sgid.gid_guid;
727
728				IBTF_DPRINTF_L3(ibtf_cm,
729				    "ibtl_cm_get_local_comp_gids: GID[%d]="
730				    "%llX:%llX", k, gidp[k].gid_prefix,
731				    gidp[k].gid_guid);
732				k++;
733				if (k == count)
734					break;
735			}
736		}
737		if (k == count)
738			break;
739	}
740	mutex_exit(&ibtl_clnt_list_mutex);
741
742	return (IBT_SUCCESS);
743}
744
745
746int
747ibtl_cm_is_multi_sm(ib_guid_t hca_guid)
748{
749	ibtl_hca_devinfo_t	*hdevp;	/* HCA Dev Info */
750	uint_t			multi_sm;
751
752	mutex_enter(&ibtl_clnt_list_mutex);
753	hdevp = ibtl_get_hcadevinfo(hca_guid);
754	if (hdevp == NULL) {
755		IBTF_DPRINTF_L2(ibtf_cm, "ibtl_cm_is_multi_sm: NO HCA (%llX) "
756		    "availble", hca_guid);
757		mutex_exit(&ibtl_clnt_list_mutex);
758		return (-1);
759	}
760	multi_sm = hdevp->hd_multism;
761	mutex_exit(&ibtl_clnt_list_mutex);
762
763	IBTF_DPRINTF_L3(ibtf_cm, "ibtl_cm_is_multi_sm(%llX): %d", hca_guid,
764	    multi_sm);
765
766	return (multi_sm);
767}
768
769char *
770ibtl_cm_get_clnt_name(ibt_clnt_hdl_t ibt_hdl)
771{
772	if (ibt_hdl)
773		return (ibt_hdl->clnt_name);
774	else
775		return (NULL);
776}
777