tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: WD_QUIRK_FORCE_LBA48
On Wed, Dec 16, 2009 at 03:16:00PM +0100, Manuel Bouyer wrote:
> I can test such a change if you don't want to do it.
Attached is the patch I propose. I think with this, we can get rid of
the LBA48 quirk completely.
Tested on a ST3160815AS drive (seagate 160GB) which did get the "LBA48 bug"
with the old code.
--
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
NetBSD: 26 ans d'experience feront toujours la difference
--
Index: wd.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/wd.c,v
retrieving revision 1.363.8.1
diff -u -p -u -r1.363.8.1 wd.c
--- wd.c 18 Feb 2009 00:23:09 -0000 1.363.8.1
+++ wd.c 16 Dec 2009 19:25:40 -0000
@@ -99,8 +99,6 @@ __KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.363
#include <prop/proplib.h>
-#define LBA48_THRESHOLD (0xfffffff) /* 128GB / DEV_BSIZE */
-
#define WDIORETRIES_SINGLE 4 /* number of retries before
single-sector */
#define WDIORETRIES 5 /* number of retries before giving up */
#define RECOVERYTIME hz/2 /* time to wait before retrying a cmd */
@@ -199,7 +197,6 @@ static void bad144intern(struct wd_softc
#endif
#define WD_QUIRK_SPLIT_MOD15_WRITE 0x0001 /* must split certain
writes */
-#define WD_QUIRK_FORCE_LBA48 0x0002 /* must use LBA48
commands */
#define WD_QUIRK_FMT "\20\1SPLIT_MOD15_WRITE\2FORCE_LBA48"
@@ -227,31 +224,6 @@ static const struct wd_quirk {
WD_QUIRK_SPLIT_MOD15_WRITE },
{ "ST380023AS",
WD_QUIRK_SPLIT_MOD15_WRITE },
-
- /*
- * These seagate drives seems to have issue addressing sector 0xfffffff
- * (aka LBA48_THRESHOLD) in LBA mode. The workaround is to force
- * LBA48
- * Note that we can't just change the code to always use LBA48 for
- * sector 0xfffffff, because this would break valid and working
- * setups using LBA48 drives on non-LBA48-capable controllers
- * (and it's hard to get a list of such controllers)
- */
- { "ST3160021A*",
- WD_QUIRK_FORCE_LBA48 },
- { "ST3160811A*",
- WD_QUIRK_FORCE_LBA48 },
- { "ST3160812A*",
- WD_QUIRK_FORCE_LBA48 },
- { "ST3160023A*",
- WD_QUIRK_FORCE_LBA48 },
- { "ST3160827A*",
- WD_QUIRK_FORCE_LBA48 },
- /* Attempt to catch all seagate drives larger than 200GB */
- { "ST3[2-9][0-9][0-9][0-9][0-9][0-9][A-Z]*",
- WD_QUIRK_FORCE_LBA48 },
- { "ST3[1-9][0-9][0-9][0-9][0-9][0-9][0-9][A-Z]*",
- WD_QUIRK_FORCE_LBA48 },
{ NULL,
0 }
};
@@ -380,14 +352,17 @@ wdattach(struct device *parent, struct d
((u_int64_t) wd->sc_params.__reserved6[10] << 32) |
((u_int64_t) wd->sc_params.__reserved6[9] << 16) |
((u_int64_t) wd->sc_params.__reserved6[8] << 0);
+ wd->sc_capacity28 =
+ (wd->sc_params.atap_capacity[1] << 16) |
+ wd->sc_params.atap_capacity[0];
} else if ((wd->sc_flags & WDF_LBA) != 0) {
aprint_verbose(" LBA addressing\n");
- wd->sc_capacity =
- ((u_int64_t)wd->sc_params.atap_capacity[1] << 16) |
+ wd->sc_capacity28 = wd->sc_capacity =
+ (wd->sc_params.atap_capacity[1] << 16) |
wd->sc_params.atap_capacity[0];
} else {
aprint_verbose(" chs addressing\n");
- wd->sc_capacity =
+ wd->sc_capacity28 = wd->sc_capacity =
wd->sc_params.atap_cylinders *
wd->sc_params.atap_heads *
wd->sc_params.atap_sectors;
@@ -732,6 +707,7 @@ __wdstart(struct wd_softc *wd, struct bu
}
wd->sc_wdc_bio.blkno = bp->b_rawblkno;
+ wd->sc_wdc_bio.bcount = bp->b_bcount;
wd->sc_wdc_bio.blkdone =0;
wd->sc_bp = bp;
/*
@@ -744,14 +720,14 @@ __wdstart(struct wd_softc *wd, struct bu
else
wd->sc_wdc_bio.flags = 0;
if (wd->sc_flags & WDF_LBA48 &&
- (wd->sc_wdc_bio.blkno > LBA48_THRESHOLD ||
- (wd->sc_quirks & WD_QUIRK_FORCE_LBA48) != 0))
+ (wd->sc_wdc_bio.blkno +
+ wd->sc_wdc_bio.bcount / wd->sc_dk.dk_label->d_secsize) >=
+ wd->sc_capacity28)
wd->sc_wdc_bio.flags |= ATA_LBA48;
if (wd->sc_flags & WDF_LBA)
wd->sc_wdc_bio.flags |= ATA_LBA;
if (bp->b_flags & B_READ)
wd->sc_wdc_bio.flags |= ATA_READ;
- wd->sc_wdc_bio.bcount = bp->b_bcount;
wd->sc_wdc_bio.databuf = bp->b_data;
/* Instrumentation. */
disk_busy(&wd->sc_dk);
@@ -774,7 +750,6 @@ wddone(void *v)
struct buf *bp = wd->sc_bp;
const char *errmsg;
int do_perror = 0;
- int nblks;
ATADEBUG_PRINT(("wddone %s\n", device_xname(wd->sc_dev)),
DEBUG_XFERS);
@@ -801,25 +776,6 @@ wddone(void *v)
goto noerror;
errmsg = "error";
do_perror = 1;
- if ((wd->sc_wdc_bio.r_error & (WDCE_IDNF | WDCE_ABRT)) &&
- (wd->sc_quirks & WD_QUIRK_FORCE_LBA48) == 0) {
- nblks = wd->sc_wdc_bio.bcount /
- wd->sc_dk.dk_label->d_secsize;
- /*
- * If we get a "id not found" when crossing the
- * LBA48_THRESHOLD, and the drive is larger than
- * 128GB, then we can assume the drive has the
- * LBA48 bug and we switch to LBA48.
- */
- if (wd->sc_wdc_bio.blkno <= LBA48_THRESHOLD &&
- wd->sc_wdc_bio.blkno + nblks > LBA48_THRESHOLD &&
- wd->sc_capacity > LBA48_THRESHOLD + 1) {
- errmsg = "LBA48 bug";
- wd->sc_quirks |= WD_QUIRK_FORCE_LBA48;
- do_perror = 0;
- goto retry2;
- }
- }
retry: /* Just reset and retry. Can we do more ? */
(*wd->atabus->ata_reset_drive)(wd->drvp, AT_RST_NOCMD);
retry2:
@@ -1634,8 +1590,7 @@ wddump(dev_t dev, daddr_t blkno, void *v
wd->sc_wdc_bio.blkno = blkno;
wd->sc_wdc_bio.flags = ATA_POLL;
if (wd->sc_flags & WDF_LBA48 &&
- (blkno > LBA48_THRESHOLD ||
- (wd->sc_quirks & WD_QUIRK_FORCE_LBA48) != 0))
+ (wd->sc_wdc_bio.blkno + nblks) >= wd->sc_capacity28)
wd->sc_wdc_bio.flags |= ATA_LBA48;
if (wd->sc_flags & WDF_LBA)
wd->sc_wdc_bio.flags |= ATA_LBA;
Index: wdvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/wdvar.h,v
retrieving revision 1.36
diff -u -p -u -r1.36 wdvar.h
--- wdvar.h 18 Mar 2008 20:46:36 -0000 1.36
+++ wdvar.h 16 Dec 2009 19:25:40 -0000
@@ -62,7 +62,8 @@ struct wd_softc {
#define WDF_LBA 0x040 /* using LBA mode */
#define WDF_KLABEL 0x080 /* retain label after 'full' close */
#define WDF_LBA48 0x100 /* using 48-bit LBA mode */
- u_int64_t sc_capacity;
+ u_int64_t sc_capacity; /* full capacity of the device */
+ u_int32_t sc_capacity28; /* capacity accessible with LBA28 commands */
int retries; /* number of xfer retry */
Home |
Main Index |
Thread Index |
Old Index