17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ae115bc7Smrj * Common Development and Distribution License (the "License"). 6ae115bc7Smrj * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22ae115bc7Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * System call to checkpoint and resume the currently running kernel 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate #include <sys/types.h> 327c478bd9Sstevel@tonic-gate #include <sys/errno.h> 337c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 347c478bd9Sstevel@tonic-gate #include <sys/syscall.h> 357c478bd9Sstevel@tonic-gate #include <sys/cred.h> 367c478bd9Sstevel@tonic-gate #include <sys/uadmin.h> 377c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 387c478bd9Sstevel@tonic-gate #include <sys/systm.h> 397c478bd9Sstevel@tonic-gate #include <sys/cpr.h> 407c478bd9Sstevel@tonic-gate #include <sys/swap.h> 417c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 427c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 437c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 447c478bd9Sstevel@tonic-gate 452df1fe9cSrandyf extern int i_cpr_is_supported(int sleeptype); 467c478bd9Sstevel@tonic-gate extern int cpr_is_ufs(struct vfs *); 477c478bd9Sstevel@tonic-gate extern int cpr_check_spec_statefile(void); 487c478bd9Sstevel@tonic-gate extern int cpr_reusable_mount_check(void); 497c478bd9Sstevel@tonic-gate extern int i_cpr_reusable_supported(void); 507c478bd9Sstevel@tonic-gate extern int i_cpr_reusefini(void); 517c478bd9Sstevel@tonic-gate extern struct mod_ops mod_miscops; 527c478bd9Sstevel@tonic-gate 532df1fe9cSrandyf extern int cpr_init(int); 542df1fe9cSrandyf extern void cpr_done(void); 552df1fe9cSrandyf extern void i_cpr_stop_other_cpus(void); 562df1fe9cSrandyf extern int i_cpr_power_down(); 572df1fe9cSrandyf 582df1fe9cSrandyf #if defined(__sparc) 592df1fe9cSrandyf extern void cpr_forget_cprconfig(void); 602df1fe9cSrandyf #endif 612df1fe9cSrandyf 627c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = { 637c478bd9Sstevel@tonic-gate &mod_miscops, "checkpoint resume" 647c478bd9Sstevel@tonic-gate }; 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 677c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modlmisc, NULL 687c478bd9Sstevel@tonic-gate }; 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate char _depends_on[] = "misc/bootdev"; /* i_devname_to_promname() */ 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate int cpr_reusable_mode; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate kmutex_t cpr_slock; /* cpr serial lock */ 757c478bd9Sstevel@tonic-gate cpr_t cpr_state; 767c478bd9Sstevel@tonic-gate int cpr_debug; 777c478bd9Sstevel@tonic-gate int cpr_test_mode; /* true if called via uadmin testmode */ 782df1fe9cSrandyf int cpr_test_point = LOOP_BACK_NONE; /* cpr test point */ 792df1fe9cSrandyf int cpr_mp_enable = 0; /* set to 1 to enable MP suspend */ 802df1fe9cSrandyf major_t cpr_device = 0; /* major number for S3 on one device */ 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /* 837c478bd9Sstevel@tonic-gate * All the loadable module related code follows 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate int 867c478bd9Sstevel@tonic-gate _init(void) 877c478bd9Sstevel@tonic-gate { 887c478bd9Sstevel@tonic-gate register int e; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) == 0) { 917c478bd9Sstevel@tonic-gate mutex_init(&cpr_slock, NULL, MUTEX_DEFAULT, NULL); 927c478bd9Sstevel@tonic-gate } 937c478bd9Sstevel@tonic-gate return (e); 947c478bd9Sstevel@tonic-gate } 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate int 977c478bd9Sstevel@tonic-gate _fini(void) 987c478bd9Sstevel@tonic-gate { 997c478bd9Sstevel@tonic-gate register int e; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate if ((e = mod_remove(&modlinkage)) == 0) { 1027c478bd9Sstevel@tonic-gate mutex_destroy(&cpr_slock); 1037c478bd9Sstevel@tonic-gate } 1047c478bd9Sstevel@tonic-gate return (e); 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate int 1087c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1097c478bd9Sstevel@tonic-gate { 1107c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate 1132df1fe9cSrandyf static 1142df1fe9cSrandyf int 1152df1fe9cSrandyf atoi(char *p) 1162df1fe9cSrandyf { 1172df1fe9cSrandyf int i; 1182df1fe9cSrandyf 1192df1fe9cSrandyf i = (*p++ - '0'); 1202df1fe9cSrandyf 1212df1fe9cSrandyf while (*p != '\0') 1222df1fe9cSrandyf i = 10 * i + (*p++ - '0'); 1232df1fe9cSrandyf 1242df1fe9cSrandyf return (i); 1252df1fe9cSrandyf } 1262df1fe9cSrandyf 1277c478bd9Sstevel@tonic-gate int 1282df1fe9cSrandyf cpr(int fcn, void *mdep) 1297c478bd9Sstevel@tonic-gate { 1302df1fe9cSrandyf 1312df1fe9cSrandyf #if defined(__sparc) 1327c478bd9Sstevel@tonic-gate static const char noswapstr[] = "reusable statefile requires " 1337c478bd9Sstevel@tonic-gate "that no swap area be configured.\n"; 1347c478bd9Sstevel@tonic-gate static const char blockstr[] = "reusable statefile must be " 1357c478bd9Sstevel@tonic-gate "a block device. See power.conf(4) and pmconfig(1M).\n"; 1367c478bd9Sstevel@tonic-gate static const char normalfmt[] = "cannot run normal " 1377c478bd9Sstevel@tonic-gate "checkpoint/resume when in reusable statefile mode. " 1387c478bd9Sstevel@tonic-gate "use uadmin A_FREEZE AD_REUSEFINI (uadmin %d %d) " 1397c478bd9Sstevel@tonic-gate "to exit reusable statefile mode.\n"; 1407c478bd9Sstevel@tonic-gate static const char modefmt[] = "%s in reusable mode.\n"; 1412df1fe9cSrandyf #endif 1427c478bd9Sstevel@tonic-gate register int rc = 0; 1432df1fe9cSrandyf int cpr_sleeptype; 1447c478bd9Sstevel@tonic-gate 1452df1fe9cSrandyf /* 1462df1fe9cSrandyf * First, reject commands that we don't (yet) support on this arch. 1472df1fe9cSrandyf * This is easier to understand broken out like this than grotting 1482df1fe9cSrandyf * through the second switch below. 1492df1fe9cSrandyf */ 1502df1fe9cSrandyf 1512df1fe9cSrandyf switch (fcn) { 1522df1fe9cSrandyf #if defined(__sparc) 1532df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_RAM: 1542df1fe9cSrandyf case AD_SUSPEND_TO_RAM: 1552df1fe9cSrandyf return (ENOTSUP); 1562df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_DISK: 1572df1fe9cSrandyf case AD_SUSPEND_TO_DISK: 1582df1fe9cSrandyf case AD_CPR_REUSEINIT: 1592df1fe9cSrandyf case AD_CPR_NOCOMPRESS: 1602df1fe9cSrandyf case AD_CPR_FORCE: 1612df1fe9cSrandyf case AD_CPR_REUSABLE: 1622df1fe9cSrandyf case AD_CPR_REUSEFINI: 1632df1fe9cSrandyf case AD_CPR_TESTZ: 1642df1fe9cSrandyf case AD_CPR_TESTNOZ: 1652df1fe9cSrandyf case AD_CPR_TESTHALT: 1662df1fe9cSrandyf case AD_CPR_SUSP_DEVICES: 1672df1fe9cSrandyf cpr_sleeptype = CPR_TODISK; 1682df1fe9cSrandyf break; 1692df1fe9cSrandyf #endif 1702df1fe9cSrandyf #if defined(__x86) 1712df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_DISK: 1722df1fe9cSrandyf case AD_SUSPEND_TO_DISK: 1732df1fe9cSrandyf case AD_CPR_REUSEINIT: 1742df1fe9cSrandyf case AD_CPR_NOCOMPRESS: 1752df1fe9cSrandyf case AD_CPR_FORCE: 1762df1fe9cSrandyf case AD_CPR_REUSABLE: 1772df1fe9cSrandyf case AD_CPR_REUSEFINI: 1782df1fe9cSrandyf case AD_CPR_TESTZ: 1792df1fe9cSrandyf case AD_CPR_TESTNOZ: 1802df1fe9cSrandyf case AD_CPR_TESTHALT: 1812df1fe9cSrandyf case AD_CPR_PRINT: 1822df1fe9cSrandyf return (ENOTSUP); 1832df1fe9cSrandyf /* The DEV_* values need to be removed after sys-syspend is fixed */ 1842df1fe9cSrandyf case DEV_CHECK_SUSPEND_TO_RAM: 1852df1fe9cSrandyf case DEV_SUSPEND_TO_RAM: 1862df1fe9cSrandyf case AD_CPR_SUSP_DEVICES: 1872df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_RAM: 1882df1fe9cSrandyf case AD_SUSPEND_TO_RAM: 1892df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_PASS: 1902df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL: 1912df1fe9cSrandyf case AD_FORCE_SUSPEND_TO_RAM: 1922df1fe9cSrandyf case AD_DEVICE_SUSPEND_TO_RAM: 1932df1fe9cSrandyf /* 1942df1fe9cSrandyf * if MP then do not support suspend to RAM, however override 1952df1fe9cSrandyf * the MP restriction if cpr_mp_enable has been set 1962df1fe9cSrandyf */ 1972df1fe9cSrandyf if (ncpus > 1 && cpr_mp_enable == 0) 1982df1fe9cSrandyf return (ENOTSUP); 1992df1fe9cSrandyf else 2002df1fe9cSrandyf cpr_sleeptype = CPR_TORAM; 2012df1fe9cSrandyf break; 2022df1fe9cSrandyf #endif 2032df1fe9cSrandyf } 2042df1fe9cSrandyf #if defined(__sparc) 2057c478bd9Sstevel@tonic-gate /* 2067c478bd9Sstevel@tonic-gate * Need to know if we're in reusable mode, but we will likely have 2077c478bd9Sstevel@tonic-gate * rebooted since REUSEINIT, so we have to get the info from the 2087c478bd9Sstevel@tonic-gate * file system 2097c478bd9Sstevel@tonic-gate */ 2107c478bd9Sstevel@tonic-gate if (!cpr_reusable_mode) 2117c478bd9Sstevel@tonic-gate cpr_reusable_mode = cpr_get_reusable_mode(); 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate cpr_forget_cprconfig(); 2142df1fe9cSrandyf #endif 2152df1fe9cSrandyf 2167c478bd9Sstevel@tonic-gate switch (fcn) { 2177c478bd9Sstevel@tonic-gate 2182df1fe9cSrandyf #if defined(__sparc) 2197c478bd9Sstevel@tonic-gate case AD_CPR_REUSEINIT: 2207c478bd9Sstevel@tonic-gate if (!i_cpr_reusable_supported()) 2217c478bd9Sstevel@tonic-gate return (ENOTSUP); 2227c478bd9Sstevel@tonic-gate if (!cpr_statefile_is_spec()) { 2237c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, blockstr); 2247c478bd9Sstevel@tonic-gate return (EINVAL); 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate if ((rc = cpr_check_spec_statefile()) != 0) 2277c478bd9Sstevel@tonic-gate return (rc); 2287c478bd9Sstevel@tonic-gate if (swapinfo) { 2297c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, noswapstr); 2307c478bd9Sstevel@tonic-gate return (EINVAL); 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate cpr_test_mode = 0; 2337c478bd9Sstevel@tonic-gate break; 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate case AD_CPR_NOCOMPRESS: 2367c478bd9Sstevel@tonic-gate case AD_CPR_COMPRESS: 2377c478bd9Sstevel@tonic-gate case AD_CPR_FORCE: 2387c478bd9Sstevel@tonic-gate if (cpr_reusable_mode) { 2397c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI); 2407c478bd9Sstevel@tonic-gate return (ENOTSUP); 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate cpr_test_mode = 0; 2437c478bd9Sstevel@tonic-gate break; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate case AD_CPR_REUSABLE: 2467c478bd9Sstevel@tonic-gate if (!i_cpr_reusable_supported()) 2477c478bd9Sstevel@tonic-gate return (ENOTSUP); 2487c478bd9Sstevel@tonic-gate if (!cpr_statefile_is_spec()) { 2497c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, blockstr); 2507c478bd9Sstevel@tonic-gate return (EINVAL); 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate if ((rc = cpr_check_spec_statefile()) != 0) 2537c478bd9Sstevel@tonic-gate return (rc); 2547c478bd9Sstevel@tonic-gate if (swapinfo) { 2557c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, noswapstr); 2567c478bd9Sstevel@tonic-gate return (EINVAL); 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate if ((rc = cpr_reusable_mount_check()) != 0) 2597c478bd9Sstevel@tonic-gate return (rc); 2607c478bd9Sstevel@tonic-gate cpr_test_mode = 0; 2617c478bd9Sstevel@tonic-gate break; 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate case AD_CPR_REUSEFINI: 2647c478bd9Sstevel@tonic-gate if (!i_cpr_reusable_supported()) 2657c478bd9Sstevel@tonic-gate return (ENOTSUP); 2667c478bd9Sstevel@tonic-gate cpr_test_mode = 0; 2677c478bd9Sstevel@tonic-gate break; 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate case AD_CPR_TESTZ: 2707c478bd9Sstevel@tonic-gate case AD_CPR_TESTNOZ: 2717c478bd9Sstevel@tonic-gate case AD_CPR_TESTHALT: 2727c478bd9Sstevel@tonic-gate if (cpr_reusable_mode) { 2737c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI); 2747c478bd9Sstevel@tonic-gate return (ENOTSUP); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate cpr_test_mode = 1; 2777c478bd9Sstevel@tonic-gate break; 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate case AD_CPR_CHECK: 2802df1fe9cSrandyf if (!i_cpr_is_supported(cpr_sleeptype) || cpr_reusable_mode) 2817c478bd9Sstevel@tonic-gate return (ENOTSUP); 2827c478bd9Sstevel@tonic-gate return (0); 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate case AD_CPR_PRINT: 2857c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END("POST CPR DELAY"); 2867c478bd9Sstevel@tonic-gate cpr_stat_event_print(); 2877c478bd9Sstevel@tonic-gate return (0); 2882df1fe9cSrandyf #endif 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG0: 2917c478bd9Sstevel@tonic-gate cpr_debug = 0; 2927c478bd9Sstevel@tonic-gate return (0); 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG1: 2957c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG2: 2967c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG3: 2977c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG4: 2987c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG5: 2997c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG7: 3007c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG8: 3017c478bd9Sstevel@tonic-gate cpr_debug |= CPR_DEBUG_BIT(fcn); 3027c478bd9Sstevel@tonic-gate return (0); 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG9: 305ae115bc7Smrj cpr_debug |= CPR_DEBUG6; 3067c478bd9Sstevel@tonic-gate return (0); 3077c478bd9Sstevel@tonic-gate 3082df1fe9cSrandyf /* The DEV_* values need to be removed after sys-syspend is fixed */ 3092df1fe9cSrandyf case DEV_CHECK_SUSPEND_TO_RAM: 3102df1fe9cSrandyf case DEV_SUSPEND_TO_RAM: 3112df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_RAM: 3122df1fe9cSrandyf case AD_SUSPEND_TO_RAM: 3132df1fe9cSrandyf cpr_test_point = LOOP_BACK_NONE; 3142df1fe9cSrandyf break; 3152df1fe9cSrandyf 3162df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_PASS: 3172df1fe9cSrandyf cpr_test_point = LOOP_BACK_PASS; 3182df1fe9cSrandyf break; 3192df1fe9cSrandyf 3202df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL: 3212df1fe9cSrandyf cpr_test_point = LOOP_BACK_FAIL; 3222df1fe9cSrandyf break; 3232df1fe9cSrandyf 3242df1fe9cSrandyf case AD_FORCE_SUSPEND_TO_RAM: 3252df1fe9cSrandyf cpr_test_point = FORCE_SUSPEND_TO_RAM; 3262df1fe9cSrandyf break; 3272df1fe9cSrandyf 3282df1fe9cSrandyf case AD_DEVICE_SUSPEND_TO_RAM: 329*c36fc336Srandyf if (mdep == NULL) { 330*c36fc336Srandyf /* Didn't pass enough arguments */ 331*c36fc336Srandyf return (EINVAL); 332*c36fc336Srandyf } 3332df1fe9cSrandyf cpr_test_point = DEVICE_SUSPEND_TO_RAM; 3342df1fe9cSrandyf cpr_device = (major_t)atoi((char *)mdep); 3352df1fe9cSrandyf break; 3362df1fe9cSrandyf 3372df1fe9cSrandyf case AD_CPR_SUSP_DEVICES: 3382df1fe9cSrandyf cpr_test_point = FORCE_SUSPEND_TO_RAM; 3392df1fe9cSrandyf if (cpr_suspend_devices(ddi_root_node()) != DDI_SUCCESS) 3402df1fe9cSrandyf cmn_err(CE_WARN, 3412df1fe9cSrandyf "Some devices did not suspend " 3422df1fe9cSrandyf "and may be unusable"); 3432df1fe9cSrandyf (void) cpr_resume_devices(ddi_root_node(), 0); 3442df1fe9cSrandyf return (0); 3452df1fe9cSrandyf 3467c478bd9Sstevel@tonic-gate default: 3477c478bd9Sstevel@tonic-gate return (ENOTSUP); 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate 3502df1fe9cSrandyf if (!i_cpr_is_supported(cpr_sleeptype) || 3512df1fe9cSrandyf (cpr_sleeptype == CPR_TODISK && !cpr_is_ufs(rootvfs))) 3527c478bd9Sstevel@tonic-gate return (ENOTSUP); 3537c478bd9Sstevel@tonic-gate 3542df1fe9cSrandyf if (fcn == AD_CHECK_SUSPEND_TO_RAM || 3552df1fe9cSrandyf fcn == DEV_CHECK_SUSPEND_TO_RAM) { 3562df1fe9cSrandyf ASSERT(i_cpr_is_supported(cpr_sleeptype)); 3572df1fe9cSrandyf return (0); 3582df1fe9cSrandyf } 3592df1fe9cSrandyf 3602df1fe9cSrandyf #if defined(__sparc) 3617c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_REUSEINIT) { 3627c478bd9Sstevel@tonic-gate if (mutex_tryenter(&cpr_slock) == 0) 3637c478bd9Sstevel@tonic-gate return (EBUSY); 3647c478bd9Sstevel@tonic-gate if (cpr_reusable_mode) { 3657c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, modefmt, "already"); 3667c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3677c478bd9Sstevel@tonic-gate return (EBUSY); 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate rc = i_cpr_reuseinit(); 3707c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3717c478bd9Sstevel@tonic-gate return (rc); 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_REUSEFINI) { 3757c478bd9Sstevel@tonic-gate if (mutex_tryenter(&cpr_slock) == 0) 3767c478bd9Sstevel@tonic-gate return (EBUSY); 3777c478bd9Sstevel@tonic-gate if (!cpr_reusable_mode) { 3787c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, modefmt, "not"); 3797c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3807c478bd9Sstevel@tonic-gate return (EINVAL); 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate rc = i_cpr_reusefini(); 3837c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3847c478bd9Sstevel@tonic-gate return (rc); 3857c478bd9Sstevel@tonic-gate } 3862df1fe9cSrandyf #endif 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate /* 3897c478bd9Sstevel@tonic-gate * acquire cpr serial lock and init cpr state structure. 3907c478bd9Sstevel@tonic-gate */ 3917c478bd9Sstevel@tonic-gate if (rc = cpr_init(fcn)) 3927c478bd9Sstevel@tonic-gate return (rc); 3937c478bd9Sstevel@tonic-gate 3942df1fe9cSrandyf #if defined(__sparc) 3957c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_REUSABLE) { 3967c478bd9Sstevel@tonic-gate if ((rc = i_cpr_check_cprinfo()) != 0) { 3977c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3987c478bd9Sstevel@tonic-gate return (rc); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate } 4012df1fe9cSrandyf #endif 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate /* 4047c478bd9Sstevel@tonic-gate * Call the main cpr routine. If we are successful, we will be coming 4057c478bd9Sstevel@tonic-gate * down from the resume side, otherwise we are still in suspend. 4067c478bd9Sstevel@tonic-gate */ 4077c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, "System is being suspended"); 4082df1fe9cSrandyf if (rc = cpr_main(cpr_sleeptype)) { 4097c478bd9Sstevel@tonic-gate CPR->c_flags |= C_ERROR; 4102df1fe9cSrandyf PMD(PMD_SX, ("cpr: Suspend operation failed.\n")) 4117c478bd9Sstevel@tonic-gate cpr_err(CE_NOTE, "Suspend operation failed."); 4127c478bd9Sstevel@tonic-gate } else if (CPR->c_flags & C_SUSPENDING) { 4132df1fe9cSrandyf 4142df1fe9cSrandyf /* 4152df1fe9cSrandyf * In the suspend to RAM case, by the time we get 4162df1fe9cSrandyf * control back we're already resumed 4172df1fe9cSrandyf */ 4182df1fe9cSrandyf if (cpr_sleeptype == CPR_TORAM) { 4192df1fe9cSrandyf PMD(PMD_SX, ("cpr: cpr CPR_TORAM done\n")) 4202df1fe9cSrandyf cpr_done(); 4212df1fe9cSrandyf return (rc); 4222df1fe9cSrandyf } 4232df1fe9cSrandyf 4242df1fe9cSrandyf #if defined(__sparc) 4252df1fe9cSrandyf 4262df1fe9cSrandyf PMD(PMD_SX, ("cpr: Suspend operation succeeded.\n")) 4277c478bd9Sstevel@tonic-gate /* 4287c478bd9Sstevel@tonic-gate * Back from a successful checkpoint 4297c478bd9Sstevel@tonic-gate */ 4307c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_TESTZ || fcn == AD_CPR_TESTNOZ) { 431edc40228Sachartre mdboot(0, AD_BOOT, "", B_FALSE); 4327c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate /* make sure there are no more changes to the device tree */ 4362df1fe9cSrandyf PMD(PMD_SX, ("cpr: dev tree freeze\n")) 4377c478bd9Sstevel@tonic-gate devtree_freeze(); 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate /* 4407c478bd9Sstevel@tonic-gate * stop other cpus and raise our priority. since there is only 4417c478bd9Sstevel@tonic-gate * one active cpu after this, and our priority will be too high 4427c478bd9Sstevel@tonic-gate * for us to be preempted, we're essentially single threaded 4437c478bd9Sstevel@tonic-gate * from here on out. 4447c478bd9Sstevel@tonic-gate */ 4452df1fe9cSrandyf PMD(PMD_SX, ("cpr: stop other cpus\n")) 4462df1fe9cSrandyf i_cpr_stop_other_cpus(); 4472df1fe9cSrandyf PMD(PMD_SX, ("cpr: spl6\n")) 4487c478bd9Sstevel@tonic-gate (void) spl6(); 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate /* 4517c478bd9Sstevel@tonic-gate * try and reset leaf devices. reset_leaves() should only 4527c478bd9Sstevel@tonic-gate * be called when there are no other threads that could be 4537c478bd9Sstevel@tonic-gate * accessing devices 4547c478bd9Sstevel@tonic-gate */ 4552df1fe9cSrandyf PMD(PMD_SX, ("cpr: reset leaves\n")) 4567c478bd9Sstevel@tonic-gate reset_leaves(); 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate /* 4592df1fe9cSrandyf * If i_cpr_power_down() succeeds, it'll not return 4607c478bd9Sstevel@tonic-gate * 4617c478bd9Sstevel@tonic-gate * Drives with write-cache enabled need to flush 4627c478bd9Sstevel@tonic-gate * their cache. 4637c478bd9Sstevel@tonic-gate */ 4642df1fe9cSrandyf if (fcn != AD_CPR_TESTHALT) { 4652df1fe9cSrandyf PMD(PMD_SX, ("cpr: power down\n")) 4662df1fe9cSrandyf (void) i_cpr_power_down(cpr_sleeptype); 4672df1fe9cSrandyf } 4682df1fe9cSrandyf ASSERT(cpr_sleeptype == CPR_TODISK); 4692df1fe9cSrandyf /* currently CPR_TODISK comes back via a boot path */ 470ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "(Done. Please Switch Off)\n"); 4717c478bd9Sstevel@tonic-gate halt(NULL); 4727c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4732df1fe9cSrandyf #endif 4747c478bd9Sstevel@tonic-gate } 4752df1fe9cSrandyf PMD(PMD_SX, ("cpr: cpr done\n")) 4767c478bd9Sstevel@tonic-gate cpr_done(); 4777c478bd9Sstevel@tonic-gate return (rc); 4787c478bd9Sstevel@tonic-gate } 479