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