xref: /illumos-gate/usr/src/uts/common/io/ib/ibtl/ibtl_ibnex.c (revision 9b9d39d2a32ff806d2431dbcc50968ef1e6d46b2)
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 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * Copyright 2023 Oxide Computer Company
28  */
29 
30 #include <sys/systm.h>
31 #include <sys/sunndi.h>
32 #include <sys/sunmdi.h>
33 #include <sys/ib/ibtl/impl/ibtl.h>
34 #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
35 
36 /*
37  * ibtl_ibnex.c
38  *    These routines tie the Device Manager into IBTL.
39  *
40  *    ibt_reprobe_dev which can be called by IBTF clients.
41  *    This results in calls to IBnexus callback.
42  */
43 
44 /*
45  * Globals.
46  */
47 static char		ibtl_ibnex[] = "ibtl_ibnex";
48 ibtl_ibnex_callback_t	ibtl_ibnex_callback_routine = NULL;
49 
50 /*
51  * Function:
52  *	ibtl_ibnex_get_hca_info
53  * Input:
54  *	hca_guid	- The HCA's node GUID.
55  *	flag		- Tells what to do
56  *			IBTL_IBNEX_LIST_CLNTS_FLAG - Build a NVLIST containing
57  *						client's names, their AP_IDs and
58  *						alternate_HCA information.
59  *						(-x list_clients option)
60  *			IBTL_IBNEX_UNCFG_CLNTS_FLAG - Build a NVLIST containing
61  *						clients' devpaths and their
62  *						AP_IDs. (-x unconfig_clients)
63  *	callback	- Callback function to get ap_id from ib(4D)
64  * Output:
65  *	buffer		- The information is returned in this buffer
66  *      bufsiz		- The size of the information buffer
67  * Returns:
68  *	IBT_SUCCESS/IBT_HCA_INVALID/IBT_INVALID_PARAM
69  * Description:
70  *      For a given HCA node GUID it figures out the registered clients
71  *	(ie. ones who called ibt_open_hca(9f) on this GUID) and creates
72  *	a NVL packed buffer (of client names/ap_ids or devpaths) and returns
73  *	it. If flag is not specified, then an error is returned.
74  */
75 ibt_status_t
76 ibtl_ibnex_get_hca_info(ib_guid_t hca_guid, int flag, char **buffer,
77     size_t *bufsiz, void (*callback)(dev_info_t *, char **))
78 {
79 	char			*node_name;
80 	char			*ret_apid;
81 	nvlist_t		*nvl;
82 	ibtl_hca_t		*ibt_hca;
83 	ibtl_clnt_t		*clntp;
84 	dev_info_t		*child;
85 	dev_info_t		*parent;
86 	ibtl_hca_devinfo_t	*hca_devp;
87 
88 	IBTF_DPRINTF_L3(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
89 	    "GUID  0x%llX, flag = 0x%x", hca_guid, flag);
90 
91 	*buffer = NULL;
92 	*bufsiz = 0;
93 
94 	/* verify that valid "flag" is passed */
95 	if (flag != IBTL_IBNEX_LIST_CLNTS_FLAG &&
96 	    flag != IBTL_IBNEX_UNCFG_CLNTS_FLAG) {
97 		return (IBT_INVALID_PARAM);
98 	}
99 
100 	mutex_enter(&ibtl_clnt_list_mutex);
101 
102 	if ((hca_devp = ibtl_get_hcadevinfo(hca_guid)) == NULL) {
103 		mutex_exit(&ibtl_clnt_list_mutex);
104 
105 		/*
106 		 * If we are here, then the requested HCA device is not
107 		 * present. Return the status as Invalid HCA GUID.
108 		 */
109 		IBTF_DPRINTF_L2(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
110 		    "HCA Not Found, Invalid HCA GUID 0x%llX", hca_guid);
111 		return (IBT_HCA_INVALID);
112 	}
113 
114 	/* Walk the client list */
115 	ibt_hca = hca_devp->hd_clnt_list;
116 	(void) nvlist_alloc(&nvl, 0, KM_SLEEP);
117 
118 	/* Allocate memory for ret_apid, instead of using stack */
119 	ret_apid = kmem_alloc(IBTL_IBNEX_APID_LEN, KM_SLEEP);
120 
121 	while (ibt_hca != NULL) {
122 		clntp = ibt_hca->ha_clnt_devp;
123 		child = clntp->clnt_dip;
124 		IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
125 		    "Client = %s", clntp->clnt_modinfop->mi_clnt_name);
126 
127 		if (flag == IBTL_IBNEX_LIST_CLNTS_FLAG) {
128 			(void) nvlist_add_string(nvl, "Client",
129 			    clntp->clnt_modinfop->mi_clnt_name);
130 
131 			/*
132 			 * Always check, first, if this client exists
133 			 * under this HCA anymore? If not, continue.
134 			 */
135 			if (clntp->clnt_hca_list == NULL) {
136 				(void) nvlist_add_string(nvl, "Alt_HCA", "no");
137 				(void) nvlist_add_string(nvl, "ApID", "-");
138 				ibt_hca = ibt_hca->ha_clnt_link;
139 				continue;
140 			}
141 
142 			/* Check if this client has more than one HCAs */
143 			if (clntp->clnt_hca_list->ha_hca_link == NULL)
144 				(void) nvlist_add_string(nvl, "Alt_HCA", "no");
145 			else
146 				(void) nvlist_add_string(nvl, "Alt_HCA", "yes");
147 
148 			if (child == NULL) {
149 				(void) nvlist_add_string(nvl, "ApID", "-");
150 				ibt_hca = ibt_hca->ha_clnt_link;
151 				continue;
152 			}
153 
154 			/*
155 			 * All IB clients (IOC, VPPA, Port, Pseudo etc.)
156 			 * need to be looked at. The parent of IOC nodes
157 			 * is "ib" nexus and node-name is "ioc". "VPPA/Port"s
158 			 * should have HCA as parent and node-name is "ibport".
159 			 * HCA validity is checked by looking at parent's "dip"
160 			 * and the dip saved in the ibtl_hca_devinfo_t.
161 			 * NOTE: We only want to list this HCA's IB clients.
162 			 * All others clients are ignored.
163 			 */
164 			parent = ddi_get_parent(child);
165 			if (parent == NULL || /* No parent? */
166 			    ddi_get_parent_data(child) == NULL) {
167 				(void) nvlist_add_string(nvl, "ApID", "-");
168 				ibt_hca = ibt_hca->ha_clnt_link;
169 				continue;
170 			}
171 
172 			node_name = ddi_node_name(child);
173 			if ((strcmp(ddi_node_name(parent), "ib") == 0) ||
174 			    ((hca_devp->hd_hca_dip == parent) &&
175 			    (strncmp(node_name, IBNEX_IBPORT_CNAME, 6) == 0))) {
176 				ASSERT(callback != NULL);
177 				/*
178 				 * Callback is invoked to figure out the
179 				 * ap_id string.
180 				 */
181 				callback(child, &ret_apid);
182 				(void) nvlist_add_string(nvl, "ApID", ret_apid);
183 			} else {
184 				(void) nvlist_add_string(nvl, "ApID", "-");
185 			}
186 
187 		} else if (flag == IBTL_IBNEX_UNCFG_CLNTS_FLAG) {
188 			char		path[MAXPATHLEN];
189 
190 			if (child == NULL) {
191 				IBTF_DPRINTF_L4(ibtl_ibnex,
192 				    "ibtl_ibnex_get_hca_info: No dip exists");
193 				ibt_hca = ibt_hca->ha_clnt_link;
194 				continue;
195 			}
196 
197 			/*
198 			 * if the child has a alternate HCA then skip it
199 			 */
200 			if (clntp->clnt_hca_list->ha_hca_link) {
201 				IBTF_DPRINTF_L4(ibtl_ibnex,
202 				    "ibtl_ibnex_get_hca_info: Alt HCA exists");
203 				ibt_hca = ibt_hca->ha_clnt_link;
204 				continue;
205 			}
206 
207 			/*
208 			 * See earlier comments on how to check if a client
209 			 * is IOC, VPPA, Port or a Pseudo node.
210 			 */
211 			parent = ddi_get_parent(child);
212 			if (parent == NULL || /* No parent? */
213 			    ddi_get_parent_data(child) == NULL) {
214 				IBTF_DPRINTF_L4(ibtl_ibnex,
215 				    "ibtl_ibnex_get_hca_info: no parent");
216 				ibt_hca = ibt_hca->ha_clnt_link;
217 				continue;
218 			}
219 
220 			node_name = ddi_node_name(child);
221 			if ((strcmp(ddi_node_name(parent), "ib") == 0) ||
222 			    ((hca_devp->hd_hca_dip == parent) &&
223 			    (strncmp(node_name, IBNEX_IBPORT_CNAME, 6) == 0))) {
224 				ASSERT(callback != NULL);
225 				/*
226 				 * Callback is invoked to figure out the
227 				 * ap_id string.
228 				 */
229 				callback(child, &ret_apid);
230 				(void) nvlist_add_string(nvl, "ApID", ret_apid);
231 
232 				/*
233 				 * ddi_pathname() doesn't supply /devices,
234 				 * so we do
235 				 */
236 				(void) strcpy(path, "/devices");
237 				(void) ddi_pathname(child, path + strlen(path));
238 				IBTF_DPRINTF_L4(ibtl_ibnex,
239 				    "ibtl_ibnex_get_hca_info: "
240 				    "device path = %s", path);
241 
242 				if (nvlist_add_string(nvl, "devpath", path)) {
243 					IBTF_DPRINTF_L2(ibtl_ibnex,
244 					    "ibtl_ibnex_get_hca_info: "
245 					    "failed to fill in path %s", path);
246 					mutex_exit(&ibtl_clnt_list_mutex);
247 					nvlist_free(nvl);
248 					kmem_free(ret_apid,
249 					    IBTL_IBNEX_APID_LEN);
250 					return (ibt_get_module_failure(
251 					    IBT_FAILURE_IBTL, 0));
252 				}
253 			} /* end of if */
254 		} /* end of while */
255 
256 		ibt_hca = ibt_hca->ha_clnt_link;
257 	} /* End of while */
258 	mutex_exit(&ibtl_clnt_list_mutex);
259 
260 	kmem_free(ret_apid, IBTL_IBNEX_APID_LEN);
261 
262 	/* Pack all data into "buffer" */
263 	if (nvlist_pack(nvl, buffer, bufsiz, NV_ENCODE_NATIVE, KM_SLEEP)) {
264 		IBTF_DPRINTF_L2(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
265 		    "nvlist_pack failed");
266 		nvlist_free(nvl);
267 		return (ibt_get_module_failure(IBT_FAILURE_IBTL, 0));
268 	}
269 
270 	IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_get_hca_info: size = %x",
271 	    *bufsiz);
272 	nvlist_free(nvl);
273 	return (IBT_SUCCESS);
274 }
275 
276 
277 /*
278  * Function:
279  *	ibtl_ibnex_register_callback()
280  * Input:
281  *	ibnex_cb	- IB nexus driver callback routine
282  * Output:
283  *	none
284  * Returns:
285  *	none
286  * Description:
287  *	Register a callback routine for IB nexus driver
288  */
289 void
290 ibtl_ibnex_register_callback(ibtl_ibnex_callback_t ibnex_cb)
291 {
292 	IBTF_DPRINTF_L5(ibtl_ibnex, "ibtl_ibnex_register_callback:");
293 
294 	mutex_enter(&ibtl_clnt_list_mutex);
295 	ibtl_ibnex_callback_routine = ibnex_cb;
296 	mutex_exit(&ibtl_clnt_list_mutex);
297 }
298 
299 /*
300  * Function:
301  *	ibtl_ibnex_unregister_callback()
302  * Input:
303  *	none
304  * Output:
305  *	none
306  * Returns:
307  *	none
308  * Description:
309  *	Un-register a callback routine for IB nexus driver
310  */
311 void
312 ibtl_ibnex_unregister_callback()
313 {
314 	IBTF_DPRINTF_L5(ibtl_ibnex, "ibtl_ibnex_unregister_callback: ibnex cb");
315 
316 	mutex_enter(&ibtl_clnt_list_mutex);
317 	ibtl_ibnex_callback_routine = NULL;
318 	mutex_exit(&ibtl_clnt_list_mutex);
319 }
320 
321 
322 /*
323  * Function:
324  *	ibtl_ibnex_hcadip2guid
325  * Input:
326  *	dev_info_t	- The "dip" of this HCA
327  * Output:
328  *	hca_guid	- The HCA's node GUID.
329  * Returns:
330  *	"HCA GUID" on SUCCESS, NULL on FAILURE
331  * Description:
332  *      For a given HCA node GUID it figures out the HCA GUID
333  *	and returns it. If not found, NULL is returned.
334  */
335 ib_guid_t
336 ibtl_ibnex_hcadip2guid(dev_info_t *hca_dip)
337 {
338 	ib_guid_t		hca_guid = 0LL;
339 	ibtl_hca_devinfo_t	*hca_devp;
340 
341 	mutex_enter(&ibtl_clnt_list_mutex);
342 	hca_devp = ibtl_hca_list;
343 
344 	while (hca_devp) {
345 		if (hca_devp->hd_hca_dip == hca_dip) {
346 			hca_guid = hca_devp->hd_hca_attr->hca_node_guid;
347 			break;
348 		}
349 		hca_devp = hca_devp->hd_hca_dev_link;
350 	}
351 	mutex_exit(&ibtl_clnt_list_mutex);
352 	IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_hcadip_guid: hca_guid 0x%llX",
353 	    hca_guid);
354 	return (hca_guid);
355 }
356 
357 
358 /*
359  * Function:
360  *	ibtl_ibnex_hcaguid2dip
361  * Input:
362  *	hca_guid	- The HCA's node GUID.
363  * Output:
364  *	dev_info_t	- The "dip" of this HCA
365  * Returns:
366  *	"dip" on SUCCESS, NULL on FAILURE
367  * Description:
368  *      For a given HCA node GUID it figures out the "dip"
369  *	and returns it. If not found, NULL is returned.
370  */
371 dev_info_t *
372 ibtl_ibnex_hcaguid2dip(ib_guid_t hca_guid)
373 {
374 	dev_info_t		*dip = NULL;
375 	ibtl_hca_devinfo_t	*hca_devp;
376 
377 	IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_hcaguid2dip:");
378 
379 	mutex_enter(&ibtl_clnt_list_mutex);
380 	hca_devp = ibtl_hca_list;
381 
382 	while (hca_devp) {
383 		if (hca_devp->hd_hca_attr->hca_node_guid == hca_guid) {
384 			dip = hca_devp->hd_hca_dip;
385 			break;
386 		}
387 		hca_devp = hca_devp->hd_hca_dev_link;
388 	}
389 	mutex_exit(&ibtl_clnt_list_mutex);
390 	return (dip);
391 }
392 
393 
394 /*
395  * Function:
396  *	ibtl_ibnex_get_hca_verbose_data
397  * Input:
398  *	hca_guid	- The HCA's node GUID.
399  * Output:
400  *	buffer		- The information is returned in this buffer
401  *      bufsiz		- The size of the information buffer
402  * Returns:
403  *	IBT_SUCCESS/IBT_HCA_INVALID
404  * Description:
405  *      For a given HCA node GUID it figures out the verbose listing display.
406  */
407 ibt_status_t
408 ibtl_ibnex_get_hca_verbose_data(ib_guid_t hca_guid, char **buffer,
409     size_t *bufsiz)
410 {
411 	char			path[IBTL_IBNEX_STR_LEN];
412 	char			tmp[MAXPATHLEN];
413 	uint_t			ii;
414 	ibt_hca_portinfo_t	*pinfop;
415 	ibtl_hca_devinfo_t	*hca_devp;
416 
417 	IBTF_DPRINTF_L3(ibtl_ibnex, "ibtl_ibnex_get_hca_verbose_data: "
418 	    "HCA GUID 0x%llX", hca_guid);
419 
420 	*buffer = NULL;
421 	*bufsiz = 0;
422 
423 	mutex_enter(&ibtl_clnt_list_mutex);
424 	if ((hca_devp = ibtl_get_hcadevinfo(hca_guid)) == NULL) {
425 		mutex_exit(&ibtl_clnt_list_mutex);
426 
427 		/*
428 		 * If we are here, then the requested HCA device is not
429 		 * present. Return the status as Invalid HCA GUID.
430 		 */
431 		IBTF_DPRINTF_L2(ibtl_ibnex, "ibtl_ibnex_get_hca_verbose_data: "
432 		    "HCA Not Found, Invalid HCA GUID");
433 		return (IBT_HCA_INVALID);
434 	}
435 
436 	(void) snprintf(tmp, MAXPATHLEN, "VID: 0x%x, PID: 0x%x, #ports: 0x%x",
437 	    hca_devp->hd_hca_attr->hca_vendor_id,
438 	    hca_devp->hd_hca_attr->hca_device_id,
439 	    hca_devp->hd_hca_attr->hca_nports);
440 
441 	pinfop = hca_devp->hd_portinfop;
442 	for (ii = 0; ii < hca_devp->hd_hca_attr->hca_nports; ii++) {
443 		(void) snprintf(path, IBTL_IBNEX_STR_LEN,
444 		    ", port%d GUID: 0x%llX", ii + 1,
445 		    (longlong_t)pinfop[ii].p_sgid_tbl->gid_guid);
446 		(void) strcat(tmp, path);
447 	}
448 	mutex_exit(&ibtl_clnt_list_mutex);
449 
450 	*bufsiz =  strlen(tmp);
451 	*buffer = kmem_alloc(*bufsiz, KM_SLEEP);
452 	(void) strncpy(*buffer, tmp, *bufsiz);
453 
454 	IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_get_hca_verbose_data: "
455 	    "data = %s, size = 0x%x", *buffer, *bufsiz);
456 	return (IBT_SUCCESS);
457 }
458 
459 /*
460  * Function:
461  *	ibt_reprobe_dev()
462  * Input:
463  *	dev_info_t	*dip
464  * Output:
465  *	none
466  * Returns:
467  *      Return value from IBnexus callback handler
468  *		IBT_ILLEGAL_OP if IBnexus callback is not installed.
469  * Description:
470  *		This function passes the IBTF client's "reprobe device
471  *		properties" request to IBnexus. See ibt_reprobe_dev(9f)
472  *		for details.
473  */
474 ibt_status_t
475 ibt_reprobe_dev(dev_info_t *dip)
476 {
477 	ibt_status_t		rv;
478 	ibtl_ibnex_cb_args_t	cb_args;
479 
480 	if (dip == NULL)
481 		return (IBT_NOT_SUPPORTED);
482 
483 	/*
484 	 * Restricting the reprobe request to the children of
485 	 * ibnexus. Note the IB_CONF_UPDATE_EVENT DDI event can
486 	 * be subscribed by any device on the IBnexus device tree.
487 	 */
488 	if (strcmp(ddi_node_name(ddi_get_parent(dip)), "ib") != 0)
489 		return (IBT_NOT_SUPPORTED);
490 
491 	/* Reprobe for IOC nodes only */
492 	if (strncmp(ddi_node_name(dip), IBNEX_IBPORT_CNAME, 6) == 0)
493 		return (IBT_NOT_SUPPORTED);
494 
495 	cb_args.cb_flag = IBTL_IBNEX_REPROBE_DEV_REQ;
496 	cb_args.cb_dip = dip;
497 	mutex_enter(&ibtl_clnt_list_mutex);
498 	if (ibtl_ibnex_callback_routine) {
499 		rv = (*ibtl_ibnex_callback_routine)(&cb_args);
500 		mutex_exit(&ibtl_clnt_list_mutex);
501 		return (rv);
502 	}
503 	mutex_exit(&ibtl_clnt_list_mutex);
504 
505 	/* Should -not- come here */
506 	IBTF_DPRINTF_L2("ibtl", "ibt_reprobe_dev: ibnex not registered!!");
507 	return (IBT_ILLEGAL_OP);
508 }
509 
510 
511 /*
512  * Function:
513  *	ibtl_ibnex_valid_hca_parent
514  * Input:
515  *	pdip		- The parent dip from client's child dev_info_t
516  * Output:
517  *	NONE
518  * Returns:
519  *	IBT_SUCCESS/IBT_NO_HCAS_AVAILABLE
520  * Description:
521  *	For a given pdip, of Port/VPPA devices, match it against all the
522  *	registered HCAs's dip.  If match found return IBT_SUCCESS,
523  *	else IBT_NO_HCAS_AVAILABLE.
524  *
525  *	For IOC/Pseudo devices check if the given pdip is that of
526  *	the ib(4D) nexus or that of the eoib(4D) nexus. If yes
527  *	return IBT_SUCCESS, else IBT_NO_HCAS_AVAILABLE.
528  */
529 ibt_status_t
530 ibtl_ibnex_valid_hca_parent(dev_info_t *pdip)
531 {
532 	ibtl_hca_devinfo_t	*hca_devp;
533 
534 	IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_valid_hca_parent: pdip %p",
535 	    pdip);
536 
537 	/* For Pseudo devices and IOCs */
538 	if (strncmp(ddi_node_name(pdip), "ib", 2) == 0 ||
539 	    strncmp(ddi_node_name(pdip), "eibnx", 5) == 0) {
540 		return (IBT_SUCCESS);
541 	} else {
542 		/* For Port devices and VPPAs */
543 		mutex_enter(&ibtl_clnt_list_mutex);
544 		hca_devp = ibtl_hca_list;
545 		while (hca_devp) {
546 			if (hca_devp->hd_hca_dip == pdip) {
547 				mutex_exit(&ibtl_clnt_list_mutex);
548 				return (IBT_SUCCESS);
549 			}
550 			hca_devp = hca_devp->hd_hca_dev_link;
551 		}
552 		mutex_exit(&ibtl_clnt_list_mutex);
553 		return (IBT_NO_HCAS_AVAILABLE);
554 	}
555 }
556 
557 /*
558  * Function:
559  *	ibtl_ibnex_phci_register
560  * Input:
561  *	hca_dip		- The HCA dip
562  * Output:
563  *	NONE
564  * Returns:
565  *	IBT_SUCCESS/IBT_FAILURE
566  * Description:
567  *	Register the HCA dip as the MPxIO PCHI.
568  */
569 ibt_status_t
570 ibtl_ibnex_phci_register(dev_info_t *hca_dip)
571 {
572 	/* Register the with MPxIO as PHCI */
573 	if (mdi_phci_register(MDI_HCI_CLASS_IB, hca_dip, 0) !=
574 	    MDI_SUCCESS) {
575 		return (IBT_FAILURE);
576 	}
577 	return (IBT_SUCCESS);
578 }
579 
580 /*
581  * Function:
582  *	ibtl_ibnex_phci_unregister
583  * Input:
584  *	hca_dip		- The HCA dip
585  * Output:
586  *	NONE
587  * Returns:
588  *	IBT_SUCCESS/IBT_FAILURE
589  * Description:
590  *	Free up any pending MPxIO Pathinfos and unregister the HCA dip as the
591  *	MPxIO PCHI.
592  */
593 ibt_status_t
594 ibtl_ibnex_phci_unregister(dev_info_t *hca_dip)
595 {
596 	mdi_pathinfo_t *pip = NULL;
597 	dev_info_t *vdip = 0;
598 
599 	/*
600 	 * Should free all the Pathinfos associated with the HCA pdip before
601 	 * unregistering the PHCI.
602 	 *
603 	 * mdi_pi_free will call ib_vhci_pi_uninit() callbackfor each PI where
604 	 * the ibnex internal datastructures (ibnex_node_data) will have to be
605 	 * cleaned up if needed.
606 	 */
607 	vdip = mdi_devi_get_vdip(hca_dip);
608 	ndi_devi_enter(vdip);
609 	ndi_devi_enter(hca_dip);
610 	while (pip = mdi_get_next_client_path(hca_dip, NULL)) {
611 		if (mdi_pi_free(pip, 0) == MDI_SUCCESS) {
612 			continue;
613 		}
614 		ndi_devi_exit(hca_dip);
615 		ndi_devi_exit(vdip);
616 		IBTF_DPRINTF_L1(ibtl_ibnex, "ibtl_ibnex_phci_unregister: "
617 		    "mdi_pi_free failed");
618 		return (IBT_FAILURE);
619 	}
620 	ndi_devi_exit(hca_dip);
621 	ndi_devi_exit(vdip);
622 
623 	if (mdi_phci_unregister(hca_dip, 0) != MDI_SUCCESS) {
624 		IBTF_DPRINTF_L1(ibtl_ibnex, "ibtl_ibnex_phci_unregister: PHCI "
625 		    "unregister failed");
626 		return (IBT_FAILURE);
627 	}
628 	return (IBT_SUCCESS);
629 }
630 
631 /*
632  * Function:
633  *	ibtl_ibnex_query_hca_byguid
634  * Input:
635  *	hca_guid	- The HCA's node GUID.
636  *	driver_name_size- size of the caller allocated driver_name buffer
637  * Output:
638  *	hca_attrs	- caller allocated buffer which will contain
639  *			  HCA attributes upon success
640  *	driver_name	- caller allocated buffer which will contain
641  *			  HCA driver name upon success
642  *	driver_instance - HCA driver instance
643  *	hca_device_path	- caller allocated buffer of size MAXPATHLEN which
644  *			  will contain hca device path upon success.
645  * Returns:
646  *	IBT_SUCCESS/IBT_FAILURE
647  * Description:
648  *	Get the HCA attributes, driver name and instance number of the
649  *	specified HCA.
650  */
651 ibt_status_t
652 ibtl_ibnex_query_hca_byguid(ib_guid_t hca_guid, ibt_hca_attr_t *hca_attrs,
653     char *driver_name, size_t driver_name_size, int *driver_instance,
654     char *hca_device_path)
655 {
656 	ibtl_hca_devinfo_t	*hca_devp;
657 
658 	IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_query_hca_byguid("
659 	    "hca_guid = 0x%llx, hca_attrs = 0x%p, driver_name = 0x%p, "
660 	    "driver_name_size = 0x%d, driver_instancep = 0x%p)", hca_guid,
661 	    hca_attrs, driver_name, (int)driver_name_size, driver_instance);
662 
663 	mutex_enter(&ibtl_clnt_list_mutex);
664 
665 	hca_devp = ibtl_get_hcadevinfo(hca_guid);
666 	if (hca_devp == NULL) {
667 		mutex_exit(&ibtl_clnt_list_mutex);
668 		return (IBT_HCA_INVALID);
669 	}
670 
671 	if (strlcpy(driver_name,
672 	    ddi_driver_name(hca_devp->hd_hca_dip), driver_name_size) >=
673 	    driver_name_size) {
674 		mutex_exit(&ibtl_clnt_list_mutex);
675 		return (IBT_INSUFF_KERNEL_RESOURCE);
676 	}
677 
678 	(void) ddi_pathname(hca_devp->hd_hca_dip, hca_device_path);
679 	*driver_instance = ddi_get_instance(hca_devp->hd_hca_dip);
680 	bcopy(hca_devp->hd_hca_attr, hca_attrs, sizeof (ibt_hca_attr_t));
681 
682 	mutex_exit(&ibtl_clnt_list_mutex);
683 	return (IBT_SUCCESS);
684 }
685