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