diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/storage/libusual.c | 7 | ||||
-rw-r--r-- | drivers/usb/storage/scsiglue.c | 8 | ||||
-rw-r--r-- | drivers/usb/storage/transport.c | 110 | ||||
-rw-r--r-- | drivers/usb/storage/unusual_devs.h | 16 | ||||
-rw-r--r-- | drivers/usb/storage/usb.c | 6 | ||||
-rw-r--r-- | drivers/usb/storage/usb.h | 4 |
6 files changed, 150 insertions, 1 deletions
diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c index d617e8ae6b0..f970b27ba30 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 | ||
61 | MODULE_DEVICE_TABLE(usb, storage_usb_ids); | 68 | MODULE_DEVICE_TABLE(usb, storage_usb_ids); |
62 | EXPORT_SYMBOL_GPL(storage_usb_ids); | 69 | EXPORT_SYMBOL_GPL(storage_usb_ids); |
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index e9d6c196a7a..8d78084abf9 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 9cc30afd6d3..1d5438e6363 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 | */ | ||
521 | static 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 0330ed53ec1..035bbc5d823 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 | */ |
51 | UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100, | 58 | UNUSUAL_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> */ | ||
715 | COMPLIANT_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> */ |
709 | UNUSUAL_DEV( 0x052b, 0x1801, 0x0100, 0x0100, | 723 | UNUSUAL_DEV( 0x052b, 0x1801, 0x0100, 0x0100, |
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index ce0b580db5e..80e234bf4e5 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); | |||
181 | static struct us_unusual_dev us_unusual_dev_list[] = { | 186 | static 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 e4674fc715e..65e674e4be9 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 */ |