aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-12-15 12:43:41 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-07 13:00:11 -0500
commit25ff1c316f6a763f1eefe7f8984b2d8c03888432 (patch)
tree623759675a8e2db8cbcacc665d97d874e57ab4c5 /drivers/usb
parent9ebd9616648bc0e47e7f8e1898c919305f1e6347 (diff)
USB: storage: add last-sector hacks
This patch (as1189b) adds some hacks to usb-storage for dealing with the growing problems involving bad capacity values and last-sector accesses: A new flag, US_FL_CAPACITY_OK, is created to indicate that the device is known to report its capacity correctly. An unusual_devs entry for Linux's own File-backed Storage Gadget is added with this flag set, since g_file_storage always reports the correct capacity and since the capacity need not be even (it is determined by the size of the backing file). An entry in unusual_devs.h which has only the CAPACITY_OK flag set shouldn't prejudice libusual, since the device will work perfectly well with either usb-storage or ub. So a new macro, COMPLIANT_DEV, is added to let libusual know about these entries. When a last-sector access succeeds and the total number of sectors is odd (the unexpected case, in which guessing that the number is even might cause trouble), a WARN is triggered. The kerneloops.org project will collect these warnings, allowing us to add CAPACITY_OK flags for the devices in question before implementing the default-to-even heuristic. If users want to prevent the stack dump produced by the WARN, they can disable the hack by adding an unusual_devs entry for their device with the CAPACITY_OK flag. When a last-sector access fails three times in a row and neither the FIX_CAPACITY nor the CAPACITY_OK flag is set, we assume the last-sector bug is present. We replace the existing status and sense data with values that will cause the SCSI core to fail the access immediately rather than retry indefinitely. This should fix the difficulties people have been having with Nokia phones. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/storage/libusual.c7
-rw-r--r--drivers/usb/storage/scsiglue.c8
-rw-r--r--drivers/usb/storage/transport.c110
-rw-r--r--drivers/usb/storage/unusual_devs.h16
-rw-r--r--drivers/usb/storage/usb.c6
-rw-r--r--drivers/usb/storage/usb.h4
6 files changed, 150 insertions, 1 deletions
diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c
index d617e8ae6b00..f970b27ba308 100644
--- a/drivers/usb/storage/libusual.c
+++ b/drivers/usb/storage/libusual.c
@@ -46,6 +46,12 @@ static int usu_probe_thread(void *arg);
46{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax), \ 46{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax), \
47 .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } 47 .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
48 48
49#define COMPLIANT_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
50 vendorName, productName, useProtocol, useTransport, \
51 initFunction, flags) \
52{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
53 .driver_info = (flags) }
54
49#define USUAL_DEV(useProto, useTrans, useType) \ 55#define USUAL_DEV(useProto, useTrans, useType) \
50{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \ 56{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \
51 .driver_info = ((useType)<<24) } 57 .driver_info = ((useType)<<24) }
@@ -57,6 +63,7 @@ struct usb_device_id storage_usb_ids [] = {
57 63
58#undef USUAL_DEV 64#undef USUAL_DEV
59#undef UNUSUAL_DEV 65#undef UNUSUAL_DEV
66#undef COMPLIANT_DEV
60 67
61MODULE_DEVICE_TABLE(usb, storage_usb_ids); 68MODULE_DEVICE_TABLE(usb, storage_usb_ids);
62EXPORT_SYMBOL_GPL(storage_usb_ids); 69EXPORT_SYMBOL_GPL(storage_usb_ids);
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index e9d6c196a7ab..8d78084abf9f 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -208,6 +208,14 @@ static int slave_configure(struct scsi_device *sdev)
208 * sector in a larger then 1 sector read, since the performance 208 * sector in a larger then 1 sector read, since the performance
209 * impact is negible we set this flag for all USB disks */ 209 * impact is negible we set this flag for all USB disks */
210 sdev->last_sector_bug = 1; 210 sdev->last_sector_bug = 1;
211
212 /* Enable last-sector hacks for single-target devices using
213 * the Bulk-only transport, unless we already know the
214 * capacity will be decremented or is correct. */
215 if (!(us->fflags & (US_FL_FIX_CAPACITY | US_FL_CAPACITY_OK |
216 US_FL_SCM_MULT_TARG)) &&
217 us->protocol == US_PR_BULK)
218 us->use_last_sector_hacks = 1;
211 } else { 219 } else {
212 220
213 /* Non-disk-type devices don't need to blacklist any pages 221 /* Non-disk-type devices don't need to blacklist any pages
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 9cc30afd6d31..1d5438e6363b 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -57,6 +57,9 @@
57#include "scsiglue.h" 57#include "scsiglue.h"
58#include "debug.h" 58#include "debug.h"
59 59
60#include <linux/blkdev.h>
61#include "../../scsi/sd.h"
62
60 63
61/*********************************************************************** 64/***********************************************************************
62 * Data transfer routines 65 * Data transfer routines
@@ -511,6 +514,110 @@ int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe,
511 * Transport routines 514 * Transport routines
512 ***********************************************************************/ 515 ***********************************************************************/
513 516
517/* There are so many devices that report the capacity incorrectly,
518 * this routine was written to counteract some of the resulting
519 * problems.
520 */
521static void last_sector_hacks(struct us_data *us, struct scsi_cmnd *srb)
522{
523 struct gendisk *disk;
524 struct scsi_disk *sdkp;
525 u32 sector;
526
527 /* To Report "Medium Error: Record Not Found */
528 static unsigned char record_not_found[18] = {
529 [0] = 0x70, /* current error */
530 [2] = MEDIUM_ERROR, /* = 0x03 */
531 [7] = 0x0a, /* additional length */
532 [12] = 0x14 /* Record Not Found */
533 };
534
535 /* If last-sector problems can't occur, whether because the
536 * capacity was already decremented or because the device is
537 * known to report the correct capacity, then we don't need
538 * to do anything.
539 */
540 if (!us->use_last_sector_hacks)
541 return;
542
543 /* Was this command a READ(10) or a WRITE(10)? */
544 if (srb->cmnd[0] != READ_10 && srb->cmnd[0] != WRITE_10)
545 goto done;
546
547 /* Did this command access the last sector? */
548 sector = (srb->cmnd[2] << 24) | (srb->cmnd[3] << 16) |
549 (srb->cmnd[4] << 8) | (srb->cmnd[5]);
550 disk = srb->request->rq_disk;
551 if (!disk)
552 goto done;
553 sdkp = scsi_disk(disk);
554 if (!sdkp)
555 goto done;
556 if (sector + 1 != sdkp->capacity)
557 goto done;
558
559 if (srb->result == SAM_STAT_GOOD && scsi_get_resid(srb) == 0) {
560
561 /* The command succeeded. If the capacity is odd
562 * (i.e., if the sector number is even) then the
563 * "always-even" heuristic would be wrong for this
564 * device. Issue a WARN() so that the kerneloops.org
565 * project will be notified and we will then know to
566 * mark the device with a CAPACITY_OK flag. Hopefully
567 * this will occur for only a few devices.
568 *
569 * Use the sign of us->last_sector_hacks to tell whether
570 * the warning has already been issued; we don't need
571 * more than one warning per device.
572 */
573 if (!(sector & 1) && us->use_last_sector_hacks > 0) {
574 unsigned vid = le16_to_cpu(
575 us->pusb_dev->descriptor.idVendor);
576 unsigned pid = le16_to_cpu(
577 us->pusb_dev->descriptor.idProduct);
578 unsigned rev = le16_to_cpu(
579 us->pusb_dev->descriptor.bcdDevice);
580
581 WARN(1, "%s: Successful last sector success at %u, "
582 "device %04x:%04x:%04x\n",
583 sdkp->disk->disk_name, sector,
584 vid, pid, rev);
585 us->use_last_sector_hacks = -1;
586 }
587
588 } else {
589 /* The command failed. Allow up to 3 retries in case this
590 * is some normal sort of failure. After that, assume the
591 * capacity is wrong and we're trying to access the sector
592 * beyond the end. Replace the result code and sense data
593 * with values that will cause the SCSI core to fail the
594 * command immediately, instead of going into an infinite
595 * (or even just a very long) retry loop.
596 */
597 if (++us->last_sector_retries < 3)
598 return;
599 srb->result = SAM_STAT_CHECK_CONDITION;
600 memcpy(srb->sense_buffer, record_not_found,
601 sizeof(record_not_found));
602
603 /* In theory we might want to issue a WARN() here if the
604 * capacity is even, since it could indicate the device
605 * has the READ CAPACITY bug _and_ the real capacity is
606 * odd. But it could also indicate that the device
607 * simply can't access its last sector, a failure mode
608 * which is surprisingly common. So no warning.
609 */
610 }
611
612 done:
613 /* Don't reset the retry counter for TEST UNIT READY commands,
614 * because they get issued after device resets which might be
615 * caused by a failed last-sector access.
616 */
617 if (srb->cmnd[0] != TEST_UNIT_READY)
618 us->last_sector_retries = 0;
619}
620
514/* Invoke the transport and basic error-handling/recovery methods 621/* Invoke the transport and basic error-handling/recovery methods
515 * 622 *
516 * This is used by the protocol layers to actually send the message to 623 * This is used by the protocol layers to actually send the message to
@@ -544,6 +651,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
544 /* if the transport provided its own sense data, don't auto-sense */ 651 /* if the transport provided its own sense data, don't auto-sense */
545 if (result == USB_STOR_TRANSPORT_NO_SENSE) { 652 if (result == USB_STOR_TRANSPORT_NO_SENSE) {
546 srb->result = SAM_STAT_CHECK_CONDITION; 653 srb->result = SAM_STAT_CHECK_CONDITION;
654 last_sector_hacks(us, srb);
547 return; 655 return;
548 } 656 }
549 657
@@ -705,6 +813,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
705 scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow) 813 scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow)
706 srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24); 814 srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24);
707 815
816 last_sector_hacks(us, srb);
708 return; 817 return;
709 818
710 /* Error and abort processing: try to resynchronize with the device 819 /* Error and abort processing: try to resynchronize with the device
@@ -732,6 +841,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
732 us->transport_reset(us); 841 us->transport_reset(us);
733 } 842 }
734 clear_bit(US_FLIDX_RESETTING, &us->dflags); 843 clear_bit(US_FLIDX_RESETTING, &us->dflags);
844 last_sector_hacks(us, srb);
735} 845}
736 846
737/* Stop the current URB transfer */ 847/* Stop the current URB transfer */
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 0330ed53ec1c..035bbc5d8231 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -27,7 +27,8 @@
27 27
28/* IMPORTANT NOTE: This file must be included in another file which does 28/* IMPORTANT NOTE: This file must be included in another file which does
29 * the following thing for it to work: 29 * the following thing for it to work:
30 * The macro UNUSUAL_DEV() must be defined before this file is included 30 * The UNUSUAL_DEV, COMPLIANT_DEV, and USUAL_DEV macros must be defined
31 * before this file is included.
31 */ 32 */
32 33
33/* If you edit this file, please try to keep it sorted first by VendorID, 34/* If you edit this file, please try to keep it sorted first by VendorID,
@@ -46,6 +47,12 @@
46 * <usb-storage@lists.one-eyed-alien.net> 47 * <usb-storage@lists.one-eyed-alien.net>
47 */ 48 */
48 49
50/* Note: If you add an entry only in order to set the CAPACITY_OK flag,
51 * use the COMPLIANT_DEV macro instead of UNUSUAL_DEV. This is
52 * because such entries mark devices which actually work correctly,
53 * as opposed to devices that do something strangely or wrongly.
54 */
55
49/* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr> 56/* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr>
50 */ 57 */
51UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100, 58UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100,
@@ -704,6 +711,13 @@ UNUSUAL_DEV( 0x0525, 0xa140, 0x0100, 0x0100,
704 US_SC_8070, US_PR_DEVICE, NULL, 711 US_SC_8070, US_PR_DEVICE, NULL,
705 US_FL_FIX_INQUIRY ), 712 US_FL_FIX_INQUIRY ),
706 713
714/* Added by Alan Stern <stern@rowland.harvard.edu> */
715COMPLIANT_DEV(0x0525, 0xa4a5, 0x0000, 0x9999,
716 "Linux",
717 "File-backed Storage Gadget",
718 US_SC_DEVICE, US_PR_DEVICE, NULL,
719 US_FL_CAPACITY_OK ),
720
707/* Yakumo Mega Image 37 721/* Yakumo Mega Image 37
708 * Submitted by Stephan Fuhrmann <atomenergie@t-online.de> */ 722 * Submitted by Stephan Fuhrmann <atomenergie@t-online.de> */
709UNUSUAL_DEV( 0x052b, 0x1801, 0x0100, 0x0100, 723UNUSUAL_DEV( 0x052b, 0x1801, 0x0100, 0x0100,
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index ce0b580db5ea..80e234bf4e50 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -134,6 +134,8 @@ static struct quirks_entry *quirks_list, *quirks_end;
134{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax), \ 134{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax), \
135 .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } 135 .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
136 136
137#define COMPLIANT_DEV UNUSUAL_DEV
138
137#define USUAL_DEV(useProto, useTrans, useType) \ 139#define USUAL_DEV(useProto, useTrans, useType) \
138{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \ 140{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \
139 .driver_info = (USB_US_TYPE_STOR<<24) } 141 .driver_info = (USB_US_TYPE_STOR<<24) }
@@ -142,6 +144,7 @@ static struct usb_device_id storage_usb_ids [] = {
142 144
143# include "unusual_devs.h" 145# include "unusual_devs.h"
144#undef UNUSUAL_DEV 146#undef UNUSUAL_DEV
147#undef COMPLIANT_DEV
145#undef USUAL_DEV 148#undef USUAL_DEV
146 /* Terminating entry */ 149 /* Terminating entry */
147 { } 150 { }
@@ -172,6 +175,8 @@ MODULE_DEVICE_TABLE (usb, storage_usb_ids);
172 .initFunction = init_function, \ 175 .initFunction = init_function, \
173} 176}
174 177
178#define COMPLIANT_DEV UNUSUAL_DEV
179
175#define USUAL_DEV(use_protocol, use_transport, use_type) \ 180#define USUAL_DEV(use_protocol, use_transport, use_type) \
176{ \ 181{ \
177 .useProtocol = use_protocol, \ 182 .useProtocol = use_protocol, \
@@ -181,6 +186,7 @@ MODULE_DEVICE_TABLE (usb, storage_usb_ids);
181static struct us_unusual_dev us_unusual_dev_list[] = { 186static struct us_unusual_dev us_unusual_dev_list[] = {
182# include "unusual_devs.h" 187# include "unusual_devs.h"
183# undef UNUSUAL_DEV 188# undef UNUSUAL_DEV
189# undef COMPLIANT_DEV
184# undef USUAL_DEV 190# undef USUAL_DEV
185 191
186 /* Terminating entry */ 192 /* Terminating entry */
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index e4674fc715e6..65e674e4be99 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -154,6 +154,10 @@ struct us_data {
154#ifdef CONFIG_PM 154#ifdef CONFIG_PM
155 pm_hook suspend_resume_hook; 155 pm_hook suspend_resume_hook;
156#endif 156#endif
157
158 /* hacks for READ CAPACITY bug handling */
159 int use_last_sector_hacks;
160 int last_sector_retries;
157}; 161};
158 162
159/* Convert between us_data and the corresponding Scsi_Host */ 163/* Convert between us_data and the corresponding Scsi_Host */