1*406c76faSDavid du Colombier /*
2*406c76faSDavid du Colombier * watchdog framework
3*406c76faSDavid du Colombier */
49ef1f84bSDavid du Colombier #include "u.h"
59ef1f84bSDavid du Colombier #include "../port/lib.h"
69ef1f84bSDavid du Colombier #include "mem.h"
79ef1f84bSDavid du Colombier #include "dat.h"
89ef1f84bSDavid du Colombier #include "fns.h"
99ef1f84bSDavid du Colombier #include "io.h"
109ef1f84bSDavid du Colombier #include "../port/error.h"
119ef1f84bSDavid du Colombier
129ef1f84bSDavid du Colombier enum {
139ef1f84bSDavid du Colombier Qdir,
149ef1f84bSDavid du Colombier Qwdctl,
159ef1f84bSDavid du Colombier };
169ef1f84bSDavid du Colombier
17*406c76faSDavid du Colombier /*
18*406c76faSDavid du Colombier * these are exposed so that delay() and the like can disable the watchdog
19*406c76faSDavid du Colombier * before busy looping for a long time.
20*406c76faSDavid du Colombier */
21*406c76faSDavid du Colombier Watchdog*watchdog;
22*406c76faSDavid du Colombier int watchdogon;
23*406c76faSDavid du Colombier
249ef1f84bSDavid du Colombier static Watchdog *wd;
25*406c76faSDavid du Colombier static int wdautopet;
26*406c76faSDavid du Colombier static int wdclock0called;
27*406c76faSDavid du Colombier static Ref refs;
289ef1f84bSDavid du Colombier static Dirtab wddir[] = {
29*406c76faSDavid du Colombier ".", { Qdir, 0, QTDIR }, 0, 0555,
30*406c76faSDavid du Colombier "wdctl", { Qwdctl, 0 }, 0, 0664,
319ef1f84bSDavid du Colombier };
329ef1f84bSDavid du Colombier
339ef1f84bSDavid du Colombier
349ef1f84bSDavid du Colombier void
addwatchdog(Watchdog * wdog)35*406c76faSDavid du Colombier addwatchdog(Watchdog *wdog)
369ef1f84bSDavid du Colombier {
379ef1f84bSDavid du Colombier if(wd){
389ef1f84bSDavid du Colombier print("addwatchdog: watchdog already installed\n");
399ef1f84bSDavid du Colombier return;
409ef1f84bSDavid du Colombier }
41*406c76faSDavid du Colombier wd = watchdog = wdog;
429ef1f84bSDavid du Colombier if(wd)
439ef1f84bSDavid du Colombier wd->disable();
449ef1f84bSDavid du Colombier }
459ef1f84bSDavid du Colombier
46*406c76faSDavid du Colombier static int
wdallowed(void)47*406c76faSDavid du Colombier wdallowed(void)
48*406c76faSDavid du Colombier {
49*406c76faSDavid du Colombier return getconf("*nowatchdog") == nil;
50*406c76faSDavid du Colombier }
51*406c76faSDavid du Colombier
52*406c76faSDavid du Colombier static void
wdshutdown(void)53*406c76faSDavid du Colombier wdshutdown(void)
54*406c76faSDavid du Colombier {
55*406c76faSDavid du Colombier if (wd) {
56*406c76faSDavid du Colombier wd->disable();
57*406c76faSDavid du Colombier watchdogon = 0;
58*406c76faSDavid du Colombier }
59*406c76faSDavid du Colombier }
60*406c76faSDavid du Colombier
61*406c76faSDavid du Colombier /* called from clock interrupt, so restart needs ilock internally */
62*406c76faSDavid du Colombier static void
wdpet(void)63*406c76faSDavid du Colombier wdpet(void)
64*406c76faSDavid du Colombier {
65*406c76faSDavid du Colombier /* watchdog could be paused; if so, don't restart */
66*406c76faSDavid du Colombier if (wdautopet && watchdogon)
67*406c76faSDavid du Colombier wd->restart();
68*406c76faSDavid du Colombier }
69*406c76faSDavid du Colombier
70*406c76faSDavid du Colombier /*
71*406c76faSDavid du Colombier * reassure the watchdog from the clock interrupt
72*406c76faSDavid du Colombier * until the user takes control of it.
73*406c76faSDavid du Colombier */
74*406c76faSDavid du Colombier static void
wdautostart(void)75*406c76faSDavid du Colombier wdautostart(void)
76*406c76faSDavid du Colombier {
77*406c76faSDavid du Colombier if (wdautopet || !wd || !wdallowed())
78*406c76faSDavid du Colombier return;
79*406c76faSDavid du Colombier if (waserror()) {
80*406c76faSDavid du Colombier print("watchdog: automatic enable failed\n");
81*406c76faSDavid du Colombier return;
82*406c76faSDavid du Colombier }
83*406c76faSDavid du Colombier wd->enable();
84*406c76faSDavid du Colombier poperror();
85*406c76faSDavid du Colombier
86*406c76faSDavid du Colombier wdautopet = watchdogon = 1;
87*406c76faSDavid du Colombier if (!wdclock0called) {
88*406c76faSDavid du Colombier addclock0link(wdpet, 200);
89*406c76faSDavid du Colombier wdclock0called = 1;
90*406c76faSDavid du Colombier }
91*406c76faSDavid du Colombier }
92*406c76faSDavid du Colombier
93*406c76faSDavid du Colombier /*
94*406c76faSDavid du Colombier * disable strokes from the clock interrupt.
95*406c76faSDavid du Colombier * have to disable the watchdog to mark it `not in use'.
96*406c76faSDavid du Colombier */
97*406c76faSDavid du Colombier static void
wdautostop(void)98*406c76faSDavid du Colombier wdautostop(void)
99*406c76faSDavid du Colombier {
100*406c76faSDavid du Colombier if (!wdautopet)
101*406c76faSDavid du Colombier return;
102*406c76faSDavid du Colombier wdautopet = 0;
103*406c76faSDavid du Colombier wdshutdown();
104*406c76faSDavid du Colombier }
105*406c76faSDavid du Colombier
106*406c76faSDavid du Colombier /*
107*406c76faSDavid du Colombier * user processes exist and up is non-nil when the
108*406c76faSDavid du Colombier * device init routines are called.
109*406c76faSDavid du Colombier */
110*406c76faSDavid du Colombier static void
wdinit(void)111*406c76faSDavid du Colombier wdinit(void)
112*406c76faSDavid du Colombier {
113*406c76faSDavid du Colombier wdautostart();
114*406c76faSDavid du Colombier }
115*406c76faSDavid du Colombier
1169ef1f84bSDavid du Colombier static Chan*
wdattach(char * spec)1179ef1f84bSDavid du Colombier wdattach(char *spec)
1189ef1f84bSDavid du Colombier {
1199ef1f84bSDavid du Colombier return devattach('w', spec);
1209ef1f84bSDavid du Colombier }
1219ef1f84bSDavid du Colombier
1229ef1f84bSDavid du Colombier static Walkqid*
wdwalk(Chan * c,Chan * nc,char ** name,int nname)1239ef1f84bSDavid du Colombier wdwalk(Chan *c, Chan *nc, char **name, int nname)
1249ef1f84bSDavid du Colombier {
1259ef1f84bSDavid du Colombier return devwalk(c, nc, name, nname, wddir, nelem(wddir), devgen);
1269ef1f84bSDavid du Colombier }
1279ef1f84bSDavid du Colombier
1289ef1f84bSDavid du Colombier static long
wdstat(Chan * c,uchar * dp,long n)1299ef1f84bSDavid du Colombier wdstat(Chan *c, uchar *dp, long n)
1309ef1f84bSDavid du Colombier {
1319ef1f84bSDavid du Colombier return devstat(c, dp, n, wddir, nelem(wddir), devgen);
1329ef1f84bSDavid du Colombier }
1339ef1f84bSDavid du Colombier
1349ef1f84bSDavid du Colombier static Chan*
wdopen(Chan * c,int omode)1359ef1f84bSDavid du Colombier wdopen(Chan* c, int omode)
1369ef1f84bSDavid du Colombier {
137*406c76faSDavid du Colombier wdautostop();
138*406c76faSDavid du Colombier c = devopen(c, omode, wddir, nelem(wddir), devgen);
139*406c76faSDavid du Colombier if (c->qid.path == Qwdctl)
140*406c76faSDavid du Colombier incref(&refs);
141*406c76faSDavid du Colombier return c;
1429ef1f84bSDavid du Colombier }
1439ef1f84bSDavid du Colombier
1449ef1f84bSDavid du Colombier static void
wdclose(Chan * c)145*406c76faSDavid du Colombier wdclose(Chan *c)
1469ef1f84bSDavid du Colombier {
147*406c76faSDavid du Colombier if(c->qid.path == Qwdctl && c->flag&COPEN && decref(&refs) <= 0)
148*406c76faSDavid du Colombier wdshutdown();
1499ef1f84bSDavid du Colombier }
1509ef1f84bSDavid du Colombier
1519ef1f84bSDavid du Colombier static long
wdread(Chan * c,void * a,long n,vlong off)1529ef1f84bSDavid du Colombier wdread(Chan* c, void* a, long n, vlong off)
1539ef1f84bSDavid du Colombier {
1549ef1f84bSDavid du Colombier long offset;
1559ef1f84bSDavid du Colombier char s[READSTR];
1569ef1f84bSDavid du Colombier
1579ef1f84bSDavid du Colombier offset = off;
1589ef1f84bSDavid du Colombier switch((ulong)c->qid.path){
1599ef1f84bSDavid du Colombier case Qdir:
1609ef1f84bSDavid du Colombier return devdirread(c, a, n, wddir, nelem(wddir), devgen);
1619ef1f84bSDavid du Colombier
1629ef1f84bSDavid du Colombier case Qwdctl:
1639ef1f84bSDavid du Colombier if(wd == nil || wd->stat == nil)
1649ef1f84bSDavid du Colombier return 0;
1659ef1f84bSDavid du Colombier
1669ef1f84bSDavid du Colombier wd->stat(s, s + READSTR);
1679ef1f84bSDavid du Colombier return readstr(offset, a, n, s);
1689ef1f84bSDavid du Colombier
1699ef1f84bSDavid du Colombier default:
1709ef1f84bSDavid du Colombier error(Egreg);
1719ef1f84bSDavid du Colombier break;
1729ef1f84bSDavid du Colombier }
1739ef1f84bSDavid du Colombier return 0;
1749ef1f84bSDavid du Colombier }
1759ef1f84bSDavid du Colombier
1769ef1f84bSDavid du Colombier static long
wdwrite(Chan * c,void * a,long n,vlong off)1779ef1f84bSDavid du Colombier wdwrite(Chan* c, void* a, long n, vlong off)
1789ef1f84bSDavid du Colombier {
1799ef1f84bSDavid du Colombier char *p;
1809ef1f84bSDavid du Colombier
1819ef1f84bSDavid du Colombier switch((ulong)c->qid.path){
1829ef1f84bSDavid du Colombier case Qdir:
1839ef1f84bSDavid du Colombier error(Eperm);
1849ef1f84bSDavid du Colombier
1859ef1f84bSDavid du Colombier case Qwdctl:
1869ef1f84bSDavid du Colombier if(wd == nil)
1879ef1f84bSDavid du Colombier return n;
1889ef1f84bSDavid du Colombier
1899ef1f84bSDavid du Colombier if(off != 0ll)
1909ef1f84bSDavid du Colombier error(Ebadarg);
1919ef1f84bSDavid du Colombier
1929ef1f84bSDavid du Colombier if(p = strchr(a, '\n'))
1939ef1f84bSDavid du Colombier *p = 0;
1949ef1f84bSDavid du Colombier
1959ef1f84bSDavid du Colombier if(!strncmp(a, "enable", n))
1969ef1f84bSDavid du Colombier wd->enable();
1979ef1f84bSDavid du Colombier else if(!strncmp(a, "disable", n))
1989ef1f84bSDavid du Colombier wd->disable();
1999ef1f84bSDavid du Colombier else if(!strncmp(a, "restart", n))
2009ef1f84bSDavid du Colombier wd->restart();
2019ef1f84bSDavid du Colombier else
2029ef1f84bSDavid du Colombier error(Ebadarg);
2039ef1f84bSDavid du Colombier return n;
2049ef1f84bSDavid du Colombier
2059ef1f84bSDavid du Colombier default:
2069ef1f84bSDavid du Colombier error(Egreg);
2079ef1f84bSDavid du Colombier break;
2089ef1f84bSDavid du Colombier }
2099ef1f84bSDavid du Colombier
2109ef1f84bSDavid du Colombier return 0;
2119ef1f84bSDavid du Colombier }
2129ef1f84bSDavid du Colombier
2139ef1f84bSDavid du Colombier Dev wddevtab = {
2149ef1f84bSDavid du Colombier 'w',
2159ef1f84bSDavid du Colombier "watchdog",
2169ef1f84bSDavid du Colombier
2179ef1f84bSDavid du Colombier devreset,
218*406c76faSDavid du Colombier wdinit,
219*406c76faSDavid du Colombier wdshutdown,
2209ef1f84bSDavid du Colombier wdattach,
2219ef1f84bSDavid du Colombier wdwalk,
2229ef1f84bSDavid du Colombier wdstat,
2239ef1f84bSDavid du Colombier wdopen,
2249ef1f84bSDavid du Colombier devcreate,
2259ef1f84bSDavid du Colombier wdclose,
2269ef1f84bSDavid du Colombier wdread,
2279ef1f84bSDavid du Colombier devbread,
2289ef1f84bSDavid du Colombier wdwrite,
2299ef1f84bSDavid du Colombier devbwrite,
2309ef1f84bSDavid du Colombier devremove,
2319ef1f84bSDavid du Colombier devwstat,
2329ef1f84bSDavid du Colombier devpower,
2339ef1f84bSDavid du Colombier };
234