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