lkml.org 
[lkml]   [2021]   [Jul]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 13/13] HV/Storvsc: Add Isolation VM support for storvsc driver
    Date
    From: Tianyu Lan <Tianyu.Lan@microsoft.com>

    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@microsoft.com>
    ---
    drivers/scsi/storvsc_drv.c | 68 +++++++++++++++++++++++++++++++++++---
    1 file changed, 63 insertions(+), 5 deletions(-)

    diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
    index 328bb961c281..78320719bdd8 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;
    };


    @@ -509,6 +513,14 @@ struct storvsc_scan_work {
    u8 tgt_id;
    };

    +#define storvsc_dma_map(dev, page, offset, size, dir) \
    + dma_map_page(dev, page, offset, size, dir)
    +
    +#define storvsc_dma_unmap(dev, dma_range, dir) \
    + dma_unmap_page(dev, dma_range.dma, \
    + dma_range.mapping_size, \
    + dir ? DMA_FROM_DEVICE : DMA_TO_DEVICE)
    +
    static void storvsc_device_scan(struct work_struct *work)
    {
    struct storvsc_scan_work *wrk;
    @@ -1260,6 +1272,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;
    @@ -1314,6 +1327,15 @@ 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++)
    + storvsc_dma_unmap(&device->device,
    + request->dma_range[i],
    + request->vstor_packet.vm_srb.data_in == READ_TYPE);
    +
    + kfree(request->dma_range);
    + }
    +
    storvsc_on_receive(stor_device, packet, request);
    continue;
    }
    @@ -1810,7 +1832,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) {

    @@ -1824,6 +1848,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)) {
    /*
    @@ -1847,9 +1878,29 @@ 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 = storvsc_dma_map(&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;
    @@ -1860,13 +1911,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
    \
     
     \ /
      Last update: 2021-07-28 16:55    [W:4.056 / U:0.032 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site