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