Module Name:    src
Committed By:   bouyer
Date:           Thu Dec 17 21:03:10 UTC 2009

Modified Files:
        src/sys/dev/ata: wd.c wdvar.h

Log Message:
ATA sepcs changed the LBA48 boundary from 0xfffffff to 0xffffffe between
ATA6r1 and ATA6r3, which caused drives conform to ATA6r3 or later to
reject LBA28 commands at sector 0xfffffff.
Get the right idea from the LBA48 boundary from IDENTIFY words 60-61.
Remove the WD_QUIRK_FORCE_LBA48 quirk, associated tables entries and
autodetect code, it's not needed any more.
Based on patch sent to teck-kern by Christoph Badura, use of words 60-61
instead of a constant for the LBA48 boundary by me.


To generate a diff of this commit:
cvs rdiff -u -r1.379 -r1.380 src/sys/dev/ata/wd.c
cvs rdiff -u -r1.37 -r1.38 src/sys/dev/ata/wdvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/ata/wd.c
diff -u src/sys/dev/ata/wd.c:1.379 src/sys/dev/ata/wd.c:1.380
--- src/sys/dev/ata/wd.c:1.379	Mon Oct 19 18:41:12 2009
+++ src/sys/dev/ata/wd.c	Thu Dec 17 21:03:10 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: wd.c,v 1.379 2009/10/19 18:41:12 bouyer Exp $ */
+/*	$NetBSD: wd.c,v 1.380 2009/12/17 21:03:10 bouyer Exp $ */
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -54,7 +54,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.379 2009/10/19 18:41:12 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.380 2009/12/17 21:03:10 bouyer Exp $");
 
 #include "opt_ata.h"
 
@@ -94,8 +94,6 @@
 
 #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 */
@@ -194,7 +192,6 @@
 #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"
 
@@ -222,31 +219,6 @@
 	  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 }
 };
@@ -374,14 +346,17 @@
 		    ((u_int64_t) wd->sc_params.atap_max_lba[2] << 32) |
 		    ((u_int64_t) wd->sc_params.atap_max_lba[1] << 16) |
 		    ((u_int64_t) wd->sc_params.atap_max_lba[0] <<  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;
@@ -714,6 +689,8 @@
 	}
 
 	wd->sc_wdc_bio.blkno = bp->b_rawblkno;
+	wd->sc_wdc_bio.bcount = bp->b_bcount;
+	wd->sc_wdc_bio.databuf = bp->b_data;
 	wd->sc_wdc_bio.blkdone =0;
 	wd->sc_bp = bp;
 	/*
@@ -726,15 +703,14 @@
 	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);
 	switch (wd->atabus->ata_bio(wd->drvp, &wd->sc_wdc_bio)) {
@@ -756,7 +732,6 @@
 	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);
@@ -783,25 +758,6 @@
 			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:
@@ -1628,8 +1584,7 @@
 	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: src/sys/dev/ata/wdvar.h
diff -u src/sys/dev/ata/wdvar.h:1.37 src/sys/dev/ata/wdvar.h:1.38
--- src/sys/dev/ata/wdvar.h:1.37	Mon Oct 19 18:41:12 2009
+++ src/sys/dev/ata/wdvar.h	Thu Dec 17 21:03:10 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: wdvar.h,v 1.37 2009/10/19 18:41:12 bouyer Exp $	*/
+/*	$NetBSD: wdvar.h,v 1.38 2009/12/17 21:03:10 bouyer Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -57,7 +57,8 @@
 #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 */
 

Reply via email to