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