xref: /titanic_50/usr/src/uts/sun4v/io/ntwdt.c (revision d3d50737e566cade9a08d73d2af95105ac7cd960)
1927a453eSwentaoy /*
2927a453eSwentaoy  * CDDL HEADER START
3927a453eSwentaoy  *
4927a453eSwentaoy  * The contents of this file are subject to the terms of the
5927a453eSwentaoy  * Common Development and Distribution License (the "License").
6927a453eSwentaoy  * You may not use this file except in compliance with the License.
7927a453eSwentaoy  *
8927a453eSwentaoy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9927a453eSwentaoy  * or http://www.opensolaris.org/os/licensing.
10927a453eSwentaoy  * See the License for the specific language governing permissions
11927a453eSwentaoy  * and limitations under the License.
12927a453eSwentaoy  *
13927a453eSwentaoy  * When distributing Covered Code, include this CDDL HEADER in each
14927a453eSwentaoy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15927a453eSwentaoy  * If applicable, add the following below this CDDL HEADER, with the
16927a453eSwentaoy  * fields enclosed by brackets "[]" replaced with your own identifying
17927a453eSwentaoy  * information: Portions Copyright [yyyy] [name of copyright owner]
18927a453eSwentaoy  *
19927a453eSwentaoy  * CDDL HEADER END
20927a453eSwentaoy  */
21927a453eSwentaoy /*
22*d3d50737SRafael Vanoni  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23927a453eSwentaoy  * Use is subject to license terms.
24927a453eSwentaoy  */
25927a453eSwentaoy 
26927a453eSwentaoy /*
27927a453eSwentaoy  * sun4v application watchdog driver
28927a453eSwentaoy  */
29927a453eSwentaoy 
30927a453eSwentaoy #include <sys/types.h>
31927a453eSwentaoy #include <sys/file.h>
32927a453eSwentaoy #include <sys/errno.h>
33927a453eSwentaoy #include <sys/open.h>
34927a453eSwentaoy #include <sys/callb.h>
35927a453eSwentaoy #include <sys/cred.h>
36927a453eSwentaoy #include <sys/cyclic.h>
37927a453eSwentaoy #include <sys/uio.h>
38927a453eSwentaoy #include <sys/stat.h>
39927a453eSwentaoy #include <sys/ksynch.h>
40927a453eSwentaoy #include <sys/modctl.h>
41927a453eSwentaoy #include <sys/conf.h>
42927a453eSwentaoy #include <sys/devops.h>
43927a453eSwentaoy #include <sys/debug.h>
44927a453eSwentaoy #include <sys/cmn_err.h>
45927a453eSwentaoy #include <sys/ddi.h>
46927a453eSwentaoy #include <sys/reboot.h>
47927a453eSwentaoy #include <sys/sunddi.h>
48927a453eSwentaoy #include <sys/signal.h>
49927a453eSwentaoy #include <sys/ntwdt.h>
50927a453eSwentaoy #include <sys/note.h>
51927a453eSwentaoy 
52927a453eSwentaoy /*
53927a453eSwentaoy  * tunables
54927a453eSwentaoy  */
55927a453eSwentaoy int ntwdt_disable_timeout_action = 0;
56927a453eSwentaoy 
57927a453eSwentaoy #ifdef DEBUG
58927a453eSwentaoy 
59927a453eSwentaoy int ntwdt_debug = 0;		/* ntwdt debug flag, dbg all for now. */
60927a453eSwentaoy 
61927a453eSwentaoy /*
62927a453eSwentaoy  * Flags to set in ntwdt_debug.
63927a453eSwentaoy  */
64927a453eSwentaoy #define	NTWDT_DBG_ENTRY	0x00000001	/* drv entry points */
65927a453eSwentaoy #define	NTWDT_DBG_IOCTL	0x00000002	/* ioctl's */
66927a453eSwentaoy #define	NTWDT_DBG_NTWDT	0x00000004	/* other ntwdt debug */
67927a453eSwentaoy 
68927a453eSwentaoy #define	NTWDT_DBG(flag, msg) \
69927a453eSwentaoy 	{ if ((ntwdt_debug) & (flag)) (void) printf msg; }
70927a453eSwentaoy #else	/* DEBUG */
71927a453eSwentaoy #define	NTWDT_DBG(flag, msg)
72927a453eSwentaoy #endif	/* DEBUG */
73927a453eSwentaoy 
74927a453eSwentaoy #define	NTWDT_MINOR_NODE	"awdt"
75927a453eSwentaoy #define	getstate(minor)	\
76927a453eSwentaoy 	((ntwdt_state_t *)ddi_get_soft_state(ntwdt_statep, (minor)))
77927a453eSwentaoy 
78927a453eSwentaoy /*
79927a453eSwentaoy  * The ntwdt cyclic interval in nanosecond unit as cyclic subsystem supports
80927a453eSwentaoy  * nanosecond resolution.
81927a453eSwentaoy  */
82927a453eSwentaoy #define	NTWDT_CYCLIC_INTERVAL	NANOSEC	/* 1 seconds */
83927a453eSwentaoy 
84927a453eSwentaoy /*
85927a453eSwentaoy  * The ntwdt decrement interval in 1 second resolution.
86927a453eSwentaoy  */
87927a453eSwentaoy #define	NTWDT_DECREMENT_INTERVAL	1	/* 1 second */
88927a453eSwentaoy 
89927a453eSwentaoy /*
90927a453eSwentaoy  * ntwdt_watchdog_flags and macros to set/clear one bit in it.
91927a453eSwentaoy  */
92927a453eSwentaoy #define	NTWDT_FLAG_SKIP_CYCLIC	0x1	/* skip next cyclic */
93927a453eSwentaoy 
94927a453eSwentaoy #define	NTWDT_MAX_TIMEOUT	(3 * 60 * 60)	/* 3 hours */
95927a453eSwentaoy 
96927a453eSwentaoy #define	WDT_MIN_COREAPI_MAJOR	1
97927a453eSwentaoy #define	WDT_MIN_COREAPI_MINOR	1
98927a453eSwentaoy 
99927a453eSwentaoy /*
100927a453eSwentaoy  * Application watchdog state.
101927a453eSwentaoy  */
102927a453eSwentaoy typedef struct ntwdt_runstate {
103927a453eSwentaoy 	kmutex_t		ntwdt_runstate_mutex;
104927a453eSwentaoy 	ddi_iblock_cookie_t	ntwdt_runstate_mtx_cookie;
105927a453eSwentaoy 	int			ntwdt_watchdog_enabled;	/* wdog enabled ? */
106927a453eSwentaoy 	int			ntwdt_reset_enabled;	/* reset enabled ? */
107927a453eSwentaoy 	int			ntwdt_timer_running;	/* wdog running ? */
108927a453eSwentaoy 	int			ntwdt_watchdog_expired;	/* wdog expired ? */
109927a453eSwentaoy 	uint32_t		ntwdt_time_remaining;	/* expiration timer */
110927a453eSwentaoy 	uint32_t		ntwdt_watchdog_timeout;	/* timeout in seconds */
111927a453eSwentaoy 	hrtime_t		ntwdt_cyclic_interval;	/* cyclic interval */
112927a453eSwentaoy 	cyc_handler_t		ntwdt_cycl_hdlr;
113927a453eSwentaoy 	cyc_time_t		ntwdt_cycl_time;
114927a453eSwentaoy 	uint32_t		ntwdt_watchdog_flags;
115927a453eSwentaoy } ntwdt_runstate_t;
116927a453eSwentaoy 
117927a453eSwentaoy /*
118927a453eSwentaoy  * softstate of NTWDT
119927a453eSwentaoy  */
120927a453eSwentaoy typedef struct {
121927a453eSwentaoy 	kmutex_t		ntwdt_mutex;
122927a453eSwentaoy 	dev_info_t		*ntwdt_dip;		/* dip */
123927a453eSwentaoy 	int			ntwdt_open_flag;	/* file open ? */
124927a453eSwentaoy 	ntwdt_runstate_t	*ntwdt_run_state;	/* wdog state */
125927a453eSwentaoy 	cyclic_id_t		ntwdt_cycl_id;
126927a453eSwentaoy } ntwdt_state_t;
127927a453eSwentaoy 
128927a453eSwentaoy static void *ntwdt_statep;	/* softstate */
129927a453eSwentaoy static dev_info_t *ntwdt_dip;
130927a453eSwentaoy 
131927a453eSwentaoy static ddi_softintr_t	ntwdt_cyclic_softint_id;
132927a453eSwentaoy 
133927a453eSwentaoy static int ntwdt_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
134927a453eSwentaoy static int ntwdt_attach(dev_info_t *, ddi_attach_cmd_t);
135927a453eSwentaoy static int ntwdt_detach(dev_info_t *, ddi_detach_cmd_t);
136927a453eSwentaoy static int ntwdt_open(dev_t *, int, int, cred_t *);
137927a453eSwentaoy static int ntwdt_close(dev_t, int, int, cred_t *);
138927a453eSwentaoy static int ntwdt_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
139927a453eSwentaoy 
140927a453eSwentaoy static int ntwdt_chk_watchdog_support();
141927a453eSwentaoy static void ntwdt_arm_watchdog(ntwdt_runstate_t *ntwdt_state);
142927a453eSwentaoy static void ntwdt_cyclic_pat(void);
143927a453eSwentaoy static uint_t ntwdt_cyclic_softint(caddr_t arg);
144927a453eSwentaoy static void ntwdt_start_timer(ntwdt_state_t *ntwdt_ptr);
145927a453eSwentaoy static void ntwdt_stop_timer_lock(void *arg);
146927a453eSwentaoy static void ntwdt_stop_timer(void *arg);
147927a453eSwentaoy static void ntwdt_enforce_timeout();
148927a453eSwentaoy 
149927a453eSwentaoy static struct cb_ops ntwdt_cb_ops = {
150927a453eSwentaoy 	ntwdt_open,		/* cb_open */
151927a453eSwentaoy 	ntwdt_close,		/* cb_close */
152927a453eSwentaoy 	nodev,			/* cb_strategy */
153927a453eSwentaoy 	nodev,			/* cb_print */
154927a453eSwentaoy 	nodev,			/* cb_dump */
155927a453eSwentaoy 	nodev,			/* cb_read */
156927a453eSwentaoy 	nodev,			/* cb_write */
157927a453eSwentaoy 	ntwdt_ioctl,		/* cb_ioctl */
158927a453eSwentaoy 	nodev,			/* cb_devmap */
159927a453eSwentaoy 	nodev,			/* cb_mmap */
160927a453eSwentaoy 	nodev,			/* cb_segmap */
161927a453eSwentaoy 	nochpoll,		/* cb_chpoll */
162927a453eSwentaoy 	ddi_prop_op,		/* cb_prop_op */
163927a453eSwentaoy 	NULL,			/* cb_str */
164927a453eSwentaoy 	D_NEW | D_MP		/* cb_flag */
165927a453eSwentaoy };
166927a453eSwentaoy 
167927a453eSwentaoy static struct dev_ops ntwdt_dev_ops = {
168927a453eSwentaoy 	DEVO_REV,		/* devo_rev */
169927a453eSwentaoy 	0,			/* devo_refcnt */
170927a453eSwentaoy 	ntwdt_info,		/* devo_info */
171927a453eSwentaoy 	nulldev,		/* devo_identify */
172927a453eSwentaoy 	nulldev,		/* devo_probe */
173927a453eSwentaoy 	ntwdt_attach,		/* devo_attach */
174927a453eSwentaoy 	ntwdt_detach,		/* devo_detach */
175927a453eSwentaoy 	nodev,			/* devo_reset */
176927a453eSwentaoy 	&ntwdt_cb_ops,		/* devo_cb_ops */
177927a453eSwentaoy 	NULL,			/* devo_bus_ops */
17819397407SSherry Moore 	nulldev,		/* devo_power */
17919397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
180927a453eSwentaoy };
181927a453eSwentaoy 
182927a453eSwentaoy static struct modldrv modldrv = {
183927a453eSwentaoy 	&mod_driverops,
18419397407SSherry Moore 	"Application Watchdog Driver",
185927a453eSwentaoy 	&ntwdt_dev_ops
186927a453eSwentaoy };
187927a453eSwentaoy 
188927a453eSwentaoy static struct modlinkage modlinkage = {
189927a453eSwentaoy 	MODREV_1,
190927a453eSwentaoy 	(void *)&modldrv,
191927a453eSwentaoy 	NULL
192927a453eSwentaoy };
193927a453eSwentaoy 
194927a453eSwentaoy int
_init(void)195927a453eSwentaoy _init(void)
196927a453eSwentaoy {
197927a453eSwentaoy 	int error = 0;
198927a453eSwentaoy 
199927a453eSwentaoy 	NTWDT_DBG(NTWDT_DBG_ENTRY, ("_init"));
200927a453eSwentaoy 
201927a453eSwentaoy 	/* Initialize the soft state structures */
202927a453eSwentaoy 	if ((error = ddi_soft_state_init(&ntwdt_statep,
203927a453eSwentaoy 	    sizeof (ntwdt_state_t), 1)) != 0) {
204927a453eSwentaoy 		return (error);
205927a453eSwentaoy 	}
206927a453eSwentaoy 
207927a453eSwentaoy 	/* Install the loadable module */
208927a453eSwentaoy 	if ((error = mod_install(&modlinkage)) != 0) {
209927a453eSwentaoy 		ddi_soft_state_fini(&ntwdt_statep);
210927a453eSwentaoy 	}
211927a453eSwentaoy 	return (error);
212927a453eSwentaoy }
213927a453eSwentaoy 
214927a453eSwentaoy int
_info(struct modinfo * modinfop)215927a453eSwentaoy _info(struct modinfo *modinfop)
216927a453eSwentaoy {
217927a453eSwentaoy 	NTWDT_DBG(NTWDT_DBG_ENTRY, ("_info"));
218927a453eSwentaoy 
219927a453eSwentaoy 	return (mod_info(&modlinkage, modinfop));
220927a453eSwentaoy }
221927a453eSwentaoy 
222927a453eSwentaoy int
_fini(void)223927a453eSwentaoy _fini(void)
224927a453eSwentaoy {
225927a453eSwentaoy 	int retval;
226927a453eSwentaoy 
227927a453eSwentaoy 	NTWDT_DBG(NTWDT_DBG_ENTRY, ("_fini"));
228927a453eSwentaoy 
229927a453eSwentaoy 	if ((retval = mod_remove(&modlinkage)) == 0) {
230927a453eSwentaoy 		ddi_soft_state_fini(&ntwdt_statep);
231927a453eSwentaoy 	}
232927a453eSwentaoy 
233927a453eSwentaoy 	return (retval);
234927a453eSwentaoy }
235927a453eSwentaoy 
236927a453eSwentaoy static int
ntwdt_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)237927a453eSwentaoy ntwdt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
238927a453eSwentaoy {
239927a453eSwentaoy 	int instance;
240927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = NULL;	/* pointer to ntwdt_runstatep */
241927a453eSwentaoy 	ntwdt_runstate_t *ntwdt_runstatep = NULL;
242927a453eSwentaoy 	cyc_handler_t *hdlr = NULL;
243927a453eSwentaoy 
244927a453eSwentaoy 	switch (cmd) {
245927a453eSwentaoy 	case DDI_ATTACH:
246927a453eSwentaoy 		break;
247927a453eSwentaoy 
248927a453eSwentaoy 	case DDI_RESUME:
249927a453eSwentaoy 		return (DDI_SUCCESS);
250927a453eSwentaoy 
251927a453eSwentaoy 	default:
252927a453eSwentaoy 		return (DDI_FAILURE);
253927a453eSwentaoy 	}
254927a453eSwentaoy 
255927a453eSwentaoy 	if (ntwdt_chk_watchdog_support() != 0) {
256927a453eSwentaoy 		return (DDI_FAILURE);
257927a453eSwentaoy 	}
258927a453eSwentaoy 
259927a453eSwentaoy 	instance = ddi_get_instance(dip);
260927a453eSwentaoy 	ASSERT(instance == 0);
261927a453eSwentaoy 
262927a453eSwentaoy 	if (ddi_soft_state_zalloc(ntwdt_statep, instance) != DDI_SUCCESS) {
263927a453eSwentaoy 		return (DDI_FAILURE);
264927a453eSwentaoy 	}
265927a453eSwentaoy 	ntwdt_ptr = ddi_get_soft_state(ntwdt_statep, instance);
266927a453eSwentaoy 	ASSERT(ntwdt_ptr != NULL);
267927a453eSwentaoy 
268927a453eSwentaoy 	ntwdt_dip = dip;
269927a453eSwentaoy 
270927a453eSwentaoy 	ntwdt_ptr->ntwdt_dip = dip;
271927a453eSwentaoy 	ntwdt_ptr->ntwdt_cycl_id = CYCLIC_NONE;
272927a453eSwentaoy 	mutex_init(&ntwdt_ptr->ntwdt_mutex, NULL,
273927a453eSwentaoy 	    MUTEX_DRIVER, NULL);
274927a453eSwentaoy 
275927a453eSwentaoy 	/*
276927a453eSwentaoy 	 * Initialize the watchdog structure
277927a453eSwentaoy 	 */
278927a453eSwentaoy 	ntwdt_ptr->ntwdt_run_state =
279927a453eSwentaoy 	    kmem_zalloc(sizeof (ntwdt_runstate_t), KM_SLEEP);
280927a453eSwentaoy 	ntwdt_runstatep = ntwdt_ptr->ntwdt_run_state;
281927a453eSwentaoy 
282927a453eSwentaoy 	if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW,
283927a453eSwentaoy 	    &ntwdt_runstatep->ntwdt_runstate_mtx_cookie) != DDI_SUCCESS) {
284927a453eSwentaoy 		cmn_err(CE_WARN, "init of iblock cookie failed "
285927a453eSwentaoy 		    "for ntwdt_runstate_mutex");
286927a453eSwentaoy 		goto err1;
287927a453eSwentaoy 	} else {
288927a453eSwentaoy 		mutex_init(&ntwdt_runstatep->ntwdt_runstate_mutex,
289927a453eSwentaoy 		    NULL,
290927a453eSwentaoy 		    MUTEX_DRIVER,
291927a453eSwentaoy 		    (void *)ntwdt_runstatep->ntwdt_runstate_mtx_cookie);
292927a453eSwentaoy 	}
293927a453eSwentaoy 
294927a453eSwentaoy 	/* Cyclic fires once per second: */
295927a453eSwentaoy 	ntwdt_runstatep->ntwdt_cyclic_interval = NTWDT_CYCLIC_INTERVAL;
296927a453eSwentaoy 
297927a453eSwentaoy 	/* init the Cyclic that drives the NTWDT */
298927a453eSwentaoy 	hdlr = &ntwdt_runstatep->ntwdt_cycl_hdlr;
299927a453eSwentaoy 	hdlr->cyh_level = CY_LOCK_LEVEL;
300927a453eSwentaoy 	hdlr->cyh_func = (cyc_func_t)ntwdt_cyclic_pat;
301927a453eSwentaoy 	hdlr->cyh_arg = NULL;
302927a453eSwentaoy 
303927a453eSwentaoy 	/* Softint that will be triggered by Cyclic that drives NTWDT */
304927a453eSwentaoy 	if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &ntwdt_cyclic_softint_id,
305927a453eSwentaoy 	    NULL, NULL, ntwdt_cyclic_softint, (caddr_t)ntwdt_ptr)
306927a453eSwentaoy 	    != DDI_SUCCESS) {
307927a453eSwentaoy 		cmn_err(CE_WARN, "failed to add cyclic softintr");
308927a453eSwentaoy 		goto err2;
309927a453eSwentaoy 	}
310927a453eSwentaoy 
311927a453eSwentaoy 	/*
312927a453eSwentaoy 	 * Create Minor Node as last activity.  This prevents
313927a453eSwentaoy 	 * application from accessing our implementation until it
314927a453eSwentaoy 	 * is initialized.
315927a453eSwentaoy 	 */
316927a453eSwentaoy 	if (ddi_create_minor_node(dip, NTWDT_MINOR_NODE, S_IFCHR, 0,
317927a453eSwentaoy 	    DDI_PSEUDO, NULL) == DDI_FAILURE) {
318927a453eSwentaoy 		cmn_err(CE_WARN, "failed to create Minor Node: %s",
319927a453eSwentaoy 		    NTWDT_MINOR_NODE);
320927a453eSwentaoy 		goto err3;
321927a453eSwentaoy 	}
322927a453eSwentaoy 
323927a453eSwentaoy 	/* Display our driver info in the banner */
324927a453eSwentaoy 	ddi_report_dev(dip);
325927a453eSwentaoy 
326927a453eSwentaoy 	return (DDI_SUCCESS);
327927a453eSwentaoy 
328927a453eSwentaoy err3:
329927a453eSwentaoy 	ddi_remove_softintr(ntwdt_cyclic_softint_id);
330927a453eSwentaoy err2:
331927a453eSwentaoy 	mutex_destroy(&ntwdt_runstatep->ntwdt_runstate_mutex);
332927a453eSwentaoy err1:
333927a453eSwentaoy 	/* clean up the driver stuff here */
334927a453eSwentaoy 	kmem_free(ntwdt_runstatep, sizeof (ntwdt_runstate_t));
335927a453eSwentaoy 	ntwdt_ptr->ntwdt_run_state = NULL;
336927a453eSwentaoy 	mutex_destroy(&ntwdt_ptr->ntwdt_mutex);
337927a453eSwentaoy 	ddi_soft_state_free(ntwdt_statep, instance);
338927a453eSwentaoy 	ntwdt_dip = NULL;
339927a453eSwentaoy 
340927a453eSwentaoy 	return (DDI_FAILURE);
341927a453eSwentaoy }
342927a453eSwentaoy 
343927a453eSwentaoy /*ARGSUSED*/
344927a453eSwentaoy static int
ntwdt_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)345927a453eSwentaoy ntwdt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
346927a453eSwentaoy {
347927a453eSwentaoy 	dev_t dev;
348927a453eSwentaoy 	int instance;
349927a453eSwentaoy 	int error = DDI_SUCCESS;
350927a453eSwentaoy 
351927a453eSwentaoy 	switch (infocmd) {
352927a453eSwentaoy 	case DDI_INFO_DEVT2DEVINFO:
353927a453eSwentaoy 		dev = (dev_t)arg;
354927a453eSwentaoy 		if (getminor(dev) == 0) {
355927a453eSwentaoy 			*result = (void *)ntwdt_dip;
356927a453eSwentaoy 		} else {
357927a453eSwentaoy 			error = DDI_FAILURE;
358927a453eSwentaoy 		}
359927a453eSwentaoy 		break;
360927a453eSwentaoy 
361927a453eSwentaoy 	case DDI_INFO_DEVT2INSTANCE:
362927a453eSwentaoy 		dev = (dev_t)arg;
363927a453eSwentaoy 		instance = getminor(dev);
364927a453eSwentaoy 		*result = (void *)(uintptr_t)instance;
365927a453eSwentaoy 		break;
366927a453eSwentaoy 
367927a453eSwentaoy 	default:
368927a453eSwentaoy 		error = DDI_FAILURE;
369927a453eSwentaoy 
370927a453eSwentaoy 	}
371927a453eSwentaoy 
372927a453eSwentaoy 	return (error);
373927a453eSwentaoy }
374927a453eSwentaoy 
375927a453eSwentaoy /*ARGSUSED*/
376927a453eSwentaoy static int
ntwdt_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)377927a453eSwentaoy ntwdt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
378927a453eSwentaoy {
379927a453eSwentaoy 	int instance = ddi_get_instance(dip);
380927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = NULL;
381927a453eSwentaoy 
382927a453eSwentaoy 	ntwdt_ptr = ddi_get_soft_state(ntwdt_statep, instance);
383927a453eSwentaoy 	if (ntwdt_ptr == NULL) {
384927a453eSwentaoy 		return (DDI_FAILURE);
385927a453eSwentaoy 	}
386927a453eSwentaoy 
387927a453eSwentaoy 	switch (cmd) {
388927a453eSwentaoy 	case DDI_SUSPEND:
389927a453eSwentaoy 		return (DDI_SUCCESS);
390927a453eSwentaoy 
391927a453eSwentaoy 	case DDI_DETACH:
392927a453eSwentaoy 		/*
393927a453eSwentaoy 		 * release resources in opposite (LIFO) order as
394927a453eSwentaoy 		 * were allocated in attach.
395927a453eSwentaoy 		 */
396927a453eSwentaoy 		ddi_remove_minor_node(dip, NULL);
397927a453eSwentaoy 		ntwdt_stop_timer_lock((void *)ntwdt_ptr);
398927a453eSwentaoy 		ddi_remove_softintr(ntwdt_cyclic_softint_id);
399927a453eSwentaoy 
400927a453eSwentaoy 		mutex_destroy(
401927a453eSwentaoy 		    &ntwdt_ptr->ntwdt_run_state->ntwdt_runstate_mutex);
402927a453eSwentaoy 		kmem_free(ntwdt_ptr->ntwdt_run_state,
403927a453eSwentaoy 		    sizeof (ntwdt_runstate_t));
404927a453eSwentaoy 		ntwdt_ptr->ntwdt_run_state = NULL;
405927a453eSwentaoy 
406927a453eSwentaoy 		mutex_destroy(&ntwdt_ptr->ntwdt_mutex);
407927a453eSwentaoy 
408927a453eSwentaoy 		ddi_soft_state_free(ntwdt_statep, instance);
409927a453eSwentaoy 
410927a453eSwentaoy 		ntwdt_dip = NULL;
411927a453eSwentaoy 		return (DDI_SUCCESS);
412927a453eSwentaoy 
413927a453eSwentaoy 	default:
414927a453eSwentaoy 		return (DDI_FAILURE);
415927a453eSwentaoy 	}
416927a453eSwentaoy }
417927a453eSwentaoy 
418927a453eSwentaoy /*ARGSUSED*/
419927a453eSwentaoy static int
ntwdt_open(dev_t * devp,int flag,int otyp,cred_t * credp)420927a453eSwentaoy ntwdt_open(dev_t *devp, int flag, int otyp, cred_t *credp)
421927a453eSwentaoy {
422927a453eSwentaoy 	int instance = getminor(*devp);
423927a453eSwentaoy 	int retval = 0;
424927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = getstate(instance);
425927a453eSwentaoy 
426927a453eSwentaoy 	if (ntwdt_ptr == NULL) {
427927a453eSwentaoy 		return (ENXIO);
428927a453eSwentaoy 	}
429927a453eSwentaoy 
430927a453eSwentaoy 	/*
431927a453eSwentaoy 	 * ensure caller is a priviledged process.
432927a453eSwentaoy 	 */
433927a453eSwentaoy 	if (drv_priv(credp) != 0) {
434927a453eSwentaoy 		return (EPERM);
435927a453eSwentaoy 	}
436927a453eSwentaoy 
437927a453eSwentaoy 	mutex_enter(&ntwdt_ptr->ntwdt_mutex);
438927a453eSwentaoy 	if (ntwdt_ptr->ntwdt_open_flag) {
439927a453eSwentaoy 		retval = EAGAIN;
440927a453eSwentaoy 	} else {
441927a453eSwentaoy 		ntwdt_ptr->ntwdt_open_flag = 1;
442927a453eSwentaoy 	}
443927a453eSwentaoy 	mutex_exit(&ntwdt_ptr->ntwdt_mutex);
444927a453eSwentaoy 
445927a453eSwentaoy 	return (retval);
446927a453eSwentaoy }
447927a453eSwentaoy 
448927a453eSwentaoy /*ARGSUSED*/
449927a453eSwentaoy static int
ntwdt_close(dev_t dev,int flag,int otyp,cred_t * credp)450927a453eSwentaoy ntwdt_close(dev_t dev, int flag, int otyp, cred_t *credp)
451927a453eSwentaoy {
452927a453eSwentaoy 	int instance = getminor(dev);
453927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = getstate(instance);
454927a453eSwentaoy 
455927a453eSwentaoy 	if (ntwdt_ptr == NULL) {
456927a453eSwentaoy 		return (ENXIO);
457927a453eSwentaoy 	}
458927a453eSwentaoy 
459927a453eSwentaoy 	mutex_enter(&ntwdt_ptr->ntwdt_mutex);
460927a453eSwentaoy 	ntwdt_ptr->ntwdt_open_flag = 0;
461927a453eSwentaoy 	mutex_exit(&ntwdt_ptr->ntwdt_mutex);
462927a453eSwentaoy 
463927a453eSwentaoy 	return (0);
464927a453eSwentaoy }
465927a453eSwentaoy 
466927a453eSwentaoy /*ARGSUSED*/
467927a453eSwentaoy static int
ntwdt_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)468927a453eSwentaoy ntwdt_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
469927a453eSwentaoy 	int *rvalp)
470927a453eSwentaoy {
471927a453eSwentaoy 	int instance = getminor(dev);
472927a453eSwentaoy 	int retval = 0;
473927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = NULL;
474927a453eSwentaoy 	ntwdt_runstate_t *ntwdt_state;
475927a453eSwentaoy 	lom_dogstate_t lom_dogstate;
476927a453eSwentaoy 	lom_dogctl_t lom_dogctl;
477927a453eSwentaoy 	uint32_t lom_dogtime;
478927a453eSwentaoy 
479927a453eSwentaoy 	if ((ntwdt_ptr = getstate(instance)) == NULL) {
480927a453eSwentaoy 		return (ENXIO);
481927a453eSwentaoy 	}
482927a453eSwentaoy 
483927a453eSwentaoy 	ntwdt_state = ntwdt_ptr->ntwdt_run_state;
484927a453eSwentaoy 
485927a453eSwentaoy 	switch (cmd) {
486927a453eSwentaoy 	case LOMIOCDOGSTATE:
487927a453eSwentaoy 		mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
488927a453eSwentaoy 		lom_dogstate.reset_enable = ntwdt_state->ntwdt_reset_enabled;
489927a453eSwentaoy 		lom_dogstate.dog_enable = ntwdt_state->ntwdt_watchdog_enabled;
490927a453eSwentaoy 		lom_dogstate.dog_timeout = ntwdt_state->ntwdt_watchdog_timeout;
491927a453eSwentaoy 		mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
492927a453eSwentaoy 
493927a453eSwentaoy 		if (ddi_copyout((caddr_t)&lom_dogstate, (caddr_t)arg,
494927a453eSwentaoy 		    sizeof (lom_dogstate_t), mode) != 0) {
495927a453eSwentaoy 			retval = EFAULT;
496927a453eSwentaoy 		}
497927a453eSwentaoy 		break;
498927a453eSwentaoy 
499927a453eSwentaoy 	case LOMIOCDOGCTL:
500927a453eSwentaoy 		if (ddi_copyin((caddr_t)arg, (caddr_t)&lom_dogctl,
501927a453eSwentaoy 		    sizeof (lom_dogctl_t), mode) != 0) {
502927a453eSwentaoy 			retval = EFAULT;
503927a453eSwentaoy 			break;
504927a453eSwentaoy 		}
505927a453eSwentaoy 
506927a453eSwentaoy 		NTWDT_DBG(NTWDT_DBG_IOCTL, ("reset_enable: %d, and dog_enable: "
507927a453eSwentaoy 		    "%d, watchdog_timeout %d", lom_dogctl.reset_enable,
508927a453eSwentaoy 		    lom_dogctl.dog_enable,
509927a453eSwentaoy 		    ntwdt_state->ntwdt_watchdog_timeout));
510927a453eSwentaoy 		/*
511927a453eSwentaoy 		 * ignore request to enable reset while disabling watchdog.
512927a453eSwentaoy 		 */
513927a453eSwentaoy 		if (!lom_dogctl.dog_enable && lom_dogctl.reset_enable) {
514927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("invalid combination of "
515927a453eSwentaoy 			    "reset_enable: %d, and dog_enable: %d",
516927a453eSwentaoy 			    lom_dogctl.reset_enable,
517927a453eSwentaoy 			    lom_dogctl.dog_enable));
518927a453eSwentaoy 			retval = EINVAL;
519927a453eSwentaoy 			break;
520927a453eSwentaoy 		}
521927a453eSwentaoy 
522927a453eSwentaoy 		mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
523927a453eSwentaoy 
524927a453eSwentaoy 		if (ntwdt_state->ntwdt_watchdog_timeout == 0) {
525927a453eSwentaoy 			/*
526927a453eSwentaoy 			 * the LOMIOCDOGTIME has never been used to setup
527927a453eSwentaoy 			 * a valid timeout.
528927a453eSwentaoy 			 */
529927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("timeout has not been set"
530927a453eSwentaoy 			    "watchdog_timeout: %d",
531927a453eSwentaoy 			    ntwdt_state->ntwdt_watchdog_timeout));
532927a453eSwentaoy 			retval = EINVAL;
533927a453eSwentaoy 			goto end;
534927a453eSwentaoy 		}
535927a453eSwentaoy 
536927a453eSwentaoy 		/*
537927a453eSwentaoy 		 * Store the user specified state in the softstate.
538927a453eSwentaoy 		 */
539927a453eSwentaoy 		ntwdt_state->ntwdt_reset_enabled = lom_dogctl.reset_enable;
540927a453eSwentaoy 		ntwdt_state->ntwdt_watchdog_enabled = lom_dogctl.dog_enable;
541927a453eSwentaoy 
542927a453eSwentaoy 		if (ntwdt_state->ntwdt_watchdog_enabled != 0) {
543927a453eSwentaoy 			/*
544927a453eSwentaoy 			 * The user wants to enable the watchdog.
545927a453eSwentaoy 			 * Arm the watchdog and start the cyclic.
546927a453eSwentaoy 			 */
547927a453eSwentaoy 			ntwdt_arm_watchdog(ntwdt_state);
548927a453eSwentaoy 
549927a453eSwentaoy 			if (ntwdt_state->ntwdt_timer_running == 0) {
550927a453eSwentaoy 				ntwdt_start_timer(ntwdt_ptr);
551927a453eSwentaoy 			}
552927a453eSwentaoy 
553927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("AWDT is enabled"));
554927a453eSwentaoy 		} else {
555927a453eSwentaoy 			/*
556927a453eSwentaoy 			 * The user wants to disable the watchdog.
557927a453eSwentaoy 			 */
558927a453eSwentaoy 			if (ntwdt_state->ntwdt_timer_running != 0) {
559927a453eSwentaoy 				ntwdt_stop_timer(ntwdt_ptr);
560927a453eSwentaoy 			}
561927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("AWDT is disabled"));
562927a453eSwentaoy 		}
563927a453eSwentaoy 
564927a453eSwentaoy 		mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
565927a453eSwentaoy 		break;
566927a453eSwentaoy 
567927a453eSwentaoy 	case LOMIOCDOGTIME:
568927a453eSwentaoy 		if (ddi_copyin((caddr_t)arg, (caddr_t)&lom_dogtime,
569927a453eSwentaoy 		    sizeof (uint32_t), mode) != 0) {
570927a453eSwentaoy 			retval = EFAULT;
571927a453eSwentaoy 			break;
572927a453eSwentaoy 		}
573927a453eSwentaoy 
574927a453eSwentaoy 		NTWDT_DBG(NTWDT_DBG_IOCTL, ("user set timeout: %d",
575927a453eSwentaoy 		    lom_dogtime));
576927a453eSwentaoy 
577927a453eSwentaoy 		/*
578927a453eSwentaoy 		 * Ensure specified timeout is valid.
579927a453eSwentaoy 		 */
580927a453eSwentaoy 		if ((lom_dogtime == 0) ||
581927a453eSwentaoy 		    (lom_dogtime > (uint32_t)NTWDT_MAX_TIMEOUT)) {
582927a453eSwentaoy 			retval = EINVAL;
583927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("user set invalid "
584927a453eSwentaoy 			    "timeout: %d", (int)TICK_TO_MSEC(lom_dogtime)));
585927a453eSwentaoy 			break;
586927a453eSwentaoy 		}
587927a453eSwentaoy 
588927a453eSwentaoy 		mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
589927a453eSwentaoy 
590927a453eSwentaoy 		ntwdt_state->ntwdt_watchdog_timeout = lom_dogtime;
591927a453eSwentaoy 
592927a453eSwentaoy 		/*
593927a453eSwentaoy 		 * If awdt is currently running, re-arm it with the
594927a453eSwentaoy 		 * newly-specified timeout value.
595927a453eSwentaoy 		 */
596927a453eSwentaoy 		if (ntwdt_state->ntwdt_timer_running != 0) {
597927a453eSwentaoy 			ntwdt_arm_watchdog(ntwdt_state);
598927a453eSwentaoy 		}
599927a453eSwentaoy 		mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
600927a453eSwentaoy 		break;
601927a453eSwentaoy 
602927a453eSwentaoy 	case LOMIOCDOGPAT:
603927a453eSwentaoy 		/*
604927a453eSwentaoy 		 * Allow user to pat the watchdog timer.
605927a453eSwentaoy 		 */
606927a453eSwentaoy 		NTWDT_DBG(NTWDT_DBG_IOCTL, ("DOGPAT is invoked"));
607927a453eSwentaoy 		mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
608927a453eSwentaoy 
609927a453eSwentaoy 		/*
610927a453eSwentaoy 		 * If awdt is not enabled or underlying cyclic is not
611927a453eSwentaoy 		 * running, exit.
612927a453eSwentaoy 		 */
613927a453eSwentaoy 		if (!(ntwdt_state->ntwdt_watchdog_enabled &&
614927a453eSwentaoy 		    ntwdt_state->ntwdt_timer_running)) {
615927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("PAT: AWDT not enabled"));
616927a453eSwentaoy 			goto end;
617927a453eSwentaoy 		}
618927a453eSwentaoy 
619927a453eSwentaoy 		if (ntwdt_state->ntwdt_watchdog_expired == 0) {
620927a453eSwentaoy 			/*
621927a453eSwentaoy 			 * re-arm the awdt.
622927a453eSwentaoy 			 */
623927a453eSwentaoy 			ntwdt_arm_watchdog(ntwdt_state);
624927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_IOCTL, ("AWDT patted, "
625927a453eSwentaoy 			    "remainning seconds: %d",
626927a453eSwentaoy 			    ntwdt_state->ntwdt_time_remaining));
627927a453eSwentaoy 		}
628927a453eSwentaoy 
629927a453eSwentaoy 		mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
630927a453eSwentaoy 		break;
631927a453eSwentaoy 
632927a453eSwentaoy 	default:
633927a453eSwentaoy 		retval = EINVAL;
634927a453eSwentaoy 		break;
635927a453eSwentaoy 	}
636927a453eSwentaoy 	return (retval);
637927a453eSwentaoy end:
638927a453eSwentaoy 	mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
639927a453eSwentaoy 	return (retval);
640927a453eSwentaoy }
641927a453eSwentaoy 
642927a453eSwentaoy static void
ntwdt_cyclic_pat(void)643927a453eSwentaoy ntwdt_cyclic_pat(void)
644927a453eSwentaoy {
645927a453eSwentaoy 	ddi_trigger_softintr(ntwdt_cyclic_softint_id);
646927a453eSwentaoy }
647927a453eSwentaoy 
648927a453eSwentaoy static uint_t
ntwdt_cyclic_softint(caddr_t arg)649927a453eSwentaoy ntwdt_cyclic_softint(caddr_t arg)
650927a453eSwentaoy {
651927a453eSwentaoy 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
652927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = (ntwdt_state_t *)arg;
653927a453eSwentaoy 	ntwdt_runstate_t *ntwdt_state;
654927a453eSwentaoy 
655927a453eSwentaoy 	ntwdt_state = ntwdt_ptr->ntwdt_run_state;
656927a453eSwentaoy 
657927a453eSwentaoy 	mutex_enter(&ntwdt_state->ntwdt_runstate_mutex);
658927a453eSwentaoy 
659927a453eSwentaoy 	if ((ntwdt_state->ntwdt_watchdog_flags & NTWDT_FLAG_SKIP_CYCLIC) != 0) {
660927a453eSwentaoy 		ntwdt_state->ntwdt_watchdog_flags &= ~NTWDT_FLAG_SKIP_CYCLIC;
661927a453eSwentaoy 		goto end;
662927a453eSwentaoy 	}
663927a453eSwentaoy 
664927a453eSwentaoy 	if ((ntwdt_state->ntwdt_timer_running == 0) ||
665927a453eSwentaoy 	    (ntwdt_ptr->ntwdt_cycl_id == CYCLIC_NONE) ||
666927a453eSwentaoy 	    (ntwdt_state->ntwdt_watchdog_enabled == 0)) {
667927a453eSwentaoy 		goto end;
668927a453eSwentaoy 	}
669927a453eSwentaoy 
670927a453eSwentaoy 	NTWDT_DBG(NTWDT_DBG_IOCTL, ("cyclic_softint: %d"
671*d3d50737SRafael Vanoni 	    "ddi_get_lbolt64(): %d\n", ntwdt_state->ntwdt_watchdog_timeout,
672*d3d50737SRafael Vanoni 	    (int)TICK_TO_MSEC(ddi_get_lbolt64())));
673927a453eSwentaoy 
674927a453eSwentaoy 	/*
675927a453eSwentaoy 	 * Decrement the virtual watchdog timer and check if it has expired.
676927a453eSwentaoy 	 */
677927a453eSwentaoy 	ntwdt_state->ntwdt_time_remaining -= NTWDT_DECREMENT_INTERVAL;
678927a453eSwentaoy 
679927a453eSwentaoy 	if (ntwdt_state->ntwdt_time_remaining == 0) {
680927a453eSwentaoy 		cmn_err(CE_WARN, "application-watchdog expired");
681927a453eSwentaoy 		ntwdt_state->ntwdt_watchdog_expired = 1;
682927a453eSwentaoy 
683927a453eSwentaoy 		if (ntwdt_state->ntwdt_reset_enabled != 0) {
684927a453eSwentaoy 			/*
685927a453eSwentaoy 			 * The user wants to reset the system.
686927a453eSwentaoy 			 */
687927a453eSwentaoy 			mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
688927a453eSwentaoy 
689927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_NTWDT, ("recovery being done"));
690927a453eSwentaoy 			ntwdt_enforce_timeout();
691927a453eSwentaoy 		} else {
692927a453eSwentaoy 			NTWDT_DBG(NTWDT_DBG_NTWDT, ("no recovery being done"));
693927a453eSwentaoy 			ntwdt_state->ntwdt_watchdog_enabled = 0;
694927a453eSwentaoy 		}
695927a453eSwentaoy 
696927a453eSwentaoy 		/*
697927a453eSwentaoy 		 * Schedule Callout to stop the cyclic.
698927a453eSwentaoy 		 */
699927a453eSwentaoy 		(void) timeout(ntwdt_stop_timer_lock, ntwdt_ptr, 0);
700927a453eSwentaoy 	} else {
701927a453eSwentaoy 		_NOTE(EMPTY)
702927a453eSwentaoy 		NTWDT_DBG(NTWDT_DBG_NTWDT, ("time remaining in AWDT: %d secs",
703927a453eSwentaoy 		    (int)TICK_TO_MSEC(ntwdt_state->ntwdt_time_remaining)));
704927a453eSwentaoy 	}
705927a453eSwentaoy 
706927a453eSwentaoy end:
707927a453eSwentaoy 	mutex_exit(&ntwdt_state->ntwdt_runstate_mutex);
708927a453eSwentaoy 	return (DDI_INTR_CLAIMED);
709927a453eSwentaoy }
710927a453eSwentaoy 
711927a453eSwentaoy static void
ntwdt_arm_watchdog(ntwdt_runstate_t * ntwdt_state)712927a453eSwentaoy ntwdt_arm_watchdog(ntwdt_runstate_t *ntwdt_state)
713927a453eSwentaoy {
714927a453eSwentaoy 	ntwdt_state->ntwdt_time_remaining = ntwdt_state->ntwdt_watchdog_timeout;
715927a453eSwentaoy 
716927a453eSwentaoy 	if (ntwdt_state->ntwdt_timer_running != 0) {
717927a453eSwentaoy 		ntwdt_state->ntwdt_watchdog_flags |= NTWDT_FLAG_SKIP_CYCLIC;
718927a453eSwentaoy 	} else {
719927a453eSwentaoy 		ntwdt_state->ntwdt_watchdog_flags &= ~NTWDT_FLAG_SKIP_CYCLIC;
720927a453eSwentaoy 	}
721927a453eSwentaoy }
722927a453eSwentaoy 
723927a453eSwentaoy static void
ntwdt_start_timer(ntwdt_state_t * ntwdt_ptr)724927a453eSwentaoy ntwdt_start_timer(ntwdt_state_t *ntwdt_ptr)
725927a453eSwentaoy {
726927a453eSwentaoy 	ntwdt_runstate_t	*ntwdt_state = ntwdt_ptr->ntwdt_run_state;
727927a453eSwentaoy 	cyc_handler_t		*hdlr = &ntwdt_state->ntwdt_cycl_hdlr;
728927a453eSwentaoy 	cyc_time_t		*when = &ntwdt_state->ntwdt_cycl_time;
729927a453eSwentaoy 
730927a453eSwentaoy 	/*
731927a453eSwentaoy 	 * Init the cyclic.
732927a453eSwentaoy 	 */
733927a453eSwentaoy 	when->cyt_interval = ntwdt_state->ntwdt_cyclic_interval;
734927a453eSwentaoy 	when->cyt_when = gethrtime() + when->cyt_interval;
735927a453eSwentaoy 
736927a453eSwentaoy 	ntwdt_state->ntwdt_watchdog_expired = 0;
737927a453eSwentaoy 	ntwdt_state->ntwdt_timer_running = 1;
738927a453eSwentaoy 
739927a453eSwentaoy 	mutex_enter(&cpu_lock);
740927a453eSwentaoy 	if (ntwdt_ptr->ntwdt_cycl_id == CYCLIC_NONE) {
741927a453eSwentaoy 		ntwdt_ptr->ntwdt_cycl_id = cyclic_add(hdlr, when);
742927a453eSwentaoy 	}
743927a453eSwentaoy 	mutex_exit(&cpu_lock);
744927a453eSwentaoy 
745927a453eSwentaoy 	NTWDT_DBG(NTWDT_DBG_NTWDT, ("cyclic-driven timer is started"));
746927a453eSwentaoy }
747927a453eSwentaoy 
748927a453eSwentaoy static void
ntwdt_stop_timer(void * arg)749927a453eSwentaoy ntwdt_stop_timer(void *arg)
750927a453eSwentaoy {
751927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = (ntwdt_state_t *)arg;
752927a453eSwentaoy 	ntwdt_runstate_t *ntwdt_state = ntwdt_ptr->ntwdt_run_state;
753927a453eSwentaoy 
754927a453eSwentaoy 	mutex_enter(&cpu_lock);
755927a453eSwentaoy 	if (ntwdt_ptr->ntwdt_cycl_id != CYCLIC_NONE) {
756927a453eSwentaoy 		cyclic_remove(ntwdt_ptr->ntwdt_cycl_id);
757927a453eSwentaoy 	}
758927a453eSwentaoy 	mutex_exit(&cpu_lock);
759927a453eSwentaoy 
760927a453eSwentaoy 	ntwdt_state->ntwdt_watchdog_flags = 0;
761927a453eSwentaoy 	ntwdt_state->ntwdt_timer_running = 0;
762927a453eSwentaoy 	ntwdt_ptr->ntwdt_cycl_id = CYCLIC_NONE;
763927a453eSwentaoy 
764927a453eSwentaoy 	NTWDT_DBG(NTWDT_DBG_NTWDT, ("cyclic-driven timer is stopped"));
765927a453eSwentaoy }
766927a453eSwentaoy 
767927a453eSwentaoy /*
768927a453eSwentaoy  * This is a wrapper function for ntwdt_stop_timer as some callers
769927a453eSwentaoy  * will already have the appropriate mutex locked, and others not.
770927a453eSwentaoy  */
771927a453eSwentaoy static void
ntwdt_stop_timer_lock(void * arg)772927a453eSwentaoy ntwdt_stop_timer_lock(void *arg)
773927a453eSwentaoy {
774927a453eSwentaoy 	ntwdt_state_t *ntwdt_ptr = (ntwdt_state_t *)arg;
775927a453eSwentaoy 
776927a453eSwentaoy 	mutex_enter(&ntwdt_ptr->ntwdt_run_state->ntwdt_runstate_mutex);
777927a453eSwentaoy 	ntwdt_stop_timer(arg);
778927a453eSwentaoy 	mutex_exit(&ntwdt_ptr->ntwdt_run_state->ntwdt_runstate_mutex);
779927a453eSwentaoy }
780927a453eSwentaoy 
781927a453eSwentaoy static void
ntwdt_enforce_timeout()782927a453eSwentaoy ntwdt_enforce_timeout()
783927a453eSwentaoy {
784927a453eSwentaoy 	if (ntwdt_disable_timeout_action != 0) {
785927a453eSwentaoy 		cmn_err(CE_NOTE, "Appication watchdog timer expired, "
786927a453eSwentaoy 		    "taking no action");
787927a453eSwentaoy 		return;
788927a453eSwentaoy 	}
789927a453eSwentaoy 
790927a453eSwentaoy 	NTWDT_DBG(NTWDT_DBG_NTWDT, ("dump cores and rebooting ..."));
791927a453eSwentaoy 
792927a453eSwentaoy 	(void) kadmin(A_DUMP, AD_BOOT, NULL, kcred);
793927a453eSwentaoy 	cmn_err(CE_PANIC, "kadmin(A_DUMP, AD_BOOT) failed");
794927a453eSwentaoy 	_NOTE(NOTREACHED);
795927a453eSwentaoy }
796927a453eSwentaoy 
797927a453eSwentaoy static int
ntwdt_chk_watchdog_support()798927a453eSwentaoy ntwdt_chk_watchdog_support()
799927a453eSwentaoy {
800927a453eSwentaoy 	int	retval = 0;
801927a453eSwentaoy 
802927a453eSwentaoy 	if ((boothowto & RB_DEBUG) != 0) {
803927a453eSwentaoy 		cmn_err(CE_WARN, "kernel debugger was booted; "
804927a453eSwentaoy 		    "application watchdog is not available.");
805927a453eSwentaoy 		retval = ENOTSUP;
806927a453eSwentaoy 	}
807927a453eSwentaoy 	return (retval);
808927a453eSwentaoy }
809