xref: /illumos-gate/usr/src/uts/common/io/ib/ibnex/ibnex.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * The InfiniBand  Nexus driver (IB nexus) is a bus nexus driver for IB bus.
29  * It supports  Port nodes, Virtual Physical Point of Attachment nodes (VPPA)
30  * for  HCAs registered with IBTL and IOC nodes for all the IOCs present in
31  * the IB fabric (that are accessible to the host). It also supports Pseudo
32  * device children to be enumerated using their .conf file(s). All Port nodes
33  * and VPPA nodes are children of HCA drivers. All the IOC nodes and the Pseudo
34  * device nodes are children of the IB nexus driver.
35  *
36  * IB nexus driver provides bus nexus entry points to all the HCA drivers.
37  *
38  * IB nexus  driver registers with  InfiniBand Device  Manager (IBDM) to get
39  * information about all the HCA ports and  I/O Controllers (IOCs) connected
40  * to the IB fabric. Based on that information, IB nexus will create all the
41  * device tree nodes.
42  */
43 
44 #pragma ident	"%Z%%M%	%I%	%E% SMI"
45 
46 
47 #include <sys/conf.h>
48 #include <sys/stat.h>
49 #include <sys/modctl.h>
50 #include <sys/taskq.h>
51 #include <sys/mdi_impldefs.h>
52 #include <sys/sunmdi.h>
53 #include <sys/sunpm.h>
54 #include <sys/ib/mgt/ibdm/ibdm_impl.h>
55 #include <sys/ib/ibnex/ibnex.h>
56 #include <sys/ib/ibnex/ibnex_devctl.h>
57 #include <sys/ib/ibtl/ibti.h>
58 #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
59 #include <sys/file.h>
60 #include <sys/hwconf.h>
61 
62 /* Function prototypes */
63 static int		ibnex_attach(dev_info_t *, ddi_attach_cmd_t);
64 static int		ibnex_getinfo(dev_info_t *, ddi_info_cmd_t,
65 			    void *, void **);
66 static int		ibnex_detach(dev_info_t *, ddi_detach_cmd_t);
67 static int		ibnex_busctl(dev_info_t *,
68 			    dev_info_t *, ddi_ctl_enum_t, void *, void *);
69 static int		ibnex_map_fault(dev_info_t *,
70 			    dev_info_t *, struct hat *, struct seg *,
71 			    caddr_t, struct devpage *, pfn_t, uint_t, uint_t);
72 static int		ibnex_init_child(dev_info_t *);
73 static ibnex_rval_t	ibnex_comm_svc_init(char *, ibnex_node_type_t);
74 static void		ibnex_comm_svc_fini();
75 dev_info_t		*ibnex_commsvc_initnode(dev_info_t *,
76 			    ibdm_port_attr_t *, int, int, ib_pkey_t, int *,
77 			    int);
78 static void		ibnex_delete_port_node_data(ibnex_node_data_t *);
79 int			ibnex_get_dip_from_guid(ib_guid_t, int,
80 			    ib_pkey_t, dev_info_t **);
81 static ibnex_node_data_t *ibnex_is_node_data_present(ibnex_node_type_t,
82 			    void *, int, ib_pkey_t);
83 static ibnex_node_data_t *ibnex_init_child_nodedata(ibnex_node_type_t, void *,
84 			    int, ib_pkey_t);
85 static int		ibnex_create_port_node_prop(ibdm_port_attr_t *,
86 			    dev_info_t *, char *, ib_pkey_t);
87 void			ibnex_dm_callback(void *, ibdm_events_t);
88 static int		ibnex_create_port_compatible_prop(dev_info_t *,
89 			    char *, ibdm_port_attr_t *);
90 static int		ibnex_create_ioc_srv_props(
91 			    dev_info_t *, ibdm_ioc_info_t *);
92 static int		ibnex_get_eventcookie(dev_info_t *,
93 			    dev_info_t *, char *, ddi_eventcookie_t *);
94 static int		ibnex_add_eventcall(dev_info_t *, dev_info_t *,
95 			    ddi_eventcookie_t, void (*)(dev_info_t *,
96 			    ddi_eventcookie_t, void *, void *),
97 			    void *arg, ddi_callback_id_t *cb_id);
98 static int		ibnex_remove_eventcall(dev_info_t *,
99 			    ddi_callback_id_t);
100 static int		ibnex_post_event(dev_info_t *, dev_info_t *,
101 			    ddi_eventcookie_t, void *);
102 static int		ibnex_bus_config(dev_info_t *, uint_t,
103 			    ddi_bus_config_op_t, void *, dev_info_t **);
104 static int		ibnex_bus_unconfig(dev_info_t *,
105 			    uint_t, ddi_bus_config_op_t, void *);
106 static dev_info_t	*ibnex_config_port_node(dev_info_t *, char *);
107 static dev_info_t	*ibnex_config_obp_args(dev_info_t *, char *);
108 static int		ibnex_get_pkey_commsvc_index_portnum(
109 			    char *, int *, ib_pkey_t *, uint8_t *);
110 static void		ibnex_config_all_children(dev_info_t *);
111 static int		ibnex_devname_to_portnum(char *, uint8_t *);
112 static void		ibnex_create_vppa_nodes(
113 			    dev_info_t *, ibdm_port_attr_t *);
114 static void		ibnex_create_port_nodes(
115 			    dev_info_t *, ibdm_port_attr_t *);
116 static void		ibnex_create_hcasvc_nodes(
117 			    dev_info_t *, ibdm_port_attr_t *);
118 static int		ibnex_config_root_iocnode(dev_info_t *, char *);
119 static int		ibnex_devname2port(char *, int *);
120 static int		ibnex_config_ioc_node(char *);
121 static int		ibnex_devname_to_node_n_ioc_guids(
122 			    char *, ib_guid_t *, ib_guid_t *);
123 static int		ibnex_is_ioc_present(ib_guid_t);
124 static void		ibnex_ioc_node_cleanup();
125 static void		ibnex_delete_ioc_node_data(ibnex_node_data_t *);
126 int			ibnex_ioc_initnode(ibdm_ioc_info_t *, int);
127 static int		ibnex_create_ioc_node_prop(
128 			    ibdm_ioc_info_t *, dev_info_t *);
129 static int		ibnex_create_ioc_compatible_prop(
130 			    dev_info_t *, ib_dm_ioc_ctrl_profile_t *);
131 uint64_t		ibnex_str2hex(char *, int, int *);
132 static int		ibnex_str2int(char *, int, int *);
133 static int		ibnex_create_ioc_portgid_prop(
134 			    dev_info_t *, ibdm_ioc_info_t *);
135 static void		ibnex_wakeup_reprobe_ioc(ibnex_node_data_t *, int);
136 static void		ibnex_wakeup_reprobe_all();
137 ibt_status_t		ibnex_ibtl_callback(ibtl_ibnex_cb_args_t *);
138 static int		ibnex_prom_devname_to_pkey_n_portnum(
139 			    char *, ib_pkey_t *, uint8_t *);
140 void			ibnex_pseudo_initnodes(void);
141 static char		*ibnex_lookup_unit_address_prop(ddi_prop_t *);
142 static void		ibnex_pseudo_node_cleanup(void);
143 static int		ibnex_name_child(dev_info_t *, char *, int);
144 static int		ibnex_name_pseudo_child(dev_info_t *, char *);
145 
146 void			ibnex_reprobe_ioc_dev(void *);
147 void			ibnex_reprobe_ioc_all();
148 static void		ibnex_update_prop(ibnex_node_data_t *,
149 			    ibdm_ioc_info_t *);
150 static ibnex_rval_t	ibnex_unique_svcname(char *);
151 static void		ibnex_handle_reprobe_dev(void *arg);
152 
153 extern int		ibnex_open(dev_t *, int, int, cred_t *);
154 extern int		ibnex_close(dev_t, int, int, cred_t *);
155 extern int		ibnex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
156 extern int		ibnex_offline_childdip(dev_info_t *);
157 
158 static int		ibnex_ioc_create_pi(
159 			    ibdm_ioc_info_t *, ibnex_node_data_t *);
160 static int		ibnex_bus_power(dev_info_t *, void *,
161 			    pm_bus_power_op_t, void *, void *);
162 int			ibnex_pseudo_create_pi(ibnex_node_data_t *);
163 int			ibnex_pseudo_config_one(
164 			    ibnex_node_data_t *, char *, char *);
165 static void		ibnex_config_pseudo_all(void);
166 /*
167  * The bus_ops structure defines the capabilities of HCA nexus driver.
168  */
169 struct bus_ops ibnex_ci_busops = {
170 	BUSO_REV,
171 	nullbusmap,		/* bus_map */
172 	NULL,			/* bus_get_intrspec */
173 	NULL,			/* bus_add_intrspec */
174 	NULL,			/* bus_remove_intrspec */
175 	ibnex_map_fault,	/* Map Fault */
176 	ddi_no_dma_map,		/* DMA related entry points */
177 	NULL,
178 	NULL,
179 	NULL,
180 	NULL,
181 	NULL,
182 	NULL,
183 	NULL,
184 	ibnex_busctl,		/* bus_ctl */
185 	ddi_bus_prop_op,	/* bus_prop_op */
186 	NULL,			/* bus_get_eventcookie	*/
187 	NULL,			/* bus_add_eventcall	*/
188 	NULL,			/* bus_remove_eventcall	*/
189 	NULL,			/* bus_post_event	*/
190 	NULL,
191 	ibnex_bus_config,	/* bus config */
192 	ibnex_bus_unconfig	/* bus unconfig */
193 };
194 
195 
196 /*
197  * Prototype declarations for the VHCI options
198  */
199 /*
200  * Functions registered with the mpxio framework
201  */
202 static int ib_vhci_pi_init(dev_info_t *, mdi_pathinfo_t *, int);
203 static int ib_vhci_pi_uninit(dev_info_t *, mdi_pathinfo_t *, int);
204 static int ib_vhci_pi_state_change(dev_info_t *, mdi_pathinfo_t *,
205 		mdi_pathinfo_state_t, uint32_t, int);
206 static int ib_vhci_failover(dev_info_t *, dev_info_t *, int);
207 
208 
209 static mdi_vhci_ops_t ibnex_vhci_ops = {
210 	MDI_VHCI_OPS_REV,
211 	ib_vhci_pi_init,
212 	ib_vhci_pi_uninit,
213 	ib_vhci_pi_state_change,
214 	ib_vhci_failover
215 };
216 
217 
218 /*
219  * The  bus_ops  structure  defines the  capabilities  of IB nexus driver.
220  * IB nexus drivers does not  support any DMA  operations for its children
221  * as there is  no  such concept in Infiniband.  All the memory operations
222  * and DMA operations required by the child drivers can be performed using
223  * the IBTF API.
224  */
225 struct bus_ops ibnex_bus_ops = {
226 	BUSO_REV,
227 	nullbusmap,		/* bus_map */
228 	NULL,			/* bus_get_intrspec */
229 	NULL,			/* bus_add_intrspec */
230 	NULL,			/* bus_remove_intrspec */
231 	ibnex_map_fault,	/* Map Fault */
232 	ddi_no_dma_map,		/* DMA related entry points */
233 	ddi_no_dma_allochdl,
234 	NULL,
235 	NULL,
236 	NULL,
237 	NULL,
238 	NULL,
239 	NULL,
240 	ibnex_busctl,		/* bus_ctl */
241 	ddi_bus_prop_op,	/* bus_prop_op */
242 	ibnex_get_eventcookie,	/* bus_get_eventcookie	*/
243 	ibnex_add_eventcall,	/* bus_add_eventcall	*/
244 	ibnex_remove_eventcall,	/* bus_remove_eventcall	*/
245 	ibnex_post_event,		/* bus_post_event	*/
246 	NULL,
247 	ibnex_bus_config,	/* bus config */
248 	ibnex_bus_unconfig,	/* bus unconfig */
249 	NULL,			/* bus fm init */
250 	NULL,			/* bus fm fini */
251 	NULL,			/* bus fm access enter */
252 	NULL,			/* bus fm access exit */
253 	ibnex_bus_power		/* bus power */
254 };
255 
256 
257 /* ibnex cb_ops */
258 static struct cb_ops ibnex_cbops = {
259 	ibnex_open,		/* open */
260 	ibnex_close,		/* close */
261 	nodev,			/* strategy */
262 	nodev,			/* print */
263 	nodev,			/* dump */
264 	nodev,			/* read */
265 	nodev,			/* write */
266 	ibnex_ioctl,		/* ioctl */
267 	nodev,			/* devmap */
268 	nodev,			/* mmap */
269 	nodev,			/* segmap */
270 	nochpoll,		/* poll */
271 	ddi_prop_op,		/* prop_op */
272 	NULL,			/* stream */
273 	D_MP,			/* cb_flag */
274 	CB_REV, 		/* rev */
275 	nodev,			/* int (*cb_aread)() */
276 	nodev			/* int (*cb_awrite)() */
277 };
278 
279 /*
280  * Device options
281  * Note: ddi_no_info needs to change during devfs time frame. The drivers
282  *	 with 1 to 1 mapping between minor node and instance should use
283  *	 ddi_1to1_info. (See bug id 4424752)
284  */
285 static struct dev_ops ibnex_ops = {
286 	DEVO_REV,		/* devo_rev, */
287 	0,			/* refcnt  */
288 	ibnex_getinfo,		/* info */
289 	nulldev,		/* identify */
290 	nulldev,		/* probe */
291 	ibnex_attach,		/* attach */
292 	ibnex_detach,		/* detach */
293 	nodev,			/* reset */
294 	&ibnex_cbops,		/* driver ops - devctl interfaces */
295 	&ibnex_bus_ops,		/* bus operations */
296 	nulldev			/* power */
297 };
298 
299 /* Module linkage information for the kernel.  */
300 static struct modldrv modldrv = {
301 	&mod_driverops,		/* Driver module */
302 	"IB nexus %I%",		/* Driver name and version */
303 	&ibnex_ops,		/* driver ops */
304 };
305 
306 static struct modlinkage modlinkage = {
307 	MODREV_1, (void *)&modldrv, NULL
308 };
309 
310 /*
311  * Global per-instance IB Nexus data.
312  * There is only one instance of IB Nexus supported.
313  */
314 ibnex_t ibnex;
315 #ifdef __lock_lint
316 extern ibdm_t ibdm;
317 #endif
318 _NOTE(MUTEX_PROTECTS_DATA(ibnex.ibnex_mutex, ibnex_s))
319 _NOTE(DATA_READABLE_WITHOUT_LOCK(ibnex.ibnex_num_comm_svcs
320 	ibnex.ibnex_comm_svc_names ibnex.ibnex_nvppa_comm_svcs
321 	ibnex.ibnex_vppa_comm_svc_names ibnex.ibnex_nhcasvc_comm_svcs
322 	ibnex.ibnex_hcasvc_comm_svc_names))
323 _NOTE(MUTEX_PROTECTS_DATA(ibnex.ibnex_mutex, ibnex_node_data_s))
324 _NOTE(LOCK_ORDER(ibdm.ibdm_hl_mutex ibnex.ibnex_mutex))
325 
326 /* The port settling time in seconds */
327 int	ibnex_port_settling_time = 8;
328 
329 /* create an array of properties supported, easier to add new ones here */
330 static struct ibnex_property {
331 	char			*name;
332 	ibnex_node_type_t	type;
333 } ibnex_properties[]  = {
334 	{ "port-svc-list",  IBNEX_PORT_COMMSVC_NODE},
335 	{ "vppa-svc-list",  IBNEX_VPPA_COMMSVC_NODE},
336 	{ "hca-svc-list",	IBNEX_HCASVC_COMMSVC_NODE}
337 };
338 
339 #define	N_IBNEX_PROPS	(sizeof (ibnex_properties))/ \
340 				(sizeof (struct ibnex_property))
341 
342 /*
343  * Event Definition
344  *	Single event, event name defined in ibti_common.h.
345  *	Event posted to specific child handler. Event posted
346  *	at kernel priority.
347  */
348 static ndi_event_definition_t ibnex_ndi_event_defs[] = {
349 	{IB_EVENT_TAG_PROP_UPDATE,  IB_PROP_UPDATE_EVENT, EPL_KERNEL,
350 		NDI_EVENT_POST_TO_TGT}
351 };
352 
353 #define	IB_N_NDI_EVENTS	\
354 	(sizeof (ibnex_ndi_event_defs) / sizeof (ndi_event_definition_t))
355 
356 static ndi_event_set_t ib_ndi_events = {
357 	NDI_EVENTS_REV1, IB_N_NDI_EVENTS, ibnex_ndi_event_defs};
358 
359 
360 /*
361  * _init
362  *	Loadable module init, called before any other module.
363  */
364 int
365 _init(void)
366 {
367 	int	error;
368 
369 	IBTF_DPRINTF_L4("ibnex", "\t_init");
370 	mutex_init(&ibnex.ibnex_mutex, NULL, MUTEX_DRIVER, NULL);
371 	cv_init(&ibnex.ibnex_reprobe_cv, NULL, CV_DRIVER, NULL);
372 	if ((error = mod_install(&modlinkage)) != 0) {
373 		IBTF_DPRINTF_L2("ibnex", "\t_init: mod_install failed");
374 		mutex_destroy(&ibnex.ibnex_mutex);
375 		cv_destroy(&ibnex.ibnex_reprobe_cv);
376 	} else {
377 		ibdm_ibnex_register_callback(ibnex_dm_callback);
378 		ibtl_ibnex_register_callback(ibnex_ibtl_callback);
379 	}
380 	return (error);
381 }
382 
383 
384 /*
385  * _fini
386  *	Prepares a module for unloading.
387  */
388 int
389 _fini(void)
390 {
391 	int	error;
392 
393 	IBTF_DPRINTF_L4("ibnex", "\t_fini");
394 	if ((error = mod_remove(&modlinkage)) != 0) {
395 		return (error);
396 	}
397 	ibdm_ibnex_unregister_callback();
398 	ibtl_ibnex_unregister_callback();
399 	mutex_destroy(&ibnex.ibnex_mutex);
400 	cv_destroy(&ibnex.ibnex_reprobe_cv);
401 	return (0);
402 }
403 
404 
405 /*
406  * _info
407  *	Returns information about loadable module.
408  */
409 int
410 _info(struct modinfo *modinfop)
411 {
412 	IBTF_DPRINTF_L4("ibnex", "\t_info");
413 	return (mod_info(&modlinkage, modinfop));
414 }
415 
416 
417 /*
418  * ibnex_attach
419  *	Configure and attach an instance of the IB Nexus driver
420  *	Only one instance of IB Nexus is supported
421  *	Create a minor node for cfgadm purpose
422  *	Initialize communication services
423  *	Register callback with IBDM
424  *	Register callback with IBTL
425  */
426 static int
427 ibnex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
428 {
429 	int		i;
430 	int		instance = ddi_get_instance(dip);
431 
432 	IBTF_DPRINTF_L4("ibnex", "\tattach: device = %p cmd = %x)", dip, cmd);
433 
434 	switch (cmd) {
435 	case DDI_ATTACH:
436 		break;
437 	case DDI_RESUME:
438 		IBTF_DPRINTF_L4("ibnex", "\tattach: RESUME");
439 		return (DDI_SUCCESS);
440 	default:
441 		return (DDI_FAILURE);
442 	}
443 
444 	/* Fail attach for more than one instance */
445 	mutex_enter(&ibnex.ibnex_mutex);
446 	if (ibnex.ibnex_dip != NULL) {
447 		mutex_exit(&ibnex.ibnex_mutex);
448 		return (DDI_FAILURE);
449 	}
450 	mutex_exit(&ibnex.ibnex_mutex);
451 
452 	/* Register with MPxIO framework */
453 
454 	if (mdi_vhci_register(MDI_HCI_CLASS_IB, dip, &ibnex_vhci_ops, 0)
455 	    != MDI_SUCCESS) {
456 		IBTF_DPRINTF_L2("ibnex",
457 		    "\tattach: mdi_vhci_register() failed");
458 		return (DDI_FAILURE);
459 	}
460 
461 
462 	/*
463 	 * Create the "fabric" devctl minor-node for IB DR support.
464 	 * The minor number for the "devctl" node is in the same format
465 	 * as the AP minor nodes.
466 	 */
467 	if (ddi_create_minor_node(dip, IBNEX_FABRIC, S_IFCHR, instance,
468 	    DDI_NT_IB_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
469 		IBTF_DPRINTF_L2("ibnex",
470 		    "\tattach: failed to create fabric minornode");
471 		(void) mdi_vhci_unregister(dip, 0);
472 		return (DDI_FAILURE);
473 	}
474 
475 
476 	/*
477 	 * Set pm-want-child-notification property for
478 	 * power management of the phci and client
479 	 */
480 	if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
481 	    "pm-want-child-notification?", NULL, NULL) != DDI_PROP_SUCCESS) {
482 		IBTF_DPRINTF_L2("ibnex",
483 		    "_attach: create pm-want-child-notification failed");
484 		(void) ddi_remove_minor_node(dip, NULL);
485 		(void) mdi_vhci_unregister(dip, 0);
486 		return (DDI_FAILURE);
487 	}
488 
489 	mutex_enter(&ibnex.ibnex_mutex);
490 	ibnex.ibnex_dip  = dip;
491 	mutex_exit(&ibnex.ibnex_mutex);
492 
493 	/*
494 	 * Event Handling: Definition and Binding.
495 	 */
496 	if (ndi_event_alloc_hdl(dip, 0, &ibnex.ibnex_ndi_event_hdl,
497 	    NDI_SLEEP) != NDI_SUCCESS) {
498 		(void) ddi_remove_minor_node(dip, NULL);
499 		IBTF_DPRINTF_L2("ibnex",
500 		    "_attach: ndi_event_alloc_hdl failed");
501 		(void) mdi_vhci_unregister(dip, 0);
502 		return (DDI_FAILURE);
503 	}
504 	if (ndi_event_bind_set(ibnex.ibnex_ndi_event_hdl, &ib_ndi_events,
505 	    NDI_SLEEP) != NDI_SUCCESS) {
506 		(void) ddi_remove_minor_node(dip, NULL);
507 		(void) ndi_event_free_hdl(ibnex.ibnex_ndi_event_hdl);
508 		IBTF_DPRINTF_L2("ibnex",
509 		    "_attach: ndi_event_bind_set failed");
510 		(void) mdi_vhci_unregister(dip, 0);
511 		return (DDI_FAILURE);
512 	}
513 
514 	for (i = 0; i < N_IBNEX_PROPS; i++) {
515 		if (ibnex_comm_svc_init(ibnex_properties[i].name,
516 		    ibnex_properties[i].type) != IBNEX_SUCCESS) {
517 			ibnex_comm_svc_fini();
518 			(void) ndi_event_unbind_set(ibnex.ibnex_ndi_event_hdl,
519 			    &ib_ndi_events, NDI_SLEEP);
520 			(void) ddi_remove_minor_node(dip, NULL);
521 			(void) ndi_event_free_hdl(
522 			    ibnex.ibnex_ndi_event_hdl);
523 			ibnex.ibnex_ndi_event_hdl = NULL;
524 			IBTF_DPRINTF_L2("ibnex", "_attach: ibnex_comm_svc_init"
525 			    " failed %s", ibnex_properties[i].name);
526 			(void) mdi_vhci_unregister(dip, 0);
527 			return (DDI_FAILURE);
528 		}
529 	}
530 
531 	/*
532 	 * before anything else comes up:
533 	 * Initialize the internal list of pseudo device nodes by
534 	 * getting all pseudo children of "ib" and processing them.
535 	 */
536 	ibnex_pseudo_initnodes();
537 
538 	return (DDI_SUCCESS);
539 }
540 
541 
542 /*
543  * ibnex_getinfo()
544  * Given the device number, return the devinfo pointer or the
545  * instance number.
546  * Note: always succeed DDI_INFO_DEVT2INSTANCE, even before attach.
547  */
548 
549 /*ARGSUSED*/
550 static int
551 ibnex_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
552 {
553 	int ret = DDI_SUCCESS;
554 
555 	IBTF_DPRINTF_L4("ibnex", "\tgetinfo: Begin");
556 	switch (cmd) {
557 	case DDI_INFO_DEVT2DEVINFO:
558 		if (ibnex.ibnex_dip != NULL)
559 			*result = ibnex.ibnex_dip;
560 		else {
561 			*result = NULL;
562 			ret = DDI_FAILURE;
563 		}
564 		break;
565 
566 	case DDI_INFO_DEVT2INSTANCE:
567 		*result = 0;
568 		break;
569 
570 	default:
571 		ret = DDI_FAILURE;
572 	}
573 	return (ret);
574 }
575 
576 
577 /*
578  * ibnex_detach
579  *	Unregister callback with the IBDM
580  *	Unregister callback with the IBTL
581  *	Uninitialize the communication entries
582  *	Remove all the minor nodes created by this instance
583  */
584 static int
585 ibnex_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
586 {
587 
588 	IBTF_DPRINTF_L4("ibnex", "\tdetach: dip = %p cmd = %x)", dip, cmd);
589 
590 	switch (cmd) {
591 
592 	case DDI_DETACH:
593 		break;
594 	case DDI_SUSPEND:
595 		IBTF_DPRINTF_L4("ibnex", "\t_detach: Suspend");
596 		return (DDI_SUCCESS);
597 	default:
598 		return (DDI_FAILURE);
599 	}
600 
601 	mutex_enter(&ibnex.ibnex_mutex);
602 	if (ibt_hw_is_present()) {
603 		IBTF_DPRINTF_L2("ibnex",
604 		    "\tdetach: IB HW is present ");
605 		mutex_exit(&ibnex.ibnex_mutex);
606 		return (DDI_FAILURE);
607 	}
608 	if (ndi_event_free_hdl(ibnex.ibnex_ndi_event_hdl)) {
609 		IBTF_DPRINTF_L2("ibnex",
610 		    "\tdetach: ndi_event_free_hdl() failed");
611 		mutex_exit(&ibnex.ibnex_mutex);
612 		return (DDI_FAILURE);
613 	}
614 	ibnex.ibnex_ndi_event_hdl = NULL;
615 	ibnex.ibnex_prop_update_evt_cookie = NULL;
616 
617 	ibnex_pseudo_node_cleanup();
618 	ibnex_comm_svc_fini();
619 	ibnex_ioc_node_cleanup();
620 
621 	(void) ddi_remove_minor_node(dip, NULL);
622 	ibnex.ibnex_dip = NULL;
623 	mutex_exit(&ibnex.ibnex_mutex);
624 	(void) mdi_vhci_unregister(dip, 0);
625 	return (DDI_SUCCESS);
626 }
627 
628 
629 /*
630  * ibnex_pseudo_node_cleanup()
631  *	This checks if all the "dips" have been deallocated (implying
632  *	that all the children have been unconfigured) first.
633  *	If not, it just returns.
634  *	If yes, then it frees up memory allocated for devi_name,
635  *	node_addr, and property list.
636  */
637 static void
638 ibnex_pseudo_node_cleanup(void)
639 {
640 	ibnex_node_data_t	*nodep =  ibnex.ibnex_pseudo_node_head;
641 	ibnex_pseudo_node_t	*pseudo;
642 
643 	IBTF_DPRINTF_L4("ibnex", "\tpseudo_node_cleanup:");
644 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
645 
646 	for (; nodep; nodep = nodep->node_next)
647 		if (nodep->node_dip)
648 			return;
649 
650 	IBTF_DPRINTF_L4("ibnex", "\tpseudo_node_cleanup: freeing up memory");
651 	for (nodep =  ibnex.ibnex_pseudo_node_head; nodep;
652 	    nodep = nodep->node_next) {
653 
654 		pseudo = &nodep->node_data.pseudo_node;
655 		if (pseudo->pseudo_node_addr) {
656 			kmem_free(pseudo->pseudo_node_addr,
657 			    strlen(pseudo-> pseudo_node_addr) + 1);
658 			pseudo->pseudo_node_addr = NULL;
659 		}
660 
661 		if (pseudo->pseudo_devi_name) {
662 			kmem_free(pseudo->pseudo_devi_name,
663 			    strlen(pseudo-> pseudo_devi_name) + 1);
664 			pseudo->pseudo_devi_name = NULL;
665 		}
666 
667 		if (pseudo->pseudo_unit_addr) {
668 			kmem_free(pseudo->pseudo_unit_addr,
669 			    pseudo->pseudo_unit_addr_len);
670 		}
671 	}
672 }
673 
674 
675 /*
676  * This functions wakes up any reprobe requests waiting for completion
677  * of reprobe of this IOC. It also send an NDI event, if  :
678  *
679  *	notify_flag is set. This is set if :
680  *		ibt_reprobe_ioc has returned with SUCCESS
681  *		IBTF client has not been notified for this node.
682  *	node_data->node_dip != NULL
683  *	node_state has IBNEX_NODE_REPROBE_NOTIFY_ALWAYS set
684  *	An NDI event cookie has been registered.
685  */
686 static void
687 ibnex_wakeup_reprobe_ioc(ibnex_node_data_t *node_data, int notify_flag)
688 {
689 	ddi_eventcookie_t	evt_cookie;
690 
691 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
692 	evt_cookie = ibnex.ibnex_prop_update_evt_cookie;
693 
694 	if ((ibnex.ibnex_reprobe_state == IBNEX_REPROBE_IOC_WAIT) ||
695 	    (node_data->node_reprobe_state != 0)) {
696 		if (notify_flag && (node_data->node_dip != NULL) &&
697 		    (node_data->node_state &
698 		    IBNEX_NODE_REPROBE_NOTIFY_ALWAYS) &&
699 		    (evt_cookie != NULL)) {
700 			ibt_prop_update_payload_t	evt_data;
701 
702 			mutex_exit(&ibnex.ibnex_mutex);
703 
704 			bzero(&evt_data, sizeof (evt_data));
705 			if (ndi_post_event(ibnex.ibnex_dip,
706 			    node_data->node_dip,
707 			    evt_cookie, &evt_data) != NDI_SUCCESS)
708 				IBTF_DPRINTF_L2("ibnex",
709 				    "\tndi_post_event failed\n");
710 
711 			mutex_enter(&ibnex.ibnex_mutex);
712 		}
713 
714 		node_data->node_reprobe_state = 0;
715 		cv_broadcast(&ibnex.ibnex_reprobe_cv);
716 	}
717 	node_data->node_reprobe_state = 0;
718 }
719 
720 /*
721  * This function wakes up any reprobe request waiting for completion
722  * of reprobe of all IOCs.
723  */
724 static void
725 ibnex_wakeup_reprobe_all()
726 {
727 	ibnex_node_data_t *ioc_node;
728 
729 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
730 
731 	/* Notify if another reprobe_all is pending */
732 	if (ibnex.ibnex_reprobe_state == IBNEX_REPROBE_ALL_WAIT) {
733 		ibnex.ibnex_reprobe_state = 0;
734 		cv_broadcast(&ibnex.ibnex_reprobe_cv);
735 	}
736 	ibnex.ibnex_reprobe_state = 0;
737 
738 	/*
739 	 * The IOC may be hot-removed after the reprobe request.
740 	 * Reset the reprobe states for such IOCs.
741 	 */
742 	for (ioc_node = ibnex.ibnex_ioc_node_head; ioc_node;
743 	    ioc_node = ioc_node->node_next) {
744 		if (ioc_node->node_reprobe_state != 0) {
745 			ibnex_wakeup_reprobe_ioc(ioc_node, 1);
746 		}
747 	}
748 }
749 
750 /*
751  * ibnex_ibnex_callback:
752  *	IBTL_IBNEX_IBC_INIT:
753  *		Called from ibc_init() which is called from
754  *		HCA driver _init entry point
755  *		Initializes the HCA dev_ops structure with default
756  *		IB nexus structure.
757  *	IBTL_IBNEX_IBC_FINI:
758  *		Called from ibc_fini() which is called from
759  *		HCA driver _fini entry point
760  *		Un-Initializes the HCA dev_ops structure with default
761  *		IB nexus strucuture.
762  *	Returns IBT_SUCCESS
763  */
764 ibt_status_t
765 ibnex_ibtl_callback(ibtl_ibnex_cb_args_t *cb_args)
766 {
767 	int			retval = IBT_SUCCESS;
768 	struct dev_ops 		*hca_dev_ops;
769 	dev_info_t		*clnt_dip;
770 	ibnex_node_data_t	*node_data;
771 
772 	IBTF_DPRINTF_L5("ibnex", "\tibtl_callback");
773 
774 	switch (cb_args->cb_flag) {
775 	case IBTL_IBNEX_IBC_INIT:
776 		/*
777 		 * Get the devops structure of the HCA,
778 		 * and put IB nexus default busops vector in its place.
779 		 */
780 		hca_dev_ops = ((struct modldrv *)
781 			(cb_args->cb_modlp->ml_linkage[0]))->drv_dev_ops;
782 		ASSERT((hca_dev_ops) && (hca_dev_ops->devo_bus_ops == NULL));
783 		hca_dev_ops->devo_bus_ops = &ibnex_ci_busops;
784 		break;
785 
786 	case IBTL_IBNEX_IBC_FINI:
787 		hca_dev_ops = ((struct modldrv *)
788 			(cb_args->cb_modlp->ml_linkage[0]))->drv_dev_ops;
789 		hca_dev_ops->devo_bus_ops = NULL;
790 		break;
791 
792 	case IBTL_IBNEX_REPROBE_DEV_REQ:
793 		/* IBTL pass down request for ibt_reprobe_dev */
794 		clnt_dip = cb_args->cb_dip;
795 		ASSERT(clnt_dip);
796 
797 		node_data = ddi_get_parent_data(clnt_dip);
798 		ASSERT(node_data);
799 
800 		/* Reprobe for IOC nodes only */
801 		ASSERT(node_data->node_type == IBNEX_IOC_NODE);
802 
803 		/*
804 		 * Start the reprobe. This could sleep as it is not
805 		 * from interrupt context.
806 		 */
807 		if (taskq_dispatch(system_taskq, ibnex_handle_reprobe_dev,
808 		    clnt_dip, TQ_SLEEP) == 0) {
809 			IBTF_DPRINTF_L2("ibnex",
810 			    "ibnex_ibtl_callback: taskq_dispatch failed");
811 			mutex_enter(&ibnex.ibnex_mutex);
812 			ibnex_wakeup_reprobe_ioc(node_data, 0);
813 			mutex_exit(&ibnex.ibnex_mutex);
814 			return (IBT_INSUFF_KERNEL_RESOURCE);
815 		}
816 		return (IBT_SUCCESS);
817 	}
818 
819 	return (retval);
820 }
821 
822 
823 /*
824  * Bus-ops entry points
825  */
826 
827 /*
828  * ibnex_map_fault
829  * 	IOC drivers need not map memory. Return failure to fail any
830  *	such calls.
831  */
832 /*ARGSUSED*/
833 static int
834 ibnex_map_fault(dev_info_t *dip, dev_info_t *rdip, struct hat *hat,
835     struct seg *seg, caddr_t addr, struct devpage *dp, pfn_t pfn,
836     uint_t prot, uint_t lock)
837 {
838 	return (DDI_FAILURE);
839 }
840 
841 
842 /*
843  * ibnex_busctl
844  * 	bus_ctl bus_ops entry point
845  */
846 /*ARGSUSED*/
847 static int
848 ibnex_busctl(dev_info_t *dip, dev_info_t *rdip,
849     ddi_ctl_enum_t ctlop, void *arg, void *result)
850 {
851 	dev_info_t		*child_dip;
852 
853 	IBTF_DPRINTF_L4("ibnex",
854 	    "\tbusctl: dip = %p, rdip = %p, ctlop = %x,", dip, rdip, ctlop);
855 	IBTF_DPRINTF_L4("ibnex", "\tbusctl: targ = %p, result %p", arg, result);
856 
857 	switch (ctlop) {
858 	case DDI_CTLOPS_REPORTDEV:
859 		if (rdip == NULL) {
860 			return (DDI_FAILURE);
861 		}
862 
863 		/* Log the relevant details of dip to sysbuf */
864 		cmn_err(CE_CONT, "?IB device: %s@%s, %s%d\n",
865 		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
866 		    ddi_driver_name(rdip), ddi_get_instance(rdip));
867 
868 		return (DDI_SUCCESS);
869 
870 	case DDI_CTLOPS_INITCHILD:
871 		child_dip = (dev_info_t *)arg;
872 		return (ibnex_init_child(child_dip));
873 
874 	case DDI_CTLOPS_UNINITCHILD:
875 		child_dip = (dev_info_t *)arg;
876 		ddi_set_name_addr(child_dip, NULL);
877 		return (DDI_SUCCESS);
878 
879 	case DDI_CTLOPS_ATTACH:
880 	case DDI_CTLOPS_DETACH:
881 	case DDI_CTLOPS_POWER :
882 		return (DDI_SUCCESS);
883 
884 	case DDI_CTLOPS_SIDDEV:
885 		/*
886 		 * Return DDI_SUCCESS for IOC/PORT/VPPA nodes and
887 		 * DDI_FAILURE for the nodes enumerated by a Pseudo file.
888 		 */
889 		return (ndi_dev_is_persistent_node(rdip) ?
890 		    DDI_SUCCESS : DDI_FAILURE);
891 
892 
893 	case DDI_CTLOPS_IOMIN:
894 		/*
895 		 * Return DDI_SUCCESS, so that consistent buf alloc
896 		 * gets the default DMA IO minimum for the platform
897 		 */
898 		return (DDI_SUCCESS);
899 
900 	/*
901 	 * These ops correspond to functions that "shouldn't" be
902 	 * called by IB Nexus driver.
903 	 */
904 	case DDI_CTLOPS_DMAPMAPC:
905 	case DDI_CTLOPS_REPORTINT:
906 	case DDI_CTLOPS_REGSIZE:
907 	case DDI_CTLOPS_NREGS:
908 	case DDI_CTLOPS_NINTRS:
909 	case DDI_CTLOPS_SLAVEONLY:
910 	case DDI_CTLOPS_AFFINITY:
911 	case DDI_CTLOPS_INTR_HILEVEL:
912 	case DDI_CTLOPS_XLATE_INTRS:
913 	case DDI_CTLOPS_POKE:
914 	case DDI_CTLOPS_PEEK:
915 		IBTF_DPRINTF_L2("ibnex",
916 		    "%s%d: invalid op (%d) from %s inst%d",
917 		    ddi_get_name(dip), ddi_get_instance(dip),
918 		    ctlop, ddi_get_name(rdip), ddi_get_instance(rdip));
919 		return (DDI_FAILURE);
920 
921 	/*
922 	 * Everything else (PTOB/BTOP/BTOPR/DVMAPAGESIZE requests) we
923 	 * pass up
924 	 */
925 	default:
926 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
927 	}
928 }
929 
930 
931 /*
932  * ibnex_init_child()
933  *
934  * Initialize a child device node. This is called for the DDI_CTLOPS_INITCHILD
935  * entry. Function returns DDI_SUCCESS,  DDI_FAILURE or DDI_NOT_WELL_FORMED.
936  */
937 static int
938 ibnex_init_child(dev_info_t *child)
939 {
940 	int			ret;
941 	char			name[MAXNAMELEN];
942 
943 	IBTF_DPRINTF_L4("ibnex", "\tinit_child: child = %p", child);
944 
945 	/* Handle Pseudo nodes of client children */
946 	if (ndi_dev_is_persistent_node(child) == 0) {
947 		if (ibnex_name_pseudo_child(child, name) != DDI_SUCCESS)
948 			return (DDI_FAILURE);
949 
950 		ddi_set_name_addr(child, name);
951 		/*
952 		 * Merge the .conf node
953 		 */
954 		if (ndi_merge_node(child,
955 		    ibnex_name_child) == DDI_SUCCESS) {
956 			ddi_set_name_addr(child, NULL);
957 			return (DDI_FAILURE);
958 		}
959 		return (DDI_NOT_WELL_FORMED);
960 
961 	}
962 
963 	if ((ret = ibnex_name_child(child, name, 0)) != DDI_SUCCESS)
964 		return (ret);
965 
966 	ddi_set_name_addr(child, name);
967 
968 	return (DDI_SUCCESS);
969 }
970 
971 
972 int
973 ibnex_name_pseudo_child(dev_info_t *child, char *name)
974 {
975 	char **unit_addr;
976 	uint_t n;
977 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
978 	    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
979 	    DDI_PROP_SUCCESS) {
980 		cmn_err(CE_WARN,
981 		    "cannot find unit-address in %s.conf",
982 		    ddi_get_name(child));
983 		return (DDI_FAILURE);
984 	}
985 	if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
986 		cmn_err(CE_WARN, "unit-address property in %s.conf"
987 		    " not well-formed", ddi_get_name(child));
988 		ddi_prop_free(unit_addr);
989 		return (DDI_FAILURE);
990 	}
991 	(void) snprintf(name, MAXNAMELEN, "%s", *unit_addr);
992 	ddi_prop_free(unit_addr);
993 	return (DDI_SUCCESS);
994 }
995 
996 
997 /*ARGSUSED*/
998 int
999 ibnex_name_child(dev_info_t *child, char *name, int flag)
1000 {
1001 	ibnex_pseudo_node_t	*pseudo;
1002 	ibnex_node_data_t	*node_datap;
1003 	ibnex_port_node_t	*port_node;
1004 	ibnex_ioc_node_t	*ioc;
1005 
1006 	node_datap = ddi_get_parent_data(child);
1007 	if (node_datap == NULL) {
1008 		IBTF_DPRINTF_L2("ibnex", "\tname_child: Node data is NULL");
1009 		return (DDI_NOT_WELL_FORMED);
1010 	}
1011 	IBTF_DPRINTF_L4("ibnex", "\tname_sid_child: Node data %p"
1012 	    "Node type %x", node_datap, node_datap->node_type);
1013 	switch (node_datap->node_type) {
1014 	case IBNEX_PORT_COMMSVC_NODE:
1015 		port_node = &node_datap->node_data.port_node;
1016 		(void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%x,0,%s",
1017 		    port_node->port_num,
1018 		    ibnex.ibnex_comm_svc_names[port_node->port_commsvc_idx]);
1019 		break;
1020 	case IBNEX_VPPA_COMMSVC_NODE:
1021 		port_node = &node_datap->node_data.port_node;
1022 		(void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%x,%x,%s",
1023 		    port_node->port_num, port_node->port_pkey, ibnex.
1024 		    ibnex_vppa_comm_svc_names[port_node->port_commsvc_idx]);
1025 		break;
1026 	case IBNEX_HCASVC_COMMSVC_NODE:
1027 		port_node = &node_datap->node_data.port_node;
1028 		(void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%x,0,%s",
1029 		    port_node->port_num,
1030 		    ibnex.ibnex_hcasvc_comm_svc_names[port_node->
1031 		    port_commsvc_idx]);
1032 		break;
1033 	case IBNEX_IOC_NODE:
1034 		ioc = &node_datap->node_data.ioc_node;
1035 		(void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%llX,%llX",
1036 		    (longlong_t)ioc->ioc_guid, (longlong_t)ioc->iou_guid);
1037 		break;
1038 	case IBNEX_PSEUDO_NODE:
1039 		pseudo = &node_datap->node_data.pseudo_node;
1040 		(void) snprintf(name,
1041 		    IBNEX_MAX_NODEADDR_SZ, pseudo->pseudo_unit_addr);
1042 		break;
1043 	default:
1044 		IBTF_DPRINTF_L2("ibnex", "\name_child: Not well formed");
1045 		return (DDI_NOT_WELL_FORMED);
1046 	}
1047 
1048 	return (DDI_SUCCESS);
1049 }
1050 
1051 
1052 /*
1053  * ibnex_bus_config()
1054  *
1055  * BUS_CONFIG_ONE:
1056  *	Enumerate the exact instance of the driver. Use the device node name
1057  *	to locate the exact instance.
1058  *	Query IBDM to find whether the hardware exits for the instance of the
1059  *	driver. If exists, create a device node and return NDI_SUCCESS.
1060  *
1061  * BUS_CONFIG_ALL:
1062  *	Enumerate all the instances of all the possible children (seen before
1063  *	and never seen before).
1064  *
1065  * BUS_CONFIG_DRIVER:
1066  *	Enumerate all the instances of a particular driver.
1067  */
1068 static int
1069 ibnex_bus_config(dev_info_t *parent, uint_t flag,
1070     ddi_bus_config_op_t op, void *devname, dev_info_t **child)
1071 {
1072 	int			ret = IBNEX_SUCCESS, len, circ;
1073 	char 			*device_name, *cname = NULL, *caddr = NULL;
1074 	char			*srvname, nameaddr[MAXNAMELEN];
1075 	dev_info_t		*cdip, *pdip = NULL;
1076 	ibnex_node_data_t	*node_data;
1077 	ibnex_port_node_t	*port_node;
1078 
1079 	ndi_devi_enter(parent, &circ);
1080 
1081 	switch (op) {
1082 	case BUS_CONFIG_ONE:
1083 		IBTF_DPRINTF_L4("ibnex", "\tbus_config: CONFIG_ONE");
1084 
1085 		len = strlen((char *)devname) + 1;
1086 		device_name = i_ddi_strdup(devname, KM_SLEEP);
1087 		i_ddi_parse_name(device_name, &cname, &caddr, NULL);
1088 
1089 		if (caddr == NULL || (strlen(caddr) == 0)) {
1090 			kmem_free(device_name, len);
1091 			ndi_devi_exit(parent, circ);
1092 			return (NDI_FAILURE);
1093 		}
1094 
1095 		IBTF_DPRINTF_L4("ibnex",
1096 		    "\tbus_config: cname %s addr %s", cname, caddr);
1097 
1098 		cdip = ndi_devi_findchild(parent, device_name);
1099 		if (cdip == NULL) {
1100 			/* Node is not present */
1101 			if (strncmp(cname, IBNEX_IOC_CNAME, 3) == 0) {
1102 				if (parent == ibnex.ibnex_dip)
1103 					ret = ibnex_config_ioc_node(devname);
1104 				else {
1105 					ret = ibnex_config_root_iocnode(
1106 					    parent, devname);
1107 					if (ibnex.ibnex_dip)
1108 						pdip = ibnex.ibnex_dip;
1109 					else
1110 						ret = IBNEX_FAILURE;
1111 				}
1112 			} else if ((strncmp(cname,
1113 			    IBNEX_IBPORT_CNAME, 6) == 0) &&
1114 			    (parent != ibnex.ibnex_dip)) { /* parent is HCA */
1115 				cdip = ibnex_config_port_node(parent, devname);
1116 				if (cdip)
1117 					ret = IBNEX_SUCCESS;
1118 				else
1119 					ret = IBNEX_FAILURE;
1120 				/* Allows enumeration under PHCI */
1121 				flag |= NDI_MDI_FALLBACK;
1122 			} else if (parent == ibnex.ibnex_dip) {
1123 				/*
1124 				 * if not IOC or PORT device then always
1125 				 * assume a Pseudo child
1126 				 */
1127 				ret = IBNEX_SUCCESS;
1128 				ibnex_pseudo_initnodes();
1129 				mutex_enter(&ibnex.ibnex_mutex);
1130 				ret = ibnex_pseudo_config_one(
1131 				    NULL, cname, caddr);
1132 				mutex_exit(&ibnex.ibnex_mutex);
1133 			} else
1134 				ret = IBNEX_FAILURE;
1135 		}
1136 		kmem_free(device_name, len);
1137 		break;
1138 
1139 	case BUS_CONFIG_OBP_ARGS:
1140 		cdip = ibnex_config_obp_args(parent, devname);
1141 		if (cdip) {
1142 			/*
1143 			 * Boot case.
1144 			 * Special handling because the "devname"
1145 			 * format for the enumerated device is
1146 			 * different.
1147 			 */
1148 			node_data = ddi_get_parent_data(cdip);
1149 			port_node = &node_data->node_data.port_node;
1150 			if (node_data->node_type ==
1151 			    IBNEX_VPPA_COMMSVC_NODE) {
1152 				srvname =
1153 				    ibnex.ibnex_vppa_comm_svc_names[
1154 				    port_node->port_commsvc_idx];
1155 				(void) snprintf(nameaddr, MAXNAMELEN,
1156 				    "ibport@%x,%x,%s",
1157 				    port_node->port_num,
1158 				    port_node->port_pkey, srvname);
1159 			}
1160 			devname = (void *)nameaddr;
1161 		} else {
1162 			IBTF_DPRINTF_L2("ibnex",
1163 			    "\tbus_config: CONFIG_OBP_ARGS : invalid state!!");
1164 
1165 			ret = IBNEX_FAILURE;
1166 		}
1167 		break;
1168 	case BUS_CONFIG_ALL:
1169 		IBTF_DPRINTF_L4("ibnex", "\tbus_config: CONFIG_ALL");
1170 		ibnex_config_all_children(parent);
1171 		break;
1172 
1173 	case BUS_CONFIG_DRIVER:
1174 		IBTF_DPRINTF_L4("ibnex", "\tbus_config: CONFIG_DRIVER");
1175 		ibnex_config_all_children(parent);
1176 		break;
1177 
1178 	default:
1179 		IBTF_DPRINTF_L4("ibnex", "\tbus_config: error");
1180 		ret = IBNEX_FAILURE;
1181 		break;
1182 	}
1183 	ndi_devi_exit(parent, circ);
1184 	if (ret == IBNEX_SUCCESS) {
1185 		if (op == BUS_CONFIG_OBP_ARGS)
1186 			op = BUS_CONFIG_ONE;
1187 
1188 		if (pdip == NULL)
1189 			pdip = parent;
1190 
1191 		ret = ndi_busop_bus_config(
1192 		    pdip, flag, op, devname, child, 0);
1193 		IBTF_DPRINTF_L4("ibnex", "\tbus_config:"
1194 		    "ndi_busop_bus_config : retval %d", ret);
1195 		return (ret);
1196 	}
1197 
1198 	IBTF_DPRINTF_L2("ibnex", "\tbus_config: Failure End");
1199 	return (NDI_FAILURE);
1200 }
1201 
1202 
1203 /*
1204  * ibnex_config_root_iocnode()
1205  *	Configures one particular instance of the IOC driver.
1206  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
1207  */
1208 static int
1209 ibnex_config_root_iocnode(dev_info_t *parent, char *device_name)
1210 {
1211 	int			ret, port = 0, iter = 0;
1212 	boolean_t		displayed = B_FALSE;
1213 	char			*portstr;
1214 	ib_guid_t		hca_guid, iou_guid, ioc_guid;
1215 	ibdm_ioc_info_t		*ioc_info;
1216 	ibdm_port_attr_t	*port_attr;
1217 
1218 	IBTF_DPRINTF_L4("ibnex",
1219 	    "\tconfig_root_iocnode: name %s", device_name);
1220 
1221 	portstr = strstr(device_name, ":port=");
1222 	if (portstr == NULL) {
1223 		return (IBNEX_FAILURE);
1224 	}
1225 
1226 	portstr[0] = 0; portstr++;
1227 	if (ibnex_devname2port(portstr, &port)) {
1228 		IBTF_DPRINTF_L4("ibnex", "\tconfig_root_iocnode: invalid port");
1229 		return (IBNEX_FAILURE);
1230 	}
1231 
1232 	if (ibnex_devname_to_node_n_ioc_guids(
1233 	    device_name, &iou_guid, &ioc_guid) != IBNEX_SUCCESS) {
1234 		return (IBNEX_FAILURE);
1235 	}
1236 
1237 	(void) snprintf(device_name, (IBNEX_MAX_NODEADDR_SZ + 4),
1238 	    "ioc@%llX,%llX", (longlong_t)ioc_guid, (longlong_t)iou_guid);
1239 
1240 	hca_guid = ibtl_ibnex_hcadip2guid(parent);
1241 	if ((port_attr = ibdm_ibnex_probe_hcaport(hca_guid, port)) == NULL) {
1242 		IBTF_DPRINTF_L2("ibnex",
1243 		    "\tconfig_root_iocnode: Port does not exist");
1244 		return (IBNEX_FAILURE);
1245 	}
1246 
1247 	/* Wait until "port is up" */
1248 	while (port_attr->pa_state != IBT_PORT_ACTIVE) {
1249 		ibdm_ibnex_free_port_attr(port_attr);
1250 		delay(drv_usectohz(10000));
1251 		if ((port_attr = ibdm_ibnex_probe_hcaport(
1252 		    hca_guid, port)) == NULL) {
1253 			return (IBNEX_FAILURE);
1254 		}
1255 
1256 		if (iter++ == 400) {
1257 			if (displayed == B_FALSE) {
1258 				cmn_err(CE_NOTE, "\tWaiting for Port %d "
1259 				    "initialization", port_attr->pa_port_num);
1260 				displayed = B_TRUE;
1261 			}
1262 		}
1263 	}
1264 	ibdm_ibnex_free_port_attr(port_attr);
1265 	IBTF_DPRINTF_L4("ibnex", "\tconfig_rootioc_node:"
1266 	    "Port is initialized");
1267 
1268 	if ((ioc_info = ibdm_ibnex_probe_ioc(iou_guid, ioc_guid, 0)) == NULL) {
1269 		ibdm_ibnex_free_ioc_list(ioc_info);
1270 		return (IBNEX_FAILURE);
1271 	}
1272 	mutex_enter(&ibnex.ibnex_mutex);
1273 	if (ibnex_is_ioc_present(ioc_guid) == IBNEX_SUCCESS) {
1274 		IBTF_DPRINTF_L4("ibnex", "\tconfig_root_iocnode: IOC present");
1275 		ret = IBNEX_SUCCESS;
1276 	} else
1277 		ret = ibnex_ioc_initnode(ioc_info, IBNEX_DEVFS_ENUMERATE);
1278 	mutex_exit(&ibnex.ibnex_mutex);
1279 	ibdm_ibnex_free_ioc_list(ioc_info);
1280 	return (ret);
1281 }
1282 
1283 
1284 static int
1285 ibnex_devname2port(char *portstr, int *port)
1286 {
1287 	char	*temp;
1288 	int	ret = IBNEX_FAILURE;
1289 
1290 	IBTF_DPRINTF_L4("ibnex", "\tdevname2port: Begin");
1291 
1292 	temp = strchr(portstr, '=');
1293 	if (temp != NULL) {
1294 		temp++;
1295 		*port = ibnex_str2int(temp, strlen(temp), &ret);
1296 	}
1297 	return (ret);
1298 }
1299 
1300 
1301 /*
1302  * ibnex_config_all_children()
1303  *	Wait for lata SM initialization case before enumerating the nodes
1304  *	Get list of HCA's and HCA port information
1305  *		Create device device nodes and its node properties
1306  *		for port nodes and VPPA nodes
1307  *	Get list of all the IOC node information
1308  *		Create device nodes and its properties for all the IOCs
1309  *		if not created already
1310  *	Bind drivers for all the newly created device nodes
1311  *	Support Pseudo nodes enumerated using their .conf file
1312  */
1313 static void
1314 ibnex_config_all_children(dev_info_t *parent)
1315 {
1316 	int			ii;
1317 	time_t			wait_time;
1318 	ibdm_ioc_info_t		*ioc_list, *ioc;
1319 	ibdm_hca_list_t		*hca_list;
1320 	ib_guid_t		hca_guid;
1321 
1322 	IBTF_DPRINTF_L4("ibnex", "\tconfig_all_children: Begin");
1323 
1324 	if (parent != ibnex.ibnex_dip) {
1325 		/*
1326 		 * Parent is a HCA node. Enumerate only children of
1327 		 * this HCA, port nodes, VPPA & HCA_SVC nodes
1328 		 */
1329 		hca_guid = ibtl_ibnex_hcadip2guid(parent);
1330 		wait_time = ibdm_ibnex_get_waittime(
1331 			hca_guid, &ibnex_port_settling_time);
1332 		if (wait_time) {
1333 			delay(drv_usectohz(wait_time * 1000000));
1334 		}
1335 		hca_list = ibdm_ibnex_get_hca_info_by_guid(hca_guid);
1336 		if (hca_list == NULL)
1337 			return;
1338 		ibnex_create_hcasvc_nodes(parent, hca_list->hl_hca_port_attr);
1339 		for (ii = 0; ii < hca_list->hl_nports; ii++) {
1340 			ibnex_create_port_nodes(
1341 			    parent, &hca_list->hl_port_attr[ii]);
1342 			ibnex_create_vppa_nodes(
1343 			    parent, &hca_list->hl_port_attr[ii]);
1344 		}
1345 		ibdm_ibnex_free_hca_list(hca_list);
1346 	} else {
1347 
1348 		ibnex_pseudo_initnodes();
1349 
1350 		/* Parent is a IB nexus. Enumerate all the IOC's */
1351 		wait_time = ibdm_ibnex_get_waittime(
1352 			0, &ibnex_port_settling_time);
1353 		if (wait_time)
1354 			delay(drv_usectohz(wait_time * 1000000));
1355 
1356 
1357 		ioc_list = ibdm_ibnex_get_ioc_list(IBDM_IBNEX_NORMAL_PROBE);
1358 		ioc = ioc_list;
1359 
1360 		mutex_enter(&ibnex.ibnex_mutex);
1361 
1362 		while (ioc_list) {
1363 			if (ibnex_is_ioc_present(
1364 			    ioc_list->ioc_profile.ioc_guid) != IBNEX_SUCCESS) {
1365 				(void) ibnex_ioc_initnode(ioc_list,
1366 				    IBNEX_DEVFS_ENUMERATE);
1367 			}
1368 			ioc_list = ioc_list->ioc_next;
1369 		}
1370 		ibnex_config_pseudo_all();
1371 		mutex_exit(&ibnex.ibnex_mutex);
1372 		ibdm_ibnex_free_ioc_list(ioc);
1373 	}
1374 	IBTF_DPRINTF_L4("ibnex", "\tconfig_all_children: End");
1375 }
1376 
1377 
1378 /*
1379  * ibnex_create_port_nodes:
1380  *	Creates a device node per each communication service defined
1381  *	in the "port-commsvc-list" property per HCA port
1382  */
1383 static void
1384 ibnex_create_port_nodes(dev_info_t *parent, ibdm_port_attr_t *port_attr)
1385 {
1386 	int		idx;
1387 	dev_info_t	*dip;
1388 	int		rval;
1389 
1390 	mutex_enter(&ibnex.ibnex_mutex);
1391 	for (idx = 0; idx < ibnex.ibnex_num_comm_svcs; idx++) {
1392 		rval = ibnex_get_dip_from_guid(port_attr->pa_port_guid,
1393 		    idx, 0, &dip);
1394 		if (rval != IBNEX_SUCCESS) {
1395 			(void) ibnex_commsvc_initnode(parent, port_attr, idx,
1396 			    IBNEX_PORT_COMMSVC_NODE, 0, &rval,
1397 			    IBNEX_DEVFS_ENUMERATE);
1398 		}
1399 	}
1400 	mutex_exit(&ibnex.ibnex_mutex);
1401 }
1402 
1403 
1404 /*
1405  * ibnex_create_vppa_nodes:
1406  *	Creates a device node per each communication service defined
1407  *	in the "vppa-commsvc-list" property and per each PKEY that
1408  *	this particular port supports and per HCA port
1409  */
1410 static void
1411 ibnex_create_vppa_nodes(dev_info_t *parent, ibdm_port_attr_t *port_attr)
1412 {
1413 	int 		idx, ii;
1414 	int		rval;
1415 	ib_pkey_t 	pkey;
1416 	dev_info_t	*dip;
1417 
1418 	IBTF_DPRINTF_L4("ibnex", "\tcreate_vppa_nodes: Begin");
1419 
1420 	mutex_enter(&ibnex.ibnex_mutex);
1421 	if (port_attr->pa_state != IBT_PORT_ACTIVE) {
1422 		IBTF_DPRINTF_L4("ibnex", "\tcreate_vppa_nodes: "
1423 		    "Port %d is down", port_attr->pa_port_num);
1424 		mutex_exit(&ibnex.ibnex_mutex);
1425 		return;
1426 	}
1427 	for (idx = 0; idx < ibnex.ibnex_nvppa_comm_svcs; idx++) {
1428 		for (ii = 0; ii < port_attr->pa_npkeys; ii++) {
1429 			pkey = port_attr->pa_pkey_tbl[ii].pt_pkey;
1430 
1431 			if (IBNEX_INVALID_PKEY(pkey)) {
1432 				continue;
1433 			}
1434 			rval = ibnex_get_dip_from_guid(
1435 			    port_attr->pa_port_guid, idx, pkey, &dip);
1436 			if (rval != IBNEX_SUCCESS) {
1437 				(void) ibnex_commsvc_initnode(parent, port_attr,
1438 					idx, IBNEX_VPPA_COMMSVC_NODE,
1439 					pkey, &rval, IBNEX_CFGADM_ENUMERATE);
1440 				IBTF_DPRINTF_L5("ibnex", "\tcreate_vppa_nodes: "
1441 				    "commsvc_initnode failed rval %x", rval);
1442 			}
1443 		}
1444 	}
1445 	mutex_exit(&ibnex.ibnex_mutex);
1446 }
1447 
1448 
1449 /*
1450  * ibnex_create_hcasvc_nodes:
1451  *	Creates a device node per each communication service defined
1452  *	in the "port-commsvc-list" property per HCA port
1453  */
1454 static void
1455 ibnex_create_hcasvc_nodes(dev_info_t *parent, ibdm_port_attr_t *port_attr)
1456 {
1457 	int		idx;
1458 	dev_info_t	*dip;
1459 	int		rval;
1460 
1461 	mutex_enter(&ibnex.ibnex_mutex);
1462 	for (idx = 0; idx < ibnex.ibnex_nhcasvc_comm_svcs; idx++) {
1463 		rval = ibnex_get_dip_from_guid(port_attr->pa_port_guid,
1464 		    idx, 0, &dip);
1465 		if (rval != IBNEX_SUCCESS) {
1466 			(void) ibnex_commsvc_initnode(parent, port_attr, idx,
1467 			    IBNEX_HCASVC_COMMSVC_NODE, 0, &rval,
1468 			    IBNEX_DEVFS_ENUMERATE);
1469 			IBTF_DPRINTF_L5("ibnex", "create_hcasvc_nodes: "
1470 			    "commsvc_initnode failed, rval %x", rval);
1471 		}
1472 	}
1473 	mutex_exit(&ibnex.ibnex_mutex);
1474 }
1475 
1476 /*
1477  * ibnex_is_ioc_present()
1478  *	Returns IBNEX_SUCCESS if an entry found in the global linked list
1479  *	Returns IBNEX_FAILURE, if no match found
1480  */
1481 static int
1482 ibnex_is_ioc_present(ib_guid_t ioc_guid)
1483 {
1484 	ibnex_node_data_t	*head;
1485 	ibnex_ioc_node_t	*ioc;
1486 	int			ret = IBNEX_FAILURE;
1487 
1488 	IBTF_DPRINTF_L4("ibnex", "\tis_ioc_present: Begin");
1489 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1490 
1491 	head = ibnex.ibnex_ioc_node_head;
1492 	while (head) {
1493 		ioc = &head->node_data.ioc_node;
1494 		if (ioc->ioc_guid == ioc_guid)
1495 			break;
1496 		head = head->node_next;
1497 	}
1498 	if (head)
1499 		ret = IBNEX_SUCCESS;
1500 
1501 	return (ret);
1502 }
1503 
1504 
1505 /*
1506  * ibnex_bus_unconfig()
1507  *
1508  *	Unconfigure a particular device node or all instance of a device
1509  *	driver device or all children of IBnex
1510  */
1511 static int
1512 ibnex_bus_unconfig(dev_info_t *parent,
1513     uint_t flag, ddi_bus_config_op_t op, void *device_name)
1514 {
1515 	return (ndi_busop_bus_unconfig(parent, flag, op, device_name));
1516 }
1517 
1518 
1519 /*
1520  * ibnex_config_port_node()
1521  *
1522  *	Configures a particular port / HCA  node for a particular
1523  *	communication service.
1524  *	The format of the device_name is
1525  *		ibport@<Port#>,<pkey>,<service name>
1526  *	where pkey = 0 for port communication service nodes
1527  *		  Port# = 0 for HCA_SVC communication service nodes
1528  *	Returns "dev_info_t" of the "child" node just created
1529  *	NULL when failed to enumerate the child node
1530  */
1531 static dev_info_t *
1532 ibnex_config_port_node(dev_info_t *parent, char *devname)
1533 {
1534 	int			ii, index;
1535 	int			rval;
1536 	time_t			wait_time;
1537 	uint8_t			port_num;
1538 	ib_guid_t		hca_guid, port_guid;
1539 	ib_pkey_t		pkey;
1540 	dev_info_t		*cdip;
1541 	ibdm_port_attr_t	*port_attr;
1542 	ibdm_hca_list_t		*hca_list;
1543 
1544 	IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: %s", devname);
1545 
1546 	if (ibnex_get_pkey_commsvc_index_portnum(devname,
1547 	    &index, &pkey, &port_num) != IBNEX_SUCCESS) {
1548 		IBTF_DPRINTF_L2("ibnex",
1549 		    "\tconfig_port_node: Invalid Service Name");
1550 		return (NULL);
1551 	}
1552 
1553 	hca_guid = ibtl_ibnex_hcadip2guid(parent);
1554 	if (port_num == 0) {
1555 		/*
1556 		 * Use the dummy port attribute for HCA node in hca_list
1557 		 * Note : pa_state is always IBT_PORT_ACTIVE.
1558 		 */
1559 		hca_list = ibdm_ibnex_get_hca_info_by_guid(hca_guid);
1560 		ASSERT(hca_list != NULL);
1561 		port_attr = hca_list->hl_hca_port_attr;
1562 	} else {
1563 		if ((port_attr = ibdm_ibnex_probe_hcaport(
1564 		    hca_guid, port_num)) == NULL) {
1565 			IBTF_DPRINTF_L2("ibnex",
1566 			    "\tconfig_port_node: Port does not exist");
1567 			return (NULL);
1568 		}
1569 
1570 		if (port_attr->pa_state != IBT_PORT_ACTIVE) {
1571 			wait_time = ibdm_ibnex_get_waittime(
1572 				hca_guid, &ibnex_port_settling_time);
1573 			if (wait_time) {
1574 				delay(drv_usectohz(wait_time * 1000000));
1575 			}
1576 			ibdm_ibnex_free_port_attr(port_attr);
1577 			if ((port_attr = ibdm_ibnex_probe_hcaport(
1578 			    hca_guid, port_num)) == NULL) {
1579 				return (NULL);
1580 			}
1581 		}
1582 	}
1583 
1584 	port_guid = port_attr->pa_port_guid;
1585 	mutex_enter(&ibnex.ibnex_mutex);
1586 	if ((rval = ibnex_get_dip_from_guid(port_guid, index, pkey,
1587 	    &cdip)) == IBNEX_SUCCESS) {
1588 		IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: Node exists");
1589 		mutex_exit(&ibnex.ibnex_mutex);
1590 		if (port_num != 0)
1591 			ibdm_ibnex_free_port_attr(port_attr);
1592 		else
1593 			ibdm_ibnex_free_hca_list(hca_list);
1594 		return (cdip);
1595 	}
1596 
1597 	if (pkey == 0 && port_num != 0) {
1598 		cdip = ibnex_commsvc_initnode(parent,
1599 		    port_attr, index, IBNEX_PORT_COMMSVC_NODE, pkey, &rval,
1600 		    IBNEX_DEVFS_ENUMERATE);
1601 		IBTF_DPRINTF_L5("ibnex",
1602 		    "\t ibnex_commsvc_initnode rval %x", rval);
1603 	} else if (pkey == 0 && port_num == 0) {
1604 		cdip = ibnex_commsvc_initnode(parent,
1605 		    port_attr, index, IBNEX_HCASVC_COMMSVC_NODE, pkey, &rval,
1606 		    IBNEX_DEVFS_ENUMERATE);
1607 		IBTF_DPRINTF_L5("ibnex",
1608 		    "\t ibnex_commsvc_initnode rval %x", rval);
1609 	} else {
1610 		if (port_attr->pa_state != IBT_PORT_ACTIVE) {
1611 			IBTF_DPRINTF_L4("ibnex", "\tconfig_port_nodes: "
1612 			    "Port %d is down", port_attr->pa_port_num);
1613 			ibdm_ibnex_free_port_attr(port_attr);
1614 			mutex_exit(&ibnex.ibnex_mutex);
1615 			return (NULL);
1616 		}
1617 		for (ii = 0; ii < port_attr->pa_npkeys; ii++) {
1618 			if (pkey == port_attr->pa_pkey_tbl[ii].pt_pkey) {
1619 				cdip = ibnex_commsvc_initnode(parent, port_attr,
1620 				    index, IBNEX_VPPA_COMMSVC_NODE,
1621 				    pkey, &rval, IBNEX_CFGADM_ENUMERATE);
1622 				IBTF_DPRINTF_L5("ibnex",
1623 				    "\t ibnex_commsvc_initnode rval %x", rval);
1624 				break;
1625 			}
1626 		}
1627 	}
1628 	mutex_exit(&ibnex.ibnex_mutex);
1629 	if (port_num != 0)
1630 		ibdm_ibnex_free_port_attr(port_attr);
1631 	else
1632 		ibdm_ibnex_free_hca_list(hca_list);
1633 	return (cdip);
1634 }
1635 
1636 
1637 /*
1638  * ibnex_config_obp_args()
1639  *	Configures a particular port node for a IP over IB communication
1640  *	service.
1641  *	The format of the input string "devname" is
1642  *		port=x,pkey=y,protocol=ip,<wanboot options>
1643  *	Thr format of the node name created here is
1644  *		ibport@<Port#>,<pkey>,<service name>
1645  *	where pkey = 0 for port communication service nodes
1646  *	Returns "dev_info_t" of the "child" node just created
1647  *	NULL when failed to enumerate the child node
1648  *
1649  */
1650 static dev_info_t *
1651 ibnex_config_obp_args(dev_info_t *parent, char *devname)
1652 {
1653 	int			ii, index;
1654 	int			rval, iter = 0;
1655 	char			*temp;
1656 	uint8_t			port_num;
1657 	ib_guid_t		hca_guid, port_guid;
1658 	ib_pkey_t		pkey;
1659 	dev_info_t		*cdip;
1660 	boolean_t		displayed = B_FALSE;
1661 	ibdm_port_attr_t	*port_attr;
1662 
1663 	IBTF_DPRINTF_L4("ibnex", "\tconfig_obp_args: %s", devname);
1664 
1665 	/* Is this OBP node for IPoIB ? */
1666 	temp = devname;
1667 	do {
1668 		temp = strstr(temp, ",protocol=ip");
1669 		if (temp == NULL)
1670 			break;
1671 
1672 		if (strlen(devname) > (int)((temp - devname) + 12)) {
1673 			if (temp[12] == ',')
1674 				break;
1675 		} else {
1676 			break;
1677 		}
1678 		temp++;
1679 	} while (temp);
1680 
1681 	if (temp == NULL)
1682 		return (NULL);
1683 	if (ibnex_prom_devname_to_pkey_n_portnum(
1684 	    devname, &pkey, &port_num) != IBNEX_SUCCESS) {
1685 		return (NULL);
1686 	}
1687 	for (index = 0; index < ibnex.ibnex_nvppa_comm_svcs; index++) {
1688 		if (strcmp(ibnex.ibnex_vppa_comm_svc_names[index],
1689 			"ipib") == 0) {
1690 			break;
1691 		}
1692 	}
1693 
1694 	hca_guid = ibtl_ibnex_hcadip2guid(parent);
1695 	if ((port_attr = ibdm_ibnex_probe_hcaport(
1696 	    hca_guid, port_num)) == NULL) {
1697 		IBTF_DPRINTF_L2("ibnex",
1698 		    "\tconfig_port_node: Port does not exist");
1699 		return (NULL);
1700 	}
1701 
1702 	/* Wait until "port is up" */
1703 	while (port_attr->pa_state != IBT_PORT_ACTIVE) {
1704 		ibdm_ibnex_free_port_attr(port_attr);
1705 		delay(drv_usectohz(10000));
1706 		if ((port_attr = ibdm_ibnex_probe_hcaport(
1707 		    hca_guid, port_num)) == NULL) {
1708 			return (NULL);
1709 		}
1710 		if (iter++ == 400) {
1711 			if (displayed == B_FALSE) {
1712 				cmn_err(CE_NOTE, "\tWaiting for Port %d "
1713 				    "initialization", port_attr->pa_port_num);
1714 				displayed = B_TRUE;
1715 			}
1716 		}
1717 	}
1718 	IBTF_DPRINTF_L4("ibnex", "\tPort is initialized");
1719 
1720 	mutex_enter(&ibnex.ibnex_mutex);
1721 	port_guid = port_attr->pa_port_guid;
1722 	if ((rval = ibnex_get_dip_from_guid(port_guid, index, pkey,
1723 	    &cdip)) == IBNEX_SUCCESS) {
1724 		IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: Node exists");
1725 		mutex_exit(&ibnex.ibnex_mutex);
1726 		ibdm_ibnex_free_port_attr(port_attr);
1727 		return (cdip);
1728 	}
1729 	for (ii = 0; ii < port_attr->pa_npkeys; ii++) {
1730 		if (pkey == port_attr->pa_pkey_tbl[ii].pt_pkey) {
1731 			cdip = ibnex_commsvc_initnode(parent, port_attr,
1732 			    index, IBNEX_VPPA_COMMSVC_NODE, pkey, &rval,
1733 			    IBNEX_CFGADM_ENUMERATE);
1734 			IBTF_DPRINTF_L5("ibnex",
1735 			    "\t ibnex_commsvc_initnode rval %x", rval);
1736 			break;
1737 		}
1738 	}
1739 	mutex_exit(&ibnex.ibnex_mutex);
1740 
1741 	ibdm_ibnex_free_port_attr(port_attr);
1742 	return (cdip);
1743 }
1744 
1745 
1746 /*
1747  * ibnex_prom_devname_to_pkey_n_portnum()
1748  *	Parses the device node name and extracts "PKEY" and "port#"
1749  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
1750  */
1751 static int
1752 ibnex_prom_devname_to_pkey_n_portnum(
1753     char *devname, ib_pkey_t *pkey, uint8_t *port)
1754 {
1755 	int	ret = IBNEX_SUCCESS;
1756 	char	*tmp, *tmp1;
1757 
1758 	if ((tmp = strstr(devname, "port=")) != NULL) {
1759 		if ((tmp = strchr(++tmp, '=')) != NULL)
1760 			if ((tmp1 = strchr(++tmp, ',')) != NULL)
1761 				*port = ibnex_str2int(tmp, (tmp1 - tmp), &ret);
1762 	} else
1763 		ret = IBNEX_FAILURE;
1764 
1765 	if ((ret == IBNEX_SUCCESS) &&
1766 	    (tmp = strstr(devname, "pkey=")) != NULL) {
1767 		if ((tmp = strchr(++tmp, '=')) != NULL)
1768 			if ((tmp1 = strchr(++tmp, ',')) != NULL)
1769 				*pkey = ibnex_str2hex(tmp, (tmp1 - tmp), &ret);
1770 	} else
1771 		ret = IBNEX_FAILURE;
1772 
1773 	return (ret);
1774 }
1775 
1776 
1777 /*
1778  * ibnex_get_pkey_commsvc_index_portnum()
1779  *	Parses the device node name and extracts PKEY, communication
1780  *	service index & Port #.
1781  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
1782  */
1783 static int
1784 ibnex_get_pkey_commsvc_index_portnum(char *device_name, int *index,
1785     ib_pkey_t *pkey, uint8_t *port_num)
1786 {
1787 	char 	*srv, **service_name, *temp;
1788 	int  	ii, ncommsvcs, ret;
1789 
1790 	if (ibnex_devname_to_portnum(device_name, port_num) !=
1791 		IBNEX_SUCCESS) {
1792 		IBTF_DPRINTF_L2("ibnex",
1793 		    "\tget_pkey_commsvc_index_portnum: Invalid PortGuid");
1794 		return (NULL);
1795 	}
1796 	srv = strchr(device_name, ',');
1797 	if (srv == 0)
1798 		return (IBNEX_FAILURE);
1799 
1800 	srv++;
1801 	temp = strchr(srv, ',');
1802 	if (temp == 0)
1803 		return (IBNEX_FAILURE);
1804 	temp++;
1805 	*pkey = ibnex_str2hex(srv, (temp - srv - 1), &ret);
1806 	if (ret != IBNEX_SUCCESS)
1807 		return (ret);
1808 
1809 	if (*pkey == 0 && *port_num != 0) {
1810 		service_name = ibnex.ibnex_comm_svc_names;
1811 		ncommsvcs = ibnex.ibnex_num_comm_svcs;
1812 	} else if (*pkey == 0 && *port_num == 0) {
1813 		service_name = ibnex.ibnex_hcasvc_comm_svc_names;
1814 		ncommsvcs = ibnex.ibnex_nhcasvc_comm_svcs;
1815 	} else {
1816 		service_name = ibnex.ibnex_vppa_comm_svc_names;
1817 		ncommsvcs = ibnex.ibnex_nvppa_comm_svcs;
1818 	}
1819 
1820 	for (ii = 0; ii < ncommsvcs; ii++) {
1821 		if (strcmp(service_name[ii], temp) == 0) {
1822 			break;
1823 		}
1824 	}
1825 	if (ii == ncommsvcs)
1826 		return (IBNEX_FAILURE);
1827 
1828 	*index = ii;
1829 	return (IBNEX_SUCCESS);
1830 }
1831 
1832 
1833 /*
1834  * ibnex_devname_to_portnum()
1835  *	Get portguid from device name
1836  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
1837  */
1838 static int
1839 ibnex_devname_to_portnum(char *device_name, uint8_t *portnum)
1840 {
1841 	int	ret;
1842 	char	*temp1, *temp2;
1843 
1844 	temp1 = strchr(device_name, '@');
1845 	if (temp1 == NULL) {
1846 		return (IBNEX_FAILURE);
1847 	}
1848 	temp2 = strchr(temp1, ',');
1849 	if (temp2 == NULL)
1850 		return (IBNEX_FAILURE);
1851 	temp1++;
1852 	*portnum = ibnex_str2hex(temp1, (temp2 - temp1), &ret);
1853 	return (ret);
1854 }
1855 
1856 
1857 /*
1858  * ibnex_config_ioc_node()
1859  *	Configures one particular instance of the IOC driver.
1860  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
1861  */
1862 static int
1863 ibnex_config_ioc_node(char *device_name)
1864 {
1865 	int			ret;
1866 	time_t			wait_time;
1867 	ib_guid_t		iou_guid, ioc_guid;
1868 	ibdm_ioc_info_t		*ioc_info;
1869 
1870 	IBTF_DPRINTF_L4("ibnex", "\tconfig_ioc_node: Begin");
1871 
1872 	if (ibnex_devname_to_node_n_ioc_guids(
1873 	    device_name, &iou_guid, &ioc_guid) != IBNEX_SUCCESS) {
1874 		return (IBNEX_FAILURE);
1875 	}
1876 
1877 	wait_time = ibdm_ibnex_get_waittime(0, &ibnex_port_settling_time);
1878 	if (wait_time)
1879 		delay(drv_usectohz(wait_time * 1000000));
1880 
1881 	if ((ioc_info = ibdm_ibnex_probe_ioc(iou_guid, ioc_guid, 0)) ==
1882 	    NULL) {
1883 		ibdm_ibnex_free_ioc_list(ioc_info);
1884 		return (IBNEX_FAILURE);
1885 	}
1886 	mutex_enter(&ibnex.ibnex_mutex);
1887 	if (ibnex_is_ioc_present(ioc_guid) == IBNEX_SUCCESS) {
1888 		IBTF_DPRINTF_L4("ibnex", "\tconfig_ioc_node: IOC present");
1889 		ret = IBNEX_SUCCESS;
1890 	} else
1891 		ret = ibnex_ioc_initnode(ioc_info, IBNEX_DEVFS_ENUMERATE);
1892 	mutex_exit(&ibnex.ibnex_mutex);
1893 	ibdm_ibnex_free_ioc_list(ioc_info);
1894 	return (ret);
1895 }
1896 
1897 
1898 /*
1899  * ibnex_devname_to_node_n_ioc_guids()
1900  *	Get node guid and ioc guid from the device name
1901  *	Format of the device node name is:
1902  *		ioc@<IOC GUID>,<IOU GUID>
1903  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
1904  */
1905 static int
1906 ibnex_devname_to_node_n_ioc_guids(
1907     char *device_name, ib_guid_t *iou_guid, ib_guid_t *ioc_guid)
1908 {
1909 	char	*temp1, *temp;
1910 	int	len, ret;
1911 
1912 	IBTF_DPRINTF_L4("ibnex", "\tdevname_to_node_n_ioc_guids:"
1913 	    "Device Name %s", device_name);
1914 
1915 	if ((temp = strchr(device_name, '@')) == NULL) {
1916 		return (IBNEX_FAILURE);
1917 	}
1918 	if ((temp1 = strchr(++temp, ',')) == NULL) {
1919 		return (IBNEX_FAILURE);
1920 	}
1921 	*ioc_guid = ibnex_str2hex(temp, (temp1 - temp), &ret);
1922 	if (ret == IBNEX_SUCCESS) {
1923 		len = device_name + strlen(device_name) - ++temp1;
1924 		*iou_guid = ibnex_str2hex(temp1, len, &ret);
1925 	}
1926 	return (ret);
1927 }
1928 
1929 
1930 /*ARGSUSED*/
1931 /*
1932  * ibnex_ioc_initnode()
1933  *	Allocate a pathinfo node for the IOC
1934  *	Initialize the device node
1935  *	Bind driver to the node
1936  *	Update IBnex global data
1937  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE/IBNEX_BUSY
1938  */
1939 int
1940 ibnex_ioc_initnode(ibdm_ioc_info_t *ioc_info, int flag)
1941 {
1942 	int			rval;
1943 	ibnex_node_data_t	*node_data;
1944 
1945 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1946 
1947 	node_data = ibnex_is_node_data_present(IBNEX_IOC_NODE,
1948 	    (void *)ioc_info, 0, 0);
1949 
1950 	/*
1951 	 * prevent any races
1952 	 * we have seen this node_data and it has been initialized
1953 	 * Note that node_dip is already NULL if unconfigure is in
1954 	 * progress.
1955 	 */
1956 	if (node_data && node_data->node_dip) {
1957 		return ((node_data->node_state == IBNEX_CFGADM_CONFIGURING) ?
1958 		    IBNEX_BUSY : IBNEX_SUCCESS);
1959 	} else if (node_data == NULL) {
1960 		node_data = ibnex_init_child_nodedata(IBNEX_IOC_NODE,
1961 		    ioc_info, 0, 0);
1962 	}
1963 
1964 	/*
1965 	 * Return EBUSY if another configure/unconfigure
1966 	 * operation is in progress
1967 	 */
1968 	if (node_data->node_state == IBNEX_CFGADM_UNCONFIGURING) {
1969 		return (IBNEX_BUSY);
1970 	}
1971 
1972 	ASSERT(node_data->node_state != IBNEX_CFGADM_CONFIGURED);
1973 	node_data->node_state = IBNEX_CFGADM_CONFIGURING;
1974 
1975 
1976 	mutex_exit(&ibnex.ibnex_mutex);
1977 
1978 	rval = ibnex_ioc_create_pi(ioc_info, node_data);
1979 
1980 	mutex_enter(&ibnex.ibnex_mutex);
1981 	if (rval == IBNEX_SUCCESS)
1982 		node_data->node_state = IBNEX_CFGADM_CONFIGURED;
1983 
1984 	return (rval);
1985 }
1986 
1987 
1988 /*
1989  * ibnex_config_pseudo_all()
1990  *	Configure all the pseudo nodes
1991  */
1992 static void
1993 ibnex_config_pseudo_all(void)
1994 {
1995 	ibnex_node_data_t	*nodep;
1996 
1997 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1998 
1999 	for (nodep = ibnex.ibnex_pseudo_node_head;
2000 	    nodep; nodep = nodep->node_next) {
2001 		(void) ibnex_pseudo_config_one(nodep, NULL, NULL);
2002 	}
2003 }
2004 
2005 
2006 /*
2007  * ibnex_pseudo_config_one()
2008  */
2009 int
2010 ibnex_pseudo_config_one(ibnex_node_data_t *node_data, char *cname, char *caddr)
2011 {
2012 	int			rval, len;
2013 	char			*node_addr;
2014 
2015 	IBTF_DPRINTF_L4("ibnex", "\tpseudo_config_one:Begin");
2016 
2017 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2018 
2019 	if (node_data == NULL) {
2020 		IBTF_DPRINTF_L4("ibnex", "\tpseudo_config_one:"
2021 		    "cname = %s caddr = %s", cname, caddr);
2022 
2023 		len = strlen(cname) + strlen(caddr) + 2;
2024 		node_addr = (char *)kmem_alloc(len, KM_SLEEP);
2025 
2026 		(void) snprintf(node_addr, len, "%s,%s", cname, caddr);
2027 		node_data = ibnex_is_node_data_present(IBNEX_PSEUDO_NODE,
2028 		    (void *)node_addr, 0, 0);
2029 		kmem_free(node_addr, len);
2030 	}
2031 
2032 	/*
2033 	 * prevent any races
2034 	 * we have seen this node_data and it has been initialized
2035 	 * Note that node_dip is already NULL if unconfigure is in
2036 	 * progress.
2037 	 */
2038 	if (node_data && node_data->node_dip) {
2039 		return ((node_data->node_state == IBNEX_CFGADM_CONFIGURING) ?
2040 		    IBNEX_BUSY : IBNEX_SUCCESS);
2041 	} else if (node_data == NULL) {
2042 		IBTF_DPRINTF_L2("ibnex", "\tpseudo_config_one: Invalid node");
2043 		return (IBNEX_FAILURE);
2044 	}
2045 
2046 	/*
2047 	 * Return EBUSY if another configure/unconfigure
2048 	 * operation is in progress
2049 	 */
2050 	if (node_data->node_state == IBNEX_CFGADM_UNCONFIGURING) {
2051 		return (IBNEX_BUSY);
2052 	}
2053 
2054 	if (node_data->node_state == IBNEX_CFGADM_CONFIGURED)
2055 		return (IBNEX_SUCCESS);
2056 
2057 	/*
2058 	 * Prevent configuring pseudo nodes specifically unconfigured
2059 	 * by cfgadm. This is done by checking if this is a newly
2060 	 * created node, not yet configured by BUS_CONFIG or cfgadm
2061 	 */
2062 	if (node_data->node_data.pseudo_node.pseudo_new_node != 1)
2063 		return (IBNEX_FAILURE);
2064 	node_data->node_data.pseudo_node.pseudo_new_node = 0;
2065 
2066 	node_data->node_state = IBNEX_CFGADM_CONFIGURING;
2067 
2068 	mutex_exit(&ibnex.ibnex_mutex);
2069 	rval = ibnex_pseudo_create_pi(node_data);
2070 	mutex_enter(&ibnex.ibnex_mutex);
2071 
2072 	if (rval == IBNEX_SUCCESS)
2073 		node_data->node_state = IBNEX_CFGADM_CONFIGURED;
2074 	else {
2075 		node_data->node_dip = NULL;
2076 		node_data->node_state = IBNEX_CFGADM_UNCONFIGURED;
2077 		node_data->node_data.pseudo_node.pseudo_new_node = 1;
2078 	}
2079 
2080 	return (rval);
2081 }
2082 
2083 
2084 /*
2085  * ibnex_pseudo_create_pi()
2086  *	Create a path info node for each pseudo entry
2087  */
2088 int
2089 ibnex_pseudo_create_pi(ibnex_node_data_t *nodep)
2090 {
2091 	mdi_pathinfo_t		*pip;
2092 	int			rval, hcacnt;
2093 	dev_info_t		*hca_dip, *cdip = NULL;
2094 	ibdm_hca_list_t		*hca_list, *head;
2095 	ibnex_pseudo_node_t	*pseudo;
2096 
2097 	IBTF_DPRINTF_L4("ibnex", "\tibnex_pseudo_create_pi: %p", nodep);
2098 
2099 	pseudo = &nodep->node_data.pseudo_node;
2100 
2101 	ibdm_ibnex_get_hca_list(&hca_list, &hcacnt);
2102 
2103 	head = hca_list;
2104 
2105 	for (; hca_list != NULL; hca_list = hca_list->hl_next) {
2106 
2107 		hca_dip = ibtl_ibnex_hcaguid2dip(hca_list->hl_hca_guid);
2108 
2109 		rval = mdi_pi_alloc(hca_dip,
2110 		    pseudo->pseudo_devi_name, pseudo->pseudo_node_addr,
2111 		    pseudo->pseudo_node_addr, 0, &pip);
2112 
2113 		if (rval != MDI_SUCCESS) {
2114 			(void) ibnex_offline_childdip(cdip);
2115 			return (IBNEX_FAILURE);
2116 		}
2117 		cdip = mdi_pi_get_client(pip);
2118 
2119 		IBTF_DPRINTF_L4("ibnex",
2120 		    "\tpseudo_create_pi: New dip %p", cdip);
2121 
2122 		nodep->node_dip = cdip;
2123 		ddi_set_parent_data(cdip, nodep);
2124 
2125 		rval = mdi_pi_online(pip, 0);
2126 
2127 		if (rval != MDI_SUCCESS) {
2128 			ddi_set_parent_data(cdip, NULL);
2129 			IBTF_DPRINTF_L2("ibnex", "\tpseudo_create_pi:"
2130 			    "mdi_pi_online: failed for pseudo dip %p,"
2131 			    " rval %d", cdip, rval);
2132 			(void) ibnex_offline_childdip(cdip);
2133 			rval = IBNEX_FAILURE;
2134 			break;
2135 		} else
2136 			rval = IBNEX_SUCCESS;
2137 	}
2138 	if (head)
2139 		ibdm_ibnex_free_hca_list(head);
2140 	return (rval);
2141 }
2142 
2143 
2144 /*
2145  * ibnex_ioc_create_pi()
2146  *	Create a pathinfo node for the ioc node
2147  */
2148 static int
2149 ibnex_ioc_create_pi(ibdm_ioc_info_t *ioc_info, ibnex_node_data_t *node_data)
2150 {
2151 	char			ioc_guid[33], iou_guid[33];
2152 	mdi_pathinfo_t		*pip;
2153 	int			rval;
2154 	dev_info_t		*hca_dip, *cdip = NULL;
2155 	int			flag = 1;
2156 	ibdm_hca_list_t		*hca_list;
2157 
2158 	IBTF_DPRINTF_L4("ibnex", "\tibnex_ioc_create_pi Begin");
2159 
2160 	(void) snprintf(ioc_guid, 33, "%llx",
2161 		(longlong_t)ioc_info->ioc_profile.ioc_guid);
2162 	(void) snprintf(iou_guid, 33, "%llx",
2163 		(longlong_t)ioc_info->ioc_iou_guid);
2164 
2165 	hca_list = ioc_info->ioc_hca_list;
2166 
2167 	for (; hca_list != NULL; hca_list = hca_list->hl_next) {
2168 
2169 		hca_dip = ibtl_ibnex_hcaguid2dip(hca_list->hl_hca_guid);
2170 
2171 		IBTF_DPRINTF_L4("ibnex", "\tioc_create_pi "
2172 		    "hca guid %llx", hca_list->hl_hca_guid);
2173 
2174 		rval =  mdi_pi_alloc(hca_dip,
2175 		    IBNEX_IOC_CNAME, ioc_guid, iou_guid, 0, &pip);
2176 		if (rval != MDI_SUCCESS) {
2177 			(void) ibnex_offline_childdip(cdip);
2178 			return (IBNEX_FAILURE);
2179 		}
2180 		cdip = mdi_pi_get_client(pip);
2181 
2182 		IBTF_DPRINTF_L4("ibnex",
2183 		    "\tioc_create_pi: New IOC dip %p", cdip);
2184 
2185 		node_data->node_dip = cdip;
2186 		ddi_set_parent_data(cdip, node_data);
2187 
2188 		if (flag) {
2189 			if ((rval = ibnex_create_ioc_node_prop(
2190 			    ioc_info, cdip)) != IBNEX_SUCCESS) {
2191 				ibnex_delete_ioc_node_data(node_data);
2192 				ddi_prop_remove_all(cdip);
2193 				ddi_set_parent_data(cdip, NULL);
2194 
2195 				(void) ibnex_offline_childdip(cdip);
2196 				return (IBNEX_FAILURE);
2197 			}
2198 			flag = 0;
2199 		}
2200 
2201 		rval = mdi_pi_online(pip, 0);
2202 
2203 		if (rval != MDI_SUCCESS) {
2204 			ibnex_delete_ioc_node_data(node_data);
2205 			ddi_prop_remove_all(cdip);
2206 			ddi_set_parent_data(cdip, NULL);
2207 			IBTF_DPRINTF_L2("ibnex", "\tioc_create_pi: "
2208 			    "mdi_pi_online() failed ioc dip %p, rval %d",
2209 			    cdip, rval);
2210 			(void) ibnex_offline_childdip(cdip);
2211 			rval = IBNEX_FAILURE;
2212 			break;
2213 		} else
2214 			rval = IBNEX_SUCCESS;
2215 	}
2216 	return (rval);
2217 }
2218 
2219 
2220 /*
2221  * ibnex_create_ioc_node_prop()
2222  *	Create IOC device node properties
2223  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
2224  */
2225 static int
2226 ibnex_create_ioc_node_prop(ibdm_ioc_info_t *ioc_info, dev_info_t *cdip)
2227 {
2228 	uint16_t		 capabilities;
2229 	ib_dm_ioc_ctrl_profile_t *ioc_profile = &ioc_info->ioc_profile;
2230 
2231 	IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_node_prop");
2232 
2233 	if (ibnex_create_ioc_compatible_prop(cdip,
2234 	    ioc_profile) != IBNEX_SUCCESS) {
2235 		return (IBNEX_FAILURE);
2236 	}
2237 	if ((ioc_info->ioc_iou_dc_valid) &&
2238 	    (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "iou-diagcode",
2239 	    ioc_info->ioc_iou_diagcode)) != DDI_PROP_SUCCESS) {
2240 		IBTF_DPRINTF_L2("ibnex",
2241 		    "\tcreate_ioc_node_prop: iou-diagcode create failed");
2242 		return (IBNEX_FAILURE);
2243 	}
2244 	if ((ioc_info->ioc_diagdeviceid) && (ioc_info->ioc_dc_valid)) {
2245 		if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "ioc-diagcode",
2246 		    ioc_info->ioc_diagcode) != DDI_PROP_SUCCESS) {
2247 			IBTF_DPRINTF_L2("ibnex", "\tcreate_ioc_node_prop: "
2248 			    "ioc-diagcode create failed");
2249 			return (IBNEX_FAILURE);
2250 		}
2251 	}
2252 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "rdma-queue-depth",
2253 	    ioc_profile->ioc_rdma_read_qdepth) != DDI_PROP_SUCCESS) {
2254 		IBTF_DPRINTF_L2("ibnex",
2255 		    "\tcreate_ioc_node_prop: rdma-queue-depth create failed");
2256 		return (IBNEX_FAILURE);
2257 	}
2258 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "rdma-transfer-size",
2259 	    ioc_profile->ioc_rdma_xfer_sz) != DDI_PROP_SUCCESS) {
2260 		IBTF_DPRINTF_L2("ibnex", "\tcreate_ioc_node_prop: "
2261 		    "rdma-transfer-size create failed");
2262 		return (IBNEX_FAILURE);
2263 	}
2264 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "send-message-size",
2265 	    ioc_profile->ioc_send_msg_sz) != DDI_PROP_SUCCESS) {
2266 		IBTF_DPRINTF_L2("ibnex",
2267 		    "\tcreate_ioc_node_prop: send-message-size create failed");
2268 		return (IBNEX_FAILURE);
2269 	}
2270 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "send-queue-depth",
2271 	    ioc_profile->ioc_send_msg_qdepth) != DDI_PROP_SUCCESS) {
2272 		IBTF_DPRINTF_L2("ibnex",
2273 		    "\tcreate_ioc_node_prop: send-queue-depth create failed");
2274 		return (IBNEX_FAILURE);
2275 	}
2276 
2277 	capabilities = (ioc_profile->ioc_ctrl_opcap_mask << 8);
2278 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
2279 		"capabilities", capabilities) != DDI_PROP_SUCCESS) {
2280 		IBTF_DPRINTF_L2("ibnex",
2281 		    "\tcreate_ioc_node_prop: capabilities create failed");
2282 		return (IBNEX_FAILURE);
2283 	}
2284 	if (ndi_prop_update_string(DDI_DEV_T_NONE, cdip, "id-string",
2285 	    (char *)ioc_profile->ioc_id_string) != DDI_PROP_SUCCESS) {
2286 		IBTF_DPRINTF_L2("ibnex",
2287 		    "\tcreate_ioc_node_prop: id-string failed");
2288 		return (IBNEX_FAILURE);
2289 	}
2290 
2291 	/*
2292 	 * Create properties to represent all the service entries supported
2293 	 * by the IOC. Each service entry consists of 1) Service ID (64 bits)
2294 	 * and 2) Service name (40 bytes). The service entry table is
2295 	 * represented by two properties, service-ids and service-names. The
2296 	 * service-id property is a array of int64's and service names is
2297 	 * array of strings. The first element in the "service-ids" property
2298 	 * corresponds to first string in the "service-names" and so on.
2299 	 */
2300 	if ((ioc_profile->ioc_service_entries != 0) &&
2301 	    (ibnex_create_ioc_srv_props(cdip, ioc_info) != IBNEX_SUCCESS))
2302 		return (IBNEX_FAILURE);
2303 
2304 	/* Create destination port GID properties */
2305 	if (ibnex_create_ioc_portgid_prop(cdip, ioc_info) != IBNEX_SUCCESS)
2306 		return (IBNEX_FAILURE);
2307 
2308 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "protocol-version",
2309 	    ioc_profile->ioc_protocol_ver) != DDI_PROP_SUCCESS) {
2310 		IBTF_DPRINTF_L2("ibnex",
2311 		    "\tcreate_ioc_node_prop: protocol-version create failed");
2312 		return (IBNEX_FAILURE);
2313 	}
2314 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "protocol",
2315 	    ioc_profile->ioc_protocol) != DDI_PROP_SUCCESS) {
2316 		IBTF_DPRINTF_L2("ibnex",
2317 		    "\tcreate_ioc_node_prop: protocol create failed");
2318 		return (IBNEX_FAILURE);
2319 	}
2320 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "io-subclass",
2321 	    ioc_profile->ioc_io_subclass) != DDI_PROP_SUCCESS) {
2322 		IBTF_DPRINTF_L2("ibnex",
2323 		    "\tcreate_ioc_node_prop: subclass create failed");
2324 		return (IBNEX_FAILURE);
2325 	}
2326 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "io-class",
2327 	    ioc_profile->ioc_io_class) != DDI_PROP_SUCCESS) {
2328 		IBTF_DPRINTF_L2("ibnex",
2329 		    "\tcreate_ioc_node_prop: class prop create failed");
2330 		return (IBNEX_FAILURE);
2331 	}
2332 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "subsystem-id",
2333 	    ioc_profile->ioc_subsys_id) != DDI_PROP_SUCCESS) {
2334 		IBTF_DPRINTF_L2("ibnex",
2335 		    "\tcreate_ioc_node_prop: subsys_id create failed");
2336 		return (IBNEX_FAILURE);
2337 	}
2338 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "subsystem-vendor-id",
2339 	    ioc_profile->ioc_subsys_vendorid) != DDI_PROP_SUCCESS) {
2340 		IBTF_DPRINTF_L2("ibnex",
2341 		    "\tcreate_ioc_node_prop: subsystem vendor create failed");
2342 		return (IBNEX_FAILURE);
2343 	}
2344 	if (ndi_prop_update_int64(DDI_DEV_T_NONE, cdip, "ioc-guid",
2345 	    ioc_profile->ioc_guid) != DDI_PROP_SUCCESS) {
2346 		IBTF_DPRINTF_L2("ibnex",
2347 		    "\tcreate_ioc_node_prop: protocol create failed");
2348 		return (IBNEX_FAILURE);
2349 	}
2350 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "device-version",
2351 	    ioc_profile->ioc_device_ver) != DDI_PROP_SUCCESS) {
2352 		IBTF_DPRINTF_L2("ibnex",
2353 		    "\tcreate_ioc_node_prop: product-id create failed");
2354 		return (IBNEX_FAILURE);
2355 	}
2356 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "device-id",
2357 	    ioc_profile->ioc_deviceid) != DDI_PROP_SUCCESS) {
2358 		IBTF_DPRINTF_L2("ibnex",
2359 		    "\tcreate_ioc_node_prop: product-id create failed");
2360 		return (IBNEX_FAILURE);
2361 	}
2362 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "vendor-id",
2363 	    ioc_profile->ioc_vendorid) != DDI_PROP_SUCCESS) {
2364 		IBTF_DPRINTF_L2("ibnex",
2365 		    "\tcreate_ioc_node_prop: vendor-id create failed");
2366 		return (IBNEX_FAILURE);
2367 	}
2368 	return (IBNEX_SUCCESS);
2369 }
2370 
2371 
2372 /*
2373  * ibnex_create_ioc_portgid_prop()
2374  *	Creates "port-entries", "port-list" properties
2375  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
2376  */
2377 static int
2378 ibnex_create_ioc_portgid_prop(
2379     dev_info_t *cdip, ibdm_ioc_info_t *ioc_info)
2380 {
2381 	uint64_t	*port_gids;
2382 	int		length, ii, jj;
2383 	int		prop_len;
2384 	ibnex_node_data_t *node_data;
2385 
2386 	IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_portgid_prop");
2387 
2388 	node_data = ddi_get_parent_data(cdip);
2389 	ASSERT(node_data);
2390 
2391 	prop_len = (ioc_info->ioc_nportgids != 0) ?
2392 	    (2 * ioc_info->ioc_nportgids) : 1;
2393 	length = sizeof (uint64_t) * prop_len;
2394 	port_gids = kmem_zalloc(length, KM_SLEEP);
2395 
2396 	for (ii = 0, jj = 0; ii < ioc_info->ioc_nportgids; ii++) {
2397 		port_gids[jj++] = ioc_info->ioc_gid_list[ii].gid_dgid_hi;
2398 		port_gids[jj++] = ioc_info->ioc_gid_list[ii].gid_dgid_lo;
2399 	}
2400 	if (ndi_prop_update_int64_array(DDI_DEV_T_NONE, cdip, "port-list",
2401 	    (int64_t *)port_gids, prop_len) != DDI_PROP_SUCCESS) {
2402 		IBTF_DPRINTF_L2("ibnex",
2403 		    "\tcreate_ioc_portgid_prop: port-list create failed");
2404 		kmem_free(port_gids, length);
2405 		return (IBNEX_FAILURE);
2406 	}
2407 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "port-entries",
2408 	    ioc_info->ioc_nportgids) != DDI_PROP_SUCCESS) {
2409 		IBTF_DPRINTF_L2("ibnex",
2410 		    "\tcreate_ioc_portgid_prop: port-entries create failed");
2411 		kmem_free(port_gids, length);
2412 		return (IBNEX_FAILURE);
2413 	}
2414 
2415 	kmem_free(port_gids, length);
2416 	return (IBNEX_SUCCESS);
2417 }
2418 
2419 
2420 /*
2421  * ibnex_create_ioc_srv_props()
2422  *	Creates "service-name" and "service-id" properties
2423  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
2424  */
2425 static int
2426 ibnex_create_ioc_srv_props(
2427     dev_info_t *cdip, ibdm_ioc_info_t *ioc_info)
2428 {
2429 	int			length, ii;
2430 	uint64_t		*srv_id;
2431 	char			*temp, *srv_names[IB_DM_MAX_IOCS_IN_IOU];
2432 	ib_dm_ioc_ctrl_profile_t *profile = &ioc_info->ioc_profile;
2433 	ibdm_srvents_info_t	 *srvents = ioc_info->ioc_serv;
2434 
2435 	IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_srv_props");
2436 
2437 	length = profile->ioc_service_entries * sizeof (ib_dm_srv_t);
2438 	srv_id = kmem_zalloc(length, KM_SLEEP);
2439 	temp = (char *)((char *)srv_id + (8 * profile->ioc_service_entries));
2440 	for (ii = 0; ii < profile->ioc_service_entries; ii++) {
2441 		srv_names[ii] = (char *)temp + (ii * IB_DM_MAX_SVC_NAME_LEN);
2442 	}
2443 
2444 	for (ii = 0; ii < profile->ioc_service_entries; ii++) {
2445 		srv_id[ii] = srvents[ii].se_attr.srv_id;
2446 		bcopy(srvents[ii].se_attr.srv_name,
2447 		    srv_names[ii], (IB_DM_MAX_SVC_NAME_LEN - 1));
2448 		IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_srv_props "
2449 		    "Service Names : %s", srv_names[ii]);
2450 		IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_srv_props "
2451 		    "Service ID : %llx", srv_id[ii]);
2452 	}
2453 
2454 	if (ndi_prop_update_int64_array(DDI_DEV_T_NONE, cdip,
2455 	    "service-id", (int64_t *)srv_id,
2456 	    profile->ioc_service_entries) != DDI_PROP_SUCCESS) {
2457 		IBTF_DPRINTF_L2("ibnex",
2458 		    "\tcreate_ioc_srv_props: service-id create failed");
2459 		kmem_free(srv_id, length);
2460 		return (IBNEX_FAILURE);
2461 	}
2462 
2463 	if (ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip,
2464 	    "service-name", (char **)srv_names,
2465 	    profile->ioc_service_entries) != DDI_PROP_SUCCESS) {
2466 		IBTF_DPRINTF_L2("ibnex",
2467 		    "\tcreate_ioc_srv_props: service-name create failed");
2468 		kmem_free(srv_id, length);
2469 		return (IBNEX_FAILURE);
2470 	}
2471 	kmem_free(srv_id, length);
2472 	return (IBNEX_SUCCESS);
2473 }
2474 
2475 
2476 /*
2477  * ibnex_create_ioc_compatible_prop()
2478  *	Creates "compatible" property values
2479  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
2480  */
2481 static int
2482 ibnex_create_ioc_compatible_prop(
2483     dev_info_t *cdip, ib_dm_ioc_ctrl_profile_t *ioc_profile)
2484 {
2485 	char		*temp;
2486 	int		rval, ii;
2487 	char		*compatible[IBNEX_MAX_COMPAT_NAMES];
2488 
2489 	/*
2490 	 * Initialize the "compatible" property string as below:
2491 	 * Compatible Strings :
2492 	 *	1. ib.V<vid>P<pid>S<subsys vid>s<subsys id>v<ver>
2493 	 *	2. ib.V<vid>P<pid>S<subsys vid>s<subsys id>
2494 	 *	3. ib.V<vid>P<pid>v<ver>
2495 	 *	4. ib.V<vid>P<pid>
2496 	 *	5. ib.C<Class>c<Subclass>p<protocol>r<protocol ver>
2497 	 *	6. ib.C<Class>c<Subclass>p<protocol>
2498 	 *
2499 	 * Note:
2500 	 *	All leading zeros must be present
2501 	 *	All numeric values must specified in hex without prefix "0x"
2502 	 */
2503 
2504 	temp = kmem_alloc(IBNEX_MAX_COMPAT_PROP_SZ, KM_SLEEP);
2505 	for (ii = 0; ii < IBNEX_MAX_COMPAT_NAMES; ii++)
2506 		compatible[ii] = temp + (ii * IBNEX_MAX_COMPAT_LEN);
2507 
2508 	(void) snprintf(compatible[0], IBNEX_MAX_COMPAT_LEN,
2509 	    "ib.V%06xP%08xS%06xs%08xv%04x",
2510 	    ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid,
2511 	    ioc_profile->ioc_subsys_vendorid, ioc_profile->ioc_subsys_id,
2512 	    ioc_profile->ioc_device_ver);
2513 
2514 	(void) snprintf(compatible[1], IBNEX_MAX_COMPAT_LEN,
2515 	    "ib.V%06xP%08xS%06xs%08x",
2516 	    ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid,
2517 	    ioc_profile->ioc_subsys_vendorid, ioc_profile->ioc_subsys_id);
2518 
2519 	(void) snprintf(compatible[2], IBNEX_MAX_COMPAT_LEN,
2520 	    "ib.V%06xP%08xv%04x",
2521 	    ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid,
2522 	    ioc_profile->ioc_device_ver);
2523 
2524 	(void) snprintf(compatible[3], IBNEX_MAX_COMPAT_LEN,
2525 	    "ib.V%06xP%08x",
2526 	    ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid);
2527 
2528 	(void) snprintf(compatible[4], IBNEX_MAX_COMPAT_LEN,
2529 	    "ib.C%04xc%04xp%04xr%04x",
2530 	    ioc_profile->ioc_io_class, ioc_profile->ioc_io_subclass,
2531 	    ioc_profile->ioc_protocol, ioc_profile->ioc_protocol_ver);
2532 
2533 	(void) snprintf(compatible[5], IBNEX_MAX_COMPAT_LEN,
2534 	    "ib.C%04xc%04xp%04x",
2535 	    ioc_profile->ioc_io_class, ioc_profile->ioc_io_subclass,
2536 	    ioc_profile->ioc_protocol);
2537 	for (ii = 0; ii < IBNEX_MAX_COMPAT_NAMES; ii++)
2538 		IBTF_DPRINTF_L4("ibnex", "\tcompatible: %s", compatible[ii]);
2539 
2540 	/* Create the compatible property for child cdip */
2541 	rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip,
2542 	    "compatible", (char **)compatible, IBNEX_MAX_COMPAT_NAMES);
2543 
2544 	if (rval != DDI_PROP_SUCCESS) {
2545 		IBTF_DPRINTF_L2("ibnex", "\tcompatible prop_create failed");
2546 		kmem_free(temp, IBNEX_MAX_COMPAT_PROP_SZ);
2547 		return (IBNEX_FAILURE);
2548 	}
2549 
2550 	kmem_free(temp, IBNEX_MAX_COMPAT_PROP_SZ);
2551 	return (IBNEX_SUCCESS);
2552 }
2553 
2554 
2555 static void
2556 ibnex_ioc_node_cleanup()
2557 {
2558 	ibnex_node_data_t *node, *delete;
2559 
2560 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2561 	for (node = ibnex.ibnex_ioc_node_head; node; ) {
2562 		delete = node;
2563 		node = node->node_next;
2564 		mutex_exit(&ibnex.ibnex_mutex);
2565 		ibnex_delete_ioc_node_data(delete);
2566 		mutex_enter(&ibnex.ibnex_mutex);
2567 	}
2568 }
2569 
2570 /*
2571  * ibnex_delete_ioc_node_data()
2572  *	Delete IOC node from the list
2573  */
2574 static void
2575 ibnex_delete_ioc_node_data(ibnex_node_data_t *node)
2576 {
2577 	IBTF_DPRINTF_L4("ibnex", "\tdelete_ioc_node_data:");
2578 
2579 	mutex_enter(&ibnex.ibnex_mutex);
2580 	if ((node->node_next == NULL) && (node->node_prev == NULL)) {
2581 		ASSERT(ibnex.ibnex_ioc_node_head == node);
2582 		ibnex.ibnex_ioc_node_head = NULL;
2583 	} else if (node->node_next == NULL)
2584 		node->node_prev->node_next = NULL;
2585 	else if (node->node_prev == NULL) {
2586 		node->node_next->node_prev = NULL;
2587 		ibnex.ibnex_ioc_node_head = node->node_next;
2588 	} else {
2589 		node->node_prev->node_next = node->node_next;
2590 		node->node_next->node_prev = node->node_prev;
2591 	}
2592 	IBTF_DPRINTF_L4("ibnex", "\tdelete_ioc_node_data: head %p",
2593 	    ibnex.ibnex_ioc_node_head);
2594 	mutex_exit(&ibnex.ibnex_mutex);
2595 	kmem_free(node, sizeof (ibnex_node_data_t));
2596 }
2597 
2598 
2599 /*
2600  * ibnex_dm_callback()
2601  *
2602  *	This routine is registered with the IBDM during IB nexus attach. It
2603  *	is called by the IBDM module when it discovers
2604  *		New HCA port
2605  *		HCA port removal
2606  *		New HCA added
2607  *		HCA removed
2608  */
2609 void
2610 ibnex_dm_callback(void *arg, ibdm_events_t flag)
2611 {
2612 	char	hca_guid[IBNEX_HCAGUID_STRSZ];
2613 	ibdm_ioc_info_t	*ioc_list, *ioc;
2614 	ibnex_node_data_t	*node_data;
2615 
2616 	IBTF_DPRINTF_L4("ibnex", "\tdm_callback: attr %p event %x", arg, flag);
2617 
2618 	switch (flag) {
2619 	case IBDM_EVENT_HCA_ADDED:
2620 		(void) snprintf(hca_guid, IBNEX_HCAGUID_STRSZ, "%llX",
2621 		    (*(longlong_t *)arg));
2622 		/* Create a devctl minor node for the HCA's port  */
2623 		if (ddi_create_minor_node(ibnex.ibnex_dip, hca_guid, S_IFCHR,
2624 		    ddi_get_instance(ibnex.ibnex_dip),
2625 		    DDI_NT_IB_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
2626 			IBTF_DPRINTF_L4("ibnex", "\tdm_callback: failed to "
2627 			    "create minor node for port w/ guid %s", hca_guid);
2628 		}
2629 
2630 		break;
2631 
2632 	case IBDM_EVENT_HCA_REMOVED:
2633 		(void) snprintf(hca_guid, IBNEX_HCAGUID_STRSZ, "%llX",
2634 		    (*(longlong_t *)arg));
2635 		ddi_remove_minor_node(ibnex.ibnex_dip, hca_guid);
2636 		break;
2637 
2638 	case IBDM_EVENT_IOC_PROP_UPDATE:
2639 		ioc = ioc_list = (ibdm_ioc_info_t *)arg;
2640 		if (ioc_list == NULL)
2641 			break;
2642 
2643 		mutex_enter(&ibnex.ibnex_mutex);
2644 		while (ioc_list) {
2645 			if ((node_data = ibnex_is_node_data_present(
2646 			    IBNEX_IOC_NODE, ioc_list, 0, 0)) != NULL &&
2647 			    node_data->node_dip != NULL) {
2648 				ibnex_update_prop(node_data, ioc_list);
2649 			}
2650 			ioc_list = ioc_list->ioc_next;
2651 		}
2652 		mutex_exit(&ibnex.ibnex_mutex);
2653 		ibdm_ibnex_free_ioc_list(ioc);
2654 	}
2655 }
2656 
2657 
2658 /*
2659  * ibnex_get_dip_from_guid()
2660  *
2661  *	Searches the linked list of the port nodes and returns the dip for
2662  *	the of the Port / Node guid requested.
2663  *	Returns NULL if not found
2664  */
2665 int
2666 ibnex_get_dip_from_guid(ib_guid_t guid, int index, ib_pkey_t pkey,
2667     dev_info_t **dip)
2668 {
2669 	int			node_index;
2670 	ib_guid_t		node_guid;
2671 	ib_pkey_t		node_pkey;
2672 	ibnex_node_data_t	*node_data;
2673 
2674 	IBTF_DPRINTF_L4("ibnex",
2675 	    "\tget_dip_from_guid: guid = %llx", guid);
2676 
2677 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2678 	/* Search for a matching entry in internal lists */
2679 	node_data = ibnex.ibnex_port_node_head;
2680 	while (node_data) {
2681 		node_guid = node_data->node_data.port_node.port_guid;
2682 		node_index = node_data->node_data.port_node.port_commsvc_idx;
2683 		node_pkey = node_data->node_data.port_node.port_pkey;
2684 		if ((node_guid == guid) && (index == node_index) &&
2685 		    (node_pkey == pkey)) {
2686 			break;
2687 		}
2688 		node_data = node_data->node_next;
2689 	}
2690 
2691 	/* matching found with a valid dip */
2692 	if (node_data && node_data->node_dip) {
2693 		*dip = node_data->node_dip;
2694 		return (IBNEX_SUCCESS);
2695 	} else if (node_data && !node_data->node_dip) {	/* dip is invalid */
2696 		*dip = NULL;
2697 		return (IBNEX_SUCCESS);
2698 	}
2699 
2700 	/* no match found */
2701 	*dip = NULL;
2702 	return (IBNEX_FAILURE);
2703 }
2704 
2705 
2706 /*
2707  * ibnex_comm_svc_init()
2708  *	Read the property and cache the values in the global
2709  *	structure.
2710  *	Check for max allowed length (4 bytes) of service name
2711  *	(each element of the property)
2712  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
2713  */
2714 static ibnex_rval_t
2715 ibnex_comm_svc_init(char *property, ibnex_node_type_t type)
2716 {
2717 	int		i, len, count;
2718 	int		ncomm_svcs;
2719 	char		**comm_svcp;
2720 	char		**servicep = NULL;
2721 	uint_t		nservices = 0;
2722 	int			*valid = NULL;
2723 
2724 	IBTF_DPRINTF_L4("ibnex", "\tcomm_svc_init : %s property, type = %x",
2725 	    property, type);
2726 
2727 	/* lookup the string array property */
2728 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, ibnex.ibnex_dip,
2729 	    DDI_PROP_DONTPASS, property, &servicep, &nservices) !=
2730 	    DDI_PROP_SUCCESS) {
2731 		IBTF_DPRINTF_L2("ibnex", "\t%s property undefined", property);
2732 		return (IBNEX_SUCCESS);
2733 	}
2734 
2735 	if (nservices)
2736 		valid = kmem_zalloc(nservices * sizeof (int), KM_SLEEP);
2737 
2738 
2739 	/* first read the file to get a count of valid service entries */
2740 	for (ncomm_svcs = 0, count = 0; count < nservices; count++) {
2741 		int j;
2742 
2743 		len = strlen(servicep[count]);
2744 		if (len == 0 || len > 4) {
2745 			IBTF_DPRINTF_L2("ibnex", "\tcomm_svc_init : "
2746 			    "Service name %s invalid : length %d",
2747 			    servicep[count], len);
2748 			continue;
2749 		}
2750 		if (ibnex_unique_svcname(servicep[count]) != IBNEX_SUCCESS) {
2751 			IBTF_DPRINTF_L2("ibnex", "\tcomm_svc_init : "
2752 			    "Service name %s invalid : Not unique",
2753 			    servicep[count]);
2754 			continue;
2755 		}
2756 
2757 		/*
2758 		 * ibnex_unique_svcname checks for uniqueness in service names
2759 		 * communication services fully initialized. Check uniqueness
2760 		 * in service names currently initialized.
2761 		 */
2762 		for (j = 0; j < count; j++)
2763 			if (valid[j] && strncmp(servicep[count],
2764 			    servicep[j], 4) == 0) {
2765 				IBTF_DPRINTF_L2("ibnex", "\tcomm_svc_init : "
2766 				    "Service name %s invalid : Not unique",
2767 				    servicep[count]);
2768 					continue;
2769 			}
2770 
2771 		valid[count] = 1;
2772 		ncomm_svcs++;
2773 	}
2774 
2775 	/* if no valid entries found, bailout */
2776 	if (nservices == 0 || ncomm_svcs == 0) {
2777 		IBTF_DPRINTF_L4("ibnex", "\tNo %s entries found", property);
2778 		ddi_prop_free(servicep); /* free the property */
2779 		if (valid)
2780 			kmem_free(valid, nservices * sizeof (int));
2781 		return (IBNEX_SUCCESS);
2782 	}
2783 
2784 	comm_svcp = kmem_zalloc((ncomm_svcs * sizeof (char *)), KM_SLEEP);
2785 	if (type == IBNEX_PORT_COMMSVC_NODE) {
2786 		ibnex.ibnex_comm_svc_names = comm_svcp;
2787 		ibnex.ibnex_num_comm_svcs = ncomm_svcs;
2788 	} else if (type == IBNEX_VPPA_COMMSVC_NODE) {
2789 		ibnex.ibnex_vppa_comm_svc_names = comm_svcp;
2790 		ibnex.ibnex_nvppa_comm_svcs = ncomm_svcs;
2791 	} else if (type == IBNEX_HCASVC_COMMSVC_NODE) {
2792 		ibnex.ibnex_hcasvc_comm_svc_names = comm_svcp;
2793 		ibnex.ibnex_nhcasvc_comm_svcs = ncomm_svcs;
2794 	}
2795 
2796 	/* copy the services into an array of strings */
2797 	for (i = 0, count = 0; count < nservices; count++) {
2798 		if (valid[count] == 0)	/* Skip invalid ones */
2799 			continue;
2800 		comm_svcp[i] = kmem_alloc(len + 1, KM_SLEEP);
2801 		(void) strcpy(comm_svcp[i], servicep[count]);
2802 		IBTF_DPRINTF_L4("ibnex",
2803 		    "\t\tService [%d]: %s", i, comm_svcp[i]);
2804 		++i;
2805 	}
2806 	ddi_prop_free(servicep);
2807 	kmem_free(valid, nservices * sizeof (int));
2808 	return (IBNEX_SUCCESS);
2809 }
2810 
2811 
2812 /*
2813  * ibnex_comm_svc_fini()
2814  *	Deallocate all the memory allocated for the communication
2815  *	service arrays.
2816  */
2817 static void
2818 ibnex_comm_svc_fini()
2819 {
2820 	int	index;
2821 
2822 	for (index = 0; index < ibnex.ibnex_num_comm_svcs; index++) {
2823 		kmem_free(ibnex.ibnex_comm_svc_names[index],
2824 		    (strlen(ibnex.ibnex_comm_svc_names[index]) + 1));
2825 	}
2826 	if (ibnex.ibnex_comm_svc_names) {
2827 		kmem_free(ibnex.ibnex_comm_svc_names,
2828 		    ibnex.ibnex_num_comm_svcs * sizeof (char *));
2829 	}
2830 	for (index = 0; index < ibnex.ibnex_nvppa_comm_svcs; index++) {
2831 		kmem_free(ibnex.ibnex_vppa_comm_svc_names[index],
2832 		    strlen(ibnex.ibnex_vppa_comm_svc_names[index]) +1);
2833 	}
2834 	if (ibnex.ibnex_vppa_comm_svc_names) {
2835 		kmem_free(ibnex.ibnex_vppa_comm_svc_names,
2836 		    ibnex.ibnex_nvppa_comm_svcs * sizeof (char *));
2837 	}
2838 	for (index = 0; index < ibnex.ibnex_nhcasvc_comm_svcs; index++) {
2839 		kmem_free(ibnex.ibnex_hcasvc_comm_svc_names[index],
2840 		    strlen(ibnex.ibnex_hcasvc_comm_svc_names[index]) +1);
2841 	}
2842 	if (ibnex.ibnex_hcasvc_comm_svc_names) {
2843 		kmem_free(ibnex.ibnex_hcasvc_comm_svc_names,
2844 		    ibnex.ibnex_nhcasvc_comm_svcs * sizeof (char *));
2845 	}
2846 	ibnex.ibnex_comm_svc_names = NULL;
2847 	ibnex.ibnex_num_comm_svcs = 0;
2848 	ibnex.ibnex_vppa_comm_svc_names = NULL;
2849 	ibnex.ibnex_nvppa_comm_svcs = 0;
2850 	ibnex.ibnex_hcasvc_comm_svc_names = NULL;
2851 	ibnex.ibnex_nhcasvc_comm_svcs = 0;
2852 }
2853 
2854 
2855 /*
2856  * ibnex_commsvc_initnode()
2857  *	This routine is specific to port/VPPA node creation
2858  *	Creates a device node for the comm service specified by commsvc_index
2859  *	Creates all the device node properties
2860  *	Allocates and initializes the node specific data
2861  *	Binds the device driver of the device node
2862  *	Returns "dev_info_t" of the child node or NULL in case of failure
2863  *	Sets IBNEX_SUCCESS/IBNEX_FAILURE/IBNEX_BUSY in "rval" to reflect
2864  *	if the operation was successful, failed or was not performed.
2865  */
2866 dev_info_t *
2867 ibnex_commsvc_initnode(dev_info_t *parent, ibdm_port_attr_t *port_attr,
2868     int index, int node_type, ib_pkey_t pkey, int *rval, int flag)
2869 {
2870 	int			ret;
2871 	char			*svcname;
2872 	dev_info_t		*cdip;
2873 	ibnex_node_data_t	*node_data;
2874 
2875 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2876 
2877 	*rval = IBNEX_SUCCESS;
2878 
2879 	/*
2880 	 * prevent any races
2881 	 * we have seen this node_data and it has been initialized
2882 	 * Note that node_dip is already NULL if unconfigure is in
2883 	 * progress.
2884 	 */
2885 	node_data = ibnex_is_node_data_present(node_type, (void *)port_attr,
2886 	    index, pkey);
2887 	if (node_data && node_data->node_dip) {
2888 		/*
2889 		 * Return NULL if another configure
2890 		 * operation is in progress
2891 		 */
2892 		if (node_data->node_state == IBNEX_CFGADM_CONFIGURING) {
2893 			*rval = IBNEX_BUSY;
2894 			return (NULL);
2895 		} else {
2896 			return (node_data->node_dip);
2897 		}
2898 	} else if (node_data == NULL) {
2899 		/* allocate a new ibnex_node_data_t */
2900 		node_data = ibnex_init_child_nodedata(node_type, port_attr,
2901 		    index, pkey);
2902 	}
2903 
2904 	/*
2905 	 * Return NULL if another unconfigure operation is in progress
2906 	 */
2907 	if (node_data->node_state == IBNEX_CFGADM_UNCONFIGURING) {
2908 		*rval = IBNEX_BUSY;
2909 		return (NULL);
2910 	}
2911 
2912 	ASSERT(node_data->node_state != IBNEX_CFGADM_CONFIGURED);
2913 	node_data->node_state = IBNEX_CFGADM_CONFIGURING;
2914 
2915 	ndi_devi_alloc_sleep(parent,
2916 	    IBNEX_IBPORT_CNAME, (dnode_t)DEVI_SID_NODEID, &cdip);
2917 
2918 	node_data->node_dip	= cdip;
2919 	ddi_set_parent_data(cdip, node_data);
2920 	mutex_exit(&ibnex.ibnex_mutex);
2921 
2922 	switch (node_type) {
2923 		case IBNEX_VPPA_COMMSVC_NODE :
2924 			svcname = ibnex.ibnex_vppa_comm_svc_names[index];
2925 			break;
2926 		case IBNEX_HCASVC_COMMSVC_NODE :
2927 			svcname = ibnex.ibnex_hcasvc_comm_svc_names[index];
2928 			break;
2929 		case IBNEX_PORT_COMMSVC_NODE :
2930 			svcname = ibnex.ibnex_comm_svc_names[index];
2931 			break;
2932 		default :
2933 			IBTF_DPRINTF_L2("ibnex", "\tcommsvc_initnode:"
2934 			    "\tInvalid Node type");
2935 			*rval = IBNEX_FAILURE;
2936 			ibnex_delete_port_node_data(node_data);
2937 			ddi_prop_remove_all(cdip);
2938 			ddi_set_parent_data(cdip, NULL);
2939 			(void) ndi_devi_free(cdip);
2940 			mutex_enter(&ibnex.ibnex_mutex);
2941 			return (NULL);
2942 	}
2943 
2944 	if (ibnex_create_port_node_prop(port_attr, cdip, svcname, pkey) ==
2945 	    IBNEX_SUCCESS) {
2946 		if (flag == IBNEX_DEVFS_ENUMERATE)
2947 			ret = ndi_devi_bind_driver(cdip, 0);
2948 		else
2949 			ret = ndi_devi_online(cdip, 0);
2950 		if (ret == NDI_SUCCESS) {
2951 			mutex_enter(&ibnex.ibnex_mutex);
2952 			node_data->node_state	= IBNEX_CFGADM_CONFIGURED;
2953 			return (cdip);
2954 		}
2955 	}
2956 	*rval = IBNEX_FAILURE;
2957 	ibnex_delete_port_node_data(node_data);
2958 	ddi_prop_remove_all(cdip);
2959 	ddi_set_parent_data(cdip, NULL);
2960 	(void) ndi_devi_free(cdip);
2961 	mutex_enter(&ibnex.ibnex_mutex);
2962 	IBTF_DPRINTF_L4("ibnex", "\tcommsvc_initnode: failure exit");
2963 	return (NULL);
2964 }
2965 
2966 
2967 /*
2968  * ibnex_create_port_node_prop()
2969  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
2970  */
2971 static int
2972 ibnex_create_port_node_prop(ibdm_port_attr_t *port_attr,
2973     dev_info_t *child_dip, char *srvname, ib_pkey_t pkey)
2974 {
2975 	if (ibnex_create_port_compatible_prop(child_dip,
2976 	    srvname, port_attr) != DDI_PROP_SUCCESS) {
2977 		IBTF_DPRINTF_L2("ibnex",
2978 		    "\tcreate_port_node_prop: compatible update failed");
2979 		return (IBNEX_FAILURE);
2980 	}
2981 	if ((pkey != 0) && (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2982 	    "port-pkey", pkey) != DDI_PROP_SUCCESS)) {
2983 		IBTF_DPRINTF_L2("ibnex",
2984 		    "\tcreate_port_node_prop: port-num update failed");
2985 		return (IBNEX_FAILURE);
2986 	}
2987 
2988 	/*
2989 	 * For HCA_SVC device nodes, port_num will be 0.
2990 	 * Do not create the "port-number" & "port-guid" properties.
2991 	 */
2992 	if (port_attr->pa_port_num != 0) {
2993 		if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2994 			"port-number", port_attr->pa_port_num) !=
2995 		    DDI_PROP_SUCCESS) {
2996 			IBTF_DPRINTF_L2("ibnex",
2997 			    "\tcreate_port_node_prop: port-num update failed");
2998 			return (IBNEX_FAILURE);
2999 		}
3000 		if (ndi_prop_update_int64(DDI_DEV_T_NONE, child_dip,
3001 			"port-guid", port_attr->pa_port_guid) !=
3002 		    DDI_PROP_SUCCESS) {
3003 			IBTF_DPRINTF_L2("ibnex",
3004 			    "\tcreate_port_node_prop: port-guid update failed");
3005 			return (IBNEX_FAILURE);
3006 		}
3007 	} else {
3008 		ibdm_hca_list_t	*hca_list;
3009 
3010 		/*
3011 		 * HCA_SVC nodes require "num-ports" & "port-guids"
3012 		 * properties.
3013 		 *
3014 		 * To create the num-ports & port-guids attribute :
3015 		 * 1. Get HCA list (ibdm_ibnex_get_hca_info_by_guid)
3016 		 * 2. Form the array of port GUIDs.
3017 		 */
3018 		if ((hca_list = ibdm_ibnex_get_hca_info_by_guid(
3019 		    port_attr->pa_hca_guid)) == NULL) {
3020 			IBTF_DPRINTF_L2("ibnex",
3021 			    "\tcreate_port_node_prop: hca_info_by_guid failed");
3022 			return (IBNEX_FAILURE);
3023 		}
3024 
3025 		if (hca_list->hl_nports != 0) {
3026 			ib_guid_t	*port_guids;
3027 			uint8_t		portnum;
3028 
3029 			ASSERT(hca_list->hl_port_attr != NULL);
3030 
3031 			port_guids = kmem_zalloc(
3032 			    hca_list->hl_nports * sizeof (ib_guid_t),
3033 			    KM_SLEEP);
3034 
3035 			for (portnum = 0; portnum < hca_list->hl_nports;
3036 			    portnum++) {
3037 				port_guids[portnum] = (hca_list->
3038 				    hl_port_attr[portnum]).pa_port_guid;
3039 			}
3040 
3041 			if (ndi_prop_update_int64_array(DDI_DEV_T_NONE,
3042 			    child_dip, "port-guids", (int64_t *)port_guids,
3043 			    hca_list->hl_nports) != DDI_PROP_SUCCESS) {
3044 				IBTF_DPRINTF_L2("ibnex",
3045 				    "\tcreate_port_node_prop: port-guids "
3046 				    "create failed");
3047 				kmem_free(port_guids, hca_list->hl_nports *
3048 				    sizeof (ib_guid_t));
3049 				ibdm_ibnex_free_hca_list(hca_list);
3050 				return (IBNEX_FAILURE);
3051 			}
3052 			kmem_free(port_guids, hca_list->hl_nports *
3053 			    sizeof (ib_guid_t));
3054 		}
3055 
3056 		if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3057 			"num-ports", hca_list->hl_nports) != DDI_PROP_SUCCESS) {
3058 			IBTF_DPRINTF_L2("ibnex",
3059 			    "\tcreate_port_node_prop: num-ports update failed");
3060 			ibdm_ibnex_free_hca_list(hca_list);
3061 			return (IBNEX_FAILURE);
3062 		}
3063 		ibdm_ibnex_free_hca_list(hca_list);
3064 	}
3065 
3066 	if (ndi_prop_update_int64(DDI_DEV_T_NONE, child_dip,
3067 		"hca-guid", port_attr->pa_hca_guid) != DDI_PROP_SUCCESS) {
3068 		IBTF_DPRINTF_L2("ibnex",
3069 		    "\tcreate_port_node_prop: hca-guid update failed");
3070 		return (IBNEX_FAILURE);
3071 	}
3072 	if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3073 		"product-id", port_attr->pa_productid) != DDI_PROP_SUCCESS) {
3074 		IBTF_DPRINTF_L2("ibnex",
3075 		    "\tcreate_port_node_prop: product-id update failed");
3076 		return (IBNEX_FAILURE);
3077 	}
3078 	if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3079 		"vendor-id", port_attr->pa_vendorid) != DDI_PROP_SUCCESS) {
3080 		IBTF_DPRINTF_L2("ibnex",
3081 		    "\tcreate_port_node_prop: vendor-id update failed");
3082 		return (IBNEX_FAILURE);
3083 	}
3084 	if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip, "device-version",
3085 	    port_attr->pa_dev_version) != DDI_PROP_SUCCESS) {
3086 		IBTF_DPRINTF_L2("ibnex",
3087 		    "\tcreate_port_node_prop: device-version update failed");
3088 		return (IBNEX_FAILURE);
3089 	}
3090 	return (IBNEX_SUCCESS);
3091 }
3092 
3093 
3094 /*
3095  * ibnex_str2int()
3096  *	Utility function that converts a string of length  "len" to
3097  *	integer.
3098  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
3099  */
3100 static int
3101 ibnex_str2int(char *c, int len, int *ret)
3102 {
3103 	int intval = 0, ii;
3104 
3105 	IBTF_DPRINTF_L4("ibnex", "\tstr2int: Int string %s..", c);
3106 	*ret = IBNEX_SUCCESS;
3107 	for (ii = 0; ii < len; ii ++) {
3108 		if ((c[ii] >= '0') && (c[ii] <= '9'))
3109 			intval = intval * 10 +c[ii] - '0';
3110 		else {
3111 			IBTF_DPRINTF_L2("ibnex",
3112 			    "\tstr2int: Invalid integer string %s..", c);
3113 			*ret = IBNEX_FAILURE;
3114 			break;
3115 		}
3116 	}
3117 
3118 	return (intval);
3119 }
3120 
3121 
3122 /*
3123  * ibnex_str2hex()
3124  *	Utility functions that converts a string of length  "len" to
3125  *	hex value. Note. This function does not handle strings which
3126  *	string length more than 8 bytes.
3127  *
3128  */
3129 uint64_t
3130 ibnex_str2hex(char *c, int len, int *ret)
3131 {
3132 	uint64_t hex = 0, ii;
3133 
3134 	*ret = IBNEX_SUCCESS;
3135 	for (ii = 0; ii < len; ii ++) {
3136 		hex = (ii == 0) ? hex : (hex << 4);
3137 		if ((c[ii] >= '0') && (c[ii] <= '9'))
3138 			hex |= c[ii] - '0';
3139 		else if ((c[ii] >= 'a') && (c[ii] <= 'f'))
3140 			hex |= c[ii] - 'a' + 10;
3141 		else if ((c[ii] >= 'A') && (c[ii] <= 'F'))
3142 			hex |= c[ii] - 'A' + 10;
3143 		else {
3144 			IBTF_DPRINTF_L2("ibnex",
3145 			    "\tstr2hex: Invalid integer string");
3146 			*ret = IBNEX_FAILURE;
3147 			break;
3148 		}
3149 	}
3150 
3151 	return (hex);
3152 }
3153 
3154 
3155 /*
3156  * ibnex_create_port_compatible_prop()
3157  *	Creates 'Compatibility' property for port / HCA_SVC device nodes
3158  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
3159  */
3160 static int
3161 ibnex_create_port_compatible_prop(dev_info_t *child_dip,
3162     char *comm_svcp, ibdm_port_attr_t *port_attr)
3163 {
3164 	int 	rval, i;
3165 	char	*temp;
3166 	char	*compatible[IBNEX_MAX_IBPORT_COMPAT_NAMES];
3167 
3168 	IBTF_DPRINTF_L4("ibnex", "\tcreate_port_compatible_prop: Begin");
3169 	/*
3170 	 * Initialize the "compatible" property string as below:
3171 	 * Compatible Strings :
3172 	 * 1. ib.V<vid>P<pid>v<revision>.<service name>.
3173 	 * 2. ib.V<vid>P<pid>.<service name>.
3174 	 * 3. ib.<service name>
3175 	 * Leading zeros must be present
3176 	 */
3177 	temp = kmem_alloc(IBNEX_MAX_IBPORT_COMPAT_PROP_SZ, KM_SLEEP);
3178 	for (i = 0; i < IBNEX_MAX_IBPORT_COMPAT_NAMES; i++) {
3179 		compatible[i] = temp + (i * IBNEX_MAX_COMPAT_LEN);
3180 	}
3181 
3182 	(void) snprintf(compatible[0], IBNEX_MAX_COMPAT_LEN,
3183 	    "ib.V%06xP%08xv%04x.%s",
3184 	    port_attr->pa_vendorid, port_attr->pa_productid,
3185 	    port_attr->pa_dev_version, comm_svcp);
3186 	(void) snprintf(compatible[1], IBNEX_MAX_COMPAT_LEN,
3187 	    "ib.V%06xP%08x.%s",
3188 	    port_attr->pa_vendorid, port_attr->pa_productid,
3189 	    comm_svcp);
3190 	(void) snprintf(compatible[2], IBNEX_MAX_COMPAT_LEN,
3191 	    "ib.%s", comm_svcp);
3192 
3193 	for (i = 0; i < IBNEX_MAX_IBPORT_COMPAT_NAMES; i++)
3194 		IBTF_DPRINTF_L4("ibnex", "\tcompatible: %s", compatible[i]);
3195 
3196 	rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
3197 	    "compatible", (char **)compatible, IBNEX_MAX_IBPORT_COMPAT_NAMES);
3198 
3199 	if (rval != DDI_PROP_SUCCESS) {
3200 		kmem_free(temp, IBNEX_MAX_IBPORT_COMPAT_PROP_SZ);
3201 		return (IBNEX_FAILURE);
3202 	}
3203 	kmem_free(temp, IBNEX_MAX_IBPORT_COMPAT_PROP_SZ);
3204 	return (IBNEX_SUCCESS);
3205 }
3206 
3207 
3208 /*
3209  * ibnex_delete_port_node_data()
3210  *	Delete the parent private node data from the linked list
3211  *	Deallocate the memory of the port/ioc attributes
3212  *	Deallocate the memory of the node data
3213  */
3214 static void
3215 ibnex_delete_port_node_data(ibnex_node_data_t *node)
3216 {
3217 	mutex_enter(&ibnex.ibnex_mutex);
3218 	if ((node->node_next == NULL) && (node->node_prev == NULL))
3219 		ibnex.ibnex_port_node_head = NULL;
3220 	else if (node->node_next == NULL)
3221 		node->node_prev->node_next = NULL;
3222 	else if (node->node_prev == NULL) {
3223 		node->node_next->node_prev = NULL;
3224 		ibnex.ibnex_port_node_head = node->node_next;
3225 	} else {
3226 		node->node_prev->node_next = node->node_next;
3227 		node->node_next->node_prev = node->node_prev;
3228 	}
3229 	mutex_exit(&ibnex.ibnex_mutex);
3230 	kmem_free(node, sizeof (ibnex_node_data_t));
3231 }
3232 
3233 
3234 /*
3235  * ibnex_is_node_data_present()
3236  *	Checks whether ibnex_node_t is created already
3237  *	Returns ibnex_node_data_t if found, otherwise NULL
3238  */
3239 static ibnex_node_data_t *
3240 ibnex_is_node_data_present(ibnex_node_type_t node_type, void *attr,
3241     int index, ib_pkey_t pkey)
3242 {
3243 	ibnex_node_data_t	*nodep;
3244 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
3245 	if (node_type == IBNEX_IOC_NODE) {
3246 		ibdm_ioc_info_t *ioc_infop = (ibdm_ioc_info_t *)attr;
3247 
3248 		for (nodep = ibnex.ibnex_ioc_node_head; nodep != NULL;
3249 		    nodep = nodep->node_next) {
3250 			if (nodep->node_data.ioc_node.ioc_guid ==
3251 			    ioc_infop->ioc_profile.ioc_guid) {
3252 				return (nodep);
3253 			}
3254 		}
3255 
3256 	} else if (node_type == IBNEX_PSEUDO_NODE) {
3257 		for (nodep = ibnex.ibnex_pseudo_node_head; nodep;
3258 		    nodep = nodep->node_next)
3259 			if (strcmp(nodep->node_data.pseudo_node.
3260 			    pseudo_node_addr, (char *)attr) == 0)
3261 				return (nodep);
3262 
3263 	} else {
3264 		ibdm_port_attr_t *pattrp = (ibdm_port_attr_t *)attr;
3265 
3266 		for (nodep = ibnex.ibnex_port_node_head; nodep != NULL;
3267 		    nodep = nodep->node_next) {
3268 			if ((nodep->node_data.port_node.port_guid ==
3269 			    pattrp->pa_port_guid) &&
3270 			    (nodep->node_data.port_node.port_commsvc_idx ==
3271 			    index) &&
3272 			    (nodep->node_data.port_node.port_pkey == pkey)) {
3273 				return (nodep);
3274 			}
3275 		}
3276 	}
3277 	return (NULL);
3278 }
3279 
3280 /*
3281  * ibnex_lookup_unit_address_prop:
3282  *
3283  *	If "unit-address" property is found, return its value
3284  *	otherwise return NULL.
3285  */
3286 static char *
3287 ibnex_lookup_unit_address_prop(ddi_prop_t *head)
3288 {
3289 	ddi_prop_t	*propp;
3290 
3291 	/* Search the list of properties for "unit-address" */
3292 	for (propp = head; propp != NULL; propp = propp->prop_next)  {
3293 		if (strcmp(propp->prop_name, "unit-address") != 0)
3294 			continue;
3295 		/* "unit-address" property should be valid and have a value */
3296 		if (propp->prop_len <= 1)
3297 			break;
3298 		return ((char *)propp->prop_val);
3299 	}
3300 
3301 	return ((char *)0);
3302 }
3303 
3304 
3305 /*
3306  * ibnex_pseudo_initnodes()
3307  *	This routine is specific to pseudo node information handling
3308  *	Creates a ibnex_node_data_t all pseudo nodes children of ibnex
3309  */
3310 void
3311 ibnex_pseudo_initnodes()
3312 {
3313 	int			pnam_len, len;
3314 	ibnex_node_data_t	*nodep;
3315 	struct hwc_spec		*list, *spec;
3316 	char			*node_addr, *temp, *unit_addr;
3317 
3318 	IBTF_DPRINTF_L4("ibnex", "\tpseudo_initnodes");
3319 
3320 	mutex_enter(&ibnex.ibnex_mutex);
3321 	/*
3322 	 * get a list of all "pseudo" children of "ib".
3323 	 * for these children initialize/allocate an internal
3324 	 * ibnex_node_data_t.
3325 	 */
3326 	list = hwc_get_child_spec(ibnex.ibnex_dip, (major_t)-1);
3327 	for (spec = list; spec != NULL; spec = spec->hwc_next) {
3328 		if (spec->hwc_devi_sys_prop_ptr == NULL)
3329 			continue;
3330 
3331 		/* "unit-address" property should be present */
3332 		temp = ibnex_lookup_unit_address_prop(
3333 		    spec->hwc_devi_sys_prop_ptr);
3334 		if (temp == NULL)
3335 			continue;
3336 
3337 		pnam_len = strlen(spec->hwc_devi_name) + strlen(temp) + 2;
3338 
3339 		node_addr = kmem_zalloc(pnam_len, KM_SLEEP);
3340 
3341 		(void) snprintf(node_addr,
3342 		    pnam_len, "%s,%s", spec->hwc_devi_name, temp);
3343 
3344 		nodep = ibnex_is_node_data_present(
3345 		    IBNEX_PSEUDO_NODE, (void *)node_addr, 0, 0);
3346 
3347 		if (nodep) {
3348 			kmem_free(node_addr, pnam_len);
3349 			continue;
3350 		}
3351 
3352 		nodep = ibnex_init_child_nodedata(IBNEX_PSEUDO_NODE,
3353 		    (void *)spec->hwc_devi_name, 0, 0);
3354 
3355 		nodep->node_data.pseudo_node.pseudo_node_addr = node_addr;
3356 		(void) snprintf(nodep->node_data.
3357 		    pseudo_node.pseudo_node_addr, pnam_len, "%s", node_addr);
3358 
3359 		len = strlen(temp) + 1;
3360 		unit_addr = (char *)kmem_alloc(len, KM_SLEEP);
3361 		nodep->node_data.pseudo_node.pseudo_unit_addr = unit_addr;
3362 		(void) snprintf(unit_addr, len, "%s", temp);
3363 		nodep->node_data.pseudo_node.pseudo_unit_addr_len = len;
3364 
3365 		/* Mark this as a new psuedo node */
3366 		nodep->node_data.pseudo_node.pseudo_new_node = 1;
3367 
3368 		IBTF_DPRINTF_L3("ibnex", "\tpseudo_initnodes: unit addr = %s"
3369 		    " : drv name = %s", unit_addr, spec->hwc_devi_name);
3370 	}
3371 	hwc_free_spec_list(list);
3372 	mutex_exit(&ibnex.ibnex_mutex);
3373 }
3374 
3375 
3376 /*
3377  * ibnex_init_child_nodedata()
3378  *
3379  *	Allocate memory for the parent private data for device node
3380  *	Initializes the parent private child device node data.
3381  *	Returns pointer to the parent private data
3382  */
3383 static ibnex_node_data_t *
3384 ibnex_init_child_nodedata(ibnex_node_type_t node_type, void *attr, int index,
3385     ib_pkey_t pkey)
3386 {
3387 	char			 *devi_name;
3388 	ibdm_ioc_info_t		 *ioc_info;
3389 	ibnex_ioc_node_t	 *ioc_node;
3390 	ibnex_node_data_t	 *node_data;
3391 	ib_dm_ioc_ctrl_profile_t *ioc_profile;
3392 
3393 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
3394 
3395 	node_data = kmem_zalloc(sizeof (ibnex_node_data_t), KM_SLEEP);
3396 	node_data->node_state = IBNEX_CFGADM_CONFIGURING;
3397 	node_data->node_type	= node_type;
3398 
3399 	if (node_type == IBNEX_IOC_NODE) {
3400 		ioc_info	= (ibdm_ioc_info_t *)attr;
3401 		ioc_profile	= &ioc_info->ioc_profile;
3402 		ioc_node	= &node_data->node_data.ioc_node;
3403 
3404 		ioc_node->iou_guid = ioc_info->ioc_iou_guid;
3405 		ioc_node->ioc_guid = ioc_profile->ioc_guid;
3406 		(void) strncpy(ioc_node->ioc_id_string,
3407 		    (char *)ioc_profile->ioc_id_string,
3408 		    IB_DM_IOC_ID_STRING_LEN);
3409 		ioc_node->ioc_ngids = ioc_info->ioc_nportgids;
3410 
3411 		node_data->node_next = ibnex.ibnex_ioc_node_head;
3412 		node_data->node_prev = NULL;
3413 		if (ibnex.ibnex_ioc_node_head)
3414 			ibnex.ibnex_ioc_node_head->node_prev = node_data;
3415 		ibnex.ibnex_ioc_node_head = node_data;
3416 	} else if (node_type == IBNEX_PSEUDO_NODE) {
3417 		devi_name = (char *)attr;
3418 		node_data->node_data.pseudo_node.pseudo_devi_name =
3419 		    kmem_zalloc(strlen(devi_name) + 1, KM_SLEEP);
3420 		(void) strncpy(node_data->node_data.pseudo_node.
3421 		    pseudo_devi_name, devi_name, strlen(devi_name));
3422 		node_data->node_next = ibnex.ibnex_pseudo_node_head;
3423 		node_data->node_prev = NULL;
3424 		if (ibnex.ibnex_pseudo_node_head)
3425 			ibnex.ibnex_pseudo_node_head->node_prev = node_data;
3426 		ibnex.ibnex_pseudo_node_head = node_data;
3427 	} else {
3428 		node_data->node_data.port_node.port_hcaguid =
3429 		    ((ibdm_port_attr_t *)attr)->pa_hca_guid;
3430 		node_data->node_data.port_node.port_guid =
3431 		    ((ibdm_port_attr_t *)attr)->pa_port_guid;
3432 		node_data->node_data.port_node.port_num =
3433 		    ((ibdm_port_attr_t *)attr)->pa_port_num;
3434 		node_data->node_data.port_node.port_commsvc_idx = index;
3435 		node_data->node_data.port_node.port_pkey = pkey;
3436 
3437 		node_data->node_next = ibnex.ibnex_port_node_head;
3438 		node_data->node_prev = NULL;
3439 		if (ibnex.ibnex_port_node_head)
3440 			ibnex.ibnex_port_node_head->node_prev = node_data;
3441 		ibnex.ibnex_port_node_head = node_data;
3442 	}
3443 	return (node_data);
3444 }
3445 
3446 static int
3447 ibnex_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
3448     char *eventname, ddi_eventcookie_t *cookie)
3449 {
3450 	int rc;
3451 
3452 
3453 	IBTF_DPRINTF_L4("ibnex", "ibnex_get_eventcookie(%p, %p, %s, 0x%X)",
3454 	    dip, rdip, eventname, cookie);
3455 
3456 	rc = ndi_event_retrieve_cookie(ibnex.ibnex_ndi_event_hdl,
3457 	    rdip, eventname, cookie, NDI_EVENT_NOPASS);
3458 	if (rc == NDI_SUCCESS) {
3459 		mutex_enter(&ibnex.ibnex_mutex);
3460 		ibnex.ibnex_prop_update_evt_cookie = *cookie;
3461 		mutex_exit(&ibnex.ibnex_mutex);
3462 	}
3463 
3464 	return (rc);
3465 }
3466 
3467 static int
3468 ibnex_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
3469     ddi_eventcookie_t cookie, void (*callback)(dev_info_t *dip,
3470     ddi_eventcookie_t cookie, void *arg, void *bus_impldata),
3471     void *arg, ddi_callback_id_t *cb_id)
3472 {
3473 	IBTF_DPRINTF_L4("ibnex",
3474 	    "ibnex_add_eventcall(%p, %p, 0x%X, %p, %p, %p)",
3475 	    dip, rdip, cookie, callback, arg, cb_id);
3476 
3477 	return (ndi_event_add_callback(ibnex.ibnex_ndi_event_hdl,
3478 	    rdip, cookie, callback, arg, NDI_SLEEP, cb_id));
3479 }
3480 
3481 static int
3482 ibnex_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
3483 {
3484 	IBTF_DPRINTF_L4("ibnex", "ibnex_remove_eventcall(%p, 0x%X)",
3485 	    dip, cb_id);
3486 
3487 	return (ndi_event_remove_callback(ibnex.ibnex_ndi_event_hdl,
3488 	    cb_id));
3489 }
3490 
3491 static int
3492 ibnex_post_event(dev_info_t *dip, dev_info_t *rdip,
3493     ddi_eventcookie_t cookie, void *bus_impldata)
3494 {
3495 	IBTF_DPRINTF_L4("ibnex", "ibnex_post_event(%p, %p, 0x%X, %p)",
3496 	    dip, rdip, cookie, bus_impldata);
3497 
3498 	return (ndi_event_run_callbacks(ibnex.ibnex_ndi_event_hdl, rdip,
3499 	    cookie, bus_impldata));
3500 }
3501 
3502 /*
3503  * ibnex_reprobe_ioc_dev()
3504  *
3505  * This could be called as a result of ibt_reprobe_dev request or
3506  * cfgadm command. The function is called from a taskq in case of
3507  * ibt_reprobe_dev and from user context for cfgadm command.
3508  *
3509  * This function reprobes the properties for one IOC dip.
3510  *
3511  * node_reprobe_state should be set before calling this function.
3512  */
3513 void
3514 ibnex_reprobe_ioc_dev(void *arg)
3515 {
3516 	dev_info_t	*dip = (dev_info_t *)arg;
3517 	ibnex_node_data_t	*node_data;
3518 	ibnex_ioc_node_t	*ioc_data;
3519 	ibdm_ioc_info_t		*ioc_info;
3520 
3521 	/* ASSERT(NO_LOCKS_HELD); */
3522 	ASSERT(dip != NULL);
3523 
3524 	node_data = ddi_get_parent_data(dip);
3525 	ASSERT(node_data);
3526 
3527 	if (node_data->node_dip == NULL) {
3528 		IBTF_DPRINTF_L4("ibnex", "reprobe for unconfigured dip");
3529 		mutex_enter(&ibnex.ibnex_mutex);
3530 		ibnex_wakeup_reprobe_ioc(node_data, 0);
3531 		mutex_exit(&ibnex.ibnex_mutex);
3532 		return;
3533 	}
3534 	ioc_data = &(node_data->node_data.ioc_node);
3535 
3536 	/* Reprobe the IOC */
3537 	ioc_info = ibdm_ibnex_probe_ioc(ioc_data->iou_guid, ioc_data->ioc_guid,
3538 	    1);
3539 	if (ioc_info == NULL) {
3540 		IBTF_DPRINTF_L2("ibnex", "Null ioc_info from reprobe");
3541 		mutex_enter(&ibnex.ibnex_mutex);
3542 		ibnex_wakeup_reprobe_ioc(node_data, 1);
3543 		mutex_exit(&ibnex.ibnex_mutex);
3544 		return;
3545 	}
3546 
3547 	mutex_enter(&ibnex.ibnex_mutex);
3548 	if (node_data->node_dip)
3549 		ibnex_update_prop(node_data, ioc_info);
3550 	ibnex_wakeup_reprobe_ioc(node_data, 0);
3551 	mutex_exit(&ibnex.ibnex_mutex);
3552 
3553 	ibdm_ibnex_free_ioc_list(ioc_info);
3554 }
3555 
3556 /*
3557  * ibnex_reprobe_all()
3558  *
3559  * This could be called as a result of cfgadm command. The function
3560  * is called from user context.
3561  *
3562  * This function reprobes the properties for all IOC dips.
3563  *
3564  * ibnex_reprobe_state should be set before calling this function.
3565  */
3566 void
3567 ibnex_reprobe_ioc_all()
3568 {
3569 	ibnex_node_data_t	*node_data;
3570 	ibdm_ioc_info_t		*ioc_info_list, *ioc;
3571 
3572 	/* ASSERT(NO_LOCKS_HELD); */
3573 
3574 	/* Sweep the fabric */
3575 	ioc = ioc_info_list = ibdm_ibnex_get_ioc_list(
3576 	    IBDM_IBNEX_REPROBE_ALL);
3577 	if (ioc_info_list == NULL) {
3578 		mutex_enter(&ibnex.ibnex_mutex);
3579 		ibnex_wakeup_reprobe_all();
3580 		mutex_exit(&ibnex.ibnex_mutex);
3581 		return;
3582 	}
3583 
3584 	mutex_enter(&ibnex.ibnex_mutex);
3585 	while (ioc_info_list) {
3586 		if ((node_data = ibnex_is_node_data_present(IBNEX_IOC_NODE,
3587 		    ioc_info_list, 0, 0)) != NULL &&
3588 		    node_data->node_dip != NULL) {
3589 			ibnex_update_prop(node_data, ioc_info_list);
3590 		}
3591 		ioc_info_list = ioc_info_list->ioc_next;
3592 	}
3593 	ibnex_wakeup_reprobe_all();
3594 	mutex_exit(&ibnex.ibnex_mutex);
3595 
3596 	ibdm_ibnex_free_ioc_list(ioc);
3597 }
3598 
3599 /*
3600  * Update the properties, if it has modified and notify IBTF client.
3601  */
3602 static void
3603 ibnex_update_prop(ibnex_node_data_t *node_data, ibdm_ioc_info_t *ioc_info)
3604 {
3605 	ibt_prop_update_payload_t	evt_data;
3606 	dev_info_t	*dip = node_data->node_dip;
3607 	ddi_eventcookie_t	evt_cookie;
3608 	ibnex_ioc_node_t *ioc;
3609 
3610 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
3611 
3612 	ASSERT(dip != NULL);
3613 
3614 	ioc = &node_data->node_data.ioc_node;
3615 
3616 	evt_data = ioc_info->ioc_info_updated;
3617 	evt_cookie = ibnex.ibnex_prop_update_evt_cookie;
3618 
3619 	/*
3620 	 * For a disconnected IOC :
3621 	 *	Store the ioc_profile for supplying cfgadm info
3622 	 *	ibdm maintains no info of disconnected IOC
3623 	 *
3624 	 * For reconnected IOC :
3625 	 *	ibdm has info of previous service entries
3626 	 *	ioc_profile maintained by ibnexus is used to
3627 	 *	update ib_srv_prop_updated.
3628 	 *	Free the ibnex maintained ioc_profile
3629 	 */
3630 	if (ioc_info->ioc_nportgids == 0) {
3631 		IBTF_DPRINTF_L4("ibnex",
3632 		    "\tupdate_prop:  IOC disconnected");
3633 		ioc->ioc_profile = (ib_dm_ioc_ctrl_profile_t *)kmem_zalloc(
3634 		    sizeof (ib_dm_ioc_ctrl_profile_t), KM_SLEEP);
3635 		bcopy(&ioc_info->ioc_profile, ioc->ioc_profile,
3636 		    sizeof (ib_dm_ioc_ctrl_profile_t));
3637 
3638 		ibnex.ibnex_num_disconnect_iocs++;
3639 	} else if (ioc_info->ioc_nportgids != 0 && ioc->ioc_ngids == 0 &&
3640 	    ioc->ioc_profile != NULL) {
3641 		IBTF_DPRINTF_L4("ibnex",
3642 		    "\tupdate_prop: IOC reconnected");
3643 		if (ioc->ioc_profile->ioc_service_entries !=
3644 		    ioc_info->ioc_profile.ioc_service_entries)
3645 			evt_data.ib_srv_prop_updated = 1;
3646 
3647 		ibnex.ibnex_num_disconnect_iocs--;
3648 		kmem_free(ioc->ioc_profile, sizeof (ib_dm_ioc_ctrl_profile_t));
3649 		ioc->ioc_profile = NULL;
3650 	}
3651 
3652 	/* Update the properties that have changed */
3653 	mutex_exit(&ibnex.ibnex_mutex);
3654 	if (evt_data.ib_gid_prop_updated) {
3655 		if (ibnex_create_ioc_portgid_prop(dip, ioc_info) !=
3656 		    IBNEX_SUCCESS) {
3657 			mutex_enter(&ibnex.ibnex_mutex);
3658 			return;
3659 		}
3660 	}
3661 	if (evt_data.ib_srv_prop_updated) {
3662 		if (ioc_info->ioc_profile.ioc_service_entries != 0 &&
3663 		    (ibnex_create_ioc_srv_props(dip, ioc_info) !=
3664 		    IBNEX_SUCCESS)) {
3665 			mutex_enter(&ibnex.ibnex_mutex);
3666 			return;
3667 		} else if (ioc_info->ioc_profile.ioc_service_entries == 0) {
3668 			(void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
3669 			    "service-id");
3670 			(void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
3671 			    "service-name");
3672 		}
3673 	}
3674 	mutex_enter(&ibnex.ibnex_mutex);
3675 	ioc->ioc_ngids = ioc_info->ioc_nportgids;
3676 
3677 	/*
3678 	 * Post an event if :
3679 	 *	1. Properites have changed or NOTIFY_ALWAYS is set.
3680 	 *	2. child dip is configured and a valid cookie for
3681 	 *	   IB_PROP_UPDATE_EVENT.
3682 	 */
3683 	if ((evt_data.ib_prop_updated != 0 ||
3684 	    (node_data->node_reprobe_state &
3685 	    IBNEX_NODE_REPROBE_NOTIFY_ALWAYS)) &&
3686 	    ((node_data->node_state == IBNEX_CFGADM_CONFIGURED) &&
3687 		    (evt_cookie != NULL))) {
3688 			mutex_exit(&ibnex.ibnex_mutex);
3689 
3690 			if (ndi_post_event(ibnex.ibnex_dip, dip,
3691 			    evt_cookie, &evt_data) != NDI_SUCCESS)
3692 				IBTF_DPRINTF_L2("ibnex",
3693 				    "\tndi_post_event failed\n");
3694 
3695 			mutex_enter(&ibnex.ibnex_mutex);
3696 	}
3697 
3698 	/*
3699 	 * Cleanup node_reprobe_state, for ibt_reprobe_dev
3700 	 * requests, when reprobe all / node reprobe is in
3701 	 * progress. ibnex_reprobe_ioc_dev is not called
3702 	 * in this case.
3703 	 */
3704 	if (node_data->node_reprobe_state ==
3705 	    IBNEX_NODE_REPROBE_NOTIFY_ALWAYS)
3706 		ibnex_wakeup_reprobe_ioc(node_data, 0);
3707 }
3708 
3709 static ibnex_rval_t
3710 ibnex_unique_svcname(char *svcname)
3711 {
3712 	int i;
3713 
3714 	/* Check Port Services */
3715 	for (i = 0; i < ibnex.ibnex_num_comm_svcs; i++)
3716 		if (ibnex.ibnex_comm_svc_names[i] && strncmp(svcname,
3717 		    ibnex.ibnex_comm_svc_names[i], 4) == 0)
3718 			return (IBNEX_FAILURE);
3719 
3720 	/* Check VPPA Services */
3721 	for (i = 0; i < ibnex.ibnex_nvppa_comm_svcs; i++)
3722 		if (ibnex.ibnex_vppa_comm_svc_names[i] && strncmp(svcname,
3723 		    ibnex.ibnex_vppa_comm_svc_names[i], 4) == 0)
3724 			return (IBNEX_FAILURE);
3725 
3726 	/* Check HCA_SVC Services */
3727 	for (i = 0; i < ibnex.ibnex_nhcasvc_comm_svcs; i++)
3728 		if (ibnex.ibnex_hcasvc_comm_svc_names[i] && strncmp(svcname,
3729 		    ibnex.ibnex_hcasvc_comm_svc_names[i], 4) == 0)
3730 			return (IBNEX_FAILURE);
3731 
3732 	return (IBNEX_SUCCESS);
3733 }
3734 
3735 static void
3736 ibnex_handle_reprobe_dev(void *arg)
3737 {
3738 	dev_info_t	*dip = (dev_info_t *)arg;
3739 	ibnex_node_data_t	*node_data;
3740 
3741 	ASSERT(dip != NULL);
3742 	node_data = ddi_get_parent_data(dip);
3743 	ASSERT(node_data);
3744 
3745 	/*
3746 	 * Return success if:
3747 	 *	1. Reprobe for all nodes are in progress
3748 	 *	2. Reprobe for this node is in progress.
3749 	 * The reprobe in progress will complete eventually and
3750 	 * update the properties, if required.
3751 	 */
3752 	mutex_enter(&ibnex.ibnex_mutex);
3753 	if (ibnex.ibnex_reprobe_state != 0 ||
3754 	    node_data->node_reprobe_state != 0) {
3755 		/*
3756 		 * Setting NOTIFY_ALWAYS to ensure that
3757 		 * DDI event is delivered always for
3758 		 * ibt_reprobe_dev
3759 		 */
3760 		node_data->node_reprobe_state |=
3761 		    IBNEX_NODE_REPROBE_NOTIFY_ALWAYS;
3762 		mutex_exit(&ibnex.ibnex_mutex);
3763 		return;
3764 	}
3765 	node_data->node_reprobe_state =
3766 	    IBNEX_NODE_REPROBE_NOTIFY_ALWAYS;
3767 	mutex_exit(&ibnex.ibnex_mutex);
3768 	ibnex_reprobe_ioc_dev(arg);
3769 }
3770 
3771 
3772 /*
3773  * MPxIO pathmangement routines. Currently IB nexus does not support
3774  * any kind of pathmangement. So, just return success to make MPxIO
3775  * framework happy.
3776  */
3777 /*ARGSUSED*/
3778 static int
3779 ib_vhci_pi_init(dev_info_t *dip, mdi_pathinfo_t *pip, int flag)
3780 {
3781 	IBTF_DPRINTF_L4("ibnex", "\tpi_init: dip %p pip %p", dip, pip);
3782 	return (MDI_SUCCESS);
3783 }
3784 
3785 
3786 /*ARGSUSED*/
3787 static int
3788 ib_vhci_pi_uninit(dev_info_t *dip, mdi_pathinfo_t *pip, int flag)
3789 {
3790 	IBTF_DPRINTF_L4("ibnex", "\tpi_uninit: dip %p pip %p", dip, pip);
3791 	return (MDI_SUCCESS);
3792 }
3793 
3794 
3795 /*ARGSUSED*/
3796 static int
3797 ib_vhci_pi_state_change(dev_info_t *dip, mdi_pathinfo_t *pip,
3798 		mdi_pathinfo_state_t state, uint32_t arg1, int arg2)
3799 {
3800 	IBTF_DPRINTF_L4("ibnex",
3801 	    "\tpi_state_change: dip %p pip %p state %x", dip, pip, state);
3802 	return (MDI_SUCCESS);
3803 }
3804 
3805 
3806 /*ARGSUSED*/
3807 static int
3808 ib_vhci_failover(dev_info_t *dip1, dev_info_t *dip2, int arg)
3809 {
3810 	return (MDI_SUCCESS);
3811 }
3812 
3813 
3814 static int
3815 ibnex_bus_power(dev_info_t *parent, void *impl_arg,
3816     pm_bus_power_op_t op, void *arg, void *result)
3817 {
3818 
3819 	int ret = DDI_SUCCESS;
3820 
3821 	IBTF_DPRINTF_L4("ibnex", "\tbus_power: begin: op = %d", op);
3822 
3823 	/*
3824 	 * Generic processing in MPxIO framework
3825 	 */
3826 	ret = mdi_bus_power(parent, impl_arg, op, arg, result);
3827 
3828 	switch (ret) {
3829 	case MDI_SUCCESS:
3830 		ret = DDI_SUCCESS;
3831 		break;
3832 	case MDI_FAILURE:
3833 		ret = DDI_FAILURE;
3834 		break;
3835 	default:
3836 		break;
3837 	}
3838 
3839 	return (ret);
3840 }
3841