sysmon.c revision 1.3 1 1.3 thorpej /* $NetBSD: sysmon.c,v 1.3 2000/11/04 18:37:19 thorpej Exp $ */
2 1.1 thorpej
3 1.1 thorpej /*-
4 1.1 thorpej * Copyright (c) 2000 Zembu Labs, Inc.
5 1.1 thorpej * All rights reserved.
6 1.1 thorpej *
7 1.1 thorpej * Author: Jason R. Thorpe <thorpej (at) zembu.com>
8 1.1 thorpej *
9 1.1 thorpej * Redistribution and use in source and binary forms, with or without
10 1.1 thorpej * modification, are permitted provided that the following conditions
11 1.1 thorpej * are met:
12 1.1 thorpej * 1. Redistributions of source code must retain the above copyright
13 1.1 thorpej * notice, this list of conditions and the following disclaimer.
14 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 thorpej * notice, this list of conditions and the following disclaimer in the
16 1.1 thorpej * documentation and/or other materials provided with the distribution.
17 1.1 thorpej * 3. All advertising materials mentioning features or use of this software
18 1.1 thorpej * must display the following acknowledgement:
19 1.1 thorpej * This product includes software developed by Zembu Labs, Inc.
20 1.1 thorpej * 4. Neither the name of Zembu Labs nor the names of its employees may
21 1.1 thorpej * be used to endorse or promote products derived from this software
22 1.1 thorpej * without specific prior written permission.
23 1.1 thorpej *
24 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY ZEMBU LABS, INC. ``AS IS'' AND ANY EXPRESS
25 1.1 thorpej * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR-
26 1.1 thorpej * RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS-
27 1.1 thorpej * CLAIMED. IN NO EVENT SHALL ZEMBU LABS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 1.1 thorpej * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 1.1 thorpej * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 1.1 thorpej * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 1.1 thorpej * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 1.1 thorpej * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 1.1 thorpej * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 1.1 thorpej */
35 1.1 thorpej
36 1.1 thorpej /*
37 1.1 thorpej * Clearing house for system monitoring hardware. This pseudo-device
38 1.1 thorpej * is a place where hardware monitors such as the LM78 and VIA 82C686A
39 1.1 thorpej * (or even ACPI, eventually) can register themselves to provide
40 1.3 thorpej * backplane fan and temperature information, etc. It also provides
41 1.3 thorpej * a place to register watchdog timers, and provides an abstract
42 1.3 thorpej * interface to them.
43 1.1 thorpej */
44 1.1 thorpej
45 1.1 thorpej #include <sys/param.h>
46 1.1 thorpej #include <sys/conf.h>
47 1.1 thorpej #include <sys/errno.h>
48 1.1 thorpej #include <sys/fcntl.h>
49 1.1 thorpej #include <sys/lock.h>
50 1.3 thorpej #include <sys/callout.h>
51 1.3 thorpej #include <sys/kernel.h>
52 1.3 thorpej #include <sys/systm.h>
53 1.3 thorpej #include <sys/proc.h>
54 1.1 thorpej
55 1.1 thorpej #include <dev/sysmon/sysmonvar.h>
56 1.1 thorpej
57 1.1 thorpej /*
58 1.1 thorpej * We run at ENVSYS version 1.
59 1.1 thorpej */
60 1.1 thorpej #define SYSMON_ENVSYS_VERSION (1 * 1000)
61 1.1 thorpej
62 1.3 thorpej struct lock sysmon_envsys_lock;
63 1.1 thorpej
64 1.3 thorpej LIST_HEAD(, sysmon_envsys) sysmon_envsys_list =
65 1.3 thorpej LIST_HEAD_INITIALIZER(&sysmon_envsys_list);
66 1.1 thorpej struct simplelock sysmon_envsys_list_slock = SIMPLELOCK_INITIALIZER;
67 1.1 thorpej u_int sysmon_envsys_next_sensor_index;
68 1.1 thorpej
69 1.3 thorpej int sysmon_envsys_initialized;
70 1.3 thorpej struct simplelock sysmon_envsys_initialized_slock = SIMPLELOCK_INITIALIZER;
71 1.1 thorpej
72 1.1 thorpej cdev_decl(sysmon);
73 1.1 thorpej
74 1.3 thorpej void sysmon_envsys_init(void);
75 1.3 thorpej
76 1.3 thorpej int sysmonioctl_envsys(dev_t, u_long, caddr_t, int, struct proc *);
77 1.3 thorpej int sysmonioctl_wdog(dev_t, u_long, caddr_t, int, struct proc *);
78 1.1 thorpej
79 1.1 thorpej struct sysmon_envsys *sysmon_envsys_find(u_int);
80 1.1 thorpej void sysmon_envsys_release(struct sysmon_envsys *);
81 1.1 thorpej
82 1.3 thorpej LIST_HEAD(, sysmon_wdog) sysmon_wdog_list =
83 1.3 thorpej LIST_HEAD_INITIALIZER(&sysmon_wdog_list);
84 1.3 thorpej int sysmon_wdog_count;
85 1.3 thorpej struct simplelock sysmon_wdog_list_slock = SIMPLELOCK_INITIALIZER;
86 1.3 thorpej
87 1.3 thorpej struct simplelock sysmon_wdog_slock = SIMPLELOCK_INITIALIZER;
88 1.3 thorpej struct sysmon_wdog *sysmon_armed_wdog;
89 1.3 thorpej struct callout sysmon_wdog_callout = CALLOUT_INITIALIZER;
90 1.3 thorpej void *sysmon_wdog_sdhook;
91 1.3 thorpej
92 1.3 thorpej #define SYSMON_WDOG_LOCK(s) \
93 1.3 thorpej do { \
94 1.3 thorpej s = splsoftclock(); \
95 1.3 thorpej simple_lock(&sysmon_wdog_slock); \
96 1.3 thorpej } while (0)
97 1.3 thorpej
98 1.3 thorpej #define SYSMON_WDOG_UNLOCK(s) \
99 1.3 thorpej do { \
100 1.3 thorpej simple_unlock(&sysmon_wdog_slock); \
101 1.3 thorpej splx(s); \
102 1.3 thorpej } while (0)
103 1.3 thorpej
104 1.3 thorpej struct sysmon_wdog *sysmon_wdog_find(const char *);
105 1.3 thorpej void sysmon_wdog_release(struct sysmon_wdog *);
106 1.3 thorpej int sysmon_wdog_setmode(struct sysmon_wdog *, int, u_int);
107 1.3 thorpej void sysmon_wdog_ktickle(void *);
108 1.3 thorpej void sysmon_wdog_shutdown(void *);
109 1.3 thorpej
110 1.3 thorpej #define SYSMON_MINOR_ENVSYS 0
111 1.3 thorpej #define SYSMON_MINOR_WDOG 1
112 1.3 thorpej
113 1.1 thorpej /*
114 1.3 thorpej * sysmon_envsys_init:
115 1.1 thorpej *
116 1.1 thorpej * Initialize the system monitor.
117 1.1 thorpej */
118 1.1 thorpej void
119 1.3 thorpej sysmon_envsys_init(void)
120 1.1 thorpej {
121 1.1 thorpej
122 1.3 thorpej lockinit(&sysmon_envsys_lock, PWAIT|PCATCH, "smenv", 0, 0);
123 1.3 thorpej sysmon_envsys_initialized = 1;
124 1.1 thorpej }
125 1.1 thorpej
126 1.1 thorpej /*
127 1.1 thorpej * sysmonopen:
128 1.1 thorpej *
129 1.1 thorpej * Open the system monitor device.
130 1.1 thorpej */
131 1.1 thorpej int
132 1.1 thorpej sysmonopen(dev_t dev, int flag, int mode, struct proc *p)
133 1.1 thorpej {
134 1.3 thorpej int error = 0;
135 1.3 thorpej
136 1.3 thorpej switch (minor(dev)) {
137 1.3 thorpej case SYSMON_MINOR_ENVSYS:
138 1.3 thorpej simple_lock(&sysmon_envsys_initialized_slock);
139 1.3 thorpej if (sysmon_envsys_initialized == 0)
140 1.3 thorpej sysmon_envsys_init();
141 1.3 thorpej
142 1.3 thorpej error = lockmgr(&sysmon_envsys_lock,
143 1.3 thorpej LK_EXCLUSIVE | LK_INTERLOCK |
144 1.3 thorpej ((flag & O_NONBLOCK) ? LK_NOWAIT : 0),
145 1.3 thorpej &sysmon_envsys_initialized_slock);
146 1.3 thorpej break;
147 1.3 thorpej
148 1.3 thorpej case SYSMON_MINOR_WDOG:
149 1.3 thorpej simple_lock(&sysmon_wdog_list_slock);
150 1.3 thorpej if (sysmon_wdog_sdhook == NULL) {
151 1.3 thorpej sysmon_wdog_sdhook =
152 1.3 thorpej shutdownhook_establish(sysmon_wdog_shutdown, NULL);
153 1.3 thorpej if (sysmon_wdog_sdhook == NULL)
154 1.3 thorpej printf("WARNING: unable to register watchdog "
155 1.3 thorpej "shutdown hook\n");
156 1.3 thorpej }
157 1.3 thorpej simple_unlock(&sysmon_wdog_list_slock);
158 1.3 thorpej break;
159 1.1 thorpej
160 1.3 thorpej default:
161 1.3 thorpej error = ENODEV;
162 1.3 thorpej }
163 1.1 thorpej
164 1.1 thorpej return (error);
165 1.1 thorpej }
166 1.1 thorpej
167 1.1 thorpej /*
168 1.1 thorpej * sysmonclose:
169 1.1 thorpej *
170 1.1 thorpej * Close the system monitor device.
171 1.1 thorpej */
172 1.1 thorpej int
173 1.1 thorpej sysmonclose(dev_t dev, int flag, int mode, struct proc *p)
174 1.1 thorpej {
175 1.3 thorpej int error = 0;
176 1.3 thorpej
177 1.3 thorpej switch (minor(dev)) {
178 1.3 thorpej case SYSMON_MINOR_ENVSYS:
179 1.3 thorpej (void) lockmgr(&sysmon_envsys_lock, LK_RELEASE, NULL);
180 1.3 thorpej break;
181 1.3 thorpej
182 1.3 thorpej case SYSMON_MINOR_WDOG:
183 1.3 thorpej {
184 1.3 thorpej struct sysmon_wdog *smw;
185 1.3 thorpej int omode, s;
186 1.3 thorpej
187 1.3 thorpej /*
188 1.3 thorpej * If this is the last close, and there is a watchdog
189 1.3 thorpej * running in UTICKLE mode, we need to disable it,
190 1.3 thorpej * otherwise the system will reset in short order.
191 1.3 thorpej *
192 1.3 thorpej * XXX Maybe we should just go into KTICKLE mode?
193 1.3 thorpej */
194 1.3 thorpej SYSMON_WDOG_LOCK(s);
195 1.3 thorpej if ((smw = sysmon_armed_wdog) != NULL) {
196 1.3 thorpej if ((omode = smw->smw_mode) == WDOG_MODE_UTICKLE) {
197 1.3 thorpej error = sysmon_wdog_setmode(smw,
198 1.3 thorpej WDOG_MODE_DISARMED, smw->smw_period);
199 1.3 thorpej if (error) {
200 1.3 thorpej printf("WARNING: UNABLE TO DISARM "
201 1.3 thorpej "WATCHDOG %s ON CLOSE!\n",
202 1.3 thorpej smw->smw_name);
203 1.3 thorpej /*
204 1.3 thorpej * ...we will probably reboot soon.
205 1.3 thorpej */
206 1.3 thorpej }
207 1.3 thorpej }
208 1.3 thorpej }
209 1.3 thorpej SYSMON_WDOG_UNLOCK(s);
210 1.3 thorpej break;
211 1.3 thorpej }
212 1.3 thorpej
213 1.3 thorpej default:
214 1.3 thorpej error = ENODEV;
215 1.3 thorpej }
216 1.1 thorpej
217 1.3 thorpej return (error);
218 1.1 thorpej }
219 1.1 thorpej
220 1.1 thorpej /*
221 1.1 thorpej * sysmonioctl:
222 1.1 thorpej *
223 1.1 thorpej * Perform a control request.
224 1.1 thorpej */
225 1.1 thorpej int
226 1.1 thorpej sysmonioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
227 1.1 thorpej {
228 1.3 thorpej int error;
229 1.3 thorpej
230 1.3 thorpej switch (minor(dev)) {
231 1.3 thorpej case SYSMON_MINOR_ENVSYS:
232 1.3 thorpej error = sysmonioctl_envsys(dev, cmd, data, flag, p);
233 1.3 thorpej break;
234 1.3 thorpej
235 1.3 thorpej case SYSMON_MINOR_WDOG:
236 1.3 thorpej error = sysmonioctl_wdog(dev, cmd, data, flag, p);
237 1.3 thorpej break;
238 1.3 thorpej
239 1.3 thorpej default:
240 1.3 thorpej error = ENODEV;
241 1.3 thorpej }
242 1.3 thorpej
243 1.3 thorpej return (error);
244 1.3 thorpej }
245 1.3 thorpej
246 1.3 thorpej /*
247 1.3 thorpej * sysmonioctl_envsys:
248 1.3 thorpej *
249 1.3 thorpej * Perform an envsys control request.
250 1.3 thorpej */
251 1.3 thorpej int
252 1.3 thorpej sysmonioctl_envsys(dev_t dev, u_long cmd, caddr_t data, int flag,
253 1.3 thorpej struct proc *p)
254 1.3 thorpej {
255 1.1 thorpej struct sysmon_envsys *sme;
256 1.1 thorpej int error = 0;
257 1.1 thorpej u_int oidx;
258 1.1 thorpej
259 1.1 thorpej switch (cmd) {
260 1.1 thorpej /*
261 1.1 thorpej * For ENVSYS commands, we translate the absolute sensor index
262 1.1 thorpej * to a device-relative sensor index.
263 1.1 thorpej */
264 1.1 thorpej case ENVSYS_VERSION:
265 1.1 thorpej *(int32_t *)data = SYSMON_ENVSYS_VERSION;
266 1.1 thorpej break;
267 1.1 thorpej
268 1.1 thorpej case ENVSYS_GRANGE:
269 1.1 thorpej {
270 1.1 thorpej struct envsys_range *rng = (void *) data;
271 1.1 thorpej
272 1.1 thorpej sme = sysmon_envsys_find(0); /* XXX */
273 1.1 thorpej if (sme == NULL) {
274 1.1 thorpej /* Return empty range for `no sensors'. */
275 1.1 thorpej rng->low = 1;
276 1.1 thorpej rng->high = 0;
277 1.1 thorpej break;
278 1.1 thorpej }
279 1.1 thorpej
280 1.1 thorpej if (rng->units < ENVSYS_NSENSORS)
281 1.1 thorpej *rng = sme->sme_ranges[rng->units];
282 1.1 thorpej else {
283 1.1 thorpej /* Return empty range for unsupported sensor types. */
284 1.1 thorpej rng->low = 1;
285 1.1 thorpej rng->high = 0;
286 1.1 thorpej }
287 1.1 thorpej sysmon_envsys_release(sme);
288 1.1 thorpej break;
289 1.1 thorpej }
290 1.1 thorpej
291 1.1 thorpej case ENVSYS_GTREDATA:
292 1.1 thorpej {
293 1.1 thorpej struct envsys_tre_data *tred = (void *) data;
294 1.1 thorpej
295 1.2 thorpej tred->validflags = 0;
296 1.2 thorpej
297 1.1 thorpej sme = sysmon_envsys_find(tred->sensor);
298 1.1 thorpej if (sme == NULL)
299 1.1 thorpej break;
300 1.1 thorpej oidx = tred->sensor;
301 1.1 thorpej tred->sensor = SME_SENSOR_IDX(sme, tred->sensor);
302 1.1 thorpej if (tred->sensor < sme->sme_nsensors)
303 1.1 thorpej error = (*sme->sme_gtredata)(sme, tred);
304 1.1 thorpej tred->sensor = oidx;
305 1.1 thorpej sysmon_envsys_release(sme);
306 1.1 thorpej break;
307 1.1 thorpej }
308 1.1 thorpej
309 1.1 thorpej case ENVSYS_STREINFO:
310 1.1 thorpej {
311 1.1 thorpej struct envsys_basic_info *binfo = (void *) data;
312 1.1 thorpej
313 1.1 thorpej sme = sysmon_envsys_find(binfo->sensor);
314 1.2 thorpej if (sme == NULL) {
315 1.2 thorpej binfo->validflags = 0;
316 1.2 thorpej break;
317 1.2 thorpej }
318 1.1 thorpej oidx = binfo->sensor;
319 1.1 thorpej binfo->sensor = SME_SENSOR_IDX(sme, binfo->sensor);
320 1.1 thorpej if (binfo->sensor < sme->sme_nsensors)
321 1.1 thorpej error = (*sme->sme_streinfo)(sme, binfo);
322 1.1 thorpej else
323 1.1 thorpej binfo->validflags = 0;
324 1.1 thorpej binfo->sensor = oidx;
325 1.1 thorpej sysmon_envsys_release(sme);
326 1.1 thorpej break;
327 1.1 thorpej }
328 1.1 thorpej
329 1.1 thorpej case ENVSYS_GTREINFO:
330 1.1 thorpej {
331 1.1 thorpej struct envsys_basic_info *binfo = (void *) data;
332 1.1 thorpej
333 1.2 thorpej binfo->validflags = 0;
334 1.2 thorpej
335 1.1 thorpej sme = sysmon_envsys_find(binfo->sensor);
336 1.2 thorpej if (sme == NULL)
337 1.2 thorpej break;
338 1.1 thorpej oidx = binfo->sensor;
339 1.1 thorpej binfo->sensor = SME_SENSOR_IDX(sme, binfo->sensor);
340 1.1 thorpej if (binfo->sensor < sme->sme_nsensors)
341 1.1 thorpej *binfo = sme->sme_sensor_info[binfo->sensor];
342 1.1 thorpej binfo->sensor = oidx;
343 1.1 thorpej sysmon_envsys_release(sme);
344 1.1 thorpej break;
345 1.1 thorpej }
346 1.1 thorpej
347 1.1 thorpej default:
348 1.1 thorpej error = ENOTTY;
349 1.1 thorpej }
350 1.1 thorpej
351 1.1 thorpej return (error);
352 1.1 thorpej }
353 1.1 thorpej
354 1.1 thorpej /*
355 1.3 thorpej * sysmonioctl_wdog:
356 1.3 thorpej *
357 1.3 thorpej * Perform a watchdog control request.
358 1.3 thorpej */
359 1.3 thorpej int
360 1.3 thorpej sysmonioctl_wdog(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
361 1.3 thorpej {
362 1.3 thorpej struct sysmon_wdog *smw;
363 1.3 thorpej int s, error = 0;
364 1.3 thorpej
365 1.3 thorpej switch (cmd) {
366 1.3 thorpej case WDOGIOC_GMODE:
367 1.3 thorpej {
368 1.3 thorpej struct wdog_mode *wm = (void *) data;
369 1.3 thorpej
370 1.3 thorpej wm->wm_name[sizeof(wm->wm_name) - 1] = '\0';
371 1.3 thorpej smw = sysmon_wdog_find(wm->wm_name);
372 1.3 thorpej if (smw == NULL) {
373 1.3 thorpej error = ESRCH;
374 1.3 thorpej break;
375 1.3 thorpej }
376 1.3 thorpej
377 1.3 thorpej wm->wm_mode = smw->smw_mode;
378 1.3 thorpej wm->wm_period = smw->smw_period;
379 1.3 thorpej sysmon_wdog_release(smw);
380 1.3 thorpej break;
381 1.3 thorpej }
382 1.3 thorpej
383 1.3 thorpej case WDOGIOC_SMODE:
384 1.3 thorpej {
385 1.3 thorpej struct wdog_mode *wm = (void *) data;
386 1.3 thorpej
387 1.3 thorpej if ((flag & FWRITE) == 0) {
388 1.3 thorpej error = EPERM;
389 1.3 thorpej break;
390 1.3 thorpej }
391 1.3 thorpej
392 1.3 thorpej wm->wm_name[sizeof(wm->wm_name) - 1] = '\0';
393 1.3 thorpej smw = sysmon_wdog_find(wm->wm_name);
394 1.3 thorpej if (smw == NULL) {
395 1.3 thorpej error = ESRCH;
396 1.3 thorpej break;
397 1.3 thorpej }
398 1.3 thorpej
399 1.3 thorpej if (wm->wm_mode & ~(WDOG_MODE_MASK|WDOG_FEATURE_MASK))
400 1.3 thorpej error = EINVAL;
401 1.3 thorpej else {
402 1.3 thorpej SYSMON_WDOG_LOCK(s);
403 1.3 thorpej error = sysmon_wdog_setmode(smw, wm->wm_mode,
404 1.3 thorpej wm->wm_period);
405 1.3 thorpej SYSMON_WDOG_UNLOCK(s);
406 1.3 thorpej }
407 1.3 thorpej
408 1.3 thorpej sysmon_wdog_release(smw);
409 1.3 thorpej break;
410 1.3 thorpej }
411 1.3 thorpej
412 1.3 thorpej case WDOGIOC_WHICH:
413 1.3 thorpej {
414 1.3 thorpej struct wdog_mode *wm = (void *) data;
415 1.3 thorpej
416 1.3 thorpej SYSMON_WDOG_LOCK(s);
417 1.3 thorpej if ((smw = sysmon_armed_wdog) != NULL) {
418 1.3 thorpej strcpy(wm->wm_name, smw->smw_name);
419 1.3 thorpej wm->wm_mode = smw->smw_mode;
420 1.3 thorpej wm->wm_period = smw->smw_period;
421 1.3 thorpej } else
422 1.3 thorpej error = ESRCH;
423 1.3 thorpej SYSMON_WDOG_UNLOCK(s);
424 1.3 thorpej break;
425 1.3 thorpej }
426 1.3 thorpej
427 1.3 thorpej case WDOGIOC_TICKLE:
428 1.3 thorpej if ((flag & FWRITE) == 0) {
429 1.3 thorpej error = EPERM;
430 1.3 thorpej break;
431 1.3 thorpej }
432 1.3 thorpej
433 1.3 thorpej SYSMON_WDOG_LOCK(s);
434 1.3 thorpej if ((smw = sysmon_armed_wdog) != NULL) {
435 1.3 thorpej error = (*smw->smw_tickle)(smw);
436 1.3 thorpej if (error == 0)
437 1.3 thorpej smw->smw_tickler = p->p_pid;
438 1.3 thorpej } else
439 1.3 thorpej error = ESRCH;
440 1.3 thorpej SYSMON_WDOG_UNLOCK(s);
441 1.3 thorpej break;
442 1.3 thorpej
443 1.3 thorpej case WDOGIOC_GTICKLER:
444 1.3 thorpej *(pid_t *)data = smw->smw_tickler;
445 1.3 thorpej break;
446 1.3 thorpej
447 1.3 thorpej case WDOGIOC_GWDOGS:
448 1.3 thorpej {
449 1.3 thorpej struct wdog_conf *wc = (void *) data;
450 1.3 thorpej char *cp;
451 1.3 thorpej int i;
452 1.3 thorpej
453 1.3 thorpej simple_lock(&sysmon_wdog_list_slock);
454 1.3 thorpej if (wc->wc_names == NULL)
455 1.3 thorpej wc->wc_count = sysmon_wdog_count;
456 1.3 thorpej else {
457 1.3 thorpej for (i = 0, cp = wc->wc_names,
458 1.3 thorpej smw = LIST_FIRST(&sysmon_wdog_list);
459 1.3 thorpej i < sysmon_wdog_count && smw != NULL && error == 0;
460 1.3 thorpej i++, cp += WDOG_NAMESIZE,
461 1.3 thorpej smw = LIST_NEXT(smw, smw_list))
462 1.3 thorpej error = copyout(smw->smw_name, cp,
463 1.3 thorpej strlen(smw->smw_name) + 1);
464 1.3 thorpej wc->wc_count = i;
465 1.3 thorpej }
466 1.3 thorpej simple_unlock(&sysmon_wdog_list_slock);
467 1.3 thorpej break;
468 1.3 thorpej }
469 1.3 thorpej
470 1.3 thorpej default:
471 1.3 thorpej error = ENOTTY;
472 1.3 thorpej }
473 1.3 thorpej
474 1.3 thorpej return (error);
475 1.3 thorpej }
476 1.3 thorpej
477 1.3 thorpej /*
478 1.1 thorpej * sysmon_envsys_register:
479 1.1 thorpej *
480 1.1 thorpej * Register an ENVSYS device.
481 1.1 thorpej */
482 1.1 thorpej int
483 1.1 thorpej sysmon_envsys_register(struct sysmon_envsys *sme)
484 1.1 thorpej {
485 1.1 thorpej int error = 0;
486 1.1 thorpej
487 1.1 thorpej simple_lock(&sysmon_envsys_list_slock);
488 1.1 thorpej
489 1.1 thorpej /* XXX Only get to register one, for now. */
490 1.1 thorpej if (LIST_FIRST(&sysmon_envsys_list) != NULL) {
491 1.1 thorpej error = EEXIST;
492 1.1 thorpej goto out;
493 1.1 thorpej }
494 1.1 thorpej
495 1.1 thorpej if (sme->sme_envsys_version != SYSMON_ENVSYS_VERSION) {
496 1.1 thorpej error = EINVAL;
497 1.1 thorpej goto out;
498 1.1 thorpej }
499 1.1 thorpej
500 1.1 thorpej sme->sme_fsensor = sysmon_envsys_next_sensor_index;
501 1.1 thorpej sysmon_envsys_next_sensor_index += sme->sme_nsensors;
502 1.1 thorpej LIST_INSERT_HEAD(&sysmon_envsys_list, sme, sme_list);
503 1.1 thorpej
504 1.1 thorpej out:
505 1.1 thorpej simple_unlock(&sysmon_envsys_list_slock);
506 1.1 thorpej return (error);
507 1.1 thorpej }
508 1.1 thorpej
509 1.1 thorpej /*
510 1.1 thorpej * sysmon_envsys_unregister:
511 1.1 thorpej *
512 1.1 thorpej * Unregister an ENVSYS device.
513 1.1 thorpej */
514 1.1 thorpej void
515 1.1 thorpej sysmon_envsys_unregister(struct sysmon_envsys *sme)
516 1.1 thorpej {
517 1.1 thorpej
518 1.1 thorpej simple_lock(&sysmon_envsys_list_slock);
519 1.1 thorpej LIST_REMOVE(sme, sme_list);
520 1.1 thorpej simple_unlock(&sysmon_envsys_list_slock);
521 1.1 thorpej }
522 1.1 thorpej
523 1.1 thorpej /*
524 1.1 thorpej * sysmon_envsys_find:
525 1.1 thorpej *
526 1.1 thorpej * Find an ENVSYS device. The list remains locked upon
527 1.1 thorpej * a match.
528 1.1 thorpej */
529 1.1 thorpej struct sysmon_envsys *
530 1.1 thorpej sysmon_envsys_find(u_int idx)
531 1.1 thorpej {
532 1.1 thorpej struct sysmon_envsys *sme;
533 1.1 thorpej
534 1.1 thorpej simple_lock(&sysmon_envsys_list_slock);
535 1.1 thorpej
536 1.1 thorpej for (sme = LIST_FIRST(&sysmon_envsys_list); sme != NULL;
537 1.1 thorpej sme = LIST_NEXT(sme, sme_list)) {
538 1.1 thorpej if (idx >= sme->sme_fsensor &&
539 1.1 thorpej idx < (sme->sme_fsensor + sme->sme_nsensors))
540 1.1 thorpej return (sme);
541 1.1 thorpej }
542 1.1 thorpej
543 1.1 thorpej simple_unlock(&sysmon_envsys_list_slock);
544 1.1 thorpej return (NULL);
545 1.1 thorpej }
546 1.1 thorpej
547 1.1 thorpej /*
548 1.1 thorpej * sysmon_envsys_release:
549 1.1 thorpej *
550 1.1 thorpej * Release an ENVSYS device.
551 1.1 thorpej */
552 1.1 thorpej /* ARGSUSED */
553 1.1 thorpej void
554 1.1 thorpej sysmon_envsys_release(struct sysmon_envsys *sme)
555 1.1 thorpej {
556 1.1 thorpej
557 1.1 thorpej simple_unlock(&sysmon_envsys_list_slock);
558 1.3 thorpej }
559 1.3 thorpej
560 1.3 thorpej /*
561 1.3 thorpej * sysmon_wdog_register:
562 1.3 thorpej *
563 1.3 thorpej * Register a watchdog device.
564 1.3 thorpej */
565 1.3 thorpej int
566 1.3 thorpej sysmon_wdog_register(struct sysmon_wdog *smw)
567 1.3 thorpej {
568 1.3 thorpej struct sysmon_wdog *lsmw;
569 1.3 thorpej int error = 0;
570 1.3 thorpej
571 1.3 thorpej simple_lock(&sysmon_wdog_list_slock);
572 1.3 thorpej
573 1.3 thorpej for (lsmw = LIST_FIRST(&sysmon_wdog_list); lsmw != NULL;
574 1.3 thorpej lsmw = LIST_NEXT(lsmw, smw_list)) {
575 1.3 thorpej if (strcmp(lsmw->smw_name, smw->smw_name) == 0) {
576 1.3 thorpej error = EEXIST;
577 1.3 thorpej goto out;
578 1.3 thorpej }
579 1.3 thorpej }
580 1.3 thorpej
581 1.3 thorpej smw->smw_mode = WDOG_MODE_DISARMED;
582 1.3 thorpej smw->smw_tickler = (pid_t) -1;
583 1.3 thorpej smw->smw_refcnt = 0;
584 1.3 thorpej sysmon_wdog_count++;
585 1.3 thorpej LIST_INSERT_HEAD(&sysmon_wdog_list, smw, smw_list);
586 1.3 thorpej
587 1.3 thorpej out:
588 1.3 thorpej simple_unlock(&sysmon_wdog_list_slock);
589 1.3 thorpej return (error);
590 1.3 thorpej }
591 1.3 thorpej
592 1.3 thorpej /*
593 1.3 thorpej * sysmon_wdog_unregister:
594 1.3 thorpej *
595 1.3 thorpej * Unregister a watchdog device.
596 1.3 thorpej */
597 1.3 thorpej void
598 1.3 thorpej sysmon_wdog_unregister(struct sysmon_wdog *smw)
599 1.3 thorpej {
600 1.3 thorpej
601 1.3 thorpej simple_lock(&sysmon_wdog_list_slock);
602 1.3 thorpej sysmon_wdog_count--;
603 1.3 thorpej LIST_REMOVE(smw, smw_list);
604 1.3 thorpej simple_unlock(&sysmon_wdog_list_slock);
605 1.3 thorpej }
606 1.3 thorpej
607 1.3 thorpej /*
608 1.3 thorpej * sysmon_wdog_find:
609 1.3 thorpej *
610 1.3 thorpej * Find a watchdog device. We increase the reference
611 1.3 thorpej * count on a match.
612 1.3 thorpej */
613 1.3 thorpej struct sysmon_wdog *
614 1.3 thorpej sysmon_wdog_find(const char *name)
615 1.3 thorpej {
616 1.3 thorpej struct sysmon_wdog *smw;
617 1.3 thorpej
618 1.3 thorpej simple_lock(&sysmon_wdog_list_slock);
619 1.3 thorpej
620 1.3 thorpej for (smw = LIST_FIRST(&sysmon_wdog_list); smw != NULL;
621 1.3 thorpej smw = LIST_NEXT(smw, smw_list)) {
622 1.3 thorpej if (strcmp(smw->smw_name, name) == 0)
623 1.3 thorpej break;
624 1.3 thorpej }
625 1.3 thorpej
626 1.3 thorpej if (smw != NULL)
627 1.3 thorpej smw->smw_refcnt++;
628 1.3 thorpej
629 1.3 thorpej simple_unlock(&sysmon_wdog_list_slock);
630 1.3 thorpej return (smw);
631 1.3 thorpej }
632 1.3 thorpej
633 1.3 thorpej /*
634 1.3 thorpej * sysmon_wdog_release:
635 1.3 thorpej *
636 1.3 thorpej * Release a watchdog device.
637 1.3 thorpej */
638 1.3 thorpej void
639 1.3 thorpej sysmon_wdog_release(struct sysmon_wdog *smw)
640 1.3 thorpej {
641 1.3 thorpej
642 1.3 thorpej simple_lock(&sysmon_wdog_list_slock);
643 1.3 thorpej KASSERT(smw->smw_refcnt != 0);
644 1.3 thorpej smw->smw_refcnt--;
645 1.3 thorpej simple_unlock(&sysmon_wdog_list_slock);
646 1.3 thorpej }
647 1.3 thorpej
648 1.3 thorpej /*
649 1.3 thorpej * sysmon_wdog_setmode:
650 1.3 thorpej *
651 1.3 thorpej * Set the mode of a watchdog device.
652 1.3 thorpej */
653 1.3 thorpej int
654 1.3 thorpej sysmon_wdog_setmode(struct sysmon_wdog *smw, int mode, u_int period)
655 1.3 thorpej {
656 1.3 thorpej u_int operiod = smw->smw_period;
657 1.3 thorpej int omode = smw->smw_mode;
658 1.3 thorpej int error = 0;
659 1.3 thorpej
660 1.3 thorpej smw->smw_period = period;
661 1.3 thorpej smw->smw_mode = mode;
662 1.3 thorpej
663 1.3 thorpej switch (mode & WDOG_MODE_MASK) {
664 1.3 thorpej case WDOG_MODE_DISARMED:
665 1.3 thorpej if (smw != sysmon_armed_wdog) {
666 1.3 thorpej error = EINVAL;
667 1.3 thorpej goto out;
668 1.3 thorpej }
669 1.3 thorpej break;
670 1.3 thorpej
671 1.3 thorpej case WDOG_MODE_KTICKLE:
672 1.3 thorpej case WDOG_MODE_UTICKLE:
673 1.3 thorpej if (sysmon_armed_wdog != NULL) {
674 1.3 thorpej error = EBUSY;
675 1.3 thorpej goto out;
676 1.3 thorpej }
677 1.3 thorpej break;
678 1.3 thorpej
679 1.3 thorpej default:
680 1.3 thorpej error = EINVAL;
681 1.3 thorpej goto out;
682 1.3 thorpej }
683 1.3 thorpej
684 1.3 thorpej error = (*smw->smw_setmode)(smw);
685 1.3 thorpej
686 1.3 thorpej out:
687 1.3 thorpej if (error) {
688 1.3 thorpej smw->smw_period = operiod;
689 1.3 thorpej smw->smw_mode = omode;
690 1.3 thorpej } else {
691 1.3 thorpej if ((mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
692 1.3 thorpej smw->smw_tickler = (pid_t) -1;
693 1.3 thorpej smw->smw_refcnt--;
694 1.3 thorpej if ((omode & WDOG_MODE_MASK) == WDOG_MODE_KTICKLE)
695 1.3 thorpej callout_stop(&sysmon_wdog_callout);
696 1.3 thorpej } else {
697 1.3 thorpej sysmon_armed_wdog = smw;
698 1.3 thorpej smw->smw_refcnt++;
699 1.3 thorpej if ((mode & WDOG_MODE_MASK) == WDOG_MODE_KTICKLE) {
700 1.3 thorpej callout_reset(&sysmon_wdog_callout,
701 1.3 thorpej WDOG_PERIOD_TO_TICKS(smw->smw_period) / 2,
702 1.3 thorpej sysmon_wdog_ktickle, NULL);
703 1.3 thorpej }
704 1.3 thorpej }
705 1.3 thorpej }
706 1.3 thorpej return (error);
707 1.3 thorpej }
708 1.3 thorpej
709 1.3 thorpej /*
710 1.3 thorpej * sysmon_wdog_ktickle:
711 1.3 thorpej *
712 1.3 thorpej * Kernel watchdog tickle routine.
713 1.3 thorpej */
714 1.3 thorpej void
715 1.3 thorpej sysmon_wdog_ktickle(void *arg)
716 1.3 thorpej {
717 1.3 thorpej struct sysmon_wdog *smw;
718 1.3 thorpej int s;
719 1.3 thorpej
720 1.3 thorpej SYSMON_WDOG_LOCK(s);
721 1.3 thorpej if ((smw = sysmon_armed_wdog) != NULL) {
722 1.3 thorpej if ((*smw->smw_tickle)(smw) != 0) {
723 1.3 thorpej printf("WARNING: KERNEL TICKLE OF WATCHDOG %s "
724 1.3 thorpej "FAILED!\n", smw->smw_name);
725 1.3 thorpej /*
726 1.3 thorpej * ...we will probably reboot soon.
727 1.3 thorpej */
728 1.3 thorpej }
729 1.3 thorpej callout_reset(&sysmon_wdog_callout,
730 1.3 thorpej WDOG_PERIOD_TO_TICKS(smw->smw_period) / 2,
731 1.3 thorpej sysmon_wdog_ktickle, NULL);
732 1.3 thorpej }
733 1.3 thorpej SYSMON_WDOG_UNLOCK(s);
734 1.3 thorpej }
735 1.3 thorpej
736 1.3 thorpej /*
737 1.3 thorpej * sysmon_wdog_shutdown:
738 1.3 thorpej *
739 1.3 thorpej * Perform shutdown-time operations.
740 1.3 thorpej */
741 1.3 thorpej void
742 1.3 thorpej sysmon_wdog_shutdown(void *arg)
743 1.3 thorpej {
744 1.3 thorpej struct sysmon_wdog *smw;
745 1.3 thorpej
746 1.3 thorpej /*
747 1.3 thorpej * XXX Locking here? I don't think it's necessary.
748 1.3 thorpej */
749 1.3 thorpej
750 1.3 thorpej if ((smw = sysmon_armed_wdog) != NULL) {
751 1.3 thorpej if (sysmon_wdog_setmode(smw, WDOG_MODE_DISARMED,
752 1.3 thorpej smw->smw_period))
753 1.3 thorpej printf("WARNING: FAILED TO SHUTDOWN WATCHDOG %s!\n",
754 1.3 thorpej smw->smw_name);
755 1.3 thorpej }
756 1.1 thorpej }
757