xref: /illumos-gate/usr/src/uts/common/io/ib/ibtl/ibtl_hca.c (revision 43ed929a6988c3778f00123f4a4a8541e515ec16)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * ibtl_hca.c
31  *
32  * This file contains Transport API functions related to
33  * Host Channel Adapter (HCA) Verbs.
34  */
35 
36 #include <sys/ib/ibtl/impl/ibtl.h>
37 
38 static char ibtf_hca[] = "ibtl_hca";
39 
40 /* Prototype declarations. */
41 static ibt_status_t ibtl_query_hca_ports(ibtl_hca_devinfo_t *hca_devp,
42     uint8_t port, ibt_hca_portinfo_t **port_info_p, uint_t *ports_p,
43     uint_t *size_p, int use_cache);
44 
45 /*
46  * Function:
47  *      ibt_open_hca
48  * Input:
49  *      ibt_hdl    - IBT Client Handle
50  *      hca_guid   - HCA's node GUID.
51  * Output:
52  *      hca_hdl_p  - IBT HCA Handle.
53  * Returns:
54  *      IBT_SUCCESS
55  *      IBT_HCA_IN_USE
56  *      IBT_HCA_INVALID
57  * Description:
58  *      Open a HCA. HCA can only be opened/closed once. This routine allocates
59  *      and returns a unique IBT Client HCA handle. Clients passes this
60  *      handle on its subsequent references to this device. Once opened by a
61  *      client, a specific HCA cannot be opened again until after it is closed.
62  *      The IBT_HCA_IN_USE error is returned if client tries to open multiple
63  *      times. In this case, previously allocated IBT HCA handle is returned to
64  *      the client. Opening the HCA prepares the HCA for use by the client.
65  */
66 ibt_status_t
67 ibt_open_hca(ibt_clnt_hdl_t ibt_hdl, ib_guid_t hca_guid,
68     ibt_hca_hdl_t *hca_hdl_p)
69 {
70 	ibtl_hca_t  		*hca_infop;
71 	ibtl_hca_devinfo_t	*hca_devp;		/* HCA Dev Info */
72 
73 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_open_hca(%p, %llX)", ibt_hdl, hca_guid);
74 
75 
76 	/*
77 	 * Get HCA Device Info Structure, referenced by HCA GUID.
78 	 */
79 	mutex_enter(&ibtl_clnt_list_mutex);
80 	hca_devp = ibtl_get_hcadevinfo(hca_guid);
81 	if (hca_devp == NULL) {
82 		/*
83 		 * If we are here, then the requested HCA device is not present.
84 		 * Return the status as Invalid HCA GUID.
85 		 */
86 		mutex_exit(&ibtl_clnt_list_mutex);
87 
88 		IBTF_DPRINTF_L2(ibtf_hca, "ibt_open_hca: "
89 		    "HCA Device Not Found: Invalid HCA GUID");
90 
91 		*hca_hdl_p = NULL;
92 		return (IBT_HCA_INVALID);
93 	}
94 
95 	/*
96 	 * Check whether open is allowed for this dip
97 	 */
98 	if (ibt_hdl->clnt_dip) {
99 		if (ddi_get_parent(ibt_hdl->clnt_dip) == hca_devp->hd_hca_dip) {
100 			if (hca_guid != hca_devp->hd_hca_attr->hca_node_guid) {
101 				mutex_exit(&ibtl_clnt_list_mutex);
102 				return (IBT_FAILURE);
103 			}
104 		}
105 	}
106 
107 	if (hca_devp->hd_state != IBTL_HCA_DEV_ATTACHED) {
108 		/*
109 		 * If we are here, then the requested HCA device has detached,
110 		 * or is in the process of detaching.
111 		 */
112 		mutex_exit(&ibtl_clnt_list_mutex);
113 
114 		IBTF_DPRINTF_L2(ibtf_hca, "ibt_open_hca: "
115 		    "HCA is busy trying to detach");
116 
117 		*hca_hdl_p = NULL;
118 		return (IBT_HCA_BUSY_DETACHING);
119 	}
120 
121 	/*
122 	 * Yes, we found a HCA Device registered with IBTF, which matches with
123 	 * the requested HCA_GUID.
124 	 *
125 	 * Check out whether this client has already opened this HCA device,
126 	 * if yes return the status as IBT_HCA_IN_USE.
127 	 */
128 	hca_infop = hca_devp->hd_clnt_list;
129 
130 	while (hca_infop != NULL) {
131 		if (ibt_hdl == hca_infop->ha_clnt_devp) {
132 			IBTF_DPRINTF_L3(ibtf_hca,
133 			    "ibt_open_hca: Already Open");
134 
135 			if (hca_infop->ha_flags & IBTL_HA_CLOSING) {
136 				mutex_exit(&ibtl_clnt_list_mutex);
137 				*hca_hdl_p = NULL;
138 				return (IBT_HCA_BUSY_CLOSING);
139 			}
140 			mutex_exit(&ibtl_clnt_list_mutex);
141 
142 			/* Already Opened. Return back old HCA Handle. */
143 			*hca_hdl_p = hca_infop;
144 
145 			return (IBT_HCA_IN_USE);
146 		}
147 		hca_infop = hca_infop->ha_clnt_link;
148 	}
149 
150 	/* Create a new HCA Info entity. */
151 	hca_infop = kmem_zalloc(sizeof (ibtl_hca_t), KM_SLEEP);
152 
153 	/* Initialize HCA Mutex. */
154 	mutex_init(&hca_infop->ha_mutex, NULL, MUTEX_DEFAULT, NULL);
155 
156 	/* Update the HCA Info entity */
157 	hca_infop->ha_hca_devp  = hca_devp;	/* HCA Device Info */
158 	hca_infop->ha_clnt_devp = ibt_hdl;	/* Client Info */
159 
160 	/* Update the HCA List, to keep track about the clients using it. */
161 	hca_infop->ha_clnt_link = hca_devp->hd_clnt_list;
162 	hca_devp->hd_clnt_list = hca_infop;
163 
164 
165 	/* Update the client's list to depict that it uses this HCA device. */
166 	hca_infop->ha_hca_link = ibt_hdl->clnt_hca_list;
167 	ibt_hdl->clnt_hca_list = hca_infop;
168 
169 	mutex_exit(&ibtl_clnt_list_mutex);
170 
171 	/*
172 	 * Return back the address of ibtl_hca_t structure as an opaque
173 	 * IBT HCA handle for the clients, to be used in future calls.
174 	 */
175 	*hca_hdl_p = hca_infop;
176 
177 	return (IBT_SUCCESS);
178 }
179 
180 
181 /*
182  * Function:
183  *      ibt_close_hca
184  * Input:
185  *      hca_hdl  - The HCA handle as returned during its open.
186  * Output:
187  *      none
188  * Returns:
189  *      IBT_SUCCESS
190  *      IBT_HCA_HDL_INVALID
191  *      IBT_HCA_RESOURCES_NOT_FREED
192  * Description:
193  *      Close a HCA.
194  */
195 ibt_status_t
196 ibt_close_hca(ibt_hca_hdl_t hca_hdl)
197 {
198 	ibtl_hca_devinfo_t	*hca_devp, *tmp_devp;
199 	ibtl_hca_t		**hcapp;
200 	ibtl_clnt_t		*clntp = hca_hdl->ha_clnt_devp;
201 
202 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_close_hca(%p)", hca_hdl);
203 
204 	/*
205 	 * Verify the Input HCA Handle, if fake return error as
206 	 * invalid HCA Handle.
207 	 */
208 	mutex_enter(&ibtl_clnt_list_mutex);
209 	hca_devp = hca_hdl->ha_hca_devp;
210 	tmp_devp = ibtl_hca_list;
211 
212 	for (; tmp_devp != NULL; tmp_devp = tmp_devp->hd_hca_dev_link)
213 		if (tmp_devp == hca_devp)
214 			break;
215 
216 	if (tmp_devp == NULL) {
217 		mutex_exit(&ibtl_clnt_list_mutex);
218 		IBTF_DPRINTF_L2(ibtf_hca, "ibt_close_hca: "
219 		    "Unable to find this on global HCA list");
220 		return (IBT_HCA_HDL_INVALID);
221 	}
222 
223 	mutex_enter(&hca_hdl->ha_mutex);
224 
225 	/* Make sure resources have been freed. */
226 	if (hca_hdl->ha_qp_cnt | hca_hdl->ha_cq_cnt | hca_hdl->ha_eec_cnt |
227 	    hca_hdl->ha_ah_cnt | hca_hdl->ha_mr_cnt | hca_hdl->ha_mw_cnt |
228 	    hca_hdl->ha_pd_cnt | hca_hdl->ha_fmr_pool_cnt |
229 	    hca_hdl->ha_ma_cnt) {
230 		IBTF_DPRINTF_L2(ibtf_hca, "ibt_close_hca: "
231 		    "some resources have not been freed by '%s': hca_hdl = %p",
232 		    hca_hdl->ha_clnt_devp->clnt_modinfop->mi_clnt_name,
233 		    hca_hdl);
234 		mutex_exit(&hca_hdl->ha_mutex);
235 		mutex_exit(&ibtl_clnt_list_mutex);
236 		return (IBT_HCA_RESOURCES_NOT_FREED);
237 	}
238 	mutex_exit(&hca_hdl->ha_mutex);	/* ok to drop this now */
239 
240 	/* we are now committed to closing the HCA */
241 	hca_hdl->ha_flags |= IBTL_HA_CLOSING;
242 	while (hca_hdl->ha_qpn_cnt > 0)
243 		cv_wait(&ibtl_close_hca_cv, &ibtl_clnt_list_mutex);
244 
245 	/*
246 	 * Remove this HCA Device entry form Client's current list of HCA
247 	 * Device Instances being used by it.
248 	 */
249 	hcapp = &clntp->clnt_hca_list;
250 
251 	for (; *hcapp != NULL; hcapp = &(*hcapp)->ha_hca_link)
252 		if (*hcapp == hca_hdl)
253 			break;
254 
255 	if (*hcapp == NULL) {
256 		IBTF_DPRINTF_L2(ibtf_hca, "ibt_close_hca: "
257 		    "Unable to find this HCA on client list");
258 		mutex_exit(&ibtl_clnt_list_mutex);
259 		return (IBT_HCA_HDL_INVALID);
260 	}
261 
262 	/* hcapp now points to a link that points to us */
263 	*hcapp = hca_hdl->ha_hca_link;		/* remove us */
264 
265 	/*
266 	 * Remove this Client's entry from this HCA Device's Clients list.
267 	 */
268 	hcapp = &hca_devp->hd_clnt_list;
269 
270 	for (; *hcapp != NULL; hcapp = &(*hcapp)->ha_clnt_link)
271 		if (*hcapp == hca_hdl)
272 			break;
273 
274 	if (*hcapp == NULL) {
275 		mutex_exit(&ibtl_clnt_list_mutex);
276 		IBTF_DPRINTF_L2(ibtf_hca, "ibt_close_hca: "
277 		    "Unable to find this HCA on the client's HCA list");
278 		return (IBT_HCA_HDL_INVALID);
279 	}
280 
281 	/* hcapp now points to a link that points to us */
282 	*hcapp = hca_hdl->ha_clnt_link;		/* remove us */
283 	mutex_exit(&ibtl_clnt_list_mutex);
284 
285 	/* Un-Initialize HCA Mutex. */
286 	mutex_destroy(&hca_hdl->ha_mutex);
287 
288 	/* Free memory for this HCA Handle */
289 	ibtl_free_hca_async_check(hca_hdl);
290 
291 	return (IBT_SUCCESS);
292 }
293 
294 void
295 ibtl_close_hca_check(ibt_hca_hdl_t hca_hdl)
296 {
297 	IBTF_DPRINTF_L3(ibtf_hca, "ibtl_close_hca_check(%p)", hca_hdl);
298 
299 	mutex_enter(&ibtl_clnt_list_mutex);
300 	if ((--hca_hdl->ha_qpn_cnt == 0) &&
301 	    (hca_hdl->ha_flags & IBTL_HA_CLOSING)) {
302 		cv_signal(&ibtl_close_hca_cv);
303 	}
304 	mutex_exit(&ibtl_clnt_list_mutex);
305 }
306 
307 /*
308  * Function:
309  *      ibt_get_hca_list
310  * Input:
311  *      hca_list_p -  Address of pointer updated here.
312  * Output:
313  *      hca_list_p -  Points to an array of ib_guid_t's allocated here.
314  * Returns:
315  *      The actual number of valid ib_guid_t's returned.
316  * Description:
317  *	If hca_list_p is not NULL then the memory for the array of GUIDs is
318  *	allocated here and should be freed by the caller using
319  *	ibt_free_hca_list(). If hca_list_p is NULL then no memory is allocated
320  *	by ibt_get_hca_list and only the number of HCAs in a system is returned.
321  */
322 uint_t
323 ibt_get_hca_list(ib_guid_t **hca_list_p)
324 {
325 	uint_t			hca_count = 0;
326 	ibtl_hca_devinfo_t	*hca_devp;
327 	ib_guid_t		*hca_listp;
328 
329 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_get_hca_list(%p)", hca_list_p);
330 
331 	mutex_enter(&ibtl_clnt_list_mutex);
332 
333 	hca_devp = ibtl_hca_list;
334 	while (hca_devp != NULL) {
335 		hca_count++;
336 		hca_devp = hca_devp->hd_hca_dev_link;
337 	}
338 
339 	if (hca_count == 0)
340 		IBTF_DPRINTF_L2(ibtf_hca, "ibt_get_hca_list: "
341 		    "HCA device not found");
342 
343 	if ((hca_count == 0) || (hca_list_p == NULL)) {
344 		mutex_exit(&ibtl_clnt_list_mutex);
345 		return (hca_count);
346 	}
347 
348 	hca_listp = kmem_alloc(hca_count * sizeof (ib_guid_t), KM_SLEEP);
349 	*hca_list_p = hca_listp;
350 
351 	hca_devp = ibtl_hca_list;
352 	while (hca_devp != NULL) {
353 		/* Traverse Global HCA List & retrieve HCA Node GUIDs. */
354 		*hca_listp++ = hca_devp->hd_hca_attr->hca_node_guid;
355 		hca_devp = hca_devp->hd_hca_dev_link;
356 	}
357 	mutex_exit(&ibtl_clnt_list_mutex);
358 
359 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_get_hca_list: "
360 	    "Returned <%d> entries @0x%p", hca_count, *hca_list_p);
361 
362 	return (hca_count);
363 }
364 
365 /*
366  * Function:
367  *      ibt_free_hca_list
368  * Input:
369  *      hca_list  - The address of an ib_guid_t pointer.
370  *      entries   - The number of ib_guid_t entries to be freed.
371  * Output:
372  *      none.
373  * Returns:
374  *      none.
375  * Description:
376  *      The memory allocated in ibt_get_hca_list() is freed in this function.
377  */
378 void
379 ibt_free_hca_list(ib_guid_t *hca_list, uint_t entries)
380 {
381 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_free_hca_list: "
382 	    "Free <%d> entries from 0x%p", entries, hca_list);
383 
384 	if ((hca_list != NULL) && (entries > 0))
385 		kmem_free(hca_list, entries * sizeof (ib_guid_t));
386 }
387 
388 /*
389  * ibtl_portinfo_locked() is called when the portinfo cache is being
390  * updated.  If this port's info update is in progress, we return 0
391  * immediately and have the c
392  * unless it's already in progress (distinguished by return value).
393  * When done updating the portinfo, they call ibtl_portinfo_unlock().
394  */
395 
396 static int
397 ibtl_portinfo_locked(ibtl_hca_devinfo_t *hca_devp, uint8_t port)
398 {
399 	ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex));
400 
401 	for (;;) {
402 		if (hca_devp->hd_portinfo_locked_port == 0) {
403 			hca_devp->hd_portinfo_locked_port = port;
404 			return (1); /* not busy, so OK to initiate update */
405 		} else if (hca_devp->hd_portinfo_locked_port == port) {
406 			IBTF_DPRINTF_L3(ibtf_hca, "ibtl_portinfo_locked: "
407 			    "HCA %p port %d is already locked",
408 			    hca_devp, port);
409 			hca_devp->hd_portinfo_waiters = 1;
410 			cv_wait(&hca_devp->hd_portinfo_cv,
411 			    &ibtl_clnt_list_mutex);
412 			return (0); /* it's now done, so no need to initiate */
413 		} else {
414 			/* need to wait for other port before we try again */
415 			hca_devp->hd_portinfo_waiters = 1;
416 			cv_wait(&hca_devp->hd_portinfo_cv,
417 			    &ibtl_clnt_list_mutex);
418 		}
419 	}
420 }
421 
422 static void
423 ibtl_portinfo_unlock(ibtl_hca_devinfo_t *hca_devp, uint8_t port)
424 {
425 	ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex));
426 	ASSERT(hca_devp->hd_portinfo_locked_port == port);
427 	hca_devp->hd_portinfo_locked_port = 0;
428 	if (hca_devp->hd_portinfo_waiters) {
429 		hca_devp->hd_portinfo_waiters = 0;
430 		cv_broadcast(&hca_devp->hd_portinfo_cv);
431 		IBTF_DPRINTF_L3(ibtf_hca, "ibtl_portinfo_unlock: "
432 		    "waking up waiters for port %d info on HCA %p",
433 		    port, hca_devp);
434 	}
435 }
436 
437 /*
438  * Function:
439  *      ibt_get_port_state
440  * Input:
441  *      hca_devp    - The HCA Dev Info pointer.
442  *	port        - Port number to query.
443  * Output:
444  *      sgid_p	    - Returned sgid[0], NULL implies no return value.
445  *      base_lid_p  - Returned base_lid, NULL implies no return value.
446  * Returns:
447  *      IBT_SUCCESS
448  *	IBT_HCA_PORT_INVALID
449  * Description:
450  *      Returns HCA port attributes for one of the HCA ports.
451  */
452 static ibt_status_t
453 ibtl_get_port_state(ibtl_hca_devinfo_t *hca_devp, uint8_t port,
454     ib_gid_t *sgid_p, ib_lid_t *base_lid_p)
455 {
456 	ibt_hca_portinfo_t *portinfop;
457 
458 	ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex));
459 
460 	if ((port < 1) || (port > hca_devp->hd_hca_attr->hca_nports)) {
461 		IBTF_DPRINTF_L2(ibtf_hca, "ibtl_get_port_state: "
462 		    "invalid port %d, nports = %d", port,
463 		    hca_devp->hd_hca_attr->hca_nports);
464 		return (IBT_HCA_PORT_INVALID);
465 	}
466 	portinfop = hca_devp->hd_portinfop + port - 1;
467 
468 	if (sgid_p)
469 		*sgid_p = portinfop->p_sgid_tbl[0];
470 	if (base_lid_p)
471 		*base_lid_p = portinfop->p_base_lid;
472 	if (portinfop->p_linkstate != IBT_PORT_ACTIVE) {
473 		IBTF_DPRINTF_L2(ibtf_hca, "ibtl_get_port_state: "
474 		    "port %d, port_state %d, base_lid %d",
475 		    port, portinfop->p_linkstate, portinfop->p_base_lid);
476 		return (IBT_HCA_PORT_NOT_ACTIVE);
477 	}
478 	IBTF_DPRINTF_L3(ibtf_hca, "ibtl_get_port_state: "
479 	    "port %d, port_state %d, base_lid %d",
480 	    port, portinfop->p_linkstate, portinfop->p_base_lid);
481 	return (IBT_SUCCESS);
482 }
483 
484 /*
485  * Function:
486  *      ibt_get_port_state
487  * Input:
488  *      hca_hdl	    - The HCA handle.
489  *	port        - Port number to query.
490  * Output:
491  *      sgid_p	    - Returned sgid[0], NULL implies no return value.
492  *      base_lid_p  - Returned base_lid, NULL implies no return value.
493  * Returns:
494  *      IBT_SUCCESS
495  *	IBT_HCA_PORT_INVALID
496  * Description:
497  *      Returns HCA port attributes for one of the HCA ports.
498  */
499 ibt_status_t
500 ibt_get_port_state(ibt_hca_hdl_t hca_hdl, uint8_t port,
501     ib_gid_t *sgid_p, ib_lid_t *base_lid_p)
502 {
503 	ibt_status_t		retval;
504 
505 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_get_port_state(%p, %d, %p, %p)",
506 	    hca_hdl, port, sgid_p, base_lid_p);
507 	mutex_enter(&ibtl_clnt_list_mutex);
508 	retval = ibtl_get_port_state(hca_hdl->ha_hca_devp, port, sgid_p,
509 	    base_lid_p);
510 	mutex_exit(&ibtl_clnt_list_mutex);
511 	return (retval);
512 }
513 
514 
515 /*
516  * Function:
517  *      ibt_get_port_state_byguid
518  * Input:
519  *      hca_guid    - The HCA node GUID.
520  *	port        - Port number to query.
521  * Output:
522  *      sgid_p	    - Returned sgid[0], NULL implies no return value.
523  *      base_lid_p  - Returned base_lid, NULL implies no return value.
524  * Returns:
525  *      IBT_SUCCESS
526  *	IBT_HCA_PORT_INVALID
527  *      IBT_HCA_INVALID
528  * Description:
529  *      Returns HCA port attributes for one of the HCA ports.
530  */
531 ibt_status_t
532 ibt_get_port_state_byguid(ib_guid_t hca_guid, uint8_t port,
533     ib_gid_t *sgid_p, ib_lid_t *base_lid_p)
534 {
535 	ibtl_hca_devinfo_t	*hca_devp;		/* HCA Dev Info */
536 	ibt_status_t		retval;
537 
538 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_get_port_state_byguid(%llx, %d, %p, "
539 	    "%p)", (longlong_t)hca_guid, port, sgid_p, base_lid_p);
540 	mutex_enter(&ibtl_clnt_list_mutex);
541 	hca_devp = ibtl_get_hcadevinfo(hca_guid);
542 	if (hca_devp == NULL)
543 		retval = IBT_HCA_INVALID;
544 	else
545 		retval = ibtl_get_port_state(hca_devp, port, sgid_p,
546 		    base_lid_p);
547 	mutex_exit(&ibtl_clnt_list_mutex);
548 	return (retval);
549 }
550 
551 
552 /*
553  * Function:
554  *      ibt_query_hca_byguid
555  * Input:
556  *      hca_guid  - The HCA node GUID.
557  * Output:
558  *      hca_attrs - A pointer to a ibt_hca_attr_t allocated by the caller,
559  *                  into which the HCA Attributes are copied.
560  * Returns:
561  *      IBT_SUCCESS
562  *      IBT_INVALID_PARAM
563  *      IBT_HCA_INVALID
564  * Description:
565  *      Returns the static attributes of the specified HCA.
566  */
567 ibt_status_t
568 ibt_query_hca_byguid(ib_guid_t hca_guid, ibt_hca_attr_t *hca_attrs)
569 {
570 	ibtl_hca_devinfo_t	*hca_devp;	/* HCA Dev Info. */
571 
572 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_query_hca_byguid(%llX)", hca_guid);
573 
574 	mutex_enter(&ibtl_clnt_list_mutex);
575 	/* Get HCA Dev Info Structure, referenced by HCA GUID. */
576 	hca_devp = ibtl_get_hcadevinfo(hca_guid);
577 	if (hca_devp == NULL) {
578 		/*
579 		 * If we are here, then the requested HCA device is not present.
580 		 */
581 		mutex_exit(&ibtl_clnt_list_mutex);
582 		IBTF_DPRINTF_L2(ibtf_hca, "ibt_query_hca_byguid: "
583 		    "Device Not Found");
584 		return (IBT_HCA_INVALID);
585 	}
586 
587 	/* Return back the static HCA attributes */
588 	bcopy(hca_devp->hd_hca_attr, hca_attrs, sizeof (ibt_hca_attr_t));
589 
590 	mutex_exit(&ibtl_clnt_list_mutex);
591 
592 	return (IBT_SUCCESS);
593 }
594 
595 
596 /*
597  * Function:
598  *      ibt_query_hca
599  * Input:
600  *      hca_hdl   - The HCA handle.
601  * Output:
602  *      hca_attrs - A pointer to a ibt_hca_attr_t allocated by the caller,
603  *                  into which the HCA Attributes are copied.
604  * Returns:
605  *      IBT_SUCCESS
606  *
607  * Description:
608  *      Returns the static attributes of the specified HCA.
609  */
610 ibt_status_t
611 ibt_query_hca(ibt_hca_hdl_t hca_hdl, ibt_hca_attr_t *hca_attrs)
612 {
613 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_query_hca(%p)", hca_hdl);
614 
615 	/* Return back the static HCA attributes */
616 	bcopy(hca_hdl->ha_hca_devp->hd_hca_attr, hca_attrs,
617 	    sizeof (ibt_hca_attr_t));
618 
619 	return (IBT_SUCCESS);
620 }
621 
622 #define	ROUNDUP(x, y)	((((x)+((y)-1))/(y))*(y))
623 
624 /*
625  * Function:
626  *      ibt_query_hca_ports
627  * Input:
628  *      hca_hdl	    - The HCA handle.
629  *	port        - Port number.  If "0", then query ALL Ports.
630  * Output:
631  *      port_info_p - The address of a pointer to a ibt_hca_portinfo_t struct.
632  *      ports_p     - The number of hca ports on the specified HCA.
633  *      size_p      - Size of the memory allocated by IBTL to get portinfo,
634  *                   to be freed by calling ibt_free_portinfo().
635  * Returns:
636  *      IBT_SUCCESS
637  *      IBT_HCA_HDL_INVALID
638  *      IBT_HCA_INVALID
639  * Description:
640  *      Returns HCA port attributes for either "one", or "all" of the HCA ports.
641  */
642 ibt_status_t
643 ibt_query_hca_ports(ibt_hca_hdl_t hca_hdl, uint8_t port,
644     ibt_hca_portinfo_t **port_info_p, uint_t *ports_p, uint_t *size_p)
645 {
646 	ibt_status_t	retval;
647 
648 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_query_hca_ports(%p, %d)",
649 	    hca_hdl, port);
650 
651 	mutex_enter(&ibtl_clnt_list_mutex);
652 
653 	retval = ibtl_query_hca_ports(hca_hdl->ha_hca_devp, port, port_info_p,
654 	    ports_p, size_p, 0);
655 
656 	mutex_exit(&ibtl_clnt_list_mutex);
657 
658 	return (retval);
659 }
660 
661 /*
662  * Function:
663  *      ibt_query_hca_ports_byguid
664  * Input:
665  *      hca_guid    - The HCA node GUID.
666  *	port        - Port number.  If "0", then query ALL Ports.
667  * Output:
668  *      port_info_p - The address of a pointer to a ibt_hca_portinfo_t struct.
669  *      ports_p     - The number of hca ports on the specified HCA.
670  *      size_p      - Size of the memory allocated by IBTL to get portinfo,
671  *                   to be freed by calling ibt_free_portinfo().
672  * Returns:
673  *      IBT_SUCCESS
674  *      IBT_HCA_HDL_INVALID
675  *      IBT_HCA_INVALID
676  * Description:
677  *      Returns HCA port attributes for either "one", or "all" of the HCA ports.
678  */
679 ibt_status_t
680 ibt_query_hca_ports_byguid(ib_guid_t hca_guid, uint8_t port,
681     ibt_hca_portinfo_t **port_info_p, uint_t *ports_p, uint_t *size_p)
682 {
683 	ibtl_hca_devinfo_t	*hca_devp;	/* HCA Dev Info */
684 	ibt_status_t		retval;
685 
686 	mutex_enter(&ibtl_clnt_list_mutex);
687 	hca_devp = ibtl_get_hcadevinfo(hca_guid);
688 	if (hca_devp == NULL) {
689 		/*
690 		 * If we are here, then the requested HCA device is not present.
691 		 * Return the status as Invalid HCA GUID.
692 		 */
693 		*ports_p = *size_p = 0;
694 		*port_info_p = NULL;
695 		mutex_exit(&ibtl_clnt_list_mutex);
696 		IBTF_DPRINTF_L2(ibtf_hca, "ibt_query_hca_ports_byguid: "
697 		    "HCA Device Not Found. ");
698 		return (IBT_HCA_INVALID);
699 	}
700 
701 	retval = ibtl_query_hca_ports(hca_devp, port, port_info_p, ports_p,
702 	    size_p, 0);
703 
704 	mutex_exit(&ibtl_clnt_list_mutex);
705 
706 	return (retval);
707 }
708 
709 /*
710  * Define the above function for CM's use that uses the cached copy.
711  */
712 ibt_status_t
713 ibtl_cm_query_hca_ports_byguid(ib_guid_t hca_guid, uint8_t port,
714     ibt_hca_portinfo_t **port_info_p, uint_t *ports_p, uint_t *size_p)
715 {
716 	ibtl_hca_devinfo_t	*hca_devp;	/* HCA Dev Info */
717 	ibt_status_t		retval;
718 
719 	mutex_enter(&ibtl_clnt_list_mutex);
720 	hca_devp = ibtl_get_hcadevinfo(hca_guid);
721 	if (hca_devp == NULL) {
722 		/*
723 		 * If we are here, then the requested HCA device is not present.
724 		 * Return the status as Invalid HCA GUID.
725 		 */
726 		*ports_p = *size_p = 0;
727 		*port_info_p = NULL;
728 		mutex_exit(&ibtl_clnt_list_mutex);
729 		IBTF_DPRINTF_L2(ibtf_hca, "ibt_query_hca_ports_byguid: "
730 		    "HCA Device Not Found. ");
731 		return (IBT_HCA_INVALID);
732 	}
733 
734 	retval = ibtl_query_hca_ports(hca_devp, port, port_info_p, ports_p,
735 	    size_p, 1);
736 
737 	mutex_exit(&ibtl_clnt_list_mutex);
738 
739 	return (retval);
740 }
741 
742 
743 /*
744  * ibtl_query_one_port - fill in portinfo for one port.
745  */
746 static ibt_status_t
747 ibtl_query_one_port(ibtl_hca_devinfo_t *hca_devp, uint8_t port,
748     ibt_hca_portinfo_t **port_info_p, uint_t *ports_p, uint_t *size_p,
749     int use_cache)
750 {
751 	ibt_hca_portinfo_t	*sp1;	/* src */
752 	ibt_hca_portinfo_t	*p1;	/* dst */
753 	caddr_t			p2;
754 	uint_t			len;
755 	uint_t			sgid_tbl_len, pkey_tbl_len;
756 
757 	ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex));
758 
759 	IBTF_DPRINTF_L3(ibtf_hca, "ibtl_query_one_port(%p, %d)",
760 	    hca_devp, port);
761 
762 	if (port > hca_devp->hd_hca_attr->hca_nports) {
763 		IBTF_DPRINTF_L2(ibtf_hca, "ibtl_query_one_port: "
764 		    "invalid port %d", port);
765 		return (IBT_HCA_PORT_INVALID);
766 	}
767 
768 	/* If the PORT_UP event is not supported, we need to query */
769 	sp1 = hca_devp->hd_portinfop + port - 1;
770 	if (use_cache == 0)
771 		ibtl_reinit_hca_portinfo(hca_devp, port);
772 
773 	*ports_p = 1;
774 
775 	/*
776 	 * Calculate how much memory we need for one port, and allocate it.
777 	 */
778 	sgid_tbl_len = ROUNDUP(sp1->p_sgid_tbl_sz * sizeof (ib_gid_t),
779 	    _LONG_LONG_ALIGNMENT);
780 	pkey_tbl_len = ROUNDUP(sp1->p_pkey_tbl_sz * sizeof (ib_pkey_t),
781 	    _LONG_LONG_ALIGNMENT);
782 
783 	len = sizeof (ibt_hca_portinfo_t) + sgid_tbl_len + pkey_tbl_len;
784 	*size_p = len;
785 
786 	p1 = kmem_zalloc(len, KM_SLEEP);
787 	*port_info_p = p1;
788 	bcopy(sp1, p1, sizeof (ibt_hca_portinfo_t));
789 
790 	/* initialize the p_pkey_tbl & p_sgid_tbl pointers. */
791 	p2 = (caddr_t)(p1 + 1);	/* pkeys follow the struct ibt_hca_portinfo_s */
792 	bcopy(sp1->p_pkey_tbl, p2, pkey_tbl_len);
793 	p1->p_pkey_tbl = (ib_pkey_t *)p2;
794 
795 	p2 += pkey_tbl_len;	/* sgids follow the pkeys */
796 	bcopy(sp1->p_sgid_tbl, p2, sgid_tbl_len);
797 	p1->p_sgid_tbl = (ib_gid_t *)p2;
798 
799 	return (IBT_SUCCESS);
800 }
801 
802 /*
803  * ibtl_query_hca_ports - worker routine to get port_info for clients.
804  */
805 static ibt_status_t
806 ibtl_query_hca_ports(ibtl_hca_devinfo_t *hca_devp, uint8_t port,
807     ibt_hca_portinfo_t **port_info_p, uint_t *ports_p, uint_t *size_p,
808     int use_cache)
809 {
810 	ibt_hca_portinfo_t	*sp1;	/* src */
811 	ibt_hca_portinfo_t	*p1;	/* dst */
812 	uint_t			i, nports;
813 	caddr_t			p2;
814 	uint_t			len;
815 	uint_t			sgid_tbl_len, pkey_tbl_len;
816 
817 	ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex));
818 
819 	/*
820 	 * If user has specified the port num, then query only that port,
821 	 * else query all ports.
822 	 */
823 	if (port)
824 		return (ibtl_query_one_port(hca_devp, port, port_info_p,
825 		    ports_p, size_p, use_cache));
826 
827 	IBTF_DPRINTF_L3(ibtf_hca, "ibtl_query_hca_ports(%p, ALL)", hca_devp);
828 
829 	nports = hca_devp->hd_hca_attr->hca_nports;
830 	*ports_p = nports;
831 
832 	/* If the PORT_UP event is not supported, we need to query */
833 	if (use_cache == 0)
834 		for (i = 0; i < nports; i++)
835 			ibtl_reinit_hca_portinfo(hca_devp, i + 1);
836 
837 	sp1 = hca_devp->hd_portinfop;
838 
839 	/*
840 	 * Calculate how much memory we need for all ports, and allocate it.
841 	 */
842 	sgid_tbl_len = ROUNDUP(sp1->p_sgid_tbl_sz * sizeof (ib_gid_t),
843 	    _LONG_LONG_ALIGNMENT);
844 	pkey_tbl_len = ROUNDUP(sp1->p_pkey_tbl_sz * sizeof (ib_pkey_t),
845 	    _LONG_LONG_ALIGNMENT);
846 
847 	len = (sizeof (ibt_hca_portinfo_t) + sgid_tbl_len + pkey_tbl_len) *
848 	    nports;
849 	*size_p = len;
850 
851 	ASSERT(len == hca_devp->hd_portinfo_len);
852 
853 	p1 = kmem_zalloc(len, KM_SLEEP);
854 	*port_info_p = p1;
855 	bcopy(sp1, p1, len);	/* start with an exact copy of our cache */
856 
857 	p2 = (caddr_t)(p1 + nports);
858 
859 	/* For each port, update the p_pkey_tbl & p_sgid_tbl ptrs. */
860 	for (i = 0; i < nports; i++) {
861 		p1->p_pkey_tbl = (ib_pkey_t *)p2;
862 		p2 += pkey_tbl_len;
863 		p1->p_sgid_tbl = (ib_gid_t *)p2;
864 		p2 += sgid_tbl_len;
865 		p1++;
866 	}
867 	return (IBT_SUCCESS);
868 }
869 
870 /*
871  *	Search for a Full pkey.  Use the pkey at index 0 if not found.
872  */
873 static void
874 ibtl_set_default_pkey_ix(ibt_hca_portinfo_t *p1)
875 {
876 	uint16_t	pkey_ix;
877 
878 	for (pkey_ix = 0; pkey_ix < p1->p_pkey_tbl_sz; pkey_ix++) {
879 		if ((p1->p_pkey_tbl[pkey_ix] & 0x8000) &&
880 		    (p1->p_pkey_tbl[pkey_ix] != IB_PKEY_INVALID_FULL)) {
881 			p1->p_def_pkey_ix = pkey_ix;
882 			IBTF_DPRINTF_L3(ibtf_hca,
883 			    "ibtl_set_default_pkey_ix: portinfop %p, "
884 			    "FULL PKEY 0x%x found, pkey_ix is %d",
885 			    p1, p1->p_pkey_tbl[pkey_ix], pkey_ix);
886 			return;
887 		}
888 	}
889 	IBTF_DPRINTF_L2(ibtf_hca,
890 	    "ibtl_set_default_pkey_ix: portinfop %p: failed "
891 	    "to find a default PKEY in the table, using PKey 0x%x",
892 	    p1, p1->p_pkey_tbl[0]);
893 	p1->p_def_pkey_ix = 0;
894 }
895 
896 /*
897  * ibtl_reinit_hca_portinfo - update the portinfo cache for use by IBTL.
898  *
899  * We have the HCA driver fill in a temporary portinfo, then we bcopy
900  * it into our cache while holding the appropriate lock.
901  */
902 void
903 ibtl_reinit_hca_portinfo(ibtl_hca_devinfo_t *hca_devp, uint8_t port)
904 {
905 	ibt_status_t		status;
906 	ibt_hca_portinfo_t	*p1, *sp1;
907 	ibt_port_state_t	old_linkstate;
908 	uint_t			len, sgid_tbl_len, pkey_tbl_len;
909 	ib_pkey_t		*saved_pkey_tbl;
910 	ib_gid_t		*saved_sgid_tbl;
911 	ib_sn_prefix_t		sn_pfx = 0;
912 	uint_t			multiSM;
913 	int			i;
914 
915 	IBTF_DPRINTF_L3(ibtf_hca, "ibtl_reinit_hca_portinfo(%p, %d)",
916 	    hca_devp, port);
917 
918 	ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex));
919 	ASSERT(port != 0);
920 
921 	if (ibtl_portinfo_locked(hca_devp, port)) {
922 		/* we got the lock, so we need to do the portinfo update */
923 
924 		/* invalidate fast_gid_cache */
925 		ibtl_fast_gid_cache_valid = B_FALSE;
926 
927 		p1 = hca_devp->hd_portinfop + port - 1;
928 		sgid_tbl_len = ROUNDUP(p1->p_sgid_tbl_sz * sizeof (ib_gid_t),
929 		    _LONG_LONG_ALIGNMENT);
930 		pkey_tbl_len = ROUNDUP(p1->p_pkey_tbl_sz * sizeof (ib_pkey_t),
931 		    _LONG_LONG_ALIGNMENT);
932 		len = sizeof (ibt_hca_portinfo_t) + sgid_tbl_len + pkey_tbl_len;
933 
934 		/* update was NOT in progress, so we do it here */
935 		mutex_exit(&ibtl_clnt_list_mutex);
936 
937 		IBTF_DPRINTF_L3(ibtf_hca, "ibtl_reinit_hca_portinfo(%p, %d): "
938 		    "calling ibc_query_hca_ports", hca_devp, port);
939 
940 		sp1 = kmem_zalloc(len, KM_SLEEP);
941 		sp1->p_pkey_tbl = (ib_pkey_t *)(sp1 + 1);
942 		sp1->p_sgid_tbl =
943 		    (ib_gid_t *)((caddr_t)sp1->p_pkey_tbl + pkey_tbl_len);
944 		status = IBTL_HDIP2CIHCAOPS_P(hca_devp)->ibc_query_hca_ports(
945 		    IBTL_HDIP2CIHCA(hca_devp), port, sp1);
946 
947 		mutex_enter(&ibtl_clnt_list_mutex);
948 		if (status != IBT_SUCCESS) {
949 			IBTF_DPRINTF_L2(ibtf_hca,
950 			    "ibtl_reinit_hca_portinfo(%p, %d): "
951 			    "ibc_query_hca_ports() failed: status = %d",
952 			    hca_devp, port, status);
953 		} else {
954 			old_linkstate = p1->p_linkstate;
955 			bcopy(sp1->p_pkey_tbl, p1->p_pkey_tbl, pkey_tbl_len);
956 			bcopy(sp1->p_sgid_tbl, p1->p_sgid_tbl, sgid_tbl_len);
957 			saved_pkey_tbl = p1->p_pkey_tbl;
958 			saved_sgid_tbl = p1->p_sgid_tbl;
959 			bcopy(sp1, p1, sizeof (ibt_hca_portinfo_t));
960 			p1->p_pkey_tbl = saved_pkey_tbl;
961 			p1->p_sgid_tbl = saved_sgid_tbl;
962 			if (p1->p_linkstate == IBT_PORT_ACTIVE) {
963 				ibtl_set_default_pkey_ix(p1);
964 				if (p1->p_linkstate != old_linkstate)
965 					IBTF_DPRINTF_L2(ibtf_hca,
966 					    "ibtl_reinit_hca_portinfo(%p, %d): "
967 					    "PORT UP", hca_devp, port);
968 			} else {
969 				p1->p_base_lid = 0;
970 				if (p1->p_linkstate != old_linkstate)
971 					IBTF_DPRINTF_L2(ibtf_hca,
972 					    "ibtl_reinit_hca_portinfo(%p, %d): "
973 					    "PORT DOWN", hca_devp, port);
974 			}
975 		}
976 		kmem_free(sp1, len);
977 
978 		/* Set multism bit accordingly. */
979 		multiSM = 0;
980 		p1 = hca_devp->hd_portinfop;
981 		for (i = 0; i < hca_devp->hd_hca_attr->hca_nports; i++) {
982 			if (p1->p_linkstate == IBT_PORT_ACTIVE) {
983 				if (sn_pfx == 0) {
984 					sn_pfx = p1->p_sgid_tbl[0].gid_prefix;
985 				} else if (sn_pfx !=
986 				    p1->p_sgid_tbl[0].gid_prefix) {
987 					multiSM = 1;
988 					IBTF_DPRINTF_L3(ibtf_hca,
989 					    "ibtl_reinit_hca_portinfo: "
990 					    "MULTI SM, Port1 SnPfx=0x%llX, "
991 					    "Port2 SnPfx=0x%llX", sn_pfx,
992 					    p1->p_sgid_tbl[0].gid_prefix);
993 				}
994 			}
995 			p1++;
996 		}
997 		hca_devp->hd_multism = multiSM;
998 
999 		ibtl_portinfo_unlock(hca_devp, port);
1000 	}
1001 }
1002 
1003 /*
1004  * ibtl_init_hca_portinfo - fill in the portinfo cache for use by IBTL.
1005  */
1006 ibt_status_t
1007 ibtl_init_hca_portinfo(ibtl_hca_devinfo_t *hca_devp)
1008 {
1009 	ibt_hca_portinfo_t	*p1;
1010 	ibt_status_t		retval;
1011 	uint_t			i, nports;
1012 	caddr_t			p2;
1013 	uint_t			len;
1014 	uint_t			sgid_tbl_len, pkey_tbl_len;
1015 	uint_t			sgid_tbl_sz, pkey_tbl_sz;
1016 	ib_sn_prefix_t		sn_pfx = 0;
1017 	uint_t			multiSM;
1018 
1019 	IBTF_DPRINTF_L2(ibtf_hca, "ibtl_init_hca_portinfo(%p)", hca_devp);
1020 
1021 	ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex));
1022 
1023 	nports = hca_devp->hd_hca_attr->hca_nports;
1024 
1025 	/*
1026 	 * Calculate how much memory we need for all ports, and allocate it.
1027 	 */
1028 	pkey_tbl_sz = IBTL_HDIP2PKEYTBLSZ(hca_devp);
1029 	sgid_tbl_sz = IBTL_HDIP2SGIDTBLSZ(hca_devp);
1030 	pkey_tbl_len = ROUNDUP(pkey_tbl_sz * sizeof (ib_pkey_t),
1031 	    _LONG_LONG_ALIGNMENT);
1032 	sgid_tbl_len = ROUNDUP(sgid_tbl_sz * sizeof (ib_gid_t),
1033 	    _LONG_LONG_ALIGNMENT);
1034 
1035 	len = (sizeof (ibt_hca_portinfo_t) + sgid_tbl_len + pkey_tbl_len) *
1036 	    nports;
1037 
1038 	p1 = kmem_zalloc(len, KM_SLEEP);
1039 	p2 = (caddr_t)(p1 + nports);
1040 
1041 	hca_devp->hd_portinfop = p1;
1042 	hca_devp->hd_portinfo_len = len;
1043 
1044 	/* For each port initialize the p_pkey_tbl & p_sgid_tbl ptrs. */
1045 	for (i = 0; i < nports; i++) {
1046 		p1->p_pkey_tbl_sz = pkey_tbl_sz;
1047 		p1->p_sgid_tbl_sz = sgid_tbl_sz;
1048 		p1->p_pkey_tbl = (ib_pkey_t *)p2;
1049 		p2 += pkey_tbl_len;
1050 		p1->p_sgid_tbl = (ib_gid_t *)p2;
1051 		p2 += sgid_tbl_len;
1052 		p1++;
1053 	}
1054 	p1 = hca_devp->hd_portinfop;
1055 	mutex_exit(&ibtl_clnt_list_mutex);
1056 
1057 	/* re-direct the call to CI's call */
1058 	retval = IBTL_HDIP2CIHCAOPS_P(hca_devp)->ibc_query_hca_ports(
1059 	    IBTL_HDIP2CIHCA(hca_devp), 0, p1);
1060 
1061 	mutex_enter(&ibtl_clnt_list_mutex);
1062 	if (retval != IBT_SUCCESS) {
1063 		IBTF_DPRINTF_L2(ibtf_hca, "ibtl_init_hca_portinfo(%p): "
1064 		    "ibc_query_hca_ports() failed: status = %d",
1065 		    hca_devp, retval);
1066 		kmem_free(hca_devp->hd_portinfop, len);
1067 		hca_devp->hd_portinfop = NULL;
1068 		hca_devp->hd_portinfo_len = 0;
1069 		return (retval);
1070 	}
1071 
1072 	p1 = hca_devp->hd_portinfop;
1073 	multiSM = 0;
1074 	for (i = 0; i < nports; i++) {
1075 		if (p1->p_linkstate == IBT_PORT_ACTIVE) {
1076 			ibtl_set_default_pkey_ix(p1);
1077 			if (sn_pfx == 0) {
1078 				sn_pfx = p1->p_sgid_tbl[0].gid_prefix;
1079 			} else if (p1->p_sgid_tbl[0].gid_prefix != sn_pfx) {
1080 				multiSM = 1;
1081 				IBTF_DPRINTF_L3(ibtf_hca,
1082 				    "ibtl_init_hca_portinfo: MULTI SM, "
1083 				    "Port1 SnPfx=0x%llX, Port2 SnPfx=0x%llX",
1084 				    sn_pfx, p1->p_sgid_tbl[0].gid_prefix);
1085 			}
1086 		} else {
1087 			p1->p_base_lid = 0;
1088 		}
1089 		p1++;
1090 	}
1091 	hca_devp->hd_multism = multiSM;
1092 
1093 	return (IBT_SUCCESS);
1094 }
1095 
1096 /*
1097  * Function:
1098  *	ibt_modify_system_image
1099  * Input:
1100  *	hca_hdl	 - The HCA handle.
1101  *	sys_guid - The New system image GUID.
1102  * Description:
1103  *	Modify specified HCA's system image GUID.
1104  */
1105 ibt_status_t
1106 ibt_modify_system_image(ibt_hca_hdl_t hca_hdl, ib_guid_t sys_guid)
1107 {
1108 	ibt_status_t		retval;
1109 
1110 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_modify_system_image(%p, %llX)",
1111 	    hca_hdl, sys_guid);
1112 
1113 	mutex_enter(&ibtl_clnt_list_mutex);
1114 	/* Get HCA Dev Info Structure, referenced by HCA GUID. */
1115 
1116 	/* re-direct the call to CI's call */
1117 	retval = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_modify_system_image(
1118 	    IBTL_HCA2CIHCA(hca_hdl), sys_guid);
1119 
1120 	mutex_exit(&ibtl_clnt_list_mutex);
1121 	return (retval);
1122 }
1123 
1124 /*
1125  * Function:
1126  *	ibt_modify_system_image_byguid
1127  *
1128  * Input:
1129  *	hca_guid - The HCA Node GUID.
1130  *	sys_guid - The New system image GUID.
1131  * Description:
1132  *	Modify specified HCA's system image GUID.
1133  */
1134 ibt_status_t
1135 ibt_modify_system_image_byguid(ib_guid_t hca_guid, ib_guid_t sys_guid)
1136 {
1137 	ibtl_hca_devinfo_t	*hca_devp;	/* HCA Dev Info. */
1138 	ibt_status_t		retval;
1139 
1140 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_modify_system_image_byguid(%llX, %llX)",
1141 	    hca_guid, sys_guid);
1142 
1143 	mutex_enter(&ibtl_clnt_list_mutex);
1144 	/* Get HCA Dev Info Structure, referenced by HCA GUID. */
1145 	hca_devp = ibtl_get_hcadevinfo(hca_guid);
1146 	if (hca_devp == NULL) {
1147 		/*
1148 		 * If we are here, then the requested HCA device is not present.
1149 		 */
1150 		mutex_exit(&ibtl_clnt_list_mutex);
1151 		return (IBT_HCA_INVALID);
1152 	}
1153 
1154 	/* re-direct the call to CI's call */
1155 	retval = IBTL_HDIP2CIHCAOPS_P(hca_devp)->ibc_modify_system_image(
1156 	    IBTL_HDIP2CIHCA(hca_devp), sys_guid);
1157 
1158 	mutex_exit(&ibtl_clnt_list_mutex);
1159 	return (retval);
1160 }
1161 
1162 /*
1163  * Function:
1164  *      ibt_modify_port_byguid
1165  * Input:
1166  *      hca_guid - The HCA Guid.
1167  *      cmds     - A pointer to an array of ibt_port_modify_t cmds. The
1168  *                 pmod_port field specifies the port to modify (all ports if 0)
1169  *                 and the pmod_flags field specifies which attribute to reset.
1170  *      num_cmds - The number of commands in the cmds array.
1171  * Output:
1172  *      none.
1173  * Returns:
1174  *      IBT_SUCCESS
1175  *      IBT_HCA_HDL_INVALID
1176  *      IBT_HCA_CNTR_INVALID
1177  *      IBT_HCA_CNTR_VAL_INVALID
1178  * Description:
1179  *      Reset the specified port, or all ports attribute(s).
1180  */
1181 ibt_status_t
1182 ibt_modify_port_byguid(ib_guid_t hca_guid,  uint8_t port,
1183     ibt_port_modify_flags_t flags, uint8_t init_type)
1184 {
1185 	ibtl_hca_devinfo_t	*hca_devp;	/* HCA Dev Info. */
1186 	ibt_status_t		retval;
1187 
1188 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_modify_port_byguid(%llX, %d, %X, %X)",
1189 	    hca_guid, port, flags, init_type);
1190 
1191 	mutex_enter(&ibtl_clnt_list_mutex);
1192 	/* Get HCA Dev Info Structure, referenced by HCA GUID. */
1193 	hca_devp = ibtl_get_hcadevinfo(hca_guid);
1194 	if (hca_devp == NULL) {
1195 		/*
1196 		 * If we are here, then the requested HCA device is not present.
1197 		 */
1198 		mutex_exit(&ibtl_clnt_list_mutex);
1199 		return (IBT_HCA_INVALID);
1200 	}
1201 
1202 	/* re-direct the call to CI's call */
1203 	retval = IBTL_HDIP2CIHCAOPS_P(hca_devp)->ibc_modify_ports(
1204 	    IBTL_HDIP2CIHCA(hca_devp), port, flags, init_type);
1205 
1206 	mutex_exit(&ibtl_clnt_list_mutex);
1207 	return (retval);
1208 }
1209 
1210 /*
1211  * Function:
1212  *      ibt_modify_port
1213  * Input:
1214  *      hca_hdl  - The HCA handle.
1215  *      cmds     - A pointer to an array of ibt_port_modify_t cmds. The
1216  *                 pmod_port field specifies the port to modify (all ports if 0)
1217  *                 and the pmod_flags field specifies which attribute to reset.
1218  *      num_cmds - The number of commands in the cmds array.
1219  * Output:
1220  *      none.
1221  * Returns:
1222  *      IBT_SUCCESS
1223  *      IBT_HCA_HDL_INVALID
1224  *      IBT_HCA_CNTR_INVALID
1225  *      IBT_HCA_CNTR_VAL_INVALID
1226  * Description:
1227  *      Reset the specified port, or all ports attribute(s).
1228  */
1229 ibt_status_t
1230 ibt_modify_port(ibt_hca_hdl_t hca_hdl, uint8_t port,
1231     ibt_port_modify_flags_t flags, uint8_t init_type)
1232 
1233 {
1234 	ibt_status_t		retval;
1235 
1236 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_modify_port(%p, %d, %X, %X)",
1237 	    hca_hdl, port, flags, init_type);
1238 
1239 	mutex_enter(&ibtl_clnt_list_mutex);
1240 
1241 	/* re-direct the call to CI's call */
1242 	retval = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_modify_ports(
1243 	    IBTL_HCA2CIHCA(hca_hdl), port, flags, init_type);
1244 
1245 	mutex_exit(&ibtl_clnt_list_mutex);
1246 	return (retval);
1247 }
1248 
1249 /*
1250  * Function:
1251  *      ibt_free_portinfo
1252  * Input:
1253  *      port_info  - The address of an array to a ibt_hca_portinfo_t struct.
1254  *	size	   - Memory Size as returned from ibt_query_hca_ports().
1255  * Output:
1256  *      none
1257  * Returns:
1258  *      none
1259  * Description:
1260  *      Frees the memory allocated for a specified ibt_hca_portinfo_t struct.
1261  */
1262 void
1263 ibt_free_portinfo(ibt_hca_portinfo_t *port_info, uint_t size)
1264 {
1265 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_free_portinfo(%p, %d)",
1266 	    port_info, size);
1267 
1268 	if ((port_info == NULL) || (size == 0)) {
1269 		IBTF_DPRINTF_L2(ibtf_hca, "ibt_free_portinfo: NULL Pointer");
1270 	} else {
1271 		kmem_free(port_info, size);
1272 	}
1273 }
1274 
1275 
1276 /*
1277  * Function:
1278  *      ibt_get_hcadevinfo
1279  * Input:
1280  *      hca_guid - The HCA's node GUID.
1281  * Output:
1282  *      none.
1283  * Returns:
1284  *      Pointer to HCA Device Info structure whose HCA GUID is requested or NULL
1285  * Description:
1286  *      Get a pointer to HCA Device Info Structure for the requested HCA GUID.
1287  *      If no matching HCA GUID Device info is found, NULL is returned.
1288  */
1289 ibtl_hca_devinfo_t *
1290 ibtl_get_hcadevinfo(ib_guid_t hca_guid)
1291 {
1292 	ibtl_hca_devinfo_t	*hca_devp;	/* HCA Dev Info */
1293 
1294 	IBTF_DPRINTF_L3(ibtf_hca, "ibtl_get_hcadevinfo(%llX)", hca_guid);
1295 
1296 	ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex));
1297 
1298 	hca_devp = ibtl_hca_list;
1299 
1300 	/*
1301 	 * Check whether a HCA device with requested Node GUID is available.
1302 	 * This is done, by searching the global HCA devinfo list and
1303 	 * comparing the Node GUID from the device attribute info.
1304 	 */
1305 	while (hca_devp != NULL) {
1306 		if (hca_devp->hd_hca_attr->hca_node_guid == hca_guid) {
1307 			/* Match Found. */
1308 			break;
1309 		}
1310 		hca_devp = hca_devp->hd_hca_dev_link;
1311 	}
1312 	return (hca_devp);
1313 }
1314 
1315 
1316 /*
1317  * Function:
1318  *      ibtl_pkey2index
1319  * Input:
1320  *      hca_devp     - The IBTL HCA Device Info.
1321  *      port_num     - The HCA port number.
1322  *      pkey         - The input PKey value, whose index we are interested in.
1323  * Output:
1324  *      pkey_ix      - The PKey index returned for the specified PKey.
1325  * Returns:
1326  *      IBT_SUCCESS/IBT_HCA_PORT_INVALID/IBT_INVALID_PARAM
1327  * Description:
1328  *      Returns the PKey Index for the specified PKey, the device as specified
1329  *      by IBT HCA Handle.
1330  */
1331 static ibt_status_t
1332 ibtl_pkey2index(ibtl_hca_devinfo_t *hca_devp, uint8_t port_num,
1333     ib_pkey_t pkey, uint16_t *pkey_ix)
1334 {
1335 	ibt_hca_portinfo_t 	*port_infop;
1336 	uint_t			ports;
1337 	uint_t			i;
1338 
1339 	IBTF_DPRINTF_L3(ibtf_hca, "ibtl_pkey2index(%p, %d, %d)",
1340 	    hca_devp, port_num, pkey);
1341 
1342 	ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex));
1343 
1344 	if ((pkey == IB_PKEY_INVALID_FULL) ||
1345 	    (pkey == IB_PKEY_INVALID_LIMITED))
1346 		return (IBT_INVALID_PARAM);
1347 
1348 	ports = hca_devp->hd_hca_attr->hca_nports;
1349 	if ((port_num == 0) || (port_num > ports)) {
1350 		IBTF_DPRINTF_L2(ibtf_hca, "ibtl_pkey2index: "
1351 		    "Invalid port_num %d, range is (1 to %d)", port_num, ports);
1352 		return (IBT_HCA_PORT_INVALID);
1353 	}
1354 
1355 	port_infop = hca_devp->hd_portinfop + port_num - 1;
1356 	for (i = 0; i < port_infop->p_pkey_tbl_sz; i++) {
1357 		if (pkey == port_infop->p_pkey_tbl[i]) {
1358 			*pkey_ix = i;
1359 			return (IBT_SUCCESS);
1360 		}
1361 	}
1362 	return (IBT_INVALID_PARAM);
1363 }
1364 
1365 /*
1366  * Function:
1367  *      ibtl_index2pkey
1368  * Input:
1369  *      hca_devp     - The IBTL HCA Device Info.
1370  *      port_num     - The HCA port
1371  *      pkey_ix      - The input PKey index, whose PKey we are interested in.
1372  * Output:
1373  *      pkey         - The returned PKey value.
1374  * Returns:
1375  *      IBT_SUCCESS/IBT_PKEY_IX_ILLEGAL/IBT_PKEY_IX_INVALID/IBT_HCA_PORT_INVALID
1376  * Description:
1377  *      Returns the PKey value for the specified PKey index, the device as
1378  *      specified by IBT HCA Handle.
1379  */
1380 static ibt_status_t
1381 ibtl_index2pkey(ibtl_hca_devinfo_t *hca_devp, uint8_t port_num,
1382     uint16_t pkey_ix, ib_pkey_t *pkey)
1383 {
1384 	ibt_hca_portinfo_t 	*port_infop;
1385 	uint_t			ports;
1386 
1387 	IBTF_DPRINTF_L3(ibtf_hca, "ibtl_index2pkey(%p, %d, %d)",
1388 	    hca_devp, port_num, pkey_ix);
1389 
1390 	ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex));
1391 
1392 	ports = hca_devp->hd_hca_attr->hca_nports;
1393 	if ((port_num == 0) || (port_num > ports)) {
1394 		IBTF_DPRINTF_L2(ibtf_hca, "ibtl_index2pkey: "
1395 		    "Invalid port_num %d, range is (1 to %d)", port_num, ports);
1396 		return (IBT_HCA_PORT_INVALID);
1397 	}
1398 
1399 	port_infop = hca_devp->hd_portinfop + port_num - 1;
1400 	if (pkey_ix >= port_infop->p_pkey_tbl_sz) {
1401 		IBTF_DPRINTF_L2(ibtf_hca, "ibtl_index2pkey: "
1402 		    "pkey index %d out of range (0, %d)",
1403 		    pkey_ix, port_infop->p_pkey_tbl_sz - 1);
1404 		return (IBT_PKEY_IX_ILLEGAL);
1405 	}
1406 
1407 	*pkey = port_infop->p_pkey_tbl[pkey_ix];
1408 	if ((*pkey == IB_PKEY_INVALID_FULL) ||
1409 	    (*pkey == IB_PKEY_INVALID_LIMITED))
1410 		return (IBT_PKEY_IX_INVALID);
1411 	return (IBT_SUCCESS);
1412 }
1413 
1414 /*
1415  * Function:
1416  *      ibt_pkey2index
1417  * Input:
1418  *      hca_hdl      - The IBT HCA handle.
1419  *      port_num     - The HCA port number.
1420  *      pkey         - The input PKey value, whose index we are interested in.
1421  * Output:
1422  *      pkey_ix      - The PKey index returned for the specified PKey.
1423  * Returns:
1424  *      IBT_SUCCESS/IBT_HCA_PORT_INVALID/IBT_INVALID_PARAM
1425  * Description:
1426  *      Returns the PKey Index for the specified PKey, the device as specified
1427  *      by IBT HCA Handle.
1428  */
1429 ibt_status_t
1430 ibt_pkey2index(ibt_hca_hdl_t hca_hdl, uint8_t port_num, ib_pkey_t pkey,
1431     uint16_t *pkey_ix)
1432 {
1433 	ibt_status_t		retval;
1434 
1435 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_pkey2index(%p, %d, %d)",
1436 	    hca_hdl, port_num, pkey);
1437 
1438 	mutex_enter(&ibtl_clnt_list_mutex);
1439 	retval = ibtl_pkey2index(hca_hdl->ha_hca_devp, port_num, pkey, pkey_ix);
1440 	mutex_exit(&ibtl_clnt_list_mutex);
1441 
1442 	return (retval);
1443 }
1444 
1445 /*
1446  * Function:
1447  *      ibt_pkey2index_byguid
1448  * Input:
1449  *      hca_guid     - The HCA's node GUID.
1450  *      port_num     - The HCA port number.
1451  *      pkey         - The input PKey value, whose index we are interested in.
1452  * Output:
1453  *      pkey_ix      - The PKey Index returned for the specified PKey.
1454  * Returns:
1455  *      IBT_SUCCESS/IBT_HCA_PORT_INVALID/IBT_INVALID_PARAM/IBT_HCA_INVALID
1456  * Description:
1457  *      Returns the PKey Index for the specified PKey, the device as specified
1458  *      by HCA GUID Info.
1459  */
1460 ibt_status_t
1461 ibt_pkey2index_byguid(ib_guid_t hca_guid, uint8_t port_num, ib_pkey_t pkey,
1462     uint16_t *pkey_ix)
1463 {
1464 	ibt_status_t		retval;
1465 	ibtl_hca_devinfo_t	*hca_devp;	/* HCA Dev Info */
1466 
1467 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_pkey2index_byguid(%llX, %d, %d)",
1468 	    hca_guid, port_num, pkey);
1469 
1470 	mutex_enter(&ibtl_clnt_list_mutex);
1471 	hca_devp = ibtl_get_hcadevinfo(hca_guid);
1472 	if (hca_devp == NULL) {
1473 		IBTF_DPRINTF_L2(ibtf_hca, "ibt_pkey2index_byguid: "
1474 		    "Invalid HCA GUID 0x%llx", hca_guid);
1475 		mutex_exit(&ibtl_clnt_list_mutex);
1476 		return (IBT_HCA_INVALID);
1477 	}
1478 	retval = ibtl_pkey2index(hca_devp, port_num, pkey, pkey_ix);
1479 	mutex_exit(&ibtl_clnt_list_mutex);
1480 
1481 	return (retval);
1482 }
1483 
1484 
1485 /*
1486  * Function:
1487  *      ibt_index2pkey
1488  * Input:
1489  *      hca_hdl      - The IBT HCA handle.
1490  *      port_num     - The HCA port
1491  *      pkey_ix      - The input PKey index, whose PKey we are interested in.
1492  * Output:
1493  *      pkey         - The returned PKey value.
1494  * Returns:
1495  *      IBT_SUCCESS/IBT_PKEY_IX_ILLEGAL/IBT_PKEY_IX_INVALID/IBT_HCA_PORT_INVALID
1496  * Description:
1497  *      Returns the PKey value for the specified PKey index, the device as
1498  *      specified by IBT HCA Handle.
1499  */
1500 ibt_status_t
1501 ibt_index2pkey(ibt_hca_hdl_t hca_hdl, uint8_t port_num, uint16_t pkey_ix,
1502     ib_pkey_t *pkey)
1503 {
1504 	ibt_status_t		retval;
1505 
1506 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_index2pkey(%p, %d, %d)",
1507 	    hca_hdl, port_num, pkey_ix);
1508 
1509 	mutex_enter(&ibtl_clnt_list_mutex);
1510 	retval = ibtl_index2pkey(hca_hdl->ha_hca_devp, port_num, pkey_ix, pkey);
1511 	mutex_exit(&ibtl_clnt_list_mutex);
1512 
1513 	return (retval);
1514 }
1515 
1516 /*
1517  * Function:
1518  *      ibt_index2pkey_byguid
1519  * Input:
1520  *      hca_guid     - The HCA's node GUID.
1521  *      port_num     - The HCA port
1522  *      pkey_ix      - The input PKey index, whose PKey we are interested in.
1523  * Output:
1524  *      pkey         - The returned PKey value, for the specified index.
1525  * Returns:
1526  *      IBT_SUCCESS/IBT_PKEY_IX_ILLEGAL/IBT_PKEY_IX_INVALID/
1527  *	IBT_HCA_PORT_INVALID/IBT_HCA_INVALID
1528  * Description:
1529  *      Returns the PKey Index for the specified PKey, the device as specified
1530  *      by HCA GUID Info.
1531  */
1532 ibt_status_t
1533 ibt_index2pkey_byguid(ib_guid_t hca_guid, uint8_t port_num, uint16_t pkey_ix,
1534     ib_pkey_t *pkey)
1535 {
1536 	ibt_status_t		retval;
1537 	ibtl_hca_devinfo_t	*hca_devp;	/* HCA Dev Info */
1538 
1539 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_index2pkey_byguid(%llX, %d, %d)",
1540 	    hca_guid, port_num, pkey_ix);
1541 
1542 	mutex_enter(&ibtl_clnt_list_mutex);
1543 	hca_devp = ibtl_get_hcadevinfo(hca_guid);
1544 	if (hca_devp == NULL) {
1545 		IBTF_DPRINTF_L2(ibtf_hca, "ibt_index2pkey_byguid: "
1546 		    "Invalid HCA GUID 0x%llx", hca_guid);
1547 		mutex_exit(&ibtl_clnt_list_mutex);
1548 		return (IBT_HCA_INVALID);
1549 	}
1550 	retval = ibtl_index2pkey(hca_devp, port_num, pkey_ix, pkey);
1551 	mutex_exit(&ibtl_clnt_list_mutex);
1552 
1553 	return (retval);
1554 }
1555 
1556 
1557 _NOTE(SCHEME_PROTECTS_DATA("client managed", ibtl_hca_s::ha_clnt_private))
1558 
1559 /*
1560  * Function:
1561  *      ibt_set_hca_private
1562  * Input:
1563  *      hca_hdl		The ibt_hca_hdl_t of the opened HCA.
1564  *      clnt_private	The client private data.
1565  * Output:
1566  *	none.
1567  * Returns:
1568  *      none
1569  * Description:
1570  *      Sets the client private data.
1571  */
1572 void
1573 ibt_set_hca_private(ibt_hca_hdl_t hca_hdl, void *clnt_private)
1574 {
1575 	hca_hdl->ha_clnt_private = clnt_private;
1576 }
1577 
1578 
1579 /*
1580  * Function:
1581  *      ibt_get_hca_private
1582  * Input:
1583  *      hca_hdl		The ibt_hca_hdl_t of the opened HCA.
1584  * Output:
1585  *      none
1586  * Returns:
1587  *      The client private data.
1588  * Description:
1589  *      Retrieves the private data from a specified HCA.
1590  */
1591 void *
1592 ibt_get_hca_private(ibt_hca_hdl_t hca_hdl)
1593 {
1594 	return (hca_hdl->ha_clnt_private);
1595 }
1596 
1597 /*
1598  * Function:
1599  *	ibt_hca_handle_to_guid
1600  * Input:
1601  *	hca		HCA Handle.
1602  * Output:
1603  *	none.
1604  * Returns:
1605  *	hca_guid	Returned HCA GUID on which the specified Channel is
1606  *			allocated. Valid if it is non-NULL on return.
1607  * Description:
1608  *	A helper function to retrieve HCA GUID for the specified handle.
1609  */
1610 ib_guid_t
1611 ibt_hca_handle_to_guid(ibt_hca_hdl_t hca)
1612 {
1613 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_hca_handle_to_guid(%p)", hca);
1614 	return (IBTL_HCA2HCAGUID(hca));
1615 }
1616 
1617 /*
1618  * Function:
1619  *	ibt_hca_guid_to_handle
1620  * Input:
1621  *	ibt_hdl		The handle returned to the client by the IBTF from
1622  *                      an ibt_attach() call.
1623  *	hca_guid	HCA GUID
1624  * Output:
1625  *	hca_hdl		Returned ibt_hca_hdl_t.
1626  * Returns:
1627  *      IBT_SUCCESS
1628  *      IBT_HCA_INVALID
1629  * Description:
1630  *	A helper function to retrieve a hca handle from a HCA GUID.
1631  */
1632 ibt_status_t
1633 ibt_hca_guid_to_handle(ibt_clnt_hdl_t ibt_hdl, ib_guid_t hca_guid,
1634     ibt_hca_hdl_t *hca_hdl)
1635 {
1636 	ibtl_hca_t  		*hca_infop;
1637 	ibtl_hca_devinfo_t	*hca_devp;		/* HCA Dev Info */
1638 	ibt_status_t		rval = IBT_HCA_INVALID;
1639 
1640 	IBTF_DPRINTF_L3(ibtf_hca, "ibt_hca_guid_to_handle(%p, %llX)",
1641 	    ibt_hdl, hca_guid);
1642 
1643 	mutex_enter(&ibtl_clnt_list_mutex);
1644 
1645 	/*
1646 	 * Get HCA Device Info Structure, referenced by HCA GUID.
1647 	 */
1648 	hca_devp = ibtl_get_hcadevinfo(hca_guid);
1649 	if (hca_devp == NULL) {
1650 		/*
1651 		 * If we are here, then the requested HCA device is not present.
1652 		 * Return the status as Invalid HCA GUID.
1653 		 */
1654 		mutex_exit(&ibtl_clnt_list_mutex);
1655 
1656 		IBTF_DPRINTF_L2(ibtf_hca, "ibt_hca_guid_to_handle: "
1657 		    "HCA Device Not Found: Invalid HCA GUID");
1658 
1659 		*hca_hdl = NULL;
1660 		return (rval);
1661 	}
1662 
1663 	/*
1664 	 * Yes, we found a HCA Device registered with IBTF, which matches with
1665 	 * the requested HCA_GUID.
1666 	 */
1667 	hca_infop = hca_devp->hd_clnt_list;
1668 
1669 	while (hca_infop != NULL) {
1670 		if (ibt_hdl == hca_infop->ha_clnt_devp) {
1671 			rval = IBT_SUCCESS;
1672 			break;
1673 		}
1674 		hca_infop = hca_infop->ha_clnt_link;
1675 	}
1676 
1677 	mutex_exit(&ibtl_clnt_list_mutex);
1678 	*hca_hdl = hca_infop;
1679 	return (rval);
1680 }
1681