Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev For ATAPI tape drives, poll for DSC (using a callout...
details: https://anonhg.NetBSD.org/src/rev/8387a2be7861
branches: trunk
changeset: 518475:8387a2be7861
user: bouyer <bouyer%NetBSD.org@localhost>
date: Sat Dec 01 00:00:29 2001 +0000
description:
For ATAPI tape drives, poll for DSC (using a callout), to get the real
status of the command, and make sure the drive is ready for the next one.
diffstat:
sys/dev/ata/atavar.h | 3 +-
sys/dev/ic/wdcvar.h | 3 +-
sys/dev/scsipi/atapi_wdc.c | 139 ++++++++++++++++++++++++++++++++------------
3 files changed, 104 insertions(+), 41 deletions(-)
diffs (235 lines):
diff -r 66c3800e59dc -r 8387a2be7861 sys/dev/ata/atavar.h
--- a/sys/dev/ata/atavar.h Fri Nov 30 23:48:50 2001 +0000
+++ b/sys/dev/ata/atavar.h Sat Dec 01 00:00:29 2001 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: atavar.h,v 1.19 2001/04/25 17:53:27 bouyer Exp $ */
+/* $NetBSD: atavar.h,v 1.20 2001/12/01 00:00:30 bouyer Exp $ */
/*
* Copyright (c) 1998 Manuel Bouyer.
@@ -49,6 +49,7 @@
#define DRIVE_MODE 0x0040 /* the drive reported its mode */
#define DRIVE_RESET 0x0080 /* reset the drive state at next xfer */
#define DRIVE_DMAERR 0x0100 /* Udma transfer had crc error, don't try DMA */
+#define DRIVE_ATAPIST 0x0100 /* device is an ATAPI tape drive */
/*
* Current setting of drive's PIO, DMA and UDMA modes.
* Is initialised by the disks drivers at attach time, and may be
diff -r 66c3800e59dc -r 8387a2be7861 sys/dev/ic/wdcvar.h
--- a/sys/dev/ic/wdcvar.h Fri Nov 30 23:48:50 2001 +0000
+++ b/sys/dev/ic/wdcvar.h Sat Dec 01 00:00:29 2001 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: wdcvar.h,v 1.30 2001/06/13 18:17:39 bjh21 Exp $ */
+/* $NetBSD: wdcvar.h,v 1.31 2001/12/01 00:00:30 bouyer Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -160,6 +160,7 @@
void *databuf;
int c_bcount; /* byte count left */
int c_skip; /* bytes already transferred */
+ int c_dscpoll; /* counter for dsc polling (ATAPI) */
TAILQ_ENTRY(wdc_xfer) c_xferchain;
void (*c_start) __P((struct channel_softc *, struct wdc_xfer *));
int (*c_intr) __P((struct channel_softc *, struct wdc_xfer *, int));
diff -r 66c3800e59dc -r 8387a2be7861 sys/dev/scsipi/atapi_wdc.c
--- a/sys/dev/scsipi/atapi_wdc.c Fri Nov 30 23:48:50 2001 +0000
+++ b/sys/dev/scsipi/atapi_wdc.c Sat Dec 01 00:00:29 2001 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: atapi_wdc.c,v 1.44 2001/11/13 06:56:38 lukem Exp $ */
+/* $NetBSD: atapi_wdc.c,v 1.45 2001/12/01 00:00:29 bouyer Exp $ */
/*
* Copyright (c) 1998 Manuel Bouyer.
@@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.44 2001/11/13 06:56:38 lukem Exp $");
+__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.45 2001/12/01 00:00:29 bouyer Exp $");
#ifndef WDCDEBUG
#define WDCDEBUG
@@ -91,11 +91,13 @@
int wdc_atapi_intr __P((struct channel_softc *, struct wdc_xfer *, int));
void wdc_atapi_kill_xfer __P((struct channel_softc *, struct wdc_xfer *));
int wdc_atapi_ctrl __P((struct channel_softc *, struct wdc_xfer *, int));
+void wdc_atapi_phase_complete __P((struct wdc_xfer *));
void wdc_atapi_done __P((struct channel_softc *, struct wdc_xfer *));
void wdc_atapi_reset __P((struct channel_softc *, struct wdc_xfer *));
void wdc_atapi_scsipi_request __P((struct scsipi_channel *,
scsipi_adapter_req_t, void *));
void wdc_atapi_kill_pending __P((struct scsipi_periph *));
+void wdc_atapi_polldsc __P((void *arg));
#define MAX_SIZE MAXPHYS
@@ -291,6 +293,8 @@
periph->periph_type = ATAPI_CFG_TYPE(id->atap_config);
if (id->atap_config & ATAPI_CFG_REMOV)
periph->periph_flags |= PERIPH_REMOVABLE;
+ if (periph->periph_type == T_SEQUENTIAL)
+ drvp->drive_flags |= DRIVE_ATAPIST;
sa.sa_periph = periph;
sa.sa_inqbuf.type = ATAPI_CFG_TYPE(id->atap_config);
@@ -372,6 +376,7 @@
xfer->c_start = wdc_atapi_start;
xfer->c_intr = wdc_atapi_intr;
xfer->c_kill_xfer = wdc_atapi_kill_xfer;
+ xfer->c_dscpoll = 0;
s = splbio();
wdc_exec_xfer(wdc->channels[channel], xfer);
#ifdef DIAGNOSTIC
@@ -752,47 +757,12 @@
case PHASE_ABORTED:
case PHASE_COMPLETED:
WDCDEBUG_PRINT(("PHASE_COMPLETED\n"), DEBUG_INTR);
- /* turn off DMA channel */
if (xfer->c_flags & C_DMA) {
xfer->c_bcount -= sc_xfer->datalen;
}
sc_xfer->resid = xfer->c_bcount;
- /*
- * Some drive occasionally set WDCS_ERR with
- * "ATA illegal length indication" in the error
- * register. If we read some data the sense is valid
- * anyway, so don't report the error.
- */
- if (chp->ch_status & WDCS_ERR &&
- ((sc_xfer->xs_control & XS_CTL_REQSENSE) == 0 ||
- sc_xfer->resid == sc_xfer->datalen)) {
- /* save the short sense */
- sc_xfer->error = XS_SHORTSENSE;
- sc_xfer->sense.atapi_sense = chp->ch_error;
- if ((sc_xfer->xs_periph->periph_quirks &
- PQUIRK_NOSENSE) == 0) {
- /* ask scsipi to send a REQUEST_SENSE */
- sc_xfer->error = XS_BUSY;
- sc_xfer->status = SCSI_CHECK;
- } else if (chp->wdc->dma_status &
- (WDC_DMAST_NOIRQ | WDC_DMAST_ERR)) {
- ata_dmaerr(drvp);
- sc_xfer->error = XS_RESET;
- wdc_atapi_reset(chp, xfer);
- return (1);
- }
- }
- if (xfer->c_bcount != 0) {
- WDCDEBUG_PRINT(("wdc_atapi_intr: bcount value is "
- "%d after io\n", xfer->c_bcount), DEBUG_XFERS);
- }
-#ifdef DIAGNOSTIC
- if (xfer->c_bcount < 0) {
- printf("wdc_atapi_intr warning: bcount value "
- "is %d after io\n", xfer->c_bcount);
- }
-#endif
- break;
+ wdc_atapi_phase_complete(xfer);
+ return(1);
default:
if (++retries<500) {
@@ -939,6 +909,90 @@
}
void
+wdc_atapi_phase_complete(xfer)
+ struct wdc_xfer *xfer;
+{
+ struct channel_softc *chp = xfer->chp;
+ struct scsipi_xfer *sc_xfer = xfer->cmd;
+ struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
+
+ /* wait for DSC if needed */
+ if (drvp->drive_flags & DRIVE_ATAPIST) {
+ WDCDEBUG_PRINT(("wdc_atapi_phase_complete(%s:%d:%d) "
+ "polldsc %d\n", chp->wdc->sc_dev.dv_xname, chp->channel,
+ xfer->drive, xfer->c_dscpoll), DEBUG_XFERS);
+ if (cold) {
+ if (wdcwait(chp, WDCS_DSC, WDCS_DSC,
+ sc_xfer->timeout)) {
+ printf("%s:%d:%d: wait_for_dsc failed\n",
+ chp->wdc->sc_dev.dv_xname, chp->channel,
+ xfer->drive);
+ sc_xfer->error = XS_TIMEOUT;
+ wdc_atapi_reset(chp, xfer);
+ return;
+ }
+ } else {
+ if (wdcwait(chp, WDCS_DSC, WDCS_DSC, 10)) {
+ /* 10ms not enouth, try again in 1 tick */
+ if (xfer->c_dscpoll++ >
+ sc_xfer->timeout * hz / 1000) {
+ printf("%s:%d:%d: wait_for_dsc "
+ "failed\n",
+ chp->wdc->sc_dev.dv_xname,
+ chp->channel, xfer->drive);
+ sc_xfer->error = XS_TIMEOUT;
+ wdc_atapi_reset(chp, xfer);
+ return;
+ }
+ callout_reset(&chp->ch_callout, 1,
+ wdc_atapi_polldsc, xfer);
+ return;
+ }
+ }
+ }
+
+ /*
+ * Some drive occasionally set WDCS_ERR with
+ * "ATA illegal length indication" in the error
+ * register. If we read some data the sense is valid
+ * anyway, so don't report the error.
+ */
+ if (chp->ch_status & WDCS_ERR &&
+ ((sc_xfer->xs_control & XS_CTL_REQSENSE) == 0 ||
+ sc_xfer->resid == sc_xfer->datalen)) {
+ /* save the short sense */
+ sc_xfer->error = XS_SHORTSENSE;
+ sc_xfer->sense.atapi_sense = chp->ch_error;
+ if ((sc_xfer->xs_periph->periph_quirks &
+ PQUIRK_NOSENSE) == 0) {
+ /* ask scsipi to send a REQUEST_SENSE */
+ sc_xfer->error = XS_BUSY;
+ sc_xfer->status = SCSI_CHECK;
+ } else if (chp->wdc->dma_status &
+ (WDC_DMAST_NOIRQ | WDC_DMAST_ERR)) {
+ ata_dmaerr(drvp);
+ sc_xfer->error = XS_RESET;
+ wdc_atapi_reset(chp, xfer);
+ return;
+ }
+ }
+ if (xfer->c_bcount != 0) {
+ WDCDEBUG_PRINT(("wdc_atapi_intr: bcount value is "
+ "%d after io\n", xfer->c_bcount), DEBUG_XFERS);
+ }
+#ifdef DIAGNOSTIC
+ if (xfer->c_bcount < 0) {
+ printf("wdc_atapi_intr warning: bcount value "
+ "is %d after io\n", xfer->c_bcount);
+ }
+#endif
+ WDCDEBUG_PRINT(("wdc_atapi_phase_complete: wdc_atapi_done(), "
+ "error 0x%x sense 0x%x\n", sc_xfer->error,
+ sc_xfer->sense.atapi_sense), DEBUG_INTR);
+ wdc_atapi_done(chp, xfer);
+}
+
+void
wdc_atapi_done(chp, xfer)
struct channel_softc *chp;
struct wdc_xfer *xfer;
@@ -978,3 +1032,10 @@
wdc_atapi_done(chp, xfer);
return;
}
+
+void
+wdc_atapi_polldsc(arg)
+ void *arg;
+{
+ wdc_atapi_phase_complete(arg);
+}
Home |
Main Index |
Thread Index |
Old Index