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> 65a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 73e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/reboot.h> 83e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/sysrq.h> 90e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <linux/stop_machine.h> 100e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <linux/freezer.h> 1119234c0819da0e043a02710488dfd9b242b42ebaRafael J. Wysocki#include <linux/syscore_ops.h> 1263c9744b9a53b8113b6d33ca361452b28f2ec391Paul Gortmaker#include <linux/export.h> 133e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 14016b6f5fe8398b0291cece60b749d7c930a2e09cStefano Stabellini#include <xen/xen.h> 153e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <xen/xenbus.h> 160e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/grant_table.h> 170e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/events.h> 180e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/hvc-console.h> 190e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/xen-ops.h> 203e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 210e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <asm/xen/hypercall.h> 220e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <asm/xen/page.h> 23016b6f5fe8398b0291cece60b749d7c930a2e09cStefano Stabellini#include <asm/xen/hypervisor.h> 240e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 250e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingeenum shutdown_state { 260e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge SHUTDOWN_INVALID = -1, 270e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge SHUTDOWN_POWEROFF = 0, 280e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge SHUTDOWN_SUSPEND = 2, 290e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only 300e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge report a crash, not be instructed to crash! 310e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge HALT is the same as POWEROFF, as far as we're concerned. The tools use 320e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge the distinction when we return the reason code to them. */ 330e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge SHUTDOWN_HALT = 4, 340e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge}; 353e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 363e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge/* Ignore multiple shutdown requests. */ 370e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingestatic enum shutdown_state shutting_down = SHUTDOWN_INVALID; 380e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 39ceb180294790c8a6a437533488616f6b591b49d0Ian Campbellstruct suspend_info { 40ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell int cancelled; 4136b401e2c2788c7b4881115ddbbff603fe4cf78dIan Campbell unsigned long arg; /* extra hypercall argument */ 4255fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell void (*pre)(void); 4355fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell void (*post)(int cancelled); 44ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell}; 45ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell 4607af38102fc4f260cc5a2418ec833707f53cdf70Ian Campbellstatic void xen_hvm_post_suspend(int cancelled) 4782043bb60d24d2897074905c94be5a53071e8913Ian Campbell{ 4807af38102fc4f260cc5a2418ec833707f53cdf70Ian Campbell xen_arch_hvm_post_suspend(cancelled); 4982043bb60d24d2897074905c94be5a53071e8913Ian Campbell gnttab_resume(); 5082043bb60d24d2897074905c94be5a53071e8913Ian Campbell} 5182043bb60d24d2897074905c94be5a53071e8913Ian Campbell 5282043bb60d24d2897074905c94be5a53071e8913Ian Campbellstatic void xen_pre_suspend(void) 5382043bb60d24d2897074905c94be5a53071e8913Ian Campbell{ 5482043bb60d24d2897074905c94be5a53071e8913Ian Campbell xen_mm_pin_all(); 5582043bb60d24d2897074905c94be5a53071e8913Ian Campbell gnttab_suspend(); 5607af38102fc4f260cc5a2418ec833707f53cdf70Ian Campbell xen_arch_pre_suspend(); 5782043bb60d24d2897074905c94be5a53071e8913Ian Campbell} 5882043bb60d24d2897074905c94be5a53071e8913Ian Campbell 5907af38102fc4f260cc5a2418ec833707f53cdf70Ian Campbellstatic void xen_post_suspend(int cancelled) 6082043bb60d24d2897074905c94be5a53071e8913Ian Campbell{ 6107af38102fc4f260cc5a2418ec833707f53cdf70Ian Campbell xen_arch_post_suspend(cancelled); 6282043bb60d24d2897074905c94be5a53071e8913Ian Campbell gnttab_resume(); 6382043bb60d24d2897074905c94be5a53071e8913Ian Campbell xen_mm_unpin_all(); 6482043bb60d24d2897074905c94be5a53071e8913Ian Campbell} 6582043bb60d24d2897074905c94be5a53071e8913Ian Campbell 661f112cee07b314e244ee9e71d9c1e6950dc13327Rafael J. Wysocki#ifdef CONFIG_HIBERNATE_CALLBACKS 67016b6f5fe8398b0291cece60b749d7c930a2e09cStefano Stabellinistatic int xen_suspend(void *data) 68016b6f5fe8398b0291cece60b749d7c930a2e09cStefano Stabellini{ 69ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell struct suspend_info *si = data; 70359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge int err; 710e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 720e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge BUG_ON(!irqs_disabled()); 730e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 742e711c04dbbf7a7732a3f7073b1fc285d12b369dRafael J. Wysocki err = syscore_suspend(); 75770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki if (err) { 7619234c0819da0e043a02710488dfd9b242b42ebaRafael J. Wysocki printk(KERN_ERR "xen_suspend: system core suspend failed: %d\n", 77770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki err); 78770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki return err; 79770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki } 80359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge 8155fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell if (si->pre) 8255fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell si->pre(); 830e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 840e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge /* 850e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge * This hypercall returns 1 if suspend was cancelled 860e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge * or the domain was merely checkpointed, and 0 if it 870e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge * is resuming in a new domain. 880e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge */ 8936b401e2c2788c7b4881115ddbbff603fe4cf78dIan Campbell si->cancelled = HYPERVISOR_suspend(si->arg); 900e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 9155fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell if (si->post) 9255fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell si->post(si->cancelled); 930e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 94ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell if (!si->cancelled) { 950e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge xen_irq_resume(); 960e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge xen_console_resume(); 97ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata xen_timer_resume(); 980e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge } 990e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 10019234c0819da0e043a02710488dfd9b242b42ebaRafael J. Wysocki syscore_resume(); 1011e6fcf840e11ceff8a656a678c6e4b0560a98e08Ian Campbell 1020e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge return 0; 1030e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge} 1040e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 1050e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingestatic void do_suspend(void) 1060e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge{ 1070e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge int err; 108ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell struct suspend_info si; 1090e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 1100e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge shutting_down = SHUTDOWN_SUSPEND; 1110e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 1120e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#ifdef CONFIG_PREEMPT 1130e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge /* If the kernel is preemptible, we need to freeze all the processes 1140e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge to prevent them from being in the middle of a pagetable update 1150e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge during suspend. */ 1160e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge err = freeze_processes(); 1170e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge if (err) { 1180e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge printk(KERN_ERR "xen suspend: freeze failed %d\n", err); 1193fc1f1e27a5b807791d72e5d992aa33b668a6626Tejun Heo goto out; 1200e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge } 1210e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#endif 1220e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 123b3e96c0c756211e805c6941d4a6e5f6e1995cb6bShriram Rajagopalan err = dpm_suspend_start(PMSG_FREEZE); 1240e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge if (err) { 125d161630297a20802d01c55847bfcba85d2118a9fAlan Stern printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err); 12665f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell goto out_thaw; 1270e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge } 1280e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 129c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbell printk(KERN_DEBUG "suspending xenstore...\n"); 130c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbell xs_suspend(); 131c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbell 132cf579dfb82550e34de7ccf3ef090d8b834ccd3a9Rafael J. Wysocki err = dpm_suspend_end(PMSG_FREEZE); 1332ed8d2b3a81bdbb0418301628ccdb008ac9f40b7Rafael J. Wysocki if (err) { 134cf579dfb82550e34de7ccf3ef090d8b834ccd3a9Rafael J. Wysocki printk(KERN_ERR "dpm_suspend_end failed: %d\n", err); 135186bab1ce04f99153b7eeb3348438b654c24c24bKonrad Rzeszutek Wilk si.cancelled = 0; 13665f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell goto out_resume; 1372ed8d2b3a81bdbb0418301628ccdb008ac9f40b7Rafael J. Wysocki } 1382ed8d2b3a81bdbb0418301628ccdb008ac9f40b7Rafael J. Wysocki 139ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell si.cancelled = 1; 140ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell 14155fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell if (xen_hvm_domain()) { 14236b401e2c2788c7b4881115ddbbff603fe4cf78dIan Campbell si.arg = 0UL; 14355fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell si.pre = NULL; 14455fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell si.post = &xen_hvm_post_suspend; 14555fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell } else { 14636b401e2c2788c7b4881115ddbbff603fe4cf78dIan Campbell si.arg = virt_to_mfn(xen_start_info); 14755fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell si.pre = &xen_pre_suspend; 14855fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell si.post = &xen_post_suspend; 14955fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell } 15036b401e2c2788c7b4881115ddbbff603fe4cf78dIan Campbell 151b056b6a0144de90707cd22cf7b4f60bf69c86d59Ian Campbell err = stop_machine(xen_suspend, &si, cpumask_of(0)); 152922cc38ab71d1360978e65207e4a4f4988987127Jeremy Fitzhardinge 153cf579dfb82550e34de7ccf3ef090d8b834ccd3a9Rafael J. Wysocki dpm_resume_start(si.cancelled ? PMSG_THAW : PMSG_RESTORE); 154922cc38ab71d1360978e65207e4a4f4988987127Jeremy Fitzhardinge 1550e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge if (err) { 1560e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge printk(KERN_ERR "failed to start xen_suspend: %d\n", err); 157ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell si.cancelled = 1; 1580e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge } 1590e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 160c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbellout_resume: 161ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell if (!si.cancelled) { 162ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata xen_arch_resume(); 163de5b31bd47de7e6f41be2e271318dbc8f1af354dIan Campbell xs_resume(); 164ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata } else 165de5b31bd47de7e6f41be2e271318dbc8f1af354dIan Campbell xs_suspend_cancel(); 1660e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 167b3e96c0c756211e805c6941d4a6e5f6e1995cb6bShriram Rajagopalan dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE); 1680e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 169359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge /* Make sure timer events get retriggered on all CPUs */ 170359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge clock_was_set(); 17165f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell 17265f63384b391bf4d384327d8a7c6de9860290b5cIan Campbellout_thaw: 1730e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#ifdef CONFIG_PREEMPT 1740e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge thaw_processes(); 17565f63384b391bf4d384327d8a7c6de9860290b5cIan Campbellout: 1763fc1f1e27a5b807791d72e5d992aa33b668a6626Tejun Heo#endif 1770e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge shutting_down = SHUTDOWN_INVALID; 1780e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge} 1791f112cee07b314e244ee9e71d9c1e6950dc13327Rafael J. Wysocki#endif /* CONFIG_HIBERNATE_CALLBACKS */ 1803e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 181552717231e50b478dfd19d63fd97879476ae051dIan Campbellstruct shutdown_handler { 182552717231e50b478dfd19d63fd97879476ae051dIan Campbell const char *command; 183552717231e50b478dfd19d63fd97879476ae051dIan Campbell void (*cb)(void); 184552717231e50b478dfd19d63fd97879476ae051dIan Campbell}; 185552717231e50b478dfd19d63fd97879476ae051dIan Campbell 186552717231e50b478dfd19d63fd97879476ae051dIan Campbellstatic void do_poweroff(void) 187552717231e50b478dfd19d63fd97879476ae051dIan Campbell{ 188552717231e50b478dfd19d63fd97879476ae051dIan Campbell shutting_down = SHUTDOWN_POWEROFF; 189552717231e50b478dfd19d63fd97879476ae051dIan Campbell orderly_poweroff(false); 190552717231e50b478dfd19d63fd97879476ae051dIan Campbell} 191552717231e50b478dfd19d63fd97879476ae051dIan Campbell 192552717231e50b478dfd19d63fd97879476ae051dIan Campbellstatic void do_reboot(void) 193552717231e50b478dfd19d63fd97879476ae051dIan Campbell{ 194552717231e50b478dfd19d63fd97879476ae051dIan Campbell shutting_down = SHUTDOWN_POWEROFF; /* ? */ 195552717231e50b478dfd19d63fd97879476ae051dIan Campbell ctrl_alt_del(); 196552717231e50b478dfd19d63fd97879476ae051dIan Campbell} 197552717231e50b478dfd19d63fd97879476ae051dIan Campbell 1983e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic void shutdown_handler(struct xenbus_watch *watch, 1993e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge const char **vec, unsigned int len) 2003e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{ 2013e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge char *str; 2023e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge struct xenbus_transaction xbt; 2033e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge int err; 204552717231e50b478dfd19d63fd97879476ae051dIan Campbell static struct shutdown_handler handlers[] = { 205552717231e50b478dfd19d63fd97879476ae051dIan Campbell { "poweroff", do_poweroff }, 206552717231e50b478dfd19d63fd97879476ae051dIan Campbell { "halt", do_poweroff }, 207552717231e50b478dfd19d63fd97879476ae051dIan Campbell { "reboot", do_reboot }, 2081f112cee07b314e244ee9e71d9c1e6950dc13327Rafael J. Wysocki#ifdef CONFIG_HIBERNATE_CALLBACKS 209552717231e50b478dfd19d63fd97879476ae051dIan Campbell { "suspend", do_suspend }, 210552717231e50b478dfd19d63fd97879476ae051dIan Campbell#endif 211552717231e50b478dfd19d63fd97879476ae051dIan Campbell {NULL, NULL}, 212552717231e50b478dfd19d63fd97879476ae051dIan Campbell }; 213552717231e50b478dfd19d63fd97879476ae051dIan Campbell static struct shutdown_handler *handler; 2143e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2153e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (shutting_down != SHUTDOWN_INVALID) 2163e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return; 2173e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2183e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge again: 2193e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge err = xenbus_transaction_start(&xbt); 2203e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (err) 2213e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return; 2223e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2233e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge str = (char *)xenbus_read(xbt, "control", "shutdown", NULL); 2243e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge /* Ignore read errors and empty reads. */ 2253e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (XENBUS_IS_ERR_READ(str)) { 2263e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge xenbus_transaction_end(xbt, 1); 2273e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return; 2283e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge } 2293e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 230552717231e50b478dfd19d63fd97879476ae051dIan Campbell for (handler = &handlers[0]; handler->command; handler++) { 231552717231e50b478dfd19d63fd97879476ae051dIan Campbell if (strcmp(str, handler->command) == 0) 232552717231e50b478dfd19d63fd97879476ae051dIan Campbell break; 233552717231e50b478dfd19d63fd97879476ae051dIan Campbell } 234552717231e50b478dfd19d63fd97879476ae051dIan Campbell 235552717231e50b478dfd19d63fd97879476ae051dIan Campbell /* Only acknowledge commands which we are prepared to handle. */ 236552717231e50b478dfd19d63fd97879476ae051dIan Campbell if (handler->cb) 237552717231e50b478dfd19d63fd97879476ae051dIan Campbell xenbus_write(xbt, "control", "shutdown", ""); 2383e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2393e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge err = xenbus_transaction_end(xbt, 0); 2403e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (err == -EAGAIN) { 2413e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge kfree(str); 2423e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge goto again; 2433e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge } 2443e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 245552717231e50b478dfd19d63fd97879476ae051dIan Campbell if (handler->cb) { 246552717231e50b478dfd19d63fd97879476ae051dIan Campbell handler->cb(); 2470e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge } else { 2483e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge printk(KERN_INFO "Ignoring shutdown request: %s\n", str); 2493e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge shutting_down = SHUTDOWN_INVALID; 2503e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge } 2513e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2523e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge kfree(str); 2533e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge} 2543e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 255f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#ifdef CONFIG_MAGIC_SYSRQ 2563e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic void sysrq_handler(struct xenbus_watch *watch, const char **vec, 2573e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge unsigned int len) 2583e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{ 2593e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge char sysrq_key = '\0'; 2603e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge struct xenbus_transaction xbt; 2613e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge int err; 2623e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2633e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge again: 2643e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge err = xenbus_transaction_start(&xbt); 2653e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (err) 2663e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return; 2673e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) { 2683e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge printk(KERN_ERR "Unable to read sysrq code in " 2693e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge "control/sysrq\n"); 2703e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge xenbus_transaction_end(xbt, 1); 2713e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return; 2723e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge } 2733e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2743e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (sysrq_key != '\0') 2753e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge xenbus_printf(xbt, "control", "sysrq", "%c", '\0'); 2763e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2773e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge err = xenbus_transaction_end(xbt, 0); 2783e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (err == -EAGAIN) 2793e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge goto again; 2803e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2813e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (sysrq_key != '\0') 282f335397d177c906256ee1bba28e8c49e8ec63817Dmitry Torokhov handle_sysrq(sysrq_key); 2833e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge} 2843e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2853e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic struct xenbus_watch sysrq_watch = { 2863e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge .node = "control/sysrq", 2873e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge .callback = sysrq_handler 2883e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}; 289f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#endif 290f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap 291f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlapstatic struct xenbus_watch shutdown_watch = { 292f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap .node = "control/shutdown", 293f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap .callback = shutdown_handler 294f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap}; 2953e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2963e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic int setup_shutdown_watcher(void) 2973e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{ 2983e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge int err; 2993e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 3003e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge err = register_xenbus_watch(&shutdown_watch); 3013e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (err) { 3023e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge printk(KERN_ERR "Failed to set shutdown watcher\n"); 3033e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return err; 3043e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge } 3053e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 306f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#ifdef CONFIG_MAGIC_SYSRQ 3073e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge err = register_xenbus_watch(&sysrq_watch); 3083e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (err) { 3093e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge printk(KERN_ERR "Failed to set sysrq watcher\n"); 3103e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return err; 3113e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge } 312f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#endif 3133e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 3143e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return 0; 3153e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge} 3163e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 3173e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic int shutdown_event(struct notifier_block *notifier, 3183e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge unsigned long event, 3193e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge void *data) 3203e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{ 3213e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge setup_shutdown_watcher(); 3223e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return NOTIFY_DONE; 3233e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge} 3243e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 325016b6f5fe8398b0291cece60b749d7c930a2e09cStefano Stabelliniint xen_setup_shutdown_event(void) 3263e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{ 3273e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge static struct notifier_block xenstore_notifier = { 3283e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge .notifier_call = shutdown_event 3293e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge }; 330702d4eb9b3de4398ab99cf0a4e799e552c7ab756Stefano Stabellini 331702d4eb9b3de4398ab99cf0a4e799e552c7ab756Stefano Stabellini if (!xen_domain()) 332702d4eb9b3de4398ab99cf0a4e799e552c7ab756Stefano Stabellini return -ENODEV; 3333e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge register_xenstore_notifier(&xenstore_notifier); 3343e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 3353e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return 0; 3363e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge} 337183d03cc4ff39e0f0d952c09aa96d0abfd6e0c3cStefano StabelliniEXPORT_SYMBOL_GPL(xen_setup_shutdown_event); 3383e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 339702d4eb9b3de4398ab99cf0a4e799e552c7ab756Stefano Stabellinisubsys_initcall(xen_setup_shutdown_event); 340