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