xref: /illumos-gate/usr/src/uts/common/io/ib/ibtl/ibtl_cm.c (revision 628e3cbed6489fa1db545d8524a06cd6535af456)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/ib/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  */
37 static char 		ibtf_cm[] = "ibtl_cm";
38 boolean_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  */
53 void
54 ibtl_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  */
79 void *
80 ibtl_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 
95 void
96 ibtl_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 
103 void
104 ibtl_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  */
126 ibt_tran_srv_t
127 ibtl_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  */
143 void
144 ibtl_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  */
177 ibt_status_t
178 ibtl_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 
287 static ibt_status_t
288 ibtl_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 			}
370 got_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 		}
434 search_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 
453 ibt_status_t
454 ibtl_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 
466 get_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 
590 void
591 ibtl_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  */
621 uint16_t
622 ibtl_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 
646 ibt_status_t
647 ibtl_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 
746 int
747 ibtl_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