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