xref: /illumos-gate/usr/src/uts/common/io/ib/ibnex/ibnex_ioctl.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 /*
28  * This file contains support required for IB cfgadm plugin.
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 
34 #include <sys/conf.h>
35 #include <sys/stat.h>
36 #include <sys/modctl.h>
37 #include <sys/ib/mgt/ibdm/ibdm_impl.h>
38 #include <sys/ib/ibnex/ibnex.h>
39 #include <sys/ib/ibnex/ibnex_devctl.h>
40 #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
41 #include <sys/file.h>
42 #include <sys/sunndi.h>
43 #include <sys/fs/dv_node.h>
44 #include <sys/mdi_impldefs.h>
45 #include <sys/sunmdi.h>
46 
47 /*
48  * function prototypes
49  */
50 int			ibnex_open(dev_t *, int, int, cred_t *);
51 int			ibnex_close(dev_t, int, int, cred_t *);
52 int			ibnex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
53 int			ibnex_offline_childdip(dev_info_t *);
54 static int		ibnex_get_num_devices(void);
55 static int		ibnex_get_snapshot(char **, size_t *, int);
56 static int		ibnex_get_commsvcnode_snapshot(nvlist_t **, ib_guid_t,
57 			    ib_guid_t, int, ib_pkey_t, ibnex_node_type_t);
58 static int		ibnex_fill_ioc_tmp(nvlist_t **, ibdm_ioc_info_t *);
59 static int		ibnex_fill_nodeinfo(nvlist_t **, ibnex_node_data_t *,
60 			    void *);
61 static void		ibnex_figure_ap_devstate(dev_info_t *,
62 			    devctl_ap_state_t *);
63 static void		ibnex_figure_ib_apid_devstate(devctl_ap_state_t *);
64 static	char 		*ibnex_get_apid(struct devctl_iocdata *);
65 static int		ibnex_get_dip_from_apid(char *, dev_info_t **,
66 			    ibnex_node_data_t **);
67 static ibnex_rval_t	ibnex_handle_pseudo_configure(char *);
68 static ibnex_rval_t	ibnex_handle_ioc_configure(char *);
69 static ibnex_rval_t	ibnex_handle_commsvcnode_configure(char *);
70 static void		ibnex_return_apid(dev_info_t *, char **);
71 static void		ibnex_port_conf_entry_add(char *);
72 static void		ibnex_vppa_conf_entry_add(char *);
73 static void		ibnex_hcasvc_conf_entry_add(char *);
74 static int		ibnex_port_conf_entry_delete(char *, char *);
75 static int		ibnex_vppa_conf_entry_delete(char *, char *);
76 static int		ibnex_hcasvc_conf_entry_delete(char *, char *);
77 
78 static ibnex_rval_t	ibnex_ioc_fininode(dev_info_t *, ibnex_ioc_node_t *);
79 static ibnex_rval_t	ibnex_commsvc_fininode(dev_info_t *);
80 static ibnex_rval_t	ibnex_pseudo_fininode(dev_info_t *);
81 
82 extern uint64_t		ibnex_str2hex(char *, int, int *);
83 extern int		ibnex_ioc_initnode(ibdm_ioc_info_t *, int);
84 extern dev_info_t	*ibnex_commsvc_initnode(dev_info_t *,
85 			    ibdm_port_attr_t *, int, int, ib_pkey_t, int *,
86 			    int);
87 extern int		ibnex_get_dip_from_guid(ib_guid_t, int,
88 			    ib_pkey_t, dev_info_t **);
89 extern void		ibnex_reprobe_ioc_dev(void *arg);
90 extern void		ibnex_reprobe_ioc_all();
91 extern int		ibnex_pseudo_create_pi(ibnex_node_data_t *);
92 extern void		ibnex_pseudo_initnodes(void);
93 
94 extern ibnex_t	ibnex;
95 
96 /*
97  * ibnex_open()
98  */
99 /* ARGSUSED */
100 int
101 ibnex_open(dev_t *dev, int flag, int otyp, cred_t *credp)
102 {
103 	IBTF_DPRINTF_L4("ibnex", "\topen");
104 	return (0);
105 }
106 
107 
108 /*
109  * ibnex_close()
110  */
111 /* ARGSUSED */
112 int
113 ibnex_close(dev_t dev, int flag, int otyp, cred_t *credp)
114 {
115 	IBTF_DPRINTF_L4("ibnex", "\tclose");
116 	return (0);
117 }
118 
119 
120 /*
121  * ibnex_ioctl()
122  *	Ioctl routine for cfgadm controls
123  *	DEVCTL_AP_GETSTATE:	returns attachment point state
124  *	DEVCTL_AP_CONTROL:	Does "ibnex" specific ioctls listed below
125  *		IBNEX_NUM_DEVICE_NODES	Gives how many device nodes exist?
126  *		IBNEX_NUM_HCA_NODES	Gives how many HCAs exist in the fabric
127  *		IBNEX_UPDATE_PKEY_TBLS	"-x update_pkey_tbls"
128  *		IBNEX_GET_SNAPSHOT	Gets the "snapshot" back to user-land
129  *		IBNEX_SNAPSHOT_SIZE	What is "snapshot" size
130  *		IBNEX_DEVICE_PATH_SZ	What is device-path size
131  *		IBNEX_GET_DEVICE_PATH	Gets the device path for Dynamic ap
132  *		IBNEX_HCA_LIST_SZ	"-x list" option size for the HCA ap_id
133  *		IBNEX_HCA_LIST_INFO	"-x list" option info for the HCA ap_id
134  *		IBNEX_UNCFG_CLNTS_SZ	"-x unconfig_client option size"
135  *		IBNEX_UNCFG_CLNTS_INFO	"-x unconfig_client data"
136  *		IBNEX_CONF_ENTRY_ADD:	"-x add_service"
137  *		IBNEX_CONF_ENTRY_DEL:	"-x delete_service"
138  *		IBNEX_HCA_VERBOSE_SZ:	"-alv hca_apid data size"
139  *		IBNEX_HCA_VERBOSE_INFO: "-alv hca_apid actual data"
140  *		IBNEX_UPDATE_IOC_CONF	"-x update_ioc_conf"
141  *	DEVCTL_AP_CONFIGURE:	"configure" the attachment point
142  *	DEVCTL_AP_UNCONFIGURE:	"unconfigure" the attachment point
143  */
144 /* ARGSUSED */
145 int
146 ibnex_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
147     int *rvalp)
148 {
149 	int			ret, rv = 0, ioc_reprobe_pending = 0;
150 	int			circ;
151 	char			*snapshot = NULL;
152 	char			*apid_n = NULL;
153 	char			*service = NULL;
154 	char			*devnm = NULL;
155 	char			*msg;
156 	char			*guid_str;
157 	uint_t			num_hcas = 0;
158 	size_t			snapshot_sz  = 0;
159 	uint32_t		ssiz;
160 	uint32_t		apid_len;
161 	ib_guid_t		hca_guid;
162 	boolean_t		apid_alloced = B_FALSE;
163 	dev_info_t		*apid_dip = NULL;
164 	dev_info_t		*pdip;
165 	ibnex_rval_t		ret_val;
166 	ib_service_type_t	svc_type = IB_NONE;
167 	devctl_ap_state_t	ap_state;
168 	ibnex_node_data_t	*nodep, *scanp;
169 	struct devctl_iocdata	*dcp = NULL;
170 
171 	IBTF_DPRINTF_L4("ibnex", "\tioctl: cmd=%x, arg=%p, mode=%x, cred=%p, "
172 	    "\t\trval=%p dev=0x%x", cmd, arg, mode, credp, rvalp, dev);
173 
174 	/* read devctl ioctl data */
175 	if ((cmd != DEVCTL_AP_CONTROL) &&
176 	    (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)) {
177 		IBTF_DPRINTF_L4("ibnex",
178 		    "\tioctl: ndi_dc_allochdl failed\n");
179 		return (EFAULT);
180 	}
181 
182 	mutex_enter(&ibnex.ibnex_mutex);
183 	switch (cmd) {
184 	case DEVCTL_AP_GETSTATE:
185 		msg = "\tioctl: DEVCTL_AP_GETSTATE";
186 		IBTF_DPRINTF_L4("ibnex", "%s:", msg);
187 
188 		apid_n = ibnex_get_apid(dcp);
189 		if (*apid_n == '\0') {
190 			IBTF_DPRINTF_L2("ibnex",
191 			    "%s: ibnex_get_apid failed", msg);
192 			rv = EIO;
193 			break;
194 		}
195 
196 		if (strncmp(apid_n, IBNEX_FABRIC, strlen(IBNEX_FABRIC)) == 0) {
197 			ibnex_figure_ib_apid_devstate(&ap_state);
198 			apid_dip = ibnex.ibnex_dip;
199 		} else {
200 			/* if this apid is already seen by IBNEX, get the dip */
201 			rv = ibnex_get_dip_from_apid(apid_n, &apid_dip, &nodep);
202 			if (rv != IBNEX_DYN_APID) {
203 				IBTF_DPRINTF_L2("ibnex",
204 				    "%s: ibnex_get_dip_from_apid failed", msg);
205 				rv = EIO;
206 				break;
207 			}
208 			if (apid_dip)
209 				ndi_rele_devi(apid_dip);
210 			/* rv could be something undesirable, so reset it */
211 			rv = 0;
212 
213 			ibnex_figure_ap_devstate(apid_dip, &ap_state);
214 		}
215 
216 		/* copy the return-AP-state information to the user space */
217 		if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS) {
218 			IBTF_DPRINTF_L2("ibnex",
219 			    "%s: ndi_dc_return_ap_state failed", msg);
220 			rv = EFAULT;
221 		}
222 		break;
223 
224 	case DEVCTL_AP_CONTROL:
225 	{
226 		int			num_nodes = 0;
227 		ibnex_ioctl_data_t	ioc;	/* for 64-bit copies only */
228 
229 		msg = "\tioctl: DEVCTL_AP_CONTROL";
230 #ifdef	_MULTI_DATAMODEL
231 		if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
232 			ibnex_ioctl_data_32_t ioc32;
233 
234 			if (ddi_copyin((void *)arg, &ioc32,
235 			    sizeof (ioc32), mode) != 0) {
236 				IBTF_DPRINTF_L2("ibnex",
237 				    "%s: ddi_copyin err 1", msg);
238 				rv = EFAULT;
239 				break;
240 			}
241 			ioc.cmd		= (uint_t)ioc32.cmd;
242 			ioc.buf		= (caddr_t)(uintptr_t)ioc32.buf;
243 			ioc.bufsiz	= (uint_t)ioc32.bufsiz;
244 			ioc.ap_id	= (caddr_t)(uintptr_t)ioc32.ap_id;
245 			ioc.ap_id_len	= (uint_t)ioc32.ap_id_len;
246 			ioc.misc_arg	= (uint_t)ioc32.misc_arg;
247 		}
248 #else
249 		if (ddi_copyin((void *)arg, &ioc, sizeof (ioc),
250 		    mode) != 0) {
251 			IBTF_DPRINTF_L2("ibnex",
252 			    "%s: ddi_copyin 2 failed", msg);
253 			rv = EFAULT;
254 			break;
255 		}
256 #endif	/* _MULTI_DATAMODEL */
257 
258 		IBTF_DPRINTF_L4("ibnex", "%s: \n\tioc: cmd=%x buf=%p, "
259 		    "bufsiz=%d", msg, ioc.cmd, ioc.buf, ioc.bufsiz);
260 
261 		/*
262 		 * figure out ap_id name as passed from user-land
263 		 * NOTE: We don't need to figure out ap_id for these
264 		 * two sub-commands:-
265 		 *	IBNEX_NUM_DEVICE_NODES, IBNEX_NUM_HCA_NODES
266 		 *
267 		 * Hence, In user-land, these two ioctls force "ap_id_len" to 0.
268 		 */
269 		if (ioc.ap_id_len > 0) {
270 			apid_alloced = B_TRUE;
271 			apid_len = ioc.ap_id_len + 1;
272 			apid_n = kmem_zalloc(apid_len, KM_SLEEP);
273 			if (ddi_copyin((void *)ioc.ap_id, apid_n,
274 			    ioc.ap_id_len, mode) != 0) {
275 				IBTF_DPRINTF_L2("ibnex",
276 				    "%s: ddi_copyin err 3", msg);
277 				rv = EFAULT;
278 				break;
279 			}
280 
281 			IBTF_DPRINTF_L3("ibnex", "%s: apid_n= %s", msg, apid_n);
282 		}
283 
284 
285 		/* process sub-commands */
286 		switch (ioc.cmd) {
287 		case IBNEX_NUM_DEVICE_NODES:
288 			msg = "\tioctl: DEVCTL_AP_CONTROL: NUM_DEVICE_NODES";
289 
290 			/*
291 			 * figure out how many IOC, VPPA,
292 			 * Pseudo and Port nodes are present
293 			 */
294 			num_nodes = ibnex_get_num_devices();
295 			IBTF_DPRINTF_L4("ibnex", "%s: num_nodes = %d",
296 			    msg, num_nodes);
297 
298 			if (ddi_copyout(&num_nodes, ioc.buf,
299 			    ioc.bufsiz, mode) != 0) {
300 				IBTF_DPRINTF_L2("ibnex", "%s: copyout", msg);
301 				rv = EIO;
302 			}
303 			mutex_exit(&ibnex.ibnex_mutex);
304 			return (rv);
305 
306 		case IBNEX_NUM_HCA_NODES:
307 			msg = "\tioctl: DEVCTL_AP_CONTROL: NUM_HCA_NODES";
308 
309 			/* figure out how many HCAs are present in the host */
310 			mutex_exit(&ibnex.ibnex_mutex);
311 			num_hcas = ibt_get_hca_list(NULL);
312 			IBTF_DPRINTF_L4("ibnex", "%s: num %d", msg, num_hcas);
313 
314 			if (ddi_copyout(&num_hcas, ioc.buf,
315 			    ioc.bufsiz, mode) != 0) {
316 				IBTF_DPRINTF_L2("ibnex", "%s: copyout", msg);
317 				rv = EIO;
318 			}
319 			return (rv);
320 
321 		case IBNEX_UPDATE_PKEY_TBLS:
322 			msg = "\tioctl: DEVCTL_AP_CONTROL: UPDATE_PKEY_TBLS";
323 			IBTF_DPRINTF_L4("ibnex", "%s", msg);
324 
325 			/*
326 			 * update P_Key tables:
327 			 *	ibdm_ibnex_update_pkey_tbls() calls
328 			 *	ibt_query_hca_ports_byguids() for all the
329 			 *	HCAs that the IBDM has "seen" in the system.
330 			 *	This ends up updating the IBTL P_Key database.
331 			 *	NOTE: Changes in this area will break this
332 			 *	assumption. Initially the plan was to call
333 			 *	ibt_query_hca_ports_byguids() in IBTL but
334 			 *	IBDM needs to call it as well. So, eliminating
335 			 *	the first invocation.
336 			 *
337 			 *	It next updates the DM P_Key database.
338 			 *	Note that the DM P_Key database updating
339 			 *	will always be driven through cfgadm.
340 			 */
341 			mutex_exit(&ibnex.ibnex_mutex);
342 			ibdm_ibnex_update_pkey_tbls();
343 			mutex_enter(&ibnex.ibnex_mutex);
344 			break;
345 
346 		case IBNEX_GET_SNAPSHOT:
347 		case IBNEX_SNAPSHOT_SIZE:
348 			msg = (ioc.cmd == IBNEX_SNAPSHOT_SIZE) ?
349 			    "\tioctl: DEVCTL_AP_CONTROL: IBNEX_SNAPSHOT_SIZE" :
350 			    "\tioctl: DEVCTL_AP_CONTROL: IBNEX_GET_SNAPSHOT";
351 
352 			IBTF_DPRINTF_L4("ibnex", "%s:", msg);
353 
354 			if (ibnex_get_snapshot(&snapshot, &snapshot_sz,
355 			    ioc.misc_arg) != 0) {
356 				IBTF_DPRINTF_L2("ibnex",
357 				    "%s:\n\tibnex_get_snapshot failed", msg);
358 				rv = EIO;
359 				break;
360 			}
361 
362 			/* ssiz needs to be reinitialized again */
363 			ssiz = snapshot_sz;
364 			IBTF_DPRINTF_L4("ibnex",
365 			    "%s:\n\tsize =%x", msg, snapshot_sz);
366 
367 			if (ioc.cmd == IBNEX_SNAPSHOT_SIZE) {
368 				if (ddi_copyout(&ssiz, ioc.buf,
369 				    ioc.bufsiz, mode) != 0) {
370 					IBTF_DPRINTF_L2("ibnex",
371 					    "%s:\n\tddi_copyout 2 failed", msg);
372 					rv = EFAULT;
373 				}
374 
375 			} else {
376 				if (ioc.bufsiz != snapshot_sz) {
377 					IBTF_DPRINTF_L2("ibnex",
378 					    "%s:\n\tinvalid buffer size (%x %x)"
379 					    " ", msg, ioc.bufsiz, snapshot_sz);
380 					rv = EINVAL;
381 
382 				} else if (ddi_copyout(snapshot, ioc.buf,
383 				    ioc.bufsiz, mode) != 0) {
384 					IBTF_DPRINTF_L2("ibnex",
385 					    "%s:\n\tddi_copyout 3 failed", msg);
386 					rv = EFAULT;
387 				}
388 			}
389 
390 			kmem_free(snapshot, snapshot_sz);
391 			break;
392 
393 		case IBNEX_DEVICE_PATH_SZ:
394 		case IBNEX_GET_DEVICE_PATH:
395 		{
396 			char	 path[MAXPATHLEN];
397 
398 			msg = (ioc.cmd == IBNEX_DEVICE_PATH_SZ) ?
399 			    "\tioctl:DEVCTL_AP_CONTROL: IBNEX_DEVICE_PATH_SZ" :
400 			    "\tioctl:DEVCTL_AP_CONTROL: IBNEX_GET_DEVICE_PATH";
401 
402 			IBTF_DPRINTF_L4("ibnex", "%s: apid = %s", msg, apid_n);
403 
404 			/* if this apid is already seen by IBNEX, get the dip */
405 			rv = ibnex_get_dip_from_apid(apid_n, &apid_dip, &nodep);
406 			if (rv != IBNEX_DYN_APID || apid_dip == NULL) {
407 				IBTF_DPRINTF_L2("ibnex",
408 				    "%s:\n\tget_dip_from_apid failed", msg);
409 				rv = EIO;
410 				break;
411 			}
412 			ndi_rele_devi(apid_dip);
413 
414 			/* ddi_pathname doesn't supply /devices, so we do. */
415 			(void) strcpy(path, "/devices");
416 			(void) ddi_pathname(apid_dip, path + strlen(path));
417 			ssiz = (uint32_t)strlen(path) + 1;
418 			IBTF_DPRINTF_L4("ibnex",
419 			    "%s: len = %x\n\tpath = %s", msg, ssiz, path);
420 
421 			/* rv could be something undesirable, so reset it */
422 			rv = 0;
423 
424 			if (ioc.cmd == IBNEX_DEVICE_PATH_SZ) {
425 				if (ddi_copyout(&ssiz, ioc.buf,
426 				    ioc.bufsiz, mode) != 0) {
427 					IBTF_DPRINTF_L2("ibnex",
428 					    "%s: ddi_copyout 4 failed", msg);
429 					rv = EFAULT;
430 				}
431 
432 			} else {
433 				if (ioc.bufsiz != ssiz) {
434 					IBTF_DPRINTF_L2("ibnex",
435 					    "%s: invalid size (%x, %x)",
436 					    msg, ioc.bufsiz, ssiz);
437 					rv = EINVAL;
438 				} else if (ddi_copyout(&path, ioc.buf,
439 				    ioc.bufsiz, mode) != 0) {
440 					IBTF_DPRINTF_L2("ibnex", "%s "
441 					    "ddi_copyout 5 failed", msg);
442 					rv = EFAULT;
443 				}
444 			}
445 			break;
446 		}
447 
448 		case IBNEX_HCA_LIST_SZ:
449 		case IBNEX_HCA_LIST_INFO:
450 			msg = (ioc.cmd == IBNEX_HCA_LIST_SZ) ?
451 			    "DEVCTL_AP_CONTROL: IBNEX_HCA_LIST_SZ" :
452 			    "DEVCTL_AP_CONTROL: IBNEX_HCA_LIST_INFO";
453 
454 			guid_str = strrchr(apid_n, ':') + 1;
455 			IBTF_DPRINTF_L4("ibnex", "%s, input apid = %s, "
456 			    "guid = %s", msg, apid_n, guid_str);
457 
458 			if (guid_str == NULL) {
459 				IBTF_DPRINTF_L2("ibnex", "%s: invalid input "
460 				    "GUID passed %s", msg, guid_str);
461 				rv = EFAULT;
462 				break;
463 			}
464 
465 			/* Get the GUID(hex value) from apid_n */
466 			hca_guid = ibnex_str2hex(guid_str, strlen(guid_str),
467 			    &ret);
468 			if (ret != IBNEX_SUCCESS) {
469 				IBTF_DPRINTF_L2("ibnex", "%s: Invalid HCA "
470 				    "GUID string", msg);
471 				rv = EIO;
472 				break;
473 			}
474 			IBTF_DPRINTF_L4("ibnex", "%s HCA GUID = %llX",
475 			    msg, hca_guid);
476 			if (ibtl_ibnex_get_hca_info(hca_guid,
477 			    IBTL_IBNEX_LIST_CLNTS_FLAG, &snapshot, &snapshot_sz,
478 			    ibnex_return_apid) != IBT_SUCCESS) {
479 				IBTF_DPRINTF_L2("ibnex",
480 				    "%s: get HCA consumers failed", msg);
481 				rv = EIO;
482 				break;
483 			}
484 
485 			ssiz = snapshot_sz;
486 			IBTF_DPRINTF_L4("ibnex", "%s: size =%x", msg, ssiz);
487 
488 			if (ioc.cmd == IBNEX_HCA_LIST_SZ) {
489 				if (ddi_copyout(&ssiz, ioc.buf,
490 				    ioc.bufsiz, mode) != 0) {
491 					IBTF_DPRINTF_L2("ibnex",
492 					    "%s: ddi_copyout 6 failed", msg);
493 					rv = EFAULT;
494 				}
495 			} else {
496 				if (ioc.bufsiz != ssiz) {
497 					IBTF_DPRINTF_L2("ibnex", "%s: invalid "
498 					    "size (%x, %x)", msg, ioc.bufsiz,
499 					    ssiz);
500 					rv = EINVAL;
501 				} else if (ddi_copyout(snapshot, ioc.buf,
502 				    ioc.bufsiz, mode) != 0) {
503 					IBTF_DPRINTF_L2("ibnex", "%s "
504 					    "ddi_copyout 7 failed", msg);
505 					rv = EFAULT;
506 				}
507 			}
508 
509 			kmem_free(snapshot, snapshot_sz);
510 			break;
511 
512 		case IBNEX_UNCFG_CLNTS_SZ:
513 		case IBNEX_UNCFG_CLNTS_INFO:
514 			msg = (ioc.cmd == IBNEX_UNCFG_CLNTS_SZ) ?
515 			    "\tioctl:DEVCTL_AP_CONTROL: IBNEX_UNCFG_CLNTS_SZ" :
516 			    "\tioctl:DEVCTL_AP_CONTROL: IBNEX_UNCFG_CLNTS_INFO";
517 
518 			guid_str = strrchr(apid_n, ':') + 1;
519 			IBTF_DPRINTF_L4("ibnex", "%s, apid = %s, guid = %s",
520 			    msg, apid_n, guid_str);
521 
522 			if (guid_str == NULL) {
523 				IBTF_DPRINTF_L2("ibnex", "%s: invalid input "
524 				    "GUID %s", msg, guid_str);
525 				rv = EFAULT;
526 				break;
527 			}
528 
529 			/* Get the GUID(hex value) from apid_n */
530 			hca_guid = ibnex_str2hex(guid_str, strlen(guid_str),
531 			    &ret);
532 			if (ret != IBNEX_SUCCESS) {
533 				IBTF_DPRINTF_L2("ibnex", "%s: Invalid HCA "
534 				    "GUID string passed", msg);
535 				rv = EIO;
536 				break;
537 			}
538 			IBTF_DPRINTF_L4("ibnex", "%s G = %llX", msg, hca_guid);
539 			if (ibtl_ibnex_get_hca_info(hca_guid,
540 			    IBTL_IBNEX_UNCFG_CLNTS_FLAG, &snapshot,
541 			    &snapshot_sz, ibnex_return_apid) != IBT_SUCCESS) {
542 				IBTF_DPRINTF_L2("ibnex",
543 				    "%s: get HCA consumers failed", msg);
544 				rv = EIO;
545 				break;
546 			}
547 			/* ssiz needs to be reinitialized again */
548 			ssiz = snapshot_sz;
549 
550 			IBTF_DPRINTF_L4("ibnex", "%s: size =%x", msg, ssiz);
551 
552 			if (ioc.cmd == IBNEX_UNCFG_CLNTS_SZ) {
553 				if (ddi_copyout(&ssiz, ioc.buf,
554 				    ioc.bufsiz, mode) != 0) {
555 					IBTF_DPRINTF_L2("ibnex",
556 					    "%s: ddi_copyout 9 failed", msg);
557 					rv = EFAULT;
558 				}
559 
560 			} else {
561 				if (ioc.bufsiz != ssiz) {
562 					IBTF_DPRINTF_L2("ibnex",
563 					    "%s: invalid size (%x, %x)",
564 					    msg, ioc.bufsiz, ssiz);
565 					rv = EINVAL;
566 				} else if (ddi_copyout(snapshot, ioc.buf,
567 				    ioc.bufsiz, mode) != 0) {
568 					IBTF_DPRINTF_L2("ibnex", "%s "
569 					    "ddi_copyout 10 failed", msg);
570 					rv = EFAULT;
571 				}
572 			}
573 
574 			kmem_free(snapshot, snapshot_sz);
575 			break;
576 
577 		case IBNEX_CONF_ENTRY_ADD:
578 			msg = "\tioctl: IBNEX_CONF_ENTRY_ADD: ";
579 			service = kmem_zalloc(ioc.bufsiz + 1, KM_SLEEP);
580 			/* read in the "service" name */
581 			if (ddi_copyin(ioc.buf, service,
582 			    ioc.bufsiz, mode) != 0) {
583 				IBTF_DPRINTF_L2("ibnex", "%s: ddi_copyin err 6",
584 				    msg);
585 				rv = EFAULT;
586 				break;
587 			}
588 
589 			/* read in the "service type" */
590 			svc_type = ioc.misc_arg;
591 			IBTF_DPRINTF_L4("ibnex", "%s: service = %s, type = %d",
592 			    msg, service, svc_type);
593 
594 			if (svc_type == IB_PORT_SERVICE) {
595 				ibnex_port_conf_entry_add(service);
596 			} else if (svc_type == IB_VPPA_SERVICE) {
597 				ibnex_vppa_conf_entry_add(service);
598 			} else if (svc_type == IB_HCASVC_SERVICE) {
599 				ibnex_hcasvc_conf_entry_add(service);
600 			}
601 			kmem_free(service, ioc.bufsiz + 1);
602 			break;
603 
604 		case IBNEX_CONF_ENTRY_DEL:
605 			msg = "\tioctl:IBNEX_CONF_ENTRY_DEL: ";
606 			service = kmem_zalloc(ioc.bufsiz + 1, KM_SLEEP);
607 			/* read in the "service" name */
608 			if (ddi_copyin(ioc.buf, service,
609 			    ioc.bufsiz, mode) != 0) {
610 				IBTF_DPRINTF_L2("ibnex", "%s: ddi_copyin err 7",
611 				    msg);
612 				rv = EFAULT;
613 				break;
614 			}
615 
616 			/* read in the "service type" */
617 			svc_type = ioc.misc_arg;
618 			IBTF_DPRINTF_L4("ibnex", "%s: service = %s, type = %d",
619 			    msg, service, svc_type);
620 
621 			if (svc_type == IB_PORT_SERVICE) {
622 				rv = ibnex_port_conf_entry_delete(msg, service);
623 			} else if (svc_type == IB_VPPA_SERVICE) {
624 				rv = ibnex_vppa_conf_entry_delete(msg, service);
625 			} else if (svc_type == IB_HCASVC_SERVICE) {
626 				rv = ibnex_hcasvc_conf_entry_delete(msg,
627 				    service);
628 			}
629 			kmem_free(service, ioc.bufsiz + 1);
630 			break;
631 
632 		case IBNEX_HCA_VERBOSE_SZ:
633 		case IBNEX_HCA_VERBOSE_INFO:
634 			msg = (ioc.cmd == IBNEX_HCA_VERBOSE_SZ) ?
635 			    "DEVCTL_AP_CONTROL: IBNEX_HCA_VERBOSE_SZ" :
636 			    "DEVCTL_AP_CONTROL: IBNEX_HCA_VERBOSE_INFO";
637 
638 			guid_str = strrchr(apid_n, ':') + 1;
639 			IBTF_DPRINTF_L4("ibnex", "%s, apid = %s, guid = %s",
640 			    msg, apid_n, guid_str);
641 
642 			if (guid_str == NULL) {
643 				IBTF_DPRINTF_L2("ibnex", "%s: invalid GUID %s",
644 				    msg, guid_str);
645 				rv = EFAULT;
646 				break;
647 			}
648 
649 			/* Get the GUID(hex value) from apid_n */
650 			hca_guid = ibnex_str2hex(guid_str, strlen(guid_str),
651 			    &ret);
652 			if (ret != IBNEX_SUCCESS) {
653 				IBTF_DPRINTF_L2("ibnex", "%s: Invalid HCA GUID "
654 				    "string", msg);
655 				rv = EIO;
656 				break;
657 			}
658 			IBTF_DPRINTF_L4("ibnex", "%s HCA GUID = 0x%llX",
659 			    msg, hca_guid);
660 
661 			if (ibtl_ibnex_get_hca_verbose_data(hca_guid, &snapshot,
662 			    &snapshot_sz) != IBT_SUCCESS) {
663 				IBTF_DPRINTF_L2("ibnex", "%s: get HCA verbose "
664 				    "data failed", msg);
665 				rv = EIO;
666 				break;
667 			}
668 
669 			ssiz = snapshot_sz;
670 			IBTF_DPRINTF_L4("ibnex", "%s: size =%x", msg, ssiz);
671 
672 			if (ioc.cmd == IBNEX_HCA_VERBOSE_SZ) {
673 				if (ddi_copyout(&ssiz, ioc.buf,
674 				    ioc.bufsiz, mode) != 0) {
675 					IBTF_DPRINTF_L2("ibnex",
676 					    "%s: ddi_copyout 11 failed", msg);
677 					rv = EFAULT;
678 				}
679 			} else {
680 				if (ioc.bufsiz != ssiz) {
681 					IBTF_DPRINTF_L2("ibnex",
682 					    "%s: invalid size (%x, %x)",
683 					    msg, ioc.bufsiz, ssiz);
684 					rv = EINVAL;
685 				} else if (ddi_copyout(snapshot,
686 				    ioc.buf, ioc.bufsiz, mode) != 0) {
687 					IBTF_DPRINTF_L2("ibnex", "%s "
688 					    "ddi_copyout 12 failed", msg);
689 					rv = EFAULT;
690 				}
691 			}
692 
693 			kmem_free(snapshot, snapshot_sz);
694 			break;
695 
696 		case IBNEX_UPDATE_IOC_CONF :
697 			msg = "\tioctl:IBNEX_UPDATE_IOC_CONF: ";
698 
699 			/*
700 			 * If IB fabric APID, call ibnex_update_all
701 			 * If IOC APID, get the apid dip and call
702 			 * ibnex_update_ioc
703 			 */
704 			if (ioc.misc_arg == IBNEX_BASE_APID) {
705 				/*
706 				 * If reprobe is in progress or another reprobe
707 				 * is already waiting, wait.
708 				 */
709 				if (ibnex.ibnex_reprobe_state != 0) {
710 					if (ibnex.ibnex_reprobe_state ==
711 					    IBNEX_REPROBE_ALL_PROGRESS)
712 						ibnex.ibnex_reprobe_state =
713 						    IBNEX_REPROBE_ALL_WAIT;
714 					while (ibnex.ibnex_reprobe_state) {
715 						cv_wait(&ibnex.ibnex_reprobe_cv,
716 						    &ibnex.ibnex_mutex);
717 					}
718 
719 					/*
720 					 * Pending reprobe all completed, return
721 					 */
722 					break;
723 				}
724 
725 				/* Check if reprobe for any IOC is pending */
726 				/* CONSTCOND */
727 				while (1) {
728 					ioc_reprobe_pending = 0;
729 					for (scanp = ibnex.ibnex_ioc_node_head;
730 					    scanp;
731 					    scanp = scanp->node_next) {
732 						if (scanp->node_reprobe_state
733 						    != 0) {
734 							ioc_reprobe_pending =
735 							    1;
736 							break;
737 						}
738 					}
739 					if (ioc_reprobe_pending == 0) {
740 						ibnex.ibnex_reprobe_state &=
741 						    ~IBNEX_REPROBE_IOC_WAIT;
742 						break;
743 					}
744 
745 					ibnex.ibnex_reprobe_state =
746 					    IBNEX_REPROBE_IOC_WAIT;
747 					cv_wait(&ibnex.ibnex_reprobe_cv,
748 					    &ibnex.ibnex_mutex);
749 				}
750 
751 				/*
752 				 * Set the REPROBE_ALL_PROGRESS state &
753 				 * start reprobe
754 				 */
755 				ibnex.ibnex_reprobe_state =
756 				    IBNEX_REPROBE_ALL_PROGRESS;
757 				mutex_exit(&ibnex.ibnex_mutex);
758 				ibnex_reprobe_ioc_all();
759 				mutex_enter(&ibnex.ibnex_mutex);
760 			} else if (ioc.misc_arg == IBNEX_DYN_APID) {
761 				rv = ibnex_get_dip_from_apid(apid_n, &apid_dip,
762 				    &nodep);
763 				ASSERT(rv == IBNEX_DYN_APID);
764 
765 				/* Device unconfigured: return */
766 				if (apid_dip == NULL)
767 					break;
768 
769 				ndi_rele_devi(apid_dip);
770 				/* Reset return value back to 0 */
771 				rv = 0;
772 				if (ibnex.ibnex_reprobe_state != 0 ||
773 				    nodep->node_reprobe_state != 0) {
774 					while (ibnex.ibnex_reprobe_state != 0 &&
775 					    nodep->node_reprobe_state != 0) {
776 						cv_wait(&ibnex.ibnex_reprobe_cv,
777 						    &ibnex.ibnex_mutex);
778 					}
779 					/* Pending reprobe completed, return */
780 					break;
781 				}
782 
783 				/* Set node_reprobe_state and start reprobe */
784 				nodep->node_reprobe_state =
785 				    IBNEX_NODE_REPROBE_NOTIFY_ON_UPDATE;
786 				mutex_exit(&ibnex.ibnex_mutex);
787 				ibnex_reprobe_ioc_dev((void *)apid_dip);
788 				mutex_enter(&ibnex.ibnex_mutex);
789 			} else {
790 				rv = EINVAL;
791 			}
792 
793 			break;
794 
795 		default:
796 			IBTF_DPRINTF_L2("ibnex",
797 			    "DEVCTL_AP_CONTROL: ioc:unknown cmd = %x", ioc.cmd);
798 			break;
799 		}
800 	}
801 	break;
802 
803 	case DEVCTL_AP_UNCONFIGURE:
804 		msg = "DEVCTL_AP_UNCONFIGURE";
805 		IBTF_DPRINTF_L4("ibnex", "%s", msg);
806 
807 		/* Check for write permissions */
808 		if (!(mode & FWRITE)) {
809 			IBTF_DPRINTF_L2("ibnex", "%s: invalid mode %x",
810 			    msg, mode);
811 			rv = EPERM;
812 			break;
813 		}
814 
815 		if ((apid_n = ibnex_get_apid(dcp)) == '\0') {
816 			IBTF_DPRINTF_L2("ibnex",
817 			    "%s: ibnex_get_apid failed", msg);
818 			rv = EIO;
819 			break;
820 		}
821 
822 		/*
823 		 * If this apid is already seen by IBNEX, get the dip
824 		 * NOTE: ibnex_get_dip_from_apid() finds a valid dip
825 		 * and also does a ndi_devi_hold() on the child.
826 		 */
827 		rv = ibnex_get_dip_from_apid(apid_n, &apid_dip, &nodep);
828 		if ((rv != IBNEX_DYN_APID) || (apid_dip == NULL)) {
829 			IBTF_DPRINTF_L2("ibnex", "%s: get_dip_from_apid "
830 			    "failed with 0x%x", msg, rv);
831 			rv = EIO;
832 			break;
833 		}
834 		IBTF_DPRINTF_L4("ibnex", "%s: DIP = %p", msg, apid_dip);
835 
836 		/* Check if it is a valid node type? */
837 		if (!IBNEX_VALID_NODE_TYPE(nodep)) {
838 			IBTF_DPRINTF_L2("ibnex", "%s: invalid IB node", msg);
839 			rv = ENODEV;
840 			ndi_rele_devi(apid_dip);
841 			break;
842 		}
843 
844 		/*
845 		 * continue unconfigure operation, only if device node
846 		 * is already configured. Return EBUSY if another
847 		 * configure/unconfigure operation is in progress.
848 		 */
849 		if (nodep->node_state == IBNEX_CFGADM_CONFIGURING ||
850 		    nodep->node_state == IBNEX_CFGADM_UNCONFIGURING) {
851 			rv = EBUSY;
852 			ndi_rele_devi(apid_dip);
853 			break;
854 		}
855 
856 		/* do this before to avoid races */
857 		nodep->node_dip = NULL;
858 		nodep->node_state = IBNEX_CFGADM_UNCONFIGURING;
859 
860 		/*
861 		 * Call devfs_clean first
862 		 * NOTE: The code so far is protected by holding ibnex_mutex
863 		 * and by doing a ndi_devi_hold() on the child.
864 		 */
865 		pdip = ddi_get_parent(apid_dip);
866 		if (i_ddi_node_state(apid_dip) >= DS_INITIALIZED) {
867 			devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
868 			(void) ddi_deviname(apid_dip, devnm);
869 			mutex_exit(&ibnex.ibnex_mutex);
870 			if (devfs_clean(pdip, devnm + 1, DV_CLEAN_FORCE)) {
871 				IBTF_DPRINTF_L2("ibnex", "%s: devfs_clean of %s"
872 				    " failed", msg, devnm);
873 				rv = EBUSY;
874 				mutex_enter(&ibnex.ibnex_mutex);
875 				ndi_rele_devi(apid_dip);
876 				nodep->node_dip = apid_dip;
877 				nodep->node_state = IBNEX_CFGADM_CONFIGURED;
878 				kmem_free(devnm, MAXNAMELEN + 1);
879 				break;
880 			}
881 			mutex_enter(&ibnex.ibnex_mutex);
882 			kmem_free(devnm, MAXNAMELEN + 1);
883 		}
884 
885 		mutex_exit(&ibnex.ibnex_mutex);
886 		ndi_devi_enter(pdip, &circ);
887 		ndi_rele_devi(apid_dip);
888 		mutex_enter(&ibnex.ibnex_mutex);
889 
890 		/* unconfigure the Port/VPPA/HCA_SVC node */
891 		if (IBNEX_COMMSVC_NODE_TYPE(nodep)) {
892 			ret_val = ibnex_commsvc_fininode(apid_dip);
893 		} else if (nodep->node_type == IBNEX_IOC_NODE) {
894 			/* unconfigure the IOC node */
895 			ret_val = ibnex_ioc_fininode(apid_dip,
896 			    &nodep->node_data.ioc_node);
897 		} else if (nodep->node_type == IBNEX_PSEUDO_NODE) {
898 			/* unconfigure the pseudo node */
899 			ret_val = ibnex_pseudo_fininode(apid_dip);
900 		}
901 
902 		/* reset upon failure */
903 		if (ret_val != IBNEX_SUCCESS) {
904 			nodep->node_dip = apid_dip;
905 			nodep->node_state = IBNEX_CFGADM_CONFIGURED;
906 		} else
907 			nodep->node_state = IBNEX_CFGADM_UNCONFIGURED;
908 
909 		rv = (ret_val != IBNEX_SUCCESS) ? EIO : 0;
910 		ndi_devi_exit(pdip, circ);
911 		IBTF_DPRINTF_L2("ibnex", "%s: DONE !! It %s", msg,
912 		    rv ? "failed" : "succeeded");
913 		break;
914 
915 	case DEVCTL_AP_CONFIGURE:
916 		msg = "DEVCTL_AP_CONFIGURE";
917 		IBTF_DPRINTF_L4("ibnex", "%s", msg);
918 		mutex_exit(&ibnex.ibnex_mutex);
919 		ndi_devi_enter(ibnex.ibnex_dip, &circ);
920 		mutex_enter(&ibnex.ibnex_mutex);
921 
922 		/* Check for write permissions */
923 		if (!(mode & FWRITE)) {
924 			IBTF_DPRINTF_L2("ibnex", "%s: invalid mode %x",
925 			    msg, mode);
926 			rv = EPERM;
927 			ndi_devi_exit(ibnex.ibnex_dip, circ);
928 			break;
929 		}
930 
931 		if ((apid_n = ibnex_get_apid(dcp)) == '\0') {
932 			IBTF_DPRINTF_L2("ibnex",
933 			    "%s: ibnex_get_apid failed", msg);
934 			rv = EIO;
935 			ndi_devi_exit(ibnex.ibnex_dip, circ);
936 			break;
937 		}
938 
939 		/*
940 		 * Five types of APIDs are supported:
941 		 *	o HCA_GUID,0,service-name	(HCA-SVC device)
942 		 *	o IOC_GUID 			(IOC device)
943 		 *	o PORT_GUID,0,service-name	(Port device)
944 		 *	o pseudo_name,unit-address, 	(Pseudo device)
945 		 *	o PORT_GUID,P_Key,service-name	(VPPA device)
946 		 * If the apid doesn't have "," then treat it as an IOC
947 		 * If the apid has one "," then it is Pseudo device
948 		 * If the apid has 2 ","s then it is one of the
949 		 * Port,VPPA,HCA_SVC devices
950 		 */
951 		if (strrchr(apid_n, ',') == NULL) {
952 			ret_val = ibnex_handle_ioc_configure(apid_n);
953 		} else {
954 			char *first = strchr(apid_n, ',');
955 			char *second;
956 
957 			second = first ? strchr(first + 1, ',') : NULL;
958 			if (first != NULL && second == NULL) {
959 				ret_val = ibnex_handle_pseudo_configure(apid_n);
960 			} else if (first != NULL && second != NULL) {
961 				ret_val = ibnex_handle_commsvcnode_configure(
962 				    apid_n);
963 			}
964 		} /* end of else */
965 
966 		if (ret_val != IBNEX_SUCCESS)
967 			rv = (ret_val == IBNEX_BUSY) ? EBUSY : EIO;
968 		IBTF_DPRINTF_L2("ibnex", "%s: DONE !! It %s", msg,
969 		    rv ? "failed" : "succeeded");
970 		ndi_devi_exit(ibnex.ibnex_dip, circ);
971 		break;
972 
973 	default:
974 		rv = EIO;
975 		break;
976 	}
977 	mutex_exit(&ibnex.ibnex_mutex);
978 
979 	if ((apid_alloced == B_TRUE) && (apid_n != NULL)) {
980 		kmem_free(apid_n, apid_len);
981 	}
982 
983 	if (dcp) {
984 		ndi_dc_freehdl(dcp);
985 	}
986 	return (rv);
987 }
988 
989 
990 /*
991  * ibnex_get_num_devices()
992  *	Figure out how many IOC, VPPA, Pseudo, HCA_SVC and Port devices exist
993  */
994 static int
995 ibnex_get_num_devices(void)
996 {
997 	int			j, k, l, hca_count;
998 	int			num_nodes = 0;
999 	ibdm_hca_list_t		*hca_list, *hcap;
1000 	ibdm_port_attr_t	*pattr;
1001 	ibnex_node_data_t	*nodep;
1002 
1003 	ASSERT(mutex_owned(&ibnex.ibnex_mutex));
1004 
1005 	/* Get a count of HCAs, first. */
1006 	mutex_exit(&ibnex.ibnex_mutex);
1007 	ibdm_ibnex_get_hca_list(&hca_list, &hca_count);
1008 	mutex_enter(&ibnex.ibnex_mutex);
1009 	for (hcap = hca_list; hca_list != NULL; hca_list = hca_list->hl_next) {
1010 		for (j = 0; j < ibnex.ibnex_nhcasvc_comm_svcs; j++)
1011 			num_nodes++;
1012 		for (j = 0; j < hca_list->hl_nports; j++) {
1013 			for (k = 0; k < ibnex.ibnex_num_comm_svcs; k++)
1014 				num_nodes++;
1015 
1016 			pattr = &hca_list->hl_port_attr[j];
1017 			for (k = 0; k < pattr->pa_npkeys; k++) {
1018 				if (IBNEX_INVALID_PKEY(pattr->pa_pkey_tbl[k].
1019 				    pt_pkey))
1020 					continue;
1021 
1022 				for (l = 0; l < ibnex.ibnex_nvppa_comm_svcs;
1023 				    l++, ++num_nodes);
1024 			} /* end of pa_npkeys */
1025 		} /* end of  hl_nports */
1026 	} /* end of hca_list != NULL */
1027 	if (hcap)
1028 		ibdm_ibnex_free_hca_list(hcap);
1029 
1030 	/*
1031 	 * Now figure out how many IOC nodes are present.
1032 	 * Add count of configured "diconnected" IOCs
1033 	 */
1034 	mutex_exit(&ibnex.ibnex_mutex);
1035 	num_nodes += ibdm_ibnex_get_ioc_count();
1036 	mutex_enter(&ibnex.ibnex_mutex);
1037 	num_nodes += ibnex.ibnex_num_disconnect_iocs;
1038 
1039 	/* Last: figure out how many Pseudo nodes are present. */
1040 	for (nodep = ibnex.ibnex_pseudo_node_head; nodep;
1041 	    nodep = nodep->node_next, ++num_nodes);
1042 	return (num_nodes);
1043 }
1044 
1045 
1046 /*
1047  * ibnex_get_snapshot()
1048  *	Get a snapshot of all Port/IOC/VPPA/HCA_SVC/Pseudo nodes
1049  *	Snapshot includes IBNEX_NODE_INFO_NVL, IBNEX_NODE_TYPE_NVL,
1050  *	IBNEX_NODE_RSTATE_NVL, IBNEX_NODE_OSTATE_NVL and
1051  *	IBNEX_NODE_COND_NVL
1052  */
1053 static int
1054 ibnex_get_snapshot(char **buf, size_t *sz, int allow_probe)
1055 {
1056 	int			i, j, k, l, hca_count;
1057 	nvlist_t		*nvl;
1058 	ib_pkey_t 		pkey;
1059 	boolean_t		found;
1060 	ibdm_ioc_info_t		*ioc_listp;
1061 	ibdm_ioc_info_t		*iocp;
1062 	ibdm_hca_list_t		*hca_list, *hcap;
1063 	ibdm_port_attr_t	*port_attr;
1064 	ibnex_node_data_t	*nodep;
1065 
1066 	ASSERT(mutex_owned(&ibnex.ibnex_mutex));
1067 
1068 	*buf = NULL;
1069 	*sz = 0;
1070 
1071 	if (!ibnex.ibnex_pseudo_inited) {
1072 		mutex_exit(&ibnex.ibnex_mutex);
1073 		ibnex_pseudo_initnodes();
1074 		mutex_enter(&ibnex.ibnex_mutex);
1075 		ibnex.ibnex_pseudo_inited = 1;
1076 	}
1077 
1078 	/* First, Port/VPPA/HCA_SVC nodes */
1079 	mutex_exit(&ibnex.ibnex_mutex);
1080 	ibdm_ibnex_get_hca_list(&hca_list, &hca_count);
1081 	mutex_enter(&ibnex.ibnex_mutex);
1082 
1083 	(void) nvlist_alloc(&nvl, 0, KM_SLEEP);
1084 
1085 	/* Go thru all the ports of all the HCAs and all the port-svc indices */
1086 	for (hcap = hca_list, i = 0; i < hca_count;
1087 	    hca_list = hca_list->hl_next, i++) {
1088 
1089 		IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: "
1090 		    "fill in  COMM service HCA_SVC nodes");
1091 		port_attr = hca_list->hl_hca_port_attr;
1092 		for (j = 0; j < ibnex.ibnex_nhcasvc_comm_svcs; j++) {
1093 			if (ibnex_get_commsvcnode_snapshot(&nvl,
1094 			    port_attr->pa_hca_guid,
1095 			    port_attr->pa_hca_guid, j, (ib_pkey_t)0,
1096 			    IBNEX_HCASVC_COMMSVC_NODE) != 0) {
1097 				IBTF_DPRINTF_L2("ibnex",
1098 				    "ibnex_get_snapshot: failed to fill"
1099 				    " HCA_SVC device (%x %x)", i, j);
1100 				ibdm_ibnex_free_hca_list(hcap);
1101 				nvlist_free(nvl);
1102 				return (-1);
1103 			}
1104 
1105 		}
1106 
1107 		for (j = 0; j < hca_list->hl_nports; j++) {
1108 			port_attr = &hca_list->hl_port_attr[j];
1109 
1110 			IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: "
1111 			    "fill in  COMM service Port nodes");
1112 			for (k = 0; k < ibnex.ibnex_num_comm_svcs; k++) {
1113 
1114 				if (ibnex_get_commsvcnode_snapshot(&nvl,
1115 				    port_attr->pa_hca_guid,
1116 				    port_attr->pa_port_guid, k, (ib_pkey_t)0,
1117 				    IBNEX_PORT_COMMSVC_NODE) != 0) {
1118 					IBTF_DPRINTF_L2("ibnex",
1119 					    "ibnex_get_snapshot: failed to fill"
1120 					    " Port device (%x %x %x)", i, j, k);
1121 					ibdm_ibnex_free_hca_list(hcap);
1122 					nvlist_free(nvl);
1123 					return (-1);
1124 				}
1125 
1126 			} /* end of num_comm_svcs for loop */
1127 
1128 			IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: "
1129 			    "fill in  VPPA service port nodes");
1130 			for (l = 0; l < port_attr->pa_npkeys; l++) {
1131 				pkey = port_attr->pa_pkey_tbl[l].pt_pkey;
1132 				if (IBNEX_INVALID_PKEY(pkey))
1133 					continue;
1134 
1135 				for (k = 0; k < ibnex.ibnex_nvppa_comm_svcs;
1136 				    k++) {
1137 
1138 					if (ibnex_get_commsvcnode_snapshot(&nvl,
1139 					    port_attr->pa_hca_guid,
1140 					    port_attr->pa_port_guid, k, pkey,
1141 					    IBNEX_VPPA_COMMSVC_NODE) != 0) {
1142 						IBTF_DPRINTF_L2("ibnex",
1143 						    "ibnex_get_snapshot: "
1144 						    "failed to fill VPPA "
1145 						    "device (%x %x %x % x)",
1146 						    i, j, k, l);
1147 						ibdm_ibnex_free_hca_list(hcap);
1148 						nvlist_free(nvl);
1149 						return (-1);
1150 					}
1151 				} /* end of ibnex_nvppa_comm_svcs loop */
1152 
1153 			} /* end of pa_npkeys for loop */
1154 
1155 		} /* end of hl_nports for loop */
1156 
1157 	} /* end of hca_count for loop */
1158 
1159 	if (hcap)
1160 		ibdm_ibnex_free_hca_list(hcap);
1161 
1162 	/* save it to free up the entire list */
1163 	mutex_exit(&ibnex.ibnex_mutex);
1164 	iocp = ioc_listp = ibdm_ibnex_get_ioc_list(allow_probe);
1165 	mutex_enter(&ibnex.ibnex_mutex);
1166 	for (; ioc_listp != NULL; ioc_listp = ioc_listp->ioc_next) {
1167 
1168 		/*
1169 		 * Say we have N IOCs and all were deleted from ibnex
1170 		 * but not from IBDM
1171 		 */
1172 		if (ibnex.ibnex_ioc_node_head == NULL) {
1173 			if (ibnex_fill_ioc_tmp(&nvl, ioc_listp) != 0) {
1174 				IBTF_DPRINTF_L2("ibnex", "ibnex_get_snapshot: "
1175 				    "filling NVL data failed");
1176 				ibdm_ibnex_free_ioc_list(iocp);
1177 				nvlist_free(nvl);
1178 				return (-1);
1179 			}
1180 			continue;
1181 
1182 		} else {
1183 			found = B_FALSE;
1184 
1185 			/* Check first, if we have already seen this IOC? */
1186 			for (nodep = ibnex.ibnex_ioc_node_head; nodep != NULL;
1187 			    nodep = nodep->node_next) {
1188 				if (ioc_listp->ioc_profile.ioc_guid ==
1189 				    nodep->node_data.ioc_node.ioc_guid) {
1190 					found = B_TRUE;
1191 					break;
1192 				}
1193 			}
1194 
1195 
1196 			/* have we seen this IOC before? */
1197 			if (found == B_TRUE) {
1198 				if (ibnex_fill_nodeinfo(&nvl, nodep,
1199 				    &ioc_listp->ioc_profile) != 0) {
1200 					IBTF_DPRINTF_L2("ibnex",
1201 					    "ibnex_get_snapshot: filling NVL "
1202 					    "for IOC node %p failed", nodep);
1203 					ibdm_ibnex_free_ioc_list(iocp);
1204 					nvlist_free(nvl);
1205 					return (-1);
1206 				}
1207 
1208 			} else {
1209 
1210 				if (ibnex_fill_ioc_tmp(&nvl, ioc_listp) != 0) {
1211 					IBTF_DPRINTF_L2("ibnex",
1212 					    "ibnex_get_snapshot: filling NVL "
1213 					    "tmp for IOC node %p failed",
1214 					    ioc_listp);
1215 					ibdm_ibnex_free_ioc_list(iocp);
1216 					nvlist_free(nvl);
1217 					return (-1);
1218 				}
1219 			}
1220 
1221 		} /* end of else ibnex_ioc_node_head == NULL */
1222 	} /* end of external for */
1223 
1224 	ibdm_ibnex_free_ioc_list(iocp);
1225 
1226 	/*
1227 	 * Add list of "disconnected" IOCs, not unconfigured.
1228 	 */
1229 	for (nodep = ibnex.ibnex_ioc_node_head; nodep != NULL;
1230 	    nodep = nodep->node_next) {
1231 		if (nodep->node_data.ioc_node.ioc_ngids == 0 &&
1232 		    nodep->node_data.ioc_node.ioc_profile != NULL &&
1233 		    nodep->node_state != IBNEX_CFGADM_UNCONFIGURED) {
1234 			if (ibnex_fill_nodeinfo(&nvl, nodep,
1235 			    nodep->node_data.ioc_node.ioc_profile) != 0) {
1236 					IBTF_DPRINTF_L2("ibnex",
1237 					    "ibnex_get_snapshot: filling NVL "
1238 					    "for disconnected IOC node %p "
1239 					    "failed", nodep);
1240 					nvlist_free(nvl);
1241 					return (-1);
1242 			}
1243 		}
1244 	}
1245 
1246 	/* lastly; pseudo nodes */
1247 	for (nodep = ibnex.ibnex_pseudo_node_head; nodep;
1248 	    nodep = nodep->node_next) {
1249 		if (ibnex_fill_nodeinfo(&nvl, nodep, NULL) != 0) {
1250 			IBTF_DPRINTF_L2("ibnex", "ibnex_get_snapshot: "
1251 			    "filling NVL data for Pseudo %p failed", nodep);
1252 			nvlist_free(nvl);
1253 			return (-1);
1254 		}
1255 	}
1256 
1257 	/* pack the data into the buffer */
1258 	if (nvlist_pack(nvl, buf, sz, NV_ENCODE_NATIVE, KM_SLEEP)) {
1259 		IBTF_DPRINTF_L2("ibnex",
1260 		    "ibnex_get_snapshot: nvlist_pack failed");
1261 		nvlist_free(nvl);
1262 		return (-1);
1263 	}
1264 
1265 	IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: size = 0x%x", *sz);
1266 	nvlist_free(nvl);
1267 	return (0);
1268 }
1269 
1270 
1271 /*
1272  * ibnex_get_commsvcnode_snapshot()
1273  *	A utility function to fill in a "dummy" Port/VPPA/HCA_SVC
1274  *	information. Cfgadm plugin will display all Port/VPPA/
1275  *	HCA_SVCs seen even if they are not all configured by IBNEX.
1276  *
1277  *	This function uses information from IBDM to fill up Port/VPPA/
1278  *	HCA_SVC snapshot. If none exists then it makes up a "temporary"
1279  *	node which will be displayed as "connected/unconfigured/unknown".
1280  *
1281  *	For HCA_SVC node port_guid will be same as hca_guid.
1282  */
1283 static int
1284 ibnex_get_commsvcnode_snapshot(nvlist_t **nvlpp, ib_guid_t hca_guid,
1285     ib_guid_t port_guid, int svc_index, ib_pkey_t p_key,
1286     ibnex_node_type_t node_type)
1287 {
1288 	int			rval;
1289 	dev_info_t		*dip = NULL;
1290 	ibnex_node_data_t	*nodep;
1291 	ibnex_node_data_t	dummy;
1292 	ibnex_node_data_t	*tmp = &dummy;
1293 
1294 	IBTF_DPRINTF_L4("ibnex", "ibnex_get_commsvcnode_snapshot: "
1295 	    "HCA GUID: %llX Port GUID: %llX svc_index = %x pkey = %x "
1296 	    "node_type = %x", hca_guid, port_guid, svc_index, p_key, node_type);
1297 
1298 	/* check if this node was seen before? */
1299 	rval = ibnex_get_dip_from_guid(port_guid, svc_index, p_key, &dip);
1300 	if (rval == IBNEX_SUCCESS && dip) {
1301 		nodep = ddi_get_parent_data(dip);
1302 
1303 		if (ibnex_fill_nodeinfo(nvlpp, nodep, NULL) != 0) {
1304 			IBTF_DPRINTF_L2("ibnex",
1305 			    "ibnex_get_commsvcnode_snapshot: failed to fill "
1306 			    "Port/VPPA device node %p NVL data", nodep);
1307 			return (-1);
1308 		}
1309 
1310 	} else {
1311 		/* Fake up a Port/VPPA/HCA_SVC node */
1312 		IBTF_DPRINTF_L4("ibnex", "ibnex_get_commsvcnode_snapshot: "
1313 		    "VPPA/Port/HCA_SVC not seen by ibnex");
1314 		bzero(tmp, sizeof (ibnex_node_data_t));
1315 		tmp->node_type = node_type;
1316 		tmp->node_data.port_node.port_guid = port_guid;
1317 		tmp->node_data.port_node.port_hcaguid = hca_guid;
1318 		tmp->node_data.port_node.port_commsvc_idx = svc_index;
1319 		/* Fill P_Key only for VPPA nodes */
1320 		if (node_type == IBNEX_VPPA_COMMSVC_NODE) {
1321 			tmp->node_data.port_node.port_pkey = p_key;
1322 		}
1323 
1324 		if (ibnex_fill_nodeinfo(nvlpp, tmp, NULL) != 0) {
1325 			IBTF_DPRINTF_L2("ibnex",
1326 			    "ibnex_get_commsvcnode_snapshot: failed to fill "
1327 			    "tmp Port/VPPA device node %p NVL data", tmp);
1328 			return (-1);
1329 		}
1330 	}
1331 
1332 	return (0);
1333 }
1334 
1335 
1336 /*
1337  * ibnex_fill_ioc_tmp()
1338  *	A utility function to fill in a "dummy" IOC information.
1339  *	Cfgadm plugin will display all IOCs seen by IBDM even if they
1340  *	are configured or not by IBNEX.
1341  *
1342  *	This function uses information from IBDM to fill up a
1343  *	dummy IOC information. It will be displayed as
1344  *	"connected/unconfigured/unknown".
1345  */
1346 static int
1347 ibnex_fill_ioc_tmp(nvlist_t **nvlpp, ibdm_ioc_info_t *ioc_listp)
1348 {
1349 	ibnex_node_data_t	dummy;
1350 	ibnex_node_data_t	*nodep = &dummy;
1351 
1352 	IBTF_DPRINTF_L4("ibnex", "\tibnex_fill_ioc_tmp:");
1353 
1354 	bzero(nodep, sizeof (ibnex_node_data_t));
1355 	nodep->node_type = IBNEX_IOC_NODE;
1356 	nodep->node_data.ioc_node.ioc_guid = ioc_listp->ioc_profile.ioc_guid;
1357 	nodep->node_data.ioc_node.iou_guid = ioc_listp->ioc_iou_guid;
1358 	(void) strncpy(nodep->node_data.ioc_node.ioc_id_string,
1359 	    (char *)ioc_listp->ioc_profile.ioc_id_string,
1360 	    IB_DM_IOC_ID_STRING_LEN);
1361 	IBTF_DPRINTF_L4("ibnex", "\tibnex_fill_ioc_tmp: %s",
1362 	    nodep->node_data.ioc_node.ioc_id_string);
1363 
1364 	if (ibnex_fill_nodeinfo(nvlpp, nodep, &ioc_listp->ioc_profile) != 0) {
1365 		IBTF_DPRINTF_L2("ibnex", "\tibnex_fill_ioc_tmp: filling NVL "
1366 		    "data for IOC node %p failed", nodep);
1367 		return (-1);
1368 	}
1369 
1370 	return (0);
1371 }
1372 
1373 
1374 /*
1375  * ibnex_fill_nodeinfo()
1376  *	A utility function to fill in to the NVLIST information about
1377  *	a Port/IOC/VPPA/HCA_SVC/Pseudo driver that is then passed over
1378  *	to cfgadm utility for display. This information is used only
1379  *	for cfgadm -ll displays.
1380  *
1381  *	Information that is filled in here is:-
1382  *		AP_ID_NAME
1383  *		AP_ID_INFO
1384  *		AP_ID_TYPE
1385  *		AP_ID_OCCUPANT_STATE
1386  *		AP_ID_RECEPTACLE_STATE
1387  *		AP_ID_CONDITION
1388  */
1389 static int
1390 ibnex_fill_nodeinfo(nvlist_t **nvlpp, ibnex_node_data_t *node_datap, void *tmp)
1391 {
1392 	char			*svcname;
1393 	char			*node_name;
1394 	char			apid[IBTL_IBNEX_APID_LEN];
1395 	char			info_data[MAXNAMELEN];
1396 	ib_dm_ioc_ctrl_profile_t *profilep;
1397 	devctl_ap_state_t	state;
1398 
1399 	IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: 0x%x addr is %p",
1400 	    node_datap->node_type, node_datap);
1401 
1402 	if (node_datap->node_type == IBNEX_PORT_COMMSVC_NODE) {
1403 		svcname = ibnex.ibnex_comm_svc_names[node_datap->node_data.
1404 		    port_node.port_commsvc_idx];
1405 		(void) snprintf(apid, IBTL_IBNEX_APID_LEN, "%llX,0,%s",
1406 		    (longlong_t)node_datap->node_data.port_node.port_guid,
1407 		    svcname);
1408 
1409 		/* Node APID */
1410 		if (nvlist_add_string(*nvlpp, IBNEX_NODE_APID_NVL, apid)) {
1411 			IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1412 			    "failed to fill %s", IBNEX_NODE_APID_NVL);
1413 			return (-1);
1414 		}
1415 
1416 		/* Node Info */
1417 		if (nvlist_add_string(*nvlpp, IBNEX_NODE_INFO_NVL, svcname)) {
1418 			IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1419 			    "failed to fill Port %s", IBNEX_NODE_INFO_NVL);
1420 			return (-1);
1421 		}
1422 
1423 		IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: "
1424 		    "Port %s = %s, %s = %s",
1425 		    IBNEX_NODE_INFO_NVL, apid, IBNEX_NODE_APID_NVL, svcname);
1426 
1427 	} else if (node_datap->node_type == IBNEX_VPPA_COMMSVC_NODE) {
1428 		svcname = ibnex.ibnex_vppa_comm_svc_names[node_datap->node_data.
1429 		    port_node.port_commsvc_idx];
1430 		(void) snprintf(apid, IBTL_IBNEX_APID_LEN, "%llX,%x,%s",
1431 		    (longlong_t)node_datap->node_data.port_node.port_guid,
1432 		    node_datap->node_data.port_node.port_pkey, svcname);
1433 
1434 		/* Node APID */
1435 		if (nvlist_add_string(*nvlpp, IBNEX_NODE_APID_NVL, apid)) {
1436 			IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1437 			    "failed to fill %s", IBNEX_NODE_APID_NVL);
1438 			return (-1);
1439 		}
1440 
1441 		/* Node Info */
1442 		if (nvlist_add_string(*nvlpp, IBNEX_NODE_INFO_NVL, svcname)) {
1443 			IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1444 			    "failed to fill VPPA %s", IBNEX_NODE_INFO_NVL);
1445 			return (-1);
1446 		}
1447 
1448 		IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: "
1449 		    "VPPA %s = %s, %s = %s",
1450 		    IBNEX_NODE_APID_NVL, apid, IBNEX_NODE_INFO_NVL, svcname);
1451 
1452 	} else if (node_datap->node_type == IBNEX_HCASVC_COMMSVC_NODE) {
1453 		svcname = ibnex.ibnex_hcasvc_comm_svc_names[node_datap->
1454 		    node_data.port_node.port_commsvc_idx];
1455 		(void) snprintf(apid, IBTL_IBNEX_APID_LEN, "%llX,0,%s",
1456 		    (longlong_t)node_datap->node_data.port_node.port_guid,
1457 		    svcname);
1458 
1459 		/* Node APID */
1460 		if (nvlist_add_string(*nvlpp, IBNEX_NODE_APID_NVL, apid)) {
1461 			IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1462 			    "failed to fill %s", IBNEX_NODE_APID_NVL);
1463 			return (-1);
1464 		}
1465 
1466 		/* Node Info */
1467 		if (nvlist_add_string(*nvlpp, IBNEX_NODE_INFO_NVL, svcname)) {
1468 			IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1469 			    "failed to fill Port %s", IBNEX_NODE_INFO_NVL);
1470 			return (-1);
1471 		}
1472 
1473 		IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: "
1474 		    "Port %s = %s, %s = %s",
1475 		    IBNEX_NODE_INFO_NVL, apid, IBNEX_NODE_APID_NVL, svcname);
1476 
1477 	} else if (node_datap->node_type == IBNEX_IOC_NODE) {
1478 
1479 		/*
1480 		 * get the IOC profile pointer from the args
1481 		 */
1482 		profilep = (ib_dm_ioc_ctrl_profile_t *)tmp;
1483 		IBNEX_FORM_GUID(apid, IBTL_IBNEX_APID_LEN, profilep->ioc_guid);
1484 
1485 		/* Node APID */
1486 		if (nvlist_add_string(*nvlpp, IBNEX_NODE_APID_NVL, apid)) {
1487 			IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1488 			    "failed to fill in %s", IBNEX_NODE_APID_NVL);
1489 			return (-1);
1490 		}
1491 		IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %s",
1492 		    IBNEX_NODE_APID_NVL, apid);
1493 
1494 		/*
1495 		 * IOC "info" filed will display the following fields
1496 		 * VendorID, IOCDeviceID, DeviceVersion, SubsystemVendorID,
1497 		 * SubsystemID, Class, Subclass, Protocol, ProtocolVersion
1498 		 */
1499 		(void) snprintf(info_data, MAXNAMELEN,
1500 		    "VID: 0x%x DEVID: 0x%x VER: 0x%x SUBSYS_VID: 0x%x "
1501 		    "SUBSYS_ID: 0x%x CLASS: 0x%x SUBCLASS: 0x%x PROTO: 0x%x "
1502 		    "PROTOVER: 0x%x ID_STRING: %s", profilep->ioc_vendorid,
1503 		    profilep->ioc_deviceid, profilep->ioc_device_ver,
1504 		    profilep->ioc_subsys_vendorid, profilep->ioc_subsys_id,
1505 		    profilep->ioc_io_class, profilep->ioc_io_subclass,
1506 		    profilep->ioc_protocol, profilep->ioc_protocol_ver,
1507 		    (char *)profilep->ioc_id_string);
1508 		IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s", info_data);
1509 
1510 		/* Node Info */
1511 		if (nvlist_add_string(*nvlpp, IBNEX_NODE_INFO_NVL, info_data)) {
1512 			IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1513 			    "failed to fill IOC %s", IBNEX_NODE_INFO_NVL);
1514 			return (-1);
1515 		}
1516 
1517 	} else if (node_datap->node_type == IBNEX_PSEUDO_NODE) {
1518 		(void) snprintf(apid, IBTL_IBNEX_APID_LEN, "%s",
1519 		    node_datap->node_data.pseudo_node.pseudo_node_addr);
1520 
1521 		/* Node APID */
1522 		if (nvlist_add_string(*nvlpp, IBNEX_NODE_APID_NVL, apid)) {
1523 			IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1524 			    "failed to fill in %s", IBNEX_NODE_APID_NVL);
1525 			return (-1);
1526 		}
1527 
1528 		/* Node Info */
1529 		node_name = node_datap->node_data.pseudo_node.pseudo_devi_name;
1530 		(void) snprintf(info_data, MAXNAMELEN,
1531 		    "Pseudo Driver = \"%s\", Unit-address = \"%s\"",
1532 		    node_name, apid + strlen(node_name) + 1);
1533 		if (nvlist_add_string(*nvlpp, IBNEX_NODE_INFO_NVL, info_data)) {
1534 			IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1535 			    "failed to fill Pseudo %s", IBNEX_NODE_INFO_NVL);
1536 			return (-1);
1537 		}
1538 
1539 		IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: Pseudo %s = %s,"
1540 		    "%s = %s", IBNEX_NODE_APID_NVL, apid, IBNEX_NODE_INFO_NVL,
1541 		    info_data);
1542 	}
1543 
1544 	/* Node type */
1545 	if (nvlist_add_int32(*nvlpp, IBNEX_NODE_TYPE_NVL,
1546 	    node_datap->node_type)) {
1547 		IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1548 		    "failed to fill in %s", IBNEX_NODE_TYPE_NVL);
1549 		return (-1);
1550 	}
1551 	IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d",
1552 	    IBNEX_NODE_TYPE_NVL, node_datap->node_type);
1553 
1554 	/* figure out "ostate", "rstate" and "condition" */
1555 	ibnex_figure_ap_devstate(node_datap->node_dip, &state);
1556 
1557 	if (nvlist_add_int32(*nvlpp, IBNEX_NODE_RSTATE_NVL, state.ap_rstate)) {
1558 		IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1559 		    "failed to fill in %s", IBNEX_NODE_RSTATE_NVL);
1560 		return (-1);
1561 	}
1562 	IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d",
1563 	    IBNEX_NODE_RSTATE_NVL, state.ap_rstate);
1564 
1565 	if (nvlist_add_int32(*nvlpp, IBNEX_NODE_OSTATE_NVL, state.ap_ostate)) {
1566 		IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1567 		    "failed to fill in %s", IBNEX_NODE_OSTATE_NVL);
1568 		return (-1);
1569 	}
1570 	IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d",
1571 	    IBNEX_NODE_OSTATE_NVL, state.ap_ostate);
1572 
1573 	if (nvlist_add_int32(*nvlpp, IBNEX_NODE_COND_NVL, state.ap_condition)) {
1574 		IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1575 		    "failed to fill in %s", IBNEX_NODE_COND_NVL);
1576 		return (-1);
1577 	}
1578 	IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d",
1579 	    IBNEX_NODE_COND_NVL, state.ap_condition);
1580 
1581 	return (0);
1582 }
1583 
1584 
1585 /*
1586  * ibnex_figure_ap_devstate()
1587  *	Fills the "devctl_ap_state_t" for a given ap_id
1588  *
1589  *	currently it assumes that we don't support "error_code" and
1590  *	"last_change" value.
1591  */
1592 static void
1593 ibnex_figure_ap_devstate(dev_info_t *dip, devctl_ap_state_t *ap_state)
1594 {
1595 	IBTF_DPRINTF_L5("ibnex", "ibnex_figure_ap_devstate: dip = %p", dip);
1596 
1597 	ap_state->ap_rstate = AP_RSTATE_CONNECTED;
1598 	if (dip == NULL) {	/* for nodes not seen by IBNEX yet */
1599 		ap_state->ap_ostate = AP_OSTATE_UNCONFIGURED;
1600 		ap_state->ap_condition = AP_COND_UNKNOWN;
1601 	} else {
1602 		if (i_ddi_node_state(dip) < DS_BOUND) {
1603 			ap_state->ap_ostate = AP_OSTATE_UNCONFIGURED;
1604 			ap_state->ap_condition = AP_COND_UNKNOWN;
1605 		} else {
1606 			ap_state->ap_ostate = AP_OSTATE_CONFIGURED;
1607 			ap_state->ap_condition = AP_COND_OK;
1608 		}
1609 	}
1610 	ap_state->ap_last_change = (time_t)-1;
1611 	ap_state->ap_error_code = 0;
1612 	ap_state->ap_in_transition = 0;
1613 }
1614 
1615 
1616 /*
1617  * ibnex_figure_ib_apid_devstate()
1618  *	Fills the "devctl_ap_state_t" for a IB static ap_id
1619  */
1620 static void
1621 ibnex_figure_ib_apid_devstate(devctl_ap_state_t *ap_state)
1622 {
1623 	ap_state->ap_rstate = AP_RSTATE_CONNECTED;
1624 	ap_state->ap_condition = AP_COND_OK;
1625 	ap_state->ap_ostate = (ibt_get_hca_list(NULL) == 0) ?
1626 	    AP_OSTATE_UNCONFIGURED : AP_OSTATE_CONFIGURED;
1627 	ap_state->ap_last_change = (time_t)-1;
1628 	ap_state->ap_error_code = 0;
1629 	ap_state->ap_in_transition = 0;
1630 }
1631 
1632 
1633 /*
1634  * ibnex_get_apid()
1635  *	Reads in the ap_id passed as an nvlist_string from user-land
1636  */
1637 static char *
1638 ibnex_get_apid(struct devctl_iocdata *dcp)
1639 {
1640 	char *ap_id;
1641 
1642 	ASSERT(mutex_owned(&ibnex.ibnex_mutex));
1643 
1644 	/* Get which ap_id to operate on.  */
1645 	if (nvlist_lookup_string(ndi_dc_get_ap_data(dcp), "apid",
1646 	    &ap_id) != 0) {
1647 		IBTF_DPRINTF_L4("ibnex", "ibnex_get_apid: ap_id lookup failed");
1648 		ap_id = NULL;
1649 	}
1650 
1651 	IBTF_DPRINTF_L4("ibnex", "ibnex_get_apid: ap_id=%s", ap_id);
1652 	return (ap_id);
1653 }
1654 
1655 
1656 /*
1657  * ibnex_get_dip_from_apid()
1658  *	Figures out the dip/node_data from an ap_id given that this ap_id
1659  *	exists as a "name" in the "ibnex" list
1660  *
1661  * NOTE: ap_id was on stack earlier and gets manipulated here. Since this
1662  * function may be called twice; it is better to make a local copy of
1663  * ap_id; if the ap_id were to be reused.
1664  */
1665 static int
1666 ibnex_get_dip_from_apid(char *apid, dev_info_t **ret_dip,
1667     ibnex_node_data_t **ret_node_datap)
1668 {
1669 	int			rv, ret;
1670 	int			index;
1671 	int			len = strlen((char *)apid) + 1;
1672 	char			*dyn;
1673 	char			*ap_id;
1674 	char			*first;
1675 	char			*second = NULL;
1676 	char			*node_addr;
1677 	char			name[100];
1678 	ibnex_node_data_t	*nodep = NULL;
1679 
1680 	ap_id = i_ddi_strdup(apid, KM_SLEEP);
1681 	IBTF_DPRINTF_L4("ibnex", "\tibnex_get_dip_from_apid: %s", ap_id);
1682 	ASSERT(mutex_owned(&ibnex.ibnex_mutex));
1683 
1684 	if ((dyn = GET_DYN(ap_id)) != NULL) {
1685 		rv = IBNEX_DYN_APID;
1686 	} else {	/* either static, hca or unknown */
1687 		*ret_dip = NULL;
1688 		if (strstr(ap_id, "hca") != 0) {
1689 			rv = IBNEX_HCA_APID;
1690 		} else if (strstr(ap_id, IBNEX_FABRIC) != 0) {
1691 			rv = IBNEX_BASE_APID;
1692 		} else {
1693 			rv = IBNEX_UNKNOWN_APID;
1694 		}
1695 		kmem_free(ap_id, len);
1696 		return (rv);
1697 	}
1698 
1699 	dyn += strlen(DYN_SEP);
1700 	if (*dyn == '\0') {
1701 		*ret_dip = NULL;
1702 		kmem_free(ap_id, len);
1703 		return (IBNEX_UNKNOWN_APID);
1704 	}
1705 
1706 	/* APID */
1707 	first = strchr(dyn, ',');
1708 	if (first != NULL)
1709 		second = strchr(first+1, ',');
1710 
1711 	/* Implies Port or VPPA or HCA_SVC Driver ap_id */
1712 	if (first != NULL && second != NULL) {
1713 		int	str_len;
1714 		int	pkey_val = 0;
1715 		char	*pkey_str = strchr(ap_id, ',');
1716 		char	*svc_str = strrchr(pkey_str, ',');
1717 
1718 		/* dyn contains ,GUID,p_key,svc_name. Change it to GUID */
1719 		str_len = strlen(dyn) - strlen(pkey_str);
1720 		dyn[str_len] = '\0';
1721 		IBTF_DPRINTF_L4("ibnex", "\tibnex_get_dip_from_apid: "
1722 		    "Port / Node Guid %s", dyn);
1723 
1724 		/* figure out comm or vppa. figure out pkey  */
1725 		++pkey_str; /* pkey_str used to point to ",p_key,svc_name" */
1726 
1727 		/* pkey_str contains p_key,svc_name. Change it to p_key */
1728 		str_len = strlen(pkey_str) - strlen(svc_str);
1729 		pkey_str[str_len] = '\0';
1730 
1731 		/* convert the string P_KEY to hex value */
1732 		pkey_val = ibnex_str2hex(pkey_str, strlen(pkey_str), &ret);
1733 		if (ret != IBNEX_SUCCESS) {
1734 			*ret_dip = NULL;
1735 			kmem_free(ap_id, len);
1736 			return (IBNEX_UNKNOWN_APID);
1737 		}
1738 
1739 		++svc_str;	/* svc_str used to point to ",svc_name" */
1740 		IBTF_DPRINTF_L5("ibnex", "\tibnex_get_dip_from_apid: pkey %s"
1741 		    ":%x service name = %s", pkey_str, pkey_val, svc_str);
1742 
1743 		for (nodep = ibnex.ibnex_port_node_head;
1744 		    nodep != NULL; nodep = nodep->node_next) {
1745 			index = nodep->node_data.port_node.port_commsvc_idx;
1746 			IBNEX_FORM_GUID(name, IBTL_IBNEX_APID_LEN,
1747 			    nodep->node_data.port_node.port_guid);
1748 
1749 			/*
1750 			 * Match P_Key, name string & service string:
1751 			 * For COMM / HCA_SVC services these should be true:
1752 			 *	P_Key matches to 0, svc_str in comm_svc_names[]
1753 			 *	and name matches the dynamic part of the ap_id
1754 			 * For VPPA services this should be true:
1755 			 *	P_Key != 0 & matches, svc_str in
1756 			 *	vppa_comm_svc_names[] and the name matches the
1757 			 *	dynamic part of the ap_id.
1758 			 */
1759 			if ((pkey_val == nodep->node_data.port_node.
1760 			    port_pkey) && (strstr(dyn, name) != NULL)) {
1761 
1762 				/* pkey != 0, COMM / HCA_SVC service */
1763 				if (((pkey_val == 0) && (
1764 					/* Port Service */
1765 				    ((ibnex.ibnex_comm_svc_names != NULL) &&
1766 				    (index < ibnex.ibnex_num_comm_svcs) &&
1767 				    (strstr(svc_str, ibnex.
1768 				    ibnex_comm_svc_names[index]) != NULL)) ||
1769 					/* HCA_SVC service */
1770 				    ((ibnex.ibnex_hcasvc_comm_svc_names !=
1771 				    NULL) && (index <
1772 				    ibnex.ibnex_nhcasvc_comm_svcs) &&
1773 				    (strstr(svc_str, ibnex.
1774 				    ibnex_hcasvc_comm_svc_names[index])
1775 					!= NULL)))) ||
1776 					/* next the VPPA strings */
1777 				    ((pkey_val != 0) && (strstr(svc_str, ibnex.
1778 				    ibnex_vppa_comm_svc_names[index]) !=
1779 				    NULL))) {
1780 					if (nodep->node_dip)
1781 						ndi_hold_devi(nodep->node_dip);
1782 					*ret_node_datap = nodep;
1783 					*ret_dip = nodep->node_dip;
1784 					kmem_free(ap_id, len);
1785 					return (rv);
1786 				}
1787 			}
1788 
1789 		} /* end of for */
1790 
1791 	} else if (first != NULL && second == NULL) {
1792 		/* pseudo ap_id */
1793 		for (nodep = ibnex.ibnex_pseudo_node_head; nodep;
1794 		    nodep = nodep->node_next) {
1795 			node_addr = nodep->node_data.pseudo_node.
1796 			    pseudo_node_addr;
1797 			if (strncmp(dyn, node_addr, strlen(node_addr)) == 0) {
1798 				if (nodep->node_dip)
1799 					ndi_hold_devi(nodep->node_dip);
1800 				*ret_node_datap = nodep;
1801 				*ret_dip = nodep->node_dip;
1802 				kmem_free(ap_id, len);
1803 				return (rv);
1804 			}
1805 		}
1806 
1807 	} else if (first == NULL && second == NULL) {
1808 		/* This is an IOC ap_id */
1809 		for (nodep = ibnex.ibnex_ioc_node_head; nodep != NULL;
1810 		    nodep = nodep->node_next) {
1811 			IBNEX_FORM_GUID(name, IBTL_IBNEX_APID_LEN,
1812 			    nodep->node_data.ioc_node.ioc_guid);
1813 			if (strstr(dyn, name) != NULL) {
1814 				if (nodep->node_dip)
1815 					ndi_hold_devi(nodep->node_dip);
1816 				*ret_node_datap = nodep;
1817 				*ret_dip = nodep->node_dip;
1818 				kmem_free(ap_id, len);
1819 				return (rv);
1820 			}
1821 		}
1822 	}
1823 
1824 	/* Could not find a matching IB device */
1825 	*ret_dip = (nodep) ? nodep->node_dip : NULL;
1826 	kmem_free(ap_id, len);
1827 	return (rv);
1828 }
1829 
1830 
1831 /*
1832  * ibnex_handle_pseudo_configure()
1833  *	Do DEVCTL_AP_CONNECT processing for Pseudo devices only.
1834  *	The code also checks if the given ap_id is valid or not.
1835  */
1836 static ibnex_rval_t
1837 ibnex_handle_pseudo_configure(char *apid)
1838 {
1839 	char			*node_addr;
1840 	char			*last = strrchr(apid, ':') + 1;
1841 	ibnex_rval_t		retval = IBNEX_FAILURE;
1842 	ibnex_node_data_t	*nodep;
1843 
1844 	IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_pseudo_configure: "
1845 	    "last = %s\n\t\tapid = %s", last, apid);
1846 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1847 
1848 	/* Check if the APID is valid first */
1849 	if (apid == NULL || last == NULL) {
1850 		IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_pseudo_configure: "
1851 		    "invalid apid %s", apid);
1852 		return (retval);
1853 	}
1854 
1855 	/* find the matching entry and configure it */
1856 	for (nodep = ibnex.ibnex_pseudo_node_head; nodep != NULL;
1857 	    nodep = nodep->node_next) {
1858 		node_addr = nodep->node_data.pseudo_node.pseudo_node_addr;
1859 		if (strncmp(node_addr, last, strlen(last)))
1860 			continue;
1861 
1862 		if (nodep->node_dip != NULL) {
1863 			/*
1864 			 * Return BUSY if another configure
1865 			 * operation is in progress
1866 			 */
1867 			if (nodep->node_state ==
1868 			    IBNEX_CFGADM_CONFIGURING)
1869 				return (IBNEX_BUSY);
1870 			else
1871 				return (IBNEX_SUCCESS);
1872 		}
1873 
1874 		/*
1875 		 * Return BUSY if another unconfigure operation is
1876 		 * in progress
1877 		 */
1878 		if (nodep->node_state == IBNEX_CFGADM_UNCONFIGURING)
1879 			return (IBNEX_BUSY);
1880 
1881 		ASSERT(nodep->node_state != IBNEX_CFGADM_CONFIGURED);
1882 		nodep->node_state = IBNEX_CFGADM_CONFIGURING;
1883 		nodep->node_data.pseudo_node.pseudo_new_node = 0;
1884 
1885 		mutex_exit(&ibnex.ibnex_mutex);
1886 		retval = ibnex_pseudo_create_pi(nodep);
1887 		mutex_enter(&ibnex.ibnex_mutex);
1888 		if (retval == NDI_SUCCESS) {
1889 			nodep->node_state = IBNEX_CFGADM_CONFIGURED;
1890 			return (IBNEX_SUCCESS);
1891 		} else {
1892 			nodep->node_state = IBNEX_CFGADM_UNCONFIGURED;
1893 			return (IBNEX_FAILURE);
1894 		}
1895 	}
1896 
1897 	IBTF_DPRINTF_L4("ibnex", "\thandle_pseudo_configure: retval=%d",
1898 	    retval);
1899 	return (retval);
1900 }
1901 
1902 
1903 /*
1904  * ibnex_handle_ioc_configure()
1905  *	Do DEVCTL_AP_CONNECT processing for IOCs only.
1906  *	The code also checks if the given ap_id is valid or not.
1907  */
1908 static ibnex_rval_t
1909 ibnex_handle_ioc_configure(char *apid)
1910 {
1911 	int			ret;
1912 	char			*guid_str = strrchr(apid, ':') + 1;
1913 	ib_guid_t		ioc_guid;
1914 	ibnex_rval_t		retval = IBNEX_FAILURE;
1915 	ibdm_ioc_info_t		*ioc_info;
1916 
1917 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1918 	IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_ioc_configure: %s", apid);
1919 
1920 	/* Check if the APID is valid first */
1921 	if (guid_str == NULL) {
1922 		IBTF_DPRINTF_L4("ibnex",
1923 		    "\tibnex_handle_ioc_configure: invalid apid %s", apid);
1924 		return (retval);
1925 	}
1926 
1927 	/*
1928 	 * Call into IBDM to get IOC information
1929 	 */
1930 	ioc_guid = ibnex_str2hex(guid_str, strlen(guid_str), &ret);
1931 	if (ret != IBNEX_SUCCESS)
1932 		return (ret);
1933 
1934 	IBTF_DPRINTF_L4("ibnex",
1935 	    "\tibnex_handle_ioc_configure: IOC GUID = %llX", ioc_guid);
1936 	mutex_exit(&ibnex.ibnex_mutex);
1937 	ioc_info = ibdm_ibnex_get_ioc_info(ioc_guid);
1938 	mutex_enter(&ibnex.ibnex_mutex);
1939 	if (ioc_info == NULL) {
1940 		IBTF_DPRINTF_L2("ibnex",
1941 		    "\tibnex_handle_ioc_configure: probe_iocguid failed");
1942 		return (retval);
1943 	}
1944 
1945 	retval = ibnex_ioc_initnode(ioc_info, IBNEX_CFGADM_ENUMERATE);
1946 	ibdm_ibnex_free_ioc_list(ioc_info);
1947 
1948 	IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_ioc_configure: "
1949 	    "done retval = %d", retval);
1950 	return (retval);
1951 }
1952 
1953 
1954 /*
1955  * ibnex_handle_commsvcnode_configure()
1956  *	Do DEVCTL_AP_CONNECT processing
1957  *	This is done for Port/VPPA/HCA_SVC drivers Only.
1958  *	The code also checks if the given ap_id is valid or not.
1959  */
1960 static ibnex_rval_t
1961 ibnex_handle_commsvcnode_configure(char *apid)
1962 {
1963 	int			ret, str_len;
1964 	int			sndx;
1965 	int			port_pkey = 0;
1966 	char			*pkey_str = strchr(apid, ',');
1967 	char			*guid_str = strrchr(apid, ':') + 1;
1968 	char			*svc_str = strrchr(pkey_str, ',');
1969 	boolean_t		found = B_FALSE;
1970 	boolean_t		is_hcasvc_node = B_FALSE;
1971 	ib_guid_t		guid;	/* Port / Node GUID */
1972 	dev_info_t		*parent;
1973 	ibnex_rval_t		retval = IBNEX_FAILURE;
1974 	ibdm_port_attr_t	*port_attr;
1975 	int			node_type;
1976 	ibdm_hca_list_t		*hca_list;
1977 
1978 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1979 	IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_commsvcnode_configure: %s",
1980 	    apid);
1981 
1982 	/* Check if the APID is valid first */
1983 	if (guid_str == NULL || ((guid_str != NULL) &&
1984 	    (pkey_str == NULL || svc_str == NULL))) {
1985 		IBTF_DPRINTF_L4("ibnex",
1986 		    "\tibnex_handle_commsvcnode_configure: "
1987 		    "invalid apid %s", apid);
1988 		return (retval);
1989 	}
1990 
1991 	/* guid_str contains GUID,p_key,svc_name. Change it to GUID */
1992 	str_len = strlen(guid_str) - strlen(pkey_str);
1993 	guid_str[str_len] = '\0';
1994 
1995 	/* convert the string GUID to hex value */
1996 	guid = ibnex_str2hex(guid_str, strlen(guid_str), &ret);
1997 	if (ret == IBNEX_FAILURE)
1998 		return (ret);
1999 	IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_commsvcnode_configure: "
2000 	    "Port / Node Guid %llX", guid);
2001 
2002 	/* figure out Port/HCA_SVC or VPPA. Also figure out the P_Key.  */
2003 	++pkey_str;	/* pkey_str used to point to ",p_key,svc_name" */
2004 
2005 	/* pkey_str contains p_key,svc_name. Change it to P_Key */
2006 	str_len = strlen(pkey_str) - strlen(svc_str);
2007 	pkey_str[str_len] = '\0';
2008 	IBTF_DPRINTF_L5("ibnex", "\tibnex_handle_commsvcnode_configure: "
2009 	    "p_key %s", pkey_str);
2010 
2011 	/* convert the string P_Key to a hexadecimal value */
2012 	port_pkey = ibnex_str2hex(pkey_str, strlen(pkey_str), &ret);
2013 	IBTF_DPRINTF_L5("ibnex", "\tibnex_handle_commsvcnode_configure: "
2014 	    "PKEY num %x", port_pkey);
2015 	if (ret == IBNEX_FAILURE)
2016 		return (ret);
2017 
2018 	++svc_str;	/* svc_str used to point to ",svc_name" */
2019 
2020 	/* find the service index */
2021 	if (port_pkey == 0) {
2022 		/* PORT Devices */
2023 		for (sndx = 0; sndx < ibnex.ibnex_num_comm_svcs; sndx++) {
2024 			if (strncmp(ibnex.ibnex_comm_svc_names[sndx],
2025 			    svc_str, strlen(svc_str)) == 0) {
2026 				found = B_TRUE;
2027 				break;
2028 			}
2029 		}
2030 
2031 		/* HCA_SVC Devices */
2032 		if (found == B_FALSE) {
2033 			for (sndx = 0; sndx < ibnex.ibnex_nhcasvc_comm_svcs;
2034 			    sndx++) {
2035 				if (strncmp(ibnex.ibnex_hcasvc_comm_svc_names
2036 				    [sndx], svc_str, strlen(svc_str)) == 0) {
2037 					found = B_TRUE;
2038 					is_hcasvc_node = B_TRUE;
2039 					break;
2040 				}
2041 			}
2042 		}
2043 
2044 	} else {
2045 		for (sndx = 0; sndx < ibnex.ibnex_nvppa_comm_svcs; sndx++) {
2046 			if (strncmp(ibnex.ibnex_vppa_comm_svc_names[sndx],
2047 			    svc_str, strlen(svc_str)) == 0) {
2048 				found = B_TRUE;
2049 				break;
2050 			}
2051 		}
2052 	}
2053 
2054 	if (found == B_FALSE) {
2055 		IBTF_DPRINTF_L2("ibnex",
2056 		    "\tibnex_handle_commsvcnode_configure: "
2057 		    "invalid service %s", svc_str);
2058 		return (retval);
2059 	}
2060 
2061 	/* get Port attributes structure */
2062 	mutex_exit(&ibnex.ibnex_mutex);
2063 	if (is_hcasvc_node == B_FALSE) {
2064 		port_attr = ibdm_ibnex_get_port_attrs(guid);
2065 		if (port_attr == NULL) {
2066 			IBTF_DPRINTF_L2("ibnex",
2067 			    "\tibnex_handle_commsvcnode_configure: "
2068 			    "ibdm_ibnex_get_port_attrs failed");
2069 			mutex_enter(&ibnex.ibnex_mutex);
2070 			return (retval);
2071 		}
2072 	} else {
2073 		hca_list = ibdm_ibnex_get_hca_info_by_guid(guid);
2074 		if (hca_list == NULL) {
2075 			IBTF_DPRINTF_L2("ibnex",
2076 			    "\tibnex_handle_commsvcnode_configure: "
2077 			    "ibdm_ibnex_get_hca_info_by_guid failed");
2078 			mutex_enter(&ibnex.ibnex_mutex);
2079 			return (retval);
2080 		}
2081 		port_attr = hca_list->hl_hca_port_attr;
2082 	}
2083 
2084 	/* get HCA's dip */
2085 	parent = ibtl_ibnex_hcaguid2dip(port_attr->pa_hca_guid);
2086 
2087 	if (parent == NULL) {
2088 		IBTF_DPRINTF_L2("ibnex",
2089 		    "\tibnex_handle_commsvcnode_configure: "
2090 		    "no HCA present");
2091 		mutex_enter(&ibnex.ibnex_mutex);
2092 		if (is_hcasvc_node == B_FALSE)
2093 			ibdm_ibnex_free_port_attr(port_attr);
2094 		else
2095 			ibdm_ibnex_free_hca_list(hca_list);
2096 		return (retval);
2097 	}
2098 
2099 	if (port_pkey == 0)
2100 		node_type = (is_hcasvc_node == B_FALSE) ?
2101 		    IBNEX_PORT_COMMSVC_NODE : IBNEX_HCASVC_COMMSVC_NODE;
2102 	else
2103 		node_type = IBNEX_VPPA_COMMSVC_NODE;
2104 
2105 	mutex_enter(&ibnex.ibnex_mutex);
2106 	if (ibnex_commsvc_initnode(parent, port_attr, sndx, node_type,
2107 	    port_pkey, &ret, IBNEX_CFGADM_ENUMERATE) != NULL) {
2108 		retval = IBNEX_SUCCESS;
2109 	} else {
2110 		retval = (ret == IBNEX_BUSY) ? IBNEX_BUSY : IBNEX_FAILURE;
2111 	}
2112 
2113 	if (is_hcasvc_node == B_FALSE)
2114 		ibdm_ibnex_free_port_attr(port_attr);
2115 	else
2116 		ibdm_ibnex_free_hca_list(hca_list);
2117 
2118 	IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_commsvcnode_configure: "
2119 	    "done retval = %d", retval);
2120 
2121 	return (retval);
2122 }
2123 
2124 
2125 /*
2126  * ibnex_return_apid()
2127  *	Construct the ap_id of a given IBTF client in kernel
2128  */
2129 static void
2130 ibnex_return_apid(dev_info_t *childp, char **ret_apid)
2131 {
2132 	ibnex_node_data_t	*nodep;
2133 
2134 	IBTF_DPRINTF_L4("ibnex", "ibnex_return_apid:");
2135 
2136 	ASSERT(childp != NULL);
2137 	nodep = ddi_get_parent_data(childp);
2138 
2139 	if (nodep->node_type == IBNEX_PORT_COMMSVC_NODE) {
2140 		(void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN,
2141 		    "ib%s%llX,0,%s", DYN_SEP,
2142 		    (longlong_t)nodep->node_data.port_node.port_guid,
2143 		    ibnex.ibnex_comm_svc_names[nodep->node_data.port_node.
2144 		    port_commsvc_idx]);
2145 
2146 	} else if (nodep->node_type == IBNEX_HCASVC_COMMSVC_NODE) {
2147 		(void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN,
2148 		    "ib%s%llX,0,%s", DYN_SEP,
2149 		    (longlong_t)nodep->node_data.port_node.port_guid, ibnex.
2150 		    ibnex_hcasvc_comm_svc_names[nodep->node_data.port_node.
2151 		    port_commsvc_idx]);
2152 
2153 	} else if (nodep->node_type == IBNEX_VPPA_COMMSVC_NODE) {
2154 		(void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN,
2155 		    "ib%s%llX,%x,%s", DYN_SEP,
2156 		    (longlong_t)nodep->node_data.port_node.port_guid,
2157 		    nodep->node_data.port_node.port_pkey,
2158 		    ibnex.ibnex_vppa_comm_svc_names[nodep->node_data.port_node.
2159 		    port_commsvc_idx]);
2160 
2161 	} else if (nodep->node_type == IBNEX_IOC_NODE) {
2162 		(void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN,
2163 		    "ib%s%llX", DYN_SEP,
2164 		    (longlong_t)nodep->node_data.ioc_node.ioc_guid);
2165 
2166 	} else if (nodep->node_type == IBNEX_PSEUDO_NODE) {
2167 		(void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN, "ib%s%s",
2168 		    DYN_SEP, nodep->node_data.pseudo_node.pseudo_node_addr);
2169 
2170 	} else {
2171 		(void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN, "%s", "-");
2172 	}
2173 
2174 	IBTF_DPRINTF_L4("ibnex", "ibnex_return_apid: %x %s",
2175 	    nodep->node_type, ret_apid);
2176 }
2177 
2178 
2179 /*
2180  * ibnex_vppa_conf_entry_add()
2181  *	Add a new service to the ibnex data base of VPPA communication
2182  *	services.
2183  */
2184 static void
2185 ibnex_vppa_conf_entry_add(char *service)
2186 {
2187 	int	i, nsvcs;
2188 	char	**service_name;
2189 
2190 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2191 	nsvcs = ibnex.ibnex_nvppa_comm_svcs;
2192 
2193 	/* Allocate space for new "ibnex.ibnex_nvppa_comm_svcs + 1" */
2194 	service_name = kmem_alloc((nsvcs + 1) * sizeof (char *), KM_SLEEP);
2195 	/*
2196 	 * Copy over the existing "ibnex.ibnex_vppa_comm_svc_names"
2197 	 * array. Add the new service at the end.
2198 	 */
2199 	for (i = 0; i < nsvcs; i++)
2200 		service_name[i] = ibnex.ibnex_vppa_comm_svc_names[i];
2201 	service_name[i] = kmem_alloc(strlen(service) + 1, KM_SLEEP);
2202 	(void) snprintf(service_name[i], 5, "%s", service);
2203 
2204 	/* Replace existing pointer to VPPA services w/ newly allocated one */
2205 	if (ibnex.ibnex_vppa_comm_svc_names) {
2206 		kmem_free(ibnex.ibnex_vppa_comm_svc_names, nsvcs *
2207 		    sizeof (char *));
2208 	}
2209 	ibnex.ibnex_nvppa_comm_svcs++;
2210 	ibnex.ibnex_vppa_comm_svc_names = service_name;
2211 }
2212 
2213 /*
2214  * ibnex_port_conf_entry_add()
2215  *	Add a new service to the ibnex data base of Port communication
2216  *	services.
2217  */
2218 static void
2219 ibnex_port_conf_entry_add(char *service)
2220 {
2221 	int	i, nsvcs;
2222 	char	**service_name;
2223 
2224 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2225 	nsvcs = ibnex.ibnex_num_comm_svcs;
2226 
2227 	/* Allocate space for new "ibnex.ibnex_num_comm_svcs + 1" */
2228 	service_name = kmem_alloc((nsvcs + 1) * sizeof (char *), KM_SLEEP);
2229 	/*
2230 	 * Copy over the existing "ibnex.ibnex_comm_svc_names" array.
2231 	 * Add the new service to the end.
2232 	 */
2233 	for (i = 0; i < nsvcs; i++)
2234 		service_name[i] = ibnex.ibnex_comm_svc_names[i];
2235 	service_name[i] = kmem_alloc(strlen(service) + 1, KM_SLEEP);
2236 	(void) snprintf(service_name[i], 5, "%s", service);
2237 
2238 	/* Replace existing pointer to Port services w/ newly allocated one */
2239 	if (ibnex.ibnex_comm_svc_names) {
2240 		kmem_free(ibnex.ibnex_comm_svc_names, nsvcs * sizeof (char *));
2241 	}
2242 	ibnex.ibnex_num_comm_svcs++;
2243 	ibnex.ibnex_comm_svc_names = service_name;
2244 }
2245 
2246 /*
2247  * ibnex_hcasvc_conf_entry_add()
2248  *	Add a new service to the ibnex data base of HCA_SVC communication
2249  *	services.
2250  */
2251 static void
2252 ibnex_hcasvc_conf_entry_add(char *service)
2253 {
2254 	int	i, nsvcs;
2255 	char	**service_name;
2256 
2257 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2258 	nsvcs = ibnex.ibnex_nhcasvc_comm_svcs;
2259 
2260 	/* Allocate space for new "ibnex.ibnex_nvppa_comm_svcs + 1" */
2261 	service_name = kmem_alloc((nsvcs + 1) * sizeof (char *), KM_SLEEP);
2262 	/*
2263 	 * Copy over the existing "ibnex.ibnex_hcasvc_comm_svc_names"
2264 	 * array. Add the new service at the end.
2265 	 */
2266 	for (i = 0; i < nsvcs; i++)
2267 		service_name[i] = ibnex.ibnex_hcasvc_comm_svc_names[i];
2268 	service_name[i] = kmem_alloc(strlen(service) + 1, KM_SLEEP);
2269 	(void) snprintf(service_name[i], 5, "%s", service);
2270 
2271 	/*
2272 	 * Replace existing pointer to HCA_SVC services w/ newly
2273 	 * allocated one
2274 	 */
2275 	if (ibnex.ibnex_hcasvc_comm_svc_names) {
2276 		kmem_free(ibnex.ibnex_hcasvc_comm_svc_names, nsvcs *
2277 		    sizeof (char *));
2278 	}
2279 	ibnex.ibnex_nhcasvc_comm_svcs++;
2280 	ibnex.ibnex_hcasvc_comm_svc_names = service_name;
2281 }
2282 
2283 
2284 /*
2285  * ibnex_vppa_conf_entry_delete()
2286  *	Delete an existing service entry from ibnex data base of
2287  *	VPPA communication services.
2288  */
2289 static int
2290 ibnex_vppa_conf_entry_delete(char *msg, char *service)
2291 {
2292 	int			i, j, nsvcs;
2293 	int			len;
2294 	int			match_ndx;
2295 	char			**service_name;
2296 	boolean_t		found = B_FALSE;
2297 	ibnex_node_data_t	*node_datap = ibnex.ibnex_port_node_head;
2298 
2299 	IBTF_DPRINTF_L4("ibnex", "\tvppa_conf_entry_delete: %s", service);
2300 
2301 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2302 	nsvcs = ibnex.ibnex_nvppa_comm_svcs;
2303 
2304 	/* find matching index */
2305 	for (i = 0; i < nsvcs; i++) {
2306 		if (strncmp(ibnex.ibnex_vppa_comm_svc_names[i], service,
2307 		    strlen(service)))
2308 			continue;
2309 		found = B_TRUE;
2310 		match_ndx = i;
2311 		break;
2312 	}
2313 
2314 	/* check for valid "nsvcs" */
2315 	if (found == B_FALSE || nsvcs == 0) {
2316 		IBTF_DPRINTF_L2("ibnex", "%s: invalid vppa services %x",
2317 		    msg, nsvcs);
2318 		return (EIO);
2319 	}
2320 
2321 	/* Check if service is in use; return failure if so */
2322 	for (; node_datap; node_datap = node_datap->node_next) {
2323 		if ((node_datap->node_data.port_node.port_commsvc_idx == i) &&
2324 		    node_datap->node_type == IBNEX_VPPA_COMMSVC_NODE &&
2325 		    node_datap->node_dip) {
2326 			IBTF_DPRINTF_L2("ibnex", "%s: service %s is in use",
2327 			    msg, service);
2328 			return (EIO);
2329 		}
2330 	}
2331 
2332 	/* if nsvcs == 1, bailout early */
2333 	if (nsvcs == 1) {
2334 		/* free up that single entry */
2335 		len = strlen(ibnex.ibnex_vppa_comm_svc_names[0]) + 1;
2336 		kmem_free(ibnex.ibnex_vppa_comm_svc_names[0], len);
2337 		kmem_free(ibnex.ibnex_vppa_comm_svc_names, sizeof (char *));
2338 		ibnex.ibnex_vppa_comm_svc_names = NULL;
2339 		ibnex.ibnex_nvppa_comm_svcs = 0;
2340 		return (0);
2341 	}
2342 
2343 	/* Allocate space for new "ibnex.ibnex_nvppa_comm_svcs - 1" */
2344 	service_name = kmem_alloc((nsvcs - 1) * sizeof (char *), KM_SLEEP);
2345 	/*
2346 	 * Copy over the existing "ibnex.ibnex_vppa_comm_svc_names"
2347 	 * array. Do not copy over the matching service.
2348 	 */
2349 	for (i = 0, j = 0; i < nsvcs; i++) {
2350 		if (i == match_ndx) {
2351 			/* free up that entry */
2352 			len = strlen(ibnex.ibnex_vppa_comm_svc_names[i]) + 1;
2353 			kmem_free(ibnex.ibnex_vppa_comm_svc_names[i], len);
2354 			continue;
2355 		}
2356 		service_name[j++] = ibnex.ibnex_vppa_comm_svc_names[i];
2357 	}
2358 
2359 	/* Replace existing pointer to VPPA services w/ newly adjusted one */
2360 	if (ibnex.ibnex_vppa_comm_svc_names) {
2361 		kmem_free(ibnex.ibnex_vppa_comm_svc_names, nsvcs *
2362 		    sizeof (char *));
2363 		ibnex.ibnex_nvppa_comm_svcs--;
2364 		ibnex.ibnex_vppa_comm_svc_names = service_name;
2365 	}
2366 	return (0);
2367 }
2368 
2369 
2370 /*
2371  * ibnex_port_conf_entry_delete()
2372  *	Delete an existing service entry from ibnex data base of
2373  *	Port communication services.
2374  */
2375 static int
2376 ibnex_port_conf_entry_delete(char *msg, char *service)
2377 {
2378 	int			i, j, nsvcs;
2379 	int			match_ndx;
2380 	int			len;
2381 	char			**service_name;
2382 	boolean_t		found = B_FALSE;
2383 	ibnex_node_data_t	*node_datap = ibnex.ibnex_port_node_head;
2384 
2385 	IBTF_DPRINTF_L4("ibnex", "\tport_conf_entry_delete: %s", service);
2386 
2387 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2388 	nsvcs = ibnex.ibnex_num_comm_svcs;
2389 
2390 	/* find matching index */
2391 	for (i = 0; i < nsvcs; i++) {
2392 		if (strncmp(ibnex.ibnex_comm_svc_names[i], service,
2393 		    strlen(service)))
2394 			continue;
2395 		found = B_TRUE;
2396 		match_ndx = i;
2397 		break;
2398 	}
2399 
2400 	/* check for valid "nsvcs" */
2401 	if (found == B_FALSE || nsvcs == 0) {
2402 		IBTF_DPRINTF_L2("ibnex", "%s: invalid services %x", msg, nsvcs);
2403 		return (EIO);
2404 	}
2405 
2406 	/* Check if service is in use; return failure if so */
2407 	for (; node_datap; node_datap = node_datap->node_next) {
2408 		if ((node_datap->node_data.port_node.port_commsvc_idx == i) &&
2409 		    node_datap->node_type == IBNEX_PORT_COMMSVC_NODE &&
2410 		    node_datap->node_dip)
2411 			return (EIO);
2412 	}
2413 
2414 	/* if nsvcs == 1, bailout early */
2415 	if (nsvcs == 1) {
2416 		/* free up that single entry */
2417 		len = strlen(ibnex.ibnex_comm_svc_names[0]) + 1;
2418 		kmem_free(ibnex.ibnex_comm_svc_names[0], len);
2419 		kmem_free(ibnex.ibnex_comm_svc_names, sizeof (char *));
2420 		ibnex.ibnex_comm_svc_names = NULL;
2421 		ibnex.ibnex_num_comm_svcs = 0;
2422 		return (0);
2423 	}
2424 
2425 	/* Allocate space for new "ibnex.ibnex_num_comm_svcs - 1" */
2426 	service_name = kmem_alloc((nsvcs - 1) * sizeof (char *), KM_SLEEP);
2427 	/*
2428 	 * Copy over the existing "ibnex.ibnex_comm_svc_names" array.
2429 	 * Skip the matching service.
2430 	 */
2431 	for (i = 0, j = 0; i < nsvcs; i++) {
2432 		if (i == match_ndx) {
2433 			/* free up that entry */
2434 			len = strlen(ibnex.ibnex_comm_svc_names[i]) + 1;
2435 			kmem_free(ibnex.ibnex_comm_svc_names[i], len);
2436 			continue;
2437 		}
2438 		service_name[j++] = ibnex.ibnex_comm_svc_names[i];
2439 	}
2440 
2441 	/* Replace existing pointer to Port services w/ newly adjusted one */
2442 	if (ibnex.ibnex_comm_svc_names) {
2443 		kmem_free(ibnex.ibnex_comm_svc_names, nsvcs * sizeof (char *));
2444 		ibnex.ibnex_num_comm_svcs--;
2445 		ibnex.ibnex_comm_svc_names = service_name;
2446 	}
2447 	return (0);
2448 }
2449 
2450 /*
2451  * ibnex_hcasvc_conf_entry_delete()
2452  *	Delete an existing service entry from ibnex data base of
2453  *	HCA_SVC communication services.
2454  */
2455 static int
2456 ibnex_hcasvc_conf_entry_delete(char *msg, char *service)
2457 {
2458 	int			i, j, nsvcs;
2459 	int			len;
2460 	int			match_ndx;
2461 	char			**service_name;
2462 	boolean_t		found = B_FALSE;
2463 	ibnex_node_data_t	*node_datap = ibnex.ibnex_port_node_head;
2464 
2465 	IBTF_DPRINTF_L4("ibnex", "\thcasvc_conf_entry_delete: %s", service);
2466 
2467 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2468 	nsvcs = ibnex.ibnex_nhcasvc_comm_svcs;
2469 
2470 	/* find matching index */
2471 	for (i = 0; i < nsvcs; i++) {
2472 		if (strncmp(ibnex.ibnex_hcasvc_comm_svc_names[i], service,
2473 		    strlen(service)))
2474 			continue;
2475 		found = B_TRUE;
2476 		match_ndx = i;
2477 		break;
2478 	}
2479 
2480 	/* check for valid "nsvcs" */
2481 	if (found == B_FALSE || nsvcs == 0) {
2482 		IBTF_DPRINTF_L2("ibnex", "%s: invalid hca_svc services %x",
2483 		    msg, nsvcs);
2484 		return (EIO);
2485 	}
2486 
2487 	/* Check if service is in use; return failure if so */
2488 	for (; node_datap; node_datap = node_datap->node_next) {
2489 		if ((node_datap->node_data.port_node.port_commsvc_idx == i) &&
2490 		    node_datap->node_type == IBNEX_HCASVC_COMMSVC_NODE &&
2491 		    node_datap->node_dip) {
2492 			IBTF_DPRINTF_L2("ibnex", "%s: service %s is in use",
2493 			    msg, service);
2494 			return (EIO);
2495 		}
2496 	}
2497 
2498 	/* if nsvcs == 1, bailout early */
2499 	if (nsvcs == 1) {
2500 		/* free up that single entry */
2501 		len = strlen(ibnex.ibnex_hcasvc_comm_svc_names[0]) + 1;
2502 		kmem_free(ibnex.ibnex_hcasvc_comm_svc_names[0], len);
2503 		kmem_free(ibnex.ibnex_hcasvc_comm_svc_names, sizeof (char *));
2504 		ibnex.ibnex_hcasvc_comm_svc_names = NULL;
2505 		ibnex.ibnex_nhcasvc_comm_svcs = 0;
2506 		return (0);
2507 	}
2508 
2509 	/* Allocate space for new "ibnex.ibnex_nhcasvc_comm_svcs - 1" */
2510 	service_name = kmem_alloc((nsvcs - 1) * sizeof (char *), KM_SLEEP);
2511 	/*
2512 	 * Copy over the existing "ibnex.ibnex_hcasvc_comm_svc_names"
2513 	 * array. Do not copy over the matching service.
2514 	 */
2515 	for (i = 0, j = 0; i < nsvcs; i++) {
2516 		if (i == match_ndx) {
2517 			/* free up that entry */
2518 			len = strlen(ibnex.ibnex_hcasvc_comm_svc_names[i]) + 1;
2519 			kmem_free(ibnex.ibnex_hcasvc_comm_svc_names[i], len);
2520 			continue;
2521 		}
2522 		service_name[j++] = ibnex.ibnex_hcasvc_comm_svc_names[i];
2523 	}
2524 
2525 	/* Replace existing pointer to VPPA services w/ newly adjusted one */
2526 	if (ibnex.ibnex_hcasvc_comm_svc_names) {
2527 		kmem_free(ibnex.ibnex_hcasvc_comm_svc_names, nsvcs *
2528 		    sizeof (char *));
2529 		ibnex.ibnex_nhcasvc_comm_svcs--;
2530 		ibnex.ibnex_hcasvc_comm_svc_names = service_name;
2531 	}
2532 	return (0);
2533 }
2534 
2535 
2536 /*
2537  * ibnex_ioc_fininode()
2538  *	Un-initialize a child device node for IOC device node
2539  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
2540  */
2541 static ibnex_rval_t
2542 ibnex_ioc_fininode(dev_info_t *dip, ibnex_ioc_node_t *ioc_nodep)
2543 {
2544 	int	rval = MDI_SUCCESS;
2545 
2546 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2547 	IBTF_DPRINTF_L4("ibnex", "\tioc_fininode");
2548 
2549 	/*
2550 	 * For a dis-connected IOC,
2551 	 *	Free the ioc_profile &&
2552 	 *	decrement ibnex_num_disconnect_iocs
2553 	 */
2554 	if (ioc_nodep->ioc_ngids == 0 && ioc_nodep->ioc_profile) {
2555 		IBTF_DPRINTF_L4("ibnex", "\tioc_fininode: unconfigure "
2556 		    "disconnected IOC: GUID %lX", ioc_nodep->ioc_guid);
2557 		ibnex.ibnex_num_disconnect_iocs--;
2558 		kmem_free(ioc_nodep->ioc_profile,
2559 		    sizeof (ib_dm_ioc_ctrl_profile_t));
2560 		ioc_nodep->ioc_profile = NULL;
2561 	}
2562 
2563 	mutex_exit(&ibnex.ibnex_mutex);
2564 	ASSERT(i_ddi_node_state(dip) >= DS_BOUND);
2565 
2566 	IBTF_DPRINTF_L4("ibnex", "\tioc_fininode: offlining the IOC");
2567 	rval = ibnex_offline_childdip(dip);
2568 
2569 	if (rval != MDI_SUCCESS) {
2570 		rval = NDI_FAILURE;
2571 		IBTF_DPRINTF_L2("ibnex", "\toffline failed for IOC "
2572 		    "dip %p with 0x%x", dip, rval);
2573 	}
2574 
2575 	mutex_enter(&ibnex.ibnex_mutex);
2576 	return (rval == MDI_SUCCESS ? IBNEX_SUCCESS : IBNEX_OFFLINE_FAILED);
2577 }
2578 
2579 
2580 int
2581 ibnex_offline_childdip(dev_info_t *dip)
2582 {
2583 	int		rval = MDI_SUCCESS;
2584 	mdi_pathinfo_t	*path = NULL, *temp;
2585 
2586 	IBTF_DPRINTF_L4("ibnex", "\toffline_childdip; begin");
2587 	if (dip == NULL) {
2588 		IBTF_DPRINTF_L2("ibnex", "\toffline_childdip; NULL dip");
2589 		return (MDI_FAILURE);
2590 	}
2591 
2592 	for (path = mdi_get_next_phci_path(dip, path); path; ) {
2593 		IBTF_DPRINTF_L4("ibnex", "\toffline_childdip: "
2594 		    "offling path %p", path);
2595 		rval = mdi_pi_offline(path, NDI_UNCONFIG);
2596 		if (rval != MDI_SUCCESS) {
2597 			IBTF_DPRINTF_L2("ibnex", "\toffline_childdip: "
2598 			    "mdi_pi_offline failed %p", dip);
2599 			break;
2600 		}
2601 		temp = path;
2602 		path = mdi_get_next_phci_path(dip, path);
2603 		(void) mdi_pi_free(temp, 0);
2604 	}
2605 	return (rval);
2606 }
2607 
2608 
2609 /*
2610  * ibnex_commsvc_fininode()
2611  *
2612  * Un-initialize a child device node for HCA port / node GUID
2613  * for a communication service.
2614  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
2615  */
2616 static ibnex_rval_t
2617 ibnex_commsvc_fininode(dev_info_t *dip)
2618 {
2619 	int	rval = NDI_SUCCESS;
2620 
2621 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2622 	IBTF_DPRINTF_L4("ibnex", "\tcommsvc_fininode");
2623 
2624 	mutex_exit(&ibnex.ibnex_mutex);
2625 	if (i_ddi_node_state(dip) < DS_BOUND) {
2626 		/*
2627 		 * if the child hasn't been bound yet, we can
2628 		 * just free the dip. This path is currently
2629 		 * untested.
2630 		 */
2631 		(void) ddi_remove_child(dip, 0);
2632 		IBTF_DPRINTF_L4("ibnex",
2633 		    "\tcommsvc_fininode: ddi_remove_child");
2634 	} else {
2635 		IBTF_DPRINTF_L4("ibnex", "\tcommsvc_fininode: offlining the "
2636 		    "Commsvc node");
2637 
2638 		rval = ndi_devi_offline(dip, NDI_DEVI_REMOVE | NDI_UNCONFIG);
2639 		if (rval != NDI_SUCCESS)
2640 			IBTF_DPRINTF_L2("ibnex", "\toffline failed for Commsvc "
2641 			    "dip %p with 0x%x", dip, rval);
2642 	}
2643 	mutex_enter(&ibnex.ibnex_mutex);
2644 	return (rval == NDI_SUCCESS ? IBNEX_SUCCESS : IBNEX_OFFLINE_FAILED);
2645 }
2646 
2647 
2648 /*
2649  * ibnex_pseudo_fininode()
2650  *	Un-initialize a child pseudo device node
2651  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
2652  */
2653 static ibnex_rval_t
2654 ibnex_pseudo_fininode(dev_info_t *dip)
2655 {
2656 	int	rval = MDI_SUCCESS;
2657 
2658 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2659 	IBTF_DPRINTF_L4("ibnex", "\tpseudo_fininode: dip = %p", dip);
2660 
2661 	mutex_exit(&ibnex.ibnex_mutex);
2662 	ASSERT(i_ddi_node_state(dip) >= DS_BOUND);
2663 
2664 	IBTF_DPRINTF_L4("ibnex", "\tpseudo_fininode: offlining the "
2665 	    "pseudo device");
2666 	rval = ibnex_offline_childdip(dip);
2667 	if (rval != MDI_SUCCESS) {
2668 		rval = NDI_FAILURE;
2669 		IBTF_DPRINTF_L2("ibnex", "\tpseudo offline failed for "
2670 		    "dip %p with 0x%x", dip, rval);
2671 	}
2672 
2673 	mutex_enter(&ibnex.ibnex_mutex);
2674 	return (rval == MDI_SUCCESS ? IBNEX_SUCCESS : IBNEX_OFFLINE_FAILED);
2675 }
2676