xref: /onnv-gate/usr/src/uts/common/io/tphci.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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * The tphci driver can be used to exercise the mpxio framework together
31*0Sstevel@tonic-gate  * with tvhci/tclient.
32*0Sstevel@tonic-gate  */
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate #include <sys/conf.h>
35*0Sstevel@tonic-gate #include <sys/file.h>
36*0Sstevel@tonic-gate #include <sys/open.h>
37*0Sstevel@tonic-gate #include <sys/stat.h>
38*0Sstevel@tonic-gate #include <sys/modctl.h>
39*0Sstevel@tonic-gate #include <sys/ddi.h>
40*0Sstevel@tonic-gate #include <sys/sunddi.h>
41*0Sstevel@tonic-gate #include <sys/sunndi.h>
42*0Sstevel@tonic-gate #include <sys/sunmdi.h>
43*0Sstevel@tonic-gate #include <sys/mdi_impldefs.h>
44*0Sstevel@tonic-gate #include <sys/disp.h>
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate /* cb_ops entry points */
47*0Sstevel@tonic-gate static int tphci_open(dev_t *, int, int, cred_t *);
48*0Sstevel@tonic-gate static int tphci_close(dev_t, int, int, cred_t *);
49*0Sstevel@tonic-gate static int tphci_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
50*0Sstevel@tonic-gate static int tphci_attach(dev_info_t *, ddi_attach_cmd_t);
51*0Sstevel@tonic-gate static int tphci_detach(dev_info_t *, ddi_detach_cmd_t);
52*0Sstevel@tonic-gate static int tphci_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate /* bus_ops entry points */
55*0Sstevel@tonic-gate static int tphci_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
56*0Sstevel@tonic-gate     void *);
57*0Sstevel@tonic-gate static int tphci_initchild(dev_info_t *, dev_info_t *);
58*0Sstevel@tonic-gate static int tphci_uninitchild(dev_info_t *, dev_info_t *);
59*0Sstevel@tonic-gate static int tphci_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t, void *,
60*0Sstevel@tonic-gate     dev_info_t **);
61*0Sstevel@tonic-gate static int tphci_bus_unconfig(dev_info_t *, uint_t, ddi_bus_config_op_t,
62*0Sstevel@tonic-gate     void *);
63*0Sstevel@tonic-gate static int tphci_intr_op(dev_info_t *dip, dev_info_t *rdip,
64*0Sstevel@tonic-gate     ddi_intr_op_t op, ddi_intr_handle_impl_t *hdlp, void *result);
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate static void *tphci_state;
68*0Sstevel@tonic-gate struct tphci_state {
69*0Sstevel@tonic-gate 	dev_info_t *dip;
70*0Sstevel@tonic-gate };
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate static struct cb_ops tphci_cb_ops = {
73*0Sstevel@tonic-gate 	tphci_open,			/* open */
74*0Sstevel@tonic-gate 	tphci_close,			/* close */
75*0Sstevel@tonic-gate 	nodev,				/* strategy */
76*0Sstevel@tonic-gate 	nodev,				/* print */
77*0Sstevel@tonic-gate 	nodev,				/* dump */
78*0Sstevel@tonic-gate 	nodev,				/* read */
79*0Sstevel@tonic-gate 	nodev,				/* write */
80*0Sstevel@tonic-gate 	tphci_ioctl,			/* ioctl */
81*0Sstevel@tonic-gate 	nodev,				/* devmap */
82*0Sstevel@tonic-gate 	nodev,				/* mmap */
83*0Sstevel@tonic-gate 	nodev,				/* segmap */
84*0Sstevel@tonic-gate 	nochpoll,			/* chpoll */
85*0Sstevel@tonic-gate 	ddi_prop_op,			/* cb_prop_op */
86*0Sstevel@tonic-gate 	0,				/* streamtab */
87*0Sstevel@tonic-gate 	D_NEW | D_MP,			/* cb_flag */
88*0Sstevel@tonic-gate 	CB_REV,				/* rev */
89*0Sstevel@tonic-gate 	nodev,				/* aread */
90*0Sstevel@tonic-gate 	nodev				/* awrite */
91*0Sstevel@tonic-gate };
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate static struct bus_ops tphci_bus_ops = {
94*0Sstevel@tonic-gate 	BUSO_REV,			/* busops_rev */
95*0Sstevel@tonic-gate 	nullbusmap,			/* bus_map */
96*0Sstevel@tonic-gate 	NULL,				/* bus_get_intrspec */
97*0Sstevel@tonic-gate 	NULL,				/* bus_add_interspec */
98*0Sstevel@tonic-gate 	NULL,				/* bus_remove_interspec */
99*0Sstevel@tonic-gate 	i_ddi_map_fault,		/* bus_map_fault */
100*0Sstevel@tonic-gate 	ddi_no_dma_map,			/* bus_dma_map */
101*0Sstevel@tonic-gate 	ddi_no_dma_allochdl,		/* bus_dma_allochdl */
102*0Sstevel@tonic-gate 	NULL,				/* bus_dma_freehdl */
103*0Sstevel@tonic-gate 	NULL,				/* bus_dma_bindhdl */
104*0Sstevel@tonic-gate 	NULL,				/* bus_dma_unbindhdl */
105*0Sstevel@tonic-gate 	NULL,				/* bus_dma_flush */
106*0Sstevel@tonic-gate 	NULL,				/* bus_dma_win */
107*0Sstevel@tonic-gate 	NULL,				/* bus_dma_ctl */
108*0Sstevel@tonic-gate 	tphci_ctl,			/* bus_ctl */
109*0Sstevel@tonic-gate 	ddi_bus_prop_op,		/* bus_prop_op */
110*0Sstevel@tonic-gate 	NULL,				/* bus_get_eventcookie */
111*0Sstevel@tonic-gate 	NULL,				/* bus_add_eventcall */
112*0Sstevel@tonic-gate 	NULL,				/* bus_remove_event */
113*0Sstevel@tonic-gate 	NULL,				/* bus_post_event */
114*0Sstevel@tonic-gate 	NULL,				/* bus_intr_ctl */
115*0Sstevel@tonic-gate 	tphci_bus_config,		/* bus_config */
116*0Sstevel@tonic-gate 	tphci_bus_unconfig,		/* bus_unconfig */
117*0Sstevel@tonic-gate 	NULL,				/* bus_fm_init */
118*0Sstevel@tonic-gate 	NULL,				/* bus_fm_fini */
119*0Sstevel@tonic-gate 	NULL,				/* bus_fm_access_enter */
120*0Sstevel@tonic-gate 	NULL,				/* bus_fm_access_exit */
121*0Sstevel@tonic-gate 	NULL,				/* bus_power */
122*0Sstevel@tonic-gate 	tphci_intr_op			/* bus_intr_op */
123*0Sstevel@tonic-gate };
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate static struct dev_ops tphci_ops = {
126*0Sstevel@tonic-gate 	DEVO_REV,
127*0Sstevel@tonic-gate 	0,
128*0Sstevel@tonic-gate 	tphci_getinfo,
129*0Sstevel@tonic-gate 	nulldev,		/* identify */
130*0Sstevel@tonic-gate 	nulldev,		/* probe */
131*0Sstevel@tonic-gate 	tphci_attach,		/* attach and detach are mandatory */
132*0Sstevel@tonic-gate 	tphci_detach,
133*0Sstevel@tonic-gate 	nodev,			/* reset */
134*0Sstevel@tonic-gate 	&tphci_cb_ops,		/* cb_ops */
135*0Sstevel@tonic-gate 	&tphci_bus_ops,		/* bus_ops */
136*0Sstevel@tonic-gate 	NULL			/* power */
137*0Sstevel@tonic-gate };
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate extern struct mod_ops mod_driverops;
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate static struct modldrv modldrv = {
142*0Sstevel@tonic-gate 	&mod_driverops,
143*0Sstevel@tonic-gate 	"test phci driver %I%",
144*0Sstevel@tonic-gate 	&tphci_ops
145*0Sstevel@tonic-gate };
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
148*0Sstevel@tonic-gate 	MODREV_1,
149*0Sstevel@tonic-gate 	&modldrv,
150*0Sstevel@tonic-gate 	NULL
151*0Sstevel@tonic-gate };
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate int
154*0Sstevel@tonic-gate _init(void)
155*0Sstevel@tonic-gate {
156*0Sstevel@tonic-gate 	int rval;
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 	if ((rval = ddi_soft_state_init(&tphci_state,
159*0Sstevel@tonic-gate 	    sizeof (struct tphci_state), 2)) != 0) {
160*0Sstevel@tonic-gate 		return (rval);
161*0Sstevel@tonic-gate 	}
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 	if ((rval = mod_install(&modlinkage)) != 0) {
164*0Sstevel@tonic-gate 		ddi_soft_state_fini(&tphci_state);
165*0Sstevel@tonic-gate 	}
166*0Sstevel@tonic-gate 	return (rval);
167*0Sstevel@tonic-gate }
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate int
171*0Sstevel@tonic-gate _fini(void)
172*0Sstevel@tonic-gate {
173*0Sstevel@tonic-gate 	int rval;
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 	/*
176*0Sstevel@tonic-gate 	 * don't start cleaning up until we know that the module remove
177*0Sstevel@tonic-gate 	 * has worked  -- if this works, then we know that each instance
178*0Sstevel@tonic-gate 	 * has successfully been detached
179*0Sstevel@tonic-gate 	 */
180*0Sstevel@tonic-gate 	if ((rval = mod_remove(&modlinkage)) != 0) {
181*0Sstevel@tonic-gate 		return (rval);
182*0Sstevel@tonic-gate 	}
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	ddi_soft_state_fini(&tphci_state);
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 	return (rval);
187*0Sstevel@tonic-gate }
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate int
190*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
191*0Sstevel@tonic-gate {
192*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
193*0Sstevel@tonic-gate }
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate /* ARGSUSED */
196*0Sstevel@tonic-gate static int
197*0Sstevel@tonic-gate tphci_open(dev_t *devp, int flag, int otype, cred_t *credp)
198*0Sstevel@tonic-gate {
199*0Sstevel@tonic-gate 	struct tphci_state *phci;
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 	if (otype != OTYP_CHR) {
202*0Sstevel@tonic-gate 		return (EINVAL);
203*0Sstevel@tonic-gate 	}
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	phci = ddi_get_soft_state(tphci_state, getminor(*devp));
206*0Sstevel@tonic-gate 	if (phci == NULL) {
207*0Sstevel@tonic-gate 		return (ENXIO);
208*0Sstevel@tonic-gate 	}
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 	return (0);
211*0Sstevel@tonic-gate }
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate /* ARGSUSED */
215*0Sstevel@tonic-gate static int
216*0Sstevel@tonic-gate tphci_close(dev_t dev, int flag, int otype, cred_t *credp)
217*0Sstevel@tonic-gate {
218*0Sstevel@tonic-gate 	struct tphci_state *phci;
219*0Sstevel@tonic-gate 	if (otype != OTYP_CHR) {
220*0Sstevel@tonic-gate 		return (EINVAL);
221*0Sstevel@tonic-gate 	}
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	phci = ddi_get_soft_state(tphci_state, getminor(dev));
224*0Sstevel@tonic-gate 	if (phci == NULL) {
225*0Sstevel@tonic-gate 		return (ENXIO);
226*0Sstevel@tonic-gate 	}
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 	return (0);
229*0Sstevel@tonic-gate }
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate /* ARGSUSED */
232*0Sstevel@tonic-gate static int
233*0Sstevel@tonic-gate tphci_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
234*0Sstevel@tonic-gate 	cred_t *credp, int *rval)
235*0Sstevel@tonic-gate {
236*0Sstevel@tonic-gate 	return (0);
237*0Sstevel@tonic-gate }
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate /*
240*0Sstevel@tonic-gate  * attach the module
241*0Sstevel@tonic-gate  */
242*0Sstevel@tonic-gate static int
243*0Sstevel@tonic-gate tphci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
244*0Sstevel@tonic-gate {
245*0Sstevel@tonic-gate 	char *vclass;
246*0Sstevel@tonic-gate 	int instance, phci_regis = 0;
247*0Sstevel@tonic-gate 	struct tphci_state *phci = NULL;
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	switch (cmd) {
252*0Sstevel@tonic-gate 	case DDI_ATTACH:
253*0Sstevel@tonic-gate 		break;
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate 	case DDI_RESUME:
256*0Sstevel@tonic-gate 	case DDI_PM_RESUME:
257*0Sstevel@tonic-gate 		return (0);	/* nothing to do */
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate 	default:
260*0Sstevel@tonic-gate 		return (DDI_FAILURE);
261*0Sstevel@tonic-gate 	}
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	/*
264*0Sstevel@tonic-gate 	 * Allocate phci data structure.
265*0Sstevel@tonic-gate 	 */
266*0Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(tphci_state, instance) != DDI_SUCCESS) {
267*0Sstevel@tonic-gate 		return (DDI_FAILURE);
268*0Sstevel@tonic-gate 	}
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	phci = ddi_get_soft_state(tphci_state, instance);
271*0Sstevel@tonic-gate 	ASSERT(phci != NULL);
272*0Sstevel@tonic-gate 	phci->dip = dip;
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	/* bus_addr has the form #,<vhci_class> */
275*0Sstevel@tonic-gate 	vclass = strchr(ddi_get_name_addr(dip), ',');
276*0Sstevel@tonic-gate 	if (vclass == NULL || vclass[1] == '\0') {
277*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "tphci invalid bus_addr %s",
278*0Sstevel@tonic-gate 		    ddi_get_name_addr(dip));
279*0Sstevel@tonic-gate 		goto attach_fail;
280*0Sstevel@tonic-gate 	}
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 	/*
283*0Sstevel@tonic-gate 	 * Attach this instance with the mpxio framework
284*0Sstevel@tonic-gate 	 */
285*0Sstevel@tonic-gate 	if (mdi_phci_register(vclass + 1, dip, 0) != MDI_SUCCESS) {
286*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s mdi_phci_register failed",
287*0Sstevel@tonic-gate 		    ddi_node_name(dip));
288*0Sstevel@tonic-gate 		goto attach_fail;
289*0Sstevel@tonic-gate 	}
290*0Sstevel@tonic-gate 	phci_regis++;
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
293*0Sstevel@tonic-gate 	    instance, DDI_NT_SCSI_NEXUS, 0) != DDI_SUCCESS) {
294*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "%s ddi_create_minor_node failed",
295*0Sstevel@tonic-gate 		    ddi_node_name(dip));
296*0Sstevel@tonic-gate 		goto attach_fail;
297*0Sstevel@tonic-gate 	}
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, DDI_NO_AUTODETACH, 1);
300*0Sstevel@tonic-gate 	ddi_report_dev(dip);
301*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate attach_fail:
304*0Sstevel@tonic-gate 	if (phci_regis)
305*0Sstevel@tonic-gate 		(void) mdi_phci_unregister(dip, 0);
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 	ddi_soft_state_free(tphci_state, instance);
308*0Sstevel@tonic-gate 	return (DDI_FAILURE);
309*0Sstevel@tonic-gate }
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate /*ARGSUSED*/
313*0Sstevel@tonic-gate static int
314*0Sstevel@tonic-gate tphci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
315*0Sstevel@tonic-gate {
316*0Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 	switch (cmd) {
319*0Sstevel@tonic-gate 	case DDI_DETACH:
320*0Sstevel@tonic-gate 		break;
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	case DDI_SUSPEND:
323*0Sstevel@tonic-gate 	case DDI_PM_SUSPEND:
324*0Sstevel@tonic-gate 		return (0);	/* nothing to do */
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 	default:
327*0Sstevel@tonic-gate 		return (DDI_FAILURE);
328*0Sstevel@tonic-gate 	}
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	if (mdi_phci_unregister(dip, 0) != MDI_SUCCESS)
331*0Sstevel@tonic-gate 		return (DDI_FAILURE);
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
334*0Sstevel@tonic-gate 	ddi_soft_state_free(tphci_state, instance);
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
337*0Sstevel@tonic-gate }
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate /*
340*0Sstevel@tonic-gate  * tphci_getinfo()
341*0Sstevel@tonic-gate  * Given the device number, return the devinfo pointer or the
342*0Sstevel@tonic-gate  * instance number.
343*0Sstevel@tonic-gate  * Note: always succeed DDI_INFO_DEVT2INSTANCE, even before attach.
344*0Sstevel@tonic-gate  */
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate /*ARGSUSED*/
347*0Sstevel@tonic-gate static int
348*0Sstevel@tonic-gate tphci_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
349*0Sstevel@tonic-gate {
350*0Sstevel@tonic-gate 	struct tphci_state *phci;
351*0Sstevel@tonic-gate 	int instance = getminor((dev_t)arg);
352*0Sstevel@tonic-gate 
353*0Sstevel@tonic-gate 	switch (cmd) {
354*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
355*0Sstevel@tonic-gate 		phci = ddi_get_soft_state(tphci_state, instance);
356*0Sstevel@tonic-gate 		if (phci != NULL)
357*0Sstevel@tonic-gate 			*result = phci->dip;
358*0Sstevel@tonic-gate 		else {
359*0Sstevel@tonic-gate 			*result = NULL;
360*0Sstevel@tonic-gate 			return (DDI_FAILURE);
361*0Sstevel@tonic-gate 		}
362*0Sstevel@tonic-gate 		break;
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
365*0Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
366*0Sstevel@tonic-gate 		break;
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	default:
369*0Sstevel@tonic-gate 		return (DDI_FAILURE);
370*0Sstevel@tonic-gate 	}
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
373*0Sstevel@tonic-gate }
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate /*
376*0Sstevel@tonic-gate  * Interrupt stuff. NO OP for pseudo drivers.
377*0Sstevel@tonic-gate  */
378*0Sstevel@tonic-gate /*ARGSUSED*/
379*0Sstevel@tonic-gate static int
380*0Sstevel@tonic-gate tphci_intr_op(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op,
381*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
382*0Sstevel@tonic-gate {
383*0Sstevel@tonic-gate 	return (DDI_FAILURE);
384*0Sstevel@tonic-gate }
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate static int
387*0Sstevel@tonic-gate tphci_ctl(dev_info_t *dip, dev_info_t *rdip,
388*0Sstevel@tonic-gate 	ddi_ctl_enum_t ctlop, void *arg, void *result)
389*0Sstevel@tonic-gate {
390*0Sstevel@tonic-gate 	switch (ctlop) {
391*0Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
392*0Sstevel@tonic-gate 		if (rdip == (dev_info_t *)0)
393*0Sstevel@tonic-gate 			return (DDI_FAILURE);
394*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "?tphci-device: %s%d\n",
395*0Sstevel@tonic-gate 		    ddi_get_name(rdip), ddi_get_instance(rdip));
396*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
399*0Sstevel@tonic-gate 	{
400*0Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
401*0Sstevel@tonic-gate 		return (tphci_initchild(dip, child));
402*0Sstevel@tonic-gate 	}
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
405*0Sstevel@tonic-gate 	{
406*0Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
407*0Sstevel@tonic-gate 		return (tphci_uninitchild(dip, child));
408*0Sstevel@tonic-gate 	}
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	case DDI_CTLOPS_DMAPMAPC:
411*0Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTINT:
412*0Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
413*0Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
414*0Sstevel@tonic-gate 	case DDI_CTLOPS_NINTRS:
415*0Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
416*0Sstevel@tonic-gate 	case DDI_CTLOPS_SLAVEONLY:
417*0Sstevel@tonic-gate 	case DDI_CTLOPS_AFFINITY:
418*0Sstevel@tonic-gate 	case DDI_CTLOPS_INTR_HILEVEL:
419*0Sstevel@tonic-gate 	case DDI_CTLOPS_XLATE_INTRS:
420*0Sstevel@tonic-gate 	case DDI_CTLOPS_POKE:
421*0Sstevel@tonic-gate 	case DDI_CTLOPS_PEEK:
422*0Sstevel@tonic-gate 		/*
423*0Sstevel@tonic-gate 		 * These ops correspond to functions that "shouldn't" be called
424*0Sstevel@tonic-gate 		 * by a pseudo driver.  So we whine when we're called.
425*0Sstevel@tonic-gate 		 */
426*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n",
427*0Sstevel@tonic-gate 			ddi_get_name(dip), ddi_get_instance(dip),
428*0Sstevel@tonic-gate 			ctlop, ddi_get_name(rdip), ddi_get_instance(rdip));
429*0Sstevel@tonic-gate 		return (DDI_FAILURE);
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	case DDI_CTLOPS_ATTACH:
432*0Sstevel@tonic-gate 	case DDI_CTLOPS_BTOP:
433*0Sstevel@tonic-gate 	case DDI_CTLOPS_BTOPR:
434*0Sstevel@tonic-gate 	case DDI_CTLOPS_DETACH:
435*0Sstevel@tonic-gate 	case DDI_CTLOPS_DVMAPAGESIZE:
436*0Sstevel@tonic-gate 	case DDI_CTLOPS_IOMIN:
437*0Sstevel@tonic-gate 	case DDI_CTLOPS_POWER:
438*0Sstevel@tonic-gate 	case DDI_CTLOPS_PTOB:
439*0Sstevel@tonic-gate 	default:
440*0Sstevel@tonic-gate 		/*
441*0Sstevel@tonic-gate 		 * The ops that we pass up (default).  We pass up memory
442*0Sstevel@tonic-gate 		 * allocation oriented ops that we receive - these may be
443*0Sstevel@tonic-gate 		 * associated with pseudo HBA drivers below us with target
444*0Sstevel@tonic-gate 		 * drivers below them that use ddi memory allocation
445*0Sstevel@tonic-gate 		 * interfaces like scsi_alloc_consistent_buf.
446*0Sstevel@tonic-gate 		 */
447*0Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
448*0Sstevel@tonic-gate 	}
449*0Sstevel@tonic-gate }
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate static int
452*0Sstevel@tonic-gate tphci_initchild(dev_info_t *dip, dev_info_t *child)
453*0Sstevel@tonic-gate {
454*0Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip))
455*0Sstevel@tonic-gate 	ddi_set_name_addr(child, "0");
456*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
457*0Sstevel@tonic-gate }
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate /*ARGSUSED*/
460*0Sstevel@tonic-gate static int
461*0Sstevel@tonic-gate tphci_uninitchild(dev_info_t *dip, dev_info_t *child)
462*0Sstevel@tonic-gate {
463*0Sstevel@tonic-gate 	ddi_set_name_addr(child, NULL);
464*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
465*0Sstevel@tonic-gate }
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate static int
468*0Sstevel@tonic-gate tp_decode_name(char *devnm, char **cname, char **paddr, char **guid)
469*0Sstevel@tonic-gate {
470*0Sstevel@tonic-gate 	char *tmp;
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	i_ddi_parse_name(devnm, cname, paddr, NULL);
473*0Sstevel@tonic-gate 	if ((strcmp(*cname, "tclient") != 0) &&
474*0Sstevel@tonic-gate 	    (strcmp(*cname, "tphci") != 0) || *paddr == NULL)
475*0Sstevel@tonic-gate 		return (-1);
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate 	tmp = strchr(*paddr, ',');
478*0Sstevel@tonic-gate 	if (tmp == NULL || tmp[1] == '\0')
479*0Sstevel@tonic-gate 		return (-1);
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 	*guid = tmp + 1;
482*0Sstevel@tonic-gate 	return (0);
483*0Sstevel@tonic-gate }
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate static int
486*0Sstevel@tonic-gate tphci_bus_config(dev_info_t *parent, uint_t flags,
487*0Sstevel@tonic-gate     ddi_bus_config_op_t op, void *arg, dev_info_t **childp)
488*0Sstevel@tonic-gate {
489*0Sstevel@tonic-gate 	_NOTE(ARGUNUSED(flags))
490*0Sstevel@tonic-gate 	char *cname, *paddr, *guid, *devnm;
491*0Sstevel@tonic-gate 	mdi_pathinfo_t *pip;
492*0Sstevel@tonic-gate 	int len;
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 	switch (op) {
495*0Sstevel@tonic-gate 	case BUS_CONFIG_ONE:
496*0Sstevel@tonic-gate 		break;
497*0Sstevel@tonic-gate 	case BUS_CONFIG_DRIVER:	/* no direct children to configure */
498*0Sstevel@tonic-gate 	case BUS_CONFIG_ALL:
499*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
500*0Sstevel@tonic-gate 	default:
501*0Sstevel@tonic-gate 		return (DDI_FAILURE);
502*0Sstevel@tonic-gate 	}
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 	/* only implement BUS_CONFIG_ONE */
505*0Sstevel@tonic-gate 	devnm = i_ddi_strdup((char *)arg, KM_SLEEP);
506*0Sstevel@tonic-gate 	len = strlen(devnm) + 1;
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate 	/* caddr is hardcoded in the form *,<guid> */
509*0Sstevel@tonic-gate 	if (tp_decode_name(devnm, &cname, &paddr, &guid) != 0) {
510*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "tphci_bus_config -- invalid device %s",
511*0Sstevel@tonic-gate 		    (char *)arg);
512*0Sstevel@tonic-gate 		kmem_free(devnm, len);
513*0Sstevel@tonic-gate 		return (DDI_FAILURE);
514*0Sstevel@tonic-gate 	}
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 	if (mdi_pi_alloc(parent, cname, guid, paddr, 0, &pip)
517*0Sstevel@tonic-gate 	    != MDI_SUCCESS) {
518*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "tphci_bus_config -- mdi_pi_alloc failed");
519*0Sstevel@tonic-gate 		kmem_free(devnm, len);
520*0Sstevel@tonic-gate 		return (DDI_FAILURE);
521*0Sstevel@tonic-gate 	}
522*0Sstevel@tonic-gate 	kmem_free(devnm, len);
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 	if (mdi_pi_online(pip, 0) != MDI_SUCCESS) {
525*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "tphci_bus_config -- mdi_pi_online failed");
526*0Sstevel@tonic-gate 		(void) mdi_pi_free(pip, 0);
527*0Sstevel@tonic-gate 		return (DDI_FAILURE);
528*0Sstevel@tonic-gate 	}
529*0Sstevel@tonic-gate 
530*0Sstevel@tonic-gate 	if (childp) {
531*0Sstevel@tonic-gate 		*childp = MDI_PI(pip)->pi_client->ct_dip;
532*0Sstevel@tonic-gate 		ndi_hold_devi(*childp);
533*0Sstevel@tonic-gate 	}
534*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
535*0Sstevel@tonic-gate }
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate static int
538*0Sstevel@tonic-gate tphci_bus_unconfig(dev_info_t *parent, uint_t flags,
539*0Sstevel@tonic-gate     ddi_bus_config_op_t op, void *arg)
540*0Sstevel@tonic-gate {
541*0Sstevel@tonic-gate 	int rval, circ;
542*0Sstevel@tonic-gate 	mdi_pathinfo_t *pip;
543*0Sstevel@tonic-gate 	mdi_phci_t *ph;
544*0Sstevel@tonic-gate 	char *devnm, *cname, *caddr;
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 	switch (op) {
547*0Sstevel@tonic-gate 	case BUS_UNCONFIG_ONE:
548*0Sstevel@tonic-gate 		devnm = (char *)arg;
549*0Sstevel@tonic-gate 		i_ddi_parse_name(devnm, &cname, &caddr, NULL);
550*0Sstevel@tonic-gate 		if (strcmp(cname, "tclient") != 0)
551*0Sstevel@tonic-gate 			return (DDI_SUCCESS);	/* no such device */
552*0Sstevel@tonic-gate 		pip = mdi_pi_find(parent, NULL, caddr);
553*0Sstevel@tonic-gate 		if (pip == NULL)
554*0Sstevel@tonic-gate 			return (DDI_SUCCESS);
555*0Sstevel@tonic-gate 		rval = mdi_pi_offline(pip, NDI_DEVI_REMOVE);
556*0Sstevel@tonic-gate 		return (rval == MDI_SUCCESS ? NDI_SUCCESS : NDI_FAILURE);
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate 	case BUS_UNCONFIG_ALL:
559*0Sstevel@tonic-gate 		if (flags & NDI_AUTODETACH)
560*0Sstevel@tonic-gate 			return (DDI_FAILURE);
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 		ph = DEVI(parent)->devi_mdi_xhci;
563*0Sstevel@tonic-gate 		ASSERT(ph != NULL);
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 		rval = MDI_SUCCESS;
566*0Sstevel@tonic-gate 		ndi_devi_enter(parent, &circ);
567*0Sstevel@tonic-gate 		pip = (mdi_pathinfo_t *)ph->ph_path_head;
568*0Sstevel@tonic-gate 		while (pip) {
569*0Sstevel@tonic-gate 			rval = mdi_pi_offline(pip, NDI_DEVI_REMOVE);
570*0Sstevel@tonic-gate 			if (rval != MDI_SUCCESS) {
571*0Sstevel@tonic-gate 				break;
572*0Sstevel@tonic-gate 			}
573*0Sstevel@tonic-gate 			pip = (mdi_pathinfo_t *)ph->ph_path_head;
574*0Sstevel@tonic-gate 		}
575*0Sstevel@tonic-gate 		ndi_devi_exit(parent, circ);
576*0Sstevel@tonic-gate 		return (rval == MDI_SUCCESS ? NDI_SUCCESS : NDI_FAILURE);
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate 	case BUS_UNCONFIG_DRIVER:	/* nothing to do */
579*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
580*0Sstevel@tonic-gate 	default:
581*0Sstevel@tonic-gate 		return (DDI_FAILURE);
582*0Sstevel@tonic-gate 	}
583*0Sstevel@tonic-gate 	/*NOTREACHED*/
584*0Sstevel@tonic-gate }
585