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