[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC PATCH V3 11/11] HV/Storvsc: Add Isolation VM support for storvsc driver



From: Tianyu Lan <Tianyu.Lan@xxxxxxxxxxxxx>

In Isolation VM, all shared memory with host needs to mark visible
to host via hvcall. vmbus_establish_gpadl() has already done it for
storvsc rx/tx ring buffer. The page buffer used by vmbus_sendpacket_
mpb_desc() still need to handle. Use DMA API to map/umap these
memory during sending/receiving packet and Hyper-V DMA ops callback
will use swiotlb function to allocate bounce buffer and copy data
from/to bounce buffer.

Signed-off-by: Tianyu Lan <Tianyu.Lan@xxxxxxxxxxxxx>
---
 drivers/scsi/storvsc_drv.c | 63 +++++++++++++++++++++++++++++++++++---
 1 file changed, 58 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 403753929320..32da419c134e 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -21,6 +21,8 @@
 #include <linux/device.h>
 #include <linux/hyperv.h>
 #include <linux/blkdev.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_host.h>
@@ -427,6 +429,8 @@ struct storvsc_cmd_request {
        u32 payload_sz;
 
        struct vstor_packet vstor_packet;
+       u32 hvpg_count;
+       struct hv_dma_range *dma_range;
 };
 
 
@@ -1267,6 +1271,7 @@ static void storvsc_on_channel_callback(void *context)
        struct hv_device *device;
        struct storvsc_device *stor_device;
        struct Scsi_Host *shost;
+       int i;
 
        if (channel->primary_channel != NULL)
                device = channel->primary_channel->device_obj;
@@ -1321,6 +1326,17 @@ static void storvsc_on_channel_callback(void *context)
                                request = (struct storvsc_cmd_request 
*)scsi_cmd_priv(scmnd);
                        }
 
+                       if (request->dma_range) {
+                               for (i = 0; i < request->hvpg_count; i++)
+                                       dma_unmap_page(&device->device,
+                                                       
request->dma_range[i].dma,
+                                                       
request->dma_range[i].mapping_size,
+                                                       
request->vstor_packet.vm_srb.data_in
+                                                            == READ_TYPE ?
+                                                       DMA_FROM_DEVICE : 
DMA_TO_DEVICE);
+                               kfree(request->dma_range);
+                       }
+
                        storvsc_on_receive(stor_device, packet, request);
                        continue;
                }
@@ -1817,7 +1833,9 @@ static int storvsc_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *scmnd)
                unsigned int hvpgoff, hvpfns_to_add;
                unsigned long offset_in_hvpg = offset_in_hvpage(sgl->offset);
                unsigned int hvpg_count = HVPFN_UP(offset_in_hvpg + length);
+               dma_addr_t dma;
                u64 hvpfn;
+               u32 size;
 
                if (hvpg_count > MAX_PAGE_BUFFER_COUNT) {
 
@@ -1831,6 +1849,13 @@ static int storvsc_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *scmnd)
                payload->range.len = length;
                payload->range.offset = offset_in_hvpg;
 
+               cmd_request->dma_range = kcalloc(hvpg_count,
+                                sizeof(*cmd_request->dma_range),
+                                GFP_ATOMIC);
+               if (!cmd_request->dma_range) {
+                       ret = -ENOMEM;
+                       goto free_payload;
+               }
 
                for (i = 0; sgl != NULL; sgl = sg_next(sgl)) {
                        /*
@@ -1854,9 +1879,30 @@ static int storvsc_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *scmnd)
                         * last sgl should be reached at the same time that
                         * the PFN array is filled.
                         */
-                       while (hvpfns_to_add--)
-                               payload->range.pfn_array[i++] = hvpfn++;
+                       while (hvpfns_to_add--) {
+                               size = min(HV_HYP_PAGE_SIZE - offset_in_hvpg,
+                                          (unsigned long)length);
+                               dma = dma_map_page(&dev->device,
+                                                        pfn_to_page(hvpfn++),
+                                                        offset_in_hvpg, size,
+                                                        
scmnd->sc_data_direction);
+                               if (dma_mapping_error(&dev->device, dma)) {
+                                       ret = -ENOMEM;
+                                       goto free_dma_range;
+                               }
+
+                               if (offset_in_hvpg) {
+                                       payload->range.offset = dma & 
~HV_HYP_PAGE_MASK;
+                                       offset_in_hvpg = 0;
+                               }
+
+                               cmd_request->dma_range[i].dma = dma;
+                               cmd_request->dma_range[i].mapping_size = size;
+                               payload->range.pfn_array[i++] = dma >> 
HV_HYP_PAGE_SHIFT;
+                               length -= size;
+                       }
                }
+               cmd_request->hvpg_count = hvpg_count;
        }
 
        cmd_request->payload = payload;
@@ -1867,13 +1913,20 @@ static int storvsc_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *scmnd)
        put_cpu();
 
        if (ret == -EAGAIN) {
-               if (payload_sz > sizeof(cmd_request->mpb))
-                       kfree(payload);
                /* no more space */
-               return SCSI_MLQUEUE_DEVICE_BUSY;
+               ret = SCSI_MLQUEUE_DEVICE_BUSY;
+               goto free_dma_range;
        }
 
        return 0;
+
+free_dma_range:
+       kfree(cmd_request->dma_range);
+
+free_payload:
+       if (payload_sz > sizeof(cmd_request->mpb))
+               kfree(payload);
+       return ret;
 }
 
 static struct scsi_host_template scsi_driver = {
-- 
2.25.1




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.