diff options
Diffstat (limited to 'usr/src/uts/common/cpr/cpr_mod.c')
-rw-r--r-- | usr/src/uts/common/cpr/cpr_mod.c | 191 |
1 files changed, 173 insertions, 18 deletions
diff --git a/usr/src/uts/common/cpr/cpr_mod.c b/usr/src/uts/common/cpr/cpr_mod.c index 365f102a2b..9358a6ab3a 100644 --- a/usr/src/uts/common/cpr/cpr_mod.c +++ b/usr/src/uts/common/cpr/cpr_mod.c @@ -42,16 +42,23 @@ #include <sys/autoconf.h> #include <sys/machsystm.h> -extern int i_cpr_is_supported(void); +extern int i_cpr_is_supported(int sleeptype); extern int cpr_is_ufs(struct vfs *); extern int cpr_check_spec_statefile(void); extern int cpr_reusable_mount_check(void); -extern void cpr_forget_cprconfig(void); extern int i_cpr_reusable_supported(void); extern int i_cpr_reusefini(void); - extern struct mod_ops mod_miscops; +extern int cpr_init(int); +extern void cpr_done(void); +extern void i_cpr_stop_other_cpus(void); +extern int i_cpr_power_down(); + +#if defined(__sparc) +extern void cpr_forget_cprconfig(void); +#endif + static struct modlmisc modlmisc = { &mod_miscops, "checkpoint resume" }; @@ -68,6 +75,9 @@ kmutex_t cpr_slock; /* cpr serial lock */ cpr_t cpr_state; int cpr_debug; int cpr_test_mode; /* true if called via uadmin testmode */ +int cpr_test_point = LOOP_BACK_NONE; /* cpr test point */ +int cpr_mp_enable = 0; /* set to 1 to enable MP suspend */ +major_t cpr_device = 0; /* major number for S3 on one device */ /* * All the loadable module related code follows @@ -100,9 +110,25 @@ _info(struct modinfo *modinfop) return (mod_info(&modlinkage, modinfop)); } +static +int +atoi(char *p) +{ + int i; + + i = (*p++ - '0'); + + while (*p != '\0') + i = 10 * i + (*p++ - '0'); + + return (i); +} + int -cpr(int fcn) +cpr(int fcn, void *mdep) { + +#if defined(__sparc) static const char noswapstr[] = "reusable statefile requires " "that no swap area be configured.\n"; static const char blockstr[] = "reusable statefile must be " @@ -112,11 +138,71 @@ cpr(int fcn) "use uadmin A_FREEZE AD_REUSEFINI (uadmin %d %d) " "to exit reusable statefile mode.\n"; static const char modefmt[] = "%s in reusable mode.\n"; +#endif register int rc = 0; - extern int cpr_init(int); - extern void cpr_done(void); + int cpr_sleeptype; /* + * First, reject commands that we don't (yet) support on this arch. + * This is easier to understand broken out like this than grotting + * through the second switch below. + */ + + switch (fcn) { +#if defined(__sparc) + case AD_CHECK_SUSPEND_TO_RAM: + case AD_SUSPEND_TO_RAM: + return (ENOTSUP); + case AD_CHECK_SUSPEND_TO_DISK: + case AD_SUSPEND_TO_DISK: + case AD_CPR_REUSEINIT: + case AD_CPR_NOCOMPRESS: + case AD_CPR_FORCE: + case AD_CPR_REUSABLE: + case AD_CPR_REUSEFINI: + case AD_CPR_TESTZ: + case AD_CPR_TESTNOZ: + case AD_CPR_TESTHALT: + case AD_CPR_SUSP_DEVICES: + cpr_sleeptype = CPR_TODISK; + break; +#endif +#if defined(__x86) + case AD_CHECK_SUSPEND_TO_DISK: + case AD_SUSPEND_TO_DISK: + case AD_CPR_REUSEINIT: + case AD_CPR_NOCOMPRESS: + case AD_CPR_FORCE: + case AD_CPR_REUSABLE: + case AD_CPR_REUSEFINI: + case AD_CPR_TESTZ: + case AD_CPR_TESTNOZ: + case AD_CPR_TESTHALT: + case AD_CPR_PRINT: + return (ENOTSUP); + /* The DEV_* values need to be removed after sys-syspend is fixed */ + case DEV_CHECK_SUSPEND_TO_RAM: + case DEV_SUSPEND_TO_RAM: + case AD_CPR_SUSP_DEVICES: + case AD_CHECK_SUSPEND_TO_RAM: + case AD_SUSPEND_TO_RAM: + case AD_LOOPBACK_SUSPEND_TO_RAM_PASS: + case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL: + case AD_FORCE_SUSPEND_TO_RAM: + case AD_DEVICE_SUSPEND_TO_RAM: + /* + * if MP then do not support suspend to RAM, however override + * the MP restriction if cpr_mp_enable has been set + */ + if (ncpus > 1 && cpr_mp_enable == 0) + return (ENOTSUP); + else + cpr_sleeptype = CPR_TORAM; + break; +#endif + } +#if defined(__sparc) + /* * Need to know if we're in reusable mode, but we will likely have * rebooted since REUSEINIT, so we have to get the info from the * file system @@ -125,8 +211,11 @@ cpr(int fcn) cpr_reusable_mode = cpr_get_reusable_mode(); cpr_forget_cprconfig(); +#endif + switch (fcn) { +#if defined(__sparc) case AD_CPR_REUSEINIT: if (!i_cpr_reusable_supported()) return (ENOTSUP); @@ -188,7 +277,7 @@ cpr(int fcn) break; case AD_CPR_CHECK: - if (!i_cpr_is_supported() || cpr_reusable_mode) + if (!i_cpr_is_supported(cpr_sleeptype) || cpr_reusable_mode) return (ENOTSUP); return (0); @@ -196,6 +285,7 @@ cpr(int fcn) CPR_STAT_EVENT_END("POST CPR DELAY"); cpr_stat_event_print(); return (0); +#endif case AD_CPR_DEBUG0: cpr_debug = 0; @@ -215,13 +305,55 @@ cpr(int fcn) cpr_debug |= CPR_DEBUG6; return (0); + /* The DEV_* values need to be removed after sys-syspend is fixed */ + case DEV_CHECK_SUSPEND_TO_RAM: + case DEV_SUSPEND_TO_RAM: + case AD_CHECK_SUSPEND_TO_RAM: + case AD_SUSPEND_TO_RAM: + cpr_test_point = LOOP_BACK_NONE; + break; + + case AD_LOOPBACK_SUSPEND_TO_RAM_PASS: + cpr_test_point = LOOP_BACK_PASS; + break; + + case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL: + cpr_test_point = LOOP_BACK_FAIL; + break; + + case AD_FORCE_SUSPEND_TO_RAM: + cpr_test_point = FORCE_SUSPEND_TO_RAM; + break; + + case AD_DEVICE_SUSPEND_TO_RAM: + cpr_test_point = DEVICE_SUSPEND_TO_RAM; + cpr_device = (major_t)atoi((char *)mdep); + break; + + case AD_CPR_SUSP_DEVICES: + cpr_test_point = FORCE_SUSPEND_TO_RAM; + if (cpr_suspend_devices(ddi_root_node()) != DDI_SUCCESS) + cmn_err(CE_WARN, + "Some devices did not suspend " + "and may be unusable"); + (void) cpr_resume_devices(ddi_root_node(), 0); + return (0); + default: return (ENOTSUP); } - if (!i_cpr_is_supported() || !cpr_is_ufs(rootvfs)) + if (!i_cpr_is_supported(cpr_sleeptype) || + (cpr_sleeptype == CPR_TODISK && !cpr_is_ufs(rootvfs))) return (ENOTSUP); + if (fcn == AD_CHECK_SUSPEND_TO_RAM || + fcn == DEV_CHECK_SUSPEND_TO_RAM) { + ASSERT(i_cpr_is_supported(cpr_sleeptype)); + return (0); + } + +#if defined(__sparc) if (fcn == AD_CPR_REUSEINIT) { if (mutex_tryenter(&cpr_slock) == 0) return (EBUSY); @@ -247,6 +379,7 @@ cpr(int fcn) mutex_exit(&cpr_slock); return (rc); } +#endif /* * acquire cpr serial lock and init cpr state structure. @@ -254,23 +387,39 @@ cpr(int fcn) if (rc = cpr_init(fcn)) return (rc); +#if defined(__sparc) if (fcn == AD_CPR_REUSABLE) { if ((rc = i_cpr_check_cprinfo()) != 0) { mutex_exit(&cpr_slock); return (rc); } } +#endif /* * Call the main cpr routine. If we are successful, we will be coming * down from the resume side, otherwise we are still in suspend. */ cpr_err(CE_CONT, "System is being suspended"); - if (rc = cpr_main()) { + if (rc = cpr_main(cpr_sleeptype)) { CPR->c_flags |= C_ERROR; + PMD(PMD_SX, ("cpr: Suspend operation failed.\n")) cpr_err(CE_NOTE, "Suspend operation failed."); } else if (CPR->c_flags & C_SUSPENDING) { - extern void cpr_power_down(); + + /* + * In the suspend to RAM case, by the time we get + * control back we're already resumed + */ + if (cpr_sleeptype == CPR_TORAM) { + PMD(PMD_SX, ("cpr: cpr CPR_TORAM done\n")) + cpr_done(); + return (rc); + } + +#if defined(__sparc) + + PMD(PMD_SX, ("cpr: Suspend operation succeeded.\n")) /* * Back from a successful checkpoint */ @@ -280,6 +429,7 @@ cpr(int fcn) } /* make sure there are no more changes to the device tree */ + PMD(PMD_SX, ("cpr: dev tree freeze\n")) devtree_freeze(); /* @@ -288,7 +438,9 @@ cpr(int fcn) * for us to be preempted, we're essentially single threaded * from here on out. */ - stop_other_cpus(); + PMD(PMD_SX, ("cpr: stop other cpus\n")) + i_cpr_stop_other_cpus(); + PMD(PMD_SX, ("cpr: spl6\n")) (void) spl6(); /* @@ -296,24 +448,27 @@ cpr(int fcn) * be called when there are no other threads that could be * accessing devices */ + PMD(PMD_SX, ("cpr: reset leaves\n")) reset_leaves(); /* - * If cpr_power_down() succeeds, it'll not return. + * If i_cpr_power_down() succeeds, it'll not return * * Drives with write-cache enabled need to flush * their cache. */ - if (fcn != AD_CPR_TESTHALT) - cpr_power_down(); - + if (fcn != AD_CPR_TESTHALT) { + PMD(PMD_SX, ("cpr: power down\n")) + (void) i_cpr_power_down(cpr_sleeptype); + } + ASSERT(cpr_sleeptype == CPR_TODISK); + /* currently CPR_TODISK comes back via a boot path */ CPR_DEBUG(CPR_DEBUG1, "(Done. Please Switch Off)\n"); halt(NULL); /* NOTREACHED */ +#endif } - /* - * For resuming: release resources and the serial lock. - */ + PMD(PMD_SX, ("cpr: cpr done\n")) cpr_done(); return (rc); } |