summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/cpr/cpr_mod.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/cpr/cpr_mod.c')
-rw-r--r--usr/src/uts/common/cpr/cpr_mod.c191
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);
}