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. 2489b43686SBayard Bell * Copyright (c) 2011 Bayard G. Bell. All rights reserved. 25*b97d6ca7SMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved. 267c478bd9Sstevel@tonic-gate */ 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 *); 47e7cbe64fSgw 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); 57*b97d6ca7SMilan Jurik extern int i_cpr_power_down(int); 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 int cpr_reusable_mode; 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate kmutex_t cpr_slock; /* cpr serial lock */ 747c478bd9Sstevel@tonic-gate cpr_t cpr_state; 757c478bd9Sstevel@tonic-gate int cpr_debug; 767c478bd9Sstevel@tonic-gate int cpr_test_mode; /* true if called via uadmin testmode */ 772df1fe9cSrandyf int cpr_test_point = LOOP_BACK_NONE; /* cpr test point */ 782df1fe9cSrandyf int cpr_mp_enable = 0; /* set to 1 to enable MP suspend */ 792df1fe9cSrandyf major_t cpr_device = 0; /* major number for S3 on one device */ 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* 827c478bd9Sstevel@tonic-gate * All the loadable module related code follows 837c478bd9Sstevel@tonic-gate */ 847c478bd9Sstevel@tonic-gate int 857c478bd9Sstevel@tonic-gate _init(void) 867c478bd9Sstevel@tonic-gate { 877c478bd9Sstevel@tonic-gate register int e; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) == 0) { 907c478bd9Sstevel@tonic-gate mutex_init(&cpr_slock, NULL, MUTEX_DEFAULT, NULL); 917c478bd9Sstevel@tonic-gate } 927c478bd9Sstevel@tonic-gate return (e); 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate int 967c478bd9Sstevel@tonic-gate _fini(void) 977c478bd9Sstevel@tonic-gate { 987c478bd9Sstevel@tonic-gate register int e; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate if ((e = mod_remove(&modlinkage)) == 0) { 1017c478bd9Sstevel@tonic-gate mutex_destroy(&cpr_slock); 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate return (e); 1047c478bd9Sstevel@tonic-gate } 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate int 1077c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1087c478bd9Sstevel@tonic-gate { 1097c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 1122df1fe9cSrandyf static 1132df1fe9cSrandyf int 1142df1fe9cSrandyf atoi(char *p) 1152df1fe9cSrandyf { 1162df1fe9cSrandyf int i; 1172df1fe9cSrandyf 1182df1fe9cSrandyf i = (*p++ - '0'); 1192df1fe9cSrandyf 1202df1fe9cSrandyf while (*p != '\0') 1212df1fe9cSrandyf i = 10 * i + (*p++ - '0'); 1222df1fe9cSrandyf 1232df1fe9cSrandyf return (i); 1242df1fe9cSrandyf } 1252df1fe9cSrandyf 1267c478bd9Sstevel@tonic-gate int 1272df1fe9cSrandyf cpr(int fcn, void *mdep) 1287c478bd9Sstevel@tonic-gate { 1292df1fe9cSrandyf 1302df1fe9cSrandyf #if defined(__sparc) 1317c478bd9Sstevel@tonic-gate static const char noswapstr[] = "reusable statefile requires " 1327c478bd9Sstevel@tonic-gate "that no swap area be configured.\n"; 1337c478bd9Sstevel@tonic-gate static const char blockstr[] = "reusable statefile must be " 1347c478bd9Sstevel@tonic-gate "a block device. See power.conf(4) and pmconfig(1M).\n"; 1357c478bd9Sstevel@tonic-gate static const char normalfmt[] = "cannot run normal " 1367c478bd9Sstevel@tonic-gate "checkpoint/resume when in reusable statefile mode. " 1377c478bd9Sstevel@tonic-gate "use uadmin A_FREEZE AD_REUSEFINI (uadmin %d %d) " 1387c478bd9Sstevel@tonic-gate "to exit reusable statefile mode.\n"; 1397c478bd9Sstevel@tonic-gate static const char modefmt[] = "%s in reusable mode.\n"; 1402df1fe9cSrandyf #endif 1417c478bd9Sstevel@tonic-gate register int rc = 0; 1422df1fe9cSrandyf int cpr_sleeptype; 1437c478bd9Sstevel@tonic-gate 1442df1fe9cSrandyf /* 1452df1fe9cSrandyf * First, reject commands that we don't (yet) support on this arch. 1462df1fe9cSrandyf * This is easier to understand broken out like this than grotting 1472df1fe9cSrandyf * through the second switch below. 1482df1fe9cSrandyf */ 1492df1fe9cSrandyf 1502df1fe9cSrandyf switch (fcn) { 1512df1fe9cSrandyf #if defined(__sparc) 1522df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_RAM: 1532df1fe9cSrandyf case AD_SUSPEND_TO_RAM: 1542df1fe9cSrandyf return (ENOTSUP); 1552df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_DISK: 1562df1fe9cSrandyf case AD_SUSPEND_TO_DISK: 1572df1fe9cSrandyf case AD_CPR_REUSEINIT: 1582df1fe9cSrandyf case AD_CPR_NOCOMPRESS: 1592df1fe9cSrandyf case AD_CPR_FORCE: 1602df1fe9cSrandyf case AD_CPR_REUSABLE: 1612df1fe9cSrandyf case AD_CPR_REUSEFINI: 1622df1fe9cSrandyf case AD_CPR_TESTZ: 1632df1fe9cSrandyf case AD_CPR_TESTNOZ: 1642df1fe9cSrandyf case AD_CPR_TESTHALT: 1652df1fe9cSrandyf case AD_CPR_SUSP_DEVICES: 1662df1fe9cSrandyf cpr_sleeptype = CPR_TODISK; 1672df1fe9cSrandyf break; 1682df1fe9cSrandyf #endif 1692df1fe9cSrandyf #if defined(__x86) 1702df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_DISK: 1712df1fe9cSrandyf case AD_SUSPEND_TO_DISK: 1722df1fe9cSrandyf case AD_CPR_REUSEINIT: 1732df1fe9cSrandyf case AD_CPR_NOCOMPRESS: 1742df1fe9cSrandyf case AD_CPR_FORCE: 1752df1fe9cSrandyf case AD_CPR_REUSABLE: 1762df1fe9cSrandyf case AD_CPR_REUSEFINI: 1772df1fe9cSrandyf case AD_CPR_TESTZ: 1782df1fe9cSrandyf case AD_CPR_TESTNOZ: 1792df1fe9cSrandyf case AD_CPR_TESTHALT: 1802df1fe9cSrandyf case AD_CPR_PRINT: 1812df1fe9cSrandyf return (ENOTSUP); 1822df1fe9cSrandyf /* The DEV_* values need to be removed after sys-syspend is fixed */ 1832df1fe9cSrandyf case DEV_CHECK_SUSPEND_TO_RAM: 1842df1fe9cSrandyf case DEV_SUSPEND_TO_RAM: 1852df1fe9cSrandyf case AD_CPR_SUSP_DEVICES: 1862df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_RAM: 1872df1fe9cSrandyf case AD_SUSPEND_TO_RAM: 1882df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_PASS: 1892df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL: 1902df1fe9cSrandyf case AD_FORCE_SUSPEND_TO_RAM: 1912df1fe9cSrandyf case AD_DEVICE_SUSPEND_TO_RAM: 1924716fd88Sjan cpr_sleeptype = CPR_TORAM; 1932df1fe9cSrandyf break; 1942df1fe9cSrandyf #endif 1952df1fe9cSrandyf } 1962df1fe9cSrandyf #if defined(__sparc) 1977c478bd9Sstevel@tonic-gate /* 1987c478bd9Sstevel@tonic-gate * Need to know if we're in reusable mode, but we will likely have 1997c478bd9Sstevel@tonic-gate * rebooted since REUSEINIT, so we have to get the info from the 2007c478bd9Sstevel@tonic-gate * file system 2017c478bd9Sstevel@tonic-gate */ 2027c478bd9Sstevel@tonic-gate if (!cpr_reusable_mode) 2037c478bd9Sstevel@tonic-gate cpr_reusable_mode = cpr_get_reusable_mode(); 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate cpr_forget_cprconfig(); 2062df1fe9cSrandyf #endif 2072df1fe9cSrandyf 2087c478bd9Sstevel@tonic-gate switch (fcn) { 2097c478bd9Sstevel@tonic-gate 2102df1fe9cSrandyf #if defined(__sparc) 2117c478bd9Sstevel@tonic-gate case AD_CPR_REUSEINIT: 2127c478bd9Sstevel@tonic-gate if (!i_cpr_reusable_supported()) 2137c478bd9Sstevel@tonic-gate return (ENOTSUP); 2147c478bd9Sstevel@tonic-gate if (!cpr_statefile_is_spec()) { 2157c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, blockstr); 2167c478bd9Sstevel@tonic-gate return (EINVAL); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate if ((rc = cpr_check_spec_statefile()) != 0) 2197c478bd9Sstevel@tonic-gate return (rc); 2207c478bd9Sstevel@tonic-gate if (swapinfo) { 2217c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, noswapstr); 2227c478bd9Sstevel@tonic-gate return (EINVAL); 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate cpr_test_mode = 0; 2257c478bd9Sstevel@tonic-gate break; 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate case AD_CPR_NOCOMPRESS: 2287c478bd9Sstevel@tonic-gate case AD_CPR_COMPRESS: 2297c478bd9Sstevel@tonic-gate case AD_CPR_FORCE: 2307c478bd9Sstevel@tonic-gate if (cpr_reusable_mode) { 2317c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI); 2327c478bd9Sstevel@tonic-gate return (ENOTSUP); 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate cpr_test_mode = 0; 2357c478bd9Sstevel@tonic-gate break; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate case AD_CPR_REUSABLE: 2387c478bd9Sstevel@tonic-gate if (!i_cpr_reusable_supported()) 2397c478bd9Sstevel@tonic-gate return (ENOTSUP); 2407c478bd9Sstevel@tonic-gate if (!cpr_statefile_is_spec()) { 2417c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, blockstr); 2427c478bd9Sstevel@tonic-gate return (EINVAL); 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate if ((rc = cpr_check_spec_statefile()) != 0) 2457c478bd9Sstevel@tonic-gate return (rc); 2467c478bd9Sstevel@tonic-gate if (swapinfo) { 2477c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, noswapstr); 2487c478bd9Sstevel@tonic-gate return (EINVAL); 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate if ((rc = cpr_reusable_mount_check()) != 0) 2517c478bd9Sstevel@tonic-gate return (rc); 2527c478bd9Sstevel@tonic-gate cpr_test_mode = 0; 2537c478bd9Sstevel@tonic-gate break; 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate case AD_CPR_REUSEFINI: 2567c478bd9Sstevel@tonic-gate if (!i_cpr_reusable_supported()) 2577c478bd9Sstevel@tonic-gate return (ENOTSUP); 2587c478bd9Sstevel@tonic-gate cpr_test_mode = 0; 2597c478bd9Sstevel@tonic-gate break; 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate case AD_CPR_TESTZ: 2627c478bd9Sstevel@tonic-gate case AD_CPR_TESTNOZ: 2637c478bd9Sstevel@tonic-gate case AD_CPR_TESTHALT: 2647c478bd9Sstevel@tonic-gate if (cpr_reusable_mode) { 2657c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI); 2667c478bd9Sstevel@tonic-gate return (ENOTSUP); 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate cpr_test_mode = 1; 2697c478bd9Sstevel@tonic-gate break; 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate case AD_CPR_CHECK: 2722df1fe9cSrandyf if (!i_cpr_is_supported(cpr_sleeptype) || cpr_reusable_mode) 2737c478bd9Sstevel@tonic-gate return (ENOTSUP); 2747c478bd9Sstevel@tonic-gate return (0); 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate case AD_CPR_PRINT: 2777c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END("POST CPR DELAY"); 2787c478bd9Sstevel@tonic-gate cpr_stat_event_print(); 2797c478bd9Sstevel@tonic-gate return (0); 2802df1fe9cSrandyf #endif 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG0: 2837c478bd9Sstevel@tonic-gate cpr_debug = 0; 2847c478bd9Sstevel@tonic-gate return (0); 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG1: 2877c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG2: 2887c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG3: 2897c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG4: 2907c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG5: 2917c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG7: 2927c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG8: 2937c478bd9Sstevel@tonic-gate cpr_debug |= CPR_DEBUG_BIT(fcn); 2947c478bd9Sstevel@tonic-gate return (0); 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate case AD_CPR_DEBUG9: 297ae115bc7Smrj cpr_debug |= CPR_DEBUG6; 2987c478bd9Sstevel@tonic-gate return (0); 2997c478bd9Sstevel@tonic-gate 3002df1fe9cSrandyf /* The DEV_* values need to be removed after sys-syspend is fixed */ 3012df1fe9cSrandyf case DEV_CHECK_SUSPEND_TO_RAM: 3022df1fe9cSrandyf case DEV_SUSPEND_TO_RAM: 3032df1fe9cSrandyf case AD_CHECK_SUSPEND_TO_RAM: 3042df1fe9cSrandyf case AD_SUSPEND_TO_RAM: 3052df1fe9cSrandyf cpr_test_point = LOOP_BACK_NONE; 3062df1fe9cSrandyf break; 3072df1fe9cSrandyf 3082df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_PASS: 3092df1fe9cSrandyf cpr_test_point = LOOP_BACK_PASS; 3102df1fe9cSrandyf break; 3112df1fe9cSrandyf 3122df1fe9cSrandyf case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL: 3132df1fe9cSrandyf cpr_test_point = LOOP_BACK_FAIL; 3142df1fe9cSrandyf break; 3152df1fe9cSrandyf 3162df1fe9cSrandyf case AD_FORCE_SUSPEND_TO_RAM: 3172df1fe9cSrandyf cpr_test_point = FORCE_SUSPEND_TO_RAM; 3182df1fe9cSrandyf break; 3192df1fe9cSrandyf 3202df1fe9cSrandyf case AD_DEVICE_SUSPEND_TO_RAM: 321c36fc336Srandyf if (mdep == NULL) { 322c36fc336Srandyf /* Didn't pass enough arguments */ 323c36fc336Srandyf return (EINVAL); 324c36fc336Srandyf } 3252df1fe9cSrandyf cpr_test_point = DEVICE_SUSPEND_TO_RAM; 3262df1fe9cSrandyf cpr_device = (major_t)atoi((char *)mdep); 3272df1fe9cSrandyf break; 3282df1fe9cSrandyf 3292df1fe9cSrandyf case AD_CPR_SUSP_DEVICES: 3302df1fe9cSrandyf cpr_test_point = FORCE_SUSPEND_TO_RAM; 3312df1fe9cSrandyf if (cpr_suspend_devices(ddi_root_node()) != DDI_SUCCESS) 3322df1fe9cSrandyf cmn_err(CE_WARN, 3332df1fe9cSrandyf "Some devices did not suspend " 3342df1fe9cSrandyf "and may be unusable"); 3352df1fe9cSrandyf (void) cpr_resume_devices(ddi_root_node(), 0); 3362df1fe9cSrandyf return (0); 3372df1fe9cSrandyf 3387c478bd9Sstevel@tonic-gate default: 3397c478bd9Sstevel@tonic-gate return (ENOTSUP); 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate 342c5c327a3SRichard Lowe if (!i_cpr_is_supported(cpr_sleeptype)) 3437c478bd9Sstevel@tonic-gate return (ENOTSUP); 3447c478bd9Sstevel@tonic-gate 345c5c327a3SRichard Lowe #if defined(__sparc) 346c5c327a3SRichard Lowe if ((cpr_sleeptype == CPR_TODISK && 347c5c327a3SRichard Lowe !cpr_is_ufs(rootvfs) && !cpr_is_zfs(rootvfs))) 348c5c327a3SRichard Lowe return (ENOTSUP); 349c5c327a3SRichard Lowe #endif 350c5c327a3SRichard Lowe 3512df1fe9cSrandyf if (fcn == AD_CHECK_SUSPEND_TO_RAM || 3522df1fe9cSrandyf fcn == DEV_CHECK_SUSPEND_TO_RAM) { 3532df1fe9cSrandyf ASSERT(i_cpr_is_supported(cpr_sleeptype)); 3542df1fe9cSrandyf return (0); 3552df1fe9cSrandyf } 3562df1fe9cSrandyf 3572df1fe9cSrandyf #if defined(__sparc) 3587c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_REUSEINIT) { 3597c478bd9Sstevel@tonic-gate if (mutex_tryenter(&cpr_slock) == 0) 3607c478bd9Sstevel@tonic-gate return (EBUSY); 3617c478bd9Sstevel@tonic-gate if (cpr_reusable_mode) { 3627c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, modefmt, "already"); 3637c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3647c478bd9Sstevel@tonic-gate return (EBUSY); 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate rc = i_cpr_reuseinit(); 3677c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3687c478bd9Sstevel@tonic-gate return (rc); 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_REUSEFINI) { 3727c478bd9Sstevel@tonic-gate if (mutex_tryenter(&cpr_slock) == 0) 3737c478bd9Sstevel@tonic-gate return (EBUSY); 3747c478bd9Sstevel@tonic-gate if (!cpr_reusable_mode) { 3757c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, modefmt, "not"); 3767c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3777c478bd9Sstevel@tonic-gate return (EINVAL); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate rc = i_cpr_reusefini(); 3807c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3817c478bd9Sstevel@tonic-gate return (rc); 3827c478bd9Sstevel@tonic-gate } 3832df1fe9cSrandyf #endif 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * acquire cpr serial lock and init cpr state structure. 3877c478bd9Sstevel@tonic-gate */ 3887c478bd9Sstevel@tonic-gate if (rc = cpr_init(fcn)) 3897c478bd9Sstevel@tonic-gate return (rc); 3907c478bd9Sstevel@tonic-gate 3912df1fe9cSrandyf #if defined(__sparc) 3927c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_REUSABLE) { 3937c478bd9Sstevel@tonic-gate if ((rc = i_cpr_check_cprinfo()) != 0) { 3947c478bd9Sstevel@tonic-gate mutex_exit(&cpr_slock); 3957c478bd9Sstevel@tonic-gate return (rc); 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate } 3982df1fe9cSrandyf #endif 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate /* 4017c478bd9Sstevel@tonic-gate * Call the main cpr routine. If we are successful, we will be coming 4027c478bd9Sstevel@tonic-gate * down from the resume side, otherwise we are still in suspend. 4037c478bd9Sstevel@tonic-gate */ 4047c478bd9Sstevel@tonic-gate cpr_err(CE_CONT, "System is being suspended"); 4052df1fe9cSrandyf if (rc = cpr_main(cpr_sleeptype)) { 4067c478bd9Sstevel@tonic-gate CPR->c_flags |= C_ERROR; 4072df1fe9cSrandyf PMD(PMD_SX, ("cpr: Suspend operation failed.\n")) 4087c478bd9Sstevel@tonic-gate cpr_err(CE_NOTE, "Suspend operation failed."); 4097c478bd9Sstevel@tonic-gate } else if (CPR->c_flags & C_SUSPENDING) { 4102df1fe9cSrandyf 4112df1fe9cSrandyf /* 4122df1fe9cSrandyf * In the suspend to RAM case, by the time we get 4132df1fe9cSrandyf * control back we're already resumed 4142df1fe9cSrandyf */ 4152df1fe9cSrandyf if (cpr_sleeptype == CPR_TORAM) { 4162df1fe9cSrandyf PMD(PMD_SX, ("cpr: cpr CPR_TORAM done\n")) 4172df1fe9cSrandyf cpr_done(); 4182df1fe9cSrandyf return (rc); 4192df1fe9cSrandyf } 4202df1fe9cSrandyf 4212df1fe9cSrandyf #if defined(__sparc) 4222df1fe9cSrandyf 4232df1fe9cSrandyf PMD(PMD_SX, ("cpr: Suspend operation succeeded.\n")) 4247c478bd9Sstevel@tonic-gate /* 4257c478bd9Sstevel@tonic-gate * Back from a successful checkpoint 4267c478bd9Sstevel@tonic-gate */ 4277c478bd9Sstevel@tonic-gate if (fcn == AD_CPR_TESTZ || fcn == AD_CPR_TESTNOZ) { 428edc40228Sachartre mdboot(0, AD_BOOT, "", B_FALSE); 4297c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* make sure there are no more changes to the device tree */ 4332df1fe9cSrandyf PMD(PMD_SX, ("cpr: dev tree freeze\n")) 4347c478bd9Sstevel@tonic-gate devtree_freeze(); 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate /* 4377c478bd9Sstevel@tonic-gate * stop other cpus and raise our priority. since there is only 4387c478bd9Sstevel@tonic-gate * one active cpu after this, and our priority will be too high 4397c478bd9Sstevel@tonic-gate * for us to be preempted, we're essentially single threaded 4407c478bd9Sstevel@tonic-gate * from here on out. 4417c478bd9Sstevel@tonic-gate */ 4422df1fe9cSrandyf PMD(PMD_SX, ("cpr: stop other cpus\n")) 4432df1fe9cSrandyf i_cpr_stop_other_cpus(); 4442df1fe9cSrandyf PMD(PMD_SX, ("cpr: spl6\n")) 4457c478bd9Sstevel@tonic-gate (void) spl6(); 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate /* 4487c478bd9Sstevel@tonic-gate * try and reset leaf devices. reset_leaves() should only 4497c478bd9Sstevel@tonic-gate * be called when there are no other threads that could be 4507c478bd9Sstevel@tonic-gate * accessing devices 4517c478bd9Sstevel@tonic-gate */ 4522df1fe9cSrandyf PMD(PMD_SX, ("cpr: reset leaves\n")) 4537c478bd9Sstevel@tonic-gate reset_leaves(); 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate /* 4562df1fe9cSrandyf * If i_cpr_power_down() succeeds, it'll not return 4577c478bd9Sstevel@tonic-gate * 4587c478bd9Sstevel@tonic-gate * Drives with write-cache enabled need to flush 4597c478bd9Sstevel@tonic-gate * their cache. 4607c478bd9Sstevel@tonic-gate */ 4612df1fe9cSrandyf if (fcn != AD_CPR_TESTHALT) { 4622df1fe9cSrandyf PMD(PMD_SX, ("cpr: power down\n")) 4632df1fe9cSrandyf (void) i_cpr_power_down(cpr_sleeptype); 4642df1fe9cSrandyf } 4652df1fe9cSrandyf ASSERT(cpr_sleeptype == CPR_TODISK); 4662df1fe9cSrandyf /* currently CPR_TODISK comes back via a boot path */ 467ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "(Done. Please Switch Off)\n"); 4687c478bd9Sstevel@tonic-gate halt(NULL); 4697c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4702df1fe9cSrandyf #endif 4717c478bd9Sstevel@tonic-gate } 4722df1fe9cSrandyf PMD(PMD_SX, ("cpr: cpr done\n")) 4737c478bd9Sstevel@tonic-gate cpr_done(); 4747c478bd9Sstevel@tonic-gate return (rc); 4757c478bd9Sstevel@tonic-gate } 476