Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys Automatically build up a list of bad sectors from failed...
details: https://anonhg.NetBSD.org/src/rev/6bd18b270f8c
branches: trunk
changeset: 545709:6bd18b270f8c
user: darrenr <darrenr%NetBSD.org@localhost>
date: Tue Apr 15 14:11:00 2003 +0000
description:
Automatically build up a list of bad sectors from failed read operations and
prempt read operations on matching regions with a failure rather than waiting
for the device to return a failure. The I/O operation must have already failed
MAXRETRIES times before being added to the list - this can generally take up
to 12 seconds.
List is made accessible to userspace via DIOCBSLIST and DIOCBSFLUSH.
diffstat:
sys/dev/ata/wd.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++-
sys/dev/ata/wdvar.h | 4 ++-
sys/sys/disk.h | 12 +++++++-
sys/sys/dkio.h | 6 +++-
4 files changed, 96 insertions(+), 5 deletions(-)
diffs (190 lines):
diff -r c130b9678151 -r 6bd18b270f8c sys/dev/ata/wd.c
--- a/sys/dev/ata/wd.c Tue Apr 15 13:59:35 2003 +0000
+++ b/sys/dev/ata/wd.c Tue Apr 15 14:11:00 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: wd.c,v 1.240 2003/04/03 22:18:23 fvdl Exp $ */
+/* $NetBSD: wd.c,v 1.241 2003/04/15 14:11:00 darrenr Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
@@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.240 2003/04/03 22:18:23 fvdl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.241 2003/04/15 14:11:00 darrenr Exp $");
#ifndef WDCDEBUG
#define WDCDEBUG
@@ -288,6 +288,7 @@
#else
bufq_alloc(&wd->sc_q, BUFQ_DISKSORT|BUFQ_SORT_RAWBLOCK);
#endif
+ SLIST_INIT(&wd->sc_bslist);
wd->atabus = adev->adev_bustype;
wd->openings = adev->adev_openings;
@@ -423,6 +424,13 @@
struct buf *bp;
int s, bmaj, cmaj, i, mn;
+ /* Clean out the bad sector list */
+ while (!SLIST_EMPTY(&sc->sc_bslist)) {
+ void *head = SLIST_FIRST(&sc->sc_bslist);
+ SLIST_REMOVE_HEAD(&sc->sc_bslist, dbs_next);
+ free(head, M_TEMP);
+ }
+
/* locate the major number */
bmaj = bdevsw_lookup_major(&wd_bdevsw);
cmaj = cdevsw_lookup_major(&wd_cdevsw);
@@ -525,6 +533,23 @@
bp->b_rawblkno = blkno;
+ /*
+ * If the transfer about to be attempted contains only a block that
+ * is known to be bad then return an error for the transfer without
+ * even attempting to start a transfer up under the premis that we
+ * will just end up doing more retries for a transfer that will end
+ * up failing again.
+ * XXX:SMP - mutex required to protect with DIOCBSFLUSH
+ */
+ if (__predict_false(!SLIST_EMPTY(&wd->sc_bslist))) {
+ struct disk_badsectors *dbs;
+ daddr_t maxblk = blkno + bp->b_bcount;
+
+ SLIST_FOREACH(dbs, &wd->sc_bslist, dbs_next)
+ if (dbs->dbs_min >= blkno && dbs->dbs_max < maxblk)
+ goto bad;
+ }
+
/* Queue transfer on drive, activate drive and controller if idle. */
s = splbio();
BUFQ_PUT(&wd->sc_q, bp);
@@ -744,6 +769,25 @@
return;
}
printf("\n");
+
+ /*
+ * Not all errors indicate a failed block but those that do,
+ * put the block on the bad-block list for the device. Only
+ * do this for reads because the drive should do it for writes,
+ * itself, according to Manuel.
+ */
+ if ((b->b_flags & B_READ) &&
+ ((wd->drvp->ata_vers >= 4 && wd->sc_wdc_bio.r_error & 64) ||
+ (wd->drvp->ata_vers < 4 && wd->sc_wdc_bio.r_error & 192)) {
+ struct disk_badsectors *dbs;
+
+ dbs = malloc(sizeof *dbs, M_TEMP, M_WAITOK);
+ dbs->dbs_min = bp->b_rawblkno;
+ dbs->dbs_max = dbs->dbs_min + bp->b_bcount - 1;
+ microtime(&dbs->dbs_failedat);
+ SLIST_INSERT_HEAD(&wd->sc_bslist, dbs, dbs_next);
+ }
+
bp->b_flags |= B_ERROR;
bp->b_error = EIO;
break;
@@ -1137,6 +1181,37 @@
return 0;
#endif
+ case DIOCBSLIST :
+ {
+ caddr_t laddr = *(caddr_t *)addr;
+ struct disk_badsectors *dbs;
+ size_t available;
+ u_int32_t count;
+
+ count = 0;
+ copyin(laddr, &available, sizeof(available));
+ laddr += sizeof(count);
+ SLIST_FOREACH(dbs, &wd->sc_bslist, dbs_next) {
+ if (available < sizeof(dbs))
+ break;
+ available -= sizeof(dbs);
+ copyout(dbs, laddr, sizeof(*dbs));
+ laddr += sizeof(*dbs);
+ count++;
+ }
+ copyout(&count, *(caddr_t *)addr, sizeof(count));
+ return 0;
+ }
+
+ case DIOCBSFLUSH :
+ /* Clean out the bad sector list */
+ while (!SLIST_EMPTY(&wd->sc_bslist)) {
+ void *head = SLIST_FIRST(&wd->sc_bslist);
+ SLIST_REMOVE_HEAD(&wd->sc_bslist, dbs_next);
+ free(head, M_TEMP);
+ }
+ return 0;
+
case DIOCGDINFO:
*(struct disklabel *)addr = *(wd->sc_dk.dk_label);
return 0;
diff -r c130b9678151 -r 6bd18b270f8c sys/dev/ata/wdvar.h
--- a/sys/dev/ata/wdvar.h Tue Apr 15 13:59:35 2003 +0000
+++ b/sys/dev/ata/wdvar.h Tue Apr 15 14:11:00 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: wdvar.h,v 1.15 2003/04/03 22:18:23 fvdl Exp $ */
+/* $NetBSD: wdvar.h,v 1.16 2003/04/15 14:11:00 darrenr Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -136,6 +136,8 @@
void *sc_sdhook; /* our shutdown hook */
+ SLIST_HEAD(, disk_badsectors) sc_bslist;
+
#if NRND > 0
rndsource_element_t rnd_source;
#endif
diff -r c130b9678151 -r 6bd18b270f8c sys/sys/disk.h
--- a/sys/sys/disk.h Tue Apr 15 13:59:35 2003 +0000
+++ b/sys/sys/disk.h Tue Apr 15 14:11:00 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: disk.h,v 1.20 2002/11/01 11:32:02 mrg Exp $ */
+/* $NetBSD: disk.h,v 1.21 2003/04/15 14:11:00 darrenr Exp $ */
/*-
* Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
@@ -182,6 +182,16 @@
*/
TAILQ_HEAD(disklist_head, disk); /* the disklist is a TAILQ */
+/*
+ * Bad sector lists per fixed disk
+ */
+struct disk_badsectors {
+ SLIST_ENTRY(disk_badsectors) dbs_next;
+ u_int64_t dbs_min; /* min. sector number */
+ u_int64_t dbs_max; /* max. sector number */
+ struct timeval dbs_failedat; /* first failure at */
+};
+
#ifdef _KERNEL
extern int disk_count; /* number of disks in global disklist */
diff -r c130b9678151 -r 6bd18b270f8c sys/sys/dkio.h
--- a/sys/sys/dkio.h Tue Apr 15 13:59:35 2003 +0000
+++ b/sys/sys/dkio.h Tue Apr 15 14:11:00 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: dkio.h,v 1.6 2002/01/09 04:12:13 thorpej Exp $ */
+/* $NetBSD: dkio.h,v 1.7 2003/04/15 14:11:00 darrenr Exp $ */
/*
* Copyright (c) 1987, 1988, 1993
@@ -88,4 +88,8 @@
/* sync disk cache */
#define DIOCCACHESYNC _IOW('d', 118, int) /* sync cache (force?) */
+ /* bad sector list */
+#define DIOCBSLIST _IOWR('d', 119, caddr_t) /* get list */
+#define DIOCBSFLUSH _IO('d', 120) /* flush list */
+
#endif /* _SYS_DKIO_H_ */
Home |
Main Index |
Thread Index |
Old Index