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