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 /* 22*5817Sjan * Copyright 2008 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, 2625331Samw (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, 2905331Samw 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; 3415331Samw (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); 3605331Samw (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 int ret = 0; 3845295Srandyf extern void *i_cpr_save_context(void *arg); 3855295Srandyf 3865295Srandyf mutex_enter(&cpu_lock); 3875295Srandyf 3885295Srandyf /* 3895295Srandyf * the machine could not have booted without a bootcpu 3905295Srandyf */ 391*5817Sjan ASSERT(i_cpr_bootcpu() != NULL); 3925295Srandyf 3935295Srandyf /* 3945295Srandyf * bring all the offline cpus online 3955295Srandyf */ 3965295Srandyf if ((ret = cpr_all_online())) { 3975295Srandyf mutex_exit(&cpu_lock); 3985295Srandyf return (ret); 3995295Srandyf } 4005295Srandyf 4015295Srandyf /* 4025295Srandyf * Set the affinity to be the boot processor 4035295Srandyf * This is cleared in either cpr_resume_cpus() or cpr_unpause_cpus() 4045295Srandyf */ 4055295Srandyf affinity_set(i_cpr_bootcpuid()); 4065295Srandyf 4075295Srandyf ASSERT(CPU->cpu_id == 0); 4085295Srandyf 4095295Srandyf PMD(PMD_SX, ("curthread running on bootcpu\n")) 4105295Srandyf 4115295Srandyf /* 4125295Srandyf * pause all other running CPUs and save the CPU state at the sametime 4135295Srandyf */ 4145295Srandyf cpu_pause_func = i_cpr_save_context; 4155295Srandyf pause_cpus(NULL); 4165295Srandyf 4175295Srandyf mutex_exit(&cpu_lock); 4185295Srandyf 4195295Srandyf return (0); 4205295Srandyf } 4215295Srandyf 4220Sstevel@tonic-gate /* 4230Sstevel@tonic-gate * Take the system down to a checkpointable state and write 4240Sstevel@tonic-gate * the state file, the following are sequentially executed: 4250Sstevel@tonic-gate * 4260Sstevel@tonic-gate * - Request all user threads to stop themselves 4270Sstevel@tonic-gate * - push out and invalidate user pages 4280Sstevel@tonic-gate * - bring statefile inode incore to prevent a miss later 4290Sstevel@tonic-gate * - request all daemons to stop 4300Sstevel@tonic-gate * - check and make sure all threads are stopped 4310Sstevel@tonic-gate * - sync the file system 4320Sstevel@tonic-gate * - suspend all devices 4330Sstevel@tonic-gate * - block intrpts 4340Sstevel@tonic-gate * - dump system state and memory to state file 4355295Srandyf * - SPARC code will not be called with CPR_TORAM, caller filters 4360Sstevel@tonic-gate */ 4370Sstevel@tonic-gate static int 4385295Srandyf cpr_suspend(int sleeptype) 4390Sstevel@tonic-gate { 4405295Srandyf #if defined(__sparc) 4415295Srandyf int sf_realloc, nverr; 4425295Srandyf #endif 4435295Srandyf int rc = 0; 4445295Srandyf int skt_rc = 0; 4450Sstevel@tonic-gate 4465295Srandyf PMD(PMD_SX, ("cpr_suspend %x\n", sleeptype)) 4470Sstevel@tonic-gate cpr_set_substate(C_ST_SUSPEND_BEGIN); 4480Sstevel@tonic-gate 4495295Srandyf cpr_suspend_init(sleeptype); 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate cpr_save_time(); 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate cpr_tod_get(&wholecycle_tv); 4540Sstevel@tonic-gate CPR_STAT_EVENT_START("Suspend Total"); 4550Sstevel@tonic-gate 4565295Srandyf i_cpr_alloc_cpus(); 4575295Srandyf 4585295Srandyf #if defined(__sparc) 4595295Srandyf ASSERT(sleeptype == CPR_TODISK); 4600Sstevel@tonic-gate if (!cpr_reusable_mode) { 4610Sstevel@tonic-gate /* 4625295Srandyf * We need to validate default file before fs 4635295Srandyf * functionality is disabled. 4640Sstevel@tonic-gate */ 4650Sstevel@tonic-gate if (rc = cpr_validate_definfo(0)) 4660Sstevel@tonic-gate return (rc); 4670Sstevel@tonic-gate } 4685295Srandyf i_cpr_save_machdep_info(); 4695295Srandyf #endif 4700Sstevel@tonic-gate 4715295Srandyf PMD(PMD_SX, ("cpr_suspend: stop scans\n")) 4720Sstevel@tonic-gate /* Stop PM scans ASAP */ 4730Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PM, CB_CODE_CPR_CHKPT); 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_CPR_SUSPEND, 4760Sstevel@tonic-gate NULL, NULL, PM_DEP_WAIT, NULL, 0); 4770Sstevel@tonic-gate 4785295Srandyf #if defined(__sparc) 4795295Srandyf ASSERT(sleeptype == CPR_TODISK); 4800Sstevel@tonic-gate cpr_set_substate(C_ST_MP_OFFLINE); 4810Sstevel@tonic-gate if (rc = cpr_mp_offline()) 4820Sstevel@tonic-gate return (rc); 4835295Srandyf #endif 4845295Srandyf /* 4855295Srandyf * Ask Xorg to suspend the frame buffer, and wait for it to happen 4865295Srandyf */ 4875295Srandyf mutex_enter(&srn_clone_lock); 4885295Srandyf if (srn_signal) { 4895295Srandyf PMD(PMD_SX, ("cpr_suspend: (*srn_signal)(..., " 4905295Srandyf "SRN_SUSPEND_REQ)\n")) 4915295Srandyf srn_inuse = 1; /* because *(srn_signal) cv_waits */ 4925295Srandyf (*srn_signal)(SRN_TYPE_APM, SRN_SUSPEND_REQ); 4935295Srandyf srn_inuse = 0; 4945295Srandyf } else { 4955295Srandyf PMD(PMD_SX, ("cpr_suspend: srn_signal NULL\n")) 4965295Srandyf } 4975295Srandyf mutex_exit(&srn_clone_lock); 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate /* 5000Sstevel@tonic-gate * Ask the user threads to stop by themselves, but 5010Sstevel@tonic-gate * if they don't or can't after 3 retries, we give up on CPR. 5020Sstevel@tonic-gate * The 3 retry is not a random number because 2 is possible if 5030Sstevel@tonic-gate * a thread has been forked before the parent thread is stopped. 5040Sstevel@tonic-gate */ 5053446Smrj CPR_DEBUG(CPR_DEBUG1, "\nstopping user threads..."); 5060Sstevel@tonic-gate CPR_STAT_EVENT_START(" stop users"); 5070Sstevel@tonic-gate cpr_set_substate(C_ST_STOP_USER_THREADS); 5085295Srandyf PMD(PMD_SX, ("cpr_suspend: stop user threads\n")) 5090Sstevel@tonic-gate if (rc = cpr_stop_user_threads()) 5100Sstevel@tonic-gate return (rc); 5110Sstevel@tonic-gate CPR_STAT_EVENT_END(" stop users"); 5123446Smrj CPR_DEBUG(CPR_DEBUG1, "done\n"); 5130Sstevel@tonic-gate 5145295Srandyf PMD(PMD_SX, ("cpr_suspend: save direct levels\n")) 5150Sstevel@tonic-gate pm_save_direct_levels(); 5160Sstevel@tonic-gate 5170Sstevel@tonic-gate /* 5180Sstevel@tonic-gate * User threads are stopped. We will start communicating with the 5190Sstevel@tonic-gate * user via prom_printf (some debug output may have already happened) 5200Sstevel@tonic-gate * so let anybody who cares know about this (bug 4096122) 5210Sstevel@tonic-gate */ 5220Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PROMPRINTF, CB_CODE_CPR_CHKPT); 5230Sstevel@tonic-gate 5245295Srandyf PMD(PMD_SX, ("cpr_suspend: send notice\n")) 5255295Srandyf #ifndef DEBUG 5260Sstevel@tonic-gate cpr_send_notice(); 5270Sstevel@tonic-gate if (cpr_debug) 5283446Smrj prom_printf("\n"); 5295295Srandyf #endif 5300Sstevel@tonic-gate 5315295Srandyf PMD(PMD_SX, ("cpr_suspend: POST USER callback\n")) 5320Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_USER, CB_CODE_CPR_CHKPT); 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate /* 5350Sstevel@tonic-gate * Reattach any drivers which originally exported the 5360Sstevel@tonic-gate * no-involuntary-power-cycles property. We need to do this before 5370Sstevel@tonic-gate * stopping kernel threads because modload is implemented using 5380Sstevel@tonic-gate * a kernel thread. 5390Sstevel@tonic-gate */ 5400Sstevel@tonic-gate cpr_set_substate(C_ST_PM_REATTACH_NOINVOL); 5415295Srandyf PMD(PMD_SX, ("cpr_suspend: reattach noinvol\n")) 5420Sstevel@tonic-gate if (!pm_reattach_noinvol()) 5430Sstevel@tonic-gate return (ENXIO); 5440Sstevel@tonic-gate 5455295Srandyf #if defined(__sparc) 5465295Srandyf ASSERT(sleeptype == CPR_TODISK); 5470Sstevel@tonic-gate /* 5480Sstevel@tonic-gate * if ufs logging is enabled, we need to disable before 5490Sstevel@tonic-gate * stopping kernel threads so that ufs delete and roll 5500Sstevel@tonic-gate * threads can do the work. 5510Sstevel@tonic-gate */ 5520Sstevel@tonic-gate cpr_set_substate(C_ST_DISABLE_UFS_LOGGING); 5530Sstevel@tonic-gate if (rc = cpr_ufs_logging(0)) 5540Sstevel@tonic-gate return (rc); 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate /* 5570Sstevel@tonic-gate * Use sync_all to swap out all user pages and find out how much 5580Sstevel@tonic-gate * extra space needed for user pages that don't have back store 5590Sstevel@tonic-gate * space left. 5600Sstevel@tonic-gate */ 5610Sstevel@tonic-gate CPR_STAT_EVENT_START(" swapout upages"); 5620Sstevel@tonic-gate vfs_sync(SYNC_ALL); 5630Sstevel@tonic-gate CPR_STAT_EVENT_END(" swapout upages"); 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate cpr_set_bitmap_size(); 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate alloc_statefile: 5680Sstevel@tonic-gate /* 5695295Srandyf * If our last state was C_ST_DUMP_NOSPC, we're trying to 5705295Srandyf * realloc the statefile, otherwise this is the first attempt. 5710Sstevel@tonic-gate */ 5720Sstevel@tonic-gate sf_realloc = (CPR->c_substate == C_ST_DUMP_NOSPC) ? 1 : 0; 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate CPR_STAT_EVENT_START(" alloc statefile"); 5750Sstevel@tonic-gate cpr_set_substate(C_ST_STATEF_ALLOC); 5760Sstevel@tonic-gate if (rc = cpr_alloc_statefile(sf_realloc)) { 5770Sstevel@tonic-gate if (sf_realloc) 5785295Srandyf errp("realloc failed\n"); 5790Sstevel@tonic-gate return (rc); 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate CPR_STAT_EVENT_END(" alloc statefile"); 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate /* 5840Sstevel@tonic-gate * Sync the filesystem to preserve its integrity. 5850Sstevel@tonic-gate * 5865295Srandyf * This sync is also used to flush out all B_DELWRI buffers 5875295Srandyf * (fs cache) which are mapped and neither dirty nor referenced 5885295Srandyf * before cpr_invalidate_pages destroys them. 5895295Srandyf * fsflush does similar thing. 5900Sstevel@tonic-gate */ 5910Sstevel@tonic-gate sync(); 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate /* 5940Sstevel@tonic-gate * destroy all clean file mapped kernel pages 5950Sstevel@tonic-gate */ 5960Sstevel@tonic-gate CPR_STAT_EVENT_START(" clean pages"); 5975295Srandyf CPR_DEBUG(CPR_DEBUG1, ("cleaning up mapped pages...")); 5980Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_VM, CB_CODE_CPR_CHKPT); 5995295Srandyf CPR_DEBUG(CPR_DEBUG1, ("done\n")); 6000Sstevel@tonic-gate CPR_STAT_EVENT_END(" clean pages"); 6015295Srandyf #endif 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate /* 6050Sstevel@tonic-gate * Hooks needed by lock manager prior to suspending. 6060Sstevel@tonic-gate * Refer to code for more comments. 6070Sstevel@tonic-gate */ 6085295Srandyf PMD(PMD_SX, ("cpr_suspend: lock mgr\n")) 6090Sstevel@tonic-gate cpr_lock_mgr(lm_cprsuspend); 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate /* 6120Sstevel@tonic-gate * Now suspend all the devices 6130Sstevel@tonic-gate */ 6140Sstevel@tonic-gate CPR_STAT_EVENT_START(" stop drivers"); 6153446Smrj CPR_DEBUG(CPR_DEBUG1, "suspending drivers..."); 6160Sstevel@tonic-gate cpr_set_substate(C_ST_SUSPEND_DEVICES); 6170Sstevel@tonic-gate pm_powering_down = 1; 6185295Srandyf PMD(PMD_SX, ("cpr_suspend: suspending devices\n")) 6190Sstevel@tonic-gate rc = cpr_suspend_devices(ddi_root_node()); 6200Sstevel@tonic-gate pm_powering_down = 0; 6210Sstevel@tonic-gate if (rc) 6220Sstevel@tonic-gate return (rc); 6233446Smrj CPR_DEBUG(CPR_DEBUG1, "done\n"); 6240Sstevel@tonic-gate CPR_STAT_EVENT_END(" stop drivers"); 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate /* 6270Sstevel@tonic-gate * Stop all daemon activities 6280Sstevel@tonic-gate */ 6290Sstevel@tonic-gate cpr_set_substate(C_ST_STOP_KERNEL_THREADS); 6305295Srandyf PMD(PMD_SX, ("cpr_suspend: stopping kernel threads\n")) 6310Sstevel@tonic-gate if (skt_rc = cpr_stop_kernel_threads()) 6320Sstevel@tonic-gate return (skt_rc); 6330Sstevel@tonic-gate 6345295Srandyf PMD(PMD_SX, ("cpr_suspend: POST KERNEL callback\n")) 6350Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_KERNEL, CB_CODE_CPR_CHKPT); 6360Sstevel@tonic-gate 6375295Srandyf PMD(PMD_SX, ("cpr_suspend: reattach noinvol fini\n")) 6380Sstevel@tonic-gate pm_reattach_noinvol_fini(); 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate cpr_sae(1); 6410Sstevel@tonic-gate 6425295Srandyf PMD(PMD_SX, ("cpr_suspend: CPR CALLOUT callback\n")) 6430Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_CALLOUT, CB_CODE_CPR_CHKPT); 6440Sstevel@tonic-gate 6455295Srandyf if (sleeptype == CPR_TODISK) { 6465295Srandyf /* 6475295Srandyf * It's safer to do tod_get before we disable all intr. 6485295Srandyf */ 6495295Srandyf CPR_STAT_EVENT_START(" write statefile"); 6505295Srandyf } 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate /* 6530Sstevel@tonic-gate * it's time to ignore the outside world, stop the real time 6540Sstevel@tonic-gate * clock and disable any further intrpt activity. 6550Sstevel@tonic-gate */ 6565295Srandyf PMD(PMD_SX, ("cpr_suspend: handle xc\n")) 6570Sstevel@tonic-gate i_cpr_handle_xc(1); /* turn it on to disable xc assertion */ 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate mutex_enter(&cpu_lock); 6605295Srandyf PMD(PMD_SX, ("cpr_suspend: cyclic suspend\n")) 6610Sstevel@tonic-gate cyclic_suspend(); 6620Sstevel@tonic-gate mutex_exit(&cpu_lock); 6630Sstevel@tonic-gate 6645295Srandyf /* 6655295Srandyf * Due to the different methods of resuming the system between 6665295Srandyf * CPR_TODISK (boot cprboot on SPARC, which reloads kernel image) 6675295Srandyf * and CPR_TORAM (restart via reset into existing kernel image) 6685295Srandyf * cpus are not suspended and restored in the SPARC case, since it 6695295Srandyf * is necessary to restart the cpus and pause them before restoring 6705295Srandyf * the OBP image 6715295Srandyf */ 6725295Srandyf 6735295Srandyf #if defined(__x86) 6740Sstevel@tonic-gate 6755295Srandyf /* pause aux cpus */ 6765295Srandyf PMD(PMD_SX, ("pause aux cpus\n")) 6775295Srandyf 6785295Srandyf cpr_set_substate(C_ST_MP_PAUSED); 6795295Srandyf 6805295Srandyf if ((rc = cpr_suspend_cpus()) != 0) 6815295Srandyf return (rc); 6825295Srandyf #endif 6835295Srandyf 6845295Srandyf PMD(PMD_SX, ("cpr_suspend: stop intr\n")) 6850Sstevel@tonic-gate i_cpr_stop_intr(); 6863446Smrj CPR_DEBUG(CPR_DEBUG1, "interrupt is stopped\n"); 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate /* 6890Sstevel@tonic-gate * Since we will now disable the mechanism that causes prom_printfs 6900Sstevel@tonic-gate * to power up (if needed) the console fb/monitor, we assert that 6910Sstevel@tonic-gate * it must be up now. 6920Sstevel@tonic-gate */ 6930Sstevel@tonic-gate ASSERT(pm_cfb_is_up()); 6945295Srandyf PMD(PMD_SX, ("cpr_suspend: prom suspend prepost\n")) 6950Sstevel@tonic-gate prom_suspend_prepost(); 6960Sstevel@tonic-gate 6975295Srandyf #if defined(__sparc) 6980Sstevel@tonic-gate /* 6990Sstevel@tonic-gate * getting ready to write ourself out, flush the register 7000Sstevel@tonic-gate * windows to make sure that our stack is good when we 7010Sstevel@tonic-gate * come back on the resume side. 7020Sstevel@tonic-gate */ 7030Sstevel@tonic-gate flush_windows(); 7045295Srandyf #endif 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate /* 7075295Srandyf * For S3, we're done 7085295Srandyf */ 7095295Srandyf if (sleeptype == CPR_TORAM) { 7105295Srandyf PMD(PMD_SX, ("cpr_suspend rets %x\n", rc)) 7115295Srandyf cpr_set_substate(C_ST_NODUMP); 7125295Srandyf return (rc); 7135295Srandyf } 7145295Srandyf #if defined(__sparc) 7155295Srandyf /* 7160Sstevel@tonic-gate * FATAL: NO MORE MEMORY ALLOCATION ALLOWED AFTER THIS POINT!!! 7170Sstevel@tonic-gate * 7180Sstevel@tonic-gate * The system is quiesced at this point, we are ready to either dump 7190Sstevel@tonic-gate * to the state file for a extended sleep or a simple shutdown for 7200Sstevel@tonic-gate * systems with non-volatile memory. 7210Sstevel@tonic-gate */ 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate /* 7240Sstevel@tonic-gate * special handling for reusable: 7250Sstevel@tonic-gate */ 7260Sstevel@tonic-gate if (cpr_reusable_mode) { 7270Sstevel@tonic-gate cpr_set_substate(C_ST_SETPROPS_1); 7280Sstevel@tonic-gate if (nverr = cpr_set_properties(1)) 7290Sstevel@tonic-gate return (nverr); 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate cpr_set_substate(C_ST_DUMP); 7330Sstevel@tonic-gate rc = cpr_dump(C_VP); 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate /* 7365331Samw * if any error occurred during dump, more 7370Sstevel@tonic-gate * special handling for reusable: 7380Sstevel@tonic-gate */ 7390Sstevel@tonic-gate if (rc && cpr_reusable_mode) { 7400Sstevel@tonic-gate cpr_set_substate(C_ST_SETPROPS_0); 7410Sstevel@tonic-gate if (nverr = cpr_set_properties(0)) 7420Sstevel@tonic-gate return (nverr); 7430Sstevel@tonic-gate } 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate if (rc == ENOSPC) { 7460Sstevel@tonic-gate cpr_set_substate(C_ST_DUMP_NOSPC); 7475295Srandyf (void) cpr_resume(sleeptype); 7480Sstevel@tonic-gate goto alloc_statefile; 7490Sstevel@tonic-gate } else if (rc == 0) { 7500Sstevel@tonic-gate if (cpr_reusable_mode) { 7510Sstevel@tonic-gate cpr_set_substate(C_ST_REUSABLE); 7520Sstevel@tonic-gate longjmp(&ttolwp(curthread)->lwp_qsav); 7530Sstevel@tonic-gate } else 7540Sstevel@tonic-gate rc = cpr_set_properties(1); 7550Sstevel@tonic-gate } 7565295Srandyf #endif 7575295Srandyf PMD(PMD_SX, ("cpr_suspend: return %d\n", rc)) 7580Sstevel@tonic-gate return (rc); 7590Sstevel@tonic-gate } 7600Sstevel@tonic-gate 7615295Srandyf void 7625295Srandyf cpr_resume_cpus(void) 7635295Srandyf { 7645295Srandyf /* 7655295Srandyf * this is a cut down version of start_other_cpus() 7665295Srandyf * just do the initialization to wake the other cpus 7675295Srandyf */ 7685295Srandyf 7695295Srandyf #if defined(__x86) 7705295Srandyf /* 7715295Srandyf * Initialize our syscall handlers 7725295Srandyf */ 7735295Srandyf init_cpu_syscall(CPU); 7745295Srandyf 7755295Srandyf #endif 7765295Srandyf 7775295Srandyf i_cpr_pre_resume_cpus(); 7785295Srandyf 7795295Srandyf /* 7805295Srandyf * Restart the paused cpus 7815295Srandyf */ 7825295Srandyf mutex_enter(&cpu_lock); 7835295Srandyf start_cpus(); 7845295Srandyf mutex_exit(&cpu_lock); 7855295Srandyf 7865295Srandyf i_cpr_post_resume_cpus(); 7875295Srandyf 7885295Srandyf mutex_enter(&cpu_lock); 7895295Srandyf /* 7905295Srandyf * Restore this cpu to use the regular cpu_pause(), so that 7915295Srandyf * online and offline will work correctly 7925295Srandyf */ 7935295Srandyf cpu_pause_func = NULL; 7945295Srandyf 7955295Srandyf /* 796*5817Sjan * clear the affinity set in cpr_suspend_cpus() 797*5817Sjan */ 798*5817Sjan affinity_clear(); 799*5817Sjan 800*5817Sjan /* 8015295Srandyf * offline all the cpus that were brought online during suspend 8025295Srandyf */ 8035295Srandyf cpr_restore_offline(); 8045295Srandyf 8055295Srandyf mutex_exit(&cpu_lock); 8065295Srandyf } 8075295Srandyf 8085295Srandyf void 8095295Srandyf cpr_unpause_cpus(void) 8105295Srandyf { 8115295Srandyf /* 8125295Srandyf * Now restore the system back to what it was before we suspended 8135295Srandyf */ 8145295Srandyf 8155295Srandyf PMD(PMD_SX, ("cpr_unpause_cpus: restoring system\n")) 8165295Srandyf 8175295Srandyf mutex_enter(&cpu_lock); 8185295Srandyf 8195295Srandyf /* 8205295Srandyf * Restore this cpu to use the regular cpu_pause(), so that 8215295Srandyf * online and offline will work correctly 8225295Srandyf */ 8235295Srandyf cpu_pause_func = NULL; 8245295Srandyf 8255295Srandyf /* 8265295Srandyf * Restart the paused cpus 8275295Srandyf */ 8285295Srandyf start_cpus(); 8295295Srandyf 8305295Srandyf /* 831*5817Sjan * clear the affinity set in cpr_suspend_cpus() 832*5817Sjan */ 833*5817Sjan affinity_clear(); 834*5817Sjan 835*5817Sjan /* 8365295Srandyf * offline all the cpus that were brought online during suspend 8375295Srandyf */ 8385295Srandyf cpr_restore_offline(); 8395295Srandyf 8405295Srandyf mutex_exit(&cpu_lock); 8415295Srandyf } 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate /* 8440Sstevel@tonic-gate * Bring the system back up from a checkpoint, at this point 8450Sstevel@tonic-gate * the VM has been minimally restored by boot, the following 8460Sstevel@tonic-gate * are executed sequentially: 8470Sstevel@tonic-gate * 8480Sstevel@tonic-gate * - machdep setup and enable interrupts (mp startup if it's mp) 8490Sstevel@tonic-gate * - resume all devices 8500Sstevel@tonic-gate * - restart daemons 8510Sstevel@tonic-gate * - put all threads back on run queue 8520Sstevel@tonic-gate */ 8530Sstevel@tonic-gate static int 8545295Srandyf cpr_resume(int sleeptype) 8550Sstevel@tonic-gate { 8560Sstevel@tonic-gate cpr_time_t pwron_tv, *ctp; 8570Sstevel@tonic-gate char *str; 8580Sstevel@tonic-gate int rc = 0; 8590Sstevel@tonic-gate 8600Sstevel@tonic-gate /* 8610Sstevel@tonic-gate * The following switch is used to resume the system 8620Sstevel@tonic-gate * that was suspended to a different level. 8630Sstevel@tonic-gate */ 8643446Smrj CPR_DEBUG(CPR_DEBUG1, "\nEntering cpr_resume...\n"); 8655295Srandyf PMD(PMD_SX, ("cpr_resume %x\n", sleeptype)) 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate /* 8680Sstevel@tonic-gate * Note: 8690Sstevel@tonic-gate * 8700Sstevel@tonic-gate * The rollback labels rb_xyz do not represent the cpr resume 8710Sstevel@tonic-gate * state when event 'xyz' has happened. Instead they represent 8720Sstevel@tonic-gate * the state during cpr suspend when event 'xyz' was being 8730Sstevel@tonic-gate * entered (and where cpr suspend failed). The actual call that 8740Sstevel@tonic-gate * failed may also need to be partially rolled back, since they 8750Sstevel@tonic-gate * aren't atomic in most cases. In other words, rb_xyz means 8760Sstevel@tonic-gate * "roll back all cpr suspend events that happened before 'xyz', 8770Sstevel@tonic-gate * and the one that caused the failure, if necessary." 8780Sstevel@tonic-gate */ 8790Sstevel@tonic-gate switch (CPR->c_substate) { 8805295Srandyf #if defined(__sparc) 8810Sstevel@tonic-gate case C_ST_DUMP: 8820Sstevel@tonic-gate /* 8830Sstevel@tonic-gate * This is most likely a full-fledged cpr_resume after 8840Sstevel@tonic-gate * a complete and successful cpr suspend. Just roll back 8850Sstevel@tonic-gate * everything. 8860Sstevel@tonic-gate */ 8875295Srandyf ASSERT(sleeptype == CPR_TODISK); 8880Sstevel@tonic-gate break; 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate case C_ST_REUSABLE: 8910Sstevel@tonic-gate case C_ST_DUMP_NOSPC: 8920Sstevel@tonic-gate case C_ST_SETPROPS_0: 8930Sstevel@tonic-gate case C_ST_SETPROPS_1: 8940Sstevel@tonic-gate /* 8950Sstevel@tonic-gate * C_ST_REUSABLE and C_ST_DUMP_NOSPC are the only two 8960Sstevel@tonic-gate * special switch cases here. The other two do not have 8970Sstevel@tonic-gate * any state change during cpr_suspend() that needs to 8980Sstevel@tonic-gate * be rolled back. But these are exit points from 8990Sstevel@tonic-gate * cpr_suspend, so theoretically (or in the future), it 9000Sstevel@tonic-gate * is possible that a need for roll back of a state 9010Sstevel@tonic-gate * change arises between these exit points. 9020Sstevel@tonic-gate */ 9035295Srandyf ASSERT(sleeptype == CPR_TODISK); 9040Sstevel@tonic-gate goto rb_dump; 9055295Srandyf #endif 9065295Srandyf 9075295Srandyf case C_ST_NODUMP: 9085295Srandyf PMD(PMD_SX, ("cpr_resume: NODUMP\n")) 9095295Srandyf goto rb_nodump; 9100Sstevel@tonic-gate 9110Sstevel@tonic-gate case C_ST_STOP_KERNEL_THREADS: 9125295Srandyf PMD(PMD_SX, ("cpr_resume: STOP_KERNEL_THREADS\n")) 9130Sstevel@tonic-gate goto rb_stop_kernel_threads; 9140Sstevel@tonic-gate 9150Sstevel@tonic-gate case C_ST_SUSPEND_DEVICES: 9165295Srandyf PMD(PMD_SX, ("cpr_resume: SUSPEND_DEVICES\n")) 9170Sstevel@tonic-gate goto rb_suspend_devices; 9180Sstevel@tonic-gate 9195295Srandyf #if defined(__sparc) 9200Sstevel@tonic-gate case C_ST_STATEF_ALLOC: 9215295Srandyf ASSERT(sleeptype == CPR_TODISK); 9220Sstevel@tonic-gate goto rb_statef_alloc; 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate case C_ST_DISABLE_UFS_LOGGING: 9255295Srandyf ASSERT(sleeptype == CPR_TODISK); 9260Sstevel@tonic-gate goto rb_disable_ufs_logging; 9275295Srandyf #endif 9280Sstevel@tonic-gate 9290Sstevel@tonic-gate case C_ST_PM_REATTACH_NOINVOL: 9305295Srandyf PMD(PMD_SX, ("cpr_resume: REATTACH_NOINVOL\n")) 9310Sstevel@tonic-gate goto rb_pm_reattach_noinvol; 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate case C_ST_STOP_USER_THREADS: 9345295Srandyf PMD(PMD_SX, ("cpr_resume: STOP_USER_THREADS\n")) 9350Sstevel@tonic-gate goto rb_stop_user_threads; 9360Sstevel@tonic-gate 9375295Srandyf #if defined(__sparc) 9380Sstevel@tonic-gate case C_ST_MP_OFFLINE: 9395295Srandyf PMD(PMD_SX, ("cpr_resume: MP_OFFLINE\n")) 9400Sstevel@tonic-gate goto rb_mp_offline; 9415295Srandyf #endif 9425295Srandyf 9435295Srandyf #if defined(__x86) 9445295Srandyf case C_ST_MP_PAUSED: 9455295Srandyf PMD(PMD_SX, ("cpr_resume: MP_PAUSED\n")) 9465295Srandyf goto rb_mp_paused; 9475295Srandyf #endif 9485295Srandyf 9490Sstevel@tonic-gate 9500Sstevel@tonic-gate default: 9515295Srandyf PMD(PMD_SX, ("cpr_resume: others\n")) 9520Sstevel@tonic-gate goto rb_others; 9530Sstevel@tonic-gate } 9540Sstevel@tonic-gate 9550Sstevel@tonic-gate rb_all: 9560Sstevel@tonic-gate /* 9570Sstevel@tonic-gate * perform platform-dependent initialization 9580Sstevel@tonic-gate */ 9590Sstevel@tonic-gate if (cpr_suspend_succeeded) 9600Sstevel@tonic-gate i_cpr_machdep_setup(); 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate /* 9630Sstevel@tonic-gate * system did not really go down if we jump here 9640Sstevel@tonic-gate */ 9650Sstevel@tonic-gate rb_dump: 9660Sstevel@tonic-gate /* 9670Sstevel@tonic-gate * IMPORTANT: SENSITIVE RESUME SEQUENCE 9680Sstevel@tonic-gate * 9690Sstevel@tonic-gate * DO NOT ADD ANY INITIALIZATION STEP BEFORE THIS POINT!! 9700Sstevel@tonic-gate */ 9715295Srandyf rb_nodump: 9725295Srandyf /* 9735295Srandyf * If we did suspend to RAM, we didn't generate a dump 9745295Srandyf */ 9755295Srandyf PMD(PMD_SX, ("cpr_resume: CPR DMA callback\n")) 9760Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_DMA, CB_CODE_CPR_RESUME); 9775295Srandyf if (cpr_suspend_succeeded) { 9785295Srandyf PMD(PMD_SX, ("cpr_resume: CPR RPC callback\n")) 9790Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_RPC, CB_CODE_CPR_RESUME); 9805295Srandyf } 9810Sstevel@tonic-gate 9820Sstevel@tonic-gate prom_resume_prepost(); 9835295Srandyf #if !defined(__sparc) 9845295Srandyf /* 9855295Srandyf * Need to sync the software clock with the hardware clock. 9865295Srandyf * On Sparc, this occurs in the sparc-specific cbe. However 9875295Srandyf * on x86 this needs to be handled _before_ we bring other cpu's 9885295Srandyf * back online. So we call a resume function in timestamp.c 9895295Srandyf */ 9905295Srandyf if (tsc_resume_in_cyclic == 0) 9915295Srandyf tsc_resume(); 9920Sstevel@tonic-gate 9935295Srandyf #endif 9945295Srandyf 9955295Srandyf #if defined(__sparc) 9960Sstevel@tonic-gate if (cpr_suspend_succeeded && (boothowto & RB_DEBUG)) 9970Sstevel@tonic-gate kdi_dvec_cpr_restart(); 9985295Srandyf #endif 9995295Srandyf 10005295Srandyf 10015295Srandyf #if defined(__x86) 10025295Srandyf rb_mp_paused: 10035295Srandyf PT(PT_RMPO); 10045295Srandyf PMD(PMD_SX, ("resume aux cpus\n")) 10055295Srandyf 10065295Srandyf if (cpr_suspend_succeeded) { 10075295Srandyf cpr_resume_cpus(); 10085295Srandyf } else { 10095295Srandyf cpr_unpause_cpus(); 10105295Srandyf } 10115295Srandyf #endif 10120Sstevel@tonic-gate 10130Sstevel@tonic-gate /* 10140Sstevel@tonic-gate * let the tmp callout catch up. 10150Sstevel@tonic-gate */ 10165295Srandyf PMD(PMD_SX, ("cpr_resume: CPR CALLOUT callback\n")) 10170Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_CALLOUT, CB_CODE_CPR_RESUME); 10180Sstevel@tonic-gate 10190Sstevel@tonic-gate i_cpr_enable_intr(); 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate mutex_enter(&cpu_lock); 10225295Srandyf PMD(PMD_SX, ("cpr_resume: cyclic resume\n")) 10230Sstevel@tonic-gate cyclic_resume(); 10240Sstevel@tonic-gate mutex_exit(&cpu_lock); 10250Sstevel@tonic-gate 10265295Srandyf PMD(PMD_SX, ("cpr_resume: handle xc\n")) 10270Sstevel@tonic-gate i_cpr_handle_xc(0); /* turn it off to allow xc assertion */ 10280Sstevel@tonic-gate 10295295Srandyf PMD(PMD_SX, ("cpr_resume: CPR POST KERNEL callback\n")) 10300Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_KERNEL, CB_CODE_CPR_RESUME); 10310Sstevel@tonic-gate 10320Sstevel@tonic-gate /* 10330Sstevel@tonic-gate * statistics gathering 10340Sstevel@tonic-gate */ 10350Sstevel@tonic-gate if (cpr_suspend_succeeded) { 10360Sstevel@tonic-gate /* 10370Sstevel@tonic-gate * Prevent false alarm in tod_validate() due to tod 10380Sstevel@tonic-gate * value change between suspend and resume 10390Sstevel@tonic-gate */ 10400Sstevel@tonic-gate cpr_tod_fault_reset(); 10410Sstevel@tonic-gate 10420Sstevel@tonic-gate cpr_convert_promtime(&pwron_tv); 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate ctp = &cpr_term.tm_shutdown; 10455295Srandyf if (sleeptype == CPR_TODISK) 10465295Srandyf CPR_STAT_EVENT_END_TMZ(" write statefile", ctp); 10470Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ("Suspend Total", ctp); 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ("Resume Total", &pwron_tv); 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate str = " prom time"; 10520Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ(str, &pwron_tv); 10530Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_start; 10540Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ(str, ctp); 10550Sstevel@tonic-gate 10560Sstevel@tonic-gate str = " read statefile"; 10570Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ(str, ctp); 10580Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_end; 10590Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ(str, ctp); 10600Sstevel@tonic-gate } 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate rb_stop_kernel_threads: 10630Sstevel@tonic-gate /* 10640Sstevel@tonic-gate * Put all threads back to where they belong; get the kernel 10650Sstevel@tonic-gate * daemons straightened up too. Note that the callback table 10660Sstevel@tonic-gate * locked during cpr_stop_kernel_threads() is released only 10670Sstevel@tonic-gate * in cpr_start_kernel_threads(). Ensure modunloading is 10680Sstevel@tonic-gate * disabled before starting kernel threads, we don't want 10690Sstevel@tonic-gate * modunload thread to start changing device tree underneath. 10700Sstevel@tonic-gate */ 10715295Srandyf PMD(PMD_SX, ("cpr_resume: modunload disable\n")) 10720Sstevel@tonic-gate modunload_disable(); 10735295Srandyf PMD(PMD_SX, ("cpr_resume: start kernel threads\n")) 10740Sstevel@tonic-gate cpr_start_kernel_threads(); 10750Sstevel@tonic-gate 10760Sstevel@tonic-gate rb_suspend_devices: 10773446Smrj CPR_DEBUG(CPR_DEBUG1, "resuming devices..."); 10780Sstevel@tonic-gate CPR_STAT_EVENT_START(" start drivers"); 10790Sstevel@tonic-gate 10805295Srandyf PMD(PMD_SX, 10815295Srandyf ("cpr_resume: rb_suspend_devices: cpr_resume_uniproc = %d\n", 10825295Srandyf cpr_resume_uniproc)) 10835295Srandyf 10845295Srandyf #if defined(__x86) 10855295Srandyf /* 10865295Srandyf * If cpr_resume_uniproc is set, then pause all the other cpus 10875295Srandyf * apart from the current cpu, so that broken drivers that think 10885295Srandyf * that they are on a uniprocessor machine will resume 10895295Srandyf */ 10905295Srandyf if (cpr_resume_uniproc) { 10915295Srandyf mutex_enter(&cpu_lock); 10925295Srandyf pause_cpus(NULL); 10935295Srandyf mutex_exit(&cpu_lock); 10945295Srandyf } 10955295Srandyf #endif 10965295Srandyf 10970Sstevel@tonic-gate /* 10980Sstevel@tonic-gate * The policy here is to continue resume everything we can if we did 10990Sstevel@tonic-gate * not successfully finish suspend; and panic if we are coming back 11000Sstevel@tonic-gate * from a fully suspended system. 11010Sstevel@tonic-gate */ 11025295Srandyf PMD(PMD_SX, ("cpr_resume: resume devices\n")) 11030Sstevel@tonic-gate rc = cpr_resume_devices(ddi_root_node(), 0); 11040Sstevel@tonic-gate 11050Sstevel@tonic-gate cpr_sae(0); 11060Sstevel@tonic-gate 11070Sstevel@tonic-gate str = "Failed to resume one or more devices."; 11085295Srandyf 11095295Srandyf if (rc) { 11105295Srandyf if (CPR->c_substate == C_ST_DUMP || 11115295Srandyf (sleeptype == CPR_TORAM && 11125295Srandyf CPR->c_substate == C_ST_NODUMP)) { 11135295Srandyf if (cpr_test_point == FORCE_SUSPEND_TO_RAM) { 11145295Srandyf PMD(PMD_SX, ("cpr_resume: resume device " 11155295Srandyf "warn\n")) 11165295Srandyf cpr_err(CE_WARN, str); 11175295Srandyf } else { 11185295Srandyf PMD(PMD_SX, ("cpr_resume: resume device " 11195295Srandyf "panic\n")) 11205295Srandyf cpr_err(CE_PANIC, str); 11215295Srandyf } 11225295Srandyf } else { 11235295Srandyf PMD(PMD_SX, ("cpr_resume: resume device warn\n")) 11245295Srandyf cpr_err(CE_WARN, str); 11255295Srandyf } 11265295Srandyf } 11275295Srandyf 11280Sstevel@tonic-gate CPR_STAT_EVENT_END(" start drivers"); 11293446Smrj CPR_DEBUG(CPR_DEBUG1, "done\n"); 11300Sstevel@tonic-gate 11315295Srandyf #if defined(__x86) 11325295Srandyf /* 11335295Srandyf * If cpr_resume_uniproc is set, then unpause all the processors 11345295Srandyf * that were paused before resuming the drivers 11355295Srandyf */ 11365295Srandyf if (cpr_resume_uniproc) { 11375295Srandyf mutex_enter(&cpu_lock); 11385295Srandyf start_cpus(); 11395295Srandyf mutex_exit(&cpu_lock); 11405295Srandyf } 11415295Srandyf #endif 11425295Srandyf 11430Sstevel@tonic-gate /* 11440Sstevel@tonic-gate * If we had disabled modunloading in this cpr resume cycle (i.e. we 11450Sstevel@tonic-gate * resumed from a state earlier than C_ST_SUSPEND_DEVICES), re-enable 11460Sstevel@tonic-gate * modunloading now. 11470Sstevel@tonic-gate */ 11485295Srandyf if (CPR->c_substate != C_ST_SUSPEND_DEVICES) { 11495295Srandyf PMD(PMD_SX, ("cpr_resume: modload enable\n")) 11500Sstevel@tonic-gate modunload_enable(); 11515295Srandyf } 11520Sstevel@tonic-gate 11530Sstevel@tonic-gate /* 11540Sstevel@tonic-gate * Hooks needed by lock manager prior to resuming. 11550Sstevel@tonic-gate * Refer to code for more comments. 11560Sstevel@tonic-gate */ 11575295Srandyf PMD(PMD_SX, ("cpr_resume: lock mgr\n")) 11580Sstevel@tonic-gate cpr_lock_mgr(lm_cprresume); 11590Sstevel@tonic-gate 11605295Srandyf #if defined(__sparc) 11610Sstevel@tonic-gate /* 11620Sstevel@tonic-gate * This is a partial (half) resume during cpr suspend, we 11630Sstevel@tonic-gate * haven't yet given up on the suspend. On return from here, 11640Sstevel@tonic-gate * cpr_suspend() will try to reallocate and retry the suspend. 11650Sstevel@tonic-gate */ 11660Sstevel@tonic-gate if (CPR->c_substate == C_ST_DUMP_NOSPC) { 11670Sstevel@tonic-gate return (0); 11680Sstevel@tonic-gate } 11690Sstevel@tonic-gate 11705295Srandyf if (sleeptype == CPR_TODISK) { 11710Sstevel@tonic-gate rb_statef_alloc: 11725295Srandyf cpr_statef_close(); 11730Sstevel@tonic-gate 11740Sstevel@tonic-gate rb_disable_ufs_logging: 11755295Srandyf /* 11765295Srandyf * if ufs logging was disabled, re-enable 11775295Srandyf */ 11785295Srandyf (void) cpr_ufs_logging(1); 11795295Srandyf } 11805295Srandyf #endif 11810Sstevel@tonic-gate 11820Sstevel@tonic-gate rb_pm_reattach_noinvol: 11830Sstevel@tonic-gate /* 11840Sstevel@tonic-gate * When pm_reattach_noinvol() succeeds, modunload_thread will 11850Sstevel@tonic-gate * remain disabled until after cpr suspend passes the 11860Sstevel@tonic-gate * C_ST_STOP_KERNEL_THREADS state. If any failure happens before 11870Sstevel@tonic-gate * cpr suspend reaches this state, we'll need to enable modunload 11880Sstevel@tonic-gate * thread during rollback. 11890Sstevel@tonic-gate */ 11900Sstevel@tonic-gate if (CPR->c_substate == C_ST_DISABLE_UFS_LOGGING || 11910Sstevel@tonic-gate CPR->c_substate == C_ST_STATEF_ALLOC || 11920Sstevel@tonic-gate CPR->c_substate == C_ST_SUSPEND_DEVICES || 11930Sstevel@tonic-gate CPR->c_substate == C_ST_STOP_KERNEL_THREADS) { 11945295Srandyf PMD(PMD_SX, ("cpr_resume: reattach noinvol fini\n")) 11950Sstevel@tonic-gate pm_reattach_noinvol_fini(); 11960Sstevel@tonic-gate } 11970Sstevel@tonic-gate 11985295Srandyf PMD(PMD_SX, ("cpr_resume: CPR POST USER callback\n")) 11990Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_USER, CB_CODE_CPR_RESUME); 12005295Srandyf PMD(PMD_SX, ("cpr_resume: CPR PROMPRINTF callback\n")) 12010Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PROMPRINTF, CB_CODE_CPR_RESUME); 12020Sstevel@tonic-gate 12035295Srandyf PMD(PMD_SX, ("cpr_resume: restore direct levels\n")) 12040Sstevel@tonic-gate pm_restore_direct_levels(); 12050Sstevel@tonic-gate 12060Sstevel@tonic-gate rb_stop_user_threads: 12073446Smrj CPR_DEBUG(CPR_DEBUG1, "starting user threads..."); 12085295Srandyf PMD(PMD_SX, ("cpr_resume: starting user threads\n")) 12090Sstevel@tonic-gate cpr_start_user_threads(); 12103446Smrj CPR_DEBUG(CPR_DEBUG1, "done\n"); 12115295Srandyf /* 12125295Srandyf * Ask Xorg to resume the frame buffer, and wait for it to happen 12135295Srandyf */ 12145295Srandyf mutex_enter(&srn_clone_lock); 12155295Srandyf if (srn_signal) { 12165295Srandyf PMD(PMD_SX, ("cpr_suspend: (*srn_signal)(..., " 12175295Srandyf "SRN_NORMAL_RESUME)\n")) 12185295Srandyf srn_inuse = 1; /* because (*srn_signal) cv_waits */ 12195295Srandyf (*srn_signal)(SRN_TYPE_APM, SRN_NORMAL_RESUME); 12205295Srandyf srn_inuse = 0; 12215295Srandyf } else { 12225295Srandyf PMD(PMD_SX, ("cpr_suspend: srn_signal NULL\n")) 12235295Srandyf } 12245295Srandyf mutex_exit(&srn_clone_lock); 12250Sstevel@tonic-gate 12265295Srandyf #if defined(__sparc) 12270Sstevel@tonic-gate rb_mp_offline: 12280Sstevel@tonic-gate if (cpr_mp_online()) 12290Sstevel@tonic-gate cpr_err(CE_WARN, "Failed to online all the processors."); 12305295Srandyf #endif 12310Sstevel@tonic-gate 12320Sstevel@tonic-gate rb_others: 12335295Srandyf PMD(PMD_SX, ("cpr_resume: dep thread\n")) 12345295Srandyf pm_dispatch_to_dep_thread(PM_DEP_WK_CPR_RESUME, NULL, NULL, 12355295Srandyf PM_DEP_WAIT, NULL, 0); 12360Sstevel@tonic-gate 12375295Srandyf PMD(PMD_SX, ("cpr_resume: CPR PM callback\n")) 12380Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PM, CB_CODE_CPR_RESUME); 12390Sstevel@tonic-gate 12400Sstevel@tonic-gate if (cpr_suspend_succeeded) { 12410Sstevel@tonic-gate cpr_stat_record_events(); 12420Sstevel@tonic-gate } 12430Sstevel@tonic-gate 12445295Srandyf #if defined(__sparc) 12455295Srandyf if (sleeptype == CPR_TODISK && !cpr_reusable_mode) 12460Sstevel@tonic-gate cpr_clear_definfo(); 12475295Srandyf #endif 12480Sstevel@tonic-gate 12495295Srandyf i_cpr_free_cpus(); 12503446Smrj CPR_DEBUG(CPR_DEBUG1, "Sending SIGTHAW..."); 12515295Srandyf PMD(PMD_SX, ("cpr_resume: SIGTHAW\n")) 12520Sstevel@tonic-gate cpr_signal_user(SIGTHAW); 12533446Smrj CPR_DEBUG(CPR_DEBUG1, "done\n"); 12540Sstevel@tonic-gate 12550Sstevel@tonic-gate CPR_STAT_EVENT_END("Resume Total"); 12560Sstevel@tonic-gate 12570Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ("WHOLE CYCLE", &wholecycle_tv); 12580Sstevel@tonic-gate CPR_STAT_EVENT_END("WHOLE CYCLE"); 12590Sstevel@tonic-gate 12603446Smrj if (cpr_debug & CPR_DEBUG1) 12613446Smrj cmn_err(CE_CONT, "\nThe system is back where you left!\n"); 12620Sstevel@tonic-gate 12630Sstevel@tonic-gate CPR_STAT_EVENT_START("POST CPR DELAY"); 12640Sstevel@tonic-gate 12650Sstevel@tonic-gate #ifdef CPR_STAT 12660Sstevel@tonic-gate ctp = &cpr_term.tm_shutdown; 12670Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ("PWROFF TIME", ctp); 12680Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ("PWROFF TIME", &pwron_tv); 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate CPR_STAT_EVENT_PRINT(); 12710Sstevel@tonic-gate #endif /* CPR_STAT */ 12720Sstevel@tonic-gate 12735295Srandyf PMD(PMD_SX, ("cpr_resume returns %x\n", rc)) 12740Sstevel@tonic-gate return (rc); 12750Sstevel@tonic-gate } 12760Sstevel@tonic-gate 12770Sstevel@tonic-gate static void 12785295Srandyf cpr_suspend_init(int sleeptype) 12790Sstevel@tonic-gate { 12800Sstevel@tonic-gate cpr_time_t *ctp; 12810Sstevel@tonic-gate 12820Sstevel@tonic-gate cpr_stat_init(); 12830Sstevel@tonic-gate 12840Sstevel@tonic-gate /* 12850Sstevel@tonic-gate * If cpr_suspend() failed before cpr_dump() gets a chance 12860Sstevel@tonic-gate * to reinitialize the terminator of the statefile, 12870Sstevel@tonic-gate * the values of the old terminator will still linger around. 12880Sstevel@tonic-gate * Since the terminator contains information that we need to 12890Sstevel@tonic-gate * decide whether suspend succeeded or not, we need to 12900Sstevel@tonic-gate * reinitialize it as early as possible. 12910Sstevel@tonic-gate */ 12920Sstevel@tonic-gate cpr_term.real_statef_size = 0; 12930Sstevel@tonic-gate ctp = &cpr_term.tm_shutdown; 12940Sstevel@tonic-gate bzero(ctp, sizeof (*ctp)); 12950Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_start; 12960Sstevel@tonic-gate bzero(ctp, sizeof (*ctp)); 12970Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_end; 12980Sstevel@tonic-gate bzero(ctp, sizeof (*ctp)); 12990Sstevel@tonic-gate 13005295Srandyf if (sleeptype == CPR_TODISK) { 13015295Srandyf /* 13025295Srandyf * Lookup the physical address of our thread structure. 13035295Srandyf * This should never be invalid and the entire thread structure 13045295Srandyf * is expected to reside within the same pfn. 13055295Srandyf */ 13065295Srandyf curthreadpfn = hat_getpfnum(kas.a_hat, (caddr_t)curthread); 13075295Srandyf ASSERT(curthreadpfn != PFN_INVALID); 13085295Srandyf ASSERT(curthreadpfn == hat_getpfnum(kas.a_hat, 13095295Srandyf (caddr_t)curthread + sizeof (kthread_t) - 1)); 13105295Srandyf } 13110Sstevel@tonic-gate 13120Sstevel@tonic-gate cpr_suspend_succeeded = 0; 13130Sstevel@tonic-gate } 13145295Srandyf 13155295Srandyf /* 13165295Srandyf * bring all the offline cpus online 13175295Srandyf */ 13185295Srandyf static int 13195295Srandyf cpr_all_online(void) 13205295Srandyf { 13215295Srandyf int rc = 0; 13225295Srandyf 13235295Srandyf #ifdef __sparc 13245295Srandyf /* 13255295Srandyf * do nothing 13265295Srandyf */ 13275295Srandyf #else 13285295Srandyf 13295295Srandyf cpu_t *cp; 13305295Srandyf 13315295Srandyf ASSERT(MUTEX_HELD(&cpu_lock)); 13325295Srandyf 13335295Srandyf cp = cpu_list; 13345295Srandyf do { 13355295Srandyf cp->cpu_cpr_flags &= ~CPU_CPR_ONLINE; 13365295Srandyf if (!CPU_ACTIVE(cp)) { 13375295Srandyf if ((rc = cpu_online(cp)) != 0) 13385295Srandyf break; 13395295Srandyf CPU_SET_CPR_FLAGS(cp, CPU_CPR_ONLINE); 13405295Srandyf } 13415295Srandyf } while ((cp = cp->cpu_next) != cpu_list); 13425295Srandyf 13435295Srandyf if (rc) { 13445295Srandyf /* 13455295Srandyf * an online operation failed so offline the cpus 13465295Srandyf * that were onlined above to restore the system 13475295Srandyf * to its original state 13485295Srandyf */ 13495295Srandyf cpr_restore_offline(); 13505295Srandyf } 13515295Srandyf #endif 13525295Srandyf return (rc); 13535295Srandyf } 13545295Srandyf 13555295Srandyf /* 13565295Srandyf * offline all the cpus that were brought online by cpr_all_online() 13575295Srandyf */ 13585295Srandyf static void 13595295Srandyf cpr_restore_offline(void) 13605295Srandyf { 13615295Srandyf 13625295Srandyf #ifdef __sparc 13635295Srandyf /* 13645295Srandyf * do nothing 13655295Srandyf */ 13665295Srandyf #else 13675295Srandyf 13685295Srandyf cpu_t *cp; 13695295Srandyf int rc = 0; 13705295Srandyf 13715295Srandyf ASSERT(MUTEX_HELD(&cpu_lock)); 13725295Srandyf 13735295Srandyf cp = cpu_list; 13745295Srandyf do { 13755295Srandyf if (CPU_CPR_IS_ONLINE(cp)) { 13765295Srandyf rc = cpu_offline(cp, 0); 13775295Srandyf /* 13785295Srandyf * this offline should work, since the cpu was 13795295Srandyf * offline originally and was successfully onlined 13805295Srandyf * by cpr_all_online() 13815295Srandyf */ 13825295Srandyf ASSERT(rc == 0); 13835295Srandyf cp->cpu_cpr_flags &= ~CPU_CPR_ONLINE; 13845295Srandyf } 13855295Srandyf } while ((cp = cp->cpu_next) != cpu_list); 13865295Srandyf 13875295Srandyf #endif 13885295Srandyf 13895295Srandyf } 1390