xref: /openbmc/linux/drivers/xen/manage.c (revision 87dffe86)
1ec9b2065SIsaku Yamahata /*
2ec9b2065SIsaku Yamahata  * Handle extern requests for shutdown, reboot and sysrq
3ec9b2065SIsaku Yamahata  */
4283c0972SJoe Perches 
5283c0972SJoe Perches #define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
6283c0972SJoe Perches 
7ec9b2065SIsaku Yamahata #include <linux/kernel.h>
8ec9b2065SIsaku Yamahata #include <linux/err.h>
95a0e3ad6STejun Heo #include <linux/slab.h>
10ec9b2065SIsaku Yamahata #include <linux/reboot.h>
11ec9b2065SIsaku Yamahata #include <linux/sysrq.h>
120e91398fSJeremy Fitzhardinge #include <linux/stop_machine.h>
130e91398fSJeremy Fitzhardinge #include <linux/freezer.h>
1419234c08SRafael J. Wysocki #include <linux/syscore_ops.h>
1563c9744bSPaul Gortmaker #include <linux/export.h>
16ec9b2065SIsaku Yamahata 
17016b6f5fSStefano Stabellini #include <xen/xen.h>
18ec9b2065SIsaku Yamahata #include <xen/xenbus.h>
190e91398fSJeremy Fitzhardinge #include <xen/grant_table.h>
200e91398fSJeremy Fitzhardinge #include <xen/events.h>
210e91398fSJeremy Fitzhardinge #include <xen/hvc-console.h>
22a9fd60e2SJulien Grall #include <xen/page.h>
230e91398fSJeremy Fitzhardinge #include <xen/xen-ops.h>
24ec9b2065SIsaku Yamahata 
250e91398fSJeremy Fitzhardinge #include <asm/xen/hypercall.h>
26016b6f5fSStefano Stabellini #include <asm/xen/hypervisor.h>
270e91398fSJeremy Fitzhardinge 
280e91398fSJeremy Fitzhardinge enum shutdown_state {
290e91398fSJeremy Fitzhardinge 	SHUTDOWN_INVALID = -1,
300e91398fSJeremy Fitzhardinge 	SHUTDOWN_POWEROFF = 0,
310e91398fSJeremy Fitzhardinge 	SHUTDOWN_SUSPEND = 2,
32ec9b2065SIsaku Yamahata 	/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
330e91398fSJeremy Fitzhardinge 	   report a crash, not be instructed to crash!
340e91398fSJeremy Fitzhardinge 	   HALT is the same as POWEROFF, as far as we're concerned.  The tools use
350e91398fSJeremy Fitzhardinge 	   the distinction when we return the reason code to them.  */
360e91398fSJeremy Fitzhardinge 	 SHUTDOWN_HALT = 4,
370e91398fSJeremy Fitzhardinge };
38ec9b2065SIsaku Yamahata 
39ec9b2065SIsaku Yamahata /* Ignore multiple shutdown requests. */
400e91398fSJeremy Fitzhardinge static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
410e91398fSJeremy Fitzhardinge 
42ceb18029SIan Campbell struct suspend_info {
43ceb18029SIan Campbell 	int cancelled;
44ceb18029SIan Campbell };
45ceb18029SIan Campbell 
46cd979883SStanislaw Gruszka static RAW_NOTIFIER_HEAD(xen_resume_notifier);
47cd979883SStanislaw Gruszka 
48cd979883SStanislaw Gruszka void xen_resume_notifier_register(struct notifier_block *nb)
49cd979883SStanislaw Gruszka {
50cd979883SStanislaw Gruszka 	raw_notifier_chain_register(&xen_resume_notifier, nb);
51cd979883SStanislaw Gruszka }
52cd979883SStanislaw Gruszka EXPORT_SYMBOL_GPL(xen_resume_notifier_register);
53cd979883SStanislaw Gruszka 
54cd979883SStanislaw Gruszka void xen_resume_notifier_unregister(struct notifier_block *nb)
55cd979883SStanislaw Gruszka {
56cd979883SStanislaw Gruszka 	raw_notifier_chain_unregister(&xen_resume_notifier, nb);
57cd979883SStanislaw Gruszka }
58cd979883SStanislaw Gruszka EXPORT_SYMBOL_GPL(xen_resume_notifier_unregister);
59cd979883SStanislaw Gruszka 
6065e053a7SStefano Stabellini #ifdef CONFIG_HIBERNATE_CALLBACKS
610e91398fSJeremy Fitzhardinge static int xen_suspend(void *data)
620e91398fSJeremy Fitzhardinge {
63ceb18029SIan Campbell 	struct suspend_info *si = data;
64359cdd3fSJeremy Fitzhardinge 	int err;
650e91398fSJeremy Fitzhardinge 
660e91398fSJeremy Fitzhardinge 	BUG_ON(!irqs_disabled());
670e91398fSJeremy Fitzhardinge 
6819234c08SRafael J. Wysocki 	err = syscore_suspend();
69770824bdSRafael J. Wysocki 	if (err) {
70283c0972SJoe Perches 		pr_err("%s: system core suspend failed: %d\n", __func__, err);
71770824bdSRafael J. Wysocki 		return err;
72770824bdSRafael J. Wysocki 	}
73359cdd3fSJeremy Fitzhardinge 
74aa8532c3SDavid Vrabel 	gnttab_suspend();
755e25f5dbSDongli Zhang 	xen_manage_runstate_time(-1);
76aa8532c3SDavid Vrabel 	xen_arch_pre_suspend();
770e91398fSJeremy Fitzhardinge 
78aa8532c3SDavid Vrabel 	si->cancelled = HYPERVISOR_suspend(xen_pv_domain()
790df4f266SJulien Grall                                            ? virt_to_gfn(xen_start_info)
80aa8532c3SDavid Vrabel                                            : 0);
810e91398fSJeremy Fitzhardinge 
82aa8532c3SDavid Vrabel 	xen_arch_post_suspend(si->cancelled);
835e25f5dbSDongli Zhang 	xen_manage_runstate_time(si->cancelled ? 1 : 0);
84aa8532c3SDavid Vrabel 	gnttab_resume();
850e91398fSJeremy Fitzhardinge 
86ceb18029SIan Campbell 	if (!si->cancelled) {
870e91398fSJeremy Fitzhardinge 		xen_irq_resume();
88ad55db9fSIsaku Yamahata 		xen_timer_resume();
890e91398fSJeremy Fitzhardinge 	}
900e91398fSJeremy Fitzhardinge 
9119234c08SRafael J. Wysocki 	syscore_resume();
921e6fcf84SIan Campbell 
930e91398fSJeremy Fitzhardinge 	return 0;
940e91398fSJeremy Fitzhardinge }
950e91398fSJeremy Fitzhardinge 
960e91398fSJeremy Fitzhardinge static void do_suspend(void)
970e91398fSJeremy Fitzhardinge {
980e91398fSJeremy Fitzhardinge 	int err;
99ceb18029SIan Campbell 	struct suspend_info si;
1000e91398fSJeremy Fitzhardinge 
1010e91398fSJeremy Fitzhardinge 	shutting_down = SHUTDOWN_SUSPEND;
1020e91398fSJeremy Fitzhardinge 
1030e91398fSJeremy Fitzhardinge 	err = freeze_processes();
1040e91398fSJeremy Fitzhardinge 	if (err) {
10572978b2fSRoss Lagerwall 		pr_err("%s: freeze processes failed %d\n", __func__, err);
1063fc1f1e2STejun Heo 		goto out;
1070e91398fSJeremy Fitzhardinge 	}
1080e91398fSJeremy Fitzhardinge 
10972978b2fSRoss Lagerwall 	err = freeze_kernel_threads();
11072978b2fSRoss Lagerwall 	if (err) {
11172978b2fSRoss Lagerwall 		pr_err("%s: freeze kernel threads failed %d\n", __func__, err);
11272978b2fSRoss Lagerwall 		goto out_thaw;
11372978b2fSRoss Lagerwall 	}
11472978b2fSRoss Lagerwall 
115b3e96c0cSShriram Rajagopalan 	err = dpm_suspend_start(PMSG_FREEZE);
1160e91398fSJeremy Fitzhardinge 	if (err) {
117283c0972SJoe Perches 		pr_err("%s: dpm_suspend_start %d\n", __func__, err);
11865f63384SIan Campbell 		goto out_thaw;
1190e91398fSJeremy Fitzhardinge 	}
1200e91398fSJeremy Fitzhardinge 
121c5cae661SIan Campbell 	printk(KERN_DEBUG "suspending xenstore...\n");
122c5cae661SIan Campbell 	xs_suspend();
123c5cae661SIan Campbell 
124cf579dfbSRafael J. Wysocki 	err = dpm_suspend_end(PMSG_FREEZE);
1252ed8d2b3SRafael J. Wysocki 	if (err) {
126283c0972SJoe Perches 		pr_err("dpm_suspend_end failed: %d\n", err);
127186bab1cSKonrad Rzeszutek Wilk 		si.cancelled = 0;
12865f63384SIan Campbell 		goto out_resume;
1292ed8d2b3SRafael J. Wysocki 	}
1302ed8d2b3SRafael J. Wysocki 
1312b953a5eSBoris Ostrovsky 	xen_arch_suspend();
1322b953a5eSBoris Ostrovsky 
133ceb18029SIan Campbell 	si.cancelled = 1;
134ceb18029SIan Campbell 
135ceb18029SIan Campbell 	err = stop_machine(xen_suspend, &si, cpumask_of(0));
136922cc38aSJeremy Fitzhardinge 
1371b647823SDavid Vrabel 	/* Resume console as early as possible. */
1381b647823SDavid Vrabel 	if (!si.cancelled)
1391b647823SDavid Vrabel 		xen_console_resume();
1401b647823SDavid Vrabel 
141cd979883SStanislaw Gruszka 	raw_notifier_call_chain(&xen_resume_notifier, 0, NULL);
142cd979883SStanislaw Gruszka 
143cf579dfbSRafael J. Wysocki 	dpm_resume_start(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
144922cc38aSJeremy Fitzhardinge 
1450e91398fSJeremy Fitzhardinge 	if (err) {
146283c0972SJoe Perches 		pr_err("failed to start xen_suspend: %d\n", err);
147ceb18029SIan Campbell 		si.cancelled = 1;
1480e91398fSJeremy Fitzhardinge 	}
1490e91398fSJeremy Fitzhardinge 
150ad55db9fSIsaku Yamahata 	xen_arch_resume();
1512b953a5eSBoris Ostrovsky 
1522b953a5eSBoris Ostrovsky out_resume:
1532b953a5eSBoris Ostrovsky 	if (!si.cancelled)
154de5b31bdSIan Campbell 		xs_resume();
1552b953a5eSBoris Ostrovsky 	else
156de5b31bdSIan Campbell 		xs_suspend_cancel();
1570e91398fSJeremy Fitzhardinge 
158b3e96c0cSShriram Rajagopalan 	dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
1590e91398fSJeremy Fitzhardinge 
16065f63384SIan Campbell out_thaw:
1610e91398fSJeremy Fitzhardinge 	thaw_processes();
16265f63384SIan Campbell out:
1630e91398fSJeremy Fitzhardinge 	shutting_down = SHUTDOWN_INVALID;
1640e91398fSJeremy Fitzhardinge }
1651f112ceeSRafael J. Wysocki #endif	/* CONFIG_HIBERNATE_CALLBACKS */
166ec9b2065SIsaku Yamahata 
16755271723SIan Campbell struct shutdown_handler {
16844b3c7afSJuergen Gross #define SHUTDOWN_CMD_SIZE 11
16944b3c7afSJuergen Gross 	const char command[SHUTDOWN_CMD_SIZE];
17044b3c7afSJuergen Gross 	bool flag;
17155271723SIan Campbell 	void (*cb)(void);
17255271723SIan Campbell };
17355271723SIan Campbell 
174eb47f712SKonrad Rzeszutek Wilk static int poweroff_nb(struct notifier_block *cb, unsigned long code, void *unused)
175eb47f712SKonrad Rzeszutek Wilk {
176eb47f712SKonrad Rzeszutek Wilk 	switch (code) {
177eb47f712SKonrad Rzeszutek Wilk 	case SYS_DOWN:
178eb47f712SKonrad Rzeszutek Wilk 	case SYS_HALT:
179eb47f712SKonrad Rzeszutek Wilk 	case SYS_POWER_OFF:
180eb47f712SKonrad Rzeszutek Wilk 		shutting_down = SHUTDOWN_POWEROFF;
181eb47f712SKonrad Rzeszutek Wilk 	default:
182eb47f712SKonrad Rzeszutek Wilk 		break;
183eb47f712SKonrad Rzeszutek Wilk 	}
184eb47f712SKonrad Rzeszutek Wilk 	return NOTIFY_DONE;
185eb47f712SKonrad Rzeszutek Wilk }
18655271723SIan Campbell static void do_poweroff(void)
18755271723SIan Campbell {
188eb47f712SKonrad Rzeszutek Wilk 	switch (system_state) {
189eb47f712SKonrad Rzeszutek Wilk 	case SYSTEM_BOOTING:
19069a78ff2SThomas Gleixner 	case SYSTEM_SCHEDULING:
191eb47f712SKonrad Rzeszutek Wilk 		orderly_poweroff(true);
192eb47f712SKonrad Rzeszutek Wilk 		break;
193eb47f712SKonrad Rzeszutek Wilk 	case SYSTEM_RUNNING:
19455271723SIan Campbell 		orderly_poweroff(false);
195eb47f712SKonrad Rzeszutek Wilk 		break;
196eb47f712SKonrad Rzeszutek Wilk 	default:
197eb47f712SKonrad Rzeszutek Wilk 		/* Don't do it when we are halting/rebooting. */
198eb47f712SKonrad Rzeszutek Wilk 		pr_info("Ignoring Xen toolstack shutdown.\n");
199eb47f712SKonrad Rzeszutek Wilk 		break;
200eb47f712SKonrad Rzeszutek Wilk 	}
20155271723SIan Campbell }
20255271723SIan Campbell 
20355271723SIan Campbell static void do_reboot(void)
20455271723SIan Campbell {
20555271723SIan Campbell 	shutting_down = SHUTDOWN_POWEROFF; /* ? */
20655271723SIan Campbell 	ctrl_alt_del();
20755271723SIan Campbell }
20855271723SIan Campbell 
20944b3c7afSJuergen Gross static struct shutdown_handler shutdown_handlers[] = {
21044b3c7afSJuergen Gross 	{ "poweroff",	true,	do_poweroff },
21144b3c7afSJuergen Gross 	{ "halt",	false,	do_poweroff },
21244b3c7afSJuergen Gross 	{ "reboot",	true,	do_reboot   },
21344b3c7afSJuergen Gross #ifdef CONFIG_HIBERNATE_CALLBACKS
21444b3c7afSJuergen Gross 	{ "suspend",	true,	do_suspend  },
21544b3c7afSJuergen Gross #endif
21644b3c7afSJuergen Gross };
21744b3c7afSJuergen Gross 
218ec9b2065SIsaku Yamahata static void shutdown_handler(struct xenbus_watch *watch,
2195584ea25SJuergen Gross 			     const char *path, const char *token)
220ec9b2065SIsaku Yamahata {
221ec9b2065SIsaku Yamahata 	char *str;
222ec9b2065SIsaku Yamahata 	struct xenbus_transaction xbt;
223ec9b2065SIsaku Yamahata 	int err;
22444b3c7afSJuergen Gross 	int idx;
225ec9b2065SIsaku Yamahata 
226ec9b2065SIsaku Yamahata 	if (shutting_down != SHUTDOWN_INVALID)
227ec9b2065SIsaku Yamahata 		return;
228ec9b2065SIsaku Yamahata 
229ec9b2065SIsaku Yamahata  again:
230ec9b2065SIsaku Yamahata 	err = xenbus_transaction_start(&xbt);
231ec9b2065SIsaku Yamahata 	if (err)
232ec9b2065SIsaku Yamahata 		return;
233ec9b2065SIsaku Yamahata 
234ec9b2065SIsaku Yamahata 	str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
235ec9b2065SIsaku Yamahata 	/* Ignore read errors and empty reads. */
236ec9b2065SIsaku Yamahata 	if (XENBUS_IS_ERR_READ(str)) {
237ec9b2065SIsaku Yamahata 		xenbus_transaction_end(xbt, 1);
238ec9b2065SIsaku Yamahata 		return;
239ec9b2065SIsaku Yamahata 	}
240ec9b2065SIsaku Yamahata 
24144b3c7afSJuergen Gross 	for (idx = 0; idx < ARRAY_SIZE(shutdown_handlers); idx++) {
24244b3c7afSJuergen Gross 		if (strcmp(str, shutdown_handlers[idx].command) == 0)
24355271723SIan Campbell 			break;
24455271723SIan Campbell 	}
24555271723SIan Campbell 
24655271723SIan Campbell 	/* Only acknowledge commands which we are prepared to handle. */
24744b3c7afSJuergen Gross 	if (idx < ARRAY_SIZE(shutdown_handlers))
248ec9b2065SIsaku Yamahata 		xenbus_write(xbt, "control", "shutdown", "");
249ec9b2065SIsaku Yamahata 
250ec9b2065SIsaku Yamahata 	err = xenbus_transaction_end(xbt, 0);
251ec9b2065SIsaku Yamahata 	if (err == -EAGAIN) {
252ec9b2065SIsaku Yamahata 		kfree(str);
253ec9b2065SIsaku Yamahata 		goto again;
254ec9b2065SIsaku Yamahata 	}
255ec9b2065SIsaku Yamahata 
25644b3c7afSJuergen Gross 	if (idx < ARRAY_SIZE(shutdown_handlers)) {
25744b3c7afSJuergen Gross 		shutdown_handlers[idx].cb();
2580e91398fSJeremy Fitzhardinge 	} else {
259283c0972SJoe Perches 		pr_info("Ignoring shutdown request: %s\n", str);
260ec9b2065SIsaku Yamahata 		shutting_down = SHUTDOWN_INVALID;
261ec9b2065SIsaku Yamahata 	}
262ec9b2065SIsaku Yamahata 
263ec9b2065SIsaku Yamahata 	kfree(str);
264ec9b2065SIsaku Yamahata }
265ec9b2065SIsaku Yamahata 
266f3bc3189SRandy Dunlap #ifdef CONFIG_MAGIC_SYSRQ
2675584ea25SJuergen Gross static void sysrq_handler(struct xenbus_watch *watch, const char *path,
2685584ea25SJuergen Gross 			  const char *token)
269ec9b2065SIsaku Yamahata {
270ec9b2065SIsaku Yamahata 	char sysrq_key = '\0';
271ec9b2065SIsaku Yamahata 	struct xenbus_transaction xbt;
272ec9b2065SIsaku Yamahata 	int err;
273ec9b2065SIsaku Yamahata 
274ec9b2065SIsaku Yamahata  again:
275ec9b2065SIsaku Yamahata 	err = xenbus_transaction_start(&xbt);
276ec9b2065SIsaku Yamahata 	if (err)
277ec9b2065SIsaku Yamahata 		return;
2784e93b648SJuergen Gross 	err = xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key);
2794e93b648SJuergen Gross 	if (err < 0) {
2804e93b648SJuergen Gross 		/*
2814e93b648SJuergen Gross 		 * The Xenstore watch fires directly after registering it and
2824e93b648SJuergen Gross 		 * after a suspend/resume cycle. So ENOENT is no error but
28387dffe86SVitaly Kuznetsov 		 * might happen in those cases. ERANGE is observed when we get
28487dffe86SVitaly Kuznetsov 		 * an empty value (''), this happens when we acknowledge the
28587dffe86SVitaly Kuznetsov 		 * request by writing '\0' below.
2864e93b648SJuergen Gross 		 */
28787dffe86SVitaly Kuznetsov 		if (err != -ENOENT && err != -ERANGE)
2884e93b648SJuergen Gross 			pr_err("Error %d reading sysrq code in control/sysrq\n",
2894e93b648SJuergen Gross 			       err);
290ec9b2065SIsaku Yamahata 		xenbus_transaction_end(xbt, 1);
291ec9b2065SIsaku Yamahata 		return;
292ec9b2065SIsaku Yamahata 	}
293ec9b2065SIsaku Yamahata 
29484c029a7SZhouyang Jia 	if (sysrq_key != '\0') {
29584c029a7SZhouyang Jia 		err = xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
29684c029a7SZhouyang Jia 		if (err) {
29784c029a7SZhouyang Jia 			pr_err("%s: Error %d writing sysrq in control/sysrq\n",
29884c029a7SZhouyang Jia 			       __func__, err);
29984c029a7SZhouyang Jia 			xenbus_transaction_end(xbt, 1);
30084c029a7SZhouyang Jia 			return;
30184c029a7SZhouyang Jia 		}
30284c029a7SZhouyang Jia 	}
303ec9b2065SIsaku Yamahata 
304ec9b2065SIsaku Yamahata 	err = xenbus_transaction_end(xbt, 0);
305ec9b2065SIsaku Yamahata 	if (err == -EAGAIN)
306ec9b2065SIsaku Yamahata 		goto again;
307ec9b2065SIsaku Yamahata 
308ec9b2065SIsaku Yamahata 	if (sysrq_key != '\0')
309f335397dSDmitry Torokhov 		handle_sysrq(sysrq_key);
310ec9b2065SIsaku Yamahata }
311ec9b2065SIsaku Yamahata 
312ec9b2065SIsaku Yamahata static struct xenbus_watch sysrq_watch = {
313ec9b2065SIsaku Yamahata 	.node = "control/sysrq",
314ec9b2065SIsaku Yamahata 	.callback = sysrq_handler
315ec9b2065SIsaku Yamahata };
316f3bc3189SRandy Dunlap #endif
317f3bc3189SRandy Dunlap 
318f3bc3189SRandy Dunlap static struct xenbus_watch shutdown_watch = {
319f3bc3189SRandy Dunlap 	.node = "control/shutdown",
320f3bc3189SRandy Dunlap 	.callback = shutdown_handler
321f3bc3189SRandy Dunlap };
322ec9b2065SIsaku Yamahata 
323eb47f712SKonrad Rzeszutek Wilk static struct notifier_block xen_reboot_nb = {
324eb47f712SKonrad Rzeszutek Wilk 	.notifier_call = poweroff_nb,
325eb47f712SKonrad Rzeszutek Wilk };
326eb47f712SKonrad Rzeszutek Wilk 
327ec9b2065SIsaku Yamahata static int setup_shutdown_watcher(void)
328ec9b2065SIsaku Yamahata {
329ec9b2065SIsaku Yamahata 	int err;
33044b3c7afSJuergen Gross 	int idx;
33144b3c7afSJuergen Gross #define FEATURE_PATH_SIZE (SHUTDOWN_CMD_SIZE + sizeof("feature-"))
33244b3c7afSJuergen Gross 	char node[FEATURE_PATH_SIZE];
333ec9b2065SIsaku Yamahata 
334ec9b2065SIsaku Yamahata 	err = register_xenbus_watch(&shutdown_watch);
335ec9b2065SIsaku Yamahata 	if (err) {
336283c0972SJoe Perches 		pr_err("Failed to set shutdown watcher\n");
337ec9b2065SIsaku Yamahata 		return err;
338ec9b2065SIsaku Yamahata 	}
339ec9b2065SIsaku Yamahata 
340eb47f712SKonrad Rzeszutek Wilk 
341f3bc3189SRandy Dunlap #ifdef CONFIG_MAGIC_SYSRQ
342ec9b2065SIsaku Yamahata 	err = register_xenbus_watch(&sysrq_watch);
343ec9b2065SIsaku Yamahata 	if (err) {
344283c0972SJoe Perches 		pr_err("Failed to set sysrq watcher\n");
345ec9b2065SIsaku Yamahata 		return err;
346ec9b2065SIsaku Yamahata 	}
347f3bc3189SRandy Dunlap #endif
348ec9b2065SIsaku Yamahata 
34944b3c7afSJuergen Gross 	for (idx = 0; idx < ARRAY_SIZE(shutdown_handlers); idx++) {
35044b3c7afSJuergen Gross 		if (!shutdown_handlers[idx].flag)
35144b3c7afSJuergen Gross 			continue;
35244b3c7afSJuergen Gross 		snprintf(node, FEATURE_PATH_SIZE, "feature-%s",
35344b3c7afSJuergen Gross 			 shutdown_handlers[idx].command);
35484c029a7SZhouyang Jia 		err = xenbus_printf(XBT_NIL, "control", node, "%u", 1);
35584c029a7SZhouyang Jia 		if (err) {
35684c029a7SZhouyang Jia 			pr_err("%s: Error %d writing %s\n", __func__,
35784c029a7SZhouyang Jia 				err, node);
35884c029a7SZhouyang Jia 			return err;
35984c029a7SZhouyang Jia 		}
36044b3c7afSJuergen Gross 	}
36144b3c7afSJuergen Gross 
362ec9b2065SIsaku Yamahata 	return 0;
363ec9b2065SIsaku Yamahata }
364ec9b2065SIsaku Yamahata 
365ec9b2065SIsaku Yamahata static int shutdown_event(struct notifier_block *notifier,
366ec9b2065SIsaku Yamahata 			  unsigned long event,
367ec9b2065SIsaku Yamahata 			  void *data)
368ec9b2065SIsaku Yamahata {
369ec9b2065SIsaku Yamahata 	setup_shutdown_watcher();
370ec9b2065SIsaku Yamahata 	return NOTIFY_DONE;
371ec9b2065SIsaku Yamahata }
372ec9b2065SIsaku Yamahata 
373016b6f5fSStefano Stabellini int xen_setup_shutdown_event(void)
374ec9b2065SIsaku Yamahata {
375ec9b2065SIsaku Yamahata 	static struct notifier_block xenstore_notifier = {
376ec9b2065SIsaku Yamahata 		.notifier_call = shutdown_event
377ec9b2065SIsaku Yamahata 	};
378702d4eb9SStefano Stabellini 
379702d4eb9SStefano Stabellini 	if (!xen_domain())
380702d4eb9SStefano Stabellini 		return -ENODEV;
381ec9b2065SIsaku Yamahata 	register_xenstore_notifier(&xenstore_notifier);
382eb47f712SKonrad Rzeszutek Wilk 	register_reboot_notifier(&xen_reboot_nb);
383ec9b2065SIsaku Yamahata 
384ec9b2065SIsaku Yamahata 	return 0;
385ec9b2065SIsaku Yamahata }
386183d03ccSStefano Stabellini EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
387ec9b2065SIsaku Yamahata 
388702d4eb9SStefano Stabellini subsys_initcall(xen_setup_shutdown_event);
389