|
@@ -1582,17 +1582,21 @@ out:
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
-static int sd_sync_cache(struct scsi_disk *sdkp)
|
|
|
+static int sd_sync_cache(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr)
|
|
|
{
|
|
|
int retries, res;
|
|
|
struct scsi_device *sdp = sdkp->device;
|
|
|
const int timeout = sdp->request_queue->rq_timeout
|
|
|
* SD_FLUSH_TIMEOUT_MULTIPLIER;
|
|
|
- struct scsi_sense_hdr sshdr;
|
|
|
+ struct scsi_sense_hdr my_sshdr;
|
|
|
|
|
|
if (!scsi_device_online(sdp))
|
|
|
return -ENODEV;
|
|
|
|
|
|
+ /* caller might not be interested in sense, but we need it */
|
|
|
+ if (!sshdr)
|
|
|
+ sshdr = &my_sshdr;
|
|
|
+
|
|
|
for (retries = 3; retries > 0; --retries) {
|
|
|
unsigned char cmd[10] = { 0 };
|
|
|
|
|
@@ -1601,7 +1605,7 @@ static int sd_sync_cache(struct scsi_disk *sdkp)
|
|
|
* Leave the rest of the command zero to indicate
|
|
|
* flush everything.
|
|
|
*/
|
|
|
- res = scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL, &sshdr,
|
|
|
+ res = scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL, sshdr,
|
|
|
timeout, SD_MAX_RETRIES, 0, RQF_PM, NULL);
|
|
|
if (res == 0)
|
|
|
break;
|
|
@@ -1611,11 +1615,12 @@ static int sd_sync_cache(struct scsi_disk *sdkp)
|
|
|
sd_print_result(sdkp, "Synchronize Cache(10) failed", res);
|
|
|
|
|
|
if (driver_byte(res) & DRIVER_SENSE)
|
|
|
- sd_print_sense_hdr(sdkp, &sshdr);
|
|
|
+ sd_print_sense_hdr(sdkp, sshdr);
|
|
|
+
|
|
|
/* we need to evaluate the error return */
|
|
|
- if (scsi_sense_valid(&sshdr) &&
|
|
|
- (sshdr.asc == 0x3a || /* medium not present */
|
|
|
- sshdr.asc == 0x20)) /* invalid command */
|
|
|
+ if (scsi_sense_valid(sshdr) &&
|
|
|
+ (sshdr->asc == 0x3a || /* medium not present */
|
|
|
+ sshdr->asc == 0x20)) /* invalid command */
|
|
|
/* this is no error here */
|
|
|
return 0;
|
|
|
|
|
@@ -3459,7 +3464,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) {
|
|
@@ -3471,6 +3476,7 @@ static void sd_shutdown(struct device *dev)
|
|
|
static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)
|
|
|
{
|
|
|
struct scsi_disk *sdkp = dev_get_drvdata(dev);
|
|
|
+ struct scsi_sense_hdr sshdr;
|
|
|
int ret = 0;
|
|
|
|
|
|
if (!sdkp) /* E.g.: runtime suspend following sd_remove() */
|
|
@@ -3478,12 +3484,23 @@ 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, &sshdr);
|
|
|
+
|
|
|
if (ret) {
|
|
|
/* ignore OFFLINE device */
|
|
|
if (ret == -ENODEV)
|
|
|
- ret = 0;
|
|
|
- goto done;
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (!scsi_sense_valid(&sshdr) ||
|
|
|
+ sshdr.sense_key != ILLEGAL_REQUEST)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * sshdr.sense_key == ILLEGAL_REQUEST means this drive
|
|
|
+ * doesn't support sync. There's not much to do and
|
|
|
+ * suspend shouldn't fail.
|
|
|
+ */
|
|
|
+ ret = 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -3495,7 +3512,6 @@ static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)
|
|
|
ret = 0;
|
|
|
}
|
|
|
|
|
|
-done:
|
|
|
return ret;
|
|
|
}
|
|
|
|