xref: /onnv-gate/usr/src/uts/sun4v/io/ntwdt.c (revision 11066:cebb50cbe4f9)
13349Swentaoy /*
23349Swentaoy  * CDDL HEADER START
33349Swentaoy  *
43349Swentaoy  * The contents of this file are subject to the terms of the
53349Swentaoy  * Common Development and Distribution License (the "License").
63349Swentaoy  * You may not use this file except in compliance with the License.
73349Swentaoy  *
83349Swentaoy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93349Swentaoy  * or http://www.opensolaris.org/os/licensing.
103349Swentaoy  * See the License for the specific language governing permissions
113349Swentaoy  * and limitations under the License.
123349Swentaoy  *
133349Swentaoy  * When distributing Covered Code, include this CDDL HEADER in each
143349Swentaoy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153349Swentaoy  * If applicable, add the following below this CDDL HEADER, with the
163349Swentaoy  * fields enclosed by brackets "[]" replaced with your own identifying
173349Swentaoy  * information: Portions Copyright [yyyy] [name of copyright owner]
183349Swentaoy  *
193349Swentaoy  * CDDL HEADER END
203349Swentaoy  */
213349Swentaoy /*
22*11066Srafael.vanoni@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
233349Swentaoy  * Use is subject to license terms.
243349Swentaoy  */
253349Swentaoy 
263349Swentaoy /*
273349Swentaoy  * sun4v application watchdog driver
283349Swentaoy  */
293349Swentaoy 
303349Swentaoy #include <sys/types.h>
313349Swentaoy #include <sys/file.h>
323349Swentaoy #include <sys/errno.h>
333349Swentaoy #include <sys/open.h>
343349Swentaoy #include <sys/callb.h>
353349Swentaoy #include <sys/cred.h>
363349Swentaoy #include <sys/cyclic.h>
373349Swentaoy #include <sys/uio.h>
383349Swentaoy #include <sys/stat.h>
393349Swentaoy #include <sys/ksynch.h>
403349Swentaoy #include <sys/modctl.h>
413349Swentaoy #include <sys/conf.h>
423349Swentaoy #include <sys/devops.h>
433349Swentaoy #include <sys/debug.h>
443349Swentaoy #include <sys/cmn_err.h>
453349Swentaoy #include <sys/ddi.h>
463349Swentaoy #include <sys/reboot.h>
473349Swentaoy #include <sys/sunddi.h>
483349Swentaoy #include <sys/signal.h>
493349Swentaoy #include <sys/ntwdt.h>
503349Swentaoy #include <sys/note.h>
513349Swentaoy 
523349Swentaoy /*
533349Swentaoy  * tunables
543349Swentaoy  */
553349Swentaoy int ntwdt_disable_timeout_action = 0;
563349Swentaoy 
573349Swentaoy #ifdef DEBUG
583349Swentaoy 
593349Swentaoy int ntwdt_debug = 0;		/* ntwdt debug flag, dbg all for now. */
603349Swentaoy 
613349Swentaoy /*
623349Swentaoy  * Flags to set in ntwdt_debug.
633349Swentaoy  */
643349Swentaoy #define	NTWDT_DBG_ENTRY	0x00000001	/* drv entry points */
653349Swentaoy #define	NTWDT_DBG_IOCTL	0x00000002	/* ioctl's */
663349Swentaoy #define	NTWDT_DBG_NTWDT	0x00000004	/* other ntwdt debug */
673349Swentaoy 
683349Swentaoy #define	NTWDT_DBG(flag, msg) \
693349Swentaoy 	{ if ((ntwdt_debug) & (flag)) (void) printf msg; }
703349Swentaoy #else	/* DEBUG */
713349Swentaoy #define	NTWDT_DBG(flag, msg)
723349Swentaoy #endif	/* DEBUG */
733349Swentaoy 
743349Swentaoy #define	NTWDT_MINOR_NODE	"awdt"
753349Swentaoy #define	getstate(minor)	\
763349Swentaoy 	((ntwdt_state_t *)ddi_get_soft_state(ntwdt_statep, (minor)))
773349Swentaoy 
783349Swentaoy /*
793349Swentaoy  * The ntwdt cyclic interval in nanosecond unit as cyclic subsystem supports
803349Swentaoy  * nanosecond resolution.
813349Swentaoy  */
823349Swentaoy #define	NTWDT_CYCLIC_INTERVAL	NANOSEC	/* 1 seconds */
833349Swentaoy 
843349Swentaoy /*
853349Swentaoy  * The ntwdt decrement interval in 1 second resolution.
863349Swentaoy  */
873349Swentaoy #define	NTWDT_DECREMENT_INTERVAL	1	/* 1 second */
883349Swentaoy 
893349Swentaoy /*
903349Swentaoy  * ntwdt_watchdog_flags and macros to set/clear one bit in it.
913349Swentaoy  */
923349Swentaoy #define	NTWDT_FLAG_SKIP_CYCLIC	0x1	/* skip next cyclic */
933349Swentaoy 
943349Swentaoy #define	NTWDT_MAX_TIMEOUT	(3 * 60 * 60)	/* 3 hours */
953349Swentaoy 
963349Swentaoy #define	WDT_MIN_COREAPI_MAJOR	1
973349Swentaoy #define	WDT_MIN_COREAPI_MINOR	1
983349Swentaoy 
993349Swentaoy /*
1003349Swentaoy  * Application watchdog state.
1013349Swentaoy  */
1023349Swentaoy typedef struct ntwdt_runstate {
1033349Swentaoy 	kmutex_t		ntwdt_runstate_mutex;
1043349Swentaoy 	ddi_iblock_cookie_t	ntwdt_runstate_mtx_cookie;
1053349Swentaoy 	int			ntwdt_watchdog_enabled;	/* wdog enabled ? */
1063349Swentaoy 	int			ntwdt_reset_enabled;	/* reset enabled ? */
1073349Swentaoy 	int			ntwdt_timer_running;	/* wdog running ? */
1083349Swentaoy 	int			ntwdt_watchdog_expired;	/* wdog expired ? */
1093349Swentaoy 	uint32_t		ntwdt_time_remaining;	/* expiration timer */
1103349Swentaoy 	uint32_t		ntwdt_watchdog_timeout;	/* timeout in seconds */
1113349Swentaoy 	hrtime_t		ntwdt_cyclic_interval;	/* cyclic interval */
1123349Swentaoy 	cyc_handler_t		ntwdt_cycl_hdlr;
1133349Swentaoy 	cyc_time_t		ntwdt_cycl_time;
1143349Swentaoy 	uint32_t		ntwdt_watchdog_flags;
1153349Swentaoy } ntwdt_runstate_t;
1163349Swentaoy 
1173349Swentaoy /*
1183349Swentaoy  * softstate of NTWDT
1193349Swentaoy  */
1203349Swentaoy typedef struct {
1213349Swentaoy 	kmutex_t		ntwdt_mutex;
1223349Swentaoy 	dev_info_t		*ntwdt_dip;		/* dip */
1233349Swentaoy 	int			ntwdt_open_flag;	/* file open ? */
1243349Swentaoy 	ntwdt_runstate_t	*ntwdt_run_state;	/* wdog state */
1253349Swentaoy 	cyclic_id_t		ntwdt_cycl_id;
1263349Swentaoy } ntwdt_state_t;
1273349Swentaoy 
1283349Swentaoy static void *ntwdt_statep;	/* softstate */
1293349Swentaoy static dev_info_t *ntwdt_dip;
1303349Swentaoy 
1313349Swentaoy static ddi_softintr_t	ntwdt_cyclic_softint_id;
1323349Swentaoy 
1333349Swentaoy static int ntwdt_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
1343349Swentaoy static int ntwdt_attach(dev_info_t *, ddi_attach_cmd_t);
1353349Swentaoy static int ntwdt_detach(dev_info_t *, ddi_detach_cmd_t);
1363349Swentaoy static int ntwdt_open(dev_t *, int, int, cred_t *);
1373349Swentaoy static int ntwdt_close(dev_t, int, int, cred_t *);
1383349Swentaoy static int ntwdt_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1393349Swentaoy 
1403349Swentaoy static int ntwdt_chk_watchdog_support();
1413349Swentaoy static void ntwdt_arm_watchdog(ntwdt_runstate_t *ntwdt_state);
1423349Swentaoy static void ntwdt_cyclic_pat(void);
1433349Swentaoy static uint_t ntwdt_cyclic_softint(caddr_t arg);
1443349Swentaoy static void ntwdt_start_timer(ntwdt_state_t *ntwdt_ptr);
1453349Swentaoy static void ntwdt_stop_timer_lock(void *arg);
1463349Swentaoy static void ntwdt_stop_timer(void *arg);
1473349Swentaoy static void ntwdt_enforce_timeout();
1483349Swentaoy 
1493349Swentaoy static struct cb_ops ntwdt_cb_ops = {
1503349Swentaoy 	ntwdt_open,		/* cb_open */
1513349Swentaoy 	ntwdt_close,		/* cb_close */
1523349Swentaoy 	nodev,			/* cb_strategy */
1533349Swentaoy 	nodev,			/* cb_print */
1543349Swentaoy 	nodev,			/* cb_dump */
1553349Swentaoy 	nodev,			/* cb_read */
1563349Swentaoy 	nodev,			/* cb_write */
1573349Swentaoy 	ntwdt_ioctl,		/* cb_ioctl */
1583349Swentaoy 	nodev,			/* cb_devmap */
1593349Swentaoy 	nodev,			/* cb_mmap */
1603349Swentaoy 	nodev,			/* cb_segmap */
1613349Swentaoy 	nochpoll,		/* cb_chpoll */
1623349Swentaoy 	ddi_prop_op,		/* cb_prop_op */
1633349Swentaoy 	NULL,			/* cb_str */
1643349Swentaoy 	D_NEW | D_MP		/* cb_flag */
1653349Swentaoy };
1663349Swentaoy 
1673349Swentaoy static struct dev_ops ntwdt_dev_ops = {
1683349Swentaoy 	DEVO_REV,		/* devo_rev */
1693349Swentaoy 	0,			/* devo_refcnt */
1703349Swentaoy 	ntwdt_info,		/* devo_info */
1713349Swentaoy 	nulldev,		/* devo_identify */
1723349Swentaoy 	nulldev,		/* devo_probe */
1733349Swentaoy 	ntwdt_attach,		/* devo_attach */
1743349Swentaoy 	ntwdt_detach,		/* devo_detach */
1753349Swentaoy 	nodev,			/* devo_reset */
1763349Swentaoy 	&ntwdt_cb_ops,		/* devo_cb_ops */
1773349Swentaoy 	NULL,			/* devo_bus_ops */
1787656SSherry.Moore@Sun.COM 	nulldev,		/* devo_power */
1797656SSherry.Moore@Sun.COM 	ddi_quiesce_not_supported,	/* devo_quiesce */
1803349Swentaoy };
1813349Swentaoy 
1823349Swentaoy static struct modldrv modldrv = {
1833349Swentaoy 	&mod_driverops,
1847656SSherry.Moore@Sun.COM 	"Application Watchdog Driver",
1853349Swentaoy 	&ntwdt_dev_ops
1863349Swentaoy };
1873349Swentaoy 
1883349Swentaoy static struct modlinkage modlinkage = {
1893349Swentaoy 	MODREV_1,
1903349Swentaoy 	(void *)&modldrv,
1913349Swentaoy 	NULL
1923349Swentaoy };
1933349Swentaoy 
1943349Swentaoy int
_init(void)1953349Swentaoy _init(void)
1963349Swentaoy {
1973349Swentaoy 	int error = 0;
1983349Swentaoy 
1993349Swentaoy 	NTWDT_DBG(NTWDT_DBG_ENTRY, ("_init"));
2003349Swentaoy 
2013349Swentaoy 	/* Initialize the soft state structures */
2023349Swentaoy 	if ((error = ddi_soft_state_init(&ntwdt_statep,
2033349Swentaoy 	    sizeof (ntwdt_state_t), 1)) != 0) {
2043349Swentaoy 		return (error);
2053349Swentaoy 	}
2063349Swentaoy 
2073349Swentaoy 	/* Install the loadable module */
2083349Swentaoy 	if ((error = mod_install(&modlinkage)) != 0) {
2093349Swentaoy 		ddi_soft_state_fini(&ntwdt_statep);
2103349Swentaoy 	}
2113349Swentaoy 	return (error);
2123349Swentaoy }
2133349Swentaoy 
2143349Swentaoy int
_info(struct modinfo * modinfop)2153349Swentaoy _info(struct modinfo *modinfop)
2163349Swentaoy {
2173349Swentaoy 	NTWDT_DBG(NTWDT_DBG_ENTRY, ("_info"));
2183349Swentaoy 
2193349Swentaoy 	return (mod_info(&modlinkage, modinfop));
2203349Swentaoy }
2213349Swentaoy 
2223349Swentaoy int
_fini(void)2233349Swentaoy _fini(void)
2243349Swentaoy {
2253349Swentaoy 	int retval;
2263349Swentaoy 
2273349Swentaoy 	NTWDT_DBG(NTWDT_DBG_ENTRY, ("_fini"));
2283349Swentaoy 
2293349Swentaoy 	if ((retval = mod_remove(&modlinkage)) == 0) {
2303349Swentaoy 		ddi_soft_state_fini(&ntwdt_statep);
2313349Swentaoy 	}
2323349Swentaoy 
2333349Swentaoy 	return (retval);
2343349Swentaoy }
2353349Swentaoy 
2363349Swentaoy static int
ntwdt_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2373349Swentaoy ntwdt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2383349Swentaoy {
2393349Swentaoy 	int instance;
2403349Swentaoy 	ntwdt_state_t *ntwdt_ptr = NULL;	/* pointer to ntwdt_runstatep */
2413349Swentaoy 	ntwdt_runstate_t *ntwdt_runstatep = NULL;
2423349Swentaoy 	cyc_handler_t *hdlr = NULL;
2433349Swentaoy 
2443349Swentaoy 	switch (cmd) {
2453349Swentaoy 	case DDI_ATTACH:
2463349Swentaoy 		break;
2473349Swentaoy 
2483349Swentaoy 	case DDI_RESUME:
2493349Swentaoy 		return (DDI_SUCCESS);
2503349Swentaoy 
2513349Swentaoy 	default:
2523349Swentaoy 		return (DDI_FAILURE);
2533349Swentaoy 	}
2543349Swentaoy 
2553349Swentaoy 	if (ntwdt_chk_watchdog_support() != 0) {
2563349Swentaoy 		return (DDI_FAILURE);
2573349Swentaoy 	}
2583349Swentaoy 
2593349Swentaoy 	instance = ddi_get_instance(dip);
2603349Swentaoy 	ASSERT(instance == 0);
2613349Swentaoy 
2623349Swentaoy 	if (ddi_soft_state_zalloc(ntwdt_statep, instance) != DDI_SUCCESS) {
2633349Swentaoy 		return (DDI_FAILURE);
2643349Swentaoy 	}
2653349Swentaoy 	ntwdt_ptr = ddi_get_soft_state(ntwdt_statep, instance);
2663349Swentaoy 	ASSERT(ntwdt_ptr != NULL);
2673349Swentaoy 
2683349Swentaoy 	ntwdt_dip = dip;
2693349Swentaoy 
2703349Swentaoy 	ntwdt_ptr->ntwdt_dip = dip;
2713349Swentaoy 	ntwdt_ptr->ntwdt_cycl_id = CYCLIC_NONE;
2723349Swentaoy 	mutex_init(&ntwdt_ptr->ntwdt_mutex, NULL,
2733349Swentaoy 	    MUTEX_DRIVER, NULL);
2743349Swentaoy 
2753349Swentaoy 	/*
2763349Swentaoy 	 * Initialize the watchdog structure
2773349Swentaoy 	 */
2783349Swentaoy 	ntwdt_ptr->ntwdt_run_state =
2793349Swentaoy 	    kmem_zalloc(sizeof (ntwdt_runstate_t), KM_SLEEP);
2803349Swentaoy 	ntwdt_runstatep = ntwdt_ptr->ntwdt_run_state;
2813349Swentaoy 
2823349Swentaoy 	if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW,
2833349Swentaoy 	    &ntwdt_runstatep->ntwdt_runstate_mtx_cookie) != DDI_SUCCESS) {
2843349Swentaoy 		cmn_err(CE_WARN, "init of iblock cookie failed "
2853349Swentaoy 		    "for ntwdt_runstate_mutex");
2863349Swentaoy 		goto err1;
2873349Swentaoy 	} else {
2883349Swentaoy 		mutex_init(&ntwdt_runstatep->ntwdt_runstate_mutex,
2893349Swentaoy 		    NULL,
2903349Swentaoy 		    MUTEX_DRIVER,
2913349Swentaoy 		    (void *)ntwdt_runstatep->ntwdt_runstate_mtx_cookie);
2923349Swentaoy 	}
2933349Swentaoy 
2943349Swentaoy 	/* Cyclic fires once per second: */
2953349Swentaoy 	ntwdt_runstatep->ntwdt_cyclic_interval = NTWDT_CYCLIC_INTERVAL;
2963349Swentaoy 
2973349Swentaoy 	/* init the Cyclic that drives the NTWDT */
2983349Swentaoy 	hdlr = &ntwdt_runstatep->ntwdt_cycl_hdlr;
2993349Swentaoy 	hdlr->cyh_level = CY_LOCK_LEVEL;
3003349Swentaoy 	hdlr->cyh_func = (cyc_func_t)ntwdt_cyclic_pat;
3013349Swentaoy 	hdlr->cyh_arg = NULL;
3023349Swentaoy 
3033349Swentaoy 	/* Softint that will be triggered by Cyclic that drives NTWDT */
3043349Swentaoy 	if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &ntwdt_cyclic_softint_id,
3053349Swentaoy 	    NULL, NULL, ntwdt_cyclic_softint, (caddr_t)ntwdt_ptr)
3063349Swentaoy 	    != DDI_SUCCESS) {
3073349Swentaoy 		cmn_err(CE_WARN, "failed to add cyclic softintr");
3083349Swentaoy 		goto err2;
3093349Swentaoy 	}
3103349Swentaoy 
3113349Swentaoy 	/*
3123349Swentaoy 	 * Create Minor Node as last activity.  This prevents
3133349Swentaoy 	 * application from accessing our implementation until it
3143349Swentaoy 	 * is initialized.
3153349Swentaoy 	 */
3163349Swentaoy 	if (ddi_create_minor_node(dip, NTWDT_MINOR_NODE, S_IFCHR, 0,
3173349Swentaoy 	    DDI_PSEUDO, NULL) == DDI_FAILURE) {
3183349Swentaoy 		cmn_err(CE_WARN, "failed to create Minor Node: %s",
3193349Swentaoy 		    NTWDT_MINOR_NODE);
3203349Swentaoy 		goto err3;
3213349Swentaoy 	}
3223349Swentaoy 
3233349Swentaoy 	/* Display our driver info in the banner */
3243349Swentaoy 	ddi_report_dev(dip);
3253349Swentaoy 
3263349Swentaoy 	return (DDI_SUCCESS);
3273349Swentaoy 
3283349Swentaoy err3:
3293349Swentaoy 	ddi_remove_softintr(ntwdt_cyclic_softint_id);
3303349Swentaoy err2:
3313349Swentaoy 	mutex_destroy(&ntwdt_runstatep->ntwdt_runstate_mutex);
3323349Swentaoy err1:
3333349Swentaoy 	/* clean up the driver stuff here */
3343349Swentaoy 	kmem_free(ntwdt_runstatep, sizeof (ntwdt_runstate_t));
3353349Swentaoy 	ntwdt_ptr->ntwdt_run_state = NULL;
3363349Swentaoy 	mutex_destroy(&ntwdt_ptr->ntwdt_mutex);
3373349Swentaoy 	ddi_soft_state_free(ntwdt_statep, instance);
3383349Swentaoy 	ntwdt_dip = NULL;
3393349Swentaoy 
3403349Swentaoy 	return (DDI_FAILURE);
3413349Swentaoy }
3423349Swentaoy 
3433349Swentaoy /*ARGSUSED*/
3443349Swentaoy static int
ntwdt_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)3453349Swentaoy ntwdt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
3463349Swentaoy {
3473349Swentaoy 	dev_t dev;
3483349Swentaoy 	int instance;
3493349Swentaoy 	int error = DDI_SUCCESS;
3503349Swentaoy 
3513349Swentaoy 	switch (infocmd) {
3523349Swentaoy 	case DDI_INFO_DEVT2DEVINFO:
3533349Swentaoy 		dev = (dev_t)arg;
3543349Swentaoy 		if (getminor(dev) == 0) {
3553349Swentaoy 			*result = (void *)ntwdt_dip;
3563349Swentaoy 		} else {
3573349Swentaoy 			error = DDI_FAILURE;
3583349Swentaoy 		}
3593349Swentaoy 		break;
3603349Swentaoy 
3613349Swentaoy 	case DDI_INFO_DEVT2INSTANCE:
3623349Swentaoy 		dev = (dev_t)arg;
3633349Swentaoy 		instance = getminor(dev);
3643349Swentaoy 		*result = (void *)(uintptr_t)instance;
3653349Swentaoy 		break;
3663349Swentaoy 
3673349Swentaoy 	default:
3683349Swentaoy 		error = DDI_FAILURE;
3693349Swentaoy 
3703349Swentaoy 	}
3713349Swentaoy 
3723349Swentaoy 	return (error);
3733349Swentaoy }
3743349Swentaoy 
3753349Swentaoy /*ARGSUSED*/
3763349Swentaoy static int
ntwdt_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)3773349Swentaoy ntwdt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3783349Swentaoy {
3793349Swentaoy 	int instance = ddi_get_instance(dip);
3803349Swentaoy 	ntwdt_state_t *ntwdt_ptr = NULL;
3813349Swentaoy 
3823349Swentaoy 	ntwdt_ptr = ddi_get_soft_state(ntwdt_statep, instance);
3833349Swentaoy 	if (ntwdt_ptr == NULL) {
3843349Swentaoy 		return (DDI_FAILURE);
3853349Swentaoy 	}
3863349Swentaoy 
3873349Swentaoy 	switch (cmd) {
3883349Swentaoy 	case DDI_SUSPEND:
3893349Swentaoy 		return (DDI_SUCCESS);
3903349Swentaoy 
3913349Swentaoy 	case DDI_DETACH:
3923349Swentaoy 		/*
3933349Swentaoy 		 * release resources in opposite (LIFO) order as
3943349Swentaoy 		 * were allocated in attach.
3953349Swentaoy 		 */
3963349Swentaoy 		ddi_remove_minor_node(dip, NULL);
3973349Swentaoy 		ntwdt_stop_timer_lock((void *)ntwdt_ptr);
3983349Swentaoy 		ddi_remove_softintr(ntwdt_cyclic_softint_id);
3993349Swentaoy 
4003349Swentaoy 		mutex_destroy(
4017656SSherry.Moore@Sun.COM 		    &ntwdt_ptr->ntwdt_run_state->ntwdt_runstate_mutex);
4023349Swentaoy 		kmem_free(ntwdt_ptr->ntwdt_run_state,
4037656SSherry.Moore@Sun.COM 		    sizeof (ntwdt_runstate_t));
4043349Swentaoy 		ntwdt_ptr->ntwdt_run_state = NULL;
4053349Swentaoy 
4063349Swentaoy 		mutex_destroy(&ntwdt_ptr->ntwdt_mutex);
4073349Swentaoy 
4083349Swentaoy 		ddi_soft_state_free(ntwdt_statep, instance);
4093349Swentaoy 
4103349Swentaoy 		ntwdt_dip = NULL;
4113349Swentaoy 		return (DDI_SUCCESS);
4123349Swentaoy 
4133349Swentaoy 	default:
4143349Swentaoy 		return (DDI_FAILURE);
4153349Swentaoy 	}
4163349Swentaoy }
4173349Swentaoy 
4183349Swentaoy /*ARGSUSED*/
4193349Swentaoy static int
ntwdt_open(dev_t * devp,int flag,int otyp,cred_t * credp)4203349Swentaoy ntwdt_open(dev_t *devp, int flag, int otyp, cred_t *credp)
4213349Swentaoy {
4223349Swentaoy 	int instance = getminor(*devp);
4233349Swentaoy 	int retval = 0;
4243349Swentaoy 	ntwdt_state_t *ntwdt_ptr = getstate(instance);
4253349Swentaoy 
4263349Swentaoy 	if (ntwdt_ptr == NULL) {
4273349Swentaoy 		return (ENXIO);
4283349Swentaoy 	}
4293349Swentaoy 
4303349Swentaoy 	/*
4313349Swentaoy 	 * ensure caller is a priviledged process.
4323349Swentaoy 	 */
4333349Swentaoy 	if (drv_priv(credp) != 0) {
4343349Swentaoy 		return (EPERM);
4353349Swentaoy 	}
4363349Swentaoy 
4373349Swentaoy 	mutex_enter(&ntwdt_ptr->ntwdt_mutex);
4383349Swentaoy 	if (ntwdt_ptr->ntwdt_open_flag) {
4393349Swentaoy 		retval = EAGAIN;
4403349Swentaoy 	} else {
4413349Swentaoy 		ntwdt_ptr->ntwdt_open_flag = 1;
4423349Swentaoy 	}
4433349Swentaoy 	mutex_exit(&ntwdt_ptr->ntwdt_mutex);
4443349Swentaoy 
4453349Swentaoy 	return (retval);
4463349Swentaoy }
4473349Swentaoy 
4483349Swentaoy /*ARGSUSED*/
4493349Swentaoy static int
ntwdt_close(dev_t dev,int flag,int otyp,cred_t * credp)4503349Swentaoy ntwdt_close(dev_t dev, int flag, int otyp, cred_t *credp)
4513349Swentaoy {
4523349Swentaoy 	int instance = getminor(dev);
4533349Swentaoy 	ntwdt_state_t *ntwdt_ptr = getstate(instance);
4543349Swentaoy 
4553349Swentaoy 	if (ntwdt_ptr == NULL) {
4563349Swentaoy 		return (ENXIO);
4573349Swentaoy 	}
4583349Swentaoy 
4593349Swentaoy 	mutex_enter(&ntwdt_ptr->ntwdt_mutex);
4603349Swentaoy 	ntwdt_ptr->ntwdt_open_flag = 0;
4613349Swentaoy 	mutex_exit(&ntwdt_ptr->ntwdt_mutex);
4623349Swentaoy 
4633349Swentaoy 	return (0);
4643349Swentaoy }
4653349Swentaoy 
4663349Swentaoy /*ARGSUSED*/
4673349Swentaoy static int
ntwdt_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)4683349Swentaoy ntwdt_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
4693349Swentaoy 	int *rvalp)
4703349Swentaoy {
4713349Swentaoy 	int instance = getminor(dev);
4723349Swentaoy 	int retval = 0;
4733349Swentaoy 	ntwdt_state_t *ntwdt_ptr = NULL;
4743349Swentaoy 	ntwdt_runstate_t *ntwdt_state;
4753349Swentaoy 	lom_dogstate_t lom_dogstate;
4763349Swentaoy 	lom_dogctl_t lom_dogctl;
4773349Swentaoy 	uint32_t lom_dogtime;
4783349Swentaoy 
4793349Swentaoy 	if ((ntwdt_ptr = getstate(instance)) == NULL) {
4803349Swentaoy 		return (ENXIO);
4813349Swentaoy 	}
4823349Swentaoy 
4833349Swentaoy 	ntwdt_state = ntwdt_ptr->ntwdt_run_state;
4843349Swentaoy 
4853349Swentaoy 	switch (cmd) {
4863349Swentaoy 	case LOMIOCDOGSTATE:
4873349Swentaoy 		mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
4883349Swentaoy 		lom_dogstate.reset_enable = ntwdt_state->ntwdt_reset_enabled;
4893349Swentaoy 		lom_dogstate.dog_enable = ntwdt_state->ntwdt_watchdog_enabled;
4903349Swentaoy 		lom_dogstate.dog_timeout = ntwdt_state->ntwdt_watchdog_timeout;
4913349Swentaoy 		mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
4923349Swentaoy 
4933349Swentaoy 		if (ddi_copyout((caddr_t)&lom_dogstate, (caddr_t)arg,
4947656SSherry.Moore@Sun.COM 		    sizeof (lom_dogstate_t), mode) != 0) {
4953349Swentaoy 			retval = EFAULT;
4963349Swentaoy 		}
4973349Swentaoy 		break;
4983349Swentaoy 
4993349Swentaoy 	case LOMIOCDOGCTL:
5003349Swentaoy 		if (ddi_copyin((caddr_t)arg, (caddr_t)&lom_dogctl,
5017656SSherry.Moore@Sun.COM 		    sizeof (lom_dogctl_t), mode) != 0) {
5023349Swentaoy 			retval = EFAULT;
5033349Swentaoy 			break;
5043349Swentaoy 		}
5053349Swentaoy 
5063349Swentaoy 		NTWDT_DBG(NTWDT_DBG_IOCTL, ("reset_enable: %d, and dog_enable: "
5077656SSherry.Moore@Sun.COM 		    "%d, watchdog_timeout %d", lom_dogctl.reset_enable,
5087656SSherry.Moore@Sun.COM 		    lom_dogctl.dog_enable,
5097656SSherry.Moore@Sun.COM 		    ntwdt_state->ntwdt_watchdog_timeout));
5103349Swentaoy 		/*
5113349Swentaoy 		 * ignore request to enable reset while disabling watchdog.
5123349Swentaoy 		 */
5133349Swentaoy 		if (!lom_dogctl.dog_enable && lom_dogctl.reset_enable) {
5143349Swentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("invalid combination of "
5157656SSherry.Moore@Sun.COM 			    "reset_enable: %d, and dog_enable: %d",
5167656SSherry.Moore@Sun.COM 			    lom_dogctl.reset_enable,
5177656SSherry.Moore@Sun.COM 			    lom_dogctl.dog_enable));
5183349Swentaoy 			retval = EINVAL;
5193349Swentaoy 			break;
5203349Swentaoy 		}
5213349Swentaoy 
5223349Swentaoy 		mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
5233349Swentaoy 
5243349Swentaoy 		if (ntwdt_state->ntwdt_watchdog_timeout == 0) {
5253349Swentaoy 			/*
5263349Swentaoy 			 * the LOMIOCDOGTIME has never been used to setup
5273349Swentaoy 			 * a valid timeout.
5283349Swentaoy 			 */
5293349Swentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("timeout has not been set"
5307656SSherry.Moore@Sun.COM 			    "watchdog_timeout: %d",
5317656SSherry.Moore@Sun.COM 			    ntwdt_state->ntwdt_watchdog_timeout));
5323349Swentaoy 			retval = EINVAL;
5333349Swentaoy 			goto end;
5343349Swentaoy 		}
5353349Swentaoy 
5363349Swentaoy 		/*
5373349Swentaoy 		 * Store the user specified state in the softstate.
5383349Swentaoy 		 */
5393349Swentaoy 		ntwdt_state->ntwdt_reset_enabled = lom_dogctl.reset_enable;
5403349Swentaoy 		ntwdt_state->ntwdt_watchdog_enabled = lom_dogctl.dog_enable;
5413349Swentaoy 
5423349Swentaoy 		if (ntwdt_state->ntwdt_watchdog_enabled != 0) {
5433349Swentaoy 			/*
5443349Swentaoy 			 * The user wants to enable the watchdog.
5453349Swentaoy 			 * Arm the watchdog and start the cyclic.
5463349Swentaoy 			 */
5473349Swentaoy 			ntwdt_arm_watchdog(ntwdt_state);
5483349Swentaoy 
5493349Swentaoy 			if (ntwdt_state->ntwdt_timer_running == 0) {
5503349Swentaoy 				ntwdt_start_timer(ntwdt_ptr);
5513349Swentaoy 			}
5523349Swentaoy 
5533349Swentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("AWDT is enabled"));
5543349Swentaoy 		} else {
5553349Swentaoy 			/*
5563349Swentaoy 			 * The user wants to disable the watchdog.
5573349Swentaoy 			 */
5583349Swentaoy 			if (ntwdt_state->ntwdt_timer_running != 0) {
5593349Swentaoy 				ntwdt_stop_timer(ntwdt_ptr);
5603349Swentaoy 			}
5613349Swentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("AWDT is disabled"));
5623349Swentaoy 		}
5633349Swentaoy 
5643349Swentaoy 		mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
5653349Swentaoy 		break;
5663349Swentaoy 
5673349Swentaoy 	case LOMIOCDOGTIME:
5683349Swentaoy 		if (ddi_copyin((caddr_t)arg, (caddr_t)&lom_dogtime,
5697656SSherry.Moore@Sun.COM 		    sizeof (uint32_t), mode) != 0) {
5703349Swentaoy 			retval = EFAULT;
5713349Swentaoy 			break;
5723349Swentaoy 		}
5733349Swentaoy 
5743349Swentaoy 		NTWDT_DBG(NTWDT_DBG_IOCTL, ("user set timeout: %d",
5757656SSherry.Moore@Sun.COM 		    lom_dogtime));
5763349Swentaoy 
5773349Swentaoy 		/*
5783349Swentaoy 		 * Ensure specified timeout is valid.
5793349Swentaoy 		 */
5803349Swentaoy 		if ((lom_dogtime == 0) ||
5817656SSherry.Moore@Sun.COM 		    (lom_dogtime > (uint32_t)NTWDT_MAX_TIMEOUT)) {
5823349Swentaoy 			retval = EINVAL;
5833349Swentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("user set invalid "
5847656SSherry.Moore@Sun.COM 			    "timeout: %d", (int)TICK_TO_MSEC(lom_dogtime)));
5853349Swentaoy 			break;
5863349Swentaoy 		}
5873349Swentaoy 
5883349Swentaoy 		mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
5893349Swentaoy 
5903349Swentaoy 		ntwdt_state->ntwdt_watchdog_timeout = lom_dogtime;
5913349Swentaoy 
5923349Swentaoy 		/*
5933349Swentaoy 		 * If awdt is currently running, re-arm it with the
5943349Swentaoy 		 * newly-specified timeout value.
5953349Swentaoy 		 */
5963349Swentaoy 		if (ntwdt_state->ntwdt_timer_running != 0) {
5973349Swentaoy 			ntwdt_arm_watchdog(ntwdt_state);
5983349Swentaoy 		}
5993349Swentaoy 		mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
6003349Swentaoy 		break;
6013349Swentaoy 
6023349Swentaoy 	case LOMIOCDOGPAT:
6033349Swentaoy 		/*
6043349Swentaoy 		 * Allow user to pat the watchdog timer.
6053349Swentaoy 		 */
6063349Swentaoy 		NTWDT_DBG(NTWDT_DBG_IOCTL, ("DOGPAT is invoked"));
6073349Swentaoy 		mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
6083349Swentaoy 
6093349Swentaoy 		/*
6103349Swentaoy 		 * If awdt is not enabled or underlying cyclic is not
6113349Swentaoy 		 * running, exit.
6123349Swentaoy 		 */
6133349Swentaoy 		if (!(ntwdt_state->ntwdt_watchdog_enabled &&
6147656SSherry.Moore@Sun.COM 		    ntwdt_state->ntwdt_timer_running)) {
6153349Swentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("PAT: AWDT not enabled"));
6163349Swentaoy 			goto end;
6173349Swentaoy 		}
6183349Swentaoy 
6193349Swentaoy 		if (ntwdt_state->ntwdt_watchdog_expired == 0) {
6203349Swentaoy 			/*
6213349Swentaoy 			 * re-arm the awdt.
6223349Swentaoy 			 */
6233349Swentaoy 			ntwdt_arm_watchdog(ntwdt_state);
6243349Swentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("AWDT patted, "
6257656SSherry.Moore@Sun.COM 			    "remainning seconds: %d",
6267656SSherry.Moore@Sun.COM 			    ntwdt_state->ntwdt_time_remaining));
6273349Swentaoy 		}
6283349Swentaoy 
6293349Swentaoy 		mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
6303349Swentaoy 		break;
6313349Swentaoy 
6323349Swentaoy 	default:
6333349Swentaoy 		retval = EINVAL;
6343349Swentaoy 		break;
6353349Swentaoy 	}
6363349Swentaoy 	return (retval);
6373349Swentaoy end:
6383349Swentaoy 	mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
6393349Swentaoy 	return (retval);
6403349Swentaoy }
6413349Swentaoy 
6423349Swentaoy static void
ntwdt_cyclic_pat(void)6433349Swentaoy ntwdt_cyclic_pat(void)
6443349Swentaoy {
6453349Swentaoy 	ddi_trigger_softintr(ntwdt_cyclic_softint_id);
6463349Swentaoy }
6473349Swentaoy 
6483349Swentaoy static uint_t
ntwdt_cyclic_softint(caddr_t arg)6493349Swentaoy ntwdt_cyclic_softint(caddr_t arg)
6503349Swentaoy {
6513349Swentaoy 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
6523349Swentaoy 	ntwdt_state_t *ntwdt_ptr = (ntwdt_state_t *)arg;
6533349Swentaoy 	ntwdt_runstate_t *ntwdt_state;
6543349Swentaoy 
6553349Swentaoy 	ntwdt_state = ntwdt_ptr->ntwdt_run_state;
6563349Swentaoy 
6573349Swentaoy 	mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
6583349Swentaoy 
6593349Swentaoy 	if ((ntwdt_state->ntwdt_watchdog_flags & NTWDT_FLAG_SKIP_CYCLIC) != 0) {
6603349Swentaoy 		ntwdt_state->ntwdt_watchdog_flags &= ~NTWDT_FLAG_SKIP_CYCLIC;
6613349Swentaoy 		goto end;
6623349Swentaoy 	}
6633349Swentaoy 
6643349Swentaoy 	if ((ntwdt_state->ntwdt_timer_running == 0) ||
6657656SSherry.Moore@Sun.COM 	    (ntwdt_ptr->ntwdt_cycl_id == CYCLIC_NONE) ||
6667656SSherry.Moore@Sun.COM 	    (ntwdt_state->ntwdt_watchdog_enabled == 0)) {
6673349Swentaoy 		goto end;
6683349Swentaoy 	}
6693349Swentaoy 
6703349Swentaoy 	NTWDT_DBG(NTWDT_DBG_IOCTL, ("cyclic_softint: %d"
671*11066Srafael.vanoni@sun.com 	    "ddi_get_lbolt64(): %d\n", ntwdt_state->ntwdt_watchdog_timeout,
672*11066Srafael.vanoni@sun.com 	    (int)TICK_TO_MSEC(ddi_get_lbolt64())));
6733349Swentaoy 
6743349Swentaoy 	/*
6753349Swentaoy 	 * Decrement the virtual watchdog timer and check if it has expired.
6763349Swentaoy 	 */
6773349Swentaoy 	ntwdt_state->ntwdt_time_remaining -= NTWDT_DECREMENT_INTERVAL;
6783349Swentaoy 
6793349Swentaoy 	if (ntwdt_state->ntwdt_time_remaining == 0) {
6803349Swentaoy 		cmn_err(CE_WARN, "application-watchdog expired");
6813349Swentaoy 		ntwdt_state->ntwdt_watchdog_expired = 1;
6823349Swentaoy 
6833349Swentaoy 		if (ntwdt_state->ntwdt_reset_enabled != 0) {
6843349Swentaoy 			/*
6853349Swentaoy 			 * The user wants to reset the system.
6863349Swentaoy 			 */
6873349Swentaoy 			mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
6883349Swentaoy 
6893349Swentaoy 			NTWDT_DBG(NTWDT_DBG_NTWDT, ("recovery being done"));
6903349Swentaoy 			ntwdt_enforce_timeout();
6913349Swentaoy 		} else {
6923349Swentaoy 			NTWDT_DBG(NTWDT_DBG_NTWDT, ("no recovery being done"));
6933349Swentaoy 			ntwdt_state->ntwdt_watchdog_enabled = 0;
6943349Swentaoy 		}
6953349Swentaoy 
6963349Swentaoy 		/*
6973349Swentaoy 		 * Schedule Callout to stop the cyclic.
6983349Swentaoy 		 */
6993349Swentaoy 		(void) timeout(ntwdt_stop_timer_lock, ntwdt_ptr, 0);
7003349Swentaoy 	} else {
7013349Swentaoy 		_NOTE(EMPTY)
7023349Swentaoy 		NTWDT_DBG(NTWDT_DBG_NTWDT, ("time remaining in AWDT: %d secs",
7037656SSherry.Moore@Sun.COM 		    (int)TICK_TO_MSEC(ntwdt_state->ntwdt_time_remaining)));
7043349Swentaoy 	}
7053349Swentaoy 
7063349Swentaoy end:
7073349Swentaoy 	mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
7083349Swentaoy 	return (DDI_INTR_CLAIMED);
7093349Swentaoy }
7103349Swentaoy 
7113349Swentaoy static void
ntwdt_arm_watchdog(ntwdt_runstate_t * ntwdt_state)7123349Swentaoy ntwdt_arm_watchdog(ntwdt_runstate_t *ntwdt_state)
7133349Swentaoy {
7143349Swentaoy 	ntwdt_state->ntwdt_time_remaining = ntwdt_state->ntwdt_watchdog_timeout;
7153349Swentaoy 
7163349Swentaoy 	if (ntwdt_state->ntwdt_timer_running != 0) {
7173349Swentaoy 		ntwdt_state->ntwdt_watchdog_flags |= NTWDT_FLAG_SKIP_CYCLIC;
7183349Swentaoy 	} else {
7193349Swentaoy 		ntwdt_state->ntwdt_watchdog_flags &= ~NTWDT_FLAG_SKIP_CYCLIC;
7203349Swentaoy 	}
7213349Swentaoy }
7223349Swentaoy 
7233349Swentaoy static void
ntwdt_start_timer(ntwdt_state_t * ntwdt_ptr)7243349Swentaoy ntwdt_start_timer(ntwdt_state_t *ntwdt_ptr)
7253349Swentaoy {
7263349Swentaoy 	ntwdt_runstate_t	*ntwdt_state = ntwdt_ptr->ntwdt_run_state;
7273349Swentaoy 	cyc_handler_t		*hdlr = &ntwdt_state->ntwdt_cycl_hdlr;
7283349Swentaoy 	cyc_time_t		*when = &ntwdt_state->ntwdt_cycl_time;
7293349Swentaoy 
7303349Swentaoy 	/*
7313349Swentaoy 	 * Init the cyclic.
7323349Swentaoy 	 */
7333349Swentaoy 	when->cyt_interval = ntwdt_state->ntwdt_cyclic_interval;
7343349Swentaoy 	when->cyt_when = gethrtime() + when->cyt_interval;
7353349Swentaoy 
7363349Swentaoy 	ntwdt_state->ntwdt_watchdog_expired = 0;
7373349Swentaoy 	ntwdt_state->ntwdt_timer_running = 1;
7383349Swentaoy 
7393349Swentaoy 	mutex_enter(&cpu_lock);
7403349Swentaoy 	if (ntwdt_ptr->ntwdt_cycl_id == CYCLIC_NONE) {
7413349Swentaoy 		ntwdt_ptr->ntwdt_cycl_id = cyclic_add(hdlr, when);
7423349Swentaoy 	}
7433349Swentaoy 	mutex_exit(&cpu_lock);
7443349Swentaoy 
7453349Swentaoy 	NTWDT_DBG(NTWDT_DBG_NTWDT, ("cyclic-driven timer is started"));
7463349Swentaoy }
7473349Swentaoy 
7483349Swentaoy static void
ntwdt_stop_timer(void * arg)7493349Swentaoy ntwdt_stop_timer(void *arg)
7503349Swentaoy {
7513349Swentaoy 	ntwdt_state_t *ntwdt_ptr = (ntwdt_state_t *)arg;
7523349Swentaoy 	ntwdt_runstate_t *ntwdt_state = ntwdt_ptr->ntwdt_run_state;
7533349Swentaoy 
7543349Swentaoy 	mutex_enter(&cpu_lock);
7553349Swentaoy 	if (ntwdt_ptr->ntwdt_cycl_id != CYCLIC_NONE) {
7563349Swentaoy 		cyclic_remove(ntwdt_ptr->ntwdt_cycl_id);
7573349Swentaoy 	}
7583349Swentaoy 	mutex_exit(&cpu_lock);
7593349Swentaoy 
7603349Swentaoy 	ntwdt_state->ntwdt_watchdog_flags = 0;
7613349Swentaoy 	ntwdt_state->ntwdt_timer_running = 0;
7623349Swentaoy 	ntwdt_ptr->ntwdt_cycl_id = CYCLIC_NONE;
7633349Swentaoy 
7643349Swentaoy 	NTWDT_DBG(NTWDT_DBG_NTWDT, ("cyclic-driven timer is stopped"));
7653349Swentaoy }
7663349Swentaoy 
7673349Swentaoy /*
7683349Swentaoy  * This is a wrapper function for ntwdt_stop_timer as some callers
7693349Swentaoy  * will already have the appropriate mutex locked, and others not.
7703349Swentaoy  */
7713349Swentaoy static void
ntwdt_stop_timer_lock(void * arg)7723349Swentaoy ntwdt_stop_timer_lock(void *arg)
7733349Swentaoy {
7743349Swentaoy 	ntwdt_state_t *ntwdt_ptr = (ntwdt_state_t *)arg;
7753349Swentaoy 
7763349Swentaoy 	mutex_enter(&ntwdt_ptr->ntwdt_run_state->ntwdt_runstate_mutex);
7773349Swentaoy 	ntwdt_stop_timer(arg);
7783349Swentaoy 	mutex_exit(&ntwdt_ptr->ntwdt_run_state->ntwdt_runstate_mutex);
7793349Swentaoy }
7803349Swentaoy 
7813349Swentaoy static void
ntwdt_enforce_timeout()7823349Swentaoy ntwdt_enforce_timeout()
7833349Swentaoy {
7843349Swentaoy 	if (ntwdt_disable_timeout_action != 0) {
7853349Swentaoy 		cmn_err(CE_NOTE, "Appication watchdog timer expired, "
7867656SSherry.Moore@Sun.COM 		    "taking no action");
7873349Swentaoy 		return;
7883349Swentaoy 	}
7893349Swentaoy 
7903349Swentaoy 	NTWDT_DBG(NTWDT_DBG_NTWDT, ("dump cores and rebooting ..."));
7913349Swentaoy 
7923349Swentaoy 	(void) kadmin(A_DUMP, AD_BOOT, NULL, kcred);
7933349Swentaoy 	cmn_err(CE_PANIC, "kadmin(A_DUMP, AD_BOOT) failed");
7943349Swentaoy 	_NOTE(NOTREACHED);
7953349Swentaoy }
7963349Swentaoy 
7973349Swentaoy static int
ntwdt_chk_watchdog_support()7983349Swentaoy ntwdt_chk_watchdog_support()
7993349Swentaoy {
8003349Swentaoy 	int	retval = 0;
8013349Swentaoy 
8023349Swentaoy 	if ((boothowto & RB_DEBUG) != 0) {
8033349Swentaoy 		cmn_err(CE_WARN, "kernel debugger was booted; "
8043349Swentaoy 		    "application watchdog is not available.");
8053349Swentaoy 		retval = ENOTSUP;
8063349Swentaoy 	}
8073349Swentaoy 	return (retval);
8083349Swentaoy }
809