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