From: Tianyu Lan
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
---
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
#include
#include
+#include
+#include
#include
#include
#include
@@ -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,
+
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(>device,
+pfn_to_page(hvpfn++),
+offset_in_hvpg, size,
+
scmnd->sc_data_direction);
+ if (dma_mapping_error(>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;
+