xref: /titanic_51/usr/src/uts/sun4v/io/ntwdt.c (revision 927a453e165c072d45bd6aa2945b3db0fce17c56)
1*927a453eSwentaoy /*
2*927a453eSwentaoy  * CDDL HEADER START
3*927a453eSwentaoy  *
4*927a453eSwentaoy  * The contents of this file are subject to the terms of the
5*927a453eSwentaoy  * Common Development and Distribution License (the "License").
6*927a453eSwentaoy  * You may not use this file except in compliance with the License.
7*927a453eSwentaoy  *
8*927a453eSwentaoy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*927a453eSwentaoy  * or http://www.opensolaris.org/os/licensing.
10*927a453eSwentaoy  * See the License for the specific language governing permissions
11*927a453eSwentaoy  * and limitations under the License.
12*927a453eSwentaoy  *
13*927a453eSwentaoy  * When distributing Covered Code, include this CDDL HEADER in each
14*927a453eSwentaoy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*927a453eSwentaoy  * If applicable, add the following below this CDDL HEADER, with the
16*927a453eSwentaoy  * fields enclosed by brackets "[]" replaced with your own identifying
17*927a453eSwentaoy  * information: Portions Copyright [yyyy] [name of copyright owner]
18*927a453eSwentaoy  *
19*927a453eSwentaoy  * CDDL HEADER END
20*927a453eSwentaoy  */
21*927a453eSwentaoy /*
22*927a453eSwentaoy  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*927a453eSwentaoy  * Use is subject to license terms.
24*927a453eSwentaoy  */
25*927a453eSwentaoy 
26*927a453eSwentaoy #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*927a453eSwentaoy 
28*927a453eSwentaoy /*
29*927a453eSwentaoy  * sun4v application watchdog driver
30*927a453eSwentaoy  */
31*927a453eSwentaoy 
32*927a453eSwentaoy #include <sys/types.h>
33*927a453eSwentaoy #include <sys/file.h>
34*927a453eSwentaoy #include <sys/errno.h>
35*927a453eSwentaoy #include <sys/open.h>
36*927a453eSwentaoy #include <sys/callb.h>
37*927a453eSwentaoy #include <sys/cred.h>
38*927a453eSwentaoy #include <sys/cyclic.h>
39*927a453eSwentaoy #include <sys/uio.h>
40*927a453eSwentaoy #include <sys/stat.h>
41*927a453eSwentaoy #include <sys/ksynch.h>
42*927a453eSwentaoy #include <sys/modctl.h>
43*927a453eSwentaoy #include <sys/conf.h>
44*927a453eSwentaoy #include <sys/devops.h>
45*927a453eSwentaoy #include <sys/debug.h>
46*927a453eSwentaoy #include <sys/cmn_err.h>
47*927a453eSwentaoy #include <sys/ddi.h>
48*927a453eSwentaoy #include <sys/reboot.h>
49*927a453eSwentaoy #include <sys/sunddi.h>
50*927a453eSwentaoy #include <sys/signal.h>
51*927a453eSwentaoy #include <sys/ntwdt.h>
52*927a453eSwentaoy #include <sys/note.h>
53*927a453eSwentaoy 
54*927a453eSwentaoy /*
55*927a453eSwentaoy  * tunables
56*927a453eSwentaoy  */
57*927a453eSwentaoy int ntwdt_disable_timeout_action = 0;
58*927a453eSwentaoy 
59*927a453eSwentaoy #ifdef DEBUG
60*927a453eSwentaoy 
61*927a453eSwentaoy int ntwdt_debug = 0;		/* ntwdt debug flag, dbg all for now. */
62*927a453eSwentaoy 
63*927a453eSwentaoy /*
64*927a453eSwentaoy  * Flags to set in ntwdt_debug.
65*927a453eSwentaoy  */
66*927a453eSwentaoy #define	NTWDT_DBG_ENTRY	0x00000001	/* drv entry points */
67*927a453eSwentaoy #define	NTWDT_DBG_IOCTL	0x00000002	/* ioctl's */
68*927a453eSwentaoy #define	NTWDT_DBG_NTWDT	0x00000004	/* other ntwdt debug */
69*927a453eSwentaoy 
70*927a453eSwentaoy #define	NTWDT_DBG(flag, msg) \
71*927a453eSwentaoy 	{ if ((ntwdt_debug) & (flag)) (void) printf msg; }
72*927a453eSwentaoy #else	/* DEBUG */
73*927a453eSwentaoy #define	NTWDT_DBG(flag, msg)
74*927a453eSwentaoy #endif	/* DEBUG */
75*927a453eSwentaoy 
76*927a453eSwentaoy #define	NTWDT_MINOR_NODE	"awdt"
77*927a453eSwentaoy #define	getstate(minor)	\
78*927a453eSwentaoy 	((ntwdt_state_t *)ddi_get_soft_state(ntwdt_statep, (minor)))
79*927a453eSwentaoy 
80*927a453eSwentaoy /*
81*927a453eSwentaoy  * The ntwdt cyclic interval in nanosecond unit as cyclic subsystem supports
82*927a453eSwentaoy  * nanosecond resolution.
83*927a453eSwentaoy  */
84*927a453eSwentaoy #define	NTWDT_CYCLIC_INTERVAL	NANOSEC	/* 1 seconds */
85*927a453eSwentaoy 
86*927a453eSwentaoy /*
87*927a453eSwentaoy  * The ntwdt decrement interval in 1 second resolution.
88*927a453eSwentaoy  */
89*927a453eSwentaoy #define	NTWDT_DECREMENT_INTERVAL	1	/* 1 second */
90*927a453eSwentaoy 
91*927a453eSwentaoy /*
92*927a453eSwentaoy  * ntwdt_watchdog_flags and macros to set/clear one bit in it.
93*927a453eSwentaoy  */
94*927a453eSwentaoy #define	NTWDT_FLAG_SKIP_CYCLIC	0x1	/* skip next cyclic */
95*927a453eSwentaoy 
96*927a453eSwentaoy #define	NTWDT_MAX_TIMEOUT	(3 * 60 * 60)	/* 3 hours */
97*927a453eSwentaoy 
98*927a453eSwentaoy #define	WDT_MIN_COREAPI_MAJOR	1
99*927a453eSwentaoy #define	WDT_MIN_COREAPI_MINOR	1
100*927a453eSwentaoy 
101*927a453eSwentaoy /*
102*927a453eSwentaoy  * Application watchdog state.
103*927a453eSwentaoy  */
104*927a453eSwentaoy typedef struct ntwdt_runstate {
105*927a453eSwentaoy 	kmutex_t		ntwdt_runstate_mutex;
106*927a453eSwentaoy 	ddi_iblock_cookie_t	ntwdt_runstate_mtx_cookie;
107*927a453eSwentaoy 	int			ntwdt_watchdog_enabled;	/* wdog enabled ? */
108*927a453eSwentaoy 	int			ntwdt_reset_enabled;	/* reset enabled ? */
109*927a453eSwentaoy 	int			ntwdt_timer_running;	/* wdog running ? */
110*927a453eSwentaoy 	int			ntwdt_watchdog_expired;	/* wdog expired ? */
111*927a453eSwentaoy 	uint32_t		ntwdt_time_remaining;	/* expiration timer */
112*927a453eSwentaoy 	uint32_t		ntwdt_watchdog_timeout;	/* timeout in seconds */
113*927a453eSwentaoy 	hrtime_t		ntwdt_cyclic_interval;	/* cyclic interval */
114*927a453eSwentaoy 	cyc_handler_t		ntwdt_cycl_hdlr;
115*927a453eSwentaoy 	cyc_time_t		ntwdt_cycl_time;
116*927a453eSwentaoy 	uint32_t		ntwdt_watchdog_flags;
117*927a453eSwentaoy } ntwdt_runstate_t;
118*927a453eSwentaoy 
119*927a453eSwentaoy /*
120*927a453eSwentaoy  * softstate of NTWDT
121*927a453eSwentaoy  */
122*927a453eSwentaoy typedef struct {
123*927a453eSwentaoy 	kmutex_t		ntwdt_mutex;
124*927a453eSwentaoy 	dev_info_t		*ntwdt_dip;		/* dip */
125*927a453eSwentaoy 	int			ntwdt_open_flag;	/* file open ? */
126*927a453eSwentaoy 	ntwdt_runstate_t	*ntwdt_run_state;	/* wdog state */
127*927a453eSwentaoy 	cyclic_id_t		ntwdt_cycl_id;
128*927a453eSwentaoy } ntwdt_state_t;
129*927a453eSwentaoy 
130*927a453eSwentaoy static void *ntwdt_statep;	/* softstate */
131*927a453eSwentaoy static dev_info_t *ntwdt_dip;
132*927a453eSwentaoy 
133*927a453eSwentaoy static ddi_softintr_t	ntwdt_cyclic_softint_id;
134*927a453eSwentaoy 
135*927a453eSwentaoy static int ntwdt_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
136*927a453eSwentaoy static int ntwdt_attach(dev_info_t *, ddi_attach_cmd_t);
137*927a453eSwentaoy static int ntwdt_detach(dev_info_t *, ddi_detach_cmd_t);
138*927a453eSwentaoy static int ntwdt_open(dev_t *, int, int, cred_t *);
139*927a453eSwentaoy static int ntwdt_close(dev_t, int, int, cred_t *);
140*927a453eSwentaoy static int ntwdt_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
141*927a453eSwentaoy 
142*927a453eSwentaoy static int ntwdt_chk_watchdog_support();
143*927a453eSwentaoy static void ntwdt_arm_watchdog(ntwdt_runstate_t *ntwdt_state);
144*927a453eSwentaoy static void ntwdt_cyclic_pat(void);
145*927a453eSwentaoy static uint_t ntwdt_cyclic_softint(caddr_t arg);
146*927a453eSwentaoy static void ntwdt_start_timer(ntwdt_state_t *ntwdt_ptr);
147*927a453eSwentaoy static void ntwdt_stop_timer_lock(void *arg);
148*927a453eSwentaoy static void ntwdt_stop_timer(void *arg);
149*927a453eSwentaoy static void ntwdt_enforce_timeout();
150*927a453eSwentaoy 
151*927a453eSwentaoy static struct cb_ops ntwdt_cb_ops = {
152*927a453eSwentaoy 	ntwdt_open,		/* cb_open */
153*927a453eSwentaoy 	ntwdt_close,		/* cb_close */
154*927a453eSwentaoy 	nodev,			/* cb_strategy */
155*927a453eSwentaoy 	nodev,			/* cb_print */
156*927a453eSwentaoy 	nodev,			/* cb_dump */
157*927a453eSwentaoy 	nodev,			/* cb_read */
158*927a453eSwentaoy 	nodev,			/* cb_write */
159*927a453eSwentaoy 	ntwdt_ioctl,		/* cb_ioctl */
160*927a453eSwentaoy 	nodev,			/* cb_devmap */
161*927a453eSwentaoy 	nodev,			/* cb_mmap */
162*927a453eSwentaoy 	nodev,			/* cb_segmap */
163*927a453eSwentaoy 	nochpoll,		/* cb_chpoll */
164*927a453eSwentaoy 	ddi_prop_op,		/* cb_prop_op */
165*927a453eSwentaoy 	NULL,			/* cb_str */
166*927a453eSwentaoy 	D_NEW | D_MP		/* cb_flag */
167*927a453eSwentaoy };
168*927a453eSwentaoy 
169*927a453eSwentaoy static struct dev_ops ntwdt_dev_ops = {
170*927a453eSwentaoy 	DEVO_REV,		/* devo_rev */
171*927a453eSwentaoy 	0,			/* devo_refcnt */
172*927a453eSwentaoy 	ntwdt_info,		/* devo_info */
173*927a453eSwentaoy 	nulldev,		/* devo_identify */
174*927a453eSwentaoy 	nulldev,		/* devo_probe */
175*927a453eSwentaoy 	ntwdt_attach,		/* devo_attach */
176*927a453eSwentaoy 	ntwdt_detach,		/* devo_detach */
177*927a453eSwentaoy 	nodev,			/* devo_reset */
178*927a453eSwentaoy 	&ntwdt_cb_ops,		/* devo_cb_ops */
179*927a453eSwentaoy 	NULL,			/* devo_bus_ops */
180*927a453eSwentaoy 	nulldev			/* devo_power */
181*927a453eSwentaoy };
182*927a453eSwentaoy 
183*927a453eSwentaoy static struct modldrv modldrv = {
184*927a453eSwentaoy 	&mod_driverops,
185*927a453eSwentaoy 	"Application Watchdog Driver 1.1",
186*927a453eSwentaoy 	&ntwdt_dev_ops
187*927a453eSwentaoy };
188*927a453eSwentaoy 
189*927a453eSwentaoy static struct modlinkage modlinkage = {
190*927a453eSwentaoy 	MODREV_1,
191*927a453eSwentaoy 	(void *)&modldrv,
192*927a453eSwentaoy 	NULL
193*927a453eSwentaoy };
194*927a453eSwentaoy 
195*927a453eSwentaoy int
196*927a453eSwentaoy _init(void)
197*927a453eSwentaoy {
198*927a453eSwentaoy 	int error = 0;
199*927a453eSwentaoy 
200*927a453eSwentaoy 	NTWDT_DBG(NTWDT_DBG_ENTRY, ("_init"));
201*927a453eSwentaoy 
202*927a453eSwentaoy 	/* Initialize the soft state structures */
203*927a453eSwentaoy 	if ((error = ddi_soft_state_init(&ntwdt_statep,
204*927a453eSwentaoy 	    sizeof (ntwdt_state_t), 1)) != 0) {
205*927a453eSwentaoy 		return (error);
206*927a453eSwentaoy 	}
207*927a453eSwentaoy 
208*927a453eSwentaoy 	/* Install the loadable module */
209*927a453eSwentaoy 	if ((error = mod_install(&modlinkage)) != 0) {
210*927a453eSwentaoy 		ddi_soft_state_fini(&ntwdt_statep);
211*927a453eSwentaoy 	}
212*927a453eSwentaoy 	return (error);
213*927a453eSwentaoy }
214*927a453eSwentaoy 
215*927a453eSwentaoy int
216*927a453eSwentaoy _info(struct modinfo *modinfop)
217*927a453eSwentaoy {
218*927a453eSwentaoy 	NTWDT_DBG(NTWDT_DBG_ENTRY, ("_info"));
219*927a453eSwentaoy 
220*927a453eSwentaoy 	return (mod_info(&modlinkage, modinfop));
221*927a453eSwentaoy }
222*927a453eSwentaoy 
223*927a453eSwentaoy int
224*927a453eSwentaoy _fini(void)
225*927a453eSwentaoy {
226*927a453eSwentaoy 	int retval;
227*927a453eSwentaoy 
228*927a453eSwentaoy 	NTWDT_DBG(NTWDT_DBG_ENTRY, ("_fini"));
229*927a453eSwentaoy 
230*927a453eSwentaoy 	if ((retval = mod_remove(&modlinkage)) == 0) {
231*927a453eSwentaoy 		ddi_soft_state_fini(&ntwdt_statep);
232*927a453eSwentaoy 	}
233*927a453eSwentaoy 
234*927a453eSwentaoy 	return (retval);
235*927a453eSwentaoy }
236*927a453eSwentaoy 
237*927a453eSwentaoy static int
238*927a453eSwentaoy ntwdt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
239*927a453eSwentaoy {
240*927a453eSwentaoy 	int instance;
241*927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = NULL;	/* pointer to ntwdt_runstatep */
242*927a453eSwentaoy 	ntwdt_runstate_t *ntwdt_runstatep = NULL;
243*927a453eSwentaoy 	cyc_handler_t *hdlr = NULL;
244*927a453eSwentaoy 
245*927a453eSwentaoy 	switch (cmd) {
246*927a453eSwentaoy 	case DDI_ATTACH:
247*927a453eSwentaoy 		break;
248*927a453eSwentaoy 
249*927a453eSwentaoy 	case DDI_RESUME:
250*927a453eSwentaoy 		return (DDI_SUCCESS);
251*927a453eSwentaoy 
252*927a453eSwentaoy 	default:
253*927a453eSwentaoy 		return (DDI_FAILURE);
254*927a453eSwentaoy 	}
255*927a453eSwentaoy 
256*927a453eSwentaoy 	if (ntwdt_chk_watchdog_support() != 0) {
257*927a453eSwentaoy 		return (DDI_FAILURE);
258*927a453eSwentaoy 	}
259*927a453eSwentaoy 
260*927a453eSwentaoy 	instance = ddi_get_instance(dip);
261*927a453eSwentaoy 	ASSERT(instance == 0);
262*927a453eSwentaoy 
263*927a453eSwentaoy 	if (ddi_soft_state_zalloc(ntwdt_statep, instance) != DDI_SUCCESS) {
264*927a453eSwentaoy 		return (DDI_FAILURE);
265*927a453eSwentaoy 	}
266*927a453eSwentaoy 	ntwdt_ptr = ddi_get_soft_state(ntwdt_statep, instance);
267*927a453eSwentaoy 	ASSERT(ntwdt_ptr != NULL);
268*927a453eSwentaoy 
269*927a453eSwentaoy 	ntwdt_dip = dip;
270*927a453eSwentaoy 
271*927a453eSwentaoy 	ntwdt_ptr->ntwdt_dip = dip;
272*927a453eSwentaoy 	ntwdt_ptr->ntwdt_cycl_id = CYCLIC_NONE;
273*927a453eSwentaoy 	mutex_init(&ntwdt_ptr->ntwdt_mutex, NULL,
274*927a453eSwentaoy 	    MUTEX_DRIVER, NULL);
275*927a453eSwentaoy 
276*927a453eSwentaoy 	/*
277*927a453eSwentaoy 	 * Initialize the watchdog structure
278*927a453eSwentaoy 	 */
279*927a453eSwentaoy 	ntwdt_ptr->ntwdt_run_state =
280*927a453eSwentaoy 	    kmem_zalloc(sizeof (ntwdt_runstate_t), KM_SLEEP);
281*927a453eSwentaoy 	ntwdt_runstatep = ntwdt_ptr->ntwdt_run_state;
282*927a453eSwentaoy 
283*927a453eSwentaoy 	if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW,
284*927a453eSwentaoy 	    &ntwdt_runstatep->ntwdt_runstate_mtx_cookie) != DDI_SUCCESS) {
285*927a453eSwentaoy 		cmn_err(CE_WARN, "init of iblock cookie failed "
286*927a453eSwentaoy 		    "for ntwdt_runstate_mutex");
287*927a453eSwentaoy 		goto err1;
288*927a453eSwentaoy 	} else {
289*927a453eSwentaoy 		mutex_init(&ntwdt_runstatep->ntwdt_runstate_mutex,
290*927a453eSwentaoy 		    NULL,
291*927a453eSwentaoy 		    MUTEX_DRIVER,
292*927a453eSwentaoy 		    (void *)ntwdt_runstatep->ntwdt_runstate_mtx_cookie);
293*927a453eSwentaoy 	}
294*927a453eSwentaoy 
295*927a453eSwentaoy 	/* Cyclic fires once per second: */
296*927a453eSwentaoy 	ntwdt_runstatep->ntwdt_cyclic_interval = NTWDT_CYCLIC_INTERVAL;
297*927a453eSwentaoy 
298*927a453eSwentaoy 	/* init the Cyclic that drives the NTWDT */
299*927a453eSwentaoy 	hdlr = &ntwdt_runstatep->ntwdt_cycl_hdlr;
300*927a453eSwentaoy 	hdlr->cyh_level = CY_LOCK_LEVEL;
301*927a453eSwentaoy 	hdlr->cyh_func = (cyc_func_t)ntwdt_cyclic_pat;
302*927a453eSwentaoy 	hdlr->cyh_arg = NULL;
303*927a453eSwentaoy 
304*927a453eSwentaoy 	/* Softint that will be triggered by Cyclic that drives NTWDT */
305*927a453eSwentaoy 	if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &ntwdt_cyclic_softint_id,
306*927a453eSwentaoy 	    NULL, NULL, ntwdt_cyclic_softint, (caddr_t)ntwdt_ptr)
307*927a453eSwentaoy 	    != DDI_SUCCESS) {
308*927a453eSwentaoy 		cmn_err(CE_WARN, "failed to add cyclic softintr");
309*927a453eSwentaoy 		goto err2;
310*927a453eSwentaoy 	}
311*927a453eSwentaoy 
312*927a453eSwentaoy 	/*
313*927a453eSwentaoy 	 * Create Minor Node as last activity.  This prevents
314*927a453eSwentaoy 	 * application from accessing our implementation until it
315*927a453eSwentaoy 	 * is initialized.
316*927a453eSwentaoy 	 */
317*927a453eSwentaoy 	if (ddi_create_minor_node(dip, NTWDT_MINOR_NODE, S_IFCHR, 0,
318*927a453eSwentaoy 	    DDI_PSEUDO, NULL) == DDI_FAILURE) {
319*927a453eSwentaoy 		cmn_err(CE_WARN, "failed to create Minor Node: %s",
320*927a453eSwentaoy 		    NTWDT_MINOR_NODE);
321*927a453eSwentaoy 		goto err3;
322*927a453eSwentaoy 	}
323*927a453eSwentaoy 
324*927a453eSwentaoy 	/* Display our driver info in the banner */
325*927a453eSwentaoy 	ddi_report_dev(dip);
326*927a453eSwentaoy 
327*927a453eSwentaoy 	return (DDI_SUCCESS);
328*927a453eSwentaoy 
329*927a453eSwentaoy err3:
330*927a453eSwentaoy 	ddi_remove_softintr(ntwdt_cyclic_softint_id);
331*927a453eSwentaoy err2:
332*927a453eSwentaoy 	mutex_destroy(&ntwdt_runstatep->ntwdt_runstate_mutex);
333*927a453eSwentaoy err1:
334*927a453eSwentaoy 	/* clean up the driver stuff here */
335*927a453eSwentaoy 	kmem_free(ntwdt_runstatep, sizeof (ntwdt_runstate_t));
336*927a453eSwentaoy 	ntwdt_ptr->ntwdt_run_state = NULL;
337*927a453eSwentaoy 	mutex_destroy(&ntwdt_ptr->ntwdt_mutex);
338*927a453eSwentaoy 	ddi_soft_state_free(ntwdt_statep, instance);
339*927a453eSwentaoy 	ntwdt_dip = NULL;
340*927a453eSwentaoy 
341*927a453eSwentaoy 	return (DDI_FAILURE);
342*927a453eSwentaoy }
343*927a453eSwentaoy 
344*927a453eSwentaoy /*ARGSUSED*/
345*927a453eSwentaoy static int
346*927a453eSwentaoy ntwdt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
347*927a453eSwentaoy {
348*927a453eSwentaoy 	dev_t dev;
349*927a453eSwentaoy 	int instance;
350*927a453eSwentaoy 	int error = DDI_SUCCESS;
351*927a453eSwentaoy 
352*927a453eSwentaoy 	switch (infocmd) {
353*927a453eSwentaoy 	case DDI_INFO_DEVT2DEVINFO:
354*927a453eSwentaoy 		dev = (dev_t)arg;
355*927a453eSwentaoy 		if (getminor(dev) == 0) {
356*927a453eSwentaoy 			*result = (void *)ntwdt_dip;
357*927a453eSwentaoy 		} else {
358*927a453eSwentaoy 			error = DDI_FAILURE;
359*927a453eSwentaoy 		}
360*927a453eSwentaoy 		break;
361*927a453eSwentaoy 
362*927a453eSwentaoy 	case DDI_INFO_DEVT2INSTANCE:
363*927a453eSwentaoy 		dev = (dev_t)arg;
364*927a453eSwentaoy 		instance = getminor(dev);
365*927a453eSwentaoy 		*result = (void *)(uintptr_t)instance;
366*927a453eSwentaoy 		break;
367*927a453eSwentaoy 
368*927a453eSwentaoy 	default:
369*927a453eSwentaoy 		error = DDI_FAILURE;
370*927a453eSwentaoy 
371*927a453eSwentaoy 	}
372*927a453eSwentaoy 
373*927a453eSwentaoy 	return (error);
374*927a453eSwentaoy }
375*927a453eSwentaoy 
376*927a453eSwentaoy /*ARGSUSED*/
377*927a453eSwentaoy static int
378*927a453eSwentaoy ntwdt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
379*927a453eSwentaoy {
380*927a453eSwentaoy 	int instance = ddi_get_instance(dip);
381*927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = NULL;
382*927a453eSwentaoy 
383*927a453eSwentaoy 	ntwdt_ptr = ddi_get_soft_state(ntwdt_statep, instance);
384*927a453eSwentaoy 	if (ntwdt_ptr == NULL) {
385*927a453eSwentaoy 		return (DDI_FAILURE);
386*927a453eSwentaoy 	}
387*927a453eSwentaoy 
388*927a453eSwentaoy 	switch (cmd) {
389*927a453eSwentaoy 	case DDI_SUSPEND:
390*927a453eSwentaoy 		return (DDI_SUCCESS);
391*927a453eSwentaoy 
392*927a453eSwentaoy 	case DDI_DETACH:
393*927a453eSwentaoy 		/*
394*927a453eSwentaoy 		 * release resources in opposite (LIFO) order as
395*927a453eSwentaoy 		 * were allocated in attach.
396*927a453eSwentaoy 		 */
397*927a453eSwentaoy 		ddi_remove_minor_node(dip, NULL);
398*927a453eSwentaoy 		ntwdt_stop_timer_lock((void *)ntwdt_ptr);
399*927a453eSwentaoy 		ddi_remove_softintr(ntwdt_cyclic_softint_id);
400*927a453eSwentaoy 
401*927a453eSwentaoy 		mutex_destroy(
402*927a453eSwentaoy 			&ntwdt_ptr->ntwdt_run_state->ntwdt_runstate_mutex);
403*927a453eSwentaoy 		kmem_free(ntwdt_ptr->ntwdt_run_state,
404*927a453eSwentaoy 			sizeof (ntwdt_runstate_t));
405*927a453eSwentaoy 		ntwdt_ptr->ntwdt_run_state = NULL;
406*927a453eSwentaoy 
407*927a453eSwentaoy 		mutex_destroy(&ntwdt_ptr->ntwdt_mutex);
408*927a453eSwentaoy 
409*927a453eSwentaoy 		ddi_soft_state_free(ntwdt_statep, instance);
410*927a453eSwentaoy 
411*927a453eSwentaoy 		ntwdt_dip = NULL;
412*927a453eSwentaoy 		return (DDI_SUCCESS);
413*927a453eSwentaoy 
414*927a453eSwentaoy 	default:
415*927a453eSwentaoy 		return (DDI_FAILURE);
416*927a453eSwentaoy 	}
417*927a453eSwentaoy }
418*927a453eSwentaoy 
419*927a453eSwentaoy /*ARGSUSED*/
420*927a453eSwentaoy static int
421*927a453eSwentaoy ntwdt_open(dev_t *devp, int flag, int otyp, cred_t *credp)
422*927a453eSwentaoy {
423*927a453eSwentaoy 	int instance = getminor(*devp);
424*927a453eSwentaoy 	int retval = 0;
425*927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = getstate(instance);
426*927a453eSwentaoy 
427*927a453eSwentaoy 	if (ntwdt_ptr == NULL) {
428*927a453eSwentaoy 		return (ENXIO);
429*927a453eSwentaoy 	}
430*927a453eSwentaoy 
431*927a453eSwentaoy 	/*
432*927a453eSwentaoy 	 * ensure caller is a priviledged process.
433*927a453eSwentaoy 	 */
434*927a453eSwentaoy 	if (drv_priv(credp) != 0) {
435*927a453eSwentaoy 		return (EPERM);
436*927a453eSwentaoy 	}
437*927a453eSwentaoy 
438*927a453eSwentaoy 	mutex_enter(&ntwdt_ptr->ntwdt_mutex);
439*927a453eSwentaoy 	if (ntwdt_ptr->ntwdt_open_flag) {
440*927a453eSwentaoy 		retval = EAGAIN;
441*927a453eSwentaoy 	} else {
442*927a453eSwentaoy 		ntwdt_ptr->ntwdt_open_flag = 1;
443*927a453eSwentaoy 	}
444*927a453eSwentaoy 	mutex_exit(&ntwdt_ptr->ntwdt_mutex);
445*927a453eSwentaoy 
446*927a453eSwentaoy 	return (retval);
447*927a453eSwentaoy }
448*927a453eSwentaoy 
449*927a453eSwentaoy /*ARGSUSED*/
450*927a453eSwentaoy static int
451*927a453eSwentaoy ntwdt_close(dev_t dev, int flag, int otyp, cred_t *credp)
452*927a453eSwentaoy {
453*927a453eSwentaoy 	int instance = getminor(dev);
454*927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = getstate(instance);
455*927a453eSwentaoy 
456*927a453eSwentaoy 	if (ntwdt_ptr == NULL) {
457*927a453eSwentaoy 		return (ENXIO);
458*927a453eSwentaoy 	}
459*927a453eSwentaoy 
460*927a453eSwentaoy 	mutex_enter(&ntwdt_ptr->ntwdt_mutex);
461*927a453eSwentaoy 	ntwdt_ptr->ntwdt_open_flag = 0;
462*927a453eSwentaoy 	mutex_exit(&ntwdt_ptr->ntwdt_mutex);
463*927a453eSwentaoy 
464*927a453eSwentaoy 	return (0);
465*927a453eSwentaoy }
466*927a453eSwentaoy 
467*927a453eSwentaoy /*ARGSUSED*/
468*927a453eSwentaoy static int
469*927a453eSwentaoy ntwdt_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
470*927a453eSwentaoy 	int *rvalp)
471*927a453eSwentaoy {
472*927a453eSwentaoy 	int instance = getminor(dev);
473*927a453eSwentaoy 	int retval = 0;
474*927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = NULL;
475*927a453eSwentaoy 	ntwdt_runstate_t *ntwdt_state;
476*927a453eSwentaoy 	lom_dogstate_t lom_dogstate;
477*927a453eSwentaoy 	lom_dogctl_t lom_dogctl;
478*927a453eSwentaoy 	uint32_t lom_dogtime;
479*927a453eSwentaoy 
480*927a453eSwentaoy 	if ((ntwdt_ptr = getstate(instance)) == NULL) {
481*927a453eSwentaoy 		return (ENXIO);
482*927a453eSwentaoy 	}
483*927a453eSwentaoy 
484*927a453eSwentaoy 	ntwdt_state = ntwdt_ptr->ntwdt_run_state;
485*927a453eSwentaoy 
486*927a453eSwentaoy 	switch (cmd) {
487*927a453eSwentaoy 	case LOMIOCDOGSTATE:
488*927a453eSwentaoy 		mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
489*927a453eSwentaoy 		lom_dogstate.reset_enable = ntwdt_state->ntwdt_reset_enabled;
490*927a453eSwentaoy 		lom_dogstate.dog_enable = ntwdt_state->ntwdt_watchdog_enabled;
491*927a453eSwentaoy 		lom_dogstate.dog_timeout = ntwdt_state->ntwdt_watchdog_timeout;
492*927a453eSwentaoy 		mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
493*927a453eSwentaoy 
494*927a453eSwentaoy 		if (ddi_copyout((caddr_t)&lom_dogstate, (caddr_t)arg,
495*927a453eSwentaoy 			sizeof (lom_dogstate_t), mode) != 0) {
496*927a453eSwentaoy 			retval = EFAULT;
497*927a453eSwentaoy 		}
498*927a453eSwentaoy 		break;
499*927a453eSwentaoy 
500*927a453eSwentaoy 	case LOMIOCDOGCTL:
501*927a453eSwentaoy 		if (ddi_copyin((caddr_t)arg, (caddr_t)&lom_dogctl,
502*927a453eSwentaoy 			sizeof (lom_dogctl_t), mode) != 0) {
503*927a453eSwentaoy 			retval = EFAULT;
504*927a453eSwentaoy 			break;
505*927a453eSwentaoy 		}
506*927a453eSwentaoy 
507*927a453eSwentaoy 		NTWDT_DBG(NTWDT_DBG_IOCTL, ("reset_enable: %d, and dog_enable: "
508*927a453eSwentaoy 			"%d, watchdog_timeout %d", lom_dogctl.reset_enable,
509*927a453eSwentaoy 			lom_dogctl.dog_enable,
510*927a453eSwentaoy 			ntwdt_state->ntwdt_watchdog_timeout));
511*927a453eSwentaoy 		/*
512*927a453eSwentaoy 		 * ignore request to enable reset while disabling watchdog.
513*927a453eSwentaoy 		 */
514*927a453eSwentaoy 		if (!lom_dogctl.dog_enable && lom_dogctl.reset_enable) {
515*927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("invalid combination of "
516*927a453eSwentaoy 				"reset_enable: %d, and dog_enable: %d",
517*927a453eSwentaoy 				lom_dogctl.reset_enable,
518*927a453eSwentaoy 				lom_dogctl.dog_enable));
519*927a453eSwentaoy 			retval = EINVAL;
520*927a453eSwentaoy 			break;
521*927a453eSwentaoy 		}
522*927a453eSwentaoy 
523*927a453eSwentaoy 		mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
524*927a453eSwentaoy 
525*927a453eSwentaoy 		if (ntwdt_state->ntwdt_watchdog_timeout == 0) {
526*927a453eSwentaoy 			/*
527*927a453eSwentaoy 			 * the LOMIOCDOGTIME has never been used to setup
528*927a453eSwentaoy 			 * a valid timeout.
529*927a453eSwentaoy 			 */
530*927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("timeout has not been set"
531*927a453eSwentaoy 				"watchdog_timeout: %d",
532*927a453eSwentaoy 				ntwdt_state->ntwdt_watchdog_timeout));
533*927a453eSwentaoy 			retval = EINVAL;
534*927a453eSwentaoy 			goto end;
535*927a453eSwentaoy 		}
536*927a453eSwentaoy 
537*927a453eSwentaoy 		/*
538*927a453eSwentaoy 		 * Store the user specified state in the softstate.
539*927a453eSwentaoy 		 */
540*927a453eSwentaoy 		ntwdt_state->ntwdt_reset_enabled = lom_dogctl.reset_enable;
541*927a453eSwentaoy 		ntwdt_state->ntwdt_watchdog_enabled = lom_dogctl.dog_enable;
542*927a453eSwentaoy 
543*927a453eSwentaoy 		if (ntwdt_state->ntwdt_watchdog_enabled != 0) {
544*927a453eSwentaoy 			/*
545*927a453eSwentaoy 			 * The user wants to enable the watchdog.
546*927a453eSwentaoy 			 * Arm the watchdog and start the cyclic.
547*927a453eSwentaoy 			 */
548*927a453eSwentaoy 			ntwdt_arm_watchdog(ntwdt_state);
549*927a453eSwentaoy 
550*927a453eSwentaoy 			if (ntwdt_state->ntwdt_timer_running == 0) {
551*927a453eSwentaoy 				ntwdt_start_timer(ntwdt_ptr);
552*927a453eSwentaoy 			}
553*927a453eSwentaoy 
554*927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("AWDT is enabled"));
555*927a453eSwentaoy 		} else {
556*927a453eSwentaoy 			/*
557*927a453eSwentaoy 			 * The user wants to disable the watchdog.
558*927a453eSwentaoy 			 */
559*927a453eSwentaoy 			if (ntwdt_state->ntwdt_timer_running != 0) {
560*927a453eSwentaoy 				ntwdt_stop_timer(ntwdt_ptr);
561*927a453eSwentaoy 			}
562*927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("AWDT is disabled"));
563*927a453eSwentaoy 		}
564*927a453eSwentaoy 
565*927a453eSwentaoy 		mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
566*927a453eSwentaoy 		break;
567*927a453eSwentaoy 
568*927a453eSwentaoy 	case LOMIOCDOGTIME:
569*927a453eSwentaoy 		if (ddi_copyin((caddr_t)arg, (caddr_t)&lom_dogtime,
570*927a453eSwentaoy 			sizeof (uint32_t), mode) != 0) {
571*927a453eSwentaoy 			retval = EFAULT;
572*927a453eSwentaoy 			break;
573*927a453eSwentaoy 		}
574*927a453eSwentaoy 
575*927a453eSwentaoy 		NTWDT_DBG(NTWDT_DBG_IOCTL, ("user set timeout: %d",
576*927a453eSwentaoy 			lom_dogtime));
577*927a453eSwentaoy 
578*927a453eSwentaoy 		/*
579*927a453eSwentaoy 		 * Ensure specified timeout is valid.
580*927a453eSwentaoy 		 */
581*927a453eSwentaoy 		if ((lom_dogtime == 0) ||
582*927a453eSwentaoy 			(lom_dogtime > (uint32_t)NTWDT_MAX_TIMEOUT)) {
583*927a453eSwentaoy 			retval = EINVAL;
584*927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("user set invalid "
585*927a453eSwentaoy 				"timeout: %d", (int)TICK_TO_MSEC(lom_dogtime)));
586*927a453eSwentaoy 			break;
587*927a453eSwentaoy 		}
588*927a453eSwentaoy 
589*927a453eSwentaoy 		mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
590*927a453eSwentaoy 
591*927a453eSwentaoy 		ntwdt_state->ntwdt_watchdog_timeout = lom_dogtime;
592*927a453eSwentaoy 
593*927a453eSwentaoy 		/*
594*927a453eSwentaoy 		 * If awdt is currently running, re-arm it with the
595*927a453eSwentaoy 		 * newly-specified timeout value.
596*927a453eSwentaoy 		 */
597*927a453eSwentaoy 		if (ntwdt_state->ntwdt_timer_running != 0) {
598*927a453eSwentaoy 			ntwdt_arm_watchdog(ntwdt_state);
599*927a453eSwentaoy 		}
600*927a453eSwentaoy 		mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
601*927a453eSwentaoy 		break;
602*927a453eSwentaoy 
603*927a453eSwentaoy 	case LOMIOCDOGPAT:
604*927a453eSwentaoy 		/*
605*927a453eSwentaoy 		 * Allow user to pat the watchdog timer.
606*927a453eSwentaoy 		 */
607*927a453eSwentaoy 		NTWDT_DBG(NTWDT_DBG_IOCTL, ("DOGPAT is invoked"));
608*927a453eSwentaoy 		mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
609*927a453eSwentaoy 
610*927a453eSwentaoy 		/*
611*927a453eSwentaoy 		 * If awdt is not enabled or underlying cyclic is not
612*927a453eSwentaoy 		 * running, exit.
613*927a453eSwentaoy 		 */
614*927a453eSwentaoy 		if (!(ntwdt_state->ntwdt_watchdog_enabled &&
615*927a453eSwentaoy 			ntwdt_state->ntwdt_timer_running)) {
616*927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("PAT: AWDT not enabled"));
617*927a453eSwentaoy 			goto end;
618*927a453eSwentaoy 		}
619*927a453eSwentaoy 
620*927a453eSwentaoy 		if (ntwdt_state->ntwdt_watchdog_expired == 0) {
621*927a453eSwentaoy 			/*
622*927a453eSwentaoy 			 * re-arm the awdt.
623*927a453eSwentaoy 			 */
624*927a453eSwentaoy 			ntwdt_arm_watchdog(ntwdt_state);
625*927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("AWDT patted, "
626*927a453eSwentaoy 				"remainning seconds: %d",
627*927a453eSwentaoy 				ntwdt_state->ntwdt_time_remaining));
628*927a453eSwentaoy 		}
629*927a453eSwentaoy 
630*927a453eSwentaoy 		mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
631*927a453eSwentaoy 		break;
632*927a453eSwentaoy 
633*927a453eSwentaoy 	default:
634*927a453eSwentaoy 		retval = EINVAL;
635*927a453eSwentaoy 		break;
636*927a453eSwentaoy 	}
637*927a453eSwentaoy 	return (retval);
638*927a453eSwentaoy end:
639*927a453eSwentaoy 	mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
640*927a453eSwentaoy 	return (retval);
641*927a453eSwentaoy }
642*927a453eSwentaoy 
643*927a453eSwentaoy static void
644*927a453eSwentaoy ntwdt_cyclic_pat(void)
645*927a453eSwentaoy {
646*927a453eSwentaoy 	ddi_trigger_softintr(ntwdt_cyclic_softint_id);
647*927a453eSwentaoy }
648*927a453eSwentaoy 
649*927a453eSwentaoy static uint_t
650*927a453eSwentaoy ntwdt_cyclic_softint(caddr_t arg)
651*927a453eSwentaoy {
652*927a453eSwentaoy 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
653*927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = (ntwdt_state_t *)arg;
654*927a453eSwentaoy 	ntwdt_runstate_t *ntwdt_state;
655*927a453eSwentaoy 
656*927a453eSwentaoy 	ntwdt_state = ntwdt_ptr->ntwdt_run_state;
657*927a453eSwentaoy 
658*927a453eSwentaoy 	mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
659*927a453eSwentaoy 
660*927a453eSwentaoy 	if ((ntwdt_state->ntwdt_watchdog_flags & NTWDT_FLAG_SKIP_CYCLIC) != 0) {
661*927a453eSwentaoy 		ntwdt_state->ntwdt_watchdog_flags &= ~NTWDT_FLAG_SKIP_CYCLIC;
662*927a453eSwentaoy 		goto end;
663*927a453eSwentaoy 	}
664*927a453eSwentaoy 
665*927a453eSwentaoy 	if ((ntwdt_state->ntwdt_timer_running == 0) ||
666*927a453eSwentaoy 		(ntwdt_ptr->ntwdt_cycl_id == CYCLIC_NONE) ||
667*927a453eSwentaoy 		(ntwdt_state->ntwdt_watchdog_enabled == 0)) {
668*927a453eSwentaoy 		goto end;
669*927a453eSwentaoy 	}
670*927a453eSwentaoy 
671*927a453eSwentaoy 	NTWDT_DBG(NTWDT_DBG_IOCTL, ("cyclic_softint: %d"
672*927a453eSwentaoy 		"lbolt64: %d\n", ntwdt_state->ntwdt_watchdog_timeout,
673*927a453eSwentaoy 		(int)TICK_TO_MSEC(lbolt64)));
674*927a453eSwentaoy 
675*927a453eSwentaoy 	/*
676*927a453eSwentaoy 	 * Decrement the virtual watchdog timer and check if it has expired.
677*927a453eSwentaoy 	 */
678*927a453eSwentaoy 	ntwdt_state->ntwdt_time_remaining -= NTWDT_DECREMENT_INTERVAL;
679*927a453eSwentaoy 
680*927a453eSwentaoy 	if (ntwdt_state->ntwdt_time_remaining == 0) {
681*927a453eSwentaoy 		cmn_err(CE_WARN, "application-watchdog expired");
682*927a453eSwentaoy 		ntwdt_state->ntwdt_watchdog_expired = 1;
683*927a453eSwentaoy 
684*927a453eSwentaoy 		if (ntwdt_state->ntwdt_reset_enabled != 0) {
685*927a453eSwentaoy 			/*
686*927a453eSwentaoy 			 * The user wants to reset the system.
687*927a453eSwentaoy 			 */
688*927a453eSwentaoy 			mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
689*927a453eSwentaoy 
690*927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_NTWDT, ("recovery being done"));
691*927a453eSwentaoy 			ntwdt_enforce_timeout();
692*927a453eSwentaoy 		} else {
693*927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_NTWDT, ("no recovery being done"));
694*927a453eSwentaoy 			ntwdt_state->ntwdt_watchdog_enabled = 0;
695*927a453eSwentaoy 		}
696*927a453eSwentaoy 
697*927a453eSwentaoy 		/*
698*927a453eSwentaoy 		 * Schedule Callout to stop the cyclic.
699*927a453eSwentaoy 		 */
700*927a453eSwentaoy 		(void) timeout(ntwdt_stop_timer_lock, ntwdt_ptr, 0);
701*927a453eSwentaoy 	} else {
702*927a453eSwentaoy 		_NOTE(EMPTY)
703*927a453eSwentaoy 		NTWDT_DBG(NTWDT_DBG_NTWDT, ("time remaining in AWDT: %d secs",
704*927a453eSwentaoy 			(int)TICK_TO_MSEC(ntwdt_state->ntwdt_time_remaining)));
705*927a453eSwentaoy 	}
706*927a453eSwentaoy 
707*927a453eSwentaoy end:
708*927a453eSwentaoy 	mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
709*927a453eSwentaoy 	return (DDI_INTR_CLAIMED);
710*927a453eSwentaoy }
711*927a453eSwentaoy 
712*927a453eSwentaoy static void
713*927a453eSwentaoy ntwdt_arm_watchdog(ntwdt_runstate_t *ntwdt_state)
714*927a453eSwentaoy {
715*927a453eSwentaoy 	ntwdt_state->ntwdt_time_remaining = ntwdt_state->ntwdt_watchdog_timeout;
716*927a453eSwentaoy 
717*927a453eSwentaoy 	if (ntwdt_state->ntwdt_timer_running != 0) {
718*927a453eSwentaoy 		ntwdt_state->ntwdt_watchdog_flags |= NTWDT_FLAG_SKIP_CYCLIC;
719*927a453eSwentaoy 	} else {
720*927a453eSwentaoy 		ntwdt_state->ntwdt_watchdog_flags &= ~NTWDT_FLAG_SKIP_CYCLIC;
721*927a453eSwentaoy 	}
722*927a453eSwentaoy }
723*927a453eSwentaoy 
724*927a453eSwentaoy static void
725*927a453eSwentaoy ntwdt_start_timer(ntwdt_state_t *ntwdt_ptr)
726*927a453eSwentaoy {
727*927a453eSwentaoy 	ntwdt_runstate_t	*ntwdt_state = ntwdt_ptr->ntwdt_run_state;
728*927a453eSwentaoy 	cyc_handler_t		*hdlr = &ntwdt_state->ntwdt_cycl_hdlr;
729*927a453eSwentaoy 	cyc_time_t		*when = &ntwdt_state->ntwdt_cycl_time;
730*927a453eSwentaoy 
731*927a453eSwentaoy 	/*
732*927a453eSwentaoy 	 * Init the cyclic.
733*927a453eSwentaoy 	 */
734*927a453eSwentaoy 	when->cyt_interval = ntwdt_state->ntwdt_cyclic_interval;
735*927a453eSwentaoy 	when->cyt_when = gethrtime() + when->cyt_interval;
736*927a453eSwentaoy 
737*927a453eSwentaoy 	ntwdt_state->ntwdt_watchdog_expired = 0;
738*927a453eSwentaoy 	ntwdt_state->ntwdt_timer_running = 1;
739*927a453eSwentaoy 
740*927a453eSwentaoy 	mutex_enter(&cpu_lock);
741*927a453eSwentaoy 	if (ntwdt_ptr->ntwdt_cycl_id == CYCLIC_NONE) {
742*927a453eSwentaoy 		ntwdt_ptr->ntwdt_cycl_id = cyclic_add(hdlr, when);
743*927a453eSwentaoy 	}
744*927a453eSwentaoy 	mutex_exit(&cpu_lock);
745*927a453eSwentaoy 
746*927a453eSwentaoy 	NTWDT_DBG(NTWDT_DBG_NTWDT, ("cyclic-driven timer is started"));
747*927a453eSwentaoy }
748*927a453eSwentaoy 
749*927a453eSwentaoy static void
750*927a453eSwentaoy ntwdt_stop_timer(void *arg)
751*927a453eSwentaoy {
752*927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = (ntwdt_state_t *)arg;
753*927a453eSwentaoy 	ntwdt_runstate_t *ntwdt_state = ntwdt_ptr->ntwdt_run_state;
754*927a453eSwentaoy 
755*927a453eSwentaoy 	mutex_enter(&cpu_lock);
756*927a453eSwentaoy 	if (ntwdt_ptr->ntwdt_cycl_id != CYCLIC_NONE) {
757*927a453eSwentaoy 		cyclic_remove(ntwdt_ptr->ntwdt_cycl_id);
758*927a453eSwentaoy 	}
759*927a453eSwentaoy 	mutex_exit(&cpu_lock);
760*927a453eSwentaoy 
761*927a453eSwentaoy 	ntwdt_state->ntwdt_watchdog_flags = 0;
762*927a453eSwentaoy 	ntwdt_state->ntwdt_timer_running = 0;
763*927a453eSwentaoy 	ntwdt_ptr->ntwdt_cycl_id = CYCLIC_NONE;
764*927a453eSwentaoy 
765*927a453eSwentaoy 	NTWDT_DBG(NTWDT_DBG_NTWDT, ("cyclic-driven timer is stopped"));
766*927a453eSwentaoy }
767*927a453eSwentaoy 
768*927a453eSwentaoy /*
769*927a453eSwentaoy  * This is a wrapper function for ntwdt_stop_timer as some callers
770*927a453eSwentaoy  * will already have the appropriate mutex locked, and others not.
771*927a453eSwentaoy  */
772*927a453eSwentaoy static void
773*927a453eSwentaoy ntwdt_stop_timer_lock(void *arg)
774*927a453eSwentaoy {
775*927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = (ntwdt_state_t *)arg;
776*927a453eSwentaoy 
777*927a453eSwentaoy 	mutex_enter(&ntwdt_ptr->ntwdt_run_state->ntwdt_runstate_mutex);
778*927a453eSwentaoy 	ntwdt_stop_timer(arg);
779*927a453eSwentaoy 	mutex_exit(&ntwdt_ptr->ntwdt_run_state->ntwdt_runstate_mutex);
780*927a453eSwentaoy }
781*927a453eSwentaoy 
782*927a453eSwentaoy static void
783*927a453eSwentaoy ntwdt_enforce_timeout()
784*927a453eSwentaoy {
785*927a453eSwentaoy 	if (ntwdt_disable_timeout_action != 0) {
786*927a453eSwentaoy 		cmn_err(CE_NOTE, "Appication watchdog timer expired, "
787*927a453eSwentaoy 			"taking no action");
788*927a453eSwentaoy 		return;
789*927a453eSwentaoy 	}
790*927a453eSwentaoy 
791*927a453eSwentaoy 	NTWDT_DBG(NTWDT_DBG_NTWDT, ("dump cores and rebooting ..."));
792*927a453eSwentaoy 
793*927a453eSwentaoy 	(void) kadmin(A_DUMP, AD_BOOT, NULL, kcred);
794*927a453eSwentaoy 	cmn_err(CE_PANIC, "kadmin(A_DUMP, AD_BOOT) failed");
795*927a453eSwentaoy 	_NOTE(NOTREACHED);
796*927a453eSwentaoy }
797*927a453eSwentaoy 
798*927a453eSwentaoy static int
799*927a453eSwentaoy ntwdt_chk_watchdog_support()
800*927a453eSwentaoy {
801*927a453eSwentaoy 	int	retval = 0;
802*927a453eSwentaoy 
803*927a453eSwentaoy 	if ((boothowto & RB_DEBUG) != 0) {
804*927a453eSwentaoy 		cmn_err(CE_WARN, "kernel debugger was booted; "
805*927a453eSwentaoy 		    "application watchdog is not available.");
806*927a453eSwentaoy 		retval = ENOTSUP;
807*927a453eSwentaoy 	}
808*927a453eSwentaoy 	return (retval);
809*927a453eSwentaoy }
810