1295958Ssephe/*-
2298446Ssephe * Copyright (c) 2014,2016 Microsoft Corp.
3295958Ssephe * All rights reserved.
4295958Ssephe *
5295958Ssephe * Redistribution and use in source and binary forms, with or without
6295958Ssephe * modification, are permitted provided that the following conditions
7295958Ssephe * are met:
8295958Ssephe * 1. Redistributions of source code must retain the above copyright
9295958Ssephe *    notice unmodified, this list of conditions, and the following
10295958Ssephe *    disclaimer.
11295958Ssephe * 2. Redistributions in binary form must reproduce the above copyright
12295958Ssephe *    notice, this list of conditions and the following disclaimer in the
13295958Ssephe *    documentation and/or other materials provided with the distribution.
14295958Ssephe *
15295958Ssephe * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16295958Ssephe * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17295958Ssephe * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18295958Ssephe * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19295958Ssephe * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20295958Ssephe * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21295958Ssephe * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22295958Ssephe * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23295958Ssephe * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24295958Ssephe * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25295958Ssephe */
26295958Ssephe
27304786Ssephe#include <sys/cdefs.h>
28304786Ssephe__FBSDID("$FreeBSD: stable/11/sys/dev/hyperv/utilities/vmbus_heartbeat.c 311386 2017-01-05 08:34:08Z sephe $");
29304786Ssephe
30295958Ssephe#include <sys/param.h>
31304786Ssephe#include <sys/bus.h>
32295958Ssephe#include <sys/kernel.h>
33295958Ssephe#include <sys/module.h>
34303422Ssephe#include <sys/systm.h>
35295958Ssephe
36295958Ssephe#include <dev/hyperv/include/hyperv.h>
37302880Ssephe#include <dev/hyperv/include/vmbus.h>
38304786Ssephe#include <dev/hyperv/utilities/vmbus_icreg.h>
39310314Ssephe#include <dev/hyperv/utilities/vmbus_icvar.h>
40304786Ssephe
41307845Ssephe#define VMBUS_HEARTBEAT_FWVER_MAJOR	3
42307845Ssephe#define VMBUS_HEARTBEAT_FWVER		\
43307845Ssephe	VMBUS_IC_VERSION(VMBUS_HEARTBEAT_FWVER_MAJOR, 0)
44307845Ssephe
45307845Ssephe#define VMBUS_HEARTBEAT_MSGVER_MAJOR	3
46307845Ssephe#define VMBUS_HEARTBEAT_MSGVER		\
47307845Ssephe	VMBUS_IC_VERSION(VMBUS_HEARTBEAT_MSGVER_MAJOR, 0)
48307845Ssephe
49310318Ssephestatic int			vmbus_heartbeat_probe(device_t);
50310318Ssephestatic int			vmbus_heartbeat_attach(device_t);
51310318Ssephe
52304273Ssephestatic const struct vmbus_ic_desc vmbus_heartbeat_descs[] = {
53304273Ssephe	{
54304273Ssephe		.ic_guid = { .hv_guid = {
55304273Ssephe		    0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
56304273Ssephe		    0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d} },
57304273Ssephe		.ic_desc = "Hyper-V Heartbeat"
58304273Ssephe	},
59304273Ssephe	VMBUS_IC_DESC_END
60304273Ssephe};
61295958Ssephe
62310318Ssephestatic device_method_t vmbus_heartbeat_methods[] = {
63310318Ssephe	/* Device interface */
64310318Ssephe	DEVMETHOD(device_probe,		vmbus_heartbeat_probe),
65310318Ssephe	DEVMETHOD(device_attach,	vmbus_heartbeat_attach),
66310318Ssephe	DEVMETHOD(device_detach,	vmbus_ic_detach),
67310318Ssephe	DEVMETHOD_END
68310318Ssephe};
69310318Ssephe
70310318Ssephestatic driver_t vmbus_heartbeat_driver = {
71310318Ssephe	"hvheartbeat",
72310318Ssephe	vmbus_heartbeat_methods,
73310318Ssephe	sizeof(struct vmbus_ic_softc)
74310318Ssephe};
75310318Ssephe
76310318Ssephestatic devclass_t vmbus_heartbeat_devclass;
77310318Ssephe
78310318SsepheDRIVER_MODULE(hv_heartbeat, vmbus, vmbus_heartbeat_driver,
79310318Ssephe    vmbus_heartbeat_devclass, NULL, NULL);
80310318SsepheMODULE_VERSION(hv_heartbeat, 1);
81310318SsepheMODULE_DEPEND(hv_heartbeat, vmbus, 1, 1, 1);
82310318Ssephe
83295958Ssephestatic void
84304786Ssephevmbus_heartbeat_cb(struct vmbus_channel *chan, void *xsc)
85295958Ssephe{
86310313Ssephe	struct vmbus_ic_softc *sc = xsc;
87304786Ssephe	struct vmbus_icmsg_hdr *hdr;
88304786Ssephe	int dlen, error;
89304786Ssephe	uint64_t xactid;
90304786Ssephe	void *data;
91295958Ssephe
92304786Ssephe	/*
93304786Ssephe	 * Receive request.
94304786Ssephe	 */
95310313Ssephe	data = sc->ic_buf;
96304786Ssephe	dlen = sc->ic_buflen;
97304786Ssephe	error = vmbus_chan_recv(chan, data, &dlen, &xactid);
98304786Ssephe	KASSERT(error != ENOBUFS, ("icbuf is not large enough"));
99304786Ssephe	if (error)
100304786Ssephe		return;
101295958Ssephe
102305279Ssephe	if (dlen < sizeof(*hdr)) {
103304786Ssephe		device_printf(sc->ic_dev, "invalid data len %d\n", dlen);
104304786Ssephe		return;
105304786Ssephe	}
106304786Ssephe	hdr = data;
107295958Ssephe
108304786Ssephe	/*
109304786Ssephe	 * Update request, which will be echoed back as response.
110304786Ssephe	 */
111304786Ssephe	switch (hdr->ic_type) {
112304786Ssephe	case VMBUS_ICMSG_TYPE_NEGOTIATE:
113307845Ssephe		error = vmbus_ic_negomsg(sc, data, &dlen,
114307845Ssephe		    VMBUS_HEARTBEAT_FWVER, VMBUS_HEARTBEAT_MSGVER);
115304730Ssephe		if (error)
116304730Ssephe			return;
117304786Ssephe		break;
118295958Ssephe
119304786Ssephe	case VMBUS_ICMSG_TYPE_HEARTBEAT:
120304786Ssephe		/* Only ic_seq is a must */
121304786Ssephe		if (dlen < VMBUS_ICMSG_HEARTBEAT_SIZE_MIN) {
122304786Ssephe			device_printf(sc->ic_dev, "invalid heartbeat len %d\n",
123304786Ssephe			    dlen);
124304786Ssephe			return;
125304786Ssephe		}
126304786Ssephe		((struct vmbus_icmsg_heartbeat *)data)->ic_seq++;
127304786Ssephe		break;
128295958Ssephe
129304786Ssephe	default:
130304786Ssephe		device_printf(sc->ic_dev, "got 0x%08x icmsg\n", hdr->ic_type);
131304786Ssephe		break;
132304786Ssephe	}
133295958Ssephe
134304786Ssephe	/*
135310312Ssephe	 * Send response by echoing the request back.
136304786Ssephe	 */
137310312Ssephe	vmbus_ic_sendresp(sc, chan, data, dlen, xactid);
138295958Ssephe}
139295958Ssephe
140295958Ssephestatic int
141310318Ssephevmbus_heartbeat_probe(device_t dev)
142295958Ssephe{
143297220Ssephe
144304273Ssephe	return (vmbus_ic_probe(dev, vmbus_heartbeat_descs));
145295958Ssephe}
146295958Ssephe
147295958Ssephestatic int
148310318Ssephevmbus_heartbeat_attach(device_t dev)
149295958Ssephe{
150304786Ssephe
151310313Ssephe	return (vmbus_ic_attach(dev, vmbus_heartbeat_cb));
152295958Ssephe}
153