xref: /titanic_41/usr/src/uts/common/io/ib/ibnex/ibnex.c (revision 4610e4a00999c6d2291b3fc263926b890ec500a5)
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_SLAVEONLY:
909 	case DDI_CTLOPS_AFFINITY:
910 	case DDI_CTLOPS_POKE:
911 	case DDI_CTLOPS_PEEK:
912 		IBTF_DPRINTF_L2("ibnex",
913 		    "%s%d: invalid op (%d) from %s inst%d",
914 		    ddi_get_name(dip), ddi_get_instance(dip),
915 		    ctlop, ddi_get_name(rdip), ddi_get_instance(rdip));
916 		return (DDI_FAILURE);
917 
918 	/*
919 	 * Everything else (PTOB/BTOP/BTOPR/DVMAPAGESIZE requests) we
920 	 * pass up
921 	 */
922 	default:
923 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
924 	}
925 }
926 
927 
928 /*
929  * ibnex_init_child()
930  *
931  * Initialize a child device node. This is called for the DDI_CTLOPS_INITCHILD
932  * entry. Function returns DDI_SUCCESS,  DDI_FAILURE or DDI_NOT_WELL_FORMED.
933  */
934 static int
935 ibnex_init_child(dev_info_t *child)
936 {
937 	int			ret;
938 	char			name[MAXNAMELEN];
939 
940 	IBTF_DPRINTF_L4("ibnex", "\tinit_child: child = %p", child);
941 
942 	/* Handle Pseudo nodes of client children */
943 	if (ndi_dev_is_persistent_node(child) == 0) {
944 		if (ibnex_name_pseudo_child(child, name) != DDI_SUCCESS)
945 			return (DDI_FAILURE);
946 
947 		ddi_set_name_addr(child, name);
948 		/*
949 		 * Merge the .conf node
950 		 */
951 		if (ndi_merge_node(child,
952 		    ibnex_name_child) == DDI_SUCCESS) {
953 			ddi_set_name_addr(child, NULL);
954 			return (DDI_FAILURE);
955 		}
956 		return (DDI_NOT_WELL_FORMED);
957 
958 	}
959 
960 	if ((ret = ibnex_name_child(child, name, 0)) != DDI_SUCCESS)
961 		return (ret);
962 
963 	ddi_set_name_addr(child, name);
964 
965 	return (DDI_SUCCESS);
966 }
967 
968 
969 int
970 ibnex_name_pseudo_child(dev_info_t *child, char *name)
971 {
972 	char **unit_addr;
973 	uint_t n;
974 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
975 	    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
976 	    DDI_PROP_SUCCESS) {
977 		cmn_err(CE_WARN,
978 		    "cannot find unit-address in %s.conf",
979 		    ddi_get_name(child));
980 		return (DDI_FAILURE);
981 	}
982 	if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
983 		cmn_err(CE_WARN, "unit-address property in %s.conf"
984 		    " not well-formed", ddi_get_name(child));
985 		ddi_prop_free(unit_addr);
986 		return (DDI_FAILURE);
987 	}
988 	(void) snprintf(name, MAXNAMELEN, "%s", *unit_addr);
989 	ddi_prop_free(unit_addr);
990 	return (DDI_SUCCESS);
991 }
992 
993 
994 /*ARGSUSED*/
995 int
996 ibnex_name_child(dev_info_t *child, char *name, int flag)
997 {
998 	ibnex_pseudo_node_t	*pseudo;
999 	ibnex_node_data_t	*node_datap;
1000 	ibnex_port_node_t	*port_node;
1001 	ibnex_ioc_node_t	*ioc;
1002 
1003 	node_datap = ddi_get_parent_data(child);
1004 	if (node_datap == NULL) {
1005 		IBTF_DPRINTF_L2("ibnex", "\tname_child: Node data is NULL");
1006 		return (DDI_NOT_WELL_FORMED);
1007 	}
1008 	IBTF_DPRINTF_L4("ibnex", "\tname_sid_child: Node data %p"
1009 	    "Node type %x", node_datap, node_datap->node_type);
1010 	switch (node_datap->node_type) {
1011 	case IBNEX_PORT_COMMSVC_NODE:
1012 		port_node = &node_datap->node_data.port_node;
1013 		(void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%x,0,%s",
1014 		    port_node->port_num,
1015 		    ibnex.ibnex_comm_svc_names[port_node->port_commsvc_idx]);
1016 		break;
1017 	case IBNEX_VPPA_COMMSVC_NODE:
1018 		port_node = &node_datap->node_data.port_node;
1019 		(void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%x,%x,%s",
1020 		    port_node->port_num, port_node->port_pkey, ibnex.
1021 		    ibnex_vppa_comm_svc_names[port_node->port_commsvc_idx]);
1022 		break;
1023 	case IBNEX_HCASVC_COMMSVC_NODE:
1024 		port_node = &node_datap->node_data.port_node;
1025 		(void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%x,0,%s",
1026 		    port_node->port_num,
1027 		    ibnex.ibnex_hcasvc_comm_svc_names[port_node->
1028 		    port_commsvc_idx]);
1029 		break;
1030 	case IBNEX_IOC_NODE:
1031 		ioc = &node_datap->node_data.ioc_node;
1032 		(void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%llX,%llX",
1033 		    (longlong_t)ioc->ioc_guid, (longlong_t)ioc->iou_guid);
1034 		break;
1035 	case IBNEX_PSEUDO_NODE:
1036 		pseudo = &node_datap->node_data.pseudo_node;
1037 		(void) snprintf(name,
1038 		    IBNEX_MAX_NODEADDR_SZ, pseudo->pseudo_unit_addr);
1039 		break;
1040 	default:
1041 		IBTF_DPRINTF_L2("ibnex", "\name_child: Not well formed");
1042 		return (DDI_NOT_WELL_FORMED);
1043 	}
1044 
1045 	return (DDI_SUCCESS);
1046 }
1047 
1048 
1049 /*
1050  * ibnex_bus_config()
1051  *
1052  * BUS_CONFIG_ONE:
1053  *	Enumerate the exact instance of the driver. Use the device node name
1054  *	to locate the exact instance.
1055  *	Query IBDM to find whether the hardware exits for the instance of the
1056  *	driver. If exists, create a device node and return NDI_SUCCESS.
1057  *
1058  * BUS_CONFIG_ALL:
1059  *	Enumerate all the instances of all the possible children (seen before
1060  *	and never seen before).
1061  *
1062  * BUS_CONFIG_DRIVER:
1063  *	Enumerate all the instances of a particular driver.
1064  */
1065 static int
1066 ibnex_bus_config(dev_info_t *parent, uint_t flag,
1067     ddi_bus_config_op_t op, void *devname, dev_info_t **child)
1068 {
1069 	int			ret = IBNEX_SUCCESS, len, circ;
1070 	char 			*device_name, *cname = NULL, *caddr = NULL;
1071 	char			*srvname, nameaddr[MAXNAMELEN];
1072 	dev_info_t		*cdip, *pdip = NULL;
1073 	ibnex_node_data_t	*node_data;
1074 	ibnex_port_node_t	*port_node;
1075 
1076 	ndi_devi_enter(parent, &circ);
1077 
1078 	switch (op) {
1079 	case BUS_CONFIG_ONE:
1080 		IBTF_DPRINTF_L4("ibnex", "\tbus_config: CONFIG_ONE");
1081 
1082 		len = strlen((char *)devname) + 1;
1083 		device_name = i_ddi_strdup(devname, KM_SLEEP);
1084 		i_ddi_parse_name(device_name, &cname, &caddr, NULL);
1085 
1086 		if (caddr == NULL || (strlen(caddr) == 0)) {
1087 			kmem_free(device_name, len);
1088 			ndi_devi_exit(parent, circ);
1089 			return (NDI_FAILURE);
1090 		}
1091 
1092 		IBTF_DPRINTF_L4("ibnex",
1093 		    "\tbus_config: cname %s addr %s", cname, caddr);
1094 
1095 		cdip = ndi_devi_findchild(parent, device_name);
1096 		if (cdip == NULL) {
1097 			/* Node is not present */
1098 			if (strncmp(cname, IBNEX_IOC_CNAME, 3) == 0) {
1099 				if (parent == ibnex.ibnex_dip)
1100 					ret = ibnex_config_ioc_node(devname);
1101 				else {
1102 					ret = ibnex_config_root_iocnode(
1103 					    parent, devname);
1104 					if (ibnex.ibnex_dip)
1105 						pdip = ibnex.ibnex_dip;
1106 					else
1107 						ret = IBNEX_FAILURE;
1108 				}
1109 			} else if ((strncmp(cname,
1110 			    IBNEX_IBPORT_CNAME, 6) == 0) &&
1111 			    (parent != ibnex.ibnex_dip)) { /* parent is HCA */
1112 				cdip = ibnex_config_port_node(parent, devname);
1113 				if (cdip)
1114 					ret = IBNEX_SUCCESS;
1115 				else
1116 					ret = IBNEX_FAILURE;
1117 				/* Allows enumeration under PHCI */
1118 				flag |= NDI_MDI_FALLBACK;
1119 			} else if (parent == ibnex.ibnex_dip) {
1120 				/*
1121 				 * if not IOC or PORT device then always
1122 				 * assume a Pseudo child
1123 				 */
1124 				ret = IBNEX_SUCCESS;
1125 				ibnex_pseudo_initnodes();
1126 				mutex_enter(&ibnex.ibnex_mutex);
1127 				ret = ibnex_pseudo_config_one(
1128 				    NULL, cname, caddr);
1129 				mutex_exit(&ibnex.ibnex_mutex);
1130 			} else
1131 				ret = IBNEX_FAILURE;
1132 		}
1133 		kmem_free(device_name, len);
1134 		break;
1135 
1136 	case BUS_CONFIG_OBP_ARGS:
1137 		cdip = ibnex_config_obp_args(parent, devname);
1138 		if (cdip) {
1139 			/*
1140 			 * Boot case.
1141 			 * Special handling because the "devname"
1142 			 * format for the enumerated device is
1143 			 * different.
1144 			 */
1145 			node_data = ddi_get_parent_data(cdip);
1146 			port_node = &node_data->node_data.port_node;
1147 			if (node_data->node_type ==
1148 			    IBNEX_VPPA_COMMSVC_NODE) {
1149 				srvname =
1150 				    ibnex.ibnex_vppa_comm_svc_names[
1151 				    port_node->port_commsvc_idx];
1152 				(void) snprintf(nameaddr, MAXNAMELEN,
1153 				    "ibport@%x,%x,%s",
1154 				    port_node->port_num,
1155 				    port_node->port_pkey, srvname);
1156 			}
1157 			devname = (void *)nameaddr;
1158 		} else {
1159 			IBTF_DPRINTF_L2("ibnex",
1160 			    "\tbus_config: CONFIG_OBP_ARGS : invalid state!!");
1161 
1162 			ret = IBNEX_FAILURE;
1163 		}
1164 		break;
1165 	case BUS_CONFIG_ALL:
1166 		IBTF_DPRINTF_L4("ibnex", "\tbus_config: CONFIG_ALL");
1167 		ibnex_config_all_children(parent);
1168 		break;
1169 
1170 	case BUS_CONFIG_DRIVER:
1171 		IBTF_DPRINTF_L4("ibnex", "\tbus_config: CONFIG_DRIVER");
1172 		ibnex_config_all_children(parent);
1173 		break;
1174 
1175 	default:
1176 		IBTF_DPRINTF_L4("ibnex", "\tbus_config: error");
1177 		ret = IBNEX_FAILURE;
1178 		break;
1179 	}
1180 	ndi_devi_exit(parent, circ);
1181 	if (ret == IBNEX_SUCCESS) {
1182 		if (op == BUS_CONFIG_OBP_ARGS)
1183 			op = BUS_CONFIG_ONE;
1184 
1185 		if (pdip == NULL)
1186 			pdip = parent;
1187 
1188 		ret = ndi_busop_bus_config(
1189 		    pdip, flag, op, devname, child, 0);
1190 		IBTF_DPRINTF_L4("ibnex", "\tbus_config:"
1191 		    "ndi_busop_bus_config : retval %d", ret);
1192 		return (ret);
1193 	}
1194 
1195 	IBTF_DPRINTF_L2("ibnex", "\tbus_config: Failure End");
1196 	return (NDI_FAILURE);
1197 }
1198 
1199 
1200 /*
1201  * ibnex_config_root_iocnode()
1202  *	Configures one particular instance of the IOC driver.
1203  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
1204  */
1205 static int
1206 ibnex_config_root_iocnode(dev_info_t *parent, char *device_name)
1207 {
1208 	int			ret, port = 0, iter = 0;
1209 	boolean_t		displayed = B_FALSE;
1210 	char			*portstr;
1211 	ib_guid_t		hca_guid, iou_guid, ioc_guid;
1212 	ibdm_ioc_info_t		*ioc_info;
1213 	ibdm_port_attr_t	*port_attr;
1214 
1215 	IBTF_DPRINTF_L4("ibnex",
1216 	    "\tconfig_root_iocnode: name %s", device_name);
1217 
1218 	portstr = strstr(device_name, ":port=");
1219 	if (portstr == NULL) {
1220 		return (IBNEX_FAILURE);
1221 	}
1222 
1223 	portstr[0] = 0; portstr++;
1224 	if (ibnex_devname2port(portstr, &port)) {
1225 		IBTF_DPRINTF_L4("ibnex", "\tconfig_root_iocnode: invalid port");
1226 		return (IBNEX_FAILURE);
1227 	}
1228 
1229 	if (ibnex_devname_to_node_n_ioc_guids(
1230 	    device_name, &iou_guid, &ioc_guid) != IBNEX_SUCCESS) {
1231 		return (IBNEX_FAILURE);
1232 	}
1233 
1234 	(void) snprintf(device_name, (IBNEX_MAX_NODEADDR_SZ + 4),
1235 	    "ioc@%llX,%llX", (longlong_t)ioc_guid, (longlong_t)iou_guid);
1236 
1237 	hca_guid = ibtl_ibnex_hcadip2guid(parent);
1238 	if ((port_attr = ibdm_ibnex_probe_hcaport(hca_guid, port)) == NULL) {
1239 		IBTF_DPRINTF_L2("ibnex",
1240 		    "\tconfig_root_iocnode: Port does not exist");
1241 		return (IBNEX_FAILURE);
1242 	}
1243 
1244 	/* Wait until "port is up" */
1245 	while (port_attr->pa_state != IBT_PORT_ACTIVE) {
1246 		ibdm_ibnex_free_port_attr(port_attr);
1247 		delay(drv_usectohz(10000));
1248 		if ((port_attr = ibdm_ibnex_probe_hcaport(
1249 		    hca_guid, port)) == NULL) {
1250 			return (IBNEX_FAILURE);
1251 		}
1252 
1253 		if (iter++ == 400) {
1254 			if (displayed == B_FALSE) {
1255 				cmn_err(CE_NOTE, "\tWaiting for Port %d "
1256 				    "initialization", port_attr->pa_port_num);
1257 				displayed = B_TRUE;
1258 			}
1259 		}
1260 	}
1261 	ibdm_ibnex_free_port_attr(port_attr);
1262 	IBTF_DPRINTF_L4("ibnex", "\tconfig_rootioc_node:"
1263 	    "Port is initialized");
1264 
1265 	if ((ioc_info = ibdm_ibnex_probe_ioc(iou_guid, ioc_guid, 0)) == NULL) {
1266 		ibdm_ibnex_free_ioc_list(ioc_info);
1267 		return (IBNEX_FAILURE);
1268 	}
1269 	mutex_enter(&ibnex.ibnex_mutex);
1270 	if (ibnex_is_ioc_present(ioc_guid) == IBNEX_SUCCESS) {
1271 		IBTF_DPRINTF_L4("ibnex", "\tconfig_root_iocnode: IOC present");
1272 		ret = IBNEX_SUCCESS;
1273 	} else
1274 		ret = ibnex_ioc_initnode(ioc_info, IBNEX_DEVFS_ENUMERATE);
1275 	mutex_exit(&ibnex.ibnex_mutex);
1276 	ibdm_ibnex_free_ioc_list(ioc_info);
1277 	return (ret);
1278 }
1279 
1280 
1281 static int
1282 ibnex_devname2port(char *portstr, int *port)
1283 {
1284 	char	*temp;
1285 	int	ret = IBNEX_FAILURE;
1286 
1287 	IBTF_DPRINTF_L4("ibnex", "\tdevname2port: Begin");
1288 
1289 	temp = strchr(portstr, '=');
1290 	if (temp != NULL) {
1291 		temp++;
1292 		*port = ibnex_str2int(temp, strlen(temp), &ret);
1293 	}
1294 	return (ret);
1295 }
1296 
1297 
1298 /*
1299  * ibnex_config_all_children()
1300  *	Wait for lata SM initialization case before enumerating the nodes
1301  *	Get list of HCA's and HCA port information
1302  *		Create device device nodes and its node properties
1303  *		for port nodes and VPPA nodes
1304  *	Get list of all the IOC node information
1305  *		Create device nodes and its properties for all the IOCs
1306  *		if not created already
1307  *	Bind drivers for all the newly created device nodes
1308  *	Support Pseudo nodes enumerated using their .conf file
1309  */
1310 static void
1311 ibnex_config_all_children(dev_info_t *parent)
1312 {
1313 	int			ii;
1314 	time_t			wait_time;
1315 	ibdm_ioc_info_t		*ioc_list, *ioc;
1316 	ibdm_hca_list_t		*hca_list;
1317 	ib_guid_t		hca_guid;
1318 
1319 	IBTF_DPRINTF_L4("ibnex", "\tconfig_all_children: Begin");
1320 
1321 	if (parent != ibnex.ibnex_dip) {
1322 		/*
1323 		 * Parent is a HCA node. Enumerate only children of
1324 		 * this HCA, port nodes, VPPA & HCA_SVC nodes
1325 		 */
1326 		hca_guid = ibtl_ibnex_hcadip2guid(parent);
1327 		wait_time = ibdm_ibnex_get_waittime(
1328 			hca_guid, &ibnex_port_settling_time);
1329 		if (wait_time) {
1330 			delay(drv_usectohz(wait_time * 1000000));
1331 		}
1332 		hca_list = ibdm_ibnex_get_hca_info_by_guid(hca_guid);
1333 		if (hca_list == NULL)
1334 			return;
1335 		ibnex_create_hcasvc_nodes(parent, hca_list->hl_hca_port_attr);
1336 		for (ii = 0; ii < hca_list->hl_nports; ii++) {
1337 			ibnex_create_port_nodes(
1338 			    parent, &hca_list->hl_port_attr[ii]);
1339 			ibnex_create_vppa_nodes(
1340 			    parent, &hca_list->hl_port_attr[ii]);
1341 		}
1342 		ibdm_ibnex_free_hca_list(hca_list);
1343 	} else {
1344 
1345 		ibnex_pseudo_initnodes();
1346 
1347 		/* Parent is a IB nexus. Enumerate all the IOC's */
1348 		wait_time = ibdm_ibnex_get_waittime(
1349 			0, &ibnex_port_settling_time);
1350 		if (wait_time)
1351 			delay(drv_usectohz(wait_time * 1000000));
1352 
1353 
1354 		ioc_list = ibdm_ibnex_get_ioc_list(IBDM_IBNEX_NORMAL_PROBE);
1355 		ioc = ioc_list;
1356 
1357 		mutex_enter(&ibnex.ibnex_mutex);
1358 
1359 		while (ioc_list) {
1360 			if (ibnex_is_ioc_present(
1361 			    ioc_list->ioc_profile.ioc_guid) != IBNEX_SUCCESS) {
1362 				(void) ibnex_ioc_initnode(ioc_list,
1363 				    IBNEX_DEVFS_ENUMERATE);
1364 			}
1365 			ioc_list = ioc_list->ioc_next;
1366 		}
1367 		ibnex_config_pseudo_all();
1368 		mutex_exit(&ibnex.ibnex_mutex);
1369 		ibdm_ibnex_free_ioc_list(ioc);
1370 	}
1371 	IBTF_DPRINTF_L4("ibnex", "\tconfig_all_children: End");
1372 }
1373 
1374 
1375 /*
1376  * ibnex_create_port_nodes:
1377  *	Creates a device node per each communication service defined
1378  *	in the "port-commsvc-list" property per HCA port
1379  */
1380 static void
1381 ibnex_create_port_nodes(dev_info_t *parent, ibdm_port_attr_t *port_attr)
1382 {
1383 	int		idx;
1384 	dev_info_t	*dip;
1385 	int		rval;
1386 
1387 	mutex_enter(&ibnex.ibnex_mutex);
1388 	for (idx = 0; idx < ibnex.ibnex_num_comm_svcs; idx++) {
1389 		rval = ibnex_get_dip_from_guid(port_attr->pa_port_guid,
1390 		    idx, 0, &dip);
1391 		if (rval != IBNEX_SUCCESS) {
1392 			(void) ibnex_commsvc_initnode(parent, port_attr, idx,
1393 			    IBNEX_PORT_COMMSVC_NODE, 0, &rval,
1394 			    IBNEX_DEVFS_ENUMERATE);
1395 		}
1396 	}
1397 	mutex_exit(&ibnex.ibnex_mutex);
1398 }
1399 
1400 
1401 /*
1402  * ibnex_create_vppa_nodes:
1403  *	Creates a device node per each communication service defined
1404  *	in the "vppa-commsvc-list" property and per each PKEY that
1405  *	this particular port supports and per HCA port
1406  */
1407 static void
1408 ibnex_create_vppa_nodes(dev_info_t *parent, ibdm_port_attr_t *port_attr)
1409 {
1410 	int 		idx, ii;
1411 	int		rval;
1412 	ib_pkey_t 	pkey;
1413 	dev_info_t	*dip;
1414 
1415 	IBTF_DPRINTF_L4("ibnex", "\tcreate_vppa_nodes: Begin");
1416 
1417 	mutex_enter(&ibnex.ibnex_mutex);
1418 	if (port_attr->pa_state != IBT_PORT_ACTIVE) {
1419 		IBTF_DPRINTF_L4("ibnex", "\tcreate_vppa_nodes: "
1420 		    "Port %d is down", port_attr->pa_port_num);
1421 		mutex_exit(&ibnex.ibnex_mutex);
1422 		return;
1423 	}
1424 	for (idx = 0; idx < ibnex.ibnex_nvppa_comm_svcs; idx++) {
1425 		for (ii = 0; ii < port_attr->pa_npkeys; ii++) {
1426 			pkey = port_attr->pa_pkey_tbl[ii].pt_pkey;
1427 
1428 			if (IBNEX_INVALID_PKEY(pkey)) {
1429 				continue;
1430 			}
1431 			rval = ibnex_get_dip_from_guid(
1432 			    port_attr->pa_port_guid, idx, pkey, &dip);
1433 			if (rval != IBNEX_SUCCESS) {
1434 				(void) ibnex_commsvc_initnode(parent, port_attr,
1435 					idx, IBNEX_VPPA_COMMSVC_NODE,
1436 					pkey, &rval, IBNEX_CFGADM_ENUMERATE);
1437 				IBTF_DPRINTF_L5("ibnex", "\tcreate_vppa_nodes: "
1438 				    "commsvc_initnode failed rval %x", rval);
1439 			}
1440 		}
1441 	}
1442 	mutex_exit(&ibnex.ibnex_mutex);
1443 }
1444 
1445 
1446 /*
1447  * ibnex_create_hcasvc_nodes:
1448  *	Creates a device node per each communication service defined
1449  *	in the "port-commsvc-list" property per HCA port
1450  */
1451 static void
1452 ibnex_create_hcasvc_nodes(dev_info_t *parent, ibdm_port_attr_t *port_attr)
1453 {
1454 	int		idx;
1455 	dev_info_t	*dip;
1456 	int		rval;
1457 
1458 	mutex_enter(&ibnex.ibnex_mutex);
1459 	for (idx = 0; idx < ibnex.ibnex_nhcasvc_comm_svcs; idx++) {
1460 		rval = ibnex_get_dip_from_guid(port_attr->pa_port_guid,
1461 		    idx, 0, &dip);
1462 		if (rval != IBNEX_SUCCESS) {
1463 			(void) ibnex_commsvc_initnode(parent, port_attr, idx,
1464 			    IBNEX_HCASVC_COMMSVC_NODE, 0, &rval,
1465 			    IBNEX_DEVFS_ENUMERATE);
1466 			IBTF_DPRINTF_L5("ibnex", "create_hcasvc_nodes: "
1467 			    "commsvc_initnode failed, rval %x", rval);
1468 		}
1469 	}
1470 	mutex_exit(&ibnex.ibnex_mutex);
1471 }
1472 
1473 /*
1474  * ibnex_is_ioc_present()
1475  *	Returns IBNEX_SUCCESS if an entry found in the global linked list
1476  *	Returns IBNEX_FAILURE, if no match found
1477  */
1478 static int
1479 ibnex_is_ioc_present(ib_guid_t ioc_guid)
1480 {
1481 	ibnex_node_data_t	*head;
1482 	ibnex_ioc_node_t	*ioc;
1483 	int			ret = IBNEX_FAILURE;
1484 
1485 	IBTF_DPRINTF_L4("ibnex", "\tis_ioc_present: Begin");
1486 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1487 
1488 	head = ibnex.ibnex_ioc_node_head;
1489 	while (head) {
1490 		ioc = &head->node_data.ioc_node;
1491 		if (ioc->ioc_guid == ioc_guid)
1492 			break;
1493 		head = head->node_next;
1494 	}
1495 	if (head)
1496 		ret = IBNEX_SUCCESS;
1497 
1498 	return (ret);
1499 }
1500 
1501 
1502 /*
1503  * ibnex_bus_unconfig()
1504  *
1505  *	Unconfigure a particular device node or all instance of a device
1506  *	driver device or all children of IBnex
1507  */
1508 static int
1509 ibnex_bus_unconfig(dev_info_t *parent,
1510     uint_t flag, ddi_bus_config_op_t op, void *device_name)
1511 {
1512 	return (ndi_busop_bus_unconfig(parent, flag, op, device_name));
1513 }
1514 
1515 
1516 /*
1517  * ibnex_config_port_node()
1518  *
1519  *	Configures a particular port / HCA  node for a particular
1520  *	communication service.
1521  *	The format of the device_name is
1522  *		ibport@<Port#>,<pkey>,<service name>
1523  *	where pkey = 0 for port communication service nodes
1524  *		  Port# = 0 for HCA_SVC communication service nodes
1525  *	Returns "dev_info_t" of the "child" node just created
1526  *	NULL when failed to enumerate the child node
1527  */
1528 static dev_info_t *
1529 ibnex_config_port_node(dev_info_t *parent, char *devname)
1530 {
1531 	int			ii, index;
1532 	int			rval;
1533 	time_t			wait_time;
1534 	uint8_t			port_num;
1535 	ib_guid_t		hca_guid, port_guid;
1536 	ib_pkey_t		pkey;
1537 	dev_info_t		*cdip;
1538 	ibdm_port_attr_t	*port_attr;
1539 	ibdm_hca_list_t		*hca_list;
1540 
1541 	IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: %s", devname);
1542 
1543 	if (ibnex_get_pkey_commsvc_index_portnum(devname,
1544 	    &index, &pkey, &port_num) != IBNEX_SUCCESS) {
1545 		IBTF_DPRINTF_L2("ibnex",
1546 		    "\tconfig_port_node: Invalid Service Name");
1547 		return (NULL);
1548 	}
1549 
1550 	hca_guid = ibtl_ibnex_hcadip2guid(parent);
1551 	if (port_num == 0) {
1552 		/*
1553 		 * Use the dummy port attribute for HCA node in hca_list
1554 		 * Note : pa_state is always IBT_PORT_ACTIVE.
1555 		 */
1556 		hca_list = ibdm_ibnex_get_hca_info_by_guid(hca_guid);
1557 		ASSERT(hca_list != NULL);
1558 		port_attr = hca_list->hl_hca_port_attr;
1559 	} else {
1560 		if ((port_attr = ibdm_ibnex_probe_hcaport(
1561 		    hca_guid, port_num)) == NULL) {
1562 			IBTF_DPRINTF_L2("ibnex",
1563 			    "\tconfig_port_node: Port does not exist");
1564 			return (NULL);
1565 		}
1566 
1567 		if (port_attr->pa_state != IBT_PORT_ACTIVE) {
1568 			wait_time = ibdm_ibnex_get_waittime(
1569 				hca_guid, &ibnex_port_settling_time);
1570 			if (wait_time) {
1571 				delay(drv_usectohz(wait_time * 1000000));
1572 			}
1573 			ibdm_ibnex_free_port_attr(port_attr);
1574 			if ((port_attr = ibdm_ibnex_probe_hcaport(
1575 			    hca_guid, port_num)) == NULL) {
1576 				return (NULL);
1577 			}
1578 		}
1579 	}
1580 
1581 	port_guid = port_attr->pa_port_guid;
1582 	mutex_enter(&ibnex.ibnex_mutex);
1583 	if ((rval = ibnex_get_dip_from_guid(port_guid, index, pkey,
1584 	    &cdip)) == IBNEX_SUCCESS) {
1585 		IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: Node exists");
1586 		mutex_exit(&ibnex.ibnex_mutex);
1587 		if (port_num != 0)
1588 			ibdm_ibnex_free_port_attr(port_attr);
1589 		else
1590 			ibdm_ibnex_free_hca_list(hca_list);
1591 		return (cdip);
1592 	}
1593 
1594 	if (pkey == 0 && port_num != 0) {
1595 		cdip = ibnex_commsvc_initnode(parent,
1596 		    port_attr, index, IBNEX_PORT_COMMSVC_NODE, pkey, &rval,
1597 		    IBNEX_DEVFS_ENUMERATE);
1598 		IBTF_DPRINTF_L5("ibnex",
1599 		    "\t ibnex_commsvc_initnode rval %x", rval);
1600 	} else if (pkey == 0 && port_num == 0) {
1601 		cdip = ibnex_commsvc_initnode(parent,
1602 		    port_attr, index, IBNEX_HCASVC_COMMSVC_NODE, pkey, &rval,
1603 		    IBNEX_DEVFS_ENUMERATE);
1604 		IBTF_DPRINTF_L5("ibnex",
1605 		    "\t ibnex_commsvc_initnode rval %x", rval);
1606 	} else {
1607 		if (port_attr->pa_state != IBT_PORT_ACTIVE) {
1608 			IBTF_DPRINTF_L4("ibnex", "\tconfig_port_nodes: "
1609 			    "Port %d is down", port_attr->pa_port_num);
1610 			ibdm_ibnex_free_port_attr(port_attr);
1611 			mutex_exit(&ibnex.ibnex_mutex);
1612 			return (NULL);
1613 		}
1614 		for (ii = 0; ii < port_attr->pa_npkeys; ii++) {
1615 			if (pkey == port_attr->pa_pkey_tbl[ii].pt_pkey) {
1616 				cdip = ibnex_commsvc_initnode(parent, port_attr,
1617 				    index, IBNEX_VPPA_COMMSVC_NODE,
1618 				    pkey, &rval, IBNEX_CFGADM_ENUMERATE);
1619 				IBTF_DPRINTF_L5("ibnex",
1620 				    "\t ibnex_commsvc_initnode rval %x", rval);
1621 				break;
1622 			}
1623 		}
1624 	}
1625 	mutex_exit(&ibnex.ibnex_mutex);
1626 	if (port_num != 0)
1627 		ibdm_ibnex_free_port_attr(port_attr);
1628 	else
1629 		ibdm_ibnex_free_hca_list(hca_list);
1630 	return (cdip);
1631 }
1632 
1633 
1634 /*
1635  * ibnex_config_obp_args()
1636  *	Configures a particular port node for a IP over IB communication
1637  *	service.
1638  *	The format of the input string "devname" is
1639  *		port=x,pkey=y,protocol=ip,<wanboot options>
1640  *	Thr format of the node name created here is
1641  *		ibport@<Port#>,<pkey>,<service name>
1642  *	where pkey = 0 for port communication service nodes
1643  *	Returns "dev_info_t" of the "child" node just created
1644  *	NULL when failed to enumerate the child node
1645  *
1646  */
1647 static dev_info_t *
1648 ibnex_config_obp_args(dev_info_t *parent, char *devname)
1649 {
1650 	int			ii, index;
1651 	int			rval, iter = 0;
1652 	char			*temp;
1653 	uint8_t			port_num;
1654 	ib_guid_t		hca_guid, port_guid;
1655 	ib_pkey_t		pkey;
1656 	dev_info_t		*cdip;
1657 	boolean_t		displayed = B_FALSE;
1658 	ibdm_port_attr_t	*port_attr;
1659 
1660 	IBTF_DPRINTF_L4("ibnex", "\tconfig_obp_args: %s", devname);
1661 
1662 	/* Is this OBP node for IPoIB ? */
1663 	temp = devname;
1664 	do {
1665 		temp = strstr(temp, ",protocol=ip");
1666 		if (temp == NULL)
1667 			break;
1668 
1669 		if (strlen(devname) > (int)((temp - devname) + 12)) {
1670 			if (temp[12] == ',')
1671 				break;
1672 		} else {
1673 			break;
1674 		}
1675 		temp++;
1676 	} while (temp);
1677 
1678 	if (temp == NULL)
1679 		return (NULL);
1680 	if (ibnex_prom_devname_to_pkey_n_portnum(
1681 	    devname, &pkey, &port_num) != IBNEX_SUCCESS) {
1682 		return (NULL);
1683 	}
1684 	for (index = 0; index < ibnex.ibnex_nvppa_comm_svcs; index++) {
1685 		if (strcmp(ibnex.ibnex_vppa_comm_svc_names[index],
1686 			"ipib") == 0) {
1687 			break;
1688 		}
1689 	}
1690 
1691 	hca_guid = ibtl_ibnex_hcadip2guid(parent);
1692 	if ((port_attr = ibdm_ibnex_probe_hcaport(
1693 	    hca_guid, port_num)) == NULL) {
1694 		IBTF_DPRINTF_L2("ibnex",
1695 		    "\tconfig_port_node: Port does not exist");
1696 		return (NULL);
1697 	}
1698 
1699 	/* Wait until "port is up" */
1700 	while (port_attr->pa_state != IBT_PORT_ACTIVE) {
1701 		ibdm_ibnex_free_port_attr(port_attr);
1702 		delay(drv_usectohz(10000));
1703 		if ((port_attr = ibdm_ibnex_probe_hcaport(
1704 		    hca_guid, port_num)) == NULL) {
1705 			return (NULL);
1706 		}
1707 		if (iter++ == 400) {
1708 			if (displayed == B_FALSE) {
1709 				cmn_err(CE_NOTE, "\tWaiting for Port %d "
1710 				    "initialization", port_attr->pa_port_num);
1711 				displayed = B_TRUE;
1712 			}
1713 		}
1714 	}
1715 	IBTF_DPRINTF_L4("ibnex", "\tPort is initialized");
1716 
1717 	mutex_enter(&ibnex.ibnex_mutex);
1718 	port_guid = port_attr->pa_port_guid;
1719 	if ((rval = ibnex_get_dip_from_guid(port_guid, index, pkey,
1720 	    &cdip)) == IBNEX_SUCCESS) {
1721 		IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: Node exists");
1722 		mutex_exit(&ibnex.ibnex_mutex);
1723 		ibdm_ibnex_free_port_attr(port_attr);
1724 		return (cdip);
1725 	}
1726 	for (ii = 0; ii < port_attr->pa_npkeys; ii++) {
1727 		if (pkey == port_attr->pa_pkey_tbl[ii].pt_pkey) {
1728 			cdip = ibnex_commsvc_initnode(parent, port_attr,
1729 			    index, IBNEX_VPPA_COMMSVC_NODE, pkey, &rval,
1730 			    IBNEX_CFGADM_ENUMERATE);
1731 			IBTF_DPRINTF_L5("ibnex",
1732 			    "\t ibnex_commsvc_initnode rval %x", rval);
1733 			break;
1734 		}
1735 	}
1736 	mutex_exit(&ibnex.ibnex_mutex);
1737 
1738 	ibdm_ibnex_free_port_attr(port_attr);
1739 	return (cdip);
1740 }
1741 
1742 
1743 /*
1744  * ibnex_prom_devname_to_pkey_n_portnum()
1745  *	Parses the device node name and extracts "PKEY" and "port#"
1746  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
1747  */
1748 static int
1749 ibnex_prom_devname_to_pkey_n_portnum(
1750     char *devname, ib_pkey_t *pkey, uint8_t *port)
1751 {
1752 	int	ret = IBNEX_SUCCESS;
1753 	char	*tmp, *tmp1;
1754 
1755 	if ((tmp = strstr(devname, "port=")) != NULL) {
1756 		if ((tmp = strchr(++tmp, '=')) != NULL)
1757 			if ((tmp1 = strchr(++tmp, ',')) != NULL)
1758 				*port = ibnex_str2int(tmp, (tmp1 - tmp), &ret);
1759 	} else
1760 		ret = IBNEX_FAILURE;
1761 
1762 	if ((ret == IBNEX_SUCCESS) &&
1763 	    (tmp = strstr(devname, "pkey=")) != NULL) {
1764 		if ((tmp = strchr(++tmp, '=')) != NULL)
1765 			if ((tmp1 = strchr(++tmp, ',')) != NULL)
1766 				*pkey = ibnex_str2hex(tmp, (tmp1 - tmp), &ret);
1767 	} else
1768 		ret = IBNEX_FAILURE;
1769 
1770 	return (ret);
1771 }
1772 
1773 
1774 /*
1775  * ibnex_get_pkey_commsvc_index_portnum()
1776  *	Parses the device node name and extracts PKEY, communication
1777  *	service index & Port #.
1778  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
1779  */
1780 static int
1781 ibnex_get_pkey_commsvc_index_portnum(char *device_name, int *index,
1782     ib_pkey_t *pkey, uint8_t *port_num)
1783 {
1784 	char 	*srv, **service_name, *temp;
1785 	int  	ii, ncommsvcs, ret;
1786 
1787 	if (ibnex_devname_to_portnum(device_name, port_num) !=
1788 		IBNEX_SUCCESS) {
1789 		IBTF_DPRINTF_L2("ibnex",
1790 		    "\tget_pkey_commsvc_index_portnum: Invalid PortGuid");
1791 		return (NULL);
1792 	}
1793 	srv = strchr(device_name, ',');
1794 	if (srv == 0)
1795 		return (IBNEX_FAILURE);
1796 
1797 	srv++;
1798 	temp = strchr(srv, ',');
1799 	if (temp == 0)
1800 		return (IBNEX_FAILURE);
1801 	temp++;
1802 	*pkey = ibnex_str2hex(srv, (temp - srv - 1), &ret);
1803 	if (ret != IBNEX_SUCCESS)
1804 		return (ret);
1805 
1806 	if (*pkey == 0 && *port_num != 0) {
1807 		service_name = ibnex.ibnex_comm_svc_names;
1808 		ncommsvcs = ibnex.ibnex_num_comm_svcs;
1809 	} else if (*pkey == 0 && *port_num == 0) {
1810 		service_name = ibnex.ibnex_hcasvc_comm_svc_names;
1811 		ncommsvcs = ibnex.ibnex_nhcasvc_comm_svcs;
1812 	} else {
1813 		service_name = ibnex.ibnex_vppa_comm_svc_names;
1814 		ncommsvcs = ibnex.ibnex_nvppa_comm_svcs;
1815 	}
1816 
1817 	for (ii = 0; ii < ncommsvcs; ii++) {
1818 		if (strcmp(service_name[ii], temp) == 0) {
1819 			break;
1820 		}
1821 	}
1822 	if (ii == ncommsvcs)
1823 		return (IBNEX_FAILURE);
1824 
1825 	*index = ii;
1826 	return (IBNEX_SUCCESS);
1827 }
1828 
1829 
1830 /*
1831  * ibnex_devname_to_portnum()
1832  *	Get portguid from device name
1833  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
1834  */
1835 static int
1836 ibnex_devname_to_portnum(char *device_name, uint8_t *portnum)
1837 {
1838 	int	ret;
1839 	char	*temp1, *temp2;
1840 
1841 	temp1 = strchr(device_name, '@');
1842 	if (temp1 == NULL) {
1843 		return (IBNEX_FAILURE);
1844 	}
1845 	temp2 = strchr(temp1, ',');
1846 	if (temp2 == NULL)
1847 		return (IBNEX_FAILURE);
1848 	temp1++;
1849 	*portnum = ibnex_str2hex(temp1, (temp2 - temp1), &ret);
1850 	return (ret);
1851 }
1852 
1853 
1854 /*
1855  * ibnex_config_ioc_node()
1856  *	Configures one particular instance of the IOC driver.
1857  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
1858  */
1859 static int
1860 ibnex_config_ioc_node(char *device_name)
1861 {
1862 	int			ret;
1863 	time_t			wait_time;
1864 	ib_guid_t		iou_guid, ioc_guid;
1865 	ibdm_ioc_info_t		*ioc_info;
1866 
1867 	IBTF_DPRINTF_L4("ibnex", "\tconfig_ioc_node: Begin");
1868 
1869 	if (ibnex_devname_to_node_n_ioc_guids(
1870 	    device_name, &iou_guid, &ioc_guid) != IBNEX_SUCCESS) {
1871 		return (IBNEX_FAILURE);
1872 	}
1873 
1874 	wait_time = ibdm_ibnex_get_waittime(0, &ibnex_port_settling_time);
1875 	if (wait_time)
1876 		delay(drv_usectohz(wait_time * 1000000));
1877 
1878 	if ((ioc_info = ibdm_ibnex_probe_ioc(iou_guid, ioc_guid, 0)) ==
1879 	    NULL) {
1880 		ibdm_ibnex_free_ioc_list(ioc_info);
1881 		return (IBNEX_FAILURE);
1882 	}
1883 	mutex_enter(&ibnex.ibnex_mutex);
1884 	if (ibnex_is_ioc_present(ioc_guid) == IBNEX_SUCCESS) {
1885 		IBTF_DPRINTF_L4("ibnex", "\tconfig_ioc_node: IOC present");
1886 		ret = IBNEX_SUCCESS;
1887 	} else
1888 		ret = ibnex_ioc_initnode(ioc_info, IBNEX_DEVFS_ENUMERATE);
1889 	mutex_exit(&ibnex.ibnex_mutex);
1890 	ibdm_ibnex_free_ioc_list(ioc_info);
1891 	return (ret);
1892 }
1893 
1894 
1895 /*
1896  * ibnex_devname_to_node_n_ioc_guids()
1897  *	Get node guid and ioc guid from the device name
1898  *	Format of the device node name is:
1899  *		ioc@<IOC GUID>,<IOU GUID>
1900  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
1901  */
1902 static int
1903 ibnex_devname_to_node_n_ioc_guids(
1904     char *device_name, ib_guid_t *iou_guid, ib_guid_t *ioc_guid)
1905 {
1906 	char	*temp1, *temp;
1907 	int	len, ret;
1908 
1909 	IBTF_DPRINTF_L4("ibnex", "\tdevname_to_node_n_ioc_guids:"
1910 	    "Device Name %s", device_name);
1911 
1912 	if ((temp = strchr(device_name, '@')) == NULL) {
1913 		return (IBNEX_FAILURE);
1914 	}
1915 	if ((temp1 = strchr(++temp, ',')) == NULL) {
1916 		return (IBNEX_FAILURE);
1917 	}
1918 	*ioc_guid = ibnex_str2hex(temp, (temp1 - temp), &ret);
1919 	if (ret == IBNEX_SUCCESS) {
1920 		len = device_name + strlen(device_name) - ++temp1;
1921 		*iou_guid = ibnex_str2hex(temp1, len, &ret);
1922 	}
1923 	return (ret);
1924 }
1925 
1926 
1927 /*ARGSUSED*/
1928 /*
1929  * ibnex_ioc_initnode()
1930  *	Allocate a pathinfo node for the IOC
1931  *	Initialize the device node
1932  *	Bind driver to the node
1933  *	Update IBnex global data
1934  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE/IBNEX_BUSY
1935  */
1936 int
1937 ibnex_ioc_initnode(ibdm_ioc_info_t *ioc_info, int flag)
1938 {
1939 	int			rval;
1940 	ibnex_node_data_t	*node_data;
1941 
1942 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1943 
1944 	node_data = ibnex_is_node_data_present(IBNEX_IOC_NODE,
1945 	    (void *)ioc_info, 0, 0);
1946 
1947 	/*
1948 	 * prevent any races
1949 	 * we have seen this node_data and it has been initialized
1950 	 * Note that node_dip is already NULL if unconfigure is in
1951 	 * progress.
1952 	 */
1953 	if (node_data && node_data->node_dip) {
1954 		return ((node_data->node_state == IBNEX_CFGADM_CONFIGURING) ?
1955 		    IBNEX_BUSY : IBNEX_SUCCESS);
1956 	} else if (node_data == NULL) {
1957 		node_data = ibnex_init_child_nodedata(IBNEX_IOC_NODE,
1958 		    ioc_info, 0, 0);
1959 	}
1960 
1961 	/*
1962 	 * Return EBUSY if another configure/unconfigure
1963 	 * operation is in progress
1964 	 */
1965 	if (node_data->node_state == IBNEX_CFGADM_UNCONFIGURING) {
1966 		return (IBNEX_BUSY);
1967 	}
1968 
1969 	ASSERT(node_data->node_state != IBNEX_CFGADM_CONFIGURED);
1970 	node_data->node_state = IBNEX_CFGADM_CONFIGURING;
1971 
1972 
1973 	mutex_exit(&ibnex.ibnex_mutex);
1974 
1975 	rval = ibnex_ioc_create_pi(ioc_info, node_data);
1976 
1977 	mutex_enter(&ibnex.ibnex_mutex);
1978 	if (rval == IBNEX_SUCCESS)
1979 		node_data->node_state = IBNEX_CFGADM_CONFIGURED;
1980 
1981 	return (rval);
1982 }
1983 
1984 
1985 /*
1986  * ibnex_config_pseudo_all()
1987  *	Configure all the pseudo nodes
1988  */
1989 static void
1990 ibnex_config_pseudo_all(void)
1991 {
1992 	ibnex_node_data_t	*nodep;
1993 
1994 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1995 
1996 	for (nodep = ibnex.ibnex_pseudo_node_head;
1997 	    nodep; nodep = nodep->node_next) {
1998 		(void) ibnex_pseudo_config_one(nodep, NULL, NULL);
1999 	}
2000 }
2001 
2002 
2003 /*
2004  * ibnex_pseudo_config_one()
2005  */
2006 int
2007 ibnex_pseudo_config_one(ibnex_node_data_t *node_data, char *cname, char *caddr)
2008 {
2009 	int			rval, len;
2010 	char			*node_addr;
2011 
2012 	IBTF_DPRINTF_L4("ibnex", "\tpseudo_config_one:Begin");
2013 
2014 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2015 
2016 	if (node_data == NULL) {
2017 		IBTF_DPRINTF_L4("ibnex", "\tpseudo_config_one:"
2018 		    "cname = %s caddr = %s", cname, caddr);
2019 
2020 		len = strlen(cname) + strlen(caddr) + 2;
2021 		node_addr = (char *)kmem_alloc(len, KM_SLEEP);
2022 
2023 		(void) snprintf(node_addr, len, "%s,%s", cname, caddr);
2024 		node_data = ibnex_is_node_data_present(IBNEX_PSEUDO_NODE,
2025 		    (void *)node_addr, 0, 0);
2026 		kmem_free(node_addr, len);
2027 	}
2028 
2029 	/*
2030 	 * prevent any races
2031 	 * we have seen this node_data and it has been initialized
2032 	 * Note that node_dip is already NULL if unconfigure is in
2033 	 * progress.
2034 	 */
2035 	if (node_data && node_data->node_dip) {
2036 		return ((node_data->node_state == IBNEX_CFGADM_CONFIGURING) ?
2037 		    IBNEX_BUSY : IBNEX_SUCCESS);
2038 	} else if (node_data == NULL) {
2039 		IBTF_DPRINTF_L2("ibnex", "\tpseudo_config_one: Invalid node");
2040 		return (IBNEX_FAILURE);
2041 	}
2042 
2043 	/*
2044 	 * Return EBUSY if another configure/unconfigure
2045 	 * operation is in progress
2046 	 */
2047 	if (node_data->node_state == IBNEX_CFGADM_UNCONFIGURING) {
2048 		return (IBNEX_BUSY);
2049 	}
2050 
2051 	if (node_data->node_state == IBNEX_CFGADM_CONFIGURED)
2052 		return (IBNEX_SUCCESS);
2053 
2054 	/*
2055 	 * Prevent configuring pseudo nodes specifically unconfigured
2056 	 * by cfgadm. This is done by checking if this is a newly
2057 	 * created node, not yet configured by BUS_CONFIG or cfgadm
2058 	 */
2059 	if (node_data->node_data.pseudo_node.pseudo_new_node != 1)
2060 		return (IBNEX_FAILURE);
2061 	node_data->node_data.pseudo_node.pseudo_new_node = 0;
2062 
2063 	node_data->node_state = IBNEX_CFGADM_CONFIGURING;
2064 
2065 	mutex_exit(&ibnex.ibnex_mutex);
2066 	rval = ibnex_pseudo_create_pi(node_data);
2067 	mutex_enter(&ibnex.ibnex_mutex);
2068 
2069 	if (rval == IBNEX_SUCCESS)
2070 		node_data->node_state = IBNEX_CFGADM_CONFIGURED;
2071 	else {
2072 		node_data->node_dip = NULL;
2073 		node_data->node_state = IBNEX_CFGADM_UNCONFIGURED;
2074 		node_data->node_data.pseudo_node.pseudo_new_node = 1;
2075 	}
2076 
2077 	return (rval);
2078 }
2079 
2080 
2081 /*
2082  * ibnex_pseudo_create_pi()
2083  *	Create a path info node for each pseudo entry
2084  */
2085 int
2086 ibnex_pseudo_create_pi(ibnex_node_data_t *nodep)
2087 {
2088 	mdi_pathinfo_t		*pip;
2089 	int			rval, hcacnt;
2090 	dev_info_t		*hca_dip, *cdip = NULL;
2091 	ibdm_hca_list_t		*hca_list, *head;
2092 	ibnex_pseudo_node_t	*pseudo;
2093 
2094 	IBTF_DPRINTF_L4("ibnex", "\tibnex_pseudo_create_pi: %p", nodep);
2095 
2096 	pseudo = &nodep->node_data.pseudo_node;
2097 
2098 	ibdm_ibnex_get_hca_list(&hca_list, &hcacnt);
2099 
2100 	head = hca_list;
2101 
2102 	for (; hca_list != NULL; hca_list = hca_list->hl_next) {
2103 
2104 		hca_dip = ibtl_ibnex_hcaguid2dip(hca_list->hl_hca_guid);
2105 
2106 		rval = mdi_pi_alloc(hca_dip,
2107 		    pseudo->pseudo_devi_name, pseudo->pseudo_node_addr,
2108 		    pseudo->pseudo_node_addr, 0, &pip);
2109 
2110 		if (rval != MDI_SUCCESS) {
2111 			(void) ibnex_offline_childdip(cdip);
2112 			return (IBNEX_FAILURE);
2113 		}
2114 		cdip = mdi_pi_get_client(pip);
2115 
2116 		IBTF_DPRINTF_L4("ibnex",
2117 		    "\tpseudo_create_pi: New dip %p", cdip);
2118 
2119 		nodep->node_dip = cdip;
2120 		ddi_set_parent_data(cdip, nodep);
2121 
2122 		rval = mdi_pi_online(pip, 0);
2123 
2124 		if (rval != MDI_SUCCESS) {
2125 			ddi_set_parent_data(cdip, NULL);
2126 			IBTF_DPRINTF_L2("ibnex", "\tpseudo_create_pi:"
2127 			    "mdi_pi_online: failed for pseudo dip %p,"
2128 			    " rval %d", cdip, rval);
2129 			(void) ibnex_offline_childdip(cdip);
2130 			rval = IBNEX_FAILURE;
2131 			break;
2132 		} else
2133 			rval = IBNEX_SUCCESS;
2134 	}
2135 	if (head)
2136 		ibdm_ibnex_free_hca_list(head);
2137 	return (rval);
2138 }
2139 
2140 
2141 /*
2142  * ibnex_ioc_create_pi()
2143  *	Create a pathinfo node for the ioc node
2144  */
2145 static int
2146 ibnex_ioc_create_pi(ibdm_ioc_info_t *ioc_info, ibnex_node_data_t *node_data)
2147 {
2148 	char			ioc_guid[33], iou_guid[33];
2149 	mdi_pathinfo_t		*pip;
2150 	int			rval;
2151 	dev_info_t		*hca_dip, *cdip = NULL;
2152 	int			flag = 1;
2153 	ibdm_hca_list_t		*hca_list;
2154 
2155 	IBTF_DPRINTF_L4("ibnex", "\tibnex_ioc_create_pi Begin");
2156 
2157 	(void) snprintf(ioc_guid, 33, "%llx",
2158 		(longlong_t)ioc_info->ioc_profile.ioc_guid);
2159 	(void) snprintf(iou_guid, 33, "%llx",
2160 		(longlong_t)ioc_info->ioc_iou_guid);
2161 
2162 	hca_list = ioc_info->ioc_hca_list;
2163 
2164 	for (; hca_list != NULL; hca_list = hca_list->hl_next) {
2165 
2166 		hca_dip = ibtl_ibnex_hcaguid2dip(hca_list->hl_hca_guid);
2167 
2168 		IBTF_DPRINTF_L4("ibnex", "\tioc_create_pi "
2169 		    "hca guid %llx", hca_list->hl_hca_guid);
2170 
2171 		rval =  mdi_pi_alloc(hca_dip,
2172 		    IBNEX_IOC_CNAME, ioc_guid, iou_guid, 0, &pip);
2173 		if (rval != MDI_SUCCESS) {
2174 			(void) ibnex_offline_childdip(cdip);
2175 			return (IBNEX_FAILURE);
2176 		}
2177 		cdip = mdi_pi_get_client(pip);
2178 
2179 		IBTF_DPRINTF_L4("ibnex",
2180 		    "\tioc_create_pi: New IOC dip %p", cdip);
2181 
2182 		node_data->node_dip = cdip;
2183 		ddi_set_parent_data(cdip, node_data);
2184 
2185 		if (flag) {
2186 			if ((rval = ibnex_create_ioc_node_prop(
2187 			    ioc_info, cdip)) != IBNEX_SUCCESS) {
2188 				ibnex_delete_ioc_node_data(node_data);
2189 				ddi_prop_remove_all(cdip);
2190 				ddi_set_parent_data(cdip, NULL);
2191 
2192 				(void) ibnex_offline_childdip(cdip);
2193 				return (IBNEX_FAILURE);
2194 			}
2195 			flag = 0;
2196 		}
2197 
2198 		rval = mdi_pi_online(pip, 0);
2199 
2200 		if (rval != MDI_SUCCESS) {
2201 			ibnex_delete_ioc_node_data(node_data);
2202 			ddi_prop_remove_all(cdip);
2203 			ddi_set_parent_data(cdip, NULL);
2204 			IBTF_DPRINTF_L2("ibnex", "\tioc_create_pi: "
2205 			    "mdi_pi_online() failed ioc dip %p, rval %d",
2206 			    cdip, rval);
2207 			(void) ibnex_offline_childdip(cdip);
2208 			rval = IBNEX_FAILURE;
2209 			break;
2210 		} else
2211 			rval = IBNEX_SUCCESS;
2212 	}
2213 	return (rval);
2214 }
2215 
2216 
2217 /*
2218  * ibnex_create_ioc_node_prop()
2219  *	Create IOC device node properties
2220  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
2221  */
2222 static int
2223 ibnex_create_ioc_node_prop(ibdm_ioc_info_t *ioc_info, dev_info_t *cdip)
2224 {
2225 	uint16_t		 capabilities;
2226 	ib_dm_ioc_ctrl_profile_t *ioc_profile = &ioc_info->ioc_profile;
2227 
2228 	IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_node_prop");
2229 
2230 	if (ibnex_create_ioc_compatible_prop(cdip,
2231 	    ioc_profile) != IBNEX_SUCCESS) {
2232 		return (IBNEX_FAILURE);
2233 	}
2234 	if ((ioc_info->ioc_iou_dc_valid) &&
2235 	    (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "iou-diagcode",
2236 	    ioc_info->ioc_iou_diagcode)) != DDI_PROP_SUCCESS) {
2237 		IBTF_DPRINTF_L2("ibnex",
2238 		    "\tcreate_ioc_node_prop: iou-diagcode create failed");
2239 		return (IBNEX_FAILURE);
2240 	}
2241 	if ((ioc_info->ioc_diagdeviceid) && (ioc_info->ioc_dc_valid)) {
2242 		if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "ioc-diagcode",
2243 		    ioc_info->ioc_diagcode) != DDI_PROP_SUCCESS) {
2244 			IBTF_DPRINTF_L2("ibnex", "\tcreate_ioc_node_prop: "
2245 			    "ioc-diagcode create failed");
2246 			return (IBNEX_FAILURE);
2247 		}
2248 	}
2249 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "rdma-queue-depth",
2250 	    ioc_profile->ioc_rdma_read_qdepth) != DDI_PROP_SUCCESS) {
2251 		IBTF_DPRINTF_L2("ibnex",
2252 		    "\tcreate_ioc_node_prop: rdma-queue-depth create failed");
2253 		return (IBNEX_FAILURE);
2254 	}
2255 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "rdma-transfer-size",
2256 	    ioc_profile->ioc_rdma_xfer_sz) != DDI_PROP_SUCCESS) {
2257 		IBTF_DPRINTF_L2("ibnex", "\tcreate_ioc_node_prop: "
2258 		    "rdma-transfer-size create failed");
2259 		return (IBNEX_FAILURE);
2260 	}
2261 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "send-message-size",
2262 	    ioc_profile->ioc_send_msg_sz) != DDI_PROP_SUCCESS) {
2263 		IBTF_DPRINTF_L2("ibnex",
2264 		    "\tcreate_ioc_node_prop: send-message-size create failed");
2265 		return (IBNEX_FAILURE);
2266 	}
2267 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "send-queue-depth",
2268 	    ioc_profile->ioc_send_msg_qdepth) != DDI_PROP_SUCCESS) {
2269 		IBTF_DPRINTF_L2("ibnex",
2270 		    "\tcreate_ioc_node_prop: send-queue-depth create failed");
2271 		return (IBNEX_FAILURE);
2272 	}
2273 
2274 	capabilities = (ioc_profile->ioc_ctrl_opcap_mask << 8);
2275 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
2276 		"capabilities", capabilities) != DDI_PROP_SUCCESS) {
2277 		IBTF_DPRINTF_L2("ibnex",
2278 		    "\tcreate_ioc_node_prop: capabilities create failed");
2279 		return (IBNEX_FAILURE);
2280 	}
2281 	if (ndi_prop_update_string(DDI_DEV_T_NONE, cdip, "id-string",
2282 	    (char *)ioc_profile->ioc_id_string) != DDI_PROP_SUCCESS) {
2283 		IBTF_DPRINTF_L2("ibnex",
2284 		    "\tcreate_ioc_node_prop: id-string failed");
2285 		return (IBNEX_FAILURE);
2286 	}
2287 
2288 	/*
2289 	 * Create properties to represent all the service entries supported
2290 	 * by the IOC. Each service entry consists of 1) Service ID (64 bits)
2291 	 * and 2) Service name (40 bytes). The service entry table is
2292 	 * represented by two properties, service-ids and service-names. The
2293 	 * service-id property is a array of int64's and service names is
2294 	 * array of strings. The first element in the "service-ids" property
2295 	 * corresponds to first string in the "service-names" and so on.
2296 	 */
2297 	if ((ioc_profile->ioc_service_entries != 0) &&
2298 	    (ibnex_create_ioc_srv_props(cdip, ioc_info) != IBNEX_SUCCESS))
2299 		return (IBNEX_FAILURE);
2300 
2301 	/* Create destination port GID properties */
2302 	if (ibnex_create_ioc_portgid_prop(cdip, ioc_info) != IBNEX_SUCCESS)
2303 		return (IBNEX_FAILURE);
2304 
2305 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "protocol-version",
2306 	    ioc_profile->ioc_protocol_ver) != DDI_PROP_SUCCESS) {
2307 		IBTF_DPRINTF_L2("ibnex",
2308 		    "\tcreate_ioc_node_prop: protocol-version create failed");
2309 		return (IBNEX_FAILURE);
2310 	}
2311 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "protocol",
2312 	    ioc_profile->ioc_protocol) != DDI_PROP_SUCCESS) {
2313 		IBTF_DPRINTF_L2("ibnex",
2314 		    "\tcreate_ioc_node_prop: protocol create failed");
2315 		return (IBNEX_FAILURE);
2316 	}
2317 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "io-subclass",
2318 	    ioc_profile->ioc_io_subclass) != DDI_PROP_SUCCESS) {
2319 		IBTF_DPRINTF_L2("ibnex",
2320 		    "\tcreate_ioc_node_prop: subclass create failed");
2321 		return (IBNEX_FAILURE);
2322 	}
2323 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "io-class",
2324 	    ioc_profile->ioc_io_class) != DDI_PROP_SUCCESS) {
2325 		IBTF_DPRINTF_L2("ibnex",
2326 		    "\tcreate_ioc_node_prop: class prop create failed");
2327 		return (IBNEX_FAILURE);
2328 	}
2329 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "subsystem-id",
2330 	    ioc_profile->ioc_subsys_id) != DDI_PROP_SUCCESS) {
2331 		IBTF_DPRINTF_L2("ibnex",
2332 		    "\tcreate_ioc_node_prop: subsys_id create failed");
2333 		return (IBNEX_FAILURE);
2334 	}
2335 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "subsystem-vendor-id",
2336 	    ioc_profile->ioc_subsys_vendorid) != DDI_PROP_SUCCESS) {
2337 		IBTF_DPRINTF_L2("ibnex",
2338 		    "\tcreate_ioc_node_prop: subsystem vendor create failed");
2339 		return (IBNEX_FAILURE);
2340 	}
2341 	if (ndi_prop_update_int64(DDI_DEV_T_NONE, cdip, "ioc-guid",
2342 	    ioc_profile->ioc_guid) != DDI_PROP_SUCCESS) {
2343 		IBTF_DPRINTF_L2("ibnex",
2344 		    "\tcreate_ioc_node_prop: protocol create failed");
2345 		return (IBNEX_FAILURE);
2346 	}
2347 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "device-version",
2348 	    ioc_profile->ioc_device_ver) != DDI_PROP_SUCCESS) {
2349 		IBTF_DPRINTF_L2("ibnex",
2350 		    "\tcreate_ioc_node_prop: product-id create failed");
2351 		return (IBNEX_FAILURE);
2352 	}
2353 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "device-id",
2354 	    ioc_profile->ioc_deviceid) != DDI_PROP_SUCCESS) {
2355 		IBTF_DPRINTF_L2("ibnex",
2356 		    "\tcreate_ioc_node_prop: product-id create failed");
2357 		return (IBNEX_FAILURE);
2358 	}
2359 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "vendor-id",
2360 	    ioc_profile->ioc_vendorid) != DDI_PROP_SUCCESS) {
2361 		IBTF_DPRINTF_L2("ibnex",
2362 		    "\tcreate_ioc_node_prop: vendor-id create failed");
2363 		return (IBNEX_FAILURE);
2364 	}
2365 	return (IBNEX_SUCCESS);
2366 }
2367 
2368 
2369 /*
2370  * ibnex_create_ioc_portgid_prop()
2371  *	Creates "port-entries", "port-list" properties
2372  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
2373  */
2374 static int
2375 ibnex_create_ioc_portgid_prop(
2376     dev_info_t *cdip, ibdm_ioc_info_t *ioc_info)
2377 {
2378 	uint64_t	*port_gids;
2379 	int		length, ii, jj;
2380 	int		prop_len;
2381 	ibnex_node_data_t *node_data;
2382 
2383 	IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_portgid_prop");
2384 
2385 	node_data = ddi_get_parent_data(cdip);
2386 	ASSERT(node_data);
2387 
2388 	prop_len = (ioc_info->ioc_nportgids != 0) ?
2389 	    (2 * ioc_info->ioc_nportgids) : 1;
2390 	length = sizeof (uint64_t) * prop_len;
2391 	port_gids = kmem_zalloc(length, KM_SLEEP);
2392 
2393 	for (ii = 0, jj = 0; ii < ioc_info->ioc_nportgids; ii++) {
2394 		port_gids[jj++] = ioc_info->ioc_gid_list[ii].gid_dgid_hi;
2395 		port_gids[jj++] = ioc_info->ioc_gid_list[ii].gid_dgid_lo;
2396 	}
2397 	if (ndi_prop_update_int64_array(DDI_DEV_T_NONE, cdip, "port-list",
2398 	    (int64_t *)port_gids, prop_len) != DDI_PROP_SUCCESS) {
2399 		IBTF_DPRINTF_L2("ibnex",
2400 		    "\tcreate_ioc_portgid_prop: port-list create failed");
2401 		kmem_free(port_gids, length);
2402 		return (IBNEX_FAILURE);
2403 	}
2404 	if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "port-entries",
2405 	    ioc_info->ioc_nportgids) != DDI_PROP_SUCCESS) {
2406 		IBTF_DPRINTF_L2("ibnex",
2407 		    "\tcreate_ioc_portgid_prop: port-entries create failed");
2408 		kmem_free(port_gids, length);
2409 		return (IBNEX_FAILURE);
2410 	}
2411 
2412 	kmem_free(port_gids, length);
2413 	return (IBNEX_SUCCESS);
2414 }
2415 
2416 
2417 /*
2418  * ibnex_create_ioc_srv_props()
2419  *	Creates "service-name" and "service-id" properties
2420  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
2421  */
2422 static int
2423 ibnex_create_ioc_srv_props(
2424     dev_info_t *cdip, ibdm_ioc_info_t *ioc_info)
2425 {
2426 	int			length, ii;
2427 	uint64_t		*srv_id;
2428 	char			*temp, *srv_names[IB_DM_MAX_IOCS_IN_IOU];
2429 	ib_dm_ioc_ctrl_profile_t *profile = &ioc_info->ioc_profile;
2430 	ibdm_srvents_info_t	 *srvents = ioc_info->ioc_serv;
2431 
2432 	IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_srv_props");
2433 
2434 	length = profile->ioc_service_entries * sizeof (ib_dm_srv_t);
2435 	srv_id = kmem_zalloc(length, KM_SLEEP);
2436 	temp = (char *)((char *)srv_id + (8 * profile->ioc_service_entries));
2437 	for (ii = 0; ii < profile->ioc_service_entries; ii++) {
2438 		srv_names[ii] = (char *)temp + (ii * IB_DM_MAX_SVC_NAME_LEN);
2439 	}
2440 
2441 	for (ii = 0; ii < profile->ioc_service_entries; ii++) {
2442 		srv_id[ii] = srvents[ii].se_attr.srv_id;
2443 		bcopy(srvents[ii].se_attr.srv_name,
2444 		    srv_names[ii], (IB_DM_MAX_SVC_NAME_LEN - 1));
2445 		IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_srv_props "
2446 		    "Service Names : %s", srv_names[ii]);
2447 		IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_srv_props "
2448 		    "Service ID : %llx", srv_id[ii]);
2449 	}
2450 
2451 	if (ndi_prop_update_int64_array(DDI_DEV_T_NONE, cdip,
2452 	    "service-id", (int64_t *)srv_id,
2453 	    profile->ioc_service_entries) != DDI_PROP_SUCCESS) {
2454 		IBTF_DPRINTF_L2("ibnex",
2455 		    "\tcreate_ioc_srv_props: service-id create failed");
2456 		kmem_free(srv_id, length);
2457 		return (IBNEX_FAILURE);
2458 	}
2459 
2460 	if (ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip,
2461 	    "service-name", (char **)srv_names,
2462 	    profile->ioc_service_entries) != DDI_PROP_SUCCESS) {
2463 		IBTF_DPRINTF_L2("ibnex",
2464 		    "\tcreate_ioc_srv_props: service-name create failed");
2465 		kmem_free(srv_id, length);
2466 		return (IBNEX_FAILURE);
2467 	}
2468 	kmem_free(srv_id, length);
2469 	return (IBNEX_SUCCESS);
2470 }
2471 
2472 
2473 /*
2474  * ibnex_create_ioc_compatible_prop()
2475  *	Creates "compatible" property values
2476  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
2477  */
2478 static int
2479 ibnex_create_ioc_compatible_prop(
2480     dev_info_t *cdip, ib_dm_ioc_ctrl_profile_t *ioc_profile)
2481 {
2482 	char		*temp;
2483 	int		rval, ii;
2484 	char		*compatible[IBNEX_MAX_COMPAT_NAMES];
2485 
2486 	/*
2487 	 * Initialize the "compatible" property string as below:
2488 	 * Compatible Strings :
2489 	 *	1. ib.V<vid>P<pid>S<subsys vid>s<subsys id>v<ver>
2490 	 *	2. ib.V<vid>P<pid>S<subsys vid>s<subsys id>
2491 	 *	3. ib.V<vid>P<pid>v<ver>
2492 	 *	4. ib.V<vid>P<pid>
2493 	 *	5. ib.C<Class>c<Subclass>p<protocol>r<protocol ver>
2494 	 *	6. ib.C<Class>c<Subclass>p<protocol>
2495 	 *
2496 	 * Note:
2497 	 *	All leading zeros must be present
2498 	 *	All numeric values must specified in hex without prefix "0x"
2499 	 */
2500 
2501 	temp = kmem_alloc(IBNEX_MAX_COMPAT_PROP_SZ, KM_SLEEP);
2502 	for (ii = 0; ii < IBNEX_MAX_COMPAT_NAMES; ii++)
2503 		compatible[ii] = temp + (ii * IBNEX_MAX_COMPAT_LEN);
2504 
2505 	(void) snprintf(compatible[0], IBNEX_MAX_COMPAT_LEN,
2506 	    "ib.V%06xP%08xS%06xs%08xv%04x",
2507 	    ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid,
2508 	    ioc_profile->ioc_subsys_vendorid, ioc_profile->ioc_subsys_id,
2509 	    ioc_profile->ioc_device_ver);
2510 
2511 	(void) snprintf(compatible[1], IBNEX_MAX_COMPAT_LEN,
2512 	    "ib.V%06xP%08xS%06xs%08x",
2513 	    ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid,
2514 	    ioc_profile->ioc_subsys_vendorid, ioc_profile->ioc_subsys_id);
2515 
2516 	(void) snprintf(compatible[2], IBNEX_MAX_COMPAT_LEN,
2517 	    "ib.V%06xP%08xv%04x",
2518 	    ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid,
2519 	    ioc_profile->ioc_device_ver);
2520 
2521 	(void) snprintf(compatible[3], IBNEX_MAX_COMPAT_LEN,
2522 	    "ib.V%06xP%08x",
2523 	    ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid);
2524 
2525 	(void) snprintf(compatible[4], IBNEX_MAX_COMPAT_LEN,
2526 	    "ib.C%04xc%04xp%04xr%04x",
2527 	    ioc_profile->ioc_io_class, ioc_profile->ioc_io_subclass,
2528 	    ioc_profile->ioc_protocol, ioc_profile->ioc_protocol_ver);
2529 
2530 	(void) snprintf(compatible[5], IBNEX_MAX_COMPAT_LEN,
2531 	    "ib.C%04xc%04xp%04x",
2532 	    ioc_profile->ioc_io_class, ioc_profile->ioc_io_subclass,
2533 	    ioc_profile->ioc_protocol);
2534 	for (ii = 0; ii < IBNEX_MAX_COMPAT_NAMES; ii++)
2535 		IBTF_DPRINTF_L4("ibnex", "\tcompatible: %s", compatible[ii]);
2536 
2537 	/* Create the compatible property for child cdip */
2538 	rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip,
2539 	    "compatible", (char **)compatible, IBNEX_MAX_COMPAT_NAMES);
2540 
2541 	if (rval != DDI_PROP_SUCCESS) {
2542 		IBTF_DPRINTF_L2("ibnex", "\tcompatible prop_create failed");
2543 		kmem_free(temp, IBNEX_MAX_COMPAT_PROP_SZ);
2544 		return (IBNEX_FAILURE);
2545 	}
2546 
2547 	kmem_free(temp, IBNEX_MAX_COMPAT_PROP_SZ);
2548 	return (IBNEX_SUCCESS);
2549 }
2550 
2551 
2552 static void
2553 ibnex_ioc_node_cleanup()
2554 {
2555 	ibnex_node_data_t *node, *delete;
2556 
2557 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2558 	for (node = ibnex.ibnex_ioc_node_head; node; ) {
2559 		delete = node;
2560 		node = node->node_next;
2561 		mutex_exit(&ibnex.ibnex_mutex);
2562 		ibnex_delete_ioc_node_data(delete);
2563 		mutex_enter(&ibnex.ibnex_mutex);
2564 	}
2565 }
2566 
2567 /*
2568  * ibnex_delete_ioc_node_data()
2569  *	Delete IOC node from the list
2570  */
2571 static void
2572 ibnex_delete_ioc_node_data(ibnex_node_data_t *node)
2573 {
2574 	IBTF_DPRINTF_L4("ibnex", "\tdelete_ioc_node_data:");
2575 
2576 	mutex_enter(&ibnex.ibnex_mutex);
2577 	if ((node->node_next == NULL) && (node->node_prev == NULL)) {
2578 		ASSERT(ibnex.ibnex_ioc_node_head == node);
2579 		ibnex.ibnex_ioc_node_head = NULL;
2580 	} else if (node->node_next == NULL)
2581 		node->node_prev->node_next = NULL;
2582 	else if (node->node_prev == NULL) {
2583 		node->node_next->node_prev = NULL;
2584 		ibnex.ibnex_ioc_node_head = node->node_next;
2585 	} else {
2586 		node->node_prev->node_next = node->node_next;
2587 		node->node_next->node_prev = node->node_prev;
2588 	}
2589 	IBTF_DPRINTF_L4("ibnex", "\tdelete_ioc_node_data: head %p",
2590 	    ibnex.ibnex_ioc_node_head);
2591 	mutex_exit(&ibnex.ibnex_mutex);
2592 	kmem_free(node, sizeof (ibnex_node_data_t));
2593 }
2594 
2595 
2596 /*
2597  * ibnex_dm_callback()
2598  *
2599  *	This routine is registered with the IBDM during IB nexus attach. It
2600  *	is called by the IBDM module when it discovers
2601  *		New HCA port
2602  *		HCA port removal
2603  *		New HCA added
2604  *		HCA removed
2605  */
2606 void
2607 ibnex_dm_callback(void *arg, ibdm_events_t flag)
2608 {
2609 	char	hca_guid[IBNEX_HCAGUID_STRSZ];
2610 	ibdm_ioc_info_t	*ioc_list, *ioc;
2611 	ibnex_node_data_t	*node_data;
2612 
2613 	IBTF_DPRINTF_L4("ibnex", "\tdm_callback: attr %p event %x", arg, flag);
2614 
2615 	switch (flag) {
2616 	case IBDM_EVENT_HCA_ADDED:
2617 		(void) snprintf(hca_guid, IBNEX_HCAGUID_STRSZ, "%llX",
2618 		    (*(longlong_t *)arg));
2619 		/* Create a devctl minor node for the HCA's port  */
2620 		if (ddi_create_minor_node(ibnex.ibnex_dip, hca_guid, S_IFCHR,
2621 		    ddi_get_instance(ibnex.ibnex_dip),
2622 		    DDI_NT_IB_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
2623 			IBTF_DPRINTF_L4("ibnex", "\tdm_callback: failed to "
2624 			    "create minor node for port w/ guid %s", hca_guid);
2625 		}
2626 
2627 		break;
2628 
2629 	case IBDM_EVENT_HCA_REMOVED:
2630 		(void) snprintf(hca_guid, IBNEX_HCAGUID_STRSZ, "%llX",
2631 		    (*(longlong_t *)arg));
2632 		ddi_remove_minor_node(ibnex.ibnex_dip, hca_guid);
2633 		break;
2634 
2635 	case IBDM_EVENT_IOC_PROP_UPDATE:
2636 		ioc = ioc_list = (ibdm_ioc_info_t *)arg;
2637 		if (ioc_list == NULL)
2638 			break;
2639 
2640 		mutex_enter(&ibnex.ibnex_mutex);
2641 		while (ioc_list) {
2642 			if ((node_data = ibnex_is_node_data_present(
2643 			    IBNEX_IOC_NODE, ioc_list, 0, 0)) != NULL &&
2644 			    node_data->node_dip != NULL) {
2645 				ibnex_update_prop(node_data, ioc_list);
2646 			}
2647 			ioc_list = ioc_list->ioc_next;
2648 		}
2649 		mutex_exit(&ibnex.ibnex_mutex);
2650 		ibdm_ibnex_free_ioc_list(ioc);
2651 	}
2652 }
2653 
2654 
2655 /*
2656  * ibnex_get_dip_from_guid()
2657  *
2658  *	Searches the linked list of the port nodes and returns the dip for
2659  *	the of the Port / Node guid requested.
2660  *	Returns NULL if not found
2661  */
2662 int
2663 ibnex_get_dip_from_guid(ib_guid_t guid, int index, ib_pkey_t pkey,
2664     dev_info_t **dip)
2665 {
2666 	int			node_index;
2667 	ib_guid_t		node_guid;
2668 	ib_pkey_t		node_pkey;
2669 	ibnex_node_data_t	*node_data;
2670 
2671 	IBTF_DPRINTF_L4("ibnex",
2672 	    "\tget_dip_from_guid: guid = %llx", guid);
2673 
2674 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2675 	/* Search for a matching entry in internal lists */
2676 	node_data = ibnex.ibnex_port_node_head;
2677 	while (node_data) {
2678 		node_guid = node_data->node_data.port_node.port_guid;
2679 		node_index = node_data->node_data.port_node.port_commsvc_idx;
2680 		node_pkey = node_data->node_data.port_node.port_pkey;
2681 		if ((node_guid == guid) && (index == node_index) &&
2682 		    (node_pkey == pkey)) {
2683 			break;
2684 		}
2685 		node_data = node_data->node_next;
2686 	}
2687 
2688 	/* matching found with a valid dip */
2689 	if (node_data && node_data->node_dip) {
2690 		*dip = node_data->node_dip;
2691 		return (IBNEX_SUCCESS);
2692 	} else if (node_data && !node_data->node_dip) {	/* dip is invalid */
2693 		*dip = NULL;
2694 		return (IBNEX_SUCCESS);
2695 	}
2696 
2697 	/* no match found */
2698 	*dip = NULL;
2699 	return (IBNEX_FAILURE);
2700 }
2701 
2702 
2703 /*
2704  * ibnex_comm_svc_init()
2705  *	Read the property and cache the values in the global
2706  *	structure.
2707  *	Check for max allowed length (4 bytes) of service name
2708  *	(each element of the property)
2709  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
2710  */
2711 static ibnex_rval_t
2712 ibnex_comm_svc_init(char *property, ibnex_node_type_t type)
2713 {
2714 	int		i, len, count;
2715 	int		ncomm_svcs;
2716 	char		**comm_svcp;
2717 	char		**servicep = NULL;
2718 	uint_t		nservices = 0;
2719 	int			*valid = NULL;
2720 
2721 	IBTF_DPRINTF_L4("ibnex", "\tcomm_svc_init : %s property, type = %x",
2722 	    property, type);
2723 
2724 	/* lookup the string array property */
2725 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, ibnex.ibnex_dip,
2726 	    DDI_PROP_DONTPASS, property, &servicep, &nservices) !=
2727 	    DDI_PROP_SUCCESS) {
2728 		IBTF_DPRINTF_L2("ibnex", "\t%s property undefined", property);
2729 		return (IBNEX_SUCCESS);
2730 	}
2731 
2732 	if (nservices)
2733 		valid = kmem_zalloc(nservices * sizeof (int), KM_SLEEP);
2734 
2735 
2736 	/* first read the file to get a count of valid service entries */
2737 	for (ncomm_svcs = 0, count = 0; count < nservices; count++) {
2738 		int j;
2739 
2740 		len = strlen(servicep[count]);
2741 		if (len == 0 || len > 4) {
2742 			IBTF_DPRINTF_L2("ibnex", "\tcomm_svc_init : "
2743 			    "Service name %s invalid : length %d",
2744 			    servicep[count], len);
2745 			continue;
2746 		}
2747 		if (ibnex_unique_svcname(servicep[count]) != IBNEX_SUCCESS) {
2748 			IBTF_DPRINTF_L2("ibnex", "\tcomm_svc_init : "
2749 			    "Service name %s invalid : Not unique",
2750 			    servicep[count]);
2751 			continue;
2752 		}
2753 
2754 		/*
2755 		 * ibnex_unique_svcname checks for uniqueness in service names
2756 		 * communication services fully initialized. Check uniqueness
2757 		 * in service names currently initialized.
2758 		 */
2759 		for (j = 0; j < count; j++)
2760 			if (valid[j] && strncmp(servicep[count],
2761 			    servicep[j], 4) == 0) {
2762 				IBTF_DPRINTF_L2("ibnex", "\tcomm_svc_init : "
2763 				    "Service name %s invalid : Not unique",
2764 				    servicep[count]);
2765 					continue;
2766 			}
2767 
2768 		valid[count] = 1;
2769 		ncomm_svcs++;
2770 	}
2771 
2772 	/* if no valid entries found, bailout */
2773 	if (nservices == 0 || ncomm_svcs == 0) {
2774 		IBTF_DPRINTF_L4("ibnex", "\tNo %s entries found", property);
2775 		ddi_prop_free(servicep); /* free the property */
2776 		if (valid)
2777 			kmem_free(valid, nservices * sizeof (int));
2778 		return (IBNEX_SUCCESS);
2779 	}
2780 
2781 	comm_svcp = kmem_zalloc((ncomm_svcs * sizeof (char *)), KM_SLEEP);
2782 	if (type == IBNEX_PORT_COMMSVC_NODE) {
2783 		ibnex.ibnex_comm_svc_names = comm_svcp;
2784 		ibnex.ibnex_num_comm_svcs = ncomm_svcs;
2785 	} else if (type == IBNEX_VPPA_COMMSVC_NODE) {
2786 		ibnex.ibnex_vppa_comm_svc_names = comm_svcp;
2787 		ibnex.ibnex_nvppa_comm_svcs = ncomm_svcs;
2788 	} else if (type == IBNEX_HCASVC_COMMSVC_NODE) {
2789 		ibnex.ibnex_hcasvc_comm_svc_names = comm_svcp;
2790 		ibnex.ibnex_nhcasvc_comm_svcs = ncomm_svcs;
2791 	}
2792 
2793 	/* copy the services into an array of strings */
2794 	for (i = 0, count = 0; count < nservices; count++) {
2795 		if (valid[count] == 0)	/* Skip invalid ones */
2796 			continue;
2797 		comm_svcp[i] = kmem_alloc(len + 1, KM_SLEEP);
2798 		(void) strcpy(comm_svcp[i], servicep[count]);
2799 		IBTF_DPRINTF_L4("ibnex",
2800 		    "\t\tService [%d]: %s", i, comm_svcp[i]);
2801 		++i;
2802 	}
2803 	ddi_prop_free(servicep);
2804 	kmem_free(valid, nservices * sizeof (int));
2805 	return (IBNEX_SUCCESS);
2806 }
2807 
2808 
2809 /*
2810  * ibnex_comm_svc_fini()
2811  *	Deallocate all the memory allocated for the communication
2812  *	service arrays.
2813  */
2814 static void
2815 ibnex_comm_svc_fini()
2816 {
2817 	int	index;
2818 
2819 	for (index = 0; index < ibnex.ibnex_num_comm_svcs; index++) {
2820 		kmem_free(ibnex.ibnex_comm_svc_names[index],
2821 		    (strlen(ibnex.ibnex_comm_svc_names[index]) + 1));
2822 	}
2823 	if (ibnex.ibnex_comm_svc_names) {
2824 		kmem_free(ibnex.ibnex_comm_svc_names,
2825 		    ibnex.ibnex_num_comm_svcs * sizeof (char *));
2826 	}
2827 	for (index = 0; index < ibnex.ibnex_nvppa_comm_svcs; index++) {
2828 		kmem_free(ibnex.ibnex_vppa_comm_svc_names[index],
2829 		    strlen(ibnex.ibnex_vppa_comm_svc_names[index]) +1);
2830 	}
2831 	if (ibnex.ibnex_vppa_comm_svc_names) {
2832 		kmem_free(ibnex.ibnex_vppa_comm_svc_names,
2833 		    ibnex.ibnex_nvppa_comm_svcs * sizeof (char *));
2834 	}
2835 	for (index = 0; index < ibnex.ibnex_nhcasvc_comm_svcs; index++) {
2836 		kmem_free(ibnex.ibnex_hcasvc_comm_svc_names[index],
2837 		    strlen(ibnex.ibnex_hcasvc_comm_svc_names[index]) +1);
2838 	}
2839 	if (ibnex.ibnex_hcasvc_comm_svc_names) {
2840 		kmem_free(ibnex.ibnex_hcasvc_comm_svc_names,
2841 		    ibnex.ibnex_nhcasvc_comm_svcs * sizeof (char *));
2842 	}
2843 	ibnex.ibnex_comm_svc_names = NULL;
2844 	ibnex.ibnex_num_comm_svcs = 0;
2845 	ibnex.ibnex_vppa_comm_svc_names = NULL;
2846 	ibnex.ibnex_nvppa_comm_svcs = 0;
2847 	ibnex.ibnex_hcasvc_comm_svc_names = NULL;
2848 	ibnex.ibnex_nhcasvc_comm_svcs = 0;
2849 }
2850 
2851 
2852 /*
2853  * ibnex_commsvc_initnode()
2854  *	This routine is specific to port/VPPA node creation
2855  *	Creates a device node for the comm service specified by commsvc_index
2856  *	Creates all the device node properties
2857  *	Allocates and initializes the node specific data
2858  *	Binds the device driver of the device node
2859  *	Returns "dev_info_t" of the child node or NULL in case of failure
2860  *	Sets IBNEX_SUCCESS/IBNEX_FAILURE/IBNEX_BUSY in "rval" to reflect
2861  *	if the operation was successful, failed or was not performed.
2862  */
2863 dev_info_t *
2864 ibnex_commsvc_initnode(dev_info_t *parent, ibdm_port_attr_t *port_attr,
2865     int index, int node_type, ib_pkey_t pkey, int *rval, int flag)
2866 {
2867 	int			ret;
2868 	char			*svcname;
2869 	dev_info_t		*cdip;
2870 	ibnex_node_data_t	*node_data;
2871 
2872 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2873 
2874 	*rval = IBNEX_SUCCESS;
2875 
2876 	/*
2877 	 * prevent any races
2878 	 * we have seen this node_data and it has been initialized
2879 	 * Note that node_dip is already NULL if unconfigure is in
2880 	 * progress.
2881 	 */
2882 	node_data = ibnex_is_node_data_present(node_type, (void *)port_attr,
2883 	    index, pkey);
2884 	if (node_data && node_data->node_dip) {
2885 		/*
2886 		 * Return NULL if another configure
2887 		 * operation is in progress
2888 		 */
2889 		if (node_data->node_state == IBNEX_CFGADM_CONFIGURING) {
2890 			*rval = IBNEX_BUSY;
2891 			return (NULL);
2892 		} else {
2893 			return (node_data->node_dip);
2894 		}
2895 	} else if (node_data == NULL) {
2896 		/* allocate a new ibnex_node_data_t */
2897 		node_data = ibnex_init_child_nodedata(node_type, port_attr,
2898 		    index, pkey);
2899 	}
2900 
2901 	/*
2902 	 * Return NULL if another unconfigure operation is in progress
2903 	 */
2904 	if (node_data->node_state == IBNEX_CFGADM_UNCONFIGURING) {
2905 		*rval = IBNEX_BUSY;
2906 		return (NULL);
2907 	}
2908 
2909 	ASSERT(node_data->node_state != IBNEX_CFGADM_CONFIGURED);
2910 	node_data->node_state = IBNEX_CFGADM_CONFIGURING;
2911 
2912 	ndi_devi_alloc_sleep(parent,
2913 	    IBNEX_IBPORT_CNAME, (pnode_t)DEVI_SID_NODEID, &cdip);
2914 
2915 	node_data->node_dip	= cdip;
2916 	ddi_set_parent_data(cdip, node_data);
2917 	mutex_exit(&ibnex.ibnex_mutex);
2918 
2919 	switch (node_type) {
2920 		case IBNEX_VPPA_COMMSVC_NODE :
2921 			svcname = ibnex.ibnex_vppa_comm_svc_names[index];
2922 			break;
2923 		case IBNEX_HCASVC_COMMSVC_NODE :
2924 			svcname = ibnex.ibnex_hcasvc_comm_svc_names[index];
2925 			break;
2926 		case IBNEX_PORT_COMMSVC_NODE :
2927 			svcname = ibnex.ibnex_comm_svc_names[index];
2928 			break;
2929 		default :
2930 			IBTF_DPRINTF_L2("ibnex", "\tcommsvc_initnode:"
2931 			    "\tInvalid Node type");
2932 			*rval = IBNEX_FAILURE;
2933 			ibnex_delete_port_node_data(node_data);
2934 			ddi_prop_remove_all(cdip);
2935 			ddi_set_parent_data(cdip, NULL);
2936 			(void) ndi_devi_free(cdip);
2937 			mutex_enter(&ibnex.ibnex_mutex);
2938 			return (NULL);
2939 	}
2940 
2941 	if (ibnex_create_port_node_prop(port_attr, cdip, svcname, pkey) ==
2942 	    IBNEX_SUCCESS) {
2943 		if (flag == IBNEX_DEVFS_ENUMERATE)
2944 			ret = ndi_devi_bind_driver(cdip, 0);
2945 		else
2946 			ret = ndi_devi_online(cdip, 0);
2947 		if (ret == NDI_SUCCESS) {
2948 			mutex_enter(&ibnex.ibnex_mutex);
2949 			node_data->node_state	= IBNEX_CFGADM_CONFIGURED;
2950 			return (cdip);
2951 		}
2952 	}
2953 	*rval = IBNEX_FAILURE;
2954 	ibnex_delete_port_node_data(node_data);
2955 	ddi_prop_remove_all(cdip);
2956 	ddi_set_parent_data(cdip, NULL);
2957 	(void) ndi_devi_free(cdip);
2958 	mutex_enter(&ibnex.ibnex_mutex);
2959 	IBTF_DPRINTF_L4("ibnex", "\tcommsvc_initnode: failure exit");
2960 	return (NULL);
2961 }
2962 
2963 
2964 /*
2965  * ibnex_create_port_node_prop()
2966  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
2967  */
2968 static int
2969 ibnex_create_port_node_prop(ibdm_port_attr_t *port_attr,
2970     dev_info_t *child_dip, char *srvname, ib_pkey_t pkey)
2971 {
2972 	if (ibnex_create_port_compatible_prop(child_dip,
2973 	    srvname, port_attr) != DDI_PROP_SUCCESS) {
2974 		IBTF_DPRINTF_L2("ibnex",
2975 		    "\tcreate_port_node_prop: compatible update failed");
2976 		return (IBNEX_FAILURE);
2977 	}
2978 	if ((pkey != 0) && (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2979 	    "port-pkey", pkey) != DDI_PROP_SUCCESS)) {
2980 		IBTF_DPRINTF_L2("ibnex",
2981 		    "\tcreate_port_node_prop: port-num update failed");
2982 		return (IBNEX_FAILURE);
2983 	}
2984 
2985 	/*
2986 	 * For HCA_SVC device nodes, port_num will be 0.
2987 	 * Do not create the "port-number" & "port-guid" properties.
2988 	 */
2989 	if (port_attr->pa_port_num != 0) {
2990 		if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2991 			"port-number", port_attr->pa_port_num) !=
2992 		    DDI_PROP_SUCCESS) {
2993 			IBTF_DPRINTF_L2("ibnex",
2994 			    "\tcreate_port_node_prop: port-num update failed");
2995 			return (IBNEX_FAILURE);
2996 		}
2997 		if (ndi_prop_update_int64(DDI_DEV_T_NONE, child_dip,
2998 			"port-guid", port_attr->pa_port_guid) !=
2999 		    DDI_PROP_SUCCESS) {
3000 			IBTF_DPRINTF_L2("ibnex",
3001 			    "\tcreate_port_node_prop: port-guid update failed");
3002 			return (IBNEX_FAILURE);
3003 		}
3004 	} else {
3005 		ibdm_hca_list_t	*hca_list;
3006 
3007 		/*
3008 		 * HCA_SVC nodes require "num-ports" & "port-guids"
3009 		 * properties.
3010 		 *
3011 		 * To create the num-ports & port-guids attribute :
3012 		 * 1. Get HCA list (ibdm_ibnex_get_hca_info_by_guid)
3013 		 * 2. Form the array of port GUIDs.
3014 		 */
3015 		if ((hca_list = ibdm_ibnex_get_hca_info_by_guid(
3016 		    port_attr->pa_hca_guid)) == NULL) {
3017 			IBTF_DPRINTF_L2("ibnex",
3018 			    "\tcreate_port_node_prop: hca_info_by_guid failed");
3019 			return (IBNEX_FAILURE);
3020 		}
3021 
3022 		if (hca_list->hl_nports != 0) {
3023 			ib_guid_t	*port_guids;
3024 			uint8_t		portnum;
3025 
3026 			ASSERT(hca_list->hl_port_attr != NULL);
3027 
3028 			port_guids = kmem_zalloc(
3029 			    hca_list->hl_nports * sizeof (ib_guid_t),
3030 			    KM_SLEEP);
3031 
3032 			for (portnum = 0; portnum < hca_list->hl_nports;
3033 			    portnum++) {
3034 				port_guids[portnum] = (hca_list->
3035 				    hl_port_attr[portnum]).pa_port_guid;
3036 			}
3037 
3038 			if (ndi_prop_update_int64_array(DDI_DEV_T_NONE,
3039 			    child_dip, "port-guids", (int64_t *)port_guids,
3040 			    hca_list->hl_nports) != DDI_PROP_SUCCESS) {
3041 				IBTF_DPRINTF_L2("ibnex",
3042 				    "\tcreate_port_node_prop: port-guids "
3043 				    "create failed");
3044 				kmem_free(port_guids, hca_list->hl_nports *
3045 				    sizeof (ib_guid_t));
3046 				ibdm_ibnex_free_hca_list(hca_list);
3047 				return (IBNEX_FAILURE);
3048 			}
3049 			kmem_free(port_guids, hca_list->hl_nports *
3050 			    sizeof (ib_guid_t));
3051 		}
3052 
3053 		if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3054 			"num-ports", hca_list->hl_nports) != DDI_PROP_SUCCESS) {
3055 			IBTF_DPRINTF_L2("ibnex",
3056 			    "\tcreate_port_node_prop: num-ports update failed");
3057 			ibdm_ibnex_free_hca_list(hca_list);
3058 			return (IBNEX_FAILURE);
3059 		}
3060 		ibdm_ibnex_free_hca_list(hca_list);
3061 	}
3062 
3063 	if (ndi_prop_update_int64(DDI_DEV_T_NONE, child_dip,
3064 		"hca-guid", port_attr->pa_hca_guid) != DDI_PROP_SUCCESS) {
3065 		IBTF_DPRINTF_L2("ibnex",
3066 		    "\tcreate_port_node_prop: hca-guid update failed");
3067 		return (IBNEX_FAILURE);
3068 	}
3069 	if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3070 		"product-id", port_attr->pa_productid) != DDI_PROP_SUCCESS) {
3071 		IBTF_DPRINTF_L2("ibnex",
3072 		    "\tcreate_port_node_prop: product-id update failed");
3073 		return (IBNEX_FAILURE);
3074 	}
3075 	if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3076 		"vendor-id", port_attr->pa_vendorid) != DDI_PROP_SUCCESS) {
3077 		IBTF_DPRINTF_L2("ibnex",
3078 		    "\tcreate_port_node_prop: vendor-id update failed");
3079 		return (IBNEX_FAILURE);
3080 	}
3081 	if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip, "device-version",
3082 	    port_attr->pa_dev_version) != DDI_PROP_SUCCESS) {
3083 		IBTF_DPRINTF_L2("ibnex",
3084 		    "\tcreate_port_node_prop: device-version update failed");
3085 		return (IBNEX_FAILURE);
3086 	}
3087 	return (IBNEX_SUCCESS);
3088 }
3089 
3090 
3091 /*
3092  * ibnex_str2int()
3093  *	Utility function that converts a string of length  "len" to
3094  *	integer.
3095  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
3096  */
3097 static int
3098 ibnex_str2int(char *c, int len, int *ret)
3099 {
3100 	int intval = 0, ii;
3101 
3102 	IBTF_DPRINTF_L4("ibnex", "\tstr2int: Int string %s..", c);
3103 	*ret = IBNEX_SUCCESS;
3104 	for (ii = 0; ii < len; ii ++) {
3105 		if ((c[ii] >= '0') && (c[ii] <= '9'))
3106 			intval = intval * 10 +c[ii] - '0';
3107 		else {
3108 			IBTF_DPRINTF_L2("ibnex",
3109 			    "\tstr2int: Invalid integer string %s..", c);
3110 			*ret = IBNEX_FAILURE;
3111 			break;
3112 		}
3113 	}
3114 
3115 	return (intval);
3116 }
3117 
3118 
3119 /*
3120  * ibnex_str2hex()
3121  *	Utility functions that converts a string of length  "len" to
3122  *	hex value. Note. This function does not handle strings which
3123  *	string length more than 8 bytes.
3124  *
3125  */
3126 uint64_t
3127 ibnex_str2hex(char *c, int len, int *ret)
3128 {
3129 	uint64_t hex = 0, ii;
3130 
3131 	*ret = IBNEX_SUCCESS;
3132 	for (ii = 0; ii < len; ii ++) {
3133 		hex = (ii == 0) ? hex : (hex << 4);
3134 		if ((c[ii] >= '0') && (c[ii] <= '9'))
3135 			hex |= c[ii] - '0';
3136 		else if ((c[ii] >= 'a') && (c[ii] <= 'f'))
3137 			hex |= c[ii] - 'a' + 10;
3138 		else if ((c[ii] >= 'A') && (c[ii] <= 'F'))
3139 			hex |= c[ii] - 'A' + 10;
3140 		else {
3141 			IBTF_DPRINTF_L2("ibnex",
3142 			    "\tstr2hex: Invalid integer string");
3143 			*ret = IBNEX_FAILURE;
3144 			break;
3145 		}
3146 	}
3147 
3148 	return (hex);
3149 }
3150 
3151 
3152 /*
3153  * ibnex_create_port_compatible_prop()
3154  *	Creates 'Compatibility' property for port / HCA_SVC device nodes
3155  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
3156  */
3157 static int
3158 ibnex_create_port_compatible_prop(dev_info_t *child_dip,
3159     char *comm_svcp, ibdm_port_attr_t *port_attr)
3160 {
3161 	int 	rval, i;
3162 	char	*temp;
3163 	char	*compatible[IBNEX_MAX_IBPORT_COMPAT_NAMES];
3164 
3165 	IBTF_DPRINTF_L4("ibnex", "\tcreate_port_compatible_prop: Begin");
3166 	/*
3167 	 * Initialize the "compatible" property string as below:
3168 	 * Compatible Strings :
3169 	 * 1. ib.V<vid>P<pid>v<revision>.<service name>.
3170 	 * 2. ib.V<vid>P<pid>.<service name>.
3171 	 * 3. ib.<service name>
3172 	 * Leading zeros must be present
3173 	 */
3174 	temp = kmem_alloc(IBNEX_MAX_IBPORT_COMPAT_PROP_SZ, KM_SLEEP);
3175 	for (i = 0; i < IBNEX_MAX_IBPORT_COMPAT_NAMES; i++) {
3176 		compatible[i] = temp + (i * IBNEX_MAX_COMPAT_LEN);
3177 	}
3178 
3179 	(void) snprintf(compatible[0], IBNEX_MAX_COMPAT_LEN,
3180 	    "ib.V%06xP%08xv%04x.%s",
3181 	    port_attr->pa_vendorid, port_attr->pa_productid,
3182 	    port_attr->pa_dev_version, comm_svcp);
3183 	(void) snprintf(compatible[1], IBNEX_MAX_COMPAT_LEN,
3184 	    "ib.V%06xP%08x.%s",
3185 	    port_attr->pa_vendorid, port_attr->pa_productid,
3186 	    comm_svcp);
3187 	(void) snprintf(compatible[2], IBNEX_MAX_COMPAT_LEN,
3188 	    "ib.%s", comm_svcp);
3189 
3190 	for (i = 0; i < IBNEX_MAX_IBPORT_COMPAT_NAMES; i++)
3191 		IBTF_DPRINTF_L4("ibnex", "\tcompatible: %s", compatible[i]);
3192 
3193 	rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
3194 	    "compatible", (char **)compatible, IBNEX_MAX_IBPORT_COMPAT_NAMES);
3195 
3196 	if (rval != DDI_PROP_SUCCESS) {
3197 		kmem_free(temp, IBNEX_MAX_IBPORT_COMPAT_PROP_SZ);
3198 		return (IBNEX_FAILURE);
3199 	}
3200 	kmem_free(temp, IBNEX_MAX_IBPORT_COMPAT_PROP_SZ);
3201 	return (IBNEX_SUCCESS);
3202 }
3203 
3204 
3205 /*
3206  * ibnex_delete_port_node_data()
3207  *	Delete the parent private node data from the linked list
3208  *	Deallocate the memory of the port/ioc attributes
3209  *	Deallocate the memory of the node data
3210  */
3211 static void
3212 ibnex_delete_port_node_data(ibnex_node_data_t *node)
3213 {
3214 	mutex_enter(&ibnex.ibnex_mutex);
3215 	if ((node->node_next == NULL) && (node->node_prev == NULL))
3216 		ibnex.ibnex_port_node_head = NULL;
3217 	else if (node->node_next == NULL)
3218 		node->node_prev->node_next = NULL;
3219 	else if (node->node_prev == NULL) {
3220 		node->node_next->node_prev = NULL;
3221 		ibnex.ibnex_port_node_head = node->node_next;
3222 	} else {
3223 		node->node_prev->node_next = node->node_next;
3224 		node->node_next->node_prev = node->node_prev;
3225 	}
3226 	mutex_exit(&ibnex.ibnex_mutex);
3227 	kmem_free(node, sizeof (ibnex_node_data_t));
3228 }
3229 
3230 
3231 /*
3232  * ibnex_is_node_data_present()
3233  *	Checks whether ibnex_node_t is created already
3234  *	Returns ibnex_node_data_t if found, otherwise NULL
3235  */
3236 static ibnex_node_data_t *
3237 ibnex_is_node_data_present(ibnex_node_type_t node_type, void *attr,
3238     int index, ib_pkey_t pkey)
3239 {
3240 	ibnex_node_data_t	*nodep;
3241 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
3242 	if (node_type == IBNEX_IOC_NODE) {
3243 		ibdm_ioc_info_t *ioc_infop = (ibdm_ioc_info_t *)attr;
3244 
3245 		for (nodep = ibnex.ibnex_ioc_node_head; nodep != NULL;
3246 		    nodep = nodep->node_next) {
3247 			if (nodep->node_data.ioc_node.ioc_guid ==
3248 			    ioc_infop->ioc_profile.ioc_guid) {
3249 				return (nodep);
3250 			}
3251 		}
3252 
3253 	} else if (node_type == IBNEX_PSEUDO_NODE) {
3254 		for (nodep = ibnex.ibnex_pseudo_node_head; nodep;
3255 		    nodep = nodep->node_next)
3256 			if (strcmp(nodep->node_data.pseudo_node.
3257 			    pseudo_node_addr, (char *)attr) == 0)
3258 				return (nodep);
3259 
3260 	} else {
3261 		ibdm_port_attr_t *pattrp = (ibdm_port_attr_t *)attr;
3262 
3263 		for (nodep = ibnex.ibnex_port_node_head; nodep != NULL;
3264 		    nodep = nodep->node_next) {
3265 			if ((nodep->node_data.port_node.port_guid ==
3266 			    pattrp->pa_port_guid) &&
3267 			    (nodep->node_data.port_node.port_commsvc_idx ==
3268 			    index) &&
3269 			    (nodep->node_data.port_node.port_pkey == pkey)) {
3270 				return (nodep);
3271 			}
3272 		}
3273 	}
3274 	return (NULL);
3275 }
3276 
3277 /*
3278  * ibnex_lookup_unit_address_prop:
3279  *
3280  *	If "unit-address" property is found, return its value
3281  *	otherwise return NULL.
3282  */
3283 static char *
3284 ibnex_lookup_unit_address_prop(ddi_prop_t *head)
3285 {
3286 	ddi_prop_t	*propp;
3287 
3288 	/* Search the list of properties for "unit-address" */
3289 	for (propp = head; propp != NULL; propp = propp->prop_next)  {
3290 		if (strcmp(propp->prop_name, "unit-address") != 0)
3291 			continue;
3292 		/* "unit-address" property should be valid and have a value */
3293 		if (propp->prop_len <= 1)
3294 			break;
3295 		return ((char *)propp->prop_val);
3296 	}
3297 
3298 	return ((char *)0);
3299 }
3300 
3301 
3302 /*
3303  * ibnex_pseudo_initnodes()
3304  *	This routine is specific to pseudo node information handling
3305  *	Creates a ibnex_node_data_t all pseudo nodes children of ibnex
3306  */
3307 void
3308 ibnex_pseudo_initnodes()
3309 {
3310 	int			pnam_len, len;
3311 	ibnex_node_data_t	*nodep;
3312 	struct hwc_spec		*list, *spec;
3313 	char			*node_addr, *temp, *unit_addr;
3314 
3315 	IBTF_DPRINTF_L4("ibnex", "\tpseudo_initnodes");
3316 
3317 	mutex_enter(&ibnex.ibnex_mutex);
3318 	/*
3319 	 * get a list of all "pseudo" children of "ib".
3320 	 * for these children initialize/allocate an internal
3321 	 * ibnex_node_data_t.
3322 	 */
3323 	list = hwc_get_child_spec(ibnex.ibnex_dip, (major_t)-1);
3324 	for (spec = list; spec != NULL; spec = spec->hwc_next) {
3325 		if (spec->hwc_devi_sys_prop_ptr == NULL)
3326 			continue;
3327 
3328 		/* "unit-address" property should be present */
3329 		temp = ibnex_lookup_unit_address_prop(
3330 		    spec->hwc_devi_sys_prop_ptr);
3331 		if (temp == NULL)
3332 			continue;
3333 
3334 		pnam_len = strlen(spec->hwc_devi_name) + strlen(temp) + 2;
3335 
3336 		node_addr = kmem_zalloc(pnam_len, KM_SLEEP);
3337 
3338 		(void) snprintf(node_addr,
3339 		    pnam_len, "%s,%s", spec->hwc_devi_name, temp);
3340 
3341 		nodep = ibnex_is_node_data_present(
3342 		    IBNEX_PSEUDO_NODE, (void *)node_addr, 0, 0);
3343 
3344 		if (nodep) {
3345 			kmem_free(node_addr, pnam_len);
3346 			continue;
3347 		}
3348 
3349 		nodep = ibnex_init_child_nodedata(IBNEX_PSEUDO_NODE,
3350 		    (void *)spec->hwc_devi_name, 0, 0);
3351 
3352 		nodep->node_data.pseudo_node.pseudo_node_addr = node_addr;
3353 		(void) snprintf(nodep->node_data.
3354 		    pseudo_node.pseudo_node_addr, pnam_len, "%s", node_addr);
3355 
3356 		len = strlen(temp) + 1;
3357 		unit_addr = (char *)kmem_alloc(len, KM_SLEEP);
3358 		nodep->node_data.pseudo_node.pseudo_unit_addr = unit_addr;
3359 		(void) snprintf(unit_addr, len, "%s", temp);
3360 		nodep->node_data.pseudo_node.pseudo_unit_addr_len = len;
3361 
3362 		/* Mark this as a new psuedo node */
3363 		nodep->node_data.pseudo_node.pseudo_new_node = 1;
3364 
3365 		IBTF_DPRINTF_L3("ibnex", "\tpseudo_initnodes: unit addr = %s"
3366 		    " : drv name = %s", unit_addr, spec->hwc_devi_name);
3367 	}
3368 	hwc_free_spec_list(list);
3369 	mutex_exit(&ibnex.ibnex_mutex);
3370 }
3371 
3372 
3373 /*
3374  * ibnex_init_child_nodedata()
3375  *
3376  *	Allocate memory for the parent private data for device node
3377  *	Initializes the parent private child device node data.
3378  *	Returns pointer to the parent private data
3379  */
3380 static ibnex_node_data_t *
3381 ibnex_init_child_nodedata(ibnex_node_type_t node_type, void *attr, int index,
3382     ib_pkey_t pkey)
3383 {
3384 	char			 *devi_name;
3385 	ibdm_ioc_info_t		 *ioc_info;
3386 	ibnex_ioc_node_t	 *ioc_node;
3387 	ibnex_node_data_t	 *node_data;
3388 	ib_dm_ioc_ctrl_profile_t *ioc_profile;
3389 
3390 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
3391 
3392 	node_data = kmem_zalloc(sizeof (ibnex_node_data_t), KM_SLEEP);
3393 	node_data->node_state = IBNEX_CFGADM_CONFIGURING;
3394 	node_data->node_type	= node_type;
3395 
3396 	if (node_type == IBNEX_IOC_NODE) {
3397 		ioc_info	= (ibdm_ioc_info_t *)attr;
3398 		ioc_profile	= &ioc_info->ioc_profile;
3399 		ioc_node	= &node_data->node_data.ioc_node;
3400 
3401 		ioc_node->iou_guid = ioc_info->ioc_iou_guid;
3402 		ioc_node->ioc_guid = ioc_profile->ioc_guid;
3403 		(void) strncpy(ioc_node->ioc_id_string,
3404 		    (char *)ioc_profile->ioc_id_string,
3405 		    IB_DM_IOC_ID_STRING_LEN);
3406 		ioc_node->ioc_ngids = ioc_info->ioc_nportgids;
3407 
3408 		node_data->node_next = ibnex.ibnex_ioc_node_head;
3409 		node_data->node_prev = NULL;
3410 		if (ibnex.ibnex_ioc_node_head)
3411 			ibnex.ibnex_ioc_node_head->node_prev = node_data;
3412 		ibnex.ibnex_ioc_node_head = node_data;
3413 	} else if (node_type == IBNEX_PSEUDO_NODE) {
3414 		devi_name = (char *)attr;
3415 		node_data->node_data.pseudo_node.pseudo_devi_name =
3416 		    kmem_zalloc(strlen(devi_name) + 1, KM_SLEEP);
3417 		(void) strncpy(node_data->node_data.pseudo_node.
3418 		    pseudo_devi_name, devi_name, strlen(devi_name));
3419 		node_data->node_next = ibnex.ibnex_pseudo_node_head;
3420 		node_data->node_prev = NULL;
3421 		if (ibnex.ibnex_pseudo_node_head)
3422 			ibnex.ibnex_pseudo_node_head->node_prev = node_data;
3423 		ibnex.ibnex_pseudo_node_head = node_data;
3424 	} else {
3425 		node_data->node_data.port_node.port_hcaguid =
3426 		    ((ibdm_port_attr_t *)attr)->pa_hca_guid;
3427 		node_data->node_data.port_node.port_guid =
3428 		    ((ibdm_port_attr_t *)attr)->pa_port_guid;
3429 		node_data->node_data.port_node.port_num =
3430 		    ((ibdm_port_attr_t *)attr)->pa_port_num;
3431 		node_data->node_data.port_node.port_commsvc_idx = index;
3432 		node_data->node_data.port_node.port_pkey = pkey;
3433 
3434 		node_data->node_next = ibnex.ibnex_port_node_head;
3435 		node_data->node_prev = NULL;
3436 		if (ibnex.ibnex_port_node_head)
3437 			ibnex.ibnex_port_node_head->node_prev = node_data;
3438 		ibnex.ibnex_port_node_head = node_data;
3439 	}
3440 	return (node_data);
3441 }
3442 
3443 static int
3444 ibnex_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
3445     char *eventname, ddi_eventcookie_t *cookie)
3446 {
3447 	int rc;
3448 
3449 
3450 	IBTF_DPRINTF_L4("ibnex", "ibnex_get_eventcookie(%p, %p, %s, 0x%X)",
3451 	    dip, rdip, eventname, cookie);
3452 
3453 	rc = ndi_event_retrieve_cookie(ibnex.ibnex_ndi_event_hdl,
3454 	    rdip, eventname, cookie, NDI_EVENT_NOPASS);
3455 	if (rc == NDI_SUCCESS) {
3456 		mutex_enter(&ibnex.ibnex_mutex);
3457 		ibnex.ibnex_prop_update_evt_cookie = *cookie;
3458 		mutex_exit(&ibnex.ibnex_mutex);
3459 	}
3460 
3461 	return (rc);
3462 }
3463 
3464 static int
3465 ibnex_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
3466     ddi_eventcookie_t cookie, void (*callback)(dev_info_t *dip,
3467     ddi_eventcookie_t cookie, void *arg, void *bus_impldata),
3468     void *arg, ddi_callback_id_t *cb_id)
3469 {
3470 	IBTF_DPRINTF_L4("ibnex",
3471 	    "ibnex_add_eventcall(%p, %p, 0x%X, %p, %p, %p)",
3472 	    dip, rdip, cookie, callback, arg, cb_id);
3473 
3474 	return (ndi_event_add_callback(ibnex.ibnex_ndi_event_hdl,
3475 	    rdip, cookie, callback, arg, NDI_SLEEP, cb_id));
3476 }
3477 
3478 static int
3479 ibnex_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
3480 {
3481 	IBTF_DPRINTF_L4("ibnex", "ibnex_remove_eventcall(%p, 0x%X)",
3482 	    dip, cb_id);
3483 
3484 	return (ndi_event_remove_callback(ibnex.ibnex_ndi_event_hdl,
3485 	    cb_id));
3486 }
3487 
3488 static int
3489 ibnex_post_event(dev_info_t *dip, dev_info_t *rdip,
3490     ddi_eventcookie_t cookie, void *bus_impldata)
3491 {
3492 	IBTF_DPRINTF_L4("ibnex", "ibnex_post_event(%p, %p, 0x%X, %p)",
3493 	    dip, rdip, cookie, bus_impldata);
3494 
3495 	return (ndi_event_run_callbacks(ibnex.ibnex_ndi_event_hdl, rdip,
3496 	    cookie, bus_impldata));
3497 }
3498 
3499 /*
3500  * ibnex_reprobe_ioc_dev()
3501  *
3502  * This could be called as a result of ibt_reprobe_dev request or
3503  * cfgadm command. The function is called from a taskq in case of
3504  * ibt_reprobe_dev and from user context for cfgadm command.
3505  *
3506  * This function reprobes the properties for one IOC dip.
3507  *
3508  * node_reprobe_state should be set before calling this function.
3509  */
3510 void
3511 ibnex_reprobe_ioc_dev(void *arg)
3512 {
3513 	dev_info_t	*dip = (dev_info_t *)arg;
3514 	ibnex_node_data_t	*node_data;
3515 	ibnex_ioc_node_t	*ioc_data;
3516 	ibdm_ioc_info_t		*ioc_info;
3517 
3518 	/* ASSERT(NO_LOCKS_HELD); */
3519 	ASSERT(dip != NULL);
3520 
3521 	node_data = ddi_get_parent_data(dip);
3522 	ASSERT(node_data);
3523 
3524 	if (node_data->node_dip == NULL) {
3525 		IBTF_DPRINTF_L4("ibnex", "reprobe for unconfigured dip");
3526 		mutex_enter(&ibnex.ibnex_mutex);
3527 		ibnex_wakeup_reprobe_ioc(node_data, 0);
3528 		mutex_exit(&ibnex.ibnex_mutex);
3529 		return;
3530 	}
3531 	ioc_data = &(node_data->node_data.ioc_node);
3532 
3533 	/* Reprobe the IOC */
3534 	ioc_info = ibdm_ibnex_probe_ioc(ioc_data->iou_guid, ioc_data->ioc_guid,
3535 	    1);
3536 	if (ioc_info == NULL) {
3537 		IBTF_DPRINTF_L2("ibnex", "Null ioc_info from reprobe");
3538 		mutex_enter(&ibnex.ibnex_mutex);
3539 		ibnex_wakeup_reprobe_ioc(node_data, 1);
3540 		mutex_exit(&ibnex.ibnex_mutex);
3541 		return;
3542 	}
3543 
3544 	mutex_enter(&ibnex.ibnex_mutex);
3545 	if (node_data->node_dip)
3546 		ibnex_update_prop(node_data, ioc_info);
3547 	ibnex_wakeup_reprobe_ioc(node_data, 0);
3548 	mutex_exit(&ibnex.ibnex_mutex);
3549 
3550 	ibdm_ibnex_free_ioc_list(ioc_info);
3551 }
3552 
3553 /*
3554  * ibnex_reprobe_all()
3555  *
3556  * This could be called as a result of cfgadm command. The function
3557  * is called from user context.
3558  *
3559  * This function reprobes the properties for all IOC dips.
3560  *
3561  * ibnex_reprobe_state should be set before calling this function.
3562  */
3563 void
3564 ibnex_reprobe_ioc_all()
3565 {
3566 	ibnex_node_data_t	*node_data;
3567 	ibdm_ioc_info_t		*ioc_info_list, *ioc;
3568 
3569 	/* ASSERT(NO_LOCKS_HELD); */
3570 
3571 	/* Sweep the fabric */
3572 	ioc = ioc_info_list = ibdm_ibnex_get_ioc_list(
3573 	    IBDM_IBNEX_REPROBE_ALL);
3574 	if (ioc_info_list == NULL) {
3575 		mutex_enter(&ibnex.ibnex_mutex);
3576 		ibnex_wakeup_reprobe_all();
3577 		mutex_exit(&ibnex.ibnex_mutex);
3578 		return;
3579 	}
3580 
3581 	mutex_enter(&ibnex.ibnex_mutex);
3582 	while (ioc_info_list) {
3583 		if ((node_data = ibnex_is_node_data_present(IBNEX_IOC_NODE,
3584 		    ioc_info_list, 0, 0)) != NULL &&
3585 		    node_data->node_dip != NULL) {
3586 			ibnex_update_prop(node_data, ioc_info_list);
3587 		}
3588 		ioc_info_list = ioc_info_list->ioc_next;
3589 	}
3590 	ibnex_wakeup_reprobe_all();
3591 	mutex_exit(&ibnex.ibnex_mutex);
3592 
3593 	ibdm_ibnex_free_ioc_list(ioc);
3594 }
3595 
3596 /*
3597  * Update the properties, if it has modified and notify IBTF client.
3598  */
3599 static void
3600 ibnex_update_prop(ibnex_node_data_t *node_data, ibdm_ioc_info_t *ioc_info)
3601 {
3602 	ibt_prop_update_payload_t	evt_data;
3603 	dev_info_t	*dip = node_data->node_dip;
3604 	ddi_eventcookie_t	evt_cookie;
3605 	ibnex_ioc_node_t *ioc;
3606 
3607 	ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
3608 
3609 	ASSERT(dip != NULL);
3610 
3611 	ioc = &node_data->node_data.ioc_node;
3612 
3613 	evt_data = ioc_info->ioc_info_updated;
3614 	evt_cookie = ibnex.ibnex_prop_update_evt_cookie;
3615 
3616 	/*
3617 	 * For a disconnected IOC :
3618 	 *	Store the ioc_profile for supplying cfgadm info
3619 	 *	ibdm maintains no info of disconnected IOC
3620 	 *
3621 	 * For reconnected IOC :
3622 	 *	ibdm has info of previous service entries
3623 	 *	ioc_profile maintained by ibnexus is used to
3624 	 *	update ib_srv_prop_updated.
3625 	 *	Free the ibnex maintained ioc_profile
3626 	 */
3627 	if (ioc_info->ioc_nportgids == 0) {
3628 		IBTF_DPRINTF_L4("ibnex",
3629 		    "\tupdate_prop:  IOC disconnected");
3630 		ioc->ioc_profile = (ib_dm_ioc_ctrl_profile_t *)kmem_zalloc(
3631 		    sizeof (ib_dm_ioc_ctrl_profile_t), KM_SLEEP);
3632 		bcopy(&ioc_info->ioc_profile, ioc->ioc_profile,
3633 		    sizeof (ib_dm_ioc_ctrl_profile_t));
3634 
3635 		ibnex.ibnex_num_disconnect_iocs++;
3636 	} else if (ioc_info->ioc_nportgids != 0 && ioc->ioc_ngids == 0 &&
3637 	    ioc->ioc_profile != NULL) {
3638 		IBTF_DPRINTF_L4("ibnex",
3639 		    "\tupdate_prop: IOC reconnected");
3640 		if (ioc->ioc_profile->ioc_service_entries !=
3641 		    ioc_info->ioc_profile.ioc_service_entries)
3642 			evt_data.ib_srv_prop_updated = 1;
3643 
3644 		ibnex.ibnex_num_disconnect_iocs--;
3645 		kmem_free(ioc->ioc_profile, sizeof (ib_dm_ioc_ctrl_profile_t));
3646 		ioc->ioc_profile = NULL;
3647 	}
3648 
3649 	/* Update the properties that have changed */
3650 	mutex_exit(&ibnex.ibnex_mutex);
3651 	if (evt_data.ib_gid_prop_updated) {
3652 		if (ibnex_create_ioc_portgid_prop(dip, ioc_info) !=
3653 		    IBNEX_SUCCESS) {
3654 			mutex_enter(&ibnex.ibnex_mutex);
3655 			return;
3656 		}
3657 	}
3658 	if (evt_data.ib_srv_prop_updated) {
3659 		if (ioc_info->ioc_profile.ioc_service_entries != 0 &&
3660 		    (ibnex_create_ioc_srv_props(dip, ioc_info) !=
3661 		    IBNEX_SUCCESS)) {
3662 			mutex_enter(&ibnex.ibnex_mutex);
3663 			return;
3664 		} else if (ioc_info->ioc_profile.ioc_service_entries == 0) {
3665 			(void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
3666 			    "service-id");
3667 			(void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
3668 			    "service-name");
3669 		}
3670 	}
3671 	mutex_enter(&ibnex.ibnex_mutex);
3672 	ioc->ioc_ngids = ioc_info->ioc_nportgids;
3673 
3674 	/*
3675 	 * Post an event if :
3676 	 *	1. Properites have changed or NOTIFY_ALWAYS is set.
3677 	 *	2. child dip is configured and a valid cookie for
3678 	 *	   IB_PROP_UPDATE_EVENT.
3679 	 */
3680 	if ((evt_data.ib_prop_updated != 0 ||
3681 	    (node_data->node_reprobe_state &
3682 	    IBNEX_NODE_REPROBE_NOTIFY_ALWAYS)) &&
3683 	    ((node_data->node_state == IBNEX_CFGADM_CONFIGURED) &&
3684 		    (evt_cookie != NULL))) {
3685 			mutex_exit(&ibnex.ibnex_mutex);
3686 
3687 			if (ndi_post_event(ibnex.ibnex_dip, dip,
3688 			    evt_cookie, &evt_data) != NDI_SUCCESS)
3689 				IBTF_DPRINTF_L2("ibnex",
3690 				    "\tndi_post_event failed\n");
3691 
3692 			mutex_enter(&ibnex.ibnex_mutex);
3693 	}
3694 
3695 	/*
3696 	 * Cleanup node_reprobe_state, for ibt_reprobe_dev
3697 	 * requests, when reprobe all / node reprobe is in
3698 	 * progress. ibnex_reprobe_ioc_dev is not called
3699 	 * in this case.
3700 	 */
3701 	if (node_data->node_reprobe_state ==
3702 	    IBNEX_NODE_REPROBE_NOTIFY_ALWAYS)
3703 		ibnex_wakeup_reprobe_ioc(node_data, 0);
3704 }
3705 
3706 static ibnex_rval_t
3707 ibnex_unique_svcname(char *svcname)
3708 {
3709 	int i;
3710 
3711 	/* Check Port Services */
3712 	for (i = 0; i < ibnex.ibnex_num_comm_svcs; i++)
3713 		if (ibnex.ibnex_comm_svc_names[i] && strncmp(svcname,
3714 		    ibnex.ibnex_comm_svc_names[i], 4) == 0)
3715 			return (IBNEX_FAILURE);
3716 
3717 	/* Check VPPA Services */
3718 	for (i = 0; i < ibnex.ibnex_nvppa_comm_svcs; i++)
3719 		if (ibnex.ibnex_vppa_comm_svc_names[i] && strncmp(svcname,
3720 		    ibnex.ibnex_vppa_comm_svc_names[i], 4) == 0)
3721 			return (IBNEX_FAILURE);
3722 
3723 	/* Check HCA_SVC Services */
3724 	for (i = 0; i < ibnex.ibnex_nhcasvc_comm_svcs; i++)
3725 		if (ibnex.ibnex_hcasvc_comm_svc_names[i] && strncmp(svcname,
3726 		    ibnex.ibnex_hcasvc_comm_svc_names[i], 4) == 0)
3727 			return (IBNEX_FAILURE);
3728 
3729 	return (IBNEX_SUCCESS);
3730 }
3731 
3732 static void
3733 ibnex_handle_reprobe_dev(void *arg)
3734 {
3735 	dev_info_t	*dip = (dev_info_t *)arg;
3736 	ibnex_node_data_t	*node_data;
3737 
3738 	ASSERT(dip != NULL);
3739 	node_data = ddi_get_parent_data(dip);
3740 	ASSERT(node_data);
3741 
3742 	/*
3743 	 * Return success if:
3744 	 *	1. Reprobe for all nodes are in progress
3745 	 *	2. Reprobe for this node is in progress.
3746 	 * The reprobe in progress will complete eventually and
3747 	 * update the properties, if required.
3748 	 */
3749 	mutex_enter(&ibnex.ibnex_mutex);
3750 	if (ibnex.ibnex_reprobe_state != 0 ||
3751 	    node_data->node_reprobe_state != 0) {
3752 		/*
3753 		 * Setting NOTIFY_ALWAYS to ensure that
3754 		 * DDI event is delivered always for
3755 		 * ibt_reprobe_dev
3756 		 */
3757 		node_data->node_reprobe_state |=
3758 		    IBNEX_NODE_REPROBE_NOTIFY_ALWAYS;
3759 		mutex_exit(&ibnex.ibnex_mutex);
3760 		return;
3761 	}
3762 	node_data->node_reprobe_state =
3763 	    IBNEX_NODE_REPROBE_NOTIFY_ALWAYS;
3764 	mutex_exit(&ibnex.ibnex_mutex);
3765 	ibnex_reprobe_ioc_dev(arg);
3766 }
3767 
3768 
3769 /*
3770  * MPxIO pathmangement routines. Currently IB nexus does not support
3771  * any kind of pathmangement. So, just return success to make MPxIO
3772  * framework happy.
3773  */
3774 /*ARGSUSED*/
3775 static int
3776 ib_vhci_pi_init(dev_info_t *dip, mdi_pathinfo_t *pip, int flag)
3777 {
3778 	IBTF_DPRINTF_L4("ibnex", "\tpi_init: dip %p pip %p", dip, pip);
3779 	return (MDI_SUCCESS);
3780 }
3781 
3782 
3783 /*ARGSUSED*/
3784 static int
3785 ib_vhci_pi_uninit(dev_info_t *dip, mdi_pathinfo_t *pip, int flag)
3786 {
3787 	IBTF_DPRINTF_L4("ibnex", "\tpi_uninit: dip %p pip %p", dip, pip);
3788 	return (MDI_SUCCESS);
3789 }
3790 
3791 
3792 /*ARGSUSED*/
3793 static int
3794 ib_vhci_pi_state_change(dev_info_t *dip, mdi_pathinfo_t *pip,
3795 		mdi_pathinfo_state_t state, uint32_t arg1, int arg2)
3796 {
3797 	IBTF_DPRINTF_L4("ibnex",
3798 	    "\tpi_state_change: dip %p pip %p state %x", dip, pip, state);
3799 	return (MDI_SUCCESS);
3800 }
3801 
3802 
3803 /*ARGSUSED*/
3804 static int
3805 ib_vhci_failover(dev_info_t *dip1, dev_info_t *dip2, int arg)
3806 {
3807 	return (MDI_SUCCESS);
3808 }
3809 
3810 
3811 static int
3812 ibnex_bus_power(dev_info_t *parent, void *impl_arg,
3813     pm_bus_power_op_t op, void *arg, void *result)
3814 {
3815 
3816 	int ret = DDI_SUCCESS;
3817 
3818 	IBTF_DPRINTF_L4("ibnex", "\tbus_power: begin: op = %d", op);
3819 
3820 	/*
3821 	 * Generic processing in MPxIO framework
3822 	 */
3823 	ret = mdi_bus_power(parent, impl_arg, op, arg, result);
3824 
3825 	switch (ret) {
3826 	case MDI_SUCCESS:
3827 		ret = DDI_SUCCESS;
3828 		break;
3829 	case MDI_FAILURE:
3830 		ret = DDI_FAILURE;
3831 		break;
3832 	default:
3833 		break;
3834 	}
3835 
3836 	return (ret);
3837 }
3838