xref: /onnv-gate/usr/src/uts/common/cpr/cpr_mod.c (revision 6423:437422a29d3a)
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 /*
225817Sjan  * 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 *);
47*6423Sgw25295 extern int cpr_is_zfs(struct vfs *);
480Sstevel@tonic-gate extern int cpr_check_spec_statefile(void);
490Sstevel@tonic-gate extern int cpr_reusable_mount_check(void);
500Sstevel@tonic-gate extern int i_cpr_reusable_supported(void);
510Sstevel@tonic-gate extern int i_cpr_reusefini(void);
525295Srandyf extern struct mod_ops mod_miscops;
530Sstevel@tonic-gate 
545295Srandyf extern int cpr_init(int);
555295Srandyf extern void cpr_done(void);
565295Srandyf extern void i_cpr_stop_other_cpus(void);
575295Srandyf extern int i_cpr_power_down();
585295Srandyf 
595295Srandyf #if defined(__sparc)
605295Srandyf extern void cpr_forget_cprconfig(void);
615295Srandyf #endif
620Sstevel@tonic-gate 
630Sstevel@tonic-gate static struct modlmisc modlmisc = {
640Sstevel@tonic-gate 	&mod_miscops, "checkpoint resume"
650Sstevel@tonic-gate };
660Sstevel@tonic-gate 
670Sstevel@tonic-gate static struct modlinkage modlinkage = {
680Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
690Sstevel@tonic-gate };
700Sstevel@tonic-gate 
710Sstevel@tonic-gate char _depends_on[] = "misc/bootdev";	/* i_devname_to_promname() */
720Sstevel@tonic-gate 
730Sstevel@tonic-gate int cpr_reusable_mode;
740Sstevel@tonic-gate 
750Sstevel@tonic-gate kmutex_t	cpr_slock;	/* cpr serial lock */
760Sstevel@tonic-gate cpr_t		cpr_state;
770Sstevel@tonic-gate int		cpr_debug;
780Sstevel@tonic-gate int		cpr_test_mode; /* true if called via uadmin testmode */
795295Srandyf int		cpr_test_point = LOOP_BACK_NONE;	/* cpr test point */
805295Srandyf int		cpr_mp_enable = 0;	/* set to 1 to enable MP suspend */
815295Srandyf major_t		cpr_device = 0;		/* major number for S3 on one device */
820Sstevel@tonic-gate 
830Sstevel@tonic-gate /*
840Sstevel@tonic-gate  * All the loadable module related code follows
850Sstevel@tonic-gate  */
860Sstevel@tonic-gate int
_init(void)870Sstevel@tonic-gate _init(void)
880Sstevel@tonic-gate {
890Sstevel@tonic-gate 	register int e;
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	if ((e = mod_install(&modlinkage)) == 0) {
920Sstevel@tonic-gate 		mutex_init(&cpr_slock, NULL, MUTEX_DEFAULT, NULL);
930Sstevel@tonic-gate 	}
940Sstevel@tonic-gate 	return (e);
950Sstevel@tonic-gate }
960Sstevel@tonic-gate 
970Sstevel@tonic-gate int
_fini(void)980Sstevel@tonic-gate _fini(void)
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate 	register int e;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	if ((e = mod_remove(&modlinkage)) == 0) {
1030Sstevel@tonic-gate 		mutex_destroy(&cpr_slock);
1040Sstevel@tonic-gate 	}
1050Sstevel@tonic-gate 	return (e);
1060Sstevel@tonic-gate }
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1090Sstevel@tonic-gate _info(struct modinfo *modinfop)
1100Sstevel@tonic-gate {
1110Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1120Sstevel@tonic-gate }
1130Sstevel@tonic-gate 
1145295Srandyf static
1150Sstevel@tonic-gate int
atoi(char * p)1165295Srandyf atoi(char *p)
1170Sstevel@tonic-gate {
1185295Srandyf 	int	i;
1195295Srandyf 
1205295Srandyf 	i = (*p++ - '0');
1215295Srandyf 
1225295Srandyf 	while (*p != '\0')
1235295Srandyf 		i = 10 * i + (*p++ - '0');
1245295Srandyf 
1255295Srandyf 	return (i);
1265295Srandyf }
1275295Srandyf 
1285295Srandyf int
cpr(int fcn,void * mdep)1295295Srandyf cpr(int fcn, void *mdep)
1305295Srandyf {
1315295Srandyf 
1325295Srandyf #if defined(__sparc)
1330Sstevel@tonic-gate 	static const char noswapstr[] = "reusable statefile requires "
1340Sstevel@tonic-gate 	    "that no swap area be configured.\n";
1350Sstevel@tonic-gate 	static const char blockstr[] = "reusable statefile must be "
1360Sstevel@tonic-gate 	    "a block device.  See power.conf(4) and pmconfig(1M).\n";
1370Sstevel@tonic-gate 	static const char normalfmt[] = "cannot run normal "
1380Sstevel@tonic-gate 	    "checkpoint/resume when in reusable statefile mode. "
1390Sstevel@tonic-gate 	    "use uadmin A_FREEZE AD_REUSEFINI (uadmin %d %d) "
1400Sstevel@tonic-gate 	    "to exit reusable statefile mode.\n";
1410Sstevel@tonic-gate 	static const char modefmt[] = "%s in reusable mode.\n";
1425295Srandyf #endif
1430Sstevel@tonic-gate 	register int rc = 0;
1445295Srandyf 	int cpr_sleeptype;
1455295Srandyf 
1465295Srandyf 	/*
1475295Srandyf 	 * First, reject commands that we don't (yet) support on this arch.
1485295Srandyf 	 * This is easier to understand broken out like this than grotting
1495295Srandyf 	 * through the second switch below.
1505295Srandyf 	 */
1510Sstevel@tonic-gate 
1525295Srandyf 	switch (fcn) {
1535295Srandyf #if defined(__sparc)
1545295Srandyf 	case AD_CHECK_SUSPEND_TO_RAM:
1555295Srandyf 	case AD_SUSPEND_TO_RAM:
1565295Srandyf 		return (ENOTSUP);
1575295Srandyf 	case AD_CHECK_SUSPEND_TO_DISK:
1585295Srandyf 	case AD_SUSPEND_TO_DISK:
1595295Srandyf 	case AD_CPR_REUSEINIT:
1605295Srandyf 	case AD_CPR_NOCOMPRESS:
1615295Srandyf 	case AD_CPR_FORCE:
1625295Srandyf 	case AD_CPR_REUSABLE:
1635295Srandyf 	case AD_CPR_REUSEFINI:
1645295Srandyf 	case AD_CPR_TESTZ:
1655295Srandyf 	case AD_CPR_TESTNOZ:
1665295Srandyf 	case AD_CPR_TESTHALT:
1675295Srandyf 	case AD_CPR_SUSP_DEVICES:
1685295Srandyf 		cpr_sleeptype = CPR_TODISK;
1695295Srandyf 		break;
1705295Srandyf #endif
1715295Srandyf #if defined(__x86)
1725295Srandyf 	case AD_CHECK_SUSPEND_TO_DISK:
1735295Srandyf 	case AD_SUSPEND_TO_DISK:
1745295Srandyf 	case AD_CPR_REUSEINIT:
1755295Srandyf 	case AD_CPR_NOCOMPRESS:
1765295Srandyf 	case AD_CPR_FORCE:
1775295Srandyf 	case AD_CPR_REUSABLE:
1785295Srandyf 	case AD_CPR_REUSEFINI:
1795295Srandyf 	case AD_CPR_TESTZ:
1805295Srandyf 	case AD_CPR_TESTNOZ:
1815295Srandyf 	case AD_CPR_TESTHALT:
1825295Srandyf 	case AD_CPR_PRINT:
1835295Srandyf 		return (ENOTSUP);
1845295Srandyf 	/* The DEV_* values need to be removed after sys-syspend is fixed */
1855295Srandyf 	case DEV_CHECK_SUSPEND_TO_RAM:
1865295Srandyf 	case DEV_SUSPEND_TO_RAM:
1875295Srandyf 	case AD_CPR_SUSP_DEVICES:
1885295Srandyf 	case AD_CHECK_SUSPEND_TO_RAM:
1895295Srandyf 	case AD_SUSPEND_TO_RAM:
1905295Srandyf 	case AD_LOOPBACK_SUSPEND_TO_RAM_PASS:
1915295Srandyf 	case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL:
1925295Srandyf 	case AD_FORCE_SUSPEND_TO_RAM:
1935295Srandyf 	case AD_DEVICE_SUSPEND_TO_RAM:
1945817Sjan 		cpr_sleeptype = CPR_TORAM;
1955295Srandyf 		break;
1965295Srandyf #endif
1975295Srandyf 	}
1985295Srandyf #if defined(__sparc)
1990Sstevel@tonic-gate 	/*
2000Sstevel@tonic-gate 	 * Need to know if we're in reusable mode, but we will likely have
2010Sstevel@tonic-gate 	 * rebooted since REUSEINIT, so we have to get the info from the
2020Sstevel@tonic-gate 	 * file system
2030Sstevel@tonic-gate 	 */
2040Sstevel@tonic-gate 	if (!cpr_reusable_mode)
2050Sstevel@tonic-gate 		cpr_reusable_mode = cpr_get_reusable_mode();
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	cpr_forget_cprconfig();
2085295Srandyf #endif
2095295Srandyf 
2100Sstevel@tonic-gate 	switch (fcn) {
2110Sstevel@tonic-gate 
2125295Srandyf #if defined(__sparc)
2130Sstevel@tonic-gate 	case AD_CPR_REUSEINIT:
2140Sstevel@tonic-gate 		if (!i_cpr_reusable_supported())
2150Sstevel@tonic-gate 			return (ENOTSUP);
2160Sstevel@tonic-gate 		if (!cpr_statefile_is_spec()) {
2170Sstevel@tonic-gate 			cpr_err(CE_CONT, blockstr);
2180Sstevel@tonic-gate 			return (EINVAL);
2190Sstevel@tonic-gate 		}
2200Sstevel@tonic-gate 		if ((rc = cpr_check_spec_statefile()) != 0)
2210Sstevel@tonic-gate 			return (rc);
2220Sstevel@tonic-gate 		if (swapinfo) {
2230Sstevel@tonic-gate 			cpr_err(CE_CONT, noswapstr);
2240Sstevel@tonic-gate 			return (EINVAL);
2250Sstevel@tonic-gate 		}
2260Sstevel@tonic-gate 		cpr_test_mode = 0;
2270Sstevel@tonic-gate 		break;
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	case AD_CPR_NOCOMPRESS:
2300Sstevel@tonic-gate 	case AD_CPR_COMPRESS:
2310Sstevel@tonic-gate 	case AD_CPR_FORCE:
2320Sstevel@tonic-gate 		if (cpr_reusable_mode) {
2330Sstevel@tonic-gate 			cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI);
2340Sstevel@tonic-gate 			return (ENOTSUP);
2350Sstevel@tonic-gate 		}
2360Sstevel@tonic-gate 		cpr_test_mode = 0;
2370Sstevel@tonic-gate 		break;
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	case AD_CPR_REUSABLE:
2400Sstevel@tonic-gate 		if (!i_cpr_reusable_supported())
2410Sstevel@tonic-gate 			return (ENOTSUP);
2420Sstevel@tonic-gate 		if (!cpr_statefile_is_spec()) {
2430Sstevel@tonic-gate 			cpr_err(CE_CONT, blockstr);
2440Sstevel@tonic-gate 			return (EINVAL);
2450Sstevel@tonic-gate 		}
2460Sstevel@tonic-gate 		if ((rc = cpr_check_spec_statefile()) != 0)
2470Sstevel@tonic-gate 			return (rc);
2480Sstevel@tonic-gate 		if (swapinfo) {
2490Sstevel@tonic-gate 			cpr_err(CE_CONT, noswapstr);
2500Sstevel@tonic-gate 			return (EINVAL);
2510Sstevel@tonic-gate 		}
2520Sstevel@tonic-gate 		if ((rc = cpr_reusable_mount_check()) != 0)
2530Sstevel@tonic-gate 			return (rc);
2540Sstevel@tonic-gate 		cpr_test_mode = 0;
2550Sstevel@tonic-gate 		break;
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	case AD_CPR_REUSEFINI:
2580Sstevel@tonic-gate 		if (!i_cpr_reusable_supported())
2590Sstevel@tonic-gate 			return (ENOTSUP);
2600Sstevel@tonic-gate 		cpr_test_mode = 0;
2610Sstevel@tonic-gate 		break;
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	case AD_CPR_TESTZ:
2640Sstevel@tonic-gate 	case AD_CPR_TESTNOZ:
2650Sstevel@tonic-gate 	case AD_CPR_TESTHALT:
2660Sstevel@tonic-gate 		if (cpr_reusable_mode) {
2670Sstevel@tonic-gate 			cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI);
2680Sstevel@tonic-gate 			return (ENOTSUP);
2690Sstevel@tonic-gate 		}
2700Sstevel@tonic-gate 		cpr_test_mode = 1;
2710Sstevel@tonic-gate 		break;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	case AD_CPR_CHECK:
2745295Srandyf 		if (!i_cpr_is_supported(cpr_sleeptype) || cpr_reusable_mode)
2750Sstevel@tonic-gate 			return (ENOTSUP);
2760Sstevel@tonic-gate 		return (0);
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	case AD_CPR_PRINT:
2790Sstevel@tonic-gate 		CPR_STAT_EVENT_END("POST CPR DELAY");
2800Sstevel@tonic-gate 		cpr_stat_event_print();
2810Sstevel@tonic-gate 		return (0);
2825295Srandyf #endif
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	case AD_CPR_DEBUG0:
2850Sstevel@tonic-gate 		cpr_debug = 0;
2860Sstevel@tonic-gate 		return (0);
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	case AD_CPR_DEBUG1:
2890Sstevel@tonic-gate 	case AD_CPR_DEBUG2:
2900Sstevel@tonic-gate 	case AD_CPR_DEBUG3:
2910Sstevel@tonic-gate 	case AD_CPR_DEBUG4:
2920Sstevel@tonic-gate 	case AD_CPR_DEBUG5:
2930Sstevel@tonic-gate 	case AD_CPR_DEBUG7:
2940Sstevel@tonic-gate 	case AD_CPR_DEBUG8:
2950Sstevel@tonic-gate 		cpr_debug |= CPR_DEBUG_BIT(fcn);
2960Sstevel@tonic-gate 		return (0);
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	case AD_CPR_DEBUG9:
2993446Smrj 		cpr_debug |= CPR_DEBUG6;
3000Sstevel@tonic-gate 		return (0);
3010Sstevel@tonic-gate 
3025295Srandyf 	/* The DEV_* values need to be removed after sys-syspend is fixed */
3035295Srandyf 	case DEV_CHECK_SUSPEND_TO_RAM:
3045295Srandyf 	case DEV_SUSPEND_TO_RAM:
3055295Srandyf 	case AD_CHECK_SUSPEND_TO_RAM:
3065295Srandyf 	case AD_SUSPEND_TO_RAM:
3075295Srandyf 		cpr_test_point = LOOP_BACK_NONE;
3085295Srandyf 		break;
3095295Srandyf 
3105295Srandyf 	case AD_LOOPBACK_SUSPEND_TO_RAM_PASS:
3115295Srandyf 		cpr_test_point = LOOP_BACK_PASS;
3125295Srandyf 		break;
3135295Srandyf 
3145295Srandyf 	case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL:
3155295Srandyf 		cpr_test_point = LOOP_BACK_FAIL;
3165295Srandyf 		break;
3175295Srandyf 
3185295Srandyf 	case AD_FORCE_SUSPEND_TO_RAM:
3195295Srandyf 		cpr_test_point = FORCE_SUSPEND_TO_RAM;
3205295Srandyf 		break;
3215295Srandyf 
3225295Srandyf 	case AD_DEVICE_SUSPEND_TO_RAM:
3235732Srandyf 		if (mdep == NULL) {
3245732Srandyf 			/* Didn't pass enough arguments */
3255732Srandyf 			return (EINVAL);
3265732Srandyf 		}
3275295Srandyf 		cpr_test_point = DEVICE_SUSPEND_TO_RAM;
3285295Srandyf 		cpr_device = (major_t)atoi((char *)mdep);
3295295Srandyf 		break;
3305295Srandyf 
3315295Srandyf 	case AD_CPR_SUSP_DEVICES:
3325295Srandyf 		cpr_test_point = FORCE_SUSPEND_TO_RAM;
3335295Srandyf 		if (cpr_suspend_devices(ddi_root_node()) != DDI_SUCCESS)
3345295Srandyf 			cmn_err(CE_WARN,
3355295Srandyf 			    "Some devices did not suspend "
3365295Srandyf 			    "and may be unusable");
3375295Srandyf 		(void) cpr_resume_devices(ddi_root_node(), 0);
3385295Srandyf 		return (0);
3395295Srandyf 
3400Sstevel@tonic-gate 	default:
3410Sstevel@tonic-gate 		return (ENOTSUP);
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate 
3445295Srandyf 	if (!i_cpr_is_supported(cpr_sleeptype) ||
345*6423Sgw25295 	    (cpr_sleeptype == CPR_TODISK &&
346*6423Sgw25295 	    !cpr_is_ufs(rootvfs)&& !cpr_is_zfs(rootvfs)))
3470Sstevel@tonic-gate 		return (ENOTSUP);
3480Sstevel@tonic-gate 
3495295Srandyf 	if (fcn == AD_CHECK_SUSPEND_TO_RAM ||
3505295Srandyf 	    fcn == DEV_CHECK_SUSPEND_TO_RAM) {
3515295Srandyf 		ASSERT(i_cpr_is_supported(cpr_sleeptype));
3525295Srandyf 		return (0);
3535295Srandyf 	}
3545295Srandyf 
3555295Srandyf #if defined(__sparc)
3560Sstevel@tonic-gate 	if (fcn == AD_CPR_REUSEINIT) {
3570Sstevel@tonic-gate 		if (mutex_tryenter(&cpr_slock) == 0)
3580Sstevel@tonic-gate 			return (EBUSY);
3590Sstevel@tonic-gate 		if (cpr_reusable_mode) {
3600Sstevel@tonic-gate 			cpr_err(CE_CONT, modefmt, "already");
3610Sstevel@tonic-gate 			mutex_exit(&cpr_slock);
3620Sstevel@tonic-gate 			return (EBUSY);
3630Sstevel@tonic-gate 		}
3640Sstevel@tonic-gate 		rc = i_cpr_reuseinit();
3650Sstevel@tonic-gate 		mutex_exit(&cpr_slock);
3660Sstevel@tonic-gate 		return (rc);
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	if (fcn == AD_CPR_REUSEFINI) {
3700Sstevel@tonic-gate 		if (mutex_tryenter(&cpr_slock) == 0)
3710Sstevel@tonic-gate 			return (EBUSY);
3720Sstevel@tonic-gate 		if (!cpr_reusable_mode) {
3730Sstevel@tonic-gate 			cpr_err(CE_CONT, modefmt, "not");
3740Sstevel@tonic-gate 			mutex_exit(&cpr_slock);
3750Sstevel@tonic-gate 			return (EINVAL);
3760Sstevel@tonic-gate 		}
3770Sstevel@tonic-gate 		rc = i_cpr_reusefini();
3780Sstevel@tonic-gate 		mutex_exit(&cpr_slock);
3790Sstevel@tonic-gate 		return (rc);
3800Sstevel@tonic-gate 	}
3815295Srandyf #endif
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	/*
3840Sstevel@tonic-gate 	 * acquire cpr serial lock and init cpr state structure.
3850Sstevel@tonic-gate 	 */
3860Sstevel@tonic-gate 	if (rc = cpr_init(fcn))
3870Sstevel@tonic-gate 		return (rc);
3880Sstevel@tonic-gate 
3895295Srandyf #if defined(__sparc)
3900Sstevel@tonic-gate 	if (fcn == AD_CPR_REUSABLE) {
3910Sstevel@tonic-gate 		if ((rc = i_cpr_check_cprinfo()) != 0)  {
3920Sstevel@tonic-gate 			mutex_exit(&cpr_slock);
3930Sstevel@tonic-gate 			return (rc);
3940Sstevel@tonic-gate 		}
3950Sstevel@tonic-gate 	}
3965295Srandyf #endif
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	/*
3990Sstevel@tonic-gate 	 * Call the main cpr routine. If we are successful, we will be coming
4000Sstevel@tonic-gate 	 * down from the resume side, otherwise we are still in suspend.
4010Sstevel@tonic-gate 	 */
4020Sstevel@tonic-gate 	cpr_err(CE_CONT, "System is being suspended");
4035295Srandyf 	if (rc = cpr_main(cpr_sleeptype)) {
4040Sstevel@tonic-gate 		CPR->c_flags |= C_ERROR;
4055295Srandyf 		PMD(PMD_SX, ("cpr: Suspend operation failed.\n"))
4060Sstevel@tonic-gate 		cpr_err(CE_NOTE, "Suspend operation failed.");
4070Sstevel@tonic-gate 	} else if (CPR->c_flags & C_SUSPENDING) {
4085295Srandyf 
4095295Srandyf 		/*
4105295Srandyf 		 * In the suspend to RAM case, by the time we get
4115295Srandyf 		 * control back we're already resumed
4125295Srandyf 		 */
4135295Srandyf 		if (cpr_sleeptype == CPR_TORAM) {
4145295Srandyf 			PMD(PMD_SX, ("cpr: cpr CPR_TORAM done\n"))
4155295Srandyf 			cpr_done();
4165295Srandyf 			return (rc);
4175295Srandyf 		}
4185295Srandyf 
4195295Srandyf #if defined(__sparc)
4205295Srandyf 
4215295Srandyf 		PMD(PMD_SX, ("cpr: Suspend operation succeeded.\n"))
4220Sstevel@tonic-gate 		/*
4230Sstevel@tonic-gate 		 * Back from a successful checkpoint
4240Sstevel@tonic-gate 		 */
4250Sstevel@tonic-gate 		if (fcn == AD_CPR_TESTZ || fcn == AD_CPR_TESTNOZ) {
426136Sachartre 			mdboot(0, AD_BOOT, "", B_FALSE);
4270Sstevel@tonic-gate 			/* NOTREACHED */
4280Sstevel@tonic-gate 		}
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 		/* make sure there are no more changes to the device tree */
4315295Srandyf 		PMD(PMD_SX, ("cpr: dev tree freeze\n"))
4320Sstevel@tonic-gate 		devtree_freeze();
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 		/*
4350Sstevel@tonic-gate 		 * stop other cpus and raise our priority.  since there is only
4360Sstevel@tonic-gate 		 * one active cpu after this, and our priority will be too high
4370Sstevel@tonic-gate 		 * for us to be preempted, we're essentially single threaded
4380Sstevel@tonic-gate 		 * from here on out.
4390Sstevel@tonic-gate 		 */
4405295Srandyf 		PMD(PMD_SX, ("cpr: stop other cpus\n"))
4415295Srandyf 		i_cpr_stop_other_cpus();
4425295Srandyf 		PMD(PMD_SX, ("cpr: spl6\n"))
4430Sstevel@tonic-gate 		(void) spl6();
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 		/*
4460Sstevel@tonic-gate 		 * try and reset leaf devices.  reset_leaves() should only
4470Sstevel@tonic-gate 		 * be called when there are no other threads that could be
4480Sstevel@tonic-gate 		 * accessing devices
4490Sstevel@tonic-gate 		 */
4505295Srandyf 		PMD(PMD_SX, ("cpr: reset leaves\n"))
4510Sstevel@tonic-gate 		reset_leaves();
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 		/*
4545295Srandyf 		 * If i_cpr_power_down() succeeds, it'll not return
4550Sstevel@tonic-gate 		 *
4560Sstevel@tonic-gate 		 * Drives with write-cache enabled need to flush
4570Sstevel@tonic-gate 		 * their cache.
4580Sstevel@tonic-gate 		 */
4595295Srandyf 		if (fcn != AD_CPR_TESTHALT) {
4605295Srandyf 			PMD(PMD_SX, ("cpr: power down\n"))
4615295Srandyf 			(void) i_cpr_power_down(cpr_sleeptype);
4625295Srandyf 		}
4635295Srandyf 		ASSERT(cpr_sleeptype == CPR_TODISK);
4645295Srandyf 		/* currently CPR_TODISK comes back via a boot path */
4653446Smrj 		CPR_DEBUG(CPR_DEBUG1, "(Done. Please Switch Off)\n");
4660Sstevel@tonic-gate 		halt(NULL);
4670Sstevel@tonic-gate 		/* NOTREACHED */
4685295Srandyf #endif
4690Sstevel@tonic-gate 	}
4705295Srandyf 	PMD(PMD_SX, ("cpr: cpr done\n"))
4710Sstevel@tonic-gate 	cpr_done();
4720Sstevel@tonic-gate 	return (rc);
4730Sstevel@tonic-gate }
474