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