]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/scsi/sd.c
Merge branch 'for-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata
[karo-tx-linux.git] / drivers / scsi / sd.c
index 5d32fd7d3a3e55fd753c3cca1a72552603e0cb7a..8796d908fcddb18c05edea309fbbb19a67878cfd 100644 (file)
@@ -848,21 +848,32 @@ static int sd_setup_write_zeroes_cmnd(struct scsi_cmnd *cmd)
        struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
        u64 sector = blk_rq_pos(rq) >> (ilog2(sdp->sector_size) - 9);
        u32 nr_sectors = blk_rq_sectors(rq) >> (ilog2(sdp->sector_size) - 9);
+       int ret;
 
        if (!(rq->cmd_flags & REQ_NOUNMAP)) {
                switch (sdkp->zeroing_mode) {
                case SD_ZERO_WS16_UNMAP:
-                       return sd_setup_write_same16_cmnd(cmd, true);
+                       ret = sd_setup_write_same16_cmnd(cmd, true);
+                       goto out;
                case SD_ZERO_WS10_UNMAP:
-                       return sd_setup_write_same10_cmnd(cmd, true);
+                       ret = sd_setup_write_same10_cmnd(cmd, true);
+                       goto out;
                }
        }
 
        if (sdp->no_write_same)
                return BLKPREP_INVALID;
+
        if (sdkp->ws16 || sector > 0xffffffff || nr_sectors > 0xffff)
-               return sd_setup_write_same16_cmnd(cmd, false);
-       return sd_setup_write_same10_cmnd(cmd, false);
+               ret = sd_setup_write_same16_cmnd(cmd, false);
+       else
+               ret = sd_setup_write_same10_cmnd(cmd, false);
+
+out:
+       if (sd_is_zoned(sdkp) && ret == BLKPREP_OK)
+               return sd_zbc_write_lock_zone(cmd);
+
+       return ret;
 }
 
 static void sd_config_write_same(struct scsi_disk *sdkp)
@@ -969,6 +980,10 @@ static int sd_setup_write_same_cmnd(struct scsi_cmnd *cmd)
        rq->__data_len = sdp->sector_size;
        ret = scsi_init_io(cmd);
        rq->__data_len = nr_bytes;
+
+       if (sd_is_zoned(sdkp) && ret != BLKPREP_OK)
+               sd_zbc_write_unlock_zone(cmd);
+
        return ret;
 }
 
@@ -1591,17 +1606,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 };
 
@@ -1610,7 +1629,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;
@@ -1620,11 +1639,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;
 
@@ -3491,7 +3511,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) {
@@ -3503,6 +3523,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() */
@@ -3510,12 +3531,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;
                }
        }
 
@@ -3527,7 +3559,6 @@ static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)
                        ret = 0;
        }
 
-done:
        return ret;
 }