- 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:
parent
f7ca917a98
commit
b43b844f6f
@ -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",
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user