1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate /* 31*0Sstevel@tonic-gate * This module contains the guts of checkpoint-resume mechanism. 32*0Sstevel@tonic-gate * All code in this module is platform independent. 33*0Sstevel@tonic-gate */ 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate #include <sys/types.h> 36*0Sstevel@tonic-gate #include <sys/errno.h> 37*0Sstevel@tonic-gate #include <sys/callb.h> 38*0Sstevel@tonic-gate #include <sys/processor.h> 39*0Sstevel@tonic-gate #include <sys/machsystm.h> 40*0Sstevel@tonic-gate #include <sys/clock.h> 41*0Sstevel@tonic-gate #include <sys/vfs.h> 42*0Sstevel@tonic-gate #include <sys/kmem.h> 43*0Sstevel@tonic-gate #include <nfs/lm.h> 44*0Sstevel@tonic-gate #include <sys/systm.h> 45*0Sstevel@tonic-gate #include <sys/cpr.h> 46*0Sstevel@tonic-gate #include <sys/bootconf.h> 47*0Sstevel@tonic-gate #include <sys/cyclic.h> 48*0Sstevel@tonic-gate #include <sys/filio.h> 49*0Sstevel@tonic-gate #include <sys/fs/ufs_filio.h> 50*0Sstevel@tonic-gate #include <sys/epm.h> 51*0Sstevel@tonic-gate #include <sys/modctl.h> 52*0Sstevel@tonic-gate #include <sys/reboot.h> 53*0Sstevel@tonic-gate #include <sys/kdi.h> 54*0Sstevel@tonic-gate #include <sys/promif.h> 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate extern struct cpr_terminator cpr_term; 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate extern int cpr_alloc_statefile(int); 59*0Sstevel@tonic-gate extern void cpr_start_kernel_threads(void); 60*0Sstevel@tonic-gate extern void cpr_abbreviate_devpath(char *, char *); 61*0Sstevel@tonic-gate extern void cpr_convert_promtime(cpr_time_t *); 62*0Sstevel@tonic-gate extern void cpr_send_notice(void); 63*0Sstevel@tonic-gate extern void cpr_set_bitmap_size(void); 64*0Sstevel@tonic-gate extern void cpr_stat_init(); 65*0Sstevel@tonic-gate extern void cpr_statef_close(void); 66*0Sstevel@tonic-gate extern void flush_windows(void); 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate extern int pm_powering_down; 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate static int cpr_suspend(void); 71*0Sstevel@tonic-gate static int cpr_resume(void); 72*0Sstevel@tonic-gate static void cpr_suspend_init(void); 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate cpr_time_t wholecycle_tv; 75*0Sstevel@tonic-gate int cpr_suspend_succeeded; 76*0Sstevel@tonic-gate pfn_t curthreadpfn; 77*0Sstevel@tonic-gate int curthreadremapped; 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate /* 80*0Sstevel@tonic-gate * save or restore abort_enable; this prevents a drop 81*0Sstevel@tonic-gate * to kadb or prom during cpr_resume_devices() when 82*0Sstevel@tonic-gate * there is no kbd present; see abort_sequence_enter() 83*0Sstevel@tonic-gate */ 84*0Sstevel@tonic-gate static void 85*0Sstevel@tonic-gate cpr_sae(int stash) 86*0Sstevel@tonic-gate { 87*0Sstevel@tonic-gate static int saved_ae = -1; 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate if (stash) { 90*0Sstevel@tonic-gate saved_ae = abort_enable; 91*0Sstevel@tonic-gate abort_enable = 0; 92*0Sstevel@tonic-gate } else if (saved_ae != -1) { 93*0Sstevel@tonic-gate abort_enable = saved_ae; 94*0Sstevel@tonic-gate saved_ae = -1; 95*0Sstevel@tonic-gate } 96*0Sstevel@tonic-gate } 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate /* 100*0Sstevel@tonic-gate * The main switching point for cpr, this routine starts the ckpt 101*0Sstevel@tonic-gate * and state file saving routines; on resume the control is 102*0Sstevel@tonic-gate * returned back to here and it then calls the resume routine. 103*0Sstevel@tonic-gate */ 104*0Sstevel@tonic-gate int 105*0Sstevel@tonic-gate cpr_main(void) 106*0Sstevel@tonic-gate { 107*0Sstevel@tonic-gate label_t saveq = ttolwp(curthread)->lwp_qsav; 108*0Sstevel@tonic-gate int rc; 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate if (rc = cpr_default_setup(1)) 111*0Sstevel@tonic-gate return (rc); 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate /* 114*0Sstevel@tonic-gate * Remember where we are for resume 115*0Sstevel@tonic-gate */ 116*0Sstevel@tonic-gate if (!setjmp(&ttolwp(curthread)->lwp_qsav)) { 117*0Sstevel@tonic-gate /* 118*0Sstevel@tonic-gate * try to checkpoint the system, if failed return back 119*0Sstevel@tonic-gate * to userland, otherwise power off. 120*0Sstevel@tonic-gate */ 121*0Sstevel@tonic-gate rc = cpr_suspend(); 122*0Sstevel@tonic-gate if (rc || cpr_reusable_mode) { 123*0Sstevel@tonic-gate /* 124*0Sstevel@tonic-gate * We don't really want to go down, or 125*0Sstevel@tonic-gate * something went wrong in suspend, do what we can 126*0Sstevel@tonic-gate * to put the system back to an operable state then 127*0Sstevel@tonic-gate * return back to userland. 128*0Sstevel@tonic-gate */ 129*0Sstevel@tonic-gate (void) cpr_resume(); 130*0Sstevel@tonic-gate } 131*0Sstevel@tonic-gate } else { 132*0Sstevel@tonic-gate /* 133*0Sstevel@tonic-gate * This is the resumed side of longjmp, restore the previous 134*0Sstevel@tonic-gate * longjmp pointer if there is one so this will be transparent 135*0Sstevel@tonic-gate * to the world. 136*0Sstevel@tonic-gate */ 137*0Sstevel@tonic-gate ttolwp(curthread)->lwp_qsav = saveq; 138*0Sstevel@tonic-gate CPR->c_flags &= ~C_SUSPENDING; 139*0Sstevel@tonic-gate CPR->c_flags |= C_RESUMING; 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate /* 142*0Sstevel@tonic-gate * resume the system back to the original state 143*0Sstevel@tonic-gate */ 144*0Sstevel@tonic-gate rc = cpr_resume(); 145*0Sstevel@tonic-gate } 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate (void) cpr_default_setup(0); 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate return (rc); 150*0Sstevel@tonic-gate } 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate /* 154*0Sstevel@tonic-gate * check/disable or re-enable UFS logging 155*0Sstevel@tonic-gate */ 156*0Sstevel@tonic-gate static void 157*0Sstevel@tonic-gate cpr_log_status(int enable, int *svstat, vnode_t *vp) 158*0Sstevel@tonic-gate { 159*0Sstevel@tonic-gate int cmd, status, error; 160*0Sstevel@tonic-gate char *str, *able; 161*0Sstevel@tonic-gate fiolog_t fl; 162*0Sstevel@tonic-gate refstr_t *mntpt; 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate str = "cpr_log_status"; 165*0Sstevel@tonic-gate bzero(&fl, sizeof (fl)); 166*0Sstevel@tonic-gate fl.error = FIOLOG_ENONE; 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate /* 169*0Sstevel@tonic-gate * when disabling, first get and save logging status (0 or 1) 170*0Sstevel@tonic-gate */ 171*0Sstevel@tonic-gate if (enable == 0) { 172*0Sstevel@tonic-gate if (error = VOP_IOCTL(vp, _FIOISLOG, 173*0Sstevel@tonic-gate (uintptr_t)&status, FKIOCTL, CRED(), NULL)) { 174*0Sstevel@tonic-gate mntpt = vfs_getmntpoint(vp->v_vfsp); 175*0Sstevel@tonic-gate errp("%s: \"%s\", cant get logging status, error %d\n", 176*0Sstevel@tonic-gate str, refstr_value(mntpt), error); 177*0Sstevel@tonic-gate refstr_rele(mntpt); 178*0Sstevel@tonic-gate return; 179*0Sstevel@tonic-gate } 180*0Sstevel@tonic-gate *svstat = status; 181*0Sstevel@tonic-gate DEBUG5( 182*0Sstevel@tonic-gate { 183*0Sstevel@tonic-gate mntpt = vfs_getmntpoint(vp->v_vfsp); 184*0Sstevel@tonic-gate errp("%s: \"%s\", logging status = %d\n", 185*0Sstevel@tonic-gate str, refstr_value(mntpt), status); 186*0Sstevel@tonic-gate refstr_rele(mntpt); 187*0Sstevel@tonic-gate }); 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate able = "disable"; 190*0Sstevel@tonic-gate cmd = _FIOLOGDISABLE; 191*0Sstevel@tonic-gate } else { 192*0Sstevel@tonic-gate able = "enable"; 193*0Sstevel@tonic-gate cmd = _FIOLOGENABLE; 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate /* 197*0Sstevel@tonic-gate * disable or re-enable logging when the saved status is 1 198*0Sstevel@tonic-gate */ 199*0Sstevel@tonic-gate if (*svstat == 1) { 200*0Sstevel@tonic-gate error = VOP_IOCTL(vp, cmd, (uintptr_t)&fl, 201*0Sstevel@tonic-gate FKIOCTL, CRED(), NULL); 202*0Sstevel@tonic-gate if (error) { 203*0Sstevel@tonic-gate mntpt = vfs_getmntpoint(vp->v_vfsp); 204*0Sstevel@tonic-gate errp("%s: \"%s\", cant %s logging, error %d\n", 205*0Sstevel@tonic-gate str, refstr_value(mntpt), able, error); 206*0Sstevel@tonic-gate refstr_rele(mntpt); 207*0Sstevel@tonic-gate } else { 208*0Sstevel@tonic-gate DEBUG5( 209*0Sstevel@tonic-gate { 210*0Sstevel@tonic-gate mntpt = vfs_getmntpoint(vp->v_vfsp); 211*0Sstevel@tonic-gate errp("%s: \"%s\", logging is now %sd\n", 212*0Sstevel@tonic-gate str, refstr_value(mntpt), able); 213*0Sstevel@tonic-gate refstr_rele(mntpt); 214*0Sstevel@tonic-gate }); 215*0Sstevel@tonic-gate } 216*0Sstevel@tonic-gate } 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate /* 219*0Sstevel@tonic-gate * when enabling logging, reset the saved status 220*0Sstevel@tonic-gate * to unknown for next time 221*0Sstevel@tonic-gate */ 222*0Sstevel@tonic-gate if (enable) 223*0Sstevel@tonic-gate *svstat = -1; 224*0Sstevel@tonic-gate } 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate /* 228*0Sstevel@tonic-gate * enable/disable UFS logging on filesystems containing cpr_default_path 229*0Sstevel@tonic-gate * and cpr statefile. since the statefile can be on any fs, that fs 230*0Sstevel@tonic-gate * needs to be handled separately. this routine and cprboot expect that 231*0Sstevel@tonic-gate * CPR_CONFIG and CPR_DEFAULT both reside on the same fs, rootfs. cprboot 232*0Sstevel@tonic-gate * is loaded from the device with rootfs and uses the same device to open 233*0Sstevel@tonic-gate * both CPR_CONFIG and CPR_DEFAULT (see common/support.c). moving either 234*0Sstevel@tonic-gate * file outside of rootfs would cause errors during cprboot, plus cpr and 235*0Sstevel@tonic-gate * fsck problems with the new fs if logging were enabled. 236*0Sstevel@tonic-gate */ 237*0Sstevel@tonic-gate static int 238*0Sstevel@tonic-gate cpr_ufs_logging(int enable) 239*0Sstevel@tonic-gate { 240*0Sstevel@tonic-gate static int def_status = -1, sf_status = -1; 241*0Sstevel@tonic-gate struct vfs *vfsp; 242*0Sstevel@tonic-gate char *fname; 243*0Sstevel@tonic-gate vnode_t *vp; 244*0Sstevel@tonic-gate int error; 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate if (cpr_reusable_mode) 247*0Sstevel@tonic-gate return (0); 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate if (error = cpr_open_deffile(FREAD, &vp)) 250*0Sstevel@tonic-gate return (error); 251*0Sstevel@tonic-gate cpr_log_status(enable, &def_status, vp); 252*0Sstevel@tonic-gate vfsp = vp->v_vfsp; 253*0Sstevel@tonic-gate (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED()); 254*0Sstevel@tonic-gate VN_RELE(vp); 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate fname = cpr_build_statefile_path(); 257*0Sstevel@tonic-gate if (fname == NULL) 258*0Sstevel@tonic-gate return (ENOENT); 259*0Sstevel@tonic-gate if (error = vn_open(fname, UIO_SYSSPACE, FCREAT|FWRITE, 260*0Sstevel@tonic-gate 0600, &vp, CRCREAT, 0)) { 261*0Sstevel@tonic-gate errp("cpr_ufs_logging: cant open/create \"%s\", error %d\n", 262*0Sstevel@tonic-gate fname, error); 263*0Sstevel@tonic-gate return (error); 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate /* 267*0Sstevel@tonic-gate * check logging status for the statefile if it resides 268*0Sstevel@tonic-gate * on a different fs and the type is a regular file 269*0Sstevel@tonic-gate */ 270*0Sstevel@tonic-gate if (vp->v_vfsp != vfsp && vp->v_type == VREG) 271*0Sstevel@tonic-gate cpr_log_status(enable, &sf_status, vp); 272*0Sstevel@tonic-gate (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED()); 273*0Sstevel@tonic-gate VN_RELE(vp); 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate return (0); 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate /* 280*0Sstevel@tonic-gate * Check if klmmod is loaded and call a lock manager service; if klmmod 281*0Sstevel@tonic-gate * is not loaded, the services aren't needed and a call would trigger a 282*0Sstevel@tonic-gate * modload, which would block since another thread would never run. 283*0Sstevel@tonic-gate */ 284*0Sstevel@tonic-gate static void 285*0Sstevel@tonic-gate cpr_lock_mgr(void (*service)(void)) 286*0Sstevel@tonic-gate { 287*0Sstevel@tonic-gate if (mod_find_by_filename(NULL, "misc/klmmod") != NULL) 288*0Sstevel@tonic-gate (*service)(); 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate /* 292*0Sstevel@tonic-gate * Take the system down to a checkpointable state and write 293*0Sstevel@tonic-gate * the state file, the following are sequentially executed: 294*0Sstevel@tonic-gate * 295*0Sstevel@tonic-gate * - Request all user threads to stop themselves 296*0Sstevel@tonic-gate * - push out and invalidate user pages 297*0Sstevel@tonic-gate * - bring statefile inode incore to prevent a miss later 298*0Sstevel@tonic-gate * - request all daemons to stop 299*0Sstevel@tonic-gate * - check and make sure all threads are stopped 300*0Sstevel@tonic-gate * - sync the file system 301*0Sstevel@tonic-gate * - suspend all devices 302*0Sstevel@tonic-gate * - block intrpts 303*0Sstevel@tonic-gate * - dump system state and memory to state file 304*0Sstevel@tonic-gate */ 305*0Sstevel@tonic-gate static int 306*0Sstevel@tonic-gate cpr_suspend(void) 307*0Sstevel@tonic-gate { 308*0Sstevel@tonic-gate int sf_realloc, rc, skt_rc, nverr; 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate cpr_set_substate(C_ST_SUSPEND_BEGIN); 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate cpr_suspend_init(); 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate cpr_save_time(); 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate cpr_tod_get(&wholecycle_tv); 317*0Sstevel@tonic-gate CPR_STAT_EVENT_START("Suspend Total"); 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate if (!cpr_reusable_mode) { 320*0Sstevel@tonic-gate /* 321*0Sstevel@tonic-gate * We need to validate default file before fs functionality 322*0Sstevel@tonic-gate * is disabled. 323*0Sstevel@tonic-gate */ 324*0Sstevel@tonic-gate if (rc = cpr_validate_definfo(0)) 325*0Sstevel@tonic-gate return (rc); 326*0Sstevel@tonic-gate } 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate i_cpr_save_machdep_info(); 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate /* Stop PM scans ASAP */ 331*0Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PM, CB_CODE_CPR_CHKPT); 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_CPR_SUSPEND, 334*0Sstevel@tonic-gate NULL, NULL, PM_DEP_WAIT, NULL, 0); 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate cpr_set_substate(C_ST_MP_OFFLINE); 337*0Sstevel@tonic-gate if (rc = cpr_mp_offline()) 338*0Sstevel@tonic-gate return (rc); 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate /* 341*0Sstevel@tonic-gate * Ask the user threads to stop by themselves, but 342*0Sstevel@tonic-gate * if they don't or can't after 3 retries, we give up on CPR. 343*0Sstevel@tonic-gate * The 3 retry is not a random number because 2 is possible if 344*0Sstevel@tonic-gate * a thread has been forked before the parent thread is stopped. 345*0Sstevel@tonic-gate */ 346*0Sstevel@tonic-gate DEBUG1(errp("\nstopping user threads...")); 347*0Sstevel@tonic-gate CPR_STAT_EVENT_START(" stop users"); 348*0Sstevel@tonic-gate cpr_set_substate(C_ST_STOP_USER_THREADS); 349*0Sstevel@tonic-gate if (rc = cpr_stop_user_threads()) 350*0Sstevel@tonic-gate return (rc); 351*0Sstevel@tonic-gate CPR_STAT_EVENT_END(" stop users"); 352*0Sstevel@tonic-gate DEBUG1(errp("done\n")); 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate pm_save_direct_levels(); 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate /* 357*0Sstevel@tonic-gate * User threads are stopped. We will start communicating with the 358*0Sstevel@tonic-gate * user via prom_printf (some debug output may have already happened) 359*0Sstevel@tonic-gate * so let anybody who cares know about this (bug 4096122) 360*0Sstevel@tonic-gate */ 361*0Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PROMPRINTF, CB_CODE_CPR_CHKPT); 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate cpr_send_notice(); 364*0Sstevel@tonic-gate if (cpr_debug) 365*0Sstevel@tonic-gate errp("\n"); 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_USER, CB_CODE_CPR_CHKPT); 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate /* 370*0Sstevel@tonic-gate * Reattach any drivers which originally exported the 371*0Sstevel@tonic-gate * no-involuntary-power-cycles property. We need to do this before 372*0Sstevel@tonic-gate * stopping kernel threads because modload is implemented using 373*0Sstevel@tonic-gate * a kernel thread. 374*0Sstevel@tonic-gate */ 375*0Sstevel@tonic-gate cpr_set_substate(C_ST_PM_REATTACH_NOINVOL); 376*0Sstevel@tonic-gate if (!pm_reattach_noinvol()) 377*0Sstevel@tonic-gate return (ENXIO); 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate /* 380*0Sstevel@tonic-gate * if ufs logging is enabled, we need to disable before 381*0Sstevel@tonic-gate * stopping kernel threads so that ufs delete and roll 382*0Sstevel@tonic-gate * threads can do the work. 383*0Sstevel@tonic-gate */ 384*0Sstevel@tonic-gate cpr_set_substate(C_ST_DISABLE_UFS_LOGGING); 385*0Sstevel@tonic-gate if (rc = cpr_ufs_logging(0)) 386*0Sstevel@tonic-gate return (rc); 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate /* 389*0Sstevel@tonic-gate * Use sync_all to swap out all user pages and find out how much 390*0Sstevel@tonic-gate * extra space needed for user pages that don't have back store 391*0Sstevel@tonic-gate * space left. 392*0Sstevel@tonic-gate */ 393*0Sstevel@tonic-gate CPR_STAT_EVENT_START(" swapout upages"); 394*0Sstevel@tonic-gate vfs_sync(SYNC_ALL); 395*0Sstevel@tonic-gate CPR_STAT_EVENT_END(" swapout upages"); 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate cpr_set_bitmap_size(); 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate alloc_statefile: 400*0Sstevel@tonic-gate /* 401*0Sstevel@tonic-gate * If our last state was C_ST_DUMP_NOSPC, we're trying to realloc 402*0Sstevel@tonic-gate * the statefile, otherwise this is the first attempt. 403*0Sstevel@tonic-gate */ 404*0Sstevel@tonic-gate sf_realloc = (CPR->c_substate == C_ST_DUMP_NOSPC) ? 1 : 0; 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate CPR_STAT_EVENT_START(" alloc statefile"); 407*0Sstevel@tonic-gate cpr_set_substate(C_ST_STATEF_ALLOC); 408*0Sstevel@tonic-gate if (rc = cpr_alloc_statefile(sf_realloc)) { 409*0Sstevel@tonic-gate if (sf_realloc) 410*0Sstevel@tonic-gate errp("realloc failed\n"); 411*0Sstevel@tonic-gate return (rc); 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate CPR_STAT_EVENT_END(" alloc statefile"); 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate /* 416*0Sstevel@tonic-gate * Sync the filesystem to preserve its integrity. 417*0Sstevel@tonic-gate * 418*0Sstevel@tonic-gate * This sync is also used to flush out all B_DELWRI buffers (fs cache) 419*0Sstevel@tonic-gate * which are mapped and neither dirty nor referenced before 420*0Sstevel@tonic-gate * cpr_invalidate_pages destroys them. fsflush does similar thing. 421*0Sstevel@tonic-gate */ 422*0Sstevel@tonic-gate sync(); 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate /* 425*0Sstevel@tonic-gate * destroy all clean file mapped kernel pages 426*0Sstevel@tonic-gate */ 427*0Sstevel@tonic-gate CPR_STAT_EVENT_START(" clean pages"); 428*0Sstevel@tonic-gate DEBUG1(errp("cleaning up mapped pages...")); 429*0Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_VM, CB_CODE_CPR_CHKPT); 430*0Sstevel@tonic-gate DEBUG1(errp("done\n")); 431*0Sstevel@tonic-gate CPR_STAT_EVENT_END(" clean pages"); 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate /* 435*0Sstevel@tonic-gate * Hooks needed by lock manager prior to suspending. 436*0Sstevel@tonic-gate * Refer to code for more comments. 437*0Sstevel@tonic-gate */ 438*0Sstevel@tonic-gate cpr_lock_mgr(lm_cprsuspend); 439*0Sstevel@tonic-gate 440*0Sstevel@tonic-gate /* 441*0Sstevel@tonic-gate * Now suspend all the devices 442*0Sstevel@tonic-gate */ 443*0Sstevel@tonic-gate CPR_STAT_EVENT_START(" stop drivers"); 444*0Sstevel@tonic-gate DEBUG1(errp("suspending drivers...")); 445*0Sstevel@tonic-gate cpr_set_substate(C_ST_SUSPEND_DEVICES); 446*0Sstevel@tonic-gate pm_powering_down = 1; 447*0Sstevel@tonic-gate rc = cpr_suspend_devices(ddi_root_node()); 448*0Sstevel@tonic-gate pm_powering_down = 0; 449*0Sstevel@tonic-gate if (rc) 450*0Sstevel@tonic-gate return (rc); 451*0Sstevel@tonic-gate DEBUG1(errp("done\n")); 452*0Sstevel@tonic-gate CPR_STAT_EVENT_END(" stop drivers"); 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate /* 455*0Sstevel@tonic-gate * Stop all daemon activities 456*0Sstevel@tonic-gate */ 457*0Sstevel@tonic-gate cpr_set_substate(C_ST_STOP_KERNEL_THREADS); 458*0Sstevel@tonic-gate if (skt_rc = cpr_stop_kernel_threads()) 459*0Sstevel@tonic-gate return (skt_rc); 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_KERNEL, CB_CODE_CPR_CHKPT); 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate pm_reattach_noinvol_fini(); 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate cpr_sae(1); 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_CALLOUT, CB_CODE_CPR_CHKPT); 468*0Sstevel@tonic-gate 469*0Sstevel@tonic-gate /* 470*0Sstevel@tonic-gate * It's safer to do tod_get before we disable all intr. 471*0Sstevel@tonic-gate */ 472*0Sstevel@tonic-gate CPR_STAT_EVENT_START(" write statefile"); 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate /* 475*0Sstevel@tonic-gate * it's time to ignore the outside world, stop the real time 476*0Sstevel@tonic-gate * clock and disable any further intrpt activity. 477*0Sstevel@tonic-gate */ 478*0Sstevel@tonic-gate i_cpr_handle_xc(1); /* turn it on to disable xc assertion */ 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate mutex_enter(&cpu_lock); 481*0Sstevel@tonic-gate cyclic_suspend(); 482*0Sstevel@tonic-gate mutex_exit(&cpu_lock); 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate mon_clock_stop(); 485*0Sstevel@tonic-gate mon_clock_unshare(); 486*0Sstevel@tonic-gate mon_clock_start(); 487*0Sstevel@tonic-gate 488*0Sstevel@tonic-gate i_cpr_stop_intr(); 489*0Sstevel@tonic-gate DEBUG1(errp("interrupt is stopped\n")); 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate /* 492*0Sstevel@tonic-gate * Since we will now disable the mechanism that causes prom_printfs 493*0Sstevel@tonic-gate * to power up (if needed) the console fb/monitor, we assert that 494*0Sstevel@tonic-gate * it must be up now. 495*0Sstevel@tonic-gate */ 496*0Sstevel@tonic-gate ASSERT(pm_cfb_is_up()); 497*0Sstevel@tonic-gate prom_suspend_prepost(); 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate /* 500*0Sstevel@tonic-gate * getting ready to write ourself out, flush the register 501*0Sstevel@tonic-gate * windows to make sure that our stack is good when we 502*0Sstevel@tonic-gate * come back on the resume side. 503*0Sstevel@tonic-gate */ 504*0Sstevel@tonic-gate flush_windows(); 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate /* 507*0Sstevel@tonic-gate * FATAL: NO MORE MEMORY ALLOCATION ALLOWED AFTER THIS POINT!!! 508*0Sstevel@tonic-gate * 509*0Sstevel@tonic-gate * The system is quiesced at this point, we are ready to either dump 510*0Sstevel@tonic-gate * to the state file for a extended sleep or a simple shutdown for 511*0Sstevel@tonic-gate * systems with non-volatile memory. 512*0Sstevel@tonic-gate */ 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate /* 515*0Sstevel@tonic-gate * special handling for reusable: 516*0Sstevel@tonic-gate */ 517*0Sstevel@tonic-gate if (cpr_reusable_mode) { 518*0Sstevel@tonic-gate cpr_set_substate(C_ST_SETPROPS_1); 519*0Sstevel@tonic-gate if (nverr = cpr_set_properties(1)) 520*0Sstevel@tonic-gate return (nverr); 521*0Sstevel@tonic-gate } 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate cpr_set_substate(C_ST_DUMP); 524*0Sstevel@tonic-gate rc = cpr_dump(C_VP); 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate /* 527*0Sstevel@tonic-gate * if any error occured during dump, more 528*0Sstevel@tonic-gate * special handling for reusable: 529*0Sstevel@tonic-gate */ 530*0Sstevel@tonic-gate if (rc && cpr_reusable_mode) { 531*0Sstevel@tonic-gate cpr_set_substate(C_ST_SETPROPS_0); 532*0Sstevel@tonic-gate if (nverr = cpr_set_properties(0)) 533*0Sstevel@tonic-gate return (nverr); 534*0Sstevel@tonic-gate } 535*0Sstevel@tonic-gate 536*0Sstevel@tonic-gate if (rc == ENOSPC) { 537*0Sstevel@tonic-gate cpr_set_substate(C_ST_DUMP_NOSPC); 538*0Sstevel@tonic-gate (void) cpr_resume(); 539*0Sstevel@tonic-gate goto alloc_statefile; 540*0Sstevel@tonic-gate } else if (rc == 0) { 541*0Sstevel@tonic-gate if (cpr_reusable_mode) { 542*0Sstevel@tonic-gate cpr_set_substate(C_ST_REUSABLE); 543*0Sstevel@tonic-gate longjmp(&ttolwp(curthread)->lwp_qsav); 544*0Sstevel@tonic-gate } else 545*0Sstevel@tonic-gate rc = cpr_set_properties(1); 546*0Sstevel@tonic-gate } 547*0Sstevel@tonic-gate return (rc); 548*0Sstevel@tonic-gate } 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate /* 552*0Sstevel@tonic-gate * Bring the system back up from a checkpoint, at this point 553*0Sstevel@tonic-gate * the VM has been minimally restored by boot, the following 554*0Sstevel@tonic-gate * are executed sequentially: 555*0Sstevel@tonic-gate * 556*0Sstevel@tonic-gate * - machdep setup and enable interrupts (mp startup if it's mp) 557*0Sstevel@tonic-gate * - resume all devices 558*0Sstevel@tonic-gate * - restart daemons 559*0Sstevel@tonic-gate * - put all threads back on run queue 560*0Sstevel@tonic-gate */ 561*0Sstevel@tonic-gate static int 562*0Sstevel@tonic-gate cpr_resume(void) 563*0Sstevel@tonic-gate { 564*0Sstevel@tonic-gate cpr_time_t pwron_tv, *ctp; 565*0Sstevel@tonic-gate char *str; 566*0Sstevel@tonic-gate int rc = 0; 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate /* 569*0Sstevel@tonic-gate * The following switch is used to resume the system 570*0Sstevel@tonic-gate * that was suspended to a different level. 571*0Sstevel@tonic-gate */ 572*0Sstevel@tonic-gate DEBUG1(errp("\nEntering cpr_resume...\n")); 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate /* 575*0Sstevel@tonic-gate * Note: 576*0Sstevel@tonic-gate * 577*0Sstevel@tonic-gate * The rollback labels rb_xyz do not represent the cpr resume 578*0Sstevel@tonic-gate * state when event 'xyz' has happened. Instead they represent 579*0Sstevel@tonic-gate * the state during cpr suspend when event 'xyz' was being 580*0Sstevel@tonic-gate * entered (and where cpr suspend failed). The actual call that 581*0Sstevel@tonic-gate * failed may also need to be partially rolled back, since they 582*0Sstevel@tonic-gate * aren't atomic in most cases. In other words, rb_xyz means 583*0Sstevel@tonic-gate * "roll back all cpr suspend events that happened before 'xyz', 584*0Sstevel@tonic-gate * and the one that caused the failure, if necessary." 585*0Sstevel@tonic-gate */ 586*0Sstevel@tonic-gate switch (CPR->c_substate) { 587*0Sstevel@tonic-gate case C_ST_DUMP: 588*0Sstevel@tonic-gate /* 589*0Sstevel@tonic-gate * This is most likely a full-fledged cpr_resume after 590*0Sstevel@tonic-gate * a complete and successful cpr suspend. Just roll back 591*0Sstevel@tonic-gate * everything. 592*0Sstevel@tonic-gate */ 593*0Sstevel@tonic-gate break; 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate case C_ST_REUSABLE: 596*0Sstevel@tonic-gate case C_ST_DUMP_NOSPC: 597*0Sstevel@tonic-gate case C_ST_SETPROPS_0: 598*0Sstevel@tonic-gate case C_ST_SETPROPS_1: 599*0Sstevel@tonic-gate /* 600*0Sstevel@tonic-gate * C_ST_REUSABLE and C_ST_DUMP_NOSPC are the only two 601*0Sstevel@tonic-gate * special switch cases here. The other two do not have 602*0Sstevel@tonic-gate * any state change during cpr_suspend() that needs to 603*0Sstevel@tonic-gate * be rolled back. But these are exit points from 604*0Sstevel@tonic-gate * cpr_suspend, so theoretically (or in the future), it 605*0Sstevel@tonic-gate * is possible that a need for roll back of a state 606*0Sstevel@tonic-gate * change arises between these exit points. 607*0Sstevel@tonic-gate */ 608*0Sstevel@tonic-gate goto rb_dump; 609*0Sstevel@tonic-gate 610*0Sstevel@tonic-gate case C_ST_STOP_KERNEL_THREADS: 611*0Sstevel@tonic-gate goto rb_stop_kernel_threads; 612*0Sstevel@tonic-gate 613*0Sstevel@tonic-gate case C_ST_SUSPEND_DEVICES: 614*0Sstevel@tonic-gate goto rb_suspend_devices; 615*0Sstevel@tonic-gate 616*0Sstevel@tonic-gate case C_ST_STATEF_ALLOC: 617*0Sstevel@tonic-gate goto rb_statef_alloc; 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate case C_ST_DISABLE_UFS_LOGGING: 620*0Sstevel@tonic-gate goto rb_disable_ufs_logging; 621*0Sstevel@tonic-gate 622*0Sstevel@tonic-gate case C_ST_PM_REATTACH_NOINVOL: 623*0Sstevel@tonic-gate goto rb_pm_reattach_noinvol; 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate case C_ST_STOP_USER_THREADS: 626*0Sstevel@tonic-gate goto rb_stop_user_threads; 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate case C_ST_MP_OFFLINE: 629*0Sstevel@tonic-gate goto rb_mp_offline; 630*0Sstevel@tonic-gate 631*0Sstevel@tonic-gate default: 632*0Sstevel@tonic-gate goto rb_others; 633*0Sstevel@tonic-gate } 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate rb_all: 636*0Sstevel@tonic-gate /* 637*0Sstevel@tonic-gate * setup debugger trapping. 638*0Sstevel@tonic-gate */ 639*0Sstevel@tonic-gate if (cpr_suspend_succeeded) 640*0Sstevel@tonic-gate i_cpr_set_tbr(); 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate /* 643*0Sstevel@tonic-gate * tell prom to monitor keys before the kernel comes alive 644*0Sstevel@tonic-gate */ 645*0Sstevel@tonic-gate mon_clock_start(); 646*0Sstevel@tonic-gate 647*0Sstevel@tonic-gate /* 648*0Sstevel@tonic-gate * perform platform-dependent initialization 649*0Sstevel@tonic-gate */ 650*0Sstevel@tonic-gate if (cpr_suspend_succeeded) 651*0Sstevel@tonic-gate i_cpr_machdep_setup(); 652*0Sstevel@tonic-gate 653*0Sstevel@tonic-gate /* 654*0Sstevel@tonic-gate * system did not really go down if we jump here 655*0Sstevel@tonic-gate */ 656*0Sstevel@tonic-gate rb_dump: 657*0Sstevel@tonic-gate /* 658*0Sstevel@tonic-gate * IMPORTANT: SENSITIVE RESUME SEQUENCE 659*0Sstevel@tonic-gate * 660*0Sstevel@tonic-gate * DO NOT ADD ANY INITIALIZATION STEP BEFORE THIS POINT!! 661*0Sstevel@tonic-gate */ 662*0Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_DMA, CB_CODE_CPR_RESUME); 663*0Sstevel@tonic-gate if (cpr_suspend_succeeded) 664*0Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_RPC, CB_CODE_CPR_RESUME); 665*0Sstevel@tonic-gate 666*0Sstevel@tonic-gate prom_resume_prepost(); 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate if (cpr_suspend_succeeded && (boothowto & RB_DEBUG)) 669*0Sstevel@tonic-gate kdi_dvec_cpr_restart(); 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate /* 672*0Sstevel@tonic-gate * let the tmp callout catch up. 673*0Sstevel@tonic-gate */ 674*0Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_CALLOUT, CB_CODE_CPR_RESUME); 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate i_cpr_enable_intr(); 677*0Sstevel@tonic-gate 678*0Sstevel@tonic-gate mon_clock_stop(); 679*0Sstevel@tonic-gate mon_clock_share(); 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate mutex_enter(&cpu_lock); 682*0Sstevel@tonic-gate cyclic_resume(); 683*0Sstevel@tonic-gate mutex_exit(&cpu_lock); 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate mon_clock_start(); 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate i_cpr_handle_xc(0); /* turn it off to allow xc assertion */ 688*0Sstevel@tonic-gate 689*0Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_KERNEL, CB_CODE_CPR_RESUME); 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate /* 692*0Sstevel@tonic-gate * statistics gathering 693*0Sstevel@tonic-gate */ 694*0Sstevel@tonic-gate if (cpr_suspend_succeeded) { 695*0Sstevel@tonic-gate /* 696*0Sstevel@tonic-gate * Prevent false alarm in tod_validate() due to tod 697*0Sstevel@tonic-gate * value change between suspend and resume 698*0Sstevel@tonic-gate */ 699*0Sstevel@tonic-gate cpr_tod_fault_reset(); 700*0Sstevel@tonic-gate 701*0Sstevel@tonic-gate cpr_convert_promtime(&pwron_tv); 702*0Sstevel@tonic-gate 703*0Sstevel@tonic-gate ctp = &cpr_term.tm_shutdown; 704*0Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ(" write statefile", ctp); 705*0Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ("Suspend Total", ctp); 706*0Sstevel@tonic-gate 707*0Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ("Resume Total", &pwron_tv); 708*0Sstevel@tonic-gate 709*0Sstevel@tonic-gate str = " prom time"; 710*0Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ(str, &pwron_tv); 711*0Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_start; 712*0Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ(str, ctp); 713*0Sstevel@tonic-gate 714*0Sstevel@tonic-gate str = " read statefile"; 715*0Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ(str, ctp); 716*0Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_end; 717*0Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ(str, ctp); 718*0Sstevel@tonic-gate } 719*0Sstevel@tonic-gate 720*0Sstevel@tonic-gate rb_stop_kernel_threads: 721*0Sstevel@tonic-gate /* 722*0Sstevel@tonic-gate * Put all threads back to where they belong; get the kernel 723*0Sstevel@tonic-gate * daemons straightened up too. Note that the callback table 724*0Sstevel@tonic-gate * locked during cpr_stop_kernel_threads() is released only 725*0Sstevel@tonic-gate * in cpr_start_kernel_threads(). Ensure modunloading is 726*0Sstevel@tonic-gate * disabled before starting kernel threads, we don't want 727*0Sstevel@tonic-gate * modunload thread to start changing device tree underneath. 728*0Sstevel@tonic-gate */ 729*0Sstevel@tonic-gate modunload_disable(); 730*0Sstevel@tonic-gate cpr_start_kernel_threads(); 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate rb_suspend_devices: 733*0Sstevel@tonic-gate DEBUG1(errp("resuming devices...")); 734*0Sstevel@tonic-gate CPR_STAT_EVENT_START(" start drivers"); 735*0Sstevel@tonic-gate 736*0Sstevel@tonic-gate /* 737*0Sstevel@tonic-gate * The policy here is to continue resume everything we can if we did 738*0Sstevel@tonic-gate * not successfully finish suspend; and panic if we are coming back 739*0Sstevel@tonic-gate * from a fully suspended system. 740*0Sstevel@tonic-gate */ 741*0Sstevel@tonic-gate rc = cpr_resume_devices(ddi_root_node(), 0); 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate cpr_sae(0); 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate str = "Failed to resume one or more devices."; 746*0Sstevel@tonic-gate if (rc && CPR->c_substate == C_ST_DUMP) 747*0Sstevel@tonic-gate cpr_err(CE_PANIC, str); 748*0Sstevel@tonic-gate else if (rc) 749*0Sstevel@tonic-gate cpr_err(CE_WARN, str); 750*0Sstevel@tonic-gate CPR_STAT_EVENT_END(" start drivers"); 751*0Sstevel@tonic-gate DEBUG1(errp("done\n")); 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate /* 754*0Sstevel@tonic-gate * If we had disabled modunloading in this cpr resume cycle (i.e. we 755*0Sstevel@tonic-gate * resumed from a state earlier than C_ST_SUSPEND_DEVICES), re-enable 756*0Sstevel@tonic-gate * modunloading now. 757*0Sstevel@tonic-gate */ 758*0Sstevel@tonic-gate if (CPR->c_substate != C_ST_SUSPEND_DEVICES) 759*0Sstevel@tonic-gate modunload_enable(); 760*0Sstevel@tonic-gate 761*0Sstevel@tonic-gate /* 762*0Sstevel@tonic-gate * Hooks needed by lock manager prior to resuming. 763*0Sstevel@tonic-gate * Refer to code for more comments. 764*0Sstevel@tonic-gate */ 765*0Sstevel@tonic-gate cpr_lock_mgr(lm_cprresume); 766*0Sstevel@tonic-gate 767*0Sstevel@tonic-gate /* 768*0Sstevel@tonic-gate * This is a partial (half) resume during cpr suspend, we 769*0Sstevel@tonic-gate * haven't yet given up on the suspend. On return from here, 770*0Sstevel@tonic-gate * cpr_suspend() will try to reallocate and retry the suspend. 771*0Sstevel@tonic-gate */ 772*0Sstevel@tonic-gate if (CPR->c_substate == C_ST_DUMP_NOSPC) { 773*0Sstevel@tonic-gate mon_clock_stop(); 774*0Sstevel@tonic-gate return (0); 775*0Sstevel@tonic-gate } 776*0Sstevel@tonic-gate 777*0Sstevel@tonic-gate rb_statef_alloc: 778*0Sstevel@tonic-gate cpr_statef_close(); 779*0Sstevel@tonic-gate 780*0Sstevel@tonic-gate rb_disable_ufs_logging: 781*0Sstevel@tonic-gate /* 782*0Sstevel@tonic-gate * if ufs logging was disabled, re-enable 783*0Sstevel@tonic-gate */ 784*0Sstevel@tonic-gate (void) cpr_ufs_logging(1); 785*0Sstevel@tonic-gate 786*0Sstevel@tonic-gate rb_pm_reattach_noinvol: 787*0Sstevel@tonic-gate /* 788*0Sstevel@tonic-gate * When pm_reattach_noinvol() succeeds, modunload_thread will 789*0Sstevel@tonic-gate * remain disabled until after cpr suspend passes the 790*0Sstevel@tonic-gate * C_ST_STOP_KERNEL_THREADS state. If any failure happens before 791*0Sstevel@tonic-gate * cpr suspend reaches this state, we'll need to enable modunload 792*0Sstevel@tonic-gate * thread during rollback. 793*0Sstevel@tonic-gate */ 794*0Sstevel@tonic-gate if (CPR->c_substate == C_ST_DISABLE_UFS_LOGGING || 795*0Sstevel@tonic-gate CPR->c_substate == C_ST_STATEF_ALLOC || 796*0Sstevel@tonic-gate CPR->c_substate == C_ST_SUSPEND_DEVICES || 797*0Sstevel@tonic-gate CPR->c_substate == C_ST_STOP_KERNEL_THREADS) { 798*0Sstevel@tonic-gate pm_reattach_noinvol_fini(); 799*0Sstevel@tonic-gate } 800*0Sstevel@tonic-gate 801*0Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_POST_USER, CB_CODE_CPR_RESUME); 802*0Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PROMPRINTF, CB_CODE_CPR_RESUME); 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate pm_restore_direct_levels(); 805*0Sstevel@tonic-gate 806*0Sstevel@tonic-gate rb_stop_user_threads: 807*0Sstevel@tonic-gate DEBUG1(errp("starting user threads...")); 808*0Sstevel@tonic-gate cpr_start_user_threads(); 809*0Sstevel@tonic-gate DEBUG1(errp("done\n")); 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate rb_mp_offline: 812*0Sstevel@tonic-gate if (cpr_mp_online()) 813*0Sstevel@tonic-gate cpr_err(CE_WARN, "Failed to online all the processors."); 814*0Sstevel@tonic-gate 815*0Sstevel@tonic-gate rb_others: 816*0Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_CPR_RESUME, NULL, NULL, PM_DEP_WAIT, 817*0Sstevel@tonic-gate NULL, 0); 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate (void) callb_execute_class(CB_CL_CPR_PM, CB_CODE_CPR_RESUME); 820*0Sstevel@tonic-gate 821*0Sstevel@tonic-gate /* 822*0Sstevel@tonic-gate * now that all the drivers are going, kernel kbd driver can 823*0Sstevel@tonic-gate * take over, turn off prom monitor clock 824*0Sstevel@tonic-gate */ 825*0Sstevel@tonic-gate mon_clock_stop(); 826*0Sstevel@tonic-gate 827*0Sstevel@tonic-gate if (cpr_suspend_succeeded) { 828*0Sstevel@tonic-gate cpr_restore_time(); 829*0Sstevel@tonic-gate cpr_stat_record_events(); 830*0Sstevel@tonic-gate } 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate if (!cpr_reusable_mode) 833*0Sstevel@tonic-gate cpr_clear_definfo(); 834*0Sstevel@tonic-gate 835*0Sstevel@tonic-gate DEBUG1(errp("Sending SIGTHAW...")); 836*0Sstevel@tonic-gate cpr_signal_user(SIGTHAW); 837*0Sstevel@tonic-gate DEBUG1(errp("done\n")); 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate CPR_STAT_EVENT_END("Resume Total"); 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ("WHOLE CYCLE", &wholecycle_tv); 842*0Sstevel@tonic-gate CPR_STAT_EVENT_END("WHOLE CYCLE"); 843*0Sstevel@tonic-gate 844*0Sstevel@tonic-gate DEBUG1(cmn_err(CE_CONT, "\nThe system is back where you left!\n")); 845*0Sstevel@tonic-gate 846*0Sstevel@tonic-gate CPR_STAT_EVENT_START("POST CPR DELAY"); 847*0Sstevel@tonic-gate 848*0Sstevel@tonic-gate #ifdef CPR_STAT 849*0Sstevel@tonic-gate ctp = &cpr_term.tm_shutdown; 850*0Sstevel@tonic-gate CPR_STAT_EVENT_START_TMZ("PWROFF TIME", ctp); 851*0Sstevel@tonic-gate CPR_STAT_EVENT_END_TMZ("PWROFF TIME", &pwron_tv); 852*0Sstevel@tonic-gate 853*0Sstevel@tonic-gate CPR_STAT_EVENT_PRINT(); 854*0Sstevel@tonic-gate #endif /* CPR_STAT */ 855*0Sstevel@tonic-gate 856*0Sstevel@tonic-gate return (rc); 857*0Sstevel@tonic-gate } 858*0Sstevel@tonic-gate 859*0Sstevel@tonic-gate static void 860*0Sstevel@tonic-gate cpr_suspend_init(void) 861*0Sstevel@tonic-gate { 862*0Sstevel@tonic-gate cpr_time_t *ctp; 863*0Sstevel@tonic-gate 864*0Sstevel@tonic-gate cpr_stat_init(); 865*0Sstevel@tonic-gate 866*0Sstevel@tonic-gate /* 867*0Sstevel@tonic-gate * If cpr_suspend() failed before cpr_dump() gets a chance 868*0Sstevel@tonic-gate * to reinitialize the terminator of the statefile, 869*0Sstevel@tonic-gate * the values of the old terminator will still linger around. 870*0Sstevel@tonic-gate * Since the terminator contains information that we need to 871*0Sstevel@tonic-gate * decide whether suspend succeeded or not, we need to 872*0Sstevel@tonic-gate * reinitialize it as early as possible. 873*0Sstevel@tonic-gate */ 874*0Sstevel@tonic-gate cpr_term.real_statef_size = 0; 875*0Sstevel@tonic-gate ctp = &cpr_term.tm_shutdown; 876*0Sstevel@tonic-gate bzero(ctp, sizeof (*ctp)); 877*0Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_start; 878*0Sstevel@tonic-gate bzero(ctp, sizeof (*ctp)); 879*0Sstevel@tonic-gate ctp = &cpr_term.tm_cprboot_end; 880*0Sstevel@tonic-gate bzero(ctp, sizeof (*ctp)); 881*0Sstevel@tonic-gate 882*0Sstevel@tonic-gate /* 883*0Sstevel@tonic-gate * Lookup the physical address of our thread structure. This should 884*0Sstevel@tonic-gate * never be invalid and the entire thread structure is expected 885*0Sstevel@tonic-gate * to reside within the same pfn. 886*0Sstevel@tonic-gate */ 887*0Sstevel@tonic-gate curthreadpfn = hat_getpfnum(kas.a_hat, (caddr_t)curthread); 888*0Sstevel@tonic-gate ASSERT(curthreadpfn != PFN_INVALID); 889*0Sstevel@tonic-gate ASSERT(curthreadpfn == hat_getpfnum(kas.a_hat, 890*0Sstevel@tonic-gate (caddr_t)curthread + sizeof (kthread_t) - 1)); 891*0Sstevel@tonic-gate 892*0Sstevel@tonic-gate cpr_suspend_succeeded = 0; 893*0Sstevel@tonic-gate } 894