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