Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[sfrench/cifs-2.6.git] / drivers / xen / manage.c
1 /*
2  * Handle extern requests for shutdown, reboot and sysrq
3  */
4 #include <linux/kernel.h>
5 #include <linux/err.h>
6 #include <linux/reboot.h>
7 #include <linux/sysrq.h>
8 #include <linux/stop_machine.h>
9 #include <linux/freezer.h>
10
11 #include <xen/xenbus.h>
12 #include <xen/grant_table.h>
13 #include <xen/events.h>
14 #include <xen/hvc-console.h>
15 #include <xen/xen-ops.h>
16
17 #include <asm/xen/hypercall.h>
18 #include <asm/xen/page.h>
19
20 enum shutdown_state {
21         SHUTDOWN_INVALID = -1,
22         SHUTDOWN_POWEROFF = 0,
23         SHUTDOWN_SUSPEND = 2,
24         /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
25            report a crash, not be instructed to crash!
26            HALT is the same as POWEROFF, as far as we're concerned.  The tools use
27            the distinction when we return the reason code to them.  */
28          SHUTDOWN_HALT = 4,
29 };
30
31 /* Ignore multiple shutdown requests. */
32 static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
33
34 #ifdef CONFIG_PM_SLEEP
35 static int xen_suspend(void *data)
36 {
37         int *cancelled = data;
38         int err;
39
40         BUG_ON(!irqs_disabled());
41
42         err = sysdev_suspend(PMSG_SUSPEND);
43         if (err) {
44                 printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
45                         err);
46                 device_power_up(PMSG_RESUME);
47                 return err;
48         }
49
50         xen_mm_pin_all();
51         gnttab_suspend();
52         xen_pre_suspend();
53
54         /*
55          * This hypercall returns 1 if suspend was cancelled
56          * or the domain was merely checkpointed, and 0 if it
57          * is resuming in a new domain.
58          */
59         *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
60
61         xen_post_suspend(*cancelled);
62         gnttab_resume();
63         xen_mm_unpin_all();
64
65         if (!*cancelled) {
66                 xen_irq_resume();
67                 xen_console_resume();
68                 xen_timer_resume();
69         }
70
71         sysdev_resume();
72         device_power_up(PMSG_RESUME);
73
74         return 0;
75 }
76
77 static void do_suspend(void)
78 {
79         int err;
80         int cancelled = 1;
81
82         shutting_down = SHUTDOWN_SUSPEND;
83
84 #ifdef CONFIG_PREEMPT
85         /* If the kernel is preemptible, we need to freeze all the processes
86            to prevent them from being in the middle of a pagetable update
87            during suspend. */
88         err = freeze_processes();
89         if (err) {
90                 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
91                 return;
92         }
93 #endif
94
95         err = device_suspend(PMSG_SUSPEND);
96         if (err) {
97                 printk(KERN_ERR "xen suspend: device_suspend %d\n", err);
98                 goto out;
99         }
100
101         printk("suspending xenbus...\n");
102         /* XXX use normal device tree? */
103         xenbus_suspend();
104
105         err = device_power_down(PMSG_SUSPEND);
106         if (err) {
107                 printk(KERN_ERR "device_power_down failed: %d\n", err);
108                 goto resume_devices;
109         }
110
111         err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
112         if (err) {
113                 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
114                 goto out;
115         }
116
117         if (!cancelled) {
118                 xen_arch_resume();
119                 xenbus_resume();
120         } else
121                 xenbus_suspend_cancel();
122
123         device_power_up(PMSG_RESUME);
124
125 resume_devices:
126         device_resume(PMSG_RESUME);
127
128         /* Make sure timer events get retriggered on all CPUs */
129         clock_was_set();
130 out:
131 #ifdef CONFIG_PREEMPT
132         thaw_processes();
133 #endif
134         shutting_down = SHUTDOWN_INVALID;
135 }
136 #endif  /* CONFIG_PM_SLEEP */
137
138 static void shutdown_handler(struct xenbus_watch *watch,
139                              const char **vec, unsigned int len)
140 {
141         char *str;
142         struct xenbus_transaction xbt;
143         int err;
144
145         if (shutting_down != SHUTDOWN_INVALID)
146                 return;
147
148  again:
149         err = xenbus_transaction_start(&xbt);
150         if (err)
151                 return;
152
153         str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
154         /* Ignore read errors and empty reads. */
155         if (XENBUS_IS_ERR_READ(str)) {
156                 xenbus_transaction_end(xbt, 1);
157                 return;
158         }
159
160         xenbus_write(xbt, "control", "shutdown", "");
161
162         err = xenbus_transaction_end(xbt, 0);
163         if (err == -EAGAIN) {
164                 kfree(str);
165                 goto again;
166         }
167
168         if (strcmp(str, "poweroff") == 0 ||
169             strcmp(str, "halt") == 0) {
170                 shutting_down = SHUTDOWN_POWEROFF;
171                 orderly_poweroff(false);
172         } else if (strcmp(str, "reboot") == 0) {
173                 shutting_down = SHUTDOWN_POWEROFF; /* ? */
174                 ctrl_alt_del();
175 #ifdef CONFIG_PM_SLEEP
176         } else if (strcmp(str, "suspend") == 0) {
177                 do_suspend();
178 #endif
179         } else {
180                 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
181                 shutting_down = SHUTDOWN_INVALID;
182         }
183
184         kfree(str);
185 }
186
187 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
188                           unsigned int len)
189 {
190         char sysrq_key = '\0';
191         struct xenbus_transaction xbt;
192         int err;
193
194  again:
195         err = xenbus_transaction_start(&xbt);
196         if (err)
197                 return;
198         if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
199                 printk(KERN_ERR "Unable to read sysrq code in "
200                        "control/sysrq\n");
201                 xenbus_transaction_end(xbt, 1);
202                 return;
203         }
204
205         if (sysrq_key != '\0')
206                 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
207
208         err = xenbus_transaction_end(xbt, 0);
209         if (err == -EAGAIN)
210                 goto again;
211
212         if (sysrq_key != '\0')
213                 handle_sysrq(sysrq_key, NULL);
214 }
215
216 static struct xenbus_watch shutdown_watch = {
217         .node = "control/shutdown",
218         .callback = shutdown_handler
219 };
220
221 static struct xenbus_watch sysrq_watch = {
222         .node = "control/sysrq",
223         .callback = sysrq_handler
224 };
225
226 static int setup_shutdown_watcher(void)
227 {
228         int err;
229
230         err = register_xenbus_watch(&shutdown_watch);
231         if (err) {
232                 printk(KERN_ERR "Failed to set shutdown watcher\n");
233                 return err;
234         }
235
236         err = register_xenbus_watch(&sysrq_watch);
237         if (err) {
238                 printk(KERN_ERR "Failed to set sysrq watcher\n");
239                 return err;
240         }
241
242         return 0;
243 }
244
245 static int shutdown_event(struct notifier_block *notifier,
246                           unsigned long event,
247                           void *data)
248 {
249         setup_shutdown_watcher();
250         return NOTIFY_DONE;
251 }
252
253 static int __init setup_shutdown_event(void)
254 {
255         static struct notifier_block xenstore_notifier = {
256                 .notifier_call = shutdown_event
257         };
258         register_xenstore_notifier(&xenstore_notifier);
259
260         return 0;
261 }
262
263 subsys_initcall(setup_shutdown_event);