Index: head/sys/dev/hyperv/utilities/hv_heartbeat.c =================================================================== --- head/sys/dev/hyperv/utilities/hv_heartbeat.c (revision 310311) +++ head/sys/dev/hyperv/utilities/hv_heartbeat.c (revision 310312) @@ -1,150 +1,146 @@ /*- * Copyright (c) 2014,2016 Microsoft Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include "vmbus_if.h" #define VMBUS_HEARTBEAT_FWVER_MAJOR 3 #define VMBUS_HEARTBEAT_FWVER \ VMBUS_IC_VERSION(VMBUS_HEARTBEAT_FWVER_MAJOR, 0) #define VMBUS_HEARTBEAT_MSGVER_MAJOR 3 #define VMBUS_HEARTBEAT_MSGVER \ VMBUS_IC_VERSION(VMBUS_HEARTBEAT_MSGVER_MAJOR, 0) static const struct vmbus_ic_desc vmbus_heartbeat_descs[] = { { .ic_guid = { .hv_guid = { 0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e, 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d} }, .ic_desc = "Hyper-V Heartbeat" }, VMBUS_IC_DESC_END }; static void vmbus_heartbeat_cb(struct vmbus_channel *chan, void *xsc) { struct hv_util_sc *sc = xsc; struct vmbus_icmsg_hdr *hdr; int dlen, error; uint64_t xactid; void *data; /* * Receive request. */ data = sc->receive_buffer; dlen = sc->ic_buflen; error = vmbus_chan_recv(chan, data, &dlen, &xactid); KASSERT(error != ENOBUFS, ("icbuf is not large enough")); if (error) return; if (dlen < sizeof(*hdr)) { device_printf(sc->ic_dev, "invalid data len %d\n", dlen); return; } hdr = data; /* * Update request, which will be echoed back as response. */ switch (hdr->ic_type) { case VMBUS_ICMSG_TYPE_NEGOTIATE: error = vmbus_ic_negomsg(sc, data, &dlen, VMBUS_HEARTBEAT_FWVER, VMBUS_HEARTBEAT_MSGVER); if (error) return; break; case VMBUS_ICMSG_TYPE_HEARTBEAT: /* Only ic_seq is a must */ if (dlen < VMBUS_ICMSG_HEARTBEAT_SIZE_MIN) { device_printf(sc->ic_dev, "invalid heartbeat len %d\n", dlen); return; } ((struct vmbus_icmsg_heartbeat *)data)->ic_seq++; break; default: device_printf(sc->ic_dev, "got 0x%08x icmsg\n", hdr->ic_type); break; } /* - * Send response by echoing the updated request back. + * Send response by echoing the request back. */ - hdr->ic_flags = VMBUS_ICMSG_FLAG_XACT | VMBUS_ICMSG_FLAG_RESP; - error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_INBAND, 0, - data, dlen, xactid); - if (error) - device_printf(sc->ic_dev, "resp send failed: %d\n", error); + vmbus_ic_sendresp(sc, chan, data, dlen, xactid); } static int hv_heartbeat_probe(device_t dev) { return (vmbus_ic_probe(dev, vmbus_heartbeat_descs)); } static int hv_heartbeat_attach(device_t dev) { return (hv_util_attach(dev, vmbus_heartbeat_cb)); } static device_method_t heartbeat_methods[] = { /* Device interface */ DEVMETHOD(device_probe, hv_heartbeat_probe), DEVMETHOD(device_attach, hv_heartbeat_attach), DEVMETHOD(device_detach, hv_util_detach), { 0, 0 } }; static driver_t heartbeat_driver = { "hvheartbeat", heartbeat_methods, sizeof(hv_util_sc)}; static devclass_t heartbeat_devclass; DRIVER_MODULE(hv_heartbeat, vmbus, heartbeat_driver, heartbeat_devclass, NULL, NULL); MODULE_VERSION(hv_heartbeat, 1); MODULE_DEPEND(hv_heartbeat, vmbus, 1, 1, 1); Index: head/sys/dev/hyperv/utilities/hv_shutdown.c =================================================================== --- head/sys/dev/hyperv/utilities/hv_shutdown.c (revision 310311) +++ head/sys/dev/hyperv/utilities/hv_shutdown.c (revision 310312) @@ -1,165 +1,161 @@ /*- * Copyright (c) 2014,2016 Microsoft Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include "vmbus_if.h" #define VMBUS_SHUTDOWN_FWVER_MAJOR 3 #define VMBUS_SHUTDOWN_FWVER \ VMBUS_IC_VERSION(VMBUS_SHUTDOWN_FWVER_MAJOR, 0) #define VMBUS_SHUTDOWN_MSGVER_MAJOR 3 #define VMBUS_SHUTDOWN_MSGVER \ VMBUS_IC_VERSION(VMBUS_SHUTDOWN_MSGVER_MAJOR, 0) static const struct vmbus_ic_desc vmbus_shutdown_descs[] = { { .ic_guid = { .hv_guid = { 0x31, 0x60, 0x0b, 0x0e, 0x13, 0x52, 0x34, 0x49, 0x81, 0x8b, 0x38, 0xd9, 0x0c, 0xed, 0x39, 0xdb } }, .ic_desc = "Hyper-V Shutdown" }, VMBUS_IC_DESC_END }; static void vmbus_shutdown_cb(struct vmbus_channel *chan, void *xsc) { struct hv_util_sc *sc = xsc; struct vmbus_icmsg_hdr *hdr; struct vmbus_icmsg_shutdown *msg; int dlen, error, do_shutdown = 0; uint64_t xactid; void *data; /* * Receive request. */ data = sc->receive_buffer; dlen = sc->ic_buflen; error = vmbus_chan_recv(chan, data, &dlen, &xactid); KASSERT(error != ENOBUFS, ("icbuf is not large enough")); if (error) return; if (dlen < sizeof(*hdr)) { device_printf(sc->ic_dev, "invalid data len %d\n", dlen); return; } hdr = data; /* * Update request, which will be echoed back as response. */ switch (hdr->ic_type) { case VMBUS_ICMSG_TYPE_NEGOTIATE: error = vmbus_ic_negomsg(sc, data, &dlen, VMBUS_SHUTDOWN_FWVER, VMBUS_SHUTDOWN_MSGVER); if (error) return; break; case VMBUS_ICMSG_TYPE_SHUTDOWN: if (dlen < VMBUS_ICMSG_SHUTDOWN_SIZE_MIN) { device_printf(sc->ic_dev, "invalid shutdown len %d\n", dlen); return; } msg = data; /* XXX ic_flags definition? */ if (msg->ic_haltflags == 0 || msg->ic_haltflags == 1) { device_printf(sc->ic_dev, "shutdown requested\n"); hdr->ic_status = VMBUS_ICMSG_STATUS_OK; do_shutdown = 1; } else { device_printf(sc->ic_dev, "unknown shutdown flags " "0x%08x\n", msg->ic_haltflags); hdr->ic_status = VMBUS_ICMSG_STATUS_FAIL; } break; default: device_printf(sc->ic_dev, "got 0x%08x icmsg\n", hdr->ic_type); break; } /* - * Send response by echoing the updated request back. + * Send response by echoing the request back. */ - hdr->ic_flags = VMBUS_ICMSG_FLAG_XACT | VMBUS_ICMSG_FLAG_RESP; - error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_INBAND, 0, - data, dlen, xactid); - if (error) - device_printf(sc->ic_dev, "resp send failed: %d\n", error); + vmbus_ic_sendresp(sc, chan, data, dlen, xactid); if (do_shutdown) shutdown_nice(RB_POWEROFF); } static int hv_shutdown_probe(device_t dev) { return (vmbus_ic_probe(dev, vmbus_shutdown_descs)); } static int hv_shutdown_attach(device_t dev) { return (hv_util_attach(dev, vmbus_shutdown_cb)); } static device_method_t shutdown_methods[] = { /* Device interface */ DEVMETHOD(device_probe, hv_shutdown_probe), DEVMETHOD(device_attach, hv_shutdown_attach), DEVMETHOD(device_detach, hv_util_detach), { 0, 0 } }; static driver_t shutdown_driver = { "hvshutdown", shutdown_methods, sizeof(hv_util_sc)}; static devclass_t shutdown_devclass; DRIVER_MODULE(hv_shutdown, vmbus, shutdown_driver, shutdown_devclass, NULL, NULL); MODULE_VERSION(hv_shutdown, 1); MODULE_DEPEND(hv_shutdown, vmbus, 1, 1, 1); Index: head/sys/dev/hyperv/utilities/hv_timesync.c =================================================================== --- head/sys/dev/hyperv/utilities/hv_timesync.c (revision 310311) +++ head/sys/dev/hyperv/utilities/hv_timesync.c (revision 310312) @@ -1,243 +1,239 @@ /*- * Copyright (c) 2014,2016 Microsoft Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "vmbus_if.h" #define VMBUS_TIMESYNC_FWVER_MAJOR 3 #define VMBUS_TIMESYNC_FWVER \ VMBUS_IC_VERSION(VMBUS_TIMESYNC_FWVER_MAJOR, 0) #define VMBUS_TIMESYNC_MSGVER_MAJOR 4 #define VMBUS_TIMESYNC_MSGVER \ VMBUS_IC_VERSION(VMBUS_TIMESYNC_MSGVER_MAJOR, 0) #define VMBUS_TIMESYNC_DORTT(sc) \ ((sc)->ic_msgver >= VMBUS_IC_VERSION(4, 0) && \ (hyperv_features & CPUID_HV_MSR_TIME_REFCNT)) static const struct vmbus_ic_desc vmbus_timesync_descs[] = { { .ic_guid = { .hv_guid = { 0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49, 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf } }, .ic_desc = "Hyper-V Timesync" }, VMBUS_IC_DESC_END }; SYSCTL_NODE(_hw, OID_AUTO, hvtimesync, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, "Hyper-V timesync interface"); static int vmbus_ts_ignore_sync = 0; SYSCTL_INT(_hw_hvtimesync, OID_AUTO, ignore_sync, CTLFLAG_RWTUN, &vmbus_ts_ignore_sync, 0, "Ignore the sync request."); /* * Trigger sample sync when drift exceeds threshold (ms). * Ignore the sample request when set to 0. */ static int vmbus_ts_sample_thresh = 100; SYSCTL_INT(_hw_hvtimesync, OID_AUTO, sample_thresh, CTLFLAG_RWTUN, &vmbus_ts_sample_thresh, 0, "Threshold that makes sample request trigger the sync (unit: ms)."); static int vmbus_ts_sample_verbose = 0; SYSCTL_INT(_hw_hvtimesync, OID_AUTO, sample_verbose, CTLFLAG_RWTUN, &vmbus_ts_sample_verbose, 0, "Increase sample request verbosity."); static void vmbus_timesync(struct hv_util_sc *sc, uint64_t hvtime, uint64_t sent_tc, uint8_t tsflags) { struct timespec vm_ts; uint64_t hv_ns, vm_ns, rtt = 0; if (VMBUS_TIMESYNC_DORTT(sc)) rtt = rdmsr(MSR_HV_TIME_REF_COUNT) - sent_tc; hv_ns = (hvtime - VMBUS_ICMSG_TS_BASE + rtt) * HYPERV_TIMER_NS_FACTOR; nanotime(&vm_ts); vm_ns = (vm_ts.tv_sec * NANOSEC) + vm_ts.tv_nsec; if ((tsflags & VMBUS_ICMSG_TS_FLAG_SYNC) && !vmbus_ts_ignore_sync) { struct timespec hv_ts; if (bootverbose) { device_printf(sc->ic_dev, "apply sync request, " "hv: %ju, vm: %ju\n", (uintmax_t)hv_ns, (uintmax_t)vm_ns); } hv_ts.tv_sec = hv_ns / NANOSEC; hv_ts.tv_nsec = hv_ns % NANOSEC; kern_clock_settime(curthread, CLOCK_REALTIME, &hv_ts); /* Done! */ return; } if ((tsflags & VMBUS_ICMSG_TS_FLAG_SAMPLE) && vmbus_ts_sample_thresh > 0) { int64_t diff; if (vmbus_ts_sample_verbose) { device_printf(sc->ic_dev, "sample request, " "hv: %ju, vm: %ju\n", (uintmax_t)hv_ns, (uintmax_t)vm_ns); } if (hv_ns > vm_ns) diff = hv_ns - vm_ns; else diff = vm_ns - hv_ns; /* nanosec -> millisec */ diff /= 1000000; if (diff > vmbus_ts_sample_thresh) { struct timespec hv_ts; if (bootverbose) { device_printf(sc->ic_dev, "apply sample request, hv: %ju, vm: %ju\n", (uintmax_t)hv_ns, (uintmax_t)vm_ns); } hv_ts.tv_sec = hv_ns / NANOSEC; hv_ts.tv_nsec = hv_ns % NANOSEC; kern_clock_settime(curthread, CLOCK_REALTIME, &hv_ts); } /* Done */ return; } } static void vmbus_timesync_cb(struct vmbus_channel *chan, void *xsc) { struct hv_util_sc *sc = xsc; struct vmbus_icmsg_hdr *hdr; const struct vmbus_icmsg_timesync *msg; int dlen, error; uint64_t xactid; void *data; /* * Receive request. */ data = sc->receive_buffer; dlen = sc->ic_buflen; error = vmbus_chan_recv(chan, data, &dlen, &xactid); KASSERT(error != ENOBUFS, ("icbuf is not large enough")); if (error) return; if (dlen < sizeof(*hdr)) { device_printf(sc->ic_dev, "invalid data len %d\n", dlen); return; } hdr = data; /* * Update request, which will be echoed back as response. */ switch (hdr->ic_type) { case VMBUS_ICMSG_TYPE_NEGOTIATE: error = vmbus_ic_negomsg(sc, data, &dlen, VMBUS_TIMESYNC_FWVER, VMBUS_TIMESYNC_MSGVER); if (error) return; if (VMBUS_TIMESYNC_DORTT(sc)) device_printf(sc->ic_dev, "RTT\n"); break; case VMBUS_ICMSG_TYPE_TIMESYNC: if (dlen < sizeof(*msg)) { device_printf(sc->ic_dev, "invalid timesync len %d\n", dlen); return; } msg = data; vmbus_timesync(sc, msg->ic_hvtime, msg->ic_sent_tc, msg->ic_tsflags); break; default: device_printf(sc->ic_dev, "got 0x%08x icmsg\n", hdr->ic_type); break; } /* - * Send response by echoing the updated request back. + * Send response by echoing the request back. */ - hdr->ic_flags = VMBUS_ICMSG_FLAG_XACT | VMBUS_ICMSG_FLAG_RESP; - error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_INBAND, 0, - data, dlen, xactid); - if (error) - device_printf(sc->ic_dev, "resp send failed: %d\n", error); + vmbus_ic_sendresp(sc, chan, data, dlen, xactid); } static int hv_timesync_probe(device_t dev) { return (vmbus_ic_probe(dev, vmbus_timesync_descs)); } static int hv_timesync_attach(device_t dev) { return (hv_util_attach(dev, vmbus_timesync_cb)); } static device_method_t timesync_methods[] = { /* Device interface */ DEVMETHOD(device_probe, hv_timesync_probe), DEVMETHOD(device_attach, hv_timesync_attach), DEVMETHOD(device_detach, hv_util_detach), { 0, 0 } }; static driver_t timesync_driver = { "hvtimesync", timesync_methods, sizeof(hv_util_sc)}; static devclass_t timesync_devclass; DRIVER_MODULE(hv_timesync, vmbus, timesync_driver, timesync_devclass, NULL, NULL); MODULE_VERSION(hv_timesync, 1); MODULE_DEPEND(hv_timesync, vmbus, 1, 1, 1); Index: head/sys/dev/hyperv/utilities/hv_util.c =================================================================== --- head/sys/dev/hyperv/utilities/hv_util.c (revision 310311) +++ head/sys/dev/hyperv/utilities/hv_util.c (revision 310312) @@ -1,289 +1,307 @@ /*- * Copyright (c) 2014,2016 Microsoft Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ /* * A common driver for all hyper-V util services. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vmbus_if.h" #define VMBUS_IC_BRSIZE (4 * PAGE_SIZE) #define VMBUS_IC_VERCNT 2 #define VMBUS_IC_NEGOSZ \ __offsetof(struct vmbus_icmsg_negotiate, ic_ver[VMBUS_IC_VERCNT]) CTASSERT(VMBUS_IC_NEGOSZ < VMBUS_IC_BRSIZE); static int vmbus_ic_fwver_sysctl(SYSCTL_HANDLER_ARGS); static int vmbus_ic_msgver_sysctl(SYSCTL_HANDLER_ARGS); int vmbus_ic_negomsg(struct hv_util_sc *sc, void *data, int *dlen0, uint32_t fw_ver, uint32_t msg_ver) { struct vmbus_icmsg_negotiate *nego; int i, cnt, dlen = *dlen0, error; uint32_t sel_fw_ver, sel_msg_ver; bool has_fw_ver, has_msg_ver; /* * Preliminary message verification. */ if (dlen < sizeof(*nego)) { device_printf(sc->ic_dev, "truncated ic negotiate, len %d\n", dlen); return (EINVAL); } nego = data; if (nego->ic_fwver_cnt == 0) { device_printf(sc->ic_dev, "ic negotiate does not contain " "framework version %u\n", nego->ic_fwver_cnt); return (EINVAL); } if (nego->ic_msgver_cnt == 0) { device_printf(sc->ic_dev, "ic negotiate does not contain " "message version %u\n", nego->ic_msgver_cnt); return (EINVAL); } cnt = nego->ic_fwver_cnt + nego->ic_msgver_cnt; if (dlen < __offsetof(struct vmbus_icmsg_negotiate, ic_ver[cnt])) { device_printf(sc->ic_dev, "ic negotiate does not contain " "versions %d\n", dlen); return (EINVAL); } error = EOPNOTSUPP; /* * Find the best match framework version. */ has_fw_ver = false; for (i = 0; i < nego->ic_fwver_cnt; ++i) { if (VMBUS_ICVER_LE(nego->ic_ver[i], fw_ver)) { if (!has_fw_ver) { sel_fw_ver = nego->ic_ver[i]; has_fw_ver = true; } else if (VMBUS_ICVER_GT(nego->ic_ver[i], sel_fw_ver)) { sel_fw_ver = nego->ic_ver[i]; } } } if (!has_fw_ver) { device_printf(sc->ic_dev, "failed to select framework " "version\n"); goto done; } /* * Fine the best match message version. */ has_msg_ver = false; for (i = nego->ic_fwver_cnt; i < nego->ic_fwver_cnt + nego->ic_msgver_cnt; ++i) { if (VMBUS_ICVER_LE(nego->ic_ver[i], msg_ver)) { if (!has_msg_ver) { sel_msg_ver = nego->ic_ver[i]; has_msg_ver = true; } else if (VMBUS_ICVER_GT(nego->ic_ver[i], sel_msg_ver)) { sel_msg_ver = nego->ic_ver[i]; } } } if (!has_msg_ver) { device_printf(sc->ic_dev, "failed to select message " "version\n"); goto done; } error = 0; done: if (bootverbose || !has_fw_ver || !has_msg_ver) { if (has_fw_ver) { device_printf(sc->ic_dev, "sel framework version: " "%u.%u\n", VMBUS_ICVER_MAJOR(sel_fw_ver), VMBUS_ICVER_MINOR(sel_fw_ver)); } for (i = 0; i < nego->ic_fwver_cnt; i++) { device_printf(sc->ic_dev, "supp framework version: " "%u.%u\n", VMBUS_ICVER_MAJOR(nego->ic_ver[i]), VMBUS_ICVER_MINOR(nego->ic_ver[i])); } if (has_msg_ver) { device_printf(sc->ic_dev, "sel message version: " "%u.%u\n", VMBUS_ICVER_MAJOR(sel_msg_ver), VMBUS_ICVER_MINOR(sel_msg_ver)); } for (i = nego->ic_fwver_cnt; i < nego->ic_fwver_cnt + nego->ic_msgver_cnt; i++) { device_printf(sc->ic_dev, "supp message version: " "%u.%u\n", VMBUS_ICVER_MAJOR(nego->ic_ver[i]), VMBUS_ICVER_MINOR(nego->ic_ver[i])); } } if (error) return (error); /* Record the selected versions. */ sc->ic_fwver = sel_fw_ver; sc->ic_msgver = sel_msg_ver; /* One framework version. */ nego->ic_fwver_cnt = 1; nego->ic_ver[0] = sel_fw_ver; /* One message version. */ nego->ic_msgver_cnt = 1; nego->ic_ver[1] = sel_msg_ver; /* Update data size. */ nego->ic_hdr.ic_dsize = VMBUS_IC_NEGOSZ - sizeof(struct vmbus_icmsg_hdr); /* Update total size, if necessary. */ if (dlen < VMBUS_IC_NEGOSZ) *dlen0 = VMBUS_IC_NEGOSZ; return (0); } int vmbus_ic_probe(device_t dev, const struct vmbus_ic_desc descs[]) { device_t bus = device_get_parent(dev); const struct vmbus_ic_desc *d; if (resource_disabled(device_get_name(dev), 0)) return (ENXIO); for (d = descs; d->ic_desc != NULL; ++d) { if (VMBUS_PROBE_GUID(bus, dev, &d->ic_guid) == 0) { device_set_desc(dev, d->ic_desc); return (BUS_PROBE_DEFAULT); } } return (ENXIO); } int hv_util_attach(device_t dev, vmbus_chan_callback_t cb) { struct hv_util_sc *sc = device_get_softc(dev); struct vmbus_channel *chan = vmbus_get_channel(dev); struct sysctl_oid_list *child; struct sysctl_ctx_list *ctx; int error; sc->ic_dev = dev; sc->ic_buflen = VMBUS_IC_BRSIZE; sc->receive_buffer = malloc(VMBUS_IC_BRSIZE, M_DEVBUF, M_WAITOK | M_ZERO); /* * These services are not performance critical and do not need * batched reading. Furthermore, some services such as KVP can * only handle one message from the host at a time. * Turn off batched reading for all util drivers before we open the * channel. */ vmbus_chan_set_readbatch(chan, false); error = vmbus_chan_open(chan, VMBUS_IC_BRSIZE, VMBUS_IC_BRSIZE, NULL, 0, cb, sc); if (error) { free(sc->receive_buffer, M_DEVBUF); return (error); } ctx = device_get_sysctl_ctx(dev); child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, vmbus_ic_fwver_sysctl, "A", "framework version"); SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "msg_version", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, vmbus_ic_msgver_sysctl, "A", "message version"); return (0); } static int vmbus_ic_fwver_sysctl(SYSCTL_HANDLER_ARGS) { struct hv_util_sc *sc = arg1; char verstr[16]; snprintf(verstr, sizeof(verstr), "%u.%u", VMBUS_ICVER_MAJOR(sc->ic_fwver), VMBUS_ICVER_MINOR(sc->ic_fwver)); return sysctl_handle_string(oidp, verstr, sizeof(verstr), req); } static int vmbus_ic_msgver_sysctl(SYSCTL_HANDLER_ARGS) { struct hv_util_sc *sc = arg1; char verstr[16]; snprintf(verstr, sizeof(verstr), "%u.%u", VMBUS_ICVER_MAJOR(sc->ic_msgver), VMBUS_ICVER_MINOR(sc->ic_msgver)); return sysctl_handle_string(oidp, verstr, sizeof(verstr), req); } int hv_util_detach(device_t dev) { struct hv_util_sc *sc = device_get_softc(dev); vmbus_chan_close(vmbus_get_channel(dev)); free(sc->receive_buffer, M_DEVBUF); return (0); } + +int +vmbus_ic_sendresp(struct hv_util_sc *sc, struct vmbus_channel *chan, + void *data, int dlen, uint64_t xactid) +{ + struct vmbus_icmsg_hdr *hdr; + int error; + + KASSERT(dlen >= sizeof(*hdr), ("invalid data length %d", dlen)); + hdr = data; + + hdr->ic_flags = VMBUS_ICMSG_FLAG_XACT | VMBUS_ICMSG_FLAG_RESP; + error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_INBAND, 0, + data, dlen, xactid); + if (error) + device_printf(sc->ic_dev, "resp send failed: %d\n", error); + return (error); +} Index: head/sys/dev/hyperv/utilities/hv_util.h =================================================================== --- head/sys/dev/hyperv/utilities/hv_util.h (revision 310311) +++ head/sys/dev/hyperv/utilities/hv_util.h (revision 310312) @@ -1,62 +1,65 @@ /*- * Copyright (c) 2009-2012,2016 Microsoft Corp. * Copyright (c) 2012 NetApp Inc. * Copyright (c) 2012 Citrix Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _HVUTIL_H_ #define _HVUTIL_H_ #include #include /** * hv_util related structures * */ typedef struct hv_util_sc { device_t ic_dev; uint8_t *receive_buffer; int ic_buflen; uint32_t ic_fwver; /* framework version */ uint32_t ic_msgver; /* message version */ } hv_util_sc; struct vmbus_ic_desc { const struct hyperv_guid ic_guid; const char *ic_desc; }; #define VMBUS_IC_DESC_END { .ic_desc = NULL } int hv_util_attach(device_t dev, vmbus_chan_callback_t cb); int hv_util_detach(device_t dev); int vmbus_ic_probe(device_t dev, const struct vmbus_ic_desc descs[]); int vmbus_ic_negomsg(struct hv_util_sc *sc, void *data, int *dlen, uint32_t fw_ver, uint32_t msg_ver); +int vmbus_ic_sendresp(struct hv_util_sc *sc, + struct vmbus_channel *chan, void *data, int dlen, + uint64_t xactid); #endif