1*5c072c8eSSepherosa Ziehau /*- 2*5c072c8eSSepherosa Ziehau * Copyright (c) 2014,2016 Microsoft Corp. 3*5c072c8eSSepherosa Ziehau * All rights reserved. 4*5c072c8eSSepherosa Ziehau * 5*5c072c8eSSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 6*5c072c8eSSepherosa Ziehau * modification, are permitted provided that the following conditions 7*5c072c8eSSepherosa Ziehau * are met: 8*5c072c8eSSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 9*5c072c8eSSepherosa Ziehau * notice unmodified, this list of conditions, and the following 10*5c072c8eSSepherosa Ziehau * disclaimer. 11*5c072c8eSSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 12*5c072c8eSSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 13*5c072c8eSSepherosa Ziehau * documentation and/or other materials provided with the distribution. 14*5c072c8eSSepherosa Ziehau * 15*5c072c8eSSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16*5c072c8eSSepherosa Ziehau * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17*5c072c8eSSepherosa Ziehau * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18*5c072c8eSSepherosa Ziehau * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19*5c072c8eSSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20*5c072c8eSSepherosa Ziehau * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21*5c072c8eSSepherosa Ziehau * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22*5c072c8eSSepherosa Ziehau * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23*5c072c8eSSepherosa Ziehau * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24*5c072c8eSSepherosa Ziehau * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25*5c072c8eSSepherosa Ziehau */ 26*5c072c8eSSepherosa Ziehau 27*5c072c8eSSepherosa Ziehau #include <sys/cdefs.h> 28*5c072c8eSSepherosa Ziehau __FBSDID("$FreeBSD$"); 29*5c072c8eSSepherosa Ziehau 30*5c072c8eSSepherosa Ziehau #include <sys/param.h> 31*5c072c8eSSepherosa Ziehau #include <sys/bus.h> 32*5c072c8eSSepherosa Ziehau #include <sys/kernel.h> 33*5c072c8eSSepherosa Ziehau #include <sys/module.h> 34*5c072c8eSSepherosa Ziehau #include <sys/reboot.h> 35*5c072c8eSSepherosa Ziehau #include <sys/systm.h> 36*5c072c8eSSepherosa Ziehau 37*5c072c8eSSepherosa Ziehau #include <dev/hyperv/include/hyperv.h> 38*5c072c8eSSepherosa Ziehau #include <dev/hyperv/include/vmbus.h> 39*5c072c8eSSepherosa Ziehau #include <dev/hyperv/utilities/vmbus_icreg.h> 40*5c072c8eSSepherosa Ziehau #include <dev/hyperv/utilities/vmbus_icvar.h> 41*5c072c8eSSepherosa Ziehau 42*5c072c8eSSepherosa Ziehau #define VMBUS_SHUTDOWN_FWVER_MAJOR 3 43*5c072c8eSSepherosa Ziehau #define VMBUS_SHUTDOWN_FWVER \ 44*5c072c8eSSepherosa Ziehau VMBUS_IC_VERSION(VMBUS_SHUTDOWN_FWVER_MAJOR, 0) 45*5c072c8eSSepherosa Ziehau 46*5c072c8eSSepherosa Ziehau #define VMBUS_SHUTDOWN_MSGVER_MAJOR 3 47*5c072c8eSSepherosa Ziehau #define VMBUS_SHUTDOWN_MSGVER \ 48*5c072c8eSSepherosa Ziehau VMBUS_IC_VERSION(VMBUS_SHUTDOWN_MSGVER_MAJOR, 0) 49*5c072c8eSSepherosa Ziehau 50*5c072c8eSSepherosa Ziehau static int vmbus_shutdown_probe(device_t); 51*5c072c8eSSepherosa Ziehau static int vmbus_shutdown_attach(device_t); 52*5c072c8eSSepherosa Ziehau 53*5c072c8eSSepherosa Ziehau static const struct vmbus_ic_desc vmbus_shutdown_descs[] = { 54*5c072c8eSSepherosa Ziehau { 55*5c072c8eSSepherosa Ziehau .ic_guid = { .hv_guid = { 56*5c072c8eSSepherosa Ziehau 0x31, 0x60, 0x0b, 0x0e, 0x13, 0x52, 0x34, 0x49, 57*5c072c8eSSepherosa Ziehau 0x81, 0x8b, 0x38, 0xd9, 0x0c, 0xed, 0x39, 0xdb } }, 58*5c072c8eSSepherosa Ziehau .ic_desc = "Hyper-V Shutdown" 59*5c072c8eSSepherosa Ziehau }, 60*5c072c8eSSepherosa Ziehau VMBUS_IC_DESC_END 61*5c072c8eSSepherosa Ziehau }; 62*5c072c8eSSepherosa Ziehau 63*5c072c8eSSepherosa Ziehau static device_method_t vmbus_shutdown_methods[] = { 64*5c072c8eSSepherosa Ziehau /* Device interface */ 65*5c072c8eSSepherosa Ziehau DEVMETHOD(device_probe, vmbus_shutdown_probe), 66*5c072c8eSSepherosa Ziehau DEVMETHOD(device_attach, vmbus_shutdown_attach), 67*5c072c8eSSepherosa Ziehau DEVMETHOD(device_detach, vmbus_ic_detach), 68*5c072c8eSSepherosa Ziehau DEVMETHOD_END 69*5c072c8eSSepherosa Ziehau }; 70*5c072c8eSSepherosa Ziehau 71*5c072c8eSSepherosa Ziehau static driver_t vmbus_shutdown_driver = { 72*5c072c8eSSepherosa Ziehau "hvshutdown", 73*5c072c8eSSepherosa Ziehau vmbus_shutdown_methods, 74*5c072c8eSSepherosa Ziehau sizeof(struct vmbus_ic_softc) 75*5c072c8eSSepherosa Ziehau }; 76*5c072c8eSSepherosa Ziehau 77*5c072c8eSSepherosa Ziehau static devclass_t vmbus_shutdown_devclass; 78*5c072c8eSSepherosa Ziehau 79*5c072c8eSSepherosa Ziehau DRIVER_MODULE(hv_shutdown, vmbus, vmbus_shutdown_driver, 80*5c072c8eSSepherosa Ziehau vmbus_shutdown_devclass, NULL, NULL); 81*5c072c8eSSepherosa Ziehau MODULE_VERSION(hv_shutdown, 1); 82*5c072c8eSSepherosa Ziehau MODULE_DEPEND(hv_shutdown, vmbus, 1, 1, 1); 83*5c072c8eSSepherosa Ziehau 84*5c072c8eSSepherosa Ziehau static void 85*5c072c8eSSepherosa Ziehau vmbus_shutdown_cb(struct vmbus_channel *chan, void *xsc) 86*5c072c8eSSepherosa Ziehau { 87*5c072c8eSSepherosa Ziehau struct vmbus_ic_softc *sc = xsc; 88*5c072c8eSSepherosa Ziehau struct vmbus_icmsg_hdr *hdr; 89*5c072c8eSSepherosa Ziehau struct vmbus_icmsg_shutdown *msg; 90*5c072c8eSSepherosa Ziehau int dlen, error, do_shutdown = 0; 91*5c072c8eSSepherosa Ziehau uint64_t xactid; 92*5c072c8eSSepherosa Ziehau void *data; 93*5c072c8eSSepherosa Ziehau 94*5c072c8eSSepherosa Ziehau /* 95*5c072c8eSSepherosa Ziehau * Receive request. 96*5c072c8eSSepherosa Ziehau */ 97*5c072c8eSSepherosa Ziehau data = sc->ic_buf; 98*5c072c8eSSepherosa Ziehau dlen = sc->ic_buflen; 99*5c072c8eSSepherosa Ziehau error = vmbus_chan_recv(chan, data, &dlen, &xactid); 100*5c072c8eSSepherosa Ziehau KASSERT(error != ENOBUFS, ("icbuf is not large enough")); 101*5c072c8eSSepherosa Ziehau if (error) 102*5c072c8eSSepherosa Ziehau return; 103*5c072c8eSSepherosa Ziehau 104*5c072c8eSSepherosa Ziehau if (dlen < sizeof(*hdr)) { 105*5c072c8eSSepherosa Ziehau device_printf(sc->ic_dev, "invalid data len %d\n", dlen); 106*5c072c8eSSepherosa Ziehau return; 107*5c072c8eSSepherosa Ziehau } 108*5c072c8eSSepherosa Ziehau hdr = data; 109*5c072c8eSSepherosa Ziehau 110*5c072c8eSSepherosa Ziehau /* 111*5c072c8eSSepherosa Ziehau * Update request, which will be echoed back as response. 112*5c072c8eSSepherosa Ziehau */ 113*5c072c8eSSepherosa Ziehau switch (hdr->ic_type) { 114*5c072c8eSSepherosa Ziehau case VMBUS_ICMSG_TYPE_NEGOTIATE: 115*5c072c8eSSepherosa Ziehau error = vmbus_ic_negomsg(sc, data, &dlen, 116*5c072c8eSSepherosa Ziehau VMBUS_SHUTDOWN_FWVER, VMBUS_SHUTDOWN_MSGVER); 117*5c072c8eSSepherosa Ziehau if (error) 118*5c072c8eSSepherosa Ziehau return; 119*5c072c8eSSepherosa Ziehau break; 120*5c072c8eSSepherosa Ziehau 121*5c072c8eSSepherosa Ziehau case VMBUS_ICMSG_TYPE_SHUTDOWN: 122*5c072c8eSSepherosa Ziehau if (dlen < VMBUS_ICMSG_SHUTDOWN_SIZE_MIN) { 123*5c072c8eSSepherosa Ziehau device_printf(sc->ic_dev, "invalid shutdown len %d\n", 124*5c072c8eSSepherosa Ziehau dlen); 125*5c072c8eSSepherosa Ziehau return; 126*5c072c8eSSepherosa Ziehau } 127*5c072c8eSSepherosa Ziehau msg = data; 128*5c072c8eSSepherosa Ziehau 129*5c072c8eSSepherosa Ziehau /* XXX ic_flags definition? */ 130*5c072c8eSSepherosa Ziehau if (msg->ic_haltflags == 0 || msg->ic_haltflags == 1) { 131*5c072c8eSSepherosa Ziehau device_printf(sc->ic_dev, "shutdown requested\n"); 132*5c072c8eSSepherosa Ziehau hdr->ic_status = VMBUS_ICMSG_STATUS_OK; 133*5c072c8eSSepherosa Ziehau do_shutdown = 1; 134*5c072c8eSSepherosa Ziehau } else { 135*5c072c8eSSepherosa Ziehau device_printf(sc->ic_dev, "unknown shutdown flags " 136*5c072c8eSSepherosa Ziehau "0x%08x\n", msg->ic_haltflags); 137*5c072c8eSSepherosa Ziehau hdr->ic_status = VMBUS_ICMSG_STATUS_FAIL; 138*5c072c8eSSepherosa Ziehau } 139*5c072c8eSSepherosa Ziehau break; 140*5c072c8eSSepherosa Ziehau 141*5c072c8eSSepherosa Ziehau default: 142*5c072c8eSSepherosa Ziehau device_printf(sc->ic_dev, "got 0x%08x icmsg\n", hdr->ic_type); 143*5c072c8eSSepherosa Ziehau break; 144*5c072c8eSSepherosa Ziehau } 145*5c072c8eSSepherosa Ziehau 146*5c072c8eSSepherosa Ziehau /* 147*5c072c8eSSepherosa Ziehau * Send response by echoing the request back. 148*5c072c8eSSepherosa Ziehau */ 149*5c072c8eSSepherosa Ziehau vmbus_ic_sendresp(sc, chan, data, dlen, xactid); 150*5c072c8eSSepherosa Ziehau 151*5c072c8eSSepherosa Ziehau if (do_shutdown) 152*5c072c8eSSepherosa Ziehau shutdown_nice(RB_POWEROFF); 153*5c072c8eSSepherosa Ziehau } 154*5c072c8eSSepherosa Ziehau 155*5c072c8eSSepherosa Ziehau static int 156*5c072c8eSSepherosa Ziehau vmbus_shutdown_probe(device_t dev) 157*5c072c8eSSepherosa Ziehau { 158*5c072c8eSSepherosa Ziehau 159*5c072c8eSSepherosa Ziehau return (vmbus_ic_probe(dev, vmbus_shutdown_descs)); 160*5c072c8eSSepherosa Ziehau } 161*5c072c8eSSepherosa Ziehau 162*5c072c8eSSepherosa Ziehau static int 163*5c072c8eSSepherosa Ziehau vmbus_shutdown_attach(device_t dev) 164*5c072c8eSSepherosa Ziehau { 165*5c072c8eSSepherosa Ziehau 166*5c072c8eSSepherosa Ziehau return (vmbus_ic_attach(dev, vmbus_shutdown_cb)); 167*5c072c8eSSepherosa Ziehau } 168