NetBSD/sys/dev/pci/pdcide.c
bouyer 5741c101e5 Clear interrupts at end of attach, in case there is one pending.
Avoid "bogus intr" messages when interrupts are enabled later.
Patch tested by myself and Chuck Silvers.
2003-11-15 16:40:46 +00:00

620 lines
20 KiB
C

/* $NetBSD: pdcide.c,v 1.7 2003/11/15 16:40:46 bouyer Exp $ */
/*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Manuel Bouyer.
* 4. 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 <sys/param.h>
#include <sys/systm.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
#include <dev/pci/pciidereg.h>
#include <dev/pci/pciidevar.h>
#include <dev/pci/pciide_pdc202xx_reg.h>
static void pdc202xx_chip_map(struct pciide_softc *, struct pci_attach_args *);
static void pdc202xx_setup_channel(struct channel_softc *);
static void pdc20268_setup_channel(struct channel_softc *);
static int pdc202xx_pci_intr(void *);
static int pdc20265_pci_intr(void *);
static void pdc20262_dma_start(void *, int, int);
static int pdc20262_dma_finish(void *, int, int, int);
static int pdcide_match(struct device *, struct cfdata *, void *);
static void pdcide_attach(struct device *, struct device *, void *);
CFATTACH_DECL(pdcide, sizeof(struct pciide_softc),
pdcide_match, pdcide_attach, NULL, NULL);
static const struct pciide_product_desc pciide_promise_products[] = {
{ PCI_PRODUCT_PROMISE_ULTRA33,
0,
"Promise Ultra33/ATA Bus Master IDE Accelerator",
pdc202xx_chip_map,
},
{ PCI_PRODUCT_PROMISE_ULTRA66,
0,
"Promise Ultra66/ATA Bus Master IDE Accelerator",
pdc202xx_chip_map,
},
{ PCI_PRODUCT_PROMISE_ULTRA100,
0,
"Promise Ultra100/ATA Bus Master IDE Accelerator",
pdc202xx_chip_map,
},
{ PCI_PRODUCT_PROMISE_ULTRA100X,
0,
"Promise Ultra100/ATA Bus Master IDE Accelerator",
pdc202xx_chip_map,
},
{ PCI_PRODUCT_PROMISE_ULTRA100TX2,
0,
"Promise Ultra100TX2/ATA Bus Master IDE Accelerator",
pdc202xx_chip_map,
},
{ PCI_PRODUCT_PROMISE_ULTRA100TX2v2,
0,
"Promise Ultra100TX2v2/ATA Bus Master IDE Accelerator",
pdc202xx_chip_map,
},
{ PCI_PRODUCT_PROMISE_ULTRA133,
0,
"Promise Ultra133/ATA Bus Master IDE Accelerator",
pdc202xx_chip_map,
},
{ PCI_PRODUCT_PROMISE_ULTRA133TX2,
0,
"Promise Ultra133TX2/ATA Bus Master IDE Accelerator",
pdc202xx_chip_map,
},
{ PCI_PRODUCT_PROMISE_MBULTRA133,
0,
"Promise Ultra133/ATA Bus Master IDE Accelerator (MB)",
pdc202xx_chip_map,
},
{ PCI_PRODUCT_PROMISE_ULTRA133TX2v2,
0,
"Promise Ultra133TX2v2/ATA Bus Master IDE Accelerator",
pdc202xx_chip_map,
},
{ PCI_PRODUCT_PROMISE_FASTTRAK133LITE,
0,
"Promise Fasttrak133 Lite Bus Master IDE Accelerator",
pdc202xx_chip_map,
},
{ PCI_PRODUCT_PROMISE_SATA150TX2PLUS,
0,
"Promise Serial ATA/150 TX2plus Bus Master IDE Accelerator",
pdc202xx_chip_map,
},
{ PCI_PRODUCT_PROMISE_SATA150FT378,
0,
"Promise FastTrak 378 Serial ATA/150 Bus Master IDE Controller",
pdc202xx_chip_map,
},
{ 0,
0,
NULL,
NULL
}
};
static int
pdcide_match(struct device *parent, struct cfdata *match, void *aux)
{
struct pci_attach_args *pa = aux;
if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_PROMISE) {
if (pciide_lookup_product(pa->pa_id, pciide_promise_products))
return (2);
}
return (0);
}
static void
pdcide_attach(struct device *parent, struct device *self, void *aux)
{
struct pci_attach_args *pa = aux;
struct pciide_softc *sc = (struct pciide_softc *)self;
pciide_common_attach(sc, pa,
pciide_lookup_product(pa->pa_id, pciide_promise_products));
}
/* Macros to test product */
#define PDC_IS_262(sc) \
((sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA66 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA100 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA100X || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA100TX2 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA100TX2v2 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA133 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA133TX2 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_MBULTRA133 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA133TX2v2 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_FASTTRAK133LITE)
#define PDC_IS_265(sc) \
((sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA100 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA100X || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA100TX2 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA100TX2v2 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA133 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA133TX2 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_MBULTRA133 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA133TX2v2 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_FASTTRAK133LITE)
#define PDC_IS_268(sc) \
((sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA100TX2 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA100TX2v2 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA133 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA133TX2 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_MBULTRA133 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA133TX2v2 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_FASTTRAK133LITE)
#define PDC_IS_276(sc) \
((sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA133 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA133TX2 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_MBULTRA133 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA133TX2v2 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_FASTTRAK133LITE)
static void
pdc202xx_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
{
struct pciide_channel *cp;
int channel;
pcireg_t interface, st, mode;
bus_size_t cmdsize, ctlsize;
if (!PDC_IS_268(sc)) {
st = pci_conf_read(sc->sc_pc, sc->sc_tag, PDC2xx_STATE);
WDCDEBUG_PRINT(("pdc202xx_setup_chip: controller state 0x%x\n",
st), DEBUG_PROBE);
/* turn off RAID mode */
if (st & PDC2xx_STATE_IDERAID) {
WDCDEBUG_PRINT(("pdc202xx_setup_chip: turning off RAID mode\n"), DEBUG_PROBE);
st &= ~PDC2xx_STATE_IDERAID;
pci_conf_write(sc->sc_pc, sc->sc_tag, PDC2xx_STATE, st);
}
} else
st = PDC2xx_STATE_NATIVE | PDC262_STATE_EN(0) | PDC262_STATE_EN(1);
if (pciide_chipen(sc, pa) == 0)
return;
/*
* can't rely on the PCI_CLASS_REG content if the chip was in raid
* mode. We have to fake interface
*/
interface = PCIIDE_INTERFACE_SETTABLE(0) | PCIIDE_INTERFACE_SETTABLE(1);
if (st & PDC2xx_STATE_NATIVE)
interface |= PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1);
aprint_normal("%s: bus-master DMA support present",
sc->sc_wdcdev.sc_dev.dv_xname);
pciide_mapreg_dma(sc, pa);
aprint_normal("\n");
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
WDC_CAPABILITY_MODE;
if (sc->sc_dma_ok) {
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
sc->sc_wdcdev.irqack = pciide_irqack;
}
if (PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE &&
PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_RAID)
sc->sc_wdcdev.cap |= WDC_CAPABILITY_RAID;
sc->sc_wdcdev.PIO_cap = 4;
sc->sc_wdcdev.DMA_cap = 2;
if (PDC_IS_276(sc))
sc->sc_wdcdev.UDMA_cap = 6;
else if (PDC_IS_265(sc))
sc->sc_wdcdev.UDMA_cap = 5;
else if (PDC_IS_262(sc))
sc->sc_wdcdev.UDMA_cap = 4;
else
sc->sc_wdcdev.UDMA_cap = 2;
sc->sc_wdcdev.set_modes = PDC_IS_268(sc) ?
pdc20268_setup_channel : pdc202xx_setup_channel;
sc->sc_wdcdev.channels = sc->wdc_chanarray;
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
if (sc->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA66 ||
sc->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA100 ||
sc->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA100X) {
sc->sc_wdcdev.dma_start = pdc20262_dma_start;
sc->sc_wdcdev.dma_finish = pdc20262_dma_finish;
}
if (!PDC_IS_268(sc)) {
/* setup failsafe defaults */
mode = 0;
mode = PDC2xx_TIM_SET_PA(mode, pdc2xx_pa[0]);
mode = PDC2xx_TIM_SET_PB(mode, pdc2xx_pb[0]);
mode = PDC2xx_TIM_SET_MB(mode, pdc2xx_dma_mb[0]);
mode = PDC2xx_TIM_SET_MC(mode, pdc2xx_dma_mc[0]);
for (channel = 0;
channel < sc->sc_wdcdev.nchannels;
channel++) {
WDCDEBUG_PRINT(("pdc202xx_setup_chip: channel %d "
"drive 0 initial timings 0x%x, now 0x%x\n",
channel, pci_conf_read(sc->sc_pc, sc->sc_tag,
PDC2xx_TIM(channel, 0)), mode | PDC2xx_TIM_IORDYp),
DEBUG_PROBE);
pci_conf_write(sc->sc_pc, sc->sc_tag,
PDC2xx_TIM(channel, 0), mode | PDC2xx_TIM_IORDYp);
WDCDEBUG_PRINT(("pdc202xx_setup_chip: channel %d "
"drive 1 initial timings 0x%x, now 0x%x\n",
channel, pci_conf_read(sc->sc_pc, sc->sc_tag,
PDC2xx_TIM(channel, 1)), mode), DEBUG_PROBE);
pci_conf_write(sc->sc_pc, sc->sc_tag,
PDC2xx_TIM(channel, 1), mode);
}
mode = PDC2xx_SCR_DMA;
if (PDC_IS_265(sc)) {
mode = PDC2xx_SCR_SET_GEN(mode, PDC265_SCR_GEN_LAT);
} else if (PDC_IS_262(sc)) {
mode = PDC2xx_SCR_SET_GEN(mode, PDC262_SCR_GEN_LAT);
} else {
/* the BIOS set it up this way */
mode = PDC2xx_SCR_SET_GEN(mode, 0x1);
}
mode = PDC2xx_SCR_SET_I2C(mode, 0x3); /* ditto */
mode = PDC2xx_SCR_SET_POLL(mode, 0x1); /* ditto */
WDCDEBUG_PRINT(("pdc202xx_setup_chip: initial SCR 0x%x, "
"now 0x%x\n",
bus_space_read_4(sc->sc_dma_iot, sc->sc_dma_ioh,
PDC2xx_SCR),
mode), DEBUG_PROBE);
bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh,
PDC2xx_SCR, mode);
/* controller initial state register is OK even without BIOS */
/* Set DMA mode to IDE DMA compatibility */
mode =
bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_PM);
WDCDEBUG_PRINT(("pdc202xx_setup_chip: primary mode 0x%x", mode),
DEBUG_PROBE);
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_PM,
mode | 0x1);
mode =
bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_SM);
WDCDEBUG_PRINT((", secondary mode 0x%x\n", mode ), DEBUG_PROBE);
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_SM,
mode | 0x1);
}
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
cp = &sc->pciide_channels[channel];
if (pciide_chansetup(sc, channel, interface) == 0)
continue;
if ((st & (PDC_IS_262(sc) ?
PDC262_STATE_EN(channel):PDC246_STATE_EN(channel))) == 0) {
aprint_normal("%s: %s channel ignored (disabled)\n",
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
cp->wdc_channel.ch_flags |= WDCF_DISABLED;
continue;
}
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
PDC_IS_265(sc) ? pdc20265_pci_intr : pdc202xx_pci_intr);
/* clear interrupt, in case there is one pending */
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
IDEDMA_CTL + IDEDMA_SCH_OFFSET * channel, IDEDMA_CTL_INTR);
}
return;
}
static void
pdc202xx_setup_channel(struct channel_softc *chp)
{
struct ata_drive_datas *drvp;
int drive;
pcireg_t mode, st;
u_int32_t idedma_ctl, scr, atapi;
struct pciide_channel *cp = (struct pciide_channel*)chp;
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
int channel = chp->channel;
/* setup DMA if needed */
pciide_channel_dma_setup(cp);
idedma_ctl = 0;
WDCDEBUG_PRINT(("pdc202xx_setup_channel %s: scr 0x%x\n",
sc->sc_wdcdev.sc_dev.dv_xname,
bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, PDC262_U66)),
DEBUG_PROBE);
/* Per channel settings */
if (PDC_IS_262(sc)) {
scr = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
PDC262_U66);
st = pci_conf_read(sc->sc_pc, sc->sc_tag, PDC2xx_STATE);
/* Trim UDMA mode */
if ((st & PDC262_STATE_80P(channel)) != 0 ||
(chp->ch_drive[0].drive_flags & DRIVE_UDMA &&
chp->ch_drive[0].UDMA_mode <= 2) ||
(chp->ch_drive[1].drive_flags & DRIVE_UDMA &&
chp->ch_drive[1].UDMA_mode <= 2)) {
if (chp->ch_drive[0].UDMA_mode > 2)
chp->ch_drive[0].UDMA_mode = 2;
if (chp->ch_drive[1].UDMA_mode > 2)
chp->ch_drive[1].UDMA_mode = 2;
}
/* Set U66 if needed */
if ((chp->ch_drive[0].drive_flags & DRIVE_UDMA &&
chp->ch_drive[0].UDMA_mode > 2) ||
(chp->ch_drive[1].drive_flags & DRIVE_UDMA &&
chp->ch_drive[1].UDMA_mode > 2))
scr |= PDC262_U66_EN(channel);
else
scr &= ~PDC262_U66_EN(channel);
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
PDC262_U66, scr);
WDCDEBUG_PRINT(("pdc202xx_setup_channel %s:%d: ATAPI 0x%x\n",
sc->sc_wdcdev.sc_dev.dv_xname, channel,
bus_space_read_4(sc->sc_dma_iot, sc->sc_dma_ioh,
PDC262_ATAPI(channel))), DEBUG_PROBE);
if (chp->ch_drive[0].drive_flags & DRIVE_ATAPI ||
chp->ch_drive[1].drive_flags & DRIVE_ATAPI) {
if (((chp->ch_drive[0].drive_flags & DRIVE_UDMA) &&
!(chp->ch_drive[1].drive_flags & DRIVE_UDMA) &&
(chp->ch_drive[1].drive_flags & DRIVE_DMA)) ||
((chp->ch_drive[1].drive_flags & DRIVE_UDMA) &&
!(chp->ch_drive[0].drive_flags & DRIVE_UDMA) &&
(chp->ch_drive[0].drive_flags & DRIVE_DMA)))
atapi = 0;
else
atapi = PDC262_ATAPI_UDMA;
bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh,
PDC262_ATAPI(channel), atapi);
}
}
for (drive = 0; drive < 2; drive++) {
drvp = &chp->ch_drive[drive];
/* If no drive, skip */
if ((drvp->drive_flags & DRIVE) == 0)
continue;
mode = 0;
if (drvp->drive_flags & DRIVE_UDMA) {
/* use Ultra/DMA */
drvp->drive_flags &= ~DRIVE_DMA;
mode = PDC2xx_TIM_SET_MB(mode,
pdc2xx_udma_mb[drvp->UDMA_mode]);
mode = PDC2xx_TIM_SET_MC(mode,
pdc2xx_udma_mc[drvp->UDMA_mode]);
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
} else if (drvp->drive_flags & DRIVE_DMA) {
mode = PDC2xx_TIM_SET_MB(mode,
pdc2xx_dma_mb[drvp->DMA_mode]);
mode = PDC2xx_TIM_SET_MC(mode,
pdc2xx_dma_mc[drvp->DMA_mode]);
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
} else {
mode = PDC2xx_TIM_SET_MB(mode,
pdc2xx_dma_mb[0]);
mode = PDC2xx_TIM_SET_MC(mode,
pdc2xx_dma_mc[0]);
}
mode = PDC2xx_TIM_SET_PA(mode, pdc2xx_pa[drvp->PIO_mode]);
mode = PDC2xx_TIM_SET_PB(mode, pdc2xx_pb[drvp->PIO_mode]);
if (drvp->drive_flags & DRIVE_ATA)
mode |= PDC2xx_TIM_PRE;
mode |= PDC2xx_TIM_SYNC | PDC2xx_TIM_ERRDY;
if (drvp->PIO_mode >= 3) {
mode |= PDC2xx_TIM_IORDY;
if (drive == 0)
mode |= PDC2xx_TIM_IORDYp;
}
WDCDEBUG_PRINT(("pdc202xx_setup_channel: %s:%d:%d "
"timings 0x%x\n",
sc->sc_wdcdev.sc_dev.dv_xname,
chp->channel, drive, mode), DEBUG_PROBE);
pci_conf_write(sc->sc_pc, sc->sc_tag,
PDC2xx_TIM(chp->channel, drive), mode);
}
if (idedma_ctl != 0) {
/* Add software bits in status register */
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
IDEDMA_CTL + (IDEDMA_SCH_OFFSET * chp->channel),
idedma_ctl);
}
}
static void
pdc20268_setup_channel(struct channel_softc *chp)
{
struct ata_drive_datas *drvp;
int drive;
u_int32_t idedma_ctl;
struct pciide_channel *cp = (struct pciide_channel*)chp;
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
int u100;
/* setup DMA if needed */
pciide_channel_dma_setup(cp);
idedma_ctl = 0;
/* I don't know what this is for, FreeBSD does it ... */
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
IDEDMA_CMD + 0x1 + IDEDMA_SCH_OFFSET * chp->channel, 0x0b);
/*
* cable type detect, from FreeBSD
*/
u100 = (bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
IDEDMA_CMD + 0x3 + IDEDMA_SCH_OFFSET * chp->channel) & 0x04) ?
0 : 1;
for (drive = 0; drive < 2; drive++) {
drvp = &chp->ch_drive[drive];
/* If no drive, skip */
if ((drvp->drive_flags & DRIVE) == 0)
continue;
if (drvp->drive_flags & DRIVE_UDMA) {
/* use Ultra/DMA */
drvp->drive_flags &= ~DRIVE_DMA;
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
if (drvp->UDMA_mode > 2 && u100 == 0)
drvp->UDMA_mode = 2;
} else if (drvp->drive_flags & DRIVE_DMA) {
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
}
}
/* nothing to do to setup modes, the controller snoop SET_FEATURE cmd */
if (idedma_ctl != 0) {
/* Add software bits in status register */
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
IDEDMA_CTL + (IDEDMA_SCH_OFFSET * chp->channel),
idedma_ctl);
}
}
static int
pdc202xx_pci_intr(void *arg)
{
struct pciide_softc *sc = arg;
struct pciide_channel *cp;
struct channel_softc *wdc_cp;
int i, rv, crv;
u_int32_t scr;
rv = 0;
scr = bus_space_read_4(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_SCR);
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
cp = &sc->pciide_channels[i];
wdc_cp = &cp->wdc_channel;
/* If a compat channel skip. */
if (cp->compat)
continue;
if (scr & PDC2xx_SCR_INT(i)) {
crv = wdcintr(wdc_cp);
if (crv == 0)
printf("%s:%d: bogus intr (reg 0x%x)\n",
sc->sc_wdcdev.sc_dev.dv_xname, i, scr);
else
rv = 1;
}
}
return rv;
}
static int
pdc20265_pci_intr(void *arg)
{
struct pciide_softc *sc = arg;
struct pciide_channel *cp;
struct channel_softc *wdc_cp;
int i, rv, crv;
u_int32_t dmastat;
rv = 0;
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
cp = &sc->pciide_channels[i];
wdc_cp = &cp->wdc_channel;
/* If a compat channel skip. */
if (cp->compat)
continue;
#if 0
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CMD + 0x1 + IDEDMA_SCH_OFFSET * i, 0x0b);
if ((bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CMD + 0x3 + IDEDMA_SCH_OFFSET * i) & 0x20) == 0)
continue;
#endif
/*
* The Ultra/100 seems to assert PDC2xx_SCR_INT * spuriously,
* however it asserts INT in IDEDMA_CTL even for non-DMA ops.
* So use it instead (requires 2 reg reads instead of 1,
* but we can't do it another way).
*/
dmastat = bus_space_read_1(sc->sc_dma_iot,
sc->sc_dma_ioh, IDEDMA_CTL + IDEDMA_SCH_OFFSET * i);
if((dmastat & IDEDMA_CTL_INTR) == 0)
continue;
crv = wdcintr(wdc_cp);
if (crv == 0)
printf("%s:%d: bogus intr\n",
sc->sc_wdcdev.sc_dev.dv_xname, i);
else
rv = 1;
}
return rv;
}
static void
pdc20262_dma_start(void *v, int channel, int drive)
{
struct pciide_softc *sc = v;
struct pciide_dma_maps *dma_maps =
&sc->pciide_channels[channel].dma_maps[drive];
int atapi;
if (dma_maps->dma_flags & WDC_DMA_LBA48) {
atapi = (dma_maps->dma_flags & WDC_DMA_READ) ?
PDC262_ATAPI_LBA48_READ : PDC262_ATAPI_LBA48_WRITE;
atapi |= dma_maps->dmamap_xfer->dm_mapsize >> 1;
bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh,
PDC262_ATAPI(channel), atapi);
}
pciide_dma_start(v, channel, drive);
}
static int
pdc20262_dma_finish(void *v, int channel, int drive, int force)
{
struct pciide_softc *sc = v;
struct pciide_dma_maps *dma_maps =
&sc->pciide_channels[channel].dma_maps[drive];
struct channel_softc *chp;
int atapi, error;
error = pciide_dma_finish(v, channel, drive, force);
if (dma_maps->dma_flags & WDC_DMA_LBA48) {
chp = sc->wdc_chanarray[channel];
atapi = 0;
if (chp->ch_drive[0].drive_flags & DRIVE_ATAPI ||
chp->ch_drive[1].drive_flags & DRIVE_ATAPI) {
if ((!(chp->ch_drive[0].drive_flags & DRIVE_UDMA) ||
(chp->ch_drive[1].drive_flags & DRIVE_UDMA) ||
!(chp->ch_drive[1].drive_flags & DRIVE_DMA)) &&
(!(chp->ch_drive[1].drive_flags & DRIVE_UDMA) ||
(chp->ch_drive[0].drive_flags & DRIVE_UDMA) ||
!(chp->ch_drive[0].drive_flags & DRIVE_DMA)))
atapi = PDC262_ATAPI_UDMA;
}
bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh,
PDC262_ATAPI(channel), atapi);
}
return error;
}