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 /* 228fc99e42STrevor Thompson * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * This module contains the guts of checkpoint-resume mechanism. 287c478bd9Sstevel@tonic-gate * All code in this module is platform independent. 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <sys/types.h> 327c478bd9Sstevel@tonic-gate #include <sys/errno.h> 337c478bd9Sstevel@tonic-gate #include <sys/callb.h> 347c478bd9Sstevel@tonic-gate #include <sys/processor.h> 357c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 367c478bd9Sstevel@tonic-gate #include <sys/clock.h> 377c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 387c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 397c478bd9Sstevel@tonic-gate #include <nfs/lm.h> 407c478bd9Sstevel@tonic-gate #include <sys/systm.h> 417c478bd9Sstevel@tonic-gate #include <sys/cpr.h> 427c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 437c478bd9Sstevel@tonic-gate #include <sys/cyclic.h> 447c478bd9Sstevel@tonic-gate #include <sys/filio.h> 457c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_filio.h> 467c478bd9Sstevel@tonic-gate #include <sys/epm.h> 477c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 487c478bd9Sstevel@tonic-gate #include <sys/reboot.h> 497c478bd9Sstevel@tonic-gate #include <sys/kdi.h> 507c478bd9Sstevel@tonic-gate #include <sys/promif.h> 512df1fe9cSrandyf #include <sys/srn.h> 522df1fe9cSrandyf #include <sys/cpr_impl.h> 532df1fe9cSrandyf 542df1fe9cSrandyf #define PPM(dip) ((dev_info_t *)DEVI(dip)->devi_pm_ppm) 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate extern struct cpr_terminator cpr_term; 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate extern int cpr_alloc_statefile(int); 597c478bd9Sstevel@tonic-gate extern void cpr_start_kernel_threads(void); 607c478bd9Sstevel@tonic-gate extern void cpr_abbreviate_devpath(char *, char *); 617c478bd9Sstevel@tonic-gate extern void cpr_convert_promtime(cpr_time_t *); 627c478bd9Sstevel@tonic-gate extern void cpr_send_notice(void); 637c478bd9Sstevel@tonic-gate extern void cpr_set_bitmap_size(void); 647c478bd9Sstevel@tonic-gate extern void cpr_stat_init(); 657c478bd9Sstevel@tonic-gate extern void cpr_statef_close(void); 667c478bd9Sstevel@tonic-gate extern void flush_windows(void); 672df1fe9cSrandyf extern void (*srn_signal)(int, int); 682df1fe9cSrandyf extern void init_cpu_syscall(struct cpu *); 692df1fe9cSrandyf extern void i_cpr_pre_resume_cpus(); 702df1fe9cSrandyf extern void i_cpr_post_resume_cpus(); 71e7cbe64fSgw25295 extern int cpr_is_ufs(struct vfs *); 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate extern int pm_powering_down; 742df1fe9cSrandyf extern kmutex_t srn_clone_lock; 752df1fe9cSrandyf extern int srn_inuse; 767c478bd9Sstevel@tonic-gate 772df1fe9cSrandyf static int cpr_suspend(int); 782df1fe9cSrandyf static int cpr_resume(int); 792df1fe9cSrandyf static void cpr_suspend_init(int); 802df1fe9cSrandyf #if defined(__x86) 812df1fe9cSrandyf static int cpr_suspend_cpus(void); 822df1fe9cSrandyf static void cpr_resume_cpus(void); 832df1fe9cSrandyf #endif 842df1fe9cSrandyf static int cpr_all_online(void); 852df1fe9cSrandyf static void cpr_restore_offline(void); 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate cpr_time_t wholecycle_tv; 887c478bd9Sstevel@tonic-gate int cpr_suspend_succeeded; 897c478bd9Sstevel@tonic-gate pfn_t curthreadpfn; 907c478bd9Sstevel@tonic-gate int curthreadremapped; 917c478bd9Sstevel@tonic-gate 922df1fe9cSrandyf extern cpuset_t cpu_ready_set; 932df1fe9cSrandyf 942df1fe9cSrandyf extern processorid_t i_cpr_bootcpuid(void); 952df1fe9cSrandyf extern cpu_t *i_cpr_bootcpu(void); 962df1fe9cSrandyf extern void tsc_adjust_delta(hrtime_t tdelta); 972df1fe9cSrandyf extern void tsc_resume(void); 982df1fe9cSrandyf extern int tsc_resume_in_cyclic; 992df1fe9cSrandyf 1002df1fe9cSrandyf /* 1012df1fe9cSrandyf * Set this variable to 1, to have device drivers resume in an 1022df1fe9cSrandyf * uniprocessor environment. This is to allow drivers that assume 1032df1fe9cSrandyf * that they resume on a UP machine to continue to work. Should be 1042df1fe9cSrandyf * deprecated once the broken drivers are fixed 1052df1fe9cSrandyf */ 1062df1fe9cSrandyf int cpr_resume_uniproc = 0; 1072df1fe9cSrandyf 1087c478bd9Sstevel@tonic-gate /* 1097c478bd9Sstevel@tonic-gate * save or restore abort_enable; this prevents a drop 1107c478bd9Sstevel@tonic-gate * to kadb or prom during cpr_resume_devices() when 1117c478bd9Sstevel@tonic-gate * there is no kbd present; see abort_sequence_enter() 1127c478bd9Sstevel@tonic-gate */ 1137c478bd9Sstevel@tonic-gate static void 1147c478bd9Sstevel@tonic-gate cpr_sae(int stash) 1157c478bd9Sstevel@tonic-gate { 1167c478bd9Sstevel@tonic-gate static int saved_ae = -1; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate if (stash) { 1197c478bd9Sstevel@tonic-gate saved_ae = abort_enable; 1207c478bd9Sstevel@tonic-gate abort_enable = 0; 1217c478bd9Sstevel@tonic-gate } else if (saved_ae != -1) { 1227c478bd9Sstevel@tonic-gate abort_enable = saved_ae; 1237c478bd9Sstevel@tonic-gate saved_ae = -1; 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate /* 1297c478bd9Sstevel@tonic-gate * The main switching point for cpr, this routine starts the ckpt 1307c478bd9Sstevel@tonic-gate * and state file saving routines; on resume the control is 1317c478bd9Sstevel@tonic-gate * returned back to here and it then calls the resume routine. 1327c478bd9Sstevel@tonic-gate */ 1337c478bd9Sstevel@tonic-gate int 1342df1fe9cSrandyf cpr_main(int sleeptype) 1357c478bd9Sstevel@tonic-gate { 1362df1fe9cSrandyf int rc, rc2; 1372df1fe9cSrandyf label_t saveq; 1382df1fe9cSrandyf klwp_t *tlwp = ttolwp(curthread); 1397c478bd9Sstevel@tonic-gate 1402df1fe9cSrandyf if (sleeptype == CPR_TODISK) { 1412df1fe9cSrandyf if ((rc = cpr_default_setup(1)) != 0) 1427c478bd9Sstevel@tonic-gate return (rc); 1432df1fe9cSrandyf ASSERT(tlwp); 1442df1fe9cSrandyf saveq = tlwp->lwp_qsav; 1452df1fe9cSrandyf } 1462df1fe9cSrandyf 1472df1fe9cSrandyf if (sleeptype == CPR_TORAM) { 1482df1fe9cSrandyf rc = cpr_suspend(sleeptype); 1492df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend rets %x\n", rc)) 1502df1fe9cSrandyf if (rc == 0) { 1512df1fe9cSrandyf int i_cpr_power_down(int sleeptype); 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate /* 1542df1fe9cSrandyf * From this point on, we should be at a high 1552df1fe9cSrandyf * spl, interrupts disabled, and all but one 1562df1fe9cSrandyf * cpu's paused (effectively UP/single threaded). 1572df1fe9cSrandyf * So this is were we want to put ASSERTS() 1582df1fe9cSrandyf * to let us know otherwise. 1597c478bd9Sstevel@tonic-gate */ 1602df1fe9cSrandyf ASSERT(cpus_paused()); 1612df1fe9cSrandyf 1622df1fe9cSrandyf /* 1632df1fe9cSrandyf * Now do the work of actually putting this 1642df1fe9cSrandyf * machine to sleep! 1652df1fe9cSrandyf */ 1662df1fe9cSrandyf rc = i_cpr_power_down(sleeptype); 1672df1fe9cSrandyf if (rc == 0) { 168fe7cd8aaSCyril Plisko PMD(PMD_SX, ("back from successful suspend\n")) 1692df1fe9cSrandyf } 1702df1fe9cSrandyf /* 1712df1fe9cSrandyf * We do care about the return value from cpr_resume 1722df1fe9cSrandyf * at this point, as it will tell us if one of the 1732df1fe9cSrandyf * resume functions failed (cpr_resume_devices()) 1742df1fe9cSrandyf * However, for this to return and _not_ panic, means 1752df1fe9cSrandyf * that we must be in one of the test functions. So 1762df1fe9cSrandyf * check for that and return an appropriate message. 1772df1fe9cSrandyf */ 1782df1fe9cSrandyf rc2 = cpr_resume(sleeptype); 1792df1fe9cSrandyf if (rc2 != 0) { 1802df1fe9cSrandyf ASSERT(cpr_test_point > 0); 1812df1fe9cSrandyf cmn_err(CE_NOTE, 1822df1fe9cSrandyf "cpr_resume returned non-zero: %d\n", rc2); 1832df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume rets %x\n", rc2)) 1842df1fe9cSrandyf } 1852df1fe9cSrandyf ASSERT(!cpus_paused()); 1862df1fe9cSrandyf } else { 1872df1fe9cSrandyf PMD(PMD_SX, ("failed suspend, resuming\n")) 1882df1fe9cSrandyf rc = cpr_resume(sleeptype); 1892df1fe9cSrandyf } 1902df1fe9cSrandyf return (rc); 1912df1fe9cSrandyf } 1922df1fe9cSrandyf /* 1932df1fe9cSrandyf * Remember where we are for resume after reboot 1942df1fe9cSrandyf */ 1952df1fe9cSrandyf if (!setjmp(&tlwp->lwp_qsav)) { 1967c478bd9Sstevel@tonic-gate /* 1977c478bd9Sstevel@tonic-gate * try to checkpoint the system, if failed return back 1987c478bd9Sstevel@tonic-gate * to userland, otherwise power off. 1997c478bd9Sstevel@tonic-gate */ 2002df1fe9cSrandyf rc = cpr_suspend(sleeptype); 2017c478bd9Sstevel@tonic-gate if (rc || cpr_reusable_mode) { 2027c478bd9Sstevel@tonic-gate /* 2037c478bd9Sstevel@tonic-gate * We don't really want to go down, or 2047c478bd9Sstevel@tonic-gate * something went wrong in suspend, do what we can 2057c478bd9Sstevel@tonic-gate * to put the system back to an operable state then 2067c478bd9Sstevel@tonic-gate * return back to userland. 2077c478bd9Sstevel@tonic-gate */ 2082df1fe9cSrandyf PMD(PMD_SX, ("failed suspend, resuming\n")) 2092df1fe9cSrandyf (void) cpr_resume(sleeptype); 2102df1fe9cSrandyf PMD(PMD_SX, ("back from failed suspend resume\n")) 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate } else { 2137c478bd9Sstevel@tonic-gate /* 2147c478bd9Sstevel@tonic-gate * This is the resumed side of longjmp, restore the previous 2157c478bd9Sstevel@tonic-gate * longjmp pointer if there is one so this will be transparent 2167c478bd9Sstevel@tonic-gate * to the world. 2172df1fe9cSrandyf * This path is only for CPR_TODISK, where we reboot 2187c478bd9Sstevel@tonic-gate */ 2192df1fe9cSrandyf ASSERT(sleeptype == CPR_TODISK); 2202df1fe9cSrandyf tlwp->lwp_qsav = saveq; 2217c478bd9Sstevel@tonic-gate CPR->c_flags &= ~C_SUSPENDING; 2227c478bd9Sstevel@tonic-gate CPR->c_flags |= C_RESUMING; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * resume the system back to the original state 2267c478bd9Sstevel@tonic-gate */ 2272df1fe9cSrandyf rc = cpr_resume(sleeptype); 2282df1fe9cSrandyf PMD(PMD_SX, ("back from successful suspend; resume rets %x\n", 2292df1fe9cSrandyf rc)) 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate (void) cpr_default_setup(0); 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate return (rc); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate 2382df1fe9cSrandyf #if defined(__sparc) 2392df1fe9cSrandyf 2407c478bd9Sstevel@tonic-gate /* 2417c478bd9Sstevel@tonic-gate * check/disable or re-enable UFS logging 2427c478bd9Sstevel@tonic-gate */ 2437c478bd9Sstevel@tonic-gate static void 2447c478bd9Sstevel@tonic-gate cpr_log_status(int enable, int *svstat, vnode_t *vp) 2457c478bd9Sstevel@tonic-gate { 2467c478bd9Sstevel@tonic-gate int cmd, status, error; 2477c478bd9Sstevel@tonic-gate char *str, *able; 2487c478bd9Sstevel@tonic-gate fiolog_t fl; 2497c478bd9Sstevel@tonic-gate refstr_t *mntpt; 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate str = "cpr_log_status"; 2527c478bd9Sstevel@tonic-gate bzero(&fl, sizeof (fl)); 2537c478bd9Sstevel@tonic-gate fl.error = FIOLOG_ENONE; 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate /* 2567c478bd9Sstevel@tonic-gate * when disabling, first get and save logging status (0 or 1) 2577c478bd9Sstevel@tonic-gate */ 2587c478bd9Sstevel@tonic-gate if (enable == 0) { 2597c478bd9Sstevel@tonic-gate if (error = VOP_IOCTL(vp, _FIOISLOG, 260da6c28aaSamw (uintptr_t)&status, FKIOCTL, CRED(), NULL, NULL)) { 2617c478bd9Sstevel@tonic-gate mntpt = vfs_getmntpoint(vp->v_vfsp); 262ae115bc7Smrj prom_printf("%s: \"%s\", cant get logging " 263ae115bc7Smrj "status, error %d\n", str, refstr_value(mntpt), 264ae115bc7Smrj error); 2657c478bd9Sstevel@tonic-gate refstr_rele(mntpt); 2667c478bd9Sstevel@tonic-gate return; 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate *svstat = status; 269ae115bc7Smrj if (cpr_debug & CPR_DEBUG5) { 2707c478bd9Sstevel@tonic-gate mntpt = vfs_getmntpoint(vp->v_vfsp); 2712df1fe9cSrandyf errp("%s: \"%s\", logging status = %d\n", 2727c478bd9Sstevel@tonic-gate str, refstr_value(mntpt), status); 2737c478bd9Sstevel@tonic-gate refstr_rele(mntpt); 274ae115bc7Smrj }; 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate able = "disable"; 2777c478bd9Sstevel@tonic-gate cmd = _FIOLOGDISABLE; 2787c478bd9Sstevel@tonic-gate } else { 2797c478bd9Sstevel@tonic-gate able = "enable"; 2807c478bd9Sstevel@tonic-gate cmd = _FIOLOGENABLE; 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate /* 2847c478bd9Sstevel@tonic-gate * disable or re-enable logging when the saved status is 1 2857c478bd9Sstevel@tonic-gate */ 2867c478bd9Sstevel@tonic-gate if (*svstat == 1) { 2877c478bd9Sstevel@tonic-gate error = VOP_IOCTL(vp, cmd, (uintptr_t)&fl, 288da6c28aaSamw FKIOCTL, CRED(), NULL, NULL); 2897c478bd9Sstevel@tonic-gate if (error) { 2907c478bd9Sstevel@tonic-gate mntpt = vfs_getmntpoint(vp->v_vfsp); 291ae115bc7Smrj prom_printf("%s: \"%s\", cant %s logging, error %d\n", 2927c478bd9Sstevel@tonic-gate str, refstr_value(mntpt), able, error); 2937c478bd9Sstevel@tonic-gate refstr_rele(mntpt); 2947c478bd9Sstevel@tonic-gate } else { 295ae115bc7Smrj if (cpr_debug & CPR_DEBUG5) { 2967c478bd9Sstevel@tonic-gate mntpt = vfs_getmntpoint(vp->v_vfsp); 2972df1fe9cSrandyf errp("%s: \"%s\", logging is now %sd\n", 2987c478bd9Sstevel@tonic-gate str, refstr_value(mntpt), able); 2997c478bd9Sstevel@tonic-gate refstr_rele(mntpt); 3002df1fe9cSrandyf }; 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * when enabling logging, reset the saved status 3067c478bd9Sstevel@tonic-gate * to unknown for next time 3077c478bd9Sstevel@tonic-gate */ 3087c478bd9Sstevel@tonic-gate if (enable) 3097c478bd9Sstevel@tonic-gate *svstat = -1; 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * enable/disable UFS logging on filesystems containing cpr_default_path 3147c478bd9Sstevel@tonic-gate * and cpr statefile. since the statefile can be on any fs, that fs 3157c478bd9Sstevel@tonic-gate * needs to be handled separately. this routine and cprboot expect that 3167c478bd9Sstevel@tonic-gate * CPR_CONFIG and CPR_DEFAULT both reside on the same fs, rootfs. cprboot 3177c478bd9Sstevel@tonic-gate * is loaded from the device with rootfs and uses the same device to open 3187c478bd9Sstevel@tonic-gate * both CPR_CONFIG and CPR_DEFAULT (see common/support.c). moving either 3197c478bd9Sstevel@tonic-gate * file outside of rootfs would cause errors during cprboot, plus cpr and 3207c478bd9Sstevel@tonic-gate * fsck problems with the new fs if logging were enabled. 3217c478bd9Sstevel@tonic-gate */ 3222df1fe9cSrandyf 3237c478bd9Sstevel@tonic-gate static int 3247c478bd9Sstevel@tonic-gate cpr_ufs_logging(int enable) 3257c478bd9Sstevel@tonic-gate { 3267c478bd9Sstevel@tonic-gate static int def_status = -1, sf_status = -1; 3277c478bd9Sstevel@tonic-gate struct vfs *vfsp; 3287c478bd9Sstevel@tonic-gate char *fname; 3297c478bd9Sstevel@tonic-gate vnode_t *vp; 3307c478bd9Sstevel@tonic-gate int error; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate if (cpr_reusable_mode) 3337c478bd9Sstevel@tonic-gate return (0); 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate if (error = cpr_open_deffile(FREAD, &vp)) 3367c478bd9Sstevel@tonic-gate return (error); 3377c478bd9Sstevel@tonic-gate vfsp = vp->v_vfsp; 338e7cbe64fSgw25295 if (!cpr_is_ufs(vfsp)) { 339e7cbe64fSgw25295 (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL); 340e7cbe64fSgw25295 VN_RELE(vp); 341e7cbe64fSgw25295 return (0); 342e7cbe64fSgw25295 } 343e7cbe64fSgw25295 344e7cbe64fSgw25295 cpr_log_status(enable, &def_status, vp); 345da6c28aaSamw (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL); 3467c478bd9Sstevel@tonic-gate VN_RELE(vp); 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate fname = cpr_build_statefile_path(); 3497c478bd9Sstevel@tonic-gate if (fname == NULL) 3507c478bd9Sstevel@tonic-gate return (ENOENT); 3517c478bd9Sstevel@tonic-gate if (error = vn_open(fname, UIO_SYSSPACE, FCREAT|FWRITE, 3527c478bd9Sstevel@tonic-gate 0600, &vp, CRCREAT, 0)) { 353ae115bc7Smrj prom_printf("cpr_ufs_logging: cant open/create \"%s\", " 354ae115bc7Smrj "error %d\n", fname, error); 3557c478bd9Sstevel@tonic-gate return (error); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* 3597c478bd9Sstevel@tonic-gate * check logging status for the statefile if it resides 3607c478bd9Sstevel@tonic-gate * on a different fs and the type is a regular file 3617c478bd9Sstevel@tonic-gate */ 3627c478bd9Sstevel@tonic-gate if (vp->v_vfsp != vfsp && vp->v_type == VREG) 3637c478bd9Sstevel@tonic-gate cpr_log_status(enable, &sf_status, vp); 364da6c28aaSamw (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL); 3657c478bd9Sstevel@tonic-gate VN_RELE(vp); 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate return (0); 3687c478bd9Sstevel@tonic-gate } 3692df1fe9cSrandyf #endif 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate /* 3737c478bd9Sstevel@tonic-gate * Check if klmmod is loaded and call a lock manager service; if klmmod 3747c478bd9Sstevel@tonic-gate * is not loaded, the services aren't needed and a call would trigger a 3757c478bd9Sstevel@tonic-gate * modload, which would block since another thread would never run. 3767c478bd9Sstevel@tonic-gate */ 3777c478bd9Sstevel@tonic-gate static void 3787c478bd9Sstevel@tonic-gate cpr_lock_mgr(void (*service)(void)) 3797c478bd9Sstevel@tonic-gate { 3807c478bd9Sstevel@tonic-gate if (mod_find_by_filename(NULL, "misc/klmmod") != NULL) 3817c478bd9Sstevel@tonic-gate (*service)(); 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate 3842df1fe9cSrandyf int 3852df1fe9cSrandyf cpr_suspend_cpus(void) 3862df1fe9cSrandyf { 3872df1fe9cSrandyf int ret = 0; 3882df1fe9cSrandyf extern void *i_cpr_save_context(void *arg); 3892df1fe9cSrandyf 3902df1fe9cSrandyf mutex_enter(&cpu_lock); 3912df1fe9cSrandyf 3922df1fe9cSrandyf /* 3932df1fe9cSrandyf * the machine could not have booted without a bootcpu 3942df1fe9cSrandyf */ 3954716fd88Sjan ASSERT(i_cpr_bootcpu() != NULL); 3962df1fe9cSrandyf 3972df1fe9cSrandyf /* 3982df1fe9cSrandyf * bring all the offline cpus online 3992df1fe9cSrandyf */ 4002df1fe9cSrandyf if ((ret = cpr_all_online())) { 4012df1fe9cSrandyf mutex_exit(&cpu_lock); 4022df1fe9cSrandyf return (ret); 4032df1fe9cSrandyf } 4042df1fe9cSrandyf 4052df1fe9cSrandyf /* 4062df1fe9cSrandyf * Set the affinity to be the boot processor 4072df1fe9cSrandyf * This is cleared in either cpr_resume_cpus() or cpr_unpause_cpus() 4082df1fe9cSrandyf */ 4092df1fe9cSrandyf affinity_set(i_cpr_bootcpuid()); 4102df1fe9cSrandyf 4112df1fe9cSrandyf ASSERT(CPU->cpu_id == 0); 4122df1fe9cSrandyf 4132df1fe9cSrandyf PMD(PMD_SX, ("curthread running on bootcpu\n")) 4142df1fe9cSrandyf 4152df1fe9cSrandyf /* 4162df1fe9cSrandyf * pause all other running CPUs and save the CPU state at the sametime 4172df1fe9cSrandyf */ 418*0ed5c46eSJosef 'Jeff' Sipek pause_cpus(NULL, i_cpr_save_context); 4192df1fe9cSrandyf 4202df1fe9cSrandyf mutex_exit(&cpu_lock); 4212df1fe9cSrandyf 4222df1fe9cSrandyf return (0); 4232df1fe9cSrandyf } 4242df1fe9cSrandyf 4257c478bd9Sstevel@tonic-gate /* 4267c478bd9Sstevel@tonic-gate * Take the system down to a checkpointable state and write 4277c478bd9Sstevel@tonic-gate * the state file, the following are sequentially executed: 4287c478bd9Sstevel@tonic-gate * 4297c478bd9Sstevel@tonic-gate * - Request all user threads to stop themselves 4307c478bd9Sstevel@tonic-gate * - push out and invalidate user pages 4317c478bd9Sstevel@tonic-gate * - bring statefile inode incore to prevent a miss later 4327c478bd9Sstevel@tonic-gate * - request all daemons to stop 4337c478bd9Sstevel@tonic-gate * - check and make sure all threads are stopped 4347c478bd9Sstevel@tonic-gate * - sync the file system 4357c478bd9Sstevel@tonic-gate * - suspend all devices 4367c478bd9Sstevel@tonic-gate * - block intrpts 4377c478bd9Sstevel@tonic-gate * - dump system state and memory to state file 4382df1fe9cSrandyf * - SPARC code will not be called with CPR_TORAM, caller filters 4397c478bd9Sstevel@tonic-gate */ 4407c478bd9Sstevel@tonic-gate static int 4412df1fe9cSrandyf cpr_suspend(int sleeptype) 4427c478bd9Sstevel@tonic-gate { 4432df1fe9cSrandyf #if defined(__sparc) 4442df1fe9cSrandyf int sf_realloc, nverr; 4452df1fe9cSrandyf #endif 4462df1fe9cSrandyf int rc = 0; 4472df1fe9cSrandyf int skt_rc = 0; 4487c478bd9Sstevel@tonic-gate 4492df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend %x\n", sleeptype)) 4507c478bd9Sstevel@tonic-gate cpr_set_substate(C_ST_SUSPEND_BEGIN); 4517c478bd9Sstevel@tonic-gate 4522df1fe9cSrandyf cpr_suspend_init(sleeptype); 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate cpr_save_time(); 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate cpr_tod_get(&wholecycle_tv); 4577c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_START("Suspend Total"); 4587c478bd9Sstevel@tonic-gate 4592df1fe9cSrandyf i_cpr_alloc_cpus(); 4602df1fe9cSrandyf 4612df1fe9cSrandyf #if defined(__sparc) 4622df1fe9cSrandyf ASSERT(sleeptype == CPR_TODISK); 4637c478bd9Sstevel@tonic-gate if (!cpr_reusable_mode) { 4647c478bd9Sstevel@tonic-gate /* 4652df1fe9cSrandyf * We need to validate default file before fs 4662df1fe9cSrandyf * functionality is disabled. 4677c478bd9Sstevel@tonic-gate */ 4687c478bd9Sstevel@tonic-gate if (rc = cpr_validate_definfo(0)) 4697c478bd9Sstevel@tonic-gate return (rc); 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate i_cpr_save_machdep_info(); 4722df1fe9cSrandyf #endif 4737c478bd9Sstevel@tonic-gate 4742df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: stop scans\n")) 4757c478bd9Sstevel@tonic-gate /* Stop PM scans ASAP */ 4767c478bd9Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PM, CB_CODE_CPR_CHKPT); 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_CPR_SUSPEND, 4797c478bd9Sstevel@tonic-gate NULL, NULL, PM_DEP_WAIT, NULL, 0); 4807c478bd9Sstevel@tonic-gate 4812df1fe9cSrandyf #if defined(__sparc) 4822df1fe9cSrandyf ASSERT(sleeptype == CPR_TODISK); 4837c478bd9Sstevel@tonic-gate cpr_set_substate(C_ST_MP_OFFLINE); 4847c478bd9Sstevel@tonic-gate if (rc = cpr_mp_offline()) 4857c478bd9Sstevel@tonic-gate return (rc); 4862df1fe9cSrandyf #endif 4872df1fe9cSrandyf /* 4882df1fe9cSrandyf * Ask Xorg to suspend the frame buffer, and wait for it to happen 4892df1fe9cSrandyf */ 4902df1fe9cSrandyf mutex_enter(&srn_clone_lock); 4912df1fe9cSrandyf if (srn_signal) { 4922df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: (*srn_signal)(..., " 4932df1fe9cSrandyf "SRN_SUSPEND_REQ)\n")) 4942df1fe9cSrandyf srn_inuse = 1; /* because *(srn_signal) cv_waits */ 4952df1fe9cSrandyf (*srn_signal)(SRN_TYPE_APM, SRN_SUSPEND_REQ); 4962df1fe9cSrandyf srn_inuse = 0; 4972df1fe9cSrandyf } else { 4982df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: srn_signal NULL\n")) 4992df1fe9cSrandyf } 5002df1fe9cSrandyf mutex_exit(&srn_clone_lock); 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate /* 5037c478bd9Sstevel@tonic-gate * Ask the user threads to stop by themselves, but 5047c478bd9Sstevel@tonic-gate * if they don't or can't after 3 retries, we give up on CPR. 5057c478bd9Sstevel@tonic-gate * The 3 retry is not a random number because 2 is possible if 5067c478bd9Sstevel@tonic-gate * a thread has been forked before the parent thread is stopped. 5077c478bd9Sstevel@tonic-gate */ 508ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "\nstopping user threads..."); 5097c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_START(" stop users"); 5107c478bd9Sstevel@tonic-gate cpr_set_substate(C_ST_STOP_USER_THREADS); 5112df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: stop user threads\n")) 5127c478bd9Sstevel@tonic-gate if (rc = cpr_stop_user_threads()) 5137c478bd9Sstevel@tonic-gate return (rc); 5147c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END(" stop users"); 515ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "done\n"); 5167c478bd9Sstevel@tonic-gate 5172df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: save direct levels\n")) 5187c478bd9Sstevel@tonic-gate pm_save_direct_levels(); 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate /* 5217c478bd9Sstevel@tonic-gate * User threads are stopped. We will start communicating with the 5227c478bd9Sstevel@tonic-gate * user via prom_printf (some debug output may have already happened) 5237c478bd9Sstevel@tonic-gate * so let anybody who cares know about this (bug 4096122) 5247c478bd9Sstevel@tonic-gate */ 5257c478bd9Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PROMPRINTF, CB_CODE_CPR_CHKPT); 5267c478bd9Sstevel@tonic-gate 5272df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: send notice\n")) 5282df1fe9cSrandyf #ifndef DEBUG 5297c478bd9Sstevel@tonic-gate cpr_send_notice(); 5307c478bd9Sstevel@tonic-gate if (cpr_debug) 531ae115bc7Smrj prom_printf("\n"); 5322df1fe9cSrandyf #endif 5337c478bd9Sstevel@tonic-gate 5342df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: POST USER callback\n")) 5357c478bd9Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_USER, CB_CODE_CPR_CHKPT); 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate /* 5387c478bd9Sstevel@tonic-gate * Reattach any drivers which originally exported the 5397c478bd9Sstevel@tonic-gate * no-involuntary-power-cycles property. We need to do this before 5407c478bd9Sstevel@tonic-gate * stopping kernel threads because modload is implemented using 5417c478bd9Sstevel@tonic-gate * a kernel thread. 5427c478bd9Sstevel@tonic-gate */ 5437c478bd9Sstevel@tonic-gate cpr_set_substate(C_ST_PM_REATTACH_NOINVOL); 5442df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: reattach noinvol\n")) 5457c478bd9Sstevel@tonic-gate if (!pm_reattach_noinvol()) 5467c478bd9Sstevel@tonic-gate return (ENXIO); 5477c478bd9Sstevel@tonic-gate 5482df1fe9cSrandyf #if defined(__sparc) 5492df1fe9cSrandyf ASSERT(sleeptype == CPR_TODISK); 5507c478bd9Sstevel@tonic-gate /* 5517c478bd9Sstevel@tonic-gate * if ufs logging is enabled, we need to disable before 5527c478bd9Sstevel@tonic-gate * stopping kernel threads so that ufs delete and roll 5537c478bd9Sstevel@tonic-gate * threads can do the work. 5547c478bd9Sstevel@tonic-gate */ 5557c478bd9Sstevel@tonic-gate cpr_set_substate(C_ST_DISABLE_UFS_LOGGING); 5567c478bd9Sstevel@tonic-gate if (rc = cpr_ufs_logging(0)) 5577c478bd9Sstevel@tonic-gate return (rc); 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate /* 5607c478bd9Sstevel@tonic-gate * Use sync_all to swap out all user pages and find out how much 5617c478bd9Sstevel@tonic-gate * extra space needed for user pages that don't have back store 5627c478bd9Sstevel@tonic-gate * space left. 5637c478bd9Sstevel@tonic-gate */ 5647c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_START(" swapout upages"); 5657c478bd9Sstevel@tonic-gate vfs_sync(SYNC_ALL); 5667c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END(" swapout upages"); 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate cpr_set_bitmap_size(); 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate alloc_statefile: 5717c478bd9Sstevel@tonic-gate /* 5722df1fe9cSrandyf * If our last state was C_ST_DUMP_NOSPC, we're trying to 5732df1fe9cSrandyf * realloc the statefile, otherwise this is the first attempt. 5747c478bd9Sstevel@tonic-gate */ 5757c478bd9Sstevel@tonic-gate sf_realloc = (CPR->c_substate == C_ST_DUMP_NOSPC) ? 1 : 0; 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_START(" alloc statefile"); 5787c478bd9Sstevel@tonic-gate cpr_set_substate(C_ST_STATEF_ALLOC); 5797c478bd9Sstevel@tonic-gate if (rc = cpr_alloc_statefile(sf_realloc)) { 5807c478bd9Sstevel@tonic-gate if (sf_realloc) 5812df1fe9cSrandyf errp("realloc failed\n"); 5827c478bd9Sstevel@tonic-gate return (rc); 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END(" alloc statefile"); 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate /* 5877c478bd9Sstevel@tonic-gate * Sync the filesystem to preserve its integrity. 5887c478bd9Sstevel@tonic-gate * 5892df1fe9cSrandyf * This sync is also used to flush out all B_DELWRI buffers 5902df1fe9cSrandyf * (fs cache) which are mapped and neither dirty nor referenced 5912df1fe9cSrandyf * before cpr_invalidate_pages destroys them. 5922df1fe9cSrandyf * fsflush does similar thing. 5937c478bd9Sstevel@tonic-gate */ 5947c478bd9Sstevel@tonic-gate sync(); 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate /* 5977c478bd9Sstevel@tonic-gate * destroy all clean file mapped kernel pages 5987c478bd9Sstevel@tonic-gate */ 5997c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_START(" clean pages"); 6002df1fe9cSrandyf CPR_DEBUG(CPR_DEBUG1, ("cleaning up mapped pages...")); 6017c478bd9Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_VM, CB_CODE_CPR_CHKPT); 6022df1fe9cSrandyf CPR_DEBUG(CPR_DEBUG1, ("done\n")); 6037c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END(" clean pages"); 6042df1fe9cSrandyf #endif 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate /* 6087c478bd9Sstevel@tonic-gate * Hooks needed by lock manager prior to suspending. 6097c478bd9Sstevel@tonic-gate * Refer to code for more comments. 6107c478bd9Sstevel@tonic-gate */ 6112df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: lock mgr\n")) 6127c478bd9Sstevel@tonic-gate cpr_lock_mgr(lm_cprsuspend); 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate /* 6157c478bd9Sstevel@tonic-gate * Now suspend all the devices 6167c478bd9Sstevel@tonic-gate */ 6177c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_START(" stop drivers"); 618ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "suspending drivers..."); 6197c478bd9Sstevel@tonic-gate cpr_set_substate(C_ST_SUSPEND_DEVICES); 6207c478bd9Sstevel@tonic-gate pm_powering_down = 1; 6212df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: suspending devices\n")) 6227c478bd9Sstevel@tonic-gate rc = cpr_suspend_devices(ddi_root_node()); 6237c478bd9Sstevel@tonic-gate pm_powering_down = 0; 6247c478bd9Sstevel@tonic-gate if (rc) 6257c478bd9Sstevel@tonic-gate return (rc); 626ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "done\n"); 6277c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END(" stop drivers"); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate /* 6307c478bd9Sstevel@tonic-gate * Stop all daemon activities 6317c478bd9Sstevel@tonic-gate */ 6327c478bd9Sstevel@tonic-gate cpr_set_substate(C_ST_STOP_KERNEL_THREADS); 6332df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: stopping kernel threads\n")) 6347c478bd9Sstevel@tonic-gate if (skt_rc = cpr_stop_kernel_threads()) 6357c478bd9Sstevel@tonic-gate return (skt_rc); 6367c478bd9Sstevel@tonic-gate 6372df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: POST KERNEL callback\n")) 6387c478bd9Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_KERNEL, CB_CODE_CPR_CHKPT); 6397c478bd9Sstevel@tonic-gate 6402df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: reattach noinvol fini\n")) 6417c478bd9Sstevel@tonic-gate pm_reattach_noinvol_fini(); 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate cpr_sae(1); 6447c478bd9Sstevel@tonic-gate 6452df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: CPR CALLOUT callback\n")) 6467c478bd9Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_CALLOUT, CB_CODE_CPR_CHKPT); 6477c478bd9Sstevel@tonic-gate 6482df1fe9cSrandyf if (sleeptype == CPR_TODISK) { 6497c478bd9Sstevel@tonic-gate /* 6507c478bd9Sstevel@tonic-gate * It's safer to do tod_get before we disable all intr. 6517c478bd9Sstevel@tonic-gate */ 6527c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_START(" write statefile"); 6532df1fe9cSrandyf } 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate /* 6567c478bd9Sstevel@tonic-gate * it's time to ignore the outside world, stop the real time 6577c478bd9Sstevel@tonic-gate * clock and disable any further intrpt activity. 6587c478bd9Sstevel@tonic-gate */ 6592df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: handle xc\n")) 6607c478bd9Sstevel@tonic-gate i_cpr_handle_xc(1); /* turn it on to disable xc assertion */ 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 6632df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: cyclic suspend\n")) 6647c478bd9Sstevel@tonic-gate cyclic_suspend(); 6657c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 6667c478bd9Sstevel@tonic-gate 6672df1fe9cSrandyf /* 6682df1fe9cSrandyf * Due to the different methods of resuming the system between 6692df1fe9cSrandyf * CPR_TODISK (boot cprboot on SPARC, which reloads kernel image) 6702df1fe9cSrandyf * and CPR_TORAM (restart via reset into existing kernel image) 6712df1fe9cSrandyf * cpus are not suspended and restored in the SPARC case, since it 6722df1fe9cSrandyf * is necessary to restart the cpus and pause them before restoring 6732df1fe9cSrandyf * the OBP image 6742df1fe9cSrandyf */ 6757c478bd9Sstevel@tonic-gate 6762df1fe9cSrandyf #if defined(__x86) 6772df1fe9cSrandyf 6782df1fe9cSrandyf /* pause aux cpus */ 6792df1fe9cSrandyf PMD(PMD_SX, ("pause aux cpus\n")) 6802df1fe9cSrandyf 6812df1fe9cSrandyf cpr_set_substate(C_ST_MP_PAUSED); 6822df1fe9cSrandyf 6832df1fe9cSrandyf if ((rc = cpr_suspend_cpus()) != 0) 6842df1fe9cSrandyf return (rc); 6852df1fe9cSrandyf #endif 6862df1fe9cSrandyf 6872df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: stop intr\n")) 6887c478bd9Sstevel@tonic-gate i_cpr_stop_intr(); 689ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "interrupt is stopped\n"); 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /* 6927c478bd9Sstevel@tonic-gate * Since we will now disable the mechanism that causes prom_printfs 6937c478bd9Sstevel@tonic-gate * to power up (if needed) the console fb/monitor, we assert that 6947c478bd9Sstevel@tonic-gate * it must be up now. 6957c478bd9Sstevel@tonic-gate */ 6967c478bd9Sstevel@tonic-gate ASSERT(pm_cfb_is_up()); 6972df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: prom suspend prepost\n")) 6987c478bd9Sstevel@tonic-gate prom_suspend_prepost(); 6997c478bd9Sstevel@tonic-gate 7002df1fe9cSrandyf #if defined(__sparc) 7017c478bd9Sstevel@tonic-gate /* 7027c478bd9Sstevel@tonic-gate * getting ready to write ourself out, flush the register 7037c478bd9Sstevel@tonic-gate * windows to make sure that our stack is good when we 7047c478bd9Sstevel@tonic-gate * come back on the resume side. 7057c478bd9Sstevel@tonic-gate */ 7067c478bd9Sstevel@tonic-gate flush_windows(); 7072df1fe9cSrandyf #endif 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate /* 7102df1fe9cSrandyf * For S3, we're done 7112df1fe9cSrandyf */ 7122df1fe9cSrandyf if (sleeptype == CPR_TORAM) { 7132df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend rets %x\n", rc)) 7142df1fe9cSrandyf cpr_set_substate(C_ST_NODUMP); 7152df1fe9cSrandyf return (rc); 7162df1fe9cSrandyf } 7172df1fe9cSrandyf #if defined(__sparc) 7182df1fe9cSrandyf /* 7197c478bd9Sstevel@tonic-gate * FATAL: NO MORE MEMORY ALLOCATION ALLOWED AFTER THIS POINT!!! 7207c478bd9Sstevel@tonic-gate * 7217c478bd9Sstevel@tonic-gate * The system is quiesced at this point, we are ready to either dump 7227c478bd9Sstevel@tonic-gate * to the state file for a extended sleep or a simple shutdown for 7237c478bd9Sstevel@tonic-gate * systems with non-volatile memory. 7247c478bd9Sstevel@tonic-gate */ 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate /* 7277c478bd9Sstevel@tonic-gate * special handling for reusable: 7287c478bd9Sstevel@tonic-gate */ 7297c478bd9Sstevel@tonic-gate if (cpr_reusable_mode) { 7307c478bd9Sstevel@tonic-gate cpr_set_substate(C_ST_SETPROPS_1); 7317c478bd9Sstevel@tonic-gate if (nverr = cpr_set_properties(1)) 7327c478bd9Sstevel@tonic-gate return (nverr); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate cpr_set_substate(C_ST_DUMP); 7367c478bd9Sstevel@tonic-gate rc = cpr_dump(C_VP); 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate /* 739da6c28aaSamw * if any error occurred during dump, more 7407c478bd9Sstevel@tonic-gate * special handling for reusable: 7417c478bd9Sstevel@tonic-gate */ 7427c478bd9Sstevel@tonic-gate if (rc && cpr_reusable_mode) { 7437c478bd9Sstevel@tonic-gate cpr_set_substate(C_ST_SETPROPS_0); 7447c478bd9Sstevel@tonic-gate if (nverr = cpr_set_properties(0)) 7457c478bd9Sstevel@tonic-gate return (nverr); 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate if (rc == ENOSPC) { 7497c478bd9Sstevel@tonic-gate cpr_set_substate(C_ST_DUMP_NOSPC); 7502df1fe9cSrandyf (void) cpr_resume(sleeptype); 7517c478bd9Sstevel@tonic-gate goto alloc_statefile; 7527c478bd9Sstevel@tonic-gate } else if (rc == 0) { 7537c478bd9Sstevel@tonic-gate if (cpr_reusable_mode) { 7547c478bd9Sstevel@tonic-gate cpr_set_substate(C_ST_REUSABLE); 7557c478bd9Sstevel@tonic-gate longjmp(&ttolwp(curthread)->lwp_qsav); 7567c478bd9Sstevel@tonic-gate } else 7577c478bd9Sstevel@tonic-gate rc = cpr_set_properties(1); 7587c478bd9Sstevel@tonic-gate } 7592df1fe9cSrandyf #endif 7602df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: return %d\n", rc)) 7617c478bd9Sstevel@tonic-gate return (rc); 7627c478bd9Sstevel@tonic-gate } 7637c478bd9Sstevel@tonic-gate 7642df1fe9cSrandyf void 7652df1fe9cSrandyf cpr_resume_cpus(void) 7662df1fe9cSrandyf { 7672df1fe9cSrandyf /* 7682df1fe9cSrandyf * this is a cut down version of start_other_cpus() 7692df1fe9cSrandyf * just do the initialization to wake the other cpus 7702df1fe9cSrandyf */ 7712df1fe9cSrandyf 7722df1fe9cSrandyf #if defined(__x86) 7732df1fe9cSrandyf /* 7742df1fe9cSrandyf * Initialize our syscall handlers 7752df1fe9cSrandyf */ 7762df1fe9cSrandyf init_cpu_syscall(CPU); 7772df1fe9cSrandyf 7782df1fe9cSrandyf #endif 7792df1fe9cSrandyf 7802df1fe9cSrandyf i_cpr_pre_resume_cpus(); 7812df1fe9cSrandyf 7822df1fe9cSrandyf /* 7832df1fe9cSrandyf * Restart the paused cpus 7842df1fe9cSrandyf */ 7852df1fe9cSrandyf mutex_enter(&cpu_lock); 7862df1fe9cSrandyf start_cpus(); 7872df1fe9cSrandyf mutex_exit(&cpu_lock); 7882df1fe9cSrandyf 7892df1fe9cSrandyf i_cpr_post_resume_cpus(); 7902df1fe9cSrandyf 7912df1fe9cSrandyf mutex_enter(&cpu_lock); 7922df1fe9cSrandyf /* 7932df1fe9cSrandyf * clear the affinity set in cpr_suspend_cpus() 7942df1fe9cSrandyf */ 7952df1fe9cSrandyf affinity_clear(); 7962df1fe9cSrandyf 7974716fd88Sjan /* 7984716fd88Sjan * offline all the cpus that were brought online during suspend 7994716fd88Sjan */ 8004716fd88Sjan cpr_restore_offline(); 8014716fd88Sjan 8022df1fe9cSrandyf mutex_exit(&cpu_lock); 8032df1fe9cSrandyf } 8042df1fe9cSrandyf 8052df1fe9cSrandyf void 8062df1fe9cSrandyf cpr_unpause_cpus(void) 8072df1fe9cSrandyf { 8082df1fe9cSrandyf /* 8092df1fe9cSrandyf * Now restore the system back to what it was before we suspended 8102df1fe9cSrandyf */ 8112df1fe9cSrandyf 8122df1fe9cSrandyf PMD(PMD_SX, ("cpr_unpause_cpus: restoring system\n")) 8132df1fe9cSrandyf 8142df1fe9cSrandyf mutex_enter(&cpu_lock); 8152df1fe9cSrandyf /* 8162df1fe9cSrandyf * Restart the paused cpus 8172df1fe9cSrandyf */ 8182df1fe9cSrandyf start_cpus(); 8192df1fe9cSrandyf 8202df1fe9cSrandyf /* 8212df1fe9cSrandyf * clear the affinity set in cpr_suspend_cpus() 8222df1fe9cSrandyf */ 8232df1fe9cSrandyf affinity_clear(); 8242df1fe9cSrandyf 8254716fd88Sjan /* 8264716fd88Sjan * offline all the cpus that were brought online during suspend 8274716fd88Sjan */ 8284716fd88Sjan cpr_restore_offline(); 8294716fd88Sjan 8302df1fe9cSrandyf mutex_exit(&cpu_lock); 8312df1fe9cSrandyf } 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate /* 8347c478bd9Sstevel@tonic-gate * Bring the system back up from a checkpoint, at this point 8357c478bd9Sstevel@tonic-gate * the VM has been minimally restored by boot, the following 8367c478bd9Sstevel@tonic-gate * are executed sequentially: 8377c478bd9Sstevel@tonic-gate * 8387c478bd9Sstevel@tonic-gate * - machdep setup and enable interrupts (mp startup if it's mp) 8397c478bd9Sstevel@tonic-gate * - resume all devices 8407c478bd9Sstevel@tonic-gate * - restart daemons 8417c478bd9Sstevel@tonic-gate * - put all threads back on run queue 8427c478bd9Sstevel@tonic-gate */ 8437c478bd9Sstevel@tonic-gate static int 8442df1fe9cSrandyf cpr_resume(int sleeptype) 8457c478bd9Sstevel@tonic-gate { 8467c478bd9Sstevel@tonic-gate cpr_time_t pwron_tv, *ctp; 8477c478bd9Sstevel@tonic-gate char *str; 8487c478bd9Sstevel@tonic-gate int rc = 0; 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate /* 8517c478bd9Sstevel@tonic-gate * The following switch is used to resume the system 8527c478bd9Sstevel@tonic-gate * that was suspended to a different level. 8537c478bd9Sstevel@tonic-gate */ 854ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "\nEntering cpr_resume...\n"); 8552df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume %x\n", sleeptype)) 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate /* 8587c478bd9Sstevel@tonic-gate * Note: 8597c478bd9Sstevel@tonic-gate * 8607c478bd9Sstevel@tonic-gate * The rollback labels rb_xyz do not represent the cpr resume 8617c478bd9Sstevel@tonic-gate * state when event 'xyz' has happened. Instead they represent 8627c478bd9Sstevel@tonic-gate * the state during cpr suspend when event 'xyz' was being 8637c478bd9Sstevel@tonic-gate * entered (and where cpr suspend failed). The actual call that 8647c478bd9Sstevel@tonic-gate * failed may also need to be partially rolled back, since they 8657c478bd9Sstevel@tonic-gate * aren't atomic in most cases. In other words, rb_xyz means 8667c478bd9Sstevel@tonic-gate * "roll back all cpr suspend events that happened before 'xyz', 8677c478bd9Sstevel@tonic-gate * and the one that caused the failure, if necessary." 8687c478bd9Sstevel@tonic-gate */ 8697c478bd9Sstevel@tonic-gate switch (CPR->c_substate) { 8702df1fe9cSrandyf #if defined(__sparc) 8717c478bd9Sstevel@tonic-gate case C_ST_DUMP: 8727c478bd9Sstevel@tonic-gate /* 8737c478bd9Sstevel@tonic-gate * This is most likely a full-fledged cpr_resume after 8747c478bd9Sstevel@tonic-gate * a complete and successful cpr suspend. Just roll back 8757c478bd9Sstevel@tonic-gate * everything. 8767c478bd9Sstevel@tonic-gate */ 8772df1fe9cSrandyf ASSERT(sleeptype == CPR_TODISK); 8787c478bd9Sstevel@tonic-gate break; 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate case C_ST_REUSABLE: 8817c478bd9Sstevel@tonic-gate case C_ST_DUMP_NOSPC: 8827c478bd9Sstevel@tonic-gate case C_ST_SETPROPS_0: 8837c478bd9Sstevel@tonic-gate case C_ST_SETPROPS_1: 8847c478bd9Sstevel@tonic-gate /* 8857c478bd9Sstevel@tonic-gate * C_ST_REUSABLE and C_ST_DUMP_NOSPC are the only two 8867c478bd9Sstevel@tonic-gate * special switch cases here. The other two do not have 8877c478bd9Sstevel@tonic-gate * any state change during cpr_suspend() that needs to 8887c478bd9Sstevel@tonic-gate * be rolled back. But these are exit points from 8897c478bd9Sstevel@tonic-gate * cpr_suspend, so theoretically (or in the future), it 8907c478bd9Sstevel@tonic-gate * is possible that a need for roll back of a state 8917c478bd9Sstevel@tonic-gate * change arises between these exit points. 8927c478bd9Sstevel@tonic-gate */ 8932df1fe9cSrandyf ASSERT(sleeptype == CPR_TODISK); 8947c478bd9Sstevel@tonic-gate goto rb_dump; 8952df1fe9cSrandyf #endif 8962df1fe9cSrandyf 8972df1fe9cSrandyf case C_ST_NODUMP: 8982df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: NODUMP\n")) 8992df1fe9cSrandyf goto rb_nodump; 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate case C_ST_STOP_KERNEL_THREADS: 9022df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: STOP_KERNEL_THREADS\n")) 9037c478bd9Sstevel@tonic-gate goto rb_stop_kernel_threads; 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate case C_ST_SUSPEND_DEVICES: 9062df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: SUSPEND_DEVICES\n")) 9077c478bd9Sstevel@tonic-gate goto rb_suspend_devices; 9087c478bd9Sstevel@tonic-gate 9092df1fe9cSrandyf #if defined(__sparc) 9107c478bd9Sstevel@tonic-gate case C_ST_STATEF_ALLOC: 9112df1fe9cSrandyf ASSERT(sleeptype == CPR_TODISK); 9127c478bd9Sstevel@tonic-gate goto rb_statef_alloc; 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate case C_ST_DISABLE_UFS_LOGGING: 9152df1fe9cSrandyf ASSERT(sleeptype == CPR_TODISK); 9167c478bd9Sstevel@tonic-gate goto rb_disable_ufs_logging; 9172df1fe9cSrandyf #endif 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate case C_ST_PM_REATTACH_NOINVOL: 9202df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: REATTACH_NOINVOL\n")) 9217c478bd9Sstevel@tonic-gate goto rb_pm_reattach_noinvol; 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate case C_ST_STOP_USER_THREADS: 9242df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: STOP_USER_THREADS\n")) 9257c478bd9Sstevel@tonic-gate goto rb_stop_user_threads; 9267c478bd9Sstevel@tonic-gate 9272df1fe9cSrandyf #if defined(__sparc) 9287c478bd9Sstevel@tonic-gate case C_ST_MP_OFFLINE: 9292df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: MP_OFFLINE\n")) 9307c478bd9Sstevel@tonic-gate goto rb_mp_offline; 9312df1fe9cSrandyf #endif 9322df1fe9cSrandyf 9332df1fe9cSrandyf #if defined(__x86) 9342df1fe9cSrandyf case C_ST_MP_PAUSED: 9352df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: MP_PAUSED\n")) 9362df1fe9cSrandyf goto rb_mp_paused; 9372df1fe9cSrandyf #endif 9382df1fe9cSrandyf 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate default: 9412df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: others\n")) 9427c478bd9Sstevel@tonic-gate goto rb_others; 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate rb_all: 9467c478bd9Sstevel@tonic-gate /* 9477c478bd9Sstevel@tonic-gate * perform platform-dependent initialization 9487c478bd9Sstevel@tonic-gate */ 9497c478bd9Sstevel@tonic-gate if (cpr_suspend_succeeded) 9507c478bd9Sstevel@tonic-gate i_cpr_machdep_setup(); 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate /* 9537c478bd9Sstevel@tonic-gate * system did not really go down if we jump here 9547c478bd9Sstevel@tonic-gate */ 9557c478bd9Sstevel@tonic-gate rb_dump: 9567c478bd9Sstevel@tonic-gate /* 9577c478bd9Sstevel@tonic-gate * IMPORTANT: SENSITIVE RESUME SEQUENCE 9587c478bd9Sstevel@tonic-gate * 9597c478bd9Sstevel@tonic-gate * DO NOT ADD ANY INITIALIZATION STEP BEFORE THIS POINT!! 9607c478bd9Sstevel@tonic-gate */ 9612df1fe9cSrandyf rb_nodump: 9622df1fe9cSrandyf /* 9632df1fe9cSrandyf * If we did suspend to RAM, we didn't generate a dump 9642df1fe9cSrandyf */ 9652df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: CPR DMA callback\n")) 9667c478bd9Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_DMA, CB_CODE_CPR_RESUME); 9672df1fe9cSrandyf if (cpr_suspend_succeeded) { 9682df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: CPR RPC callback\n")) 9697c478bd9Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_RPC, CB_CODE_CPR_RESUME); 9702df1fe9cSrandyf } 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate prom_resume_prepost(); 9732df1fe9cSrandyf #if !defined(__sparc) 9742df1fe9cSrandyf /* 9752df1fe9cSrandyf * Need to sync the software clock with the hardware clock. 9762df1fe9cSrandyf * On Sparc, this occurs in the sparc-specific cbe. However 9772df1fe9cSrandyf * on x86 this needs to be handled _before_ we bring other cpu's 9782df1fe9cSrandyf * back online. So we call a resume function in timestamp.c 9792df1fe9cSrandyf */ 9802df1fe9cSrandyf if (tsc_resume_in_cyclic == 0) 9812df1fe9cSrandyf tsc_resume(); 9827c478bd9Sstevel@tonic-gate 9832df1fe9cSrandyf #endif 9842df1fe9cSrandyf 9852df1fe9cSrandyf #if defined(__sparc) 9867c478bd9Sstevel@tonic-gate if (cpr_suspend_succeeded && (boothowto & RB_DEBUG)) 9877c478bd9Sstevel@tonic-gate kdi_dvec_cpr_restart(); 9882df1fe9cSrandyf #endif 9892df1fe9cSrandyf 9902df1fe9cSrandyf 9912df1fe9cSrandyf #if defined(__x86) 9922df1fe9cSrandyf rb_mp_paused: 9932df1fe9cSrandyf PT(PT_RMPO); 9942df1fe9cSrandyf PMD(PMD_SX, ("resume aux cpus\n")) 9952df1fe9cSrandyf 9962df1fe9cSrandyf if (cpr_suspend_succeeded) { 9972df1fe9cSrandyf cpr_resume_cpus(); 9982df1fe9cSrandyf } else { 9992df1fe9cSrandyf cpr_unpause_cpus(); 10002df1fe9cSrandyf } 10012df1fe9cSrandyf #endif 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate /* 10047c478bd9Sstevel@tonic-gate * let the tmp callout catch up. 10057c478bd9Sstevel@tonic-gate */ 10062df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: CPR CALLOUT callback\n")) 10077c478bd9Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_CALLOUT, CB_CODE_CPR_RESUME); 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate i_cpr_enable_intr(); 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 10122df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: cyclic resume\n")) 10137c478bd9Sstevel@tonic-gate cyclic_resume(); 10147c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 10157c478bd9Sstevel@tonic-gate 10162df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: handle xc\n")) 10177c478bd9Sstevel@tonic-gate i_cpr_handle_xc(0); /* turn it off to allow xc assertion */ 10187c478bd9Sstevel@tonic-gate 10192df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: CPR POST KERNEL callback\n")) 10207c478bd9Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_KERNEL, CB_CODE_CPR_RESUME); 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate /* 10237c478bd9Sstevel@tonic-gate * statistics gathering 10247c478bd9Sstevel@tonic-gate */ 10257c478bd9Sstevel@tonic-gate if (cpr_suspend_succeeded) { 10267c478bd9Sstevel@tonic-gate /* 10277c478bd9Sstevel@tonic-gate * Prevent false alarm in tod_validate() due to tod 10287c478bd9Sstevel@tonic-gate * value change between suspend and resume 10297c478bd9Sstevel@tonic-gate */ 10308fc99e42STrevor Thompson cpr_tod_status_set(TOD_CPR_RESUME_DONE); 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate cpr_convert_promtime(&pwron_tv); 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate ctp = &cpr_term.tm_shutdown; 10352df1fe9cSrandyf if (sleeptype == CPR_TODISK) 10367c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ(" write statefile", ctp); 10377c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ("Suspend Total", ctp); 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ("Resume Total", &pwron_tv); 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate str = " prom time"; 10427c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ(str, &pwron_tv); 10437c478bd9Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_start; 10447c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ(str, ctp); 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate str = " read statefile"; 10477c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ(str, ctp); 10487c478bd9Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_end; 10497c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ(str, ctp); 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate rb_stop_kernel_threads: 10537c478bd9Sstevel@tonic-gate /* 10547c478bd9Sstevel@tonic-gate * Put all threads back to where they belong; get the kernel 10557c478bd9Sstevel@tonic-gate * daemons straightened up too. Note that the callback table 10567c478bd9Sstevel@tonic-gate * locked during cpr_stop_kernel_threads() is released only 10577c478bd9Sstevel@tonic-gate * in cpr_start_kernel_threads(). Ensure modunloading is 10587c478bd9Sstevel@tonic-gate * disabled before starting kernel threads, we don't want 10597c478bd9Sstevel@tonic-gate * modunload thread to start changing device tree underneath. 10607c478bd9Sstevel@tonic-gate */ 10612df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: modunload disable\n")) 10627c478bd9Sstevel@tonic-gate modunload_disable(); 10632df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: start kernel threads\n")) 10647c478bd9Sstevel@tonic-gate cpr_start_kernel_threads(); 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate rb_suspend_devices: 1067ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "resuming devices..."); 10687c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_START(" start drivers"); 10697c478bd9Sstevel@tonic-gate 10702df1fe9cSrandyf PMD(PMD_SX, 10712df1fe9cSrandyf ("cpr_resume: rb_suspend_devices: cpr_resume_uniproc = %d\n", 10722df1fe9cSrandyf cpr_resume_uniproc)) 10732df1fe9cSrandyf 10742df1fe9cSrandyf #if defined(__x86) 10752df1fe9cSrandyf /* 10762df1fe9cSrandyf * If cpr_resume_uniproc is set, then pause all the other cpus 10772df1fe9cSrandyf * apart from the current cpu, so that broken drivers that think 10782df1fe9cSrandyf * that they are on a uniprocessor machine will resume 10792df1fe9cSrandyf */ 10802df1fe9cSrandyf if (cpr_resume_uniproc) { 10812df1fe9cSrandyf mutex_enter(&cpu_lock); 1082*0ed5c46eSJosef 'Jeff' Sipek pause_cpus(NULL, NULL); 10832df1fe9cSrandyf mutex_exit(&cpu_lock); 10842df1fe9cSrandyf } 10852df1fe9cSrandyf #endif 10862df1fe9cSrandyf 10877c478bd9Sstevel@tonic-gate /* 10887c478bd9Sstevel@tonic-gate * The policy here is to continue resume everything we can if we did 10897c478bd9Sstevel@tonic-gate * not successfully finish suspend; and panic if we are coming back 10907c478bd9Sstevel@tonic-gate * from a fully suspended system. 10917c478bd9Sstevel@tonic-gate */ 10922df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: resume devices\n")) 10937c478bd9Sstevel@tonic-gate rc = cpr_resume_devices(ddi_root_node(), 0); 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate cpr_sae(0); 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate str = "Failed to resume one or more devices."; 10982df1fe9cSrandyf 10992df1fe9cSrandyf if (rc) { 11002df1fe9cSrandyf if (CPR->c_substate == C_ST_DUMP || 11012df1fe9cSrandyf (sleeptype == CPR_TORAM && 11022df1fe9cSrandyf CPR->c_substate == C_ST_NODUMP)) { 11032df1fe9cSrandyf if (cpr_test_point == FORCE_SUSPEND_TO_RAM) { 11042df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: resume device " 11052df1fe9cSrandyf "warn\n")) 11067c478bd9Sstevel@tonic-gate cpr_err(CE_WARN, str); 11072df1fe9cSrandyf } else { 11082df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: resume device " 11092df1fe9cSrandyf "panic\n")) 11102df1fe9cSrandyf cpr_err(CE_PANIC, str); 11112df1fe9cSrandyf } 11122df1fe9cSrandyf } else { 11132df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: resume device warn\n")) 11142df1fe9cSrandyf cpr_err(CE_WARN, str); 11152df1fe9cSrandyf } 11162df1fe9cSrandyf } 11172df1fe9cSrandyf 11187c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END(" start drivers"); 1119ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "done\n"); 11207c478bd9Sstevel@tonic-gate 11212df1fe9cSrandyf #if defined(__x86) 11222df1fe9cSrandyf /* 11232df1fe9cSrandyf * If cpr_resume_uniproc is set, then unpause all the processors 11242df1fe9cSrandyf * that were paused before resuming the drivers 11252df1fe9cSrandyf */ 11262df1fe9cSrandyf if (cpr_resume_uniproc) { 11272df1fe9cSrandyf mutex_enter(&cpu_lock); 11282df1fe9cSrandyf start_cpus(); 11292df1fe9cSrandyf mutex_exit(&cpu_lock); 11302df1fe9cSrandyf } 11312df1fe9cSrandyf #endif 11322df1fe9cSrandyf 11337c478bd9Sstevel@tonic-gate /* 11347c478bd9Sstevel@tonic-gate * If we had disabled modunloading in this cpr resume cycle (i.e. we 11357c478bd9Sstevel@tonic-gate * resumed from a state earlier than C_ST_SUSPEND_DEVICES), re-enable 11367c478bd9Sstevel@tonic-gate * modunloading now. 11377c478bd9Sstevel@tonic-gate */ 11382df1fe9cSrandyf if (CPR->c_substate != C_ST_SUSPEND_DEVICES) { 11392df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: modload enable\n")) 11407c478bd9Sstevel@tonic-gate modunload_enable(); 11412df1fe9cSrandyf } 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate /* 11447c478bd9Sstevel@tonic-gate * Hooks needed by lock manager prior to resuming. 11457c478bd9Sstevel@tonic-gate * Refer to code for more comments. 11467c478bd9Sstevel@tonic-gate */ 11472df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: lock mgr\n")) 11487c478bd9Sstevel@tonic-gate cpr_lock_mgr(lm_cprresume); 11497c478bd9Sstevel@tonic-gate 11502df1fe9cSrandyf #if defined(__sparc) 11517c478bd9Sstevel@tonic-gate /* 11527c478bd9Sstevel@tonic-gate * This is a partial (half) resume during cpr suspend, we 11537c478bd9Sstevel@tonic-gate * haven't yet given up on the suspend. On return from here, 11547c478bd9Sstevel@tonic-gate * cpr_suspend() will try to reallocate and retry the suspend. 11557c478bd9Sstevel@tonic-gate */ 11567c478bd9Sstevel@tonic-gate if (CPR->c_substate == C_ST_DUMP_NOSPC) { 11577c478bd9Sstevel@tonic-gate return (0); 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate 11602df1fe9cSrandyf if (sleeptype == CPR_TODISK) { 11617c478bd9Sstevel@tonic-gate rb_statef_alloc: 11627c478bd9Sstevel@tonic-gate cpr_statef_close(); 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate rb_disable_ufs_logging: 11657c478bd9Sstevel@tonic-gate /* 11667c478bd9Sstevel@tonic-gate * if ufs logging was disabled, re-enable 11677c478bd9Sstevel@tonic-gate */ 11687c478bd9Sstevel@tonic-gate (void) cpr_ufs_logging(1); 11692df1fe9cSrandyf } 11702df1fe9cSrandyf #endif 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate rb_pm_reattach_noinvol: 11737c478bd9Sstevel@tonic-gate /* 11747c478bd9Sstevel@tonic-gate * When pm_reattach_noinvol() succeeds, modunload_thread will 11757c478bd9Sstevel@tonic-gate * remain disabled until after cpr suspend passes the 11767c478bd9Sstevel@tonic-gate * C_ST_STOP_KERNEL_THREADS state. If any failure happens before 11777c478bd9Sstevel@tonic-gate * cpr suspend reaches this state, we'll need to enable modunload 11787c478bd9Sstevel@tonic-gate * thread during rollback. 11797c478bd9Sstevel@tonic-gate */ 11807c478bd9Sstevel@tonic-gate if (CPR->c_substate == C_ST_DISABLE_UFS_LOGGING || 11817c478bd9Sstevel@tonic-gate CPR->c_substate == C_ST_STATEF_ALLOC || 11827c478bd9Sstevel@tonic-gate CPR->c_substate == C_ST_SUSPEND_DEVICES || 11837c478bd9Sstevel@tonic-gate CPR->c_substate == C_ST_STOP_KERNEL_THREADS) { 11842df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: reattach noinvol fini\n")) 11857c478bd9Sstevel@tonic-gate pm_reattach_noinvol_fini(); 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate 11882df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: CPR POST USER callback\n")) 11897c478bd9Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_USER, CB_CODE_CPR_RESUME); 11902df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: CPR PROMPRINTF callback\n")) 11917c478bd9Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PROMPRINTF, CB_CODE_CPR_RESUME); 11927c478bd9Sstevel@tonic-gate 11932df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: restore direct levels\n")) 11947c478bd9Sstevel@tonic-gate pm_restore_direct_levels(); 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate rb_stop_user_threads: 1197ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "starting user threads..."); 11982df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: starting user threads\n")) 11997c478bd9Sstevel@tonic-gate cpr_start_user_threads(); 1200ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "done\n"); 12012df1fe9cSrandyf /* 12022df1fe9cSrandyf * Ask Xorg to resume the frame buffer, and wait for it to happen 12032df1fe9cSrandyf */ 12042df1fe9cSrandyf mutex_enter(&srn_clone_lock); 12052df1fe9cSrandyf if (srn_signal) { 12062df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: (*srn_signal)(..., " 12072df1fe9cSrandyf "SRN_NORMAL_RESUME)\n")) 12082df1fe9cSrandyf srn_inuse = 1; /* because (*srn_signal) cv_waits */ 12092df1fe9cSrandyf (*srn_signal)(SRN_TYPE_APM, SRN_NORMAL_RESUME); 12102df1fe9cSrandyf srn_inuse = 0; 12112df1fe9cSrandyf } else { 12122df1fe9cSrandyf PMD(PMD_SX, ("cpr_suspend: srn_signal NULL\n")) 12132df1fe9cSrandyf } 12142df1fe9cSrandyf mutex_exit(&srn_clone_lock); 12157c478bd9Sstevel@tonic-gate 12162df1fe9cSrandyf #if defined(__sparc) 12177c478bd9Sstevel@tonic-gate rb_mp_offline: 12187c478bd9Sstevel@tonic-gate if (cpr_mp_online()) 12197c478bd9Sstevel@tonic-gate cpr_err(CE_WARN, "Failed to online all the processors."); 12202df1fe9cSrandyf #endif 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate rb_others: 12232df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: dep thread\n")) 12242df1fe9cSrandyf pm_dispatch_to_dep_thread(PM_DEP_WK_CPR_RESUME, NULL, NULL, 12252df1fe9cSrandyf PM_DEP_WAIT, NULL, 0); 12267c478bd9Sstevel@tonic-gate 12272df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: CPR PM callback\n")) 12287c478bd9Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PM, CB_CODE_CPR_RESUME); 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate if (cpr_suspend_succeeded) { 12317c478bd9Sstevel@tonic-gate cpr_stat_record_events(); 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate 12342df1fe9cSrandyf #if defined(__sparc) 12352df1fe9cSrandyf if (sleeptype == CPR_TODISK && !cpr_reusable_mode) 12367c478bd9Sstevel@tonic-gate cpr_clear_definfo(); 12372df1fe9cSrandyf #endif 12387c478bd9Sstevel@tonic-gate 12392df1fe9cSrandyf i_cpr_free_cpus(); 1240ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "Sending SIGTHAW..."); 12412df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume: SIGTHAW\n")) 12427c478bd9Sstevel@tonic-gate cpr_signal_user(SIGTHAW); 1243ae115bc7Smrj CPR_DEBUG(CPR_DEBUG1, "done\n"); 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END("Resume Total"); 12467c478bd9Sstevel@tonic-gate 12477c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ("WHOLE CYCLE", &wholecycle_tv); 12487c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END("WHOLE CYCLE"); 12497c478bd9Sstevel@tonic-gate 1250ae115bc7Smrj if (cpr_debug & CPR_DEBUG1) 1251ae115bc7Smrj cmn_err(CE_CONT, "\nThe system is back where you left!\n"); 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_START("POST CPR DELAY"); 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate #ifdef CPR_STAT 12567c478bd9Sstevel@tonic-gate ctp = &cpr_term.tm_shutdown; 12577c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ("PWROFF TIME", ctp); 12587c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ("PWROFF TIME", &pwron_tv); 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate CPR_STAT_EVENT_PRINT(); 12617c478bd9Sstevel@tonic-gate #endif /* CPR_STAT */ 12627c478bd9Sstevel@tonic-gate 12632df1fe9cSrandyf PMD(PMD_SX, ("cpr_resume returns %x\n", rc)) 12647c478bd9Sstevel@tonic-gate return (rc); 12657c478bd9Sstevel@tonic-gate } 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate static void 12682df1fe9cSrandyf cpr_suspend_init(int sleeptype) 12697c478bd9Sstevel@tonic-gate { 12707c478bd9Sstevel@tonic-gate cpr_time_t *ctp; 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate cpr_stat_init(); 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate /* 12757c478bd9Sstevel@tonic-gate * If cpr_suspend() failed before cpr_dump() gets a chance 12767c478bd9Sstevel@tonic-gate * to reinitialize the terminator of the statefile, 12777c478bd9Sstevel@tonic-gate * the values of the old terminator will still linger around. 12787c478bd9Sstevel@tonic-gate * Since the terminator contains information that we need to 12797c478bd9Sstevel@tonic-gate * decide whether suspend succeeded or not, we need to 12807c478bd9Sstevel@tonic-gate * reinitialize it as early as possible. 12817c478bd9Sstevel@tonic-gate */ 12827c478bd9Sstevel@tonic-gate cpr_term.real_statef_size = 0; 12837c478bd9Sstevel@tonic-gate ctp = &cpr_term.tm_shutdown; 12847c478bd9Sstevel@tonic-gate bzero(ctp, sizeof (*ctp)); 12857c478bd9Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_start; 12867c478bd9Sstevel@tonic-gate bzero(ctp, sizeof (*ctp)); 12877c478bd9Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_end; 12887c478bd9Sstevel@tonic-gate bzero(ctp, sizeof (*ctp)); 12897c478bd9Sstevel@tonic-gate 12902df1fe9cSrandyf if (sleeptype == CPR_TODISK) { 12917c478bd9Sstevel@tonic-gate /* 12922df1fe9cSrandyf * Lookup the physical address of our thread structure. 12932df1fe9cSrandyf * This should never be invalid and the entire thread structure 12942df1fe9cSrandyf * is expected to reside within the same pfn. 12957c478bd9Sstevel@tonic-gate */ 12967c478bd9Sstevel@tonic-gate curthreadpfn = hat_getpfnum(kas.a_hat, (caddr_t)curthread); 12977c478bd9Sstevel@tonic-gate ASSERT(curthreadpfn != PFN_INVALID); 12987c478bd9Sstevel@tonic-gate ASSERT(curthreadpfn == hat_getpfnum(kas.a_hat, 12997c478bd9Sstevel@tonic-gate (caddr_t)curthread + sizeof (kthread_t) - 1)); 13002df1fe9cSrandyf } 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate cpr_suspend_succeeded = 0; 13037c478bd9Sstevel@tonic-gate } 13042df1fe9cSrandyf 13052df1fe9cSrandyf /* 13062df1fe9cSrandyf * bring all the offline cpus online 13072df1fe9cSrandyf */ 13082df1fe9cSrandyf static int 13092df1fe9cSrandyf cpr_all_online(void) 13102df1fe9cSrandyf { 13112df1fe9cSrandyf int rc = 0; 13122df1fe9cSrandyf 13132df1fe9cSrandyf #ifdef __sparc 13142df1fe9cSrandyf /* 13152df1fe9cSrandyf * do nothing 13162df1fe9cSrandyf */ 13172df1fe9cSrandyf #else 13182df1fe9cSrandyf 13192df1fe9cSrandyf cpu_t *cp; 13202df1fe9cSrandyf 13212df1fe9cSrandyf ASSERT(MUTEX_HELD(&cpu_lock)); 13222df1fe9cSrandyf 13232df1fe9cSrandyf cp = cpu_list; 13242df1fe9cSrandyf do { 13252df1fe9cSrandyf cp->cpu_cpr_flags &= ~CPU_CPR_ONLINE; 13262df1fe9cSrandyf if (!CPU_ACTIVE(cp)) { 13272df1fe9cSrandyf if ((rc = cpu_online(cp)) != 0) 13282df1fe9cSrandyf break; 13292df1fe9cSrandyf CPU_SET_CPR_FLAGS(cp, CPU_CPR_ONLINE); 13302df1fe9cSrandyf } 13312df1fe9cSrandyf } while ((cp = cp->cpu_next) != cpu_list); 13322df1fe9cSrandyf 13332df1fe9cSrandyf if (rc) { 13342df1fe9cSrandyf /* 13352df1fe9cSrandyf * an online operation failed so offline the cpus 13362df1fe9cSrandyf * that were onlined above to restore the system 13372df1fe9cSrandyf * to its original state 13382df1fe9cSrandyf */ 13392df1fe9cSrandyf cpr_restore_offline(); 13402df1fe9cSrandyf } 13412df1fe9cSrandyf #endif 13422df1fe9cSrandyf return (rc); 13432df1fe9cSrandyf } 13442df1fe9cSrandyf 13452df1fe9cSrandyf /* 13462df1fe9cSrandyf * offline all the cpus that were brought online by cpr_all_online() 13472df1fe9cSrandyf */ 13482df1fe9cSrandyf static void 13492df1fe9cSrandyf cpr_restore_offline(void) 13502df1fe9cSrandyf { 13512df1fe9cSrandyf 13522df1fe9cSrandyf #ifdef __sparc 13532df1fe9cSrandyf /* 13542df1fe9cSrandyf * do nothing 13552df1fe9cSrandyf */ 13562df1fe9cSrandyf #else 13572df1fe9cSrandyf 13582df1fe9cSrandyf cpu_t *cp; 13592df1fe9cSrandyf int rc = 0; 13602df1fe9cSrandyf 13612df1fe9cSrandyf ASSERT(MUTEX_HELD(&cpu_lock)); 13622df1fe9cSrandyf 13632df1fe9cSrandyf cp = cpu_list; 13642df1fe9cSrandyf do { 13652df1fe9cSrandyf if (CPU_CPR_IS_ONLINE(cp)) { 13662df1fe9cSrandyf rc = cpu_offline(cp, 0); 13672df1fe9cSrandyf /* 13682df1fe9cSrandyf * this offline should work, since the cpu was 13692df1fe9cSrandyf * offline originally and was successfully onlined 13702df1fe9cSrandyf * by cpr_all_online() 13712df1fe9cSrandyf */ 13722df1fe9cSrandyf ASSERT(rc == 0); 13732df1fe9cSrandyf cp->cpu_cpr_flags &= ~CPU_CPR_ONLINE; 13742df1fe9cSrandyf } 13752df1fe9cSrandyf } while ((cp = cp->cpu_next) != cpu_list); 13762df1fe9cSrandyf 13772df1fe9cSrandyf #endif 13782df1fe9cSrandyf 13792df1fe9cSrandyf } 1380