]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/scsi/storvsc_drv.c
drivers: scsi: storvsc: Correctly handle TEST_UNIT_READY failure
[karo-tx-linux.git] / drivers / scsi / storvsc_drv.c
index 8f8847ef110822a6536201c8c4db19afed20d5ad..ed0f899e8aa56cf39dcc639129a5ecf1713d0011 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/device.h>
 #include <linux/hyperv.h>
 #include <linux/mempool.h>
+#include <linux/blkdev.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_host.h>
@@ -1017,6 +1018,13 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
                case ATA_12:
                        set_host_byte(scmnd, DID_PASSTHROUGH);
                        break;
+               /*
+                * On Some Windows hosts TEST_UNIT_READY command can return
+                * SRB_STATUS_ERROR, let the upper level code deal with it
+                * based on the sense information.
+                */
+               case TEST_UNIT_READY:
+                       break;
                default:
                        set_host_byte(scmnd, DID_TARGET_FAILURE);
                }
@@ -1518,6 +1526,16 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
        return SUCCESS;
 }
 
+/*
+ * The host guarantees to respond to each command, although I/O latencies might
+ * be unbounded on Azure.  Reset the timer unconditionally to give the host a
+ * chance to perform EH.
+ */
+static enum blk_eh_timer_return storvsc_eh_timed_out(struct scsi_cmnd *scmnd)
+{
+       return BLK_EH_RESET_TIMER;
+}
+
 static bool storvsc_scsi_cmd_ok(struct scsi_cmnd *scmnd)
 {
        bool allowed = true;
@@ -1590,26 +1608,24 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
        vm_srb = &cmd_request->vstor_packet.vm_srb;
        vm_srb->win8_extension.time_out_value = 60;
 
+       vm_srb->win8_extension.srb_flags |=
+               (SRB_FLAGS_QUEUE_ACTION_ENABLE |
+               SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
 
        /* Build the SRB */
        switch (scmnd->sc_data_direction) {
        case DMA_TO_DEVICE:
                vm_srb->data_in = WRITE_TYPE;
                vm_srb->win8_extension.srb_flags |= SRB_FLAGS_DATA_OUT;
-               vm_srb->win8_extension.srb_flags |=
-                       (SRB_FLAGS_QUEUE_ACTION_ENABLE |
-                       SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
                break;
        case DMA_FROM_DEVICE:
                vm_srb->data_in = READ_TYPE;
                vm_srb->win8_extension.srb_flags |= SRB_FLAGS_DATA_IN;
-               vm_srb->win8_extension.srb_flags |=
-                       (SRB_FLAGS_QUEUE_ACTION_ENABLE |
-                       SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
                break;
        default:
                vm_srb->data_in = UNKNOWN_TYPE;
-               vm_srb->win8_extension.srb_flags = 0;
+               vm_srb->win8_extension.srb_flags |= (SRB_FLAGS_DATA_IN |
+                                                    SRB_FLAGS_DATA_OUT);
                break;
        }
 
@@ -1697,6 +1713,7 @@ static struct scsi_host_template scsi_driver = {
        .bios_param =           storvsc_get_chs,
        .queuecommand =         storvsc_queuecommand,
        .eh_host_reset_handler =        storvsc_host_reset_handler,
+       .eh_timed_out =         storvsc_eh_timed_out,
        .slave_alloc =          storvsc_device_alloc,
        .slave_destroy =        storvsc_device_destroy,
        .slave_configure =      storvsc_device_configure,
@@ -1752,19 +1769,22 @@ static int storvsc_probe(struct hv_device *device,
         * set state to properly communicate with the host.
         */
 
-       if (vmbus_proto_version == VERSION_WIN8) {
-               sense_buffer_size = POST_WIN7_STORVSC_SENSE_BUFFER_SIZE;
-               vmscsi_size_delta = 0;
-               vmstor_current_major = VMSTOR_WIN8_MAJOR;
-               vmstor_current_minor = VMSTOR_WIN8_MINOR;
-       } else {
+       switch (vmbus_proto_version) {
+       case VERSION_WS2008:
+       case VERSION_WIN7:
                sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE;
                vmscsi_size_delta = sizeof(struct vmscsi_win8_extension);
                vmstor_current_major = VMSTOR_WIN7_MAJOR;
                vmstor_current_minor = VMSTOR_WIN7_MINOR;
+               break;
+       default:
+               sense_buffer_size = POST_WIN7_STORVSC_SENSE_BUFFER_SIZE;
+               vmscsi_size_delta = 0;
+               vmstor_current_major = VMSTOR_WIN8_MAJOR;
+               vmstor_current_minor = VMSTOR_WIN8_MINOR;
+               break;
        }
 
-
        if (dev_id->driver_data == SFC_GUID)
                scsi_driver.can_queue = (STORVSC_MAX_IO_REQUESTS *
                                         STORVSC_FC_MAX_TARGETS);