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
51int	pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
52int	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
67static 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
87static 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
91static	int		pciide_ddi_ctlops(dev_info_t *dip, dev_info_t *rdip,
92				ddi_ctl_enum_t ctlop, void *arg,
93				void *result);
94
95static	int		pciide_get_pri(dev_info_t *dip, dev_info_t *rdip,
96				ddi_intr_handle_impl_t *hdlp, int *pri);
97
98static	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
102static struct intrspec *pciide_get_ispec(dev_info_t *dip, dev_info_t *rdip,
103				int inum);
104
105/*
106 * Local Functions
107 */
108static	int	pciide_initchild(dev_info_t *mydip, dev_info_t *cdip);
109
110static	void	pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip,
111				    int dev);
112static	int	pciide_pre26_rnumber_map(dev_info_t *mydip, int rnumber);
113static	int	pciide_map_rnumber(int canonical_rnumber, int pri_native,
114				    int sec_native);
115static int pciide_alloc_intr(dev_info_t *, dev_info_t *,
116    ddi_intr_handle_impl_t *, void *);
117static int pciide_free_intr(dev_info_t *, dev_info_t *,
118    ddi_intr_handle_impl_t *);
119
120extern 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
127struct 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
159struct 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
178static 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
184static struct modlinkage modlinkage = {
185	MODREV_1,
186	&modldrv,
187	NULL
188};
189
190
191int
192_init(void)
193{
194	return (mod_install(&modlinkage));
195}
196
197int
198_fini(void)
199{
200	return (mod_remove(&modlinkage));
201}
202
203int
204_info(struct modinfo *modinfop)
205{
206	return (mod_info(&modlinkage, modinfop));
207}
208
209int
210pciide_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*/
270int
271pciide_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*/
288static int
289pciide_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
458static int
459pciide_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
540static int
541pciide_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
614static struct intrspec *
615pciide_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
654static	int
655pciide_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
703static int
704pciide_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
777int
778pciide_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
830int
831pciide_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 */
885static void
886pciide_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
926static int
927pciide_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
985static	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
994static int
995pciide_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