From b9ec3a55389560a13e226c8d835db6bf0b3d61fd Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 27 Mar 2015 00:27:14 -0700 Subject: scsi: storvsc: Increase the ring buffer size Increase the default ring buffer size as this can significantly improve performance especially on high latency storage back-ends. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Signed-off-by: James Bottomley --- drivers/scsi/storvsc_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/storvsc_drv.c') diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index efc6e446b6c8..27fe850bdfed 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -308,7 +308,7 @@ enum storvsc_request_type { * This is the end of Protocol specific defines. */ -static int storvsc_ringbuffer_size = (20 * PAGE_SIZE); +static int storvsc_ringbuffer_size = (256 * PAGE_SIZE); module_param(storvsc_ringbuffer_size, int, S_IRUGO); MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)"); -- cgit v1.2.1 From f458aada75891e6e9aff391f8f12a2cb2aac7d58 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 27 Mar 2015 00:27:15 -0700 Subject: scsi: storvsc: Size the queue depth based on the ringbuffer size Size the queue depth based on the ringbuffer size. Also accommodate for the fact that we could have multiple channels (ringbuffers) per adaptor. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Signed-off-by: James Bottomley --- drivers/scsi/storvsc_drv.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers/scsi/storvsc_drv.c') diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 27fe850bdfed..7f569f971164 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -309,10 +309,15 @@ enum storvsc_request_type { */ static int storvsc_ringbuffer_size = (256 * PAGE_SIZE); +static u32 max_outstanding_req_per_channel; + +static int storvsc_vcpus_per_sub_channel = 4; module_param(storvsc_ringbuffer_size, int, S_IRUGO); MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)"); +module_param(storvsc_vcpus_per_sub_channel, int, S_IRUGO); +MODULE_PARM_DESC(vcpus_per_sub_channel, "Ratio of VCPUs to subchannels"); /* * Timeout in seconds for all devices managed by this driver. */ @@ -320,7 +325,6 @@ static int storvsc_timeout = 180; static int msft_blist_flags = BLIST_TRY_VPD_PAGES; -#define STORVSC_MAX_IO_REQUESTS 200 static void storvsc_on_channel_callback(void *context); @@ -1376,7 +1380,6 @@ static int storvsc_do_io(struct hv_device *device, static int storvsc_device_configure(struct scsi_device *sdevice) { - scsi_change_queue_depth(sdevice, STORVSC_MAX_IO_REQUESTS); blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE); @@ -1646,7 +1649,6 @@ static struct scsi_host_template scsi_driver = { .eh_timed_out = storvsc_eh_timed_out, .slave_configure = storvsc_device_configure, .cmd_per_lun = 255, - .can_queue = STORVSC_MAX_IO_REQUESTS*STORVSC_MAX_TARGETS, .this_id = -1, /* no use setting to 0 since ll_blk_rw reset it to 1 */ /* currently 32 */ @@ -1686,6 +1688,7 @@ static int storvsc_probe(struct hv_device *device, const struct hv_vmbus_device_id *dev_id) { int ret; + int num_cpus = num_online_cpus(); struct Scsi_Host *host; struct hv_host_device *host_dev; bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false); @@ -1694,6 +1697,7 @@ static int storvsc_probe(struct hv_device *device, int max_luns_per_target; int max_targets; int max_channels; + int max_sub_channels = 0; /* * Based on the windows host we are running on, @@ -1719,12 +1723,18 @@ static int storvsc_probe(struct hv_device *device, max_luns_per_target = STORVSC_MAX_LUNS_PER_TARGET; max_targets = STORVSC_MAX_TARGETS; max_channels = STORVSC_MAX_CHANNELS; + /* + * On Windows8 and above, we support sub-channels for storage. + * The number of sub-channels offerred is based on the number of + * VCPUs in the guest. + */ + max_sub_channels = (num_cpus / storvsc_vcpus_per_sub_channel); break; } - if (dev_id->driver_data == SFC_GUID) - scsi_driver.can_queue = (STORVSC_MAX_IO_REQUESTS * - STORVSC_FC_MAX_TARGETS); + scsi_driver.can_queue = (max_outstanding_req_per_channel * + (max_sub_channels + 1)); + host = scsi_host_alloc(&scsi_driver, sizeof(struct hv_host_device)); if (!host) @@ -1837,7 +1847,6 @@ static struct hv_driver storvsc_drv = { static int __init storvsc_drv_init(void) { - u32 max_outstanding_req_per_channel; /* * Divide the ring buffer data size (which is 1 page less @@ -1852,10 +1861,6 @@ static int __init storvsc_drv_init(void) vmscsi_size_delta, sizeof(u64))); - if (max_outstanding_req_per_channel < - STORVSC_MAX_IO_REQUESTS) - return -EINVAL; - return vmbus_driver_register(&storvsc_drv); } -- cgit v1.2.1 From 0147dabc4404b3c91d65a47151283d9aa478b666 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 27 Mar 2015 00:27:16 -0700 Subject: scsi: storvsc: Always send on the selected outgoing channel The current code always sent packets without data on the primary channel. Properly distribute sending of packets with no data amongst all available channels. I would like to thank Long Li for noticing this problem. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Signed-off-by: James Bottomley --- drivers/scsi/storvsc_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/storvsc_drv.c') diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 7f569f971164..0ba7f2cbbbc3 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1362,7 +1362,7 @@ static int storvsc_do_io(struct hv_device *device, vmscsi_size_delta), (unsigned long)request); } else { - ret = vmbus_sendpacket(device->channel, vstor_packet, + ret = vmbus_sendpacket(outgoing_channel, vstor_packet, (sizeof(struct vstor_packet) - vmscsi_size_delta), (unsigned long)request, -- cgit v1.2.1 From 5117b93696fae092be92acf1b80ae19cb28f4ba3 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 27 Mar 2015 00:27:17 -0700 Subject: scsi: storvsc: Retrieve information about the capability of the target The storage protocol informs the guest of the I/O capabilities of the storage stack. Retrieve this information and use it in the guest. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Signed-off-by: James Bottomley --- drivers/scsi/storvsc_drv.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/scsi/storvsc_drv.c') diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 0ba7f2cbbbc3..cdf048ba4d2d 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -377,6 +377,10 @@ struct storvsc_device { unsigned char path_id; unsigned char target_id; + /* + * Max I/O, the device can support. + */ + u32 max_transfer_bytes; /* Used for vsc/vsp channel reset process */ struct storvsc_cmd_request init_request; struct storvsc_cmd_request reset_request; @@ -974,6 +978,8 @@ static int storvsc_channel_init(struct hv_device *device) STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL) process_sub_channels = true; } + stor_device->max_transfer_bytes = + vstor_packet->storage_channel_properties.max_transfer_bytes; memset(vstor_packet, 0, sizeof(struct vstor_packet)); vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION; -- cgit v1.2.1 From 8de580742fee8bc34d116f57a20b22b9a5f08403 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 27 Mar 2015 00:27:18 -0700 Subject: scsi: storvsc: Fix a bug in copy_from_bounce_buffer() We may exit this function without properly freeing up the maapings we may have acquired. Fix the bug. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Cc: Signed-off-by: James Bottomley --- drivers/scsi/storvsc_drv.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/scsi/storvsc_drv.c') diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index cdf048ba4d2d..f8e4dd925a9d 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -754,21 +754,22 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl, if (bounce_sgl[j].length == PAGE_SIZE) { /* full..move to next entry */ sg_kunmap_atomic(bounce_addr); + bounce_addr = 0; j++; + } - /* if we need to use another bounce buffer */ - if (srclen || i != orig_sgl_count - 1) - bounce_addr = sg_kmap_atomic(bounce_sgl,j); + /* if we need to use another bounce buffer */ + if (srclen && bounce_addr == 0) + bounce_addr = sg_kmap_atomic(bounce_sgl, j); - } else if (srclen == 0 && i == orig_sgl_count - 1) { - /* unmap the last bounce that is < PAGE_SIZE */ - sg_kunmap_atomic(bounce_addr); - } } sg_kunmap_atomic(src_addr - orig_sgl[i].offset); } + if (bounce_addr) + sg_kunmap_atomic(bounce_addr); + local_irq_restore(flags); return total_copied; -- cgit v1.2.1 From aaced9934d2231227fec4255f394eb86af818ce2 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 27 Mar 2015 00:27:19 -0700 Subject: scsi: storvsc: Don't assume that the scatterlist is not chained The current code assumes that the scatterlists presented are not chained. Fix the code to not make this assumption. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Signed-off-by: James Bottomley --- drivers/scsi/storvsc_drv.c | 99 ++++++++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 42 deletions(-) (limited to 'drivers/scsi/storvsc_drv.c') diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index f8e4dd925a9d..4156e297ea64 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -626,19 +626,6 @@ cleanup: return NULL; } -/* Disgusting wrapper functions */ -static inline unsigned long sg_kmap_atomic(struct scatterlist *sgl, int idx) -{ - void *addr = kmap_atomic(sg_page(sgl + idx)); - return (unsigned long)addr; -} - -static inline void sg_kunmap_atomic(unsigned long addr) -{ - kunmap_atomic((void *)addr); -} - - /* Assume the original sgl has enough room */ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl, struct scatterlist *bounce_sgl, @@ -653,32 +640,38 @@ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl, 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 = sg_kmap_atomic(orig_sgl,i) + orig_sgl[i].offset; + dest_addr = (unsigned long) + kmap_atomic(sg_page(cur_dest_sgl)) + + cur_dest_sgl->offset; dest = dest_addr; - destlen = orig_sgl[i].length; + destlen = cur_dest_sgl->length; if (bounce_addr == 0) - bounce_addr = sg_kmap_atomic(bounce_sgl,j); + bounce_addr = (unsigned long)kmap_atomic( + sg_page(cur_src_sgl)); while (destlen) { - src = bounce_addr + bounce_sgl[j].offset; - srclen = bounce_sgl[j].length - bounce_sgl[j].offset; + 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; - bounce_sgl[j].offset += copylen; + cur_src_sgl->offset += copylen; destlen -= copylen; dest += copylen; - if (bounce_sgl[j].offset == bounce_sgl[j].length) { + if (cur_src_sgl->offset == cur_src_sgl->length) { /* full */ - sg_kunmap_atomic(bounce_addr); + kunmap_atomic((void *)bounce_addr); j++; /* @@ -692,21 +685,27 @@ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl, /* * We are done; cleanup and return. */ - sg_kunmap_atomic(dest_addr - orig_sgl[i].offset); + 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) - bounce_addr = sg_kmap_atomic(bounce_sgl,j); + 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 */ - sg_kunmap_atomic(bounce_addr); + kunmap_atomic((void *)bounce_addr); } } - sg_kunmap_atomic(dest_addr - orig_sgl[i].offset); + kunmap_atomic((void *)(dest_addr - cur_dest_sgl->offset)); + cur_dest_sgl = sg_next(cur_dest_sgl); } local_irq_restore(flags); @@ -727,48 +726,61 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl, 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 = sg_kmap_atomic(orig_sgl,i) + orig_sgl[i].offset; + src_addr = (unsigned long) + kmap_atomic(sg_page(cur_src_sgl)) + + cur_src_sgl->offset; src = src_addr; - srclen = orig_sgl[i].length; + srclen = cur_src_sgl->length; if (bounce_addr == 0) - bounce_addr = sg_kmap_atomic(bounce_sgl,j); + bounce_addr = (unsigned long) + kmap_atomic(sg_page(cur_dest_sgl)); while (srclen) { /* assume bounce offset always == 0 */ - dest = bounce_addr + bounce_sgl[j].length; - destlen = PAGE_SIZE - bounce_sgl[j].length; + 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; - bounce_sgl[j].length += copylen; + cur_dest_sgl->length += copylen; srclen -= copylen; src += copylen; - if (bounce_sgl[j].length == PAGE_SIZE) { + if (cur_dest_sgl->length == PAGE_SIZE) { /* full..move to next entry */ - sg_kunmap_atomic(bounce_addr); + kunmap_atomic((void *)bounce_addr); bounce_addr = 0; j++; } /* if we need to use another bounce buffer */ - if (srclen && bounce_addr == 0) - bounce_addr = sg_kmap_atomic(bounce_sgl, j); + if (srclen && bounce_addr == 0) { + cur_dest_sgl = sg_next(cur_dest_sgl); + bounce_addr = (unsigned long) + kmap_atomic( + sg_page(cur_dest_sgl)); + } } - sg_kunmap_atomic(src_addr - orig_sgl[i].offset); + kunmap_atomic((void *)(src_addr - cur_src_sgl->offset)); + cur_src_sgl = sg_next(cur_src_sgl); } if (bounce_addr) - sg_kunmap_atomic(bounce_addr); + kunmap_atomic((void *)bounce_addr); local_irq_restore(flags); @@ -1536,6 +1548,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) struct scatterlist *sgl; unsigned int sg_count = 0; struct vmscsi_request *vm_srb; + struct scatterlist *cur_sgl; if (vmstor_current_major <= VMSTOR_WIN8_MAJOR) { /* @@ -1617,10 +1630,12 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) } cmd_request->data_buffer.offset = sgl[0].offset; - - for (i = 0; i < sg_count; i++) + cur_sgl = sgl; + for (i = 0; i < sg_count; i++) { cmd_request->data_buffer.pfn_array[i] = - page_to_pfn(sg_page((&sgl[i]))); + page_to_pfn(sg_page((cur_sgl))); + cur_sgl = sg_next(cur_sgl); + } } else if (scsi_sglist(scmnd)) { cmd_request->data_buffer.offset = -- cgit v1.2.1 From be0cf6ca301c61458dc4aa1a37acf4f58d2ed3d6 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 27 Mar 2015 00:27:20 -0700 Subject: scsi: storvsc: Set the tablesize based on the information given by the host Set the tablesize based on the information given by the host. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Tested-by: Long Li Signed-off-by: James Bottomley --- drivers/scsi/storvsc_drv.c | 89 +++++++++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 25 deletions(-) (limited to 'drivers/scsi/storvsc_drv.c') diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 4156e297ea64..d9dad90344d5 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -351,7 +351,10 @@ struct storvsc_cmd_request { /* Synchronize the request/response if needed */ struct completion wait_event; - struct hv_multipage_buffer data_buffer; + struct vmbus_channel_packet_multipage_buffer mpb; + struct vmbus_packet_mpb_array *payload; + u32 payload_sz; + struct vstor_packet vstor_packet; }; @@ -1103,6 +1106,8 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) struct Scsi_Host *host; struct storvsc_device *stor_dev; struct hv_device *dev = host_dev->dev; + u32 payload_sz = cmd_request->payload_sz; + void *payload = cmd_request->payload; stor_dev = get_in_stor_device(dev); host = stor_dev->host; @@ -1132,10 +1137,14 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) sense_hdr.ascq); scsi_set_resid(scmnd, - cmd_request->data_buffer.len - + cmd_request->payload->range.len - vm_srb->data_transfer_length); scmnd->scsi_done(scmnd); + + if (payload_sz > + sizeof(struct vmbus_channel_packet_multipage_buffer)) + kfree(payload); } static void storvsc_on_io_completion(struct hv_device *device, @@ -1337,7 +1346,7 @@ static int storvsc_dev_remove(struct hv_device *device) } static int storvsc_do_io(struct hv_device *device, - struct storvsc_cmd_request *request) + struct storvsc_cmd_request *request) { struct storvsc_device *stor_device; struct vstor_packet *vstor_packet; @@ -1369,13 +1378,14 @@ static int storvsc_do_io(struct hv_device *device, vstor_packet->vm_srb.data_transfer_length = - request->data_buffer.len; + request->payload->range.len; vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB; - if (request->data_buffer.len) { - ret = vmbus_sendpacket_multipagebuffer(outgoing_channel, - &request->data_buffer, + if (request->payload->range.len) { + + ret = vmbus_sendpacket_mpb_desc(outgoing_channel, + request->payload, request->payload_sz, vstor_packet, (sizeof(struct vstor_packet) - vmscsi_size_delta), @@ -1549,6 +1559,9 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) unsigned int sg_count = 0; struct vmscsi_request *vm_srb; struct scatterlist *cur_sgl; + struct vmbus_packet_mpb_array *payload; + u32 payload_sz; + u32 length; if (vmstor_current_major <= VMSTOR_WIN8_MAJOR) { /* @@ -1602,48 +1615,71 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) memcpy(vm_srb->cdb, scmnd->cmnd, vm_srb->cdb_length); - cmd_request->data_buffer.len = scsi_bufflen(scmnd); - if (scsi_sg_count(scmnd)) { - sgl = (struct scatterlist *)scsi_sglist(scmnd); - sg_count = scsi_sg_count(scmnd); + sgl = (struct scatterlist *)scsi_sglist(scmnd); + sg_count = scsi_sg_count(scmnd); + length = scsi_bufflen(scmnd); + payload = (struct vmbus_packet_mpb_array *)&cmd_request->mpb; + 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, scsi_sg_count(scmnd), - scsi_bufflen(scmnd), + 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(scsi_bufflen(scmnd), PAGE_SIZE) >> - PAGE_SHIFT; + ALIGN(length, PAGE_SIZE) >> PAGE_SHIFT; if (vm_srb->data_in == WRITE_TYPE) copy_to_bounce_buffer(sgl, - cmd_request->bounce_sgl, - scsi_sg_count(scmnd)); + cmd_request->bounce_sgl, sg_count); sgl = cmd_request->bounce_sgl; sg_count = cmd_request->bounce_sgl_count; } - cmd_request->data_buffer.offset = sgl[0].offset; + + 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; + } + } + + payload->range.len = length; + payload->range.offset = sgl[0].offset; + cur_sgl = sgl; for (i = 0; i < sg_count; i++) { - cmd_request->data_buffer.pfn_array[i] = + payload->range.pfn_array[i] = page_to_pfn(sg_page((cur_sgl))); cur_sgl = sg_next(cur_sgl); } } else if (scsi_sglist(scmnd)) { - cmd_request->data_buffer.offset = + payload->range.len = length; + payload->range.offset = virt_to_phys(scsi_sglist(scmnd)) & (PAGE_SIZE-1); - cmd_request->data_buffer.pfn_array[0] = + payload->range.pfn_array[0] = virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT; } + cmd_request->payload = payload; + cmd_request->payload_sz = payload_sz; + /* Invokes the vsc to start an IO */ ret = storvsc_do_io(dev, cmd_request); @@ -1672,10 +1708,7 @@ static struct scsi_host_template scsi_driver = { .slave_configure = storvsc_device_configure, .cmd_per_lun = 255, .this_id = -1, - /* no use setting to 0 since ll_blk_rw reset it to 1 */ - /* currently 32 */ - .sg_tablesize = MAX_MULTIPAGE_BUFFER_COUNT, - .use_clustering = DISABLE_CLUSTERING, + .use_clustering = ENABLE_CLUSTERING, /* Make sure we dont get a sg segment crosses a page boundary */ .dma_boundary = PAGE_SIZE-1, .no_write_same = 1, @@ -1812,6 +1845,12 @@ static int storvsc_probe(struct hv_device *device, /* max cmd length */ host->max_cmd_len = STORVSC_MAX_CMD_LEN; + /* + * set the table size based on the info we got + * from the host. + */ + host->sg_tablesize = (stor_device->max_transfer_bytes >> PAGE_SHIFT); + /* Register the HBA and start the scsi bus scan */ ret = scsi_add_host(host, &device->device); if (ret != 0) -- cgit v1.2.1