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
netvsc 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 fucntion to allocate bounce buffer and copy data
from/to bounce buffer.
Signed-off-by: Tianyu Lan
---
drivers/scsi/storvsc_drv.c | 67 +-
1 file changed, 66 insertions(+), 1 deletion(-)
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 2e4fa77445fd..d271578b1811 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
@@ -414,6 +416,11 @@ static void storvsc_on_channel_callback(void *context);
#define STORVSC_IDE_MAX_TARGETS1
#define STORVSC_IDE_MAX_CHANNELS 1
+struct dma_range {
+ dma_addr_t dma;
+ u32 mapping_size;
+};
+
struct storvsc_cmd_request {
struct scsi_cmnd *cmd;
@@ -427,6 +434,8 @@ struct storvsc_cmd_request {
u32 payload_sz;
struct vstor_packet vstor_packet;
+ u32 hvpg_count;
+ struct dma_range *dma_range;
};
@@ -1236,6 +1245,7 @@ static void storvsc_on_channel_callback(void *context)
const struct vmpacket_descriptor *desc;
struct hv_device *device;
struct storvsc_device *stor_device;
+ int i;
if (channel->primary_channel != NULL)
device = channel->primary_channel->device_obj;
@@ -1249,6 +1259,8 @@ static void storvsc_on_channel_callback(void *context)
foreach_vmbus_pkt(desc, channel) {
void *packet = hv_pkt_data(desc);
struct storvsc_cmd_request *request;
+ enum dma_data_direction dir;
+ u32 attrs;
u64 cmd_rqst;
cmd_rqst = vmbus_request_addr(>requestor,
@@ -1261,6 +1273,22 @@ static void storvsc_on_channel_callback(void *context)
request = (struct storvsc_cmd_request *)(unsigned long)cmd_rqst;
+ if (request->vstor_packet.vm_srb.data_in == READ_TYPE)
+ dir = DMA_FROM_DEVICE;
+else
+ dir = DMA_TO_DEVICE;
+
+ if (request->dma_range) {
+ for (i = 0; i < request->hvpg_count; i++)
+ dma_unmap_page_attrs(>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, attrs);
+ kfree(request->dma_range);
+ }
+
if (request == _device->init_request ||
request == _device->reset_request) {
memcpy(>vstor_packet, packet,
@@ -1682,8 +1710,10 @@ static int storvsc_queuecommand(struct Scsi_Host *host,
struct scsi_cmnd *scmnd)
struct vmscsi_request *vm_srb;
struct scatterlist *cur_sgl;
struct vmbus_packet_mpb_array *payload;
+ enum dma_data_direction dir;
u32 payload_sz;
u32 length;
+ u32 attrs;
if (vmstor_proto_version <= VMSTOR_PROTO_VERSION_WIN8) {
/*
@@ -1722,14 +1752,17 @@ static int storvsc_queuecommand(struct Scsi_Host *host,
struct scsi_cmnd *scmnd)
case DMA_TO_DEVICE:
vm_srb->data_in = WRITE_TYPE;
vm_srb->win8_extension.srb_flags |= SRB_FLAGS_DATA_OUT;
+ dir = DMA_TO_DEVICE;
break;
case DMA_FROM_DEVICE:
vm_srb->data_in = READ_TYPE;
vm_srb->win8_extension.srb_flags |= SRB_FLAGS_DATA_IN;
+ dir = DMA_FROM_DEVICE;
break;
case DMA_NONE:
vm_srb->data_in = UNKNOWN_TYPE;
vm_srb->win8_extension.srb_flags |= SRB_FLAGS_NO_DATA_TRANSFER;
+ dir = DMA_NONE;
break;
default:
/*
@@ -1786,6 +1819,12 @@ static int storvsc_queuecommand(struct Scsi_Host *host,
struct scsi_cmnd *scmnd)
hvpgoff = sgl->offset >> HV_HYP_PAGE_SHIFT;
cur_sgl = sgl;
+
+ cmd_request->dma_range = kzalloc(sizeof(struct dma_range) *
hvpg_count,
+ GFP_ATOMIC);
+ if (!cmd_request->dma_range)
+ return -ENOMEM;
+
for (i = 0; i < hvpg_count; i++) {
/*
* 'i' is the