xref: /netbsd-src/sys/dev/pci/pciide_common.c (revision 8c2c2eb16dae7953125fa4c904cda99dac6fe7a6)
1*8c2c2eb1Sthorpej /*	$NetBSD: pciide_common.c,v 1.71 2024/03/31 18:59:52 thorpej Exp $	*/
29d02ccdbSbouyer 
39d02ccdbSbouyer 
49d02ccdbSbouyer /*
59d02ccdbSbouyer  * Copyright (c) 1999, 2000, 2001, 2003 Manuel Bouyer.
69d02ccdbSbouyer  *
79d02ccdbSbouyer  * Redistribution and use in source and binary forms, with or without
89d02ccdbSbouyer  * modification, are permitted provided that the following conditions
99d02ccdbSbouyer  * are met:
109d02ccdbSbouyer  * 1. Redistributions of source code must retain the above copyright
119d02ccdbSbouyer  *    notice, this list of conditions and the following disclaimer.
129d02ccdbSbouyer  * 2. Redistributions in binary form must reproduce the above copyright
139d02ccdbSbouyer  *    notice, this list of conditions and the following disclaimer in the
149d02ccdbSbouyer  *    documentation and/or other materials provided with the distribution.
159d02ccdbSbouyer  *
169d02ccdbSbouyer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
179d02ccdbSbouyer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
189d02ccdbSbouyer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
199d02ccdbSbouyer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
209d02ccdbSbouyer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
219d02ccdbSbouyer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
229d02ccdbSbouyer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
239d02ccdbSbouyer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
249d02ccdbSbouyer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
259d02ccdbSbouyer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
269d02ccdbSbouyer  *
279d02ccdbSbouyer  */
289d02ccdbSbouyer 
299d02ccdbSbouyer 
309d02ccdbSbouyer /*
319d02ccdbSbouyer  * Copyright (c) 1996, 1998 Christopher G. Demetriou.  All rights reserved.
329d02ccdbSbouyer  *
339d02ccdbSbouyer  * Redistribution and use in source and binary forms, with or without
349d02ccdbSbouyer  * modification, are permitted provided that the following conditions
359d02ccdbSbouyer  * are met:
369d02ccdbSbouyer  * 1. Redistributions of source code must retain the above copyright
379d02ccdbSbouyer  *    notice, this list of conditions and the following disclaimer.
389d02ccdbSbouyer  * 2. Redistributions in binary form must reproduce the above copyright
399d02ccdbSbouyer  *    notice, this list of conditions and the following disclaimer in the
409d02ccdbSbouyer  *    documentation and/or other materials provided with the distribution.
419d02ccdbSbouyer  * 3. All advertising materials mentioning features or use of this software
429d02ccdbSbouyer  *    must display the following acknowledgement:
439d02ccdbSbouyer  *      This product includes software developed by Christopher G. Demetriou
449d02ccdbSbouyer  *	for the NetBSD Project.
459d02ccdbSbouyer  * 4. The name of the author may not be used to endorse or promote products
469d02ccdbSbouyer  *    derived from this software without specific prior written permission
479d02ccdbSbouyer  *
489d02ccdbSbouyer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
499d02ccdbSbouyer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
509d02ccdbSbouyer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
519d02ccdbSbouyer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
529d02ccdbSbouyer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
539d02ccdbSbouyer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
549d02ccdbSbouyer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
559d02ccdbSbouyer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
569d02ccdbSbouyer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
579d02ccdbSbouyer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
589d02ccdbSbouyer  */
599d02ccdbSbouyer 
609d02ccdbSbouyer /*
619d02ccdbSbouyer  * PCI IDE controller driver.
629d02ccdbSbouyer  *
639d02ccdbSbouyer  * Author: Christopher G. Demetriou, March 2, 1998 (derived from NetBSD
649d02ccdbSbouyer  * sys/dev/pci/ppb.c, revision 1.16).
659d02ccdbSbouyer  *
669d02ccdbSbouyer  * See "PCI IDE Controller Specification, Revision 1.0 3/4/94" and
679d02ccdbSbouyer  * "Programming Interface for Bus Master IDE Controller, Revision 1.0
689d02ccdbSbouyer  * 5/16/94" from the PCI SIG.
699d02ccdbSbouyer  *
709d02ccdbSbouyer  */
719d02ccdbSbouyer 
729d02ccdbSbouyer #include <sys/cdefs.h>
73*8c2c2eb1Sthorpej __KERNEL_RCSID(0, "$NetBSD: pciide_common.c,v 1.71 2024/03/31 18:59:52 thorpej Exp $");
749d02ccdbSbouyer 
759d02ccdbSbouyer #include <sys/param.h>
769d02ccdbSbouyer 
779d02ccdbSbouyer #include <dev/pci/pcireg.h>
789d02ccdbSbouyer #include <dev/pci/pcivar.h>
799d02ccdbSbouyer #include <dev/pci/pcidevs.h>
809d02ccdbSbouyer #include <dev/pci/pciidereg.h>
819d02ccdbSbouyer #include <dev/pci/pciidevar.h>
829d02ccdbSbouyer 
836242a545Sfvdl #include <dev/ic/wdcreg.h>
846242a545Sfvdl 
8546f42775Sthorpej #ifdef ATADEBUG
8646f42775Sthorpej int atadebug_pciide_mask = 0;
879d02ccdbSbouyer #endif
889d02ccdbSbouyer 
89bb09c44eSitohy #if NATA_DMA
909d02ccdbSbouyer static const char dmaerrfmt[] =
919d02ccdbSbouyer     "%s:%d: unable to %s table DMA map for drive %d, error=%d\n";
92bb09c44eSitohy #endif
939d02ccdbSbouyer 
949d02ccdbSbouyer /* Default product description for devices not known from this controller */
959d02ccdbSbouyer const struct pciide_product_desc default_product_desc = {
969d02ccdbSbouyer 	0,
979d02ccdbSbouyer 	0,
989d02ccdbSbouyer 	"Generic PCI IDE controller",
999d02ccdbSbouyer 	default_chip_map,
1009d02ccdbSbouyer };
1019d02ccdbSbouyer 
1029d02ccdbSbouyer const struct pciide_product_desc *
pciide_lookup_product(pcireg_t id,const struct pciide_product_desc * pp)103454af1c0Sdsl pciide_lookup_product(pcireg_t id, const struct pciide_product_desc *pp)
1049d02ccdbSbouyer {
1059d02ccdbSbouyer 	for (; pp->chip_map != NULL; pp++)
1069d02ccdbSbouyer 		if (PCI_PRODUCT(id) == pp->ide_product)
1079d02ccdbSbouyer 			break;
1089d02ccdbSbouyer 
1099d02ccdbSbouyer 	if (pp->chip_map == NULL)
1109d02ccdbSbouyer 		return NULL;
1119d02ccdbSbouyer 	return pp;
1129d02ccdbSbouyer }
1139d02ccdbSbouyer 
1149d02ccdbSbouyer void
pciide_common_attach(struct pciide_softc * sc,const struct pci_attach_args * pa,const struct pciide_product_desc * pp)1158bc54e5bSmsaitoh pciide_common_attach(struct pciide_softc *sc, const struct pci_attach_args *pa,
1168bc54e5bSmsaitoh     const struct pciide_product_desc *pp)
1179d02ccdbSbouyer {
1189d02ccdbSbouyer 	pci_chipset_tag_t pc = pa->pa_pc;
1199d02ccdbSbouyer 	pcitag_t tag = pa->pa_tag;
120bb09c44eSitohy #if NATA_DMA
1219d02ccdbSbouyer 	pcireg_t csr;
122bb09c44eSitohy #endif
123d8e1a7b6Sdrochner 	const char *displaydev = NULL;
124d8e1a7b6Sdrochner 	int dontprint = 0;
1259d02ccdbSbouyer 
1269d02ccdbSbouyer 	sc->sc_pci_id = pa->pa_id;
1279d02ccdbSbouyer 	if (pp == NULL) {
1289d02ccdbSbouyer 		/* should only happen for generic pciide devices */
1299d02ccdbSbouyer 		sc->sc_pp = &default_product_desc;
1309d02ccdbSbouyer 	} else {
1319d02ccdbSbouyer 		sc->sc_pp = pp;
132d8e1a7b6Sdrochner 		/* if ide_name == NULL, printf is done in chip-specific map */
133d8e1a7b6Sdrochner 		if (pp->ide_name)
134d8e1a7b6Sdrochner 			displaydev = pp->ide_name;
135d8e1a7b6Sdrochner 		else
136d8e1a7b6Sdrochner 			dontprint = 1;
1379d02ccdbSbouyer 	}
1389d02ccdbSbouyer 
139d8e1a7b6Sdrochner 	if (dontprint) {
140d8e1a7b6Sdrochner 		aprint_naive("disk controller\n");
141d8e1a7b6Sdrochner 		aprint_normal("\n"); /* ??? */
142d8e1a7b6Sdrochner 	} else
143d8e1a7b6Sdrochner 		pci_aprint_devinfo_fancy(pa, "disk controller", displaydev, 1);
1449d02ccdbSbouyer 
1459d02ccdbSbouyer 	sc->sc_pc = pa->pa_pc;
1469d02ccdbSbouyer 	sc->sc_tag = pa->pa_tag;
1479d02ccdbSbouyer 
148bb09c44eSitohy #if NATA_DMA
1499d02ccdbSbouyer 	/* Set up DMA defaults; these might be adjusted by chip_map. */
1509d02ccdbSbouyer 	sc->sc_dma_maxsegsz = IDEDMA_BYTE_COUNT_MAX;
1519d02ccdbSbouyer 	sc->sc_dma_boundary = IDEDMA_BYTE_COUNT_ALIGN;
152bb09c44eSitohy #endif
1539d02ccdbSbouyer 
15446f42775Sthorpej #ifdef ATADEBUG
15546f42775Sthorpej 	if (atadebug_pciide_mask & DEBUG_PROBE)
1569d02ccdbSbouyer 		pci_conf_print(sc->sc_pc, sc->sc_tag, NULL);
1579d02ccdbSbouyer #endif
1589d02ccdbSbouyer 	sc->sc_pp->chip_map(sc, pa);
1599d02ccdbSbouyer 
160bb09c44eSitohy #if NATA_DMA
1619d02ccdbSbouyer 	if (sc->sc_dma_ok) {
1629d02ccdbSbouyer 		csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
1639d02ccdbSbouyer 		csr |= PCI_COMMAND_MASTER_ENABLE;
1649d02ccdbSbouyer 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
1659d02ccdbSbouyer 	}
166bb09c44eSitohy #endif
16746f42775Sthorpej 	ATADEBUG_PRINT(("pciide: command/status register=%x\n",
1689d02ccdbSbouyer 	    pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG)), DEBUG_PROBE);
1699d02ccdbSbouyer }
1709d02ccdbSbouyer 
1715947ac4eSjakllsch int
pciide_common_detach(struct pciide_softc * sc,int flags)1725947ac4eSjakllsch pciide_common_detach(struct pciide_softc *sc, int flags)
1735947ac4eSjakllsch {
1745947ac4eSjakllsch 	struct pciide_channel *cp;
1755947ac4eSjakllsch 	struct ata_channel *wdc_cp;
1765947ac4eSjakllsch 	struct wdc_regs *wdr;
1775947ac4eSjakllsch 	int channel, drive;
1785947ac4eSjakllsch 	int rv;
1795947ac4eSjakllsch 
1805947ac4eSjakllsch 	rv = wdcdetach(sc->sc_wdcdev.sc_atac.atac_dev, flags);
1815947ac4eSjakllsch 	if (rv)
1825947ac4eSjakllsch 		return rv;
1835947ac4eSjakllsch 
1845947ac4eSjakllsch 	for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels;
1855947ac4eSjakllsch 	     channel++) {
1865947ac4eSjakllsch 		cp = &sc->pciide_channels[channel];
1875947ac4eSjakllsch 		wdc_cp = &cp->ata_channel;
1885947ac4eSjakllsch 		wdr = CHAN_TO_WDC_REGS(wdc_cp);
1895947ac4eSjakllsch 
1905947ac4eSjakllsch 		if (wdc_cp->ch_flags & ATACH_DISABLED)
1915947ac4eSjakllsch 			continue;
1925947ac4eSjakllsch 
1935947ac4eSjakllsch 		if (wdr->cmd_ios != 0)
1945947ac4eSjakllsch 			bus_space_unmap(wdr->cmd_iot,
1955947ac4eSjakllsch 			    wdr->cmd_baseioh, wdr->cmd_ios);
1965947ac4eSjakllsch 		if (cp->compat != 0) {
1975947ac4eSjakllsch 			if (wdr->ctl_ios != 0)
1985947ac4eSjakllsch 				bus_space_unmap(wdr->ctl_iot,
1995947ac4eSjakllsch 				    wdr->ctl_ioh, wdr->ctl_ios);
2005947ac4eSjakllsch 		} else {
2015947ac4eSjakllsch 			if (cp->ctl_ios != 0)
2025947ac4eSjakllsch 				bus_space_unmap(wdr->ctl_iot,
2035947ac4eSjakllsch 				    cp->ctl_baseioh, cp->ctl_ios);
2045947ac4eSjakllsch 		}
2055947ac4eSjakllsch 
2069edd4d81Sbouyer 		for (drive = 0; drive < sc->sc_wdcdev.wdc_maxdrives; drive++) {
2074c604820Sdholland #if NATA_DMA
2085947ac4eSjakllsch 			pciide_dma_table_teardown(sc, channel, drive);
2094c604820Sdholland #endif
2105947ac4eSjakllsch 		}
2115947ac4eSjakllsch 	}
2125947ac4eSjakllsch 
2134c604820Sdholland #if NATA_DMA
2145947ac4eSjakllsch 	if (sc->sc_dma_ios != 0)
2155947ac4eSjakllsch 		bus_space_unmap(sc->sc_dma_iot, sc->sc_dma_ioh, sc->sc_dma_ios);
2165947ac4eSjakllsch 	if (sc->sc_ba5_ss != 0)
217311896a4Sjakllsch 		bus_space_unmap(sc->sc_ba5_st, sc->sc_ba5_sh, sc->sc_ba5_ss);
2184c604820Sdholland #endif
2195947ac4eSjakllsch 
2205947ac4eSjakllsch 	return 0;
2215947ac4eSjakllsch }
2225947ac4eSjakllsch 
2234d3ab04cSjakllsch int
pciide_detach(device_t self,int flags)2244d3ab04cSjakllsch pciide_detach(device_t self, int flags)
2254d3ab04cSjakllsch {
2264d3ab04cSjakllsch 	struct pciide_softc *sc = device_private(self);
2274d3ab04cSjakllsch 	struct pciide_channel *cp;
2284d3ab04cSjakllsch 	int channel;
2294d3ab04cSjakllsch #ifndef __HAVE_PCIIDE_MACHDEP_COMPAT_INTR_DISESTABLISH
2304d3ab04cSjakllsch 	bool has_compat_chan;
2314d3ab04cSjakllsch 
2324d3ab04cSjakllsch 	has_compat_chan = false;
2334d3ab04cSjakllsch 	for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels;
2344d3ab04cSjakllsch 	     channel++) {
2354d3ab04cSjakllsch 		cp = &sc->pciide_channels[channel];
2364d3ab04cSjakllsch 		if (cp->compat != 0) {
2374d3ab04cSjakllsch 			has_compat_chan = true;
2384d3ab04cSjakllsch 		}
2394d3ab04cSjakllsch 	}
2404d3ab04cSjakllsch 
2414d3ab04cSjakllsch 	if (has_compat_chan != false)
2424d3ab04cSjakllsch 		return EBUSY;
2434d3ab04cSjakllsch #endif
2444d3ab04cSjakllsch 
2454d3ab04cSjakllsch 	for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels;
2464d3ab04cSjakllsch 	     channel++) {
2474d3ab04cSjakllsch 		cp = &sc->pciide_channels[channel];
2484d3ab04cSjakllsch 		if (cp->compat != 0)
2498ec6a202Sjakllsch 			if (cp->ih != NULL) {
2504d3ab04cSjakllsch 			       pciide_unmap_compat_intr(sc->sc_pc, cp, channel);
2518ec6a202Sjakllsch 			       cp->ih = NULL;
2528ec6a202Sjakllsch 			}
2534d3ab04cSjakllsch 	}
2544d3ab04cSjakllsch 
2558ec6a202Sjakllsch 	if (sc->sc_pci_ih != NULL) {
2564d3ab04cSjakllsch 		pci_intr_disestablish(sc->sc_pc, sc->sc_pci_ih);
2578ec6a202Sjakllsch 		sc->sc_pci_ih = NULL;
2588ec6a202Sjakllsch 	}
2594d3ab04cSjakllsch 
2604d3ab04cSjakllsch 	return pciide_common_detach(sc, flags);
2614d3ab04cSjakllsch }
2624d3ab04cSjakllsch 
2639d02ccdbSbouyer /* tell whether the chip is enabled or not */
2649d02ccdbSbouyer int
pciide_chipen(struct pciide_softc * sc,const struct pci_attach_args * pa)265d3e53912Sdyoung pciide_chipen(struct pciide_softc *sc, const struct pci_attach_args *pa)
2669d02ccdbSbouyer {
2679d02ccdbSbouyer 	pcireg_t csr;
2689d02ccdbSbouyer 
269a6b2b839Sdyoung 	if ((pa->pa_flags & PCI_FLAGS_IO_OKAY) == 0) {
2707aa6248cScube 		aprint_normal_dev(sc->sc_wdcdev.sc_atac.atac_dev,
271e4c26632Sdyoung 		    "I/O access disabled at bridge\n");
272e4c26632Sdyoung 		return 0;
273e4c26632Sdyoung 	}
274e4c26632Sdyoung 	csr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG);
275e4c26632Sdyoung 	if ((csr & PCI_COMMAND_IO_ENABLE) == 0) {
276e4c26632Sdyoung 		aprint_normal_dev(sc->sc_wdcdev.sc_atac.atac_dev,
277e4c26632Sdyoung 		    "I/O access disabled at device\n");
2789d02ccdbSbouyer 		return 0;
2799d02ccdbSbouyer 	}
2809d02ccdbSbouyer 	return 1;
2819d02ccdbSbouyer }
2829d02ccdbSbouyer 
2839d02ccdbSbouyer void
pciide_mapregs_compat(const struct pci_attach_args * pa,struct pciide_channel * cp,int compatchan)2848bc54e5bSmsaitoh pciide_mapregs_compat(const struct pci_attach_args *pa,
2858bc54e5bSmsaitoh     struct pciide_channel *cp, int compatchan)
2869d02ccdbSbouyer {
2871600c8b8Sthorpej 	struct pciide_softc *sc = CHAN_TO_PCIIDE(&cp->ata_channel);
2884b51cecfSthorpej 	struct ata_channel *wdc_cp = &cp->ata_channel;
2891600c8b8Sthorpej 	struct wdc_regs *wdr = CHAN_TO_WDC_REGS(wdc_cp);
2906242a545Sfvdl 	int i;
2919d02ccdbSbouyer 
2929d02ccdbSbouyer 	cp->compat = 1;
2939d02ccdbSbouyer 
2944b51cecfSthorpej 	wdr->cmd_iot = pa->pa_iot;
2954b51cecfSthorpej 	if (bus_space_map(wdr->cmd_iot, PCIIDE_COMPAT_CMD_BASE(compatchan),
2964b51cecfSthorpej 	    PCIIDE_COMPAT_CMD_SIZE, 0, &wdr->cmd_baseioh) != 0) {
2977aa6248cScube 		aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
2987aa6248cScube 		    "couldn't map %s channel cmd regs\n", cp->name);
2999d02ccdbSbouyer 		goto bad;
3009d02ccdbSbouyer 	}
3015947ac4eSjakllsch 	wdr->cmd_ios = PCIIDE_COMPAT_CMD_SIZE;
3029d02ccdbSbouyer 
3034b51cecfSthorpej 	wdr->ctl_iot = pa->pa_iot;
3044b51cecfSthorpej 	if (bus_space_map(wdr->ctl_iot, PCIIDE_COMPAT_CTL_BASE(compatchan),
3054b51cecfSthorpej 	    PCIIDE_COMPAT_CTL_SIZE, 0, &wdr->ctl_ioh) != 0) {
3067aa6248cScube 		aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
3077aa6248cScube 		    "couldn't map %s channel ctl regs\n", cp->name);
3085947ac4eSjakllsch 		bus_space_unmap(wdr->cmd_iot, wdr->cmd_baseioh, wdr->cmd_ios);
3099d02ccdbSbouyer 		goto bad;
3109d02ccdbSbouyer 	}
3115947ac4eSjakllsch 	wdr->ctl_ios = PCIIDE_COMPAT_CTL_SIZE;
3129d02ccdbSbouyer 
3136242a545Sfvdl 	for (i = 0; i < WDC_NREG; i++) {
3144b51cecfSthorpej 		if (bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh, i,
3154b51cecfSthorpej 		    i == 0 ? 4 : 1, &wdr->cmd_iohs[i]) != 0) {
3167aa6248cScube 			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
3177aa6248cScube 			    "couldn't subregion %s channel cmd regs\n",
3187aa6248cScube 			    cp->name);
3196242a545Sfvdl 			goto bad;
3206242a545Sfvdl 		}
3216242a545Sfvdl 	}
32226cf6855Sjdolecek 	wdc_init_shadow_regs(wdr);
3234b51cecfSthorpej 	wdr->data32iot = wdr->cmd_iot;
3244b51cecfSthorpej 	wdr->data32ioh = wdr->cmd_iohs[0];
3259d02ccdbSbouyer 	return;
3269d02ccdbSbouyer 
3279d02ccdbSbouyer bad:
3284b51cecfSthorpej 	cp->ata_channel.ch_flags |= ATACH_DISABLED;
3299d02ccdbSbouyer 	return;
3309d02ccdbSbouyer }
3319d02ccdbSbouyer 
3329d02ccdbSbouyer void
pciide_mapregs_native(const struct pci_attach_args * pa,struct pciide_channel * cp,int (* pci_intr)(void *))333d3e53912Sdyoung pciide_mapregs_native(const struct pci_attach_args *pa,
3345947ac4eSjakllsch 	struct pciide_channel *cp, int (*pci_intr)(void *))
3359d02ccdbSbouyer {
3361600c8b8Sthorpej 	struct pciide_softc *sc = CHAN_TO_PCIIDE(&cp->ata_channel);
3374b51cecfSthorpej 	struct ata_channel *wdc_cp = &cp->ata_channel;
3381600c8b8Sthorpej 	struct wdc_regs *wdr = CHAN_TO_WDC_REGS(wdc_cp);
3399d02ccdbSbouyer 	const char *intrstr;
3409d02ccdbSbouyer 	pci_intr_handle_t intrhandle;
3416242a545Sfvdl 	int i;
342e58a356cSchristos 	char intrbuf[PCI_INTRSTR_LEN];
3439d02ccdbSbouyer 
3449d02ccdbSbouyer 	cp->compat = 0;
3459d02ccdbSbouyer 
3469d02ccdbSbouyer 	if (sc->sc_pci_ih == NULL) {
3479d02ccdbSbouyer 		if (pci_intr_map(pa, &intrhandle) != 0) {
3487aa6248cScube 			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
3497aa6248cScube 			    "couldn't map native-PCI interrupt\n");
3509d02ccdbSbouyer 			goto bad;
3519d02ccdbSbouyer 		}
352e58a356cSchristos 		intrstr = pci_intr_string(pa->pa_pc, intrhandle, intrbuf, sizeof(intrbuf));
3539270f1e8Sjdolecek 		sc->sc_pci_ih = pci_intr_establish_xname(pa->pa_pc,
3549270f1e8Sjdolecek 		    intrhandle, IPL_BIO, pci_intr, sc,
3559270f1e8Sjdolecek 		    device_xname(sc->sc_wdcdev.sc_atac.atac_dev));
3569d02ccdbSbouyer 		if (sc->sc_pci_ih != NULL) {
3577aa6248cScube 			aprint_normal_dev(sc->sc_wdcdev.sc_atac.atac_dev,
3587aa6248cScube 			    "using %s for native-PCI interrupt\n",
3599d02ccdbSbouyer 			    intrstr ? intrstr : "unknown interrupt");
3609d02ccdbSbouyer 		} else {
3617aa6248cScube 			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
3627aa6248cScube 			    "couldn't establish native-PCI interrupt");
3639d02ccdbSbouyer 			if (intrstr != NULL)
3647aa6248cScube 				aprint_error(" at %s", intrstr);
3657aa6248cScube 			aprint_error("\n");
3669d02ccdbSbouyer 			goto bad;
3679d02ccdbSbouyer 		}
3689d02ccdbSbouyer 	}
3699d02ccdbSbouyer 	cp->ih = sc->sc_pci_ih;
370a963286fSthorpej 	if (pci_mapreg_map(pa, PCIIDE_REG_CMD_BASE(wdc_cp->ch_channel),
3719d02ccdbSbouyer 	    PCI_MAPREG_TYPE_IO, 0,
3725947ac4eSjakllsch 	    &wdr->cmd_iot, &wdr->cmd_baseioh, NULL, &wdr->cmd_ios) != 0) {
3737aa6248cScube 		aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
3747aa6248cScube 		    "couldn't map %s channel cmd regs\n", cp->name);
3759d02ccdbSbouyer 		goto bad;
3769d02ccdbSbouyer 	}
3779d02ccdbSbouyer 
378a963286fSthorpej 	if (pci_mapreg_map(pa, PCIIDE_REG_CTL_BASE(wdc_cp->ch_channel),
3799d02ccdbSbouyer 	    PCI_MAPREG_TYPE_IO, 0,
3805947ac4eSjakllsch 	    &wdr->ctl_iot, &cp->ctl_baseioh, NULL, &cp->ctl_ios) != 0) {
3817aa6248cScube 		aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
3827aa6248cScube 		    "couldn't map %s channel ctl regs\n", cp->name);
3835947ac4eSjakllsch 		bus_space_unmap(wdr->cmd_iot, wdr->cmd_baseioh, wdr->cmd_ios);
3849d02ccdbSbouyer 		goto bad;
3859d02ccdbSbouyer 	}
3869d02ccdbSbouyer 	/*
3879d02ccdbSbouyer 	 * In native mode, 4 bytes of I/O space are mapped for the control
3889d02ccdbSbouyer 	 * register, the control register is at offset 2. Pass the generic
3899d02ccdbSbouyer 	 * code a handle for only one byte at the right offset.
3909d02ccdbSbouyer 	 */
3914b51cecfSthorpej 	if (bus_space_subregion(wdr->ctl_iot, cp->ctl_baseioh, 2, 1,
3924b51cecfSthorpej 	    &wdr->ctl_ioh) != 0) {
3937aa6248cScube 		aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
3947aa6248cScube 		    "unable to subregion %s channel ctl regs\n", cp->name);
3955947ac4eSjakllsch 		bus_space_unmap(wdr->cmd_iot, wdr->cmd_baseioh, wdr->cmd_ios);
3965947ac4eSjakllsch 		bus_space_unmap(wdr->cmd_iot, cp->ctl_baseioh, cp->ctl_ios);
3979d02ccdbSbouyer 		goto bad;
3989d02ccdbSbouyer 	}
3999d02ccdbSbouyer 
4006242a545Sfvdl 	for (i = 0; i < WDC_NREG; i++) {
4014b51cecfSthorpej 		if (bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh, i,
4024b51cecfSthorpej 		    i == 0 ? 4 : 1, &wdr->cmd_iohs[i]) != 0) {
4037aa6248cScube 			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
4047aa6248cScube 			    "couldn't subregion %s channel cmd regs\n",
4057aa6248cScube 			    cp->name);
4066242a545Sfvdl 			goto bad;
4076242a545Sfvdl 		}
4086242a545Sfvdl 	}
40926cf6855Sjdolecek 	wdc_init_shadow_regs(wdr);
4104b51cecfSthorpej 	wdr->data32iot = wdr->cmd_iot;
4114b51cecfSthorpej 	wdr->data32ioh = wdr->cmd_iohs[0];
4129d02ccdbSbouyer 	return;
4139d02ccdbSbouyer 
4149d02ccdbSbouyer bad:
4154b51cecfSthorpej 	cp->ata_channel.ch_flags |= ATACH_DISABLED;
4169d02ccdbSbouyer 	return;
4179d02ccdbSbouyer }
4189d02ccdbSbouyer 
419bb09c44eSitohy #if NATA_DMA
4209d02ccdbSbouyer void
pciide_mapreg_dma(struct pciide_softc * sc,const struct pci_attach_args * pa)421d3e53912Sdyoung pciide_mapreg_dma(struct pciide_softc *sc, const struct pci_attach_args *pa)
4229d02ccdbSbouyer {
4239d02ccdbSbouyer 	pcireg_t maptype;
4249d02ccdbSbouyer 	bus_addr_t addr;
4256242a545Sfvdl 	struct pciide_channel *pc;
4266242a545Sfvdl 	int reg, chan;
4276242a545Sfvdl 	bus_size_t size;
4289d02ccdbSbouyer 
4299d02ccdbSbouyer 	/*
4309d02ccdbSbouyer 	 * Map DMA registers
4319d02ccdbSbouyer 	 *
4329d02ccdbSbouyer 	 * Note that sc_dma_ok is the right variable to test to see if
4339d02ccdbSbouyer 	 * DMA can be done.  If the interface doesn't support DMA,
4349d02ccdbSbouyer 	 * sc_dma_ok will never be non-zero.  If the DMA regs couldn't
4359d02ccdbSbouyer 	 * be mapped, it'll be zero.  I.e., sc_dma_ok will only be
4369d02ccdbSbouyer 	 * non-zero if the interface supports DMA and the registers
4379d02ccdbSbouyer 	 * could be mapped.
4389d02ccdbSbouyer 	 *
4399d02ccdbSbouyer 	 * XXX Note that despite the fact that the Bus Master IDE specs
4409d02ccdbSbouyer 	 * XXX say that "The bus master IDE function uses 16 bytes of IO
4419d02ccdbSbouyer 	 * XXX space," some controllers (at least the United
4429d02ccdbSbouyer 	 * XXX Microelectronics UM8886BF) place it in memory space.
4439d02ccdbSbouyer 	 */
4449d02ccdbSbouyer 	maptype = pci_mapreg_type(pa->pa_pc, pa->pa_tag,
4459d02ccdbSbouyer 	    PCIIDE_REG_BUS_MASTER_DMA);
4469d02ccdbSbouyer 
4479d02ccdbSbouyer 	switch (maptype) {
4489d02ccdbSbouyer 	case PCI_MAPREG_TYPE_IO:
4499d02ccdbSbouyer 		sc->sc_dma_ok = (pci_mapreg_info(pa->pa_pc, pa->pa_tag,
4509d02ccdbSbouyer 		    PCIIDE_REG_BUS_MASTER_DMA, PCI_MAPREG_TYPE_IO,
4519d02ccdbSbouyer 		    &addr, NULL, NULL) == 0);
4529d02ccdbSbouyer 		if (sc->sc_dma_ok == 0) {
453b07ec3fcSad 			aprint_verbose(
4549d02ccdbSbouyer 			    ", but unused (couldn't query registers)");
4559d02ccdbSbouyer 			break;
4569d02ccdbSbouyer 		}
4579d02ccdbSbouyer 		if ((sc->sc_pp->ide_flags & IDE_16BIT_IOSPACE)
4589d02ccdbSbouyer 		    && addr >= 0x10000) {
4599d02ccdbSbouyer 			sc->sc_dma_ok = 0;
460b07ec3fcSad 			aprint_verbose(
4619d02ccdbSbouyer 			    ", but unused (registers at unsafe address "
4629d02ccdbSbouyer 			    "%#lx)", (unsigned long)addr);
4639d02ccdbSbouyer 			break;
4649d02ccdbSbouyer 		}
4659d02ccdbSbouyer 		/* FALLTHROUGH */
4669d02ccdbSbouyer 
4679d02ccdbSbouyer 	case PCI_MAPREG_MEM_TYPE_32BIT:
4689d02ccdbSbouyer 		sc->sc_dma_ok = (pci_mapreg_map(pa,
4699d02ccdbSbouyer 		    PCIIDE_REG_BUS_MASTER_DMA, maptype, 0,
4705947ac4eSjakllsch 		    &sc->sc_dma_iot, &sc->sc_dma_ioh, NULL, &sc->sc_dma_ios)
4715947ac4eSjakllsch 		    == 0);
4729d02ccdbSbouyer 		sc->sc_dmat = pa->pa_dmat;
4739d02ccdbSbouyer 		if (sc->sc_dma_ok == 0) {
474b07ec3fcSad 			aprint_verbose(", but unused (couldn't map registers)");
4759d02ccdbSbouyer 		} else {
4769d02ccdbSbouyer 			sc->sc_wdcdev.dma_arg = sc;
4779d02ccdbSbouyer 			sc->sc_wdcdev.dma_init = pciide_dma_init;
4789d02ccdbSbouyer 			sc->sc_wdcdev.dma_start = pciide_dma_start;
4799d02ccdbSbouyer 			sc->sc_wdcdev.dma_finish = pciide_dma_finish;
4809d02ccdbSbouyer 		}
4819d02ccdbSbouyer 
4827aa6248cScube 		if (device_cfdata(sc->sc_wdcdev.sc_atac.atac_dev)->cf_flags &
4839d02ccdbSbouyer 		    PCIIDE_OPTIONS_NODMA) {
484b07ec3fcSad 			aprint_verbose(
4859d02ccdbSbouyer 			    ", but unused (forced off by config file)");
4869d02ccdbSbouyer 			sc->sc_dma_ok = 0;
487*8c2c2eb1Sthorpej 		} else {
488*8c2c2eb1Sthorpej 			bool disable;
489*8c2c2eb1Sthorpej 
490*8c2c2eb1Sthorpej 			if (prop_dictionary_get_bool(
491*8c2c2eb1Sthorpej 			    device_properties(sc->sc_wdcdev.sc_atac.atac_dev),
492*8c2c2eb1Sthorpej 			    "pciide-disable-dma", &disable) && disable) {
493*8c2c2eb1Sthorpej 				aprint_verbose(
494*8c2c2eb1Sthorpej 				    ", but unused (disabled by platform)");
495*8c2c2eb1Sthorpej 				sc->sc_dma_ok = 0;
496*8c2c2eb1Sthorpej 			}
4979d02ccdbSbouyer 		}
4989d02ccdbSbouyer 		break;
4999d02ccdbSbouyer 
5009d02ccdbSbouyer 	default:
5019d02ccdbSbouyer 		sc->sc_dma_ok = 0;
502b07ec3fcSad 		aprint_verbose(
5039d02ccdbSbouyer 		    ", but unsupported register maptype (0x%x)", maptype);
5049d02ccdbSbouyer 	}
5056242a545Sfvdl 
506851ca6faSbouyer 	if (sc->sc_dma_ok == 0)
507851ca6faSbouyer 		return;
508851ca6faSbouyer 
5096242a545Sfvdl 	/*
5106242a545Sfvdl 	 * Set up the default handles for the DMA registers.
5116242a545Sfvdl 	 * Just reserve 32 bits for each handle, unless space
5126242a545Sfvdl 	 * doesn't permit it.
5136242a545Sfvdl 	 */
5146242a545Sfvdl 	for (chan = 0; chan < PCIIDE_NUM_CHANNELS; chan++) {
5156242a545Sfvdl 		pc = &sc->pciide_channels[chan];
5166242a545Sfvdl 		for (reg = 0; reg < IDEDMA_NREGS; reg++) {
5176242a545Sfvdl 			size = 4;
5186242a545Sfvdl 			if (size > (IDEDMA_SCH_OFFSET - reg))
5196242a545Sfvdl 				size = IDEDMA_SCH_OFFSET - reg;
5206242a545Sfvdl 			if (bus_space_subregion(sc->sc_dma_iot, sc->sc_dma_ioh,
5216242a545Sfvdl 			    IDEDMA_SCH_OFFSET * chan + reg, size,
5226242a545Sfvdl 			    &pc->dma_iohs[reg]) != 0) {
5236242a545Sfvdl 				sc->sc_dma_ok = 0;
524b07ec3fcSad 				aprint_verbose(", but can't subregion offset %d "
5256242a545Sfvdl 					      "size %lu", reg, (u_long)size);
5266242a545Sfvdl 				return;
5276242a545Sfvdl 			}
5286242a545Sfvdl 		}
5296242a545Sfvdl 	}
5309d02ccdbSbouyer }
531bb09c44eSitohy #endif	/* NATA_DMA */
5329d02ccdbSbouyer 
5339d02ccdbSbouyer int
pciide_compat_intr(void * arg)534454af1c0Sdsl pciide_compat_intr(void *arg)
5359d02ccdbSbouyer {
5369d02ccdbSbouyer 	struct pciide_channel *cp = arg;
5379d02ccdbSbouyer 
5389d02ccdbSbouyer #ifdef DIAGNOSTIC
5399d02ccdbSbouyer 	/* should only be called for a compat channel */
5409d02ccdbSbouyer 	if (cp->compat == 0)
5419d02ccdbSbouyer 		panic("pciide compat intr called for non-compat chan %p", cp);
5429d02ccdbSbouyer #endif
5434b51cecfSthorpej 	return (wdcintr(&cp->ata_channel));
5449d02ccdbSbouyer }
5459d02ccdbSbouyer 
5469d02ccdbSbouyer int
pciide_pci_intr(void * arg)547454af1c0Sdsl pciide_pci_intr(void *arg)
5489d02ccdbSbouyer {
5499d02ccdbSbouyer 	struct pciide_softc *sc = arg;
5509d02ccdbSbouyer 	struct pciide_channel *cp;
5514b51cecfSthorpej 	struct ata_channel *wdc_cp;
5529d02ccdbSbouyer 	int i, rv, crv;
5539d02ccdbSbouyer 
5549d02ccdbSbouyer 	rv = 0;
5559cc521a1Sthorpej 	for (i = 0; i < sc->sc_wdcdev.sc_atac.atac_nchannels; i++) {
5569d02ccdbSbouyer 		cp = &sc->pciide_channels[i];
5574b51cecfSthorpej 		wdc_cp = &cp->ata_channel;
5589d02ccdbSbouyer 
5599d02ccdbSbouyer 		/* If a compat channel skip. */
5609d02ccdbSbouyer 		if (cp->compat)
5619d02ccdbSbouyer 			continue;
5629d02ccdbSbouyer 
5632ee262caSjdolecek 		/* if this channel not waiting for intr, skip */
5642ee262caSjdolecek 		if ((wdc_cp->ch_flags & ATACH_IRQ_WAIT) == 0)
5652ee262caSjdolecek 			continue;
5662ee262caSjdolecek 
5679d02ccdbSbouyer 		crv = wdcintr(wdc_cp);
5689d02ccdbSbouyer 		if (crv == 0)
5699d02ccdbSbouyer 			;		/* leave rv alone */
5709d02ccdbSbouyer 		else if (crv == 1)
5719d02ccdbSbouyer 			rv = 1;		/* claim the intr */
5729d02ccdbSbouyer 		else if (rv == 0)	/* crv should be -1 in this case */
5739d02ccdbSbouyer 			rv = crv;	/* if we've done no better, take it */
5749d02ccdbSbouyer 	}
5759d02ccdbSbouyer 	return (rv);
5769d02ccdbSbouyer }
5779d02ccdbSbouyer 
578bb09c44eSitohy #if NATA_DMA
5799d02ccdbSbouyer void
pciide_channel_dma_setup(struct pciide_channel * cp)580454af1c0Sdsl pciide_channel_dma_setup(struct pciide_channel *cp)
5819d02ccdbSbouyer {
582335b7995Sthorpej 	int drive, s;
5831600c8b8Sthorpej 	struct pciide_softc *sc = CHAN_TO_PCIIDE(&cp->ata_channel);
5849d02ccdbSbouyer 	struct ata_drive_datas *drvp;
5859d02ccdbSbouyer 
5869edd4d81Sbouyer 	KASSERT(cp->ata_channel.ch_ndrives != 0);
5874b51cecfSthorpej 
5889edd4d81Sbouyer 	for (drive = 0; drive < cp->ata_channel.ch_ndrives; drive++) {
5894b51cecfSthorpej 		drvp = &cp->ata_channel.ch_drive[drive];
5909d02ccdbSbouyer 		/* If no drive, skip */
5919edd4d81Sbouyer 		if (drvp->drive_type == ATA_DRIVET_NONE)
5929d02ccdbSbouyer 			continue;
5939d02ccdbSbouyer 		/* setup DMA if needed */
5949edd4d81Sbouyer 		if (((drvp->drive_flags & ATA_DRIVE_DMA) == 0 &&
5959edd4d81Sbouyer 		    (drvp->drive_flags & ATA_DRIVE_UDMA) == 0) ||
5969d02ccdbSbouyer 		    sc->sc_dma_ok == 0) {
597335b7995Sthorpej 			s = splbio();
5989edd4d81Sbouyer 			drvp->drive_flags &= ~(ATA_DRIVE_DMA | ATA_DRIVE_UDMA);
599335b7995Sthorpej 			splx(s);
6009d02ccdbSbouyer 			continue;
6019d02ccdbSbouyer 		}
6024b51cecfSthorpej 		if (pciide_dma_table_setup(sc, cp->ata_channel.ch_channel,
603a963286fSthorpej 					   drive) != 0) {
6049d02ccdbSbouyer 			/* Abort DMA setup */
605335b7995Sthorpej 			s = splbio();
6069edd4d81Sbouyer 			drvp->drive_flags &= ~(ATA_DRIVE_DMA | ATA_DRIVE_UDMA);
607335b7995Sthorpej 			splx(s);
6089d02ccdbSbouyer 			continue;
6099d02ccdbSbouyer 		}
6109d02ccdbSbouyer 	}
6119d02ccdbSbouyer }
6129d02ccdbSbouyer 
613f5218aadSbriggs #define NIDEDMA_TABLES(sc)	\
614d1579b2dSriastradh 	(MAXPHYS/(uimin((sc)->sc_dma_maxsegsz, PAGE_SIZE)) + 1)
615f5218aadSbriggs 
6169d02ccdbSbouyer int
pciide_dma_table_setup(struct pciide_softc * sc,int channel,int drive)61782357f6dSdsl pciide_dma_table_setup(struct pciide_softc *sc, int channel, int drive)
6189d02ccdbSbouyer {
6195947ac4eSjakllsch 	int error;
6209d02ccdbSbouyer 	const bus_size_t dma_table_size =
621f5218aadSbriggs 	    sizeof(struct idedma_table) * NIDEDMA_TABLES(sc);
6229d02ccdbSbouyer 	struct pciide_dma_maps *dma_maps =
6239d02ccdbSbouyer 	    &sc->pciide_channels[channel].dma_maps[drive];
6249d02ccdbSbouyer 
6259d02ccdbSbouyer 	/* If table was already allocated, just return */
6269d02ccdbSbouyer 	if (dma_maps->dma_table)
6279d02ccdbSbouyer 		return 0;
6289d02ccdbSbouyer 
6299d02ccdbSbouyer 	/* Allocate memory for the DMA tables and map it */
6309d02ccdbSbouyer 	if ((error = bus_dmamem_alloc(sc->sc_dmat, dma_table_size,
6315947ac4eSjakllsch 	    IDEDMA_TBL_ALIGN, IDEDMA_TBL_ALIGN, &dma_maps->dmamap_table_seg,
6325947ac4eSjakllsch 	    1, &dma_maps->dmamap_table_nseg, BUS_DMA_NOWAIT)) != 0) {
6337aa6248cScube 		aprint_error(dmaerrfmt,
6347aa6248cScube 		    device_xname(sc->sc_wdcdev.sc_atac.atac_dev), channel,
6357aa6248cScube 		    "allocate", drive, error);
6369d02ccdbSbouyer 		return error;
6379d02ccdbSbouyer 	}
6385947ac4eSjakllsch 	if ((error = bus_dmamem_map(sc->sc_dmat, &dma_maps->dmamap_table_seg,
6395947ac4eSjakllsch 	    dma_maps->dmamap_table_nseg, dma_table_size,
64053524e44Schristos 	    (void **)&dma_maps->dma_table,
6419d02ccdbSbouyer 	    BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
6427aa6248cScube 		aprint_error(dmaerrfmt,
6437aa6248cScube 		    device_xname(sc->sc_wdcdev.sc_atac.atac_dev), channel,
6447aa6248cScube 		    "map", drive, error);
6459d02ccdbSbouyer 		return error;
6469d02ccdbSbouyer 	}
64746f42775Sthorpej 	ATADEBUG_PRINT(("pciide_dma_table_setup: table at %p len %lu, "
6489d02ccdbSbouyer 	    "phy 0x%lx\n", dma_maps->dma_table, (u_long)dma_table_size,
6495947ac4eSjakllsch 	    (unsigned long)dma_maps->dmamap_table_seg.ds_addr), DEBUG_PROBE);
6509d02ccdbSbouyer 	/* Create and load table DMA map for this disk */
6519d02ccdbSbouyer 	if ((error = bus_dmamap_create(sc->sc_dmat, dma_table_size,
6529d02ccdbSbouyer 	    1, dma_table_size, IDEDMA_TBL_ALIGN, BUS_DMA_NOWAIT,
6539d02ccdbSbouyer 	    &dma_maps->dmamap_table)) != 0) {
6547aa6248cScube 		aprint_error(dmaerrfmt,
6557aa6248cScube 		    device_xname(sc->sc_wdcdev.sc_atac.atac_dev), channel,
6567aa6248cScube 		    "create", drive, error);
6579d02ccdbSbouyer 		return error;
6589d02ccdbSbouyer 	}
6599d02ccdbSbouyer 	if ((error = bus_dmamap_load(sc->sc_dmat,
6609d02ccdbSbouyer 	    dma_maps->dmamap_table,
6619d02ccdbSbouyer 	    dma_maps->dma_table,
6629d02ccdbSbouyer 	    dma_table_size, NULL, BUS_DMA_NOWAIT)) != 0) {
6637aa6248cScube 		aprint_error(dmaerrfmt,
6647aa6248cScube 		    device_xname(sc->sc_wdcdev.sc_atac.atac_dev), channel,
6657aa6248cScube 		    "load", drive, error);
6669d02ccdbSbouyer 		return error;
6679d02ccdbSbouyer 	}
66846f42775Sthorpej 	ATADEBUG_PRINT(("pciide_dma_table_setup: phy addr of table 0x%lx\n",
6699d02ccdbSbouyer 	    (unsigned long)dma_maps->dmamap_table->dm_segs[0].ds_addr),
6709d02ccdbSbouyer 	    DEBUG_PROBE);
6719d02ccdbSbouyer 	/* Create a xfer DMA map for this drive */
67210a93c41Sbriggs 	if ((error = bus_dmamap_create(sc->sc_dmat, MAXPHYS,
673f5218aadSbriggs 	    NIDEDMA_TABLES(sc), sc->sc_dma_maxsegsz, sc->sc_dma_boundary,
6749d02ccdbSbouyer 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
6759d02ccdbSbouyer 	    &dma_maps->dmamap_xfer)) != 0) {
6767aa6248cScube 		aprint_error(dmaerrfmt,
6777aa6248cScube 		    device_xname(sc->sc_wdcdev.sc_atac.atac_dev), channel,
6787aa6248cScube 		    "create xfer", drive, error);
6799d02ccdbSbouyer 		return error;
6809d02ccdbSbouyer 	}
6819d02ccdbSbouyer 	return 0;
6829d02ccdbSbouyer }
6839d02ccdbSbouyer 
6845947ac4eSjakllsch void
pciide_dma_table_teardown(struct pciide_softc * sc,int channel,int drive)6855947ac4eSjakllsch pciide_dma_table_teardown(struct pciide_softc *sc, int channel, int drive)
6865947ac4eSjakllsch {
6875947ac4eSjakllsch 	struct pciide_channel *cp;
6885947ac4eSjakllsch 	struct pciide_dma_maps *dma_maps;
6895947ac4eSjakllsch 
6905947ac4eSjakllsch 	cp = &sc->pciide_channels[channel];
6915947ac4eSjakllsch 	dma_maps = &cp->dma_maps[drive];
6925947ac4eSjakllsch 
6935947ac4eSjakllsch 	if (dma_maps->dma_table == NULL)
6945947ac4eSjakllsch 		return;
6955947ac4eSjakllsch 
6965947ac4eSjakllsch 	bus_dmamap_destroy(sc->sc_dmat, dma_maps->dmamap_xfer);
6975947ac4eSjakllsch 	bus_dmamap_unload(sc->sc_dmat, dma_maps->dmamap_table);
6985947ac4eSjakllsch 	bus_dmamap_destroy(sc->sc_dmat, dma_maps->dmamap_table);
6995947ac4eSjakllsch 	bus_dmamem_unmap(sc->sc_dmat, dma_maps->dma_table,
7005947ac4eSjakllsch 	    sizeof(struct idedma_table) * NIDEDMA_TABLES(sc));
7015947ac4eSjakllsch 	bus_dmamem_free(sc->sc_dmat, &dma_maps->dmamap_table_seg,
7025947ac4eSjakllsch 	    dma_maps->dmamap_table_nseg);
7035947ac4eSjakllsch 
7045947ac4eSjakllsch 	dma_maps->dma_table = NULL;
7055947ac4eSjakllsch 
7065947ac4eSjakllsch 	return;
7075947ac4eSjakllsch }
7085947ac4eSjakllsch 
7099d02ccdbSbouyer int
pciide_dma_dmamap_setup(struct pciide_softc * sc,int channel,int drive,void * databuf,size_t datalen,int flags)7108bc54e5bSmsaitoh pciide_dma_dmamap_setup(struct pciide_softc *sc, int channel, int drive,
7118bc54e5bSmsaitoh     void *databuf, size_t datalen, int flags)
7129d02ccdbSbouyer {
7139d02ccdbSbouyer 	int error, seg;
7146242a545Sfvdl 	struct pciide_channel *cp = &sc->pciide_channels[channel];
7156242a545Sfvdl 	struct pciide_dma_maps *dma_maps = &cp->dma_maps[drive];
7169d02ccdbSbouyer 
7179d02ccdbSbouyer 	error = bus_dmamap_load(sc->sc_dmat,
7189d02ccdbSbouyer 	    dma_maps->dmamap_xfer,
7199d02ccdbSbouyer 	    databuf, datalen, NULL, BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
7209d02ccdbSbouyer 	    ((flags & WDC_DMA_READ) ? BUS_DMA_READ : BUS_DMA_WRITE));
7219d02ccdbSbouyer 	if (error) {
7227aa6248cScube 		aprint_error(dmaerrfmt,
7237aa6248cScube 		    device_xname(sc->sc_wdcdev.sc_atac.atac_dev), channel,
7247aa6248cScube 		    "load xfer", drive, error);
7259d02ccdbSbouyer 		return error;
7269d02ccdbSbouyer 	}
7279d02ccdbSbouyer 
7289d02ccdbSbouyer 	bus_dmamap_sync(sc->sc_dmat, dma_maps->dmamap_xfer, 0,
7299d02ccdbSbouyer 	    dma_maps->dmamap_xfer->dm_mapsize,
7309d02ccdbSbouyer 	    (flags & WDC_DMA_READ) ?
7319d02ccdbSbouyer 	    BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
7329d02ccdbSbouyer 
7339d02ccdbSbouyer 	for (seg = 0; seg < dma_maps->dmamap_xfer->dm_nsegs; seg++) {
7349c0baf1cSthorpej 		bus_addr_t phys = dma_maps->dmamap_xfer->dm_segs[seg].ds_addr;
7359c0baf1cSthorpej 		bus_size_t len = dma_maps->dmamap_xfer->dm_segs[seg].ds_len;
7369c0baf1cSthorpej 
7379d02ccdbSbouyer #ifdef DIAGNOSTIC
7389d02ccdbSbouyer 		/* A segment must not cross a 64k boundary */
7399d02ccdbSbouyer 		{
7409d02ccdbSbouyer 		if ((phys & ~IDEDMA_BYTE_COUNT_MASK) !=
7419d02ccdbSbouyer 		    ((phys + len - 1) & ~IDEDMA_BYTE_COUNT_MASK)) {
7429c0baf1cSthorpej 			printf("pciide_dma: seg %d addr 0x%" PRIx64
7439c0baf1cSthorpej 			    " len 0x%" PRIx64 " not properly aligned\n",
7449c0baf1cSthorpej 			    seg, (uint64_t)phys, (uint64_t)len);
7459d02ccdbSbouyer 			panic("pciide_dma: buf align");
7469d02ccdbSbouyer 		}
7479d02ccdbSbouyer 		}
7489d02ccdbSbouyer #endif
7499c0baf1cSthorpej 		/*
7509c0baf1cSthorpej 		 * Some controllers get really upset if the length
7519c0baf1cSthorpej 		 * of any DMA segment is odd.  This isn't something
7529c0baf1cSthorpej 		 * that's going to happen in normal steady-state
7539c0baf1cSthorpej 		 * operation (reading VM pages, etc.), but physio users
7549c0baf1cSthorpej 		 * don't have as many guard rails.
7559c0baf1cSthorpej 		 *
7569c0baf1cSthorpej 		 * Consider an 8K read request that starts at an odd
7579c0baf1cSthorpej 		 * offset within a page.  At first blush, all of the
7589c0baf1cSthorpej 		 * checks pass because it's a sector-rounded size, but
7599c0baf1cSthorpej 		 * unless the buffer spans 2 physically contiguous pages,
7609c0baf1cSthorpej 		 * it's going to result in 2 odd-length DMA segments.
7619c0baf1cSthorpej 		 *
7629c0baf1cSthorpej 		 * Odd start addresses are also frowned upon, so we
7639c0baf1cSthorpej 		 * catch those here, too.
7649c0baf1cSthorpej 		 *
7659c0baf1cSthorpej 		 * Returning EINVAL here will cause the upper layers to
7669c0baf1cSthorpej 		 * fall back onto PIO.
7679c0baf1cSthorpej 		 */
7689c0baf1cSthorpej 		if ((phys & 1) != 0 || (len & 1) != 0) {
7699c0baf1cSthorpej 			aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev,
7709c0baf1cSthorpej 			    "Invalid DMA segment: "
7719c0baf1cSthorpej 			    "seg %d addr 0x%" PRIx64 " len 0x%" PRIx64 "\n",
7729c0baf1cSthorpej 			    seg, (uint64_t)phys, (uint64_t)len);
7739c0baf1cSthorpej 			bus_dmamap_unload(sc->sc_dmat, dma_maps->dmamap_xfer);
7749c0baf1cSthorpej 			return EINVAL;
7759c0baf1cSthorpej 		}
7769c0baf1cSthorpej 		dma_maps->dma_table[seg].base_addr = htole32(phys);
7779d02ccdbSbouyer 		dma_maps->dma_table[seg].byte_count =
7789c0baf1cSthorpej 		    htole32(len & IDEDMA_BYTE_COUNT_MASK);
77946f42775Sthorpej 		ATADEBUG_PRINT(("\t seg %d len %d addr 0x%x\n",
7809d02ccdbSbouyer 		   seg, le32toh(dma_maps->dma_table[seg].byte_count),
7819d02ccdbSbouyer 		   le32toh(dma_maps->dma_table[seg].base_addr)), DEBUG_DMA);
7829d02ccdbSbouyer 
7839d02ccdbSbouyer 	}
7849d02ccdbSbouyer 	dma_maps->dma_table[dma_maps->dmamap_xfer->dm_nsegs -1].byte_count |=
7859d02ccdbSbouyer 	    htole32(IDEDMA_BYTE_COUNT_EOT);
7869d02ccdbSbouyer 
7879d02ccdbSbouyer 	bus_dmamap_sync(sc->sc_dmat, dma_maps->dmamap_table, 0,
7889d02ccdbSbouyer 	    dma_maps->dmamap_table->dm_mapsize,
7899d02ccdbSbouyer 	    BUS_DMASYNC_PREWRITE);
7909d02ccdbSbouyer 
7919d02ccdbSbouyer #ifdef DIAGNOSTIC
7929d02ccdbSbouyer 	if (dma_maps->dmamap_table->dm_segs[0].ds_addr & ~IDEDMA_TBL_MASK) {
793489e5e52Sbouyer 		printf("pciide_dma_dmamap_setup: addr 0x%lx "
794489e5e52Sbouyer 		    "not properly aligned\n",
7959d02ccdbSbouyer 		    (u_long)dma_maps->dmamap_table->dm_segs[0].ds_addr);
7969d02ccdbSbouyer 		panic("pciide_dma_init: table align");
7979d02ccdbSbouyer 	}
7989d02ccdbSbouyer #endif
799489e5e52Sbouyer 	/* remember flags */
800489e5e52Sbouyer 	dma_maps->dma_flags = flags;
8019d02ccdbSbouyer 
802489e5e52Sbouyer 	return 0;
803489e5e52Sbouyer }
804489e5e52Sbouyer 
805489e5e52Sbouyer int
pciide_dma_init(void * v,int channel,int drive,void * databuf,size_t datalen,int flags)8068bc54e5bSmsaitoh pciide_dma_init(void *v, int channel, int drive, void *databuf, size_t datalen,
8078bc54e5bSmsaitoh     int flags)
808489e5e52Sbouyer {
809489e5e52Sbouyer 	struct pciide_softc *sc = v;
810489e5e52Sbouyer 	int error;
811489e5e52Sbouyer 	struct pciide_channel *cp = &sc->pciide_channels[channel];
812489e5e52Sbouyer 	struct pciide_dma_maps *dma_maps = &cp->dma_maps[drive];
813489e5e52Sbouyer 
814489e5e52Sbouyer 	if ((error = pciide_dma_dmamap_setup(sc, channel, drive,
815489e5e52Sbouyer 	    databuf, datalen, flags)) != 0)
816489e5e52Sbouyer 		return error;
817489e5e52Sbouyer 	/* Maps are ready. Start DMA function */
8189d02ccdbSbouyer 	/* Clear status bits */
8196242a545Sfvdl 	bus_space_write_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CTL], 0,
8206242a545Sfvdl 	    bus_space_read_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CTL], 0));
8219d02ccdbSbouyer 	/* Write table addr */
8226242a545Sfvdl 	bus_space_write_4(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_TBL], 0,
8239d02ccdbSbouyer 	    dma_maps->dmamap_table->dm_segs[0].ds_addr);
8249d02ccdbSbouyer 	/* set read/write */
8256242a545Sfvdl 	bus_space_write_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CMD], 0,
826f6aaf54dSthorpej 	    ((flags & WDC_DMA_READ) ? IDEDMA_CMD_WRITE : 0) | cp->idedma_cmd);
8279d02ccdbSbouyer 	return 0;
8289d02ccdbSbouyer }
8299d02ccdbSbouyer 
8309d02ccdbSbouyer void
pciide_dma_start(void * v,int channel,int drive)831168cd830Schristos pciide_dma_start(void *v, int channel, int drive)
8329d02ccdbSbouyer {
8339d02ccdbSbouyer 	struct pciide_softc *sc = v;
8346242a545Sfvdl 	struct pciide_channel *cp = &sc->pciide_channels[channel];
8359d02ccdbSbouyer 
83646f42775Sthorpej 	ATADEBUG_PRINT(("pciide_dma_start\n"),DEBUG_XFERS);
8376242a545Sfvdl 	bus_space_write_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CMD], 0,
8386242a545Sfvdl 	    bus_space_read_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CMD], 0)
8396242a545Sfvdl 		| IDEDMA_CMD_START);
8409d02ccdbSbouyer }
8419d02ccdbSbouyer 
8429d02ccdbSbouyer int
pciide_dma_finish(void * v,int channel,int drive,int force)84382357f6dSdsl pciide_dma_finish(void *v, int channel, int drive, int force)
8449d02ccdbSbouyer {
8459d02ccdbSbouyer 	struct pciide_softc *sc = v;
8469d02ccdbSbouyer 	u_int8_t status;
8479d02ccdbSbouyer 	int error = 0;
8486242a545Sfvdl 	struct pciide_channel *cp = &sc->pciide_channels[channel];
8496242a545Sfvdl 	struct pciide_dma_maps *dma_maps = &cp->dma_maps[drive];
8509d02ccdbSbouyer 
8516242a545Sfvdl 	status = bus_space_read_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CTL], 0);
85246f42775Sthorpej 	ATADEBUG_PRINT(("pciide_dma_finish: status 0x%x\n", status),
8539d02ccdbSbouyer 	    DEBUG_XFERS);
8549d02ccdbSbouyer 
85573203a82Sbouyer 	if (force == WDC_DMAEND_END && (status & IDEDMA_CTL_INTR) == 0)
8569d02ccdbSbouyer 		return WDC_DMAST_NOIRQ;
8579d02ccdbSbouyer 
8589d02ccdbSbouyer 	/* stop DMA channel */
8596242a545Sfvdl 	bus_space_write_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CMD], 0,
8606242a545Sfvdl 	    bus_space_read_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CMD], 0)
8616242a545Sfvdl 		& ~IDEDMA_CMD_START);
8629d02ccdbSbouyer 
8639d02ccdbSbouyer 	/* Unload the map of the data buffer */
8649d02ccdbSbouyer 	bus_dmamap_sync(sc->sc_dmat, dma_maps->dmamap_xfer, 0,
8659d02ccdbSbouyer 	    dma_maps->dmamap_xfer->dm_mapsize,
8669d02ccdbSbouyer 	    (dma_maps->dma_flags & WDC_DMA_READ) ?
8679d02ccdbSbouyer 	    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
8689d02ccdbSbouyer 	bus_dmamap_unload(sc->sc_dmat, dma_maps->dmamap_xfer);
8699d02ccdbSbouyer 
87073203a82Sbouyer 	if ((status & IDEDMA_CTL_ERR) != 0 && force != WDC_DMAEND_ABRT_QUIET) {
8717aa6248cScube 		aprint_error("%s:%d:%d: bus-master DMA error: status=0x%x\n",
8727aa6248cScube 		    device_xname(sc->sc_wdcdev.sc_atac.atac_dev), channel,
8737aa6248cScube 		    drive, status);
8749d02ccdbSbouyer 		error |= WDC_DMAST_ERR;
8759d02ccdbSbouyer 	}
8769d02ccdbSbouyer 
87773203a82Sbouyer 	if ((status & IDEDMA_CTL_INTR) == 0 && force != WDC_DMAEND_ABRT_QUIET) {
8787aa6248cScube 		aprint_error("%s:%d:%d: bus-master DMA error: missing "
8797aa6248cScube 		    "interrupt, status=0x%x\n",
8807aa6248cScube 		    device_xname(sc->sc_wdcdev.sc_atac.atac_dev),
8819cc521a1Sthorpej 		    channel, drive, status);
8829d02ccdbSbouyer 		error |= WDC_DMAST_NOIRQ;
8839d02ccdbSbouyer 	}
8849d02ccdbSbouyer 
88573203a82Sbouyer 	if ((status & IDEDMA_CTL_ACT) != 0 && force != WDC_DMAEND_ABRT_QUIET) {
8869d02ccdbSbouyer 		/* data underrun, may be a valid condition for ATAPI */
8879d02ccdbSbouyer 		error |= WDC_DMAST_UNDER;
8889d02ccdbSbouyer 	}
8899d02ccdbSbouyer 	return error;
8909d02ccdbSbouyer }
8919d02ccdbSbouyer 
8929d02ccdbSbouyer void
pciide_irqack(struct ata_channel * chp)893454af1c0Sdsl pciide_irqack(struct ata_channel *chp)
8949d02ccdbSbouyer {
8951600c8b8Sthorpej 	struct pciide_channel *cp = CHAN_TO_PCHAN(chp);
8961600c8b8Sthorpej 	struct pciide_softc *sc = CHAN_TO_PCIIDE(chp);
8979d02ccdbSbouyer 
8989d02ccdbSbouyer 	/* clear status bits in IDE DMA registers */
8996242a545Sfvdl 	bus_space_write_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CTL], 0,
9006242a545Sfvdl 	    bus_space_read_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CTL], 0));
9019d02ccdbSbouyer }
902bb09c44eSitohy #endif	/* NATA_DMA */
9039d02ccdbSbouyer 
9049d02ccdbSbouyer /* some common code used by several chip_map */
9059d02ccdbSbouyer int
pciide_chansetup(struct pciide_softc * sc,int channel,pcireg_t interface)906454af1c0Sdsl pciide_chansetup(struct pciide_softc *sc, int channel, pcireg_t interface)
9079d02ccdbSbouyer {
9089d02ccdbSbouyer 	struct pciide_channel *cp = &sc->pciide_channels[channel];
9094b51cecfSthorpej 	sc->wdc_chanarray[channel] = &cp->ata_channel;
9109d02ccdbSbouyer 	cp->name = PCIIDE_CHANNEL_NAME(channel);
9114b51cecfSthorpej 	cp->ata_channel.ch_channel = channel;
9129cc521a1Sthorpej 	cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
91362fb6131Sjdolecek 
9147aa6248cScube 	aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev,
9157aa6248cScube 	    "%s channel %s to %s mode\n", cp->name,
9169d02ccdbSbouyer 	    (interface & PCIIDE_INTERFACE_SETTABLE(channel)) ?
9179d02ccdbSbouyer 	    "configured" : "wired",
9189d02ccdbSbouyer 	    (interface & PCIIDE_INTERFACE_PCI(channel)) ?
9199d02ccdbSbouyer 	    "native-PCI" : "compatibility");
9209d02ccdbSbouyer 	return 1;
9219d02ccdbSbouyer }
9229d02ccdbSbouyer 
9239d02ccdbSbouyer /* some common code used by several chip channel_map */
9249d02ccdbSbouyer void
pciide_mapchan(const struct pci_attach_args * pa,struct pciide_channel * cp,pcireg_t interface,int (* pci_intr)(void *))9258bc54e5bSmsaitoh pciide_mapchan(const struct pci_attach_args *pa, struct pciide_channel *cp,
9265947ac4eSjakllsch 	pcireg_t interface, int (*pci_intr)(void *))
9279d02ccdbSbouyer {
9284b51cecfSthorpej 	struct ata_channel *wdc_cp = &cp->ata_channel;
9299d02ccdbSbouyer 
930a963286fSthorpej 	if (interface & PCIIDE_INTERFACE_PCI(wdc_cp->ch_channel))
9315947ac4eSjakllsch 		pciide_mapregs_native(pa, cp, pci_intr);
93283b68475Sbouyer 	else {
9335947ac4eSjakllsch 		pciide_mapregs_compat(pa, cp, wdc_cp->ch_channel);
9344b51cecfSthorpej 		if ((cp->ata_channel.ch_flags & ATACH_DISABLED) == 0)
93583b68475Sbouyer 			pciide_map_compat_intr(pa, cp, wdc_cp->ch_channel);
93683b68475Sbouyer 	}
9379d02ccdbSbouyer 	wdcattach(wdc_cp);
9389d02ccdbSbouyer }
9399d02ccdbSbouyer 
9409d02ccdbSbouyer /*
9419d02ccdbSbouyer  * generic code to map the compat intr.
9429d02ccdbSbouyer  */
9439d02ccdbSbouyer void
pciide_map_compat_intr(const struct pci_attach_args * pa,struct pciide_channel * cp,int compatchan)9448bc54e5bSmsaitoh pciide_map_compat_intr(const struct pci_attach_args *pa,
9458bc54e5bSmsaitoh     struct pciide_channel *cp, int compatchan)
9469d02ccdbSbouyer {
9471600c8b8Sthorpej 	struct pciide_softc *sc = CHAN_TO_PCIIDE(&cp->ata_channel);
9489d02ccdbSbouyer 
9499d02ccdbSbouyer #ifdef __HAVE_PCIIDE_MACHDEP_COMPAT_INTR_ESTABLISH
9509cc521a1Sthorpej 	cp->ih =
9517aa6248cScube 	   pciide_machdep_compat_intr_establish(sc->sc_wdcdev.sc_atac.atac_dev,
9529d02ccdbSbouyer 	   pa, compatchan, pciide_compat_intr, cp);
9539d02ccdbSbouyer 	if (cp->ih == NULL) {
9549d02ccdbSbouyer #endif
9557aa6248cScube 		aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
9567aa6248cScube 		    "no compatibility interrupt for use by %s "
9577aa6248cScube 		    "channel\n", cp->name);
9584b51cecfSthorpej 		cp->ata_channel.ch_flags |= ATACH_DISABLED;
9599d02ccdbSbouyer #ifdef __HAVE_PCIIDE_MACHDEP_COMPAT_INTR_ESTABLISH
9609d02ccdbSbouyer 	}
9619d02ccdbSbouyer #endif
9629d02ccdbSbouyer }
9639d02ccdbSbouyer 
9649d02ccdbSbouyer void
pciide_unmap_compat_intr(pci_chipset_tag_t pc,struct pciide_channel * cp,int compatchan)9658bc54e5bSmsaitoh pciide_unmap_compat_intr(pci_chipset_tag_t pc, struct pciide_channel *cp,
9668bc54e5bSmsaitoh     int compatchan)
9674d3ab04cSjakllsch {
9684d3ab04cSjakllsch #ifdef __HAVE_PCIIDE_MACHDEP_COMPAT_INTR_DISESTABLISH
9694d3ab04cSjakllsch 	struct pciide_softc *sc = CHAN_TO_PCIIDE(&cp->ata_channel);
9704d3ab04cSjakllsch 
9714d3ab04cSjakllsch 	pciide_machdep_compat_intr_disestablish(sc->sc_wdcdev.sc_atac.atac_dev,
9724d3ab04cSjakllsch 	    sc->sc_pc, compatchan, cp->ih);
9734d3ab04cSjakllsch #endif
9744d3ab04cSjakllsch }
9754d3ab04cSjakllsch 
9764d3ab04cSjakllsch void
default_chip_map(struct pciide_softc * sc,const struct pci_attach_args * pa)977d3e53912Sdyoung default_chip_map(struct pciide_softc *sc, const struct pci_attach_args *pa)
9789d02ccdbSbouyer {
9799d02ccdbSbouyer 	struct pciide_channel *cp;
9809d02ccdbSbouyer 	pcireg_t interface = PCI_INTERFACE(pa->pa_class);
9819d02ccdbSbouyer 	pcireg_t csr;
982bb09c44eSitohy 	int channel;
983bb09c44eSitohy #if NATA_DMA
984bb09c44eSitohy 	int drive;
9859d02ccdbSbouyer 	u_int8_t idedma_ctl;
986bb09c44eSitohy #endif
987cdec0c5eSchristos 	const char *failreason;
9884b51cecfSthorpej 	struct wdc_regs *wdr;
9899d02ccdbSbouyer 
9909d02ccdbSbouyer 	if (pciide_chipen(sc, pa) == 0)
9919d02ccdbSbouyer 		return;
9929d02ccdbSbouyer 
9939d02ccdbSbouyer 	if (interface & PCIIDE_INTERFACE_BUS_MASTER_DMA) {
994bb09c44eSitohy #if NATA_DMA
9957aa6248cScube 		aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev,
9967aa6248cScube 		    "bus-master DMA support present");
9979d02ccdbSbouyer 		if (sc->sc_pp == &default_product_desc &&
9987aa6248cScube 		    (device_cfdata(sc->sc_wdcdev.sc_atac.atac_dev)->cf_flags &
9999d02ccdbSbouyer 		    PCIIDE_OPTIONS_DMA) == 0) {
1000b07ec3fcSad 			aprint_verbose(", but unused (no driver support)");
10019d02ccdbSbouyer 			sc->sc_dma_ok = 0;
10029d02ccdbSbouyer 		} else {
10039d02ccdbSbouyer 			pciide_mapreg_dma(sc, pa);
10049d02ccdbSbouyer 			if (sc->sc_dma_ok != 0)
1005b07ec3fcSad 				aprint_verbose(", used without full driver "
10069d02ccdbSbouyer 				    "support");
10079d02ccdbSbouyer 		}
1008bb09c44eSitohy #else
10097aa6248cScube 		aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev,
10107aa6248cScube 		    "bus-master DMA support present, but unused (no driver "
10117aa6248cScube 		    "support)");
1012bb09c44eSitohy #endif	/* NATA_DMA */
10139d02ccdbSbouyer 	} else {
10147aa6248cScube 		aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev,
10157aa6248cScube 		    "hardware does not support DMA");
1016bb09c44eSitohy #if NATA_DMA
10179d02ccdbSbouyer 		sc->sc_dma_ok = 0;
1018bb09c44eSitohy #endif
10199d02ccdbSbouyer 	}
1020b07ec3fcSad 	aprint_verbose("\n");
1021bb09c44eSitohy #if NATA_DMA
10229d02ccdbSbouyer 	if (sc->sc_dma_ok) {
10239cc521a1Sthorpej 		sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DMA;
10249d02ccdbSbouyer 		sc->sc_wdcdev.irqack = pciide_irqack;
10259d02ccdbSbouyer 	}
1026bb09c44eSitohy #endif
10279cc521a1Sthorpej 	sc->sc_wdcdev.sc_atac.atac_pio_cap = 0;
1028bb09c44eSitohy #if NATA_DMA
10299cc521a1Sthorpej 	sc->sc_wdcdev.sc_atac.atac_dma_cap = 0;
1030bb09c44eSitohy #endif
10319d02ccdbSbouyer 
10329cc521a1Sthorpej 	sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
10339cc521a1Sthorpej 	sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
10349cc521a1Sthorpej 	sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16;
10359edd4d81Sbouyer 	sc->sc_wdcdev.wdc_maxdrives = 2;
10369d02ccdbSbouyer 
10374b51cecfSthorpej 	wdc_allocate_regs(&sc->sc_wdcdev);
10384b51cecfSthorpej 
10399cc521a1Sthorpej 	for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels;
10409cc521a1Sthorpej 	     channel++) {
10419d02ccdbSbouyer 		cp = &sc->pciide_channels[channel];
10429d02ccdbSbouyer 		if (pciide_chansetup(sc, channel, interface) == 0)
10439d02ccdbSbouyer 			continue;
10441600c8b8Sthorpej 		wdr = CHAN_TO_WDC_REGS(&cp->ata_channel);
104502bbaa62Sbouyer 		if (interface & PCIIDE_INTERFACE_PCI(channel))
10465947ac4eSjakllsch 			pciide_mapregs_native(pa, cp, pciide_pci_intr);
104702bbaa62Sbouyer 		else
104802bbaa62Sbouyer 			pciide_mapregs_compat(pa, cp,
10495947ac4eSjakllsch 			    cp->ata_channel.ch_channel);
10504b51cecfSthorpej 		if (cp->ata_channel.ch_flags & ATACH_DISABLED)
10519d02ccdbSbouyer 			continue;
10529d02ccdbSbouyer 		/*
10539d02ccdbSbouyer 		 * Check to see if something appears to be there.
10549d02ccdbSbouyer 		 */
10559d02ccdbSbouyer 		failreason = NULL;
10569d02ccdbSbouyer 		/*
10579d02ccdbSbouyer 		 * In native mode, always enable the controller. It's
10589d02ccdbSbouyer 		 * not possible to have an ISA board using the same address
10599d02ccdbSbouyer 		 * anyway.
10609d02ccdbSbouyer 		 */
106183b68475Sbouyer 		if (interface & PCIIDE_INTERFACE_PCI(channel)) {
10624b51cecfSthorpej 			wdcattach(&cp->ata_channel);
106383b68475Sbouyer 			continue;
106483b68475Sbouyer 		}
106526cf6855Sjdolecek 		if (!wdcprobe(CHAN_TO_WDC_REGS(&cp->ata_channel))) {
10669d02ccdbSbouyer 			failreason = "not responding; disabled or no drives?";
10679d02ccdbSbouyer 			goto next;
10689d02ccdbSbouyer 		}
10699d02ccdbSbouyer 		/*
10709d02ccdbSbouyer 		 * Now, make sure it's actually attributable to this PCI IDE
10719d02ccdbSbouyer 		 * channel by trying to access the channel again while the
10729d02ccdbSbouyer 		 * PCI IDE controller's I/O space is disabled.  (If the
10739d02ccdbSbouyer 		 * channel no longer appears to be there, it belongs to
10749d02ccdbSbouyer 		 * this controller.)  YUCK!
10759d02ccdbSbouyer 		 */
10769d02ccdbSbouyer 		csr = pci_conf_read(sc->sc_pc, sc->sc_tag,
10779d02ccdbSbouyer 		    PCI_COMMAND_STATUS_REG);
10789d02ccdbSbouyer 		pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG,
10799d02ccdbSbouyer 		    csr & ~PCI_COMMAND_IO_ENABLE);
108026cf6855Sjdolecek 		if (wdcprobe(CHAN_TO_WDC_REGS(&cp->ata_channel)))
10819d02ccdbSbouyer 			failreason = "other hardware responding at addresses";
10829d02ccdbSbouyer 		pci_conf_write(sc->sc_pc, sc->sc_tag,
10839d02ccdbSbouyer 		    PCI_COMMAND_STATUS_REG, csr);
10849d02ccdbSbouyer next:
10859d02ccdbSbouyer 		if (failreason) {
10867aa6248cScube 			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
10877aa6248cScube 			    "%s channel ignored (%s)\n", cp->name, failreason);
10884b51cecfSthorpej 			cp->ata_channel.ch_flags |= ATACH_DISABLED;
10894b51cecfSthorpej 			bus_space_unmap(wdr->cmd_iot, wdr->cmd_baseioh,
10905947ac4eSjakllsch 			    wdr->cmd_ios);
10915947ac4eSjakllsch 			bus_space_unmap(wdr->ctl_iot, wdr->ctl_ioh,
10925947ac4eSjakllsch 			    wdr->ctl_ios);
109302bbaa62Sbouyer 		} else {
109483b68475Sbouyer 			pciide_map_compat_intr(pa, cp,
10954b51cecfSthorpej 			    cp->ata_channel.ch_channel);
10964b51cecfSthorpej 			wdcattach(&cp->ata_channel);
10979d02ccdbSbouyer 		}
10989d02ccdbSbouyer 	}
10999d02ccdbSbouyer 
1100bb09c44eSitohy #if NATA_DMA
11019d02ccdbSbouyer 	if (sc->sc_dma_ok == 0)
11029d02ccdbSbouyer 		return;
11039d02ccdbSbouyer 
11049d02ccdbSbouyer 	/* Allocate DMA maps */
11059cc521a1Sthorpej 	for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels;
11069cc521a1Sthorpej 	     channel++) {
11079d02ccdbSbouyer 		idedma_ctl = 0;
11089d02ccdbSbouyer 		cp = &sc->pciide_channels[channel];
11099edd4d81Sbouyer 		for (drive = 0; drive < sc->sc_wdcdev.wdc_maxdrives; drive++) {
11106ad7a02dSbouyer 			/*
11116ad7a02dSbouyer 			 * we have not probed the drives yet, allocate
111261571269Smsaitoh 			 * resources for all of them.
11136ad7a02dSbouyer 			 */
11149d02ccdbSbouyer 			if (pciide_dma_table_setup(sc, channel, drive) != 0) {
11159d02ccdbSbouyer 				/* Abort DMA setup */
11169d02ccdbSbouyer 				aprint_error(
11179d02ccdbSbouyer 				    "%s:%d:%d: can't allocate DMA maps, "
11189d02ccdbSbouyer 				    "using PIO transfers\n",
11197aa6248cScube 				    device_xname(
11207aa6248cScube 				      sc->sc_wdcdev.sc_atac.atac_dev),
11219d02ccdbSbouyer 				    channel, drive);
11226ad7a02dSbouyer 				sc->sc_dma_ok = 0;
11236ad7a02dSbouyer 				sc->sc_wdcdev.sc_atac.atac_cap &= ~ATAC_CAP_DMA;
11246ad7a02dSbouyer 				sc->sc_wdcdev.irqack = NULL;
11256ad7a02dSbouyer 				break;
11269d02ccdbSbouyer 			}
11279d02ccdbSbouyer 			idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
11289d02ccdbSbouyer 		}
11299d02ccdbSbouyer 		if (idedma_ctl != 0) {
11309d02ccdbSbouyer 			/* Add software bits in status register */
11316242a545Sfvdl 			bus_space_write_1(sc->sc_dma_iot,
11326242a545Sfvdl 			    cp->dma_iohs[IDEDMA_CTL], 0, idedma_ctl);
11339d02ccdbSbouyer 		}
11349d02ccdbSbouyer 	}
1135bb09c44eSitohy #endif	/* NATA_DMA */
11369d02ccdbSbouyer }
11379d02ccdbSbouyer 
11389d02ccdbSbouyer void
sata_setup_channel(struct ata_channel * chp)1139454af1c0Sdsl sata_setup_channel(struct ata_channel *chp)
11409d02ccdbSbouyer {
1141bb09c44eSitohy #if NATA_DMA
11429d02ccdbSbouyer 	struct ata_drive_datas *drvp;
1143f9212d6bSitohy 	int drive;
1144f9212d6bSitohy #if NATA_UDMA
1145f9212d6bSitohy 	int s;
1146f9212d6bSitohy #endif
11479d02ccdbSbouyer 	u_int32_t idedma_ctl;
11481600c8b8Sthorpej 	struct pciide_channel *cp = CHAN_TO_PCHAN(chp);
11491600c8b8Sthorpej 	struct pciide_softc *sc = CHAN_TO_PCIIDE(chp);
11509d02ccdbSbouyer 
11519d02ccdbSbouyer 	/* setup DMA if needed */
11529d02ccdbSbouyer 	pciide_channel_dma_setup(cp);
11539d02ccdbSbouyer 
11549d02ccdbSbouyer 	idedma_ctl = 0;
11559d02ccdbSbouyer 
11569edd4d81Sbouyer 	KASSERT(cp->ata_channel.ch_ndrives != 0);
11579edd4d81Sbouyer 	for (drive = 0; drive < cp->ata_channel.ch_ndrives; drive++) {
11589d02ccdbSbouyer 		drvp = &chp->ch_drive[drive];
11599d02ccdbSbouyer 		/* If no drive, skip */
11609edd4d81Sbouyer 		if (drvp->drive_type == ATA_DRIVET_NONE)
11619d02ccdbSbouyer 			continue;
1162bb09c44eSitohy #if NATA_UDMA
11639edd4d81Sbouyer 		if (drvp->drive_flags & ATA_DRIVE_UDMA) {
11649d02ccdbSbouyer 			/* use Ultra/DMA */
1165335b7995Sthorpej 			s = splbio();
11669edd4d81Sbouyer 			drvp->drive_flags &= ~ATA_DRIVE_DMA;
1167335b7995Sthorpej 			splx(s);
11689d02ccdbSbouyer 			idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
1169bb09c44eSitohy 		} else
1170bb09c44eSitohy #endif	/* NATA_UDMA */
11719edd4d81Sbouyer 		if (drvp->drive_flags & ATA_DRIVE_DMA) {
11729d02ccdbSbouyer 			idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
11739d02ccdbSbouyer 		}
11749d02ccdbSbouyer 	}
11759d02ccdbSbouyer 
11769d02ccdbSbouyer 	/*
11779d02ccdbSbouyer 	 * Nothing to do to setup modes; it is meaningless in S-ATA
11789d02ccdbSbouyer 	 * (but many S-ATA drives still want to get the SET_FEATURE
11799d02ccdbSbouyer 	 * command).
11809d02ccdbSbouyer 	 */
11819d02ccdbSbouyer 	if (idedma_ctl != 0) {
11829d02ccdbSbouyer 		/* Add software bits in status register */
11836242a545Sfvdl 		bus_space_write_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CTL], 0,
11849d02ccdbSbouyer 		    idedma_ctl);
11859d02ccdbSbouyer 	}
1186bb09c44eSitohy #endif	/* NATA_DMA */
11879d02ccdbSbouyer }
1188