162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * An implementation of file copy service.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2014, Microsoft, Inc.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/nls.h>
1362306a36Sopenharmony_ci#include <linux/workqueue.h>
1462306a36Sopenharmony_ci#include <linux/hyperv.h>
1562306a36Sopenharmony_ci#include <linux/sched.h>
1662306a36Sopenharmony_ci#include <asm/hyperv-tlfs.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "hyperv_vmbus.h"
1962306a36Sopenharmony_ci#include "hv_utils_transport.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define WIN8_SRV_MAJOR		1
2262306a36Sopenharmony_ci#define WIN8_SRV_MINOR		1
2362306a36Sopenharmony_ci#define WIN8_SRV_VERSION	(WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define FCOPY_VER_COUNT 1
2662306a36Sopenharmony_cistatic const int fcopy_versions[] = {
2762306a36Sopenharmony_ci	WIN8_SRV_VERSION
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define FW_VER_COUNT 1
3162306a36Sopenharmony_cistatic const int fw_versions[] = {
3262306a36Sopenharmony_ci	UTIL_FW_VERSION
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci * Global state maintained for transaction that is being processed.
3762306a36Sopenharmony_ci * For a class of integration services, including the "file copy service",
3862306a36Sopenharmony_ci * the specified protocol is a "request/response" protocol which means that
3962306a36Sopenharmony_ci * there can only be single outstanding transaction from the host at any
4062306a36Sopenharmony_ci * given point in time. We use this to simplify memory management in this
4162306a36Sopenharmony_ci * driver - we cache and process only one message at a time.
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * While the request/response protocol is guaranteed by the host, we further
4462306a36Sopenharmony_ci * ensure this by serializing packet processing in this driver - we do not
4562306a36Sopenharmony_ci * read additional packets from the VMBUs until the current packet is fully
4662306a36Sopenharmony_ci * handled.
4762306a36Sopenharmony_ci */
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic struct {
5062306a36Sopenharmony_ci	int state;   /* hvutil_device_state */
5162306a36Sopenharmony_ci	int recv_len; /* number of bytes received. */
5262306a36Sopenharmony_ci	struct hv_fcopy_hdr  *fcopy_msg; /* current message */
5362306a36Sopenharmony_ci	struct vmbus_channel *recv_channel; /* chn we got the request */
5462306a36Sopenharmony_ci	u64 recv_req_id; /* request ID. */
5562306a36Sopenharmony_ci} fcopy_transaction;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic void fcopy_respond_to_host(int error);
5862306a36Sopenharmony_cistatic void fcopy_send_data(struct work_struct *dummy);
5962306a36Sopenharmony_cistatic void fcopy_timeout_func(struct work_struct *dummy);
6062306a36Sopenharmony_cistatic DECLARE_DELAYED_WORK(fcopy_timeout_work, fcopy_timeout_func);
6162306a36Sopenharmony_cistatic DECLARE_WORK(fcopy_send_work, fcopy_send_data);
6262306a36Sopenharmony_cistatic const char fcopy_devname[] = "vmbus/hv_fcopy";
6362306a36Sopenharmony_cistatic u8 *recv_buffer;
6462306a36Sopenharmony_cistatic struct hvutil_transport *hvt;
6562306a36Sopenharmony_ci/*
6662306a36Sopenharmony_ci * This state maintains the version number registered by the daemon.
6762306a36Sopenharmony_ci */
6862306a36Sopenharmony_cistatic int dm_reg_value;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic void fcopy_poll_wrapper(void *channel)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	/* Transaction is finished, reset the state here to avoid races. */
7362306a36Sopenharmony_ci	fcopy_transaction.state = HVUTIL_READY;
7462306a36Sopenharmony_ci	tasklet_schedule(&((struct vmbus_channel *)channel)->callback_event);
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic void fcopy_timeout_func(struct work_struct *dummy)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	/*
8062306a36Sopenharmony_ci	 * If the timer fires, the user-mode component has not responded;
8162306a36Sopenharmony_ci	 * process the pending transaction.
8262306a36Sopenharmony_ci	 */
8362306a36Sopenharmony_ci	fcopy_respond_to_host(HV_E_FAIL);
8462306a36Sopenharmony_ci	hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic void fcopy_register_done(void)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	pr_debug("FCP: userspace daemon registered\n");
9062306a36Sopenharmony_ci	hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic int fcopy_handle_handshake(u32 version)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	u32 our_ver = FCOPY_CURRENT_VERSION;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	switch (version) {
9862306a36Sopenharmony_ci	case FCOPY_VERSION_0:
9962306a36Sopenharmony_ci		/* Daemon doesn't expect us to reply */
10062306a36Sopenharmony_ci		dm_reg_value = version;
10162306a36Sopenharmony_ci		break;
10262306a36Sopenharmony_ci	case FCOPY_VERSION_1:
10362306a36Sopenharmony_ci		/* Daemon expects us to reply with our own version */
10462306a36Sopenharmony_ci		if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver),
10562306a36Sopenharmony_ci		    fcopy_register_done))
10662306a36Sopenharmony_ci			return -EFAULT;
10762306a36Sopenharmony_ci		dm_reg_value = version;
10862306a36Sopenharmony_ci		break;
10962306a36Sopenharmony_ci	default:
11062306a36Sopenharmony_ci		/*
11162306a36Sopenharmony_ci		 * For now we will fail the registration.
11262306a36Sopenharmony_ci		 * If and when we have multiple versions to
11362306a36Sopenharmony_ci		 * deal with, we will be backward compatible.
11462306a36Sopenharmony_ci		 * We will add this code when needed.
11562306a36Sopenharmony_ci		 */
11662306a36Sopenharmony_ci		return -EINVAL;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci	pr_debug("FCP: userspace daemon ver. %d connected\n", version);
11962306a36Sopenharmony_ci	return 0;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic void fcopy_send_data(struct work_struct *dummy)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	struct hv_start_fcopy *smsg_out = NULL;
12562306a36Sopenharmony_ci	int operation = fcopy_transaction.fcopy_msg->operation;
12662306a36Sopenharmony_ci	struct hv_start_fcopy *smsg_in;
12762306a36Sopenharmony_ci	void *out_src;
12862306a36Sopenharmony_ci	int rc, out_len;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/*
13162306a36Sopenharmony_ci	 * The  strings sent from the host are encoded in
13262306a36Sopenharmony_ci	 * utf16; convert it to utf8 strings.
13362306a36Sopenharmony_ci	 * The host assures us that the utf16 strings will not exceed
13462306a36Sopenharmony_ci	 * the max lengths specified. We will however, reserve room
13562306a36Sopenharmony_ci	 * for the string terminating character - in the utf16s_utf8s()
13662306a36Sopenharmony_ci	 * function we limit the size of the buffer where the converted
13762306a36Sopenharmony_ci	 * string is placed to W_MAX_PATH -1 to guarantee
13862306a36Sopenharmony_ci	 * that the strings can be properly terminated!
13962306a36Sopenharmony_ci	 */
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	switch (operation) {
14262306a36Sopenharmony_ci	case START_FILE_COPY:
14362306a36Sopenharmony_ci		out_len = sizeof(struct hv_start_fcopy);
14462306a36Sopenharmony_ci		smsg_out = kzalloc(sizeof(*smsg_out), GFP_KERNEL);
14562306a36Sopenharmony_ci		if (!smsg_out)
14662306a36Sopenharmony_ci			return;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci		smsg_out->hdr.operation = operation;
14962306a36Sopenharmony_ci		smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH,
15262306a36Sopenharmony_ci				UTF16_LITTLE_ENDIAN,
15362306a36Sopenharmony_ci				(__u8 *)&smsg_out->file_name, W_MAX_PATH - 1);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci		utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH,
15662306a36Sopenharmony_ci				UTF16_LITTLE_ENDIAN,
15762306a36Sopenharmony_ci				(__u8 *)&smsg_out->path_name, W_MAX_PATH - 1);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci		smsg_out->copy_flags = smsg_in->copy_flags;
16062306a36Sopenharmony_ci		smsg_out->file_size = smsg_in->file_size;
16162306a36Sopenharmony_ci		out_src = smsg_out;
16262306a36Sopenharmony_ci		break;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	case WRITE_TO_FILE:
16562306a36Sopenharmony_ci		out_src = fcopy_transaction.fcopy_msg;
16662306a36Sopenharmony_ci		out_len = sizeof(struct hv_do_fcopy);
16762306a36Sopenharmony_ci		break;
16862306a36Sopenharmony_ci	default:
16962306a36Sopenharmony_ci		out_src = fcopy_transaction.fcopy_msg;
17062306a36Sopenharmony_ci		out_len = fcopy_transaction.recv_len;
17162306a36Sopenharmony_ci		break;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	fcopy_transaction.state = HVUTIL_USERSPACE_REQ;
17562306a36Sopenharmony_ci	rc = hvutil_transport_send(hvt, out_src, out_len, NULL);
17662306a36Sopenharmony_ci	if (rc) {
17762306a36Sopenharmony_ci		pr_debug("FCP: failed to communicate to the daemon: %d\n", rc);
17862306a36Sopenharmony_ci		if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
17962306a36Sopenharmony_ci			fcopy_respond_to_host(HV_E_FAIL);
18062306a36Sopenharmony_ci			fcopy_transaction.state = HVUTIL_READY;
18162306a36Sopenharmony_ci		}
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci	kfree(smsg_out);
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci/*
18762306a36Sopenharmony_ci * Send a response back to the host.
18862306a36Sopenharmony_ci */
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic void
19162306a36Sopenharmony_cifcopy_respond_to_host(int error)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	struct icmsg_hdr *icmsghdr;
19462306a36Sopenharmony_ci	u32 buf_len;
19562306a36Sopenharmony_ci	struct vmbus_channel *channel;
19662306a36Sopenharmony_ci	u64 req_id;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	/*
19962306a36Sopenharmony_ci	 * Copy the global state for completing the transaction. Note that
20062306a36Sopenharmony_ci	 * only one transaction can be active at a time. This is guaranteed
20162306a36Sopenharmony_ci	 * by the file copy protocol implemented by the host. Furthermore,
20262306a36Sopenharmony_ci	 * the "transaction active" state we maintain ensures that there can
20362306a36Sopenharmony_ci	 * only be one active transaction at a time.
20462306a36Sopenharmony_ci	 */
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	buf_len = fcopy_transaction.recv_len;
20762306a36Sopenharmony_ci	channel = fcopy_transaction.recv_channel;
20862306a36Sopenharmony_ci	req_id = fcopy_transaction.recv_req_id;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	icmsghdr = (struct icmsg_hdr *)
21162306a36Sopenharmony_ci			&recv_buffer[sizeof(struct vmbuspipe_hdr)];
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (channel->onchannel_callback == NULL)
21462306a36Sopenharmony_ci		/*
21562306a36Sopenharmony_ci		 * We have raced with util driver being unloaded;
21662306a36Sopenharmony_ci		 * silently return.
21762306a36Sopenharmony_ci		 */
21862306a36Sopenharmony_ci		return;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	icmsghdr->status = error;
22162306a36Sopenharmony_ci	icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
22262306a36Sopenharmony_ci	vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
22362306a36Sopenharmony_ci				VM_PKT_DATA_INBAND, 0);
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_civoid hv_fcopy_onchannelcallback(void *context)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	struct vmbus_channel *channel = context;
22962306a36Sopenharmony_ci	u32 recvlen;
23062306a36Sopenharmony_ci	u64 requestid;
23162306a36Sopenharmony_ci	struct hv_fcopy_hdr *fcopy_msg;
23262306a36Sopenharmony_ci	struct icmsg_hdr *icmsghdr;
23362306a36Sopenharmony_ci	int fcopy_srv_version;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	if (fcopy_transaction.state > HVUTIL_READY)
23662306a36Sopenharmony_ci		return;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	if (vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 2, &recvlen, &requestid)) {
23962306a36Sopenharmony_ci		pr_err_ratelimited("Fcopy request received. Could not read into recv buf\n");
24062306a36Sopenharmony_ci		return;
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (!recvlen)
24462306a36Sopenharmony_ci		return;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	/* Ensure recvlen is big enough to read header data */
24762306a36Sopenharmony_ci	if (recvlen < ICMSG_HDR) {
24862306a36Sopenharmony_ci		pr_err_ratelimited("Fcopy request received. Packet length too small: %d\n",
24962306a36Sopenharmony_ci				   recvlen);
25062306a36Sopenharmony_ci		return;
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	icmsghdr = (struct icmsg_hdr *)&recv_buffer[
25462306a36Sopenharmony_ci			sizeof(struct vmbuspipe_hdr)];
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) {
25762306a36Sopenharmony_ci		if (vmbus_prep_negotiate_resp(icmsghdr,
25862306a36Sopenharmony_ci				recv_buffer, recvlen,
25962306a36Sopenharmony_ci				fw_versions, FW_VER_COUNT,
26062306a36Sopenharmony_ci				fcopy_versions, FCOPY_VER_COUNT,
26162306a36Sopenharmony_ci				NULL, &fcopy_srv_version)) {
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci			pr_info("FCopy IC version %d.%d\n",
26462306a36Sopenharmony_ci				fcopy_srv_version >> 16,
26562306a36Sopenharmony_ci				fcopy_srv_version & 0xFFFF);
26662306a36Sopenharmony_ci		}
26762306a36Sopenharmony_ci	} else if (icmsghdr->icmsgtype == ICMSGTYPE_FCOPY) {
26862306a36Sopenharmony_ci		/* Ensure recvlen is big enough to contain hv_fcopy_hdr */
26962306a36Sopenharmony_ci		if (recvlen < ICMSG_HDR + sizeof(struct hv_fcopy_hdr)) {
27062306a36Sopenharmony_ci			pr_err_ratelimited("Invalid Fcopy hdr. Packet length too small: %u\n",
27162306a36Sopenharmony_ci					   recvlen);
27262306a36Sopenharmony_ci			return;
27362306a36Sopenharmony_ci		}
27462306a36Sopenharmony_ci		fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[ICMSG_HDR];
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci		/*
27762306a36Sopenharmony_ci		 * Stash away this global state for completing the
27862306a36Sopenharmony_ci		 * transaction; note transactions are serialized.
27962306a36Sopenharmony_ci		 */
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci		fcopy_transaction.recv_len = recvlen;
28262306a36Sopenharmony_ci		fcopy_transaction.recv_req_id = requestid;
28362306a36Sopenharmony_ci		fcopy_transaction.fcopy_msg = fcopy_msg;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci		if (fcopy_transaction.state < HVUTIL_READY) {
28662306a36Sopenharmony_ci			/* Userspace is not registered yet */
28762306a36Sopenharmony_ci			fcopy_respond_to_host(HV_E_FAIL);
28862306a36Sopenharmony_ci			return;
28962306a36Sopenharmony_ci		}
29062306a36Sopenharmony_ci		fcopy_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci		/*
29362306a36Sopenharmony_ci		 * Send the information to the user-level daemon.
29462306a36Sopenharmony_ci		 */
29562306a36Sopenharmony_ci		schedule_work(&fcopy_send_work);
29662306a36Sopenharmony_ci		schedule_delayed_work(&fcopy_timeout_work,
29762306a36Sopenharmony_ci				      HV_UTIL_TIMEOUT * HZ);
29862306a36Sopenharmony_ci		return;
29962306a36Sopenharmony_ci	} else {
30062306a36Sopenharmony_ci		pr_err_ratelimited("Fcopy request received. Invalid msg type: %d\n",
30162306a36Sopenharmony_ci				   icmsghdr->icmsgtype);
30262306a36Sopenharmony_ci		return;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci	icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
30562306a36Sopenharmony_ci	vmbus_sendpacket(channel, recv_buffer, recvlen, requestid,
30662306a36Sopenharmony_ci			VM_PKT_DATA_INBAND, 0);
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci/* Callback when data is received from userspace */
31062306a36Sopenharmony_cistatic int fcopy_on_msg(void *msg, int len)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	int *val = (int *)msg;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (len != sizeof(int))
31562306a36Sopenharmony_ci		return -EINVAL;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	if (fcopy_transaction.state == HVUTIL_DEVICE_INIT)
31862306a36Sopenharmony_ci		return fcopy_handle_handshake(*val);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	if (fcopy_transaction.state != HVUTIL_USERSPACE_REQ)
32162306a36Sopenharmony_ci		return -EINVAL;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	/*
32462306a36Sopenharmony_ci	 * Complete the transaction by forwarding the result
32562306a36Sopenharmony_ci	 * to the host. But first, cancel the timeout.
32662306a36Sopenharmony_ci	 */
32762306a36Sopenharmony_ci	if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
32862306a36Sopenharmony_ci		fcopy_transaction.state = HVUTIL_USERSPACE_RECV;
32962306a36Sopenharmony_ci		fcopy_respond_to_host(*val);
33062306a36Sopenharmony_ci		hv_poll_channel(fcopy_transaction.recv_channel,
33162306a36Sopenharmony_ci				fcopy_poll_wrapper);
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	return 0;
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic void fcopy_on_reset(void)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	/*
34062306a36Sopenharmony_ci	 * The daemon has exited; reset the state.
34162306a36Sopenharmony_ci	 */
34262306a36Sopenharmony_ci	fcopy_transaction.state = HVUTIL_DEVICE_INIT;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if (cancel_delayed_work_sync(&fcopy_timeout_work))
34562306a36Sopenharmony_ci		fcopy_respond_to_host(HV_E_FAIL);
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ciint hv_fcopy_init(struct hv_util_service *srv)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	recv_buffer = srv->recv_buffer;
35162306a36Sopenharmony_ci	fcopy_transaction.recv_channel = srv->channel;
35262306a36Sopenharmony_ci	fcopy_transaction.recv_channel->max_pkt_size = HV_HYP_PAGE_SIZE * 2;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/*
35562306a36Sopenharmony_ci	 * When this driver loads, the user level daemon that
35662306a36Sopenharmony_ci	 * processes the host requests may not yet be running.
35762306a36Sopenharmony_ci	 * Defer processing channel callbacks until the daemon
35862306a36Sopenharmony_ci	 * has registered.
35962306a36Sopenharmony_ci	 */
36062306a36Sopenharmony_ci	fcopy_transaction.state = HVUTIL_DEVICE_INIT;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	hvt = hvutil_transport_init(fcopy_devname, 0, 0,
36362306a36Sopenharmony_ci				    fcopy_on_msg, fcopy_on_reset);
36462306a36Sopenharmony_ci	if (!hvt)
36562306a36Sopenharmony_ci		return -EFAULT;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	return 0;
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_cistatic void hv_fcopy_cancel_work(void)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	cancel_delayed_work_sync(&fcopy_timeout_work);
37362306a36Sopenharmony_ci	cancel_work_sync(&fcopy_send_work);
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ciint hv_fcopy_pre_suspend(void)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	struct vmbus_channel *channel = fcopy_transaction.recv_channel;
37962306a36Sopenharmony_ci	struct hv_fcopy_hdr *fcopy_msg;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	/*
38262306a36Sopenharmony_ci	 * Fake a CANCEL_FCOPY message for the user space daemon in case the
38362306a36Sopenharmony_ci	 * daemon is in the middle of copying some file. It doesn't matter if
38462306a36Sopenharmony_ci	 * there is already a message pending to be delivered to the user
38562306a36Sopenharmony_ci	 * space since we force fcopy_transaction.state to be HVUTIL_READY, so
38662306a36Sopenharmony_ci	 * the user space daemon's write() will fail with EINVAL (see
38762306a36Sopenharmony_ci	 * fcopy_on_msg()), and the daemon will reset the device by closing
38862306a36Sopenharmony_ci	 * and re-opening it.
38962306a36Sopenharmony_ci	 */
39062306a36Sopenharmony_ci	fcopy_msg = kzalloc(sizeof(*fcopy_msg), GFP_KERNEL);
39162306a36Sopenharmony_ci	if (!fcopy_msg)
39262306a36Sopenharmony_ci		return -ENOMEM;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	tasklet_disable(&channel->callback_event);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	fcopy_msg->operation = CANCEL_FCOPY;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	hv_fcopy_cancel_work();
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	/* We don't care about the return value. */
40162306a36Sopenharmony_ci	hvutil_transport_send(hvt, fcopy_msg, sizeof(*fcopy_msg), NULL);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	kfree(fcopy_msg);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	fcopy_transaction.state = HVUTIL_READY;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	/* tasklet_enable() will be called in hv_fcopy_pre_resume(). */
40862306a36Sopenharmony_ci	return 0;
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ciint hv_fcopy_pre_resume(void)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	struct vmbus_channel *channel = fcopy_transaction.recv_channel;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	tasklet_enable(&channel->callback_event);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	return 0;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_civoid hv_fcopy_deinit(void)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	fcopy_transaction.state = HVUTIL_DEVICE_DYING;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	hv_fcopy_cancel_work();
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	hvutil_transport_destroy(hvt);
42762306a36Sopenharmony_ci}
428