xref: /openbmc/linux/drivers/hv/hv_fcopy.c (revision 676576d1)
143aa3132SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
201325476SK. Y. Srinivasan /*
301325476SK. Y. Srinivasan  * An implementation of file copy service.
401325476SK. Y. Srinivasan  *
501325476SK. Y. Srinivasan  * Copyright (C) 2014, Microsoft, Inc.
601325476SK. Y. Srinivasan  *
701325476SK. Y. Srinivasan  * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
801325476SK. Y. Srinivasan  */
901325476SK. Y. Srinivasan 
1001325476SK. Y. Srinivasan #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1101325476SK. Y. Srinivasan 
1201325476SK. Y. Srinivasan #include <linux/nls.h>
1301325476SK. Y. Srinivasan #include <linux/workqueue.h>
1401325476SK. Y. Srinivasan #include <linux/hyperv.h>
1501325476SK. Y. Srinivasan #include <linux/sched.h>
16b14d749aSHimadri Pandya #include <asm/hyperv-tlfs.h>
1701325476SK. Y. Srinivasan 
1801325476SK. Y. Srinivasan #include "hyperv_vmbus.h"
19c7e490fcSVitaly Kuznetsov #include "hv_utils_transport.h"
2001325476SK. Y. Srinivasan 
2101325476SK. Y. Srinivasan #define WIN8_SRV_MAJOR		1
2201325476SK. Y. Srinivasan #define WIN8_SRV_MINOR		1
2301325476SK. Y. Srinivasan #define WIN8_SRV_VERSION	(WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
2401325476SK. Y. Srinivasan 
25a1656454SAlex Ng #define FCOPY_VER_COUNT 1
26a1656454SAlex Ng static const int fcopy_versions[] = {
27a1656454SAlex Ng 	WIN8_SRV_VERSION
28a1656454SAlex Ng };
29a1656454SAlex Ng 
30a1656454SAlex Ng #define FW_VER_COUNT 1
31a1656454SAlex Ng static const int fw_versions[] = {
32a1656454SAlex Ng 	UTIL_FW_VERSION
33a1656454SAlex Ng };
34a1656454SAlex Ng 
3501325476SK. Y. Srinivasan /*
3601325476SK. Y. Srinivasan  * Global state maintained for transaction that is being processed.
3701325476SK. Y. Srinivasan  * For a class of integration services, including the "file copy service",
3801325476SK. Y. Srinivasan  * the specified protocol is a "request/response" protocol which means that
3901325476SK. Y. Srinivasan  * there can only be single outstanding transaction from the host at any
4001325476SK. Y. Srinivasan  * given point in time. We use this to simplify memory management in this
4101325476SK. Y. Srinivasan  * driver - we cache and process only one message at a time.
4201325476SK. Y. Srinivasan  *
4301325476SK. Y. Srinivasan  * While the request/response protocol is guaranteed by the host, we further
4401325476SK. Y. Srinivasan  * ensure this by serializing packet processing in this driver - we do not
4501325476SK. Y. Srinivasan  * read additional packets from the VMBUs until the current packet is fully
4601325476SK. Y. Srinivasan  * handled.
4701325476SK. Y. Srinivasan  */
4801325476SK. Y. Srinivasan 
4901325476SK. Y. Srinivasan static struct {
504c93ccccSVitaly Kuznetsov 	int state;   /* hvutil_device_state */
5101325476SK. Y. Srinivasan 	int recv_len; /* number of bytes received. */
5201325476SK. Y. Srinivasan 	struct hv_fcopy_hdr  *fcopy_msg; /* current message */
5301325476SK. Y. Srinivasan 	struct vmbus_channel *recv_channel; /* chn we got the request */
5401325476SK. Y. Srinivasan 	u64 recv_req_id; /* request ID. */
5501325476SK. Y. Srinivasan } fcopy_transaction;
5601325476SK. Y. Srinivasan 
5701325476SK. Y. Srinivasan static void fcopy_respond_to_host(int error);
58c7e490fcSVitaly Kuznetsov static void fcopy_send_data(struct work_struct *dummy);
591d072339SVitaly Kuznetsov static void fcopy_timeout_func(struct work_struct *dummy);
601d072339SVitaly Kuznetsov static DECLARE_DELAYED_WORK(fcopy_timeout_work, fcopy_timeout_func);
61c7e490fcSVitaly Kuznetsov static DECLARE_WORK(fcopy_send_work, fcopy_send_data);
62c7e490fcSVitaly Kuznetsov static const char fcopy_devname[] = "vmbus/hv_fcopy";
6301325476SK. Y. Srinivasan static u8 *recv_buffer;
64c7e490fcSVitaly Kuznetsov static struct hvutil_transport *hvt;
65a4d1ee5bSVitaly Kuznetsov /*
66a4d1ee5bSVitaly Kuznetsov  * This state maintains the version number registered by the daemon.
67a4d1ee5bSVitaly Kuznetsov  */
68a4d1ee5bSVitaly Kuznetsov static int dm_reg_value;
6901325476SK. Y. Srinivasan 
fcopy_poll_wrapper(void * channel)703cace4a6SOlaf Hering static void fcopy_poll_wrapper(void *channel)
713cace4a6SOlaf Hering {
723cace4a6SOlaf Hering 	/* Transaction is finished, reset the state here to avoid races. */
733cace4a6SOlaf Hering 	fcopy_transaction.state = HVUTIL_READY;
74238d2ed8SAndrea Parri (Microsoft) 	tasklet_schedule(&((struct vmbus_channel *)channel)->callback_event);
753cace4a6SOlaf Hering }
763cace4a6SOlaf Hering 
fcopy_timeout_func(struct work_struct * dummy)771d072339SVitaly Kuznetsov static void fcopy_timeout_func(struct work_struct *dummy)
7801325476SK. Y. Srinivasan {
7901325476SK. Y. Srinivasan 	/*
8001325476SK. Y. Srinivasan 	 * If the timer fires, the user-mode component has not responded;
8101325476SK. Y. Srinivasan 	 * process the pending transaction.
8201325476SK. Y. Srinivasan 	 */
8301325476SK. Y. Srinivasan 	fcopy_respond_to_host(HV_E_FAIL);
843cace4a6SOlaf Hering 	hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
8501325476SK. Y. Srinivasan }
8601325476SK. Y. Srinivasan 
fcopy_register_done(void)87e0fa3e5eSVitaly Kuznetsov static void fcopy_register_done(void)
88e0fa3e5eSVitaly Kuznetsov {
89e0fa3e5eSVitaly Kuznetsov 	pr_debug("FCP: userspace daemon registered\n");
90e0fa3e5eSVitaly Kuznetsov 	hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
91e0fa3e5eSVitaly Kuznetsov }
92e0fa3e5eSVitaly Kuznetsov 
fcopy_handle_handshake(u32 version)9301325476SK. Y. Srinivasan static int fcopy_handle_handshake(u32 version)
9401325476SK. Y. Srinivasan {
95a4d1ee5bSVitaly Kuznetsov 	u32 our_ver = FCOPY_CURRENT_VERSION;
96a4d1ee5bSVitaly Kuznetsov 
9701325476SK. Y. Srinivasan 	switch (version) {
98a4d1ee5bSVitaly Kuznetsov 	case FCOPY_VERSION_0:
99a4d1ee5bSVitaly Kuznetsov 		/* Daemon doesn't expect us to reply */
100a4d1ee5bSVitaly Kuznetsov 		dm_reg_value = version;
101a4d1ee5bSVitaly Kuznetsov 		break;
102a4d1ee5bSVitaly Kuznetsov 	case FCOPY_VERSION_1:
103a4d1ee5bSVitaly Kuznetsov 		/* Daemon expects us to reply with our own version */
104e0fa3e5eSVitaly Kuznetsov 		if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver),
105e0fa3e5eSVitaly Kuznetsov 		    fcopy_register_done))
106a4d1ee5bSVitaly Kuznetsov 			return -EFAULT;
107a4d1ee5bSVitaly Kuznetsov 		dm_reg_value = version;
10801325476SK. Y. Srinivasan 		break;
10901325476SK. Y. Srinivasan 	default:
11001325476SK. Y. Srinivasan 		/*
11101325476SK. Y. Srinivasan 		 * For now we will fail the registration.
11201325476SK. Y. Srinivasan 		 * If and when we have multiple versions to
11301325476SK. Y. Srinivasan 		 * deal with, we will be backward compatible.
11401325476SK. Y. Srinivasan 		 * We will add this code when needed.
11501325476SK. Y. Srinivasan 		 */
11601325476SK. Y. Srinivasan 		return -EINVAL;
11701325476SK. Y. Srinivasan 	}
118e0fa3e5eSVitaly Kuznetsov 	pr_debug("FCP: userspace daemon ver. %d connected\n", version);
11901325476SK. Y. Srinivasan 	return 0;
12001325476SK. Y. Srinivasan }
12101325476SK. Y. Srinivasan 
fcopy_send_data(struct work_struct * dummy)122c7e490fcSVitaly Kuznetsov static void fcopy_send_data(struct work_struct *dummy)
12301325476SK. Y. Srinivasan {
12425ef06feSVitaly Kuznetsov 	struct hv_start_fcopy *smsg_out = NULL;
12501325476SK. Y. Srinivasan 	int operation = fcopy_transaction.fcopy_msg->operation;
12601325476SK. Y. Srinivasan 	struct hv_start_fcopy *smsg_in;
127c7e490fcSVitaly Kuznetsov 	void *out_src;
128c7e490fcSVitaly Kuznetsov 	int rc, out_len;
12901325476SK. Y. Srinivasan 
13001325476SK. Y. Srinivasan 	/*
13101325476SK. Y. Srinivasan 	 * The  strings sent from the host are encoded in
132*676576d1SShaomin Deng 	 * utf16; convert it to utf8 strings.
13301325476SK. Y. Srinivasan 	 * The host assures us that the utf16 strings will not exceed
13401325476SK. Y. Srinivasan 	 * the max lengths specified. We will however, reserve room
13501325476SK. Y. Srinivasan 	 * for the string terminating character - in the utf16s_utf8s()
13601325476SK. Y. Srinivasan 	 * function we limit the size of the buffer where the converted
13701325476SK. Y. Srinivasan 	 * string is placed to W_MAX_PATH -1 to guarantee
13801325476SK. Y. Srinivasan 	 * that the strings can be properly terminated!
13901325476SK. Y. Srinivasan 	 */
14001325476SK. Y. Srinivasan 
14101325476SK. Y. Srinivasan 	switch (operation) {
14201325476SK. Y. Srinivasan 	case START_FILE_COPY:
143c7e490fcSVitaly Kuznetsov 		out_len = sizeof(struct hv_start_fcopy);
14425ef06feSVitaly Kuznetsov 		smsg_out = kzalloc(sizeof(*smsg_out), GFP_KERNEL);
14525ef06feSVitaly Kuznetsov 		if (!smsg_out)
14625ef06feSVitaly Kuznetsov 			return;
14725ef06feSVitaly Kuznetsov 
14825ef06feSVitaly Kuznetsov 		smsg_out->hdr.operation = operation;
14901325476SK. Y. Srinivasan 		smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg;
15001325476SK. Y. Srinivasan 
15101325476SK. Y. Srinivasan 		utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH,
15201325476SK. Y. Srinivasan 				UTF16_LITTLE_ENDIAN,
15325ef06feSVitaly Kuznetsov 				(__u8 *)&smsg_out->file_name, W_MAX_PATH - 1);
15401325476SK. Y. Srinivasan 
15501325476SK. Y. Srinivasan 		utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH,
15601325476SK. Y. Srinivasan 				UTF16_LITTLE_ENDIAN,
15725ef06feSVitaly Kuznetsov 				(__u8 *)&smsg_out->path_name, W_MAX_PATH - 1);
15801325476SK. Y. Srinivasan 
15925ef06feSVitaly Kuznetsov 		smsg_out->copy_flags = smsg_in->copy_flags;
16025ef06feSVitaly Kuznetsov 		smsg_out->file_size = smsg_in->file_size;
16125ef06feSVitaly Kuznetsov 		out_src = smsg_out;
16201325476SK. Y. Srinivasan 		break;
16301325476SK. Y. Srinivasan 
164549e658aSOlaf Hering 	case WRITE_TO_FILE:
165549e658aSOlaf Hering 		out_src = fcopy_transaction.fcopy_msg;
166549e658aSOlaf Hering 		out_len = sizeof(struct hv_do_fcopy);
167549e658aSOlaf Hering 		break;
16801325476SK. Y. Srinivasan 	default:
169c7e490fcSVitaly Kuznetsov 		out_src = fcopy_transaction.fcopy_msg;
170c7e490fcSVitaly Kuznetsov 		out_len = fcopy_transaction.recv_len;
17101325476SK. Y. Srinivasan 		break;
17201325476SK. Y. Srinivasan 	}
173c7e490fcSVitaly Kuznetsov 
174c7e490fcSVitaly Kuznetsov 	fcopy_transaction.state = HVUTIL_USERSPACE_REQ;
175e0fa3e5eSVitaly Kuznetsov 	rc = hvutil_transport_send(hvt, out_src, out_len, NULL);
176c7e490fcSVitaly Kuznetsov 	if (rc) {
177c7e490fcSVitaly Kuznetsov 		pr_debug("FCP: failed to communicate to the daemon: %d\n", rc);
178c7e490fcSVitaly Kuznetsov 		if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
179c7e490fcSVitaly Kuznetsov 			fcopy_respond_to_host(HV_E_FAIL);
180c7e490fcSVitaly Kuznetsov 			fcopy_transaction.state = HVUTIL_READY;
181c7e490fcSVitaly Kuznetsov 		}
182c7e490fcSVitaly Kuznetsov 	}
18325ef06feSVitaly Kuznetsov 	kfree(smsg_out);
18401325476SK. Y. Srinivasan }
18501325476SK. Y. Srinivasan 
18601325476SK. Y. Srinivasan /*
18701325476SK. Y. Srinivasan  * Send a response back to the host.
18801325476SK. Y. Srinivasan  */
18901325476SK. Y. Srinivasan 
19001325476SK. Y. Srinivasan static void
fcopy_respond_to_host(int error)19101325476SK. Y. Srinivasan fcopy_respond_to_host(int error)
19201325476SK. Y. Srinivasan {
19301325476SK. Y. Srinivasan 	struct icmsg_hdr *icmsghdr;
19401325476SK. Y. Srinivasan 	u32 buf_len;
19501325476SK. Y. Srinivasan 	struct vmbus_channel *channel;
19601325476SK. Y. Srinivasan 	u64 req_id;
19701325476SK. Y. Srinivasan 
19801325476SK. Y. Srinivasan 	/*
19901325476SK. Y. Srinivasan 	 * Copy the global state for completing the transaction. Note that
20001325476SK. Y. Srinivasan 	 * only one transaction can be active at a time. This is guaranteed
20101325476SK. Y. Srinivasan 	 * by the file copy protocol implemented by the host. Furthermore,
20201325476SK. Y. Srinivasan 	 * the "transaction active" state we maintain ensures that there can
20301325476SK. Y. Srinivasan 	 * only be one active transaction at a time.
20401325476SK. Y. Srinivasan 	 */
20501325476SK. Y. Srinivasan 
20601325476SK. Y. Srinivasan 	buf_len = fcopy_transaction.recv_len;
20701325476SK. Y. Srinivasan 	channel = fcopy_transaction.recv_channel;
20801325476SK. Y. Srinivasan 	req_id = fcopy_transaction.recv_req_id;
20901325476SK. Y. Srinivasan 
21001325476SK. Y. Srinivasan 	icmsghdr = (struct icmsg_hdr *)
21101325476SK. Y. Srinivasan 			&recv_buffer[sizeof(struct vmbuspipe_hdr)];
21201325476SK. Y. Srinivasan 
21301325476SK. Y. Srinivasan 	if (channel->onchannel_callback == NULL)
21401325476SK. Y. Srinivasan 		/*
21501325476SK. Y. Srinivasan 		 * We have raced with util driver being unloaded;
21601325476SK. Y. Srinivasan 		 * silently return.
21701325476SK. Y. Srinivasan 		 */
21801325476SK. Y. Srinivasan 		return;
21901325476SK. Y. Srinivasan 
22001325476SK. Y. Srinivasan 	icmsghdr->status = error;
22101325476SK. Y. Srinivasan 	icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
22201325476SK. Y. Srinivasan 	vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
22301325476SK. Y. Srinivasan 				VM_PKT_DATA_INBAND, 0);
22401325476SK. Y. Srinivasan }
22501325476SK. Y. Srinivasan 
hv_fcopy_onchannelcallback(void * context)22601325476SK. Y. Srinivasan void hv_fcopy_onchannelcallback(void *context)
22701325476SK. Y. Srinivasan {
22801325476SK. Y. Srinivasan 	struct vmbus_channel *channel = context;
22901325476SK. Y. Srinivasan 	u32 recvlen;
23001325476SK. Y. Srinivasan 	u64 requestid;
23101325476SK. Y. Srinivasan 	struct hv_fcopy_hdr *fcopy_msg;
23201325476SK. Y. Srinivasan 	struct icmsg_hdr *icmsghdr;
23301325476SK. Y. Srinivasan 	int fcopy_srv_version;
23401325476SK. Y. Srinivasan 
2353cace4a6SOlaf Hering 	if (fcopy_transaction.state > HVUTIL_READY)
23601325476SK. Y. Srinivasan 		return;
23701325476SK. Y. Srinivasan 
23806caa778SAndres Beltran 	if (vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 2, &recvlen, &requestid)) {
23906caa778SAndres Beltran 		pr_err_ratelimited("Fcopy request received. Could not read into recv buf\n");
24001325476SK. Y. Srinivasan 		return;
24106caa778SAndres Beltran 	}
24206caa778SAndres Beltran 
24306caa778SAndres Beltran 	if (!recvlen)
24406caa778SAndres Beltran 		return;
24506caa778SAndres Beltran 
24606caa778SAndres Beltran 	/* Ensure recvlen is big enough to read header data */
24706caa778SAndres Beltran 	if (recvlen < ICMSG_HDR) {
24806caa778SAndres Beltran 		pr_err_ratelimited("Fcopy request received. Packet length too small: %d\n",
24906caa778SAndres Beltran 				   recvlen);
25006caa778SAndres Beltran 		return;
25106caa778SAndres Beltran 	}
25201325476SK. Y. Srinivasan 
25301325476SK. Y. Srinivasan 	icmsghdr = (struct icmsg_hdr *)&recv_buffer[
25401325476SK. Y. Srinivasan 			sizeof(struct vmbuspipe_hdr)];
25506caa778SAndres Beltran 
25601325476SK. Y. Srinivasan 	if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) {
25706caa778SAndres Beltran 		if (vmbus_prep_negotiate_resp(icmsghdr,
25806caa778SAndres Beltran 				recv_buffer, recvlen,
259a1656454SAlex Ng 				fw_versions, FW_VER_COUNT,
260a1656454SAlex Ng 				fcopy_versions, FCOPY_VER_COUNT,
2611274a690SAlex Ng 				NULL, &fcopy_srv_version)) {
2621274a690SAlex Ng 
2631274a690SAlex Ng 			pr_info("FCopy IC version %d.%d\n",
2641274a690SAlex Ng 				fcopy_srv_version >> 16,
2651274a690SAlex Ng 				fcopy_srv_version & 0xFFFF);
2661274a690SAlex Ng 		}
26706caa778SAndres Beltran 	} else if (icmsghdr->icmsgtype == ICMSGTYPE_FCOPY) {
26806caa778SAndres Beltran 		/* Ensure recvlen is big enough to contain hv_fcopy_hdr */
26906caa778SAndres Beltran 		if (recvlen < ICMSG_HDR + sizeof(struct hv_fcopy_hdr)) {
27006caa778SAndres Beltran 			pr_err_ratelimited("Invalid Fcopy hdr. Packet length too small: %u\n",
27106caa778SAndres Beltran 					   recvlen);
27206caa778SAndres Beltran 			return;
27306caa778SAndres Beltran 		}
27406caa778SAndres Beltran 		fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[ICMSG_HDR];
27501325476SK. Y. Srinivasan 
27601325476SK. Y. Srinivasan 		/*
27701325476SK. Y. Srinivasan 		 * Stash away this global state for completing the
27801325476SK. Y. Srinivasan 		 * transaction; note transactions are serialized.
27901325476SK. Y. Srinivasan 		 */
28001325476SK. Y. Srinivasan 
28101325476SK. Y. Srinivasan 		fcopy_transaction.recv_len = recvlen;
28201325476SK. Y. Srinivasan 		fcopy_transaction.recv_req_id = requestid;
28301325476SK. Y. Srinivasan 		fcopy_transaction.fcopy_msg = fcopy_msg;
28401325476SK. Y. Srinivasan 
2854c93ccccSVitaly Kuznetsov 		if (fcopy_transaction.state < HVUTIL_READY) {
2864c93ccccSVitaly Kuznetsov 			/* Userspace is not registered yet */
2874c93ccccSVitaly Kuznetsov 			fcopy_respond_to_host(HV_E_FAIL);
2884c93ccccSVitaly Kuznetsov 			return;
2894c93ccccSVitaly Kuznetsov 		}
2904c93ccccSVitaly Kuznetsov 		fcopy_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
2914c93ccccSVitaly Kuznetsov 
29201325476SK. Y. Srinivasan 		/*
29301325476SK. Y. Srinivasan 		 * Send the information to the user-level daemon.
29401325476SK. Y. Srinivasan 		 */
295c7e490fcSVitaly Kuznetsov 		schedule_work(&fcopy_send_work);
296c0b200cfSK. Y. Srinivasan 		schedule_delayed_work(&fcopy_timeout_work,
297c0b200cfSK. Y. Srinivasan 				      HV_UTIL_TIMEOUT * HZ);
29801325476SK. Y. Srinivasan 		return;
29906caa778SAndres Beltran 	} else {
30006caa778SAndres Beltran 		pr_err_ratelimited("Fcopy request received. Invalid msg type: %d\n",
30106caa778SAndres Beltran 				   icmsghdr->icmsgtype);
30206caa778SAndres Beltran 		return;
30301325476SK. Y. Srinivasan 	}
30401325476SK. Y. Srinivasan 	icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
30501325476SK. Y. Srinivasan 	vmbus_sendpacket(channel, recv_buffer, recvlen, requestid,
30601325476SK. Y. Srinivasan 			VM_PKT_DATA_INBAND, 0);
30701325476SK. Y. Srinivasan }
30801325476SK. Y. Srinivasan 
309c7e490fcSVitaly Kuznetsov /* Callback when data is received from userspace */
fcopy_on_msg(void * msg,int len)310c7e490fcSVitaly Kuznetsov static int fcopy_on_msg(void *msg, int len)
31101325476SK. Y. Srinivasan {
312c7e490fcSVitaly Kuznetsov 	int *val = (int *)msg;
31301325476SK. Y. Srinivasan 
314c7e490fcSVitaly Kuznetsov 	if (len != sizeof(int))
31501325476SK. Y. Srinivasan 		return -EINVAL;
31601325476SK. Y. Srinivasan 
317c7e490fcSVitaly Kuznetsov 	if (fcopy_transaction.state == HVUTIL_DEVICE_INIT)
318c7e490fcSVitaly Kuznetsov 		return fcopy_handle_handshake(*val);
31901325476SK. Y. Srinivasan 
3204c93ccccSVitaly Kuznetsov 	if (fcopy_transaction.state != HVUTIL_USERSPACE_REQ)
3214c93ccccSVitaly Kuznetsov 		return -EINVAL;
3224c93ccccSVitaly Kuznetsov 
32301325476SK. Y. Srinivasan 	/*
32401325476SK. Y. Srinivasan 	 * Complete the transaction by forwarding the result
32501325476SK. Y. Srinivasan 	 * to the host. But first, cancel the timeout.
32601325476SK. Y. Srinivasan 	 */
3274c93ccccSVitaly Kuznetsov 	if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
3284c93ccccSVitaly Kuznetsov 		fcopy_transaction.state = HVUTIL_USERSPACE_RECV;
329c7e490fcSVitaly Kuznetsov 		fcopy_respond_to_host(*val);
3303cace4a6SOlaf Hering 		hv_poll_channel(fcopy_transaction.recv_channel,
3313cace4a6SOlaf Hering 				fcopy_poll_wrapper);
332242f3122SVitaly Kuznetsov 	}
33301325476SK. Y. Srinivasan 
33401325476SK. Y. Srinivasan 	return 0;
33501325476SK. Y. Srinivasan }
33601325476SK. Y. Srinivasan 
fcopy_on_reset(void)337c7e490fcSVitaly Kuznetsov static void fcopy_on_reset(void)
33801325476SK. Y. Srinivasan {
33901325476SK. Y. Srinivasan 	/*
34001325476SK. Y. Srinivasan 	 * The daemon has exited; reset the state.
34101325476SK. Y. Srinivasan 	 */
3424c93ccccSVitaly Kuznetsov 	fcopy_transaction.state = HVUTIL_DEVICE_INIT;
343d9b16529SDexuan Cui 
344c7e490fcSVitaly Kuznetsov 	if (cancel_delayed_work_sync(&fcopy_timeout_work))
345d9b16529SDexuan Cui 		fcopy_respond_to_host(HV_E_FAIL);
346d9b16529SDexuan Cui }
34701325476SK. Y. Srinivasan 
hv_fcopy_init(struct hv_util_service * srv)34801325476SK. Y. Srinivasan int hv_fcopy_init(struct hv_util_service *srv)
34901325476SK. Y. Srinivasan {
35001325476SK. Y. Srinivasan 	recv_buffer = srv->recv_buffer;
351b9830d12SK. Y. Srinivasan 	fcopy_transaction.recv_channel = srv->channel;
352adae1e93SAndres Beltran 	fcopy_transaction.recv_channel->max_pkt_size = HV_HYP_PAGE_SIZE * 2;
35301325476SK. Y. Srinivasan 
35401325476SK. Y. Srinivasan 	/*
35501325476SK. Y. Srinivasan 	 * When this driver loads, the user level daemon that
35601325476SK. Y. Srinivasan 	 * processes the host requests may not yet be running.
35701325476SK. Y. Srinivasan 	 * Defer processing channel callbacks until the daemon
35801325476SK. Y. Srinivasan 	 * has registered.
35901325476SK. Y. Srinivasan 	 */
3604c93ccccSVitaly Kuznetsov 	fcopy_transaction.state = HVUTIL_DEVICE_INIT;
36101325476SK. Y. Srinivasan 
362c7e490fcSVitaly Kuznetsov 	hvt = hvutil_transport_init(fcopy_devname, 0, 0,
363c7e490fcSVitaly Kuznetsov 				    fcopy_on_msg, fcopy_on_reset);
364c7e490fcSVitaly Kuznetsov 	if (!hvt)
365c7e490fcSVitaly Kuznetsov 		return -EFAULT;
366c7e490fcSVitaly Kuznetsov 
367c7e490fcSVitaly Kuznetsov 	return 0;
36801325476SK. Y. Srinivasan }
36901325476SK. Y. Srinivasan 
hv_fcopy_cancel_work(void)37054e19d34SDexuan Cui static void hv_fcopy_cancel_work(void)
37154e19d34SDexuan Cui {
37254e19d34SDexuan Cui 	cancel_delayed_work_sync(&fcopy_timeout_work);
37354e19d34SDexuan Cui 	cancel_work_sync(&fcopy_send_work);
37454e19d34SDexuan Cui }
37554e19d34SDexuan Cui 
hv_fcopy_pre_suspend(void)37654e19d34SDexuan Cui int hv_fcopy_pre_suspend(void)
37754e19d34SDexuan Cui {
37854e19d34SDexuan Cui 	struct vmbus_channel *channel = fcopy_transaction.recv_channel;
37954e19d34SDexuan Cui 	struct hv_fcopy_hdr *fcopy_msg;
38054e19d34SDexuan Cui 
38154e19d34SDexuan Cui 	/*
38254e19d34SDexuan Cui 	 * Fake a CANCEL_FCOPY message for the user space daemon in case the
38354e19d34SDexuan Cui 	 * daemon is in the middle of copying some file. It doesn't matter if
38454e19d34SDexuan Cui 	 * there is already a message pending to be delivered to the user
38554e19d34SDexuan Cui 	 * space since we force fcopy_transaction.state to be HVUTIL_READY, so
38654e19d34SDexuan Cui 	 * the user space daemon's write() will fail with EINVAL (see
38754e19d34SDexuan Cui 	 * fcopy_on_msg()), and the daemon will reset the device by closing
38854e19d34SDexuan Cui 	 * and re-opening it.
38954e19d34SDexuan Cui 	 */
39054e19d34SDexuan Cui 	fcopy_msg = kzalloc(sizeof(*fcopy_msg), GFP_KERNEL);
39154e19d34SDexuan Cui 	if (!fcopy_msg)
39254e19d34SDexuan Cui 		return -ENOMEM;
39354e19d34SDexuan Cui 
39454e19d34SDexuan Cui 	tasklet_disable(&channel->callback_event);
39554e19d34SDexuan Cui 
39654e19d34SDexuan Cui 	fcopy_msg->operation = CANCEL_FCOPY;
39754e19d34SDexuan Cui 
39854e19d34SDexuan Cui 	hv_fcopy_cancel_work();
39954e19d34SDexuan Cui 
40054e19d34SDexuan Cui 	/* We don't care about the return value. */
40154e19d34SDexuan Cui 	hvutil_transport_send(hvt, fcopy_msg, sizeof(*fcopy_msg), NULL);
40254e19d34SDexuan Cui 
40354e19d34SDexuan Cui 	kfree(fcopy_msg);
40454e19d34SDexuan Cui 
40554e19d34SDexuan Cui 	fcopy_transaction.state = HVUTIL_READY;
40654e19d34SDexuan Cui 
40754e19d34SDexuan Cui 	/* tasklet_enable() will be called in hv_fcopy_pre_resume(). */
40854e19d34SDexuan Cui 	return 0;
40954e19d34SDexuan Cui }
41054e19d34SDexuan Cui 
hv_fcopy_pre_resume(void)41154e19d34SDexuan Cui int hv_fcopy_pre_resume(void)
41254e19d34SDexuan Cui {
41354e19d34SDexuan Cui 	struct vmbus_channel *channel = fcopy_transaction.recv_channel;
41454e19d34SDexuan Cui 
41554e19d34SDexuan Cui 	tasklet_enable(&channel->callback_event);
41654e19d34SDexuan Cui 
41754e19d34SDexuan Cui 	return 0;
41854e19d34SDexuan Cui }
41954e19d34SDexuan Cui 
hv_fcopy_deinit(void)42001325476SK. Y. Srinivasan void hv_fcopy_deinit(void)
42101325476SK. Y. Srinivasan {
4224c93ccccSVitaly Kuznetsov 	fcopy_transaction.state = HVUTIL_DEVICE_DYING;
42354e19d34SDexuan Cui 
42454e19d34SDexuan Cui 	hv_fcopy_cancel_work();
42554e19d34SDexuan Cui 
426c7e490fcSVitaly Kuznetsov 	hvutil_transport_destroy(hvt);
42701325476SK. Y. Srinivasan }
428