satalink.c revision 1.1
1/* $NetBSD: satalink.c,v 1.1 2003/12/13 23:13:41 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 1999, 2000, 2001 Manuel Bouyer. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Manuel Bouyer. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/malloc.h> 35 36#include <dev/pci/pcivar.h> 37#include <dev/pci/pcidevs.h> 38#include <dev/pci/pciidereg.h> 39#include <dev/pci/pciidevar.h> 40#include <dev/pci/pciide_sii3112_reg.h> 41 42 43static int satalink_match(struct device *, struct cfdata *, void *); 44static void satalink_attach(struct device *, struct device *, void *); 45 46CFATTACH_DECL(satalink, sizeof(struct pciide_softc), 47 satalink_match, satalink_attach, NULL, NULL); 48 49static void sii3112_chip_map(struct pciide_softc*, struct pci_attach_args*); 50static void sii3112_setup_channel(struct channel_softc*); 51 52static const struct pciide_product_desc pciide_satalink_products[] = { 53 { PCI_PRODUCT_CMDTECH_3112, 54 0, 55 "Silicon Image SATALink 3112", 56 sii3112_chip_map, 57 }, 58 { 0, 59 0, 60 NULL, 61 NULL 62 } 63}; 64 65static int 66satalink_match(struct device *parent, struct cfdata *match, void *aux) 67{ 68 struct pci_attach_args *pa = aux; 69 70 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_CMDTECH) { 71 if (pciide_lookup_product(pa->pa_id, pciide_satalink_products)) 72 return (2); 73 } 74 return (0); 75} 76 77static void 78satalink_attach(struct device *parent, struct device *self, void *aux) 79{ 80 struct pci_attach_args *pa = aux; 81 struct pciide_softc *sc = (struct pciide_softc *)self; 82 83 pciide_common_attach(sc, pa, 84 pciide_lookup_product(pa->pa_id, pciide_satalink_products)); 85 86} 87 88static void 89sii3112_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa) 90{ 91 struct pciide_channel *cp; 92 bus_size_t cmdsize, ctlsize; 93 pcireg_t interface; 94 int channel; 95 96 if (pciide_chipen(sc, pa) == 0) 97 return; 98 99 aprint_normal("%s: bus-master DMA support present", 100 sc->sc_wdcdev.sc_dev.dv_xname); 101 pciide_mapreg_dma(sc, pa); 102 aprint_normal("\n"); 103 104 /* 105 * Rev. <= 0x01 of the 3112 have a bug that can cause data 106 * corruption if DMA transfers cross an 8K boundary. This is 107 * apparently hard to tickle, but we'll go ahead and play it 108 * safe. 109 */ 110 if (PCI_REVISION(pa->pa_class) <= 0x01) { 111 sc->sc_dma_maxsegsz = 8192; 112 sc->sc_dma_boundary = 8192; 113 } 114 115 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 | 116 WDC_CAPABILITY_MODE; 117 sc->sc_wdcdev.PIO_cap = 4; 118 if (sc->sc_dma_ok) { 119 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA; 120 sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK; 121 sc->sc_wdcdev.irqack = pciide_irqack; 122 sc->sc_wdcdev.DMA_cap = 2; 123 sc->sc_wdcdev.UDMA_cap = 6; 124 } 125 sc->sc_wdcdev.set_modes = sii3112_setup_channel; 126 127 sc->sc_wdcdev.channels = sc->wdc_chanarray; 128 sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS; 129 130 /* 131 * The 3112 can be told to identify as a RAID controller. 132 * In this case, we have to fake interface 133 */ 134 if (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_IDE) { 135 interface = PCI_INTERFACE(pa->pa_class); 136 } else { 137 interface = PCIIDE_INTERFACE_BUS_MASTER_DMA | 138 PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1); 139 } 140 141 for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { 142 cp = &sc->pciide_channels[channel]; 143 if (pciide_chansetup(sc, channel, interface) == 0) 144 continue; 145 pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize, 146 pciide_pci_intr); 147 } 148} 149 150static void 151sii3112_setup_channel(struct channel_softc *chp) 152{ 153 struct ata_drive_datas *drvp; 154 int drive; 155 u_int32_t idedma_ctl, dtm; 156 struct pciide_channel *cp = (struct pciide_channel*)chp; 157 struct pciide_softc *sc = (struct pciide_softc*)cp->wdc_channel.wdc; 158 159 /* setup DMA if needed */ 160 pciide_channel_dma_setup(cp); 161 162 idedma_ctl = 0; 163 dtm = 0; 164 165 for (drive = 0; drive < 2; drive++) { 166 drvp = &chp->ch_drive[drive]; 167 /* If no drive, skip */ 168 if ((drvp->drive_flags & DRIVE) == 0) 169 continue; 170 if (drvp->drive_flags & DRIVE_UDMA) { 171 /* use Ultra/DMA */ 172 drvp->drive_flags &= ~DRIVE_DMA; 173 idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); 174 dtm |= DTM_IDEx_DMA; 175 } else if (drvp->drive_flags & DRIVE_DMA) { 176 idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); 177 dtm |= DTM_IDEx_DMA; 178 } else { 179 dtm |= DTM_IDEx_PIO; 180 } 181 } 182 183 /* 184 * Nothing to do to setup modes; it is meaningless in S-ATA 185 * (but many S-ATA drives still want to get the SET_FEATURE 186 * command). 187 */ 188 if (idedma_ctl != 0) { 189 /* Add software bits in status register */ 190 bus_space_write_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CTL], 0, 191 idedma_ctl); 192 } 193 pci_conf_write(sc->sc_pc, sc->sc_tag, 194 chp->channel == 0 ? SII3112_DTM_IDE0 : SII3112_DTM_IDE1, dtm); 195} 196