? sys/dev/cardbus/satalink_cardbus.c ? sys/dev/pci/satalinkvar.h Index: sys/dev/pci/pciidevar.h =================================================================== RCS file: /cvsroot/src/sys/dev/pci/pciidevar.h,v retrieving revision 1.36 diff -u -r1.36 pciidevar.h --- sys/dev/pci/pciidevar.h 4 Jan 2008 00:27:27 -0000 1.36 +++ sys/dev/pci/pciidevar.h 28 Sep 2008 16:53:18 -0000 @@ -115,7 +119,10 @@ */ bus_space_tag_t sc_ba5_st; bus_space_handle_t sc_ba5_sh; + bus_size_t sc_ba5_ssize; int sc_ba5_en; + uint32_t (*sc_ba5_read_4)(struct pciide_softc *, bus_addr_t); + void (*sc_ba5_write_4)(struct pciide_softc *, bus_addr_t, uint32_t); #endif /* NATA_DMA */ /* Vendor info (for interpreting Chip description) */ Index: sys/dev/pci/satalink.c =================================================================== RCS file: /cvsroot/src/sys/dev/pci/satalink.c,v retrieving revision 1.38 diff -u -r1.38 satalink.c --- sys/dev/pci/satalink.c 28 Apr 2008 20:23:55 -0000 1.38 +++ sys/dev/pci/satalink.c 28 Sep 2008 16:53:19 -0000 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -49,46 +50,7 @@ /* * Register map for BA5 register space, indexed by channel. */ -static const struct { - bus_addr_t ba5_IDEDMA_CMD; - bus_addr_t ba5_IDEDMA_CTL; - bus_addr_t ba5_IDEDMA_TBL; - bus_addr_t ba5_IDEDMA_CMD2; - bus_addr_t ba5_IDEDMA_CTL2; - bus_addr_t ba5_IDE_TF0; - bus_addr_t ba5_IDE_TF1; - bus_addr_t ba5_IDE_TF2; - bus_addr_t ba5_IDE_TF3; - bus_addr_t ba5_IDE_TF4; - bus_addr_t ba5_IDE_TF5; - bus_addr_t ba5_IDE_TF6; - bus_addr_t ba5_IDE_TF7; - bus_addr_t ba5_IDE_TF8; - bus_addr_t ba5_IDE_RAD; - bus_addr_t ba5_IDE_TF9; - bus_addr_t ba5_IDE_TF10; - bus_addr_t ba5_IDE_TF11; - bus_addr_t ba5_IDE_TF12; - bus_addr_t ba5_IDE_TF13; - bus_addr_t ba5_IDE_TF14; - bus_addr_t ba5_IDE_TF15; - bus_addr_t ba5_IDE_TF16; - bus_addr_t ba5_IDE_TF17; - bus_addr_t ba5_IDE_TF18; - bus_addr_t ba5_IDE_TF19; - bus_addr_t ba5_IDE_RABC; - bus_addr_t ba5_IDE_CMD_STS; - bus_addr_t ba5_IDE_CFG_STS; - bus_addr_t ba5_IDE_DTM; - bus_addr_t ba5_SControl; - bus_addr_t ba5_SStatus; - bus_addr_t ba5_SError; - bus_addr_t ba5_SActive; /* 3114 */ - bus_addr_t ba5_SMisc; - bus_addr_t ba5_PHY_CONFIG; - bus_addr_t ba5_SIEN; - bus_addr_t ba5_SFISCfg; -} satalink_ba5_regmap[] = { +const struct satalink_ba5_regmap satalink_ba5_regmap[] = { { /* Channel 0 */ .ba5_IDEDMA_CMD = 0x000, .ba5_IDEDMA_CTL = 0x002, @@ -251,21 +213,19 @@ }, }; -#define ba5_SIS 0x214 /* summary interrupt status */ - -/* Interrupt steering bit in BA5[0x200]. */ -#define IDEDMA_CMD_INT_STEER (1U << 1) - static int satalink_match(device_t, cfdata_t, void *); static void satalink_attach(device_t, device_t, void *); CFATTACH_DECL_NEW(satalink, sizeof(struct pciide_softc), satalink_match, satalink_attach, NULL, NULL); -static void sii3112_chip_map(struct pciide_softc*, struct pci_attach_args*); -static void sii3114_chip_map(struct pciide_softc*, struct pci_attach_args*); -static void sii3112_drv_probe(struct ata_channel*); -static void sii3112_setup_channel(struct ata_channel*); +static uint32_t ba5_read_4(struct pciide_softc *, bus_addr_t); +static void ba5_write_4(struct pciide_softc *, bus_addr_t, uint32_t); + +static void sii3112_chip_map(struct pciide_softc*, union bus_attach_args*); +static void sii3114_chip_map(struct pciide_softc*, union bus_attach_args*); +void sii3112_drv_probe(struct ata_channel*); +void sii3112_setup_channel(struct ata_channel*); static const struct pciide_product_desc pciide_satalink_products[] = { { PCI_PRODUCT_CMDTECH_3112, @@ -314,6 +274,8 @@ struct pciide_softc *sc = device_private(self); sc->sc_wdcdev.sc_atac.atac_dev = self; + sc->sc_ba5_read_4 = ba5_read_4; + sc->sc_ba5_write_4 = ba5_write_4; pciide_common_attach(sc, pa, pciide_lookup_product(pa->pa_id, pciide_satalink_products)); @@ -334,7 +296,7 @@ return (rv); } -static inline uint32_t +static uint32_t ba5_read_4(struct pciide_softc *sc, bus_addr_t reg) { @@ -344,9 +306,6 @@ return (ba5_read_4_ind(sc, reg)); } -#define BA5_READ_4(sc, chan, reg) \ - ba5_read_4((sc), satalink_ba5_regmap[(chan)].reg) - static inline void ba5_write_4_ind(struct pciide_softc *sc, bus_addr_t reg, uint32_t val) { @@ -358,7 +317,7 @@ splx(s); } -static inline void +static void ba5_write_4(struct pciide_softc *sc, bus_addr_t reg, uint32_t val) { @@ -368,9 +327,6 @@ ba5_write_4_ind(sc, reg, val); } -#define BA5_WRITE_4(sc, chan, reg, val) \ - ba5_write_4((sc), satalink_ba5_regmap[(chan)].reg, (val)) - /* * When the Silicon Image 3112 retries a PCI memory read command, * it may retry it as a memory read multiple command under some @@ -568,7 +525,7 @@ sc->sc_dma_ok = 1; } -static int +int sii3114_chansetup(struct pciide_softc *sc, int channel) { static const char *channel_names[] = { @@ -603,7 +560,7 @@ return (1); } -static void +void sii3114_mapchan(struct pciide_channel *cp) { struct ata_channel *wdc_cp = &cp->ata_channel; @@ -775,7 +733,7 @@ /* Probe the drives using SATA registers. * Note we can't use wdc_sataprobe as we may not be able to map ba5 */ -static void +void sii3112_drv_probe(struct ata_channel *chp) { struct pciide_softc *sc = CHAN_TO_PCIIDE(chp); @@ -886,7 +844,7 @@ } } -static void +void sii3112_setup_channel(struct ata_channel *chp) { struct ata_drive_datas *drvp; --- sys/dev/cardbus/satalink_cardbus.c.orig 1970-01-01 09:00:00.000000000 +0900 +++ sys/dev/cardbus/satalink_cardbus.c 2008-09-28 23:07:39.000000000 +0900 @@ -0,0 +1,498 @@ +/* $NetBSD: satalink.c,v 1.38 2008/04/28 20:23:55 martin Exp $ */ + +/*- + * Copyright (c) 2003 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: satalink.c,v 1.38 2008/04/28 20:23:55 martin Exp $"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +static int satalink_cardbus_match(device_t, cfdata_t, void *); +static void satalink_cardbus_attach(device_t, device_t, void *); +static int satalink_cardbus_detach(device_t, int); + +static inline uint32_t ba5_cardbus_read_4_ind(struct cardbus_pciide_softc *, + bus_addr_t); +static uint32_t ba5_cardbus_read_4(struct pciide_softc *, bus_addr_t); +static inline void ba5_cardbus_write_4_ind(struct cardbus_pciide_softc *, + bus_addr_t, uint32_t); +static void ba5_cardbus_write_4(struct pciide_softc *, bus_addr_t, uint32_t); + +static void sii_cardbus_fixup_cacheline(struct cardbus_pciide_softc *, + struct cardbus_attach_args *, int); +static void sii3112_cardbus_chip_map(struct pciide_softc *, + union bus_attach_args *); +static void sii3114_cardbus_mapreg_dma(struct cardbus_pciide_softc *, + struct cardbus_attach_args *); +static void sii3114_cardbus_chip_map(struct pciide_softc *, + union bus_attach_args *); + +CFATTACH_DECL_NEW(satalink_cardbus, sizeof(struct cardbus_pciide_softc), + satalink_cardbus_match, satalink_cardbus_attach, satalink_cardbus_detach, + NULL); + + +static const struct pciide_product_desc pciide_satalink_cardbus_products[] = { + { PCI_PRODUCT_CMDTECH_3112, + 0, + "Silicon Image SATALink 3112", + sii3112_cardbus_chip_map, + }, + { PCI_PRODUCT_CMDTECH_3512, + 0, + "Silicon Image SATALink 3512", + sii3112_cardbus_chip_map, + }, + { PCI_PRODUCT_CMDTECH_AAR_1210SA, + 0, + "Adaptec AAR-1210SA serial ATA RAID controller", + sii3112_cardbus_chip_map, + }, + { PCI_PRODUCT_CMDTECH_3114, + 0, + "Silicon Image SATALink 3114", + sii3114_cardbus_chip_map, + }, + { 0, + 0, + NULL, + NULL, + } +}; +/* ARGSUSED */ +static int +satalink_cardbus_match(device_t parent, cfdata_t match, void *aux) +{ + struct cardbus_attach_args *ca = aux; + + if (CARDBUS_VENDOR(ca->ca_id) == PCI_VENDOR_CMDTECH) + if (pciide_lookup_product(ca->ca_id, + pciide_satalink_cardbus_products)) + return (2); + return (0); +} + +/* ARGSUSED */ +static void +satalink_cardbus_attach(device_t parent, device_t self, void *aux) +{ + struct cardbus_attach_args *ca = aux; + struct cardbus_pciide_softc *sc = device_private(self); + struct pciide_softc *psc = &sc->sc_pidesc; + + psc->sc_wdcdev.sc_atac.atac_dev = self; + psc->sc_ba5_read_4 = ba5_cardbus_read_4; + psc->sc_ba5_write_4 = ba5_cardbus_write_4; + + pciide_cardbus_common_attach(sc, ca, + pciide_lookup_product(ca->ca_id, pciide_satalink_cardbus_products)); +} + +static int +satalink_cardbus_detach(device_t self, int flags) +{ + struct cardbus_pciide_softc *sc = device_private(self); + struct pciide_softc *psc = &sc->sc_pidesc; + int rv; + + rv = pciide_cardbus_common_detach(sc, flags); + if (psc->sc_ba5_en) + Cardbus_mapreg_unmap(sc->sc_ct, CARDBUS_BASE5_REG, + psc->sc_ba5_st, psc->sc_ba5_sh, psc->sc_ba5_ssize); + return rv; +} + + +static inline uint32_t +ba5_cardbus_read_4_ind(struct cardbus_pciide_softc *sc, bus_addr_t reg) +{ + uint32_t rv; + int s; + + s = splbio(); + cardbus_conf_write(sc->sc_cc, sc->sc_cf, sc->sc_ctag, + SII3112_BA5_IND_ADDR, reg); + rv = cardbus_conf_read(sc->sc_cc, sc->sc_cf, sc->sc_ctag, + SII3112_BA5_IND_DATA); + splx(s); + + return (rv); +} + +static uint32_t +ba5_cardbus_read_4(struct pciide_softc *psc, bus_addr_t reg) +{ + + if (__predict_true(psc->sc_ba5_en != 0)) + return (bus_space_read_4(psc->sc_ba5_st, psc->sc_ba5_sh, reg)); + + return ba5_cardbus_read_4_ind((struct cardbus_pciide_softc *)psc, reg); +} + +static inline void +ba5_cardbus_write_4_ind(struct cardbus_pciide_softc *sc, bus_addr_t reg, + uint32_t val) +{ + int s; + + s = splbio(); + cardbus_conf_write(sc->sc_cc, sc->sc_cf, sc->sc_ctag, + SII3112_BA5_IND_ADDR, reg); + cardbus_conf_write(sc->sc_cc, sc->sc_cf, sc->sc_ctag, + SII3112_BA5_IND_DATA, val); + splx(s); +} + +static void +ba5_cardbus_write_4(struct pciide_softc *psc, bus_addr_t reg, uint32_t val) +{ + + if (__predict_true(psc->sc_ba5_en != 0)) + bus_space_write_4(psc->sc_ba5_st, psc->sc_ba5_sh, reg, val); + else + ba5_cardbus_write_4_ind((struct cardbus_pciide_softc *)psc, reg, + val); +} + +/* + * When the Silicon Image 3112 retries a PCI memory read command, + * it may retry it as a memory read multiple command under some + * circumstances. This can totally confuse some PCI controllers, + * so ensure that it will never do this by making sure that the + * Read Threshold (FIFO Read Request Control) field of the FIFO + * Valid Byte Count and Control registers for both channels (BA5 + * offset 0x40 and 0x44) are set to be at least as large as the + * cacheline size register. + * This may also happen on the 3114 (ragge 050527) + */ +static void +sii_cardbus_fixup_cacheline(struct cardbus_pciide_softc *sc, + struct cardbus_attach_args *ca, int n) +{ + struct pciide_softc *psc = (struct pciide_softc *)sc; + cardbus_devfunc_t ct = ca->ca_ct; + cardbus_chipset_tag_t cc = ct->ct_cc; + cardbus_function_tag_t cf = ct->ct_cf; + cardbustag_t tag = ca->ca_tag; + cardbusreg_t cls, reg; + int i; + static bus_addr_t addr[] = { 0x40, 0x44, 0x240, 0x244 }; + + cls = cardbus_conf_read(cc, cf, tag, CARDBUS_BHLC_REG); + cls = (cls >> CARDBUS_CACHELINE_SHIFT) & CARDBUS_CACHELINE_MASK; + cls *= 4; + if (cls > 224) { + cls = cardbus_conf_read(cc, cf, tag, CARDBUS_BHLC_REG); + cls &= ~(CARDBUS_CACHELINE_MASK << CARDBUS_CACHELINE_SHIFT); + cls |= ((224/4) << CARDBUS_CACHELINE_SHIFT); + cardbus_conf_write(cc, cf, tag, CARDBUS_BHLC_REG, cls); + cls = 224; + } + if (cls < 32) + cls = 32; + cls = (cls + 31) / 32; + for (i = 0; i < n; i++) { + reg = ba5_cardbus_read_4(psc, addr[i]); + if ((reg & 0x7) < cls) + ba5_cardbus_write_4(psc, addr[i], (reg & 0x07) | cls); + } +} + +static void +sii3112_cardbus_chip_map(struct pciide_softc *psc, union bus_attach_args *ba) +{ + struct cardbus_pciide_softc *sc = (struct cardbus_pciide_softc *)psc; + struct cardbus_attach_args *ca = ba->ca; + cardbus_devfunc_t ct = ca->ca_ct; + cardbus_chipset_tag_t cc = ct->ct_cc; + cardbus_function_tag_t cf = ct->ct_cf; + cardbustag_t tag = ca->ca_tag; + struct pciide_channel *cp; + bus_size_t cmdsize, ctlsize; + cardbusreg_t interface, scs_cmd; + int channel; + +#define SII3112_RESET_BITS \ + (SCS_CMD_PBM_RESET | SCS_CMD_ARB_RESET | \ + SCS_CMD_FF1_RESET | SCS_CMD_FF0_RESET | \ + SCS_CMD_IDE1_RESET | SCS_CMD_IDE0_RESET) + + /* + * Reset everything and then unblock all of the interrupts. + */ + scs_cmd = cardbus_conf_read(cc, cf, tag, SII3112_SCS_CMD); + cardbus_conf_write(cc, cf, tag, SII3112_SCS_CMD, + scs_cmd | SII3112_RESET_BITS); + delay(50 * 1000); + scs_cmd |= SCS_CMD_BA5_EN; + cardbus_conf_write(cc, cf, tag, SII3112_SCS_CMD, + scs_cmd & SCS_CMD_BA5_EN); + delay(50 * 1000); + + aprint_verbose_dev(psc->sc_wdcdev.sc_atac.atac_dev, + "SATALink BA5 register space enabled\n"); + if (Cardbus_mapreg_map(ct, CARDBUS_BASE5_REG, + CARDBUS_MAPREG_TYPE_MEM, 0, + &psc->sc_ba5_st, &psc->sc_ba5_sh, + NULL, &psc->sc_ba5_ssize) != 0) + aprint_error_dev(psc->sc_wdcdev.sc_atac.atac_dev, + "unable to map SATALink BA5 register space\n"); + else + psc->sc_ba5_en = 1; + + aprint_verbose_dev(psc->sc_wdcdev.sc_atac.atac_dev, + "bus-master DMA support present"); + pciide_cardbus_mapreg_dma(sc, ca); + aprint_verbose("\n"); + + /* + * Rev. <= 0x01 of the 3112 have a bug that can cause data + * corruption if DMA transfers cross an 8K boundary. This is + * apparently hard to tickle, but we'll go ahead and play it + * safe. + */ + if (CARDBUS_REVISION(ca->ca_class) <= 0x01) { + psc->sc_dma_maxsegsz = 8192; + psc->sc_dma_boundary = 8192; + } + + sii_cardbus_fixup_cacheline(sc, ca, 2); + + psc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16 | ATAC_CAP_DATA32; + psc->sc_wdcdev.sc_atac.atac_pio_cap = 4; + if (psc->sc_dma_ok) { + psc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DMA | ATAC_CAP_UDMA; + psc->sc_wdcdev.irqack = pciide_irqack; + psc->sc_wdcdev.sc_atac.atac_dma_cap = 2; + psc->sc_wdcdev.sc_atac.atac_udma_cap = 6; + } + psc->sc_wdcdev.sc_atac.atac_set_modes = sii3112_setup_channel; + + /* We can use SControl and SStatus to probe for drives. */ + psc->sc_wdcdev.sc_atac.atac_probe = sii3112_drv_probe; + + psc->sc_wdcdev.sc_atac.atac_channels = psc->wdc_chanarray; + psc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS; + + wdc_allocate_regs(&psc->sc_wdcdev); + + /* + * The 3112 either identifies itself as a RAID storage device + * or a Misc storage device. Fake up the interface bits for + * what our driver expects. + */ + if (CARDBUS_SUBCLASS(ca->ca_class) == PCI_SUBCLASS_MASS_STORAGE_IDE) { + interface = CARDBUS_INTERFACE(ca->ca_class); + } else { + interface = PCIIDE_INTERFACE_BUS_MASTER_DMA | + PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1); + } + + for (channel = 0; channel < psc->sc_wdcdev.sc_atac.atac_nchannels; + channel++) { + cp = &psc->pciide_channels[channel]; + if (pciide_chansetup(psc, channel, interface) == 0) + continue; + pciide_cardbus_mapchan(ca, cp, interface, &cmdsize, &ctlsize, + pciide_pci_intr); + } +} + +static void +sii3114_cardbus_mapreg_dma(struct cardbus_pciide_softc *sc, + struct cardbus_attach_args *ca) +{ + struct pciide_softc *psc = &sc->sc_pidesc; + struct pciide_channel *pc; + int chan, reg; + bus_size_t size; + + psc->sc_wdcdev.dma_arg = psc; + psc->sc_wdcdev.dma_init = pciide_dma_init; + psc->sc_wdcdev.dma_start = pciide_dma_start; + psc->sc_wdcdev.dma_finish = pciide_dma_finish; + + if (device_cfdata(psc->sc_wdcdev.sc_atac.atac_dev)->cf_flags & + PCIIDE_OPTIONS_NODMA) { + aprint_verbose(", but unused (forced off by config file)"); + psc->sc_dma_ok = 0; + return; + } + + /* + * Slice off a subregion of BA5 for each of the channel's DMA + * registers. + */ + + psc->sc_dma_iot = psc->sc_ba5_st; + for (chan = 0; chan < 4; chan++) { + pc = &psc->pciide_channels[chan]; + for (reg = 0; reg < IDEDMA_NREGS; reg++) { + size = 4; + if (size > (IDEDMA_SCH_OFFSET - reg)) + size = IDEDMA_SCH_OFFSET - reg; + if (bus_space_subregion(psc->sc_ba5_st, psc->sc_ba5_sh, + satalink_ba5_regmap[chan].ba5_IDEDMA_CMD + reg, + size, &pc->dma_iohs[reg]) != 0) { + psc->sc_dma_ok = 0; + aprint_verbose(", but can't subregion offset " + "%lu size %lu", + (u_long) satalink_ba5_regmap[ + chan].ba5_IDEDMA_CMD + reg, + (u_long) size); + return; + } + } + } + + /* DMA registers all set up! */ + psc->sc_dmat = ca->ca_dmat; + psc->sc_dma_ok = 1; +} + +void +sii3114_cardbus_chip_map(struct pciide_softc *psc, union bus_attach_args *ba) +{ + struct cardbus_pciide_softc *sc = (struct cardbus_pciide_softc *)psc; + struct cardbus_attach_args *ca = ba->ca; + cardbus_devfunc_t ct = ca->ca_ct; + cardbus_chipset_tag_t cc = ct->ct_cc; + cardbus_function_tag_t cf = ct->ct_cf; + cardbustag_t tag = ca->ca_tag; + struct pciide_channel *cp; + cardbusreg_t scs_cmd; + int channel; + +#define SII3114_RESET_BITS \ + (SCS_CMD_PBM_RESET | SCS_CMD_ARB_RESET | \ + SCS_CMD_FF1_RESET | SCS_CMD_FF0_RESET | \ + SCS_CMD_FF3_RESET | SCS_CMD_FF2_RESET | \ + SCS_CMD_IDE1_RESET | SCS_CMD_IDE0_RESET | \ + SCS_CMD_IDE3_RESET | SCS_CMD_IDE2_RESET) + + /* + * Reset everything and then unblock all of the interrupts. + */ + scs_cmd = cardbus_conf_read(cc, cf, tag, SII3112_SCS_CMD); + cardbus_conf_write(cc, cf, tag, SII3112_SCS_CMD, + scs_cmd | SII3114_RESET_BITS); + delay(50 * 1000); + cardbus_conf_write(cc, cf, tag, SII3112_SCS_CMD, + scs_cmd & SCS_CMD_M66EN); + delay(50 * 1000); + + /* + * On the 3114, the BA5 register space is always enabled. In + * order to use the 3114 in any sane way, we must use this BA5 + * register space, and so we consider it an error if we cannot + * map it. + * + * As a consequence of using BA5, our register mapping is different + * from a normal PCI IDE controller's, and so we are unable to use + * most of the common PCI IDE register mapping functions. + */ + if (Cardbus_mapreg_map(ct, CARDBUS_BASE5_REG, + CARDBUS_MAPREG_TYPE_MEM, 0, + &psc->sc_ba5_st, &psc->sc_ba5_sh, + NULL, &psc->sc_ba5_ssize) != 0) { + aprint_error_dev(psc->sc_wdcdev.sc_atac.atac_dev, + "unable to map SATALink BA5 register space\n"); + return; + } + psc->sc_ba5_en = 1; + + aprint_verbose_dev(psc->sc_wdcdev.sc_atac.atac_dev, + "%dMHz PCI bus\n", (scs_cmd & SCS_CMD_M66EN) ? 66 : 33); + + /* + * Set the Interrupt Steering bit in the IDEDMA_CMD register of + * channel 2. This is required at all times for proper operation + * when using the BA5 register space (otherwise interrupts from + * all 4 channels won't work). + */ + BA5_WRITE_4(psc, 2, ba5_IDEDMA_CMD, IDEDMA_CMD_INT_STEER); + + aprint_verbose_dev(psc->sc_wdcdev.sc_atac.atac_dev, + "bus-master DMA support present"); + sii3114_cardbus_mapreg_dma(sc, ca); + aprint_verbose("\n"); + + sii_cardbus_fixup_cacheline(sc, ca, 4); + + psc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16 | ATAC_CAP_DATA32; + psc->sc_wdcdev.sc_atac.atac_pio_cap = 4; + if (psc->sc_dma_ok) { + psc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DMA | ATAC_CAP_UDMA; + psc->sc_wdcdev.irqack = pciide_irqack; + psc->sc_wdcdev.sc_atac.atac_dma_cap = 2; + psc->sc_wdcdev.sc_atac.atac_udma_cap = 6; + } + psc->sc_wdcdev.sc_atac.atac_set_modes = sii3112_setup_channel; + + /* We can use SControl and SStatus to probe for drives. */ + psc->sc_wdcdev.sc_atac.atac_probe = sii3112_drv_probe; + + psc->sc_wdcdev.sc_atac.atac_channels = psc->wdc_chanarray; + psc->sc_wdcdev.sc_atac.atac_nchannels = 4; + + wdc_allocate_regs(&psc->sc_wdcdev); + + /* establish the interrupt handler. */ + psc->sc_pci_ih = cardbus_intr_establish(cc, cf, ca->ca_intrline, + IPL_BIO, pciide_pci_intr, sc); + if (psc->sc_pci_ih == NULL) { + aprint_error_dev(psc->sc_wdcdev.sc_atac.atac_dev, + "couldn't establish interrupt\n"); + return; + } + + for (channel = 0; channel < psc->sc_wdcdev.sc_atac.atac_nchannels; + channel++) { + cp = &psc->pciide_channels[channel]; + if (sii3114_chansetup(psc, channel) == 0) + continue; + sii3114_mapchan(cp); + } +} --- sys/dev/pci/satalinkvar.h.orig 1970-01-01 09:00:00.000000000 +0900 +++ sys/dev/pci/satalinkvar.h 2008-09-28 21:10:08.000000000 +0900 @@ -0,0 +1,94 @@ +/* $NetBSD: satalink.c,v 1.38 2008/04/28 20:23:55 martin Exp $ */ + +/*- + * Copyright (c) 2003 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _DEV_PCI_SATALINKVAR_H_ +#define _DEV_PCI_SATALINKVAR_H_ + +/* + * Register map for BA5 register space, indexed by channel. + */ +struct satalink_ba5_regmap { + bus_addr_t ba5_IDEDMA_CMD; + bus_addr_t ba5_IDEDMA_CTL; + bus_addr_t ba5_IDEDMA_TBL; + bus_addr_t ba5_IDEDMA_CMD2; + bus_addr_t ba5_IDEDMA_CTL2; + bus_addr_t ba5_IDE_TF0; + bus_addr_t ba5_IDE_TF1; + bus_addr_t ba5_IDE_TF2; + bus_addr_t ba5_IDE_TF3; + bus_addr_t ba5_IDE_TF4; + bus_addr_t ba5_IDE_TF5; + bus_addr_t ba5_IDE_TF6; + bus_addr_t ba5_IDE_TF7; + bus_addr_t ba5_IDE_TF8; + bus_addr_t ba5_IDE_RAD; + bus_addr_t ba5_IDE_TF9; + bus_addr_t ba5_IDE_TF10; + bus_addr_t ba5_IDE_TF11; + bus_addr_t ba5_IDE_TF12; + bus_addr_t ba5_IDE_TF13; + bus_addr_t ba5_IDE_TF14; + bus_addr_t ba5_IDE_TF15; + bus_addr_t ba5_IDE_TF16; + bus_addr_t ba5_IDE_TF17; + bus_addr_t ba5_IDE_TF18; + bus_addr_t ba5_IDE_TF19; + bus_addr_t ba5_IDE_RABC; + bus_addr_t ba5_IDE_CMD_STS; + bus_addr_t ba5_IDE_CFG_STS; + bus_addr_t ba5_IDE_DTM; + bus_addr_t ba5_SControl; + bus_addr_t ba5_SStatus; + bus_addr_t ba5_SError; + bus_addr_t ba5_SActive; /* 3114 */ + bus_addr_t ba5_SMisc; + bus_addr_t ba5_PHY_CONFIG; + bus_addr_t ba5_SIEN; + bus_addr_t ba5_SFISCfg; +}; +extern const struct satalink_ba5_regmap satalink_ba5_regmap[]; + +#define ba5_SIS 0x214 /* summary interrupt status */ + +/* Interrupt steering bit in BA5[0x200]. */ +#define IDEDMA_CMD_INT_STEER (1U << 1) + +#define BA5_READ_4(sc, chan, reg) \ + (sc)->sc_ba5_read_4((sc), satalink_ba5_regmap[(chan)].reg) +#define BA5_WRITE_4(sc, chan, reg, val) \ + (sc)->sc_ba5_write_4((sc), satalink_ba5_regmap[(chan)].reg, (val)) + +int sii3114_chansetup(struct pciide_softc *, int); +void sii3114_mapchan(struct pciide_channel *); +void sii3112_drv_probe(struct ata_channel *); +void sii3112_setup_channel(struct ata_channel*); + +#endif /* _DEV_PCI_SATALINKVAR_H_ */