manage.c revision 770824bdc421ff58a64db608294323571c949f4c
13e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge/*
23e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge * Handle extern requests for shutdown, reboot and sysrq
33e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge */
43e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/kernel.h>
53e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/err.h>
63e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/reboot.h>
73e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/sysrq.h>
80e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <linux/stop_machine.h>
90e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <linux/freezer.h>
103e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
113e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <xen/xenbus.h>
120e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/grant_table.h>
130e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/events.h>
140e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/hvc-console.h>
150e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/xen-ops.h>
163e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
170e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <asm/xen/hypercall.h>
180e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <asm/xen/page.h>
190e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
200e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingeenum shutdown_state {
210e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	SHUTDOWN_INVALID = -1,
220e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	SHUTDOWN_POWEROFF = 0,
230e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	SHUTDOWN_SUSPEND = 2,
240e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
250e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   report a crash, not be instructed to crash!
260e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   HALT is the same as POWEROFF, as far as we're concerned.  The tools use
270e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   the distinction when we return the reason code to them.  */
280e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 SHUTDOWN_HALT = 4,
290e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge};
303e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
313e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge/* Ignore multiple shutdown requests. */
320e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingestatic enum shutdown_state shutting_down = SHUTDOWN_INVALID;
330e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
34c78277288e3d561d55fb48bc0fe8d6e2cf4d0880Jeremy Fitzhardinge#ifdef CONFIG_PM_SLEEP
350e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingestatic int xen_suspend(void *data)
360e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge{
370e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	int *cancelled = data;
38359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge	int err;
390e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
400e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	BUG_ON(!irqs_disabled());
410e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
42359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge	err = device_power_down(PMSG_SUSPEND);
43359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge	if (err) {
44359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge		printk(KERN_ERR "xen_suspend: device_power_down failed: %d\n",
45359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge		       err);
46359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge		return err;
47359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge	}
48770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki	err = sysdev_suspend(PMSG_SUSPEND);
49770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki	if (err) {
50770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki		printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
51770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki			err);
52770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki		device_power_up(PMSG_RESUME);
53770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki		return err;
54770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki	}
55359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge
560e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	xen_mm_pin_all();
570e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	gnttab_suspend();
580e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	xen_pre_suspend();
590e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
600e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	/*
610e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 * This hypercall returns 1 if suspend was cancelled
620e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 * or the domain was merely checkpointed, and 0 if it
630e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 * is resuming in a new domain.
640e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 */
650e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	*cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
660e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
670e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	xen_post_suspend(*cancelled);
680e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	gnttab_resume();
690e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	xen_mm_unpin_all();
700e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
71770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki	sysdev_resume();
7255ca089e2579de90f048aca2a3030b8b2f864813Stephen Rothwell	device_power_up(PMSG_RESUME);
73359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge
740e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	if (!*cancelled) {
750e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		xen_irq_resume();
760e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		xen_console_resume();
77ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata		xen_timer_resume();
780e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
790e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
800e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	return 0;
810e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge}
820e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
830e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingestatic void do_suspend(void)
840e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge{
850e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	int err;
860e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	int cancelled = 1;
870e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
880e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	shutting_down = SHUTDOWN_SUSPEND;
890e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
900e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#ifdef CONFIG_PREEMPT
910e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	/* If the kernel is preemptible, we need to freeze all the processes
920e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   to prevent them from being in the middle of a pagetable update
930e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   during suspend. */
940e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	err = freeze_processes();
950e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	if (err) {
960e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
970e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		return;
980e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
990e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#endif
1000e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
1010e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	err = device_suspend(PMSG_SUSPEND);
1020e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	if (err) {
1030e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		printk(KERN_ERR "xen suspend: device_suspend %d\n", err);
1040e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		goto out;
1050e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
1060e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
1070e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	printk("suspending xenbus...\n");
1080e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	/* XXX use normal device tree? */
1090e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	xenbus_suspend();
1100e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
11137a7c0f3e3e808b8d24f2187a25d2de39e46d822Rusty Russell	err = stop_machine(xen_suspend, &cancelled, &cpumask_of_cpu(0));
1120e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	if (err) {
1130e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
1140e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		goto out;
1150e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
1160e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
117ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata	if (!cancelled) {
118ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata		xen_arch_resume();
1190e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		xenbus_resume();
120ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata	} else
1210e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		xenbus_suspend_cancel();
1220e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
12355ca089e2579de90f048aca2a3030b8b2f864813Stephen Rothwell	device_resume(PMSG_RESUME);
1240e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
125359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge	/* Make sure timer events get retriggered on all CPUs */
126359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge	clock_was_set();
1270e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingeout:
1280e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#ifdef CONFIG_PREEMPT
1290e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	thaw_processes();
1300e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#endif
1310e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	shutting_down = SHUTDOWN_INVALID;
1320e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge}
133c78277288e3d561d55fb48bc0fe8d6e2cf4d0880Jeremy Fitzhardinge#endif	/* CONFIG_PM_SLEEP */
1343e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1353e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic void shutdown_handler(struct xenbus_watch *watch,
1363e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			     const char **vec, unsigned int len)
1373e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
1383e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	char *str;
1393e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	struct xenbus_transaction xbt;
1403e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	int err;
1413e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1423e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (shutting_down != SHUTDOWN_INVALID)
1433e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
1443e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1453e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge again:
1463e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_start(&xbt);
1473e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err)
1483e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
1493e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1503e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
1513e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	/* Ignore read errors and empty reads. */
1523e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (XENBUS_IS_ERR_READ(str)) {
1533e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		xenbus_transaction_end(xbt, 1);
1543e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
1553e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
1563e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1573e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	xenbus_write(xbt, "control", "shutdown", "");
1583e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1593e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_end(xbt, 0);
1603e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err == -EAGAIN) {
1613e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		kfree(str);
1623e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		goto again;
1633e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
1643e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1653e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (strcmp(str, "poweroff") == 0 ||
1660e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	    strcmp(str, "halt") == 0) {
1670e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		shutting_down = SHUTDOWN_POWEROFF;
1683e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		orderly_poweroff(false);
1690e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	} else if (strcmp(str, "reboot") == 0) {
1700e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		shutting_down = SHUTDOWN_POWEROFF; /* ? */
1713e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		ctrl_alt_del();
1720e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#ifdef CONFIG_PM_SLEEP
1730e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	} else if (strcmp(str, "suspend") == 0) {
1740e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		do_suspend();
1750e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#endif
1760e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	} else {
1773e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
1783e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		shutting_down = SHUTDOWN_INVALID;
1793e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
1803e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1813e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	kfree(str);
1823e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
1833e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1843e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic void sysrq_handler(struct xenbus_watch *watch, const char **vec,
1853e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			  unsigned int len)
1863e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
1873e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	char sysrq_key = '\0';
1883e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	struct xenbus_transaction xbt;
1893e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	int err;
1903e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1913e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge again:
1923e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_start(&xbt);
1933e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err)
1943e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
1953e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
1963e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_ERR "Unable to read sysrq code in "
1973e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		       "control/sysrq\n");
1983e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		xenbus_transaction_end(xbt, 1);
1993e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
2003e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
2013e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2023e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (sysrq_key != '\0')
2033e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
2043e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2053e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_end(xbt, 0);
2063e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err == -EAGAIN)
2073e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		goto again;
2083e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2093e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (sysrq_key != '\0')
2103e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		handle_sysrq(sysrq_key, NULL);
2113e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
2123e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2133e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic struct xenbus_watch shutdown_watch = {
2143e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	.node = "control/shutdown",
2153e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	.callback = shutdown_handler
2163e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge};
2173e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2183e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic struct xenbus_watch sysrq_watch = {
2193e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	.node = "control/sysrq",
2203e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	.callback = sysrq_handler
2213e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge};
2223e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2233e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic int setup_shutdown_watcher(void)
2243e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
2253e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	int err;
2263e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2273e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = register_xenbus_watch(&shutdown_watch);
2283e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err) {
2293e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_ERR "Failed to set shutdown watcher\n");
2303e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return err;
2313e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
2323e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2333e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = register_xenbus_watch(&sysrq_watch);
2343e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err) {
2353e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_ERR "Failed to set sysrq watcher\n");
2363e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return err;
2373e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
2383e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2393e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	return 0;
2403e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
2413e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2423e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic int shutdown_event(struct notifier_block *notifier,
2433e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			  unsigned long event,
2443e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			  void *data)
2453e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
2463e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	setup_shutdown_watcher();
2473e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	return NOTIFY_DONE;
2483e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
2493e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2503e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic int __init setup_shutdown_event(void)
2513e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
2523e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	static struct notifier_block xenstore_notifier = {
2533e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		.notifier_call = shutdown_event
2543e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	};
2553e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	register_xenstore_notifier(&xenstore_notifier);
2563e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2573e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	return 0;
2583e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
2593e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2603e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingesubsys_initcall(setup_shutdown_event);
261