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