Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev Fix more probe delay and/or failure problems:



details:   https://anonhg.NetBSD.org/src/rev/d8f8a1e95f72
branches:  trunk
changeset: 552295:d8f8a1e95f72
user:      mycroft <mycroft%NetBSD.org@localhost>
date:      Tue Sep 23 09:19:22 2003 +0000

description:
Fix more probe delay and/or failure problems:
1) Don't wait for DRQ on an IDENTIFY command -- if it's not set when we see
   BSY clear, abort the command and ignore the drive.  (Do this by testing
   for DRQ in the read/write cases in __wdccommand_intr().)
2) Don't wait for DRQ to deassert when we finish an IDENTIFY (or any other
   non-block command that reads data) -- we don't do this for block I/O, and
   empirically it doesn't clear on my CF cards at all, causing a pointless 1s
   delay.
3) Add comments to some of the delay()s, and add missing ones in wdcreset()
   and the WDCC_RECAL in the so-called "pre-ATA" probe.
4) Slightly simplify the reset sequence -- we were doing an extra I/O.
5) Modify the register writability test to make sure that registers are not
   overlapped -- this can happen in some weird cases with a missing device 1.
6) Check the error register value after the reset -- if it's not 01h or 81h,
   as appropriate (see ATA spec), punt.
Tested with a number of ATA-only, ATAPI-only, mixed ATA-ATAPI, CF, and IDE
disk configurations.

Also remove the SINGLE_DRIVE nonsense again.

diffstat:

 sys/dev/ata/ata.c           |   10 +-
 sys/dev/ic/wdc.c            |  121 +++++++++++++++++++------------------------
 sys/dev/ic/wdcvar.h         |    3 +-
 sys/dev/isa/wdc_isa.c       |    7 +-
 sys/dev/pci/pciide.c        |    6 +-
 sys/dev/pcmcia/wdc_pcmcia.c |    5 +-
 6 files changed, 67 insertions(+), 85 deletions(-)

diffs (truncated from 471 to 300 lines):

diff -r 31a30cad3f26 -r d8f8a1e95f72 sys/dev/ata/ata.c
--- a/sys/dev/ata/ata.c Tue Sep 23 09:16:07 2003 +0000
+++ b/sys/dev/ata/ata.c Tue Sep 23 09:19:22 2003 +0000
@@ -1,4 +1,4 @@
-/*      $NetBSD: ata.c,v 1.18 2003/01/27 21:27:52 bouyer Exp $      */
+/*      $NetBSD: ata.c,v 1.19 2003/09/23 09:19:22 mycroft Exp $      */
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
  *
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.18 2003/01/27 21:27:52 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.19 2003/09/23 09:19:22 mycroft Exp $");
 
 #ifndef WDCDEBUG
 #define WDCDEBUG
@@ -87,12 +87,12 @@
        if (drvp->drive_flags & DRIVE_ATA) {
                wdc_c.r_command = WDCC_IDENTIFY;
                wdc_c.r_st_bmask = WDCS_DRDY;
-               wdc_c.r_st_pmask = WDCS_DRQ;
+               wdc_c.r_st_pmask = 0;
                wdc_c.timeout = 3000; /* 3s */
        } else if (drvp->drive_flags & DRIVE_ATAPI) {
                wdc_c.r_command = ATAPI_IDENTIFY_DEVICE;
                wdc_c.r_st_bmask = 0;
-               wdc_c.r_st_pmask = WDCS_DRQ;
+               wdc_c.r_st_pmask = 0;
                wdc_c.timeout = 10000; /* 10s */
        } else {
                WDCDEBUG_PRINT(("wdc_ata_get_parms: no disks\n"),
@@ -162,7 +162,7 @@
        wdc_c.r_st_pmask = 0;
        wdc_c.r_precomp = WDSF_SET_MODE;
        wdc_c.r_count = mode;
-       wdc_c.flags = AT_READ | flags;
+       wdc_c.flags = flags;
        wdc_c.timeout = 1000; /* 1s */
        if (wdc_exec_command(drvp, &wdc_c) != WDC_COMPLETE)
                return CMD_AGAIN;
diff -r 31a30cad3f26 -r d8f8a1e95f72 sys/dev/ic/wdc.c
--- a/sys/dev/ic/wdc.c  Tue Sep 23 09:16:07 2003 +0000
+++ b/sys/dev/ic/wdc.c  Tue Sep 23 09:19:22 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: wdc.c,v 1.130 2003/09/21 11:56:40 enami Exp $ */
+/*     $NetBSD: wdc.c,v 1.131 2003/09/23 09:19:23 mycroft Exp $ */
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -70,7 +70,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.130 2003/09/21 11:56:40 enami Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.131 2003/09/23 09:19:23 mycroft Exp $");
 
 #ifndef WDCDEBUG
 #define WDCDEBUG
@@ -193,7 +193,6 @@
        u_int8_t st0, st1, sc, sn, cl, ch;
        u_int8_t ret_value = 0x03;
        u_int8_t drive;
-       int found;
 
        /*
         * Sanity check to see if the wdc channel responds at all.
@@ -206,14 +205,14 @@
                        chp->wdc->select(chp,0);
                bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
                    WDSD_IBM);
-               delay(10);
+               delay(10);      /* 400ns delay */
                st0 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status);
                
                if (chp->wdc && (chp->wdc->cap & WDC_CAPABILITY_SELECT))
                        chp->wdc->select(chp,1);
                bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
                    WDSD_IBM | 0x10);
-               delay(10);
+               delay(10);      /* 400ns delay */
                st1 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status);
 
                WDCDEBUG_PRINT(("%s:%d: before reset, st0=0x%x, st1=0x%x\n",
@@ -232,15 +231,15 @@
                        bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
                            WDSD_IBM);
                        bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo,
+                           0x02);
+                       if (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
+                           wd_cyl_lo) != 0x02)
+                               ret_value &= ~0x01;
+                       bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo,
                            0x01);
                        if (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
                            wd_cyl_lo) != 0x01)
                                ret_value &= ~0x01;
-                       bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo,
-                           0x02);
-                       if (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
-                           wd_cyl_lo) != 0x02)
-                               ret_value &= ~0x01;
                        bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sector,
                            0x01);
                        if (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
@@ -251,6 +250,9 @@
                        if (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
                            wd_sector) != 0x02)
                                ret_value &= ~0x01;
+                       if (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
+                           wd_cyl_lo) != 0x01)
+                               ret_value &= ~0x01;
                }
 
                /* Register writability test, drive 1. */
@@ -260,15 +262,15 @@
                        bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
                            WDSD_IBM | 0x10);
                        bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo,
+                           0x02);
+                       if (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
+                           wd_cyl_lo) != 0x02)
+                               ret_value &= ~0x02;
+                       bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo,
                            0x01);
                        if (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
                            wd_cyl_lo) != 0x01)
                                ret_value &= ~0x02;
-                       bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo,
-                           0x02);
-                       if (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
-                           wd_cyl_lo) != 0x02)
-                               ret_value &= ~0x02;
                        bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sector,
                            0x01);
                        if (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
@@ -279,6 +281,9 @@
                        if (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
                            wd_sector) != 0x02)
                                ret_value &= ~0x02;
+                       if (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
+                           wd_cyl_lo) != 0x01)
+                               ret_value &= ~0x02;
                }
 
                if (ret_value == 0)
@@ -291,16 +296,13 @@
        /* assert SRST, wait for reset to complete */
        bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
            WDSD_IBM);
-       delay(10);
+       delay(10);      /* 400ns delay */
        bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
-           WDCTL_RST | WDCTL_IDS); 
-       DELAY(1000);
-       bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
-           WDCTL_IDS);
-       delay(1000);
+           WDCTL_RST | WDCTL_IDS | WDCTL_4BIT); 
+       delay(2000);
        (void) bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_error);
        bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
-       delay(10);
+       delay(10);      /* 400ns delay */
 
        ret_value = __wdcwait_reset(chp, ret_value);
        WDCDEBUG_PRINT(("%s:%d: after reset, ret_value=0x%d\n",
@@ -317,30 +319,14 @@
         * something here assume it's ATA or OLD. Ghost will be killed later in
         * attach routine.
         */
-       found = 0;
        for (drive = 0; drive < 2; drive++) {
                if ((ret_value & (0x01 << drive)) == 0)
                        continue;
-               if (1 < ++found && chp->wdc != NULL &&
-                   (chp->wdc->cap & WDC_CAPABILITY_SINGLE_DRIVE)) {
-                       /*
-                        * Ignore second drive if WDC_CAPABILITY_SINGLE_DRIVE
-                        * is set.
-                        *
-                        * Some CF Card (for ex. IBM MicroDrive and SanDisk)
-                        * doesn't seem to implement drive select command. In
-                        * this case, you can't eliminate ghost drive properly.
-                        */
-                       WDCDEBUG_PRINT(("%s:%d:%d: ignored.\n",
-                           chp->wdc->sc_dev.dv_xname,
-                           chp->channel, drive), DEBUG_PROBE);
-                       break;
-               }
                if (chp->wdc && chp->wdc->cap & WDC_CAPABILITY_SELECT)
                        chp->wdc->select(chp,drive);
                bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
                    WDSD_IBM | (drive << 4));
-               delay(10);
+               delay(10);      /* 400ns delay */
                /* Save registers contents */
                sc = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_seccnt);
                sn = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_sector);
@@ -459,7 +445,7 @@
                                chp->wdc->select(chp,i);
                        bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
                            WDSD_IBM | (i << 4));
-                       delay(10);
+                       delay(10);      /* 400ns delay */
                        bus_space_write_1(chp->cmd_iot, chp->cmd_ioh,
                            wd_error, 0x58);
                        bus_space_write_1(chp->cmd_iot, chp->cmd_ioh,
@@ -474,11 +460,6 @@
                                    chp->channel, i), DEBUG_PROBE);
                                    chp->ch_drive[i].drive_flags &= ~DRIVE_OLD;
                        }
-                       if (chp->wdc->cap & WDC_CAPABILITY_SELECT)
-                               chp->wdc->select(chp,i);
-                       bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
-                           WDSD_IBM | (i << 4));
-                       delay(100);
                        if (wait_for_ready(chp, 10000) != 0) {
                                WDCDEBUG_PRINT(("%s:%d:%d: not ready\n",
                                    chp->wdc->sc_dev.dv_xname,
@@ -488,6 +469,7 @@
                        }
                        bus_space_write_1(chp->cmd_iot, chp->cmd_ioh,
                            wd_command, WDCC_RECAL);
+                       delay(10);      /* 400ns delay */
                        if (wait_for_ready(chp, 10000) != 0) {
                                WDCDEBUG_PRINT(("%s:%d:%d: WDCC_RECAL failed\n",
                                    chp->wdc->sc_dev.dv_xname,
@@ -851,15 +833,13 @@
                chp->wdc->select(chp,0);
        bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
            WDSD_IBM); /* master */
-       bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
-           WDCTL_RST | WDCTL_IDS);
-       delay(1000);
+       delay(10);      /* 400ns delay */
        bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
-           WDCTL_IDS);
-       delay(1000);
+           WDCTL_RST | WDCTL_IDS | WDCTL_4BIT);
+       delay(2000);
        (void) bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_error);
-       bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
-           WDCTL_4BIT);
+       bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
+       delay(10);      /* 400ns delay */
 
        drv_mask1 = (chp->ch_drive[0].drive_flags & DRIVE) ? 0x01:0x00;
        drv_mask1 |= (chp->ch_drive[1].drive_flags & DRIVE) ? 0x02:0x00;
@@ -882,7 +862,7 @@
        int drv_mask;
 {
        int timeout;
-       u_int8_t st0, st1;
+       u_int8_t st0, er0, st1, er1;
 #ifdef WDCDEBUG
        u_int8_t sc0, sn0, cl0, ch0;
        u_int8_t sc1, sn1, cl1, ch1;
@@ -895,6 +875,7 @@
                    WDSD_IBM); /* master */
                delay(10);
                st0 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status);
+               er0 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_error);
 #ifdef WDCDEBUG
                sc0 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_seccnt);
                sn0 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_sector);
@@ -907,6 +888,7 @@
                    WDSD_IBM | 0x10); /* slave */
                delay(10);
                st1 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status);
+               er1 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_error);
 #ifdef WDCDEBUG
                sc1 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_seccnt);
                sn1 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_sector);
@@ -940,6 +922,10 @@
        if (st1 & WDCS_BSY)
                drv_mask &= ~0x02;
 end:
+       if (er0 != 0x01 && er0 != 0x81)
+               drv_mask &= ~0x01;
+       if (er1 != 0x01)
+               drv_mask &= ~0x02;
        WDCDEBUG_PRINT(("%s:%d:0: after reset, sc=0x%x sn=0x%x "
            "cl=0x%x ch=0x%x\n",
             chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",
@@ -949,9 +935,9 @@
             chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",
             chp->channel, sc1, sn1, cl1, ch1), DEBUG_PROBE);
 
-       WDCDEBUG_PRINT(("%s:%d: wdcwait_reset() end, st0=0x%x, st1=0x%x\n",
+       WDCDEBUG_PRINT(("%s:%d: wdcwait_reset() end, st0=0x%x er0=0x%x, st1=0x%x er1=0x%x\n",
            chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe", chp->channel,
-           st0, st1), DEBUG_PROBE);
+           st0, er0, st1, er1), DEBUG_PROBE);
 
        return drv_mask;
 }
@@ -977,7 +963,7 @@
        for (;;) {



Home | Main Index | Thread Index | Old Index