29949e866e40b95795203f3ee46f44a197c946e4stevel * CDDL HEADER START
29949e866e40b95795203f3ee46f44a197c946e4stevel * The contents of this file are subject to the terms of the
29949e866e40b95795203f3ee46f44a197c946e4stevel * Common Development and Distribution License (the "License").
29949e866e40b95795203f3ee46f44a197c946e4stevel * You may not use this file except in compliance with the License.
29949e866e40b95795203f3ee46f44a197c946e4stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
29949e866e40b95795203f3ee46f44a197c946e4stevel * See the License for the specific language governing permissions
29949e866e40b95795203f3ee46f44a197c946e4stevel * and limitations under the License.
29949e866e40b95795203f3ee46f44a197c946e4stevel * When distributing Covered Code, include this CDDL HEADER in each
29949e866e40b95795203f3ee46f44a197c946e4stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
29949e866e40b95795203f3ee46f44a197c946e4stevel * If applicable, add the following below this CDDL HEADER, with the
29949e866e40b95795203f3ee46f44a197c946e4stevel * fields enclosed by brackets "[]" replaced with your own identifying
29949e866e40b95795203f3ee46f44a197c946e4stevel * information: Portions Copyright [yyyy] [name of copyright owner]
29949e866e40b95795203f3ee46f44a197c946e4stevel * CDDL HEADER END
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
29949e866e40b95795203f3ee46f44a197c946e4stevel * Use is subject to license terms.
29949e866e40b95795203f3ee46f44a197c946e4stevel * This workaround inhibits prom_printf after the cpus are grabbed.
29949e866e40b95795203f3ee46f44a197c946e4stevel * This can be removed when 4154263 is corrected.
29949e866e40b95795203f3ee46f44a197c946e4stevel * A CPR derivative specifically for sunfire
29949e866e40b95795203f3ee46f44a197c946e4stevel * sysctrl_skip_user_threads is used to control if user threads should
29949e866e40b95795203f3ee46f44a197c946e4stevel * be suspended. If sysctrl_skip_user_threads is true, the rest of the
29949e866e40b95795203f3ee46f44a197c946e4stevel * flags are not used; if it is false, sysctrl_check_user_stop_result
29949e866e40b95795203f3ee46f44a197c946e4stevel * will be used to control whether or not we need to check suspend
29949e866e40b95795203f3ee46f44a197c946e4stevel * result, and sysctrl_allow_blocked_threads will be used to control
29949e866e40b95795203f3ee46f44a197c946e4stevel * whether or not we allow suspend to continue if there are blocked
29949e866e40b95795203f3ee46f44a197c946e4stevel * threads. We allow all combinations of sysctrl_check_user_stop_result
29949e866e40b95795203f3ee46f44a197c946e4stevel * and sysctrl_allow_block_threads, even though it might not make much
29949e866e40b95795203f3ee46f44a197c946e4stevel * sense to not allow block threads when we don't even check stop
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic int sysctrl_skip_user_threads = 0; /* default to FALSE */
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic int sysctrl_check_user_stop_result = 1; /* default to TRUE */
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic int sysctrl_allow_blocked_threads = 1; /* default to TRUE */
29949e866e40b95795203f3ee46f44a197c946e4stevel extern void sysctrl_freeze(void);
29949e866e40b95795203f3ee46f44a197c946e4stevel for (i = 0; i < NCPU; i++)
29949e866e40b95795203f3ee46f44a197c946e4stevel /* tell other cpus to go quiet and wait for continue signal */
29949e866e40b95795203f3ee46f44a197c946e4stevel xt_some(others, (xcfunc_t *)sysctrl_freeze, (uint64_t)sysctrl_gate,
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson sysc_tick_limit = ((uint64_t)sys_tick_freq * SYSC_CPU_LOOP_MSEC) / 1000;
29949e866e40b95795203f3ee46f44a197c946e4stevel /* wait for each cpu to check in */
29949e866e40b95795203f3ee46f44a197c946e4stevel for (i = 0; i < NCPU; i++) {
29949e866e40b95795203f3ee46f44a197c946e4stevel * Get current tick value and calculate the deadline tick
29949e866e40b95795203f3ee46f44a197c946e4stevel sysc_tick_deadline = sysc_current_tick + sysc_tick_limit;
29949e866e40b95795203f3ee46f44a197c946e4stevel while (sysctrl_gate[i] == 0) {
29949e866e40b95795203f3ee46f44a197c946e4stevel /* If in panic, we just return */
29949e866e40b95795203f3ee46f44a197c946e4stevel /* Panic the system if cpu not responsed by deadline */
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "responding to quiesce command", i);
29949e866e40b95795203f3ee46f44a197c946e4stevel /* now even our interrupts are disabled -- really quiet now */
29949e866e40b95795203f3ee46f44a197c946e4stevel /* let the other cpus go */
29949e866e40b95795203f3ee46f44a197c946e4stevel /* restore our interrupts too */
29949e866e40b95795203f3ee46f44a197c946e4stevel if (DEVI(dip)->devi_pm_flags & (PMC_NEEDS_SR|PMC_PARENTAL_SR))
29949e866e40b95795203f3ee46f44a197c946e4stevel * now the general case
29949e866e40b95795203f3ee46f44a197c946e4stevel rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_suspend_devices(dev_info_t *dip, sysc_cfga_pkt_t *pkt)
29949e866e40b95795203f3ee46f44a197c946e4stevel for (; dip != NULL; dip = ddi_get_next_sibling(dip)) {
29949e866e40b95795203f3ee46f44a197c946e4stevel * Hold parent busy while walking child list
29949e866e40b95795203f3ee46f44a197c946e4stevel if (sysctrl_suspend_devices(ddi_get_child(dip), pkt)) {
29949e866e40b95795203f3ee46f44a197c946e4stevel * Safe to call ddi_pathname() as parent is held busy
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp(" suspending device %s\n", device_path));
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_resume_devices(dev_info_t *start, sysc_cfga_pkt_t *pkt)
29949e866e40b95795203f3ee46f44a197c946e4stevel ASSERT(start == NULL || ddi_get_parent(start) == NULL ||
29949e866e40b95795203f3ee46f44a197c946e4stevel /* attach in reverse device tree order */
29949e866e40b95795203f3ee46f44a197c946e4stevel * Parent dip is held busy, so ddi_pathname() can
29949e866e40b95795203f3ee46f44a197c946e4stevel * be safely called.
29949e866e40b95795203f3ee46f44a197c946e4stevel * XXX - if in the future we decide not to
29949e866e40b95795203f3ee46f44a197c946e4stevel * panic the system, we need to set the error
29949e866e40b95795203f3ee46f44a197c946e4stevel * SYSC_ERR_RESUME here and also change the
29949e866e40b95795203f3ee46f44a197c946e4stevel * cfgadm platform library.
29949e866e40b95795203f3ee46f44a197c946e4stevel * True if thread is virtually stopped. Similar to CPR_VSTOPPED
29949e866e40b95795203f3ee46f44a197c946e4stevel * but from DR point of view. These user threads are waiting in
29949e866e40b95795203f3ee46f44a197c946e4stevel * the kernel. Once they complete in the kernel, they will process
29949e866e40b95795203f3ee46f44a197c946e4stevel * the stop signal and stop.
29949e866e40b95795203f3ee46f44a197c946e4stevel extern void add_one_utstop();
29949e866e40b95795203f3ee46f44a197c946e4stevel extern void utstop_init(void);
29949e866e40b95795203f3ee46f44a197c946e4stevel /* we need to try a few times to get past fork, etc. */
29949e866e40b95795203f3ee46f44a197c946e4stevel for (count = 0; count < SYSCTRL_UTSTOP_RETRY; count++) {
29949e866e40b95795203f3ee46f44a197c946e4stevel /* walk the entire threadlist */
29949e866e40b95795203f3ee46f44a197c946e4stevel for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) {
29949e866e40b95795203f3ee46f44a197c946e4stevel /* handle kernel threads separately */
29949e866e40b95795203f3ee46f44a197c946e4stevel /* add another reason to stop this thread */
29949e866e40b95795203f3ee46f44a197c946e4stevel /* grab thread if needed */
29949e866e40b95795203f3ee46f44a197c946e4stevel /* let everything catch up */
29949e866e40b95795203f3ee46f44a197c946e4stevel utstop_timedwait(count * count * SYSCTRL_UTSTOP_WAIT);
29949e866e40b95795203f3ee46f44a197c946e4stevel /* now, walk the threadlist again to see if we are done */
29949e866e40b95795203f3ee46f44a197c946e4stevel /* handle kernel threads separately */
29949e866e40b95795203f3ee46f44a197c946e4stevel * If this thread didn't stop, and we don't allow
29949e866e40b95795203f3ee46f44a197c946e4stevel * unstopped blocked threads, bail.
29949e866e40b95795203f3ee46f44a197c946e4stevel /* did this thread stop? */
29949e866e40b95795203f3ee46f44a197c946e4stevel /* nope, cache the details for later */
29949e866e40b95795203f3ee46f44a197c946e4stevel /* were all the threads stopped? */
29949e866e40b95795203f3ee46f44a197c946e4stevel /* were we unable to stop all threads after a few tries? */
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) sprintf(pkt->errbuf, "process: %s id: %d state: %x"
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson " thread descriptor: %p", cache_psargs, (int)pid,
29949e866e40b95795203f3ee46f44a197c946e4stevel * Note: we unlock the table in resume.
29949e866e40b95795203f3ee46f44a197c946e4stevel * We only need to lock the callback table if we are actually
29949e866e40b95795203f3ee46f44a197c946e4stevel * suspending kernel threads.
29949e866e40b95795203f3ee46f44a197c946e4stevel * Verify that all threads are accounted for
29949e866e40b95795203f3ee46f44a197c946e4stevel for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) {
29949e866e40b95795203f3ee46f44a197c946e4stevel /* walk all threads and release them */
29949e866e40b95795203f3ee46f44a197c946e4stevel for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) {
29949e866e40b95795203f3ee46f44a197c946e4stevel /* skip kernel threads */
29949e866e40b95795203f3ee46f44a197c946e4stevel /* back on the runq */
29949e866e40b95795203f3ee46f44a197c946e4stevel /* only user threads */
29949e866e40b95795203f3ee46f44a197c946e4stevel /* add a bit of delay */
29949e866e40b95795203f3ee46f44a197c946e4stevel * release all the other cpus
646e55b6807cdf761fecd1e4095d73116cdefdb5cth * Prevent false alarm in tod_validate() due to tod
646e55b6807cdf761fecd1e4095d73116cdefdb5cth * value change between suspend and resume
29949e866e40b95795203f3ee46f44a197c946e4stevel * If we suspended hw watchdog at suspend,
29949e866e40b95795203f3ee46f44a197c946e4stevel * re-enable it now.
29949e866e40b95795203f3ee46f44a197c946e4stevel * resume callout
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) callb_execute_class(CB_CL_CPR_RPC, CB_CODE_CPR_RESUME);
29949e866e40b95795203f3ee46f44a197c946e4stevel /* FALLTHROUGH */
29949e866e40b95795203f3ee46f44a197c946e4stevel * resume drivers
29949e866e40b95795203f3ee46f44a197c946e4stevel * resume the lock manager
29949e866e40b95795203f3ee46f44a197c946e4stevel /* FALLTHROUGH */
29949e866e40b95795203f3ee46f44a197c946e4stevel * resume kernel daemons
29949e866e40b95795203f3ee46f44a197c946e4stevel /* FALLTHROUGH */
29949e866e40b95795203f3ee46f44a197c946e4stevel * finally, resume user threads
29949e866e40b95795203f3ee46f44a197c946e4stevel /* FALLTHROUGH */
29949e866e40b95795203f3ee46f44a197c946e4stevel * let those who care know that we've just resumed
29949e866e40b95795203f3ee46f44a197c946e4stevel /* Restore sysctrl detach/suspend to its original value */
29949e866e40b95795203f3ee46f44a197c946e4stevel * We use a function, lm_cprsuspend(), in the suspend flow that
29949e866e40b95795203f3ee46f44a197c946e4stevel * is redirected to a module through the modstubs mechanism.
29949e866e40b95795203f3ee46f44a197c946e4stevel * If the module is currently not loaded, modstubs attempts
29949e866e40b95795203f3ee46f44a197c946e4stevel * the modload. The context this happens in below causes the
29949e866e40b95795203f3ee46f44a197c946e4stevel * module load to block forever, so this function must be called
29949e866e40b95795203f3ee46f44a197c946e4stevel * in the normal system call context ahead of time.
29949e866e40b95795203f3ee46f44a197c946e4stevel /* enable sysctrl detach/suspend function */
29949e866e40b95795203f3ee46f44a197c946e4stevel * first, stop all user threads
29949e866e40b95795203f3ee46f44a197c946e4stevel if (((rc = sysctrl_stop_user_threads(pkt)) != DDI_SUCCESS) &&
29949e866e40b95795203f3ee46f44a197c946e4stevel * now stop daemon activities
29949e866e40b95795203f3ee46f44a197c946e4stevel * This sync swap out all user pages
29949e866e40b95795203f3ee46f44a197c946e4stevel * special treatment for lock manager
29949e866e40b95795203f3ee46f44a197c946e4stevel * sync the file system in case we never make it back
29949e866e40b95795203f3ee46f44a197c946e4stevel * now suspend drivers
29949e866e40b95795203f3ee46f44a197c946e4stevel if (rc = sysctrl_suspend_devices(ddi_root_node(), pkt)) {
29949e866e40b95795203f3ee46f44a197c946e4stevel * handle the callout table
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) callb_execute_class(CB_CL_CPR_CALLOUT, CB_CODE_CPR_CHKPT);
29949e866e40b95795203f3ee46f44a197c946e4stevel * if watchdog was activated, disable it
29949e866e40b95795203f3ee46f44a197c946e4stevel * finally, grab all cpus