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