Home | History | Annotate | Download | only in cpr
      1 /*
      2  * CDDL HEADER START
      3  *
      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.
      7  *
      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.
     12  *
     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]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 /*
     29  * System call to checkpoint and resume the currently running kernel
     30  */
     31 #include <sys/types.h>
     32 #include <sys/errno.h>
     33 #include <sys/modctl.h>
     34 #include <sys/syscall.h>
     35 #include <sys/cred.h>
     36 #include <sys/uadmin.h>
     37 #include <sys/cmn_err.h>
     38 #include <sys/systm.h>
     39 #include <sys/cpr.h>
     40 #include <sys/swap.h>
     41 #include <sys/vfs.h>
     42 #include <sys/autoconf.h>
     43 #include <sys/machsystm.h>
     44 
     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;
     53 
     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();
     58 
     59 #if defined(__sparc)
     60 extern void cpr_forget_cprconfig(void);
     61 #endif
     62 
     63 static struct modlmisc modlmisc = {
     64 	&mod_miscops, "checkpoint resume"
     65 };
     66 
     67 static struct modlinkage modlinkage = {
     68 	MODREV_1, (void *)&modlmisc, NULL
     69 };
     70 
     71 char _depends_on[] = "misc/bootdev";	/* i_devname_to_promname() */
     72 
     73 int cpr_reusable_mode;
     74 
     75 kmutex_t	cpr_slock;	/* cpr serial lock */
     76 cpr_t		cpr_state;
     77 int		cpr_debug;
     78 int		cpr_test_mode; /* true if called via uadmin testmode */
     79 int		cpr_test_point = LOOP_BACK_NONE;	/* cpr test point */
     80 int		cpr_mp_enable = 0;	/* set to 1 to enable MP suspend */
     81 major_t		cpr_device = 0;		/* major number for S3 on one device */
     82 
     83 /*
     84  * All the loadable module related code follows
     85  */
     86 int
     87 _init(void)
     88 {
     89 	register int e;
     90 
     91 	if ((e = mod_install(&modlinkage)) == 0) {
     92 		mutex_init(&cpr_slock, NULL, MUTEX_DEFAULT, NULL);
     93 	}
     94 	return (e);
     95 }
     96 
     97 int
     98 _fini(void)
     99 {
    100 	register int e;
    101 
    102 	if ((e = mod_remove(&modlinkage)) == 0) {
    103 		mutex_destroy(&cpr_slock);
    104 	}
    105 	return (e);
    106 }
    107 
    108 int
    109 _info(struct modinfo *modinfop)
    110 {
    111 	return (mod_info(&modlinkage, modinfop));
    112 }
    113 
    114 static
    115 int
    116 atoi(char *p)
    117 {
    118 	int	i;
    119 
    120 	i = (*p++ - '0');
    121 
    122 	while (*p != '\0')
    123 		i = 10 * i + (*p++ - '0');
    124 
    125 	return (i);
    126 }
    127 
    128 int
    129 cpr(int fcn, void *mdep)
    130 {
    131 
    132 #if defined(__sparc)
    133 	static const char noswapstr[] = "reusable statefile requires "
    134 	    "that no swap area be configured.\n";
    135 	static const char blockstr[] = "reusable statefile must be "
    136 	    "a block device.  See power.conf(4) and pmconfig(1M).\n";
    137 	static const char normalfmt[] = "cannot run normal "
    138 	    "checkpoint/resume when in reusable statefile mode. "
    139 	    "use uadmin A_FREEZE AD_REUSEFINI (uadmin %d %d) "
    140 	    "to exit reusable statefile mode.\n";
    141 	static const char modefmt[] = "%s in reusable mode.\n";
    142 #endif
    143 	register int rc = 0;
    144 	int cpr_sleeptype;
    145 
    146 	/*
    147 	 * First, reject commands that we don't (yet) support on this arch.
    148 	 * This is easier to understand broken out like this than grotting
    149 	 * through the second switch below.
    150 	 */
    151 
    152 	switch (fcn) {
    153 #if defined(__sparc)
    154 	case AD_CHECK_SUSPEND_TO_RAM:
    155 	case AD_SUSPEND_TO_RAM:
    156 		return (ENOTSUP);
    157 	case AD_CHECK_SUSPEND_TO_DISK:
    158 	case AD_SUSPEND_TO_DISK:
    159 	case AD_CPR_REUSEINIT:
    160 	case AD_CPR_NOCOMPRESS:
    161 	case AD_CPR_FORCE:
    162 	case AD_CPR_REUSABLE:
    163 	case AD_CPR_REUSEFINI:
    164 	case AD_CPR_TESTZ:
    165 	case AD_CPR_TESTNOZ:
    166 	case AD_CPR_TESTHALT:
    167 	case AD_CPR_SUSP_DEVICES:
    168 		cpr_sleeptype = CPR_TODISK;
    169 		break;
    170 #endif
    171 #if defined(__x86)
    172 	case AD_CHECK_SUSPEND_TO_DISK:
    173 	case AD_SUSPEND_TO_DISK:
    174 	case AD_CPR_REUSEINIT:
    175 	case AD_CPR_NOCOMPRESS:
    176 	case AD_CPR_FORCE:
    177 	case AD_CPR_REUSABLE:
    178 	case AD_CPR_REUSEFINI:
    179 	case AD_CPR_TESTZ:
    180 	case AD_CPR_TESTNOZ:
    181 	case AD_CPR_TESTHALT:
    182 	case AD_CPR_PRINT:
    183 		return (ENOTSUP);
    184 	/* The DEV_* values need to be removed after sys-syspend is fixed */
    185 	case DEV_CHECK_SUSPEND_TO_RAM:
    186 	case DEV_SUSPEND_TO_RAM:
    187 	case AD_CPR_SUSP_DEVICES:
    188 	case AD_CHECK_SUSPEND_TO_RAM:
    189 	case AD_SUSPEND_TO_RAM:
    190 	case AD_LOOPBACK_SUSPEND_TO_RAM_PASS:
    191 	case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL:
    192 	case AD_FORCE_SUSPEND_TO_RAM:
    193 	case AD_DEVICE_SUSPEND_TO_RAM:
    194 		cpr_sleeptype = CPR_TORAM;
    195 		break;
    196 #endif
    197 	}
    198 #if defined(__sparc)
    199 	/*
    200 	 * Need to know if we're in reusable mode, but we will likely have
    201 	 * rebooted since REUSEINIT, so we have to get the info from the
    202 	 * file system
    203 	 */
    204 	if (!cpr_reusable_mode)
    205 		cpr_reusable_mode = cpr_get_reusable_mode();
    206 
    207 	cpr_forget_cprconfig();
    208 #endif
    209 
    210 	switch (fcn) {
    211 
    212 #if defined(__sparc)
    213 	case AD_CPR_REUSEINIT:
    214 		if (!i_cpr_reusable_supported())
    215 			return (ENOTSUP);
    216 		if (!cpr_statefile_is_spec()) {
    217 			cpr_err(CE_CONT, blockstr);
    218 			return (EINVAL);
    219 		}
    220 		if ((rc = cpr_check_spec_statefile()) != 0)
    221 			return (rc);
    222 		if (swapinfo) {
    223 			cpr_err(CE_CONT, noswapstr);
    224 			return (EINVAL);
    225 		}
    226 		cpr_test_mode = 0;
    227 		break;
    228 
    229 	case AD_CPR_NOCOMPRESS:
    230 	case AD_CPR_COMPRESS:
    231 	case AD_CPR_FORCE:
    232 		if (cpr_reusable_mode) {
    233 			cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI);
    234 			return (ENOTSUP);
    235 		}
    236 		cpr_test_mode = 0;
    237 		break;
    238 
    239 	case AD_CPR_REUSABLE:
    240 		if (!i_cpr_reusable_supported())
    241 			return (ENOTSUP);
    242 		if (!cpr_statefile_is_spec()) {
    243 			cpr_err(CE_CONT, blockstr);
    244 			return (EINVAL);
    245 		}
    246 		if ((rc = cpr_check_spec_statefile()) != 0)
    247 			return (rc);
    248 		if (swapinfo) {
    249 			cpr_err(CE_CONT, noswapstr);
    250 			return (EINVAL);
    251 		}
    252 		if ((rc = cpr_reusable_mount_check()) != 0)
    253 			return (rc);
    254 		cpr_test_mode = 0;
    255 		break;
    256 
    257 	case AD_CPR_REUSEFINI:
    258 		if (!i_cpr_reusable_supported())
    259 			return (ENOTSUP);
    260 		cpr_test_mode = 0;
    261 		break;
    262 
    263 	case AD_CPR_TESTZ:
    264 	case AD_CPR_TESTNOZ:
    265 	case AD_CPR_TESTHALT:
    266 		if (cpr_reusable_mode) {
    267 			cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI);
    268 			return (ENOTSUP);
    269 		}
    270 		cpr_test_mode = 1;
    271 		break;
    272 
    273 	case AD_CPR_CHECK:
    274 		if (!i_cpr_is_supported(cpr_sleeptype) || cpr_reusable_mode)
    275 			return (ENOTSUP);
    276 		return (0);
    277 
    278 	case AD_CPR_PRINT:
    279 		CPR_STAT_EVENT_END("POST CPR DELAY");
    280 		cpr_stat_event_print();
    281 		return (0);
    282 #endif
    283 
    284 	case AD_CPR_DEBUG0:
    285 		cpr_debug = 0;
    286 		return (0);
    287 
    288 	case AD_CPR_DEBUG1:
    289 	case AD_CPR_DEBUG2:
    290 	case AD_CPR_DEBUG3:
    291 	case AD_CPR_DEBUG4:
    292 	case AD_CPR_DEBUG5:
    293 	case AD_CPR_DEBUG7:
    294 	case AD_CPR_DEBUG8:
    295 		cpr_debug |= CPR_DEBUG_BIT(fcn);
    296 		return (0);
    297 
    298 	case AD_CPR_DEBUG9:
    299 		cpr_debug |= CPR_DEBUG6;
    300 		return (0);
    301 
    302 	/* The DEV_* values need to be removed after sys-syspend is fixed */
    303 	case DEV_CHECK_SUSPEND_TO_RAM:
    304 	case DEV_SUSPEND_TO_RAM:
    305 	case AD_CHECK_SUSPEND_TO_RAM:
    306 	case AD_SUSPEND_TO_RAM:
    307 		cpr_test_point = LOOP_BACK_NONE;
    308 		break;
    309 
    310 	case AD_LOOPBACK_SUSPEND_TO_RAM_PASS:
    311 		cpr_test_point = LOOP_BACK_PASS;
    312 		break;
    313 
    314 	case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL:
    315 		cpr_test_point = LOOP_BACK_FAIL;
    316 		break;
    317 
    318 	case AD_FORCE_SUSPEND_TO_RAM:
    319 		cpr_test_point = FORCE_SUSPEND_TO_RAM;
    320 		break;
    321 
    322 	case AD_DEVICE_SUSPEND_TO_RAM:
    323 		if (mdep == NULL) {
    324 			/* Didn't pass enough arguments */
    325 			return (EINVAL);
    326 		}
    327 		cpr_test_point = DEVICE_SUSPEND_TO_RAM;
    328 		cpr_device = (major_t)atoi((char *)mdep);
    329 		break;
    330 
    331 	case AD_CPR_SUSP_DEVICES:
    332 		cpr_test_point = FORCE_SUSPEND_TO_RAM;
    333 		if (cpr_suspend_devices(ddi_root_node()) != DDI_SUCCESS)
    334 			cmn_err(CE_WARN,
    335 			    "Some devices did not suspend "
    336 			    "and may be unusable");
    337 		(void) cpr_resume_devices(ddi_root_node(), 0);
    338 		return (0);
    339 
    340 	default:
    341 		return (ENOTSUP);
    342 	}
    343 
    344 	if (!i_cpr_is_supported(cpr_sleeptype) ||
    345 	    (cpr_sleeptype == CPR_TODISK &&
    346 	    !cpr_is_ufs(rootvfs)&& !cpr_is_zfs(rootvfs)))
    347 		return (ENOTSUP);
    348 
    349 	if (fcn == AD_CHECK_SUSPEND_TO_RAM ||
    350 	    fcn == DEV_CHECK_SUSPEND_TO_RAM) {
    351 		ASSERT(i_cpr_is_supported(cpr_sleeptype));
    352 		return (0);
    353 	}
    354 
    355 #if defined(__sparc)
    356 	if (fcn == AD_CPR_REUSEINIT) {
    357 		if (mutex_tryenter(&cpr_slock) == 0)
    358 			return (EBUSY);
    359 		if (cpr_reusable_mode) {
    360 			cpr_err(CE_CONT, modefmt, "already");
    361 			mutex_exit(&cpr_slock);
    362 			return (EBUSY);
    363 		}
    364 		rc = i_cpr_reuseinit();
    365 		mutex_exit(&cpr_slock);
    366 		return (rc);
    367 	}
    368 
    369 	if (fcn == AD_CPR_REUSEFINI) {
    370 		if (mutex_tryenter(&cpr_slock) == 0)
    371 			return (EBUSY);
    372 		if (!cpr_reusable_mode) {
    373 			cpr_err(CE_CONT, modefmt, "not");
    374 			mutex_exit(&cpr_slock);
    375 			return (EINVAL);
    376 		}
    377 		rc = i_cpr_reusefini();
    378 		mutex_exit(&cpr_slock);
    379 		return (rc);
    380 	}
    381 #endif
    382 
    383 	/*
    384 	 * acquire cpr serial lock and init cpr state structure.
    385 	 */
    386 	if (rc = cpr_init(fcn))
    387 		return (rc);
    388 
    389 #if defined(__sparc)
    390 	if (fcn == AD_CPR_REUSABLE) {
    391 		if ((rc = i_cpr_check_cprinfo()) != 0)  {
    392 			mutex_exit(&cpr_slock);
    393 			return (rc);
    394 		}
    395 	}
    396 #endif
    397 
    398 	/*
    399 	 * Call the main cpr routine. If we are successful, we will be coming
    400 	 * down from the resume side, otherwise we are still in suspend.
    401 	 */
    402 	cpr_err(CE_CONT, "System is being suspended");
    403 	if (rc = cpr_main(cpr_sleeptype)) {
    404 		CPR->c_flags |= C_ERROR;
    405 		PMD(PMD_SX, ("cpr: Suspend operation failed.\n"))
    406 		cpr_err(CE_NOTE, "Suspend operation failed.");
    407 	} else if (CPR->c_flags & C_SUSPENDING) {
    408 
    409 		/*
    410 		 * In the suspend to RAM case, by the time we get
    411 		 * control back we're already resumed
    412 		 */
    413 		if (cpr_sleeptype == CPR_TORAM) {
    414 			PMD(PMD_SX, ("cpr: cpr CPR_TORAM done\n"))
    415 			cpr_done();
    416 			return (rc);
    417 		}
    418 
    419 #if defined(__sparc)
    420 
    421 		PMD(PMD_SX, ("cpr: Suspend operation succeeded.\n"))
    422 		/*
    423 		 * Back from a successful checkpoint
    424 		 */
    425 		if (fcn == AD_CPR_TESTZ || fcn == AD_CPR_TESTNOZ) {
    426 			mdboot(0, AD_BOOT, "", B_FALSE);
    427 			/* NOTREACHED */
    428 		}
    429 
    430 		/* make sure there are no more changes to the device tree */
    431 		PMD(PMD_SX, ("cpr: dev tree freeze\n"))
    432 		devtree_freeze();
    433 
    434 		/*
    435 		 * stop other cpus and raise our priority.  since there is only
    436 		 * one active cpu after this, and our priority will be too high
    437 		 * for us to be preempted, we're essentially single threaded
    438 		 * from here on out.
    439 		 */
    440 		PMD(PMD_SX, ("cpr: stop other cpus\n"))
    441 		i_cpr_stop_other_cpus();
    442 		PMD(PMD_SX, ("cpr: spl6\n"))
    443 		(void) spl6();
    444 
    445 		/*
    446 		 * try and reset leaf devices.  reset_leaves() should only
    447 		 * be called when there are no other threads that could be
    448 		 * accessing devices
    449 		 */
    450 		PMD(PMD_SX, ("cpr: reset leaves\n"))
    451 		reset_leaves();
    452 
    453 		/*
    454 		 * If i_cpr_power_down() succeeds, it'll not return
    455 		 *
    456 		 * Drives with write-cache enabled need to flush
    457 		 * their cache.
    458 		 */
    459 		if (fcn != AD_CPR_TESTHALT) {
    460 			PMD(PMD_SX, ("cpr: power down\n"))
    461 			(void) i_cpr_power_down(cpr_sleeptype);
    462 		}
    463 		ASSERT(cpr_sleeptype == CPR_TODISK);
    464 		/* currently CPR_TODISK comes back via a boot path */
    465 		CPR_DEBUG(CPR_DEBUG1, "(Done. Please Switch Off)\n");
    466 		halt(NULL);
    467 		/* NOTREACHED */
    468 #endif
    469 	}
    470 	PMD(PMD_SX, ("cpr: cpr done\n"))
    471 	cpr_done();
    472 	return (rc);
    473 }
    474