xref: /openbmc/linux/drivers/hv/hv_fcopy.c (revision 54e19d34)
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 
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;
743cace4a6SOlaf Hering 	hv_fcopy_onchannelcallback(channel);
753cace4a6SOlaf Hering }
763cace4a6SOlaf Hering 
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 
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 
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 
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
13201325476SK. Y. Srinivasan 	 * in 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
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 
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 
238b14d749aSHimadri Pandya 	vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 2, &recvlen,
23901325476SK. Y. Srinivasan 			 &requestid);
24001325476SK. Y. Srinivasan 	if (recvlen <= 0)
24101325476SK. Y. Srinivasan 		return;
24201325476SK. Y. Srinivasan 
24301325476SK. Y. Srinivasan 	icmsghdr = (struct icmsg_hdr *)&recv_buffer[
24401325476SK. Y. Srinivasan 			sizeof(struct vmbuspipe_hdr)];
24501325476SK. Y. Srinivasan 	if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) {
2461274a690SAlex Ng 		if (vmbus_prep_negotiate_resp(icmsghdr, recv_buffer,
247a1656454SAlex Ng 				fw_versions, FW_VER_COUNT,
248a1656454SAlex Ng 				fcopy_versions, FCOPY_VER_COUNT,
2491274a690SAlex Ng 				NULL, &fcopy_srv_version)) {
2501274a690SAlex Ng 
2511274a690SAlex Ng 			pr_info("FCopy IC version %d.%d\n",
2521274a690SAlex Ng 				fcopy_srv_version >> 16,
2531274a690SAlex Ng 				fcopy_srv_version & 0xFFFF);
2541274a690SAlex Ng 		}
25501325476SK. Y. Srinivasan 	} else {
25601325476SK. Y. Srinivasan 		fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[
25701325476SK. Y. Srinivasan 				sizeof(struct vmbuspipe_hdr) +
25801325476SK. Y. Srinivasan 				sizeof(struct icmsg_hdr)];
25901325476SK. Y. Srinivasan 
26001325476SK. Y. Srinivasan 		/*
26101325476SK. Y. Srinivasan 		 * Stash away this global state for completing the
26201325476SK. Y. Srinivasan 		 * transaction; note transactions are serialized.
26301325476SK. Y. Srinivasan 		 */
26401325476SK. Y. Srinivasan 
26501325476SK. Y. Srinivasan 		fcopy_transaction.recv_len = recvlen;
26601325476SK. Y. Srinivasan 		fcopy_transaction.recv_req_id = requestid;
26701325476SK. Y. Srinivasan 		fcopy_transaction.fcopy_msg = fcopy_msg;
26801325476SK. Y. Srinivasan 
2694c93ccccSVitaly Kuznetsov 		if (fcopy_transaction.state < HVUTIL_READY) {
2704c93ccccSVitaly Kuznetsov 			/* Userspace is not registered yet */
2714c93ccccSVitaly Kuznetsov 			fcopy_respond_to_host(HV_E_FAIL);
2724c93ccccSVitaly Kuznetsov 			return;
2734c93ccccSVitaly Kuznetsov 		}
2744c93ccccSVitaly Kuznetsov 		fcopy_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
2754c93ccccSVitaly Kuznetsov 
27601325476SK. Y. Srinivasan 		/*
27701325476SK. Y. Srinivasan 		 * Send the information to the user-level daemon.
27801325476SK. Y. Srinivasan 		 */
279c7e490fcSVitaly Kuznetsov 		schedule_work(&fcopy_send_work);
280c0b200cfSK. Y. Srinivasan 		schedule_delayed_work(&fcopy_timeout_work,
281c0b200cfSK. Y. Srinivasan 				      HV_UTIL_TIMEOUT * HZ);
28201325476SK. Y. Srinivasan 		return;
28301325476SK. Y. Srinivasan 	}
28401325476SK. Y. Srinivasan 	icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
28501325476SK. Y. Srinivasan 	vmbus_sendpacket(channel, recv_buffer, recvlen, requestid,
28601325476SK. Y. Srinivasan 			VM_PKT_DATA_INBAND, 0);
28701325476SK. Y. Srinivasan }
28801325476SK. Y. Srinivasan 
289c7e490fcSVitaly Kuznetsov /* Callback when data is received from userspace */
290c7e490fcSVitaly Kuznetsov static int fcopy_on_msg(void *msg, int len)
29101325476SK. Y. Srinivasan {
292c7e490fcSVitaly Kuznetsov 	int *val = (int *)msg;
29301325476SK. Y. Srinivasan 
294c7e490fcSVitaly Kuznetsov 	if (len != sizeof(int))
29501325476SK. Y. Srinivasan 		return -EINVAL;
29601325476SK. Y. Srinivasan 
297c7e490fcSVitaly Kuznetsov 	if (fcopy_transaction.state == HVUTIL_DEVICE_INIT)
298c7e490fcSVitaly Kuznetsov 		return fcopy_handle_handshake(*val);
29901325476SK. Y. Srinivasan 
3004c93ccccSVitaly Kuznetsov 	if (fcopy_transaction.state != HVUTIL_USERSPACE_REQ)
3014c93ccccSVitaly Kuznetsov 		return -EINVAL;
3024c93ccccSVitaly Kuznetsov 
30301325476SK. Y. Srinivasan 	/*
30401325476SK. Y. Srinivasan 	 * Complete the transaction by forwarding the result
30501325476SK. Y. Srinivasan 	 * to the host. But first, cancel the timeout.
30601325476SK. Y. Srinivasan 	 */
3074c93ccccSVitaly Kuznetsov 	if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
3084c93ccccSVitaly Kuznetsov 		fcopy_transaction.state = HVUTIL_USERSPACE_RECV;
309c7e490fcSVitaly Kuznetsov 		fcopy_respond_to_host(*val);
3103cace4a6SOlaf Hering 		hv_poll_channel(fcopy_transaction.recv_channel,
3113cace4a6SOlaf Hering 				fcopy_poll_wrapper);
312242f3122SVitaly Kuznetsov 	}
31301325476SK. Y. Srinivasan 
31401325476SK. Y. Srinivasan 	return 0;
31501325476SK. Y. Srinivasan }
31601325476SK. Y. Srinivasan 
317c7e490fcSVitaly Kuznetsov static void fcopy_on_reset(void)
31801325476SK. Y. Srinivasan {
31901325476SK. Y. Srinivasan 	/*
32001325476SK. Y. Srinivasan 	 * The daemon has exited; reset the state.
32101325476SK. Y. Srinivasan 	 */
3224c93ccccSVitaly Kuznetsov 	fcopy_transaction.state = HVUTIL_DEVICE_INIT;
323d9b16529SDexuan Cui 
324c7e490fcSVitaly Kuznetsov 	if (cancel_delayed_work_sync(&fcopy_timeout_work))
325d9b16529SDexuan Cui 		fcopy_respond_to_host(HV_E_FAIL);
326d9b16529SDexuan Cui }
32701325476SK. Y. Srinivasan 
32801325476SK. Y. Srinivasan int hv_fcopy_init(struct hv_util_service *srv)
32901325476SK. Y. Srinivasan {
33001325476SK. Y. Srinivasan 	recv_buffer = srv->recv_buffer;
331b9830d12SK. Y. Srinivasan 	fcopy_transaction.recv_channel = srv->channel;
33201325476SK. Y. Srinivasan 
33301325476SK. Y. Srinivasan 	/*
33401325476SK. Y. Srinivasan 	 * When this driver loads, the user level daemon that
33501325476SK. Y. Srinivasan 	 * processes the host requests may not yet be running.
33601325476SK. Y. Srinivasan 	 * Defer processing channel callbacks until the daemon
33701325476SK. Y. Srinivasan 	 * has registered.
33801325476SK. Y. Srinivasan 	 */
3394c93ccccSVitaly Kuznetsov 	fcopy_transaction.state = HVUTIL_DEVICE_INIT;
34001325476SK. Y. Srinivasan 
341c7e490fcSVitaly Kuznetsov 	hvt = hvutil_transport_init(fcopy_devname, 0, 0,
342c7e490fcSVitaly Kuznetsov 				    fcopy_on_msg, fcopy_on_reset);
343c7e490fcSVitaly Kuznetsov 	if (!hvt)
344c7e490fcSVitaly Kuznetsov 		return -EFAULT;
345c7e490fcSVitaly Kuznetsov 
346c7e490fcSVitaly Kuznetsov 	return 0;
34701325476SK. Y. Srinivasan }
34801325476SK. Y. Srinivasan 
34954e19d34SDexuan Cui static void hv_fcopy_cancel_work(void)
35054e19d34SDexuan Cui {
35154e19d34SDexuan Cui 	cancel_delayed_work_sync(&fcopy_timeout_work);
35254e19d34SDexuan Cui 	cancel_work_sync(&fcopy_send_work);
35354e19d34SDexuan Cui }
35454e19d34SDexuan Cui 
35554e19d34SDexuan Cui int hv_fcopy_pre_suspend(void)
35654e19d34SDexuan Cui {
35754e19d34SDexuan Cui 	struct vmbus_channel *channel = fcopy_transaction.recv_channel;
35854e19d34SDexuan Cui 	struct hv_fcopy_hdr *fcopy_msg;
35954e19d34SDexuan Cui 
36054e19d34SDexuan Cui 	/*
36154e19d34SDexuan Cui 	 * Fake a CANCEL_FCOPY message for the user space daemon in case the
36254e19d34SDexuan Cui 	 * daemon is in the middle of copying some file. It doesn't matter if
36354e19d34SDexuan Cui 	 * there is already a message pending to be delivered to the user
36454e19d34SDexuan Cui 	 * space since we force fcopy_transaction.state to be HVUTIL_READY, so
36554e19d34SDexuan Cui 	 * the user space daemon's write() will fail with EINVAL (see
36654e19d34SDexuan Cui 	 * fcopy_on_msg()), and the daemon will reset the device by closing
36754e19d34SDexuan Cui 	 * and re-opening it.
36854e19d34SDexuan Cui 	 */
36954e19d34SDexuan Cui 	fcopy_msg = kzalloc(sizeof(*fcopy_msg), GFP_KERNEL);
37054e19d34SDexuan Cui 	if (!fcopy_msg)
37154e19d34SDexuan Cui 		return -ENOMEM;
37254e19d34SDexuan Cui 
37354e19d34SDexuan Cui 	tasklet_disable(&channel->callback_event);
37454e19d34SDexuan Cui 
37554e19d34SDexuan Cui 	fcopy_msg->operation = CANCEL_FCOPY;
37654e19d34SDexuan Cui 
37754e19d34SDexuan Cui 	hv_fcopy_cancel_work();
37854e19d34SDexuan Cui 
37954e19d34SDexuan Cui 	/* We don't care about the return value. */
38054e19d34SDexuan Cui 	hvutil_transport_send(hvt, fcopy_msg, sizeof(*fcopy_msg), NULL);
38154e19d34SDexuan Cui 
38254e19d34SDexuan Cui 	kfree(fcopy_msg);
38354e19d34SDexuan Cui 
38454e19d34SDexuan Cui 	fcopy_transaction.state = HVUTIL_READY;
38554e19d34SDexuan Cui 
38654e19d34SDexuan Cui 	/* tasklet_enable() will be called in hv_fcopy_pre_resume(). */
38754e19d34SDexuan Cui 	return 0;
38854e19d34SDexuan Cui }
38954e19d34SDexuan Cui 
39054e19d34SDexuan Cui int hv_fcopy_pre_resume(void)
39154e19d34SDexuan Cui {
39254e19d34SDexuan Cui 	struct vmbus_channel *channel = fcopy_transaction.recv_channel;
39354e19d34SDexuan Cui 
39454e19d34SDexuan Cui 	tasklet_enable(&channel->callback_event);
39554e19d34SDexuan Cui 
39654e19d34SDexuan Cui 	return 0;
39754e19d34SDexuan Cui }
39854e19d34SDexuan Cui 
39901325476SK. Y. Srinivasan void hv_fcopy_deinit(void)
40001325476SK. Y. Srinivasan {
4014c93ccccSVitaly Kuznetsov 	fcopy_transaction.state = HVUTIL_DEVICE_DYING;
40254e19d34SDexuan Cui 
40354e19d34SDexuan Cui 	hv_fcopy_cancel_work();
40454e19d34SDexuan Cui 
405c7e490fcSVitaly Kuznetsov 	hvutil_transport_destroy(hvt);
40601325476SK. Y. Srinivasan }
407