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 /* 224716fd88Sjan * Copyright 2008 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 *); 47*e7cbe64fSgw extern int cpr_is_zfs(struct vfs *); 487c478bd9Sstevel@tonic-gate extern int cpr_check_spec_statefile(void); 497c478bd9Sstevel@tonic-gate extern int cpr_reusable_mount_check(void); 507c478bd9Sstevel@tonic-gate extern int i_cpr_reusable_supported(void); 517c478bd9Sstevel@tonic-gate extern int i_cpr_reusefini(void); 527c478bd9Sstevel@tonic-gate extern struct mod_ops mod_miscops; 537c478bd9Sstevel@tonic-gate 542df1fe9cSrandyf extern int cpr_init(int); 552df1fe9cSrandyf extern void cpr_done(void); 562df1fe9cSrandyf extern void i_cpr_stop_other_cpus(void); 572df1fe9cSrandyf extern int i_cpr_power_down(); 582df1fe9cSrandyf 592df1fe9cSrandyf #if defined(__sparc) 602df1fe9cSrandyf extern void cpr_forget_cprconfig(void); 612df1fe9cSrandyf #endif 622df1fe9cSrandyf 637c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = { 647c478bd9Sstevel@tonic-gate &mod_miscops, "checkpoint resume" 657c478bd9Sstevel@tonic-gate }; 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 687c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modlmisc, NULL 697c478bd9Sstevel@tonic-gate }; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate char _depends_on[] = "misc/bootdev"; /* i_devname_to_promname() */ 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate int cpr_reusable_mode; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate kmutex_t cpr_slock; /* cpr serial lock */ 767c478bd9Sstevel@tonic-gate cpr_t cpr_state; 777c478bd9Sstevel@tonic-gate int cpr_debug; 787c478bd9Sstevel@tonic-gate int cpr_test_mode; /* true if called via uadmin testmode */ 792df1fe9cSrandyf int cpr_test_point = LOOP_BACK_NONE; /* cpr test point */ 802df1fe9cSrandyf int cpr_mp_enable = 0; /* set to 1 to enable MP suspend */ 812df1fe9cSrandyf major_t cpr_device = 0; /* major number for S3 on one device */ 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* 847c478bd9Sstevel@tonic-gate * All the loadable module related code follows 857c478bd9Sstevel@tonic-gate */ 867c478bd9Sstevel@tonic-gate int 877c478bd9Sstevel@tonic-gate _init(void) 887c478bd9Sstevel@tonic-gate { 897c478bd9Sstevel@tonic-gate register int e; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) == 0) { 927c478bd9Sstevel@tonic-gate mutex_init(&cpr_slock, NULL, MUTEX_DEFAULT, NULL); 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate return (e); 957c478bd9Sstevel@tonic-gate } 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate int 987c478bd9Sstevel@tonic-gate _fini(void) 997c478bd9Sstevel@tonic-gate { 1007c478bd9Sstevel@tonic-gate register int e; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate if ((e = mod_remove(&modlinkage)) == 0) { 1037c478bd9Sstevel@tonic-gate mutex_destroy(&cpr_slock); 1047c478bd9Sstevel@tonic-gate } 1057c478bd9Sstevel@tonic-gate return (e); 1067c478bd9Sstevel@tonic-gate } 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate int 1097c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1107c478bd9Sstevel@tonic-gate { 1117c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate 1142df1fe9cSrandyf static 1152df1fe9cSrandyf int 1162df1fe9cSrandyf atoi(char *p) 1172df1fe9cSrandyf { 1182df1fe9cSrandyf int i; 1192df1fe9cSrandyf 1202df1fe9cSrandyf i = (*p++ - '0'); 1212df1fe9cSrandyf 1222df1fe9cSrandyf while (*p != '\0') 1232df1fe9cSrandyf i = 10 * i + (*p++ - '0'); 1242df1fe9cSrandyf 1252df1fe9cSrandyf return (i); 1262df1fe9cSrandyf } 1272df1fe9cSrandyf 1287c478bd9Sstevel@tonic-gate int 1292df1fe9cSrandyf cpr(int fcn, void *mdep) 1307c478bd9Sstevel@tonic-gate { 1312df1fe9cSrandyf 1322df1fe9cSrandyf #if defined(__sparc) 1337c478bd9Sstevel@tonic-gate static const char noswapstr[] = "reusable statefile requires " 1347c478bd9Sstevel@tonic-gate "that no swap area be configured.\n"; 1357c478bd9Sstevel@tonic-gate static const char blockstr[] = "reusable statefile must be " 1367c478bd9Sstevel@tonic-gate "a block device. See power.conf(4) and pmconfig(1M).\n"; 1377c478bd9Sstevel@tonic-gate static const char normalfmt[] = "cannot run normal " 1387c478bd9Sstevel@tonic-gate "checkpoint/resume when in reusable statefile mode. " 1397c478bd9Sstevel@tonic-gate "use uadmin A_FREEZE AD_REUSEFINI (uadmin %d %d) " 1407c478bd9Sstevel@tonic-gate "to exit reusable statefile mode.\n"; 1417c478bd9Sstevel@tonic-gate static const char modefmt[] = "%s in reusable mode.\n"; 1422df1fe9cSrandyf #endif 1437c478bd9Sstevel@tonic-gate register int rc = 0; 1442df1fe9cSrandyf int cpr_sleeptype; 1457c478bd9Sstevel@tonic-gate 1462df1fe9cSrandyf /* 1472df1fe9cSrandyf * First, reject commands that we don't (yet) support on this arch. 1482df1fe9cSrandyf * This is easier to understand broken out like this than grotting 1492df1fe9cSrandyf * through the second switch below. 1502df1fe9cSrandyf */ 1512df1fe9cSrandyf 1522df1fe9cSrandyf switch (fcn) { 1532df1fe9cSrandyf #if defined(__sparc) 1542df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_RAM: 1552df1fe9cSrandyf case AD_SUSPEND_TO_RAM: 1562df1fe9cSrandyf return (ENOTSUP); 1572df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_DISK: 1582df1fe9cSrandyf case AD_SUSPEND_TO_DISK: 1592df1fe9cSrandyf case AD_CPR_REUSEINIT: 1602df1fe9cSrandyf case AD_CPR_NOCOMPRESS: 1612df1fe9cSrandyf case AD_CPR_FORCE: 1622df1fe9cSrandyf case AD_CPR_REUSABLE: 1632df1fe9cSrandyf case AD_CPR_REUSEFINI: 1642df1fe9cSrandyf case AD_CPR_TESTZ: 1652df1fe9cSrandyf case AD_CPR_TESTNOZ: 1662df1fe9cSrandyf case AD_CPR_TESTHALT: 1672df1fe9cSrandyf case AD_CPR_SUSP_DEVICES: 1682df1fe9cSrandyf cpr_sleeptype = CPR_TODISK; 1692df1fe9cSrandyf break; 1702df1fe9cSrandyf #endif 1712df1fe9cSrandyf #if defined(__x86) 1722df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_DISK: 1732df1fe9cSrandyf case AD_SUSPEND_TO_DISK: 1742df1fe9cSrandyf case AD_CPR_REUSEINIT: 1752df1fe9cSrandyf case AD_CPR_NOCOMPRESS: 1762df1fe9cSrandyf case AD_CPR_FORCE: 1772df1fe9cSrandyf case AD_CPR_REUSABLE: 1782df1fe9cSrandyf case AD_CPR_REUSEFINI: 1792df1fe9cSrandyf case AD_CPR_TESTZ: 1802df1fe9cSrandyf case AD_CPR_TESTNOZ: 1812df1fe9cSrandyf case AD_CPR_TESTHALT: 1822df1fe9cSrandyf case AD_CPR_PRINT: 1832df1fe9cSrandyf return (ENOTSUP); 1842df1fe9cSrandyf /* The DEV_* values need to be removed after sys-syspend is fixed */ 1852df1fe9cSrandyf case DEV_CHECK_SUSPEND_TO_RAM: 1862df1fe9cSrandyf case DEV_SUSPEND_TO_RAM: 1872df1fe9cSrandyf case AD_CPR_SUSP_DEVICES: 1882df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_RAM: 1892df1fe9cSrandyf case AD_SUSPEND_TO_RAM: 1902df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_PASS: 1912df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL: 1922df1fe9cSrandyf case AD_FORCE_SUSPEND_TO_RAM: 1932df1fe9cSrandyf case AD_DEVICE_SUSPEND_TO_RAM: 1944716fd88Sjan cpr_sleeptype = CPR_TORAM; 1952df1fe9cSrandyf break; 1962df1fe9cSrandyf #endif 1972df1fe9cSrandyf } 1982df1fe9cSrandyf #if defined(__sparc) 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * Need to know if we're in reusable mode, but we will likely have 2017c478bd9Sstevel@tonic-gate * rebooted since REUSEINIT, so we have to get the info from the 2027c478bd9Sstevel@tonic-gate * file system 2037c478bd9Sstevel@tonic-gate */ 2047c478bd9Sstevel@tonic-gate if (!cpr_reusable_mode) 2057c478bd9Sstevel@tonic-gate cpr_reusable_mode = cpr_get_reusable_mode(); 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate cpr_forget_cprconfig(); 2082df1fe9cSrandyf #endif 2092df1fe9cSrandyf 2107c478bd9Sstevel@tonic-gate switch (fcn) { 2117c478bd9Sstevel@tonic-gate 2122df1fe9cSrandyf #if defined(__sparc) 2137c478bd9Sstevel@tonic-gate case AD_CPR_REUSEINIT: 2147c478bd9Sstevel@tonic-gate if (!i_cpr_reusable_supported()) 2157c478bd9Sstevel@tonic-gate return (ENOTSUP); 2167c478bd9Sstevel@tonic-gate if (!cpr_statefile_is_spec()) { 2177c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, blockstr); 2187c478bd9Sstevel@tonic-gate return (EINVAL); 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate if ((rc = cpr_check_spec_statefile()) != 0) 2217c478bd9Sstevel@tonic-gate return (rc); 2227c478bd9Sstevel@tonic-gate if (swapinfo) { 2237c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, noswapstr); 2247c478bd9Sstevel@tonic-gate return (EINVAL); 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate cpr_test_mode = 0; 2277c478bd9Sstevel@tonic-gate break; 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate case AD_CPR_NOCOMPRESS: 2307c478bd9Sstevel@tonic-gate case AD_CPR_COMPRESS: 2317c478bd9Sstevel@tonic-gate case AD_CPR_FORCE: 2327c478bd9Sstevel@tonic-gate if (cpr_reusable_mode) { 2337c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI); 2347c478bd9Sstevel@tonic-gate return (ENOTSUP); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate cpr_test_mode = 0; 2377c478bd9Sstevel@tonic-gate break; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate case AD_CPR_REUSABLE: 2407c478bd9Sstevel@tonic-gate if (!i_cpr_reusable_supported()) 2417c478bd9Sstevel@tonic-gate return (ENOTSUP); 2427c478bd9Sstevel@tonic-gate if (!cpr_statefile_is_spec()) { 2437c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, blockstr); 2447c478bd9Sstevel@tonic-gate return (EINVAL); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate if ((rc = cpr_check_spec_statefile()) != 0) 2477c478bd9Sstevel@tonic-gate return (rc); 2487c478bd9Sstevel@tonic-gate if (swapinfo) { 2497c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, noswapstr); 2507c478bd9Sstevel@tonic-gate return (EINVAL); 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate if ((rc = cpr_reusable_mount_check()) != 0) 2537c478bd9Sstevel@tonic-gate return (rc); 2547c478bd9Sstevel@tonic-gate cpr_test_mode = 0; 2557c478bd9Sstevel@tonic-gate break; 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate case AD_CPR_REUSEFINI: 2587c478bd9Sstevel@tonic-gate if (!i_cpr_reusable_supported()) 2597c478bd9Sstevel@tonic-gate return (ENOTSUP); 2607c478bd9Sstevel@tonic-gate cpr_test_mode = 0; 2617c478bd9Sstevel@tonic-gate break; 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate case AD_CPR_TESTZ: 2647c478bd9Sstevel@tonic-gate case AD_CPR_TESTNOZ: 2657c478bd9Sstevel@tonic-gate case AD_CPR_TESTHALT: 2667c478bd9Sstevel@tonic-gate if (cpr_reusable_mode) { 2677c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI); 2687c478bd9Sstevel@tonic-gate return (ENOTSUP); 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate cpr_test_mode = 1; 2717c478bd9Sstevel@tonic-gate break; 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate case AD_CPR_CHECK: 2742df1fe9cSrandyf if (!i_cpr_is_supported(cpr_sleeptype) || cpr_reusable_mode) 2757c478bd9Sstevel@tonic-gate return (ENOTSUP); 2767c478bd9Sstevel@tonic-gate return (0); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate case AD_CPR_PRINT: 2797c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END("POST CPR DELAY"); 2807c478bd9Sstevel@tonic-gate cpr_stat_event_print(); 2817c478bd9Sstevel@tonic-gate return (0); 2822df1fe9cSrandyf #endif 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG0: 2857c478bd9Sstevel@tonic-gate cpr_debug = 0; 2867c478bd9Sstevel@tonic-gate return (0); 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG1: 2897c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG2: 2907c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG3: 2917c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG4: 2927c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG5: 2937c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG7: 2947c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG8: 2957c478bd9Sstevel@tonic-gate cpr_debug |= CPR_DEBUG_BIT(fcn); 2967c478bd9Sstevel@tonic-gate return (0); 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG9: 299ae115bc7Smrj cpr_debug |= CPR_DEBUG6; 3007c478bd9Sstevel@tonic-gate return (0); 3017c478bd9Sstevel@tonic-gate 3022df1fe9cSrandyf /* The DEV_* values need to be removed after sys-syspend is fixed */ 3032df1fe9cSrandyf case DEV_CHECK_SUSPEND_TO_RAM: 3042df1fe9cSrandyf case DEV_SUSPEND_TO_RAM: 3052df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_RAM: 3062df1fe9cSrandyf case AD_SUSPEND_TO_RAM: 3072df1fe9cSrandyf cpr_test_point = LOOP_BACK_NONE; 3082df1fe9cSrandyf break; 3092df1fe9cSrandyf 3102df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_PASS: 3112df1fe9cSrandyf cpr_test_point = LOOP_BACK_PASS; 3122df1fe9cSrandyf break; 3132df1fe9cSrandyf 3142df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL: 3152df1fe9cSrandyf cpr_test_point = LOOP_BACK_FAIL; 3162df1fe9cSrandyf break; 3172df1fe9cSrandyf 3182df1fe9cSrandyf case AD_FORCE_SUSPEND_TO_RAM: 3192df1fe9cSrandyf cpr_test_point = FORCE_SUSPEND_TO_RAM; 3202df1fe9cSrandyf break; 3212df1fe9cSrandyf 3222df1fe9cSrandyf case AD_DEVICE_SUSPEND_TO_RAM: 323c36fc336Srandyf if (mdep == NULL) { 324c36fc336Srandyf /* Didn't pass enough arguments */ 325c36fc336Srandyf return (EINVAL); 326c36fc336Srandyf } 3272df1fe9cSrandyf cpr_test_point = DEVICE_SUSPEND_TO_RAM; 3282df1fe9cSrandyf cpr_device = (major_t)atoi((char *)mdep); 3292df1fe9cSrandyf break; 3302df1fe9cSrandyf 3312df1fe9cSrandyf case AD_CPR_SUSP_DEVICES: 3322df1fe9cSrandyf cpr_test_point = FORCE_SUSPEND_TO_RAM; 3332df1fe9cSrandyf if (cpr_suspend_devices(ddi_root_node()) != DDI_SUCCESS) 3342df1fe9cSrandyf cmn_err(CE_WARN, 3352df1fe9cSrandyf "Some devices did not suspend " 3362df1fe9cSrandyf "and may be unusable"); 3372df1fe9cSrandyf (void) cpr_resume_devices(ddi_root_node(), 0); 3382df1fe9cSrandyf return (0); 3392df1fe9cSrandyf 3407c478bd9Sstevel@tonic-gate default: 3417c478bd9Sstevel@tonic-gate return (ENOTSUP); 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate 3442df1fe9cSrandyf if (!i_cpr_is_supported(cpr_sleeptype) || 345*e7cbe64fSgw (cpr_sleeptype == CPR_TODISK && 346*e7cbe64fSgw !cpr_is_ufs(rootvfs)&& !cpr_is_zfs(rootvfs))) 3477c478bd9Sstevel@tonic-gate return (ENOTSUP); 3487c478bd9Sstevel@tonic-gate 3492df1fe9cSrandyf if (fcn == AD_CHECK_SUSPEND_TO_RAM || 3502df1fe9cSrandyf fcn == DEV_CHECK_SUSPEND_TO_RAM) { 3512df1fe9cSrandyf ASSERT(i_cpr_is_supported(cpr_sleeptype)); 3522df1fe9cSrandyf return (0); 3532df1fe9cSrandyf } 3542df1fe9cSrandyf 3552df1fe9cSrandyf #if defined(__sparc) 3567c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_REUSEINIT) { 3577c478bd9Sstevel@tonic-gate if (mutex_tryenter(&cpr_slock) == 0) 3587c478bd9Sstevel@tonic-gate return (EBUSY); 3597c478bd9Sstevel@tonic-gate if (cpr_reusable_mode) { 3607c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, modefmt, "already"); 3617c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3627c478bd9Sstevel@tonic-gate return (EBUSY); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate rc = i_cpr_reuseinit(); 3657c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3667c478bd9Sstevel@tonic-gate return (rc); 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_REUSEFINI) { 3707c478bd9Sstevel@tonic-gate if (mutex_tryenter(&cpr_slock) == 0) 3717c478bd9Sstevel@tonic-gate return (EBUSY); 3727c478bd9Sstevel@tonic-gate if (!cpr_reusable_mode) { 3737c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, modefmt, "not"); 3747c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3757c478bd9Sstevel@tonic-gate return (EINVAL); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate rc = i_cpr_reusefini(); 3787c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3797c478bd9Sstevel@tonic-gate return (rc); 3807c478bd9Sstevel@tonic-gate } 3812df1fe9cSrandyf #endif 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate /* 3847c478bd9Sstevel@tonic-gate * acquire cpr serial lock and init cpr state structure. 3857c478bd9Sstevel@tonic-gate */ 3867c478bd9Sstevel@tonic-gate if (rc = cpr_init(fcn)) 3877c478bd9Sstevel@tonic-gate return (rc); 3887c478bd9Sstevel@tonic-gate 3892df1fe9cSrandyf #if defined(__sparc) 3907c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_REUSABLE) { 3917c478bd9Sstevel@tonic-gate if ((rc = i_cpr_check_cprinfo()) != 0) { 3927c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3937c478bd9Sstevel@tonic-gate return (rc); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate } 3962df1fe9cSrandyf #endif 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate /* 3997c478bd9Sstevel@tonic-gate * Call the main cpr routine. If we are successful, we will be coming 4007c478bd9Sstevel@tonic-gate * down from the resume side, otherwise we are still in suspend. 4017c478bd9Sstevel@tonic-gate */ 4027c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, "System is being suspended"); 4032df1fe9cSrandyf if (rc = cpr_main(cpr_sleeptype)) { 4047c478bd9Sstevel@tonic-gate CPR->c_flags |= C_ERROR; 4052df1fe9cSrandyf PMD(PMD_SX, ("cpr: Suspend operation failed.\n")) 4067c478bd9Sstevel@tonic-gate cpr_err(CE_NOTE, "Suspend operation failed."); 4077c478bd9Sstevel@tonic-gate } else if (CPR->c_flags & C_SUSPENDING) { 4082df1fe9cSrandyf 4092df1fe9cSrandyf /* 4102df1fe9cSrandyf * In the suspend to RAM case, by the time we get 4112df1fe9cSrandyf * control back we're already resumed 4122df1fe9cSrandyf */ 4132df1fe9cSrandyf if (cpr_sleeptype == CPR_TORAM) { 4142df1fe9cSrandyf PMD(PMD_SX, ("cpr: cpr CPR_TORAM done\n")) 4152df1fe9cSrandyf cpr_done(); 4162df1fe9cSrandyf return (rc); 4172df1fe9cSrandyf } 4182df1fe9cSrandyf 4192df1fe9cSrandyf #if defined(__sparc) 4202df1fe9cSrandyf 4212df1fe9cSrandyf PMD(PMD_SX, ("cpr: Suspend operation succeeded.\n")) 4227c478bd9Sstevel@tonic-gate /* 4237c478bd9Sstevel@tonic-gate * Back from a successful checkpoint 4247c478bd9Sstevel@tonic-gate */ 4257c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_TESTZ || fcn == AD_CPR_TESTNOZ) { 426edc40228Sachartre mdboot(0, AD_BOOT, "", B_FALSE); 4277c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate /* make sure there are no more changes to the device tree */ 4312df1fe9cSrandyf PMD(PMD_SX, ("cpr: dev tree freeze\n")) 4327c478bd9Sstevel@tonic-gate devtree_freeze(); 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate /* 4357c478bd9Sstevel@tonic-gate * stop other cpus and raise our priority. since there is only 4367c478bd9Sstevel@tonic-gate * one active cpu after this, and our priority will be too high 4377c478bd9Sstevel@tonic-gate * for us to be preempted, we're essentially single threaded 4387c478bd9Sstevel@tonic-gate * from here on out. 4397c478bd9Sstevel@tonic-gate */ 4402df1fe9cSrandyf PMD(PMD_SX, ("cpr: stop other cpus\n")) 4412df1fe9cSrandyf i_cpr_stop_other_cpus(); 4422df1fe9cSrandyf PMD(PMD_SX, ("cpr: spl6\n")) 4437c478bd9Sstevel@tonic-gate (void) spl6(); 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate /* 4467c478bd9Sstevel@tonic-gate * try and reset leaf devices. reset_leaves() should only 4477c478bd9Sstevel@tonic-gate * be called when there are no other threads that could be 4487c478bd9Sstevel@tonic-gate * accessing devices 4497c478bd9Sstevel@tonic-gate */ 4502df1fe9cSrandyf PMD(PMD_SX, ("cpr: reset leaves\n")) 4517c478bd9Sstevel@tonic-gate reset_leaves(); 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate /* 4542df1fe9cSrandyf * If i_cpr_power_down() succeeds, it'll not return 4557c478bd9Sstevel@tonic-gate * 4567c478bd9Sstevel@tonic-gate * Drives with write-cache enabled need to flush 4577c478bd9Sstevel@tonic-gate * their cache. 4587c478bd9Sstevel@tonic-gate */ 4592df1fe9cSrandyf if (fcn != AD_CPR_TESTHALT) { 4602df1fe9cSrandyf PMD(PMD_SX, ("cpr: power down\n")) 4612df1fe9cSrandyf (void) i_cpr_power_down(cpr_sleeptype); 4622df1fe9cSrandyf } 4632df1fe9cSrandyf ASSERT(cpr_sleeptype == CPR_TODISK); 4642df1fe9cSrandyf /* currently CPR_TODISK comes back via a boot path */ 465ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "(Done. Please Switch Off)\n"); 4667c478bd9Sstevel@tonic-gate halt(NULL); 4677c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4682df1fe9cSrandyf #endif 4697c478bd9Sstevel@tonic-gate } 4702df1fe9cSrandyf PMD(PMD_SX, ("cpr: cpr done\n")) 4717c478bd9Sstevel@tonic-gate cpr_done(); 4727c478bd9Sstevel@tonic-gate return (rc); 4737c478bd9Sstevel@tonic-gate } 474