xref: /onnv-gate/usr/src/uts/common/cpr/cpr_mod.c (revision 5817:99b261e22ee4)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53446Smrj  * Common Development and Distribution License (the "License").
63446Smrj  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*5817Sjan  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * System call to checkpoint and resume the currently running kernel
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/errno.h>
330Sstevel@tonic-gate #include <sys/modctl.h>
340Sstevel@tonic-gate #include <sys/syscall.h>
350Sstevel@tonic-gate #include <sys/cred.h>
360Sstevel@tonic-gate #include <sys/uadmin.h>
370Sstevel@tonic-gate #include <sys/cmn_err.h>
380Sstevel@tonic-gate #include <sys/systm.h>
390Sstevel@tonic-gate #include <sys/cpr.h>
400Sstevel@tonic-gate #include <sys/swap.h>
410Sstevel@tonic-gate #include <sys/vfs.h>
420Sstevel@tonic-gate #include <sys/autoconf.h>
430Sstevel@tonic-gate #include <sys/machsystm.h>
440Sstevel@tonic-gate 
455295Srandyf extern int i_cpr_is_supported(int sleeptype);
460Sstevel@tonic-gate extern int cpr_is_ufs(struct vfs *);
470Sstevel@tonic-gate extern int cpr_check_spec_statefile(void);
480Sstevel@tonic-gate extern int cpr_reusable_mount_check(void);
490Sstevel@tonic-gate extern int i_cpr_reusable_supported(void);
500Sstevel@tonic-gate extern int i_cpr_reusefini(void);
515295Srandyf extern struct mod_ops mod_miscops;
520Sstevel@tonic-gate 
535295Srandyf extern int cpr_init(int);
545295Srandyf extern void cpr_done(void);
555295Srandyf extern void i_cpr_stop_other_cpus(void);
565295Srandyf extern int i_cpr_power_down();
575295Srandyf 
585295Srandyf #if defined(__sparc)
595295Srandyf extern void cpr_forget_cprconfig(void);
605295Srandyf #endif
610Sstevel@tonic-gate 
620Sstevel@tonic-gate static struct modlmisc modlmisc = {
630Sstevel@tonic-gate 	&mod_miscops, "checkpoint resume"
640Sstevel@tonic-gate };
650Sstevel@tonic-gate 
660Sstevel@tonic-gate static struct modlinkage modlinkage = {
670Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
680Sstevel@tonic-gate };
690Sstevel@tonic-gate 
700Sstevel@tonic-gate char _depends_on[] = "misc/bootdev";	/* i_devname_to_promname() */
710Sstevel@tonic-gate 
720Sstevel@tonic-gate int cpr_reusable_mode;
730Sstevel@tonic-gate 
740Sstevel@tonic-gate kmutex_t	cpr_slock;	/* cpr serial lock */
750Sstevel@tonic-gate cpr_t		cpr_state;
760Sstevel@tonic-gate int		cpr_debug;
770Sstevel@tonic-gate int		cpr_test_mode; /* true if called via uadmin testmode */
785295Srandyf int		cpr_test_point = LOOP_BACK_NONE;	/* cpr test point */
795295Srandyf int		cpr_mp_enable = 0;	/* set to 1 to enable MP suspend */
805295Srandyf major_t		cpr_device = 0;		/* major number for S3 on one device */
810Sstevel@tonic-gate 
820Sstevel@tonic-gate /*
830Sstevel@tonic-gate  * All the loadable module related code follows
840Sstevel@tonic-gate  */
850Sstevel@tonic-gate int
860Sstevel@tonic-gate _init(void)
870Sstevel@tonic-gate {
880Sstevel@tonic-gate 	register int e;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	if ((e = mod_install(&modlinkage)) == 0) {
910Sstevel@tonic-gate 		mutex_init(&cpr_slock, NULL, MUTEX_DEFAULT, NULL);
920Sstevel@tonic-gate 	}
930Sstevel@tonic-gate 	return (e);
940Sstevel@tonic-gate }
950Sstevel@tonic-gate 
960Sstevel@tonic-gate int
970Sstevel@tonic-gate _fini(void)
980Sstevel@tonic-gate {
990Sstevel@tonic-gate 	register int e;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	if ((e = mod_remove(&modlinkage)) == 0) {
1020Sstevel@tonic-gate 		mutex_destroy(&cpr_slock);
1030Sstevel@tonic-gate 	}
1040Sstevel@tonic-gate 	return (e);
1050Sstevel@tonic-gate }
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate int
1080Sstevel@tonic-gate _info(struct modinfo *modinfop)
1090Sstevel@tonic-gate {
1100Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate 
1135295Srandyf static
1140Sstevel@tonic-gate int
1155295Srandyf atoi(char *p)
1160Sstevel@tonic-gate {
1175295Srandyf 	int	i;
1185295Srandyf 
1195295Srandyf 	i = (*p++ - '0');
1205295Srandyf 
1215295Srandyf 	while (*p != '\0')
1225295Srandyf 		i = 10 * i + (*p++ - '0');
1235295Srandyf 
1245295Srandyf 	return (i);
1255295Srandyf }
1265295Srandyf 
1275295Srandyf int
1285295Srandyf cpr(int fcn, void *mdep)
1295295Srandyf {
1305295Srandyf 
1315295Srandyf #if defined(__sparc)
1320Sstevel@tonic-gate 	static const char noswapstr[] = "reusable statefile requires "
1330Sstevel@tonic-gate 	    "that no swap area be configured.\n";
1340Sstevel@tonic-gate 	static const char blockstr[] = "reusable statefile must be "
1350Sstevel@tonic-gate 	    "a block device.  See power.conf(4) and pmconfig(1M).\n";
1360Sstevel@tonic-gate 	static const char normalfmt[] = "cannot run normal "
1370Sstevel@tonic-gate 	    "checkpoint/resume when in reusable statefile mode. "
1380Sstevel@tonic-gate 	    "use uadmin A_FREEZE AD_REUSEFINI (uadmin %d %d) "
1390Sstevel@tonic-gate 	    "to exit reusable statefile mode.\n";
1400Sstevel@tonic-gate 	static const char modefmt[] = "%s in reusable mode.\n";
1415295Srandyf #endif
1420Sstevel@tonic-gate 	register int rc = 0;
1435295Srandyf 	int cpr_sleeptype;
1445295Srandyf 
1455295Srandyf 	/*
1465295Srandyf 	 * First, reject commands that we don't (yet) support on this arch.
1475295Srandyf 	 * This is easier to understand broken out like this than grotting
1485295Srandyf 	 * through the second switch below.
1495295Srandyf 	 */
1500Sstevel@tonic-gate 
1515295Srandyf 	switch (fcn) {
1525295Srandyf #if defined(__sparc)
1535295Srandyf 	case AD_CHECK_SUSPEND_TO_RAM:
1545295Srandyf 	case AD_SUSPEND_TO_RAM:
1555295Srandyf 		return (ENOTSUP);
1565295Srandyf 	case AD_CHECK_SUSPEND_TO_DISK:
1575295Srandyf 	case AD_SUSPEND_TO_DISK:
1585295Srandyf 	case AD_CPR_REUSEINIT:
1595295Srandyf 	case AD_CPR_NOCOMPRESS:
1605295Srandyf 	case AD_CPR_FORCE:
1615295Srandyf 	case AD_CPR_REUSABLE:
1625295Srandyf 	case AD_CPR_REUSEFINI:
1635295Srandyf 	case AD_CPR_TESTZ:
1645295Srandyf 	case AD_CPR_TESTNOZ:
1655295Srandyf 	case AD_CPR_TESTHALT:
1665295Srandyf 	case AD_CPR_SUSP_DEVICES:
1675295Srandyf 		cpr_sleeptype = CPR_TODISK;
1685295Srandyf 		break;
1695295Srandyf #endif
1705295Srandyf #if defined(__x86)
1715295Srandyf 	case AD_CHECK_SUSPEND_TO_DISK:
1725295Srandyf 	case AD_SUSPEND_TO_DISK:
1735295Srandyf 	case AD_CPR_REUSEINIT:
1745295Srandyf 	case AD_CPR_NOCOMPRESS:
1755295Srandyf 	case AD_CPR_FORCE:
1765295Srandyf 	case AD_CPR_REUSABLE:
1775295Srandyf 	case AD_CPR_REUSEFINI:
1785295Srandyf 	case AD_CPR_TESTZ:
1795295Srandyf 	case AD_CPR_TESTNOZ:
1805295Srandyf 	case AD_CPR_TESTHALT:
1815295Srandyf 	case AD_CPR_PRINT:
1825295Srandyf 		return (ENOTSUP);
1835295Srandyf 	/* The DEV_* values need to be removed after sys-syspend is fixed */
1845295Srandyf 	case DEV_CHECK_SUSPEND_TO_RAM:
1855295Srandyf 	case DEV_SUSPEND_TO_RAM:
1865295Srandyf 	case AD_CPR_SUSP_DEVICES:
1875295Srandyf 	case AD_CHECK_SUSPEND_TO_RAM:
1885295Srandyf 	case AD_SUSPEND_TO_RAM:
1895295Srandyf 	case AD_LOOPBACK_SUSPEND_TO_RAM_PASS:
1905295Srandyf 	case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL:
1915295Srandyf 	case AD_FORCE_SUSPEND_TO_RAM:
1925295Srandyf 	case AD_DEVICE_SUSPEND_TO_RAM:
193*5817Sjan 		cpr_sleeptype = CPR_TORAM;
1945295Srandyf 		break;
1955295Srandyf #endif
1965295Srandyf 	}
1975295Srandyf #if defined(__sparc)
1980Sstevel@tonic-gate 	/*
1990Sstevel@tonic-gate 	 * Need to know if we're in reusable mode, but we will likely have
2000Sstevel@tonic-gate 	 * rebooted since REUSEINIT, so we have to get the info from the
2010Sstevel@tonic-gate 	 * file system
2020Sstevel@tonic-gate 	 */
2030Sstevel@tonic-gate 	if (!cpr_reusable_mode)
2040Sstevel@tonic-gate 		cpr_reusable_mode = cpr_get_reusable_mode();
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	cpr_forget_cprconfig();
2075295Srandyf #endif
2085295Srandyf 
2090Sstevel@tonic-gate 	switch (fcn) {
2100Sstevel@tonic-gate 
2115295Srandyf #if defined(__sparc)
2120Sstevel@tonic-gate 	case AD_CPR_REUSEINIT:
2130Sstevel@tonic-gate 		if (!i_cpr_reusable_supported())
2140Sstevel@tonic-gate 			return (ENOTSUP);
2150Sstevel@tonic-gate 		if (!cpr_statefile_is_spec()) {
2160Sstevel@tonic-gate 			cpr_err(CE_CONT, blockstr);
2170Sstevel@tonic-gate 			return (EINVAL);
2180Sstevel@tonic-gate 		}
2190Sstevel@tonic-gate 		if ((rc = cpr_check_spec_statefile()) != 0)
2200Sstevel@tonic-gate 			return (rc);
2210Sstevel@tonic-gate 		if (swapinfo) {
2220Sstevel@tonic-gate 			cpr_err(CE_CONT, noswapstr);
2230Sstevel@tonic-gate 			return (EINVAL);
2240Sstevel@tonic-gate 		}
2250Sstevel@tonic-gate 		cpr_test_mode = 0;
2260Sstevel@tonic-gate 		break;
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	case AD_CPR_NOCOMPRESS:
2290Sstevel@tonic-gate 	case AD_CPR_COMPRESS:
2300Sstevel@tonic-gate 	case AD_CPR_FORCE:
2310Sstevel@tonic-gate 		if (cpr_reusable_mode) {
2320Sstevel@tonic-gate 			cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI);
2330Sstevel@tonic-gate 			return (ENOTSUP);
2340Sstevel@tonic-gate 		}
2350Sstevel@tonic-gate 		cpr_test_mode = 0;
2360Sstevel@tonic-gate 		break;
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	case AD_CPR_REUSABLE:
2390Sstevel@tonic-gate 		if (!i_cpr_reusable_supported())
2400Sstevel@tonic-gate 			return (ENOTSUP);
2410Sstevel@tonic-gate 		if (!cpr_statefile_is_spec()) {
2420Sstevel@tonic-gate 			cpr_err(CE_CONT, blockstr);
2430Sstevel@tonic-gate 			return (EINVAL);
2440Sstevel@tonic-gate 		}
2450Sstevel@tonic-gate 		if ((rc = cpr_check_spec_statefile()) != 0)
2460Sstevel@tonic-gate 			return (rc);
2470Sstevel@tonic-gate 		if (swapinfo) {
2480Sstevel@tonic-gate 			cpr_err(CE_CONT, noswapstr);
2490Sstevel@tonic-gate 			return (EINVAL);
2500Sstevel@tonic-gate 		}
2510Sstevel@tonic-gate 		if ((rc = cpr_reusable_mount_check()) != 0)
2520Sstevel@tonic-gate 			return (rc);
2530Sstevel@tonic-gate 		cpr_test_mode = 0;
2540Sstevel@tonic-gate 		break;
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	case AD_CPR_REUSEFINI:
2570Sstevel@tonic-gate 		if (!i_cpr_reusable_supported())
2580Sstevel@tonic-gate 			return (ENOTSUP);
2590Sstevel@tonic-gate 		cpr_test_mode = 0;
2600Sstevel@tonic-gate 		break;
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	case AD_CPR_TESTZ:
2630Sstevel@tonic-gate 	case AD_CPR_TESTNOZ:
2640Sstevel@tonic-gate 	case AD_CPR_TESTHALT:
2650Sstevel@tonic-gate 		if (cpr_reusable_mode) {
2660Sstevel@tonic-gate 			cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI);
2670Sstevel@tonic-gate 			return (ENOTSUP);
2680Sstevel@tonic-gate 		}
2690Sstevel@tonic-gate 		cpr_test_mode = 1;
2700Sstevel@tonic-gate 		break;
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	case AD_CPR_CHECK:
2735295Srandyf 		if (!i_cpr_is_supported(cpr_sleeptype) || cpr_reusable_mode)
2740Sstevel@tonic-gate 			return (ENOTSUP);
2750Sstevel@tonic-gate 		return (0);
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	case AD_CPR_PRINT:
2780Sstevel@tonic-gate 		CPR_STAT_EVENT_END("POST CPR DELAY");
2790Sstevel@tonic-gate 		cpr_stat_event_print();
2800Sstevel@tonic-gate 		return (0);
2815295Srandyf #endif
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	case AD_CPR_DEBUG0:
2840Sstevel@tonic-gate 		cpr_debug = 0;
2850Sstevel@tonic-gate 		return (0);
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	case AD_CPR_DEBUG1:
2880Sstevel@tonic-gate 	case AD_CPR_DEBUG2:
2890Sstevel@tonic-gate 	case AD_CPR_DEBUG3:
2900Sstevel@tonic-gate 	case AD_CPR_DEBUG4:
2910Sstevel@tonic-gate 	case AD_CPR_DEBUG5:
2920Sstevel@tonic-gate 	case AD_CPR_DEBUG7:
2930Sstevel@tonic-gate 	case AD_CPR_DEBUG8:
2940Sstevel@tonic-gate 		cpr_debug |= CPR_DEBUG_BIT(fcn);
2950Sstevel@tonic-gate 		return (0);
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	case AD_CPR_DEBUG9:
2983446Smrj 		cpr_debug |= CPR_DEBUG6;
2990Sstevel@tonic-gate 		return (0);
3000Sstevel@tonic-gate 
3015295Srandyf 	/* The DEV_* values need to be removed after sys-syspend is fixed */
3025295Srandyf 	case DEV_CHECK_SUSPEND_TO_RAM:
3035295Srandyf 	case DEV_SUSPEND_TO_RAM:
3045295Srandyf 	case AD_CHECK_SUSPEND_TO_RAM:
3055295Srandyf 	case AD_SUSPEND_TO_RAM:
3065295Srandyf 		cpr_test_point = LOOP_BACK_NONE;
3075295Srandyf 		break;
3085295Srandyf 
3095295Srandyf 	case AD_LOOPBACK_SUSPEND_TO_RAM_PASS:
3105295Srandyf 		cpr_test_point = LOOP_BACK_PASS;
3115295Srandyf 		break;
3125295Srandyf 
3135295Srandyf 	case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL:
3145295Srandyf 		cpr_test_point = LOOP_BACK_FAIL;
3155295Srandyf 		break;
3165295Srandyf 
3175295Srandyf 	case AD_FORCE_SUSPEND_TO_RAM:
3185295Srandyf 		cpr_test_point = FORCE_SUSPEND_TO_RAM;
3195295Srandyf 		break;
3205295Srandyf 
3215295Srandyf 	case AD_DEVICE_SUSPEND_TO_RAM:
3225732Srandyf 		if (mdep == NULL) {
3235732Srandyf 			/* Didn't pass enough arguments */
3245732Srandyf 			return (EINVAL);
3255732Srandyf 		}
3265295Srandyf 		cpr_test_point = DEVICE_SUSPEND_TO_RAM;
3275295Srandyf 		cpr_device = (major_t)atoi((char *)mdep);
3285295Srandyf 		break;
3295295Srandyf 
3305295Srandyf 	case AD_CPR_SUSP_DEVICES:
3315295Srandyf 		cpr_test_point = FORCE_SUSPEND_TO_RAM;
3325295Srandyf 		if (cpr_suspend_devices(ddi_root_node()) != DDI_SUCCESS)
3335295Srandyf 			cmn_err(CE_WARN,
3345295Srandyf 			    "Some devices did not suspend "
3355295Srandyf 			    "and may be unusable");
3365295Srandyf 		(void) cpr_resume_devices(ddi_root_node(), 0);
3375295Srandyf 		return (0);
3385295Srandyf 
3390Sstevel@tonic-gate 	default:
3400Sstevel@tonic-gate 		return (ENOTSUP);
3410Sstevel@tonic-gate 	}
3420Sstevel@tonic-gate 
3435295Srandyf 	if (!i_cpr_is_supported(cpr_sleeptype) ||
3445295Srandyf 	    (cpr_sleeptype == CPR_TODISK && !cpr_is_ufs(rootvfs)))
3450Sstevel@tonic-gate 		return (ENOTSUP);
3460Sstevel@tonic-gate 
3475295Srandyf 	if (fcn == AD_CHECK_SUSPEND_TO_RAM ||
3485295Srandyf 	    fcn == DEV_CHECK_SUSPEND_TO_RAM) {
3495295Srandyf 		ASSERT(i_cpr_is_supported(cpr_sleeptype));
3505295Srandyf 		return (0);
3515295Srandyf 	}
3525295Srandyf 
3535295Srandyf #if defined(__sparc)
3540Sstevel@tonic-gate 	if (fcn == AD_CPR_REUSEINIT) {
3550Sstevel@tonic-gate 		if (mutex_tryenter(&cpr_slock) == 0)
3560Sstevel@tonic-gate 			return (EBUSY);
3570Sstevel@tonic-gate 		if (cpr_reusable_mode) {
3580Sstevel@tonic-gate 			cpr_err(CE_CONT, modefmt, "already");
3590Sstevel@tonic-gate 			mutex_exit(&cpr_slock);
3600Sstevel@tonic-gate 			return (EBUSY);
3610Sstevel@tonic-gate 		}
3620Sstevel@tonic-gate 		rc = i_cpr_reuseinit();
3630Sstevel@tonic-gate 		mutex_exit(&cpr_slock);
3640Sstevel@tonic-gate 		return (rc);
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	if (fcn == AD_CPR_REUSEFINI) {
3680Sstevel@tonic-gate 		if (mutex_tryenter(&cpr_slock) == 0)
3690Sstevel@tonic-gate 			return (EBUSY);
3700Sstevel@tonic-gate 		if (!cpr_reusable_mode) {
3710Sstevel@tonic-gate 			cpr_err(CE_CONT, modefmt, "not");
3720Sstevel@tonic-gate 			mutex_exit(&cpr_slock);
3730Sstevel@tonic-gate 			return (EINVAL);
3740Sstevel@tonic-gate 		}
3750Sstevel@tonic-gate 		rc = i_cpr_reusefini();
3760Sstevel@tonic-gate 		mutex_exit(&cpr_slock);
3770Sstevel@tonic-gate 		return (rc);
3780Sstevel@tonic-gate 	}
3795295Srandyf #endif
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	/*
3820Sstevel@tonic-gate 	 * acquire cpr serial lock and init cpr state structure.
3830Sstevel@tonic-gate 	 */
3840Sstevel@tonic-gate 	if (rc = cpr_init(fcn))
3850Sstevel@tonic-gate 		return (rc);
3860Sstevel@tonic-gate 
3875295Srandyf #if defined(__sparc)
3880Sstevel@tonic-gate 	if (fcn == AD_CPR_REUSABLE) {
3890Sstevel@tonic-gate 		if ((rc = i_cpr_check_cprinfo()) != 0)  {
3900Sstevel@tonic-gate 			mutex_exit(&cpr_slock);
3910Sstevel@tonic-gate 			return (rc);
3920Sstevel@tonic-gate 		}
3930Sstevel@tonic-gate 	}
3945295Srandyf #endif
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	/*
3970Sstevel@tonic-gate 	 * Call the main cpr routine. If we are successful, we will be coming
3980Sstevel@tonic-gate 	 * down from the resume side, otherwise we are still in suspend.
3990Sstevel@tonic-gate 	 */
4000Sstevel@tonic-gate 	cpr_err(CE_CONT, "System is being suspended");
4015295Srandyf 	if (rc = cpr_main(cpr_sleeptype)) {
4020Sstevel@tonic-gate 		CPR->c_flags |= C_ERROR;
4035295Srandyf 		PMD(PMD_SX, ("cpr: Suspend operation failed.\n"))
4040Sstevel@tonic-gate 		cpr_err(CE_NOTE, "Suspend operation failed.");
4050Sstevel@tonic-gate 	} else if (CPR->c_flags & C_SUSPENDING) {
4065295Srandyf 
4075295Srandyf 		/*
4085295Srandyf 		 * In the suspend to RAM case, by the time we get
4095295Srandyf 		 * control back we're already resumed
4105295Srandyf 		 */
4115295Srandyf 		if (cpr_sleeptype == CPR_TORAM) {
4125295Srandyf 			PMD(PMD_SX, ("cpr: cpr CPR_TORAM done\n"))
4135295Srandyf 			cpr_done();
4145295Srandyf 			return (rc);
4155295Srandyf 		}
4165295Srandyf 
4175295Srandyf #if defined(__sparc)
4185295Srandyf 
4195295Srandyf 		PMD(PMD_SX, ("cpr: Suspend operation succeeded.\n"))
4200Sstevel@tonic-gate 		/*
4210Sstevel@tonic-gate 		 * Back from a successful checkpoint
4220Sstevel@tonic-gate 		 */
4230Sstevel@tonic-gate 		if (fcn == AD_CPR_TESTZ || fcn == AD_CPR_TESTNOZ) {
424136Sachartre 			mdboot(0, AD_BOOT, "", B_FALSE);
4250Sstevel@tonic-gate 			/* NOTREACHED */
4260Sstevel@tonic-gate 		}
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 		/* make sure there are no more changes to the device tree */
4295295Srandyf 		PMD(PMD_SX, ("cpr: dev tree freeze\n"))
4300Sstevel@tonic-gate 		devtree_freeze();
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 		/*
4330Sstevel@tonic-gate 		 * stop other cpus and raise our priority.  since there is only
4340Sstevel@tonic-gate 		 * one active cpu after this, and our priority will be too high
4350Sstevel@tonic-gate 		 * for us to be preempted, we're essentially single threaded
4360Sstevel@tonic-gate 		 * from here on out.
4370Sstevel@tonic-gate 		 */
4385295Srandyf 		PMD(PMD_SX, ("cpr: stop other cpus\n"))
4395295Srandyf 		i_cpr_stop_other_cpus();
4405295Srandyf 		PMD(PMD_SX, ("cpr: spl6\n"))
4410Sstevel@tonic-gate 		(void) spl6();
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 		/*
4440Sstevel@tonic-gate 		 * try and reset leaf devices.  reset_leaves() should only
4450Sstevel@tonic-gate 		 * be called when there are no other threads that could be
4460Sstevel@tonic-gate 		 * accessing devices
4470Sstevel@tonic-gate 		 */
4485295Srandyf 		PMD(PMD_SX, ("cpr: reset leaves\n"))
4490Sstevel@tonic-gate 		reset_leaves();
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 		/*
4525295Srandyf 		 * If i_cpr_power_down() succeeds, it'll not return
4530Sstevel@tonic-gate 		 *
4540Sstevel@tonic-gate 		 * Drives with write-cache enabled need to flush
4550Sstevel@tonic-gate 		 * their cache.
4560Sstevel@tonic-gate 		 */
4575295Srandyf 		if (fcn != AD_CPR_TESTHALT) {
4585295Srandyf 			PMD(PMD_SX, ("cpr: power down\n"))
4595295Srandyf 			(void) i_cpr_power_down(cpr_sleeptype);
4605295Srandyf 		}
4615295Srandyf 		ASSERT(cpr_sleeptype == CPR_TODISK);
4625295Srandyf 		/* currently CPR_TODISK comes back via a boot path */
4633446Smrj 		CPR_DEBUG(CPR_DEBUG1, "(Done. Please Switch Off)\n");
4640Sstevel@tonic-gate 		halt(NULL);
4650Sstevel@tonic-gate 		/* NOTREACHED */
4665295Srandyf #endif
4670Sstevel@tonic-gate 	}
4685295Srandyf 	PMD(PMD_SX, ("cpr: cpr done\n"))
4690Sstevel@tonic-gate 	cpr_done();
4700Sstevel@tonic-gate 	return (rc);
4710Sstevel@tonic-gate }
472