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