4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
25 * Copyright 2012 Milan Jurik. All rights reserved.
29 * System call to checkpoint and resume the currently running kernel
31 #include <sys/types.h>
32 #include <sys/errno.h>
33 #include <sys/modctl.h>
34 #include <sys/syscall.h>
36 #include <sys/uadmin.h>
37 #include <sys/cmn_err.h>
38 #include <sys/systm.h>
42 #include <sys/autoconf.h>
43 #include <sys/machsystm.h>
45 extern int i_cpr_is_supported(int sleeptype
);
46 extern int cpr_is_ufs(struct vfs
*);
47 extern int cpr_is_zfs(struct vfs
*);
48 extern int cpr_check_spec_statefile(void);
49 extern int cpr_reusable_mount_check(void);
50 extern int i_cpr_reusable_supported(void);
51 extern int i_cpr_reusefini(void);
52 extern struct mod_ops mod_miscops
;
54 extern int cpr_init(int);
55 extern void cpr_done(void);
56 extern void i_cpr_stop_other_cpus(void);
57 extern int i_cpr_power_down(int);
60 static struct modlmisc modlmisc
= {
61 &mod_miscops
, "checkpoint resume"
64 static struct modlinkage modlinkage
= {
65 MODREV_1
, (void *)&modlmisc
, NULL
68 int cpr_reusable_mode
;
70 kmutex_t cpr_slock
; /* cpr serial lock */
73 int cpr_test_mode
; /* true if called via uadmin testmode */
74 int cpr_test_point
= LOOP_BACK_NONE
; /* cpr test point */
75 int cpr_mp_enable
= 0; /* set to 1 to enable MP suspend */
76 major_t cpr_device
= 0; /* major number for S3 on one device */
79 * All the loadable module related code follows
86 if ((e
= mod_install(&modlinkage
)) == 0) {
87 mutex_init(&cpr_slock
, NULL
, MUTEX_DEFAULT
, NULL
);
97 if ((e
= mod_remove(&modlinkage
)) == 0) {
98 mutex_destroy(&cpr_slock
);
104 _info(struct modinfo
*modinfop
)
106 return (mod_info(&modlinkage
, modinfop
));
118 i
= 10 * i
+ (*p
++ - '0');
124 cpr(int fcn
, void *mdep
)
131 * First, reject commands that we don't (yet) support on this arch.
132 * This is easier to understand broken out like this than grotting
133 * through the second switch below.
138 case AD_CHECK_SUSPEND_TO_DISK
:
139 case AD_SUSPEND_TO_DISK
:
140 case AD_CPR_REUSEINIT
:
141 case AD_CPR_NOCOMPRESS
:
143 case AD_CPR_REUSABLE
:
144 case AD_CPR_REUSEFINI
:
147 case AD_CPR_TESTHALT
:
150 /* The DEV_* values need to be removed after sys-syspend is fixed */
151 case DEV_CHECK_SUSPEND_TO_RAM
:
152 case DEV_SUSPEND_TO_RAM
:
153 case AD_CPR_SUSP_DEVICES
:
154 case AD_CHECK_SUSPEND_TO_RAM
:
155 case AD_SUSPEND_TO_RAM
:
156 case AD_LOOPBACK_SUSPEND_TO_RAM_PASS
:
157 case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL
:
158 case AD_FORCE_SUSPEND_TO_RAM
:
159 case AD_DEVICE_SUSPEND_TO_RAM
:
160 cpr_sleeptype
= CPR_TORAM
;
179 cpr_debug
|= CPR_DEBUG_BIT(fcn
);
183 cpr_debug
|= CPR_DEBUG6
;
186 /* The DEV_* values need to be removed after sys-syspend is fixed */
187 case DEV_CHECK_SUSPEND_TO_RAM
:
188 case DEV_SUSPEND_TO_RAM
:
189 case AD_CHECK_SUSPEND_TO_RAM
:
190 case AD_SUSPEND_TO_RAM
:
191 cpr_test_point
= LOOP_BACK_NONE
;
194 case AD_LOOPBACK_SUSPEND_TO_RAM_PASS
:
195 cpr_test_point
= LOOP_BACK_PASS
;
198 case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL
:
199 cpr_test_point
= LOOP_BACK_FAIL
;
202 case AD_FORCE_SUSPEND_TO_RAM
:
203 cpr_test_point
= FORCE_SUSPEND_TO_RAM
;
206 case AD_DEVICE_SUSPEND_TO_RAM
:
208 /* Didn't pass enough arguments */
211 cpr_test_point
= DEVICE_SUSPEND_TO_RAM
;
212 cpr_device
= (major_t
)atoi((char *)mdep
);
215 case AD_CPR_SUSP_DEVICES
:
216 cpr_test_point
= FORCE_SUSPEND_TO_RAM
;
217 if (cpr_suspend_devices(ddi_root_node()) != DDI_SUCCESS
)
219 "Some devices did not suspend "
220 "and may be unusable");
221 (void) cpr_resume_devices(ddi_root_node(), 0);
228 if (!i_cpr_is_supported(cpr_sleeptype
))
232 if (fcn
== AD_CHECK_SUSPEND_TO_RAM
||
233 fcn
== DEV_CHECK_SUSPEND_TO_RAM
) {
234 ASSERT(i_cpr_is_supported(cpr_sleeptype
));
240 * acquire cpr serial lock and init cpr state structure.
242 if (rc
= cpr_init(fcn
))
247 * Call the main cpr routine. If we are successful, we will be coming
248 * down from the resume side, otherwise we are still in suspend.
250 cpr_err(CE_CONT
, "System is being suspended");
251 if (rc
= cpr_main(cpr_sleeptype
)) {
252 CPR
->c_flags
|= C_ERROR
;
253 PMD(PMD_SX
, ("cpr: Suspend operation failed.\n"))
254 cpr_err(CE_NOTE
, "Suspend operation failed.");
255 } else if (CPR
->c_flags
& C_SUSPENDING
) {
258 * In the suspend to RAM case, by the time we get
259 * control back we're already resumed
261 if (cpr_sleeptype
== CPR_TORAM
) {
262 PMD(PMD_SX
, ("cpr: cpr CPR_TORAM done\n"))
268 PMD(PMD_SX
, ("cpr: cpr done\n"))