/*
* Copyright (c) 1999, 2000, 2001 Manuel Bouyer.
*
* 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 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.
*/
/*
* The 0648/0649 can be told to identify as a RAID controller.
* In this case, we have to fake interface
*/
if (PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_MASS_STORAGE_IDE) {
interface = PCIIDE_INTERFACE_SETTABLE(0) |
PCIIDE_INTERFACE_SETTABLE(1);
if (pciide_pci_read(pa->pa_pc, pa->pa_tag, CMD_CONF) &
CMD_CONF_DSA1)
interface |= PCIIDE_INTERFACE_PCI(0) |
PCIIDE_INTERFACE_PCI(1);
} else {
interface = PCI_INTERFACE(pa->pa_class);
}
/*
* with a CMD PCI64x, if we get here, the first channel is enabled:
* there's no way to disable the first channel without disabling
* the whole device
*/
if (channel != 0 && (ctrl & CMD_CTRL_2PORT) == 0) {
aprint_normal_dev(sc->sc_wdcdev.sc_atac.atac_dev,
"%s channel ignored (disabled)\n", cp->name);
cp->ata_channel.ch_flags |= ATACH_DISABLED;
return;
}
/*
* Check if we can execute next xfer on the channel.
* Called with chp channel lock held.
*/
static int
cmd064x_claim_hw(struct ata_channel *chp, int maysleep)
{
struct pciide_softc *sc = CHAN_TO_PCIIDE(chp);
/* Allow another channel to run. Called with ochp channel lock held. */
static void
cmd064x_free_hw(struct ata_channel *ochp)
{
struct pciide_softc *sc = CHAN_TO_PCIIDE(ochp);
uint oact = atomic_cas_uint(&sc->sc_cmd_act_channel,
ochp->ch_channel, CMDIDE_ACT_CHANNEL_NONE);
struct ata_channel *nchp;
KASSERT(oact == ochp->ch_channel);
/* Start the other channel(s) */
for(uint i = 0; i < sc->sc_wdcdev.sc_atac.atac_nchannels; i++) {
/* Skip the current channel */
if (i == oact)
continue;
nchp = &sc->pciide_channels[i].ata_channel;
if (nchp->ch_ndrives == 0)
continue;
atastart(nchp);
}
}
static int
cmd_pci_intr(void *arg)
{
struct pciide_softc *sc = arg;
struct pciide_channel *cp;
struct ata_channel *wdc_cp;
int i, rv, crv;
u_int32_t priirq, secirq;
rv = 0;
priirq = pciide_pci_read(sc->sc_pc, sc->sc_tag, CMD_CONF);
secirq = pciide_pci_read(sc->sc_pc, sc->sc_tag, CMD_ARTTIM23);
for (i = 0; i < sc->sc_wdcdev.sc_atac.atac_nchannels; i++) {
cp = &sc->pciide_channels[i];
wdc_cp = &cp->ata_channel;
/* If a compat channel skip. */
if (cp->compat)
continue;
if ((i == 0 && (priirq & CMD_CONF_DRV0_INTR)) ||
(i == 1 && (secirq & CMD_ARTTIM23_IRQ))) {
crv = wdcintr(wdc_cp);
if (crv == 0) {
aprint_verbose("%s:%d: bogus intr\n",
device_xname(
sc->sc_wdcdev.sc_atac.atac_dev), i);
} else
rv = 1;
}
}
return rv;
}
/*
* For a CMD PCI064x, the use of PCI_COMMAND_IO_ENABLE
* and base addresses registers can be disabled at
* hardware level. In this case, the device is wired
* in compat mode and its first channel is always enabled,
* but we can't rely on PCI_COMMAND_IO_ENABLE.
* In fact, it seems that the first channel of the CMD PCI0640
* can't be disabled.
*/
#ifdef PCIIDE_CMD064x_DISABLE
if (pciide_chipen(sc, pa) == 0)
return;
#endif
aprint_normal_dev(sc->sc_wdcdev.sc_atac.atac_dev,
"hardware does not support DMA\n");
sc->sc_dma_ok = 0;
/*
* For a CMD PCI064x, the use of PCI_COMMAND_IO_ENABLE
* and base addresses registers can be disabled at
* hardware level. In this case, the device is wired
* in compat mode and its first channel is always enabled,
* but we can't rely on PCI_COMMAND_IO_ENABLE.
* In fact, it seems that the first channel of the CMD PCI0640
* can't be disabled.
*/
#ifdef PCIIDE_CMD064x_DISABLE
if (pciide_chipen(sc, pa) == 0)
return;
#endif
aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev,
"bus-master DMA support present");
pciide_mapreg_dma(sc, pa);
aprint_verbose("\n");
sc->sc_wdcdev.sc_atac.atac_cap = ATAC_CAP_DATA16 | ATAC_CAP_DATA32;
if (sc->sc_dma_ok) {
sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DMA;
switch (sc->sc_pp->ide_product) {
case PCI_PRODUCT_CMDTECH_649:
sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_UDMA;
sc->sc_wdcdev.sc_atac.atac_udma_cap = 5;
sc->sc_wdcdev.irqack = cmd646_9_irqack;
break;
case PCI_PRODUCT_CMDTECH_648:
sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_UDMA;
sc->sc_wdcdev.sc_atac.atac_udma_cap = 4;
sc->sc_wdcdev.irqack = cmd646_9_irqack;
break;
case PCI_PRODUCT_CMDTECH_646:
if (rev >= CMD0646U2_REV) {
sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_UDMA;
sc->sc_wdcdev.sc_atac.atac_udma_cap = 2;
} else if (rev >= CMD0646U_REV) {
/*
* Linux's driver claims that the 646U is broken
* with UDMA. Only enable it if we know what we're
* doing
*/
#ifdef PCIIDE_CMD0646U_ENABLEUDMA
sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_UDMA;
sc->sc_wdcdev.sc_atac.atac_udma_cap = 2;
#endif
/* explicitly disable UDMA */
pciide_pci_write(sc->sc_pc, sc->sc_tag,
CMD_UDMATIM(0), 0);
pciide_pci_write(sc->sc_pc, sc->sc_tag,
CMD_UDMATIM(1), 0);
}
sc->sc_wdcdev.irqack = cmd646_9_irqack;
break;
default:
sc->sc_wdcdev.irqack = pciide_irqack;
}
}