aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sd.c
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2010-10-01 17:20:10 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-10-22 13:22:05 -0400
commit5ce524bdff367b4abda20bcfd4dafd9d30c773df (patch)
tree97b48a75d6a475cb71367d3a1ce7cc7f17680122 /drivers/scsi/sd.c
parentae38c78a03e1b77ad45248fcf097e4568e740209 (diff)
scsi/sd: add a no_read_capacity_16 scsi_device flag
I seem to have a knack for digging up buggy usb devices which don't work with Linux, and I'm crazy enough to try to make them work. So this time a friend of mine asked me to get an mp4 player (an mp3 player which can play videos on a small screen) to work with Linux. It is based on the well known rockbox chipset for which we already have an unusual devs entries to work around some of its bugs. But this model comes with an additional twist. This model chokes on read_capacity_16 calls. Now normally we don't make those calls, but this model comes with an sdcard slot and when there is no card in there (and shipped from the factory there is none), it reports a size of 0. However this time the programmers actually got the read_capacity_10 response right! So they substract one from the size as stored internally in the mp3 player before reporting it back, resulting in an answer of ... 0xffffffff sectors, causing sd.c to try a read_capacity_16, on which the device crashes. This patch adds a flag to scsi_device to indicate that a a device cannot handle read_capacity_16, and when this flag is set if a device reports an lba of 0xffffffff as answer to a read_capacity_10, assumes it tries to report a size of 0. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Cc: James Bottomley <James.Bottomley@HansenPartnership.com> Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Matthew Dharm <mdharm-usb@one-eyed-alien.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r--drivers/scsi/sd.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index ffa0689ee840..ff4c9a3aa5b2 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1498,6 +1498,9 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
1498 unsigned long long lba; 1498 unsigned long long lba;
1499 unsigned sector_size; 1499 unsigned sector_size;
1500 1500
1501 if (sdp->no_read_capacity_16)
1502 return -EINVAL;
1503
1501 do { 1504 do {
1502 memset(cmd, 0, 16); 1505 memset(cmd, 0, 16);
1503 cmd[0] = SERVICE_ACTION_IN; 1506 cmd[0] = SERVICE_ACTION_IN;
@@ -1626,6 +1629,15 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
1626 sector_size = get_unaligned_be32(&buffer[4]); 1629 sector_size = get_unaligned_be32(&buffer[4]);
1627 lba = get_unaligned_be32(&buffer[0]); 1630 lba = get_unaligned_be32(&buffer[0]);
1628 1631
1632 if (sdp->no_read_capacity_16 && (lba == 0xffffffff)) {
1633 /* Some buggy (usb cardreader) devices return an lba of
1634 0xffffffff when the want to report a size of 0 (with
1635 which they really mean no media is present) */
1636 sdkp->capacity = 0;
1637 sdkp->hw_sector_size = sector_size;
1638 return sector_size;
1639 }
1640
1629 if ((sizeof(sdkp->capacity) == 4) && (lba == 0xffffffff)) { 1641 if ((sizeof(sdkp->capacity) == 4) && (lba == 0xffffffff)) {
1630 sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a " 1642 sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
1631 "kernel compiled with support for large block " 1643 "kernel compiled with support for large block "