1214077Sgibbs/*-
2214077Sgibbs * Copyright (c) 2010 Justin T. Gibbs, Spectra Logic Corporation
3214077Sgibbs * All rights reserved.
4214077Sgibbs *
5214077Sgibbs * Redistribution and use in source and binary forms, with or without
6214077Sgibbs * modification, are permitted provided that the following conditions
7214077Sgibbs * are met:
8214077Sgibbs * 1. Redistributions of source code must retain the above copyright
9214077Sgibbs *    notice, this list of conditions, and the following disclaimer,
10214077Sgibbs *    without modification.
11214077Sgibbs * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12214077Sgibbs *    substantially similar to the "NO WARRANTY" disclaimer below
13214077Sgibbs *    ("Disclaimer") and any redistribution must be conditioned upon
14214077Sgibbs *    including a substantially similar Disclaimer requirement for further
15214077Sgibbs *    binary redistribution.
16214077Sgibbs *
17214077Sgibbs * NO WARRANTY
18214077Sgibbs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19214077Sgibbs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20214077Sgibbs * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21214077Sgibbs * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22214077Sgibbs * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23214077Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24214077Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25214077Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26214077Sgibbs * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27214077Sgibbs * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28214077Sgibbs * POSSIBILITY OF SUCH DAMAGES.
29214077Sgibbs */
30214077Sgibbs
31214077Sgibbs/*-
32214077Sgibbs * PV suspend/resume support:
33214077Sgibbs *
34214077Sgibbs * Copyright (c) 2004 Christian Limpach.
35214077Sgibbs * Copyright (c) 2004-2006,2008 Kip Macy
36214077Sgibbs * All rights reserved.
37214077Sgibbs *
38214077Sgibbs * Redistribution and use in source and binary forms, with or without
39214077Sgibbs * modification, are permitted provided that the following conditions
40214077Sgibbs * are met:
41214077Sgibbs * 1. Redistributions of source code must retain the above copyright
42214077Sgibbs *    notice, this list of conditions and the following disclaimer.
43214077Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
44214077Sgibbs *    notice, this list of conditions and the following disclaimer in the
45214077Sgibbs *    documentation and/or other materials provided with the distribution.
46214077Sgibbs * 3. All advertising materials mentioning features or use of this software
47214077Sgibbs *    must display the following acknowledgement:
48214077Sgibbs *      This product includes software developed by Christian Limpach.
49214077Sgibbs * 4. The name of the author may not be used to endorse or promote products
50214077Sgibbs *    derived from this software without specific prior written permission.
51214077Sgibbs *
52214077Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
53214077Sgibbs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
54214077Sgibbs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
55214077Sgibbs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
56214077Sgibbs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
57214077Sgibbs * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58214077Sgibbs * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59214077Sgibbs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60214077Sgibbs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
61214077Sgibbs * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62214077Sgibbs */
63214077Sgibbs
64214077Sgibbs/*-
65214077Sgibbs * HVM suspend/resume support:
66214077Sgibbs *
67214077Sgibbs * Copyright (c) 2008 Citrix Systems, Inc.
68214077Sgibbs * All rights reserved.
69214077Sgibbs *
70214077Sgibbs * Redistribution and use in source and binary forms, with or without
71214077Sgibbs * modification, are permitted provided that the following conditions
72214077Sgibbs * are met:
73214077Sgibbs * 1. Redistributions of source code must retain the above copyright
74214077Sgibbs *    notice, this list of conditions and the following disclaimer.
75214077Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
76214077Sgibbs *    notice, this list of conditions and the following disclaimer in the
77214077Sgibbs *    documentation and/or other materials provided with the distribution.
78214077Sgibbs *
79214077Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
80214077Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
81214077Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
82214077Sgibbs * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
83214077Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
84214077Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
85214077Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
86214077Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
87214077Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
88214077Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
89214077Sgibbs * SUCH DAMAGE.
90214077Sgibbs */
91214077Sgibbs#include <sys/cdefs.h>
92214077Sgibbs__FBSDID("$FreeBSD$");
93214077Sgibbs
94214077Sgibbs/**
95214077Sgibbs * \file control.c
96214077Sgibbs *
97214077Sgibbs * \brief Device driver to repond to control domain events that impact
98214077Sgibbs *        this VM.
99214077Sgibbs */
100214077Sgibbs
101214077Sgibbs#include <sys/param.h>
102214077Sgibbs#include <sys/systm.h>
103214077Sgibbs#include <sys/kernel.h>
104214077Sgibbs#include <sys/malloc.h>
105214077Sgibbs
106214077Sgibbs#include <sys/bio.h>
107214077Sgibbs#include <sys/bus.h>
108214077Sgibbs#include <sys/conf.h>
109214077Sgibbs#include <sys/disk.h>
110214077Sgibbs#include <sys/fcntl.h>
111214077Sgibbs#include <sys/filedesc.h>
112214077Sgibbs#include <sys/kdb.h>
113214077Sgibbs#include <sys/module.h>
114214077Sgibbs#include <sys/namei.h>
115214077Sgibbs#include <sys/proc.h>
116214077Sgibbs#include <sys/reboot.h>
117214077Sgibbs#include <sys/rman.h>
118225704Sgibbs#include <sys/sched.h>
119214077Sgibbs#include <sys/taskqueue.h>
120214077Sgibbs#include <sys/types.h>
121214077Sgibbs#include <sys/vnode.h>
122214077Sgibbs#include <sys/sched.h>
123214077Sgibbs#include <sys/smp.h>
124255726Sgibbs#include <sys/eventhandler.h>
125214077Sgibbs
126214077Sgibbs#include <geom/geom.h>
127214077Sgibbs
128214077Sgibbs#include <machine/_inttypes.h>
129255040Sgibbs#include <machine/intr_machdep.h>
130214077Sgibbs
131214077Sgibbs#include <vm/vm.h>
132214077Sgibbs#include <vm/vm_extern.h>
133214077Sgibbs#include <vm/vm_kern.h>
134214077Sgibbs
135255040Sgibbs#include <xen/xen-os.h>
136214077Sgibbs#include <xen/blkif.h>
137214077Sgibbs#include <xen/evtchn.h>
138214077Sgibbs#include <xen/gnttab.h>
139214077Sgibbs#include <xen/xen_intr.h>
140214077Sgibbs
141255726Sgibbs#ifdef XENHVM
142255726Sgibbs#include <xen/hvm.h>
143255726Sgibbs#endif
144255726Sgibbs
145214077Sgibbs#include <xen/interface/event_channel.h>
146214077Sgibbs#include <xen/interface/grant_table.h>
147214077Sgibbs
148214077Sgibbs#include <xen/xenbus/xenbusvar.h>
149214077Sgibbs
150255040Sgibbs#include <machine/xen/xenvar.h>
151255040Sgibbs#include <machine/xen/xenfunc.h>
152255040Sgibbs
153214077Sgibbs/*--------------------------- Forward Declarations --------------------------*/
154214077Sgibbs/** Function signature for shutdown event handlers. */
155214077Sgibbstypedef	void (xctrl_shutdown_handler_t)(void);
156214077Sgibbs
157214077Sgibbsstatic xctrl_shutdown_handler_t xctrl_poweroff;
158214077Sgibbsstatic xctrl_shutdown_handler_t xctrl_reboot;
159214077Sgibbsstatic xctrl_shutdown_handler_t xctrl_suspend;
160214077Sgibbsstatic xctrl_shutdown_handler_t xctrl_crash;
161214077Sgibbs
162214077Sgibbs/*-------------------------- Private Data Structures -------------------------*/
163214077Sgibbs/** Element type for lookup table of event name to handler. */
164214077Sgibbsstruct xctrl_shutdown_reason {
165214077Sgibbs	const char		 *name;
166214077Sgibbs	xctrl_shutdown_handler_t *handler;
167214077Sgibbs};
168214077Sgibbs
169214077Sgibbs/** Lookup table for shutdown event name to handler. */
170244990Smariusstatic const struct xctrl_shutdown_reason xctrl_shutdown_reasons[] = {
171214077Sgibbs	{ "poweroff", xctrl_poweroff },
172214077Sgibbs	{ "reboot",   xctrl_reboot   },
173214077Sgibbs	{ "suspend",  xctrl_suspend  },
174214077Sgibbs	{ "crash",    xctrl_crash    },
175258995Sroyger	{ "halt",     xctrl_poweroff },
176214077Sgibbs};
177214077Sgibbs
178214077Sgibbsstruct xctrl_softc {
179214077Sgibbs	struct xs_watch    xctrl_watch;
180214077Sgibbs};
181214077Sgibbs
182214077Sgibbs/*------------------------------ Event Handlers ------------------------------*/
183214077Sgibbsstatic void
184214077Sgibbsxctrl_poweroff()
185214077Sgibbs{
186214077Sgibbs	shutdown_nice(RB_POWEROFF|RB_HALT);
187214077Sgibbs}
188214077Sgibbs
189214077Sgibbsstatic void
190214077Sgibbsxctrl_reboot()
191214077Sgibbs{
192214077Sgibbs	shutdown_nice(0);
193214077Sgibbs}
194214077Sgibbs
195214077Sgibbs#ifndef XENHVM
196214077Sgibbsextern void xencons_suspend(void);
197214077Sgibbsextern void xencons_resume(void);
198214077Sgibbs
199214077Sgibbs/* Full PV mode suspension. */
200214077Sgibbsstatic void
201214077Sgibbsxctrl_suspend()
202214077Sgibbs{
203255726Sgibbs	int i, j, k, fpp, suspend_cancelled;
204214077Sgibbs	unsigned long max_pfn, start_info_mfn;
205214077Sgibbs
206225704Sgibbs	EVENTHANDLER_INVOKE(power_suspend);
207225704Sgibbs
208214077Sgibbs#ifdef SMP
209222813Sattilio	struct thread *td;
210222813Sattilio	cpuset_t map;
211244990Smarius	u_int cpuid;
212244990Smarius
213214077Sgibbs	/*
214214077Sgibbs	 * Bind us to CPU 0 and stop any other VCPUs.
215214077Sgibbs	 */
216222813Sattilio	td = curthread;
217222813Sattilio	thread_lock(td);
218222813Sattilio	sched_bind(td, 0);
219222813Sattilio	thread_unlock(td);
220223758Sattilio	cpuid = PCPU_GET(cpuid);
221223758Sattilio	KASSERT(cpuid == 0, ("xen_suspend: not running on cpu 0"));
222214077Sgibbs
223223758Sattilio	map = all_cpus;
224223758Sattilio	CPU_CLR(cpuid, &map);
225222813Sattilio	CPU_NAND(&map, &stopped_cpus);
226222813Sattilio	if (!CPU_EMPTY(&map))
227214077Sgibbs		stop_cpus(map);
228214077Sgibbs#endif
229214077Sgibbs
230225704Sgibbs	/*
231225704Sgibbs	 * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE
232225704Sgibbs	 * drivers need this.
233225704Sgibbs	 */
234225704Sgibbs	mtx_lock(&Giant);
235214077Sgibbs	if (DEVICE_SUSPEND(root_bus) != 0) {
236225704Sgibbs		mtx_unlock(&Giant);
237244990Smarius		printf("%s: device_suspend failed\n", __func__);
238214077Sgibbs#ifdef SMP
239222813Sattilio		if (!CPU_EMPTY(&map))
240214077Sgibbs			restart_cpus(map);
241214077Sgibbs#endif
242214077Sgibbs		return;
243214077Sgibbs	}
244225704Sgibbs	mtx_unlock(&Giant);
245214077Sgibbs
246214077Sgibbs	local_irq_disable();
247214077Sgibbs
248214077Sgibbs	xencons_suspend();
249214077Sgibbs	gnttab_suspend();
250255040Sgibbs	intr_suspend();
251214077Sgibbs
252214077Sgibbs	max_pfn = HYPERVISOR_shared_info->arch.max_pfn;
253214077Sgibbs
254214077Sgibbs	void *shared_info = HYPERVISOR_shared_info;
255214077Sgibbs	HYPERVISOR_shared_info = NULL;
256214077Sgibbs	pmap_kremove((vm_offset_t) shared_info);
257214077Sgibbs	PT_UPDATES_FLUSH();
258214077Sgibbs
259214077Sgibbs	xen_start_info->store_mfn = MFNTOPFN(xen_start_info->store_mfn);
260214077Sgibbs	xen_start_info->console.domU.mfn = MFNTOPFN(xen_start_info->console.domU.mfn);
261214077Sgibbs
262214077Sgibbs	/*
263214077Sgibbs	 * We'll stop somewhere inside this hypercall. When it returns,
264214077Sgibbs	 * we'll start resuming after the restore.
265214077Sgibbs	 */
266214077Sgibbs	start_info_mfn = VTOMFN(xen_start_info);
267214077Sgibbs	pmap_suspend();
268255726Sgibbs	suspend_cancelled = HYPERVISOR_suspend(start_info_mfn);
269214077Sgibbs	pmap_resume();
270214077Sgibbs
271214077Sgibbs	pmap_kenter_ma((vm_offset_t) shared_info, xen_start_info->shared_info);
272214077Sgibbs	HYPERVISOR_shared_info = shared_info;
273214077Sgibbs
274214077Sgibbs	HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
275214077Sgibbs		VTOMFN(xen_pfn_to_mfn_frame_list_list);
276214077Sgibbs
277214077Sgibbs	fpp = PAGE_SIZE/sizeof(unsigned long);
278214077Sgibbs	for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
279214077Sgibbs		if ((j % fpp) == 0) {
280214077Sgibbs			k++;
281214077Sgibbs			xen_pfn_to_mfn_frame_list_list[k] =
282214077Sgibbs				VTOMFN(xen_pfn_to_mfn_frame_list[k]);
283214077Sgibbs			j = 0;
284214077Sgibbs		}
285214077Sgibbs		xen_pfn_to_mfn_frame_list[k][j] =
286214077Sgibbs			VTOMFN(&xen_phys_machine[i]);
287214077Sgibbs	}
288214077Sgibbs	HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
289214077Sgibbs
290214077Sgibbs	gnttab_resume();
291255726Sgibbs	intr_resume(suspend_cancelled != 0);
292214077Sgibbs	local_irq_enable();
293214077Sgibbs	xencons_resume();
294214077Sgibbs
295214077Sgibbs#ifdef CONFIG_SMP
296214077Sgibbs	for_each_cpu(i)
297214077Sgibbs		vcpu_prepare(i);
298214077Sgibbs
299214077Sgibbs#endif
300225704Sgibbs
301214077Sgibbs	/*
302214077Sgibbs	 * Only resume xenbus /after/ we've prepared our VCPUs; otherwise
303214077Sgibbs	 * the VCPU hotplug callback can race with our vcpu_prepare
304214077Sgibbs	 */
305225704Sgibbs	mtx_lock(&Giant);
306214077Sgibbs	DEVICE_RESUME(root_bus);
307225704Sgibbs	mtx_unlock(&Giant);
308214077Sgibbs
309214077Sgibbs#ifdef SMP
310214077Sgibbs	thread_lock(curthread);
311214077Sgibbs	sched_unbind(curthread);
312214077Sgibbs	thread_unlock(curthread);
313222813Sattilio	if (!CPU_EMPTY(&map))
314214077Sgibbs		restart_cpus(map);
315214077Sgibbs#endif
316225704Sgibbs	EVENTHANDLER_INVOKE(power_resume);
317214077Sgibbs}
318214077Sgibbs
319214077Sgibbsstatic void
320214077Sgibbsxen_pv_shutdown_final(void *arg, int howto)
321214077Sgibbs{
322214077Sgibbs	/*
323214077Sgibbs	 * Inform the hypervisor that shutdown is complete.
324214077Sgibbs	 * This is not necessary in HVM domains since Xen
325214077Sgibbs	 * emulates ACPI in that mode and FreeBSD's ACPI
326214077Sgibbs	 * support will request this transition.
327214077Sgibbs	 */
328214077Sgibbs	if (howto & (RB_HALT | RB_POWEROFF))
329214077Sgibbs		HYPERVISOR_shutdown(SHUTDOWN_poweroff);
330214077Sgibbs	else
331214077Sgibbs		HYPERVISOR_shutdown(SHUTDOWN_reboot);
332214077Sgibbs}
333214077Sgibbs
334214077Sgibbs#else
335214077Sgibbs
336214077Sgibbs/* HVM mode suspension. */
337214077Sgibbsstatic void
338214077Sgibbsxctrl_suspend()
339214077Sgibbs{
340255726Sgibbs#ifdef SMP
341255726Sgibbs	cpuset_t cpu_suspend_map;
342255726Sgibbs#endif
343214077Sgibbs	int suspend_cancelled;
344214077Sgibbs
345225704Sgibbs	EVENTHANDLER_INVOKE(power_suspend);
346225704Sgibbs
347255726Sgibbs	if (smp_started) {
348255726Sgibbs		thread_lock(curthread);
349255726Sgibbs		sched_bind(curthread, 0);
350255726Sgibbs		thread_unlock(curthread);
351255726Sgibbs	}
352255726Sgibbs	KASSERT((PCPU_GET(cpuid) == 0), ("Not running on CPU#0"));
353255726Sgibbs
354225704Sgibbs	/*
355255726Sgibbs	 * Clear our XenStore node so the toolstack knows we are
356255726Sgibbs	 * responding to the suspend request.
357255726Sgibbs	 */
358255726Sgibbs	xs_write(XST_NIL, "control", "shutdown", "");
359255726Sgibbs
360255726Sgibbs	/*
361225704Sgibbs	 * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE
362225704Sgibbs	 * drivers need this.
363225704Sgibbs	 */
364225704Sgibbs	mtx_lock(&Giant);
365244990Smarius	if (DEVICE_SUSPEND(root_bus) != 0) {
366225704Sgibbs		mtx_unlock(&Giant);
367244990Smarius		printf("%s: device_suspend failed\n", __func__);
368214077Sgibbs		return;
369214077Sgibbs	}
370225704Sgibbs	mtx_unlock(&Giant);
371214077Sgibbs
372255726Sgibbs#ifdef SMP
373256117Sdim	CPU_ZERO(&cpu_suspend_map);	/* silence gcc */
374255726Sgibbs	if (smp_started) {
375255726Sgibbs		/*
376255726Sgibbs		 * Suspend other CPUs. This prevents IPIs while we
377255726Sgibbs		 * are resuming, and will allow us to reset per-cpu
378255726Sgibbs		 * vcpu_info on resume.
379255726Sgibbs		 */
380255726Sgibbs		cpu_suspend_map = all_cpus;
381255726Sgibbs		CPU_CLR(PCPU_GET(cpuid), &cpu_suspend_map);
382255726Sgibbs		if (!CPU_EMPTY(&cpu_suspend_map))
383255726Sgibbs			suspend_cpus(cpu_suspend_map);
384255726Sgibbs	}
385255726Sgibbs#endif
386255726Sgibbs
387214077Sgibbs	/*
388214077Sgibbs	 * Prevent any races with evtchn_interrupt() handler.
389214077Sgibbs	 */
390225704Sgibbs	disable_intr();
391255040Sgibbs	intr_suspend();
392255726Sgibbs	xen_hvm_suspend();
393214077Sgibbs
394214077Sgibbs	suspend_cancelled = HYPERVISOR_suspend(0);
395214077Sgibbs
396255726Sgibbs	xen_hvm_resume(suspend_cancelled != 0);
397255726Sgibbs	intr_resume(suspend_cancelled != 0);
398255726Sgibbs	enable_intr();
399255040Sgibbs
400214077Sgibbs	/*
401255726Sgibbs	 * Reset grant table info.
402214077Sgibbs	 */
403255726Sgibbs	gnttab_resume();
404214077Sgibbs
405255726Sgibbs#ifdef SMP
406255726Sgibbs	if (smp_started && !CPU_EMPTY(&cpu_suspend_map)) {
407255726Sgibbs		/*
408255726Sgibbs		 * Now that event channels have been initialized,
409255726Sgibbs		 * resume CPUs.
410255726Sgibbs		 */
411255726Sgibbs		resume_cpus(cpu_suspend_map);
412255726Sgibbs	}
413255726Sgibbs#endif
414255726Sgibbs
415214077Sgibbs	/*
416214077Sgibbs	 * FreeBSD really needs to add DEVICE_SUSPEND_CANCEL or
417214077Sgibbs	 * similar.
418214077Sgibbs	 */
419225704Sgibbs	mtx_lock(&Giant);
420255726Sgibbs	DEVICE_RESUME(root_bus);
421225704Sgibbs	mtx_unlock(&Giant);
422225704Sgibbs
423255726Sgibbs	if (smp_started) {
424255726Sgibbs		thread_lock(curthread);
425255726Sgibbs		sched_unbind(curthread);
426255726Sgibbs		thread_unlock(curthread);
427255726Sgibbs	}
428255726Sgibbs
429225704Sgibbs	EVENTHANDLER_INVOKE(power_resume);
430255726Sgibbs
431255726Sgibbs	if (bootverbose)
432255726Sgibbs		printf("System resumed after suspension\n");
433255726Sgibbs
434214077Sgibbs}
435214077Sgibbs#endif
436214077Sgibbs
437214077Sgibbsstatic void
438214077Sgibbsxctrl_crash()
439214077Sgibbs{
440214077Sgibbs	panic("Xen directed crash");
441214077Sgibbs}
442214077Sgibbs
443214077Sgibbs/*------------------------------ Event Reception -----------------------------*/
444214077Sgibbsstatic void
445214077Sgibbsxctrl_on_watch_event(struct xs_watch *watch, const char **vec, unsigned int len)
446214077Sgibbs{
447244990Smarius	const struct xctrl_shutdown_reason *reason;
448244990Smarius	const struct xctrl_shutdown_reason *last_reason;
449214077Sgibbs	char *result;
450214077Sgibbs	int   error;
451214077Sgibbs	int   result_len;
452214077Sgibbs
453214077Sgibbs	error = xs_read(XST_NIL, "control", "shutdown",
454214077Sgibbs			&result_len, (void **)&result);
455214077Sgibbs	if (error != 0)
456214077Sgibbs		return;
457214077Sgibbs
458214077Sgibbs	reason = xctrl_shutdown_reasons;
459244990Smarius	last_reason = reason + nitems(xctrl_shutdown_reasons);
460214077Sgibbs	while (reason < last_reason) {
461214077Sgibbs
462214077Sgibbs		if (!strcmp(result, reason->name)) {
463214077Sgibbs			reason->handler();
464214077Sgibbs			break;
465214077Sgibbs		}
466214077Sgibbs		reason++;
467214077Sgibbs	}
468214077Sgibbs
469214077Sgibbs	free(result, M_XENSTORE);
470214077Sgibbs}
471214077Sgibbs
472214077Sgibbs/*------------------ Private Device Attachment Functions  --------------------*/
473214077Sgibbs/**
474214077Sgibbs * \brief Identify instances of this device type in the system.
475214077Sgibbs *
476214077Sgibbs * \param driver  The driver performing this identify action.
477214077Sgibbs * \param parent  The NewBus parent device for any devices this method adds.
478214077Sgibbs */
479214077Sgibbsstatic void
480214077Sgibbsxctrl_identify(driver_t *driver __unused, device_t parent)
481214077Sgibbs{
482214077Sgibbs	/*
483214077Sgibbs	 * A single device instance for our driver is always present
484214077Sgibbs	 * in a system operating under Xen.
485214077Sgibbs	 */
486214077Sgibbs	BUS_ADD_CHILD(parent, 0, driver->name, 0);
487214077Sgibbs}
488214077Sgibbs
489214077Sgibbs/**
490214077Sgibbs * \brief Probe for the existance of the Xen Control device
491214077Sgibbs *
492214077Sgibbs * \param dev  NewBus device_t for this Xen control instance.
493214077Sgibbs *
494214077Sgibbs * \return  Always returns 0 indicating success.
495214077Sgibbs */
496214077Sgibbsstatic int
497214077Sgibbsxctrl_probe(device_t dev)
498214077Sgibbs{
499214077Sgibbs	device_set_desc(dev, "Xen Control Device");
500214077Sgibbs
501214077Sgibbs	return (0);
502214077Sgibbs}
503214077Sgibbs
504214077Sgibbs/**
505214077Sgibbs * \brief Attach the Xen control device.
506214077Sgibbs *
507214077Sgibbs * \param dev  NewBus device_t for this Xen control instance.
508214077Sgibbs *
509214077Sgibbs * \return  On success, 0. Otherwise an errno value indicating the
510214077Sgibbs *          type of failure.
511214077Sgibbs */
512214077Sgibbsstatic int
513214077Sgibbsxctrl_attach(device_t dev)
514214077Sgibbs{
515214077Sgibbs	struct xctrl_softc *xctrl;
516214077Sgibbs
517214077Sgibbs	xctrl = device_get_softc(dev);
518214077Sgibbs
519214077Sgibbs	/* Activate watch */
520214077Sgibbs	xctrl->xctrl_watch.node = "control/shutdown";
521214077Sgibbs	xctrl->xctrl_watch.callback = xctrl_on_watch_event;
522222975Sgibbs	xctrl->xctrl_watch.callback_data = (uintptr_t)xctrl;
523214077Sgibbs	xs_register_watch(&xctrl->xctrl_watch);
524214077Sgibbs
525214077Sgibbs#ifndef XENHVM
526214077Sgibbs	EVENTHANDLER_REGISTER(shutdown_final, xen_pv_shutdown_final, NULL,
527214077Sgibbs			      SHUTDOWN_PRI_LAST);
528214077Sgibbs#endif
529214077Sgibbs
530214077Sgibbs	return (0);
531214077Sgibbs}
532214077Sgibbs
533214077Sgibbs/**
534214077Sgibbs * \brief Detach the Xen control device.
535214077Sgibbs *
536214077Sgibbs * \param dev  NewBus device_t for this Xen control device instance.
537214077Sgibbs *
538214077Sgibbs * \return  On success, 0. Otherwise an errno value indicating the
539214077Sgibbs *          type of failure.
540214077Sgibbs */
541214077Sgibbsstatic int
542214077Sgibbsxctrl_detach(device_t dev)
543214077Sgibbs{
544214077Sgibbs	struct xctrl_softc *xctrl;
545214077Sgibbs
546214077Sgibbs	xctrl = device_get_softc(dev);
547214077Sgibbs
548214077Sgibbs	/* Release watch */
549214077Sgibbs	xs_unregister_watch(&xctrl->xctrl_watch);
550214077Sgibbs
551214077Sgibbs	return (0);
552214077Sgibbs}
553214077Sgibbs
554214077Sgibbs/*-------------------- Private Device Attachment Data  -----------------------*/
555214077Sgibbsstatic device_method_t xctrl_methods[] = {
556214077Sgibbs	/* Device interface */
557214077Sgibbs	DEVMETHOD(device_identify,	xctrl_identify),
558214077Sgibbs	DEVMETHOD(device_probe,         xctrl_probe),
559214077Sgibbs	DEVMETHOD(device_attach,        xctrl_attach),
560214077Sgibbs	DEVMETHOD(device_detach,        xctrl_detach),
561214077Sgibbs
562244990Smarius	DEVMETHOD_END
563214077Sgibbs};
564214077Sgibbs
565214077SgibbsDEFINE_CLASS_0(xctrl, xctrl_driver, xctrl_methods, sizeof(struct xctrl_softc));
566214077Sgibbsdevclass_t xctrl_devclass;
567214077Sgibbs
568244990SmariusDRIVER_MODULE(xctrl, xenstore, xctrl_driver, xctrl_devclass, NULL, NULL);
569