These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / scsi / storvsc_drv.c
index 3c6584f..3fba42a 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_WIN7_MAJOR 4
-#define VMSTOR_WIN7_MINOR 2
-
-#define VMSTOR_WIN8_MAJOR 5
-#define VMSTOR_WIN8_MINOR 1
-
+#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 {
@@ -148,21 +151,18 @@ struct hv_fc_wwn_packet {
 
 /*
  * Sense buffer size changed in win8; have a run-time
- * variable to track the size we should use.
+ * variable to track the size we should use.  This value will
+ * likely change during protocol negotiation but it is valid
+ * to start by assuming pre-Win8.
  */
-static int sense_buffer_size;
+static int sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE;
 
 /*
- * The size of the vmscsi_request has changed in win8. The
- * additional size is because of new elements added to the
- * structure. These elements are valid only when we are talking
- * to a win8 host.
- * Track the correction to size we need to apply.
- */
-
-static int vmscsi_size_delta;
-static int vmstor_current_major;
-static int vmstor_current_minor;
+ * The storage protocol version is determined during the
+ * initial exchange with the host.  It will indicate which
+ * storage functionality is available in the host.
+*/
+static int vmstor_proto_version;
 
 struct vmscsi_win8_extension {
        /*
@@ -206,6 +206,56 @@ struct vmscsi_request {
 } __attribute((packed));
 
 
+/*
+ * The size of the vmscsi_request has changed in win8. The
+ * additional size is because of new elements added to the
+ * structure. These elements are valid only when we are talking
+ * to a win8 host.
+ * Track the correction to size we need to apply. This value
+ * will likely change during protocol negotiation but it is
+ * valid to start by assuming pre-Win8.
+ */
+static int vmscsi_size_delta = sizeof(struct vmscsi_win8_extension);
+
+/*
+ * 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.
@@ -299,11 +349,14 @@ enum storvsc_request_type {
  */
 
 #define SRB_STATUS_AUTOSENSE_VALID     0x80
+#define SRB_STATUS_QUEUE_FROZEN                0x40
 #define SRB_STATUS_INVALID_LUN 0x20
 #define SRB_STATUS_SUCCESS     0x01
 #define SRB_STATUS_ABORTED     0x02
 #define SRB_STATUS_ERROR       0x04
 
+#define SRB_STATUS(status) \
+       (status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN))
 /*
  * This is the end of Protocol specific defines.
  */
@@ -343,9 +396,6 @@ static void storvsc_on_channel_callback(void *context);
 struct storvsc_cmd_request {
        struct scsi_cmnd *cmd;
 
-       unsigned int bounce_sgl_count;
-       struct scatterlist *bounce_sgl;
-
        struct hv_device *device;
 
        /* Synchronize the request/response if needed */
@@ -426,7 +476,6 @@ static void storvsc_host_scan(struct work_struct *work)
        struct storvsc_scan_work *wrk;
        struct Scsi_Host *host;
        struct scsi_device *sdev;
-       unsigned long flags;
 
        wrk = container_of(work, struct storvsc_scan_work, work);
        host = wrk->host;
@@ -443,14 +492,8 @@ static void storvsc_host_scan(struct work_struct *work)
         * may have been removed this way.
         */
        mutex_lock(&host->scan_mutex);
-       spin_lock_irqsave(host->host_lock, flags);
-       list_for_each_entry(sdev, &host->__devices, siblings) {
-               spin_unlock_irqrestore(host->host_lock, flags);
+       shost_for_each_device(sdev, host)
                scsi_test_unit_ready(sdev, 1, 1, NULL);
-               spin_lock_irqsave(host->host_lock, flags);
-               continue;
-       }
-       spin_unlock_irqrestore(host->host_lock, flags);
        mutex_unlock(&host->scan_mutex);
        /*
         * Now scan the host to discover LUNs that may have been added.
@@ -481,18 +524,6 @@ done:
        kfree(wrk);
 }
 
-/*
- * Major/minor macros.  Minor version is in LSB, meaning that earlier flat
- * version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1).
- */
-
-static inline u16 storvsc_get_version(u8 major, u8 minor)
-{
-       u16 version;
-
-       version = ((major << 8) | minor);
-       return version;
-}
 
 /*
  * We can get incoming messages from the host that are not in response to
@@ -555,241 +586,6 @@ get_in_err:
 
 }
 
-static void destroy_bounce_buffer(struct scatterlist *sgl,
-                                 unsigned int sg_count)
-{
-       int i;
-       struct page *page_buf;
-
-       for (i = 0; i < sg_count; i++) {
-               page_buf = sg_page((&sgl[i]));
-               if (page_buf != NULL)
-                       __free_page(page_buf);
-       }
-
-       kfree(sgl);
-}
-
-static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count)
-{
-       int i;
-
-       /* No need to check */
-       if (sg_count < 2)
-               return -1;
-
-       /* We have at least 2 sg entries */
-       for (i = 0; i < sg_count; i++) {
-               if (i == 0) {
-                       /* make sure 1st one does not have hole */
-                       if (sgl[i].offset + sgl[i].length != PAGE_SIZE)
-                               return i;
-               } else if (i == sg_count - 1) {
-                       /* make sure last one does not have hole */
-                       if (sgl[i].offset != 0)
-                               return i;
-               } else {
-                       /* make sure no hole in the middle */
-                       if (sgl[i].length != PAGE_SIZE || sgl[i].offset != 0)
-                               return i;
-               }
-       }
-       return -1;
-}
-
-static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl,
-                                               unsigned int sg_count,
-                                               unsigned int len,
-                                               int write)
-{
-       int i;
-       int num_pages;
-       struct scatterlist *bounce_sgl;
-       struct page *page_buf;
-       unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE);
-
-       num_pages = ALIGN(len, PAGE_SIZE) >> PAGE_SHIFT;
-
-       bounce_sgl = kcalloc(num_pages, sizeof(struct scatterlist), GFP_ATOMIC);
-       if (!bounce_sgl)
-               return NULL;
-
-       sg_init_table(bounce_sgl, num_pages);
-       for (i = 0; i < num_pages; i++) {
-               page_buf = alloc_page(GFP_ATOMIC);
-               if (!page_buf)
-                       goto cleanup;
-               sg_set_page(&bounce_sgl[i], page_buf, buf_len, 0);
-       }
-
-       return bounce_sgl;
-
-cleanup:
-       destroy_bounce_buffer(bounce_sgl, num_pages);
-       return NULL;
-}
-
-/* Assume the original sgl has enough room */
-static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
-                                           struct scatterlist *bounce_sgl,
-                                           unsigned int orig_sgl_count,
-                                           unsigned int bounce_sgl_count)
-{
-       int i;
-       int j = 0;
-       unsigned long src, dest;
-       unsigned int srclen, destlen, copylen;
-       unsigned int total_copied = 0;
-       unsigned long bounce_addr = 0;
-       unsigned long dest_addr = 0;
-       unsigned long flags;
-       struct scatterlist *cur_dest_sgl;
-       struct scatterlist *cur_src_sgl;
-
-       local_irq_save(flags);
-       cur_dest_sgl = orig_sgl;
-       cur_src_sgl = bounce_sgl;
-       for (i = 0; i < orig_sgl_count; i++) {
-               dest_addr = (unsigned long)
-                               kmap_atomic(sg_page(cur_dest_sgl)) +
-                               cur_dest_sgl->offset;
-               dest = dest_addr;
-               destlen = cur_dest_sgl->length;
-
-               if (bounce_addr == 0)
-                       bounce_addr = (unsigned long)kmap_atomic(
-                                                       sg_page(cur_src_sgl));
-
-               while (destlen) {
-                       src = bounce_addr + cur_src_sgl->offset;
-                       srclen = cur_src_sgl->length - cur_src_sgl->offset;
-
-                       copylen = min(srclen, destlen);
-                       memcpy((void *)dest, (void *)src, copylen);
-
-                       total_copied += copylen;
-                       cur_src_sgl->offset += copylen;
-                       destlen -= copylen;
-                       dest += copylen;
-
-                       if (cur_src_sgl->offset == cur_src_sgl->length) {
-                               /* full */
-                               kunmap_atomic((void *)bounce_addr);
-                               j++;
-
-                               /*
-                                * It is possible that the number of elements
-                                * in the bounce buffer may not be equal to
-                                * the number of elements in the original
-                                * scatter list. Handle this correctly.
-                                */
-
-                               if (j == bounce_sgl_count) {
-                                       /*
-                                        * We are done; cleanup and return.
-                                        */
-                                       kunmap_atomic((void *)(dest_addr -
-                                               cur_dest_sgl->offset));
-                                       local_irq_restore(flags);
-                                       return total_copied;
-                               }
-
-                               /* if we need to use another bounce buffer */
-                               if (destlen || i != orig_sgl_count - 1) {
-                                       cur_src_sgl = sg_next(cur_src_sgl);
-                                       bounce_addr = (unsigned long)
-                                                       kmap_atomic(
-                                                       sg_page(cur_src_sgl));
-                               }
-                       } else if (destlen == 0 && i == orig_sgl_count - 1) {
-                               /* unmap the last bounce that is < PAGE_SIZE */
-                               kunmap_atomic((void *)bounce_addr);
-                       }
-               }
-
-               kunmap_atomic((void *)(dest_addr - cur_dest_sgl->offset));
-               cur_dest_sgl = sg_next(cur_dest_sgl);
-       }
-
-       local_irq_restore(flags);
-
-       return total_copied;
-}
-
-/* Assume the bounce_sgl has enough room ie using the create_bounce_buffer() */
-static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
-                                         struct scatterlist *bounce_sgl,
-                                         unsigned int orig_sgl_count)
-{
-       int i;
-       int j = 0;
-       unsigned long src, dest;
-       unsigned int srclen, destlen, copylen;
-       unsigned int total_copied = 0;
-       unsigned long bounce_addr = 0;
-       unsigned long src_addr = 0;
-       unsigned long flags;
-       struct scatterlist *cur_src_sgl;
-       struct scatterlist *cur_dest_sgl;
-
-       local_irq_save(flags);
-
-       cur_src_sgl = orig_sgl;
-       cur_dest_sgl = bounce_sgl;
-
-       for (i = 0; i < orig_sgl_count; i++) {
-               src_addr = (unsigned long)
-                               kmap_atomic(sg_page(cur_src_sgl)) +
-                               cur_src_sgl->offset;
-               src = src_addr;
-               srclen = cur_src_sgl->length;
-
-               if (bounce_addr == 0)
-                       bounce_addr = (unsigned long)
-                                       kmap_atomic(sg_page(cur_dest_sgl));
-
-               while (srclen) {
-                       /* assume bounce offset always == 0 */
-                       dest = bounce_addr + cur_dest_sgl->length;
-                       destlen = PAGE_SIZE - cur_dest_sgl->length;
-
-                       copylen = min(srclen, destlen);
-                       memcpy((void *)dest, (void *)src, copylen);
-
-                       total_copied += copylen;
-                       cur_dest_sgl->length += copylen;
-                       srclen -= copylen;
-                       src += copylen;
-
-                       if (cur_dest_sgl->length == PAGE_SIZE) {
-                               /* full..move to next entry */
-                               kunmap_atomic((void *)bounce_addr);
-                               bounce_addr = 0;
-                               j++;
-                       }
-
-                       /* if we need to use another bounce buffer */
-                       if (srclen && bounce_addr == 0) {
-                               cur_dest_sgl = sg_next(cur_dest_sgl);
-                               bounce_addr = (unsigned long)
-                                               kmap_atomic(
-                                               sg_page(cur_dest_sgl));
-                       }
-
-               }
-
-               kunmap_atomic((void *)(src_addr - cur_src_sgl->offset));
-               cur_src_sgl = sg_next(cur_src_sgl);
-       }
-
-       if (bounce_addr)
-               kunmap_atomic((void *)bounce_addr);
-
-       local_irq_restore(flags);
-
-       return total_copied;
-}
-
 static void handle_sc_creation(struct vmbus_channel *new_sc)
 {
        struct hv_device *device = new_sc->primary_channel->device_obj;
@@ -885,7 +681,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;
 
@@ -921,41 +717,65 @@ static int storvsc_channel_init(struct hv_device *device)
        }
 
        if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
-           vstor_packet->status != 0)
+           vstor_packet->status != 0) {
+               ret = -EINVAL;
                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 =
-               storvsc_get_version(vmstor_current_major, vmstor_current_minor);
+               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));
@@ -979,8 +799,10 @@ static int storvsc_channel_init(struct hv_device *device)
        }
 
        if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
-           vstor_packet->status != 0)
+           vstor_packet->status != 0) {
+               ret = -EINVAL;
                goto cleanup;
+       }
 
        /*
         * Check to see if multi-channel support is there.
@@ -988,8 +810,7 @@ static int storvsc_channel_init(struct hv_device *device)
         * support multi-channel.
         */
        max_chns = vstor_packet->storage_channel_properties.max_channel_cnt;
-       if ((vmbus_proto_version != VERSION_WIN7) &&
-          (vmbus_proto_version != VERSION_WS2008))  {
+       if (vmstor_proto_version >= VMSTOR_PROTO_VERSION_WIN8) {
                if (vstor_packet->storage_channel_properties.flags &
                    STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL)
                        process_sub_channels = true;
@@ -1018,8 +839,10 @@ static int storvsc_channel_init(struct hv_device *device)
        }
 
        if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
-           vstor_packet->status != 0)
+           vstor_packet->status != 0) {
+               ret = -EINVAL;
                goto cleanup;
+       }
 
        if (process_sub_channels)
                handle_multichannel_storage(device, max_chns);
@@ -1038,7 +861,7 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
        void (*process_err_fn)(struct work_struct *work);
        bool do_work = false;
 
-       switch (vm_srb->srb_status) {
+       switch (SRB_STATUS(vm_srb->srb_status)) {
        case SRB_STATUS_ERROR:
                /*
                 * If there is an error; offline the device since all
@@ -1113,15 +936,6 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
        host = stor_dev->host;
 
        vm_srb = &cmd_request->vstor_packet.vm_srb;
-       if (cmd_request->bounce_sgl_count) {
-               if (vm_srb->data_in == READ_TYPE)
-                       copy_from_bounce_buffer(scsi_sglist(scmnd),
-                                       cmd_request->bounce_sgl,
-                                       scsi_sg_count(scmnd),
-                                       cmd_request->bounce_sgl_count);
-               destroy_bounce_buffer(cmd_request->bounce_sgl,
-                                       cmd_request->bounce_sgl_count);
-       }
 
        scmnd->result = vm_srb->scsi_status;
 
@@ -1416,6 +1230,9 @@ static int storvsc_device_configure(struct scsi_device *sdevice)
 
        blk_queue_rq_timeout(sdevice->request_queue, (storvsc_timeout * HZ));
 
+       /* Ensure there are no gaps in presented sgls */
+       blk_queue_virt_boundary(sdevice->request_queue, PAGE_SIZE - 1);
+
        sdevice->no_write_same = 1;
 
        /*
@@ -1428,15 +1245,19 @@ static int storvsc_device_configure(struct scsi_device *sdevice)
 
        /*
         * If the host is WIN8 or WIN8 R2, claim conformance to SPC-3
-        * if the device is a MSFT virtual device.
+        * if the device is a MSFT virtual device.  If the host is
+        * WIN10 or newer, allow write_same.
         */
        if (!strncmp(sdevice->vendor, "Msft", 4)) {
-               switch (vmbus_proto_version) {
-               case VERSION_WIN8:
-               case VERSION_WIN8_1:
+               switch (vmstor_proto_version) {
+               case VMSTOR_PROTO_VERSION_WIN8:
+               case VMSTOR_PROTO_VERSION_WIN8_1:
                        sdevice->scsi_level = SCSI_SPC_3;
                        break;
                }
+
+               if (vmstor_proto_version >= VMSTOR_PROTO_VERSION_WIN10)
+                       sdevice->no_write_same = 0;
        }
 
        return 0;
@@ -1563,7 +1384,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
        u32 payload_sz;
        u32 length;
 
-       if (vmstor_current_major <= VMSTOR_WIN8_MAJOR) {
+       if (vmstor_proto_version <= VMSTOR_PROTO_VERSION_WIN8) {
                /*
                 * On legacy hosts filter unimplemented commands.
                 * Future hosts are expected to correctly handle
@@ -1585,8 +1406,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
        vm_srb->win8_extension.time_out_value = 60;
 
        vm_srb->win8_extension.srb_flags |=
-               (SRB_FLAGS_QUEUE_ACTION_ENABLE |
-               SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
+               SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
 
        /* Build the SRB */
        switch (scmnd->sc_data_direction) {
@@ -1598,10 +1418,18 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
                vm_srb->data_in = READ_TYPE;
                vm_srb->win8_extension.srb_flags |= SRB_FLAGS_DATA_IN;
                break;
-       default:
+       case DMA_NONE:
                vm_srb->data_in = UNKNOWN_TYPE;
                vm_srb->win8_extension.srb_flags |= SRB_FLAGS_NO_DATA_TRANSFER;
                break;
+       default:
+               /*
+                * This is DMA_BIDIRECTIONAL or something else we are never
+                * supposed to see here.
+                */
+               WARN(1, "Unexpected data direction: %d\n",
+                    scmnd->sc_data_direction);
+               return -EINVAL;
        }
 
 
@@ -1622,40 +1450,13 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
        payload_sz = sizeof(cmd_request->mpb);
 
        if (sg_count) {
-               /* check if we need to bounce the sgl */
-               if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) {
-                       cmd_request->bounce_sgl =
-                               create_bounce_buffer(sgl, sg_count,
-                                                    length,
-                                                    vm_srb->data_in);
-                       if (!cmd_request->bounce_sgl)
-                               return SCSI_MLQUEUE_HOST_BUSY;
-
-                       cmd_request->bounce_sgl_count =
-                               ALIGN(length, PAGE_SIZE) >> PAGE_SHIFT;
-
-                       if (vm_srb->data_in == WRITE_TYPE)
-                               copy_to_bounce_buffer(sgl,
-                                       cmd_request->bounce_sgl, sg_count);
-
-                       sgl = cmd_request->bounce_sgl;
-                       sg_count = cmd_request->bounce_sgl_count;
-               }
-
-
                if (sg_count > MAX_PAGE_BUFFER_COUNT) {
 
                        payload_sz = (sg_count * sizeof(void *) +
                                      sizeof(struct vmbus_packet_mpb_array));
                        payload = kmalloc(payload_sz, GFP_ATOMIC);
-                       if (!payload) {
-                               if (cmd_request->bounce_sgl_count)
-                                       destroy_bounce_buffer(
-                                       cmd_request->bounce_sgl,
-                                       cmd_request->bounce_sgl_count);
-
-                                       return SCSI_MLQUEUE_DEVICE_BUSY;
-                       }
+                       if (!payload)
+                               return SCSI_MLQUEUE_DEVICE_BUSY;
                }
 
                payload->range.len = length;
@@ -1684,11 +1485,6 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
 
        if (ret == -EAGAIN) {
                /* no more space */
-
-               if (cmd_request->bounce_sgl_count)
-                       destroy_bounce_buffer(cmd_request->bounce_sgl,
-                                       cmd_request->bounce_sgl_count);
-
                return SCSI_MLQUEUE_DEVICE_BUSY;
        }
 
@@ -1758,22 +1554,11 @@ static int storvsc_probe(struct hv_device *device,
         * set state to properly communicate with the host.
         */
 
-       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;
+       if (vmbus_proto_version < VERSION_WIN8) {
                max_luns_per_target = STORVSC_IDE_MAX_LUNS_PER_TARGET;
                max_targets = STORVSC_IDE_MAX_TARGETS;
                max_channels = STORVSC_IDE_MAX_CHANNELS;
-               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;
+       } else {
                max_luns_per_target = STORVSC_MAX_LUNS_PER_TARGET;
                max_targets = STORVSC_MAX_TARGETS;
                max_channels = STORVSC_MAX_CHANNELS;
@@ -1783,7 +1568,6 @@ static int storvsc_probe(struct hv_device *device,
                 * VCPUs in the guest.
                 */
                max_sub_channels = (num_cpus / storvsc_vcpus_per_sub_channel);
-               break;
        }
 
        scsi_driver.can_queue = (max_outstanding_req_per_channel *