storvsc: Untangle the storage protocol negotiation from the vmbus protocol negotiation.
authorKeith Mange <keith.mange@microsoft.com>
Thu, 13 Aug 2015 15:43:48 +0000 (08:43 -0700)
committerJames Bottomley <JBottomley@Odin.com>
Thu, 27 Aug 2015 05:41:34 +0000 (22:41 -0700)
Currently we are making decisions based on vmbus protocol versions
that have been negotiated; use storage potocol versions instead.

[jejb: fold ARRAY_SIZE conversion suggested by Johannes Thumshirn
<jthumshirn@suse.de>
make vmstor_protocol static]
Tested-by: Alex Ng <alexng@microsoft.com>
Signed-off-by: Keith Mange <keith.mange@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
drivers/scsi/storvsc_drv.c

index 367f66cc1f0721b35b94184836f82d0a0583f1b6..d6a42c0000481ec3dc195421bfe2bc92a143112d 100644 (file)
  * V1 RC > 2008/1/31:  2.0
  * Win7: 4.2
  * Win8: 5.1
+ * Win8.1: 6.0
+ * Win10: 6.2
  */
 
 #define VMSTOR_PROTO_VERSION(MAJOR_, MINOR_)   ((((MAJOR_) & 0xff) << 8) | \
                                                (((MINOR_) & 0xff)))
 
+#define VMSTOR_PROTO_VERSION_WIN6      VMSTOR_PROTO_VERSION(2, 0)
 #define VMSTOR_PROTO_VERSION_WIN7      VMSTOR_PROTO_VERSION(4, 2)
 #define VMSTOR_PROTO_VERSION_WIN8      VMSTOR_PROTO_VERSION(5, 1)
-
+#define VMSTOR_PROTO_VERSION_WIN8_1    VMSTOR_PROTO_VERSION(6, 0)
+#define VMSTOR_PROTO_VERSION_WIN10     VMSTOR_PROTO_VERSION(6, 2)
 
 /*  Packet structure describing virtual storage requests. */
 enum vstor_packet_operation {
@@ -204,6 +208,45 @@ struct vmscsi_request {
 } __attribute((packed));
 
 
+/*
+ * The list of storage protocols in order of preference.
+ */
+struct vmstor_protocol {
+       int protocol_version;
+       int sense_buffer_size;
+       int vmscsi_size_delta;
+};
+
+
+static const struct vmstor_protocol vmstor_protocols[] = {
+       {
+               VMSTOR_PROTO_VERSION_WIN10,
+               POST_WIN7_STORVSC_SENSE_BUFFER_SIZE,
+               0
+       },
+       {
+               VMSTOR_PROTO_VERSION_WIN8_1,
+               POST_WIN7_STORVSC_SENSE_BUFFER_SIZE,
+               0
+       },
+       {
+               VMSTOR_PROTO_VERSION_WIN8,
+               POST_WIN7_STORVSC_SENSE_BUFFER_SIZE,
+               0
+       },
+       {
+               VMSTOR_PROTO_VERSION_WIN7,
+               PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE,
+               sizeof(struct vmscsi_win8_extension),
+       },
+       {
+               VMSTOR_PROTO_VERSION_WIN6,
+               PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE,
+               sizeof(struct vmscsi_win8_extension),
+       }
+};
+
+
 /*
  * This structure is sent during the intialization phase to get the different
  * properties of the channel.
@@ -864,7 +907,7 @@ static int storvsc_channel_init(struct hv_device *device)
        struct storvsc_device *stor_device;
        struct storvsc_cmd_request *request;
        struct vstor_packet *vstor_packet;
-       int ret, t;
+       int ret, t, i;
        int max_chns;
        bool process_sub_channels = false;
 
@@ -904,36 +947,59 @@ static int storvsc_channel_init(struct hv_device *device)
                goto cleanup;
 
 
-       /* reuse the packet for version range supported */
-       memset(vstor_packet, 0, sizeof(struct vstor_packet));
-       vstor_packet->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
-       vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+       for (i = 0; i < ARRAY_SIZE(vmstor_protocols); i++) {
+               /* reuse the packet for version range supported */
+               memset(vstor_packet, 0, sizeof(struct vstor_packet));
+               vstor_packet->operation =
+                       VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
+               vstor_packet->flags = REQUEST_COMPLETION_FLAG;
 
-       vstor_packet->version.major_minor = vmstor_proto_version;
+               vstor_packet->version.major_minor =
+                       vmstor_protocols[i].protocol_version;
 
-       /*
-        * The revision number is only used in Windows; set it to 0.
-        */
-       vstor_packet->version.revision = 0;
+               /*
+                * The revision number is only used in Windows; set it to 0.
+                */
+               vstor_packet->version.revision = 0;
 
-       ret = vmbus_sendpacket(device->channel, vstor_packet,
+               ret = vmbus_sendpacket(device->channel, vstor_packet,
                               (sizeof(struct vstor_packet) -
                                vmscsi_size_delta),
                               (unsigned long)request,
                               VM_PKT_DATA_INBAND,
                               VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-       if (ret != 0)
-               goto cleanup;
+               if (ret != 0)
+                       goto cleanup;
 
-       t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-       if (t == 0) {
-               ret = -ETIMEDOUT;
-               goto cleanup;
+               t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
+               if (t == 0) {
+                       ret = -ETIMEDOUT;
+                       goto cleanup;
+               }
+
+               if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO) {
+                       ret = -EINVAL;
+                       goto cleanup;
+               }
+
+               if (vstor_packet->status == 0) {
+                       vmstor_proto_version =
+                               vmstor_protocols[i].protocol_version;
+
+                       sense_buffer_size =
+                               vmstor_protocols[i].sense_buffer_size;
+
+                       vmscsi_size_delta =
+                               vmstor_protocols[i].vmscsi_size_delta;
+
+                       break;
+               }
        }
 
-       if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
-           vstor_packet->status != 0)
+       if (vstor_packet->status != 0) {
+               ret = -EINVAL;
                goto cleanup;
+       }
 
 
        memset(vstor_packet, 0, sizeof(struct vstor_packet));
@@ -1746,14 +1812,12 @@ static int storvsc_probe(struct hv_device *device,
        if (vmbus_proto_version < VERSION_WIN8) {
                sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE;
                vmscsi_size_delta = sizeof(struct vmscsi_win8_extension);
-               vmstor_proto_version = VMSTOR_PROTO_VERSION_WIN7;
                max_luns_per_target = STORVSC_IDE_MAX_LUNS_PER_TARGET;
                max_targets = STORVSC_IDE_MAX_TARGETS;
                max_channels = STORVSC_IDE_MAX_CHANNELS;
        } else {
                sense_buffer_size = POST_WIN7_STORVSC_SENSE_BUFFER_SIZE;
                vmscsi_size_delta = 0;
-               vmstor_proto_version = VMSTOR_PROTO_VERSION_WIN8;
                max_luns_per_target = STORVSC_MAX_LUNS_PER_TARGET;
                max_targets = STORVSC_MAX_TARGETS;
                max_channels = STORVSC_MAX_CHANNELS;