1*38df7c85Snonaka /* $NetBSD: hvheartbeat.c,v 1.2 2019/03/01 08:17:51 nonaka Exp $ */
250517e57Snonaka
350517e57Snonaka /*-
450517e57Snonaka * Copyright (c) 2014,2016 Microsoft Corp.
550517e57Snonaka * All rights reserved.
650517e57Snonaka *
750517e57Snonaka * Redistribution and use in source and binary forms, with or without
850517e57Snonaka * modification, are permitted provided that the following conditions
950517e57Snonaka * are met:
1050517e57Snonaka * 1. Redistributions of source code must retain the above copyright
1150517e57Snonaka * notice unmodified, this list of conditions, and the following
1250517e57Snonaka * disclaimer.
1350517e57Snonaka * 2. Redistributions in binary form must reproduce the above copyright
1450517e57Snonaka * notice, this list of conditions and the following disclaimer in the
1550517e57Snonaka * documentation and/or other materials provided with the distribution.
1650517e57Snonaka *
1750517e57Snonaka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1850517e57Snonaka * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1950517e57Snonaka * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2050517e57Snonaka * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2150517e57Snonaka * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2250517e57Snonaka * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2350517e57Snonaka * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2450517e57Snonaka * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2550517e57Snonaka * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2650517e57Snonaka * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2750517e57Snonaka */
2850517e57Snonaka
2950517e57Snonaka #include <sys/cdefs.h>
3050517e57Snonaka #ifdef __KERNEL_RCSID
31*38df7c85Snonaka __KERNEL_RCSID(0, "$NetBSD: hvheartbeat.c,v 1.2 2019/03/01 08:17:51 nonaka Exp $");
3250517e57Snonaka #endif
3350517e57Snonaka #ifdef __FBSDID
3450517e57Snonaka __FBSDID("$FreeBSD: head/sys/dev/hyperv/utilities/vmbus_heartbeat.c 310324 2016-12-20 09:46:14Z sephe $");
3550517e57Snonaka #endif
3650517e57Snonaka
3750517e57Snonaka #include <sys/param.h>
3850517e57Snonaka #include <sys/systm.h>
3950517e57Snonaka #include <sys/device.h>
4050517e57Snonaka #include <sys/module.h>
4150517e57Snonaka #include <sys/pmf.h>
4250517e57Snonaka
4350517e57Snonaka #include <dev/hyperv/vmbusvar.h>
4450517e57Snonaka #include <dev/hyperv/vmbusicreg.h>
4550517e57Snonaka #include <dev/hyperv/vmbusicvar.h>
4650517e57Snonaka
4750517e57Snonaka #define VMBUS_HEARTBEAT_FWVER_MAJOR 3
4850517e57Snonaka #define VMBUS_HEARTBEAT_FWVER \
4950517e57Snonaka VMBUS_IC_VERSION(VMBUS_HEARTBEAT_FWVER_MAJOR, 0)
5050517e57Snonaka
5150517e57Snonaka #define VMBUS_HEARTBEAT_MSGVER_MAJOR 3
5250517e57Snonaka #define VMBUS_HEARTBEAT_MSGVER \
5350517e57Snonaka VMBUS_IC_VERSION(VMBUS_HEARTBEAT_MSGVER_MAJOR, 0)
5450517e57Snonaka
5550517e57Snonaka static int hvheartbeat_match(device_t, cfdata_t, void *);
5650517e57Snonaka static void hvheartbeat_attach(device_t, device_t, void *);
5750517e57Snonaka static int hvheartbeat_detach(device_t, int);
5850517e57Snonaka
5950517e57Snonaka static void hvheartbeat_channel_cb(void *);
6050517e57Snonaka
6150517e57Snonaka struct hvheartbeat_softc {
6250517e57Snonaka struct vmbusic_softc sc_vmbusic;
6350517e57Snonaka };
6450517e57Snonaka
6550517e57Snonaka CFATTACH_DECL_NEW(hvheartbeat, sizeof(struct hvheartbeat_softc),
6650517e57Snonaka hvheartbeat_match, hvheartbeat_attach, hvheartbeat_detach, NULL);
6750517e57Snonaka
6850517e57Snonaka static int
hvheartbeat_match(device_t parent,cfdata_t cf,void * aux)6950517e57Snonaka hvheartbeat_match(device_t parent, cfdata_t cf, void *aux)
7050517e57Snonaka {
7150517e57Snonaka struct vmbus_attach_args *aa = aux;
7250517e57Snonaka
7350517e57Snonaka return vmbusic_probe(aa, &hyperv_guid_heartbeat);
7450517e57Snonaka }
7550517e57Snonaka
7650517e57Snonaka static void
hvheartbeat_attach(device_t parent,device_t self,void * aux)7750517e57Snonaka hvheartbeat_attach(device_t parent, device_t self, void *aux)
7850517e57Snonaka {
7950517e57Snonaka struct vmbus_attach_args *aa = aux;
8050517e57Snonaka int error;
8150517e57Snonaka
8250517e57Snonaka aprint_naive("\n");
83*38df7c85Snonaka aprint_normal(": Hyper-V Heartbeat Service\n");
8450517e57Snonaka
8550517e57Snonaka error = vmbusic_attach(self, aa, hvheartbeat_channel_cb);
8650517e57Snonaka if (error)
8750517e57Snonaka return;
8850517e57Snonaka
8950517e57Snonaka (void) pmf_device_register(self, NULL, NULL);
9050517e57Snonaka }
9150517e57Snonaka
9250517e57Snonaka static int
hvheartbeat_detach(device_t self,int flags)9350517e57Snonaka hvheartbeat_detach(device_t self, int flags)
9450517e57Snonaka {
9550517e57Snonaka int error;
9650517e57Snonaka
9750517e57Snonaka error = vmbusic_detach(self, flags);
9850517e57Snonaka if (error)
9950517e57Snonaka return error;
10050517e57Snonaka
10150517e57Snonaka pmf_device_deregister(self);
10250517e57Snonaka
10350517e57Snonaka return 0;
10450517e57Snonaka }
10550517e57Snonaka
10650517e57Snonaka static void
hvheartbeat_channel_cb(void * arg)10750517e57Snonaka hvheartbeat_channel_cb(void *arg)
10850517e57Snonaka {
10950517e57Snonaka struct hvheartbeat_softc *sc = arg;
11050517e57Snonaka struct vmbusic_softc *vsc = &sc->sc_vmbusic;
11150517e57Snonaka struct vmbus_channel *ch = vsc->sc_chan;
11250517e57Snonaka struct vmbus_icmsg_hdr *hdr;
11350517e57Snonaka struct vmbus_icmsg_heartbeat *msg;
11450517e57Snonaka uint64_t rid;
11550517e57Snonaka uint32_t rlen;
11650517e57Snonaka int error;
11750517e57Snonaka
11850517e57Snonaka error = vmbus_channel_recv(ch, vsc->sc_buf, vsc->sc_buflen,
11950517e57Snonaka &rlen, &rid, 0);
12050517e57Snonaka if (error || rlen == 0) {
12150517e57Snonaka if (error != EAGAIN) {
12250517e57Snonaka DPRINTF("%s: heartbeat error=%d len=%u\n",
12350517e57Snonaka device_xname(vsc->sc_dev), error, rlen);
12450517e57Snonaka }
12550517e57Snonaka return;
12650517e57Snonaka }
12750517e57Snonaka if (rlen < sizeof(*hdr)) {
12850517e57Snonaka DPRINTF("%s: heartbeat short read len=%u\n",
12950517e57Snonaka device_xname(vsc->sc_dev), rlen);
13050517e57Snonaka return;
13150517e57Snonaka }
13250517e57Snonaka
13350517e57Snonaka hdr = (struct vmbus_icmsg_hdr *)vsc->sc_buf;
13450517e57Snonaka switch (hdr->ic_type) {
13550517e57Snonaka case VMBUS_ICMSG_TYPE_NEGOTIATE:
13650517e57Snonaka error = vmbusic_negotiate(vsc, hdr, &rlen,
13750517e57Snonaka VMBUS_HEARTBEAT_FWVER, VMBUS_HEARTBEAT_MSGVER);
13850517e57Snonaka if (error)
13950517e57Snonaka return;
14050517e57Snonaka break;
14150517e57Snonaka
14250517e57Snonaka case VMBUS_ICMSG_TYPE_HEARTBEAT:
14350517e57Snonaka if (rlen < VMBUS_ICMSG_HEARTBEAT_SIZE_MIN) {
14450517e57Snonaka DPRINTF("%s: invalid heartbeat len=%u\n",
14550517e57Snonaka device_xname(vsc->sc_dev), rlen);
14650517e57Snonaka return;
14750517e57Snonaka }
14850517e57Snonaka
14950517e57Snonaka msg = (struct vmbus_icmsg_heartbeat *)hdr;
15050517e57Snonaka msg->ic_seq++;
15150517e57Snonaka break;
15250517e57Snonaka
15350517e57Snonaka default:
15450517e57Snonaka device_printf(vsc->sc_dev,
15550517e57Snonaka "unhandled heartbeat message type %u\n", hdr->ic_type);
15650517e57Snonaka return;
15750517e57Snonaka }
15850517e57Snonaka
15950517e57Snonaka (void) vmbusic_sendresp(vsc, ch, vsc->sc_buf, rlen, rid);
16050517e57Snonaka }
16150517e57Snonaka
16250517e57Snonaka MODULE(MODULE_CLASS_DRIVER, hvheartbeat, "vmbus");
16350517e57Snonaka
16450517e57Snonaka #ifdef _MODULE
16550517e57Snonaka #include "ioconf.c"
16650517e57Snonaka #endif
16750517e57Snonaka
16850517e57Snonaka static int
hvheartbeat_modcmd(modcmd_t cmd,void * aux)16950517e57Snonaka hvheartbeat_modcmd(modcmd_t cmd, void *aux)
17050517e57Snonaka {
17150517e57Snonaka int error = 0;
17250517e57Snonaka
17350517e57Snonaka switch (cmd) {
17450517e57Snonaka case MODULE_CMD_INIT:
17550517e57Snonaka #ifdef _MODULE
17650517e57Snonaka error = config_init_component(cfdriver_ioconf_hvheartbeat,
17750517e57Snonaka cfattach_ioconf_hvheartbeat, cfdata_ioconf_hvheartbeat);
17850517e57Snonaka #endif
17950517e57Snonaka break;
18050517e57Snonaka
18150517e57Snonaka case MODULE_CMD_FINI:
18250517e57Snonaka #ifdef _MODULE
18350517e57Snonaka error = config_fini_component(cfdriver_ioconf_hvheartbeat,
18450517e57Snonaka cfattach_ioconf_hvheartbeat, cfdata_ioconf_hvheartbeat);
18550517e57Snonaka #endif
18650517e57Snonaka break;
18750517e57Snonaka
18850517e57Snonaka case MODULE_CMD_AUTOUNLOAD:
18950517e57Snonaka error = EBUSY;
19050517e57Snonaka break;
19150517e57Snonaka
19250517e57Snonaka default:
19350517e57Snonaka error = ENOTTY;
19450517e57Snonaka break;
19550517e57Snonaka }
19650517e57Snonaka
19750517e57Snonaka return error;
19850517e57Snonaka }
199