xref: /titanic_53/usr/src/uts/common/io/tvhci.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * The tvhci driver can be used to exercise the mpxio framework together
31*7c478bd9Sstevel@tonic-gate  * with tphci/tclient.
32*7c478bd9Sstevel@tonic-gate  */
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/scsi/impl/scsi_reset_notify.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/mdi_impldefs.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/disp.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate /* cb_ops entry points */
45*7c478bd9Sstevel@tonic-gate static int tvhci_open(dev_t *, int, int, cred_t *);
46*7c478bd9Sstevel@tonic-gate static int tvhci_close(dev_t, int, int, cred_t *);
47*7c478bd9Sstevel@tonic-gate static int tvhci_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
48*7c478bd9Sstevel@tonic-gate static int tvhci_attach(dev_info_t *, ddi_attach_cmd_t);
49*7c478bd9Sstevel@tonic-gate static int tvhci_detach(dev_info_t *, ddi_detach_cmd_t);
50*7c478bd9Sstevel@tonic-gate static int tvhci_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate /* bus_ops entry points */
53*7c478bd9Sstevel@tonic-gate static int tvhci_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
54*7c478bd9Sstevel@tonic-gate     void *);
55*7c478bd9Sstevel@tonic-gate static int tvhci_initchild(dev_info_t *, dev_info_t *);
56*7c478bd9Sstevel@tonic-gate static int tvhci_uninitchild(dev_info_t *, dev_info_t *);
57*7c478bd9Sstevel@tonic-gate static int tvhci_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t, void *,
58*7c478bd9Sstevel@tonic-gate     dev_info_t **);
59*7c478bd9Sstevel@tonic-gate static int tvhci_bus_unconfig(dev_info_t *, uint_t, ddi_bus_config_op_t,
60*7c478bd9Sstevel@tonic-gate     void *);
61*7c478bd9Sstevel@tonic-gate static int tvhci_intr_op(dev_info_t *dip, dev_info_t *rdip,
62*7c478bd9Sstevel@tonic-gate     ddi_intr_op_t op, ddi_intr_handle_impl_t *hdlp, void *result);
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate /* vhci ops */
65*7c478bd9Sstevel@tonic-gate static int tvhci_pi_init(dev_info_t *, mdi_pathinfo_t *, int);
66*7c478bd9Sstevel@tonic-gate static int tvhci_pi_uninit(dev_info_t *, mdi_pathinfo_t *, int);
67*7c478bd9Sstevel@tonic-gate static int tvhci_pi_state_change(dev_info_t *, mdi_pathinfo_t *,
68*7c478bd9Sstevel@tonic-gate     mdi_pathinfo_state_t, uint32_t, int);
69*7c478bd9Sstevel@tonic-gate static int tvhci_failover(dev_info_t *, dev_info_t *, int);
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate static void *tvhci_state;
72*7c478bd9Sstevel@tonic-gate struct tvhci_state {
73*7c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
74*7c478bd9Sstevel@tonic-gate };
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate static mdi_vhci_ops_t tvhci_opinfo = {
77*7c478bd9Sstevel@tonic-gate 	MDI_VHCI_OPS_REV,
78*7c478bd9Sstevel@tonic-gate 	tvhci_pi_init,
79*7c478bd9Sstevel@tonic-gate 	tvhci_pi_uninit,
80*7c478bd9Sstevel@tonic-gate 	tvhci_pi_state_change,
81*7c478bd9Sstevel@tonic-gate 	tvhci_failover
82*7c478bd9Sstevel@tonic-gate };
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate static struct cb_ops tvhci_cb_ops = {
85*7c478bd9Sstevel@tonic-gate 	tvhci_open,			/* open */
86*7c478bd9Sstevel@tonic-gate 	tvhci_close,			/* close */
87*7c478bd9Sstevel@tonic-gate 	nodev,				/* strategy */
88*7c478bd9Sstevel@tonic-gate 	nodev,				/* print */
89*7c478bd9Sstevel@tonic-gate 	nodev,				/* dump */
90*7c478bd9Sstevel@tonic-gate 	nodev,				/* read */
91*7c478bd9Sstevel@tonic-gate 	nodev,				/* write */
92*7c478bd9Sstevel@tonic-gate 	tvhci_ioctl,			/* ioctl */
93*7c478bd9Sstevel@tonic-gate 	nodev,				/* devmap */
94*7c478bd9Sstevel@tonic-gate 	nodev,				/* mmap */
95*7c478bd9Sstevel@tonic-gate 	nodev,				/* segmap */
96*7c478bd9Sstevel@tonic-gate 	nochpoll,			/* chpoll */
97*7c478bd9Sstevel@tonic-gate 	ddi_prop_op,			/* cb_prop_op */
98*7c478bd9Sstevel@tonic-gate 	0,				/* streamtab */
99*7c478bd9Sstevel@tonic-gate 	D_NEW | D_MP,			/* cb_flag */
100*7c478bd9Sstevel@tonic-gate 	CB_REV,				/* rev */
101*7c478bd9Sstevel@tonic-gate 	nodev,				/* aread */
102*7c478bd9Sstevel@tonic-gate 	nodev				/* awrite */
103*7c478bd9Sstevel@tonic-gate };
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate static struct bus_ops tvhci_bus_ops = {
106*7c478bd9Sstevel@tonic-gate 	BUSO_REV,			/* busops_rev */
107*7c478bd9Sstevel@tonic-gate 	nullbusmap,			/* bus_map */
108*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_get_intrspec */
109*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_add_interspec */
110*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_remove_interspec */
111*7c478bd9Sstevel@tonic-gate 	i_ddi_map_fault,		/* bus_map_fault */
112*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_map,			/* bus_dma_map */
113*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_allochdl,		/* bus_dma_allochdl */
114*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_dma_freehdl */
115*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_dma_bindhdl */
116*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_dma_unbindhdl */
117*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_dma_flush */
118*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_dma_win */
119*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_dma_ctl */
120*7c478bd9Sstevel@tonic-gate 	tvhci_ctl,			/* bus_ctl */
121*7c478bd9Sstevel@tonic-gate 	ddi_bus_prop_op,		/* bus_prop_op */
122*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_get_eventcookie */
123*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_add_eventcall */
124*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_remove_event */
125*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_post_event */
126*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_intr_ctl */
127*7c478bd9Sstevel@tonic-gate 	tvhci_bus_config,		/* bus_config */
128*7c478bd9Sstevel@tonic-gate 	tvhci_bus_unconfig,		/* bus_unconfig */
129*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_init */
130*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_fini */
131*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_access_enter */
132*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_access_exit */
133*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_power */
134*7c478bd9Sstevel@tonic-gate 	tvhci_intr_op			/* bus_intr_op */
135*7c478bd9Sstevel@tonic-gate };
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate static struct dev_ops tvhci_ops = {
138*7c478bd9Sstevel@tonic-gate 	DEVO_REV,
139*7c478bd9Sstevel@tonic-gate 	0,
140*7c478bd9Sstevel@tonic-gate 	tvhci_getinfo,
141*7c478bd9Sstevel@tonic-gate 	nulldev,		/* identify */
142*7c478bd9Sstevel@tonic-gate 	nulldev,		/* probe */
143*7c478bd9Sstevel@tonic-gate 	tvhci_attach,		/* attach and detach are mandatory */
144*7c478bd9Sstevel@tonic-gate 	tvhci_detach,
145*7c478bd9Sstevel@tonic-gate 	nodev,			/* reset */
146*7c478bd9Sstevel@tonic-gate 	&tvhci_cb_ops,		/* cb_ops */
147*7c478bd9Sstevel@tonic-gate 	&tvhci_bus_ops,		/* bus_ops */
148*7c478bd9Sstevel@tonic-gate 	NULL,			/* power */
149*7c478bd9Sstevel@tonic-gate };
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops;
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
154*7c478bd9Sstevel@tonic-gate 	&mod_driverops,
155*7c478bd9Sstevel@tonic-gate 	"test vhci driver %I%",
156*7c478bd9Sstevel@tonic-gate 	&tvhci_ops
157*7c478bd9Sstevel@tonic-gate };
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
160*7c478bd9Sstevel@tonic-gate 	MODREV_1,
161*7c478bd9Sstevel@tonic-gate 	&modldrv,
162*7c478bd9Sstevel@tonic-gate 	NULL
163*7c478bd9Sstevel@tonic-gate };
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate int
166*7c478bd9Sstevel@tonic-gate _init(void)
167*7c478bd9Sstevel@tonic-gate {
168*7c478bd9Sstevel@tonic-gate 	int rval;
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	if ((rval = ddi_soft_state_init(&tvhci_state,
171*7c478bd9Sstevel@tonic-gate 	    sizeof (struct tvhci_state), 2)) != 0) {
172*7c478bd9Sstevel@tonic-gate 		return (rval);
173*7c478bd9Sstevel@tonic-gate 	}
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	if ((rval = mod_install(&modlinkage)) != 0) {
176*7c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&tvhci_state);
177*7c478bd9Sstevel@tonic-gate 	}
178*7c478bd9Sstevel@tonic-gate 	return (rval);
179*7c478bd9Sstevel@tonic-gate }
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate int
183*7c478bd9Sstevel@tonic-gate _fini(void)
184*7c478bd9Sstevel@tonic-gate {
185*7c478bd9Sstevel@tonic-gate 	int rval;
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 	/*
188*7c478bd9Sstevel@tonic-gate 	 * don't start cleaning up until we know that the module remove
189*7c478bd9Sstevel@tonic-gate 	 * has worked  -- if this works, then we know that each instance
190*7c478bd9Sstevel@tonic-gate 	 * has successfully been detached
191*7c478bd9Sstevel@tonic-gate 	 */
192*7c478bd9Sstevel@tonic-gate 	if ((rval = mod_remove(&modlinkage)) != 0) {
193*7c478bd9Sstevel@tonic-gate 		return (rval);
194*7c478bd9Sstevel@tonic-gate 	}
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&tvhci_state);
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	return (rval);
199*7c478bd9Sstevel@tonic-gate }
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate int
202*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
203*7c478bd9Sstevel@tonic-gate {
204*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
205*7c478bd9Sstevel@tonic-gate }
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
208*7c478bd9Sstevel@tonic-gate static int
209*7c478bd9Sstevel@tonic-gate tvhci_open(dev_t *devp, int flag, int otype, cred_t *credp)
210*7c478bd9Sstevel@tonic-gate {
211*7c478bd9Sstevel@tonic-gate 	struct tvhci_state *vhci;
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	if (otype != OTYP_CHR) {
214*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
215*7c478bd9Sstevel@tonic-gate 	}
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	vhci = ddi_get_soft_state(tvhci_state, getminor(*devp));
218*7c478bd9Sstevel@tonic-gate 	if (vhci == NULL) {
219*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
220*7c478bd9Sstevel@tonic-gate 	}
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	return (0);
223*7c478bd9Sstevel@tonic-gate }
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
227*7c478bd9Sstevel@tonic-gate static int
228*7c478bd9Sstevel@tonic-gate tvhci_close(dev_t dev, int flag, int otype, cred_t *credp)
229*7c478bd9Sstevel@tonic-gate {
230*7c478bd9Sstevel@tonic-gate 	struct tvhci_state *vhci;
231*7c478bd9Sstevel@tonic-gate 	if (otype != OTYP_CHR) {
232*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
233*7c478bd9Sstevel@tonic-gate 	}
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	vhci = ddi_get_soft_state(tvhci_state, getminor(dev));
236*7c478bd9Sstevel@tonic-gate 	if (vhci == NULL) {
237*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
238*7c478bd9Sstevel@tonic-gate 	}
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	return (0);
241*7c478bd9Sstevel@tonic-gate }
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
244*7c478bd9Sstevel@tonic-gate static int
245*7c478bd9Sstevel@tonic-gate tvhci_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
246*7c478bd9Sstevel@tonic-gate 	cred_t *credp, int *rval)
247*7c478bd9Sstevel@tonic-gate {
248*7c478bd9Sstevel@tonic-gate 	return (0);
249*7c478bd9Sstevel@tonic-gate }
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate /*
252*7c478bd9Sstevel@tonic-gate  * attach the module
253*7c478bd9Sstevel@tonic-gate  */
254*7c478bd9Sstevel@tonic-gate static int
255*7c478bd9Sstevel@tonic-gate tvhci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
256*7c478bd9Sstevel@tonic-gate {
257*7c478bd9Sstevel@tonic-gate 	char *vclass;
258*7c478bd9Sstevel@tonic-gate 	int instance, vhci_regis = 0;
259*7c478bd9Sstevel@tonic-gate 	struct tvhci_state *vhci = NULL;
260*7c478bd9Sstevel@tonic-gate 	dev_info_t *pdip;
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
265*7c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
266*7c478bd9Sstevel@tonic-gate 		break;
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
269*7c478bd9Sstevel@tonic-gate 	case DDI_PM_RESUME:
270*7c478bd9Sstevel@tonic-gate 		return (0);	/* nothing to do */
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 	default:
273*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
274*7c478bd9Sstevel@tonic-gate 	}
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 	/*
277*7c478bd9Sstevel@tonic-gate 	 * Allocate vhci data structure.
278*7c478bd9Sstevel@tonic-gate 	 */
279*7c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(tvhci_state, instance) != DDI_SUCCESS) {
280*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
281*7c478bd9Sstevel@tonic-gate 	}
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	vhci = ddi_get_soft_state(tvhci_state, instance);
284*7c478bd9Sstevel@tonic-gate 	ASSERT(vhci != NULL);
285*7c478bd9Sstevel@tonic-gate 	vhci->dip = dip;
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	/* parent must be /pshot */
288*7c478bd9Sstevel@tonic-gate 	pdip = ddi_get_parent(dip);
289*7c478bd9Sstevel@tonic-gate 	if (strcmp(ddi_driver_name(pdip), "pshot") != 0 ||
290*7c478bd9Sstevel@tonic-gate 	    ddi_get_parent(pdip) != ddi_root_node()) {
291*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "tvhci must be under /pshot/");
292*7c478bd9Sstevel@tonic-gate 		goto attach_fail;
293*7c478bd9Sstevel@tonic-gate 	}
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	/*
296*7c478bd9Sstevel@tonic-gate 	 * XXX add mpxio-disable property. need to remove the check
297*7c478bd9Sstevel@tonic-gate 	 *	from the framework
298*7c478bd9Sstevel@tonic-gate 	 */
299*7c478bd9Sstevel@tonic-gate 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
300*7c478bd9Sstevel@tonic-gate 	    "mpxio-disable", "no");
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	/* bus_addr is the <vhci_class> */
303*7c478bd9Sstevel@tonic-gate 	vclass = ddi_get_name_addr(dip);
304*7c478bd9Sstevel@tonic-gate 	if (vclass == NULL || vclass[1] == '\0') {
305*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "tvhci invalid vhci class");
306*7c478bd9Sstevel@tonic-gate 		goto attach_fail;
307*7c478bd9Sstevel@tonic-gate 	}
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	/*
310*7c478bd9Sstevel@tonic-gate 	 * Attach this instance with the mpxio framework
311*7c478bd9Sstevel@tonic-gate 	 */
312*7c478bd9Sstevel@tonic-gate 	if (mdi_vhci_register(vclass, dip, &tvhci_opinfo, 0) != MDI_SUCCESS) {
313*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s mdi_vhci_register failed",
314*7c478bd9Sstevel@tonic-gate 		    ddi_node_name(dip));
315*7c478bd9Sstevel@tonic-gate 		goto attach_fail;
316*7c478bd9Sstevel@tonic-gate 	}
317*7c478bd9Sstevel@tonic-gate 	vhci_regis++;
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
320*7c478bd9Sstevel@tonic-gate 	    instance, DDI_NT_SCSI_NEXUS, 0) != DDI_SUCCESS) {
321*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "%s ddi_create_minor_node failed",
322*7c478bd9Sstevel@tonic-gate 		    ddi_node_name(dip));
323*7c478bd9Sstevel@tonic-gate 		goto attach_fail;
324*7c478bd9Sstevel@tonic-gate 	}
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, DDI_NO_AUTODETACH, 1);
327*7c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
328*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate attach_fail:
331*7c478bd9Sstevel@tonic-gate 	if (vhci_regis)
332*7c478bd9Sstevel@tonic-gate 		(void) mdi_vhci_unregister(dip, 0);
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(tvhci_state, instance);
335*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
336*7c478bd9Sstevel@tonic-gate }
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
340*7c478bd9Sstevel@tonic-gate static int
341*7c478bd9Sstevel@tonic-gate tvhci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
342*7c478bd9Sstevel@tonic-gate {
343*7c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
346*7c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
347*7c478bd9Sstevel@tonic-gate 		break;
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
350*7c478bd9Sstevel@tonic-gate 	case DDI_PM_SUSPEND:
351*7c478bd9Sstevel@tonic-gate 		return (0);	/* nothing to do */
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 	default:
354*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
355*7c478bd9Sstevel@tonic-gate 	}
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	if (mdi_vhci_unregister(dip, 0) != MDI_SUCCESS)
358*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
361*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(tvhci_state, instance);
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
364*7c478bd9Sstevel@tonic-gate }
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate /*
367*7c478bd9Sstevel@tonic-gate  * tvhci_getinfo()
368*7c478bd9Sstevel@tonic-gate  * Given the device number, return the devinfo pointer or the
369*7c478bd9Sstevel@tonic-gate  * instance number.
370*7c478bd9Sstevel@tonic-gate  * Note: always succeed DDI_INFO_DEVT2INSTANCE, even before attach.
371*7c478bd9Sstevel@tonic-gate  */
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
374*7c478bd9Sstevel@tonic-gate static int
375*7c478bd9Sstevel@tonic-gate tvhci_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
376*7c478bd9Sstevel@tonic-gate {
377*7c478bd9Sstevel@tonic-gate 	struct tvhci_state *vhci;
378*7c478bd9Sstevel@tonic-gate 	int instance = getminor((dev_t)arg);
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
381*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
382*7c478bd9Sstevel@tonic-gate 		vhci = ddi_get_soft_state(tvhci_state, instance);
383*7c478bd9Sstevel@tonic-gate 		if (vhci != NULL)
384*7c478bd9Sstevel@tonic-gate 			*result = vhci->dip;
385*7c478bd9Sstevel@tonic-gate 		else {
386*7c478bd9Sstevel@tonic-gate 			*result = NULL;
387*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
388*7c478bd9Sstevel@tonic-gate 		}
389*7c478bd9Sstevel@tonic-gate 		break;
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
392*7c478bd9Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
393*7c478bd9Sstevel@tonic-gate 		break;
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 	default:
396*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
397*7c478bd9Sstevel@tonic-gate 	}
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
400*7c478bd9Sstevel@tonic-gate }
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
403*7c478bd9Sstevel@tonic-gate static int
404*7c478bd9Sstevel@tonic-gate tvhci_pi_init(dev_info_t *vdip, mdi_pathinfo_t *pip, int flags)
405*7c478bd9Sstevel@tonic-gate {
406*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
407*7c478bd9Sstevel@tonic-gate }
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
410*7c478bd9Sstevel@tonic-gate static int
411*7c478bd9Sstevel@tonic-gate tvhci_pi_uninit(dev_info_t *vdip, mdi_pathinfo_t *pip, int flags)
412*7c478bd9Sstevel@tonic-gate {
413*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
414*7c478bd9Sstevel@tonic-gate }
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
417*7c478bd9Sstevel@tonic-gate static int
418*7c478bd9Sstevel@tonic-gate tvhci_pi_state_change(dev_info_t *vdip, mdi_pathinfo_t *pip,
419*7c478bd9Sstevel@tonic-gate     mdi_pathinfo_state_t state, uint32_t ext_state, int flags)
420*7c478bd9Sstevel@tonic-gate {
421*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
422*7c478bd9Sstevel@tonic-gate }
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
425*7c478bd9Sstevel@tonic-gate static int
426*7c478bd9Sstevel@tonic-gate tvhci_failover(dev_info_t *vdip, dev_info_t *cdip, int flags)
427*7c478bd9Sstevel@tonic-gate {
428*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
429*7c478bd9Sstevel@tonic-gate }
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate /*
432*7c478bd9Sstevel@tonic-gate  * Interrupt stuff. NO OP for pseudo drivers.
433*7c478bd9Sstevel@tonic-gate  */
434*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
435*7c478bd9Sstevel@tonic-gate static int
436*7c478bd9Sstevel@tonic-gate tvhci_intr_op(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op,
437*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
438*7c478bd9Sstevel@tonic-gate {
439*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
440*7c478bd9Sstevel@tonic-gate }
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
443*7c478bd9Sstevel@tonic-gate static int
444*7c478bd9Sstevel@tonic-gate tvhci_ctl(dev_info_t *dip, dev_info_t *rdip,
445*7c478bd9Sstevel@tonic-gate 	ddi_ctl_enum_t ctlop, void *arg, void *result)
446*7c478bd9Sstevel@tonic-gate {
447*7c478bd9Sstevel@tonic-gate 	switch (ctlop) {
448*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
449*7c478bd9Sstevel@tonic-gate 		if (rdip == (dev_info_t *)0)
450*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
451*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "?tvhci-device: %s%d\n",
452*7c478bd9Sstevel@tonic-gate 		    ddi_get_name(rdip), ddi_get_instance(rdip));
453*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
456*7c478bd9Sstevel@tonic-gate 	{
457*7c478bd9Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
458*7c478bd9Sstevel@tonic-gate 		return (tvhci_initchild(dip, child));
459*7c478bd9Sstevel@tonic-gate 	}
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
462*7c478bd9Sstevel@tonic-gate 	{
463*7c478bd9Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
464*7c478bd9Sstevel@tonic-gate 		return (tvhci_uninitchild(dip, child));
465*7c478bd9Sstevel@tonic-gate 	}
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_DMAPMAPC:
468*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTINT:
469*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
470*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
471*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NINTRS:
472*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
473*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_SLAVEONLY:
474*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_AFFINITY:
475*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INTR_HILEVEL:
476*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_XLATE_INTRS:
477*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_POKE:
478*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_PEEK:
479*7c478bd9Sstevel@tonic-gate 		/*
480*7c478bd9Sstevel@tonic-gate 		 * These ops correspond to functions that "shouldn't" be called
481*7c478bd9Sstevel@tonic-gate 		 * by a pseudo driver.  So we whine when we're called.
482*7c478bd9Sstevel@tonic-gate 		 */
483*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n",
484*7c478bd9Sstevel@tonic-gate 			ddi_get_name(dip), ddi_get_instance(dip),
485*7c478bd9Sstevel@tonic-gate 			ctlop, ddi_get_name(rdip), ddi_get_instance(rdip));
486*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_ATTACH:
489*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_BTOP:
490*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_BTOPR:
491*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_DETACH:
492*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_DVMAPAGESIZE:
493*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_IOMIN:
494*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_POWER:
495*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_PTOB:
496*7c478bd9Sstevel@tonic-gate 	default:
497*7c478bd9Sstevel@tonic-gate 		/*
498*7c478bd9Sstevel@tonic-gate 		 * The ops that we pass up (default).  We pass up memory
499*7c478bd9Sstevel@tonic-gate 		 * allocation oriented ops that we receive - these may be
500*7c478bd9Sstevel@tonic-gate 		 * associated with pseudo HBA drivers below us with target
501*7c478bd9Sstevel@tonic-gate 		 * drivers below them that use ddi memory allocation
502*7c478bd9Sstevel@tonic-gate 		 * interfaces like scsi_alloc_consistent_buf.
503*7c478bd9Sstevel@tonic-gate 		 */
504*7c478bd9Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
505*7c478bd9Sstevel@tonic-gate 	}
506*7c478bd9Sstevel@tonic-gate }
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate /* set devi_addr to "g<guid>" */
509*7c478bd9Sstevel@tonic-gate static int
510*7c478bd9Sstevel@tonic-gate tvhci_initchild(dev_info_t *dip, dev_info_t *child)
511*7c478bd9Sstevel@tonic-gate {
512*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip))
513*7c478bd9Sstevel@tonic-gate 	char *guid, *addr;
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
516*7c478bd9Sstevel@tonic-gate 	    MDI_CLIENT_GUID_PROP, &guid) != DDI_SUCCESS) {
517*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "tvhci_initchild - no guid property");
518*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
519*7c478bd9Sstevel@tonic-gate 	}
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 	addr = kmem_alloc(MAXNAMELEN, KM_SLEEP);
522*7c478bd9Sstevel@tonic-gate 	(void) snprintf(addr, MAXNAMELEN, "g%s", guid);
523*7c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(child, addr);
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 	kmem_free(addr, MAXNAMELEN);
526*7c478bd9Sstevel@tonic-gate 	ddi_prop_free(guid);
527*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
528*7c478bd9Sstevel@tonic-gate }
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
531*7c478bd9Sstevel@tonic-gate static int
532*7c478bd9Sstevel@tonic-gate tvhci_uninitchild(dev_info_t *dip, dev_info_t *child)
533*7c478bd9Sstevel@tonic-gate {
534*7c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(child, NULL);
535*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
536*7c478bd9Sstevel@tonic-gate }
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate /* form paddr by cname@<phci_inst>,<guid> */
539*7c478bd9Sstevel@tonic-gate static char *
540*7c478bd9Sstevel@tonic-gate tvh_get_phci_devname(char *cname, char *guid,
541*7c478bd9Sstevel@tonic-gate     dev_info_t *pdip, char *pname, int len)
542*7c478bd9Sstevel@tonic-gate {
543*7c478bd9Sstevel@tonic-gate 	(void) snprintf(pname, len, "%s@%d,%s",
544*7c478bd9Sstevel@tonic-gate 	    cname, ddi_get_instance(pdip), guid);
545*7c478bd9Sstevel@tonic-gate 	return (pname);
546*7c478bd9Sstevel@tonic-gate }
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate static int
549*7c478bd9Sstevel@tonic-gate tvh_enum_by_phci(dev_info_t *vdip, char *devnm, int flags)
550*7c478bd9Sstevel@tonic-gate {
551*7c478bd9Sstevel@tonic-gate 	mdi_phci_t *ph;
552*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t *vh = (mdi_vhci_t *)DEVI(vdip)->devi_mdi_xhci;
553*7c478bd9Sstevel@tonic-gate 	dev_info_t *pdip, *cdip;
554*7c478bd9Sstevel@tonic-gate 	char *cname, *caddr, *guid, *pname;
555*7c478bd9Sstevel@tonic-gate 	int rval = DDI_FAILURE;
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	(void) i_ddi_parse_name(devnm, &cname, &caddr, NULL);
558*7c478bd9Sstevel@tonic-gate 	if (cname == NULL || caddr == NULL || caddr[0] != 'g')
559*7c478bd9Sstevel@tonic-gate 		return (rval);
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 	guid = caddr + 1;
562*7c478bd9Sstevel@tonic-gate 	pname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 	/* mutex_enter(&mdi_mutex); XXX need lock access */
565*7c478bd9Sstevel@tonic-gate 	ph = vh->vh_phci_head;
566*7c478bd9Sstevel@tonic-gate 	while (ph) {
567*7c478bd9Sstevel@tonic-gate 		pdip = ph->ph_dip;
568*7c478bd9Sstevel@tonic-gate 		/* mutex_exit(&mdi_mutex); */
569*7c478bd9Sstevel@tonic-gate 		(void) tvh_get_phci_devname(cname, guid, pdip, pname,
570*7c478bd9Sstevel@tonic-gate 		    MAXNAMELEN);
571*7c478bd9Sstevel@tonic-gate 		if (ndi_devi_config_one(pdip, pname, &cdip, flags)
572*7c478bd9Sstevel@tonic-gate 		    == DDI_SUCCESS) {
573*7c478bd9Sstevel@tonic-gate 			ndi_rele_devi(cdip);
574*7c478bd9Sstevel@tonic-gate 			rval = DDI_SUCCESS;
575*7c478bd9Sstevel@tonic-gate 		}
576*7c478bd9Sstevel@tonic-gate 		/* mutex_enter(&mdi_mutex); */
577*7c478bd9Sstevel@tonic-gate 		ph = ph->ph_next;
578*7c478bd9Sstevel@tonic-gate 	}
579*7c478bd9Sstevel@tonic-gate 	/* mutex_exit(&mdi_mutex); */
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	*(caddr - 1) = '@';	/* undo damage from i_ddi_parse_name() */
582*7c478bd9Sstevel@tonic-gate 	kmem_free(pname, MAXNAMELEN);
583*7c478bd9Sstevel@tonic-gate 	return (rval);
584*7c478bd9Sstevel@tonic-gate }
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate static int
587*7c478bd9Sstevel@tonic-gate tvh_remove_by_phci(dev_info_t *vdip, char *devnm, int flags)
588*7c478bd9Sstevel@tonic-gate {
589*7c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
590*7c478bd9Sstevel@tonic-gate 	mdi_phci_t *ph;
591*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t *vh = (mdi_vhci_t *)DEVI(vdip)->devi_mdi_xhci;
592*7c478bd9Sstevel@tonic-gate 	dev_info_t *pdip;
593*7c478bd9Sstevel@tonic-gate 	char *cname, *caddr, *guid, *pname;
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 	(void) i_ddi_parse_name(devnm, &cname, &caddr, NULL);
596*7c478bd9Sstevel@tonic-gate 	if (cname == NULL || caddr == NULL || caddr[0] != 'g')
597*7c478bd9Sstevel@tonic-gate 		return (rval);	/* devnm can't exist */
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 	guid = caddr + 1;
600*7c478bd9Sstevel@tonic-gate 	pname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	/* mutex_enter(&mdi_mutex); XXX need lock access */
603*7c478bd9Sstevel@tonic-gate 	ph = vh->vh_phci_head;
604*7c478bd9Sstevel@tonic-gate 	while (ph) {
605*7c478bd9Sstevel@tonic-gate 		pdip = ph->ph_dip;
606*7c478bd9Sstevel@tonic-gate 		/* mutex_exit(&mdi_mutex); */
607*7c478bd9Sstevel@tonic-gate 		(void) tvh_get_phci_devname(cname, guid, pdip, pname,
608*7c478bd9Sstevel@tonic-gate 		    MAXNAMELEN);
609*7c478bd9Sstevel@tonic-gate 		rval = ndi_devi_unconfig_one(pdip, pname, NULL, flags);
610*7c478bd9Sstevel@tonic-gate 		/* mutex_enter(&mdi_mutex); */
611*7c478bd9Sstevel@tonic-gate 		if (rval != NDI_SUCCESS)
612*7c478bd9Sstevel@tonic-gate 			break;
613*7c478bd9Sstevel@tonic-gate 		ph = ph->ph_next;
614*7c478bd9Sstevel@tonic-gate 	}
615*7c478bd9Sstevel@tonic-gate 	/* mutex_exit(&mdi_mutex); */
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 	kmem_free(pname, MAXNAMELEN);
618*7c478bd9Sstevel@tonic-gate 	return (rval);
619*7c478bd9Sstevel@tonic-gate }
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate static int
622*7c478bd9Sstevel@tonic-gate tvhci_bus_config(dev_info_t *parent, uint_t flags,
623*7c478bd9Sstevel@tonic-gate     ddi_bus_config_op_t op, void *arg, dev_info_t **childp)
624*7c478bd9Sstevel@tonic-gate {
625*7c478bd9Sstevel@tonic-gate 	char *devnm;
626*7c478bd9Sstevel@tonic-gate 	dev_info_t *cdip;
627*7c478bd9Sstevel@tonic-gate 	int circ;
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 	switch (op) {
630*7c478bd9Sstevel@tonic-gate 	case BUS_CONFIG_ONE:
631*7c478bd9Sstevel@tonic-gate 		break;
632*7c478bd9Sstevel@tonic-gate 	case BUS_CONFIG_ALL:
633*7c478bd9Sstevel@tonic-gate 		/* XXX call into phci's here? */
634*7c478bd9Sstevel@tonic-gate 	case BUS_CONFIG_DRIVER:
635*7c478bd9Sstevel@tonic-gate 		return (ndi_busop_bus_config(parent, flags, op, arg, childp,
636*7c478bd9Sstevel@tonic-gate 		    0));
637*7c478bd9Sstevel@tonic-gate 	default:
638*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
639*7c478bd9Sstevel@tonic-gate 	}
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 	devnm = (char *)arg;
642*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(parent, &circ);
643*7c478bd9Sstevel@tonic-gate 	cdip = ndi_devi_findchild(parent, devnm);
644*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(parent, circ);
645*7c478bd9Sstevel@tonic-gate 	if (cdip == NULL) {
646*7c478bd9Sstevel@tonic-gate 		/* call into registered phci's */
647*7c478bd9Sstevel@tonic-gate 		(void) tvh_enum_by_phci(parent, devnm, flags);
648*7c478bd9Sstevel@tonic-gate 	}
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate 	return (ndi_busop_bus_config(parent, flags, op, arg, childp, 0));
651*7c478bd9Sstevel@tonic-gate }
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate static int
654*7c478bd9Sstevel@tonic-gate tvhci_bus_unconfig(dev_info_t *parent, uint_t flags,
655*7c478bd9Sstevel@tonic-gate     ddi_bus_config_op_t op, void *arg)
656*7c478bd9Sstevel@tonic-gate {
657*7c478bd9Sstevel@tonic-gate 	char *devnm, *slashname;
658*7c478bd9Sstevel@tonic-gate 	int rval, circ;
659*7c478bd9Sstevel@tonic-gate 	dev_info_t *cdip, *ndip;
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate 	/*
662*7c478bd9Sstevel@tonic-gate 	 * If we are not removing device nodes, pathinfo can be
663*7c478bd9Sstevel@tonic-gate 	 * left as is. So no need to disturb the phci's.
664*7c478bd9Sstevel@tonic-gate 	 */
665*7c478bd9Sstevel@tonic-gate 	if ((flags & NDI_DEVI_REMOVE) == 0) {
666*7c478bd9Sstevel@tonic-gate 		return (ndi_busop_bus_unconfig(parent, flags, op, arg));
667*7c478bd9Sstevel@tonic-gate 	}
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate 	switch (op) {
670*7c478bd9Sstevel@tonic-gate 	case BUS_UNCONFIG_ONE:
671*7c478bd9Sstevel@tonic-gate 		devnm = (char *)arg;
672*7c478bd9Sstevel@tonic-gate 		ndi_devi_enter(parent, &circ);
673*7c478bd9Sstevel@tonic-gate 		if (ndi_devi_findchild(parent, devnm) == NULL) {
674*7c478bd9Sstevel@tonic-gate 			ndi_devi_exit(parent, circ);
675*7c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
676*7c478bd9Sstevel@tonic-gate 		}
677*7c478bd9Sstevel@tonic-gate 		ndi_devi_exit(parent, circ);
678*7c478bd9Sstevel@tonic-gate 		return (tvh_remove_by_phci(parent, devnm, flags));
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate 	case BUS_UNCONFIG_ALL:
681*7c478bd9Sstevel@tonic-gate 		/* this functionality is for developers only */
682*7c478bd9Sstevel@tonic-gate 		rval = DDI_SUCCESS;
683*7c478bd9Sstevel@tonic-gate 		slashname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
684*7c478bd9Sstevel@tonic-gate 		devnm = slashname + 1;
685*7c478bd9Sstevel@tonic-gate 		ndi_devi_enter(parent, &circ);
686*7c478bd9Sstevel@tonic-gate 		cdip = ddi_get_child(parent);
687*7c478bd9Sstevel@tonic-gate 		while (cdip != NULL) {
688*7c478bd9Sstevel@tonic-gate 			ndip = ddi_get_next_sibling(cdip);
689*7c478bd9Sstevel@tonic-gate 			(void) ddi_deviname(cdip, slashname);
690*7c478bd9Sstevel@tonic-gate 			ndi_devi_exit(parent, circ);
691*7c478bd9Sstevel@tonic-gate 			rval = tvh_remove_by_phci(parent, devnm, flags);
692*7c478bd9Sstevel@tonic-gate 			if (rval != DDI_SUCCESS) {
693*7c478bd9Sstevel@tonic-gate 				break;
694*7c478bd9Sstevel@tonic-gate 			}
695*7c478bd9Sstevel@tonic-gate 			ndi_devi_enter(parent, &circ);
696*7c478bd9Sstevel@tonic-gate 			cdip = ndip;
697*7c478bd9Sstevel@tonic-gate 		}
698*7c478bd9Sstevel@tonic-gate 		ndi_devi_exit(parent, circ);
699*7c478bd9Sstevel@tonic-gate 		return (rval);
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 	case BUS_UNCONFIG_DRIVER:
702*7c478bd9Sstevel@tonic-gate 		/* unconfig driver never comes with NDI_DEVI_REMOVE */
703*7c478bd9Sstevel@tonic-gate 	default:
704*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
705*7c478bd9Sstevel@tonic-gate 	}
706*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
707*7c478bd9Sstevel@tonic-gate }
708