control.c revision 255040
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: head/sys/dev/xen/control/control.c 255040 2013-08-29 19:52:18Z gibbs $");
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
123214077Sgibbs#ifndef XENHVM
124214077Sgibbs#include <sys/sched.h>
125214077Sgibbs#include <sys/smp.h>
126214077Sgibbs#endif
127214077Sgibbs
128214077Sgibbs#include <geom/geom.h>
129214077Sgibbs
130214077Sgibbs#include <machine/_inttypes.h>
131255040Sgibbs#include <machine/intr_machdep.h>
132214077Sgibbs
133214077Sgibbs#include <vm/vm.h>
134214077Sgibbs#include <vm/vm_extern.h>
135214077Sgibbs#include <vm/vm_kern.h>
136214077Sgibbs
137255040Sgibbs#include <xen/xen-os.h>
138214077Sgibbs#include <xen/blkif.h>
139214077Sgibbs#include <xen/evtchn.h>
140214077Sgibbs#include <xen/gnttab.h>
141214077Sgibbs#include <xen/xen_intr.h>
142214077Sgibbs
143214077Sgibbs#include <xen/interface/event_channel.h>
144214077Sgibbs#include <xen/interface/grant_table.h>
145214077Sgibbs
146214077Sgibbs#include <xen/xenbus/xenbusvar.h>
147214077Sgibbs
148255040Sgibbs#include <machine/xen/xenvar.h>
149255040Sgibbs#include <machine/xen/xenfunc.h>
150255040Sgibbs
151214077Sgibbs/*--------------------------- Forward Declarations --------------------------*/
152214077Sgibbs/** Function signature for shutdown event handlers. */
153214077Sgibbstypedef	void (xctrl_shutdown_handler_t)(void);
154214077Sgibbs
155214077Sgibbsstatic xctrl_shutdown_handler_t xctrl_poweroff;
156214077Sgibbsstatic xctrl_shutdown_handler_t xctrl_reboot;
157214077Sgibbsstatic xctrl_shutdown_handler_t xctrl_suspend;
158214077Sgibbsstatic xctrl_shutdown_handler_t xctrl_crash;
159214077Sgibbsstatic xctrl_shutdown_handler_t xctrl_halt;
160214077Sgibbs
161214077Sgibbs/*-------------------------- Private Data Structures -------------------------*/
162214077Sgibbs/** Element type for lookup table of event name to handler. */
163214077Sgibbsstruct xctrl_shutdown_reason {
164214077Sgibbs	const char		 *name;
165214077Sgibbs	xctrl_shutdown_handler_t *handler;
166214077Sgibbs};
167214077Sgibbs
168214077Sgibbs/** Lookup table for shutdown event name to handler. */
169244990Smariusstatic const struct xctrl_shutdown_reason xctrl_shutdown_reasons[] = {
170214077Sgibbs	{ "poweroff", xctrl_poweroff },
171214077Sgibbs	{ "reboot",   xctrl_reboot   },
172214077Sgibbs	{ "suspend",  xctrl_suspend  },
173214077Sgibbs	{ "crash",    xctrl_crash    },
174214077Sgibbs	{ "halt",     xctrl_halt     },
175214077Sgibbs};
176214077Sgibbs
177214077Sgibbsstruct xctrl_softc {
178214077Sgibbs	struct xs_watch    xctrl_watch;
179214077Sgibbs};
180214077Sgibbs
181214077Sgibbs/*------------------------------ Event Handlers ------------------------------*/
182214077Sgibbsstatic void
183214077Sgibbsxctrl_poweroff()
184214077Sgibbs{
185214077Sgibbs	shutdown_nice(RB_POWEROFF|RB_HALT);
186214077Sgibbs}
187214077Sgibbs
188214077Sgibbsstatic void
189214077Sgibbsxctrl_reboot()
190214077Sgibbs{
191214077Sgibbs	shutdown_nice(0);
192214077Sgibbs}
193214077Sgibbs
194214077Sgibbs#ifndef XENHVM
195214077Sgibbsextern void xencons_suspend(void);
196214077Sgibbsextern void xencons_resume(void);
197214077Sgibbs
198214077Sgibbs/* Full PV mode suspension. */
199214077Sgibbsstatic void
200214077Sgibbsxctrl_suspend()
201214077Sgibbs{
202214077Sgibbs	int i, j, k, fpp;
203214077Sgibbs	unsigned long max_pfn, start_info_mfn;
204214077Sgibbs
205225704Sgibbs	EVENTHANDLER_INVOKE(power_suspend);
206225704Sgibbs
207214077Sgibbs#ifdef SMP
208222813Sattilio	struct thread *td;
209222813Sattilio	cpuset_t map;
210244990Smarius	u_int cpuid;
211244990Smarius
212214077Sgibbs	/*
213214077Sgibbs	 * Bind us to CPU 0 and stop any other VCPUs.
214214077Sgibbs	 */
215222813Sattilio	td = curthread;
216222813Sattilio	thread_lock(td);
217222813Sattilio	sched_bind(td, 0);
218222813Sattilio	thread_unlock(td);
219223758Sattilio	cpuid = PCPU_GET(cpuid);
220223758Sattilio	KASSERT(cpuid == 0, ("xen_suspend: not running on cpu 0"));
221214077Sgibbs
222223758Sattilio	map = all_cpus;
223223758Sattilio	CPU_CLR(cpuid, &map);
224222813Sattilio	CPU_NAND(&map, &stopped_cpus);
225222813Sattilio	if (!CPU_EMPTY(&map))
226214077Sgibbs		stop_cpus(map);
227214077Sgibbs#endif
228214077Sgibbs
229225704Sgibbs	/*
230225704Sgibbs	 * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE
231225704Sgibbs	 * drivers need this.
232225704Sgibbs	 */
233225704Sgibbs	mtx_lock(&Giant);
234214077Sgibbs	if (DEVICE_SUSPEND(root_bus) != 0) {
235225704Sgibbs		mtx_unlock(&Giant);
236244990Smarius		printf("%s: device_suspend failed\n", __func__);
237214077Sgibbs#ifdef SMP
238222813Sattilio		if (!CPU_EMPTY(&map))
239214077Sgibbs			restart_cpus(map);
240214077Sgibbs#endif
241214077Sgibbs		return;
242214077Sgibbs	}
243225704Sgibbs	mtx_unlock(&Giant);
244214077Sgibbs
245214077Sgibbs	local_irq_disable();
246214077Sgibbs
247214077Sgibbs	xencons_suspend();
248214077Sgibbs	gnttab_suspend();
249255040Sgibbs	intr_suspend();
250214077Sgibbs
251214077Sgibbs	max_pfn = HYPERVISOR_shared_info->arch.max_pfn;
252214077Sgibbs
253214077Sgibbs	void *shared_info = HYPERVISOR_shared_info;
254214077Sgibbs	HYPERVISOR_shared_info = NULL;
255214077Sgibbs	pmap_kremove((vm_offset_t) shared_info);
256214077Sgibbs	PT_UPDATES_FLUSH();
257214077Sgibbs
258214077Sgibbs	xen_start_info->store_mfn = MFNTOPFN(xen_start_info->store_mfn);
259214077Sgibbs	xen_start_info->console.domU.mfn = MFNTOPFN(xen_start_info->console.domU.mfn);
260214077Sgibbs
261214077Sgibbs	/*
262214077Sgibbs	 * We'll stop somewhere inside this hypercall. When it returns,
263214077Sgibbs	 * we'll start resuming after the restore.
264214077Sgibbs	 */
265214077Sgibbs	start_info_mfn = VTOMFN(xen_start_info);
266214077Sgibbs	pmap_suspend();
267214077Sgibbs	HYPERVISOR_suspend(start_info_mfn);
268214077Sgibbs	pmap_resume();
269214077Sgibbs
270214077Sgibbs	pmap_kenter_ma((vm_offset_t) shared_info, xen_start_info->shared_info);
271214077Sgibbs	HYPERVISOR_shared_info = shared_info;
272214077Sgibbs
273214077Sgibbs	HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
274214077Sgibbs		VTOMFN(xen_pfn_to_mfn_frame_list_list);
275214077Sgibbs
276214077Sgibbs	fpp = PAGE_SIZE/sizeof(unsigned long);
277214077Sgibbs	for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
278214077Sgibbs		if ((j % fpp) == 0) {
279214077Sgibbs			k++;
280214077Sgibbs			xen_pfn_to_mfn_frame_list_list[k] =
281214077Sgibbs				VTOMFN(xen_pfn_to_mfn_frame_list[k]);
282214077Sgibbs			j = 0;
283214077Sgibbs		}
284214077Sgibbs		xen_pfn_to_mfn_frame_list[k][j] =
285214077Sgibbs			VTOMFN(&xen_phys_machine[i]);
286214077Sgibbs	}
287214077Sgibbs	HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
288214077Sgibbs
289214077Sgibbs	gnttab_resume();
290255040Sgibbs	intr_resume();
291214077Sgibbs	local_irq_enable();
292214077Sgibbs	xencons_resume();
293214077Sgibbs
294214077Sgibbs#ifdef CONFIG_SMP
295214077Sgibbs	for_each_cpu(i)
296214077Sgibbs		vcpu_prepare(i);
297214077Sgibbs
298214077Sgibbs#endif
299225704Sgibbs
300214077Sgibbs	/*
301214077Sgibbs	 * Only resume xenbus /after/ we've prepared our VCPUs; otherwise
302214077Sgibbs	 * the VCPU hotplug callback can race with our vcpu_prepare
303214077Sgibbs	 */
304225704Sgibbs	mtx_lock(&Giant);
305214077Sgibbs	DEVICE_RESUME(root_bus);
306225704Sgibbs	mtx_unlock(&Giant);
307214077Sgibbs
308214077Sgibbs#ifdef SMP
309214077Sgibbs	thread_lock(curthread);
310214077Sgibbs	sched_unbind(curthread);
311214077Sgibbs	thread_unlock(curthread);
312222813Sattilio	if (!CPU_EMPTY(&map))
313214077Sgibbs		restart_cpus(map);
314214077Sgibbs#endif
315225704Sgibbs	EVENTHANDLER_INVOKE(power_resume);
316214077Sgibbs}
317214077Sgibbs
318214077Sgibbsstatic void
319214077Sgibbsxen_pv_shutdown_final(void *arg, int howto)
320214077Sgibbs{
321214077Sgibbs	/*
322214077Sgibbs	 * Inform the hypervisor that shutdown is complete.
323214077Sgibbs	 * This is not necessary in HVM domains since Xen
324214077Sgibbs	 * emulates ACPI in that mode and FreeBSD's ACPI
325214077Sgibbs	 * support will request this transition.
326214077Sgibbs	 */
327214077Sgibbs	if (howto & (RB_HALT | RB_POWEROFF))
328214077Sgibbs		HYPERVISOR_shutdown(SHUTDOWN_poweroff);
329214077Sgibbs	else
330214077Sgibbs		HYPERVISOR_shutdown(SHUTDOWN_reboot);
331214077Sgibbs}
332214077Sgibbs
333214077Sgibbs#else
334214077Sgibbsextern void xenpci_resume(void);
335214077Sgibbs
336214077Sgibbs/* HVM mode suspension. */
337214077Sgibbsstatic void
338214077Sgibbsxctrl_suspend()
339214077Sgibbs{
340214077Sgibbs	int suspend_cancelled;
341214077Sgibbs
342225704Sgibbs	EVENTHANDLER_INVOKE(power_suspend);
343225704Sgibbs
344225704Sgibbs	/*
345225704Sgibbs	 * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE
346225704Sgibbs	 * drivers need this.
347225704Sgibbs	 */
348225704Sgibbs	mtx_lock(&Giant);
349244990Smarius	if (DEVICE_SUSPEND(root_bus) != 0) {
350225704Sgibbs		mtx_unlock(&Giant);
351244990Smarius		printf("%s: device_suspend failed\n", __func__);
352214077Sgibbs		return;
353214077Sgibbs	}
354225704Sgibbs	mtx_unlock(&Giant);
355214077Sgibbs
356214077Sgibbs	/*
357214077Sgibbs	 * Prevent any races with evtchn_interrupt() handler.
358214077Sgibbs	 */
359225704Sgibbs	disable_intr();
360255040Sgibbs	intr_suspend();
361214077Sgibbs
362214077Sgibbs	suspend_cancelled = HYPERVISOR_suspend(0);
363214077Sgibbs
364255040Sgibbs	intr_resume();
365255040Sgibbs
366214077Sgibbs	/*
367214077Sgibbs	 * Re-enable interrupts and put the scheduler back to normal.
368214077Sgibbs	 */
369214077Sgibbs	enable_intr();
370214077Sgibbs
371214077Sgibbs	/*
372214077Sgibbs	 * FreeBSD really needs to add DEVICE_SUSPEND_CANCEL or
373214077Sgibbs	 * similar.
374214077Sgibbs	 */
375225704Sgibbs	mtx_lock(&Giant);
376214077Sgibbs	if (!suspend_cancelled)
377214077Sgibbs		DEVICE_RESUME(root_bus);
378225704Sgibbs	mtx_unlock(&Giant);
379225704Sgibbs
380225704Sgibbs	EVENTHANDLER_INVOKE(power_resume);
381214077Sgibbs}
382214077Sgibbs#endif
383214077Sgibbs
384214077Sgibbsstatic void
385214077Sgibbsxctrl_crash()
386214077Sgibbs{
387214077Sgibbs	panic("Xen directed crash");
388214077Sgibbs}
389214077Sgibbs
390214077Sgibbsstatic void
391214077Sgibbsxctrl_halt()
392214077Sgibbs{
393214077Sgibbs	shutdown_nice(RB_HALT);
394214077Sgibbs}
395214077Sgibbs
396214077Sgibbs/*------------------------------ Event Reception -----------------------------*/
397214077Sgibbsstatic void
398214077Sgibbsxctrl_on_watch_event(struct xs_watch *watch, const char **vec, unsigned int len)
399214077Sgibbs{
400244990Smarius	const struct xctrl_shutdown_reason *reason;
401244990Smarius	const struct xctrl_shutdown_reason *last_reason;
402214077Sgibbs	char *result;
403214077Sgibbs	int   error;
404214077Sgibbs	int   result_len;
405214077Sgibbs
406214077Sgibbs	error = xs_read(XST_NIL, "control", "shutdown",
407214077Sgibbs			&result_len, (void **)&result);
408214077Sgibbs	if (error != 0)
409214077Sgibbs		return;
410214077Sgibbs
411214077Sgibbs	reason = xctrl_shutdown_reasons;
412244990Smarius	last_reason = reason + nitems(xctrl_shutdown_reasons);
413214077Sgibbs	while (reason < last_reason) {
414214077Sgibbs
415214077Sgibbs		if (!strcmp(result, reason->name)) {
416214077Sgibbs			reason->handler();
417214077Sgibbs			break;
418214077Sgibbs		}
419214077Sgibbs		reason++;
420214077Sgibbs	}
421214077Sgibbs
422214077Sgibbs	free(result, M_XENSTORE);
423214077Sgibbs}
424214077Sgibbs
425214077Sgibbs/*------------------ Private Device Attachment Functions  --------------------*/
426214077Sgibbs/**
427214077Sgibbs * \brief Identify instances of this device type in the system.
428214077Sgibbs *
429214077Sgibbs * \param driver  The driver performing this identify action.
430214077Sgibbs * \param parent  The NewBus parent device for any devices this method adds.
431214077Sgibbs */
432214077Sgibbsstatic void
433214077Sgibbsxctrl_identify(driver_t *driver __unused, device_t parent)
434214077Sgibbs{
435214077Sgibbs	/*
436214077Sgibbs	 * A single device instance for our driver is always present
437214077Sgibbs	 * in a system operating under Xen.
438214077Sgibbs	 */
439214077Sgibbs	BUS_ADD_CHILD(parent, 0, driver->name, 0);
440214077Sgibbs}
441214077Sgibbs
442214077Sgibbs/**
443214077Sgibbs * \brief Probe for the existance of the Xen Control device
444214077Sgibbs *
445214077Sgibbs * \param dev  NewBus device_t for this Xen control instance.
446214077Sgibbs *
447214077Sgibbs * \return  Always returns 0 indicating success.
448214077Sgibbs */
449214077Sgibbsstatic int
450214077Sgibbsxctrl_probe(device_t dev)
451214077Sgibbs{
452214077Sgibbs	device_set_desc(dev, "Xen Control Device");
453214077Sgibbs
454214077Sgibbs	return (0);
455214077Sgibbs}
456214077Sgibbs
457214077Sgibbs/**
458214077Sgibbs * \brief Attach the Xen control device.
459214077Sgibbs *
460214077Sgibbs * \param dev  NewBus device_t for this Xen control instance.
461214077Sgibbs *
462214077Sgibbs * \return  On success, 0. Otherwise an errno value indicating the
463214077Sgibbs *          type of failure.
464214077Sgibbs */
465214077Sgibbsstatic int
466214077Sgibbsxctrl_attach(device_t dev)
467214077Sgibbs{
468214077Sgibbs	struct xctrl_softc *xctrl;
469214077Sgibbs
470214077Sgibbs	xctrl = device_get_softc(dev);
471214077Sgibbs
472214077Sgibbs	/* Activate watch */
473214077Sgibbs	xctrl->xctrl_watch.node = "control/shutdown";
474214077Sgibbs	xctrl->xctrl_watch.callback = xctrl_on_watch_event;
475222975Sgibbs	xctrl->xctrl_watch.callback_data = (uintptr_t)xctrl;
476214077Sgibbs	xs_register_watch(&xctrl->xctrl_watch);
477214077Sgibbs
478214077Sgibbs#ifndef XENHVM
479214077Sgibbs	EVENTHANDLER_REGISTER(shutdown_final, xen_pv_shutdown_final, NULL,
480214077Sgibbs			      SHUTDOWN_PRI_LAST);
481214077Sgibbs#endif
482214077Sgibbs
483214077Sgibbs	return (0);
484214077Sgibbs}
485214077Sgibbs
486214077Sgibbs/**
487214077Sgibbs * \brief Detach the Xen control device.
488214077Sgibbs *
489214077Sgibbs * \param dev  NewBus device_t for this Xen control device instance.
490214077Sgibbs *
491214077Sgibbs * \return  On success, 0. Otherwise an errno value indicating the
492214077Sgibbs *          type of failure.
493214077Sgibbs */
494214077Sgibbsstatic int
495214077Sgibbsxctrl_detach(device_t dev)
496214077Sgibbs{
497214077Sgibbs	struct xctrl_softc *xctrl;
498214077Sgibbs
499214077Sgibbs	xctrl = device_get_softc(dev);
500214077Sgibbs
501214077Sgibbs	/* Release watch */
502214077Sgibbs	xs_unregister_watch(&xctrl->xctrl_watch);
503214077Sgibbs
504214077Sgibbs	return (0);
505214077Sgibbs}
506214077Sgibbs
507214077Sgibbs/*-------------------- Private Device Attachment Data  -----------------------*/
508214077Sgibbsstatic device_method_t xctrl_methods[] = {
509214077Sgibbs	/* Device interface */
510214077Sgibbs	DEVMETHOD(device_identify,	xctrl_identify),
511214077Sgibbs	DEVMETHOD(device_probe,         xctrl_probe),
512214077Sgibbs	DEVMETHOD(device_attach,        xctrl_attach),
513214077Sgibbs	DEVMETHOD(device_detach,        xctrl_detach),
514214077Sgibbs
515244990Smarius	DEVMETHOD_END
516214077Sgibbs};
517214077Sgibbs
518214077SgibbsDEFINE_CLASS_0(xctrl, xctrl_driver, xctrl_methods, sizeof(struct xctrl_softc));
519214077Sgibbsdevclass_t xctrl_devclass;
520214077Sgibbs
521244990SmariusDRIVER_MODULE(xctrl, xenstore, xctrl_driver, xctrl_devclass, NULL, NULL);
522