All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
To: James.Bottomley@HansenPartnership.com
Cc: linux-scsi@vger.kernel.org, Alan Stern <stern@rowland.harvard.edu>
Subject: scsi: Generalise last_sector_bug; fixes regression and potential future issues on USB cardreaders
Date: Thu, 24 Jul 2008 11:15:55 +0100	[thread overview]
Message-ID: <4888565B.4020102@tuffmail.co.uk> (raw)
In-Reply-To: <4888524D.9070906@tuffmail.co.uk>

The last_sector_bug flag was added to work around a bug in certain usb
cardreaders, where they would crash if a multiple sector read included the
last sector. The original implementation avoids this by e.g. splitting an 8
sector read which includes the last sector into a 7 sector read, and a single
sector read for the last sector.  The flag is enabled for all USB devices.

This revealed a second bug in other usb cardreaders, which crash when they
get a multiple sector read which stops 1 sector short of the last sector.
Affected hardware includes the Kingston "MobileLite" external USB cardreader
and the internal USB cardreader on the Asus EeePC.

Extend the last_sector_bug workaround to ensure that any access which touches
the last 8 hardware sectors of the device is a single sector long.  Requests
are shrunk as necessary to meet this constraint.

This gives us a safety margin against potential unknown or future bugs
affecting multi-sector access to the end of the device.  The two known bugs
only affect the last 2 sectors.  However, they suggest that these devices
are prone to fencepost errors and that multi-sector access to the end of the
device is not well tested.  Popular OS's use multi-sector accesses, but they
rarely read the last few sectors.  Linux (with udev & vol_id) automatically
reads sectors from the end of the device on insertion.  It is assumed that
single sector accesses are more thoroughly tested during development.

Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
Tested-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>

diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 01cefbb..2415a1b 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -406,13 +406,23 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
 	}
 
 	/*
-	 * Some devices (some sdcards for one) don't like it if the
-	 * last sector gets read in a larger then 1 sector read.
+	 * Some sd cardreaders can't handle multisector accesses which touch
+	 * the last one or two hardware sectors.  There are likely to be even
+	 * buggier devices, so apply a workaround to the last eight sectors.
 	 */
-	if (unlikely(sdp->last_sector_bug &&
-	    rq->nr_sectors > sdp->sector_size / 512 &&
-	    block + this_count == get_capacity(disk)))
-		this_count -= sdp->sector_size / 512;
+	if (sdp->last_sector_bug) {
+		unsigned threshold = get_capacity(disk) - 8 * (sdp->sector_size / 512);
+
+		if (block + this_count <= threshold) {
+			;	/* Okay as is */
+		} else if (block < threshold) {
+			/* Access up to the threshold but not beyond */
+			this_count = threshold - block;
+		} else {
+			/* Access only a single hardware sector */
+			this_count = sdp->sector_size / 512;
+		}
+	}
 
 	SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
 					(unsigned long long)block));
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index f6a9fe0..0d8d9c1 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -139,7 +139,8 @@ struct scsi_device {
 	unsigned fix_capacity:1;	/* READ_CAPACITY is too high by 1 */
 	unsigned guess_capacity:1;	/* READ_CAPACITY might be too high by 1 */
 	unsigned retry_hwerror:1;	/* Retry HARDWARE_ERROR */
-	unsigned last_sector_bug:1;	/* Always read last sector in a 1 sector read */
+	unsigned last_sector_bug:1;	/* do not use multisector accesses on
+					   the last 8 hardware sectors */
 
 	DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */
 	struct list_head event_list;	/* asserted events */



       reply	other threads:[~2008-07-24 10:15 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <4888524D.9070906@tuffmail.co.uk>
2008-07-24 10:15 ` Alan Jenkins [this message]
2008-07-26 19:26   ` scsi: Generalise last_sector_bug; fixes regression and potential future issues on USB cardreaders James Bottomley
2008-07-27  8:36     ` Alan Jenkins
2008-07-27  8:38       ` [PATCH] " Alan Jenkins

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4888565B.4020102@tuffmail.co.uk \
    --to=alan-jenkins@tuffmail.co.uk \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=linux-scsi@vger.kernel.org \
    --cc=stern@rowland.harvard.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.