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