- change the interrupt routines to take a 3rd arguments, set to 1 if we

are called from the interrupt or timeout handler, 0 otherwise.
- use this to know if we can busy-wait for wait_for_unbusy or wait_for_ready
This fixes a bug where CDs withot the DRQ_INTR capability would not busy-wait
for the CMDOUT phase.
While I'm there change 2 delay() to DELAY() for consistency, and
garbage-collect some old code from wdcintr() which has been ifdef'd out
for some time now.
This commit is contained in:
bouyer 1999-04-01 21:46:28 +00:00
parent f7ca917a98
commit b43b844f6f
4 changed files with 46 additions and 72 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ata_wdc.c,v 1.18 1999/03/25 16:17:36 bouyer Exp $ */
/* $NetBSD: ata_wdc.c,v 1.19 1999/04/01 21:46:28 bouyer Exp $ */
/*
* Copyright (c) 1998 Manuel Bouyer.
@ -117,9 +117,9 @@ int wdcdebug_wd_mask = 0;
#define ATA_DELAY 10000 /* 10s for a drive I/O */
void wdc_ata_bio_start __P((struct channel_softc *,struct wdc_xfer *));
int wdc_ata_bio_intr __P((struct channel_softc *, struct wdc_xfer *));
int wdc_ata_bio_intr __P((struct channel_softc *, struct wdc_xfer *, int));
void wdc_ata_bio_done __P((struct channel_softc *, struct wdc_xfer *));
int wdc_ata_ctrl_intr __P((struct channel_softc *, struct wdc_xfer *));
int wdc_ata_ctrl_intr __P((struct channel_softc *, struct wdc_xfer *, int));
int wdc_ata_err __P((struct ata_drive_datas *, struct ata_bio *));
#define WDC_ATA_NOERR 0x00 /* Drive doesn't report an error */
#define WDC_ATA_RECOV 0x01 /* There was a recovered error */
@ -199,8 +199,8 @@ wdc_ata_bio_start(chp, xfer)
ATA_DELAY / 1000 * hz);
} else {
/* Wait for at last 400ns for status bit to be valid */
delay(1);
wdc_ata_ctrl_intr(chp, xfer);
DELAY(1);
wdc_ata_ctrl_intr(chp, xfer, 0);
}
return;
}
@ -372,7 +372,7 @@ intr: /* Wait for IRQ (either real or polled) */
} else {
/* Wait for at last 400ns for status bit to be valid */
delay(1);
wdc_ata_bio_intr(chp, xfer);
wdc_ata_bio_intr(chp, xfer, 0);
if ((ata_bio->flags & ATA_ITSDONE) == 0)
goto again;
}
@ -388,9 +388,10 @@ timeout:
}
int
wdc_ata_bio_intr(chp, xfer)
wdc_ata_bio_intr(chp, xfer, irq)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int irq;
{
struct ata_bio *ata_bio = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
@ -417,9 +418,8 @@ wdc_ata_bio_intr(chp, xfer)
/* Ack interrupt done by wait_for_unbusy */
if (wait_for_unbusy(chp,
(ata_bio->flags & ATA_POLL) ? ATA_DELAY : 0) < 0) {
if ((ata_bio->flags & ATA_POLL) == 0 &&
(xfer->c_flags & C_TIMEOU) == 0)
(irq == 0) ? ATA_DELAY : 0) < 0) {
if (irq && (xfer->c_flags & C_TIMEOU) == 0)
return 0; /* IRQ was not for us */
printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip%d\n",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
@ -585,14 +585,15 @@ wdc_ata_bio_done(chp, xfer)
* Implement operations needed before read/write.
*/
int
wdc_ata_ctrl_intr(chp, xfer)
wdc_ata_ctrl_intr(chp, xfer, irq)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int irq;
{
struct ata_bio *ata_bio = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
char *errstring = NULL;
int delay = (ata_bio->flags & ATA_POLL) ? ATA_DELAY : 0;
int delay = (irq == 0) ? ATA_DELAY : 0;
WDCDEBUG_PRINT(("wdc_ata_ctrl_intr: state %d\n", drvp->state),
DEBUG_FUNCS);
@ -708,7 +709,7 @@ again:
return 1;
timeout:
if ((xfer->c_flags & C_TIMEOU) == 0 && delay == 0) {
if (irq && (xfer->c_flags & C_TIMEOU) == 0) {
return 0; /* IRQ was not for us */
}
printf("%s:%d:%d: %s timed out\n",

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdc.c,v 1.65 1999/03/31 11:18:31 bouyer Exp $ */
/* $NetBSD: wdc.c,v 1.66 1999/04/01 21:46:29 bouyer Exp $ */
/*
@ -117,7 +117,7 @@ static void __wdcerror __P((struct channel_softc*, char *));
static int __wdcwait_reset __P((struct channel_softc *, int));
void __wdccommand_done __P((struct channel_softc *, struct wdc_xfer *));
void __wdccommand_start __P((struct channel_softc *, struct wdc_xfer *));
int __wdccommand_intr __P((struct channel_softc *, struct wdc_xfer *));
int __wdccommand_intr __P((struct channel_softc *, struct wdc_xfer *, int));
int wdprint __P((void *, const char *));
@ -518,35 +518,7 @@ wdcintr(arg)
struct wdc_xfer *xfer;
if ((chp->ch_flags & WDCF_IRQ_WAIT) == 0) {
#if 0
/* Clear the pending interrupt and abort. */
u_int8_t s =
bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status);
#ifdef WDCDEBUG
u_int8_t e =
bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_error);
u_int8_t i =
bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_seccnt);
#else
bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_error);
bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_seccnt);
#endif
WDCDEBUG_PRINT(("wdcintr: inactive controller, "
"punting st=%02x er=%02x irr=%02x\n", s, e, i), DEBUG_INTR);
if (s & WDCS_DRQ) {
int len;
len = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
wd_cyl_lo) + 256 * bus_space_read_1(chp->cmd_iot,
chp->cmd_ioh, wd_cyl_hi);
WDCDEBUG_PRINT(("wdcintr: clearing up %d bytes\n",
len), DEBUG_INTR);
wdcbit_bucket (chp, len);
}
#else
WDCDEBUG_PRINT(("wdcintr: inactive controller\n"), DEBUG_INTR);
#endif
return 0;
}
@ -554,7 +526,7 @@ wdcintr(arg)
untimeout(wdctimeout, chp);
chp->ch_flags &= ~WDCF_IRQ_WAIT;
xfer = chp->ch_queue->sc_xfer.tqh_first;
return xfer->c_intr(chp, xfer);
return xfer->c_intr(chp, xfer, 1);
}
/* Put all disk in RESET state */
@ -738,7 +710,7 @@ wdctimeout(arg)
*/
xfer->c_flags |= C_TIMEOU;
chp->ch_flags &= ~WDCF_IRQ_WAIT;
xfer->c_intr(chp, xfer);
xfer->c_intr(chp, xfer, 1);
} else
__wdcerror(chp, "missing untimeout");
splx(s);
@ -1079,13 +1051,14 @@ __wdccommand_start(chp, xfer)
* Wait for at last 400ns for status bit to be valid.
*/
delay(10);
__wdccommand_intr(chp, xfer);
__wdccommand_intr(chp, xfer, 0);
}
int
__wdccommand_intr(chp, xfer)
__wdccommand_intr(chp, xfer, irq)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int irq;
{
struct wdc_command *wdc_c = xfer->cmd;
int bcount = wdc_c->bcount;
@ -1094,9 +1067,8 @@ __wdccommand_intr(chp, xfer)
WDCDEBUG_PRINT(("__wdccommand_intr %s:%d:%d\n",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive), DEBUG_INTR);
if (wdcwait(chp, wdc_c->r_st_pmask, wdc_c->r_st_pmask,
(wdc_c->flags & AT_POLL) ? wdc_c->timeout : 0)) {
if ((xfer->c_flags & C_TIMEOU) == 0 &&
(wdc_c->flags & AT_POLL) == 0)
(irq == 0) ? wdc_c->timeout : 0)) {
if (irq && (xfer->c_flags & C_TIMEOU) == 0)
return 0; /* IRQ was not for us */
wdc_c->flags |= AT_TIMEOU;
__wdccommand_done(chp, xfer);

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdcvar.h,v 1.15 1999/02/08 15:22:29 bouyer Exp $ */
/* $NetBSD: wdcvar.h,v 1.16 1999/04/01 21:46:30 bouyer Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -145,7 +145,7 @@ struct wdc_xfer {
TAILQ_ENTRY(wdc_xfer) c_xferchain;
LIST_ENTRY(wdc_xfer) free_list;
void (*c_start) __P((struct channel_softc *, struct wdc_xfer *));
int (*c_intr) __P((struct channel_softc *, struct wdc_xfer *));
int (*c_intr) __P((struct channel_softc *, struct wdc_xfer *, int));
};
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: atapi_wdc.c,v 1.19 1999/03/25 16:17:37 bouyer Exp $ */
/* $NetBSD: atapi_wdc.c,v 1.20 1999/04/01 21:46:30 bouyer Exp $ */
/*
* Copyright (c) 1998 Manuel Bouyer.
@ -86,8 +86,8 @@ int wdcdebug_atapi_mask = 0;
void wdc_atapi_minphys __P((struct buf *bp));
void wdc_atapi_start __P((struct channel_softc *,struct wdc_xfer *));
int wdc_atapi_intr __P((struct channel_softc *, struct wdc_xfer *));
int wdc_atapi_ctrl __P((struct channel_softc *, struct wdc_xfer *));
int wdc_atapi_intr __P((struct channel_softc *, struct wdc_xfer *, int));
int wdc_atapi_ctrl __P((struct channel_softc *, struct wdc_xfer *, int));
void wdc_atapi_done __P((struct channel_softc *, struct wdc_xfer *));
void wdc_atapi_reset __P((struct channel_softc *, struct wdc_xfer *));
int wdc_atapi_send_cmd __P((struct scsipi_xfer *sc_xfer));
@ -246,7 +246,7 @@ wdc_atapi_start(chp, xfer)
xfer->drive, drvp->state);
panic("wdc_atapi_start: bad state");
}
wdc_atapi_ctrl(chp, xfer);
wdc_atapi_ctrl(chp, xfer, 0);
return;
}
bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
@ -281,26 +281,23 @@ wdc_atapi_start(chp, xfer)
if ((sc_xfer->sc_link->scsipi_atapi.cap & 0x0300) != ACAP_DRQ_INTR ||
sc_xfer->flags & SCSI_POLL) {
/* Wait for at last 400ns for status bit to be valid */
delay(1);
if (wdc_atapi_intr(chp, xfer) == 0) {
sc_xfer->error = XS_TIMEOUT;
wdc_atapi_reset(chp, xfer);
return;
}
DELAY(1);
wdc_atapi_intr(chp, xfer, 0);
}
if (sc_xfer->flags & SCSI_POLL) {
while ((sc_xfer->flags & ITSDONE) == 0) {
/* Wait for at last 400ns for status bit to be valid */
delay(1);
wdc_atapi_intr(chp, xfer);
DELAY(1);
wdc_atapi_intr(chp, xfer, 0);
}
}
}
int
wdc_atapi_intr(chp, xfer)
wdc_atapi_intr(chp, xfer, irq)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int irq;
{
struct scsipi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
@ -326,9 +323,8 @@ wdc_atapi_intr(chp, xfer)
bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
WDSD_IBM | (xfer->drive << 4));
if (wait_for_unbusy(chp,
(sc_xfer->flags & SCSI_POLL) ? sc_xfer->timeout : 0) != 0) {
if ((sc_xfer->flags & SCSI_POLL) == 0 &&
(xfer->c_flags & C_TIMEOU) == 0)
(irq == 0) ? sc_xfer->timeout : 0) != 0) {
if (irq && (xfer->c_flags & C_TIMEOU) == 0)
return 0; /* IRQ was not for us */
printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip=%d\n",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
@ -592,7 +588,11 @@ again:
if (xfer->c_flags & C_DMA) {
dma_err = (*chp->wdc->dma_finish)(chp->wdc->dma_arg,
chp->channel, xfer->drive, dma_flags);
xfer->c_bcount -= sc_xfer->datalen;
if (xfer->c_flags & C_SENSE)
xfer->c_bcount -=
sizeof(sc_xfer->sense.scsi_sense);
else
xfer->c_bcount -= sc_xfer->datalen;
}
if (xfer->c_flags & C_SENSE) {
if ((chp->ch_status & WDCS_ERR) || dma_err < 0) {
@ -680,14 +680,15 @@ again:
}
int
wdc_atapi_ctrl(chp, xfer)
wdc_atapi_ctrl(chp, xfer, irq)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int irq;
{
struct scsipi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
char *errstring = NULL;
int delay = (sc_xfer->flags & SCSI_POLL) ? ATAPI_DELAY : 0;
int delay = (irq == 0) ? ATAPI_DELAY : 0;
/* Ack interrupt done in wait_for_unbusy */
again:
@ -753,7 +754,7 @@ again:
return 1;
timeout:
if ((xfer->c_flags & C_TIMEOU) == 0 && delay == 0) {
if (irq && (xfer->c_flags & C_TIMEOU) == 0) {
return 0; /* IRQ was not for us */
}
printf("%s:%d:%d: %s timed out\n",