xref: /plan9-contrib/sys/src/9k/port/devwd.c (revision 406c76facc4b13aa2a55454bf4091aab9f03da22)
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