Index: sys/dev/cardbus/files.cardbus *************** *** 131,133 **** --- 131,137 ---- # attach njata at cardbus with njata_cardbus file dev/cardbus/njata_cardbus.c njata_cardbus + + device viasata: ata, ata_dma, ata_udma, pciide_common, wdc_common, sata + attach viasata at cardbus with viasata_cardbus + file dev/cardbus/viasata_cardbus.c viasata_cardbus Index: sys/dev/cardbus/viasata_cardbus.c *************** *** 0 **** --- 1,234 ---- + /* $Id: viasata_cardbus.c,v 1.7 2009/01/27 05:48:13 tsubai Exp $ */ + + /*- + * Copyright (c) 2009 Tsubai Masanari. All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 + #include + #include + + #include + #include + #include + #include + + struct viasata_cardbus_softc { + struct pciide_softc sc_pciide; + struct wdc_regs sc_wdc_regs[2]; + + cardbus_devfunc_t sc_ct; + cardbustag_t sc_tag; + void *sc_ih; + }; + + int viasata_cardbus_match(struct device *, struct cfdata *, void *); + void viasata_cardbus_attach(struct device *, struct device *, void *); + int viasata_cardbus_detach(struct device *, int); + + CFATTACH_DECL_NEW(viasata_cardbus, sizeof(struct viasata_cardbus_softc), + viasata_cardbus_match, viasata_cardbus_attach, viasata_cardbus_detach, NULL); + + int + viasata_cardbus_match(parent, match, aux) + struct device *parent; + struct cfdata *match; + void *aux; + { + struct cardbus_attach_args *ca = aux; + + if (CARDBUS_VENDOR(ca->ca_id) == PCI_VENDOR_VIATECH && + CARDBUS_PRODUCT(ca->ca_id) == PCI_PRODUCT_VIATECH_VT6421_RAID) + return 1; + + return 0; + } + + void + viasata_cardbus_attach(parent, self, aux) + struct device *parent, *self; + void *aux; + { + struct cardbus_attach_args *ca = aux; + struct viasata_cardbus_softc *csc = device_private(self); + struct pciide_softc *sc = &csc->sc_pciide; + cardbus_devfunc_t ct = ca->ca_ct; + cardbus_chipset_tag_t cc = ct->ct_cc; + cardbus_function_tag_t cf = ct->ct_cf; + struct ata_channel *chp; + struct wdc_regs *wdr; + u_int csr, interface; + int chan, i; + + sc->sc_dma_maxsegsz = IDEDMA_BYTE_COUNT_MAX; + sc->sc_dma_boundary = IDEDMA_BYTE_COUNT_ALIGN; + + if (Cardbus_mapreg_map(ct, 0x24, PCI_MAPREG_TYPE_IO, 0, + &sc->sc_ba5_st, &sc->sc_ba5_sh, NULL, NULL)) { + printf(": failed to map BA5 registers\n"); + return; + } + sc->sc_ba5_en = 1; + + if (Cardbus_mapreg_map(ct, 0x20, PCI_MAPREG_TYPE_IO, 0, + &sc->sc_dma_iot, &sc->sc_dma_ioh, NULL, NULL)) { + printf(": failed to map dma registers\n"); + return; + } + + sc->sc_dmat = ca->ca_dmat; + csc->sc_ct = ct; + csc->sc_tag = ca->ca_tag; + + csc->sc_ih = cardbus_intr_establish(cc, cf, ca->ca_intrline, IPL_BIO, + pciide_pci_intr, sc); + if (csc->sc_ih == NULL) { + printf(": failed to establish interrupt\n"); + return; + } + + /* Make sure the right access type is on the CardBus bridge. */ + (*cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE); + (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); + + /* Enable the appropriate bits in the PCI CSR. */ + csr = cardbus_conf_read(cc, cf, ca->ca_tag, PCI_COMMAND_STATUS_REG); + csr |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_IO_ENABLE; + cardbus_conf_write(cc, cf, ca->ca_tag, PCI_COMMAND_STATUS_REG, csr); + + sc->sc_wdcdev.regs = csc->sc_wdc_regs; + sc->sc_wdcdev.sc_atac.atac_dev = self; + sc->sc_wdcdev.sc_atac.atac_nchannels = 2; + sc->sc_wdcdev.sc_atac.atac_pio_cap = 4; + sc->sc_wdcdev.sc_atac.atac_dma_cap = 2; + sc->sc_wdcdev.sc_atac.atac_udma_cap = 6; + sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16 | ATAC_CAP_DATA32; + sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_UDMA | ATAC_CAP_DMA; + sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray; + sc->sc_wdcdev.sc_atac.atac_probe = wdc_sataprobe; + sc->sc_wdcdev.sc_atac.atac_set_modes = sata_setup_channel; + sc->sc_wdcdev.irqack = pciide_irqack; + + sc->sc_dma_ok = 1; + sc->sc_wdcdev.dma_arg = sc; + sc->sc_wdcdev.dma_init = pciide_dma_init; + sc->sc_wdcdev.dma_start = pciide_dma_start; + sc->sc_wdcdev.dma_finish = pciide_dma_finish; + + interface = PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1); + interface |= PCIIDE_INTERFACE_BUS_MASTER_DMA; + + for (chan = 0; chan < sc->sc_wdcdev.sc_atac.atac_nchannels; chan++) { + pciide_chansetup(sc, chan, interface); + + chp = &sc->pciide_channels[chan].ata_channel; + chp->ch_ndrive = 1; + wdr = CHAN_TO_WDC_REGS(chp); + + if (Cardbus_mapreg_map(ct, 0x10 + chan * 4, PCI_MAPREG_TYPE_IO, + 0, &wdr->cmd_iot, &wdr->cmd_baseioh, NULL, NULL)) { + printf(": failed to map device registers\n"); + return; + } + } + for (chan = 0; chan < sc->sc_wdcdev.sc_atac.atac_nchannels; chan++) { + struct pciide_channel *pc = &sc->pciide_channels[chan]; + + for (i = 0; i < IDEDMA_NREGS; i++) { + bus_space_subregion(sc->sc_dma_iot, sc->sc_dma_ioh, + IDEDMA_SCH_OFFSET * chan + i, 4, + &pc->dma_iohs[i]); + } + } + printf("\n"); + + for (chan = 0; chan < sc->sc_wdcdev.sc_atac.atac_nchannels; chan++) { + chp = &sc->pciide_channels[chan].ata_channel; + wdr = CHAN_TO_WDC_REGS(chp); + + wdr->ctl_iot = wdr->cmd_iot; + for (i = 0; i < WDC_NREG; i++) + bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh, + i, 1, &wdr->cmd_iohs[i]); + bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh, + WDC_NREG + 2, 1, &wdr->ctl_ioh); + + wdc_init_shadow_regs(chp); + wdr->data32iot = wdr->cmd_iot; + wdr->data32ioh = wdr->cmd_iohs[0]; + + wdr->sata_iot = sc->sc_ba5_st; + wdr->sata_baseioh = sc->sc_ba5_sh; + bus_space_subregion(wdr->sata_iot, wdr->sata_baseioh, + (chan << 6) + 0x0, 1, &wdr->sata_status); + bus_space_subregion(wdr->sata_iot, wdr->sata_baseioh, + (chan << 6) + 0x4, 1, &wdr->sata_error); + bus_space_subregion(wdr->sata_iot, wdr->sata_baseioh, + (chan << 6) + 0x8, 1, &wdr->sata_control); + + wdcattach(chp); + } + } + + int + viasata_cardbus_detach(self, flags) + struct device *self; + int flags; + { + struct viasata_cardbus_softc *csc = device_private(self); + struct pciide_softc *sc = &csc->sc_pciide; + struct ata_channel *chp; + struct wdc_regs *wdr; + int chan, error; + + error = wdcdetach(sc->sc_wdcdev.sc_atac.atac_dev, flags); + if (error) + return error; + + for (chan = 0; chan < sc->sc_wdcdev.sc_atac.atac_nchannels; chan++) { + chp = &sc->pciide_channels[chan].ata_channel; + wdr = CHAN_TO_WDC_REGS(chp); + if (wdr->cmd_baseioh) + Cardbus_mapreg_unmap(csc->sc_ct, 0x10 + chan * 4, + wdr->cmd_iot, wdr->cmd_baseioh, 16); + + } + + if (sc->sc_dma_ioh) + Cardbus_mapreg_unmap(csc->sc_ct, 0x20, sc->sc_dma_iot, + sc->sc_dma_ioh, 32); + + if (sc->sc_ba5_sh) + Cardbus_mapreg_unmap(csc->sc_ct, 0x24, sc->sc_ba5_st, + sc->sc_ba5_sh, 256); + + /* XXX bus_dmamap */ + + if (csc->sc_ih) + cardbus_intr_disestablish(csc->sc_ct->ct_cc, + csc->sc_ct->ct_cf, csc->sc_ih); + + return 0; + }