xen: use device model for suspending xenbus devices
[safe/jmp/linux-2.6] / 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 = device_power_down(PMSG_SUSPEND);
43         if (err) {
44                 printk(KERN_ERR "xen_suspend: device_power_down failed: %d\n",
45                        err);
46                 return err;
47         }
48         err = sysdev_suspend(PMSG_SUSPEND);
49         if (err) {
50                 printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
51                         err);
52                 device_power_up(PMSG_RESUME);
53                 return err;
54         }
55
56         xen_mm_pin_all();
57         gnttab_suspend();
58         xen_pre_suspend();
59
60         /*
61          * This hypercall returns 1 if suspend was cancelled
62          * or the domain was merely checkpointed, and 0 if it
63          * is resuming in a new domain.
64          */
65         *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
66
67         xen_post_suspend(*cancelled);
68         gnttab_resume();
69         xen_mm_unpin_all();
70
71         if (!*cancelled) {
72                 xen_irq_resume();
73                 xen_console_resume();
74                 xen_timer_resume();
75         }
76
77         sysdev_resume();
78         device_power_up(PMSG_RESUME);
79
80         return 0;
81 }
82
83 static void do_suspend(void)
84 {
85         int err;
86         int cancelled = 1;
87
88         shutting_down = SHUTDOWN_SUSPEND;
89
90 #ifdef CONFIG_PREEMPT
91         /* If the kernel is preemptible, we need to freeze all the processes
92            to prevent them from being in the middle of a pagetable update
93            during suspend. */
94         err = freeze_processes();
95         if (err) {
96                 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
97                 return;
98         }
99 #endif
100
101         err = device_suspend(PMSG_SUSPEND);
102         if (err) {
103                 printk(KERN_ERR "xen suspend: device_suspend %d\n", err);
104                 goto out;
105         }
106
107         printk(KERN_DEBUG "suspending xenstore...\n");
108         xs_suspend();
109
110         err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
111         if (err) {
112                 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
113                 goto out;
114         }
115
116         if (!cancelled) {
117                 xen_arch_resume();
118                 xs_resume();
119         } else
120                 xs_suspend_cancel();
121
122         device_resume(PMSG_RESUME);
123
124         /* Make sure timer events get retriggered on all CPUs */
125         clock_was_set();
126 out:
127 #ifdef CONFIG_PREEMPT
128         thaw_processes();
129 #endif
130         shutting_down = SHUTDOWN_INVALID;
131 }
132 #endif  /* CONFIG_PM_SLEEP */
133
134 static void shutdown_handler(struct xenbus_watch *watch,
135                              const char **vec, unsigned int len)
136 {
137         char *str;
138         struct xenbus_transaction xbt;
139         int err;
140
141         if (shutting_down != SHUTDOWN_INVALID)
142                 return;
143
144  again:
145         err = xenbus_transaction_start(&xbt);
146         if (err)
147                 return;
148
149         str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
150         /* Ignore read errors and empty reads. */
151         if (XENBUS_IS_ERR_READ(str)) {
152                 xenbus_transaction_end(xbt, 1);
153                 return;
154         }
155
156         xenbus_write(xbt, "control", "shutdown", "");
157
158         err = xenbus_transaction_end(xbt, 0);
159         if (err == -EAGAIN) {
160                 kfree(str);
161                 goto again;
162         }
163
164         if (strcmp(str, "poweroff") == 0 ||
165             strcmp(str, "halt") == 0) {
166                 shutting_down = SHUTDOWN_POWEROFF;
167                 orderly_poweroff(false);
168         } else if (strcmp(str, "reboot") == 0) {
169                 shutting_down = SHUTDOWN_POWEROFF; /* ? */
170                 ctrl_alt_del();
171 #ifdef CONFIG_PM_SLEEP
172         } else if (strcmp(str, "suspend") == 0) {
173                 do_suspend();
174 #endif
175         } else {
176                 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
177                 shutting_down = SHUTDOWN_INVALID;
178         }
179
180         kfree(str);
181 }
182
183 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
184                           unsigned int len)
185 {
186         char sysrq_key = '\0';
187         struct xenbus_transaction xbt;
188         int err;
189
190  again:
191         err = xenbus_transaction_start(&xbt);
192         if (err)
193                 return;
194         if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
195                 printk(KERN_ERR "Unable to read sysrq code in "
196                        "control/sysrq\n");
197                 xenbus_transaction_end(xbt, 1);
198                 return;
199         }
200
201         if (sysrq_key != '\0')
202                 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
203
204         err = xenbus_transaction_end(xbt, 0);
205         if (err == -EAGAIN)
206                 goto again;
207
208         if (sysrq_key != '\0')
209                 handle_sysrq(sysrq_key, NULL);
210 }
211
212 static struct xenbus_watch shutdown_watch = {
213         .node = "control/shutdown",
214         .callback = shutdown_handler
215 };
216
217 static struct xenbus_watch sysrq_watch = {
218         .node = "control/sysrq",
219         .callback = sysrq_handler
220 };
221
222 static int setup_shutdown_watcher(void)
223 {
224         int err;
225
226         err = register_xenbus_watch(&shutdown_watch);
227         if (err) {
228                 printk(KERN_ERR "Failed to set shutdown watcher\n");
229                 return err;
230         }
231
232         err = register_xenbus_watch(&sysrq_watch);
233         if (err) {
234                 printk(KERN_ERR "Failed to set sysrq watcher\n");
235                 return err;
236         }
237
238         return 0;
239 }
240
241 static int shutdown_event(struct notifier_block *notifier,
242                           unsigned long event,
243                           void *data)
244 {
245         setup_shutdown_watcher();
246         return NOTIFY_DONE;
247 }
248
249 static int __init setup_shutdown_event(void)
250 {
251         static struct notifier_block xenstore_notifier = {
252                 .notifier_call = shutdown_event
253         };
254         register_xenstore_notifier(&xenstore_notifier);
255
256         return 0;
257 }
258
259 subsys_initcall(setup_shutdown_event);