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