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 45*2df1fe9cSrandyf 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 53*2df1fe9cSrandyf extern int cpr_init(int); 54*2df1fe9cSrandyf extern void cpr_done(void); 55*2df1fe9cSrandyf extern void i_cpr_stop_other_cpus(void); 56*2df1fe9cSrandyf extern int i_cpr_power_down(); 57*2df1fe9cSrandyf 58*2df1fe9cSrandyf #if defined(__sparc) 59*2df1fe9cSrandyf extern void cpr_forget_cprconfig(void); 60*2df1fe9cSrandyf #endif 61*2df1fe9cSrandyf 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 */ 78*2df1fe9cSrandyf int cpr_test_point = LOOP_BACK_NONE; /* cpr test point */ 79*2df1fe9cSrandyf int cpr_mp_enable = 0; /* set to 1 to enable MP suspend */ 80*2df1fe9cSrandyf 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 113*2df1fe9cSrandyf static 114*2df1fe9cSrandyf int 115*2df1fe9cSrandyf atoi(char *p) 116*2df1fe9cSrandyf { 117*2df1fe9cSrandyf int i; 118*2df1fe9cSrandyf 119*2df1fe9cSrandyf i = (*p++ - '0'); 120*2df1fe9cSrandyf 121*2df1fe9cSrandyf while (*p != '\0') 122*2df1fe9cSrandyf i = 10 * i + (*p++ - '0'); 123*2df1fe9cSrandyf 124*2df1fe9cSrandyf return (i); 125*2df1fe9cSrandyf } 126*2df1fe9cSrandyf 1277c478bd9Sstevel@tonic-gate int 128*2df1fe9cSrandyf cpr(int fcn, void *mdep) 1297c478bd9Sstevel@tonic-gate { 130*2df1fe9cSrandyf 131*2df1fe9cSrandyf #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"; 141*2df1fe9cSrandyf #endif 1427c478bd9Sstevel@tonic-gate register int rc = 0; 143*2df1fe9cSrandyf int cpr_sleeptype; 1447c478bd9Sstevel@tonic-gate 145*2df1fe9cSrandyf /* 146*2df1fe9cSrandyf * First, reject commands that we don't (yet) support on this arch. 147*2df1fe9cSrandyf * This is easier to understand broken out like this than grotting 148*2df1fe9cSrandyf * through the second switch below. 149*2df1fe9cSrandyf */ 150*2df1fe9cSrandyf 151*2df1fe9cSrandyf switch (fcn) { 152*2df1fe9cSrandyf #if defined(__sparc) 153*2df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_RAM: 154*2df1fe9cSrandyf case AD_SUSPEND_TO_RAM: 155*2df1fe9cSrandyf return (ENOTSUP); 156*2df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_DISK: 157*2df1fe9cSrandyf case AD_SUSPEND_TO_DISK: 158*2df1fe9cSrandyf case AD_CPR_REUSEINIT: 159*2df1fe9cSrandyf case AD_CPR_NOCOMPRESS: 160*2df1fe9cSrandyf case AD_CPR_FORCE: 161*2df1fe9cSrandyf case AD_CPR_REUSABLE: 162*2df1fe9cSrandyf case AD_CPR_REUSEFINI: 163*2df1fe9cSrandyf case AD_CPR_TESTZ: 164*2df1fe9cSrandyf case AD_CPR_TESTNOZ: 165*2df1fe9cSrandyf case AD_CPR_TESTHALT: 166*2df1fe9cSrandyf case AD_CPR_SUSP_DEVICES: 167*2df1fe9cSrandyf cpr_sleeptype = CPR_TODISK; 168*2df1fe9cSrandyf break; 169*2df1fe9cSrandyf #endif 170*2df1fe9cSrandyf #if defined(__x86) 171*2df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_DISK: 172*2df1fe9cSrandyf case AD_SUSPEND_TO_DISK: 173*2df1fe9cSrandyf case AD_CPR_REUSEINIT: 174*2df1fe9cSrandyf case AD_CPR_NOCOMPRESS: 175*2df1fe9cSrandyf case AD_CPR_FORCE: 176*2df1fe9cSrandyf case AD_CPR_REUSABLE: 177*2df1fe9cSrandyf case AD_CPR_REUSEFINI: 178*2df1fe9cSrandyf case AD_CPR_TESTZ: 179*2df1fe9cSrandyf case AD_CPR_TESTNOZ: 180*2df1fe9cSrandyf case AD_CPR_TESTHALT: 181*2df1fe9cSrandyf case AD_CPR_PRINT: 182*2df1fe9cSrandyf return (ENOTSUP); 183*2df1fe9cSrandyf /* The DEV_* values need to be removed after sys-syspend is fixed */ 184*2df1fe9cSrandyf case DEV_CHECK_SUSPEND_TO_RAM: 185*2df1fe9cSrandyf case DEV_SUSPEND_TO_RAM: 186*2df1fe9cSrandyf case AD_CPR_SUSP_DEVICES: 187*2df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_RAM: 188*2df1fe9cSrandyf case AD_SUSPEND_TO_RAM: 189*2df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_PASS: 190*2df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL: 191*2df1fe9cSrandyf case AD_FORCE_SUSPEND_TO_RAM: 192*2df1fe9cSrandyf case AD_DEVICE_SUSPEND_TO_RAM: 193*2df1fe9cSrandyf /* 194*2df1fe9cSrandyf * if MP then do not support suspend to RAM, however override 195*2df1fe9cSrandyf * the MP restriction if cpr_mp_enable has been set 196*2df1fe9cSrandyf */ 197*2df1fe9cSrandyf if (ncpus > 1 && cpr_mp_enable == 0) 198*2df1fe9cSrandyf return (ENOTSUP); 199*2df1fe9cSrandyf else 200*2df1fe9cSrandyf cpr_sleeptype = CPR_TORAM; 201*2df1fe9cSrandyf break; 202*2df1fe9cSrandyf #endif 203*2df1fe9cSrandyf } 204*2df1fe9cSrandyf #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(); 214*2df1fe9cSrandyf #endif 215*2df1fe9cSrandyf 2167c478bd9Sstevel@tonic-gate switch (fcn) { 2177c478bd9Sstevel@tonic-gate 218*2df1fe9cSrandyf #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: 280*2df1fe9cSrandyf 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); 288*2df1fe9cSrandyf #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 308*2df1fe9cSrandyf /* The DEV_* values need to be removed after sys-syspend is fixed */ 309*2df1fe9cSrandyf case DEV_CHECK_SUSPEND_TO_RAM: 310*2df1fe9cSrandyf case DEV_SUSPEND_TO_RAM: 311*2df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_RAM: 312*2df1fe9cSrandyf case AD_SUSPEND_TO_RAM: 313*2df1fe9cSrandyf cpr_test_point = LOOP_BACK_NONE; 314*2df1fe9cSrandyf break; 315*2df1fe9cSrandyf 316*2df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_PASS: 317*2df1fe9cSrandyf cpr_test_point = LOOP_BACK_PASS; 318*2df1fe9cSrandyf break; 319*2df1fe9cSrandyf 320*2df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL: 321*2df1fe9cSrandyf cpr_test_point = LOOP_BACK_FAIL; 322*2df1fe9cSrandyf break; 323*2df1fe9cSrandyf 324*2df1fe9cSrandyf case AD_FORCE_SUSPEND_TO_RAM: 325*2df1fe9cSrandyf cpr_test_point = FORCE_SUSPEND_TO_RAM; 326*2df1fe9cSrandyf break; 327*2df1fe9cSrandyf 328*2df1fe9cSrandyf case AD_DEVICE_SUSPEND_TO_RAM: 329*2df1fe9cSrandyf cpr_test_point = DEVICE_SUSPEND_TO_RAM; 330*2df1fe9cSrandyf cpr_device = (major_t)atoi((char *)mdep); 331*2df1fe9cSrandyf break; 332*2df1fe9cSrandyf 333*2df1fe9cSrandyf case AD_CPR_SUSP_DEVICES: 334*2df1fe9cSrandyf cpr_test_point = FORCE_SUSPEND_TO_RAM; 335*2df1fe9cSrandyf if (cpr_suspend_devices(ddi_root_node()) != DDI_SUCCESS) 336*2df1fe9cSrandyf cmn_err(CE_WARN, 337*2df1fe9cSrandyf "Some devices did not suspend " 338*2df1fe9cSrandyf "and may be unusable"); 339*2df1fe9cSrandyf (void) cpr_resume_devices(ddi_root_node(), 0); 340*2df1fe9cSrandyf return (0); 341*2df1fe9cSrandyf 3427c478bd9Sstevel@tonic-gate default: 3437c478bd9Sstevel@tonic-gate return (ENOTSUP); 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate 346*2df1fe9cSrandyf if (!i_cpr_is_supported(cpr_sleeptype) || 347*2df1fe9cSrandyf (cpr_sleeptype == CPR_TODISK && !cpr_is_ufs(rootvfs))) 3487c478bd9Sstevel@tonic-gate return (ENOTSUP); 3497c478bd9Sstevel@tonic-gate 350*2df1fe9cSrandyf if (fcn == AD_CHECK_SUSPEND_TO_RAM || 351*2df1fe9cSrandyf fcn == DEV_CHECK_SUSPEND_TO_RAM) { 352*2df1fe9cSrandyf ASSERT(i_cpr_is_supported(cpr_sleeptype)); 353*2df1fe9cSrandyf return (0); 354*2df1fe9cSrandyf } 355*2df1fe9cSrandyf 356*2df1fe9cSrandyf #if defined(__sparc) 3577c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_REUSEINIT) { 3587c478bd9Sstevel@tonic-gate if (mutex_tryenter(&cpr_slock) == 0) 3597c478bd9Sstevel@tonic-gate return (EBUSY); 3607c478bd9Sstevel@tonic-gate if (cpr_reusable_mode) { 3617c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, modefmt, "already"); 3627c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3637c478bd9Sstevel@tonic-gate return (EBUSY); 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate rc = i_cpr_reuseinit(); 3667c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3677c478bd9Sstevel@tonic-gate return (rc); 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_REUSEFINI) { 3717c478bd9Sstevel@tonic-gate if (mutex_tryenter(&cpr_slock) == 0) 3727c478bd9Sstevel@tonic-gate return (EBUSY); 3737c478bd9Sstevel@tonic-gate if (!cpr_reusable_mode) { 3747c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, modefmt, "not"); 3757c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3767c478bd9Sstevel@tonic-gate return (EINVAL); 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate rc = i_cpr_reusefini(); 3797c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3807c478bd9Sstevel@tonic-gate return (rc); 3817c478bd9Sstevel@tonic-gate } 382*2df1fe9cSrandyf #endif 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate /* 3857c478bd9Sstevel@tonic-gate * acquire cpr serial lock and init cpr state structure. 3867c478bd9Sstevel@tonic-gate */ 3877c478bd9Sstevel@tonic-gate if (rc = cpr_init(fcn)) 3887c478bd9Sstevel@tonic-gate return (rc); 3897c478bd9Sstevel@tonic-gate 390*2df1fe9cSrandyf #if defined(__sparc) 3917c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_REUSABLE) { 3927c478bd9Sstevel@tonic-gate if ((rc = i_cpr_check_cprinfo()) != 0) { 3937c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3947c478bd9Sstevel@tonic-gate return (rc); 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate } 397*2df1fe9cSrandyf #endif 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate /* 4007c478bd9Sstevel@tonic-gate * Call the main cpr routine. If we are successful, we will be coming 4017c478bd9Sstevel@tonic-gate * down from the resume side, otherwise we are still in suspend. 4027c478bd9Sstevel@tonic-gate */ 4037c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, "System is being suspended"); 404*2df1fe9cSrandyf if (rc = cpr_main(cpr_sleeptype)) { 4057c478bd9Sstevel@tonic-gate CPR->c_flags |= C_ERROR; 406*2df1fe9cSrandyf PMD(PMD_SX, ("cpr: Suspend operation failed.\n")) 4077c478bd9Sstevel@tonic-gate cpr_err(CE_NOTE, "Suspend operation failed."); 4087c478bd9Sstevel@tonic-gate } else if (CPR->c_flags & C_SUSPENDING) { 409*2df1fe9cSrandyf 410*2df1fe9cSrandyf /* 411*2df1fe9cSrandyf * In the suspend to RAM case, by the time we get 412*2df1fe9cSrandyf * control back we're already resumed 413*2df1fe9cSrandyf */ 414*2df1fe9cSrandyf if (cpr_sleeptype == CPR_TORAM) { 415*2df1fe9cSrandyf PMD(PMD_SX, ("cpr: cpr CPR_TORAM done\n")) 416*2df1fe9cSrandyf cpr_done(); 417*2df1fe9cSrandyf return (rc); 418*2df1fe9cSrandyf } 419*2df1fe9cSrandyf 420*2df1fe9cSrandyf #if defined(__sparc) 421*2df1fe9cSrandyf 422*2df1fe9cSrandyf PMD(PMD_SX, ("cpr: Suspend operation succeeded.\n")) 4237c478bd9Sstevel@tonic-gate /* 4247c478bd9Sstevel@tonic-gate * Back from a successful checkpoint 4257c478bd9Sstevel@tonic-gate */ 4267c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_TESTZ || fcn == AD_CPR_TESTNOZ) { 427edc40228Sachartre mdboot(0, AD_BOOT, "", B_FALSE); 4287c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate /* make sure there are no more changes to the device tree */ 432*2df1fe9cSrandyf PMD(PMD_SX, ("cpr: dev tree freeze\n")) 4337c478bd9Sstevel@tonic-gate devtree_freeze(); 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate /* 4367c478bd9Sstevel@tonic-gate * stop other cpus and raise our priority. since there is only 4377c478bd9Sstevel@tonic-gate * one active cpu after this, and our priority will be too high 4387c478bd9Sstevel@tonic-gate * for us to be preempted, we're essentially single threaded 4397c478bd9Sstevel@tonic-gate * from here on out. 4407c478bd9Sstevel@tonic-gate */ 441*2df1fe9cSrandyf PMD(PMD_SX, ("cpr: stop other cpus\n")) 442*2df1fe9cSrandyf i_cpr_stop_other_cpus(); 443*2df1fe9cSrandyf PMD(PMD_SX, ("cpr: spl6\n")) 4447c478bd9Sstevel@tonic-gate (void) spl6(); 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* 4477c478bd9Sstevel@tonic-gate * try and reset leaf devices. reset_leaves() should only 4487c478bd9Sstevel@tonic-gate * be called when there are no other threads that could be 4497c478bd9Sstevel@tonic-gate * accessing devices 4507c478bd9Sstevel@tonic-gate */ 451*2df1fe9cSrandyf PMD(PMD_SX, ("cpr: reset leaves\n")) 4527c478bd9Sstevel@tonic-gate reset_leaves(); 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* 455*2df1fe9cSrandyf * If i_cpr_power_down() succeeds, it'll not return 4567c478bd9Sstevel@tonic-gate * 4577c478bd9Sstevel@tonic-gate * Drives with write-cache enabled need to flush 4587c478bd9Sstevel@tonic-gate * their cache. 4597c478bd9Sstevel@tonic-gate */ 460*2df1fe9cSrandyf if (fcn != AD_CPR_TESTHALT) { 461*2df1fe9cSrandyf PMD(PMD_SX, ("cpr: power down\n")) 462*2df1fe9cSrandyf (void) i_cpr_power_down(cpr_sleeptype); 463*2df1fe9cSrandyf } 464*2df1fe9cSrandyf ASSERT(cpr_sleeptype == CPR_TODISK); 465*2df1fe9cSrandyf /* currently CPR_TODISK comes back via a boot path */ 466ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "(Done. Please Switch Off)\n"); 4677c478bd9Sstevel@tonic-gate halt(NULL); 4687c478bd9Sstevel@tonic-gate /* NOTREACHED */ 469*2df1fe9cSrandyf #endif 4707c478bd9Sstevel@tonic-gate } 471*2df1fe9cSrandyf PMD(PMD_SX, ("cpr: cpr done\n")) 4727c478bd9Sstevel@tonic-gate cpr_done(); 4737c478bd9Sstevel@tonic-gate return (rc); 4747c478bd9Sstevel@tonic-gate } 475