Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 127285
b: refs/heads/master
c: 25ff1c3
h: refs/heads/master
i:
  127283: 0d428a6
v: v3
  • Loading branch information
Alan Stern authored and Greg Kroah-Hartman committed Jan 7, 2009
1 parent 124cafb commit d2e816e
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 4 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9ebd9616648bc0e47e7f8e1898c919305f1e6347
refs/heads/master: 25ff1c316f6a763f1eefe7f8984b2d8c03888432
7 changes: 7 additions & 0 deletions trunk/drivers/usb/storage/libusual.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ static int usu_probe_thread(void *arg);
{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax), \
.driver_info = (flags)|(USB_US_TYPE_STOR<<24) }

#define COMPLIANT_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
vendorName, productName, useProtocol, useTransport, \
initFunction, flags) \
{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
.driver_info = (flags) }

#define USUAL_DEV(useProto, useTrans, useType) \
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \
.driver_info = ((useType)<<24) }
Expand All @@ -57,6 +63,7 @@ struct usb_device_id storage_usb_ids [] = {

#undef USUAL_DEV
#undef UNUSUAL_DEV
#undef COMPLIANT_DEV

MODULE_DEVICE_TABLE(usb, storage_usb_ids);
EXPORT_SYMBOL_GPL(storage_usb_ids);
Expand Down
8 changes: 8 additions & 0 deletions trunk/drivers/usb/storage/scsiglue.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,14 @@ static int slave_configure(struct scsi_device *sdev)
* sector in a larger then 1 sector read, since the performance
* impact is negible we set this flag for all USB disks */
sdev->last_sector_bug = 1;

/* Enable last-sector hacks for single-target devices using
* the Bulk-only transport, unless we already know the
* capacity will be decremented or is correct. */
if (!(us->fflags & (US_FL_FIX_CAPACITY | US_FL_CAPACITY_OK |
US_FL_SCM_MULT_TARG)) &&
us->protocol == US_PR_BULK)
us->use_last_sector_hacks = 1;
} else {

/* Non-disk-type devices don't need to blacklist any pages
Expand Down
110 changes: 110 additions & 0 deletions trunk/drivers/usb/storage/transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
#include "scsiglue.h"
#include "debug.h"

#include <linux/blkdev.h>
#include "../../scsi/sd.h"


/***********************************************************************
* Data transfer routines
Expand Down Expand Up @@ -511,6 +514,110 @@ int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe,
* Transport routines
***********************************************************************/

/* There are so many devices that report the capacity incorrectly,
* this routine was written to counteract some of the resulting
* problems.
*/
static void last_sector_hacks(struct us_data *us, struct scsi_cmnd *srb)
{
struct gendisk *disk;
struct scsi_disk *sdkp;
u32 sector;

/* To Report "Medium Error: Record Not Found */
static unsigned char record_not_found[18] = {
[0] = 0x70, /* current error */
[2] = MEDIUM_ERROR, /* = 0x03 */
[7] = 0x0a, /* additional length */
[12] = 0x14 /* Record Not Found */
};

/* If last-sector problems can't occur, whether because the
* capacity was already decremented or because the device is
* known to report the correct capacity, then we don't need
* to do anything.
*/
if (!us->use_last_sector_hacks)
return;

/* Was this command a READ(10) or a WRITE(10)? */
if (srb->cmnd[0] != READ_10 && srb->cmnd[0] != WRITE_10)
goto done;

/* Did this command access the last sector? */
sector = (srb->cmnd[2] << 24) | (srb->cmnd[3] << 16) |
(srb->cmnd[4] << 8) | (srb->cmnd[5]);
disk = srb->request->rq_disk;
if (!disk)
goto done;
sdkp = scsi_disk(disk);
if (!sdkp)
goto done;
if (sector + 1 != sdkp->capacity)
goto done;

if (srb->result == SAM_STAT_GOOD && scsi_get_resid(srb) == 0) {

/* The command succeeded. If the capacity is odd
* (i.e., if the sector number is even) then the
* "always-even" heuristic would be wrong for this
* device. Issue a WARN() so that the kerneloops.org
* project will be notified and we will then know to
* mark the device with a CAPACITY_OK flag. Hopefully
* this will occur for only a few devices.
*
* Use the sign of us->last_sector_hacks to tell whether
* the warning has already been issued; we don't need
* more than one warning per device.
*/
if (!(sector & 1) && us->use_last_sector_hacks > 0) {
unsigned vid = le16_to_cpu(
us->pusb_dev->descriptor.idVendor);
unsigned pid = le16_to_cpu(
us->pusb_dev->descriptor.idProduct);
unsigned rev = le16_to_cpu(
us->pusb_dev->descriptor.bcdDevice);

WARN(1, "%s: Successful last sector success at %u, "
"device %04x:%04x:%04x\n",
sdkp->disk->disk_name, sector,
vid, pid, rev);
us->use_last_sector_hacks = -1;
}

} else {
/* The command failed. Allow up to 3 retries in case this
* is some normal sort of failure. After that, assume the
* capacity is wrong and we're trying to access the sector
* beyond the end. Replace the result code and sense data
* with values that will cause the SCSI core to fail the
* command immediately, instead of going into an infinite
* (or even just a very long) retry loop.
*/
if (++us->last_sector_retries < 3)
return;
srb->result = SAM_STAT_CHECK_CONDITION;
memcpy(srb->sense_buffer, record_not_found,
sizeof(record_not_found));

/* In theory we might want to issue a WARN() here if the
* capacity is even, since it could indicate the device
* has the READ CAPACITY bug _and_ the real capacity is
* odd. But it could also indicate that the device
* simply can't access its last sector, a failure mode
* which is surprisingly common. So no warning.
*/
}

done:
/* Don't reset the retry counter for TEST UNIT READY commands,
* because they get issued after device resets which might be
* caused by a failed last-sector access.
*/
if (srb->cmnd[0] != TEST_UNIT_READY)
us->last_sector_retries = 0;
}

/* Invoke the transport and basic error-handling/recovery methods
*
* This is used by the protocol layers to actually send the message to
Expand Down Expand Up @@ -544,6 +651,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
/* if the transport provided its own sense data, don't auto-sense */
if (result == USB_STOR_TRANSPORT_NO_SENSE) {
srb->result = SAM_STAT_CHECK_CONDITION;
last_sector_hacks(us, srb);
return;
}

Expand Down Expand Up @@ -705,6 +813,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow)
srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24);

last_sector_hacks(us, srb);
return;

/* Error and abort processing: try to resynchronize with the device
Expand Down Expand Up @@ -732,6 +841,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
us->transport_reset(us);
}
clear_bit(US_FLIDX_RESETTING, &us->dflags);
last_sector_hacks(us, srb);
}

/* Stop the current URB transfer */
Expand Down
16 changes: 15 additions & 1 deletion trunk/drivers/usb/storage/unusual_devs.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@

/* IMPORTANT NOTE: This file must be included in another file which does
* the following thing for it to work:
* The macro UNUSUAL_DEV() must be defined before this file is included
* The UNUSUAL_DEV, COMPLIANT_DEV, and USUAL_DEV macros must be defined
* before this file is included.
*/

/* If you edit this file, please try to keep it sorted first by VendorID,
Expand All @@ -46,6 +47,12 @@
* <usb-storage@lists.one-eyed-alien.net>
*/

/* Note: If you add an entry only in order to set the CAPACITY_OK flag,
* use the COMPLIANT_DEV macro instead of UNUSUAL_DEV. This is
* because such entries mark devices which actually work correctly,
* as opposed to devices that do something strangely or wrongly.
*/

/* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr>
*/
UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100,
Expand Down Expand Up @@ -704,6 +711,13 @@ UNUSUAL_DEV( 0x0525, 0xa140, 0x0100, 0x0100,
US_SC_8070, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),

/* Added by Alan Stern <stern@rowland.harvard.edu> */
COMPLIANT_DEV(0x0525, 0xa4a5, 0x0000, 0x9999,
"Linux",
"File-backed Storage Gadget",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_CAPACITY_OK ),

/* Yakumo Mega Image 37
* Submitted by Stephan Fuhrmann <atomenergie@t-online.de> */
UNUSUAL_DEV( 0x052b, 0x1801, 0x0100, 0x0100,
Expand Down
6 changes: 6 additions & 0 deletions trunk/drivers/usb/storage/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ static struct quirks_entry *quirks_list, *quirks_end;
{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax), \
.driver_info = (flags)|(USB_US_TYPE_STOR<<24) }

#define COMPLIANT_DEV UNUSUAL_DEV

#define USUAL_DEV(useProto, useTrans, useType) \
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \
.driver_info = (USB_US_TYPE_STOR<<24) }
Expand All @@ -142,6 +144,7 @@ static struct usb_device_id storage_usb_ids [] = {

# include "unusual_devs.h"
#undef UNUSUAL_DEV
#undef COMPLIANT_DEV
#undef USUAL_DEV
/* Terminating entry */
{ }
Expand Down Expand Up @@ -172,6 +175,8 @@ MODULE_DEVICE_TABLE (usb, storage_usb_ids);
.initFunction = init_function, \
}

#define COMPLIANT_DEV UNUSUAL_DEV

#define USUAL_DEV(use_protocol, use_transport, use_type) \
{ \
.useProtocol = use_protocol, \
Expand All @@ -181,6 +186,7 @@ MODULE_DEVICE_TABLE (usb, storage_usb_ids);
static struct us_unusual_dev us_unusual_dev_list[] = {
# include "unusual_devs.h"
# undef UNUSUAL_DEV
# undef COMPLIANT_DEV
# undef USUAL_DEV

/* Terminating entry */
Expand Down
4 changes: 4 additions & 0 deletions trunk/drivers/usb/storage/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ struct us_data {
#ifdef CONFIG_PM
pm_hook suspend_resume_hook;
#endif

/* hacks for READ CAPACITY bug handling */
int use_last_sector_hacks;
int last_sector_retries;
};

/* Convert between us_data and the corresponding Scsi_Host */
Expand Down
6 changes: 4 additions & 2 deletions trunk/include/linux/usb_usual.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@
/* Sets max_sectors to arch min */ \
US_FLAG(BULK_IGNORE_TAG,0x00004000) \
/* Ignore tag mismatch in bulk operations */ \
US_FLAG(SANE_SENSE, 0x00008000)
/* Sane Sense (> 18 bytes) */
US_FLAG(SANE_SENSE, 0x00008000) \
/* Sane Sense (> 18 bytes) */ \
US_FLAG(CAPACITY_OK, 0x00010000) \
/* READ CAPACITY response is correct */

#define US_FLAG(name, value) US_FL_##name = value ,
enum { US_DO_ALL_FLAGS };
Expand Down

0 comments on commit d2e816e

Please sign in to comment.