Home | History | Annotate | Download | only in io
      1  1708   stevel /*
      2  1708   stevel  * CDDL HEADER START
      3  1708   stevel  *
      4  1708   stevel  * The contents of this file are subject to the terms of the
      5  1708   stevel  * Common Development and Distribution License (the "License").
      6  1708   stevel  * You may not use this file except in compliance with the License.
      7  1708   stevel  *
      8  1708   stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  1708   stevel  * or http://www.opensolaris.org/os/licensing.
     10  1708   stevel  * See the License for the specific language governing permissions
     11  1708   stevel  * and limitations under the License.
     12  1708   stevel  *
     13  1708   stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14  1708   stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  1708   stevel  * If applicable, add the following below this CDDL HEADER, with the
     16  1708   stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17  1708   stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  1708   stevel  *
     19  1708   stevel  * CDDL HEADER END
     20  1708   stevel  */
     21  1708   stevel 
     22  1708   stevel /*
     23  7799  Richard  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  1708   stevel  * Use is subject to license terms.
     25  1708   stevel  */
     26  1708   stevel 
     27  1708   stevel /*
     28  1708   stevel  * ntwdt driver
     29  1708   stevel  * ------------
     30  1708   stevel  *
     31  1708   stevel  * Subsystem Overview
     32  1708   stevel  * ------------------
     33  1708   stevel  *
     34  1708   stevel  * This is a pseudo driver for the Netra-1280 watchdog
     35  1708   stevel  * timer (WDT).  It provides for an *application-driven*
     36  1708   stevel  * WDT (AWDT), not a traditional, hardware-based WDT.  A
     37  1708   stevel  * hardware-based feature is already present on the
     38  1708   stevel  * Netra-1280, and it is referred to here as the
     39  1708   stevel  * System WDT (SWDT).
     40  1708   stevel  *
     41  1708   stevel  * ScApp and Solaris cooperate to provide either a SWDT or
     42  1708   stevel  * an AWDT; they are mutually-exclusive.  Once in AWDT
     43  1708   stevel  * mode, one can only transition to SWDT mode via a reboot.
     44  1708   stevel  * This obviously gives priority to the AWDT and was done
     45  1708   stevel  * to handle scenarios where the customer might temporarily
     46  1708   stevel  * terminate their wdog-app in order to do some debugging,
     47  1708   stevel  * or even to load a new version of the wdog-app.
     48  1708   stevel  *
     49  1708   stevel  * The wdog-app does an open() of the /dev/ntwdt device node
     50  1708   stevel  * and then issues ioctl's to control the state of the AWDT.
     51  1708   stevel  * The ioctl's are implemented by this driver.  Only one
     52  1708   stevel  * concurrent instance of open() is allowed.  On the close(),
     53  1708   stevel  * a watchdog timer still in progress is NOT terminated.
     54  1708   stevel  * This allows the global state machine to monitor the
     55  1708   stevel  * progress of a Solaris reboot.  ScApp will reset Solaris
     56  1708   stevel  * (eg, send an XIR) if the actual boot/crashdump latency
     57  1708   stevel  * is larger than the current AWDT timeout.
     58  1708   stevel  *
     59  1708   stevel  * The rationale for implementing an AWDT (vs a SWDT) is
     60  1708   stevel  * that it is more sensitive to system outage scenarios than
     61  1708   stevel  * a SWDT.  Eg, a system could be in such a failed state that
     62  1708   stevel  * even though its clock-interrupt could still run (and the
     63  1708   stevel  * SWDT's watchdog timer therefore re-armed), the system could
     64  1708   stevel  * in effect have a corrupt or very poor dispatch latency.
     65  1708   stevel  * An AWDT would be sensitive to dispatch latency issues, as
     66  1708   stevel  * well as problems with its own execution (eg, a hang or
     67  1708   stevel  * crash).
     68  1708   stevel  *
     69  1708   stevel  * Subsystem Interface Overview
     70  1708   stevel  * ----------------------------
     71  1708   stevel  *
     72  1708   stevel  * This pseudo-driver does not have any 'extern' functions.
     73  1708   stevel  *
     74  1708   stevel  * All system interaction is done via the traditional driver
     75  1708   stevel  * entry points (eg, attach(9e), _init(9e)).
     76  1708   stevel  *
     77  1708   stevel  * All interaction with user is via the entry points in the
     78  1708   stevel  * 'struct cb_ops' vector (eg, open(9e), ioctl(9e), and
     79  1708   stevel  * close(9e)).
     80  1708   stevel  *
     81  1708   stevel  * Subsystem Implementation Overview
     82  1708   stevel  * ---------------------------------
     83  1708   stevel  *
     84  1708   stevel  * ScApp and Solaris (eg, ntwdt) cooperate so that a state
     85  1708   stevel  * machine global to ScApp and ntwdt is either in AWDT mode
     86  1708   stevel  * or in SWDT mode.  These two peers communicate via the SBBC
     87  1708   stevel  * Mailbox that resides in IOSRAM (SBBC_MAILBOX_KEY).
     88  1708   stevel  * They use two new mailbox messages (LW8_MBOX_WDT_GET and
     89  1708   stevel  * LW8_MBOX_WDT_SET) and one new event (LW8_EVENT_SC_RESTARTED).
     90  1708   stevel  *
     91  1708   stevel  * ntwdt implements the AWDT by implementing a "virtual
     92  1708   stevel  * WDT" (VWDT).  Eg, the watchdog timer is not a traditional
     93  1708   stevel  * counter in hardware, it is a variable in ntwdt's
     94  1708   stevel  * softstate.  The wdog-app's actions cause changes to this
     95  1708   stevel  * and other variables in ntwdt's softstate.
     96  1708   stevel  *
     97  1708   stevel  * The wdog-app uses the LOMIOCDOGTIME ioctl to specify
     98  1708   stevel  * the number of seconds in the watchdog timeout (and
     99  1708   stevel  * therefore the VWDT).  The wdog-app then uses the
    100  1708   stevel  * LOMIOCDOGCTL ioctl to enable the wdog.  This causes
    101  1708   stevel  * ntwdt to create a Cyclic that will both decrement
    102  1708   stevel  * the VWDT and check to see if it has expired.  To keep
    103  1708   stevel  * the VWDT from expiring, the wdog-app uses the
    104  1708   stevel  * LOMIOCDOGPAT ioctl to re-arm (or "pat") the watchdog.
    105  1708   stevel  * This sets the VWDT value to that specified in the
    106  1708   stevel  * last LOMIOCDOGTIME ioctl.  The wdog-app can use the
    107  1708   stevel  * LOMIOCDOGSTATE ioctl to query the state of the VWDT.
    108  1708   stevel  *
    109  1708   stevel  * The wdog-app can also specify how Recovery is to be
    110  1708   stevel  * done.  The only choice is whether to do a crashdump
    111  1708   stevel  * or not.  If ntwdt computes a VWDT expiration, then
    112  1708   stevel  * ntwdt initiates the Recovery, else ScApp will.  Eg,
    113  1708   stevel  * a hang in Solaris will be sensed by ScApp and not
    114  1708   stevel  * ntwdt.  The wdog-app specifies the Recovery policy
    115  1708   stevel  * via the DOGCTL ioctl.
    116  1708   stevel  *
    117  1708   stevel  *   Timeout Expiration
    118  1708   stevel  *   ------------------
    119  1708   stevel  *   In our implementation, ScApp senses a watchdog
    120  1708   stevel  *   expiration the same way it historically has:
    121  1708   stevel  *   by reading a well-known area of IOSRAM (SBBC_TOD_KEY)
    122  1708   stevel  *   to see if the timestamp associated with a
    123  1708   stevel  *   Solaris-generated "heartbeat" field is older
    124  1708   stevel  *   than the currently specified timeout (which is
    125  1708   stevel  *   also specified in this same IOSRAM section).
    126  1708   stevel  *
    127  1708   stevel  *   What is different when ntwdt is running is that
    128  1708   stevel  *   ntwdt is responsible for updating the Heartbeat,
    129  1708   stevel  *   and not the normal client (todsg).  When ntwdt
    130  1708   stevel  *   puts the system in AWDT mode, it disables todsg's
    131  1708   stevel  *   updating of the Heartbeat by changing the state of
    132  1708   stevel  *   a pair of kernel tunables (watchdog_activated and
    133  1708   stevel  *   watchdog_enable).  ntwdt then takes responsibility
    134  1708   stevel  *   for updating the Heartbeat.  It does this by
    135  1708   stevel  *   updating the Heartbeat from the Cyclic that is
    136  1708   stevel  *   created when the user enables the AWDT (DOGCTL)
    137  1708   stevel  *   or specifies a new timeout value (DOGTIME).
    138  1708   stevel  *
    139  1708   stevel  *   As long as the AWDT is enabled, ntwdt will update
    140  1708   stevel  *   the real system Heartbeat.  As a result, ScApp
    141  1708   stevel  *   will conclude that Solaris is still running.  If
    142  1708   stevel  *   the user stops re-arming the VWDT or Solaris
    143  1708   stevel  *   hangs (eg), ntwdt will stop updating the Heartbeat.
    144  1708   stevel  *
    145  1708   stevel  *   Note that ntwdt computes expiration via the
    146  1708   stevel  *   repeatedly firing Cyclic, and ScApp computes
    147  1708   stevel  *   expiration via a cessation of Heartbeat update.
    148  1708   stevel  *   Since Heartbeat update stops once user stops
    149  1708   stevel  *   re-arming the VWDT (ie, DOGPAT ioctl), ntwdt
    150  1708   stevel  *   will compute a timeout at t(x), and ScApp will
    151  1708   stevel  *   compute a timeout at t(2x), where 'x' is the
    152  1708   stevel  *   current timeout value.  When ntwdt computes
    153  1708   stevel  *   the expiration, ntwdt masks this asymmetry.
    154  1708   stevel  *
    155  1708   stevel  *   Lifecycle Events
    156  1708   stevel  *   ----------------
    157  1708   stevel  *
    158  1708   stevel  *   ntwdt only handles one of the coarse-grained
    159  1708   stevel  *   "lifecycle events" (eg, entering OBP, shutdown,
    160  1708   stevel  *   power-down, DR) that are possible during a Solaris
    161  1708   stevel  *   session: a panic.  (Note that ScApp handles one
    162  1708   stevel  *   of the others: "entering OBP").  Other than these,
    163  1708   stevel  *   a user choosing such a state transition must first
    164  1708   stevel  *   use the wdog-app to disable the watchdog, else
    165  1708   stevel  *   an expiration could occur.
    166  1708   stevel  *
    167  1708   stevel  *   Solaris handles a panic by registering a handler
    168  1708   stevel  *   that's called during the panic.  The handler will
    169  1708   stevel  *   set the watchdog timeout to the value specified
    170  1708   stevel  *   in the NTWDT_BOOT_TIMEOUT_PROP driver Property.
    171  1708   stevel  *   Again, this value should be greater than the actual
    172  1708   stevel  *   Solaris reboot/crashdump latency.
    173  1708   stevel  *
    174  1708   stevel  *   When the user enters OBP via the System Controller,
    175  1708   stevel  *   ScApp will disable the watchdog (from ScApp's
    176  1708   stevel  *   perspective), but it will not communicate this to
    177  1708   stevel  *   ntwdt.  After having exited OBP, the wdog-app can
    178  1708   stevel  *   be used to enable or disable the watchdog (which
    179  1708   stevel  *   will get both ScApp and ntwdt in-sync).
    180  1708   stevel  *
    181  1708   stevel  *   Locking
    182  1708   stevel  *   -------
    183  1708   stevel  *
    184  1708   stevel  *   ntwdt has code running at three interrupt levels as
    185  1708   stevel  *   well as base level.
    186  1708   stevel  *
    187  1708   stevel  *   The ioctls run at base level in User Context.  The
    188  1708   stevel  *   driver's entry points run at base level in Kernel
    189  1708   stevel  *   Context.
    190  1708   stevel  *
    191  1708   stevel  *   ntwdt's three interrupt levels are used by:
    192  1708   stevel  *
    193  1708   stevel  *    o LOCK_LEVEL :
    194  1708   stevel  *        the Cyclic used to manage the VWDT is initialized
    195  1708   stevel  *        to CY_LOCK_LEVEL
    196  1708   stevel  *
    197  1708   stevel  *    o DDI_SOFTINT_MED :
    198  1708   stevel  *        the SBBC mailbox implementation registers the
    199  1708   stevel  *        specified handlers at this level
    200  1708   stevel  *
    201  1708   stevel  *    o DDI_SOFTINT_LOW :
    202  1708   stevel  *        this level is used by two handlers.  One handler
    203  1708   stevel  *        is triggered by the LOCK_LEVEL Cyclic.  The other
    204  1708   stevel  *        handler is triggered by the DDI_SOFTINT_MED
    205  1708   stevel  *        handler registered to handle SBBC mailbox events.
    206  1708   stevel  *
    207  1708   stevel  *   The centralizing concept is that the ntwdt_wdog_mutex
    208  1708   stevel  *   in the driver's softstate is initialized to have an
    209  1708   stevel  *   interrupt-block-cookie corresponding to DDI_SOFTINT_LOW.
    210  1708   stevel  *
    211  1708   stevel  *   As a result, any base level code grabs ntwdt_wdog_mutex
    212  1708   stevel  *   before doing work.  Also, any handler running at interrupt
    213  1708   stevel  *   level higher than DDI_SOFTINT_LOW "posts down" so that
    214  1708   stevel  *   a DDI_SOFTINT_LOW handler is responsible for executing
    215  1708   stevel  *   the "real work".  Each DDI_SOFTINT_LOW handler also
    216  1708   stevel  *   first grabs ntwdt_wdog_mutex, and so base level is
    217  1708   stevel  *   synchronized with all interrupt levels.
    218  1708   stevel  *
    219  1708   stevel  *   Note there's another mutex in the softstate: ntwdt_mutex.
    220  1708   stevel  *   This mutex has few responsibilities.  However, this
    221  1708   stevel  *   locking order must be followed: ntwdt_wdog_mutex is
    222  1708   stevel  *   held first, and then ntwdt_mutex.  This choice results
    223  1708   stevel  *   from the fact that the number of dynamic call sites
    224  1708   stevel  *   for ntwdt_wdog_mutex is MUCH greater than that of
    225  1708   stevel  *   ntwdt_mutex.  As a result, almost all uses of
    226  1708   stevel  *   ntwdt_wdog_mutex do not even require ntwdt_mutex to
    227  1708   stevel  *   be held, which saves resources.
    228  1708   stevel  *
    229  1708   stevel  *   Driver Properties
    230  1708   stevel  *   -----------------
    231  1708   stevel  *
    232  1708   stevel  *   "ddi-forceattach=1;"
    233  1708   stevel  *    ------------------
    234  1708   stevel  *
    235  1708   stevel  *    Using this allows our driver to be automatically
    236  1708   stevel  *    loaded at boot-time AND to not be removed from memory
    237  1708   stevel  *    solely due to memory-pressure.
    238  1708   stevel  *
    239  1708   stevel  *    Being loaded at boot allows ntwdt to (as soon as
    240  1708   stevel  *    possible) tell ScApp of the current mode of the
    241  1708   stevel  *    state-machine (eg, SWDT).  This is needed for the case
    242  1708   stevel  *    when Solaris is re-loaded while in AWDT mode; having
    243  1708   stevel  *    Solaris communicate ASAP with ScApp reduces the duration
    244  1708   stevel  *    of any "split-brain" scenario where ScApp and Solaris
    245  1708   stevel  *    are not in the same mode.
    246  1708   stevel  *
    247  1708   stevel  *    Having ntwdt remain in memory even after a close()
    248  1708   stevel  *    allows ntwdt to answer any SBBC mailbox commands
    249  1708   stevel  *    that ScApp sends (as the mailbox infrastructure is
    250  1708   stevel  *    not torn down until ntwdt is detach()'d).  Specifically,
    251  1708   stevel  *    ScApp could be re-loaded after AWDT mode had been
    252  1708   stevel  *    entered and the wdog-app had close()'d ntwdt.  ScApp
    253  1708   stevel  *    will then eventually send a LW8_EVENT_SC_RESTARTED
    254  1708   stevel  *    mailbox event in order to learn the current state of
    255  1708   stevel  *    state-machine.  Having ntwdt remain loaded allows this
    256  1708   stevel  *    event to never go unanswered.
    257  1708   stevel  *
    258  1708   stevel  *   "ntwdt-boottimeout=600;"
    259  1708   stevel  *    ----------------------
    260  1708   stevel  *
    261  1708   stevel  *    This specifies the watchdog timeout value (in seconds) to
    262  1708   stevel  *    use when ntwdt is aware of the need to reboot/reload Solaris.
    263  1708   stevel  *
    264  1708   stevel  *    ntwdt will update ScApp by setting the watchdog timeout
    265  1708   stevel  *    to the specified number of seconds when either a) Solaris
    266  1708   stevel  *    panics or b) the VWDT expires.  Note that this is only done
    267  1708   stevel  *    if the user has chosen to enable Reset.
    268  1708   stevel  *
    269  1708   stevel  *    ntwdt boundary-checks the specified value, and if out-of-range,
    270  1708   stevel  *    it initializes the watchdog timeout to a default value of
    271  1708   stevel  *    NTWDT_DEFAULT_BOOT_TIMEOUT seconds.  Note that this is a
    272  1708   stevel  *    default value and is not a *minimum* value.  The valid range
    273  1708   stevel  *    for the watchdog timeout is between one second and
    274  1708   stevel  *    NTWDT_MAX_TIMEOUT seconds, inclusive.
    275  1708   stevel  *
    276  1708   stevel  *    If ntwdt-boottimeout is set to a value less than an actual
    277  1708   stevel  *    Solaris boot's latency, ScApp will reset Solaris during boot.
    278  1708   stevel  *    Note that a continuous series of ScApp-induced resets will
    279  1708   stevel  *    not occur; ScApp only resets Solaris on the first transition
    280  1708   stevel  *    into the watchdog-expired state.
    281  1708   stevel  */
    282  1708   stevel 
    283  1708   stevel #include <sys/note.h>
    284  1708   stevel #include <sys/types.h>
    285  1708   stevel #include <sys/callb.h>
    286  1708   stevel #include <sys/stat.h>
    287  1708   stevel #include <sys/conf.h>
    288  1708   stevel #include <sys/ddi.h>
    289  1708   stevel #include <sys/sunddi.h>
    290  1708   stevel #include <sys/modctl.h>
    291  1708   stevel #include <sys/ddi_impldefs.h>
    292  1708   stevel #include <sys/kmem.h>
    293  1708   stevel #include <sys/devops.h>
    294  1708   stevel #include <sys/cyclic.h>
    295  1708   stevel #include <sys/uadmin.h>
    296  1708   stevel #include <sys/lw8_impl.h>
    297  1708   stevel #include <sys/sgsbbc.h>
    298  1708   stevel #include <sys/sgsbbc_iosram.h>
    299  1708   stevel #include <sys/sgsbbc_mailbox.h>
    300  1708   stevel #include <sys/todsg.h>
    301  1708   stevel #include <sys/mem_config.h>
    302  1708   stevel #include <sys/lom_io.h>
    303  1708   stevel #include <sys/reboot.h>
    304  1708   stevel #include <sys/clock.h>
    305  1708   stevel 
    306  1708   stevel 
    307  1708   stevel /*
    308  1708   stevel  * tunables
    309  1708   stevel  */
    310  1708   stevel int ntwdt_disable_timeout_action = 0;
    311  1708   stevel #ifdef DEBUG
    312  1708   stevel /*
    313  1708   stevel  * tunable to simulate a Solaris hang. If is non-zero, then
    314  1708   stevel  * no system heartbeats ("hardware patting") will be done,
    315  1708   stevel  * even though all AWDT machinery is functioning OK.
    316  1708   stevel  */
    317  1708   stevel int ntwdt_stop_heart;
    318  1708   stevel #endif
    319  1708   stevel 
    320  1708   stevel /*
    321  1708   stevel  * Driver Property
    322  1708   stevel  */
    323  1708   stevel #define	NTWDT_BOOT_TIMEOUT_PROP	"ntwdt-boottimeout"
    324  1708   stevel 
    325  1708   stevel /*
    326  1708   stevel  * watchdog-timeout values (in seconds):
    327  1708   stevel  *
    328  1708   stevel  * NTWDT_DEFAULT_BOOT_TIMEOUT: the default value used if
    329  1708   stevel  *                             this driver is aware of the
    330  1708   stevel  *                             reboot.
    331  1708   stevel  *
    332  1708   stevel  * NTWDT_MAX_TIMEOUT:  max value settable by app (via the
    333  1708   stevel  *                     LOMIOCDOGTIME ioctl)
    334  1708   stevel  */
    335  1708   stevel #define	NTWDT_DEFAULT_BOOT_TIMEOUT	(10*60)
    336  1708   stevel #define	NTWDT_MAX_TIMEOUT		(180*60)
    337  1708   stevel 
    338  1708   stevel 
    339  1708   stevel #define	NTWDT_CYCLIC_CHK_PERCENT	(20)
    340  1708   stevel #define	NTWDT_MINOR_NODE	"awdt"
    341  1708   stevel #define	OFFSET(base, field)	((char *)&base.field - (char *)&base)
    342  1708   stevel 
    343  1708   stevel #define	NTWDT_SUCCESS	0
    344  1708   stevel #define	NTWDT_FAILURE	1
    345  1708   stevel 
    346  1708   stevel typedef struct {
    347  1708   stevel 	callb_id_t	ntwdt_panic_cb;
    348  1708   stevel } ntwdt_callback_ids_t;
    349  1708   stevel static ntwdt_callback_ids_t ntwdt_callback_ids;
    350  1708   stevel 
    351  1708   stevel /* MBOX_EVENT_LW8 that is sent in IOSRAM Mailbox: */
    352  1708   stevel static lw8_event_t	lw8_event;		/* payload */
    353  1708   stevel static sbbc_msg_t	sbbc_msg;		/* message */
    354  1708   stevel 
    355  1708   stevel static ddi_softintr_t	ntwdt_mbox_softint_id;
    356  1708   stevel static ddi_softintr_t	ntwdt_cyclic_softint_id;
    357  1708   stevel 
    358  1708   stevel /*
    359  1708   stevel  * VWDT (i.e., Virtual Watchdog Timer) state
    360  1708   stevel  */
    361  1708   stevel typedef struct {
    362  1708   stevel 	kmutex_t		ntwdt_wdog_mutex;
    363  1708   stevel 	ddi_iblock_cookie_t	ntwdt_wdog_mtx_cookie;
    364  1708   stevel 	int			ntwdt_wdog_enabled;	/* wdog enabled ? */
    365  1708   stevel 	int			ntwdt_reset_enabled;	/* reset enabled ? */
    366  1708   stevel 	int			ntwdt_timer_running;	/* wdog running ? */
    367  1708   stevel 	int			ntwdt_wdog_expired;	/* wdog expired ? */
    368  1708   stevel 	int			ntwdt_is_initial_enable; /* 1st wdog-enable? */
    369  1708   stevel 	uint32_t		ntwdt_boot_timeout;	/* timeout for boot */
    370  1708   stevel 	uint32_t		ntwdt_secs_remaining;	/* expiration timer */
    371  1708   stevel 	uint8_t			ntwdt_wdog_action;	/* Reset action */
    372  1708   stevel 	uint32_t		ntwdt_wdog_timeout;	/* timeout in seconds */
    373  1708   stevel 	hrtime_t		ntwdt_cyclic_interval;	/* cyclic interval */
    374  1708   stevel 	cyc_handler_t		ntwdt_cycl_hdlr;
    375  1708   stevel 	cyc_time_t		ntwdt_cycl_time;
    376  1708   stevel 	kmutex_t		ntwdt_event_lock;	/* lock */
    377  1708   stevel 	uint64_t		ntwdt_wdog_flags;
    378  1708   stevel } ntwdt_wdog_t;
    379  1708   stevel 
    380  1708   stevel /* ntwdt_wdog_flags */
    381  1708   stevel #define	NTWDT_FLAG_SKIP_CYCLIC		0x1	/* skip next Cyclic */
    382  1708   stevel 
    383  1708   stevel /* macros to set/clear one bit in ntwdt_wdog_flags */
    384  1708   stevel #define	NTWDT_FLAG_SET(p, f)\
    385  1708   stevel 	((p)->ntwdt_wdog_flags |= NTWDT_FLAG_##f)
    386  1708   stevel #define	NTWDT_FLAG_CLR(p, f)\
    387  1708   stevel 	((p)->ntwdt_wdog_flags &= ~NTWDT_FLAG_##f)
    388  1708   stevel 
    389  1708   stevel 
    390  1708   stevel /* softstate */
    391  1708   stevel typedef struct {
    392  1708   stevel 	kmutex_t		ntwdt_mutex;
    393  1708   stevel 	dev_info_t		*ntwdt_dip;		/* dip */
    394  1708   stevel 	int			ntwdt_open_flag;	/* file open ? */
    395  1708   stevel 	ntwdt_wdog_t		*ntwdt_wdog_state;	/* wdog state */
    396  1708   stevel 	cyclic_id_t		ntwdt_cycl_id;
    397  1708   stevel } ntwdt_state_t;
    398  1708   stevel 
    399  1708   stevel static	void		*ntwdt_statep;	/* softstate */
    400  1708   stevel static	dev_info_t	*ntwdt_dip;
    401  1708   stevel /*
    402  1708   stevel  * if non-zero, then the app-wdog feature is available on
    403  1708   stevel  * this system configuration.
    404  1708   stevel  */
    405  1708   stevel static	int	ntwdt_watchdog_available;
    406  1708   stevel /*
    407  1708   stevel  * if non-zero, then application has used the LOMIOCDOGCTL
    408  1708   stevel  * ioctl at least once in order to Enable the app-wdog.
    409  1708   stevel  * Also, if this is non-zero, then system is in AWDT mode,
    410  1708   stevel  * else it is in SWDT mode.
    411  1708   stevel  */
    412  1708   stevel static	int	ntwdt_watchdog_activated;
    413  1708   stevel 
    414  1708   stevel #define	getstate(minor)	\
    415  1708   stevel 	((ntwdt_state_t *)ddi_get_soft_state(ntwdt_statep, (minor)))
    416  1708   stevel 
    417  1708   stevel static int	ntwdt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
    418  1708   stevel static int	ntwdt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
    419  1708   stevel static int	ntwdt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
    420  1708   stevel 		    void **result);
    421  1708   stevel static int	ntwdt_open(dev_t *, int, int, cred_t *);
    422  1708   stevel static int	ntwdt_close(dev_t, int, int, cred_t *);
    423  1708   stevel static int	ntwdt_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
    424  1708   stevel 
    425  1708   stevel static void	ntwdt_reprogram_wd(ntwdt_state_t *);
    426  1708   stevel static boolean_t	ntwdt_panic_cb(void *arg, int code);
    427  1708   stevel static void	ntwdt_start_timer(ntwdt_state_t *);
    428  1708   stevel static void	ntwdt_stop_timer(void *);
    429  1708   stevel static void	ntwdt_stop_timer_lock(void *arg);
    430  1708   stevel static void	ntwdt_add_callbacks(ntwdt_state_t *ntwdt_ptr);
    431  1708   stevel static void	ntwdt_remove_callbacks();
    432  1708   stevel static void	ntwdt_cyclic_pat(void *arg);
    433  1708   stevel static void	ntwdt_enforce_timeout();
    434  1708   stevel static void	ntwdt_pat_hw_watchdog();
    435  1708   stevel static int	ntwdt_set_cfgvar(int var, int val);
    436  1708   stevel static void	ntwdt_set_cfgvar_noreply(int var, int val);
    437  1708   stevel static int	ntwdt_read_props(ntwdt_state_t *);
    438  1708   stevel static int	ntwdt_add_mbox_handlers(ntwdt_state_t *);
    439  1708   stevel static int	ntwdt_set_hw_timeout(uint32_t period);
    440  1708   stevel static int	ntwdt_remove_mbox_handlers(void);
    441  1708   stevel static uint_t	ntwdt_event_data_handler(char *arg);
    442  1708   stevel static uint_t	ntwdt_mbox_softint(char *arg);
    443  1708   stevel static uint_t	ntwdt_cyclic_softint(char *arg);
    444  1708   stevel static int	ntwdt_lomcmd(int cmd, intptr_t arg);
    445  1708   stevel static int	ntwdt_chk_wdog_support();
    446  1708   stevel static int	ntwdt_chk_sc_support();
    447  1708   stevel static int	ntwdt_set_swdt_state();
    448  1708   stevel static void	ntwdt_swdt_to_awdt(ntwdt_wdog_t *);
    449  1708   stevel static void	ntwdt_arm_vwdt(ntwdt_wdog_t *wdog_state);
    450  1708   stevel #ifdef DEBUG
    451  1708   stevel static int	ntwdt_get_cfgvar(int var, int *val);
    452  1708   stevel #endif
    453  1708   stevel 
    454  1708   stevel struct cb_ops ntwdt_cb_ops = {
    455  1708   stevel 	ntwdt_open,	/* open  */
    456  1708   stevel 	ntwdt_close,	/* close */
    457  1708   stevel 	nulldev,	/* strategy */
    458  1708   stevel 	nulldev,	/* print */
    459  1708   stevel 	nulldev,	/* dump */
    460  1708   stevel 	nulldev,	/* read */
    461  1708   stevel 	nulldev,	/* write */
    462  1708   stevel 	ntwdt_ioctl,	/* ioctl */
    463  1708   stevel 	nulldev,	/* devmap */
    464  1708   stevel 	nulldev,	/* mmap */
    465  1708   stevel 	nulldev,	/* segmap */
    466  1708   stevel 	nochpoll,	/* poll */
    467  1708   stevel 	ddi_prop_op,	/* cb_prop_op */
    468  1708   stevel 	NULL,		/* streamtab  */
    469  1708   stevel 	D_MP | D_NEW
    470  1708   stevel };
    471  1708   stevel 
    472  1708   stevel static struct dev_ops ntwdt_ops = {
    473  1708   stevel 	DEVO_REV,		/* Devo_rev */
    474  1708   stevel 	0,			/* Refcnt */
    475  1708   stevel 	ntwdt_info,		/* Info */
    476  1708   stevel 	nulldev,		/* Identify */
    477  1708   stevel 	nulldev,		/* Probe */
    478  1708   stevel 	ntwdt_attach,		/* Attach */
    479  1708   stevel 	ntwdt_detach,		/* Detach */
    480  1708   stevel 	nodev,			/* Reset */
    481  1708   stevel 	&ntwdt_cb_ops,		/* Driver operations */
    482  1708   stevel 	0,			/* Bus operations */
    483  1708   stevel 	NULL			/* Power */
    484  1708   stevel };
    485  1708   stevel 
    486  1708   stevel static struct modldrv modldrv = {
    487  1708   stevel 	&mod_driverops, 		/* This one is a driver */
    488  7799  Richard 	"ntwdt-Netra-T12",		/* Name of the module. */
    489  1708   stevel 	&ntwdt_ops,			/* Driver ops */
    490  1708   stevel };
    491  1708   stevel 
    492  1708   stevel static struct modlinkage modlinkage = {
    493  1708   stevel 	MODREV_1, (void *)&modldrv, NULL
    494  1708   stevel };
    495  1708   stevel 
    496  1708   stevel 
    497  1708   stevel /*
    498  1708   stevel  * Flags to set in ntwdt_debug.
    499  1708   stevel  *
    500  1708   stevel  * Use either the NTWDT_DBG or NTWDT_NDBG macros
    501  1708   stevel  */
    502  1708   stevel #define	WDT_DBG_ENTRY	0x00000001	/* drv entry points */
    503  1708   stevel #define	WDT_DBG_HEART	0x00000002	/* system heartbeat */
    504  1708   stevel #define	WDT_DBG_VWDT	0x00000004	/* virtual WDT */
    505  1708   stevel #define	WDT_DBG_EVENT	0x00000010	/* SBBC Mbox events */
    506  1708   stevel #define	WDT_DBG_PROT	0x00000020	/* SC/Solaris protocol */
    507  1708   stevel #define	WDT_DBG_IOCTL	0x00000040	/* ioctl's */
    508  1708   stevel 
    509  1708   stevel uint64_t ntwdt_debug;	/* enables tracing of module's activity */
    510  1708   stevel 
    511  1708   stevel /* used in non-debug version of module */
    512  1708   stevel #define	NTWDT_NDBG(flag, msg)	{ if ((ntwdt_debug & (flag)) != 0) \
    513  1708   stevel 	(void) printf msg; }
    514  1708   stevel 
    515  1708   stevel #ifdef DEBUG
    516  1708   stevel typedef struct {
    517  1708   stevel 	uint32_t	ntwdt_wd1;
    518  1708   stevel 	uint8_t		ntwdt_wd2;
    519  1708   stevel } ntwdt_data_t;
    520  1708   stevel 
    521  1708   stevel #define	NTWDTIOCSTATE	_IOWR('a', 0xa, ntwdt_data_t)
    522  1708   stevel #define	NTWDTIOCPANIC	_IOR('a',  0xb, uint32_t)
    523  1708   stevel 
    524  1708   stevel /* used in debug version of module */
    525  1708   stevel #define	NTWDT_DBG(flag, msg)	{ if ((ntwdt_debug & (flag)) != 0) \
    526  1708   stevel 	(void) printf msg; }
    527  1708   stevel #else
    528  1708   stevel #define	NTWDT_DBG(flag, msg)
    529  1708   stevel #endif
    530  1708   stevel 
    531  1708   stevel 
    532  1708   stevel int
    533  1708   stevel _init(void)
    534  1708   stevel {
    535  1708   stevel 	int error = 0;
    536  1708   stevel 
    537  1708   stevel 	NTWDT_DBG(WDT_DBG_ENTRY, ("_init"));
    538  1708   stevel 
    539  1708   stevel 	/* Initialize the soft state structures */
    540  1708   stevel 	if ((error = ddi_soft_state_init(&ntwdt_statep,
    541  1708   stevel 	    sizeof (ntwdt_state_t), 1)) != 0) {
    542  1708   stevel 		return (error);
    543  1708   stevel 	}
    544  1708   stevel 
    545  1708   stevel 	/* Install the loadable module */
    546  1708   stevel 	if ((error = mod_install(&modlinkage)) != 0) {
    547  1708   stevel 		ddi_soft_state_fini(&ntwdt_statep);
    548  1708   stevel 	}
    549  1708   stevel 	return (error);
    550  1708   stevel }
    551  1708   stevel 
    552  1708   stevel int
    553  1708   stevel _info(struct modinfo *modinfop)
    554  1708   stevel {
    555  1708   stevel 	NTWDT_DBG(WDT_DBG_ENTRY, ("_info"));
    556  1708   stevel 
    557  1708   stevel 	return (mod_info(&modlinkage, modinfop));
    558  1708   stevel }
    559  1708   stevel 
    560  1708   stevel int
    561  1708   stevel _fini(void)
    562  1708   stevel {
    563  1708   stevel 	int error;
    564  1708   stevel 
    565  1708   stevel 	NTWDT_DBG(WDT_DBG_ENTRY, ("_fini"));
    566  1708   stevel 
    567  1708   stevel 	error = mod_remove(&modlinkage);
    568  1708   stevel 	if (error == 0) {
    569  1708   stevel 		ddi_soft_state_fini(&ntwdt_statep);
    570  1708   stevel 	}
    571  1708   stevel 
    572  1708   stevel 	return (error);
    573  1708   stevel }
    574  1708   stevel 
    575  1708   stevel static int
    576  1708   stevel ntwdt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    577  1708   stevel {
    578  1708   stevel 	int			instance;
    579  1708   stevel 	ntwdt_state_t		*ntwdt_ptr = NULL;
    580  1708   stevel 	ntwdt_wdog_t		*wdog_state = NULL;
    581  1708   stevel 	cyc_handler_t		*hdlr = NULL;
    582  1708   stevel 
    583  1708   stevel 	NTWDT_DBG(WDT_DBG_ENTRY, ("attach: dip/cmd: 0x%p/%d",
    584  1708   stevel 	    dip, cmd));
    585  1708   stevel 
    586  1708   stevel 	switch (cmd) {
    587  1708   stevel 	case DDI_ATTACH:
    588  1708   stevel 		break;
    589  1708   stevel 
    590  1708   stevel 	case DDI_RESUME:
    591  1708   stevel 		return (DDI_SUCCESS);
    592  1708   stevel 
    593  1708   stevel 	default:
    594  1708   stevel 		return (DDI_FAILURE);
    595  1708   stevel 	}
    596  1708   stevel 
    597  1708   stevel 	/* see if app-wdog is supported on our config */
    598  1708   stevel 	if (ntwdt_chk_wdog_support() != 0)
    599  1708   stevel 		return (DDI_FAILURE);
    600  1708   stevel 
    601  1708   stevel 	/* (unsolicitedly) send SWDT state to ScApp via mailbox */
    602  1708   stevel 	ntwdt_set_swdt_state();
    603  1708   stevel 
    604  1708   stevel 	instance = ddi_get_instance(dip);
    605  1708   stevel 	ASSERT(instance == 0);
    606  1708   stevel 
    607  1708   stevel 	if (ddi_soft_state_zalloc(ntwdt_statep, instance)
    608  1708   stevel 	    != DDI_SUCCESS) {
    609  1708   stevel 		return (DDI_FAILURE);
    610  1708   stevel 	}
    611  1708   stevel 	ntwdt_ptr = ddi_get_soft_state(ntwdt_statep, instance);
    612  1708   stevel 	ASSERT(ntwdt_ptr != NULL);
    613  1708   stevel 
    614  1708   stevel 	ntwdt_dip = dip;
    615  1708   stevel 
    616  1708   stevel 	ntwdt_ptr->ntwdt_dip = dip;
    617  1708   stevel 	ntwdt_ptr->ntwdt_cycl_id = CYCLIC_NONE;
    618  1708   stevel 	mutex_init(&ntwdt_ptr->ntwdt_mutex, NULL,
    619  1708   stevel 	    MUTEX_DRIVER, NULL);
    620  1708   stevel 
    621  1708   stevel 	/*
    622  1708   stevel 	 * Initialize the watchdog structure
    623  1708   stevel 	 */
    624  1708   stevel 	ntwdt_ptr->ntwdt_wdog_state =
    625  1708   stevel 	    kmem_zalloc(sizeof (ntwdt_wdog_t), KM_SLEEP);
    626  1708   stevel 	wdog_state = ntwdt_ptr->ntwdt_wdog_state;
    627  1708   stevel 
    628  1708   stevel 	/*
    629  1708   stevel 	 * Create an iblock-cookie so that ntwdt_wdog_mutex can be
    630  1708   stevel 	 * used at User Context and Interrupt Context.
    631  1708   stevel 	 */
    632  1708   stevel 	if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW,
    633  1708   stevel 	    &wdog_state->ntwdt_wdog_mtx_cookie) != DDI_SUCCESS) {
    634  1708   stevel 		cmn_err(CE_WARN, "init of iblock cookie failed "
    635  1708   stevel 		    "for ntwdt_wdog_mutex");
    636  1708   stevel 		goto err1;
    637  1708   stevel 	} else {
    638  1708   stevel 		mutex_init(&wdog_state->ntwdt_wdog_mutex, NULL, MUTEX_DRIVER,
    639  1708   stevel 		    (void *)wdog_state->ntwdt_wdog_mtx_cookie);
    640  1708   stevel 	}
    641  1708   stevel 
    642  1708   stevel 	mutex_init(&wdog_state->ntwdt_event_lock, NULL,
    643  1708   stevel 	    MUTEX_DRIVER, NULL);
    644  1708   stevel 
    645  1708   stevel 	/* Cyclic fires once per second: */
    646  1708   stevel 	wdog_state->ntwdt_cyclic_interval = NANOSEC;
    647  1708   stevel 
    648  1708   stevel 	/* interpret our .conf file. */
    649  1708   stevel 	(void) ntwdt_read_props(ntwdt_ptr);
    650  1708   stevel 
    651  1708   stevel 	/* init the Cyclic that drives the VWDT */
    652  1708   stevel 	hdlr = &wdog_state->ntwdt_cycl_hdlr;
    653  1708   stevel 	hdlr->cyh_level = CY_LOCK_LEVEL;
    654  1708   stevel 	hdlr->cyh_func = ntwdt_cyclic_pat;
    655  1708   stevel 	hdlr->cyh_arg = (void *)ntwdt_ptr;
    656  1708   stevel 
    657  1708   stevel 	/* Register handler for SBBC Mailbox events */
    658  1708   stevel 	if (ntwdt_add_mbox_handlers(ntwdt_ptr) != DDI_SUCCESS)
    659  1708   stevel 		goto err2;
    660  1708   stevel 
    661  1708   stevel 	/* Softint that will be triggered by Cyclic that drives VWDT */
    662  1708   stevel 	if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &ntwdt_cyclic_softint_id,
    663  1708   stevel 	    NULL, NULL, ntwdt_cyclic_softint, (caddr_t)ntwdt_ptr)
    664  1708   stevel 	    != DDI_SUCCESS) {
    665  1708   stevel 		cmn_err(CE_WARN, "failed to add cyclic softintr");
    666  1708   stevel 		goto err3;
    667  1708   stevel 	}
    668  1708   stevel 
    669  1708   stevel 	/* Register callbacks for various system events, e.g. panic */
    670  1708   stevel 	ntwdt_add_callbacks(ntwdt_ptr);
    671  1708   stevel 
    672  1708   stevel 	/*
    673  1708   stevel 	 * Create Minor Node as last activity.  This prevents
    674  1708   stevel 	 * application from accessing our implementation until it
    675  1708   stevel 	 * is initialized.
    676  1708   stevel 	 */
    677  1708   stevel 	if (ddi_create_minor_node(dip, NTWDT_MINOR_NODE, S_IFCHR, 0,
    678  1708   stevel 	    DDI_PSEUDO, NULL) == DDI_FAILURE) {
    679  1708   stevel 		cmn_err(CE_WARN, "failed to create Minor Node: %s",
    680  1708   stevel 		    NTWDT_MINOR_NODE);
    681  1708   stevel 		goto err4;
    682  1708   stevel 	}
    683  1708   stevel 
    684  1708   stevel 	/* Display our driver info in the banner */
    685  1708   stevel 	ddi_report_dev(dip);
    686  1708   stevel 
    687  1708   stevel 	return (DDI_SUCCESS);
    688  1708   stevel 
    689  1708   stevel err4:
    690  1708   stevel 	ntwdt_remove_callbacks();
    691  1708   stevel 	ddi_remove_softintr(ntwdt_cyclic_softint_id);
    692  1708   stevel err3:
    693  1708   stevel 	ntwdt_remove_mbox_handlers();
    694  1708   stevel err2:
    695  1708   stevel 	mutex_destroy(&wdog_state->ntwdt_event_lock);
    696  1708   stevel 	mutex_destroy(&wdog_state->ntwdt_wdog_mutex);
    697  1708   stevel err1:
    698  1708   stevel 	kmem_free(wdog_state, sizeof (ntwdt_wdog_t));
    699  1708   stevel 	ntwdt_ptr->ntwdt_wdog_state = NULL;
    700  1708   stevel 
    701  1708   stevel 	mutex_destroy(&ntwdt_ptr->ntwdt_mutex);
    702  1708   stevel 	ddi_soft_state_free(ntwdt_statep, instance);
    703  1708   stevel 
    704  1708   stevel 	ntwdt_dip = NULL;
    705  1708   stevel 
    706  1708   stevel 	return (DDI_FAILURE);
    707  1708   stevel }
    708  1708   stevel 
    709  1708   stevel /*
    710  1708   stevel  * Do static checks to see if the app-wdog feature is supported in
    711  1708   stevel  * the current configuration.
    712  1708   stevel  *
    713  1708   stevel  * If the kernel debugger was booted, then we disallow the app-wdog
    714  1708   stevel  * feature, as we assume the user will be interested more in
    715  1708   stevel  * debuggability of system than its ability to support an app-wdog.
    716  1708   stevel  * (Note that the System Watchdog (SWDT) can still be available).
    717  1708   stevel  *
    718  1708   stevel  * If the currently loaded version of ScApp does not understand one
    719  1708   stevel  * of the IOSRAM mailbox messages that is specific to the app-wdog
    720  1708   stevel  * protocol, then we disallow use of the app-wdog feature (else
    721  1708   stevel  * we could have a "split-brain" scenario where Solaris supports
    722  1708   stevel  * app-wdog but ScApp doesn't).
    723  1708   stevel  *
    724  1708   stevel  * Note that there is no *dynamic* checking of whether ScApp supports
    725  1708   stevel  * the wdog protocol.  Eg, if a new version of ScApp was loaded out
    726  1708   stevel  * from under Solaris, then once in AWDT mode, Solaris has no way
    727  1708   stevel  * of knowing that (a possibly older version of) ScApp was loaded.
    728  1708   stevel  */
    729  1708   stevel static int
    730  1708   stevel ntwdt_chk_wdog_support()
    731  1708   stevel {
    732  1708   stevel 	int	retval = ENOTSUP;
    733  1708   stevel 	int	rv;
    734  1708   stevel 
    735  1708   stevel 	if ((boothowto & RB_DEBUG) != 0) {
    736  1708   stevel 		cmn_err(CE_WARN, "kernel debugger was booted; "
    737  1708   stevel 		    "application watchdog is not available.");
    738  1708   stevel 		return (retval);
    739  1708   stevel 	}
    740  1708   stevel 
    741  1708   stevel 	/*
    742  1708   stevel 	 * if ScApp does not support the MBOX_GET cmd, then
    743  1708   stevel 	 * it does not support the app-wdog feature.  Also,
    744  1708   stevel 	 * if there is *any* type of SBBC Mailbox error at
    745  1708   stevel 	 * this point, we will disable the app watchdog
    746  1708   stevel 	 * feature.
    747  1708   stevel 	 */
    748  1708   stevel 	if ((rv = ntwdt_chk_sc_support()) != 0) {
    749  1708   stevel 		if (rv == EINVAL)
    750  1708   stevel 			cmn_err(CE_WARN, "ScApp does not support "
    751  1708   stevel 			    "the application watchdog feature.");
    752  1708   stevel 		else
    753  1708   stevel 			cmn_err(CE_WARN, "SBBC mailbox had error;"
    754  1708   stevel 			    "application watchdog is not available.");
    755  1708   stevel 		retval = rv;
    756  1708   stevel 	} else {
    757  1708   stevel 		ntwdt_watchdog_available = 1;
    758  1708   stevel 		retval = 0;
    759  1708   stevel 	}
    760  1708   stevel 
    761  1708   stevel 	NTWDT_DBG(WDT_DBG_PROT, ("app-wdog is %savailable",
    762  1708   stevel 	    (ntwdt_watchdog_available != 0) ? "" : "not "));
    763  1708   stevel 
    764  1708   stevel 	return (retval);
    765  1708   stevel }
    766  1708   stevel 
    767  1708   stevel /*
    768  1708   stevel  * Check to see if ScApp supports the app-watchdog feature.
    769  1708   stevel  *
    770  1708   stevel  * Do this by sending one of the mailbox commands that is
    771  1708   stevel  * specific to the app-wdog protocol.  If ScApp does not
    772  1708   stevel  * return an error code, we will assume it understands it
    773  1708   stevel  * (as well as the remainder of the app-wdog protocol).
    774  1708   stevel  *
    775  1708   stevel  * Notes:
    776  1708   stevel  *  ntwdt_lomcmd() will return EINVAL if ScApp does not
    777  1708   stevel  *  understand the message.  The underlying sbbc_mbox_
    778  1708   stevel  *  utility function returns SG_MBOX_STATUS_ILLEGAL_PARAMETER
    779  1708   stevel  *  ("illegal ioctl parameter").
    780  1708   stevel  */
    781  1708   stevel static int
    782  1708   stevel ntwdt_chk_sc_support()
    783  1708   stevel {
    784  1708   stevel 	lw8_get_wdt_t	get_wdt;
    785  1708   stevel 
    786  1708   stevel 	return (ntwdt_lomcmd(LW8_MBOX_WDT_GET, (intptr_t)&get_wdt));
    787  1708   stevel }
    788  1708   stevel 
    789  1708   stevel static int
    790  1708   stevel ntwdt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
    791  1708   stevel {
    792  1708   stevel 	int		instance = ddi_get_instance(dip);
    793  1708   stevel 	ntwdt_state_t	*ntwdt_ptr = NULL;
    794  1708   stevel 
    795  1708   stevel 	NTWDT_DBG(WDT_DBG_ENTRY, ("detach: dip/cmd: 0x%p/%d",
    796  1708   stevel 	    dip, cmd));
    797  1708   stevel 
    798  1708   stevel 	ntwdt_ptr = ddi_get_soft_state(ntwdt_statep, instance);
    799  1708   stevel 	if (ntwdt_ptr == NULL) {
    800  1708   stevel 		return (DDI_FAILURE);
    801  1708   stevel 	}
    802  1708   stevel 
    803  1708   stevel 	switch (cmd) {
    804  1708   stevel 	case DDI_SUSPEND:
    805  1708   stevel 		return (DDI_SUCCESS);
    806  1708   stevel 
    807  1708   stevel 	case DDI_DETACH:
    808  1708   stevel 		/*
    809  1708   stevel 		 * release resources in opposite (LIFO) order as
    810  1708   stevel 		 * were allocated in attach(9f).
    811  1708   stevel 		 */
    812  1708   stevel 		ddi_remove_minor_node(dip, NULL);
    813  1708   stevel 
    814  1708   stevel 		ntwdt_stop_timer_lock((void *)ntwdt_ptr);
    815  1708   stevel 
    816  1708   stevel 		ntwdt_remove_callbacks(ntwdt_ptr);
    817  1708   stevel 
    818  1708   stevel 		ddi_remove_softintr(ntwdt_cyclic_softint_id);
    819  1708   stevel 
    820  1708   stevel 		ntwdt_remove_mbox_handlers();
    821  1708   stevel 
    822  1708   stevel 		mutex_destroy(&ntwdt_ptr->ntwdt_wdog_state->ntwdt_event_lock);
    823  1708   stevel 		mutex_destroy(&ntwdt_ptr->ntwdt_wdog_state->ntwdt_wdog_mutex);
    824  1708   stevel 		kmem_free(ntwdt_ptr->ntwdt_wdog_state,
    825  1708   stevel 		    sizeof (ntwdt_wdog_t));
    826  1708   stevel 		ntwdt_ptr->ntwdt_wdog_state = NULL;
    827  1708   stevel 
    828  1708   stevel 		mutex_destroy(&ntwdt_ptr->ntwdt_mutex);
    829  1708   stevel 
    830  1708   stevel 		ddi_soft_state_free(ntwdt_statep, instance);
    831  1708   stevel 
    832  1708   stevel 		ntwdt_dip = NULL;
    833  1708   stevel 		return (DDI_SUCCESS);
    834  1708   stevel 
    835  1708   stevel 	default:
    836  1708   stevel 		return (DDI_FAILURE);
    837  1708   stevel 	}
    838  1708   stevel }
    839  1708   stevel 
    840  1708   stevel /*
    841  1708   stevel  * Register the SBBC Mailbox handlers.
    842  1708   stevel  *
    843  1708   stevel  * Currently, only one handler is used.  It processes the MBOX_EVENT_LW8
    844  1708   stevel  * Events that are sent by ScApp.  Of the Events that are sent, only
    845  1708   stevel  * the Event declaring that ScApp is coming up from a reboot
    846  1708   stevel  * (LW8_EVENT_SC_RESTARTED) is processed.
    847  1708   stevel  *
    848  1708   stevel  * sbbc_mbox_reg_intr registers the handler so that it executes at
    849  1708   stevel  * a DDI_SOFTINT_MED priority.
    850  1708   stevel  */
    851  1708   stevel static int
    852  1708   stevel ntwdt_add_mbox_handlers(ntwdt_state_t *ntwdt_ptr)
    853  1708   stevel {
    854  1708   stevel 	int	err;
    855  1708   stevel 
    856  1708   stevel 	/*
    857  1708   stevel 	 * We need two interrupt handlers to handle the SBBC mbox
    858  1708   stevel 	 * events.  The sbbc_mbox_xxx implementation will
    859  1708   stevel 	 * trigger our ntwdt_event_data_handler, which itself will
    860  1708   stevel 	 * trigger our ntwdt_mbox_softint.  As a result, we'll
    861  1708   stevel 	 * register ntwdt_mbox_softint first, to ensure it cannot
    862  1708   stevel 	 * be called (until its caller, ntwdt_event_data_handler)
    863  1708   stevel 	 * is registered.
    864  1708   stevel 	 */
    865  1708   stevel 
    866  1708   stevel 	/*
    867  1708   stevel 	 * add the softint that will do the real work of handling the
    868  1708   stevel 	 * LW8_SC_RESTARTED_EVENT sent from ScApp.
    869  1708   stevel 	 */
    870  1708   stevel 	if (ddi_add_softintr(ntwdt_ptr->ntwdt_dip, DDI_SOFTINT_LOW,
    871  1708   stevel 	    &ntwdt_mbox_softint_id, NULL, NULL, ntwdt_mbox_softint,
    872  1708   stevel 	    (caddr_t)ntwdt_ptr) != DDI_SUCCESS) {
    873  1708   stevel 		cmn_err(CE_WARN, "Failed to add MBOX_EVENT_LW8 softintr");
    874  1708   stevel 		return (DDI_FAILURE);
    875  1708   stevel 	}
    876  1708   stevel 
    877  1708   stevel 	/*
    878  1708   stevel 	 * Register an interrupt handler with the SBBC mailbox utility.
    879  1708   stevel 	 * This handler will get called on each event of each type of
    880  1708   stevel 	 * MBOX_EVENT_LW8 events.  However, it will only conditionally
    881  1708   stevel 	 * trigger the worker-handler (ntwdt_mbox_softintr).
    882  1708   stevel 	 */
    883  1708   stevel 	sbbc_msg.msg_buf = (caddr_t)&lw8_event;
    884  1708   stevel 	sbbc_msg.msg_len = sizeof (lw8_event);
    885  1708   stevel 
    886  1708   stevel 	err = sbbc_mbox_reg_intr(MBOX_EVENT_LW8, ntwdt_event_data_handler,
    887  1708   stevel 	    &sbbc_msg, NULL, &ntwdt_ptr->ntwdt_wdog_state->ntwdt_event_lock);
    888  1708   stevel 	if (err != 0) {
    889  1708   stevel 		cmn_err(CE_WARN, "Failed to register SBBC MBOX_EVENT_LW8"
    890  1708   stevel 		    " handler. err=%d", err);
    891  1708   stevel 
    892  1708   stevel 		ddi_remove_softintr(ntwdt_mbox_softint_id);
    893  1708   stevel 		return (DDI_FAILURE);
    894  1708   stevel 	}
    895  1708   stevel 
    896  1708   stevel 	return (DDI_SUCCESS);
    897  1708   stevel }
    898  1708   stevel 
    899  1708   stevel /*
    900  1708   stevel  * Unregister the SBBC Mailbox handlers that were registered
    901  1708   stevel  * by ntwdt_add_mbox_handlers.
    902  1708   stevel  */
    903  1708   stevel static int
    904  1708   stevel ntwdt_remove_mbox_handlers(void)
    905  1708   stevel {
    906  1708   stevel 	int	rv = DDI_SUCCESS;
    907  1708   stevel 	int	err;
    908  1708   stevel 
    909  1708   stevel 	/*
    910  1708   stevel 	 * unregister the two handlers that cooperate to handle
    911  1708   stevel 	 * the LW8_SC_RESTARTED_EVENT.  Note that they are unregistered
    912  1708   stevel 	 * in LIFO order (as compared to how they were registered).
    913  1708   stevel 	 */
    914  1708   stevel 	err = sbbc_mbox_unreg_intr(MBOX_EVENT_LW8, ntwdt_event_data_handler);
    915  1708   stevel 	if (err != 0) {
    916  1708   stevel 		cmn_err(CE_WARN, "Failed to unregister sbbc MBOX_EVENT_LW8 "
    917  1708   stevel 		    "handler. Err=%d", err);
    918  1708   stevel 		rv = DDI_FAILURE;
    919  1708   stevel 	}
    920  1708   stevel 
    921  1708   stevel 	/* remove the associated softint */
    922  1708   stevel 	ddi_remove_softintr(ntwdt_mbox_softint_id);
    923  1708   stevel 
    924  1708   stevel 	return (rv);
    925  1708   stevel }
    926  1708   stevel 
    927  1708   stevel _NOTE(ARGSUSED(0))
    928  1708   stevel static int
    929  1708   stevel ntwdt_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
    930  1708   stevel     void *arg, void **result)
    931  1708   stevel {
    932  1708   stevel 	dev_t	dev;
    933  1708   stevel 	int	instance;
    934  1708   stevel 	int	error = DDI_SUCCESS;
    935  1708   stevel 
    936  1708   stevel 	if (result == NULL)
    937  1708   stevel 		return (DDI_FAILURE);
    938  1708   stevel 
    939  1708   stevel 	switch (infocmd) {
    940  1708   stevel 	case DDI_INFO_DEVT2DEVINFO:
    941  1708   stevel 		dev = (dev_t)arg;
    942  1708   stevel 		if (getminor(dev) == 0)
    943  1708   stevel 			*result = (void *)ntwdt_dip;
    944  1708   stevel 		else
    945  1708   stevel 			error = DDI_FAILURE;
    946  1708   stevel 		break;
    947  1708   stevel 
    948  1708   stevel 	case DDI_INFO_DEVT2INSTANCE:
    949  1708   stevel 		dev = (dev_t)arg;
    950  1708   stevel 		instance = getminor(dev);
    951  1708   stevel 		*result = (void *)(uintptr_t)instance;
    952  1708   stevel 		break;
    953  1708   stevel 
    954  1708   stevel 	default:
    955  1708   stevel 		error = DDI_FAILURE;
    956  1708   stevel 	}
    957  1708   stevel 
    958  1708   stevel 	return (error);
    959  1708   stevel }
    960  1708   stevel 
    961  1708   stevel /*
    962  1708   stevel  * Open the device this driver manages.
    963  1708   stevel  *
    964  1708   stevel  * Ensure the caller is a privileged process, else
    965  1708   stevel  * a non-privileged user could cause denial-of-service
    966  1708   stevel  * and/or negatively impact reliability/availability.
    967  1708   stevel  *
    968  1708   stevel  * Ensure there is only one concurrent open().
    969  1708   stevel  */
    970  1708   stevel _NOTE(ARGSUSED(1))
    971  1708   stevel static int
    972  1708   stevel ntwdt_open(dev_t *devp, int flag, int otyp, cred_t *credp)
    973  1708   stevel {
    974  1708   stevel 	int		inst = getminor(*devp);
    975  1708   stevel 	int		ret = 0;
    976  1708   stevel 	ntwdt_state_t	*ntwdt_ptr = getstate(inst);
    977  1708   stevel 
    978  1708   stevel 	NTWDT_DBG(WDT_DBG_ENTRY, ("open: inst/soft: %d/0x%p",
    979  1708   stevel 	    inst, ntwdt_ptr));
    980  1708   stevel 
    981  1708   stevel 	/* ensure caller is a privileged process */
    982  1708   stevel 	if (drv_priv(credp) != 0)
    983  1708   stevel 		return (EPERM);
    984  1708   stevel 
    985  1708   stevel 	/*
    986  1708   stevel 	 * Check for a Deferred Attach scenario.
    987  1708   stevel 	 * Return ENXIO so DDI framework will call
    988  1708   stevel 	 * attach() and then retry the open().
    989  1708   stevel 	 */
    990  1708   stevel 	if (ntwdt_ptr == NULL)
    991  1708   stevel 		return (ENXIO);
    992  1708   stevel 
    993  1708   stevel 	mutex_enter(&ntwdt_ptr->ntwdt_wdog_state->ntwdt_wdog_mutex);
    994  1708   stevel 	mutex_enter(&ntwdt_ptr->ntwdt_mutex);
    995  1708   stevel 	if (ntwdt_ptr->ntwdt_open_flag != 0)
    996  1708   stevel 		ret = EAGAIN;
    997  1708   stevel 	else
    998  1708   stevel 		ntwdt_ptr->ntwdt_open_flag = 1;
    999  1708   stevel 	mutex_exit(&ntwdt_ptr->ntwdt_mutex);
   1000  1708   stevel 	mutex_exit(&ntwdt_ptr->ntwdt_wdog_state->ntwdt_wdog_mutex);
   1001  1708   stevel 
   1002  1708   stevel 	return (ret);
   1003  1708   stevel }
   1004  1708   stevel 
   1005  1708   stevel /*
   1006  1708   stevel  * Close the device this driver manages.
   1007  1708   stevel  *
   1008  1708   stevel  * Notes:
   1009  1708   stevel  *
   1010  1708   stevel  *  The close() can happen while the AWDT is running !
   1011  1708   stevel  *  (and nothing is done, eg, to disable the watchdog
   1012  1708   stevel  *  or to stop updating the system heartbeat).  This
   1013  1708   stevel  *  is the desired behavior, as this allows for the
   1014  1708   stevel  *  case of monitoring a Solaris reboot in terms
   1015  1708   stevel  *  of watchdog expiration.
   1016  1708   stevel  */
   1017  1708   stevel _NOTE(ARGSUSED(1))
   1018  1708   stevel static int
   1019  1708   stevel ntwdt_close(dev_t dev, int flag, int otyp, cred_t *credp)
   1020  1708   stevel {
   1021  1708   stevel 	int		inst = getminor(dev);
   1022  1708   stevel 	ntwdt_state_t	*ntwdt_ptr = getstate(inst);
   1023  1708   stevel 
   1024  1708   stevel 	NTWDT_DBG(WDT_DBG_ENTRY, ("close: inst/soft: %d/0x%p",
   1025  1708   stevel 	    inst, ntwdt_ptr));
   1026  1708   stevel 
   1027  1708   stevel 	if (ntwdt_ptr == NULL)
   1028  1708   stevel 		return (ENXIO);
   1029  1708   stevel 
   1030  1708   stevel 	mutex_enter(&ntwdt_ptr->ntwdt_wdog_state->ntwdt_wdog_mutex);
   1031  1708   stevel 	mutex_enter(&ntwdt_ptr->ntwdt_mutex);
   1032  1708   stevel 	if (ntwdt_ptr->ntwdt_open_flag != 0) {
   1033  1708   stevel 		ntwdt_ptr->ntwdt_open_flag = 0;
   1034  1708   stevel 	}
   1035  1708   stevel 	mutex_exit(&ntwdt_ptr->ntwdt_mutex);
   1036  1708   stevel 	mutex_exit(&ntwdt_ptr->ntwdt_wdog_state->ntwdt_wdog_mutex);
   1037  1708   stevel 
   1038  1708   stevel 	return (0);
   1039  1708   stevel }
   1040  1708   stevel 
   1041  1708   stevel _NOTE(ARGSUSED(4))
   1042  1708   stevel static int
   1043  1708   stevel ntwdt_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
   1044  1708   stevel     cred_t *credp, int *rvalp)
   1045  1708   stevel {
   1046  1708   stevel 	int		inst = getminor(dev);
   1047  1708   stevel 	int		retval = 0;
   1048  1708   stevel 	ntwdt_state_t	*ntwdt_ptr = NULL;
   1049  1708   stevel 	ntwdt_wdog_t	*wdog_state;
   1050  1708   stevel 
   1051  1708   stevel 	if ((ntwdt_ptr = getstate(inst)) == NULL)
   1052  1708   stevel 		return (ENXIO);
   1053  1708   stevel 
   1054  1708   stevel 	/* Only allow ioctl's if Solaris/ScApp support app-wdog */
   1055  1708   stevel 	if (ntwdt_watchdog_available == 0)
   1056  1708   stevel 		return (ENXIO);
   1057  1708   stevel 
   1058  1708   stevel 	wdog_state = ntwdt_ptr->ntwdt_wdog_state;
   1059  1708   stevel 
   1060  1708   stevel 	switch (cmd) {
   1061  1708   stevel 	case LOMIOCDOGSTATE: {
   1062  1708   stevel 		/*
   1063  1708   stevel 		 * Return the state of the AWDT to the application.
   1064  1708   stevel 		 */
   1065  1708   stevel 		lom_dogstate_t lom_dogstate;
   1066  1708   stevel 
   1067  1708   stevel 		mutex_enter(&wdog_state->ntwdt_wdog_mutex);
   1068  1708   stevel 		lom_dogstate.reset_enable =
   1069  1708   stevel 		    wdog_state->ntwdt_reset_enabled;
   1070  1708   stevel 		lom_dogstate.dog_enable =
   1071  1708   stevel 		    wdog_state->ntwdt_wdog_enabled;
   1072  1708   stevel 		lom_dogstate.dog_timeout =
   1073  1708   stevel 		    wdog_state->ntwdt_wdog_timeout;
   1074  1708   stevel 		mutex_exit(&wdog_state->ntwdt_wdog_mutex);
   1075  1708   stevel 
   1076  1708   stevel 		NTWDT_DBG(WDT_DBG_IOCTL, ("DOGSTATE: wdog/reset/timeout:"
   1077  1708   stevel 		    " %d/%d/%d", lom_dogstate.dog_enable,
   1078  1708   stevel 		    lom_dogstate.reset_enable, lom_dogstate.dog_timeout));
   1079  1708   stevel 
   1080  1708   stevel 		if (ddi_copyout((caddr_t)&lom_dogstate, (caddr_t)arg,
   1081  1708   stevel 		    sizeof (lom_dogstate_t), mode) != 0) {
   1082  1708   stevel 			retval = EFAULT;
   1083  1708   stevel 		}
   1084  1708   stevel 		break;
   1085  1708   stevel 	}
   1086  1708   stevel 
   1087  1708   stevel 	case LOMIOCDOGCTL: {
   1088  1708   stevel 		/*
   1089  1708   stevel 		 * Allow application to control whether watchdog
   1090  1708   stevel 		 * is {dis,en}abled and whether Reset is
   1091  1708   stevel 		 * {dis,en}abled.
   1092  1708   stevel 		 */
   1093  1708   stevel 		lom_dogctl_t	lom_dogctl;
   1094  1708   stevel 
   1095  1708   stevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&lom_dogctl,
   1096  1708   stevel 		    sizeof (lom_dogctl_t), mode) != 0) {
   1097  1708   stevel 			retval = EFAULT;
   1098  1708   stevel 			break;
   1099  1708   stevel 		}
   1100  1708   stevel 
   1101  1708   stevel 		NTWDT_DBG(WDT_DBG_IOCTL, ("DOGCTL: wdog/reset:"
   1102  1708   stevel 		    " %d/%d", lom_dogctl.dog_enable,
   1103  1708   stevel 		    lom_dogctl.reset_enable));
   1104  1708   stevel 
   1105  1708   stevel 		mutex_enter(&wdog_state->ntwdt_wdog_mutex);
   1106  1708   stevel 
   1107  1708   stevel 		if (wdog_state->ntwdt_wdog_timeout == 0) {
   1108  1708   stevel 			/*
   1109  1708   stevel 			 * then LOMIOCDOGTIME has never been used
   1110  1708   stevel 			 * to setup a valid timeout.
   1111  1708   stevel 			 */
   1112  1708   stevel 			retval = EINVAL;
   1113  1708   stevel 			goto end;
   1114  1708   stevel 		}
   1115  1708   stevel 
   1116  1708   stevel 		/*
   1117  1708   stevel 		 * Return error for the non-sensical combination:
   1118  1708   stevel 		 * "enable Reset" and "disable watchdog".
   1119  1708   stevel 		 */
   1120  1708   stevel 		if (lom_dogctl.dog_enable == 0 &&
   1121  1708   stevel 		    lom_dogctl.reset_enable != 0) {
   1122  1708   stevel 			retval = EINVAL;
   1123  1708   stevel 			goto end;
   1124  1708   stevel 		}
   1125  1708   stevel 
   1126  1708   stevel 		/*
   1127  1708   stevel 		 * Store the user-specified state in our softstate.
   1128  1708   stevel 		 * Note that our implementation here is stateless.
   1129  1708   stevel 		 * Eg, we do not disallow an "enable the watchdog"
   1130  1708   stevel 		 * command when the watchdog is currently enabled.
   1131  1708   stevel 		 * This is needed (at least in the case) when
   1132  1708   stevel 		 * the user enters OBP via ScApp/lom.  In that case,
   1133  1708   stevel 		 * ScApp disables the watchdog, but does not inform
   1134  1708   stevel 		 * Solaris.  As a result, an ensuing, unfiltered DOGCTL
   1135  1708   stevel 		 * to enable the watchdog is required.
   1136  1708   stevel 		 */
   1137  1708   stevel 		wdog_state->ntwdt_reset_enabled =
   1138  1708   stevel 		    lom_dogctl.reset_enable;
   1139  1708   stevel 		wdog_state->ntwdt_wdog_enabled =
   1140  1708   stevel 		    lom_dogctl.dog_enable;
   1141  1708   stevel 
   1142  1708   stevel 		if (wdog_state->ntwdt_wdog_enabled != 0) {
   1143  1708   stevel 			/*
   1144  1708   stevel 			 * then user wants to enable watchdog.
   1145  1708   stevel 			 * Arm the watchdog timer and start the
   1146  1708   stevel 			 * Cyclic, if it is not running.
   1147  1708   stevel 			 */
   1148  1708   stevel 			ntwdt_arm_vwdt(wdog_state);
   1149  1708   stevel 
   1150  1708   stevel 			if (wdog_state->ntwdt_timer_running == 0) {
   1151  1708   stevel 				ntwdt_start_timer(ntwdt_ptr);
   1152  1708   stevel 			}
   1153  1708   stevel 		} else {
   1154  1708   stevel 			/*
   1155  1708   stevel 			 * user wants to disable the watchdog.
   1156  1708   stevel 			 * Note that we do not set ntwdt_secs_remaining
   1157  1708   stevel 			 * to zero; that could cause a false expiration.
   1158  1708   stevel 			 */
   1159  1708   stevel 			if (wdog_state->ntwdt_timer_running != 0) {
   1160  1708   stevel 				ntwdt_stop_timer(ntwdt_ptr);
   1161  1708   stevel 			}
   1162  1708   stevel 		}
   1163  1708   stevel 
   1164  1708   stevel 		/*
   1165  1708   stevel 		 * Send a permutation of mailbox commands to
   1166  1708   stevel 		 * ScApp that describes the current state of the
   1167  1708   stevel 		 * watchdog timer.  Note that the permutation
   1168  1708   stevel 		 * depends on whether this is the first
   1169  1708   stevel 		 * Enabling of the watchdog or not.
   1170  1708   stevel 		 */
   1171  1708   stevel 		if (wdog_state->ntwdt_wdog_enabled != 0 &&
   1172  1708   stevel 		    wdog_state->ntwdt_is_initial_enable == 0) {
   1173  1708   stevel 
   1174  1708   stevel 			/* switch from SWDT to AWDT mode */
   1175  1708   stevel 			ntwdt_swdt_to_awdt(wdog_state);
   1176  1708   stevel 
   1177  1708   stevel 			/* Tell ScApp we're in AWDT mode */
   1178  1708   stevel 			ntwdt_set_cfgvar(LW8_WDT_PROP_MODE,
   1179  1708   stevel 			    LW8_PROP_MODE_AWDT);
   1180  1708   stevel 		}
   1181  1708   stevel 
   1182  1708   stevel 		/* Inform ScApp of the choices made by the app */
   1183  1708   stevel 		ntwdt_set_cfgvar(LW8_WDT_PROP_WDT,
   1184  1708   stevel 		    wdog_state->ntwdt_wdog_enabled);
   1185  1708   stevel 		ntwdt_set_cfgvar(LW8_WDT_PROP_RECOV,
   1186  1708   stevel 		    wdog_state->ntwdt_reset_enabled);
   1187  1708   stevel 
   1188  1708   stevel 		if (wdog_state->ntwdt_wdog_enabled != 0 &&
   1189  1708   stevel 		    wdog_state->ntwdt_is_initial_enable == 0) {
   1190  1708   stevel 			/*
   1191  1708   stevel 			 * Clear tod_iosram_t.tod_timeout_period,
   1192  1708   stevel 			 * which is used in SWDT part of state
   1193  1708   stevel 			 * machine.  (If this field is non-zero,
   1194  1708   stevel 			 * ScApp assumes that Solaris' SWDT is active).
   1195  1708   stevel 			 *
   1196  1708   stevel 			 * Clearing this is useful in case SC reboots
   1197  1708   stevel 			 * while Solaris is running, as ScApp will read
   1198  1708   stevel 			 * a zero and not assume SWDT is running.
   1199  1708   stevel 			 */
   1200  1708   stevel 			ntwdt_set_hw_timeout(0);
   1201  1708   stevel 
   1202  1708   stevel 			/* "the first watchdog-enable has been seen" */
   1203  1708   stevel 			wdog_state->ntwdt_is_initial_enable = 1;
   1204  1708   stevel 		}
   1205  1708   stevel 
   1206  1708   stevel 		mutex_exit(&wdog_state->ntwdt_wdog_mutex);
   1207  1708   stevel 		break;
   1208  1708   stevel 	}
   1209  1708   stevel 
   1210  1708   stevel 	case LOMIOCDOGTIME: {
   1211  1708   stevel 		/*
   1212  1708   stevel 		 * Allow application to set the period (in seconds)
   1213  1708   stevel 		 * of the watchdog timeout.
   1214  1708   stevel 		 */
   1215  1708   stevel 		uint32_t	lom_dogtime;
   1216  1708   stevel 
   1217  1708   stevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&lom_dogtime,
   1218  1708   stevel 		    sizeof (uint32_t), mode) != 0) {
   1219  1708   stevel 			retval = EFAULT;
   1220  1708   stevel 			break;
   1221  1708   stevel 		}
   1222  1708   stevel 
   1223  1708   stevel 		NTWDT_DBG(WDT_DBG_IOCTL, ("DOGTIME: %u seconds",
   1224  1708   stevel 		    lom_dogtime));
   1225  1708   stevel 
   1226  1708   stevel 		/* Ensure specified timeout is within range. */
   1227  1708   stevel 		if ((lom_dogtime == 0) ||
   1228  1708   stevel 		    (lom_dogtime > NTWDT_MAX_TIMEOUT)) {
   1229  1708   stevel 			retval = EINVAL;
   1230  1708   stevel 			break;
   1231  1708   stevel 		}
   1232  1708   stevel 
   1233  1708   stevel 		mutex_enter(&wdog_state->ntwdt_wdog_mutex);
   1234  1708   stevel 
   1235  1708   stevel 		wdog_state->ntwdt_wdog_timeout = lom_dogtime;
   1236  1708   stevel 
   1237  1708   stevel 		/*
   1238  1708   stevel 		 * If watchdog is currently running, re-arm the
   1239  1708   stevel 		 * watchdog timeout with the specified value.
   1240  1708   stevel 		 */
   1241  1708   stevel 		if (wdog_state->ntwdt_timer_running != 0) {
   1242  1708   stevel 			ntwdt_arm_vwdt(wdog_state);
   1243  1708   stevel 		}
   1244  1708   stevel 
   1245  1708   stevel 		/* Tell ScApp of the specified timeout */
   1246  1708   stevel 		ntwdt_set_cfgvar(LW8_WDT_PROP_TO, lom_dogtime);
   1247  1708   stevel 
   1248  1708   stevel 		mutex_exit(&wdog_state->ntwdt_wdog_mutex);
   1249  1708   stevel 		break;
   1250  1708   stevel 	}
   1251  1708   stevel 
   1252  1708   stevel 	case LOMIOCDOGPAT: {
   1253  1708   stevel 		/*
   1254  1708   stevel 		 * Allow user to re-arm ("pat") the watchdog.
   1255  1708   stevel 		 */
   1256  1708   stevel 		NTWDT_DBG(WDT_DBG_IOCTL, ("DOGPAT"));
   1257  1708   stevel 
   1258  1708   stevel 		mutex_enter(&wdog_state->ntwdt_wdog_mutex);
   1259  1708   stevel 
   1260  1708   stevel 		/*
   1261  1708   stevel 		 * If watchdog is not enabled or underlying
   1262  1708   stevel 		 * Cyclic timer is not running, exit.
   1263  1708   stevel 		 */
   1264  1708   stevel 		if (!(wdog_state->ntwdt_wdog_enabled &&
   1265  1708   stevel 		    wdog_state->ntwdt_timer_running))
   1266  1708   stevel 			goto end;
   1267  1708   stevel 
   1268  1708   stevel 		if (wdog_state->ntwdt_wdog_expired == 0) {
   1269  1708   stevel 			/* then VWDT has not expired; re-arm it */
   1270  1708   stevel 			ntwdt_arm_vwdt(wdog_state);
   1271  1708   stevel 
   1272  1708   stevel 			NTWDT_DBG(WDT_DBG_VWDT, ("VWDT re-armed:"
   1273  1708   stevel 			    " %d seconds",
   1274  1708   stevel 			    wdog_state->ntwdt_secs_remaining));
   1275  1708   stevel 		}
   1276  1708   stevel 
   1277  1708   stevel 		mutex_exit(&wdog_state->ntwdt_wdog_mutex);
   1278  1708   stevel 		break;
   1279  1708   stevel 	}
   1280  1708   stevel 
   1281  1708   stevel #ifdef DEBUG
   1282  1708   stevel 	case NTWDTIOCPANIC: {
   1283  1708   stevel 		/*
   1284  1708   stevel 		 * Use in unit/integration testing to test our
   1285  1708   stevel 		 * panic-handler code.
   1286  1708   stevel 		 */
   1287  1708   stevel 		cmn_err(CE_PANIC, "NTWDTIOCPANIC: force a panic");
   1288  1708   stevel 		break;
   1289  1708   stevel 	}
   1290  1708   stevel 
   1291  1708   stevel 	case NTWDTIOCSTATE: {
   1292  1708   stevel 		/*
   1293  1708   stevel 		 * Allow application to read wdog state from the
   1294  1708   stevel 		 * SC (and *not* the driver's softstate).
   1295  1708   stevel 		 *
   1296  1708   stevel 		 * Return state of:
   1297  1708   stevel 		 *  o recovery-enabled
   1298  1708   stevel 		 *  o current timeout value
   1299  1708   stevel 		 */
   1300  1708   stevel 		ntwdt_data_t	ntwdt_data;
   1301  1708   stevel 		int		action;
   1302  1708   stevel 		int		timeout;
   1303  1708   stevel 		int		ret;
   1304  1708   stevel 
   1305  1708   stevel 		mutex_enter(&wdog_state->ntwdt_wdog_mutex);
   1306  1708   stevel 		ret = ntwdt_get_cfgvar(LW8_WDT_PROP_TO, &timeout);
   1307  1708   stevel 		ret |= ntwdt_get_cfgvar(LW8_WDT_PROP_RECOV, &action);
   1308  1708   stevel 		mutex_exit(&wdog_state->ntwdt_wdog_mutex);
   1309  1708   stevel 
   1310  1708   stevel 		bzero((caddr_t)&ntwdt_data, sizeof (ntwdt_data));
   1311  1708   stevel 
   1312  1708   stevel 		if (ret != NTWDT_SUCCESS) {
   1313  1708   stevel 			retval = EIO;
   1314  1708   stevel 			break;
   1315  1708   stevel 		}
   1316  1708   stevel 
   1317  1708   stevel 		NTWDT_DBG(WDT_DBG_IOCTL, ("NTWDTIOCSTATE:"
   1318  1708   stevel 		    " timeout/action: %d/%d", timeout, action));
   1319  1708   stevel 
   1320  1708   stevel 		ntwdt_data.ntwdt_wd1 = (uint32_t)timeout;
   1321  1708   stevel 		ntwdt_data.ntwdt_wd2 = (uint8_t)action;
   1322  1708   stevel 
   1323  1708   stevel 		if (ddi_copyout((caddr_t)&ntwdt_data, (caddr_t)arg,
   1324  1708   stevel 		    sizeof (ntwdt_data_t), mode) != 0) {
   1325  1708   stevel 			retval = EFAULT;
   1326  1708   stevel 		}
   1327  1708   stevel 		break;
   1328  1708   stevel 	}
   1329  1708   stevel #endif
   1330  1708   stevel 	default:
   1331  1708   stevel 		retval = EINVAL;
   1332  1708   stevel 		break;
   1333  1708   stevel 	}
   1334  1708   stevel 
   1335  1708   stevel 	return (retval);
   1336  1708   stevel end:
   1337  1708   stevel 	mutex_exit(&wdog_state->ntwdt_wdog_mutex);
   1338  1708   stevel 	return (retval);
   1339  1708   stevel }
   1340  1708   stevel 
   1341  1708   stevel /*
   1342  1708   stevel  * Arm the Virtual Watchdog Timer (VWDT).
   1343  1708   stevel  *
   1344  1708   stevel  * Assign the current watchdog timeout (ntwdt_wdog_timeout)
   1345  1708   stevel  * to the softstate variable representing the watchdog
   1346  1708   stevel  * timer (ntwdt_secs_remaining).
   1347  1708   stevel  *
   1348  1708   stevel  * To ensure (from ntwdt's perspective) that any actual
   1349  1708   stevel  * timeout expiration is at least as large as the expected
   1350  1708   stevel  * timeout, conditionally set/clear a bit that will be
   1351  1708   stevel  * checked in the Cyclic's softint.
   1352  1708   stevel  *
   1353  1708   stevel  * If the Cyclic has been started, the goal is to ignore
   1354  1708   stevel  * the _next_ firing of the Cyclic, as that firing will
   1355  1708   stevel  * NOT represent a full, one-second period.  If the Cyclic
   1356  1708   stevel  * has NOT been started yet, then do not ignore the next
   1357  1708   stevel  * Cyclic's firing, as that's the First One, and it was
   1358  1708   stevel  * programmed to fire at a specific time (see ntwdt_start_timer).
   1359  1708   stevel  */
   1360  1708   stevel static void
   1361  1708   stevel ntwdt_arm_vwdt(ntwdt_wdog_t *wdog_state)
   1362  1708   stevel {
   1363  1708   stevel 	/* arm the watchdog timer (VWDT) */
   1364  1708   stevel 	wdog_state->ntwdt_secs_remaining =
   1365  1708   stevel 	    wdog_state->ntwdt_wdog_timeout;
   1366  1708   stevel 
   1367  1708   stevel 	if (wdog_state->ntwdt_timer_running != 0)
   1368  1708   stevel 		NTWDT_FLAG_SET(wdog_state, SKIP_CYCLIC);
   1369  1708   stevel 	else
   1370  1708   stevel 		NTWDT_FLAG_CLR(wdog_state, SKIP_CYCLIC);
   1371  1708   stevel }
   1372  1708   stevel 
   1373  1708   stevel /*
   1374  1708   stevel  * Switch from SWDT mode to AWDT mode.
   1375  1708   stevel  */
   1376  1708   stevel _NOTE(ARGSUSED(0))
   1377  1708   stevel static void
   1378  1708   stevel ntwdt_swdt_to_awdt(ntwdt_wdog_t *wdog_state)
   1379  1708   stevel {
   1380  1708   stevel 	ASSERT(wdog_state->ntwdt_is_initial_enable == 0);
   1381  1708   stevel 
   1382  1708   stevel 	/*
   1383  1708   stevel 	 * Disable SWDT.  If SWDT is currently active,
   1384  1708   stevel 	 * display a message so user knows that SWDT Mode
   1385  1708   stevel 	 * has terminated.
   1386  1708   stevel 	 */
   1387  1708   stevel 	if (watchdog_enable != 0 ||
   1388  1708   stevel 	    watchdog_activated != 0)
   1389  1708   stevel 		cmn_err(CE_NOTE, "Hardware watchdog disabled");
   1390  1708   stevel 	watchdog_enable = 0;
   1391  1708   stevel 	watchdog_activated = 0;
   1392  1708   stevel 
   1393  1708   stevel 	/* "we are in AWDT mode" */
   1394  1708   stevel 	ntwdt_watchdog_activated = 1;
   1395  1708   stevel 	NTWDT_DBG(WDT_DBG_VWDT, ("AWDT is enabled"));
   1396  1708   stevel }
   1397  1708   stevel 
   1398  1708   stevel /*
   1399  1708   stevel  * This is the Cyclic that runs at a multiple of the
   1400  1708   stevel  * AWDT's watchdog-timeout period.  This Cyclic runs at
   1401  1708   stevel  * LOCK_LEVEL (eg, CY_LOCK_LEVEL) and will post a
   1402  1708   stevel  * soft-interrupt in order to complete all processing.
   1403  1708   stevel  *
   1404  1708   stevel  * Executing at LOCK_LEVEL gives this function a high
   1405  1708   stevel  * interrupt priority, while performing its work via
   1406  1708   stevel  * a soft-interrupt allows for a consistent (eg, MT-safe)
   1407  1708   stevel  * view of driver softstate between User and Interrupt
   1408  1708   stevel  * context.
   1409  1708   stevel  *
   1410  1708   stevel  * Context:
   1411  1708   stevel  *  interrupt context: Cyclic framework calls at
   1412  1708   stevel  *                     CY_LOCK_LEVEL (=> 10)
   1413  1708   stevel  */
   1414  1708   stevel _NOTE(ARGSUSED(0))
   1415  1708   stevel static void
   1416  1708   stevel ntwdt_cyclic_pat(void *arg)
   1417  1708   stevel {
   1418  1708   stevel 	/* post-down to DDI_SOFTINT_LOW */
   1419  1708   stevel 	ddi_trigger_softintr(ntwdt_cyclic_softint_id);
   1420  1708   stevel }
   1421  1708   stevel 
   1422  1708   stevel /*
   1423  1708   stevel  * This is the soft-interrupt triggered by the AWDT
   1424  1708   stevel  * Cyclic.
   1425  1708   stevel  *
   1426  1708   stevel  * This softint does all the work re: computing whether
   1427  1708   stevel  * the VWDT expired.  It grabs ntwdt_wdog_mutex
   1428  1708   stevel  * so User Context code (eg, the IOCTLs) cannot run,
   1429  1708   stevel  * and then it tests whether the VWDT expired.  If it
   1430  1708   stevel  * hasn't, it decrements the VWDT timer by the amount
   1431  1708   stevel  * of the Cyclic's period.  If the timer has expired,
   1432  1708   stevel  * it initiates Recovery (based on what user specified
   1433  1708   stevel  * in LOMIOCDOGCTL).
   1434  1708   stevel  *
   1435  1708   stevel  * This function also updates the normal system "heartbeat".
   1436  1708   stevel  *
   1437  1708   stevel  * Context:
   1438  1708   stevel  *  interrupt-context: DDI_SOFTINT_LOW
   1439  1708   stevel  */
   1440  1708   stevel static uint_t
   1441  1708   stevel ntwdt_cyclic_softint(char *arg)
   1442  1708   stevel {
   1443  1708   stevel 	ntwdt_state_t	*ntwdt_ptr = (ntwdt_state_t *)arg;
   1444  1708   stevel 	ntwdt_wdog_t	*wdog_state;
   1445  1708   stevel 
   1446  1708   stevel 	wdog_state = ntwdt_ptr->ntwdt_wdog_state;
   1447  1708   stevel 
   1448  1708   stevel 	mutex_enter(&wdog_state->ntwdt_wdog_mutex);
   1449  1708   stevel 
   1450  1708   stevel 	if ((wdog_state->ntwdt_wdog_flags &
   1451  1708   stevel 	    NTWDT_FLAG_SKIP_CYCLIC) != 0) {
   1452  1708   stevel 		/*
   1453  1708   stevel 		 * then skip all processing by this interrupt.
   1454  1708   stevel 		 * (see ntwdt_arm_vwdt()).
   1455  1708   stevel 		 */
   1456  1708   stevel 		wdog_state->ntwdt_wdog_flags &= ~NTWDT_FLAG_SKIP_CYCLIC;
   1457  1708   stevel 		goto end;
   1458  1708   stevel 	}
   1459  1708   stevel 
   1460  1708   stevel 	if (wdog_state->ntwdt_timer_running == 0 ||
   1461  1708   stevel 	    (ntwdt_ptr->ntwdt_cycl_id == CYCLIC_NONE) ||
   1462  1708   stevel 	    (wdog_state->ntwdt_wdog_enabled == 0))
   1463  1708   stevel 		goto end;
   1464  1708   stevel 
   1465  1708   stevel 	/* re-arm ("pat") the hardware watchdog */
   1466  1708   stevel 	ntwdt_pat_hw_watchdog();
   1467  1708   stevel 
   1468  1708   stevel 	/* Decrement the VWDT and see if it has expired. */
   1469  1708   stevel 	if (--wdog_state->ntwdt_secs_remaining == 0) {
   1470  1708   stevel 
   1471  1708   stevel 		cmn_err(CE_WARN, "application-watchdog expired");
   1472  1708   stevel 
   1473  1708   stevel 		wdog_state->ntwdt_wdog_expired = 1;
   1474  1708   stevel 
   1475  1708   stevel 		if (wdog_state->ntwdt_reset_enabled != 0) {
   1476  1708   stevel 			/*
   1477  1708   stevel 			 * Update ScApp so that the new wdog-timeout
   1478  1708   stevel 			 * value is as specified in the
   1479  1708   stevel 			 * NTWDT_BOOT_TIMEOUT_PROP driver Property.
   1480  1708   stevel 			 * This timeout is assumedly larger than the
   1481  1708   stevel 			 * actual Solaris reboot time.  This will allow
   1482  1708   stevel 			 * our forced-reboot to not cause an unplanned
   1483  1708   stevel 			 * (series of) watchdog expiration(s).
   1484  1708   stevel 			 */
   1485  1708   stevel 			if (ntwdt_disable_timeout_action == 0)
   1486  1708   stevel 				ntwdt_reprogram_wd(ntwdt_ptr);
   1487  1708   stevel 
   1488  1708   stevel 			mutex_exit(&wdog_state->ntwdt_wdog_mutex);
   1489  1708   stevel 
   1490  1708   stevel 			NTWDT_DBG(WDT_DBG_VWDT, ("recovery being done"));
   1491  1708   stevel 
   1492  1708   stevel 			ntwdt_enforce_timeout();
   1493  1708   stevel 		} else {
   1494  1708   stevel 			NTWDT_DBG(WDT_DBG_VWDT, ("no recovery being done"));
   1495  1708   stevel 
   1496  1708   stevel 			wdog_state->ntwdt_wdog_enabled = 0;
   1497  1708   stevel 
   1498  1708   stevel 			/*
   1499  1708   stevel 			 * Tell ScApp to disable wdog; this prevents
   1500  1708   stevel 			 * the "2x-timeout" artifact.  Eg, Solaris
   1501  1708   stevel 			 * times-out at t(x) and ScApp times-out at t(2x),
   1502  1708   stevel 			 * where (x==ntwdt_wdog_timeout).
   1503  1708   stevel 			 */
   1504  1708   stevel 			(void) ntwdt_set_cfgvar(LW8_WDT_PROP_WDT,
   1505  1708   stevel 			    wdog_state->ntwdt_wdog_enabled);
   1506  1708   stevel 		}
   1507  1708   stevel 
   1508  1708   stevel 		/* Schedule Callout to stop this Cyclic */
   1509  1708   stevel 		timeout(ntwdt_stop_timer_lock, ntwdt_ptr, 0);
   1510  1708   stevel 
   1511  1708   stevel 	} else {
   1512  1708   stevel 		_NOTE(EMPTY)
   1513  1708   stevel 		NTWDT_DBG(WDT_DBG_VWDT, ("time remaining in VWDT: %d"
   1514  1708   stevel 		    " seconds", wdog_state->ntwdt_secs_remaining));
   1515  1708   stevel 	}
   1516  1708   stevel end:
   1517  1708   stevel 	mutex_exit(&wdog_state->ntwdt_wdog_mutex);
   1518  1708   stevel 
   1519  1708   stevel 	return (DDI_INTR_CLAIMED);
   1520  1708   stevel }
   1521  1708   stevel 
   1522  1708   stevel /*
   1523  1708   stevel  * Program the AWDT watchdog-timeout value to that specified
   1524  1708   stevel  * in the NTWDT_BOOT_TIMEOUT_PROP driver Property.  However,
   1525  1708   stevel  * only do this if the AWDT is in the correct state.
   1526  1708   stevel  *
   1527  1708   stevel  * Caller's Context:
   1528  1708   stevel  *  o interrupt context: (from software-interrupt)
   1529  1708   stevel  *  o during a panic
   1530  1708   stevel  */
   1531  1708   stevel static void
   1532  1708   stevel ntwdt_reprogram_wd(ntwdt_state_t *ntwdt_ptr)
   1533  1708   stevel {
   1534  1708   stevel 	ntwdt_wdog_t *wdog_state = ntwdt_ptr->ntwdt_wdog_state;
   1535  1708   stevel 
   1536  1708   stevel 	/*
   1537  1708   stevel 	 * Program the AWDT watchdog-timeout value only if the
   1538  1708   stevel 	 * watchdog is enabled, the user wants to do recovery,
   1539  1708   stevel 	 * ("reset is enabled") and the AWDT timer is currently
   1540  1708   stevel 	 * running.
   1541  1708   stevel 	 */
   1542  1708   stevel 	if (wdog_state->ntwdt_wdog_enabled != 0 &&
   1543  1708   stevel 	    wdog_state->ntwdt_reset_enabled != 0 &&
   1544  1708   stevel 	    wdog_state->ntwdt_timer_running != 0) {
   1545  1708   stevel 		if (ddi_in_panic() != 0)
   1546  1708   stevel 			ntwdt_set_cfgvar_noreply(LW8_WDT_PROP_TO,
   1547  1708   stevel 			    wdog_state->ntwdt_boot_timeout);
   1548  1708   stevel 		else
   1549  1708   stevel 			(void) ntwdt_set_cfgvar(LW8_WDT_PROP_TO,
   1550  1708   stevel 			    wdog_state->ntwdt_boot_timeout);
   1551  1708   stevel 	}
   1552  1708   stevel }
   1553  1708   stevel 
   1554  1708   stevel /*
   1555  1708   stevel  * This is the callback that was registered to run during a panic.
   1556  1708   stevel  * It will set the watchdog-timeout value to be that as specified
   1557  1708   stevel  * in the NTWDT_BOOT_TIMEOUT_PROP driver Property.
   1558  1708   stevel  *
   1559  1708   stevel  * Note that unless this Property's value specifies a timeout
   1560  1708   stevel  * that's larger than the actual reboot latency, ScApp will
   1561  1708   stevel  * experience a timeout and initiate Recovery.
   1562  1708   stevel  */
   1563  1708   stevel _NOTE(ARGSUSED(1))
   1564  1708   stevel static boolean_t
   1565  1708   stevel ntwdt_panic_cb(void *arg, int code)
   1566  1708   stevel {
   1567  1708   stevel 	ASSERT(ddi_in_panic() != 0);
   1568  1708   stevel 
   1569  1708   stevel 	ntwdt_reprogram_wd((ntwdt_state_t *)arg);
   1570  1708   stevel 
   1571  1708   stevel 	return (B_TRUE);
   1572  1708   stevel }
   1573  1708   stevel 
   1574  1708   stevel /*
   1575  1708   stevel  * Initialize the Cyclic that is used to monitor the VWDT.
   1576  1708   stevel  */
   1577  1708   stevel static void
   1578  1708   stevel ntwdt_start_timer(ntwdt_state_t *ntwdt_ptr)
   1579  1708   stevel {
   1580  1708   stevel 	ntwdt_wdog_t	*wdog_state = ntwdt_ptr->ntwdt_wdog_state;
   1581  1708   stevel 	cyc_handler_t	*hdlr = &wdog_state->ntwdt_cycl_hdlr;
   1582  1708   stevel 	cyc_time_t	*when = &wdog_state->ntwdt_cycl_time;
   1583  1708   stevel 
   1584  1708   stevel 	/*
   1585  1708   stevel 	 * Init Cyclic so its first expiry occurs wdog-timeout
   1586  1708   stevel 	 * seconds from the current, absolute time.
   1587  1708   stevel 	 */
   1588  1708   stevel 	when->cyt_interval = wdog_state->ntwdt_cyclic_interval;
   1589  1708   stevel 	when->cyt_when = gethrtime() + when->cyt_interval;
   1590  1708   stevel 
   1591  1708   stevel 	wdog_state->ntwdt_wdog_expired = 0;
   1592  1708   stevel 	wdog_state->ntwdt_timer_running = 1;
   1593  1708   stevel 
   1594  1708   stevel 	mutex_enter(&cpu_lock);
   1595  1708   stevel 	if (ntwdt_ptr->ntwdt_cycl_id == CYCLIC_NONE)
   1596  1708   stevel 		ntwdt_ptr->ntwdt_cycl_id = cyclic_add(hdlr, when);
   1597  1708   stevel 	mutex_exit(&cpu_lock);
   1598  1708   stevel 
   1599  1708   stevel 	NTWDT_DBG(WDT_DBG_VWDT, ("AWDT's cyclic-driven timer is started"));
   1600  1708   stevel }
   1601  1708   stevel 
   1602  1708   stevel /*
   1603  1708   stevel  * Stop the cyclic that is used to monitor the VWDT (and
   1604  1708   stevel  * was Started by ntwdt_start_timer).
   1605  1708   stevel  *
   1606  1708   stevel  * Context: per the Cyclic API, cyclic_remove cannot be called
   1607  1708   stevel  *          from interrupt-context.  Note that when this is
   1608  1708   stevel  *	    called via a Callout, it's called from base level.
   1609  1708   stevel  */
   1610  1708   stevel static void
   1611  1708   stevel ntwdt_stop_timer(void *arg)
   1612  1708   stevel {
   1613  1708   stevel 	ntwdt_state_t	*ntwdt_ptr = (void *)arg;
   1614  1708   stevel 	ntwdt_wdog_t	*wdog_state = ntwdt_ptr->ntwdt_wdog_state;
   1615  1708   stevel 
   1616  1708   stevel 	mutex_enter(&cpu_lock);
   1617  1708   stevel 	if (ntwdt_ptr->ntwdt_cycl_id != CYCLIC_NONE)
   1618  1708   stevel 		cyclic_remove(ntwdt_ptr->ntwdt_cycl_id);
   1619  1708   stevel 	mutex_exit(&cpu_lock);
   1620  1708   stevel 
   1621  1708   stevel 	wdog_state->ntwdt_timer_running = 0;
   1622  1708   stevel 	ntwdt_ptr->ntwdt_cycl_id = CYCLIC_NONE;
   1623  1708   stevel 
   1624  1708   stevel 	NTWDT_DBG(WDT_DBG_VWDT, ("AWDT's cyclic-driven timer is stopped"));
   1625  1708   stevel }
   1626  1708   stevel 
   1627  1708   stevel /*
   1628  1708   stevel  * Stop the cyclic that is used to monitor the VWDT (and
   1629  1708   stevel  * do it in a thread-safe manner).
   1630  1708   stevel  *
   1631  1708   stevel  * This is a wrapper function for the core function,
   1632  1708   stevel  * ntwdt_stop_timer.  Both functions are useful, as some
   1633  1708   stevel  * callers will already have the appropriate mutex locked, and
   1634  1708   stevel  * other callers will not.
   1635  1708   stevel  */
   1636  1708   stevel static void
   1637  1708   stevel ntwdt_stop_timer_lock(void *arg)
   1638  1708   stevel {
   1639  1708   stevel 	ntwdt_state_t	*ntwdt_ptr = (void *)arg;
   1640  1708   stevel 	ntwdt_wdog_t	*wdog_state = ntwdt_ptr->ntwdt_wdog_state;
   1641  1708   stevel 
   1642  1708   stevel 	mutex_enter(&wdog_state->ntwdt_wdog_mutex);
   1643  1708   stevel 	ntwdt_stop_timer(arg);
   1644  1708   stevel 	mutex_exit(&wdog_state->ntwdt_wdog_mutex);
   1645  1708   stevel }
   1646  1708   stevel 
   1647  1708   stevel /*
   1648  1708   stevel  * Add callbacks needed to react to major system state transitions.
   1649  1708   stevel  */
   1650  1708   stevel static void
   1651  1708   stevel ntwdt_add_callbacks(ntwdt_state_t *ntwdt_ptr)
   1652  1708   stevel {
   1653  1708   stevel 	/* register a callback that's called during a panic */
   1654  1708   stevel 	ntwdt_callback_ids.ntwdt_panic_cb = callb_add(ntwdt_panic_cb,
   1655  1708   stevel 	    (void *)ntwdt_ptr, CB_CL_PANIC, "ntwdt_panic_cb");
   1656  1708   stevel }
   1657  1708   stevel 
   1658  1708   stevel /*
   1659  1708   stevel  * Remove callbacks added by ntwdt_add_callbacks.
   1660  1708   stevel  */
   1661  1708   stevel static void
   1662  1708   stevel ntwdt_remove_callbacks()
   1663  1708   stevel {
   1664  1708   stevel 	callb_delete(ntwdt_callback_ids.ntwdt_panic_cb);
   1665  1708   stevel }
   1666  1708   stevel 
   1667  1708   stevel /*
   1668  1708   stevel  * Initiate a Reset (as a result of the VWDT timeout expiring).
   1669  1708   stevel  */
   1670  1708   stevel static void
   1671  1708   stevel ntwdt_enforce_timeout()
   1672  1708   stevel {
   1673  1708   stevel 	if (ntwdt_disable_timeout_action != 0) {
   1674  1708   stevel 		cmn_err(CE_NOTE, "OS timeout expired, taking no action");
   1675  1708   stevel 		return;
   1676  1708   stevel 	}
   1677  1708   stevel 
   1678  1708   stevel 	NTWDT_DBG(WDT_DBG_VWDT, ("VWDT expired; do a crashdump"));
   1679  1708   stevel 
   1680  1708   stevel 	(void) kadmin(A_DUMP, AD_BOOT, NULL, kcred);
   1681  1708   stevel 	cmn_err(CE_PANIC, "kadmin(A_DUMP, AD_BOOT) failed");
   1682  1708   stevel 	_NOTE(NOTREACHED)
   1683  1708   stevel }
   1684  1708   stevel 
   1685  1708   stevel /*
   1686  1708   stevel  * Interpret the Properties from driver's config file.
   1687  1708   stevel  */
   1688  1708   stevel static int
   1689  1708   stevel ntwdt_read_props(ntwdt_state_t *ntwdt_ptr)
   1690  1708   stevel {
   1691  1708   stevel 	ntwdt_wdog_t	*wdog_state;
   1692  1708   stevel 	int		boot_timeout;
   1693  1708   stevel 
   1694  1708   stevel 	wdog_state = ntwdt_ptr->ntwdt_wdog_state;
   1695  1708   stevel 
   1696  1708   stevel 	/*
   1697  1708   stevel 	 * interpret Property that specifies how long
   1698  1708   stevel 	 * the watchdog-timeout should be set to when
   1699  1708   stevel 	 * Solaris panics.  Assumption is that this value
   1700  1708   stevel 	 * is larger than the amount of time it takes
   1701  1708   stevel 	 * to reboot and write crashdump.  If not,
   1702  1708   stevel 	 * ScApp could induce a reset, due to an expired
   1703  1708   stevel 	 * watchdog-timeout.
   1704  1708   stevel 	 */
   1705  1708   stevel 	wdog_state->ntwdt_boot_timeout =
   1706  1708   stevel 	    NTWDT_DEFAULT_BOOT_TIMEOUT;
   1707  1708   stevel 
   1708  1708   stevel 	boot_timeout = ddi_prop_get_int(DDI_DEV_T_ANY,
   1709  1708   stevel 	    ntwdt_ptr->ntwdt_dip, DDI_PROP_DONTPASS,
   1710  1708   stevel 	    NTWDT_BOOT_TIMEOUT_PROP, -1);
   1711  1708   stevel 
   1712  1708   stevel 	if (boot_timeout != -1 && boot_timeout > 0 &&
   1713  1708   stevel 	    boot_timeout <= NTWDT_MAX_TIMEOUT) {
   1714  1708   stevel 		wdog_state->ntwdt_boot_timeout =
   1715  1708   stevel 		    boot_timeout;
   1716  1708   stevel 	} else {
   1717  1708   stevel 		_NOTE(EMPTY)
   1718  1708   stevel 		NTWDT_DBG(WDT_DBG_ENTRY, (NTWDT_BOOT_TIMEOUT_PROP
   1719  1708   stevel 		    ": using default of %d seconds.",
   1720  1708   stevel 		    wdog_state->ntwdt_boot_timeout));
   1721  1708   stevel 	}
   1722  1708   stevel 
   1723  1708   stevel 	return (DDI_SUCCESS);
   1724  1708   stevel }
   1725  1708   stevel 
   1726  1708   stevel /*
   1727  1708   stevel  * Write state of SWDT to ScApp.
   1728  1708   stevel  *
   1729  1708   stevel  * Currently, this function is only called on attach()
   1730  1708   stevel  * of our driver.
   1731  1708   stevel  *
   1732  1708   stevel  * Note that we do not need to call this function, eg,
   1733  1708   stevel  * in response to a solicitation from ScApp (eg,
   1734  1708   stevel  * the LW8_SC_RESTARTED_EVENT).
   1735  1708   stevel  *
   1736  1708   stevel  * Context:
   1737  1708   stevel  *  called in Kernel Context
   1738  1708   stevel  */
   1739  1708   stevel static int
   1740  1708   stevel ntwdt_set_swdt_state()
   1741  1708   stevel {
   1742  1708   stevel 	/*
   1743  1708   stevel 	 * note that ScApp only needs this one
   1744  1708   stevel 	 * variable when system is in SWDT mode.
   1745  1708   stevel 	 */
   1746  1708   stevel 	ntwdt_set_cfgvar(LW8_WDT_PROP_MODE,
   1747  1708   stevel 	    LW8_PROP_MODE_SWDT);
   1748  1708   stevel 
   1749  1708   stevel 	return (0);
   1750  1708   stevel }
   1751  1708   stevel 
   1752  1708   stevel /*
   1753  1708   stevel  * Write all AWDT state to ScApp via the SBBC mailbox
   1754  1708   stevel  * in IOSRAM.  Note that the permutation of Writes
   1755  1708   stevel  * is as specified in the design spec.
   1756  1708   stevel  *
   1757  1708   stevel  * Notes: caller must perform synchronization so that
   1758  1708   stevel  *        this series of Writes is consistent as viewed
   1759  1708   stevel  *        by ScApp (eg, there is no LW8_WDT_xxx mailbox
   1760  1708   stevel  *        command that contains "all Properties"; each
   1761  1708   stevel  *        Property must be written individually).
   1762  1708   stevel  */
   1763  1708   stevel static int
   1764  1708   stevel ntwdt_set_awdt_state(ntwdt_wdog_t *rstatep)
   1765  1708   stevel {
   1766  1708   stevel 	/* ScApp expects values in this order: */
   1767  1708   stevel 	ntwdt_set_cfgvar(LW8_WDT_PROP_MODE,
   1768  1708   stevel 	    ntwdt_watchdog_activated != 0);
   1769  1708   stevel 	ntwdt_set_cfgvar(LW8_WDT_PROP_TO,
   1770  1708   stevel 	    rstatep->ntwdt_wdog_timeout);
   1771  1708   stevel 	ntwdt_set_cfgvar(LW8_WDT_PROP_RECOV,
   1772  1708   stevel 	    rstatep->ntwdt_reset_enabled);
   1773  1708   stevel 	ntwdt_set_cfgvar(LW8_WDT_PROP_WDT,
   1774  1708   stevel 	    rstatep->ntwdt_wdog_enabled);
   1775  1708   stevel 
   1776  1708   stevel 	return (NTWDT_SUCCESS);
   1777  1708   stevel }
   1778  1708   stevel 
   1779  1708   stevel /*
   1780  1708   stevel  * Write a specified WDT Property (and Value) to ScApp.
   1781  1708   stevel  *
   1782  1708   stevel  * <Property, Value> is passed in the LW8_MBOX_WDT_SET
   1783  1708   stevel  * (SBBC) mailbox message.  The SBBC mailbox resides in
   1784  1708   stevel  * IOSRAM.
   1785  1708   stevel  *
   1786  1708   stevel  * Note that this function is responsible for ensuring that
   1787  1708   stevel  * a driver-specific representation of a mailbox <Value> is
   1788  1708   stevel  * mapped into the representation that is expected by ScApp
   1789  1708   stevel  * (eg, see LW8_WDT_PROP_RECOV).
   1790  1708   stevel  */
   1791  1708   stevel static int
   1792  1708   stevel ntwdt_set_cfgvar(int var, int val)
   1793  1708   stevel {
   1794  1708   stevel 	int 		rv;
   1795  1708   stevel 	int 		mbox_val;
   1796  1708   stevel 	lw8_set_wdt_t	set_wdt;
   1797  1708   stevel 
   1798  1708   stevel 	switch (var) {
   1799  1708   stevel 	case LW8_WDT_PROP_RECOV:
   1800  1708   stevel #ifdef DEBUG
   1801  1708   stevel 		NTWDT_DBG(WDT_DBG_PROT, ("MBOX_SET of 'recovery-enabled':"
   1802  1708   stevel 		    " %s (%d)", (val != 0) ? "enabled" : "disabled", val));
   1803  1708   stevel #endif
   1804  1708   stevel 		mbox_val = (val != 0) ? LW8_PROP_RECOV_ENABLED :
   1805  1708   stevel 		    LW8_PROP_RECOV_DISABLED;
   1806  1708   stevel 		break;
   1807  1708   stevel 
   1808  1708   stevel 	case LW8_WDT_PROP_WDT:
   1809  1708   stevel #ifdef DEBUG
   1810  1708   stevel 		NTWDT_DBG(WDT_DBG_PROT, ("MBOX_SET of 'wdog-enabled':"
   1811  1708   stevel 		    " %s (%d)", (val != 0) ? "enabled" : "disabled", val));
   1812  1708   stevel #endif
   1813  1708   stevel 		mbox_val = (val != 0) ? LW8_PROP_WDT_ENABLED :
   1814  1708   stevel 		    LW8_PROP_WDT_DISABLED;
   1815  1708   stevel 		break;
   1816  1708   stevel 
   1817  1708   stevel 	case LW8_WDT_PROP_TO:
   1818  1708   stevel #ifdef DEBUG
   1819  1708   stevel 		NTWDT_DBG(WDT_DBG_PROT, ("MBOX_SET of 'wdog-timeout':"
   1820  1708   stevel 		    " %d seconds", val));
   1821  1708   stevel #endif
   1822  1708   stevel 		mbox_val = val;
   1823  1708   stevel 		break;
   1824  1708   stevel 
   1825  1708   stevel 	case LW8_WDT_PROP_MODE:
   1826  1708   stevel #ifdef DEBUG
   1827  1708   stevel 		NTWDT_DBG(WDT_DBG_PROT, ("MBOX_SET of 'wdog-mode':"
   1828  1708   stevel 		    " %s (%d)", (val != LW8_PROP_MODE_SWDT) ?
   1829  1708   stevel 		    "AWDT" : "SWDT", val));
   1830  1708   stevel #endif
   1831  1708   stevel 		mbox_val = val;
   1832  1708   stevel 		break;
   1833  1708   stevel 
   1834  1708   stevel 	default:
   1835  1708   stevel 		ASSERT(0);
   1836  1708   stevel 		_NOTE(NOTREACHED)
   1837  1708   stevel 	}
   1838  1708   stevel 
   1839  1708   stevel 	set_wdt.property_id = var;
   1840  1708   stevel 	set_wdt.value = mbox_val;
   1841  1708   stevel 
   1842  1708   stevel 	rv = ntwdt_lomcmd(LW8_MBOX_WDT_SET, (intptr_t)&set_wdt);
   1843  1708   stevel 	if (rv != 0) {
   1844  1708   stevel 		_NOTE(EMPTY)
   1845  1708   stevel 		NTWDT_DBG(WDT_DBG_PROT, ("MBOX_SET of prop/val %d/%d "
   1846  1708   stevel 		    "failed: %d", var, mbox_val, rv));
   1847  1708   stevel 	}
   1848  1708   stevel 
   1849  1708   stevel 	return (rv);
   1850  1708   stevel }
   1851  1708   stevel 
   1852  1708   stevel static void
   1853  1708   stevel ntwdt_set_cfgvar_noreply(int var, int val)
   1854  1708   stevel {
   1855  1708   stevel 	ntwdt_set_cfgvar(var, val);
   1856  1708   stevel }
   1857  1708   stevel 
   1858  1708   stevel #ifdef DEBUG
   1859  1708   stevel /*
   1860  1708   stevel  * Read a specified WDT Property from ScApp.
   1861  1708   stevel  *
   1862  1708   stevel  * <Property> is passed in the Request of the LW8_MBOX_WDT_GET
   1863  1708   stevel  * (SBBC) mailbox message, and the Property's <Value>
   1864  1708   stevel  * is returned in the message's Response.  The SBBC mailbox
   1865  1708   stevel  * resides in IOSRAM.
   1866  1708   stevel  */
   1867  1708   stevel static int
   1868  1708   stevel ntwdt_get_cfgvar(int var, int *val)
   1869  1708   stevel {
   1870  1708   stevel 	lw8_get_wdt_t	get_wdt;
   1871  1708   stevel 	int		rv;
   1872  1708   stevel 
   1873  1708   stevel 	rv = ntwdt_lomcmd(LW8_MBOX_WDT_GET, (intptr_t)&get_wdt);
   1874  1708   stevel 	if (rv != 0) {
   1875  1708   stevel 		_NOTE(EMPTY)
   1876  1708   stevel 		NTWDT_DBG(WDT_DBG_PROT, ("MBOX_GET failed: %d", rv));
   1877  1708   stevel 	} else {
   1878  1708   stevel 		switch (var) {
   1879  1708   stevel 		case LW8_WDT_PROP_RECOV:
   1880  1708   stevel 			*val = (uint8_t)get_wdt.recovery_enabled;
   1881  1708   stevel 			NTWDT_DBG(WDT_DBG_PROT, ("MBOX_GET of 'reset-enabled':"
   1882  1708   stevel 			    " %s (%d)", (*val != 0) ? "enabled" : "disabled",
   1883  1708   stevel 			    *val));
   1884  1708   stevel 			break;
   1885  1708   stevel 
   1886  1708   stevel 		case LW8_WDT_PROP_WDT:
   1887  1708   stevel 			*val = (uint8_t)get_wdt.watchdog_enabled;
   1888  1708   stevel 			NTWDT_DBG(WDT_DBG_PROT, ("MBOX_GET of 'wdog-enabled':"
   1889  1708   stevel 			    " %s (%d)", (*val != 0) ? "enabled" : "disabled",
   1890  1708   stevel 			    *val));
   1891  1708   stevel 			break;
   1892  1708   stevel 
   1893  1708   stevel 		case LW8_WDT_PROP_TO:
   1894  1708   stevel 			*val = (uint8_t)get_wdt.timeout;
   1895  1708   stevel 			NTWDT_DBG(WDT_DBG_PROT, ("MBOX_GET of 'wdog-timeout':"
   1896  1708   stevel 			    " %d seconds", *val));
   1897  1708   stevel 			break;
   1898  1708   stevel 
   1899  1708   stevel 		default:
   1900  1708   stevel 			ASSERT(0);
   1901  1708   stevel 			_NOTE(NOTREACHED)
   1902  1708   stevel 		}
   1903  1708   stevel 	}
   1904  1708   stevel 
   1905  1708   stevel 	return (rv);
   1906  1708   stevel }
   1907  1708   stevel #endif
   1908  1708   stevel 
   1909  1708   stevel /*
   1910  1708   stevel  * Update the real system "heartbeat", which resides in IOSRAM.
   1911  1708   stevel  * This "heartbeat" is normally used in SWDT Mode, but when
   1912  1708   stevel  * in AWDT Mode, ScApp also uses its value to determine if Solaris
   1913  1708   stevel  * is up-and-running.
   1914  1708   stevel  */
   1915  1708   stevel static void
   1916  1708   stevel ntwdt_pat_hw_watchdog()
   1917  1708   stevel {
   1918  1708   stevel 	tod_iosram_t	tod_buf;
   1919  1708   stevel 	static uint32_t	i_am_alive = 0;
   1920  1708   stevel #ifdef DEBUG
   1921  1708   stevel 	if (ntwdt_stop_heart != 0)
   1922  1708   stevel 		return;
   1923  1708   stevel #endif
   1924  1708   stevel 	/* Update the system heartbeat */
   1925  1708   stevel 	if (i_am_alive == UINT32_MAX)
   1926  1708   stevel 		i_am_alive = 0;
   1927  1708   stevel 	else
   1928  1708   stevel 		i_am_alive++;
   1929  1708   stevel 
   1930  1708   stevel 	NTWDT_DBG(WDT_DBG_HEART, ("update heartbeat: %d",
   1931  1708   stevel 	    i_am_alive));
   1932  1708   stevel 
   1933  1708   stevel 	if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_i_am_alive),
   1934  7799  Richard 	    (char *)&i_am_alive, sizeof (uint32_t))) {
   1935  1708   stevel 		cmn_err(CE_WARN, "ntwdt_pat_hw_watchdog(): "
   1936  1708   stevel 		    "write heartbeat failed");
   1937  1708   stevel 	}
   1938  1708   stevel }
   1939  1708   stevel 
   1940  1708   stevel /*
   1941  1708   stevel  * Write the specified value to the system's normal (IOSRAM)
   1942  1708   stevel  * location that's used to specify Solaris' watchdog-timeout
   1943  1708   stevel  * on Serengeti platforms.
   1944  1708   stevel  *
   1945  1708   stevel  * In SWDT Mode, this location can hold values [0,n).
   1946  1708   stevel  * In AWDT Mode, this location must have value 0 (else
   1947  1708   stevel  * after a ScApp-reboot, ScApp could mistakenly interpret
   1948  1708   stevel  * that the system is in SWDT Mode).
   1949  1708   stevel  */
   1950  1708   stevel static int
   1951  1708   stevel ntwdt_set_hw_timeout(uint32_t period)
   1952  1708   stevel {
   1953  1708   stevel 	tod_iosram_t	tod_buf;
   1954  1708   stevel 	int		rv;
   1955  1708   stevel 
   1956  1708   stevel 	rv = iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
   1957  1708   stevel 	    (char *)&period, sizeof (uint32_t));
   1958  1708   stevel 	if (rv != 0)
   1959  1708   stevel 		cmn_err(CE_WARN, "write of %d for TOD timeout "
   1960  1708   stevel 		    "period failed: %d", period, rv);
   1961  1708   stevel 
   1962  1708   stevel 	return (rv);
   1963  1708   stevel }
   1964  1708   stevel 
   1965  1708   stevel /*
   1966  1708   stevel  * Soft-interrupt handler that is triggered when ScApp wants
   1967  1708   stevel  * to know the current state of the app-wdog.
   1968  1708   stevel  *
   1969  1708   stevel  * Grab ntwdt_wdog_mutex so that we synchronize with any
   1970  1708   stevel  * concurrent User Context and Interrupt Context activity.  Call
   1971  1708   stevel  * a function that writes a permutation of the watchdog state
   1972  1708   stevel  * to the SC, then release the mutex.
   1973  1708   stevel  *
   1974  1708   stevel  * We grab the mutex not only so that each variable is consistent
   1975  1708   stevel  * but also so that the *permutation* of variables is consistent.
   1976  1708   stevel  * I.e., any set of one or more variables (that we write to SC
   1977  1708   stevel  * using multiple mailbox commands) will truly be seen as a
   1978  1708   stevel  * consistent snapshot.  Note that if our protocol had a MBOX_SET
   1979  1708   stevel  * command that allowed writing all watchdog state in one
   1980  1708   stevel  * command, then the lock-hold latency would be greatly reduced.
   1981  1708   stevel  * To our advantage, this softint normally executes very
   1982  1708   stevel  * infrequently.
   1983  1708   stevel  *
   1984  1708   stevel  * Context:
   1985  1708   stevel  *  called at Interrupt Context (DDI_SOFTINT_LOW)
   1986  1708   stevel  */
   1987  1708   stevel static uint_t
   1988  1708   stevel ntwdt_mbox_softint(char *arg)
   1989  1708   stevel {
   1990  1708   stevel 	ntwdt_wdog_t	*wdog_state;
   1991  1708   stevel 
   1992  1708   stevel 	wdog_state = ((ntwdt_state_t *)arg)->ntwdt_wdog_state;
   1993  1708   stevel 
   1994  1708   stevel 	ASSERT(wdog_state != NULL);
   1995  1708   stevel 
   1996  1708   stevel 	mutex_enter(&wdog_state->ntwdt_wdog_mutex);
   1997  1708   stevel 
   1998  1708   stevel 	/* tell ScApp state of AWDT */
   1999  1708   stevel 	ntwdt_set_awdt_state(wdog_state);
   2000  1708   stevel 
   2001  1708   stevel 	mutex_exit(&wdog_state->ntwdt_wdog_mutex);
   2002  1708   stevel 
   2003  1708   stevel 	return (DDI_INTR_CLAIMED);
   2004  1708   stevel }
   2005  1708   stevel 
   2006  1708   stevel /*
   2007  1708   stevel  * Handle MBOX_EVENT_LW8 Events that are sent from ScApp.
   2008  1708   stevel  *
   2009  1708   stevel  * The only (sub-)type of Event we handle is the
   2010  1708   stevel  * LW8_EVENT_SC_RESTARTED Event.  We handle this by triggering
   2011  1708   stevel  * a soft-interrupt only if we are in AWDT mode.
   2012  1708   stevel  *
   2013  1708   stevel  * ScApp sends this Event when it wants to learn the current
   2014  1708   stevel  * state of the AWDT variables.  Design-wise, this is used to
   2015  1708   stevel  * handle the case where the SC reboots while the system is in
   2016  1708   stevel  * AWDT mode (if the SC reboots in SWDT mode, then ScApp
   2017  1708   stevel  * already knows all necessary info and therefore won't send
   2018  1708   stevel  * this Event).
   2019  1708   stevel  *
   2020  1708   stevel  * Context:
   2021  1708   stevel  *  function is called in Interrupt Context (at DDI_SOFTINT_MED)
   2022  1708   stevel  *  and we conditionally trigger a softint that will run at
   2023  1708   stevel  *  DDI_SOFTINT_LOW.  Note that function executes at
   2024  1708   stevel  *  DDI_SOFTINT_MED due to how this handler was registered by
   2025  1708   stevel  *  the implementation of sbbc_mbox_reg_intr().
   2026  1708   stevel  *
   2027  1708   stevel  * Notes:
   2028  1708   stevel  *  Currently, the LW8_EVENT_SC_RESTARTED Event is only sent
   2029  1708   stevel  *  by SC when in AWDT mode.
   2030  1708   stevel  */
   2031  1708   stevel static uint_t
   2032  1708   stevel ntwdt_event_data_handler(char *arg)
   2033  1708   stevel {
   2034  1708   stevel 	lw8_event_t	*payload;
   2035  1708   stevel 	sbbc_msg_t	*msg;
   2036  1708   stevel 
   2037  1708   stevel 	if (arg == NULL) {
   2038  1708   stevel 		return (DDI_INTR_CLAIMED);
   2039  1708   stevel 	}
   2040  1708   stevel 
   2041  1708   stevel 	msg = (sbbc_msg_t *)arg;
   2042  1708   stevel 	if (msg->msg_buf == NULL) {
   2043  1708   stevel 		return (DDI_INTR_CLAIMED);
   2044  1708   stevel 	}
   2045  1708   stevel 
   2046  1708   stevel 	payload = (lw8_event_t *)msg->msg_buf;
   2047  1708   stevel 
   2048  1708   stevel 	switch (payload->event_type) {
   2049  1708   stevel 	case LW8_EVENT_SC_RESTARTED:
   2050  1708   stevel 		/*
   2051  1708   stevel 		 * then SC probably was rebooted, and it therefore
   2052  1708   stevel 		 * needs to know what the current state of AWDT is.
   2053  1708   stevel 		 */
   2054  1708   stevel 		NTWDT_DBG(WDT_DBG_EVENT, ("LW8_EVENT_SC_RESTARTED "
   2055  1708   stevel 		    "received in %s mode",
   2056  1708   stevel 		    (ntwdt_watchdog_activated != 0) ? "AWDT" : "SWDT"));
   2057  1708   stevel 
   2058  1708   stevel 		if (ntwdt_watchdog_activated != 0) {
   2059  1708   stevel 			/* then system is in AWDT mode */
   2060  1708   stevel 			ddi_trigger_softintr(ntwdt_mbox_softint_id);
   2061  1708   stevel 		}
   2062  1708   stevel 		break;
   2063  1708   stevel 
   2064  1708   stevel 	default:
   2065  1708   stevel 		NTWDT_DBG(WDT_DBG_EVENT,
   2066  1708   stevel 		    ("MBOX_EVENT_LW8: %d", payload->event_type));
   2067  1708   stevel 		break;
   2068  1708   stevel 	}
   2069  1708   stevel 
   2070  1708   stevel 	return (DDI_INTR_CLAIMED);
   2071  1708   stevel }
   2072  1708   stevel 
   2073  1708   stevel /*
   2074  1708   stevel  * Send an SBBC Mailbox command to ScApp.
   2075  1708   stevel  *
   2076  1708   stevel  * Use the sbbc_mbox_request_response utility function to
   2077  1708   stevel  * send the Request and receive the optional Response.
   2078  1708   stevel  *
   2079  1708   stevel  * Context:
   2080  1708   stevel  *  can be called from Interrupt Context or User Context.
   2081  1708   stevel  */
   2082  1708   stevel static int
   2083  1708   stevel ntwdt_lomcmd(int cmd, intptr_t arg)
   2084  1708   stevel {
   2085  1708   stevel 	sbbc_msg_t	request;
   2086  1708   stevel 	sbbc_msg_t	*reqp;
   2087  1708   stevel 	sbbc_msg_t	response;
   2088  1708   stevel 	sbbc_msg_t	*resp;
   2089  1708   stevel 	int		rv = 0;
   2090  1708   stevel 
   2091  1708   stevel 	reqp = &request;
   2092  1708   stevel 	bzero((caddr_t)&request, sizeof (request));
   2093  1708   stevel 	reqp->msg_type.type = LW8_MBOX;
   2094  1708   stevel 	reqp->msg_type.sub_type = (uint16_t)cmd;
   2095  1708   stevel 
   2096  1708   stevel 	resp = &response;
   2097  1708   stevel 	bzero((caddr_t)&response, sizeof (response));
   2098  1708   stevel 	resp->msg_type.type = LW8_MBOX;
   2099  1708   stevel 	resp->msg_type.sub_type = (uint16_t)cmd;
   2100  1708   stevel 
   2101  1708   stevel 	switch (cmd) {
   2102  1708   stevel 	case LW8_MBOX_WDT_GET:
   2103  1708   stevel 		reqp->msg_len = 0;
   2104  1708   stevel 		reqp->msg_buf = (caddr_t)NULL;
   2105  1708   stevel 		resp->msg_len = sizeof (lw8_get_wdt_t);
   2106  1708   stevel 		resp->msg_buf = (caddr_t)arg;
   2107  1708   stevel 		break;
   2108  1708   stevel 
   2109  1708   stevel 	case LW8_MBOX_WDT_SET:
   2110  1708   stevel 		reqp->msg_len = sizeof (lw8_set_wdt_t);
   2111  1708   stevel 		reqp->msg_buf = (caddr_t)arg;
   2112  1708   stevel 		resp->msg_len = 0;
   2113  1708   stevel 		resp->msg_buf = (caddr_t)NULL;
   2114  1708   stevel 		break;
   2115  1708   stevel 
   2116  1708   stevel 	default:
   2117  1708   stevel 		return (EINVAL);
   2118  1708   stevel 	}
   2119  1708   stevel 
   2120  1708   stevel 	rv = sbbc_mbox_request_response(reqp, resp,
   2121  7799  Richard 	    LW8_DEFAULT_MAX_MBOX_WAIT_TIME);
   2122  1708   stevel 
   2123  1708   stevel 	if ((rv) || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
   2124  1708   stevel 
   2125  1708   stevel 		NTWDT_NDBG(WDT_DBG_PROT, ("SBBC mailbox error:"
   2126  1708   stevel 		    " (rv/msg_status)=(%d/%d)", rv, resp->msg_status));
   2127  1708   stevel 
   2128  1708   stevel 		/* errors from sgsbbc */
   2129  1708   stevel 		if (resp->msg_status > 0) {
   2130  1708   stevel 			return (resp->msg_status);
   2131  1708   stevel 		}
   2132  1708   stevel 
   2133  1708   stevel 		/* errors from ScApp */
   2134  1708   stevel 		switch (resp->msg_status) {
   2135  1708   stevel 		case SG_MBOX_STATUS_ILLEGAL_PARAMETER:
   2136  1708   stevel 			/* illegal ioctl parameter */
   2137  1708   stevel 			return (EINVAL);
   2138  1708   stevel 
   2139  1708   stevel 		default:
   2140  1708   stevel 			return (EIO);
   2141  1708   stevel 		}
   2142  1708   stevel 	}
   2143  1708   stevel 	return (0);
   2144  1708   stevel }
   2145