diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/char/ipmi/ipmi_watchdog.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/char/ipmi/ipmi_watchdog.c')
-rw-r--r-- | drivers/char/ipmi/ipmi_watchdog.c | 1068 |
1 files changed, 1068 insertions, 0 deletions
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c new file mode 100644 index 000000000000..fd7093879c66 --- /dev/null +++ b/drivers/char/ipmi/ipmi_watchdog.c | |||
@@ -0,0 +1,1068 @@ | |||
1 | /* | ||
2 | * ipmi_watchdog.c | ||
3 | * | ||
4 | * A watchdog timer based upon the IPMI interface. | ||
5 | * | ||
6 | * Author: MontaVista Software, Inc. | ||
7 | * Corey Minyard <minyard@mvista.com> | ||
8 | * source@mvista.com | ||
9 | * | ||
10 | * Copyright 2002 MontaVista Software Inc. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | * | ||
17 | * | ||
18 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
19 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
20 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
23 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | ||
24 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
25 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | ||
26 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | ||
27 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
28 | * | ||
29 | * You should have received a copy of the GNU General Public License along | ||
30 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
31 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
32 | */ | ||
33 | |||
34 | #include <linux/config.h> | ||
35 | #include <linux/module.h> | ||
36 | #include <linux/moduleparam.h> | ||
37 | #include <linux/ipmi.h> | ||
38 | #include <linux/ipmi_smi.h> | ||
39 | #include <linux/watchdog.h> | ||
40 | #include <linux/miscdevice.h> | ||
41 | #include <linux/init.h> | ||
42 | #include <linux/rwsem.h> | ||
43 | #include <linux/errno.h> | ||
44 | #include <asm/uaccess.h> | ||
45 | #include <linux/notifier.h> | ||
46 | #include <linux/nmi.h> | ||
47 | #include <linux/reboot.h> | ||
48 | #include <linux/wait.h> | ||
49 | #include <linux/poll.h> | ||
50 | #ifdef CONFIG_X86_LOCAL_APIC | ||
51 | #include <asm/apic.h> | ||
52 | #endif | ||
53 | |||
54 | #define PFX "IPMI Watchdog: " | ||
55 | |||
56 | #define IPMI_WATCHDOG_VERSION "v33" | ||
57 | |||
58 | /* | ||
59 | * The IPMI command/response information for the watchdog timer. | ||
60 | */ | ||
61 | |||
62 | /* values for byte 1 of the set command, byte 2 of the get response. */ | ||
63 | #define WDOG_DONT_LOG (1 << 7) | ||
64 | #define WDOG_DONT_STOP_ON_SET (1 << 6) | ||
65 | #define WDOG_SET_TIMER_USE(byte, use) \ | ||
66 | byte = ((byte) & 0xf8) | ((use) & 0x7) | ||
67 | #define WDOG_GET_TIMER_USE(byte) ((byte) & 0x7) | ||
68 | #define WDOG_TIMER_USE_BIOS_FRB2 1 | ||
69 | #define WDOG_TIMER_USE_BIOS_POST 2 | ||
70 | #define WDOG_TIMER_USE_OS_LOAD 3 | ||
71 | #define WDOG_TIMER_USE_SMS_OS 4 | ||
72 | #define WDOG_TIMER_USE_OEM 5 | ||
73 | |||
74 | /* values for byte 2 of the set command, byte 3 of the get response. */ | ||
75 | #define WDOG_SET_PRETIMEOUT_ACT(byte, use) \ | ||
76 | byte = ((byte) & 0x8f) | (((use) & 0x7) << 4) | ||
77 | #define WDOG_GET_PRETIMEOUT_ACT(byte) (((byte) >> 4) & 0x7) | ||
78 | #define WDOG_PRETIMEOUT_NONE 0 | ||
79 | #define WDOG_PRETIMEOUT_SMI 1 | ||
80 | #define WDOG_PRETIMEOUT_NMI 2 | ||
81 | #define WDOG_PRETIMEOUT_MSG_INT 3 | ||
82 | |||
83 | /* Operations that can be performed on a pretimout. */ | ||
84 | #define WDOG_PREOP_NONE 0 | ||
85 | #define WDOG_PREOP_PANIC 1 | ||
86 | #define WDOG_PREOP_GIVE_DATA 2 /* Cause data to be available to | ||
87 | read. Doesn't work in NMI | ||
88 | mode. */ | ||
89 | |||
90 | /* Actions to perform on a full timeout. */ | ||
91 | #define WDOG_SET_TIMEOUT_ACT(byte, use) \ | ||
92 | byte = ((byte) & 0xf8) | ((use) & 0x7) | ||
93 | #define WDOG_GET_TIMEOUT_ACT(byte) ((byte) & 0x7) | ||
94 | #define WDOG_TIMEOUT_NONE 0 | ||
95 | #define WDOG_TIMEOUT_RESET 1 | ||
96 | #define WDOG_TIMEOUT_POWER_DOWN 2 | ||
97 | #define WDOG_TIMEOUT_POWER_CYCLE 3 | ||
98 | |||
99 | /* Byte 3 of the get command, byte 4 of the get response is the | ||
100 | pre-timeout in seconds. */ | ||
101 | |||
102 | /* Bits for setting byte 4 of the set command, byte 5 of the get response. */ | ||
103 | #define WDOG_EXPIRE_CLEAR_BIOS_FRB2 (1 << 1) | ||
104 | #define WDOG_EXPIRE_CLEAR_BIOS_POST (1 << 2) | ||
105 | #define WDOG_EXPIRE_CLEAR_OS_LOAD (1 << 3) | ||
106 | #define WDOG_EXPIRE_CLEAR_SMS_OS (1 << 4) | ||
107 | #define WDOG_EXPIRE_CLEAR_OEM (1 << 5) | ||
108 | |||
109 | /* Setting/getting the watchdog timer value. This is for bytes 5 and | ||
110 | 6 (the timeout time) of the set command, and bytes 6 and 7 (the | ||
111 | timeout time) and 8 and 9 (the current countdown value) of the | ||
112 | response. The timeout value is given in seconds (in the command it | ||
113 | is 100ms intervals). */ | ||
114 | #define WDOG_SET_TIMEOUT(byte1, byte2, val) \ | ||
115 | (byte1) = (((val) * 10) & 0xff), (byte2) = (((val) * 10) >> 8) | ||
116 | #define WDOG_GET_TIMEOUT(byte1, byte2) \ | ||
117 | (((byte1) | ((byte2) << 8)) / 10) | ||
118 | |||
119 | #define IPMI_WDOG_RESET_TIMER 0x22 | ||
120 | #define IPMI_WDOG_SET_TIMER 0x24 | ||
121 | #define IPMI_WDOG_GET_TIMER 0x25 | ||
122 | |||
123 | /* These are here until the real ones get into the watchdog.h interface. */ | ||
124 | #ifndef WDIOC_GETTIMEOUT | ||
125 | #define WDIOC_GETTIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 20, int) | ||
126 | #endif | ||
127 | #ifndef WDIOC_SET_PRETIMEOUT | ||
128 | #define WDIOC_SET_PRETIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 21, int) | ||
129 | #endif | ||
130 | #ifndef WDIOC_GET_PRETIMEOUT | ||
131 | #define WDIOC_GET_PRETIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 22, int) | ||
132 | #endif | ||
133 | |||
134 | #ifdef CONFIG_WATCHDOG_NOWAYOUT | ||
135 | static int nowayout = 1; | ||
136 | #else | ||
137 | static int nowayout; | ||
138 | #endif | ||
139 | |||
140 | static ipmi_user_t watchdog_user = NULL; | ||
141 | |||
142 | /* Default the timeout to 10 seconds. */ | ||
143 | static int timeout = 10; | ||
144 | |||
145 | /* The pre-timeout is disabled by default. */ | ||
146 | static int pretimeout = 0; | ||
147 | |||
148 | /* Default action is to reset the board on a timeout. */ | ||
149 | static unsigned char action_val = WDOG_TIMEOUT_RESET; | ||
150 | |||
151 | static char action[16] = "reset"; | ||
152 | |||
153 | static unsigned char preaction_val = WDOG_PRETIMEOUT_NONE; | ||
154 | |||
155 | static char preaction[16] = "pre_none"; | ||
156 | |||
157 | static unsigned char preop_val = WDOG_PREOP_NONE; | ||
158 | |||
159 | static char preop[16] = "preop_none"; | ||
160 | static DEFINE_SPINLOCK(ipmi_read_lock); | ||
161 | static char data_to_read = 0; | ||
162 | static DECLARE_WAIT_QUEUE_HEAD(read_q); | ||
163 | static struct fasync_struct *fasync_q = NULL; | ||
164 | static char pretimeout_since_last_heartbeat = 0; | ||
165 | static char expect_close; | ||
166 | |||
167 | /* If true, the driver will start running as soon as it is configured | ||
168 | and ready. */ | ||
169 | static int start_now = 0; | ||
170 | |||
171 | module_param(timeout, int, 0); | ||
172 | MODULE_PARM_DESC(timeout, "Timeout value in seconds."); | ||
173 | module_param(pretimeout, int, 0); | ||
174 | MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds."); | ||
175 | module_param_string(action, action, sizeof(action), 0); | ||
176 | MODULE_PARM_DESC(action, "Timeout action. One of: " | ||
177 | "reset, none, power_cycle, power_off."); | ||
178 | module_param_string(preaction, preaction, sizeof(preaction), 0); | ||
179 | MODULE_PARM_DESC(preaction, "Pretimeout action. One of: " | ||
180 | "pre_none, pre_smi, pre_nmi, pre_int."); | ||
181 | module_param_string(preop, preop, sizeof(preop), 0); | ||
182 | MODULE_PARM_DESC(preop, "Pretimeout driver operation. One of: " | ||
183 | "preop_none, preop_panic, preop_give_data."); | ||
184 | module_param(start_now, int, 0); | ||
185 | MODULE_PARM_DESC(start_now, "Set to 1 to start the watchdog as" | ||
186 | "soon as the driver is loaded."); | ||
187 | module_param(nowayout, int, 0); | ||
188 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | ||
189 | |||
190 | /* Default state of the timer. */ | ||
191 | static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE; | ||
192 | |||
193 | /* If shutting down via IPMI, we ignore the heartbeat. */ | ||
194 | static int ipmi_ignore_heartbeat = 0; | ||
195 | |||
196 | /* Is someone using the watchdog? Only one user is allowed. */ | ||
197 | static unsigned long ipmi_wdog_open = 0; | ||
198 | |||
199 | /* If set to 1, the heartbeat command will set the state to reset and | ||
200 | start the timer. The timer doesn't normally run when the driver is | ||
201 | first opened until the heartbeat is set the first time, this | ||
202 | variable is used to accomplish this. */ | ||
203 | static int ipmi_start_timer_on_heartbeat = 0; | ||
204 | |||
205 | /* IPMI version of the BMC. */ | ||
206 | static unsigned char ipmi_version_major; | ||
207 | static unsigned char ipmi_version_minor; | ||
208 | |||
209 | |||
210 | static int ipmi_heartbeat(void); | ||
211 | static void panic_halt_ipmi_heartbeat(void); | ||
212 | |||
213 | |||
214 | /* We use a semaphore to make sure that only one thing can send a set | ||
215 | timeout at one time, because we only have one copy of the data. | ||
216 | The semaphore is claimed when the set_timeout is sent and freed | ||
217 | when both messages are free. */ | ||
218 | static atomic_t set_timeout_tofree = ATOMIC_INIT(0); | ||
219 | static DECLARE_MUTEX(set_timeout_lock); | ||
220 | static void set_timeout_free_smi(struct ipmi_smi_msg *msg) | ||
221 | { | ||
222 | if (atomic_dec_and_test(&set_timeout_tofree)) | ||
223 | up(&set_timeout_lock); | ||
224 | } | ||
225 | static void set_timeout_free_recv(struct ipmi_recv_msg *msg) | ||
226 | { | ||
227 | if (atomic_dec_and_test(&set_timeout_tofree)) | ||
228 | up(&set_timeout_lock); | ||
229 | } | ||
230 | static struct ipmi_smi_msg set_timeout_smi_msg = | ||
231 | { | ||
232 | .done = set_timeout_free_smi | ||
233 | }; | ||
234 | static struct ipmi_recv_msg set_timeout_recv_msg = | ||
235 | { | ||
236 | .done = set_timeout_free_recv | ||
237 | }; | ||
238 | |||
239 | static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, | ||
240 | struct ipmi_recv_msg *recv_msg, | ||
241 | int *send_heartbeat_now) | ||
242 | { | ||
243 | struct kernel_ipmi_msg msg; | ||
244 | unsigned char data[6]; | ||
245 | int rv; | ||
246 | struct ipmi_system_interface_addr addr; | ||
247 | int hbnow = 0; | ||
248 | |||
249 | |||
250 | data[0] = 0; | ||
251 | WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS); | ||
252 | |||
253 | if ((ipmi_version_major > 1) | ||
254 | || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5))) | ||
255 | { | ||
256 | /* This is an IPMI 1.5-only feature. */ | ||
257 | data[0] |= WDOG_DONT_STOP_ON_SET; | ||
258 | } else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) { | ||
259 | /* In ipmi 1.0, setting the timer stops the watchdog, we | ||
260 | need to start it back up again. */ | ||
261 | hbnow = 1; | ||
262 | } | ||
263 | |||
264 | data[1] = 0; | ||
265 | WDOG_SET_TIMEOUT_ACT(data[1], ipmi_watchdog_state); | ||
266 | if (pretimeout > 0) { | ||
267 | WDOG_SET_PRETIMEOUT_ACT(data[1], preaction_val); | ||
268 | data[2] = pretimeout; | ||
269 | } else { | ||
270 | WDOG_SET_PRETIMEOUT_ACT(data[1], WDOG_PRETIMEOUT_NONE); | ||
271 | data[2] = 0; /* No pretimeout. */ | ||
272 | } | ||
273 | data[3] = 0; | ||
274 | WDOG_SET_TIMEOUT(data[4], data[5], timeout); | ||
275 | |||
276 | addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; | ||
277 | addr.channel = IPMI_BMC_CHANNEL; | ||
278 | addr.lun = 0; | ||
279 | |||
280 | msg.netfn = 0x06; | ||
281 | msg.cmd = IPMI_WDOG_SET_TIMER; | ||
282 | msg.data = data; | ||
283 | msg.data_len = sizeof(data); | ||
284 | rv = ipmi_request_supply_msgs(watchdog_user, | ||
285 | (struct ipmi_addr *) &addr, | ||
286 | 0, | ||
287 | &msg, | ||
288 | NULL, | ||
289 | smi_msg, | ||
290 | recv_msg, | ||
291 | 1); | ||
292 | if (rv) { | ||
293 | printk(KERN_WARNING PFX "set timeout error: %d\n", | ||
294 | rv); | ||
295 | } | ||
296 | |||
297 | if (send_heartbeat_now) | ||
298 | *send_heartbeat_now = hbnow; | ||
299 | |||
300 | return rv; | ||
301 | } | ||
302 | |||
303 | /* Parameters to ipmi_set_timeout */ | ||
304 | #define IPMI_SET_TIMEOUT_NO_HB 0 | ||
305 | #define IPMI_SET_TIMEOUT_HB_IF_NECESSARY 1 | ||
306 | #define IPMI_SET_TIMEOUT_FORCE_HB 2 | ||
307 | |||
308 | static int ipmi_set_timeout(int do_heartbeat) | ||
309 | { | ||
310 | int send_heartbeat_now; | ||
311 | int rv; | ||
312 | |||
313 | |||
314 | /* We can only send one of these at a time. */ | ||
315 | down(&set_timeout_lock); | ||
316 | |||
317 | atomic_set(&set_timeout_tofree, 2); | ||
318 | |||
319 | rv = i_ipmi_set_timeout(&set_timeout_smi_msg, | ||
320 | &set_timeout_recv_msg, | ||
321 | &send_heartbeat_now); | ||
322 | if (rv) { | ||
323 | up(&set_timeout_lock); | ||
324 | } else { | ||
325 | if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB) | ||
326 | || ((send_heartbeat_now) | ||
327 | && (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY))) | ||
328 | { | ||
329 | rv = ipmi_heartbeat(); | ||
330 | } | ||
331 | } | ||
332 | |||
333 | return rv; | ||
334 | } | ||
335 | |||
336 | static void dummy_smi_free(struct ipmi_smi_msg *msg) | ||
337 | { | ||
338 | } | ||
339 | static void dummy_recv_free(struct ipmi_recv_msg *msg) | ||
340 | { | ||
341 | } | ||
342 | static struct ipmi_smi_msg panic_halt_smi_msg = | ||
343 | { | ||
344 | .done = dummy_smi_free | ||
345 | }; | ||
346 | static struct ipmi_recv_msg panic_halt_recv_msg = | ||
347 | { | ||
348 | .done = dummy_recv_free | ||
349 | }; | ||
350 | |||
351 | /* Special call, doesn't claim any locks. This is only to be called | ||
352 | at panic or halt time, in run-to-completion mode, when the caller | ||
353 | is the only CPU and the only thing that will be going is these IPMI | ||
354 | calls. */ | ||
355 | static void panic_halt_ipmi_set_timeout(void) | ||
356 | { | ||
357 | int send_heartbeat_now; | ||
358 | int rv; | ||
359 | |||
360 | rv = i_ipmi_set_timeout(&panic_halt_smi_msg, | ||
361 | &panic_halt_recv_msg, | ||
362 | &send_heartbeat_now); | ||
363 | if (!rv) { | ||
364 | if (send_heartbeat_now) | ||
365 | panic_halt_ipmi_heartbeat(); | ||
366 | } | ||
367 | } | ||
368 | |||
369 | /* We use a semaphore to make sure that only one thing can send a | ||
370 | heartbeat at one time, because we only have one copy of the data. | ||
371 | The semaphore is claimed when the set_timeout is sent and freed | ||
372 | when both messages are free. */ | ||
373 | static atomic_t heartbeat_tofree = ATOMIC_INIT(0); | ||
374 | static DECLARE_MUTEX(heartbeat_lock); | ||
375 | static DECLARE_MUTEX_LOCKED(heartbeat_wait_lock); | ||
376 | static void heartbeat_free_smi(struct ipmi_smi_msg *msg) | ||
377 | { | ||
378 | if (atomic_dec_and_test(&heartbeat_tofree)) | ||
379 | up(&heartbeat_wait_lock); | ||
380 | } | ||
381 | static void heartbeat_free_recv(struct ipmi_recv_msg *msg) | ||
382 | { | ||
383 | if (atomic_dec_and_test(&heartbeat_tofree)) | ||
384 | up(&heartbeat_wait_lock); | ||
385 | } | ||
386 | static struct ipmi_smi_msg heartbeat_smi_msg = | ||
387 | { | ||
388 | .done = heartbeat_free_smi | ||
389 | }; | ||
390 | static struct ipmi_recv_msg heartbeat_recv_msg = | ||
391 | { | ||
392 | .done = heartbeat_free_recv | ||
393 | }; | ||
394 | |||
395 | static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = | ||
396 | { | ||
397 | .done = dummy_smi_free | ||
398 | }; | ||
399 | static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = | ||
400 | { | ||
401 | .done = dummy_recv_free | ||
402 | }; | ||
403 | |||
404 | static int ipmi_heartbeat(void) | ||
405 | { | ||
406 | struct kernel_ipmi_msg msg; | ||
407 | int rv; | ||
408 | struct ipmi_system_interface_addr addr; | ||
409 | |||
410 | if (ipmi_ignore_heartbeat) { | ||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | if (ipmi_start_timer_on_heartbeat) { | ||
415 | ipmi_start_timer_on_heartbeat = 0; | ||
416 | ipmi_watchdog_state = action_val; | ||
417 | return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); | ||
418 | } else if (pretimeout_since_last_heartbeat) { | ||
419 | /* A pretimeout occurred, make sure we set the timeout. | ||
420 | We don't want to set the action, though, we want to | ||
421 | leave that alone (thus it can't be combined with the | ||
422 | above operation. */ | ||
423 | pretimeout_since_last_heartbeat = 0; | ||
424 | return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); | ||
425 | } | ||
426 | |||
427 | down(&heartbeat_lock); | ||
428 | |||
429 | atomic_set(&heartbeat_tofree, 2); | ||
430 | |||
431 | /* Don't reset the timer if we have the timer turned off, that | ||
432 | re-enables the watchdog. */ | ||
433 | if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) { | ||
434 | up(&heartbeat_lock); | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; | ||
439 | addr.channel = IPMI_BMC_CHANNEL; | ||
440 | addr.lun = 0; | ||
441 | |||
442 | msg.netfn = 0x06; | ||
443 | msg.cmd = IPMI_WDOG_RESET_TIMER; | ||
444 | msg.data = NULL; | ||
445 | msg.data_len = 0; | ||
446 | rv = ipmi_request_supply_msgs(watchdog_user, | ||
447 | (struct ipmi_addr *) &addr, | ||
448 | 0, | ||
449 | &msg, | ||
450 | NULL, | ||
451 | &heartbeat_smi_msg, | ||
452 | &heartbeat_recv_msg, | ||
453 | 1); | ||
454 | if (rv) { | ||
455 | up(&heartbeat_lock); | ||
456 | printk(KERN_WARNING PFX "heartbeat failure: %d\n", | ||
457 | rv); | ||
458 | return rv; | ||
459 | } | ||
460 | |||
461 | /* Wait for the heartbeat to be sent. */ | ||
462 | down(&heartbeat_wait_lock); | ||
463 | |||
464 | if (heartbeat_recv_msg.msg.data[0] != 0) { | ||
465 | /* Got an error in the heartbeat response. It was already | ||
466 | reported in ipmi_wdog_msg_handler, but we should return | ||
467 | an error here. */ | ||
468 | rv = -EINVAL; | ||
469 | } | ||
470 | |||
471 | up(&heartbeat_lock); | ||
472 | |||
473 | return rv; | ||
474 | } | ||
475 | |||
476 | static void panic_halt_ipmi_heartbeat(void) | ||
477 | { | ||
478 | struct kernel_ipmi_msg msg; | ||
479 | struct ipmi_system_interface_addr addr; | ||
480 | |||
481 | |||
482 | /* Don't reset the timer if we have the timer turned off, that | ||
483 | re-enables the watchdog. */ | ||
484 | if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) | ||
485 | return; | ||
486 | |||
487 | addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; | ||
488 | addr.channel = IPMI_BMC_CHANNEL; | ||
489 | addr.lun = 0; | ||
490 | |||
491 | msg.netfn = 0x06; | ||
492 | msg.cmd = IPMI_WDOG_RESET_TIMER; | ||
493 | msg.data = NULL; | ||
494 | msg.data_len = 0; | ||
495 | ipmi_request_supply_msgs(watchdog_user, | ||
496 | (struct ipmi_addr *) &addr, | ||
497 | 0, | ||
498 | &msg, | ||
499 | NULL, | ||
500 | &panic_halt_heartbeat_smi_msg, | ||
501 | &panic_halt_heartbeat_recv_msg, | ||
502 | 1); | ||
503 | } | ||
504 | |||
505 | static struct watchdog_info ident= | ||
506 | { | ||
507 | .options = 0, /* WDIOF_SETTIMEOUT, */ | ||
508 | .firmware_version = 1, | ||
509 | .identity = "IPMI" | ||
510 | }; | ||
511 | |||
512 | static int ipmi_ioctl(struct inode *inode, struct file *file, | ||
513 | unsigned int cmd, unsigned long arg) | ||
514 | { | ||
515 | void __user *argp = (void __user *)arg; | ||
516 | int i; | ||
517 | int val; | ||
518 | |||
519 | switch(cmd) { | ||
520 | case WDIOC_GETSUPPORT: | ||
521 | i = copy_to_user(argp, &ident, sizeof(ident)); | ||
522 | return i ? -EFAULT : 0; | ||
523 | |||
524 | case WDIOC_SETTIMEOUT: | ||
525 | i = copy_from_user(&val, argp, sizeof(int)); | ||
526 | if (i) | ||
527 | return -EFAULT; | ||
528 | timeout = val; | ||
529 | return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); | ||
530 | |||
531 | case WDIOC_GETTIMEOUT: | ||
532 | i = copy_to_user(argp, &timeout, sizeof(timeout)); | ||
533 | if (i) | ||
534 | return -EFAULT; | ||
535 | return 0; | ||
536 | |||
537 | case WDIOC_SET_PRETIMEOUT: | ||
538 | i = copy_from_user(&val, argp, sizeof(int)); | ||
539 | if (i) | ||
540 | return -EFAULT; | ||
541 | pretimeout = val; | ||
542 | return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); | ||
543 | |||
544 | case WDIOC_GET_PRETIMEOUT: | ||
545 | i = copy_to_user(argp, &pretimeout, sizeof(pretimeout)); | ||
546 | if (i) | ||
547 | return -EFAULT; | ||
548 | return 0; | ||
549 | |||
550 | case WDIOC_KEEPALIVE: | ||
551 | return ipmi_heartbeat(); | ||
552 | |||
553 | case WDIOC_SETOPTIONS: | ||
554 | i = copy_from_user(&val, argp, sizeof(int)); | ||
555 | if (i) | ||
556 | return -EFAULT; | ||
557 | if (val & WDIOS_DISABLECARD) | ||
558 | { | ||
559 | ipmi_watchdog_state = WDOG_TIMEOUT_NONE; | ||
560 | ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); | ||
561 | ipmi_start_timer_on_heartbeat = 0; | ||
562 | } | ||
563 | |||
564 | if (val & WDIOS_ENABLECARD) | ||
565 | { | ||
566 | ipmi_watchdog_state = action_val; | ||
567 | ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); | ||
568 | } | ||
569 | return 0; | ||
570 | |||
571 | case WDIOC_GETSTATUS: | ||
572 | val = 0; | ||
573 | i = copy_to_user(argp, &val, sizeof(val)); | ||
574 | if (i) | ||
575 | return -EFAULT; | ||
576 | return 0; | ||
577 | |||
578 | default: | ||
579 | return -ENOIOCTLCMD; | ||
580 | } | ||
581 | } | ||
582 | |||
583 | static ssize_t ipmi_write(struct file *file, | ||
584 | const char __user *buf, | ||
585 | size_t len, | ||
586 | loff_t *ppos) | ||
587 | { | ||
588 | int rv; | ||
589 | |||
590 | if (len) { | ||
591 | if (!nowayout) { | ||
592 | size_t i; | ||
593 | |||
594 | /* In case it was set long ago */ | ||
595 | expect_close = 0; | ||
596 | |||
597 | for (i = 0; i != len; i++) { | ||
598 | char c; | ||
599 | |||
600 | if (get_user(c, buf + i)) | ||
601 | return -EFAULT; | ||
602 | if (c == 'V') | ||
603 | expect_close = 42; | ||
604 | } | ||
605 | } | ||
606 | rv = ipmi_heartbeat(); | ||
607 | if (rv) | ||
608 | return rv; | ||
609 | return 1; | ||
610 | } | ||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | static ssize_t ipmi_read(struct file *file, | ||
615 | char __user *buf, | ||
616 | size_t count, | ||
617 | loff_t *ppos) | ||
618 | { | ||
619 | int rv = 0; | ||
620 | wait_queue_t wait; | ||
621 | |||
622 | if (count <= 0) | ||
623 | return 0; | ||
624 | |||
625 | /* Reading returns if the pretimeout has gone off, and it only does | ||
626 | it once per pretimeout. */ | ||
627 | spin_lock(&ipmi_read_lock); | ||
628 | if (!data_to_read) { | ||
629 | if (file->f_flags & O_NONBLOCK) { | ||
630 | rv = -EAGAIN; | ||
631 | goto out; | ||
632 | } | ||
633 | |||
634 | init_waitqueue_entry(&wait, current); | ||
635 | add_wait_queue(&read_q, &wait); | ||
636 | while (!data_to_read) { | ||
637 | set_current_state(TASK_INTERRUPTIBLE); | ||
638 | spin_unlock(&ipmi_read_lock); | ||
639 | schedule(); | ||
640 | spin_lock(&ipmi_read_lock); | ||
641 | } | ||
642 | remove_wait_queue(&read_q, &wait); | ||
643 | |||
644 | if (signal_pending(current)) { | ||
645 | rv = -ERESTARTSYS; | ||
646 | goto out; | ||
647 | } | ||
648 | } | ||
649 | data_to_read = 0; | ||
650 | |||
651 | out: | ||
652 | spin_unlock(&ipmi_read_lock); | ||
653 | |||
654 | if (rv == 0) { | ||
655 | if (copy_to_user(buf, &data_to_read, 1)) | ||
656 | rv = -EFAULT; | ||
657 | else | ||
658 | rv = 1; | ||
659 | } | ||
660 | |||
661 | return rv; | ||
662 | } | ||
663 | |||
664 | static int ipmi_open(struct inode *ino, struct file *filep) | ||
665 | { | ||
666 | switch (iminor(ino)) | ||
667 | { | ||
668 | case WATCHDOG_MINOR: | ||
669 | if(test_and_set_bit(0, &ipmi_wdog_open)) | ||
670 | return -EBUSY; | ||
671 | |||
672 | /* Don't start the timer now, let it start on the | ||
673 | first heartbeat. */ | ||
674 | ipmi_start_timer_on_heartbeat = 1; | ||
675 | return nonseekable_open(ino, filep); | ||
676 | |||
677 | default: | ||
678 | return (-ENODEV); | ||
679 | } | ||
680 | } | ||
681 | |||
682 | static unsigned int ipmi_poll(struct file *file, poll_table *wait) | ||
683 | { | ||
684 | unsigned int mask = 0; | ||
685 | |||
686 | poll_wait(file, &read_q, wait); | ||
687 | |||
688 | spin_lock(&ipmi_read_lock); | ||
689 | if (data_to_read) | ||
690 | mask |= (POLLIN | POLLRDNORM); | ||
691 | spin_unlock(&ipmi_read_lock); | ||
692 | |||
693 | return mask; | ||
694 | } | ||
695 | |||
696 | static int ipmi_fasync(int fd, struct file *file, int on) | ||
697 | { | ||
698 | int result; | ||
699 | |||
700 | result = fasync_helper(fd, file, on, &fasync_q); | ||
701 | |||
702 | return (result); | ||
703 | } | ||
704 | |||
705 | static int ipmi_close(struct inode *ino, struct file *filep) | ||
706 | { | ||
707 | if (iminor(ino)==WATCHDOG_MINOR) | ||
708 | { | ||
709 | if (expect_close == 42) { | ||
710 | ipmi_watchdog_state = WDOG_TIMEOUT_NONE; | ||
711 | ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); | ||
712 | clear_bit(0, &ipmi_wdog_open); | ||
713 | } else { | ||
714 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | ||
715 | ipmi_heartbeat(); | ||
716 | } | ||
717 | } | ||
718 | |||
719 | ipmi_fasync (-1, filep, 0); | ||
720 | expect_close = 0; | ||
721 | |||
722 | return 0; | ||
723 | } | ||
724 | |||
725 | static struct file_operations ipmi_wdog_fops = { | ||
726 | .owner = THIS_MODULE, | ||
727 | .read = ipmi_read, | ||
728 | .poll = ipmi_poll, | ||
729 | .write = ipmi_write, | ||
730 | .ioctl = ipmi_ioctl, | ||
731 | .open = ipmi_open, | ||
732 | .release = ipmi_close, | ||
733 | .fasync = ipmi_fasync, | ||
734 | }; | ||
735 | |||
736 | static struct miscdevice ipmi_wdog_miscdev = { | ||
737 | .minor = WATCHDOG_MINOR, | ||
738 | .name = "watchdog", | ||
739 | .fops = &ipmi_wdog_fops | ||
740 | }; | ||
741 | |||
742 | static DECLARE_RWSEM(register_sem); | ||
743 | |||
744 | static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg, | ||
745 | void *handler_data) | ||
746 | { | ||
747 | if (msg->msg.data[0] != 0) { | ||
748 | printk(KERN_ERR PFX "response: Error %x on cmd %x\n", | ||
749 | msg->msg.data[0], | ||
750 | msg->msg.cmd); | ||
751 | } | ||
752 | |||
753 | ipmi_free_recv_msg(msg); | ||
754 | } | ||
755 | |||
756 | static void ipmi_wdog_pretimeout_handler(void *handler_data) | ||
757 | { | ||
758 | if (preaction_val != WDOG_PRETIMEOUT_NONE) { | ||
759 | if (preop_val == WDOG_PREOP_PANIC) | ||
760 | panic("Watchdog pre-timeout"); | ||
761 | else if (preop_val == WDOG_PREOP_GIVE_DATA) { | ||
762 | spin_lock(&ipmi_read_lock); | ||
763 | data_to_read = 1; | ||
764 | wake_up_interruptible(&read_q); | ||
765 | kill_fasync(&fasync_q, SIGIO, POLL_IN); | ||
766 | |||
767 | spin_unlock(&ipmi_read_lock); | ||
768 | } | ||
769 | } | ||
770 | |||
771 | /* On some machines, the heartbeat will give | ||
772 | an error and not work unless we re-enable | ||
773 | the timer. So do so. */ | ||
774 | pretimeout_since_last_heartbeat = 1; | ||
775 | } | ||
776 | |||
777 | static struct ipmi_user_hndl ipmi_hndlrs = | ||
778 | { | ||
779 | .ipmi_recv_hndl = ipmi_wdog_msg_handler, | ||
780 | .ipmi_watchdog_pretimeout = ipmi_wdog_pretimeout_handler | ||
781 | }; | ||
782 | |||
783 | static void ipmi_register_watchdog(int ipmi_intf) | ||
784 | { | ||
785 | int rv = -EBUSY; | ||
786 | |||
787 | down_write(®ister_sem); | ||
788 | if (watchdog_user) | ||
789 | goto out; | ||
790 | |||
791 | rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user); | ||
792 | if (rv < 0) { | ||
793 | printk(KERN_CRIT PFX "Unable to register with ipmi\n"); | ||
794 | goto out; | ||
795 | } | ||
796 | |||
797 | ipmi_get_version(watchdog_user, | ||
798 | &ipmi_version_major, | ||
799 | &ipmi_version_minor); | ||
800 | |||
801 | rv = misc_register(&ipmi_wdog_miscdev); | ||
802 | if (rv < 0) { | ||
803 | ipmi_destroy_user(watchdog_user); | ||
804 | watchdog_user = NULL; | ||
805 | printk(KERN_CRIT PFX "Unable to register misc device\n"); | ||
806 | } | ||
807 | |||
808 | out: | ||
809 | up_write(®ister_sem); | ||
810 | |||
811 | if ((start_now) && (rv == 0)) { | ||
812 | /* Run from startup, so start the timer now. */ | ||
813 | start_now = 0; /* Disable this function after first startup. */ | ||
814 | ipmi_watchdog_state = action_val; | ||
815 | ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); | ||
816 | printk(KERN_INFO PFX "Starting now!\n"); | ||
817 | } | ||
818 | } | ||
819 | |||
820 | #ifdef HAVE_NMI_HANDLER | ||
821 | static int | ||
822 | ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled) | ||
823 | { | ||
824 | /* If no one else handled the NMI, we assume it was the IPMI | ||
825 | watchdog. */ | ||
826 | if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) | ||
827 | panic(PFX "pre-timeout"); | ||
828 | |||
829 | /* On some machines, the heartbeat will give | ||
830 | an error and not work unless we re-enable | ||
831 | the timer. So do so. */ | ||
832 | pretimeout_since_last_heartbeat = 1; | ||
833 | |||
834 | return NOTIFY_DONE; | ||
835 | } | ||
836 | |||
837 | static struct nmi_handler ipmi_nmi_handler = | ||
838 | { | ||
839 | .link = LIST_HEAD_INIT(ipmi_nmi_handler.link), | ||
840 | .dev_name = "ipmi_watchdog", | ||
841 | .dev_id = NULL, | ||
842 | .handler = ipmi_nmi, | ||
843 | .priority = 0, /* Call us last. */ | ||
844 | }; | ||
845 | #endif | ||
846 | |||
847 | static int wdog_reboot_handler(struct notifier_block *this, | ||
848 | unsigned long code, | ||
849 | void *unused) | ||
850 | { | ||
851 | static int reboot_event_handled = 0; | ||
852 | |||
853 | if ((watchdog_user) && (!reboot_event_handled)) { | ||
854 | /* Make sure we only do this once. */ | ||
855 | reboot_event_handled = 1; | ||
856 | |||
857 | if (code == SYS_DOWN || code == SYS_HALT) { | ||
858 | /* Disable the WDT if we are shutting down. */ | ||
859 | ipmi_watchdog_state = WDOG_TIMEOUT_NONE; | ||
860 | panic_halt_ipmi_set_timeout(); | ||
861 | } else { | ||
862 | /* Set a long timer to let the reboot happens, but | ||
863 | reboot if it hangs. */ | ||
864 | timeout = 120; | ||
865 | pretimeout = 0; | ||
866 | ipmi_watchdog_state = WDOG_TIMEOUT_RESET; | ||
867 | panic_halt_ipmi_set_timeout(); | ||
868 | } | ||
869 | } | ||
870 | return NOTIFY_OK; | ||
871 | } | ||
872 | |||
873 | static struct notifier_block wdog_reboot_notifier = { | ||
874 | .notifier_call = wdog_reboot_handler, | ||
875 | .next = NULL, | ||
876 | .priority = 0 | ||
877 | }; | ||
878 | |||
879 | static int wdog_panic_handler(struct notifier_block *this, | ||
880 | unsigned long event, | ||
881 | void *unused) | ||
882 | { | ||
883 | static int panic_event_handled = 0; | ||
884 | |||
885 | /* On a panic, if we have a panic timeout, make sure that the thing | ||
886 | reboots, even if it hangs during that panic. */ | ||
887 | if (watchdog_user && !panic_event_handled) { | ||
888 | /* Make sure the panic doesn't hang, and make sure we | ||
889 | do this only once. */ | ||
890 | panic_event_handled = 1; | ||
891 | |||
892 | timeout = 255; | ||
893 | pretimeout = 0; | ||
894 | ipmi_watchdog_state = WDOG_TIMEOUT_RESET; | ||
895 | panic_halt_ipmi_set_timeout(); | ||
896 | } | ||
897 | |||
898 | return NOTIFY_OK; | ||
899 | } | ||
900 | |||
901 | static struct notifier_block wdog_panic_notifier = { | ||
902 | .notifier_call = wdog_panic_handler, | ||
903 | .next = NULL, | ||
904 | .priority = 150 /* priority: INT_MAX >= x >= 0 */ | ||
905 | }; | ||
906 | |||
907 | |||
908 | static void ipmi_new_smi(int if_num) | ||
909 | { | ||
910 | ipmi_register_watchdog(if_num); | ||
911 | } | ||
912 | |||
913 | static void ipmi_smi_gone(int if_num) | ||
914 | { | ||
915 | /* This can never be called, because once the watchdog is | ||
916 | registered, the interface can't go away until the watchdog | ||
917 | is unregistered. */ | ||
918 | } | ||
919 | |||
920 | static struct ipmi_smi_watcher smi_watcher = | ||
921 | { | ||
922 | .owner = THIS_MODULE, | ||
923 | .new_smi = ipmi_new_smi, | ||
924 | .smi_gone = ipmi_smi_gone | ||
925 | }; | ||
926 | |||
927 | static int __init ipmi_wdog_init(void) | ||
928 | { | ||
929 | int rv; | ||
930 | |||
931 | printk(KERN_INFO PFX "driver version " | ||
932 | IPMI_WATCHDOG_VERSION "\n"); | ||
933 | |||
934 | if (strcmp(action, "reset") == 0) { | ||
935 | action_val = WDOG_TIMEOUT_RESET; | ||
936 | } else if (strcmp(action, "none") == 0) { | ||
937 | action_val = WDOG_TIMEOUT_NONE; | ||
938 | } else if (strcmp(action, "power_cycle") == 0) { | ||
939 | action_val = WDOG_TIMEOUT_POWER_CYCLE; | ||
940 | } else if (strcmp(action, "power_off") == 0) { | ||
941 | action_val = WDOG_TIMEOUT_POWER_DOWN; | ||
942 | } else { | ||
943 | action_val = WDOG_TIMEOUT_RESET; | ||
944 | printk(KERN_INFO PFX "Unknown action '%s', defaulting to" | ||
945 | " reset\n", action); | ||
946 | } | ||
947 | |||
948 | if (strcmp(preaction, "pre_none") == 0) { | ||
949 | preaction_val = WDOG_PRETIMEOUT_NONE; | ||
950 | } else if (strcmp(preaction, "pre_smi") == 0) { | ||
951 | preaction_val = WDOG_PRETIMEOUT_SMI; | ||
952 | #ifdef HAVE_NMI_HANDLER | ||
953 | } else if (strcmp(preaction, "pre_nmi") == 0) { | ||
954 | preaction_val = WDOG_PRETIMEOUT_NMI; | ||
955 | #endif | ||
956 | } else if (strcmp(preaction, "pre_int") == 0) { | ||
957 | preaction_val = WDOG_PRETIMEOUT_MSG_INT; | ||
958 | } else { | ||
959 | preaction_val = WDOG_PRETIMEOUT_NONE; | ||
960 | printk(KERN_INFO PFX "Unknown preaction '%s', defaulting to" | ||
961 | " none\n", preaction); | ||
962 | } | ||
963 | |||
964 | if (strcmp(preop, "preop_none") == 0) { | ||
965 | preop_val = WDOG_PREOP_NONE; | ||
966 | } else if (strcmp(preop, "preop_panic") == 0) { | ||
967 | preop_val = WDOG_PREOP_PANIC; | ||
968 | } else if (strcmp(preop, "preop_give_data") == 0) { | ||
969 | preop_val = WDOG_PREOP_GIVE_DATA; | ||
970 | } else { | ||
971 | preop_val = WDOG_PREOP_NONE; | ||
972 | printk(KERN_INFO PFX "Unknown preop '%s', defaulting to" | ||
973 | " none\n", preop); | ||
974 | } | ||
975 | |||
976 | #ifdef HAVE_NMI_HANDLER | ||
977 | if (preaction_val == WDOG_PRETIMEOUT_NMI) { | ||
978 | if (preop_val == WDOG_PREOP_GIVE_DATA) { | ||
979 | printk(KERN_WARNING PFX "Pretimeout op is to give data" | ||
980 | " but NMI pretimeout is enabled, setting" | ||
981 | " pretimeout op to none\n"); | ||
982 | preop_val = WDOG_PREOP_NONE; | ||
983 | } | ||
984 | #ifdef CONFIG_X86_LOCAL_APIC | ||
985 | if (nmi_watchdog == NMI_IO_APIC) { | ||
986 | printk(KERN_WARNING PFX "nmi_watchdog is set to IO APIC" | ||
987 | " mode (value is %d), that is incompatible" | ||
988 | " with using NMI in the IPMI watchdog." | ||
989 | " Disabling IPMI nmi pretimeout.\n", | ||
990 | nmi_watchdog); | ||
991 | preaction_val = WDOG_PRETIMEOUT_NONE; | ||
992 | } else { | ||
993 | #endif | ||
994 | rv = request_nmi(&ipmi_nmi_handler); | ||
995 | if (rv) { | ||
996 | printk(KERN_WARNING PFX "Can't register nmi handler\n"); | ||
997 | return rv; | ||
998 | } | ||
999 | #ifdef CONFIG_X86_LOCAL_APIC | ||
1000 | } | ||
1001 | #endif | ||
1002 | } | ||
1003 | #endif | ||
1004 | |||
1005 | rv = ipmi_smi_watcher_register(&smi_watcher); | ||
1006 | if (rv) { | ||
1007 | #ifdef HAVE_NMI_HANDLER | ||
1008 | if (preaction_val == WDOG_PRETIMEOUT_NMI) | ||
1009 | release_nmi(&ipmi_nmi_handler); | ||
1010 | #endif | ||
1011 | printk(KERN_WARNING PFX "can't register smi watcher\n"); | ||
1012 | return rv; | ||
1013 | } | ||
1014 | |||
1015 | register_reboot_notifier(&wdog_reboot_notifier); | ||
1016 | notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier); | ||
1017 | |||
1018 | return 0; | ||
1019 | } | ||
1020 | |||
1021 | static __exit void ipmi_unregister_watchdog(void) | ||
1022 | { | ||
1023 | int rv; | ||
1024 | |||
1025 | down_write(®ister_sem); | ||
1026 | |||
1027 | #ifdef HAVE_NMI_HANDLER | ||
1028 | if (preaction_val == WDOG_PRETIMEOUT_NMI) | ||
1029 | release_nmi(&ipmi_nmi_handler); | ||
1030 | #endif | ||
1031 | |||
1032 | notifier_chain_unregister(&panic_notifier_list, &wdog_panic_notifier); | ||
1033 | unregister_reboot_notifier(&wdog_reboot_notifier); | ||
1034 | |||
1035 | if (! watchdog_user) | ||
1036 | goto out; | ||
1037 | |||
1038 | /* Make sure no one can call us any more. */ | ||
1039 | misc_deregister(&ipmi_wdog_miscdev); | ||
1040 | |||
1041 | /* Wait to make sure the message makes it out. The lower layer has | ||
1042 | pointers to our buffers, we want to make sure they are done before | ||
1043 | we release our memory. */ | ||
1044 | while (atomic_read(&set_timeout_tofree)) { | ||
1045 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
1046 | schedule_timeout(1); | ||
1047 | } | ||
1048 | |||
1049 | /* Disconnect from IPMI. */ | ||
1050 | rv = ipmi_destroy_user(watchdog_user); | ||
1051 | if (rv) { | ||
1052 | printk(KERN_WARNING PFX "error unlinking from IPMI: %d\n", | ||
1053 | rv); | ||
1054 | } | ||
1055 | watchdog_user = NULL; | ||
1056 | |||
1057 | out: | ||
1058 | up_write(®ister_sem); | ||
1059 | } | ||
1060 | |||
1061 | static void __exit ipmi_wdog_exit(void) | ||
1062 | { | ||
1063 | ipmi_smi_watcher_unregister(&smi_watcher); | ||
1064 | ipmi_unregister_watchdog(); | ||
1065 | } | ||
1066 | module_exit(ipmi_wdog_exit); | ||
1067 | module_init(ipmi_wdog_init); | ||
1068 | MODULE_LICENSE("GPL"); | ||