xref: /openbmc/linux/drivers/hv/hv_fcopy.c (revision 20951c75)
101325476SK. Y. Srinivasan /*
201325476SK. Y. Srinivasan  * An implementation of file copy service.
301325476SK. Y. Srinivasan  *
401325476SK. Y. Srinivasan  * Copyright (C) 2014, Microsoft, Inc.
501325476SK. Y. Srinivasan  *
601325476SK. Y. Srinivasan  * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
701325476SK. Y. Srinivasan  *
801325476SK. Y. Srinivasan  * This program is free software; you can redistribute it and/or modify it
901325476SK. Y. Srinivasan  * under the terms of the GNU General Public License version 2 as published
1001325476SK. Y. Srinivasan  * by the Free Software Foundation.
1101325476SK. Y. Srinivasan  *
1201325476SK. Y. Srinivasan  * This program is distributed in the hope that it will be useful, but
1301325476SK. Y. Srinivasan  * WITHOUT ANY WARRANTY; without even the implied warranty of
1401325476SK. Y. Srinivasan  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
1501325476SK. Y. Srinivasan  * NON INFRINGEMENT.  See the GNU General Public License for more
1601325476SK. Y. Srinivasan  * details.
1701325476SK. Y. Srinivasan  *
1801325476SK. Y. Srinivasan  */
1901325476SK. Y. Srinivasan 
2001325476SK. Y. Srinivasan #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2101325476SK. Y. Srinivasan 
2201325476SK. Y. Srinivasan #include <linux/nls.h>
2301325476SK. Y. Srinivasan #include <linux/workqueue.h>
2401325476SK. Y. Srinivasan #include <linux/hyperv.h>
2501325476SK. Y. Srinivasan #include <linux/sched.h>
2601325476SK. Y. Srinivasan 
2701325476SK. Y. Srinivasan #include "hyperv_vmbus.h"
28c7e490fcSVitaly Kuznetsov #include "hv_utils_transport.h"
2901325476SK. Y. Srinivasan 
3001325476SK. Y. Srinivasan #define WIN8_SRV_MAJOR		1
3101325476SK. Y. Srinivasan #define WIN8_SRV_MINOR		1
3201325476SK. Y. Srinivasan #define WIN8_SRV_VERSION	(WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
3301325476SK. Y. Srinivasan 
3401325476SK. Y. Srinivasan /*
3501325476SK. Y. Srinivasan  * Global state maintained for transaction that is being processed.
3601325476SK. Y. Srinivasan  * For a class of integration services, including the "file copy service",
3701325476SK. Y. Srinivasan  * the specified protocol is a "request/response" protocol which means that
3801325476SK. Y. Srinivasan  * there can only be single outstanding transaction from the host at any
3901325476SK. Y. Srinivasan  * given point in time. We use this to simplify memory management in this
4001325476SK. Y. Srinivasan  * driver - we cache and process only one message at a time.
4101325476SK. Y. Srinivasan  *
4201325476SK. Y. Srinivasan  * While the request/response protocol is guaranteed by the host, we further
4301325476SK. Y. Srinivasan  * ensure this by serializing packet processing in this driver - we do not
4401325476SK. Y. Srinivasan  * read additional packets from the VMBUs until the current packet is fully
4501325476SK. Y. Srinivasan  * handled.
4601325476SK. Y. Srinivasan  */
4701325476SK. Y. Srinivasan 
4801325476SK. Y. Srinivasan static struct {
494c93ccccSVitaly Kuznetsov 	int state;   /* hvutil_device_state */
5001325476SK. Y. Srinivasan 	int recv_len; /* number of bytes received. */
5101325476SK. Y. Srinivasan 	struct hv_fcopy_hdr  *fcopy_msg; /* current message */
5201325476SK. Y. Srinivasan 	struct vmbus_channel *recv_channel; /* chn we got the request */
5301325476SK. Y. Srinivasan 	u64 recv_req_id; /* request ID. */
5401325476SK. Y. Srinivasan } fcopy_transaction;
5501325476SK. Y. Srinivasan 
5601325476SK. Y. Srinivasan static void fcopy_respond_to_host(int error);
57c7e490fcSVitaly Kuznetsov static void fcopy_send_data(struct work_struct *dummy);
581d072339SVitaly Kuznetsov static void fcopy_timeout_func(struct work_struct *dummy);
591d072339SVitaly Kuznetsov static DECLARE_DELAYED_WORK(fcopy_timeout_work, fcopy_timeout_func);
60c7e490fcSVitaly Kuznetsov static DECLARE_WORK(fcopy_send_work, fcopy_send_data);
61c7e490fcSVitaly Kuznetsov static const char fcopy_devname[] = "vmbus/hv_fcopy";
6201325476SK. Y. Srinivasan static u8 *recv_buffer;
63c7e490fcSVitaly Kuznetsov static struct hvutil_transport *hvt;
6420951c75SK. Y. Srinivasan static struct completion release_event;
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 
16401325476SK. Y. Srinivasan 	default:
165c7e490fcSVitaly Kuznetsov 		out_src = fcopy_transaction.fcopy_msg;
166c7e490fcSVitaly Kuznetsov 		out_len = fcopy_transaction.recv_len;
16701325476SK. Y. Srinivasan 		break;
16801325476SK. Y. Srinivasan 	}
169c7e490fcSVitaly Kuznetsov 
170c7e490fcSVitaly Kuznetsov 	fcopy_transaction.state = HVUTIL_USERSPACE_REQ;
171e0fa3e5eSVitaly Kuznetsov 	rc = hvutil_transport_send(hvt, out_src, out_len, NULL);
172c7e490fcSVitaly Kuznetsov 	if (rc) {
173c7e490fcSVitaly Kuznetsov 		pr_debug("FCP: failed to communicate to the daemon: %d\n", rc);
174c7e490fcSVitaly Kuznetsov 		if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
175c7e490fcSVitaly Kuznetsov 			fcopy_respond_to_host(HV_E_FAIL);
176c7e490fcSVitaly Kuznetsov 			fcopy_transaction.state = HVUTIL_READY;
177c7e490fcSVitaly Kuznetsov 		}
178c7e490fcSVitaly Kuznetsov 	}
17925ef06feSVitaly Kuznetsov 	kfree(smsg_out);
18025ef06feSVitaly Kuznetsov 
18101325476SK. Y. Srinivasan 	return;
18201325476SK. Y. Srinivasan }
18301325476SK. Y. Srinivasan 
18401325476SK. Y. Srinivasan /*
18501325476SK. Y. Srinivasan  * Send a response back to the host.
18601325476SK. Y. Srinivasan  */
18701325476SK. Y. Srinivasan 
18801325476SK. Y. Srinivasan static void
18901325476SK. Y. Srinivasan fcopy_respond_to_host(int error)
19001325476SK. Y. Srinivasan {
19101325476SK. Y. Srinivasan 	struct icmsg_hdr *icmsghdr;
19201325476SK. Y. Srinivasan 	u32 buf_len;
19301325476SK. Y. Srinivasan 	struct vmbus_channel *channel;
19401325476SK. Y. Srinivasan 	u64 req_id;
19501325476SK. Y. Srinivasan 
19601325476SK. Y. Srinivasan 	/*
19701325476SK. Y. Srinivasan 	 * Copy the global state for completing the transaction. Note that
19801325476SK. Y. Srinivasan 	 * only one transaction can be active at a time. This is guaranteed
19901325476SK. Y. Srinivasan 	 * by the file copy protocol implemented by the host. Furthermore,
20001325476SK. Y. Srinivasan 	 * the "transaction active" state we maintain ensures that there can
20101325476SK. Y. Srinivasan 	 * only be one active transaction at a time.
20201325476SK. Y. Srinivasan 	 */
20301325476SK. Y. Srinivasan 
20401325476SK. Y. Srinivasan 	buf_len = fcopy_transaction.recv_len;
20501325476SK. Y. Srinivasan 	channel = fcopy_transaction.recv_channel;
20601325476SK. Y. Srinivasan 	req_id = fcopy_transaction.recv_req_id;
20701325476SK. Y. Srinivasan 
20801325476SK. Y. Srinivasan 	icmsghdr = (struct icmsg_hdr *)
20901325476SK. Y. Srinivasan 			&recv_buffer[sizeof(struct vmbuspipe_hdr)];
21001325476SK. Y. Srinivasan 
21101325476SK. Y. Srinivasan 	if (channel->onchannel_callback == NULL)
21201325476SK. Y. Srinivasan 		/*
21301325476SK. Y. Srinivasan 		 * We have raced with util driver being unloaded;
21401325476SK. Y. Srinivasan 		 * silently return.
21501325476SK. Y. Srinivasan 		 */
21601325476SK. Y. Srinivasan 		return;
21701325476SK. Y. Srinivasan 
21801325476SK. Y. Srinivasan 	icmsghdr->status = error;
21901325476SK. Y. Srinivasan 	icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
22001325476SK. Y. Srinivasan 	vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
22101325476SK. Y. Srinivasan 				VM_PKT_DATA_INBAND, 0);
22201325476SK. Y. Srinivasan }
22301325476SK. Y. Srinivasan 
22401325476SK. Y. Srinivasan void hv_fcopy_onchannelcallback(void *context)
22501325476SK. Y. Srinivasan {
22601325476SK. Y. Srinivasan 	struct vmbus_channel *channel = context;
22701325476SK. Y. Srinivasan 	u32 recvlen;
22801325476SK. Y. Srinivasan 	u64 requestid;
22901325476SK. Y. Srinivasan 	struct hv_fcopy_hdr *fcopy_msg;
23001325476SK. Y. Srinivasan 	struct icmsg_hdr *icmsghdr;
23101325476SK. Y. Srinivasan 	struct icmsg_negotiate *negop = NULL;
23201325476SK. Y. Srinivasan 	int util_fw_version;
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 
23801325476SK. Y. Srinivasan 	vmbus_recvpacket(channel, recv_buffer, 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) {
24601325476SK. Y. Srinivasan 		util_fw_version = UTIL_FW_VERSION;
24701325476SK. Y. Srinivasan 		fcopy_srv_version = WIN8_SRV_VERSION;
24801325476SK. Y. Srinivasan 		vmbus_prep_negotiate_resp(icmsghdr, negop, recv_buffer,
24901325476SK. Y. Srinivasan 				util_fw_version, fcopy_srv_version);
25001325476SK. Y. Srinivasan 	} else {
25101325476SK. Y. Srinivasan 		fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[
25201325476SK. Y. Srinivasan 				sizeof(struct vmbuspipe_hdr) +
25301325476SK. Y. Srinivasan 				sizeof(struct icmsg_hdr)];
25401325476SK. Y. Srinivasan 
25501325476SK. Y. Srinivasan 		/*
25601325476SK. Y. Srinivasan 		 * Stash away this global state for completing the
25701325476SK. Y. Srinivasan 		 * transaction; note transactions are serialized.
25801325476SK. Y. Srinivasan 		 */
25901325476SK. Y. Srinivasan 
26001325476SK. Y. Srinivasan 		fcopy_transaction.recv_len = recvlen;
26101325476SK. Y. Srinivasan 		fcopy_transaction.recv_req_id = requestid;
26201325476SK. Y. Srinivasan 		fcopy_transaction.fcopy_msg = fcopy_msg;
26301325476SK. Y. Srinivasan 
2644c93ccccSVitaly Kuznetsov 		if (fcopy_transaction.state < HVUTIL_READY) {
2654c93ccccSVitaly Kuznetsov 			/* Userspace is not registered yet */
2664c93ccccSVitaly Kuznetsov 			fcopy_respond_to_host(HV_E_FAIL);
2674c93ccccSVitaly Kuznetsov 			return;
2684c93ccccSVitaly Kuznetsov 		}
2694c93ccccSVitaly Kuznetsov 		fcopy_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
2704c93ccccSVitaly Kuznetsov 
27101325476SK. Y. Srinivasan 		/*
27201325476SK. Y. Srinivasan 		 * Send the information to the user-level daemon.
27301325476SK. Y. Srinivasan 		 */
274c7e490fcSVitaly Kuznetsov 		schedule_work(&fcopy_send_work);
275c0b200cfSK. Y. Srinivasan 		schedule_delayed_work(&fcopy_timeout_work,
276c0b200cfSK. Y. Srinivasan 				      HV_UTIL_TIMEOUT * HZ);
27701325476SK. Y. Srinivasan 		return;
27801325476SK. Y. Srinivasan 	}
27901325476SK. Y. Srinivasan 	icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
28001325476SK. Y. Srinivasan 	vmbus_sendpacket(channel, recv_buffer, recvlen, requestid,
28101325476SK. Y. Srinivasan 			VM_PKT_DATA_INBAND, 0);
28201325476SK. Y. Srinivasan }
28301325476SK. Y. Srinivasan 
284c7e490fcSVitaly Kuznetsov /* Callback when data is received from userspace */
285c7e490fcSVitaly Kuznetsov static int fcopy_on_msg(void *msg, int len)
28601325476SK. Y. Srinivasan {
287c7e490fcSVitaly Kuznetsov 	int *val = (int *)msg;
28801325476SK. Y. Srinivasan 
289c7e490fcSVitaly Kuznetsov 	if (len != sizeof(int))
29001325476SK. Y. Srinivasan 		return -EINVAL;
29101325476SK. Y. Srinivasan 
292c7e490fcSVitaly Kuznetsov 	if (fcopy_transaction.state == HVUTIL_DEVICE_INIT)
293c7e490fcSVitaly Kuznetsov 		return fcopy_handle_handshake(*val);
29401325476SK. Y. Srinivasan 
2954c93ccccSVitaly Kuznetsov 	if (fcopy_transaction.state != HVUTIL_USERSPACE_REQ)
2964c93ccccSVitaly Kuznetsov 		return -EINVAL;
2974c93ccccSVitaly Kuznetsov 
29801325476SK. Y. Srinivasan 	/*
29901325476SK. Y. Srinivasan 	 * Complete the transaction by forwarding the result
30001325476SK. Y. Srinivasan 	 * to the host. But first, cancel the timeout.
30101325476SK. Y. Srinivasan 	 */
3024c93ccccSVitaly Kuznetsov 	if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
3034c93ccccSVitaly Kuznetsov 		fcopy_transaction.state = HVUTIL_USERSPACE_RECV;
304c7e490fcSVitaly Kuznetsov 		fcopy_respond_to_host(*val);
3053cace4a6SOlaf Hering 		hv_poll_channel(fcopy_transaction.recv_channel,
3063cace4a6SOlaf Hering 				fcopy_poll_wrapper);
307242f3122SVitaly Kuznetsov 	}
30801325476SK. Y. Srinivasan 
30901325476SK. Y. Srinivasan 	return 0;
31001325476SK. Y. Srinivasan }
31101325476SK. Y. Srinivasan 
312c7e490fcSVitaly Kuznetsov static void fcopy_on_reset(void)
31301325476SK. Y. Srinivasan {
31401325476SK. Y. Srinivasan 	/*
31501325476SK. Y. Srinivasan 	 * The daemon has exited; reset the state.
31601325476SK. Y. Srinivasan 	 */
3174c93ccccSVitaly Kuznetsov 	fcopy_transaction.state = HVUTIL_DEVICE_INIT;
318d9b16529SDexuan Cui 
319c7e490fcSVitaly Kuznetsov 	if (cancel_delayed_work_sync(&fcopy_timeout_work))
320d9b16529SDexuan Cui 		fcopy_respond_to_host(HV_E_FAIL);
32120951c75SK. Y. Srinivasan 	complete(&release_event);
322d9b16529SDexuan Cui }
32301325476SK. Y. Srinivasan 
32401325476SK. Y. Srinivasan int hv_fcopy_init(struct hv_util_service *srv)
32501325476SK. Y. Srinivasan {
32601325476SK. Y. Srinivasan 	recv_buffer = srv->recv_buffer;
327b9830d12SK. Y. Srinivasan 	fcopy_transaction.recv_channel = srv->channel;
32801325476SK. Y. Srinivasan 
32920951c75SK. Y. Srinivasan 	init_completion(&release_event);
33001325476SK. Y. Srinivasan 	/*
33101325476SK. Y. Srinivasan 	 * When this driver loads, the user level daemon that
33201325476SK. Y. Srinivasan 	 * processes the host requests may not yet be running.
33301325476SK. Y. Srinivasan 	 * Defer processing channel callbacks until the daemon
33401325476SK. Y. Srinivasan 	 * has registered.
33501325476SK. Y. Srinivasan 	 */
3364c93ccccSVitaly Kuznetsov 	fcopy_transaction.state = HVUTIL_DEVICE_INIT;
33701325476SK. Y. Srinivasan 
338c7e490fcSVitaly Kuznetsov 	hvt = hvutil_transport_init(fcopy_devname, 0, 0,
339c7e490fcSVitaly Kuznetsov 				    fcopy_on_msg, fcopy_on_reset);
340c7e490fcSVitaly Kuznetsov 	if (!hvt)
341c7e490fcSVitaly Kuznetsov 		return -EFAULT;
342c7e490fcSVitaly Kuznetsov 
343c7e490fcSVitaly Kuznetsov 	return 0;
34401325476SK. Y. Srinivasan }
34501325476SK. Y. Srinivasan 
34601325476SK. Y. Srinivasan void hv_fcopy_deinit(void)
34701325476SK. Y. Srinivasan {
3484c93ccccSVitaly Kuznetsov 	fcopy_transaction.state = HVUTIL_DEVICE_DYING;
3491d072339SVitaly Kuznetsov 	cancel_delayed_work_sync(&fcopy_timeout_work);
350c7e490fcSVitaly Kuznetsov 	hvutil_transport_destroy(hvt);
35120951c75SK. Y. Srinivasan 	wait_for_completion(&release_event);
35201325476SK. Y. Srinivasan }
353