summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorwentaoy <none@none>2007-01-02 16:27:54 -0800
committerwentaoy <none@none>2007-01-02 16:27:54 -0800
commit927a453e165c072d45bd6aa2945b3db0fce17c56 (patch)
tree8afe7d0b14c219c125cc46c8fad331a957b33de6 /usr/src
parentf345c0beb4c8f75cb54c2e070498e56febd468ac (diff)
downloadillumos-gate-927a453e165c072d45bd6aa2945b3db0fce17c56.tar.gz
6461636 Watchdog timer should not display messages when disabled
6500505 sun4v backward compatibility ntwdt driver for Niagara based system
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/pkgdefs/SUNWcakr.v/prototype_com4
-rw-r--r--usr/src/pkgdefs/SUNWhea/prototype_sparc3
-rw-r--r--usr/src/uts/sparc/sys/wdt.h5
-rw-r--r--usr/src/uts/sun4v/Makefile.files3
-rw-r--r--usr/src/uts/sun4v/Makefile.sun4v.shared3
-rw-r--r--usr/src/uts/sun4v/io/ntwdt.c809
-rw-r--r--usr/src/uts/sun4v/io/ntwdt.conf32
-rw-r--r--usr/src/uts/sun4v/ntwdt/Makefile94
-rw-r--r--usr/src/uts/sun4v/os/mach_cpu_states.c9
-rw-r--r--usr/src/uts/sun4v/os/wdt.c4
-rw-r--r--usr/src/uts/sun4v/sys/Makefile3
-rw-r--r--usr/src/uts/sun4v/sys/ntwdt.h60
12 files changed, 1018 insertions, 11 deletions
diff --git a/usr/src/pkgdefs/SUNWcakr.v/prototype_com b/usr/src/pkgdefs/SUNWcakr.v/prototype_com
index 1655ef2feb..b42caed3d2 100644
--- a/usr/src/pkgdefs/SUNWcakr.v/prototype_com
+++ b/usr/src/pkgdefs/SUNWcakr.v/prototype_com
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -70,10 +70,12 @@ f none platform/sun4v/kernel/drv/sparcv9/su 755 root sys
f none platform/sun4v/kernel/drv/sparcv9/trapstat 755 root sys
f none platform/sun4v/kernel/drv/sparcv9/vnex 755 root sys
f none platform/sun4v/kernel/drv/sparcv9/glvc 755 root sys
+f none platform/sun4v/kernel/drv/sparcv9/ntwdt 755 root sys
f none platform/sun4v/kernel/drv/sparcv9/ncp 755 root sys
f none platform/sun4v/kernel/drv/sparcv9/n2rng 755 root sys
f none platform/sun4v/kernel/drv/sparcv9/mdesc 755 root sys
f none platform/sun4v/kernel/drv/mdesc.conf 644 root sys
+f none platform/sun4v/kernel/drv/ntwdt.conf 644 root sys
d none platform/sun4v/kernel/misc 755 root sys
d none platform/sun4v/kernel/misc/sparcv9 755 root sys
l none platform/sun4v/kernel/misc/sparcv9/md5=../../../kernel/crypto/sparcv9/md5
diff --git a/usr/src/pkgdefs/SUNWhea/prototype_sparc b/usr/src/pkgdefs/SUNWhea/prototype_sparc
index 5e34804584..06c0af845f 100644
--- a/usr/src/pkgdefs/SUNWhea/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWhea/prototype_sparc
@@ -20,7 +20,7 @@
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -299,6 +299,7 @@ f none usr/platform/sun4v/include/sys/memnode.h 644 root bin
f none usr/platform/sun4v/include/sys/nexusdebug.h 644 root bin
f none usr/platform/sun4v/include/sys/niagaraasi.h 644 root bin
f none usr/platform/sun4v/include/sys/niagararegs.h 644 root bin
+f none usr/platform/sun4v/include/sys/ntwdt.h 644 root bin
f none usr/platform/sun4v/include/sys/prom_debug.h 644 root bin
f none usr/platform/sun4v/include/sys/prom_plat.h 644 root bin
f none usr/platform/sun4v/include/sys/pte.h 644 root bin
diff --git a/usr/src/uts/sparc/sys/wdt.h b/usr/src/uts/sparc/sys/wdt.h
index 009916169d..a7e2932651 100644
--- a/usr/src/uts/sparc/sys/wdt.h
+++ b/usr/src/uts/sparc/sys/wdt.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -39,6 +39,9 @@ extern void watchdog_resume(void);
extern void watchdog_clear(void);
extern void restore_watchdog_on_entry(void);
+extern int watchdog_enabled;
+extern int watchdog_activated;
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/sun4v/Makefile.files b/usr/src/uts/sun4v/Makefile.files
index de459794db..6c5813118d 100644
--- a/usr/src/uts/sun4v/Makefile.files
+++ b/usr/src/uts/sun4v/Makefile.files
@@ -20,7 +20,7 @@
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -139,6 +139,7 @@ CNEX_OBJS = cnex.o
GLVC_OBJS = glvc.o glvc_hcall.o
MDESC_OBJS = mdesc.o
LDC_OBJS = ldc.o vio_util.o vdsk_common.o
+NTWDT_OBJS = ntwdt.o
VLDC_OBJS = vldc.o
VCC_OBJS = vcc.o
VNET_OBJS = vnet.o vnet_gen.o
diff --git a/usr/src/uts/sun4v/Makefile.sun4v.shared b/usr/src/uts/sun4v/Makefile.sun4v.shared
index a0e308041c..921d3ad0f5 100644
--- a/usr/src/uts/sun4v/Makefile.sun4v.shared
+++ b/usr/src/uts/sun4v/Makefile.sun4v.shared
@@ -20,7 +20,7 @@
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -326,6 +326,7 @@ DRV_KMODS += fpc
DRV_KMODS += glvc
DRV_KMODS += mdesc
DRV_KMODS += niumx
+DRV_KMODS += ntwdt
DRV_KMODS += nxge
DRV_KMODS += n2piupc
DRV_KMODS += px
diff --git a/usr/src/uts/sun4v/io/ntwdt.c b/usr/src/uts/sun4v/io/ntwdt.c
new file mode 100644
index 0000000000..fb0b8e7259
--- /dev/null
+++ b/usr/src/uts/sun4v/io/ntwdt.c
@@ -0,0 +1,809 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * sun4v application watchdog driver
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+#include <sys/open.h>
+#include <sys/callb.h>
+#include <sys/cred.h>
+#include <sys/cyclic.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/ksynch.h>
+#include <sys/modctl.h>
+#include <sys/conf.h>
+#include <sys/devops.h>
+#include <sys/debug.h>
+#include <sys/cmn_err.h>
+#include <sys/ddi.h>
+#include <sys/reboot.h>
+#include <sys/sunddi.h>
+#include <sys/signal.h>
+#include <sys/ntwdt.h>
+#include <sys/note.h>
+
+/*
+ * tunables
+ */
+int ntwdt_disable_timeout_action = 0;
+
+#ifdef DEBUG
+
+int ntwdt_debug = 0; /* ntwdt debug flag, dbg all for now. */
+
+/*
+ * Flags to set in ntwdt_debug.
+ */
+#define NTWDT_DBG_ENTRY 0x00000001 /* drv entry points */
+#define NTWDT_DBG_IOCTL 0x00000002 /* ioctl's */
+#define NTWDT_DBG_NTWDT 0x00000004 /* other ntwdt debug */
+
+#define NTWDT_DBG(flag, msg) \
+ { if ((ntwdt_debug) & (flag)) (void) printf msg; }
+#else /* DEBUG */
+#define NTWDT_DBG(flag, msg)
+#endif /* DEBUG */
+
+#define NTWDT_MINOR_NODE "awdt"
+#define getstate(minor) \
+ ((ntwdt_state_t *)ddi_get_soft_state(ntwdt_statep, (minor)))
+
+/*
+ * The ntwdt cyclic interval in nanosecond unit as cyclic subsystem supports
+ * nanosecond resolution.
+ */
+#define NTWDT_CYCLIC_INTERVAL NANOSEC /* 1 seconds */
+
+/*
+ * The ntwdt decrement interval in 1 second resolution.
+ */
+#define NTWDT_DECREMENT_INTERVAL 1 /* 1 second */
+
+/*
+ * ntwdt_watchdog_flags and macros to set/clear one bit in it.
+ */
+#define NTWDT_FLAG_SKIP_CYCLIC 0x1 /* skip next cyclic */
+
+#define NTWDT_MAX_TIMEOUT (3 * 60 * 60) /* 3 hours */
+
+#define WDT_MIN_COREAPI_MAJOR 1
+#define WDT_MIN_COREAPI_MINOR 1
+
+/*
+ * Application watchdog state.
+ */
+typedef struct ntwdt_runstate {
+ kmutex_t ntwdt_runstate_mutex;
+ ddi_iblock_cookie_t ntwdt_runstate_mtx_cookie;
+ int ntwdt_watchdog_enabled; /* wdog enabled ? */
+ int ntwdt_reset_enabled; /* reset enabled ? */
+ int ntwdt_timer_running; /* wdog running ? */
+ int ntwdt_watchdog_expired; /* wdog expired ? */
+ uint32_t ntwdt_time_remaining; /* expiration timer */
+ uint32_t ntwdt_watchdog_timeout; /* timeout in seconds */
+ hrtime_t ntwdt_cyclic_interval; /* cyclic interval */
+ cyc_handler_t ntwdt_cycl_hdlr;
+ cyc_time_t ntwdt_cycl_time;
+ uint32_t ntwdt_watchdog_flags;
+} ntwdt_runstate_t;
+
+/*
+ * softstate of NTWDT
+ */
+typedef struct {
+ kmutex_t ntwdt_mutex;
+ dev_info_t *ntwdt_dip; /* dip */
+ int ntwdt_open_flag; /* file open ? */
+ ntwdt_runstate_t *ntwdt_run_state; /* wdog state */
+ cyclic_id_t ntwdt_cycl_id;
+} ntwdt_state_t;
+
+static void *ntwdt_statep; /* softstate */
+static dev_info_t *ntwdt_dip;
+
+static ddi_softintr_t ntwdt_cyclic_softint_id;
+
+static int ntwdt_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int ntwdt_attach(dev_info_t *, ddi_attach_cmd_t);
+static int ntwdt_detach(dev_info_t *, ddi_detach_cmd_t);
+static int ntwdt_open(dev_t *, int, int, cred_t *);
+static int ntwdt_close(dev_t, int, int, cred_t *);
+static int ntwdt_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+
+static int ntwdt_chk_watchdog_support();
+static void ntwdt_arm_watchdog(ntwdt_runstate_t *ntwdt_state);
+static void ntwdt_cyclic_pat(void);
+static uint_t ntwdt_cyclic_softint(caddr_t arg);
+static void ntwdt_start_timer(ntwdt_state_t *ntwdt_ptr);
+static void ntwdt_stop_timer_lock(void *arg);
+static void ntwdt_stop_timer(void *arg);
+static void ntwdt_enforce_timeout();
+
+static struct cb_ops ntwdt_cb_ops = {
+ ntwdt_open, /* cb_open */
+ ntwdt_close, /* cb_close */
+ nodev, /* cb_strategy */
+ nodev, /* cb_print */
+ nodev, /* cb_dump */
+ nodev, /* cb_read */
+ nodev, /* cb_write */
+ ntwdt_ioctl, /* cb_ioctl */
+ nodev, /* cb_devmap */
+ nodev, /* cb_mmap */
+ nodev, /* cb_segmap */
+ nochpoll, /* cb_chpoll */
+ ddi_prop_op, /* cb_prop_op */
+ NULL, /* cb_str */
+ D_NEW | D_MP /* cb_flag */
+};
+
+static struct dev_ops ntwdt_dev_ops = {
+ DEVO_REV, /* devo_rev */
+ 0, /* devo_refcnt */
+ ntwdt_info, /* devo_info */
+ nulldev, /* devo_identify */
+ nulldev, /* devo_probe */
+ ntwdt_attach, /* devo_attach */
+ ntwdt_detach, /* devo_detach */
+ nodev, /* devo_reset */
+ &ntwdt_cb_ops, /* devo_cb_ops */
+ NULL, /* devo_bus_ops */
+ nulldev /* devo_power */
+};
+
+static struct modldrv modldrv = {
+ &mod_driverops,
+ "Application Watchdog Driver 1.1",
+ &ntwdt_dev_ops
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ (void *)&modldrv,
+ NULL
+};
+
+int
+_init(void)
+{
+ int error = 0;
+
+ NTWDT_DBG(NTWDT_DBG_ENTRY, ("_init"));
+
+ /* Initialize the soft state structures */
+ if ((error = ddi_soft_state_init(&ntwdt_statep,
+ sizeof (ntwdt_state_t), 1)) != 0) {
+ return (error);
+ }
+
+ /* Install the loadable module */
+ if ((error = mod_install(&modlinkage)) != 0) {
+ ddi_soft_state_fini(&ntwdt_statep);
+ }
+ return (error);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ NTWDT_DBG(NTWDT_DBG_ENTRY, ("_info"));
+
+ return (mod_info(&modlinkage, modinfop));
+}
+
+int
+_fini(void)
+{
+ int retval;
+
+ NTWDT_DBG(NTWDT_DBG_ENTRY, ("_fini"));
+
+ if ((retval = mod_remove(&modlinkage)) == 0) {
+ ddi_soft_state_fini(&ntwdt_statep);
+ }
+
+ return (retval);
+}
+
+static int
+ntwdt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ int instance;
+ ntwdt_state_t *ntwdt_ptr = NULL; /* pointer to ntwdt_runstatep */
+ ntwdt_runstate_t *ntwdt_runstatep = NULL;
+ cyc_handler_t *hdlr = NULL;
+
+ switch (cmd) {
+ case DDI_ATTACH:
+ break;
+
+ case DDI_RESUME:
+ return (DDI_SUCCESS);
+
+ default:
+ return (DDI_FAILURE);
+ }
+
+ if (ntwdt_chk_watchdog_support() != 0) {
+ return (DDI_FAILURE);
+ }
+
+ instance = ddi_get_instance(dip);
+ ASSERT(instance == 0);
+
+ if (ddi_soft_state_zalloc(ntwdt_statep, instance) != DDI_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+ ntwdt_ptr = ddi_get_soft_state(ntwdt_statep, instance);
+ ASSERT(ntwdt_ptr != NULL);
+
+ ntwdt_dip = dip;
+
+ ntwdt_ptr->ntwdt_dip = dip;
+ ntwdt_ptr->ntwdt_cycl_id = CYCLIC_NONE;
+ mutex_init(&ntwdt_ptr->ntwdt_mutex, NULL,
+ MUTEX_DRIVER, NULL);
+
+ /*
+ * Initialize the watchdog structure
+ */
+ ntwdt_ptr->ntwdt_run_state =
+ kmem_zalloc(sizeof (ntwdt_runstate_t), KM_SLEEP);
+ ntwdt_runstatep = ntwdt_ptr->ntwdt_run_state;
+
+ if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW,
+ &ntwdt_runstatep->ntwdt_runstate_mtx_cookie) != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "init of iblock cookie failed "
+ "for ntwdt_runstate_mutex");
+ goto err1;
+ } else {
+ mutex_init(&ntwdt_runstatep->ntwdt_runstate_mutex,
+ NULL,
+ MUTEX_DRIVER,
+ (void *)ntwdt_runstatep->ntwdt_runstate_mtx_cookie);
+ }
+
+ /* Cyclic fires once per second: */
+ ntwdt_runstatep->ntwdt_cyclic_interval = NTWDT_CYCLIC_INTERVAL;
+
+ /* init the Cyclic that drives the NTWDT */
+ hdlr = &ntwdt_runstatep->ntwdt_cycl_hdlr;
+ hdlr->cyh_level = CY_LOCK_LEVEL;
+ hdlr->cyh_func = (cyc_func_t)ntwdt_cyclic_pat;
+ hdlr->cyh_arg = NULL;
+
+ /* Softint that will be triggered by Cyclic that drives NTWDT */
+ if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &ntwdt_cyclic_softint_id,
+ NULL, NULL, ntwdt_cyclic_softint, (caddr_t)ntwdt_ptr)
+ != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "failed to add cyclic softintr");
+ goto err2;
+ }
+
+ /*
+ * Create Minor Node as last activity. This prevents
+ * application from accessing our implementation until it
+ * is initialized.
+ */
+ if (ddi_create_minor_node(dip, NTWDT_MINOR_NODE, S_IFCHR, 0,
+ DDI_PSEUDO, NULL) == DDI_FAILURE) {
+ cmn_err(CE_WARN, "failed to create Minor Node: %s",
+ NTWDT_MINOR_NODE);
+ goto err3;
+ }
+
+ /* Display our driver info in the banner */
+ ddi_report_dev(dip);
+
+ return (DDI_SUCCESS);
+
+err3:
+ ddi_remove_softintr(ntwdt_cyclic_softint_id);
+err2:
+ mutex_destroy(&ntwdt_runstatep->ntwdt_runstate_mutex);
+err1:
+ /* clean up the driver stuff here */
+ kmem_free(ntwdt_runstatep, sizeof (ntwdt_runstate_t));
+ ntwdt_ptr->ntwdt_run_state = NULL;
+ mutex_destroy(&ntwdt_ptr->ntwdt_mutex);
+ ddi_soft_state_free(ntwdt_statep, instance);
+ ntwdt_dip = NULL;
+
+ return (DDI_FAILURE);
+}
+
+/*ARGSUSED*/
+static int
+ntwdt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
+{
+ dev_t dev;
+ int instance;
+ int error = DDI_SUCCESS;
+
+ switch (infocmd) {
+ case DDI_INFO_DEVT2DEVINFO:
+ dev = (dev_t)arg;
+ if (getminor(dev) == 0) {
+ *result = (void *)ntwdt_dip;
+ } else {
+ error = DDI_FAILURE;
+ }
+ break;
+
+ case DDI_INFO_DEVT2INSTANCE:
+ dev = (dev_t)arg;
+ instance = getminor(dev);
+ *result = (void *)(uintptr_t)instance;
+ break;
+
+ default:
+ error = DDI_FAILURE;
+
+ }
+
+ return (error);
+}
+
+/*ARGSUSED*/
+static int
+ntwdt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ int instance = ddi_get_instance(dip);
+ ntwdt_state_t *ntwdt_ptr = NULL;
+
+ ntwdt_ptr = ddi_get_soft_state(ntwdt_statep, instance);
+ if (ntwdt_ptr == NULL) {
+ return (DDI_FAILURE);
+ }
+
+ switch (cmd) {
+ case DDI_SUSPEND:
+ return (DDI_SUCCESS);
+
+ case DDI_DETACH:
+ /*
+ * release resources in opposite (LIFO) order as
+ * were allocated in attach.
+ */
+ ddi_remove_minor_node(dip, NULL);
+ ntwdt_stop_timer_lock((void *)ntwdt_ptr);
+ ddi_remove_softintr(ntwdt_cyclic_softint_id);
+
+ mutex_destroy(
+ &ntwdt_ptr->ntwdt_run_state->ntwdt_runstate_mutex);
+ kmem_free(ntwdt_ptr->ntwdt_run_state,
+ sizeof (ntwdt_runstate_t));
+ ntwdt_ptr->ntwdt_run_state = NULL;
+
+ mutex_destroy(&ntwdt_ptr->ntwdt_mutex);
+
+ ddi_soft_state_free(ntwdt_statep, instance);
+
+ ntwdt_dip = NULL;
+ return (DDI_SUCCESS);
+
+ default:
+ return (DDI_FAILURE);
+ }
+}
+
+/*ARGSUSED*/
+static int
+ntwdt_open(dev_t *devp, int flag, int otyp, cred_t *credp)
+{
+ int instance = getminor(*devp);
+ int retval = 0;
+ ntwdt_state_t *ntwdt_ptr = getstate(instance);
+
+ if (ntwdt_ptr == NULL) {
+ return (ENXIO);
+ }
+
+ /*
+ * ensure caller is a priviledged process.
+ */
+ if (drv_priv(credp) != 0) {
+ return (EPERM);
+ }
+
+ mutex_enter(&ntwdt_ptr->ntwdt_mutex);
+ if (ntwdt_ptr->ntwdt_open_flag) {
+ retval = EAGAIN;
+ } else {
+ ntwdt_ptr->ntwdt_open_flag = 1;
+ }
+ mutex_exit(&ntwdt_ptr->ntwdt_mutex);
+
+ return (retval);
+}
+
+/*ARGSUSED*/
+static int
+ntwdt_close(dev_t dev, int flag, int otyp, cred_t *credp)
+{
+ int instance = getminor(dev);
+ ntwdt_state_t *ntwdt_ptr = getstate(instance);
+
+ if (ntwdt_ptr == NULL) {
+ return (ENXIO);
+ }
+
+ mutex_enter(&ntwdt_ptr->ntwdt_mutex);
+ ntwdt_ptr->ntwdt_open_flag = 0;
+ mutex_exit(&ntwdt_ptr->ntwdt_mutex);
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+ntwdt_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
+ int *rvalp)
+{
+ int instance = getminor(dev);
+ int retval = 0;
+ ntwdt_state_t *ntwdt_ptr = NULL;
+ ntwdt_runstate_t *ntwdt_state;
+ lom_dogstate_t lom_dogstate;
+ lom_dogctl_t lom_dogctl;
+ uint32_t lom_dogtime;
+
+ if ((ntwdt_ptr = getstate(instance)) == NULL) {
+ return (ENXIO);
+ }
+
+ ntwdt_state = ntwdt_ptr->ntwdt_run_state;
+
+ switch (cmd) {
+ case LOMIOCDOGSTATE:
+ mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
+ lom_dogstate.reset_enable = ntwdt_state->ntwdt_reset_enabled;
+ lom_dogstate.dog_enable = ntwdt_state->ntwdt_watchdog_enabled;
+ lom_dogstate.dog_timeout = ntwdt_state->ntwdt_watchdog_timeout;
+ mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
+
+ if (ddi_copyout((caddr_t)&lom_dogstate, (caddr_t)arg,
+ sizeof (lom_dogstate_t), mode) != 0) {
+ retval = EFAULT;
+ }
+ break;
+
+ case LOMIOCDOGCTL:
+ if (ddi_copyin((caddr_t)arg, (caddr_t)&lom_dogctl,
+ sizeof (lom_dogctl_t), mode) != 0) {
+ retval = EFAULT;
+ break;
+ }
+
+ NTWDT_DBG(NTWDT_DBG_IOCTL, ("reset_enable: %d, and dog_enable: "
+ "%d, watchdog_timeout %d", lom_dogctl.reset_enable,
+ lom_dogctl.dog_enable,
+ ntwdt_state->ntwdt_watchdog_timeout));
+ /*
+ * ignore request to enable reset while disabling watchdog.
+ */
+ if (!lom_dogctl.dog_enable && lom_dogctl.reset_enable) {
+ NTWDT_DBG(NTWDT_DBG_IOCTL, ("invalid combination of "
+ "reset_enable: %d, and dog_enable: %d",
+ lom_dogctl.reset_enable,
+ lom_dogctl.dog_enable));
+ retval = EINVAL;
+ break;
+ }
+
+ mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
+
+ if (ntwdt_state->ntwdt_watchdog_timeout == 0) {
+ /*
+ * the LOMIOCDOGTIME has never been used to setup
+ * a valid timeout.
+ */
+ NTWDT_DBG(NTWDT_DBG_IOCTL, ("timeout has not been set"
+ "watchdog_timeout: %d",
+ ntwdt_state->ntwdt_watchdog_timeout));
+ retval = EINVAL;
+ goto end;
+ }
+
+ /*
+ * Store the user specified state in the softstate.
+ */
+ ntwdt_state->ntwdt_reset_enabled = lom_dogctl.reset_enable;
+ ntwdt_state->ntwdt_watchdog_enabled = lom_dogctl.dog_enable;
+
+ if (ntwdt_state->ntwdt_watchdog_enabled != 0) {
+ /*
+ * The user wants to enable the watchdog.
+ * Arm the watchdog and start the cyclic.
+ */
+ ntwdt_arm_watchdog(ntwdt_state);
+
+ if (ntwdt_state->ntwdt_timer_running == 0) {
+ ntwdt_start_timer(ntwdt_ptr);
+ }
+
+ NTWDT_DBG(NTWDT_DBG_IOCTL, ("AWDT is enabled"));
+ } else {
+ /*
+ * The user wants to disable the watchdog.
+ */
+ if (ntwdt_state->ntwdt_timer_running != 0) {
+ ntwdt_stop_timer(ntwdt_ptr);
+ }
+ NTWDT_DBG(NTWDT_DBG_IOCTL, ("AWDT is disabled"));
+ }
+
+ mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
+ break;
+
+ case LOMIOCDOGTIME:
+ if (ddi_copyin((caddr_t)arg, (caddr_t)&lom_dogtime,
+ sizeof (uint32_t), mode) != 0) {
+ retval = EFAULT;
+ break;
+ }
+
+ NTWDT_DBG(NTWDT_DBG_IOCTL, ("user set timeout: %d",
+ lom_dogtime));
+
+ /*
+ * Ensure specified timeout is valid.
+ */
+ if ((lom_dogtime == 0) ||
+ (lom_dogtime > (uint32_t)NTWDT_MAX_TIMEOUT)) {
+ retval = EINVAL;
+ NTWDT_DBG(NTWDT_DBG_IOCTL, ("user set invalid "
+ "timeout: %d", (int)TICK_TO_MSEC(lom_dogtime)));
+ break;
+ }
+
+ mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
+
+ ntwdt_state->ntwdt_watchdog_timeout = lom_dogtime;
+
+ /*
+ * If awdt is currently running, re-arm it with the
+ * newly-specified timeout value.
+ */
+ if (ntwdt_state->ntwdt_timer_running != 0) {
+ ntwdt_arm_watchdog(ntwdt_state);
+ }
+ mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
+ break;
+
+ case LOMIOCDOGPAT:
+ /*
+ * Allow user to pat the watchdog timer.
+ */
+ NTWDT_DBG(NTWDT_DBG_IOCTL, ("DOGPAT is invoked"));
+ mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
+
+ /*
+ * If awdt is not enabled or underlying cyclic is not
+ * running, exit.
+ */
+ if (!(ntwdt_state->ntwdt_watchdog_enabled &&
+ ntwdt_state->ntwdt_timer_running)) {
+ NTWDT_DBG(NTWDT_DBG_IOCTL, ("PAT: AWDT not enabled"));
+ goto end;
+ }
+
+ if (ntwdt_state->ntwdt_watchdog_expired == 0) {
+ /*
+ * re-arm the awdt.
+ */
+ ntwdt_arm_watchdog(ntwdt_state);
+ NTWDT_DBG(NTWDT_DBG_IOCTL, ("AWDT patted, "
+ "remainning seconds: %d",
+ ntwdt_state->ntwdt_time_remaining));
+ }
+
+ mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
+ break;
+
+ default:
+ retval = EINVAL;
+ break;
+ }
+ return (retval);
+end:
+ mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
+ return (retval);
+}
+
+static void
+ntwdt_cyclic_pat(void)
+{
+ ddi_trigger_softintr(ntwdt_cyclic_softint_id);
+}
+
+static uint_t
+ntwdt_cyclic_softint(caddr_t arg)
+{
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ntwdt_state_t *ntwdt_ptr = (ntwdt_state_t *)arg;
+ ntwdt_runstate_t *ntwdt_state;
+
+ ntwdt_state = ntwdt_ptr->ntwdt_run_state;
+
+ mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
+
+ if ((ntwdt_state->ntwdt_watchdog_flags & NTWDT_FLAG_SKIP_CYCLIC) != 0) {
+ ntwdt_state->ntwdt_watchdog_flags &= ~NTWDT_FLAG_SKIP_CYCLIC;
+ goto end;
+ }
+
+ if ((ntwdt_state->ntwdt_timer_running == 0) ||
+ (ntwdt_ptr->ntwdt_cycl_id == CYCLIC_NONE) ||
+ (ntwdt_state->ntwdt_watchdog_enabled == 0)) {
+ goto end;
+ }
+
+ NTWDT_DBG(NTWDT_DBG_IOCTL, ("cyclic_softint: %d"
+ "lbolt64: %d\n", ntwdt_state->ntwdt_watchdog_timeout,
+ (int)TICK_TO_MSEC(lbolt64)));
+
+ /*
+ * Decrement the virtual watchdog timer and check if it has expired.
+ */
+ ntwdt_state->ntwdt_time_remaining -= NTWDT_DECREMENT_INTERVAL;
+
+ if (ntwdt_state->ntwdt_time_remaining == 0) {
+ cmn_err(CE_WARN, "application-watchdog expired");
+ ntwdt_state->ntwdt_watchdog_expired = 1;
+
+ if (ntwdt_state->ntwdt_reset_enabled != 0) {
+ /*
+ * The user wants to reset the system.
+ */
+ mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
+
+ NTWDT_DBG(NTWDT_DBG_NTWDT, ("recovery being done"));
+ ntwdt_enforce_timeout();
+ } else {
+ NTWDT_DBG(NTWDT_DBG_NTWDT, ("no recovery being done"));
+ ntwdt_state->ntwdt_watchdog_enabled = 0;
+ }
+
+ /*
+ * Schedule Callout to stop the cyclic.
+ */
+ (void) timeout(ntwdt_stop_timer_lock, ntwdt_ptr, 0);
+ } else {
+ _NOTE(EMPTY)
+ NTWDT_DBG(NTWDT_DBG_NTWDT, ("time remaining in AWDT: %d secs",
+ (int)TICK_TO_MSEC(ntwdt_state->ntwdt_time_remaining)));
+ }
+
+end:
+ mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
+ return (DDI_INTR_CLAIMED);
+}
+
+static void
+ntwdt_arm_watchdog(ntwdt_runstate_t *ntwdt_state)
+{
+ ntwdt_state->ntwdt_time_remaining = ntwdt_state->ntwdt_watchdog_timeout;
+
+ if (ntwdt_state->ntwdt_timer_running != 0) {
+ ntwdt_state->ntwdt_watchdog_flags |= NTWDT_FLAG_SKIP_CYCLIC;
+ } else {
+ ntwdt_state->ntwdt_watchdog_flags &= ~NTWDT_FLAG_SKIP_CYCLIC;
+ }
+}
+
+static void
+ntwdt_start_timer(ntwdt_state_t *ntwdt_ptr)
+{
+ ntwdt_runstate_t *ntwdt_state = ntwdt_ptr->ntwdt_run_state;
+ cyc_handler_t *hdlr = &ntwdt_state->ntwdt_cycl_hdlr;
+ cyc_time_t *when = &ntwdt_state->ntwdt_cycl_time;
+
+ /*
+ * Init the cyclic.
+ */
+ when->cyt_interval = ntwdt_state->ntwdt_cyclic_interval;
+ when->cyt_when = gethrtime() + when->cyt_interval;
+
+ ntwdt_state->ntwdt_watchdog_expired = 0;
+ ntwdt_state->ntwdt_timer_running = 1;
+
+ mutex_enter(&cpu_lock);
+ if (ntwdt_ptr->ntwdt_cycl_id == CYCLIC_NONE) {
+ ntwdt_ptr->ntwdt_cycl_id = cyclic_add(hdlr, when);
+ }
+ mutex_exit(&cpu_lock);
+
+ NTWDT_DBG(NTWDT_DBG_NTWDT, ("cyclic-driven timer is started"));
+}
+
+static void
+ntwdt_stop_timer(void *arg)
+{
+ ntwdt_state_t *ntwdt_ptr = (ntwdt_state_t *)arg;
+ ntwdt_runstate_t *ntwdt_state = ntwdt_ptr->ntwdt_run_state;
+
+ mutex_enter(&cpu_lock);
+ if (ntwdt_ptr->ntwdt_cycl_id != CYCLIC_NONE) {
+ cyclic_remove(ntwdt_ptr->ntwdt_cycl_id);
+ }
+ mutex_exit(&cpu_lock);
+
+ ntwdt_state->ntwdt_watchdog_flags = 0;
+ ntwdt_state->ntwdt_timer_running = 0;
+ ntwdt_ptr->ntwdt_cycl_id = CYCLIC_NONE;
+
+ NTWDT_DBG(NTWDT_DBG_NTWDT, ("cyclic-driven timer is stopped"));
+}
+
+/*
+ * This is a wrapper function for ntwdt_stop_timer as some callers
+ * will already have the appropriate mutex locked, and others not.
+ */
+static void
+ntwdt_stop_timer_lock(void *arg)
+{
+ ntwdt_state_t *ntwdt_ptr = (ntwdt_state_t *)arg;
+
+ mutex_enter(&ntwdt_ptr->ntwdt_run_state->ntwdt_runstate_mutex);
+ ntwdt_stop_timer(arg);
+ mutex_exit(&ntwdt_ptr->ntwdt_run_state->ntwdt_runstate_mutex);
+}
+
+static void
+ntwdt_enforce_timeout()
+{
+ if (ntwdt_disable_timeout_action != 0) {
+ cmn_err(CE_NOTE, "Appication watchdog timer expired, "
+ "taking no action");
+ return;
+ }
+
+ NTWDT_DBG(NTWDT_DBG_NTWDT, ("dump cores and rebooting ..."));
+
+ (void) kadmin(A_DUMP, AD_BOOT, NULL, kcred);
+ cmn_err(CE_PANIC, "kadmin(A_DUMP, AD_BOOT) failed");
+ _NOTE(NOTREACHED);
+}
+
+static int
+ntwdt_chk_watchdog_support()
+{
+ int retval = 0;
+
+ if ((boothowto & RB_DEBUG) != 0) {
+ cmn_err(CE_WARN, "kernel debugger was booted; "
+ "application watchdog is not available.");
+ retval = ENOTSUP;
+ }
+ return (retval);
+}
diff --git a/usr/src/uts/sun4v/io/ntwdt.conf b/usr/src/uts/sun4v/io/ntwdt.conf
new file mode 100644
index 0000000000..3381f9d9f0
--- /dev/null
+++ b/usr/src/uts/sun4v/io/ntwdt.conf
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Configuration file for ntwdt driver
+#
+name="ntwdt" parent="pseudo" instance=0;
+# 600 seconds is the default timeout for a Solaris reboot
+ntwdt-boottimeout=600;
diff --git a/usr/src/uts/sun4v/ntwdt/Makefile b/usr/src/uts/sun4v/ntwdt/Makefile
new file mode 100644
index 0000000000..5aae3d419a
--- /dev/null
+++ b/usr/src/uts/sun4v/ntwdt/Makefile
@@ -0,0 +1,94 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# This makefile drives the production of the ntwdt driver module.
+#
+# sun4v implementation architecture dependent
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = ntwdt
+OBJECTS = $(NTWDT_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(NTWDT_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_PSM_DRV_DIR)/$(MODULE)
+CONF_SRCDIR = $(UTSBASE)/sun4v/io
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/sun4v/Makefile.sun4v
+
+#
+# Override defaults to build a unique, local modstubs.o.
+#
+MODSTUBS_DIR = $(OBJS_DIR)
+
+CLEANFILES += $(MODSTUBS_O)
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY) $(SRC_CONFILE)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+# lint pass one enforcement
+#
+CFLAGS += -v
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/$(PLATFORM)/Makefile.targ
diff --git a/usr/src/uts/sun4v/os/mach_cpu_states.c b/usr/src/uts/sun4v/os/mach_cpu_states.c
index ac943937aa..d7219b64e7 100644
--- a/usr/src/uts/sun4v/os/mach_cpu_states.c
+++ b/usr/src/uts/sun4v/os/mach_cpu_states.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -481,8 +481,11 @@ ptl1_panic_handler(ptl1_state_t *pstate)
void
clear_watchdog_on_exit(void)
{
- prom_printf("Debugging requested; hardware watchdog suspended.\n");
- (void) watchdog_suspend();
+ if (watchdog_enabled && watchdog_activated) {
+ prom_printf("Debugging requested; hardware watchdog "
+ "suspended.\n");
+ (void) watchdog_suspend();
+ }
}
/*
diff --git a/usr/src/uts/sun4v/os/wdt.c b/usr/src/uts/sun4v/os/wdt.c
index 829348039f..ef1c41e8b6 100644
--- a/usr/src/uts/sun4v/os/wdt.c
+++ b/usr/src/uts/sun4v/os/wdt.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -60,7 +60,7 @@ static void config_watchdog(uint64_t, int);
/*
* Flag used to pat/suspend/resume the watchdog timer.
*/
-static int watchdog_activated = WDT_OFF;
+int watchdog_activated = WDT_OFF;
static uint64_t watchdog_regular_timeout = WDT_REGULAR_TIMEOUT;
static uint64_t watchdog_long_timeout = 0;
static uint64_t watchdog_resolution = WDT_DEFAULT_RESOLUTION;
diff --git a/usr/src/uts/sun4v/sys/Makefile b/usr/src/uts/sun4v/sys/Makefile
index a897d3455f..470abd51f8 100644
--- a/usr/src/uts/sun4v/sys/Makefile
+++ b/usr/src/uts/sun4v/sys/Makefile
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -84,6 +84,7 @@ HDRS= \
mmu.h \
niagaraasi.h \
niagararegs.h \
+ ntwdt.h \
pte.h \
prom_plat.h \
qcn.h \
diff --git a/usr/src/uts/sun4v/sys/ntwdt.h b/usr/src/uts/sun4v/sys/ntwdt.h
new file mode 100644
index 0000000000..f7d90fba86
--- /dev/null
+++ b/usr/src/uts/sun4v/sys/ntwdt.h
@@ -0,0 +1,60 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_NTWDT_H
+#define _SYS_NTWDT_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/ioccom.h>
+
+/* ioctls for application watchdog */
+#define LOMIOCDOGSTATE _IOR('a', 6, lom_dogstate_t)
+#define LOMIOCDOGCTL _IOW('a', 7, lom_dogctl_t)
+#define LOMIOCDOGTIME _IOW('a', 8, uint_t)
+#define LOMIOCDOGPAT _IO('a', 9)
+
+typedef
+struct {
+ int reset_enable;
+ int dog_enable;
+} lom_dogctl_t;
+
+typedef
+struct {
+ int reset_enable;
+ int dog_enable;
+ uint_t dog_timeout;
+} lom_dogstate_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_NTWDT_H */