> Hyper-V provides Confidential VMBus to communicate between device model
> and device guest driver via encrypted/private memory in Confidential VM. The
> device model is in OpenHCL
> (https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fopenvm
> m.dev%2Fguide%2Fuser_guide%2Fopenhcl.html&data=05%7C02%7Clongli%40mi
> crosoft.com%7C0ccfea7cda8e4500ae9808de9540d01e%7C72f988bf86f141af91a
> b2d7cd011db47%7C1%7C0%7C639112302777934798%7CUnknown%7CTWFpbG
> Zsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIk
> FOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=5Uc%2FM4ZVgJT1
> NAq08cIlNtfF5oW4n%2FTj%2Bqg3YqBUeZg%3D&reserved=0) that plays the
> paravisor role.
> 
> For a VMBus device, there are two communication methods to talk with
> Host/Hypervisor. 1) VMBUS Ring buffer 2) Dynamic DMA transfer.
> 
> The Confidential VMBus Ring buffer has been upstreamed by Roman Kisel(commit
> 6802d8af47d1).
> 
> The dynamic DMA transition of VMBus device normally goes through DMA core
> and it uses SWIOTLB as bounce buffer in a CoCo VM.
> 
> The Confidential VMBus device can do DMA directly to private/encrypted
> memory. Because the swiotlb is decrypted memory, the DMA transfer must not
> be bounced through the swiotlb, so as to preserve confidentiality. This is 
> different
> from the default for Linux CoCo VMs, so not use DMA(SWIOTLB) API in VMBus
> driver when confidential dynamic DMA transfers capability is present.
> 
> Signed-off-by: Tianyu Lan <[email protected]>
> ---
>  drivers/scsi/storvsc_drv.c | 28 +++++++++++++++++++++-------
>  include/linux/hyperv.h     |  1 +
>  2 files changed, 22 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index
> ae1abab97835..79b7611518b7 100644
> --- a/drivers/scsi/storvsc_drv.c
> +++ b/drivers/scsi/storvsc_drv.c
> @@ -1316,7 +1316,8 @@ static void storvsc_on_channel_callback(void *context)
>                                       continue;
>                               }
>                               request = (struct storvsc_cmd_request
> *)scsi_cmd_priv(scmnd);
> -                             scsi_dma_unmap(scmnd);
> +                             if (!device->co_external_memory)
> +                                     scsi_dma_unmap(scmnd);
>                       }
> 
>                       storvsc_on_receive(stor_device, packet, request); @@ -
> 1339,6 +1340,8 @@ static int storvsc_connect_to_vsp(struct hv_device *device,
> u32 ring_size,
> 
>       device->channel->max_pkt_size = STORVSC_MAX_PKT_SIZE;
>       device->channel->next_request_id_callback = storvsc_next_request_id;
> +     if (device->channel->co_external_memory)
> +             device->co_external_memory = true;
> 
>       ret = vmbus_open(device->channel,
>                        ring_size,
> @@ -1805,7 +1808,7 @@ static enum scsi_qc_status
> storvsc_queuecommand(struct Scsi_Host *host,
>               unsigned long offset_in_hvpg = offset_in_hvpage(sgl->offset);
>               unsigned int hvpg_count = HVPFN_UP(offset_in_hvpg + length);
>               struct scatterlist *sg;
> -             unsigned long hvpfn, hvpfns_to_add;
> +             unsigned long hvpfn, hvpfns_to_add, hvpgoff;
>               int j, i = 0, sg_count;
> 
>               payload_sz = (hvpg_count * sizeof(u64) + @@ -1821,7 +1824,11
> @@ static enum scsi_qc_status storvsc_queuecommand(struct Scsi_Host *host,
>               payload->range.len = length;
>               payload->range.offset = offset_in_hvpg;
> 
> -             sg_count = scsi_dma_map(scmnd);
> +             if (dev->co_external_memory)
> +                     sg_count = scsi_sg_count(scmnd);

scsi_sg_count() returns unsigned int, sg_count can't be negative. The check for 
sg_count < 0 below becomes dead code. Add a comment to say this is expected 
behavior.

> +             else
> +                     sg_count = scsi_dma_map(scmnd);
> +
>               if (sg_count < 0) {
>                       ret = SCSI_MLQUEUE_DEVICE_BUSY;
>                       goto err_free_payload;
> @@ -1836,9 +1843,16 @@ static enum scsi_qc_status
> storvsc_queuecommand(struct Scsi_Host *host,
>                        * Such offsets are handled even on other than the first
>                        * sgl entry, provided they are a multiple of PAGE_SIZE.
>                        */
> -                     hvpfn = HVPFN_DOWN(sg_dma_address(sg));
> -                     hvpfns_to_add = HVPFN_UP(sg_dma_address(sg) +
> -                                              sg_dma_len(sg)) - hvpfn;
> +                     if (dev->co_external_memory) {
> +                             hvpgoff = HVPFN_DOWN(sg->offset);
> +                             hvpfn = page_to_hvpfn(sg_page(sg)) + hvpgoff;
> +                             hvpfns_to_add = HVPFN_UP(sg->offset
> + sg->length) -
> +                                                     hvpgoff;
> +                     } else {
> +                             hvpfn = HVPFN_DOWN(sg_dma_address(sg));
> +                             hvpfns_to_add =
> HVPFN_UP(sg_dma_address(sg) +
> +                                                      sg_dma_len(sg)) -
> hvpfn;
> +                     }
> 
>                       /*
>                        * Fill the next portion of the PFN array with @@ 
> -1860,7
> +1874,7 @@ static enum scsi_qc_status storvsc_queuecommand(struct
> Scsi_Host *host,
>       ret = storvsc_do_io(dev, cmd_request, smp_processor_id());
>       migrate_enable();
> 
> -     if (ret)
> +     if (ret && (!dev->co_external_memory))
>               scsi_dma_unmap(scmnd);
> 
>       if (ret == -EAGAIN) {
> diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index
> dfc516c1c719..bcb143766d6e 100644
> --- a/include/linux/hyperv.h
> +++ b/include/linux/hyperv.h
> @@ -1285,6 +1285,7 @@ struct hv_device {
> 
>       /* place holder to keep track of the dir for hv device in debugfs */
>       struct dentry *debug_dir;
> +     bool co_external_memory;

You don't need to introduce co_external_memory in hv_device, vmbus_channel 
already has co_external_memory. Is it possible that you can check the 
vmbus_channel->co_external_memory directly? If you can remove this,  you can 
reword this patch to " scsi: storvsc: Confidential VMBus for dynamic DMA 
transfers".

Thanks,
Long



Reply via email to