@@ -139,7 +139,7 @@ static void sd_set_flush_flag(struct scsi_disk *sdkp)
{
bool wc = false, fua = false;
- if (sdkp->WCE) {
+ if (sdkp->WCE || sdkp->device->always_sync) {
wc = true;
if (sdkp->DPOFUA)
fua = true;
@@ -3228,7 +3228,7 @@ static void sd_shutdown(struct device *dev)
if (pm_runtime_suspended(dev))
return;
- if (sdkp->WCE && sdkp->media_present) {
+ if ((sdkp->WCE || sdkp->device->always_sync) && sdkp->media_present) {
sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
sd_sync_cache(sdkp);
}
@@ -3247,7 +3247,7 @@ static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)
if (!sdkp) /* E.g.: runtime suspend following sd_remove() */
return 0;
- if (sdkp->WCE && sdkp->media_present) {
+ if ((sdkp->WCE || sdkp->device->always_sync) && sdkp->media_present) {
sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
ret = sd_sync_cache(sdkp);
if (ret) {
@@ -296,6 +296,10 @@ 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)
+ sdev->always_sync = 1;
+
} else {
/*
@@ -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 */
}
}
@@ -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 };
@@ -179,6 +179,7 @@ struct scsi_device {
unsigned try_rc_10_first:1; /* Try READ_CAPACACITY_10 first */
unsigned is_visible:1; /* is the device visible in sysfs */
unsigned wce_default_on:1; /* Cache is ON by default */
+ unsigned always_sync:1; /* synchronize cache in every case*/
unsigned no_dif:1; /* T10 PI (DIF) should be disabled */
unsigned broken_fua:1; /* Don't set FUA bit */
unsigned lun_in_cdb:1; /* Store LUN bits in CDB[1] */
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> --- drivers/scsi/sd.c | 6 +++--- drivers/usb/storage/scsiglue.c | 4 ++++ drivers/usb/storage/usb.c | 6 +++++- include/linux/usb_usual.h | 2 ++ include/scsi/scsi_device.h | 1 + 5 files changed, 15 insertions(+), 4 deletions(-)