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