29949e866e40b95795203f3ee46f44a197c946e4stevel/*
29949e866e40b95795203f3ee46f44a197c946e4stevel * CDDL HEADER START
29949e866e40b95795203f3ee46f44a197c946e4stevel *
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 *
29949e866e40b95795203f3ee46f44a197c946e4stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
29949e866e40b95795203f3ee46f44a197c946e4stevel * or http://www.opensolaris.org/os/licensing.
29949e866e40b95795203f3ee46f44a197c946e4stevel * See the License for the specific language governing permissions
29949e866e40b95795203f3ee46f44a197c946e4stevel * and limitations under the License.
29949e866e40b95795203f3ee46f44a197c946e4stevel *
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 *
29949e866e40b95795203f3ee46f44a197c946e4stevel * CDDL HEADER END
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel/*
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
29949e866e40b95795203f3ee46f44a197c946e4stevel * Use is subject to license terms.
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel/*
29949e866e40b95795203f3ee46f44a197c946e4stevel * This workaround inhibits prom_printf after the cpus are grabbed.
29949e866e40b95795203f3ee46f44a197c946e4stevel * This can be removed when 4154263 is corrected.
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel#define Bug_4154263
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel/*
29949e866e40b95795203f3ee46f44a197c946e4stevel * A CPR derivative specifically for sunfire
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/types.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/systm.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/machparam.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/machsystm.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/ddi.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#define SUNDDI_IMPL
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/sunddi.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/time.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/kmem.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <nfs/lm.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/ddi_impldefs.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/obpdefs.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/cmn_err.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/debug.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/errno.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/callb.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/clock.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/x_call.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/cpuvar.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/epm.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/vfs.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/fhc.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/sysctrl.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/promif.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/conf.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/modctl.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/cyclic.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/sunndi.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/machsystm.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic enum sysctrl_suspend_state {
29949e866e40b95795203f3ee46f44a197c946e4stevel SYSC_STATE_BEGIN = 0,
29949e866e40b95795203f3ee46f44a197c946e4stevel SYSC_STATE_USER,
29949e866e40b95795203f3ee46f44a197c946e4stevel SYSC_STATE_DAEMON,
29949e866e40b95795203f3ee46f44a197c946e4stevel SYSC_STATE_DRIVER,
29949e866e40b95795203f3ee46f44a197c946e4stevel SYSC_STATE_FULL } suspend_state;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic int pstate_save;
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic uint_t sysctrl_gate[NCPU];
29949e866e40b95795203f3ee46f44a197c946e4stevelint sysctrl_quiesce_debug = FALSE;
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic int sysctrl_skip_kernel_threads = TRUE;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel/*
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
29949e866e40b95795203f3ee46f44a197c946e4stevel * result.
29949e866e40b95795203f3ee46f44a197c946e4stevel */
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
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic int sysc_watchdog_suspended;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelextern int sysctrl_enable_detach_suspend;
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic int sysc_lastval;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel#define DEBUGP(p) { if (sysctrl_quiesce_debug) p; }
29949e866e40b95795203f3ee46f44a197c946e4stevel#define errp prom_printf
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel#define SYSC_CPU_LOOP_MSEC 1000
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic void
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_grab_cpus(void)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel int i;
29949e866e40b95795203f3ee46f44a197c946e4stevel cpuset_t others;
29949e866e40b95795203f3ee46f44a197c946e4stevel extern cpuset_t cpu_ready_set;
29949e866e40b95795203f3ee46f44a197c946e4stevel extern void sysctrl_freeze(void);
29949e866e40b95795203f3ee46f44a197c946e4stevel uint64_t sysc_tick_limit;
29949e866e40b95795203f3ee46f44a197c946e4stevel uint64_t sysc_current_tick;
29949e866e40b95795203f3ee46f44a197c946e4stevel uint64_t sysc_tick_deadline;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel extern u_longlong_t gettick(void);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel for (i = 0; i < NCPU; i++)
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_gate[i] = 0;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* tell other cpus to go quiet and wait for continue signal */
29949e866e40b95795203f3ee46f44a197c946e4stevel others = cpu_ready_set;
29949e866e40b95795203f3ee46f44a197c946e4stevel CPUSET_DEL(others, CPU->cpu_id);
29949e866e40b95795203f3ee46f44a197c946e4stevel xt_some(others, (xcfunc_t *)sysctrl_freeze, (uint64_t)sysctrl_gate,
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson (uint64_t)(&sysctrl_gate[CPU->cpu_id]));
29949e866e40b95795203f3ee46f44a197c946e4stevel
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson sysc_tick_limit = ((uint64_t)sys_tick_freq * SYSC_CPU_LOOP_MSEC) / 1000;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* wait for each cpu to check in */
29949e866e40b95795203f3ee46f44a197c946e4stevel for (i = 0; i < NCPU; i++) {
29949e866e40b95795203f3ee46f44a197c946e4stevel if (!CPU_IN_SET(others, i))
29949e866e40b95795203f3ee46f44a197c946e4stevel continue;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * Get current tick value and calculate the deadline tick
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel sysc_current_tick = gettick();
29949e866e40b95795203f3ee46f44a197c946e4stevel sysc_tick_deadline = sysc_current_tick + sysc_tick_limit;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel while (sysctrl_gate[i] == 0) {
29949e866e40b95795203f3ee46f44a197c946e4stevel /* If in panic, we just return */
29949e866e40b95795203f3ee46f44a197c946e4stevel if (panicstr)
29949e866e40b95795203f3ee46f44a197c946e4stevel break;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* Panic the system if cpu not responsed by deadline */
29949e866e40b95795203f3ee46f44a197c946e4stevel sysc_current_tick = gettick();
29949e866e40b95795203f3ee46f44a197c946e4stevel if (sysc_current_tick >= sysc_tick_deadline) {
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson cmn_err(CE_PANIC, "sysctrl: cpu %d not "
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "responding to quiesce command", i);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* now even our interrupts are disabled -- really quiet now */
29949e866e40b95795203f3ee46f44a197c946e4stevel pstate_save = disable_vec_intr();
29949e866e40b95795203f3ee46f44a197c946e4stevel}
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic void
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_release_cpus(void)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel /* let the other cpus go */
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_gate[CPU->cpu_id] = 1;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* restore our interrupts too */
29949e866e40b95795203f3ee46f44a197c946e4stevel enable_vec_intr(pstate_save);
29949e866e40b95795203f3ee46f44a197c946e4stevel}
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic void
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_stop_intr(void)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_enter(&cpu_lock);
29949e866e40b95795203f3ee46f44a197c946e4stevel kpreempt_disable();
29949e866e40b95795203f3ee46f44a197c946e4stevel cyclic_suspend();
29949e866e40b95795203f3ee46f44a197c946e4stevel}
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic void
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_enable_intr(void)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel cyclic_resume();
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) spl0();
29949e866e40b95795203f3ee46f44a197c946e4stevel kpreempt_enable();
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_exit(&cpu_lock);
29949e866e40b95795203f3ee46f44a197c946e4stevel}
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic int
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_is_real_device(dev_info_t *dip)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel struct regspec *regbuf;
29949e866e40b95795203f3ee46f44a197c946e4stevel int length;
29949e866e40b95795203f3ee46f44a197c946e4stevel int rc;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel if (ddi_get_driver(dip) == NULL)
29949e866e40b95795203f3ee46f44a197c946e4stevel return (FALSE);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel if (DEVI(dip)->devi_pm_flags & (PMC_NEEDS_SR|PMC_PARENTAL_SR))
29949e866e40b95795203f3ee46f44a197c946e4stevel return (TRUE);
29949e866e40b95795203f3ee46f44a197c946e4stevel if (DEVI(dip)->devi_pm_flags & PMC_NO_SR)
29949e866e40b95795203f3ee46f44a197c946e4stevel return (FALSE);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * now the general case
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson (caddr_t)&regbuf, &length);
29949e866e40b95795203f3ee46f44a197c946e4stevel ASSERT(rc != DDI_PROP_NO_MEMORY);
29949e866e40b95795203f3ee46f44a197c946e4stevel if (rc != DDI_PROP_SUCCESS) {
29949e866e40b95795203f3ee46f44a197c946e4stevel return (FALSE);
29949e866e40b95795203f3ee46f44a197c946e4stevel } else {
29949e866e40b95795203f3ee46f44a197c946e4stevel kmem_free(regbuf, length);
29949e866e40b95795203f3ee46f44a197c946e4stevel return (TRUE);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel}
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic dev_info_t *failed_driver;
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic char device_path[MAXPATHLEN];
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic int
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_suspend_devices(dev_info_t *dip, sysc_cfga_pkt_t *pkt)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel int circ;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel ASSERT(dip == NULL || ddi_get_parent(dip) == NULL ||
29949e866e40b95795203f3ee46f44a197c946e4stevel DEVI_BUSY_OWNED(ddi_get_parent(dip)));
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel failed_driver = NULL;
29949e866e40b95795203f3ee46f44a197c946e4stevel for (; dip != NULL; dip = ddi_get_next_sibling(dip)) {
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * Hold parent busy while walking child list
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel ndi_devi_enter(dip, &circ);
29949e866e40b95795203f3ee46f44a197c946e4stevel if (sysctrl_suspend_devices(ddi_get_child(dip), pkt)) {
29949e866e40b95795203f3ee46f44a197c946e4stevel ndi_devi_exit(dip, circ);
29949e866e40b95795203f3ee46f44a197c946e4stevel return (ENXIO);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel ndi_devi_exit(dip, circ);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel if (!sysctrl_is_real_device(dip))
29949e866e40b95795203f3ee46f44a197c946e4stevel continue;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * Safe to call ddi_pathname() as parent is held busy
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) ddi_pathname(dip, device_path);
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp(" suspending device %s\n", device_path));
29949e866e40b95795203f3ee46f44a197c946e4stevel if (devi_detach(dip, DDI_SUSPEND) != DDI_SUCCESS) {
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp(" unable to suspend device %s\n",
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson device_path));
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) strncpy(pkt->errbuf, device_path,
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson SYSC_OUTPUT_LEN);
29949e866e40b95795203f3ee46f44a197c946e4stevel SYSC_ERR_SET(pkt, SYSC_ERR_SUSPEND);
29949e866e40b95795203f3ee46f44a197c946e4stevel ndi_hold_devi(dip);
29949e866e40b95795203f3ee46f44a197c946e4stevel failed_driver = dip;
29949e866e40b95795203f3ee46f44a197c946e4stevel return (ENXIO);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel return (DDI_SUCCESS);
29949e866e40b95795203f3ee46f44a197c946e4stevel}
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic void
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_resume_devices(dev_info_t *start, sysc_cfga_pkt_t *pkt)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel int circ;
29949e866e40b95795203f3ee46f44a197c946e4stevel dev_info_t *dip, *next, *last = NULL;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel ASSERT(start == NULL || ddi_get_parent(start) == NULL ||
29949e866e40b95795203f3ee46f44a197c946e4stevel DEVI_BUSY_OWNED(ddi_get_parent(start)));
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* attach in reverse device tree order */
29949e866e40b95795203f3ee46f44a197c946e4stevel while (last != start) {
29949e866e40b95795203f3ee46f44a197c946e4stevel dip = start;
29949e866e40b95795203f3ee46f44a197c946e4stevel next = ddi_get_next_sibling(dip);
29949e866e40b95795203f3ee46f44a197c946e4stevel while (next != last && dip != failed_driver) {
29949e866e40b95795203f3ee46f44a197c946e4stevel dip = next;
29949e866e40b95795203f3ee46f44a197c946e4stevel next = ddi_get_next_sibling(dip);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel if (dip == failed_driver) {
29949e866e40b95795203f3ee46f44a197c946e4stevel failed_driver = NULL;
29949e866e40b95795203f3ee46f44a197c946e4stevel ndi_rele_devi(dip);
29949e866e40b95795203f3ee46f44a197c946e4stevel } else if (sysctrl_is_real_device(dip) &&
29949e866e40b95795203f3ee46f44a197c946e4stevel failed_driver == NULL) {
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * Parent dip is held busy, so ddi_pathname() can
29949e866e40b95795203f3ee46f44a197c946e4stevel * be safely called.
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) ddi_pathname(dip, device_path);
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp(" resuming device %s\n", device_path));
29949e866e40b95795203f3ee46f44a197c946e4stevel if (devi_attach(dip, DDI_RESUME) != DDI_SUCCESS) {
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
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 */
29949e866e40b95795203f3ee46f44a197c946e4stevel cmn_err(CE_PANIC, "Unable to resume device %s",
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson device_path);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel ndi_devi_enter(dip, &circ);
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_resume_devices(ddi_get_child(dip), pkt);
29949e866e40b95795203f3ee46f44a197c946e4stevel ndi_devi_exit(dip, circ);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel last = dip;
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel}
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel/*
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 */
29949e866e40b95795203f3ee46f44a197c946e4stevel#define SYSCTRL_VSTOPPED(t) \
29949e866e40b95795203f3ee46f44a197c946e4stevel ((t)->t_state == TS_SLEEP && \
29949e866e40b95795203f3ee46f44a197c946e4stevel (t)->t_wchan != NULL && \
29949e866e40b95795203f3ee46f44a197c946e4stevel (t)->t_astflag && \
29949e866e40b95795203f3ee46f44a197c946e4stevel ((t)->t_proc_flag & TP_CHKPT))
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic int
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_stop_user_threads(sysc_cfga_pkt_t *pkt)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel int count;
29949e866e40b95795203f3ee46f44a197c946e4stevel char cache_psargs[PSARGSZ];
29949e866e40b95795203f3ee46f44a197c946e4stevel kthread_id_t cache_tp;
29949e866e40b95795203f3ee46f44a197c946e4stevel uint_t cache_t_state;
29949e866e40b95795203f3ee46f44a197c946e4stevel int bailout;
29949e866e40b95795203f3ee46f44a197c946e4stevel pid_t pid;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel extern void add_one_utstop();
29949e866e40b95795203f3ee46f44a197c946e4stevel extern void utstop_timedwait(clock_t);
29949e866e40b95795203f3ee46f44a197c946e4stevel extern void utstop_init(void);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel#define SYSCTRL_UTSTOP_RETRY 4
29949e866e40b95795203f3ee46f44a197c946e4stevel#define SYSCTRL_UTSTOP_WAIT hz
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel if (sysctrl_skip_user_threads)
29949e866e40b95795203f3ee46f44a197c946e4stevel return (DDI_SUCCESS);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel utstop_init();
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* we need to try a few times to get past fork, etc. */
29949e866e40b95795203f3ee46f44a197c946e4stevel for (count = 0; count < SYSCTRL_UTSTOP_RETRY; count++) {
29949e866e40b95795203f3ee46f44a197c946e4stevel kthread_id_t tp;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* walk the entire threadlist */
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_enter(&pidlock);
29949e866e40b95795203f3ee46f44a197c946e4stevel for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) {
29949e866e40b95795203f3ee46f44a197c946e4stevel proc_t *p = ttoproc(tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* handle kernel threads separately */
29949e866e40b95795203f3ee46f44a197c946e4stevel if (p->p_as == &kas || p->p_stat == SZOMB)
29949e866e40b95795203f3ee46f44a197c946e4stevel continue;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_enter(&p->p_lock);
29949e866e40b95795203f3ee46f44a197c946e4stevel thread_lock(tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel if (tp->t_state == TS_STOPPED) {
29949e866e40b95795203f3ee46f44a197c946e4stevel /* add another reason to stop this thread */
29949e866e40b95795203f3ee46f44a197c946e4stevel tp->t_schedflag &= ~TS_RESUME;
29949e866e40b95795203f3ee46f44a197c946e4stevel } else {
29949e866e40b95795203f3ee46f44a197c946e4stevel tp->t_proc_flag |= TP_CHKPT;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel thread_unlock(tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_exit(&p->p_lock);
29949e866e40b95795203f3ee46f44a197c946e4stevel add_one_utstop();
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_enter(&p->p_lock);
29949e866e40b95795203f3ee46f44a197c946e4stevel thread_lock(tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel aston(tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel
c97ad5cdc75eb73e3cc38542ca3ba783574b0a7aakolb if (ISWAKEABLE(tp) || ISWAITING(tp)) {
29949e866e40b95795203f3ee46f44a197c946e4stevel setrun_locked(tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* grab thread if needed */
29949e866e40b95795203f3ee46f44a197c946e4stevel if (tp->t_state == TS_ONPROC && tp->t_cpu != CPU)
29949e866e40b95795203f3ee46f44a197c946e4stevel poke_cpu(tp->t_cpu->cpu_id);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel thread_unlock(tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_exit(&p->p_lock);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_exit(&pidlock);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* let everything catch up */
29949e866e40b95795203f3ee46f44a197c946e4stevel utstop_timedwait(count * count * SYSCTRL_UTSTOP_WAIT);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* now, walk the threadlist again to see if we are done */
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_enter(&pidlock);
29949e866e40b95795203f3ee46f44a197c946e4stevel for (tp = curthread->t_next, bailout = 0;
29949e866e40b95795203f3ee46f44a197c946e4stevel bailout == 0 && tp != curthread; tp = tp->t_next) {
29949e866e40b95795203f3ee46f44a197c946e4stevel proc_t *p = ttoproc(tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* handle kernel threads separately */
29949e866e40b95795203f3ee46f44a197c946e4stevel if (p->p_as == &kas || p->p_stat == SZOMB)
29949e866e40b95795203f3ee46f44a197c946e4stevel continue;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * If this thread didn't stop, and we don't allow
29949e866e40b95795203f3ee46f44a197c946e4stevel * unstopped blocked threads, bail.
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel /* did this thread stop? */
29949e866e40b95795203f3ee46f44a197c946e4stevel thread_lock(tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel if (!CPR_ISTOPPED(tp) &&
29949e866e40b95795203f3ee46f44a197c946e4stevel !(sysctrl_allow_blocked_threads &&
29949e866e40b95795203f3ee46f44a197c946e4stevel SYSCTRL_VSTOPPED(tp))) {
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* nope, cache the details for later */
29949e866e40b95795203f3ee46f44a197c946e4stevel bcopy(p->p_user.u_psargs, cache_psargs,
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson sizeof (cache_psargs));
29949e866e40b95795203f3ee46f44a197c946e4stevel cache_tp = tp;
29949e866e40b95795203f3ee46f44a197c946e4stevel cache_t_state = tp->t_state;
29949e866e40b95795203f3ee46f44a197c946e4stevel bailout = 1;
29949e866e40b95795203f3ee46f44a197c946e4stevel pid = p->p_pidp->pid_id;
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel thread_unlock(tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_exit(&pidlock);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* were all the threads stopped? */
29949e866e40b95795203f3ee46f44a197c946e4stevel if (!bailout)
29949e866e40b95795203f3ee46f44a197c946e4stevel break;
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* were we unable to stop all threads after a few tries? */
29949e866e40b95795203f3ee46f44a197c946e4stevel if (bailout) {
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) sprintf(pkt->errbuf, "process: %s id: %d state: %x"
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson " thread descriptor: %p", cache_psargs, (int)pid,
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson cache_t_state, (void *)cache_tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel SYSC_ERR_SET(pkt, SYSC_ERR_UTHREAD);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel return (ESRCH);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel return (DDI_SUCCESS);
29949e866e40b95795203f3ee46f44a197c946e4stevel}
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic int
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_stop_kernel_threads(sysc_cfga_pkt_t *pkt)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel caddr_t name;
29949e866e40b95795203f3ee46f44a197c946e4stevel kthread_id_t tp;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel if (sysctrl_skip_kernel_threads) {
29949e866e40b95795203f3ee46f44a197c946e4stevel return (DDI_SUCCESS);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
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 */
29949e866e40b95795203f3ee46f44a197c946e4stevel callb_lock_table();
29949e866e40b95795203f3ee46f44a197c946e4stevel if ((name = callb_execute_class(CB_CL_CPR_DAEMON,
29949e866e40b95795203f3ee46f44a197c946e4stevel CB_CODE_CPR_CHKPT)) != (caddr_t)NULL) {
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) strncpy(pkt->errbuf, name, SYSC_OUTPUT_LEN);
29949e866e40b95795203f3ee46f44a197c946e4stevel SYSC_ERR_SET(pkt, SYSC_ERR_KTHREAD);
29949e866e40b95795203f3ee46f44a197c946e4stevel return (EBUSY);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * Verify that all threads are accounted for
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_enter(&pidlock);
29949e866e40b95795203f3ee46f44a197c946e4stevel for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) {
29949e866e40b95795203f3ee46f44a197c946e4stevel proc_t *p = ttoproc(tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel if (p->p_as != &kas)
29949e866e40b95795203f3ee46f44a197c946e4stevel continue;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel if (tp->t_flag & T_INTR_THREAD)
29949e866e40b95795203f3ee46f44a197c946e4stevel continue;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel if (!callb_is_stopped(tp, &name)) {
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_exit(&pidlock);
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) strncpy(pkt->errbuf, name, SYSC_OUTPUT_LEN);
29949e866e40b95795203f3ee46f44a197c946e4stevel SYSC_ERR_SET(pkt, SYSC_ERR_KTHREAD);
29949e866e40b95795203f3ee46f44a197c946e4stevel return (EBUSY);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_exit(&pidlock);
29949e866e40b95795203f3ee46f44a197c946e4stevel return (DDI_SUCCESS);
29949e866e40b95795203f3ee46f44a197c946e4stevel}
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic void
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_start_user_threads(void)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel kthread_id_t tp;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_enter(&pidlock);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* walk all threads and release them */
29949e866e40b95795203f3ee46f44a197c946e4stevel for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) {
29949e866e40b95795203f3ee46f44a197c946e4stevel proc_t *p = ttoproc(tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* skip kernel threads */
29949e866e40b95795203f3ee46f44a197c946e4stevel if (ttoproc(tp)->p_as == &kas)
29949e866e40b95795203f3ee46f44a197c946e4stevel continue;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_enter(&p->p_lock);
29949e866e40b95795203f3ee46f44a197c946e4stevel tp->t_proc_flag &= ~TP_CHKPT;
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_exit(&p->p_lock);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel thread_lock(tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel if (CPR_ISTOPPED(tp)) {
29949e866e40b95795203f3ee46f44a197c946e4stevel /* back on the runq */
29949e866e40b95795203f3ee46f44a197c946e4stevel tp->t_schedflag |= TS_RESUME;
29949e866e40b95795203f3ee46f44a197c946e4stevel setrun_locked(tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel thread_unlock(tp);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_exit(&pidlock);
29949e866e40b95795203f3ee46f44a197c946e4stevel}
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic void
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_signal_user(int sig)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel struct proc *p;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_enter(&pidlock);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel for (p = practive; p != NULL; p = p->p_next) {
29949e866e40b95795203f3ee46f44a197c946e4stevel /* only user threads */
29949e866e40b95795203f3ee46f44a197c946e4stevel if (p->p_exec == NULL || p->p_stat == SZOMB ||
29949e866e40b95795203f3ee46f44a197c946e4stevel p == proc_init || p == ttoproc(curthread))
29949e866e40b95795203f3ee46f44a197c946e4stevel continue;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_enter(&p->p_lock);
29949e866e40b95795203f3ee46f44a197c946e4stevel sigtoproc(p, NULL, sig);
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_exit(&p->p_lock);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_exit(&pidlock);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* add a bit of delay */
29949e866e40b95795203f3ee46f44a197c946e4stevel delay(hz);
29949e866e40b95795203f3ee46f44a197c946e4stevel}
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelvoid
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_resume(sysc_cfga_pkt_t *pkt)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel#ifndef Bug_4154263
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("resume system...\n"));
29949e866e40b95795203f3ee46f44a197c946e4stevel#endif
29949e866e40b95795203f3ee46f44a197c946e4stevel switch (suspend_state) {
29949e866e40b95795203f3ee46f44a197c946e4stevel case SYSC_STATE_FULL:
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * release all the other cpus
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel#ifndef Bug_4154263
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("release cpus..."));
29949e866e40b95795203f3ee46f44a197c946e4stevel#endif
646e55b6807cdf761fecd1e4095d73116cdefdb5cth /*
646e55b6807cdf761fecd1e4095d73116cdefdb5cth * Prevent false alarm in tod_validate() due to tod
646e55b6807cdf761fecd1e4095d73116cdefdb5cth * value change between suspend and resume
646e55b6807cdf761fecd1e4095d73116cdefdb5cth */
646e55b6807cdf761fecd1e4095d73116cdefdb5cth mutex_enter(&tod_lock);
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson tod_status_set(TOD_DR_RESUME_DONE);
646e55b6807cdf761fecd1e4095d73116cdefdb5cth mutex_exit(&tod_lock);
646e55b6807cdf761fecd1e4095d73116cdefdb5cth
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_release_cpus();
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("cpus resumed...\n"));
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * If we suspended hw watchdog at suspend,
29949e866e40b95795203f3ee46f44a197c946e4stevel * re-enable it now.
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel if (sysc_watchdog_suspended) {
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_enter(&tod_lock);
29949e866e40b95795203f3ee46f44a197c946e4stevel tod_ops.tod_set_watchdog_timer(
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson watchdog_timeout_seconds);
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_exit(&tod_lock);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * resume callout
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) callb_execute_class(CB_CL_CPR_RPC, CB_CODE_CPR_RESUME);
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) callb_execute_class(CB_CL_CPR_CALLOUT,
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson CB_CODE_CPR_RESUME);
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_enable_intr();
29949e866e40b95795203f3ee46f44a197c946e4stevel /* FALLTHROUGH */
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel case SYSC_STATE_DRIVER:
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * resume drivers
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("resume drivers..."));
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_resume_devices(ddi_root_node(), pkt);
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("done\n"));
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * resume the lock manager
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel lm_cprresume();
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* FALLTHROUGH */
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel case SYSC_STATE_DAEMON:
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * resume kernel daemons
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel if (!sysctrl_skip_kernel_threads) {
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("starting kernel daemons..."));
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) callb_execute_class(CB_CL_CPR_DAEMON,
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson CB_CODE_CPR_RESUME);
29949e866e40b95795203f3ee46f44a197c946e4stevel callb_unlock_table();
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("done\n"));
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* FALLTHROUGH */
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel case SYSC_STATE_USER:
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * finally, resume user threads
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel if (!sysctrl_skip_user_threads) {
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("starting user threads..."));
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_start_user_threads();
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("done\n"));
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel /* FALLTHROUGH */
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel case SYSC_STATE_BEGIN:
29949e866e40b95795203f3ee46f44a197c946e4stevel default:
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * let those who care know that we've just resumed
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("sending SIGTHAW..."));
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_signal_user(SIGTHAW);
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("done\n"));
29949e866e40b95795203f3ee46f44a197c946e4stevel break;
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* Restore sysctrl detach/suspend to its original value */
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_enable_detach_suspend = sysc_lastval;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("system state restored\n"));
29949e866e40b95795203f3ee46f44a197c946e4stevel}
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelvoid
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_suspend_prepare(void)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
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 */
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) modload("misc", "klmmod");
29949e866e40b95795203f3ee46f44a197c946e4stevel}
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelint
29949e866e40b95795203f3ee46f44a197c946e4stevelsysctrl_suspend(sysc_cfga_pkt_t *pkt)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel int rc = DDI_SUCCESS;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* enable sysctrl detach/suspend function */
29949e866e40b95795203f3ee46f44a197c946e4stevel sysc_lastval = sysctrl_enable_detach_suspend;
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_enable_detach_suspend = 1;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * first, stop all user threads
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("\nstopping user threads..."));
29949e866e40b95795203f3ee46f44a197c946e4stevel suspend_state = SYSC_STATE_USER;
29949e866e40b95795203f3ee46f44a197c946e4stevel if (((rc = sysctrl_stop_user_threads(pkt)) != DDI_SUCCESS) &&
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_check_user_stop_result) {
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_resume(pkt);
29949e866e40b95795203f3ee46f44a197c946e4stevel return (rc);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("done\n"));
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * now stop daemon activities
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("stopping kernel daemons..."));
29949e866e40b95795203f3ee46f44a197c946e4stevel suspend_state = SYSC_STATE_DAEMON;
29949e866e40b95795203f3ee46f44a197c946e4stevel if (rc = sysctrl_stop_kernel_threads(pkt)) {
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_resume(pkt);
29949e866e40b95795203f3ee46f44a197c946e4stevel return (rc);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("done\n"));
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * This sync swap out all user pages
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel vfs_sync(SYNC_ALL);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * special treatment for lock manager
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel lm_cprsuspend();
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * sync the file system in case we never make it back
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel sync();
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * now suspend drivers
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("suspending drivers..."));
29949e866e40b95795203f3ee46f44a197c946e4stevel suspend_state = SYSC_STATE_DRIVER;
29949e866e40b95795203f3ee46f44a197c946e4stevel if (rc = sysctrl_suspend_devices(ddi_root_node(), pkt)) {
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_resume(pkt);
29949e866e40b95795203f3ee46f44a197c946e4stevel return (rc);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("done\n"));
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * handle the callout table
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_stop_intr();
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) callb_execute_class(CB_CL_CPR_CALLOUT, CB_CODE_CPR_CHKPT);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * if watchdog was activated, disable it
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel if (watchdog_activated) {
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_enter(&tod_lock);
29949e866e40b95795203f3ee46f44a197c946e4stevel tod_ops.tod_clear_watchdog_timer();
29949e866e40b95795203f3ee46f44a197c946e4stevel mutex_exit(&tod_lock);
29949e866e40b95795203f3ee46f44a197c946e4stevel sysc_watchdog_suspended = 1;
29949e866e40b95795203f3ee46f44a197c946e4stevel } else {
29949e866e40b95795203f3ee46f44a197c946e4stevel sysc_watchdog_suspended = 0;
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * finally, grab all cpus
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("freezing all cpus...\n"));
29949e866e40b95795203f3ee46f44a197c946e4stevel suspend_state = SYSC_STATE_FULL;
29949e866e40b95795203f3ee46f44a197c946e4stevel sysctrl_grab_cpus();
29949e866e40b95795203f3ee46f44a197c946e4stevel#ifndef Bug_4154263
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("done\n"));
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel DEBUGP(errp("system is quiesced\n"));
29949e866e40b95795203f3ee46f44a197c946e4stevel#endif
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel return (rc);
29949e866e40b95795203f3ee46f44a197c946e4stevel}