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