On Thu, May 14, 2026 at 2:30 AM Long Li <[email protected]> wrote:
>
> > 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.
>

Hi Long:
     Thanks for your review. Nice catch and will update.

> > +             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".
>

Good idea. Will update in the next version.

-- 
Thanks
Tianyu Lan

Reply via email to