xref: /onnv-gate/usr/src/uts/common/io/pci-ide/pci-ide.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  *	PCI-IDE bus nexus driver
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <sys/types.h>
34*0Sstevel@tonic-gate #include <sys/cmn_err.h>
35*0Sstevel@tonic-gate #include <sys/conf.h>
36*0Sstevel@tonic-gate #include <sys/errno.h>
37*0Sstevel@tonic-gate #include <sys/debug.h>
38*0Sstevel@tonic-gate #include <sys/ddidmareq.h>
39*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
40*0Sstevel@tonic-gate #include <sys/dma_engine.h>
41*0Sstevel@tonic-gate #include <sys/modctl.h>
42*0Sstevel@tonic-gate #include <sys/ddi.h>
43*0Sstevel@tonic-gate #include <sys/sunddi.h>
44*0Sstevel@tonic-gate #include <sys/kmem.h>
45*0Sstevel@tonic-gate #include <sys/pci.h>
46*0Sstevel@tonic-gate #include <sys/promif.h>
47*0Sstevel@tonic-gate #include <sys/pci_intr_lib.h>
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate int	pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate #define	PCIIDE_NATIVE_MODE(dip)						\
52*0Sstevel@tonic-gate 	(!ddi_prop_exists(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, 	\
53*0Sstevel@tonic-gate 	"compatibility-mode"))
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate #define	PCIIDE_PRE26(dip)	\
56*0Sstevel@tonic-gate 	ddi_prop_exists(DDI_DEV_T_ANY, (dip), 0, "ignore-hardware-nodes")
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate #define	PCI_IDE_IF_BM_CAP_MASK	0x80
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate #ifdef DEBUG
61*0Sstevel@tonic-gate static int pci_ide_debug = 0;
62*0Sstevel@tonic-gate #define	PDBG(fmt)				\
63*0Sstevel@tonic-gate 		if (pci_ide_debug) {		\
64*0Sstevel@tonic-gate 			prom_printf fmt;	\
65*0Sstevel@tonic-gate 		}
66*0Sstevel@tonic-gate #else
67*0Sstevel@tonic-gate #define	PDBG(fmt)
68*0Sstevel@tonic-gate #endif
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate #ifndef	TRUE
71*0Sstevel@tonic-gate #define	TRUE	1
72*0Sstevel@tonic-gate #endif
73*0Sstevel@tonic-gate #ifndef	FALSE
74*0Sstevel@tonic-gate #define	FALSE	0
75*0Sstevel@tonic-gate #endif
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate /*
78*0Sstevel@tonic-gate  * bus_ops functions
79*0Sstevel@tonic-gate  */
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate static int		pciide_bus_map(dev_info_t *dip, dev_info_t *rdip,
82*0Sstevel@tonic-gate 				ddi_map_req_t *mp, off_t offset, off_t len,
83*0Sstevel@tonic-gate 				caddr_t *vaddrp);
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate static	int		pciide_ddi_ctlops(dev_info_t *dip, dev_info_t *rdip,
86*0Sstevel@tonic-gate 				ddi_ctl_enum_t ctlop, void *arg,
87*0Sstevel@tonic-gate 				void *result);
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate static	int		pciide_get_pri(dev_info_t *dip, dev_info_t *rdip,
90*0Sstevel@tonic-gate 				ddi_intr_handle_impl_t *hdlp, int *pri);
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate static	int		pciide_intr_ops(dev_info_t *dip, dev_info_t *rdip,
93*0Sstevel@tonic-gate 				ddi_intr_op_t intr_op,
94*0Sstevel@tonic-gate 				ddi_intr_handle_impl_t *hdlp, void *result);
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate static struct intrspec *pciide_get_ispec(dev_info_t *dip, dev_info_t *rdip,
97*0Sstevel@tonic-gate 				int inum);
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate /*
100*0Sstevel@tonic-gate  * Local Functions
101*0Sstevel@tonic-gate  */
102*0Sstevel@tonic-gate static	int	pciide_initchild(dev_info_t *mydip, dev_info_t *cdip);
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate static	void	pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip,
105*0Sstevel@tonic-gate 				    int dev);
106*0Sstevel@tonic-gate static	int	pciide_pre26_rnumber_map(dev_info_t *mydip, int rnumber);
107*0Sstevel@tonic-gate static	int	pciide_map_rnumber(int canonical_rnumber, int pri_native,
108*0Sstevel@tonic-gate 				    int sec_native);
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate /*
112*0Sstevel@tonic-gate  * Config information
113*0Sstevel@tonic-gate  */
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate struct bus_ops pciide_bus_ops = {
116*0Sstevel@tonic-gate 	BUSO_REV,
117*0Sstevel@tonic-gate 	pciide_bus_map,
118*0Sstevel@tonic-gate 	0,
119*0Sstevel@tonic-gate 	0,
120*0Sstevel@tonic-gate 	0,
121*0Sstevel@tonic-gate 	i_ddi_map_fault,
122*0Sstevel@tonic-gate 	ddi_dma_map,
123*0Sstevel@tonic-gate 	ddi_dma_allochdl,
124*0Sstevel@tonic-gate 	ddi_dma_freehdl,
125*0Sstevel@tonic-gate 	ddi_dma_bindhdl,
126*0Sstevel@tonic-gate 	ddi_dma_unbindhdl,
127*0Sstevel@tonic-gate 	ddi_dma_flush,
128*0Sstevel@tonic-gate 	ddi_dma_win,
129*0Sstevel@tonic-gate 	ddi_dma_mctl,
130*0Sstevel@tonic-gate 	pciide_ddi_ctlops,
131*0Sstevel@tonic-gate 	ddi_bus_prop_op,
132*0Sstevel@tonic-gate 	0,	/* (*bus_get_eventcookie)();	*/
133*0Sstevel@tonic-gate 	0,	/* (*bus_add_eventcall)();	*/
134*0Sstevel@tonic-gate 	0,	/* (*bus_remove_eventcall)();	*/
135*0Sstevel@tonic-gate 	0,	/* (*bus_post_event)();		*/
136*0Sstevel@tonic-gate 	0,
137*0Sstevel@tonic-gate 	0,
138*0Sstevel@tonic-gate 	0,
139*0Sstevel@tonic-gate 	0,
140*0Sstevel@tonic-gate 	0,
141*0Sstevel@tonic-gate 	0,
142*0Sstevel@tonic-gate 	0,
143*0Sstevel@tonic-gate 	0,
144*0Sstevel@tonic-gate 	pciide_intr_ops
145*0Sstevel@tonic-gate };
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate struct dev_ops pciide_ops = {
148*0Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
149*0Sstevel@tonic-gate 	0,			/* refcnt  */
150*0Sstevel@tonic-gate 	ddi_no_info,		/* info */
151*0Sstevel@tonic-gate 	nulldev,		/* identify */
152*0Sstevel@tonic-gate 	nulldev,		/* probe */
153*0Sstevel@tonic-gate 	pciide_attach,		/* attach */
154*0Sstevel@tonic-gate 	nodev,			/* detach */
155*0Sstevel@tonic-gate 	nodev,			/* reset */
156*0Sstevel@tonic-gate 	(struct cb_ops *)0,	/* driver operations */
157*0Sstevel@tonic-gate 	&pciide_bus_ops	/* bus operations */
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate };
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate /*
162*0Sstevel@tonic-gate  * Module linkage information for the kernel.
163*0Sstevel@tonic-gate  */
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate static struct modldrv modldrv = {
166*0Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This is PCI-IDE bus driver */
167*0Sstevel@tonic-gate 	"pciide nexus driver for 'PCI-IDE' %I%",
168*0Sstevel@tonic-gate 	&pciide_ops,	/* driver ops */
169*0Sstevel@tonic-gate };
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
172*0Sstevel@tonic-gate 	MODREV_1,
173*0Sstevel@tonic-gate 	&modldrv,
174*0Sstevel@tonic-gate 	NULL
175*0Sstevel@tonic-gate };
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate int
179*0Sstevel@tonic-gate _init(void)
180*0Sstevel@tonic-gate {
181*0Sstevel@tonic-gate 	return (mod_install(&modlinkage));
182*0Sstevel@tonic-gate }
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate int
185*0Sstevel@tonic-gate _fini(void)
186*0Sstevel@tonic-gate {
187*0Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
188*0Sstevel@tonic-gate }
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate int
191*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
192*0Sstevel@tonic-gate {
193*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
194*0Sstevel@tonic-gate }
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate int
197*0Sstevel@tonic-gate pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
198*0Sstevel@tonic-gate {
199*0Sstevel@tonic-gate 	uint16_t cmdreg;
200*0Sstevel@tonic-gate 	ddi_acc_handle_t conf_hdl = NULL;
201*0Sstevel@tonic-gate 	caddr_t	mp_addr;
202*0Sstevel@tonic-gate 	ddi_device_acc_attr_t dev_attr;
203*0Sstevel@tonic-gate 	int rc;
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	if (cmd == DDI_ATTACH) {
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 		/*
209*0Sstevel@tonic-gate 		 * Make sure bus-mastering is enabled, even if
210*0Sstevel@tonic-gate 		 * BIOS didn't.
211*0Sstevel@tonic-gate 		 */
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 		dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
214*0Sstevel@tonic-gate 		dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
215*0Sstevel@tonic-gate 		dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 		rc = ddi_regs_map_setup(dip, 0, &mp_addr, 0, 0,
218*0Sstevel@tonic-gate 			&dev_attr, &conf_hdl);
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 		/*
221*0Sstevel@tonic-gate 		 * In case of error, return SUCCESS. This is because
222*0Sstevel@tonic-gate 		 * bus-mastering could be already enabled by BIOS.
223*0Sstevel@tonic-gate 		 */
224*0Sstevel@tonic-gate 		if (rc != DDI_SUCCESS)
225*0Sstevel@tonic-gate 			return (DDI_SUCCESS);
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 		cmdreg = ddi_get16(conf_hdl, (uint16_t *)PCI_CONF_COMM);
228*0Sstevel@tonic-gate 		if ((cmdreg & PCI_COMM_ME) == 0) {
229*0Sstevel@tonic-gate 			ddi_put16(conf_hdl, (uint16_t *)PCI_CONF_COMM,
230*0Sstevel@tonic-gate 			    cmdreg | PCI_COMM_ME);
231*0Sstevel@tonic-gate 		}
232*0Sstevel@tonic-gate 		ddi_regs_map_free(&conf_hdl);
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
235*0Sstevel@tonic-gate 	} else {
236*0Sstevel@tonic-gate 		return (DDI_FAILURE);
237*0Sstevel@tonic-gate 	}
238*0Sstevel@tonic-gate }
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate /*ARGSUSED*/
242*0Sstevel@tonic-gate static int
243*0Sstevel@tonic-gate pciide_ddi_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
244*0Sstevel@tonic-gate     void *arg, void *result)
245*0Sstevel@tonic-gate {
246*0Sstevel@tonic-gate 	off_t	tmp;
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate 	PDBG(("pciide_bus_ctl\n"));
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	switch (ctlop) {
251*0Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
252*0Sstevel@tonic-gate 		return (pciide_initchild(dip, (dev_info_t *)arg));
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
255*0Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, DDI_CTLOPS_UNINITCHILD,
256*0Sstevel@tonic-gate 			(dev_info_t *)arg, &tmp));
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
259*0Sstevel@tonic-gate 		*(int *)result = 3;
260*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
263*0Sstevel@tonic-gate 	{
264*0Sstevel@tonic-gate 		int	controller;
265*0Sstevel@tonic-gate 		int	rnumber;
266*0Sstevel@tonic-gate 		int	rc;
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 		/*
269*0Sstevel@tonic-gate 		 * Adjust the rnumbers based on which controller instance
270*0Sstevel@tonic-gate 		 * is requested; adjust for the 2 tuples per controller.
271*0Sstevel@tonic-gate 		 */
272*0Sstevel@tonic-gate 		if (strcmp("0", ddi_get_name_addr(rdip)) == 0)
273*0Sstevel@tonic-gate 			controller = 0;
274*0Sstevel@tonic-gate 		else
275*0Sstevel@tonic-gate 			controller = 1;
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 		switch (rnumber = *(int *)arg) {
279*0Sstevel@tonic-gate 		case 0:
280*0Sstevel@tonic-gate 		case 1:
281*0Sstevel@tonic-gate 			rnumber += (2 * controller);
282*0Sstevel@tonic-gate 			break;
283*0Sstevel@tonic-gate 		case 2:
284*0Sstevel@tonic-gate 			rnumber = 4;
285*0Sstevel@tonic-gate 			break;
286*0Sstevel@tonic-gate 		default:
287*0Sstevel@tonic-gate 			PDBG(("pciide_ctlops invalid rnumber\n"));
288*0Sstevel@tonic-gate 			return (DDI_FAILURE);
289*0Sstevel@tonic-gate 		}
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 		if (PCIIDE_PRE26(dip)) {
293*0Sstevel@tonic-gate 			int	old_rnumber;
294*0Sstevel@tonic-gate 			int	new_rnumber;
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 			old_rnumber = rnumber;
297*0Sstevel@tonic-gate 			new_rnumber
298*0Sstevel@tonic-gate 				= pciide_pre26_rnumber_map(dip, old_rnumber);
299*0Sstevel@tonic-gate 			PDBG(("pciide rnumber old %d new %d\n",
300*0Sstevel@tonic-gate 				old_rnumber, new_rnumber));
301*0Sstevel@tonic-gate 			rnumber = new_rnumber;
302*0Sstevel@tonic-gate 		}
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 		/*
305*0Sstevel@tonic-gate 		 * Add 1 to skip over the PCI config space tuple
306*0Sstevel@tonic-gate 		 */
307*0Sstevel@tonic-gate 		rnumber++;
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 		/*
310*0Sstevel@tonic-gate 		 * If it's not tuple #2 pass the adjusted request to my parent
311*0Sstevel@tonic-gate 		 */
312*0Sstevel@tonic-gate 		if (*(int *)arg != 2) {
313*0Sstevel@tonic-gate 			return (ddi_ctlops(dip, dip, ctlop, &rnumber, result));
314*0Sstevel@tonic-gate 		}
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 		/*
317*0Sstevel@tonic-gate 		 * Handle my child's reg-tuple #2 here by splitting my 16 byte
318*0Sstevel@tonic-gate 		 * reg-tuple #4 into two 8 byte ranges based on the
319*0Sstevel@tonic-gate 		 * the child's controller #.
320*0Sstevel@tonic-gate 		 */
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 		tmp = 8;
323*0Sstevel@tonic-gate 		rc = ddi_ctlops(dip, dip, ctlop, &rnumber, &tmp);
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 		/*
326*0Sstevel@tonic-gate 		 * Allow for the possibility of less than 16 bytes by
327*0Sstevel@tonic-gate 		 * by checking what's actually returned for my reg-tuple #4.
328*0Sstevel@tonic-gate 		 */
329*0Sstevel@tonic-gate 		if (controller == 1) {
330*0Sstevel@tonic-gate 			if (tmp < 8)
331*0Sstevel@tonic-gate 				tmp = 0;
332*0Sstevel@tonic-gate 			else
333*0Sstevel@tonic-gate 				tmp -= 8;
334*0Sstevel@tonic-gate 		}
335*0Sstevel@tonic-gate 		if (tmp > 8)
336*0Sstevel@tonic-gate 			tmp = 8;
337*0Sstevel@tonic-gate 		*(off_t *)result = tmp;
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 		return (rc);
340*0Sstevel@tonic-gate 	}
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 	default:
343*0Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
344*0Sstevel@tonic-gate 	}
345*0Sstevel@tonic-gate }
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate /*
348*0Sstevel@tonic-gate  * IEEE 1275 Working Group Proposal #414 says that the Primary
349*0Sstevel@tonic-gate  * controller is "ata@0" and the Secondary controller "ata@1".
350*0Sstevel@tonic-gate  *
351*0Sstevel@tonic-gate  * By the time we get here, boot Bootconf (2.6+) has created devinfo
352*0Sstevel@tonic-gate  * nodes with the appropriate "reg", "assigned-addresses" and "interrupts"
353*0Sstevel@tonic-gate  * properites on the pci-ide node and both ide child nodes.
354*0Sstevel@tonic-gate  *
355*0Sstevel@tonic-gate  * In compatibility mode the "reg" and "assigned-addresses" properties
356*0Sstevel@tonic-gate  * of the pci-ide node are set up like this:
357*0Sstevel@tonic-gate  *
358*0Sstevel@tonic-gate  *   1. PCI-IDE Nexus
359*0Sstevel@tonic-gate  *
360*0Sstevel@tonic-gate  *	interrupts=0
361*0Sstevel@tonic-gate  *				(addr-hi addr-mid addr-low size-hi  size-low)
362*0Sstevel@tonic-gate  *	reg= assigned-addresses=00000000.00000000.00000000.00000000.00000000
363*0Sstevel@tonic-gate  *				81000000.00000000.000001f0.00000000.00000008
364*0Sstevel@tonic-gate  *				81000000.00000000.000003f4.00000000.00000004
365*0Sstevel@tonic-gate  *				81000000.00000000,00000170.00000000.00000008
366*0Sstevel@tonic-gate  *				81000000.00000000,00000374.00000000.00000004
367*0Sstevel@tonic-gate  *				01000020.00000000,-[BAR4]-.00000000.00000010
368*0Sstevel@tonic-gate  *
369*0Sstevel@tonic-gate  * In native PCI mode the "reg" and "assigned-addresses" properties
370*0Sstevel@tonic-gate  * would be set up like this:
371*0Sstevel@tonic-gate  *
372*0Sstevel@tonic-gate  *   2. PCI-IDE Nexus
373*0Sstevel@tonic-gate  *
374*0Sstevel@tonic-gate  *	interrupts=0
375*0Sstevel@tonic-gate  *	reg= assigned-addresses=00000000.00000000.00000000.00000000.00000000
376*0Sstevel@tonic-gate  *				01000010.00000000.-[BAR0]-.00000000.00000008
377*0Sstevel@tonic-gate  *				01000014,00000000.-[BAR1]-.00000000.00000004
378*0Sstevel@tonic-gate  *				01000018.00000000.-[BAR2]-.00000000.00000008
379*0Sstevel@tonic-gate  *				0100001c.00000000.-[BAR3]-.00000000.00000004
380*0Sstevel@tonic-gate  *				01000020.00000000.-[BAR4]-.00000000.00000010
381*0Sstevel@tonic-gate  *
382*0Sstevel@tonic-gate  *
383*0Sstevel@tonic-gate  * In both modes the child nodes simply have the following:
384*0Sstevel@tonic-gate  *
385*0Sstevel@tonic-gate  *   2. primary controller (compatibility mode)
386*0Sstevel@tonic-gate  *
387*0Sstevel@tonic-gate  *	interrupts=14
388*0Sstevel@tonic-gate  *	reg=00000000
389*0Sstevel@tonic-gate  *
390*0Sstevel@tonic-gate  *   3. secondary controller
391*0Sstevel@tonic-gate  *
392*0Sstevel@tonic-gate  *	interrupts=15
393*0Sstevel@tonic-gate  *	reg=00000001
394*0Sstevel@tonic-gate  *
395*0Sstevel@tonic-gate  * The pciide_bus_map() function is responsible for turning requests
396*0Sstevel@tonic-gate  * to map primary or secondary controller rnumbers into mapping requests
397*0Sstevel@tonic-gate  * of the appropriate regspec on the pci-ide node.
398*0Sstevel@tonic-gate  *
399*0Sstevel@tonic-gate  */
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate static int
402*0Sstevel@tonic-gate pciide_initchild(dev_info_t *mydip, dev_info_t *cdip)
403*0Sstevel@tonic-gate {
404*0Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr;
405*0Sstevel@tonic-gate 	struct intrspec	*ispecp;
406*0Sstevel@tonic-gate 	int	vec;
407*0Sstevel@tonic-gate 	int	*rp;
408*0Sstevel@tonic-gate 	uint_t	proplen;
409*0Sstevel@tonic-gate 	char	name[80];
410*0Sstevel@tonic-gate 	int	dev;
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 	PDBG(("pciide_initchild\n"));
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	/*
415*0Sstevel@tonic-gate 	 * Set the address portion of the node name based on
416*0Sstevel@tonic-gate 	 * the controller number (0 or 1) from the 'reg' property.
417*0Sstevel@tonic-gate 	 */
418*0Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
419*0Sstevel@tonic-gate 	    "reg", &rp, (uint_t *)&proplen) != DDI_PROP_SUCCESS) {
420*0Sstevel@tonic-gate 		PDBG(("pciide_intchild prop error\n"));
421*0Sstevel@tonic-gate 		return (DDI_NOT_WELL_FORMED);
422*0Sstevel@tonic-gate 	}
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	/*
425*0Sstevel@tonic-gate 	 * copy the controller number and
426*0Sstevel@tonic-gate 	 * free the memory allocated by ddi_prop_lookup_int_array
427*0Sstevel@tonic-gate 	 */
428*0Sstevel@tonic-gate 	dev = *rp;
429*0Sstevel@tonic-gate 	ddi_prop_free(rp);
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	/*
432*0Sstevel@tonic-gate 	 * I only support two controllers per device, determine
433*0Sstevel@tonic-gate 	 * which this one is and set its unit address.
434*0Sstevel@tonic-gate 	 */
435*0Sstevel@tonic-gate 	if (dev > 1) {
436*0Sstevel@tonic-gate 		PDBG(("pciide_initchild bad dev\n"));
437*0Sstevel@tonic-gate 		return (DDI_NOT_WELL_FORMED);
438*0Sstevel@tonic-gate 	}
439*0Sstevel@tonic-gate 	(void) sprintf(name, "%d", dev);
440*0Sstevel@tonic-gate 	ddi_set_name_addr(cdip, name);
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 	/*
443*0Sstevel@tonic-gate 	 * determine if this instance is running in native or compat mode
444*0Sstevel@tonic-gate 	 */
445*0Sstevel@tonic-gate 	pciide_compat_setup(mydip, cdip, dev);
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	/* interrupts property is required */
448*0Sstevel@tonic-gate 	if (PCIIDE_NATIVE_MODE(cdip)) {
449*0Sstevel@tonic-gate 		vec = 1;
450*0Sstevel@tonic-gate 	} else {
451*0Sstevel@tonic-gate 		/*
452*0Sstevel@tonic-gate 		 * In compatibility mode, dev 0 should always be
453*0Sstevel@tonic-gate 		 * IRQ 14 and dev 1 is IRQ 15. If for some reason
454*0Sstevel@tonic-gate 		 * this needs to be changed, do it via the interrupts
455*0Sstevel@tonic-gate 		 * property in the ata.conf file.
456*0Sstevel@tonic-gate 		 */
457*0Sstevel@tonic-gate 		vec = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
458*0Sstevel@tonic-gate 				"interrupts", -1);
459*0Sstevel@tonic-gate 		if (vec == -1) {
460*0Sstevel@tonic-gate 			/* setup compatibility mode interrupts */
461*0Sstevel@tonic-gate 			if (dev == 0) {
462*0Sstevel@tonic-gate 				vec = 14;
463*0Sstevel@tonic-gate 			} else if (dev == 1) {
464*0Sstevel@tonic-gate 				vec = 15;
465*0Sstevel@tonic-gate 			} else {
466*0Sstevel@tonic-gate 				PDBG(("pciide_initchild bad intr\n"));
467*0Sstevel@tonic-gate 				return (DDI_NOT_WELL_FORMED);
468*0Sstevel@tonic-gate 			}
469*0Sstevel@tonic-gate 		}
470*0Sstevel@tonic-gate 	}
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	pdptr = kmem_zalloc((sizeof (struct ddi_parent_private_data) +
473*0Sstevel@tonic-gate 	    sizeof (struct intrspec)), KM_SLEEP);
474*0Sstevel@tonic-gate 	ispecp = (struct intrspec *)(pdptr + 1);
475*0Sstevel@tonic-gate 	pdptr->par_nintr = 1;
476*0Sstevel@tonic-gate 	pdptr->par_intr = ispecp;
477*0Sstevel@tonic-gate 	ispecp->intrspec_vec = vec;
478*0Sstevel@tonic-gate 	ddi_set_parent_data(cdip, pdptr);
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate 	PDBG(("pciide_initchild okay\n"));
481*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
482*0Sstevel@tonic-gate }
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate static int
485*0Sstevel@tonic-gate pciide_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
486*0Sstevel@tonic-gate     off_t offset, off_t len, caddr_t *vaddrp)
487*0Sstevel@tonic-gate {
488*0Sstevel@tonic-gate 	dev_info_t *pdip;
489*0Sstevel@tonic-gate 	int	    rnumber = mp->map_obj.rnumber;
490*0Sstevel@tonic-gate 	int	    controller;
491*0Sstevel@tonic-gate 	int	    rc;
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	PDBG(("pciide_bus_map\n"));
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 	if (strcmp("0", ddi_get_name_addr(rdip)) == 0)
496*0Sstevel@tonic-gate 		controller = 0;
497*0Sstevel@tonic-gate 	else
498*0Sstevel@tonic-gate 		controller = 1;
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 	/*
501*0Sstevel@tonic-gate 	 * Adjust the rnumbers based on which controller instance
502*0Sstevel@tonic-gate 	 * is being mapped; adjust for the 2 tuples per controller.
503*0Sstevel@tonic-gate 	 */
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 	switch (rnumber) {
506*0Sstevel@tonic-gate 	case 0:
507*0Sstevel@tonic-gate 	case 1:
508*0Sstevel@tonic-gate 		mp->map_obj.rnumber += (controller * 2);
509*0Sstevel@tonic-gate 		break;
510*0Sstevel@tonic-gate 	case 2:
511*0Sstevel@tonic-gate 		/*
512*0Sstevel@tonic-gate 		 * split the 16 I/O ports into two 8 port ranges
513*0Sstevel@tonic-gate 		 */
514*0Sstevel@tonic-gate 		mp->map_obj.rnumber = 4;
515*0Sstevel@tonic-gate 		if (offset + len > 8) {
516*0Sstevel@tonic-gate 			PDBG(("pciide_bus_map offset\n"));
517*0Sstevel@tonic-gate 			return (DDI_FAILURE);
518*0Sstevel@tonic-gate 		}
519*0Sstevel@tonic-gate 		if (len == 0)
520*0Sstevel@tonic-gate 			len = 8 - offset;
521*0Sstevel@tonic-gate 		offset += 8 * controller;
522*0Sstevel@tonic-gate 		break;
523*0Sstevel@tonic-gate 	default:
524*0Sstevel@tonic-gate 		PDBG(("pciide_bus_map default\n"));
525*0Sstevel@tonic-gate 		return (DDI_FAILURE);
526*0Sstevel@tonic-gate 	}
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	if (PCIIDE_PRE26(dip)) {
529*0Sstevel@tonic-gate 		int	old_rnumber;
530*0Sstevel@tonic-gate 		int	new_rnumber;
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate 		old_rnumber = mp->map_obj.rnumber;
533*0Sstevel@tonic-gate 		new_rnumber = pciide_pre26_rnumber_map(dip, old_rnumber);
534*0Sstevel@tonic-gate 		PDBG(("pciide rnumber old %d new %d\n",
535*0Sstevel@tonic-gate 			old_rnumber, new_rnumber));
536*0Sstevel@tonic-gate 		mp->map_obj.rnumber = new_rnumber;
537*0Sstevel@tonic-gate 	}
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate 	/*
540*0Sstevel@tonic-gate 	 * Add 1 to skip over the PCI config space tuple
541*0Sstevel@tonic-gate 	 */
542*0Sstevel@tonic-gate 	mp->map_obj.rnumber++;
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 	/*
546*0Sstevel@tonic-gate 	 * pass the adjusted request to my parent
547*0Sstevel@tonic-gate 	 */
548*0Sstevel@tonic-gate 	pdip = ddi_get_parent(dip);
549*0Sstevel@tonic-gate 	rc = ((*(DEVI(pdip)->devi_ops->devo_bus_ops->bus_map))
550*0Sstevel@tonic-gate 			(pdip, dip, mp, offset, len, vaddrp));
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate 	PDBG(("pciide_bus_map %s\n", rc == DDI_SUCCESS ? "okay" : "!ok"));
553*0Sstevel@tonic-gate 
554*0Sstevel@tonic-gate 	return (rc);
555*0Sstevel@tonic-gate }
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate static struct intrspec *
559*0Sstevel@tonic-gate pciide_get_ispec(dev_info_t *dip, dev_info_t *rdip, int inumber)
560*0Sstevel@tonic-gate {
561*0Sstevel@tonic-gate 	struct ddi_parent_private_data *ppdptr;
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 	PDBG(("pciide_get_ispec\n"));
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 	/*
566*0Sstevel@tonic-gate 	 * Native mode PCI-IDE controllers share the parent's
567*0Sstevel@tonic-gate 	 * PCI interrupt line.
568*0Sstevel@tonic-gate 	 *
569*0Sstevel@tonic-gate 	 * Compatibility mode PCI-IDE controllers have their
570*0Sstevel@tonic-gate 	 * own intrspec which specifies ISA IRQ 14 or 15.
571*0Sstevel@tonic-gate 	 *
572*0Sstevel@tonic-gate 	 */
573*0Sstevel@tonic-gate 	if (PCIIDE_NATIVE_MODE(rdip)) {
574*0Sstevel@tonic-gate 		ddi_intrspec_t is;
575*0Sstevel@tonic-gate 
576*0Sstevel@tonic-gate 		is = pci_intx_get_ispec(dip, dip, inumber);
577*0Sstevel@tonic-gate 		PDBG(("pciide_get_ispec okay\n"));
578*0Sstevel@tonic-gate 		return ((struct intrspec *)is);
579*0Sstevel@tonic-gate 	}
580*0Sstevel@tonic-gate 
581*0Sstevel@tonic-gate 	/* Else compatibility mode, use the ISA IRQ */
582*0Sstevel@tonic-gate 	if ((ppdptr = ddi_get_parent_data(rdip)) == NULL) {
583*0Sstevel@tonic-gate 		PDBG(("pciide_get_ispec null\n"));
584*0Sstevel@tonic-gate 		return (NULL);
585*0Sstevel@tonic-gate 	}
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate 	/* validate the interrupt number  */
588*0Sstevel@tonic-gate 	if (inumber >= ppdptr->par_nintr) {
589*0Sstevel@tonic-gate 		PDBG(("pciide_get_inum\n"));
590*0Sstevel@tonic-gate 		return (NULL);
591*0Sstevel@tonic-gate 	}
592*0Sstevel@tonic-gate 
593*0Sstevel@tonic-gate 	PDBG(("pciide_get_ispec ok\n"));
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 	return ((struct intrspec *)&ppdptr->par_intr[inumber]);
596*0Sstevel@tonic-gate }
597*0Sstevel@tonic-gate 
598*0Sstevel@tonic-gate static	int
599*0Sstevel@tonic-gate pciide_get_pri(dev_info_t *dip, dev_info_t *rdip,
600*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, int *pri)
601*0Sstevel@tonic-gate {
602*0Sstevel@tonic-gate 	struct intrspec	*ispecp;
603*0Sstevel@tonic-gate 	int		*intpriorities;
604*0Sstevel@tonic-gate 	uint_t		 num_intpriorities;
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 	PDBG(("pciide_get_pri\n"));
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 	if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == NULL) {
609*0Sstevel@tonic-gate 		PDBG(("pciide_get_pri null\n"));
610*0Sstevel@tonic-gate 		return (DDI_FAILURE);
611*0Sstevel@tonic-gate 	}
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 	if (PCIIDE_NATIVE_MODE(rdip)) {
614*0Sstevel@tonic-gate 		*pri = ispecp->intrspec_pri;
615*0Sstevel@tonic-gate 		PDBG(("pciide_get_pri ok\n"));
616*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
617*0Sstevel@tonic-gate 	}
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	/* check if the intrspec has been initialized */
620*0Sstevel@tonic-gate 	if (ispecp->intrspec_pri != 0) {
621*0Sstevel@tonic-gate 		*pri = ispecp->intrspec_pri;
622*0Sstevel@tonic-gate 		PDBG(("pciide_get_pri ok2\n"));
623*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
624*0Sstevel@tonic-gate 	}
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate 	/* Use a default of level 5  */
627*0Sstevel@tonic-gate 	ispecp->intrspec_pri = 5;
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	/*
630*0Sstevel@tonic-gate 	 * If there's an interrupt-priorities property, use it to
631*0Sstevel@tonic-gate 	 * over-ride the default interrupt priority.
632*0Sstevel@tonic-gate 	 */
633*0Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
634*0Sstevel@tonic-gate 	    "interrupt-priorities", &intpriorities, &num_intpriorities) ==
635*0Sstevel@tonic-gate 	    DDI_PROP_SUCCESS) {
636*0Sstevel@tonic-gate 		if (hdlp->ih_inum < num_intpriorities)
637*0Sstevel@tonic-gate 			ispecp->intrspec_pri = intpriorities[hdlp->ih_inum];
638*0Sstevel@tonic-gate 		ddi_prop_free(intpriorities);
639*0Sstevel@tonic-gate 	}
640*0Sstevel@tonic-gate 	*pri = ispecp->intrspec_pri;
641*0Sstevel@tonic-gate 
642*0Sstevel@tonic-gate 	PDBG(("pciide_get_pri ok3\n"));
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
645*0Sstevel@tonic-gate }
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate static int
648*0Sstevel@tonic-gate pciide_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
649*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
650*0Sstevel@tonic-gate {
651*0Sstevel@tonic-gate 	struct ddi_parent_private_data *ppdptr;
652*0Sstevel@tonic-gate 	struct intrspec	*ispecp;
653*0Sstevel@tonic-gate 	int		rc;
654*0Sstevel@tonic-gate 	int		pri = 0;
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 	PDBG(("pciide_intr_ops: dip %p rdip %p op %x hdlp %p\n",
657*0Sstevel@tonic-gate 	    (void *)dip, (void *)rdip, intr_op, (void *)hdlp));
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 	switch (intr_op) {
660*0Sstevel@tonic-gate 	case DDI_INTROP_SUPPORTED_TYPES:
661*0Sstevel@tonic-gate 		*(int *)result = DDI_INTR_TYPE_FIXED;
662*0Sstevel@tonic-gate 		break;
663*0Sstevel@tonic-gate 	case DDI_INTROP_GETCAP:
664*0Sstevel@tonic-gate 		if (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result)
665*0Sstevel@tonic-gate 		    == DDI_FAILURE)
666*0Sstevel@tonic-gate 			*(int *)result = 0;
667*0Sstevel@tonic-gate 		break;
668*0Sstevel@tonic-gate 	case DDI_INTROP_NINTRS:
669*0Sstevel@tonic-gate 		if (!PCIIDE_NATIVE_MODE(rdip)) {
670*0Sstevel@tonic-gate 			if ((ppdptr = ddi_get_parent_data(rdip)) == NULL) {
671*0Sstevel@tonic-gate 				*(int *)result = 0;
672*0Sstevel@tonic-gate 				return (DDI_FAILURE);
673*0Sstevel@tonic-gate 			}
674*0Sstevel@tonic-gate 			*(int *)result = ppdptr->par_nintr;
675*0Sstevel@tonic-gate 		} else
676*0Sstevel@tonic-gate 			*(int *)result = 1;
677*0Sstevel@tonic-gate 		break;
678*0Sstevel@tonic-gate 	case DDI_INTROP_ALLOC:
679*0Sstevel@tonic-gate 		if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
680*0Sstevel@tonic-gate 		    NULL)
681*0Sstevel@tonic-gate 			return (DDI_FAILURE);
682*0Sstevel@tonic-gate 		*(int *)result = hdlp->ih_scratch1;
683*0Sstevel@tonic-gate 		hdlp->ih_private = (void *)ispecp;
684*0Sstevel@tonic-gate 		break;
685*0Sstevel@tonic-gate 	case DDI_INTROP_FREE:
686*0Sstevel@tonic-gate 		hdlp->ih_private = NULL;
687*0Sstevel@tonic-gate 		break;
688*0Sstevel@tonic-gate 	case DDI_INTROP_GETPRI:
689*0Sstevel@tonic-gate 		if (pciide_get_pri(dip, rdip, hdlp, &pri) != DDI_SUCCESS) {
690*0Sstevel@tonic-gate 			*(int *)result = 0;
691*0Sstevel@tonic-gate 			return (DDI_FAILURE);
692*0Sstevel@tonic-gate 		}
693*0Sstevel@tonic-gate 		*(int *)result = pri;
694*0Sstevel@tonic-gate 		break;
695*0Sstevel@tonic-gate 	case DDI_INTROP_ADDISR:
696*0Sstevel@tonic-gate 		if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
697*0Sstevel@tonic-gate 		    NULL)
698*0Sstevel@tonic-gate 			return (DDI_FAILURE);
699*0Sstevel@tonic-gate 		hdlp->ih_private = (void *)ispecp;
700*0Sstevel@tonic-gate 		ispecp->intrspec_func = hdlp->ih_cb_func;
701*0Sstevel@tonic-gate 		break;
702*0Sstevel@tonic-gate 	case DDI_INTROP_REMISR:
703*0Sstevel@tonic-gate 		if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
704*0Sstevel@tonic-gate 		    NULL)
705*0Sstevel@tonic-gate 			return (DDI_FAILURE);
706*0Sstevel@tonic-gate 		ispecp->intrspec_func = (uint_t (*)()) 0;
707*0Sstevel@tonic-gate 		break;
708*0Sstevel@tonic-gate 	case DDI_INTROP_ENABLE:
709*0Sstevel@tonic-gate 	/* FALLTHRU */
710*0Sstevel@tonic-gate 	case DDI_INTROP_DISABLE:
711*0Sstevel@tonic-gate 		if (PCIIDE_NATIVE_MODE(rdip)) {
712*0Sstevel@tonic-gate 			rdip = dip;
713*0Sstevel@tonic-gate 			dip = ddi_get_parent(dip);
714*0Sstevel@tonic-gate 		} else {	/* get ptr to the root node */
715*0Sstevel@tonic-gate 			dip = ddi_root_node();
716*0Sstevel@tonic-gate 		}
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate 		rc = (*(DEVI(dip)->devi_ops->devo_bus_ops->bus_intr_op))(dip,
719*0Sstevel@tonic-gate 		    rdip, intr_op, hdlp, result);
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate #ifdef	DEBUG
722*0Sstevel@tonic-gate 		if (intr_op == DDI_INTROP_ENABLE) {
723*0Sstevel@tonic-gate 			PDBG(("pciide_enable rc=%d", rc));
724*0Sstevel@tonic-gate 		} else
725*0Sstevel@tonic-gate 			PDBG(("pciide_disable rc=%d", rc));
726*0Sstevel@tonic-gate #endif	/* DEBUG */
727*0Sstevel@tonic-gate 		return (rc);
728*0Sstevel@tonic-gate 	case DDI_INTROP_NAVAIL:
729*0Sstevel@tonic-gate 		*(int *)result = 1;
730*0Sstevel@tonic-gate 		break;
731*0Sstevel@tonic-gate 	default:
732*0Sstevel@tonic-gate 		return (DDI_FAILURE);
733*0Sstevel@tonic-gate 	}
734*0Sstevel@tonic-gate 
735*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
736*0Sstevel@tonic-gate }
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate /*
739*0Sstevel@tonic-gate  * This is one of the places where controller specific setup needs to be
740*0Sstevel@tonic-gate  * considered.
741*0Sstevel@tonic-gate  * At this point the controller was already pre-qualified as a known and
742*0Sstevel@tonic-gate  * supported pciide controller.
743*0Sstevel@tonic-gate  * Some controllers do not provide PCI_MASS_IDE sub-class code and IDE
744*0Sstevel@tonic-gate  * programming interface code but rather PCI_MASS_OTHER sub-class code
745*0Sstevel@tonic-gate  * without any additional data.
746*0Sstevel@tonic-gate  * For those controllers IDE programming interface cannot be extracted
747*0Sstevel@tonic-gate  * from PCI class - we assume that they are pci-native type and we fix
748*0Sstevel@tonic-gate  * the programming interface used by other functions.
749*0Sstevel@tonic-gate  * The programming interface byte is set to indicate pci-native mode
750*0Sstevel@tonic-gate  * for both controllers and the Bus Master DMA capabilitiy of the controller.
751*0Sstevel@tonic-gate  */
752*0Sstevel@tonic-gate static void
753*0Sstevel@tonic-gate pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip, int dev)
754*0Sstevel@tonic-gate {
755*0Sstevel@tonic-gate 	int	class_code;
756*0Sstevel@tonic-gate 	int	rc = DDI_PROP_SUCCESS;
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate 	class_code = ddi_prop_get_int(DDI_DEV_T_ANY, mydip,
759*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "class-code", 0);
760*0Sstevel@tonic-gate 
761*0Sstevel@tonic-gate 	if (((class_code & 0x00FF00) >> 8) == PCI_MASS_IDE) {
762*0Sstevel@tonic-gate 		/*
763*0Sstevel@tonic-gate 		 * Controller provides PCI_MASS_IDE sub-class code first
764*0Sstevel@tonic-gate 		 * (implied IDE programming interface)
765*0Sstevel@tonic-gate 		 */
766*0Sstevel@tonic-gate 		if ((dev == 0 && !(class_code & PCI_IDE_IF_NATIVE_PRI)) ||
767*0Sstevel@tonic-gate 		    (dev == 1 && !(class_code & PCI_IDE_IF_NATIVE_SEC))) {
768*0Sstevel@tonic-gate 			rc = ddi_prop_update_int(DDI_DEV_T_NONE, cdip,
769*0Sstevel@tonic-gate 					"compatibility-mode", 1);
770*0Sstevel@tonic-gate 			if (rc != DDI_PROP_SUCCESS)
771*0Sstevel@tonic-gate 				cmn_err(CE_WARN,
772*0Sstevel@tonic-gate 				    "pciide prop error %d compat-mode", rc);
773*0Sstevel@tonic-gate 		}
774*0Sstevel@tonic-gate 	} else {
775*0Sstevel@tonic-gate 		/*
776*0Sstevel@tonic-gate 		 * Pci-ide controllers not providing PCI_MASS_IDE sub-class are
777*0Sstevel@tonic-gate 		 * assumed to be of pci-native type and bus master DMA capable.
778*0Sstevel@tonic-gate 		 * Programming interface part of the class-code property is
779*0Sstevel@tonic-gate 		 * fixed here.
780*0Sstevel@tonic-gate 		 */
781*0Sstevel@tonic-gate 		class_code &= 0x00ffff00;
782*0Sstevel@tonic-gate 		class_code |= PCI_IDE_IF_BM_CAP_MASK |
783*0Sstevel@tonic-gate 			PCI_IDE_IF_NATIVE_PRI | PCI_IDE_IF_NATIVE_SEC;
784*0Sstevel@tonic-gate 		rc = ddi_prop_update_int(DDI_DEV_T_NONE, mydip,
785*0Sstevel@tonic-gate 			"class-code", class_code);
786*0Sstevel@tonic-gate 		if (rc != DDI_PROP_SUCCESS)
787*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
788*0Sstevel@tonic-gate 			    "pciide prop error %d class-code", rc);
789*0Sstevel@tonic-gate 	}
790*0Sstevel@tonic-gate }
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate static int
794*0Sstevel@tonic-gate pciide_pre26_rnumber_map(dev_info_t *mydip, int rnumber)
795*0Sstevel@tonic-gate {
796*0Sstevel@tonic-gate 	int	pri_native;
797*0Sstevel@tonic-gate 	int	sec_native;
798*0Sstevel@tonic-gate 	int	class_code;
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate 	class_code = ddi_prop_get_int(DDI_DEV_T_ANY, mydip, DDI_PROP_DONTPASS,
801*0Sstevel@tonic-gate 				"class-code", 0);
802*0Sstevel@tonic-gate 
803*0Sstevel@tonic-gate 	pri_native = (class_code & PCI_IDE_IF_NATIVE_PRI) ? TRUE : FALSE;
804*0Sstevel@tonic-gate 	sec_native = (class_code & PCI_IDE_IF_NATIVE_SEC) ? TRUE : FALSE;
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 	return (pciide_map_rnumber(rnumber, pri_native, sec_native));
807*0Sstevel@tonic-gate 
808*0Sstevel@tonic-gate }
809*0Sstevel@tonic-gate 
810*0Sstevel@tonic-gate /*
811*0Sstevel@tonic-gate  *	The canonical order of the reg property tuples for the
812*0Sstevel@tonic-gate  *	Base Address Registers is supposed to be:
813*0Sstevel@tonic-gate  *
814*0Sstevel@tonic-gate  *	primary controller (BAR 0)
815*0Sstevel@tonic-gate  *	primary controller (BAR 1)
816*0Sstevel@tonic-gate  *	secondary controller (BAR 2)
817*0Sstevel@tonic-gate  *	secondary controller (BAR 3)
818*0Sstevel@tonic-gate  *	bus mastering regs (BAR 4)
819*0Sstevel@tonic-gate  *
820*0Sstevel@tonic-gate  *	For 2.6, bootconf has been fixed to always generate the
821*0Sstevel@tonic-gate  *	reg property (and assigned-addresses property) tuples
822*0Sstevel@tonic-gate  *	in the above order.
823*0Sstevel@tonic-gate  *
824*0Sstevel@tonic-gate  *	But in releases prior to 2.6 the order varies depending
825*0Sstevel@tonic-gate  *	on whether compatibility or native mode is being used for
826*0Sstevel@tonic-gate  *	each controller. There ends up being four possible
827*0Sstevel@tonic-gate  *	orders:
828*0Sstevel@tonic-gate  *
829*0Sstevel@tonic-gate  *	BM, P0, P1, S0, S1	primary compatible, secondary compatible
830*0Sstevel@tonic-gate  *	S0, S1, BM, P0, P1	primary compatible, secondary native
831*0Sstevel@tonic-gate  *	P0, P1, BM, S0, S1	primary native, secondary compatible
832*0Sstevel@tonic-gate  *	P0, P1, S0, S1, BM	primary native, secondary native
833*0Sstevel@tonic-gate  *
834*0Sstevel@tonic-gate  *	where: Px is the primary tuples, Sx the secondary tuples, and
835*0Sstevel@tonic-gate  *	B the Bus Master tuple.
836*0Sstevel@tonic-gate  *
837*0Sstevel@tonic-gate  *	Here's the results for each of the four states:
838*0Sstevel@tonic-gate  *
839*0Sstevel@tonic-gate  *		0, 1, 2, 3, 4
840*0Sstevel@tonic-gate  *
841*0Sstevel@tonic-gate  *	CC	1, 2, 3, 4, 0
842*0Sstevel@tonic-gate  *	CN	3, 4, 0, 1, 2
843*0Sstevel@tonic-gate  *	NC	0, 1, 3, 4, 2
844*0Sstevel@tonic-gate  *	NN	0, 1, 2, 3, 4
845*0Sstevel@tonic-gate  *
846*0Sstevel@tonic-gate  *	C = compatible(!native) == 0
847*0Sstevel@tonic-gate  *	N = native == 1
848*0Sstevel@tonic-gate  *
849*0Sstevel@tonic-gate  *	Here's the transformation matrix:
850*0Sstevel@tonic-gate  */
851*0Sstevel@tonic-gate 
852*0Sstevel@tonic-gate static	int	pciide_transform[2][2][5] = {
853*0Sstevel@tonic-gate /*  P  S  */
854*0Sstevel@tonic-gate /* [C][C] */	+1, +1, +1, +1, -4,
855*0Sstevel@tonic-gate /* [C][N] */	+3, +3, -2, -2, -2,
856*0Sstevel@tonic-gate /* [N][C] */	+0, +0, +1, +1, -2,
857*0Sstevel@tonic-gate /* [N][N] */	+0, +0, +0, +0, +0
858*0Sstevel@tonic-gate };
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 
861*0Sstevel@tonic-gate static int
862*0Sstevel@tonic-gate pciide_map_rnumber(int rnumber, int pri_native, int sec_native)
863*0Sstevel@tonic-gate {
864*0Sstevel@tonic-gate 	/* transform flags into indexes */
865*0Sstevel@tonic-gate 	pri_native = pri_native ? 1 : 0;
866*0Sstevel@tonic-gate 	sec_native = sec_native ? 1 : 0;
867*0Sstevel@tonic-gate 
868*0Sstevel@tonic-gate 	rnumber += pciide_transform[pri_native][sec_native][rnumber];
869*0Sstevel@tonic-gate 	return (rnumber);
870*0Sstevel@tonic-gate }
871