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