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