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