From bd3c11e205fe9f695733b52fb3df4ab9c5cd5269 Mon Sep 17 00:00:00 2001 From: Derek Basehore Date: Fri, 11 Oct 2013 14:04:39 -0700 Subject: [PATCH] scsi: sd: Ignore sync failures when not supported Some external hard drives don't support the sync command even though the hard drive has write cache enabled. In this case, ignore sync cache failures when the error is for an illegal request for suspend. There's not much we can do for these drives, so we shouldn't fail to suspend for this error case. The drive may stay powered if that's setup for the port you have it plugged into. BUG=chromium:282666 TEST=Plus Lacie hard drive into machine and make sure the machine can suspend. The Lacie hard drive may stay powered depending on the machine. Change-Id: I88248f0715b70eae33eda171df3b803a5d7513b3 Signed-off-by: Derek Basehore Reviewed-on: https://chromium-review.googlesource.com/172863 Reviewed-by: Grant Grundler [benzh: 3.14 rebase. Merged error handling code for sd_sync_cache()] Signed-off-by: Ben Zhang --- drivers/scsi/sd.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index b60a2d8891b6..f429c3d5a3a8 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1432,7 +1432,7 @@ out: return retval; } -static int sd_sync_cache(struct scsi_disk *sdkp) +static int sd_sync_cache(struct scsi_disk *sdkp, int *sense_key) { int retries, res; struct scsi_device *sdp = sdkp->device; @@ -1461,8 +1461,11 @@ static int sd_sync_cache(struct scsi_disk *sdkp) if (res) { sd_print_result(sdkp, res); - if (driver_byte(res) & DRIVER_SENSE) + if (driver_byte(res) & DRIVER_SENSE) { sd_print_sense_hdr(sdkp, &sshdr); + if (sense_key) + *sense_key = sshdr.sense_key; + } /* we need to evaluate the error return */ if (scsi_sense_valid(&sshdr) && /* 0x3a is medium not present */ @@ -3123,7 +3126,7 @@ static void sd_shutdown(struct device *dev) if (sdkp->WCE && sdkp->media_present) { sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); - sd_sync_cache(sdkp); + sd_sync_cache(sdkp, NULL); } if (system_state != SYSTEM_RESTART && sdkp->device->manage_start_stop) { @@ -3138,6 +3141,7 @@ exit: static int sd_suspend_common(struct device *dev, bool ignore_stop_errors) { struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); + int sense_key = 0; int ret = 0; if (!sdkp) @@ -3149,12 +3153,20 @@ static int sd_suspend_common(struct device *dev, bool ignore_stop_errors) if (sdkp->WCE && sdkp->media_present) { sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); - ret = sd_sync_cache(sdkp); + ret = sd_sync_cache(sdkp, &sense_key); if (ret) { - /* ignore OFFLINE device */ - if (ret == -ENODEV) + if (sense_key == ILLEGAL_REQUEST) { + /* + * If this is a bad drive that doesn't support + * sync, there's not much to do. + */ ret = 0; - goto done; + } else { + /* ignore OFFLINE device */ + if (ret == -ENODEV) + ret = 0; + goto done; + } } }