10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 53446Smrj * Common Development and Distribution License (the "License"). 63446Smrj * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 223446Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * This module contains the guts of checkpoint-resume mechanism. 300Sstevel@tonic-gate * All code in this module is platform independent. 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate #include <sys/errno.h> 350Sstevel@tonic-gate #include <sys/callb.h> 360Sstevel@tonic-gate #include <sys/processor.h> 370Sstevel@tonic-gate #include <sys/machsystm.h> 380Sstevel@tonic-gate #include <sys/clock.h> 390Sstevel@tonic-gate #include <sys/vfs.h> 400Sstevel@tonic-gate #include <sys/kmem.h> 410Sstevel@tonic-gate #include <nfs/lm.h> 420Sstevel@tonic-gate #include <sys/systm.h> 430Sstevel@tonic-gate #include <sys/cpr.h> 440Sstevel@tonic-gate #include <sys/bootconf.h> 450Sstevel@tonic-gate #include <sys/cyclic.h> 460Sstevel@tonic-gate #include <sys/filio.h> 470Sstevel@tonic-gate #include <sys/fs/ufs_filio.h> 480Sstevel@tonic-gate #include <sys/epm.h> 490Sstevel@tonic-gate #include <sys/modctl.h> 500Sstevel@tonic-gate #include <sys/reboot.h> 510Sstevel@tonic-gate #include <sys/kdi.h> 520Sstevel@tonic-gate #include <sys/promif.h> 535295Srandyf #include <sys/srn.h> 545295Srandyf #include <sys/cpr_impl.h> 555295Srandyf 565295Srandyf #define PPM(dip) ((dev_info_t *)DEVI(dip)->devi_pm_ppm) 570Sstevel@tonic-gate 580Sstevel@tonic-gate extern struct cpr_terminator cpr_term; 590Sstevel@tonic-gate 600Sstevel@tonic-gate extern int cpr_alloc_statefile(int); 610Sstevel@tonic-gate extern void cpr_start_kernel_threads(void); 620Sstevel@tonic-gate extern void cpr_abbreviate_devpath(char *, char *); 630Sstevel@tonic-gate extern void cpr_convert_promtime(cpr_time_t *); 640Sstevel@tonic-gate extern void cpr_send_notice(void); 650Sstevel@tonic-gate extern void cpr_set_bitmap_size(void); 660Sstevel@tonic-gate extern void cpr_stat_init(); 670Sstevel@tonic-gate extern void cpr_statef_close(void); 680Sstevel@tonic-gate extern void flush_windows(void); 695295Srandyf extern void (*srn_signal)(int, int); 705295Srandyf extern void init_cpu_syscall(struct cpu *); 715295Srandyf extern void i_cpr_pre_resume_cpus(); 725295Srandyf extern void i_cpr_post_resume_cpus(); 730Sstevel@tonic-gate 740Sstevel@tonic-gate extern int pm_powering_down; 755295Srandyf extern kmutex_t srn_clone_lock; 765295Srandyf extern int srn_inuse; 770Sstevel@tonic-gate 785295Srandyf static int cpr_suspend(int); 795295Srandyf static int cpr_resume(int); 805295Srandyf static void cpr_suspend_init(int); 815295Srandyf #if defined(__x86) 825295Srandyf static int cpr_suspend_cpus(void); 835295Srandyf static void cpr_resume_cpus(void); 845295Srandyf #endif 855295Srandyf static int cpr_all_online(void); 865295Srandyf static void cpr_restore_offline(void); 870Sstevel@tonic-gate 880Sstevel@tonic-gate cpr_time_t wholecycle_tv; 890Sstevel@tonic-gate int cpr_suspend_succeeded; 900Sstevel@tonic-gate pfn_t curthreadpfn; 910Sstevel@tonic-gate int curthreadremapped; 920Sstevel@tonic-gate 935295Srandyf extern cpuset_t cpu_ready_set; 945295Srandyf extern void *(*cpu_pause_func)(void *); 955295Srandyf 965295Srandyf extern processorid_t i_cpr_bootcpuid(void); 975295Srandyf extern cpu_t *i_cpr_bootcpu(void); 985295Srandyf extern void tsc_adjust_delta(hrtime_t tdelta); 995295Srandyf extern void tsc_resume(void); 1005295Srandyf extern int tsc_resume_in_cyclic; 1015295Srandyf 1025295Srandyf /* 1035295Srandyf * Set this variable to 1, to have device drivers resume in an 1045295Srandyf * uniprocessor environment. This is to allow drivers that assume 1055295Srandyf * that they resume on a UP machine to continue to work. Should be 1065295Srandyf * deprecated once the broken drivers are fixed 1075295Srandyf */ 1085295Srandyf int cpr_resume_uniproc = 0; 1095295Srandyf 1100Sstevel@tonic-gate /* 1110Sstevel@tonic-gate * save or restore abort_enable; this prevents a drop 1120Sstevel@tonic-gate * to kadb or prom during cpr_resume_devices() when 1130Sstevel@tonic-gate * there is no kbd present; see abort_sequence_enter() 1140Sstevel@tonic-gate */ 1150Sstevel@tonic-gate static void 1160Sstevel@tonic-gate cpr_sae(int stash) 1170Sstevel@tonic-gate { 1180Sstevel@tonic-gate static int saved_ae = -1; 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate if (stash) { 1210Sstevel@tonic-gate saved_ae = abort_enable; 1220Sstevel@tonic-gate abort_enable = 0; 1230Sstevel@tonic-gate } else if (saved_ae != -1) { 1240Sstevel@tonic-gate abort_enable = saved_ae; 1250Sstevel@tonic-gate saved_ae = -1; 1260Sstevel@tonic-gate } 1270Sstevel@tonic-gate } 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate /* 1310Sstevel@tonic-gate * The main switching point for cpr, this routine starts the ckpt 1320Sstevel@tonic-gate * and state file saving routines; on resume the control is 1330Sstevel@tonic-gate * returned back to here and it then calls the resume routine. 1340Sstevel@tonic-gate */ 1350Sstevel@tonic-gate int 1365295Srandyf cpr_main(int sleeptype) 1370Sstevel@tonic-gate { 1385295Srandyf int rc, rc2; 1395295Srandyf label_t saveq; 1405295Srandyf klwp_t *tlwp = ttolwp(curthread); 1415295Srandyf 1425295Srandyf if (sleeptype == CPR_TODISK) { 1435295Srandyf if ((rc = cpr_default_setup(1)) != 0) 1445295Srandyf return (rc); 1455295Srandyf ASSERT(tlwp); 1465295Srandyf saveq = tlwp->lwp_qsav; 1475295Srandyf } 1485295Srandyf 1495295Srandyf if (sleeptype == CPR_TORAM) { 1505295Srandyf rc = cpr_suspend(sleeptype); 1515295Srandyf PMD(PMD_SX, ("cpr_suspend rets %x\n", rc)) 1525295Srandyf if (rc == 0) { 1535295Srandyf int i_cpr_power_down(int sleeptype); 1545295Srandyf 1555295Srandyf /* 1565295Srandyf * From this point on, we should be at a high 1575295Srandyf * spl, interrupts disabled, and all but one 1585295Srandyf * cpu's paused (effectively UP/single threaded). 1595295Srandyf * So this is were we want to put ASSERTS() 1605295Srandyf * to let us know otherwise. 1615295Srandyf */ 1625295Srandyf ASSERT(cpus_paused()); 1630Sstevel@tonic-gate 1645295Srandyf /* 1655295Srandyf * Now do the work of actually putting this 1665295Srandyf * machine to sleep! 1675295Srandyf */ 1685295Srandyf rc = i_cpr_power_down(sleeptype); 1695295Srandyf if (rc == 0) { 1705295Srandyf PMD(PMD_SX, ("back from succssful suspend\n")) 1715295Srandyf } 1725295Srandyf /* 1735295Srandyf * We do care about the return value from cpr_resume 1745295Srandyf * at this point, as it will tell us if one of the 1755295Srandyf * resume functions failed (cpr_resume_devices()) 1765295Srandyf * However, for this to return and _not_ panic, means 1775295Srandyf * that we must be in one of the test functions. So 1785295Srandyf * check for that and return an appropriate message. 1795295Srandyf */ 1805295Srandyf rc2 = cpr_resume(sleeptype); 1815295Srandyf if (rc2 != 0) { 1825295Srandyf ASSERT(cpr_test_point > 0); 1835295Srandyf cmn_err(CE_NOTE, 1845295Srandyf "cpr_resume returned non-zero: %d\n", rc2); 1855295Srandyf PMD(PMD_SX, ("cpr_resume rets %x\n", rc2)) 1865295Srandyf } 1875295Srandyf ASSERT(!cpus_paused()); 1885295Srandyf } else { 1895295Srandyf PMD(PMD_SX, ("failed suspend, resuming\n")) 1905295Srandyf rc = cpr_resume(sleeptype); 1915295Srandyf } 1920Sstevel@tonic-gate return (rc); 1935295Srandyf } 1940Sstevel@tonic-gate /* 1955295Srandyf * Remember where we are for resume after reboot 1960Sstevel@tonic-gate */ 1975295Srandyf if (!setjmp(&tlwp->lwp_qsav)) { 1980Sstevel@tonic-gate /* 1990Sstevel@tonic-gate * try to checkpoint the system, if failed return back 2000Sstevel@tonic-gate * to userland, otherwise power off. 2010Sstevel@tonic-gate */ 2025295Srandyf rc = cpr_suspend(sleeptype); 2030Sstevel@tonic-gate if (rc || cpr_reusable_mode) { 2040Sstevel@tonic-gate /* 2050Sstevel@tonic-gate * We don't really want to go down, or 2060Sstevel@tonic-gate * something went wrong in suspend, do what we can 2070Sstevel@tonic-gate * to put the system back to an operable state then 2080Sstevel@tonic-gate * return back to userland. 2090Sstevel@tonic-gate */ 2105295Srandyf PMD(PMD_SX, ("failed suspend, resuming\n")) 2115295Srandyf (void) cpr_resume(sleeptype); 2125295Srandyf PMD(PMD_SX, ("back from failed suspend resume\n")) 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate } else { 2150Sstevel@tonic-gate /* 2160Sstevel@tonic-gate * This is the resumed side of longjmp, restore the previous 2170Sstevel@tonic-gate * longjmp pointer if there is one so this will be transparent 2180Sstevel@tonic-gate * to the world. 2195295Srandyf * This path is only for CPR_TODISK, where we reboot 2200Sstevel@tonic-gate */ 2215295Srandyf ASSERT(sleeptype == CPR_TODISK); 2225295Srandyf tlwp->lwp_qsav = saveq; 2230Sstevel@tonic-gate CPR->c_flags &= ~C_SUSPENDING; 2240Sstevel@tonic-gate CPR->c_flags |= C_RESUMING; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate /* 2270Sstevel@tonic-gate * resume the system back to the original state 2280Sstevel@tonic-gate */ 2295295Srandyf rc = cpr_resume(sleeptype); 2305295Srandyf PMD(PMD_SX, ("back from successful suspend; resume rets %x\n", 2315295Srandyf rc)) 2320Sstevel@tonic-gate } 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate (void) cpr_default_setup(0); 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate return (rc); 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate 2405295Srandyf #if defined(__sparc) 2415295Srandyf 2420Sstevel@tonic-gate /* 2430Sstevel@tonic-gate * check/disable or re-enable UFS logging 2440Sstevel@tonic-gate */ 2450Sstevel@tonic-gate static void 2460Sstevel@tonic-gate cpr_log_status(int enable, int *svstat, vnode_t *vp) 2470Sstevel@tonic-gate { 2480Sstevel@tonic-gate int cmd, status, error; 2490Sstevel@tonic-gate char *str, *able; 2500Sstevel@tonic-gate fiolog_t fl; 2510Sstevel@tonic-gate refstr_t *mntpt; 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate str = "cpr_log_status"; 2540Sstevel@tonic-gate bzero(&fl, sizeof (fl)); 2550Sstevel@tonic-gate fl.error = FIOLOG_ENONE; 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate /* 2580Sstevel@tonic-gate * when disabling, first get and save logging status (0 or 1) 2590Sstevel@tonic-gate */ 2600Sstevel@tonic-gate if (enable == 0) { 2610Sstevel@tonic-gate if (error = VOP_IOCTL(vp, _FIOISLOG, 262*5331Samw (uintptr_t)&status, FKIOCTL, CRED(), NULL, NULL)) { 2630Sstevel@tonic-gate mntpt = vfs_getmntpoint(vp->v_vfsp); 2643446Smrj prom_printf("%s: \"%s\", cant get logging " 2653446Smrj "status, error %d\n", str, refstr_value(mntpt), 2663446Smrj error); 2670Sstevel@tonic-gate refstr_rele(mntpt); 2680Sstevel@tonic-gate return; 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate *svstat = status; 2713446Smrj if (cpr_debug & CPR_DEBUG5) { 2720Sstevel@tonic-gate mntpt = vfs_getmntpoint(vp->v_vfsp); 2735295Srandyf errp("%s: \"%s\", logging status = %d\n", 2740Sstevel@tonic-gate str, refstr_value(mntpt), status); 2750Sstevel@tonic-gate refstr_rele(mntpt); 2763446Smrj }; 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate able = "disable"; 2790Sstevel@tonic-gate cmd = _FIOLOGDISABLE; 2800Sstevel@tonic-gate } else { 2810Sstevel@tonic-gate able = "enable"; 2820Sstevel@tonic-gate cmd = _FIOLOGENABLE; 2830Sstevel@tonic-gate } 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate /* 2860Sstevel@tonic-gate * disable or re-enable logging when the saved status is 1 2870Sstevel@tonic-gate */ 2880Sstevel@tonic-gate if (*svstat == 1) { 2890Sstevel@tonic-gate error = VOP_IOCTL(vp, cmd, (uintptr_t)&fl, 290*5331Samw FKIOCTL, CRED(), NULL, NULL); 2910Sstevel@tonic-gate if (error) { 2920Sstevel@tonic-gate mntpt = vfs_getmntpoint(vp->v_vfsp); 2933446Smrj prom_printf("%s: \"%s\", cant %s logging, error %d\n", 2940Sstevel@tonic-gate str, refstr_value(mntpt), able, error); 2950Sstevel@tonic-gate refstr_rele(mntpt); 2960Sstevel@tonic-gate } else { 2973446Smrj if (cpr_debug & CPR_DEBUG5) { 2980Sstevel@tonic-gate mntpt = vfs_getmntpoint(vp->v_vfsp); 2995295Srandyf errp("%s: \"%s\", logging is now %sd\n", 3000Sstevel@tonic-gate str, refstr_value(mntpt), able); 3010Sstevel@tonic-gate refstr_rele(mntpt); 3025295Srandyf }; 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate /* 3070Sstevel@tonic-gate * when enabling logging, reset the saved status 3080Sstevel@tonic-gate * to unknown for next time 3090Sstevel@tonic-gate */ 3100Sstevel@tonic-gate if (enable) 3110Sstevel@tonic-gate *svstat = -1; 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* 3150Sstevel@tonic-gate * enable/disable UFS logging on filesystems containing cpr_default_path 3160Sstevel@tonic-gate * and cpr statefile. since the statefile can be on any fs, that fs 3170Sstevel@tonic-gate * needs to be handled separately. this routine and cprboot expect that 3180Sstevel@tonic-gate * CPR_CONFIG and CPR_DEFAULT both reside on the same fs, rootfs. cprboot 3190Sstevel@tonic-gate * is loaded from the device with rootfs and uses the same device to open 3200Sstevel@tonic-gate * both CPR_CONFIG and CPR_DEFAULT (see common/support.c). moving either 3210Sstevel@tonic-gate * file outside of rootfs would cause errors during cprboot, plus cpr and 3220Sstevel@tonic-gate * fsck problems with the new fs if logging were enabled. 3230Sstevel@tonic-gate */ 3245295Srandyf 3250Sstevel@tonic-gate static int 3260Sstevel@tonic-gate cpr_ufs_logging(int enable) 3270Sstevel@tonic-gate { 3280Sstevel@tonic-gate static int def_status = -1, sf_status = -1; 3290Sstevel@tonic-gate struct vfs *vfsp; 3300Sstevel@tonic-gate char *fname; 3310Sstevel@tonic-gate vnode_t *vp; 3320Sstevel@tonic-gate int error; 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate if (cpr_reusable_mode) 3350Sstevel@tonic-gate return (0); 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate if (error = cpr_open_deffile(FREAD, &vp)) 3380Sstevel@tonic-gate return (error); 3390Sstevel@tonic-gate cpr_log_status(enable, &def_status, vp); 3400Sstevel@tonic-gate vfsp = vp->v_vfsp; 341*5331Samw (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL); 3420Sstevel@tonic-gate VN_RELE(vp); 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate fname = cpr_build_statefile_path(); 3450Sstevel@tonic-gate if (fname == NULL) 3460Sstevel@tonic-gate return (ENOENT); 3470Sstevel@tonic-gate if (error = vn_open(fname, UIO_SYSSPACE, FCREAT|FWRITE, 3480Sstevel@tonic-gate 0600, &vp, CRCREAT, 0)) { 3493446Smrj prom_printf("cpr_ufs_logging: cant open/create \"%s\", " 3503446Smrj "error %d\n", fname, error); 3510Sstevel@tonic-gate return (error); 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate /* 3550Sstevel@tonic-gate * check logging status for the statefile if it resides 3560Sstevel@tonic-gate * on a different fs and the type is a regular file 3570Sstevel@tonic-gate */ 3580Sstevel@tonic-gate if (vp->v_vfsp != vfsp && vp->v_type == VREG) 3590Sstevel@tonic-gate cpr_log_status(enable, &sf_status, vp); 360*5331Samw (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL); 3610Sstevel@tonic-gate VN_RELE(vp); 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate return (0); 3640Sstevel@tonic-gate } 3655295Srandyf #endif 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate /* 3690Sstevel@tonic-gate * Check if klmmod is loaded and call a lock manager service; if klmmod 3700Sstevel@tonic-gate * is not loaded, the services aren't needed and a call would trigger a 3710Sstevel@tonic-gate * modload, which would block since another thread would never run. 3720Sstevel@tonic-gate */ 3730Sstevel@tonic-gate static void 3740Sstevel@tonic-gate cpr_lock_mgr(void (*service)(void)) 3750Sstevel@tonic-gate { 3760Sstevel@tonic-gate if (mod_find_by_filename(NULL, "misc/klmmod") != NULL) 3770Sstevel@tonic-gate (*service)(); 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3805295Srandyf int 3815295Srandyf cpr_suspend_cpus(void) 3825295Srandyf { 3835295Srandyf cpu_t *bootcpu; 3845295Srandyf int ret = 0; 3855295Srandyf extern void *i_cpr_save_context(void *arg); 3865295Srandyf 3875295Srandyf mutex_enter(&cpu_lock); 3885295Srandyf 3895295Srandyf /* 3905295Srandyf * if bootcpu is offline bring it back online 3915295Srandyf */ 3925295Srandyf bootcpu = i_cpr_bootcpu(); 3935295Srandyf 3945295Srandyf /* 3955295Srandyf * the machine could not have booted without a bootcpu 3965295Srandyf */ 3975295Srandyf ASSERT(bootcpu != NULL); 3985295Srandyf 3995295Srandyf /* 4005295Srandyf * bring all the offline cpus online 4015295Srandyf */ 4025295Srandyf if ((ret = cpr_all_online())) { 4035295Srandyf mutex_exit(&cpu_lock); 4045295Srandyf return (ret); 4055295Srandyf } 4065295Srandyf 4075295Srandyf /* 4085295Srandyf * Set the affinity to be the boot processor 4095295Srandyf * This is cleared in either cpr_resume_cpus() or cpr_unpause_cpus() 4105295Srandyf */ 4115295Srandyf affinity_set(i_cpr_bootcpuid()); 4125295Srandyf 4135295Srandyf ASSERT(CPU->cpu_id == 0); 4145295Srandyf 4155295Srandyf PMD(PMD_SX, ("curthread running on bootcpu\n")) 4165295Srandyf 4175295Srandyf /* 4185295Srandyf * pause all other running CPUs and save the CPU state at the sametime 4195295Srandyf */ 4205295Srandyf cpu_pause_func = i_cpr_save_context; 4215295Srandyf pause_cpus(NULL); 4225295Srandyf 4235295Srandyf mutex_exit(&cpu_lock); 4245295Srandyf 4255295Srandyf return (0); 4265295Srandyf } 4275295Srandyf 4280Sstevel@tonic-gate /* 4290Sstevel@tonic-gate * Take the system down to a checkpointable state and write 4300Sstevel@tonic-gate * the state file, the following are sequentially executed: 4310Sstevel@tonic-gate * 4320Sstevel@tonic-gate * - Request all user threads to stop themselves 4330Sstevel@tonic-gate * - push out and invalidate user pages 4340Sstevel@tonic-gate * - bring statefile inode incore to prevent a miss later 4350Sstevel@tonic-gate * - request all daemons to stop 4360Sstevel@tonic-gate * - check and make sure all threads are stopped 4370Sstevel@tonic-gate * - sync the file system 4380Sstevel@tonic-gate * - suspend all devices 4390Sstevel@tonic-gate * - block intrpts 4400Sstevel@tonic-gate * - dump system state and memory to state file 4415295Srandyf * - SPARC code will not be called with CPR_TORAM, caller filters 4420Sstevel@tonic-gate */ 4430Sstevel@tonic-gate static int 4445295Srandyf cpr_suspend(int sleeptype) 4450Sstevel@tonic-gate { 4465295Srandyf #if defined(__sparc) 4475295Srandyf int sf_realloc, nverr; 4485295Srandyf #endif 4495295Srandyf int rc = 0; 4505295Srandyf int skt_rc = 0; 4510Sstevel@tonic-gate 4525295Srandyf PMD(PMD_SX, ("cpr_suspend %x\n", sleeptype)) 4530Sstevel@tonic-gate cpr_set_substate(C_ST_SUSPEND_BEGIN); 4540Sstevel@tonic-gate 4555295Srandyf cpr_suspend_init(sleeptype); 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate cpr_save_time(); 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate cpr_tod_get(&wholecycle_tv); 4600Sstevel@tonic-gate CPR_STAT_EVENT_START("Suspend Total"); 4610Sstevel@tonic-gate 4625295Srandyf i_cpr_alloc_cpus(); 4635295Srandyf 4645295Srandyf #if defined(__sparc) 4655295Srandyf ASSERT(sleeptype == CPR_TODISK); 4660Sstevel@tonic-gate if (!cpr_reusable_mode) { 4670Sstevel@tonic-gate /* 4685295Srandyf * We need to validate default file before fs 4695295Srandyf * functionality is disabled. 4700Sstevel@tonic-gate */ 4710Sstevel@tonic-gate if (rc = cpr_validate_definfo(0)) 4720Sstevel@tonic-gate return (rc); 4730Sstevel@tonic-gate } 4745295Srandyf i_cpr_save_machdep_info(); 4755295Srandyf #endif 4760Sstevel@tonic-gate 4775295Srandyf PMD(PMD_SX, ("cpr_suspend: stop scans\n")) 4780Sstevel@tonic-gate /* Stop PM scans ASAP */ 4790Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PM, CB_CODE_CPR_CHKPT); 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_CPR_SUSPEND, 4820Sstevel@tonic-gate NULL, NULL, PM_DEP_WAIT, NULL, 0); 4830Sstevel@tonic-gate 4845295Srandyf #if defined(__sparc) 4855295Srandyf ASSERT(sleeptype == CPR_TODISK); 4860Sstevel@tonic-gate cpr_set_substate(C_ST_MP_OFFLINE); 4870Sstevel@tonic-gate if (rc = cpr_mp_offline()) 4880Sstevel@tonic-gate return (rc); 4895295Srandyf #endif 4905295Srandyf /* 4915295Srandyf * Ask Xorg to suspend the frame buffer, and wait for it to happen 4925295Srandyf */ 4935295Srandyf mutex_enter(&srn_clone_lock); 4945295Srandyf if (srn_signal) { 4955295Srandyf PMD(PMD_SX, ("cpr_suspend: (*srn_signal)(..., " 4965295Srandyf "SRN_SUSPEND_REQ)\n")) 4975295Srandyf srn_inuse = 1; /* because *(srn_signal) cv_waits */ 4985295Srandyf (*srn_signal)(SRN_TYPE_APM, SRN_SUSPEND_REQ); 4995295Srandyf srn_inuse = 0; 5005295Srandyf } else { 5015295Srandyf PMD(PMD_SX, ("cpr_suspend: srn_signal NULL\n")) 5025295Srandyf } 5035295Srandyf mutex_exit(&srn_clone_lock); 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate /* 5060Sstevel@tonic-gate * Ask the user threads to stop by themselves, but 5070Sstevel@tonic-gate * if they don't or can't after 3 retries, we give up on CPR. 5080Sstevel@tonic-gate * The 3 retry is not a random number because 2 is possible if 5090Sstevel@tonic-gate * a thread has been forked before the parent thread is stopped. 5100Sstevel@tonic-gate */ 5113446Smrj CPR_DEBUG(CPR_DEBUG1, "\nstopping user threads..."); 5120Sstevel@tonic-gate CPR_STAT_EVENT_START(" stop users"); 5130Sstevel@tonic-gate cpr_set_substate(C_ST_STOP_USER_THREADS); 5145295Srandyf PMD(PMD_SX, ("cpr_suspend: stop user threads\n")) 5150Sstevel@tonic-gate if (rc = cpr_stop_user_threads()) 5160Sstevel@tonic-gate return (rc); 5170Sstevel@tonic-gate CPR_STAT_EVENT_END(" stop users"); 5183446Smrj CPR_DEBUG(CPR_DEBUG1, "done\n"); 5190Sstevel@tonic-gate 5205295Srandyf PMD(PMD_SX, ("cpr_suspend: save direct levels\n")) 5210Sstevel@tonic-gate pm_save_direct_levels(); 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate /* 5240Sstevel@tonic-gate * User threads are stopped. We will start communicating with the 5250Sstevel@tonic-gate * user via prom_printf (some debug output may have already happened) 5260Sstevel@tonic-gate * so let anybody who cares know about this (bug 4096122) 5270Sstevel@tonic-gate */ 5280Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PROMPRINTF, CB_CODE_CPR_CHKPT); 5290Sstevel@tonic-gate 5305295Srandyf PMD(PMD_SX, ("cpr_suspend: send notice\n")) 5315295Srandyf #ifndef DEBUG 5320Sstevel@tonic-gate cpr_send_notice(); 5330Sstevel@tonic-gate if (cpr_debug) 5343446Smrj prom_printf("\n"); 5355295Srandyf #endif 5360Sstevel@tonic-gate 5375295Srandyf PMD(PMD_SX, ("cpr_suspend: POST USER callback\n")) 5380Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_USER, CB_CODE_CPR_CHKPT); 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate /* 5410Sstevel@tonic-gate * Reattach any drivers which originally exported the 5420Sstevel@tonic-gate * no-involuntary-power-cycles property. We need to do this before 5430Sstevel@tonic-gate * stopping kernel threads because modload is implemented using 5440Sstevel@tonic-gate * a kernel thread. 5450Sstevel@tonic-gate */ 5460Sstevel@tonic-gate cpr_set_substate(C_ST_PM_REATTACH_NOINVOL); 5475295Srandyf PMD(PMD_SX, ("cpr_suspend: reattach noinvol\n")) 5480Sstevel@tonic-gate if (!pm_reattach_noinvol()) 5490Sstevel@tonic-gate return (ENXIO); 5500Sstevel@tonic-gate 5515295Srandyf #if defined(__sparc) 5525295Srandyf ASSERT(sleeptype == CPR_TODISK); 5530Sstevel@tonic-gate /* 5540Sstevel@tonic-gate * if ufs logging is enabled, we need to disable before 5550Sstevel@tonic-gate * stopping kernel threads so that ufs delete and roll 5560Sstevel@tonic-gate * threads can do the work. 5570Sstevel@tonic-gate */ 5580Sstevel@tonic-gate cpr_set_substate(C_ST_DISABLE_UFS_LOGGING); 5590Sstevel@tonic-gate if (rc = cpr_ufs_logging(0)) 5600Sstevel@tonic-gate return (rc); 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate /* 5630Sstevel@tonic-gate * Use sync_all to swap out all user pages and find out how much 5640Sstevel@tonic-gate * extra space needed for user pages that don't have back store 5650Sstevel@tonic-gate * space left. 5660Sstevel@tonic-gate */ 5670Sstevel@tonic-gate CPR_STAT_EVENT_START(" swapout upages"); 5680Sstevel@tonic-gate vfs_sync(SYNC_ALL); 5690Sstevel@tonic-gate CPR_STAT_EVENT_END(" swapout upages"); 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate cpr_set_bitmap_size(); 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate alloc_statefile: 5740Sstevel@tonic-gate /* 5755295Srandyf * If our last state was C_ST_DUMP_NOSPC, we're trying to 5765295Srandyf * realloc the statefile, otherwise this is the first attempt. 5770Sstevel@tonic-gate */ 5780Sstevel@tonic-gate sf_realloc = (CPR->c_substate == C_ST_DUMP_NOSPC) ? 1 : 0; 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate CPR_STAT_EVENT_START(" alloc statefile"); 5810Sstevel@tonic-gate cpr_set_substate(C_ST_STATEF_ALLOC); 5820Sstevel@tonic-gate if (rc = cpr_alloc_statefile(sf_realloc)) { 5830Sstevel@tonic-gate if (sf_realloc) 5845295Srandyf errp("realloc failed\n"); 5850Sstevel@tonic-gate return (rc); 5860Sstevel@tonic-gate } 5870Sstevel@tonic-gate CPR_STAT_EVENT_END(" alloc statefile"); 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate /* 5900Sstevel@tonic-gate * Sync the filesystem to preserve its integrity. 5910Sstevel@tonic-gate * 5925295Srandyf * This sync is also used to flush out all B_DELWRI buffers 5935295Srandyf * (fs cache) which are mapped and neither dirty nor referenced 5945295Srandyf * before cpr_invalidate_pages destroys them. 5955295Srandyf * fsflush does similar thing. 5960Sstevel@tonic-gate */ 5970Sstevel@tonic-gate sync(); 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate /* 6000Sstevel@tonic-gate * destroy all clean file mapped kernel pages 6010Sstevel@tonic-gate */ 6020Sstevel@tonic-gate CPR_STAT_EVENT_START(" clean pages"); 6035295Srandyf CPR_DEBUG(CPR_DEBUG1, ("cleaning up mapped pages...")); 6040Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_VM, CB_CODE_CPR_CHKPT); 6055295Srandyf CPR_DEBUG(CPR_DEBUG1, ("done\n")); 6060Sstevel@tonic-gate CPR_STAT_EVENT_END(" clean pages"); 6075295Srandyf #endif 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate /* 6110Sstevel@tonic-gate * Hooks needed by lock manager prior to suspending. 6120Sstevel@tonic-gate * Refer to code for more comments. 6130Sstevel@tonic-gate */ 6145295Srandyf PMD(PMD_SX, ("cpr_suspend: lock mgr\n")) 6150Sstevel@tonic-gate cpr_lock_mgr(lm_cprsuspend); 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate /* 6180Sstevel@tonic-gate * Now suspend all the devices 6190Sstevel@tonic-gate */ 6200Sstevel@tonic-gate CPR_STAT_EVENT_START(" stop drivers"); 6213446Smrj CPR_DEBUG(CPR_DEBUG1, "suspending drivers..."); 6220Sstevel@tonic-gate cpr_set_substate(C_ST_SUSPEND_DEVICES); 6230Sstevel@tonic-gate pm_powering_down = 1; 6245295Srandyf PMD(PMD_SX, ("cpr_suspend: suspending devices\n")) 6250Sstevel@tonic-gate rc = cpr_suspend_devices(ddi_root_node()); 6260Sstevel@tonic-gate pm_powering_down = 0; 6270Sstevel@tonic-gate if (rc) 6280Sstevel@tonic-gate return (rc); 6293446Smrj CPR_DEBUG(CPR_DEBUG1, "done\n"); 6300Sstevel@tonic-gate CPR_STAT_EVENT_END(" stop drivers"); 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate /* 6330Sstevel@tonic-gate * Stop all daemon activities 6340Sstevel@tonic-gate */ 6350Sstevel@tonic-gate cpr_set_substate(C_ST_STOP_KERNEL_THREADS); 6365295Srandyf PMD(PMD_SX, ("cpr_suspend: stopping kernel threads\n")) 6370Sstevel@tonic-gate if (skt_rc = cpr_stop_kernel_threads()) 6380Sstevel@tonic-gate return (skt_rc); 6390Sstevel@tonic-gate 6405295Srandyf PMD(PMD_SX, ("cpr_suspend: POST KERNEL callback\n")) 6410Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_KERNEL, CB_CODE_CPR_CHKPT); 6420Sstevel@tonic-gate 6435295Srandyf PMD(PMD_SX, ("cpr_suspend: reattach noinvol fini\n")) 6440Sstevel@tonic-gate pm_reattach_noinvol_fini(); 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate cpr_sae(1); 6470Sstevel@tonic-gate 6485295Srandyf PMD(PMD_SX, ("cpr_suspend: CPR CALLOUT callback\n")) 6490Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_CALLOUT, CB_CODE_CPR_CHKPT); 6500Sstevel@tonic-gate 6515295Srandyf if (sleeptype == CPR_TODISK) { 6525295Srandyf /* 6535295Srandyf * It's safer to do tod_get before we disable all intr. 6545295Srandyf */ 6555295Srandyf CPR_STAT_EVENT_START(" write statefile"); 6565295Srandyf } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate /* 6590Sstevel@tonic-gate * it's time to ignore the outside world, stop the real time 6600Sstevel@tonic-gate * clock and disable any further intrpt activity. 6610Sstevel@tonic-gate */ 6625295Srandyf PMD(PMD_SX, ("cpr_suspend: handle xc\n")) 6630Sstevel@tonic-gate i_cpr_handle_xc(1); /* turn it on to disable xc assertion */ 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate mutex_enter(&cpu_lock); 6665295Srandyf PMD(PMD_SX, ("cpr_suspend: cyclic suspend\n")) 6670Sstevel@tonic-gate cyclic_suspend(); 6680Sstevel@tonic-gate mutex_exit(&cpu_lock); 6690Sstevel@tonic-gate 6705295Srandyf /* 6715295Srandyf * Due to the different methods of resuming the system between 6725295Srandyf * CPR_TODISK (boot cprboot on SPARC, which reloads kernel image) 6735295Srandyf * and CPR_TORAM (restart via reset into existing kernel image) 6745295Srandyf * cpus are not suspended and restored in the SPARC case, since it 6755295Srandyf * is necessary to restart the cpus and pause them before restoring 6765295Srandyf * the OBP image 6775295Srandyf */ 6785295Srandyf 6795295Srandyf #if defined(__x86) 6800Sstevel@tonic-gate 6815295Srandyf /* pause aux cpus */ 6825295Srandyf PMD(PMD_SX, ("pause aux cpus\n")) 6835295Srandyf 6845295Srandyf cpr_set_substate(C_ST_MP_PAUSED); 6855295Srandyf 6865295Srandyf if ((rc = cpr_suspend_cpus()) != 0) 6875295Srandyf return (rc); 6885295Srandyf #endif 6895295Srandyf 6905295Srandyf PMD(PMD_SX, ("cpr_suspend: stop intr\n")) 6910Sstevel@tonic-gate i_cpr_stop_intr(); 6923446Smrj CPR_DEBUG(CPR_DEBUG1, "interrupt is stopped\n"); 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate /* 6950Sstevel@tonic-gate * Since we will now disable the mechanism that causes prom_printfs 6960Sstevel@tonic-gate * to power up (if needed) the console fb/monitor, we assert that 6970Sstevel@tonic-gate * it must be up now. 6980Sstevel@tonic-gate */ 6990Sstevel@tonic-gate ASSERT(pm_cfb_is_up()); 7005295Srandyf PMD(PMD_SX, ("cpr_suspend: prom suspend prepost\n")) 7010Sstevel@tonic-gate prom_suspend_prepost(); 7020Sstevel@tonic-gate 7035295Srandyf #if defined(__sparc) 7040Sstevel@tonic-gate /* 7050Sstevel@tonic-gate * getting ready to write ourself out, flush the register 7060Sstevel@tonic-gate * windows to make sure that our stack is good when we 7070Sstevel@tonic-gate * come back on the resume side. 7080Sstevel@tonic-gate */ 7090Sstevel@tonic-gate flush_windows(); 7105295Srandyf #endif 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate /* 7135295Srandyf * For S3, we're done 7145295Srandyf */ 7155295Srandyf if (sleeptype == CPR_TORAM) { 7165295Srandyf PMD(PMD_SX, ("cpr_suspend rets %x\n", rc)) 7175295Srandyf cpr_set_substate(C_ST_NODUMP); 7185295Srandyf return (rc); 7195295Srandyf } 7205295Srandyf #if defined(__sparc) 7215295Srandyf /* 7220Sstevel@tonic-gate * FATAL: NO MORE MEMORY ALLOCATION ALLOWED AFTER THIS POINT!!! 7230Sstevel@tonic-gate * 7240Sstevel@tonic-gate * The system is quiesced at this point, we are ready to either dump 7250Sstevel@tonic-gate * to the state file for a extended sleep or a simple shutdown for 7260Sstevel@tonic-gate * systems with non-volatile memory. 7270Sstevel@tonic-gate */ 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate /* 7300Sstevel@tonic-gate * special handling for reusable: 7310Sstevel@tonic-gate */ 7320Sstevel@tonic-gate if (cpr_reusable_mode) { 7330Sstevel@tonic-gate cpr_set_substate(C_ST_SETPROPS_1); 7340Sstevel@tonic-gate if (nverr = cpr_set_properties(1)) 7350Sstevel@tonic-gate return (nverr); 7360Sstevel@tonic-gate } 7370Sstevel@tonic-gate 7380Sstevel@tonic-gate cpr_set_substate(C_ST_DUMP); 7390Sstevel@tonic-gate rc = cpr_dump(C_VP); 7400Sstevel@tonic-gate 7410Sstevel@tonic-gate /* 742*5331Samw * if any error occurred during dump, more 7430Sstevel@tonic-gate * special handling for reusable: 7440Sstevel@tonic-gate */ 7450Sstevel@tonic-gate if (rc && cpr_reusable_mode) { 7460Sstevel@tonic-gate cpr_set_substate(C_ST_SETPROPS_0); 7470Sstevel@tonic-gate if (nverr = cpr_set_properties(0)) 7480Sstevel@tonic-gate return (nverr); 7490Sstevel@tonic-gate } 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate if (rc == ENOSPC) { 7520Sstevel@tonic-gate cpr_set_substate(C_ST_DUMP_NOSPC); 7535295Srandyf (void) cpr_resume(sleeptype); 7540Sstevel@tonic-gate goto alloc_statefile; 7550Sstevel@tonic-gate } else if (rc == 0) { 7560Sstevel@tonic-gate if (cpr_reusable_mode) { 7570Sstevel@tonic-gate cpr_set_substate(C_ST_REUSABLE); 7580Sstevel@tonic-gate longjmp(&ttolwp(curthread)->lwp_qsav); 7590Sstevel@tonic-gate } else 7600Sstevel@tonic-gate rc = cpr_set_properties(1); 7610Sstevel@tonic-gate } 7625295Srandyf #endif 7635295Srandyf PMD(PMD_SX, ("cpr_suspend: return %d\n", rc)) 7640Sstevel@tonic-gate return (rc); 7650Sstevel@tonic-gate } 7660Sstevel@tonic-gate 7675295Srandyf void 7685295Srandyf cpr_resume_cpus(void) 7695295Srandyf { 7705295Srandyf /* 7715295Srandyf * this is a cut down version of start_other_cpus() 7725295Srandyf * just do the initialization to wake the other cpus 7735295Srandyf */ 7745295Srandyf 7755295Srandyf #if defined(__x86) 7765295Srandyf /* 7775295Srandyf * Initialize our syscall handlers 7785295Srandyf */ 7795295Srandyf init_cpu_syscall(CPU); 7805295Srandyf 7815295Srandyf #endif 7825295Srandyf 7835295Srandyf i_cpr_pre_resume_cpus(); 7845295Srandyf 7855295Srandyf /* 7865295Srandyf * Restart the paused cpus 7875295Srandyf */ 7885295Srandyf mutex_enter(&cpu_lock); 7895295Srandyf start_cpus(); 7905295Srandyf mutex_exit(&cpu_lock); 7915295Srandyf 7925295Srandyf /* 7935295Srandyf * clear the affinity set in cpr_suspend_cpus() 7945295Srandyf */ 7955295Srandyf affinity_clear(); 7965295Srandyf 7975295Srandyf i_cpr_post_resume_cpus(); 7985295Srandyf 7995295Srandyf mutex_enter(&cpu_lock); 8005295Srandyf /* 8015295Srandyf * Restore this cpu to use the regular cpu_pause(), so that 8025295Srandyf * online and offline will work correctly 8035295Srandyf */ 8045295Srandyf cpu_pause_func = NULL; 8055295Srandyf 8065295Srandyf /* 8075295Srandyf * offline all the cpus that were brought online during suspend 8085295Srandyf */ 8095295Srandyf cpr_restore_offline(); 8105295Srandyf 8115295Srandyf /* 8125295Srandyf * clear the affinity set in cpr_suspend_cpus() 8135295Srandyf */ 8145295Srandyf affinity_clear(); 8155295Srandyf 8165295Srandyf mutex_exit(&cpu_lock); 8175295Srandyf } 8185295Srandyf 8195295Srandyf void 8205295Srandyf cpr_unpause_cpus(void) 8215295Srandyf { 8225295Srandyf /* 8235295Srandyf * Now restore the system back to what it was before we suspended 8245295Srandyf */ 8255295Srandyf 8265295Srandyf PMD(PMD_SX, ("cpr_unpause_cpus: restoring system\n")) 8275295Srandyf 8285295Srandyf mutex_enter(&cpu_lock); 8295295Srandyf 8305295Srandyf /* 8315295Srandyf * Restore this cpu to use the regular cpu_pause(), so that 8325295Srandyf * online and offline will work correctly 8335295Srandyf */ 8345295Srandyf cpu_pause_func = NULL; 8355295Srandyf 8365295Srandyf /* 8375295Srandyf * Restart the paused cpus 8385295Srandyf */ 8395295Srandyf start_cpus(); 8405295Srandyf 8415295Srandyf /* 8425295Srandyf * offline all the cpus that were brought online during suspend 8435295Srandyf */ 8445295Srandyf cpr_restore_offline(); 8455295Srandyf 8465295Srandyf /* 8475295Srandyf * clear the affinity set in cpr_suspend_cpus() 8485295Srandyf */ 8495295Srandyf affinity_clear(); 8505295Srandyf 8515295Srandyf mutex_exit(&cpu_lock); 8525295Srandyf } 8530Sstevel@tonic-gate 8540Sstevel@tonic-gate /* 8550Sstevel@tonic-gate * Bring the system back up from a checkpoint, at this point 8560Sstevel@tonic-gate * the VM has been minimally restored by boot, the following 8570Sstevel@tonic-gate * are executed sequentially: 8580Sstevel@tonic-gate * 8590Sstevel@tonic-gate * - machdep setup and enable interrupts (mp startup if it's mp) 8600Sstevel@tonic-gate * - resume all devices 8610Sstevel@tonic-gate * - restart daemons 8620Sstevel@tonic-gate * - put all threads back on run queue 8630Sstevel@tonic-gate */ 8640Sstevel@tonic-gate static int 8655295Srandyf cpr_resume(int sleeptype) 8660Sstevel@tonic-gate { 8670Sstevel@tonic-gate cpr_time_t pwron_tv, *ctp; 8680Sstevel@tonic-gate char *str; 8690Sstevel@tonic-gate int rc = 0; 8700Sstevel@tonic-gate 8710Sstevel@tonic-gate /* 8720Sstevel@tonic-gate * The following switch is used to resume the system 8730Sstevel@tonic-gate * that was suspended to a different level. 8740Sstevel@tonic-gate */ 8753446Smrj CPR_DEBUG(CPR_DEBUG1, "\nEntering cpr_resume...\n"); 8765295Srandyf PMD(PMD_SX, ("cpr_resume %x\n", sleeptype)) 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate /* 8790Sstevel@tonic-gate * Note: 8800Sstevel@tonic-gate * 8810Sstevel@tonic-gate * The rollback labels rb_xyz do not represent the cpr resume 8820Sstevel@tonic-gate * state when event 'xyz' has happened. Instead they represent 8830Sstevel@tonic-gate * the state during cpr suspend when event 'xyz' was being 8840Sstevel@tonic-gate * entered (and where cpr suspend failed). The actual call that 8850Sstevel@tonic-gate * failed may also need to be partially rolled back, since they 8860Sstevel@tonic-gate * aren't atomic in most cases. In other words, rb_xyz means 8870Sstevel@tonic-gate * "roll back all cpr suspend events that happened before 'xyz', 8880Sstevel@tonic-gate * and the one that caused the failure, if necessary." 8890Sstevel@tonic-gate */ 8900Sstevel@tonic-gate switch (CPR->c_substate) { 8915295Srandyf #if defined(__sparc) 8920Sstevel@tonic-gate case C_ST_DUMP: 8930Sstevel@tonic-gate /* 8940Sstevel@tonic-gate * This is most likely a full-fledged cpr_resume after 8950Sstevel@tonic-gate * a complete and successful cpr suspend. Just roll back 8960Sstevel@tonic-gate * everything. 8970Sstevel@tonic-gate */ 8985295Srandyf ASSERT(sleeptype == CPR_TODISK); 8990Sstevel@tonic-gate break; 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate case C_ST_REUSABLE: 9020Sstevel@tonic-gate case C_ST_DUMP_NOSPC: 9030Sstevel@tonic-gate case C_ST_SETPROPS_0: 9040Sstevel@tonic-gate case C_ST_SETPROPS_1: 9050Sstevel@tonic-gate /* 9060Sstevel@tonic-gate * C_ST_REUSABLE and C_ST_DUMP_NOSPC are the only two 9070Sstevel@tonic-gate * special switch cases here. The other two do not have 9080Sstevel@tonic-gate * any state change during cpr_suspend() that needs to 9090Sstevel@tonic-gate * be rolled back. But these are exit points from 9100Sstevel@tonic-gate * cpr_suspend, so theoretically (or in the future), it 9110Sstevel@tonic-gate * is possible that a need for roll back of a state 9120Sstevel@tonic-gate * change arises between these exit points. 9130Sstevel@tonic-gate */ 9145295Srandyf ASSERT(sleeptype == CPR_TODISK); 9150Sstevel@tonic-gate goto rb_dump; 9165295Srandyf #endif 9175295Srandyf 9185295Srandyf case C_ST_NODUMP: 9195295Srandyf PMD(PMD_SX, ("cpr_resume: NODUMP\n")) 9205295Srandyf goto rb_nodump; 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate case C_ST_STOP_KERNEL_THREADS: 9235295Srandyf PMD(PMD_SX, ("cpr_resume: STOP_KERNEL_THREADS\n")) 9240Sstevel@tonic-gate goto rb_stop_kernel_threads; 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate case C_ST_SUSPEND_DEVICES: 9275295Srandyf PMD(PMD_SX, ("cpr_resume: SUSPEND_DEVICES\n")) 9280Sstevel@tonic-gate goto rb_suspend_devices; 9290Sstevel@tonic-gate 9305295Srandyf #if defined(__sparc) 9310Sstevel@tonic-gate case C_ST_STATEF_ALLOC: 9325295Srandyf ASSERT(sleeptype == CPR_TODISK); 9330Sstevel@tonic-gate goto rb_statef_alloc; 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate case C_ST_DISABLE_UFS_LOGGING: 9365295Srandyf ASSERT(sleeptype == CPR_TODISK); 9370Sstevel@tonic-gate goto rb_disable_ufs_logging; 9385295Srandyf #endif 9390Sstevel@tonic-gate 9400Sstevel@tonic-gate case C_ST_PM_REATTACH_NOINVOL: 9415295Srandyf PMD(PMD_SX, ("cpr_resume: REATTACH_NOINVOL\n")) 9420Sstevel@tonic-gate goto rb_pm_reattach_noinvol; 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate case C_ST_STOP_USER_THREADS: 9455295Srandyf PMD(PMD_SX, ("cpr_resume: STOP_USER_THREADS\n")) 9460Sstevel@tonic-gate goto rb_stop_user_threads; 9470Sstevel@tonic-gate 9485295Srandyf #if defined(__sparc) 9490Sstevel@tonic-gate case C_ST_MP_OFFLINE: 9505295Srandyf PMD(PMD_SX, ("cpr_resume: MP_OFFLINE\n")) 9510Sstevel@tonic-gate goto rb_mp_offline; 9525295Srandyf #endif 9535295Srandyf 9545295Srandyf #if defined(__x86) 9555295Srandyf case C_ST_MP_PAUSED: 9565295Srandyf PMD(PMD_SX, ("cpr_resume: MP_PAUSED\n")) 9575295Srandyf goto rb_mp_paused; 9585295Srandyf #endif 9595295Srandyf 9600Sstevel@tonic-gate 9610Sstevel@tonic-gate default: 9625295Srandyf PMD(PMD_SX, ("cpr_resume: others\n")) 9630Sstevel@tonic-gate goto rb_others; 9640Sstevel@tonic-gate } 9650Sstevel@tonic-gate 9660Sstevel@tonic-gate rb_all: 9670Sstevel@tonic-gate /* 9680Sstevel@tonic-gate * perform platform-dependent initialization 9690Sstevel@tonic-gate */ 9700Sstevel@tonic-gate if (cpr_suspend_succeeded) 9710Sstevel@tonic-gate i_cpr_machdep_setup(); 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate /* 9740Sstevel@tonic-gate * system did not really go down if we jump here 9750Sstevel@tonic-gate */ 9760Sstevel@tonic-gate rb_dump: 9770Sstevel@tonic-gate /* 9780Sstevel@tonic-gate * IMPORTANT: SENSITIVE RESUME SEQUENCE 9790Sstevel@tonic-gate * 9800Sstevel@tonic-gate * DO NOT ADD ANY INITIALIZATION STEP BEFORE THIS POINT!! 9810Sstevel@tonic-gate */ 9825295Srandyf rb_nodump: 9835295Srandyf /* 9845295Srandyf * If we did suspend to RAM, we didn't generate a dump 9855295Srandyf */ 9865295Srandyf PMD(PMD_SX, ("cpr_resume: CPR DMA callback\n")) 9870Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_DMA, CB_CODE_CPR_RESUME); 9885295Srandyf if (cpr_suspend_succeeded) { 9895295Srandyf PMD(PMD_SX, ("cpr_resume: CPR RPC callback\n")) 9900Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_RPC, CB_CODE_CPR_RESUME); 9915295Srandyf } 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate prom_resume_prepost(); 9945295Srandyf #if !defined(__sparc) 9955295Srandyf /* 9965295Srandyf * Need to sync the software clock with the hardware clock. 9975295Srandyf * On Sparc, this occurs in the sparc-specific cbe. However 9985295Srandyf * on x86 this needs to be handled _before_ we bring other cpu's 9995295Srandyf * back online. So we call a resume function in timestamp.c 10005295Srandyf */ 10015295Srandyf if (tsc_resume_in_cyclic == 0) 10025295Srandyf tsc_resume(); 10030Sstevel@tonic-gate 10045295Srandyf #endif 10055295Srandyf 10065295Srandyf #if defined(__sparc) 10070Sstevel@tonic-gate if (cpr_suspend_succeeded && (boothowto & RB_DEBUG)) 10080Sstevel@tonic-gate kdi_dvec_cpr_restart(); 10095295Srandyf #endif 10105295Srandyf 10115295Srandyf 10125295Srandyf #if defined(__x86) 10135295Srandyf rb_mp_paused: 10145295Srandyf PT(PT_RMPO); 10155295Srandyf PMD(PMD_SX, ("resume aux cpus\n")) 10165295Srandyf 10175295Srandyf if (cpr_suspend_succeeded) { 10185295Srandyf cpr_resume_cpus(); 10195295Srandyf } else { 10205295Srandyf cpr_unpause_cpus(); 10215295Srandyf } 10225295Srandyf #endif 10230Sstevel@tonic-gate 10240Sstevel@tonic-gate /* 10250Sstevel@tonic-gate * let the tmp callout catch up. 10260Sstevel@tonic-gate */ 10275295Srandyf PMD(PMD_SX, ("cpr_resume: CPR CALLOUT callback\n")) 10280Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_CALLOUT, CB_CODE_CPR_RESUME); 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate i_cpr_enable_intr(); 10310Sstevel@tonic-gate 10320Sstevel@tonic-gate mutex_enter(&cpu_lock); 10335295Srandyf PMD(PMD_SX, ("cpr_resume: cyclic resume\n")) 10340Sstevel@tonic-gate cyclic_resume(); 10350Sstevel@tonic-gate mutex_exit(&cpu_lock); 10360Sstevel@tonic-gate 10375295Srandyf PMD(PMD_SX, ("cpr_resume: handle xc\n")) 10380Sstevel@tonic-gate i_cpr_handle_xc(0); /* turn it off to allow xc assertion */ 10390Sstevel@tonic-gate 10405295Srandyf PMD(PMD_SX, ("cpr_resume: CPR POST KERNEL callback\n")) 10410Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_KERNEL, CB_CODE_CPR_RESUME); 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate /* 10440Sstevel@tonic-gate * statistics gathering 10450Sstevel@tonic-gate */ 10460Sstevel@tonic-gate if (cpr_suspend_succeeded) { 10470Sstevel@tonic-gate /* 10480Sstevel@tonic-gate * Prevent false alarm in tod_validate() due to tod 10490Sstevel@tonic-gate * value change between suspend and resume 10500Sstevel@tonic-gate */ 10510Sstevel@tonic-gate cpr_tod_fault_reset(); 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate cpr_convert_promtime(&pwron_tv); 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate ctp = &cpr_term.tm_shutdown; 10565295Srandyf if (sleeptype == CPR_TODISK) 10575295Srandyf CPR_STAT_EVENT_END_TMZ(" write statefile", ctp); 10580Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ("Suspend Total", ctp); 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ("Resume Total", &pwron_tv); 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate str = " prom time"; 10630Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ(str, &pwron_tv); 10640Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_start; 10650Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ(str, ctp); 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate str = " read statefile"; 10680Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ(str, ctp); 10690Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_end; 10700Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ(str, ctp); 10710Sstevel@tonic-gate } 10720Sstevel@tonic-gate 10730Sstevel@tonic-gate rb_stop_kernel_threads: 10740Sstevel@tonic-gate /* 10750Sstevel@tonic-gate * Put all threads back to where they belong; get the kernel 10760Sstevel@tonic-gate * daemons straightened up too. Note that the callback table 10770Sstevel@tonic-gate * locked during cpr_stop_kernel_threads() is released only 10780Sstevel@tonic-gate * in cpr_start_kernel_threads(). Ensure modunloading is 10790Sstevel@tonic-gate * disabled before starting kernel threads, we don't want 10800Sstevel@tonic-gate * modunload thread to start changing device tree underneath. 10810Sstevel@tonic-gate */ 10825295Srandyf PMD(PMD_SX, ("cpr_resume: modunload disable\n")) 10830Sstevel@tonic-gate modunload_disable(); 10845295Srandyf PMD(PMD_SX, ("cpr_resume: start kernel threads\n")) 10850Sstevel@tonic-gate cpr_start_kernel_threads(); 10860Sstevel@tonic-gate 10870Sstevel@tonic-gate rb_suspend_devices: 10883446Smrj CPR_DEBUG(CPR_DEBUG1, "resuming devices..."); 10890Sstevel@tonic-gate CPR_STAT_EVENT_START(" start drivers"); 10900Sstevel@tonic-gate 10915295Srandyf PMD(PMD_SX, 10925295Srandyf ("cpr_resume: rb_suspend_devices: cpr_resume_uniproc = %d\n", 10935295Srandyf cpr_resume_uniproc)) 10945295Srandyf 10955295Srandyf #if defined(__x86) 10965295Srandyf /* 10975295Srandyf * If cpr_resume_uniproc is set, then pause all the other cpus 10985295Srandyf * apart from the current cpu, so that broken drivers that think 10995295Srandyf * that they are on a uniprocessor machine will resume 11005295Srandyf */ 11015295Srandyf if (cpr_resume_uniproc) { 11025295Srandyf mutex_enter(&cpu_lock); 11035295Srandyf pause_cpus(NULL); 11045295Srandyf mutex_exit(&cpu_lock); 11055295Srandyf } 11065295Srandyf #endif 11075295Srandyf 11080Sstevel@tonic-gate /* 11090Sstevel@tonic-gate * The policy here is to continue resume everything we can if we did 11100Sstevel@tonic-gate * not successfully finish suspend; and panic if we are coming back 11110Sstevel@tonic-gate * from a fully suspended system. 11120Sstevel@tonic-gate */ 11135295Srandyf PMD(PMD_SX, ("cpr_resume: resume devices\n")) 11140Sstevel@tonic-gate rc = cpr_resume_devices(ddi_root_node(), 0); 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate cpr_sae(0); 11170Sstevel@tonic-gate 11180Sstevel@tonic-gate str = "Failed to resume one or more devices."; 11195295Srandyf 11205295Srandyf if (rc) { 11215295Srandyf if (CPR->c_substate == C_ST_DUMP || 11225295Srandyf (sleeptype == CPR_TORAM && 11235295Srandyf CPR->c_substate == C_ST_NODUMP)) { 11245295Srandyf if (cpr_test_point == FORCE_SUSPEND_TO_RAM) { 11255295Srandyf PMD(PMD_SX, ("cpr_resume: resume device " 11265295Srandyf "warn\n")) 11275295Srandyf cpr_err(CE_WARN, str); 11285295Srandyf } else { 11295295Srandyf PMD(PMD_SX, ("cpr_resume: resume device " 11305295Srandyf "panic\n")) 11315295Srandyf cpr_err(CE_PANIC, str); 11325295Srandyf } 11335295Srandyf } else { 11345295Srandyf PMD(PMD_SX, ("cpr_resume: resume device warn\n")) 11355295Srandyf cpr_err(CE_WARN, str); 11365295Srandyf } 11375295Srandyf } 11385295Srandyf 11390Sstevel@tonic-gate CPR_STAT_EVENT_END(" start drivers"); 11403446Smrj CPR_DEBUG(CPR_DEBUG1, "done\n"); 11410Sstevel@tonic-gate 11425295Srandyf #if defined(__x86) 11435295Srandyf /* 11445295Srandyf * If cpr_resume_uniproc is set, then unpause all the processors 11455295Srandyf * that were paused before resuming the drivers 11465295Srandyf */ 11475295Srandyf if (cpr_resume_uniproc) { 11485295Srandyf mutex_enter(&cpu_lock); 11495295Srandyf start_cpus(); 11505295Srandyf mutex_exit(&cpu_lock); 11515295Srandyf } 11525295Srandyf #endif 11535295Srandyf 11540Sstevel@tonic-gate /* 11550Sstevel@tonic-gate * If we had disabled modunloading in this cpr resume cycle (i.e. we 11560Sstevel@tonic-gate * resumed from a state earlier than C_ST_SUSPEND_DEVICES), re-enable 11570Sstevel@tonic-gate * modunloading now. 11580Sstevel@tonic-gate */ 11595295Srandyf if (CPR->c_substate != C_ST_SUSPEND_DEVICES) { 11605295Srandyf PMD(PMD_SX, ("cpr_resume: modload enable\n")) 11610Sstevel@tonic-gate modunload_enable(); 11625295Srandyf } 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate /* 11650Sstevel@tonic-gate * Hooks needed by lock manager prior to resuming. 11660Sstevel@tonic-gate * Refer to code for more comments. 11670Sstevel@tonic-gate */ 11685295Srandyf PMD(PMD_SX, ("cpr_resume: lock mgr\n")) 11690Sstevel@tonic-gate cpr_lock_mgr(lm_cprresume); 11700Sstevel@tonic-gate 11715295Srandyf #if defined(__sparc) 11720Sstevel@tonic-gate /* 11730Sstevel@tonic-gate * This is a partial (half) resume during cpr suspend, we 11740Sstevel@tonic-gate * haven't yet given up on the suspend. On return from here, 11750Sstevel@tonic-gate * cpr_suspend() will try to reallocate and retry the suspend. 11760Sstevel@tonic-gate */ 11770Sstevel@tonic-gate if (CPR->c_substate == C_ST_DUMP_NOSPC) { 11780Sstevel@tonic-gate return (0); 11790Sstevel@tonic-gate } 11800Sstevel@tonic-gate 11815295Srandyf if (sleeptype == CPR_TODISK) { 11820Sstevel@tonic-gate rb_statef_alloc: 11835295Srandyf cpr_statef_close(); 11840Sstevel@tonic-gate 11850Sstevel@tonic-gate rb_disable_ufs_logging: 11865295Srandyf /* 11875295Srandyf * if ufs logging was disabled, re-enable 11885295Srandyf */ 11895295Srandyf (void) cpr_ufs_logging(1); 11905295Srandyf } 11915295Srandyf #endif 11920Sstevel@tonic-gate 11930Sstevel@tonic-gate rb_pm_reattach_noinvol: 11940Sstevel@tonic-gate /* 11950Sstevel@tonic-gate * When pm_reattach_noinvol() succeeds, modunload_thread will 11960Sstevel@tonic-gate * remain disabled until after cpr suspend passes the 11970Sstevel@tonic-gate * C_ST_STOP_KERNEL_THREADS state. If any failure happens before 11980Sstevel@tonic-gate * cpr suspend reaches this state, we'll need to enable modunload 11990Sstevel@tonic-gate * thread during rollback. 12000Sstevel@tonic-gate */ 12010Sstevel@tonic-gate if (CPR->c_substate == C_ST_DISABLE_UFS_LOGGING || 12020Sstevel@tonic-gate CPR->c_substate == C_ST_STATEF_ALLOC || 12030Sstevel@tonic-gate CPR->c_substate == C_ST_SUSPEND_DEVICES || 12040Sstevel@tonic-gate CPR->c_substate == C_ST_STOP_KERNEL_THREADS) { 12055295Srandyf PMD(PMD_SX, ("cpr_resume: reattach noinvol fini\n")) 12060Sstevel@tonic-gate pm_reattach_noinvol_fini(); 12070Sstevel@tonic-gate } 12080Sstevel@tonic-gate 12095295Srandyf PMD(PMD_SX, ("cpr_resume: CPR POST USER callback\n")) 12100Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_USER, CB_CODE_CPR_RESUME); 12115295Srandyf PMD(PMD_SX, ("cpr_resume: CPR PROMPRINTF callback\n")) 12120Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PROMPRINTF, CB_CODE_CPR_RESUME); 12130Sstevel@tonic-gate 12145295Srandyf PMD(PMD_SX, ("cpr_resume: restore direct levels\n")) 12150Sstevel@tonic-gate pm_restore_direct_levels(); 12160Sstevel@tonic-gate 12170Sstevel@tonic-gate rb_stop_user_threads: 12183446Smrj CPR_DEBUG(CPR_DEBUG1, "starting user threads..."); 12195295Srandyf PMD(PMD_SX, ("cpr_resume: starting user threads\n")) 12200Sstevel@tonic-gate cpr_start_user_threads(); 12213446Smrj CPR_DEBUG(CPR_DEBUG1, "done\n"); 12225295Srandyf /* 12235295Srandyf * Ask Xorg to resume the frame buffer, and wait for it to happen 12245295Srandyf */ 12255295Srandyf mutex_enter(&srn_clone_lock); 12265295Srandyf if (srn_signal) { 12275295Srandyf PMD(PMD_SX, ("cpr_suspend: (*srn_signal)(..., " 12285295Srandyf "SRN_NORMAL_RESUME)\n")) 12295295Srandyf srn_inuse = 1; /* because (*srn_signal) cv_waits */ 12305295Srandyf (*srn_signal)(SRN_TYPE_APM, SRN_NORMAL_RESUME); 12315295Srandyf srn_inuse = 0; 12325295Srandyf } else { 12335295Srandyf PMD(PMD_SX, ("cpr_suspend: srn_signal NULL\n")) 12345295Srandyf } 12355295Srandyf mutex_exit(&srn_clone_lock); 12360Sstevel@tonic-gate 12375295Srandyf #if defined(__sparc) 12380Sstevel@tonic-gate rb_mp_offline: 12390Sstevel@tonic-gate if (cpr_mp_online()) 12400Sstevel@tonic-gate cpr_err(CE_WARN, "Failed to online all the processors."); 12415295Srandyf #endif 12420Sstevel@tonic-gate 12430Sstevel@tonic-gate rb_others: 12445295Srandyf PMD(PMD_SX, ("cpr_resume: dep thread\n")) 12455295Srandyf pm_dispatch_to_dep_thread(PM_DEP_WK_CPR_RESUME, NULL, NULL, 12465295Srandyf PM_DEP_WAIT, NULL, 0); 12470Sstevel@tonic-gate 12485295Srandyf PMD(PMD_SX, ("cpr_resume: CPR PM callback\n")) 12490Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PM, CB_CODE_CPR_RESUME); 12500Sstevel@tonic-gate 12510Sstevel@tonic-gate if (cpr_suspend_succeeded) { 12520Sstevel@tonic-gate cpr_stat_record_events(); 12530Sstevel@tonic-gate } 12540Sstevel@tonic-gate 12555295Srandyf #if defined(__sparc) 12565295Srandyf if (sleeptype == CPR_TODISK && !cpr_reusable_mode) 12570Sstevel@tonic-gate cpr_clear_definfo(); 12585295Srandyf #endif 12590Sstevel@tonic-gate 12605295Srandyf i_cpr_free_cpus(); 12613446Smrj CPR_DEBUG(CPR_DEBUG1, "Sending SIGTHAW..."); 12625295Srandyf PMD(PMD_SX, ("cpr_resume: SIGTHAW\n")) 12630Sstevel@tonic-gate cpr_signal_user(SIGTHAW); 12643446Smrj CPR_DEBUG(CPR_DEBUG1, "done\n"); 12650Sstevel@tonic-gate 12660Sstevel@tonic-gate CPR_STAT_EVENT_END("Resume Total"); 12670Sstevel@tonic-gate 12680Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ("WHOLE CYCLE", &wholecycle_tv); 12690Sstevel@tonic-gate CPR_STAT_EVENT_END("WHOLE CYCLE"); 12700Sstevel@tonic-gate 12713446Smrj if (cpr_debug & CPR_DEBUG1) 12723446Smrj cmn_err(CE_CONT, "\nThe system is back where you left!\n"); 12730Sstevel@tonic-gate 12740Sstevel@tonic-gate CPR_STAT_EVENT_START("POST CPR DELAY"); 12750Sstevel@tonic-gate 12760Sstevel@tonic-gate #ifdef CPR_STAT 12770Sstevel@tonic-gate ctp = &cpr_term.tm_shutdown; 12780Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ("PWROFF TIME", ctp); 12790Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ("PWROFF TIME", &pwron_tv); 12800Sstevel@tonic-gate 12810Sstevel@tonic-gate CPR_STAT_EVENT_PRINT(); 12820Sstevel@tonic-gate #endif /* CPR_STAT */ 12830Sstevel@tonic-gate 12845295Srandyf PMD(PMD_SX, ("cpr_resume returns %x\n", rc)) 12850Sstevel@tonic-gate return (rc); 12860Sstevel@tonic-gate } 12870Sstevel@tonic-gate 12880Sstevel@tonic-gate static void 12895295Srandyf cpr_suspend_init(int sleeptype) 12900Sstevel@tonic-gate { 12910Sstevel@tonic-gate cpr_time_t *ctp; 12920Sstevel@tonic-gate 12930Sstevel@tonic-gate cpr_stat_init(); 12940Sstevel@tonic-gate 12950Sstevel@tonic-gate /* 12960Sstevel@tonic-gate * If cpr_suspend() failed before cpr_dump() gets a chance 12970Sstevel@tonic-gate * to reinitialize the terminator of the statefile, 12980Sstevel@tonic-gate * the values of the old terminator will still linger around. 12990Sstevel@tonic-gate * Since the terminator contains information that we need to 13000Sstevel@tonic-gate * decide whether suspend succeeded or not, we need to 13010Sstevel@tonic-gate * reinitialize it as early as possible. 13020Sstevel@tonic-gate */ 13030Sstevel@tonic-gate cpr_term.real_statef_size = 0; 13040Sstevel@tonic-gate ctp = &cpr_term.tm_shutdown; 13050Sstevel@tonic-gate bzero(ctp, sizeof (*ctp)); 13060Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_start; 13070Sstevel@tonic-gate bzero(ctp, sizeof (*ctp)); 13080Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_end; 13090Sstevel@tonic-gate bzero(ctp, sizeof (*ctp)); 13100Sstevel@tonic-gate 13115295Srandyf if (sleeptype == CPR_TODISK) { 13125295Srandyf /* 13135295Srandyf * Lookup the physical address of our thread structure. 13145295Srandyf * This should never be invalid and the entire thread structure 13155295Srandyf * is expected to reside within the same pfn. 13165295Srandyf */ 13175295Srandyf curthreadpfn = hat_getpfnum(kas.a_hat, (caddr_t)curthread); 13185295Srandyf ASSERT(curthreadpfn != PFN_INVALID); 13195295Srandyf ASSERT(curthreadpfn == hat_getpfnum(kas.a_hat, 13205295Srandyf (caddr_t)curthread + sizeof (kthread_t) - 1)); 13215295Srandyf } 13220Sstevel@tonic-gate 13230Sstevel@tonic-gate cpr_suspend_succeeded = 0; 13240Sstevel@tonic-gate } 13255295Srandyf 13265295Srandyf /* 13275295Srandyf * bring all the offline cpus online 13285295Srandyf */ 13295295Srandyf static int 13305295Srandyf cpr_all_online(void) 13315295Srandyf { 13325295Srandyf int rc = 0; 13335295Srandyf 13345295Srandyf #ifdef __sparc 13355295Srandyf /* 13365295Srandyf * do nothing 13375295Srandyf */ 13385295Srandyf #else 13395295Srandyf 13405295Srandyf cpu_t *cp; 13415295Srandyf 13425295Srandyf ASSERT(MUTEX_HELD(&cpu_lock)); 13435295Srandyf 13445295Srandyf cp = cpu_list; 13455295Srandyf do { 13465295Srandyf cp->cpu_cpr_flags &= ~CPU_CPR_ONLINE; 13475295Srandyf if (!CPU_ACTIVE(cp)) { 13485295Srandyf if ((rc = cpu_online(cp)) != 0) 13495295Srandyf break; 13505295Srandyf CPU_SET_CPR_FLAGS(cp, CPU_CPR_ONLINE); 13515295Srandyf } 13525295Srandyf } while ((cp = cp->cpu_next) != cpu_list); 13535295Srandyf 13545295Srandyf if (rc) { 13555295Srandyf /* 13565295Srandyf * an online operation failed so offline the cpus 13575295Srandyf * that were onlined above to restore the system 13585295Srandyf * to its original state 13595295Srandyf */ 13605295Srandyf cpr_restore_offline(); 13615295Srandyf } 13625295Srandyf #endif 13635295Srandyf return (rc); 13645295Srandyf } 13655295Srandyf 13665295Srandyf /* 13675295Srandyf * offline all the cpus that were brought online by cpr_all_online() 13685295Srandyf */ 13695295Srandyf static void 13705295Srandyf cpr_restore_offline(void) 13715295Srandyf { 13725295Srandyf 13735295Srandyf #ifdef __sparc 13745295Srandyf /* 13755295Srandyf * do nothing 13765295Srandyf */ 13775295Srandyf #else 13785295Srandyf 13795295Srandyf cpu_t *cp; 13805295Srandyf int rc = 0; 13815295Srandyf 13825295Srandyf ASSERT(MUTEX_HELD(&cpu_lock)); 13835295Srandyf 13845295Srandyf cp = cpu_list; 13855295Srandyf do { 13865295Srandyf if (CPU_CPR_IS_ONLINE(cp)) { 13875295Srandyf rc = cpu_offline(cp, 0); 13885295Srandyf /* 13895295Srandyf * this offline should work, since the cpu was 13905295Srandyf * offline originally and was successfully onlined 13915295Srandyf * by cpr_all_online() 13925295Srandyf */ 13935295Srandyf ASSERT(rc == 0); 13945295Srandyf cp->cpu_cpr_flags &= ~CPU_CPR_ONLINE; 13955295Srandyf } 13965295Srandyf } while ((cp = cp->cpu_next) != cpu_list); 13975295Srandyf 13985295Srandyf #endif 13995295Srandyf 14005295Srandyf } 1401