scsi: introduce a quirk for false cache reporting
authorOliver Neukum <oneukum@suse.com>
Mon, 12 Sep 2016 13:19:41 +0000 (15:19 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 13 Sep 2016 06:08:24 +0000 (08:08 +0200)
Some SATA to USB bridges fail to cooperate with some
drives resulting in no cache being present being reported
to the host. That causes the host to skip sending
a command to synchronize caches. That causes data loss
when the drive is powered down.

Signed-off-by: Oliver Neukum <oneukum@suse.com>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/kernel-parameters.txt
drivers/usb/storage/scsiglue.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
include/linux/usb_usual.h

index a4f4d69..edb7d5d 100644 (file)
@@ -4238,6 +4238,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                                u = IGNORE_UAS (don't bind to the uas driver);
                                w = NO_WP_DETECT (don't test whether the
                                        medium is write-protected).
+                               y = ALWAYS_SYNC (issue a SYNCHRONIZE_CACHE
+                                       even if the device claims no cache)
                        Example: quirks=0419:aaf5:rl,0421:0433:rc
 
        user_debug=     [KNL,ARM]
index 33eb923..8cd2926 100644 (file)
@@ -296,6 +296,14 @@ static int slave_configure(struct scsi_device *sdev)
                if (us->fflags & US_FL_BROKEN_FUA)
                        sdev->broken_fua = 1;
 
+               /* Some even totally fail to indicate a cache */
+               if (us->fflags & US_FL_ALWAYS_SYNC) {
+                       /* don't read caching information */
+                       sdev->skip_ms_page_8 = 1;
+                       sdev->skip_ms_page_3f = 1;
+                       /* assume sync is needed */
+                       sdev->wce_default_on = 1;
+               }
        } else {
 
                /*
index aa35392..af3c7ee 100644 (file)
@@ -338,6 +338,13 @@ UNUSUAL_DEV(  0x046b, 0xff40, 0x0100, 0x0100,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_WP_DETECT),
 
+/* Reported by Egbert Eich <eich@suse.com> */
+UNUSUAL_DEV(  0x0480, 0xd010, 0x0100, 0x9999,
+               "Toshiba",
+               "External USB 3.0",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_ALWAYS_SYNC),
+
 /* Patch submitted by Philipp Friedrich <philipp@void.at> */
 UNUSUAL_DEV(  0x0482, 0x0100, 0x0100, 0x0100,
                "Kyocera",
index c8afd2d..2cba13a 100644 (file)
@@ -498,7 +498,8 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags)
                        US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16 |
                        US_FL_INITIAL_READ10 | US_FL_WRITE_CACHE |
                        US_FL_NO_ATA_1X | US_FL_NO_REPORT_OPCODES |
-                       US_FL_MAX_SECTORS_240 | US_FL_NO_REPORT_LUNS);
+                       US_FL_MAX_SECTORS_240 | US_FL_NO_REPORT_LUNS |
+                       US_FL_ALWAYS_SYNC);
 
        p = quirks;
        while (*p) {
@@ -581,6 +582,9 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags)
                case 'w':
                        f |= US_FL_NO_WP_DETECT;
                        break;
+               case 'y':
+                       f |= US_FL_ALWAYS_SYNC;
+                       break;
                /* Ignore unrecognized flag characters */
                }
        }
index 245f57d..0aae1b2 100644 (file)
@@ -81,6 +81,8 @@
                /* Sets max_sectors to 240 */                   \
        US_FLAG(NO_REPORT_LUNS, 0x10000000)                     \
                /* Cannot handle REPORT_LUNS */                 \
+       US_FLAG(ALWAYS_SYNC, 0x20000000)                        \
+               /* lies about caching, so always sync */        \
 
 #define US_FLAG(name, value)   US_FL_##name = value ,
 enum { US_DO_ALL_FLAGS };