blob: 19a8683bd25d3c81ac6b8a84462bbd01ce763f81 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/module.h>
35#include <linux/moduleparam.h>
36#include <linux/ipmi.h>
37#include <linux/ipmi_smi.h>
38#include <linux/watchdog.h>
39#include <linux/miscdevice.h>
40#include <linux/init.h>
Corey Minyardd6dfd132006-03-31 02:30:41 -080041#include <linux/completion.h>
Christoph Hellwig1eeb66a2007-05-08 00:27:03 -070042#include <linux/kdebug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/rwsem.h>
44#include <linux/errno.h>
45#include <asm/uaccess.h>
46#include <linux/notifier.h>
47#include <linux/nmi.h>
48#include <linux/reboot.h>
49#include <linux/wait.h>
50#include <linux/poll.h>
Corey Minyardcc4673e2005-11-07 00:59:57 -080051#include <linux/string.h>
52#include <linux/ctype.h>
Corey Minyardb3856762005-11-07 01:00:05 -080053#include <asm/atomic.h>
Corey Minyardf64da952007-05-08 00:23:58 -070054
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -070055#ifdef CONFIG_X86_LOCAL_APIC
56#include <asm/apic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#endif
58
59#define PFX "IPMI Watchdog: "
60
Linus Torvalds1da177e2005-04-16 15:20:36 -070061/*
62 * The IPMI command/response information for the watchdog timer.
63 */
64
65/* values for byte 1 of the set command, byte 2 of the get response. */
66#define WDOG_DONT_LOG (1 << 7)
67#define WDOG_DONT_STOP_ON_SET (1 << 6)
68#define WDOG_SET_TIMER_USE(byte, use) \
69 byte = ((byte) & 0xf8) | ((use) & 0x7)
70#define WDOG_GET_TIMER_USE(byte) ((byte) & 0x7)
71#define WDOG_TIMER_USE_BIOS_FRB2 1
72#define WDOG_TIMER_USE_BIOS_POST 2
73#define WDOG_TIMER_USE_OS_LOAD 3
74#define WDOG_TIMER_USE_SMS_OS 4
75#define WDOG_TIMER_USE_OEM 5
76
77/* values for byte 2 of the set command, byte 3 of the get response. */
78#define WDOG_SET_PRETIMEOUT_ACT(byte, use) \
79 byte = ((byte) & 0x8f) | (((use) & 0x7) << 4)
80#define WDOG_GET_PRETIMEOUT_ACT(byte) (((byte) >> 4) & 0x7)
81#define WDOG_PRETIMEOUT_NONE 0
82#define WDOG_PRETIMEOUT_SMI 1
83#define WDOG_PRETIMEOUT_NMI 2
84#define WDOG_PRETIMEOUT_MSG_INT 3
85
86/* Operations that can be performed on a pretimout. */
87#define WDOG_PREOP_NONE 0
88#define WDOG_PREOP_PANIC 1
89#define WDOG_PREOP_GIVE_DATA 2 /* Cause data to be available to
90 read. Doesn't work in NMI
91 mode. */
92
93/* Actions to perform on a full timeout. */
94#define WDOG_SET_TIMEOUT_ACT(byte, use) \
95 byte = ((byte) & 0xf8) | ((use) & 0x7)
96#define WDOG_GET_TIMEOUT_ACT(byte) ((byte) & 0x7)
97#define WDOG_TIMEOUT_NONE 0
98#define WDOG_TIMEOUT_RESET 1
99#define WDOG_TIMEOUT_POWER_DOWN 2
100#define WDOG_TIMEOUT_POWER_CYCLE 3
101
102/* Byte 3 of the get command, byte 4 of the get response is the
103 pre-timeout in seconds. */
104
105/* Bits for setting byte 4 of the set command, byte 5 of the get response. */
106#define WDOG_EXPIRE_CLEAR_BIOS_FRB2 (1 << 1)
107#define WDOG_EXPIRE_CLEAR_BIOS_POST (1 << 2)
108#define WDOG_EXPIRE_CLEAR_OS_LOAD (1 << 3)
109#define WDOG_EXPIRE_CLEAR_SMS_OS (1 << 4)
110#define WDOG_EXPIRE_CLEAR_OEM (1 << 5)
111
112/* Setting/getting the watchdog timer value. This is for bytes 5 and
113 6 (the timeout time) of the set command, and bytes 6 and 7 (the
114 timeout time) and 8 and 9 (the current countdown value) of the
115 response. The timeout value is given in seconds (in the command it
116 is 100ms intervals). */
117#define WDOG_SET_TIMEOUT(byte1, byte2, val) \
118 (byte1) = (((val) * 10) & 0xff), (byte2) = (((val) * 10) >> 8)
119#define WDOG_GET_TIMEOUT(byte1, byte2) \
120 (((byte1) | ((byte2) << 8)) / 10)
121
122#define IPMI_WDOG_RESET_TIMER 0x22
123#define IPMI_WDOG_SET_TIMER 0x24
124#define IPMI_WDOG_GET_TIMER 0x25
125
126/* These are here until the real ones get into the watchdog.h interface. */
127#ifndef WDIOC_GETTIMEOUT
128#define WDIOC_GETTIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 20, int)
129#endif
130#ifndef WDIOC_SET_PRETIMEOUT
131#define WDIOC_SET_PRETIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 21, int)
132#endif
133#ifndef WDIOC_GET_PRETIMEOUT
134#define WDIOC_GET_PRETIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 22, int)
135#endif
136
Andrey Panin4bfdf372005-07-27 11:43:58 -0700137static int nowayout = WATCHDOG_NOWAYOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800139static ipmi_user_t watchdog_user;
Corey Minyardb2c03942006-12-06 20:41:00 -0800140static int watchdog_ifnum;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142/* Default the timeout to 10 seconds. */
143static int timeout = 10;
144
145/* The pre-timeout is disabled by default. */
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800146static int pretimeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
148/* Default action is to reset the board on a timeout. */
149static unsigned char action_val = WDOG_TIMEOUT_RESET;
150
151static char action[16] = "reset";
152
153static unsigned char preaction_val = WDOG_PRETIMEOUT_NONE;
154
155static char preaction[16] = "pre_none";
156
157static unsigned char preop_val = WDOG_PREOP_NONE;
158
159static char preop[16] = "preop_none";
160static DEFINE_SPINLOCK(ipmi_read_lock);
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800161static char data_to_read;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162static DECLARE_WAIT_QUEUE_HEAD(read_q);
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800163static struct fasync_struct *fasync_q;
164static char pretimeout_since_last_heartbeat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165static char expect_close;
166
Corey Minyardb2c03942006-12-06 20:41:00 -0800167static int ifnum_to_use = -1;
168
Corey Minyardcc4673e2005-11-07 00:59:57 -0800169/* Parameters to ipmi_set_timeout */
170#define IPMI_SET_TIMEOUT_NO_HB 0
171#define IPMI_SET_TIMEOUT_HB_IF_NECESSARY 1
172#define IPMI_SET_TIMEOUT_FORCE_HB 2
173
174static int ipmi_set_timeout(int do_heartbeat);
Corey Minyardb2c03942006-12-06 20:41:00 -0800175static void ipmi_register_watchdog(int ipmi_intf);
176static void ipmi_unregister_watchdog(int ipmi_intf);
Corey Minyardcc4673e2005-11-07 00:59:57 -0800177
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178/* If true, the driver will start running as soon as it is configured
179 and ready. */
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800180static int start_now;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
Corey Minyardcc4673e2005-11-07 00:59:57 -0800182static int set_param_int(const char *val, struct kernel_param *kp)
183{
184 char *endp;
185 int l;
186 int rv = 0;
187
188 if (!val)
189 return -EINVAL;
190 l = simple_strtoul(val, &endp, 0);
191 if (endp == val)
192 return -EINVAL;
193
Corey Minyardcc4673e2005-11-07 00:59:57 -0800194 *((int *)kp->arg) = l;
195 if (watchdog_user)
196 rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
Corey Minyardcc4673e2005-11-07 00:59:57 -0800197
198 return rv;
199}
200
201static int get_param_int(char *buffer, struct kernel_param *kp)
202{
203 return sprintf(buffer, "%i", *((int *)kp->arg));
204}
205
206typedef int (*action_fn)(const char *intval, char *outval);
207
208static int action_op(const char *inval, char *outval);
209static int preaction_op(const char *inval, char *outval);
210static int preop_op(const char *inval, char *outval);
211static void check_parms(void);
212
213static int set_param_str(const char *val, struct kernel_param *kp)
214{
215 action_fn fn = (action_fn) kp->arg;
216 int rv = 0;
Sebastien Dugué43cdff92006-12-29 16:46:53 -0800217 char valcp[16];
218 char *s;
Corey Minyardcc4673e2005-11-07 00:59:57 -0800219
Sebastien Dugué43cdff92006-12-29 16:46:53 -0800220 strncpy(valcp, val, 16);
221 valcp[15] = '\0';
Pekka Enberg66f969d2006-06-23 02:05:45 -0700222
Sebastien Dugué43cdff92006-12-29 16:46:53 -0800223 s = strstrip(valcp);
Corey Minyardcc4673e2005-11-07 00:59:57 -0800224
Pekka Enberg66f969d2006-06-23 02:05:45 -0700225 rv = fn(s, NULL);
Corey Minyardcc4673e2005-11-07 00:59:57 -0800226 if (rv)
Corey Minyardf8fbcd32007-10-18 03:07:08 -0700227 goto out;
Corey Minyardcc4673e2005-11-07 00:59:57 -0800228
229 check_parms();
230 if (watchdog_user)
231 rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
232
Corey Minyardf8fbcd32007-10-18 03:07:08 -0700233 out:
Corey Minyardcc4673e2005-11-07 00:59:57 -0800234 return rv;
235}
236
237static int get_param_str(char *buffer, struct kernel_param *kp)
238{
239 action_fn fn = (action_fn) kp->arg;
240 int rv;
241
242 rv = fn(NULL, buffer);
243 if (rv)
244 return rv;
245 return strlen(buffer);
246}
247
Corey Minyardb2c03942006-12-06 20:41:00 -0800248
249static int set_param_wdog_ifnum(const char *val, struct kernel_param *kp)
250{
251 int rv = param_set_int(val, kp);
252 if (rv)
253 return rv;
254 if ((ifnum_to_use < 0) || (ifnum_to_use == watchdog_ifnum))
255 return 0;
256
257 ipmi_unregister_watchdog(watchdog_ifnum);
258 ipmi_register_watchdog(ifnum_to_use);
259 return 0;
260}
261
262module_param_call(ifnum_to_use, set_param_wdog_ifnum, get_param_int,
263 &ifnum_to_use, 0644);
264MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog "
265 "timer. Setting to -1 defaults to the first registered "
266 "interface");
267
Corey Minyardcc4673e2005-11-07 00:59:57 -0800268module_param_call(timeout, set_param_int, get_param_int, &timeout, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269MODULE_PARM_DESC(timeout, "Timeout value in seconds.");
Corey Minyardcc4673e2005-11-07 00:59:57 -0800270
271module_param_call(pretimeout, set_param_int, get_param_int, &pretimeout, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds.");
Corey Minyardcc4673e2005-11-07 00:59:57 -0800273
274module_param_call(action, set_param_str, get_param_str, action_op, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275MODULE_PARM_DESC(action, "Timeout action. One of: "
276 "reset, none, power_cycle, power_off.");
Corey Minyardcc4673e2005-11-07 00:59:57 -0800277
278module_param_call(preaction, set_param_str, get_param_str, preaction_op, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279MODULE_PARM_DESC(preaction, "Pretimeout action. One of: "
280 "pre_none, pre_smi, pre_nmi, pre_int.");
Corey Minyardcc4673e2005-11-07 00:59:57 -0800281
282module_param_call(preop, set_param_str, get_param_str, preop_op, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283MODULE_PARM_DESC(preop, "Pretimeout driver operation. One of: "
284 "preop_none, preop_panic, preop_give_data.");
Corey Minyardcc4673e2005-11-07 00:59:57 -0800285
Corey Minyardb2c03942006-12-06 20:41:00 -0800286module_param(start_now, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287MODULE_PARM_DESC(start_now, "Set to 1 to start the watchdog as"
288 "soon as the driver is loaded.");
Corey Minyardcc4673e2005-11-07 00:59:57 -0800289
290module_param(nowayout, int, 0644);
Corey Minyardb2c03942006-12-06 20:41:00 -0800291MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
292 "(default=CONFIG_WATCHDOG_NOWAYOUT)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
294/* Default state of the timer. */
295static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
296
297/* If shutting down via IPMI, we ignore the heartbeat. */
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800298static int ipmi_ignore_heartbeat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
300/* Is someone using the watchdog? Only one user is allowed. */
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800301static unsigned long ipmi_wdog_open;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
303/* If set to 1, the heartbeat command will set the state to reset and
304 start the timer. The timer doesn't normally run when the driver is
305 first opened until the heartbeat is set the first time, this
306 variable is used to accomplish this. */
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800307static int ipmi_start_timer_on_heartbeat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309/* IPMI version of the BMC. */
310static unsigned char ipmi_version_major;
311static unsigned char ipmi_version_minor;
312
Corey Minyardb3856762005-11-07 01:00:05 -0800313/* If a pretimeout occurs, this is used to allow only one panic to happen. */
314static atomic_t preop_panic_excl = ATOMIC_INIT(-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316static int ipmi_heartbeat(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Corey Minyardd6dfd132006-03-31 02:30:41 -0800318/* We use a mutex to make sure that only one thing can send a set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 timeout at one time, because we only have one copy of the data.
Corey Minyardd6dfd132006-03-31 02:30:41 -0800320 The mutex is claimed when the set_timeout is sent and freed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 when both messages are free. */
322static atomic_t set_timeout_tofree = ATOMIC_INIT(0);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800323static DEFINE_MUTEX(set_timeout_lock);
324static DECLARE_COMPLETION(set_timeout_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325static void set_timeout_free_smi(struct ipmi_smi_msg *msg)
326{
327 if (atomic_dec_and_test(&set_timeout_tofree))
Corey Minyardd6dfd132006-03-31 02:30:41 -0800328 complete(&set_timeout_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329}
330static void set_timeout_free_recv(struct ipmi_recv_msg *msg)
331{
332 if (atomic_dec_and_test(&set_timeout_tofree))
Corey Minyardd6dfd132006-03-31 02:30:41 -0800333 complete(&set_timeout_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335static struct ipmi_smi_msg set_timeout_smi_msg =
336{
337 .done = set_timeout_free_smi
338};
339static struct ipmi_recv_msg set_timeout_recv_msg =
340{
341 .done = set_timeout_free_recv
342};
343
344static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
345 struct ipmi_recv_msg *recv_msg,
346 int *send_heartbeat_now)
347{
348 struct kernel_ipmi_msg msg;
349 unsigned char data[6];
350 int rv;
351 struct ipmi_system_interface_addr addr;
352 int hbnow = 0;
353
354
355 data[0] = 0;
356 WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS);
357
358 if ((ipmi_version_major > 1)
359 || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5)))
360 {
361 /* This is an IPMI 1.5-only feature. */
362 data[0] |= WDOG_DONT_STOP_ON_SET;
363 } else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
364 /* In ipmi 1.0, setting the timer stops the watchdog, we
365 need to start it back up again. */
366 hbnow = 1;
367 }
368
369 data[1] = 0;
370 WDOG_SET_TIMEOUT_ACT(data[1], ipmi_watchdog_state);
Corey Minyard8f05ee92005-09-06 15:18:39 -0700371 if ((pretimeout > 0) && (ipmi_watchdog_state != WDOG_TIMEOUT_NONE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 WDOG_SET_PRETIMEOUT_ACT(data[1], preaction_val);
373 data[2] = pretimeout;
374 } else {
375 WDOG_SET_PRETIMEOUT_ACT(data[1], WDOG_PRETIMEOUT_NONE);
376 data[2] = 0; /* No pretimeout. */
377 }
378 data[3] = 0;
379 WDOG_SET_TIMEOUT(data[4], data[5], timeout);
380
381 addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
382 addr.channel = IPMI_BMC_CHANNEL;
383 addr.lun = 0;
384
385 msg.netfn = 0x06;
386 msg.cmd = IPMI_WDOG_SET_TIMER;
387 msg.data = data;
388 msg.data_len = sizeof(data);
389 rv = ipmi_request_supply_msgs(watchdog_user,
390 (struct ipmi_addr *) &addr,
391 0,
392 &msg,
393 NULL,
394 smi_msg,
395 recv_msg,
396 1);
397 if (rv) {
398 printk(KERN_WARNING PFX "set timeout error: %d\n",
399 rv);
400 }
401
402 if (send_heartbeat_now)
403 *send_heartbeat_now = hbnow;
404
405 return rv;
406}
407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408static int ipmi_set_timeout(int do_heartbeat)
409{
410 int send_heartbeat_now;
411 int rv;
412
413
414 /* We can only send one of these at a time. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800415 mutex_lock(&set_timeout_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
417 atomic_set(&set_timeout_tofree, 2);
418
419 rv = i_ipmi_set_timeout(&set_timeout_smi_msg,
420 &set_timeout_recv_msg,
421 &send_heartbeat_now);
422 if (rv) {
Corey Minyardd6dfd132006-03-31 02:30:41 -0800423 mutex_unlock(&set_timeout_lock);
424 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 }
426
Corey Minyardd6dfd132006-03-31 02:30:41 -0800427 wait_for_completion(&set_timeout_wait);
428
429 if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB)
430 || ((send_heartbeat_now)
431 && (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY)))
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700432 {
Corey Minyardd6dfd132006-03-31 02:30:41 -0800433 rv = ipmi_heartbeat();
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700434 }
435 mutex_unlock(&set_timeout_lock);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800436
437out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 return rv;
439}
440
Corey Minyardfcfa4722007-10-18 03:07:09 -0700441static atomic_t panic_done_count = ATOMIC_INIT(0);
442
443static void panic_smi_free(struct ipmi_smi_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444{
Corey Minyardfcfa4722007-10-18 03:07:09 -0700445 atomic_dec(&panic_done_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446}
Corey Minyardfcfa4722007-10-18 03:07:09 -0700447static void panic_recv_free(struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
Corey Minyardfcfa4722007-10-18 03:07:09 -0700449 atomic_dec(&panic_done_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450}
Corey Minyardfcfa4722007-10-18 03:07:09 -0700451
452static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg =
453{
454 .done = panic_smi_free
455};
456static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg =
457{
458 .done = panic_recv_free
459};
460
461static void panic_halt_ipmi_heartbeat(void)
462{
463 struct kernel_ipmi_msg msg;
464 struct ipmi_system_interface_addr addr;
465 int rv;
466
467 /* Don't reset the timer if we have the timer turned off, that
468 re-enables the watchdog. */
469 if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
470 return;
471
472 addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
473 addr.channel = IPMI_BMC_CHANNEL;
474 addr.lun = 0;
475
476 msg.netfn = 0x06;
477 msg.cmd = IPMI_WDOG_RESET_TIMER;
478 msg.data = NULL;
479 msg.data_len = 0;
480 rv = ipmi_request_supply_msgs(watchdog_user,
481 (struct ipmi_addr *) &addr,
482 0,
483 &msg,
484 NULL,
485 &panic_halt_heartbeat_smi_msg,
486 &panic_halt_heartbeat_recv_msg,
487 1);
488 if (!rv)
489 atomic_add(2, &panic_done_count);
490}
491
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492static struct ipmi_smi_msg panic_halt_smi_msg =
493{
Corey Minyardfcfa4722007-10-18 03:07:09 -0700494 .done = panic_smi_free
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495};
496static struct ipmi_recv_msg panic_halt_recv_msg =
497{
Corey Minyardfcfa4722007-10-18 03:07:09 -0700498 .done = panic_recv_free
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499};
500
501/* Special call, doesn't claim any locks. This is only to be called
502 at panic or halt time, in run-to-completion mode, when the caller
503 is the only CPU and the only thing that will be going is these IPMI
504 calls. */
505static void panic_halt_ipmi_set_timeout(void)
506{
507 int send_heartbeat_now;
508 int rv;
509
Corey Minyardfcfa4722007-10-18 03:07:09 -0700510 /* Wait for the messages to be free. */
511 while (atomic_read(&panic_done_count) != 0)
512 ipmi_poll_interface(watchdog_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
514 &panic_halt_recv_msg,
515 &send_heartbeat_now);
516 if (!rv) {
Corey Minyardfcfa4722007-10-18 03:07:09 -0700517 atomic_add(2, &panic_done_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 if (send_heartbeat_now)
519 panic_halt_ipmi_heartbeat();
Corey Minyardfcfa4722007-10-18 03:07:09 -0700520 } else
521 printk(KERN_WARNING PFX
522 "Unable to extend the watchdog timeout.");
523 while (atomic_read(&panic_done_count) != 0)
524 ipmi_poll_interface(watchdog_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525}
526
527/* We use a semaphore to make sure that only one thing can send a
528 heartbeat at one time, because we only have one copy of the data.
529 The semaphore is claimed when the set_timeout is sent and freed
530 when both messages are free. */
531static atomic_t heartbeat_tofree = ATOMIC_INIT(0);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800532static DEFINE_MUTEX(heartbeat_lock);
533static DECLARE_COMPLETION(heartbeat_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534static void heartbeat_free_smi(struct ipmi_smi_msg *msg)
535{
536 if (atomic_dec_and_test(&heartbeat_tofree))
Corey Minyardd6dfd132006-03-31 02:30:41 -0800537 complete(&heartbeat_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538}
539static void heartbeat_free_recv(struct ipmi_recv_msg *msg)
540{
541 if (atomic_dec_and_test(&heartbeat_tofree))
Corey Minyardd6dfd132006-03-31 02:30:41 -0800542 complete(&heartbeat_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543}
544static struct ipmi_smi_msg heartbeat_smi_msg =
545{
546 .done = heartbeat_free_smi
547};
548static struct ipmi_recv_msg heartbeat_recv_msg =
549{
550 .done = heartbeat_free_recv
551};
552
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553static int ipmi_heartbeat(void)
554{
555 struct kernel_ipmi_msg msg;
556 int rv;
557 struct ipmi_system_interface_addr addr;
558
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700559 if (ipmi_ignore_heartbeat) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 return 0;
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
563 if (ipmi_start_timer_on_heartbeat) {
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700564 ipmi_start_timer_on_heartbeat = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 ipmi_watchdog_state = action_val;
566 return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
567 } else if (pretimeout_since_last_heartbeat) {
568 /* A pretimeout occurred, make sure we set the timeout.
569 We don't want to set the action, though, we want to
570 leave that alone (thus it can't be combined with the
571 above operation. */
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700572 pretimeout_since_last_heartbeat = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
574 }
575
Corey Minyardd6dfd132006-03-31 02:30:41 -0800576 mutex_lock(&heartbeat_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
578 atomic_set(&heartbeat_tofree, 2);
579
580 /* Don't reset the timer if we have the timer turned off, that
581 re-enables the watchdog. */
582 if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) {
Corey Minyardd6dfd132006-03-31 02:30:41 -0800583 mutex_unlock(&heartbeat_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 return 0;
585 }
586
587 addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
588 addr.channel = IPMI_BMC_CHANNEL;
589 addr.lun = 0;
590
591 msg.netfn = 0x06;
592 msg.cmd = IPMI_WDOG_RESET_TIMER;
593 msg.data = NULL;
594 msg.data_len = 0;
595 rv = ipmi_request_supply_msgs(watchdog_user,
596 (struct ipmi_addr *) &addr,
597 0,
598 &msg,
599 NULL,
600 &heartbeat_smi_msg,
601 &heartbeat_recv_msg,
602 1);
603 if (rv) {
Corey Minyardd6dfd132006-03-31 02:30:41 -0800604 mutex_unlock(&heartbeat_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 printk(KERN_WARNING PFX "heartbeat failure: %d\n",
606 rv);
607 return rv;
608 }
609
610 /* Wait for the heartbeat to be sent. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800611 wait_for_completion(&heartbeat_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
613 if (heartbeat_recv_msg.msg.data[0] != 0) {
614 /* Got an error in the heartbeat response. It was already
615 reported in ipmi_wdog_msg_handler, but we should return
616 an error here. */
617 rv = -EINVAL;
618 }
619
Corey Minyardd6dfd132006-03-31 02:30:41 -0800620 mutex_unlock(&heartbeat_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
622 return rv;
623}
624
Corey Minyard8a3628d2006-03-31 02:30:40 -0800625static struct watchdog_info ident =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626{
627 .options = 0, /* WDIOF_SETTIMEOUT, */
628 .firmware_version = 1,
629 .identity = "IPMI"
630};
631
632static int ipmi_ioctl(struct inode *inode, struct file *file,
633 unsigned int cmd, unsigned long arg)
634{
635 void __user *argp = (void __user *)arg;
636 int i;
637 int val;
638
639 switch(cmd) {
640 case WDIOC_GETSUPPORT:
641 i = copy_to_user(argp, &ident, sizeof(ident));
642 return i ? -EFAULT : 0;
643
644 case WDIOC_SETTIMEOUT:
645 i = copy_from_user(&val, argp, sizeof(int));
646 if (i)
647 return -EFAULT;
648 timeout = val;
649 return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
650
651 case WDIOC_GETTIMEOUT:
652 i = copy_to_user(argp, &timeout, sizeof(timeout));
653 if (i)
654 return -EFAULT;
655 return 0;
656
657 case WDIOC_SET_PRETIMEOUT:
658 i = copy_from_user(&val, argp, sizeof(int));
659 if (i)
660 return -EFAULT;
661 pretimeout = val;
662 return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
663
664 case WDIOC_GET_PRETIMEOUT:
665 i = copy_to_user(argp, &pretimeout, sizeof(pretimeout));
666 if (i)
667 return -EFAULT;
668 return 0;
669
670 case WDIOC_KEEPALIVE:
671 return ipmi_heartbeat();
672
673 case WDIOC_SETOPTIONS:
674 i = copy_from_user(&val, argp, sizeof(int));
675 if (i)
676 return -EFAULT;
677 if (val & WDIOS_DISABLECARD)
678 {
679 ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
680 ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
681 ipmi_start_timer_on_heartbeat = 0;
682 }
683
684 if (val & WDIOS_ENABLECARD)
685 {
686 ipmi_watchdog_state = action_val;
687 ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
688 }
689 return 0;
690
691 case WDIOC_GETSTATUS:
692 val = 0;
693 i = copy_to_user(argp, &val, sizeof(val));
694 if (i)
695 return -EFAULT;
696 return 0;
697
698 default:
699 return -ENOIOCTLCMD;
700 }
701}
702
703static ssize_t ipmi_write(struct file *file,
704 const char __user *buf,
705 size_t len,
706 loff_t *ppos)
707{
708 int rv;
709
710 if (len) {
711 if (!nowayout) {
712 size_t i;
713
714 /* In case it was set long ago */
715 expect_close = 0;
716
717 for (i = 0; i != len; i++) {
718 char c;
719
720 if (get_user(c, buf + i))
721 return -EFAULT;
722 if (c == 'V')
723 expect_close = 42;
724 }
725 }
726 rv = ipmi_heartbeat();
727 if (rv)
728 return rv;
729 return 1;
730 }
731 return 0;
732}
733
734static ssize_t ipmi_read(struct file *file,
735 char __user *buf,
736 size_t count,
737 loff_t *ppos)
738{
739 int rv = 0;
740 wait_queue_t wait;
741
742 if (count <= 0)
743 return 0;
744
745 /* Reading returns if the pretimeout has gone off, and it only does
746 it once per pretimeout. */
747 spin_lock(&ipmi_read_lock);
748 if (!data_to_read) {
749 if (file->f_flags & O_NONBLOCK) {
750 rv = -EAGAIN;
751 goto out;
752 }
753
754 init_waitqueue_entry(&wait, current);
755 add_wait_queue(&read_q, &wait);
756 while (!data_to_read) {
757 set_current_state(TASK_INTERRUPTIBLE);
758 spin_unlock(&ipmi_read_lock);
759 schedule();
760 spin_lock(&ipmi_read_lock);
761 }
762 remove_wait_queue(&read_q, &wait);
763
764 if (signal_pending(current)) {
765 rv = -ERESTARTSYS;
766 goto out;
767 }
768 }
769 data_to_read = 0;
770
771 out:
772 spin_unlock(&ipmi_read_lock);
773
774 if (rv == 0) {
775 if (copy_to_user(buf, &data_to_read, 1))
776 rv = -EFAULT;
777 else
778 rv = 1;
779 }
780
781 return rv;
782}
783
784static int ipmi_open(struct inode *ino, struct file *filep)
785{
Corey Minyarde8b33612005-09-06 15:18:45 -0700786 switch (iminor(ino)) {
787 case WATCHDOG_MINOR:
788 if (test_and_set_bit(0, &ipmi_wdog_open))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 return -EBUSY;
790
Corey Minyarde8b33612005-09-06 15:18:45 -0700791 /* Don't start the timer now, let it start on the
792 first heartbeat. */
793 ipmi_start_timer_on_heartbeat = 1;
794 return nonseekable_open(ino, filep);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
Corey Minyarde8b33612005-09-06 15:18:45 -0700796 default:
797 return (-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 }
799}
800
801static unsigned int ipmi_poll(struct file *file, poll_table *wait)
802{
803 unsigned int mask = 0;
804
805 poll_wait(file, &read_q, wait);
806
807 spin_lock(&ipmi_read_lock);
808 if (data_to_read)
809 mask |= (POLLIN | POLLRDNORM);
810 spin_unlock(&ipmi_read_lock);
811
812 return mask;
813}
814
815static int ipmi_fasync(int fd, struct file *file, int on)
816{
817 int result;
818
819 result = fasync_helper(fd, file, on, &fasync_q);
820
821 return (result);
822}
823
824static int ipmi_close(struct inode *ino, struct file *filep)
825{
Corey Minyard8a3628d2006-03-31 02:30:40 -0800826 if (iminor(ino) == WATCHDOG_MINOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 if (expect_close == 42) {
828 ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
829 ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 } else {
Corey Minyard8a3628d2006-03-31 02:30:40 -0800831 printk(KERN_CRIT PFX
832 "Unexpected close, not stopping watchdog!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 ipmi_heartbeat();
834 }
Corey Minyardec26d792005-05-01 08:59:11 -0700835 clear_bit(0, &ipmi_wdog_open);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 }
837
838 ipmi_fasync (-1, filep, 0);
839 expect_close = 0;
840
841 return 0;
842}
843
Arjan van de Ven62322d22006-07-03 00:24:21 -0700844static const struct file_operations ipmi_wdog_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 .owner = THIS_MODULE,
846 .read = ipmi_read,
847 .poll = ipmi_poll,
848 .write = ipmi_write,
849 .ioctl = ipmi_ioctl,
850 .open = ipmi_open,
851 .release = ipmi_close,
852 .fasync = ipmi_fasync,
853};
854
855static struct miscdevice ipmi_wdog_miscdev = {
856 .minor = WATCHDOG_MINOR,
857 .name = "watchdog",
858 .fops = &ipmi_wdog_fops
859};
860
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg,
862 void *handler_data)
863{
864 if (msg->msg.data[0] != 0) {
865 printk(KERN_ERR PFX "response: Error %x on cmd %x\n",
866 msg->msg.data[0],
867 msg->msg.cmd);
868 }
869
870 ipmi_free_recv_msg(msg);
871}
872
873static void ipmi_wdog_pretimeout_handler(void *handler_data)
874{
875 if (preaction_val != WDOG_PRETIMEOUT_NONE) {
Corey Minyardb3856762005-11-07 01:00:05 -0800876 if (preop_val == WDOG_PREOP_PANIC) {
877 if (atomic_inc_and_test(&preop_panic_excl))
878 panic("Watchdog pre-timeout");
879 } else if (preop_val == WDOG_PREOP_GIVE_DATA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 spin_lock(&ipmi_read_lock);
881 data_to_read = 1;
882 wake_up_interruptible(&read_q);
883 kill_fasync(&fasync_q, SIGIO, POLL_IN);
884
885 spin_unlock(&ipmi_read_lock);
886 }
887 }
888
889 /* On some machines, the heartbeat will give
890 an error and not work unless we re-enable
891 the timer. So do so. */
892 pretimeout_since_last_heartbeat = 1;
893}
894
895static struct ipmi_user_hndl ipmi_hndlrs =
896{
897 .ipmi_recv_hndl = ipmi_wdog_msg_handler,
898 .ipmi_watchdog_pretimeout = ipmi_wdog_pretimeout_handler
899};
900
901static void ipmi_register_watchdog(int ipmi_intf)
902{
903 int rv = -EBUSY;
904
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 if (watchdog_user)
906 goto out;
907
Corey Minyardb2c03942006-12-06 20:41:00 -0800908 if ((ifnum_to_use >= 0) && (ifnum_to_use != ipmi_intf))
909 goto out;
910
911 watchdog_ifnum = ipmi_intf;
912
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user);
914 if (rv < 0) {
915 printk(KERN_CRIT PFX "Unable to register with ipmi\n");
916 goto out;
917 }
918
919 ipmi_get_version(watchdog_user,
920 &ipmi_version_major,
921 &ipmi_version_minor);
922
923 rv = misc_register(&ipmi_wdog_miscdev);
924 if (rv < 0) {
925 ipmi_destroy_user(watchdog_user);
926 watchdog_user = NULL;
927 printk(KERN_CRIT PFX "Unable to register misc device\n");
928 }
929
930 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 if ((start_now) && (rv == 0)) {
932 /* Run from startup, so start the timer now. */
933 start_now = 0; /* Disable this function after first startup. */
934 ipmi_watchdog_state = action_val;
935 ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
936 printk(KERN_INFO PFX "Starting now!\n");
937 }
938}
939
Corey Minyardb2c03942006-12-06 20:41:00 -0800940static void ipmi_unregister_watchdog(int ipmi_intf)
941{
942 int rv;
943
Corey Minyardb2c03942006-12-06 20:41:00 -0800944 if (!watchdog_user)
945 goto out;
946
947 if (watchdog_ifnum != ipmi_intf)
948 goto out;
949
950 /* Make sure no one can call us any more. */
951 misc_deregister(&ipmi_wdog_miscdev);
952
953 /* Wait to make sure the message makes it out. The lower layer has
954 pointers to our buffers, we want to make sure they are done before
955 we release our memory. */
956 while (atomic_read(&set_timeout_tofree))
957 schedule_timeout_uninterruptible(1);
958
959 /* Disconnect from IPMI. */
960 rv = ipmi_destroy_user(watchdog_user);
961 if (rv) {
962 printk(KERN_WARNING PFX "error unlinking from IPMI: %d\n",
963 rv);
964 }
965 watchdog_user = NULL;
966
967 out:
Corey Minyardf8fbcd32007-10-18 03:07:08 -0700968 return;
Corey Minyardb2c03942006-12-06 20:41:00 -0800969}
970
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700971#ifdef HAVE_NMI_HANDLER
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972static int
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700973ipmi_nmi(void *dev_id, int cpu, int handled)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974{
Corey Minyard8f05ee92005-09-06 15:18:39 -0700975 /* If we are not expecting a timeout, ignore it. */
976 if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700977 return NOTIFY_DONE;
Corey Minyard8f05ee92005-09-06 15:18:39 -0700978
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 /* If no one else handled the NMI, we assume it was the IPMI
980 watchdog. */
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700981 if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) {
Corey Minyard8f05ee92005-09-06 15:18:39 -0700982 /* On some machines, the heartbeat will give
983 an error and not work unless we re-enable
984 the timer. So do so. */
985 pretimeout_since_last_heartbeat = 1;
Corey Minyardb3856762005-11-07 01:00:05 -0800986 if (atomic_inc_and_test(&preop_panic_excl))
987 panic(PFX "pre-timeout");
Corey Minyard8f05ee92005-09-06 15:18:39 -0700988 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700990 return NOTIFY_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991}
992
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700993static struct nmi_handler ipmi_nmi_handler =
994{
995 .link = LIST_HEAD_INIT(ipmi_nmi_handler.link),
996 .dev_name = "ipmi_watchdog",
997 .dev_id = NULL,
998 .handler = ipmi_nmi,
999 .priority = 0, /* Call us last. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000};
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001001int nmi_handler_registered;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002#endif
1003
1004static int wdog_reboot_handler(struct notifier_block *this,
1005 unsigned long code,
1006 void *unused)
1007{
1008 static int reboot_event_handled = 0;
1009
1010 if ((watchdog_user) && (!reboot_event_handled)) {
1011 /* Make sure we only do this once. */
1012 reboot_event_handled = 1;
1013
Corey Minyardfcfa4722007-10-18 03:07:09 -07001014 if (code == SYS_POWER_OFF || code == SYS_HALT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 /* Disable the WDT if we are shutting down. */
1016 ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
1017 panic_halt_ipmi_set_timeout();
Corey Minyard96febe92006-06-28 04:26:55 -07001018 } else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 /* Set a long timer to let the reboot happens, but
Corey Minyard96febe92006-06-28 04:26:55 -07001020 reboot if it hangs, but only if the watchdog
1021 timer was already running. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 timeout = 120;
1023 pretimeout = 0;
1024 ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
1025 panic_halt_ipmi_set_timeout();
1026 }
1027 }
1028 return NOTIFY_OK;
1029}
1030
1031static struct notifier_block wdog_reboot_notifier = {
1032 .notifier_call = wdog_reboot_handler,
1033 .next = NULL,
1034 .priority = 0
1035};
1036
1037static int wdog_panic_handler(struct notifier_block *this,
1038 unsigned long event,
1039 void *unused)
1040{
1041 static int panic_event_handled = 0;
1042
Corey Minyard96febe92006-06-28 04:26:55 -07001043 /* On a panic, if we have a panic timeout, make sure to extend
1044 the watchdog timer to a reasonable value to complete the
1045 panic, if the watchdog timer is running. Plus the
1046 pretimeout is meaningless at panic time. */
1047 if (watchdog_user && !panic_event_handled &&
1048 ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
1049 /* Make sure we do this only once. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 panic_event_handled = 1;
1051
1052 timeout = 255;
1053 pretimeout = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 panic_halt_ipmi_set_timeout();
1055 }
1056
1057 return NOTIFY_OK;
1058}
1059
1060static struct notifier_block wdog_panic_notifier = {
1061 .notifier_call = wdog_panic_handler,
1062 .next = NULL,
1063 .priority = 150 /* priority: INT_MAX >= x >= 0 */
1064};
1065
1066
Corey Minyard50c812b2006-03-26 01:37:21 -08001067static void ipmi_new_smi(int if_num, struct device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068{
1069 ipmi_register_watchdog(if_num);
1070}
1071
1072static void ipmi_smi_gone(int if_num)
1073{
Corey Minyardb2c03942006-12-06 20:41:00 -08001074 ipmi_unregister_watchdog(if_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075}
1076
1077static struct ipmi_smi_watcher smi_watcher =
1078{
1079 .owner = THIS_MODULE,
1080 .new_smi = ipmi_new_smi,
1081 .smi_gone = ipmi_smi_gone
1082};
1083
Corey Minyardcc4673e2005-11-07 00:59:57 -08001084static int action_op(const char *inval, char *outval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085{
Corey Minyardcc4673e2005-11-07 00:59:57 -08001086 if (outval)
1087 strcpy(outval, action);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
Corey Minyardcc4673e2005-11-07 00:59:57 -08001089 if (!inval)
1090 return 0;
1091
1092 if (strcmp(inval, "reset") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 action_val = WDOG_TIMEOUT_RESET;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001094 else if (strcmp(inval, "none") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 action_val = WDOG_TIMEOUT_NONE;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001096 else if (strcmp(inval, "power_cycle") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 action_val = WDOG_TIMEOUT_POWER_CYCLE;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001098 else if (strcmp(inval, "power_off") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 action_val = WDOG_TIMEOUT_POWER_DOWN;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001100 else
1101 return -EINVAL;
1102 strcpy(action, inval);
1103 return 0;
1104}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
Corey Minyardcc4673e2005-11-07 00:59:57 -08001106static int preaction_op(const char *inval, char *outval)
1107{
1108 if (outval)
1109 strcpy(outval, preaction);
1110
1111 if (!inval)
1112 return 0;
1113
1114 if (strcmp(inval, "pre_none") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 preaction_val = WDOG_PRETIMEOUT_NONE;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001116 else if (strcmp(inval, "pre_smi") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 preaction_val = WDOG_PRETIMEOUT_SMI;
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001118#ifdef HAVE_NMI_HANDLER
Corey Minyardcc4673e2005-11-07 00:59:57 -08001119 else if (strcmp(inval, "pre_nmi") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 preaction_val = WDOG_PRETIMEOUT_NMI;
1121#endif
Corey Minyardcc4673e2005-11-07 00:59:57 -08001122 else if (strcmp(inval, "pre_int") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 preaction_val = WDOG_PRETIMEOUT_MSG_INT;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001124 else
1125 return -EINVAL;
1126 strcpy(preaction, inval);
1127 return 0;
1128}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
Corey Minyardcc4673e2005-11-07 00:59:57 -08001130static int preop_op(const char *inval, char *outval)
1131{
1132 if (outval)
1133 strcpy(outval, preop);
1134
1135 if (!inval)
1136 return 0;
1137
1138 if (strcmp(inval, "preop_none") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 preop_val = WDOG_PREOP_NONE;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001140 else if (strcmp(inval, "preop_panic") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 preop_val = WDOG_PREOP_PANIC;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001142 else if (strcmp(inval, "preop_give_data") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 preop_val = WDOG_PREOP_GIVE_DATA;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001144 else
1145 return -EINVAL;
1146 strcpy(preop, inval);
1147 return 0;
1148}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
Corey Minyardcc4673e2005-11-07 00:59:57 -08001150static void check_parms(void)
1151{
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001152#ifdef HAVE_NMI_HANDLER
Corey Minyardcc4673e2005-11-07 00:59:57 -08001153 int do_nmi = 0;
1154 int rv;
1155
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 if (preaction_val == WDOG_PRETIMEOUT_NMI) {
Corey Minyardcc4673e2005-11-07 00:59:57 -08001157 do_nmi = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 if (preop_val == WDOG_PREOP_GIVE_DATA) {
1159 printk(KERN_WARNING PFX "Pretimeout op is to give data"
1160 " but NMI pretimeout is enabled, setting"
1161 " pretimeout op to none\n");
Corey Minyardcc4673e2005-11-07 00:59:57 -08001162 preop_op("preop_none", NULL);
1163 do_nmi = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 }
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001165#ifdef CONFIG_X86_LOCAL_APIC
1166 if (nmi_watchdog == NMI_IO_APIC) {
1167 printk(KERN_WARNING PFX "nmi_watchdog is set to IO APIC"
1168 " mode (value is %d), that is incompatible"
1169 " with using NMI in the IPMI watchdog."
1170 " Disabling IPMI nmi pretimeout.\n",
1171 nmi_watchdog);
1172 preaction_val = WDOG_PRETIMEOUT_NONE;
1173 do_nmi = 0;
1174 }
1175#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 }
Corey Minyardcc4673e2005-11-07 00:59:57 -08001177 if (do_nmi && !nmi_handler_registered) {
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001178 rv = request_nmi(&ipmi_nmi_handler);
Corey Minyardcc4673e2005-11-07 00:59:57 -08001179 if (rv) {
1180 printk(KERN_WARNING PFX
1181 "Can't register nmi handler\n");
1182 return;
1183 } else
1184 nmi_handler_registered = 1;
1185 } else if (!do_nmi && nmi_handler_registered) {
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001186 release_nmi(&ipmi_nmi_handler);
Corey Minyardcc4673e2005-11-07 00:59:57 -08001187 nmi_handler_registered = 0;
1188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189#endif
Corey Minyardcc4673e2005-11-07 00:59:57 -08001190}
1191
1192static int __init ipmi_wdog_init(void)
1193{
1194 int rv;
1195
1196 if (action_op(action, NULL)) {
1197 action_op("reset", NULL);
1198 printk(KERN_INFO PFX "Unknown action '%s', defaulting to"
1199 " reset\n", action);
1200 }
1201
1202 if (preaction_op(preaction, NULL)) {
1203 preaction_op("pre_none", NULL);
1204 printk(KERN_INFO PFX "Unknown preaction '%s', defaulting to"
1205 " none\n", preaction);
1206 }
1207
1208 if (preop_op(preop, NULL)) {
1209 preop_op("preop_none", NULL);
1210 printk(KERN_INFO PFX "Unknown preop '%s', defaulting to"
1211 " none\n", preop);
1212 }
1213
1214 check_parms();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
Corey Minyardb2c03942006-12-06 20:41:00 -08001216 register_reboot_notifier(&wdog_reboot_notifier);
1217 atomic_notifier_chain_register(&panic_notifier_list,
1218 &wdog_panic_notifier);
1219
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 rv = ipmi_smi_watcher_register(&smi_watcher);
1221 if (rv) {
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001222#ifdef HAVE_NMI_HANDLER
1223 if (preaction_val == WDOG_PRETIMEOUT_NMI)
1224 release_nmi(&ipmi_nmi_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225#endif
Corey Minyardb2c03942006-12-06 20:41:00 -08001226 atomic_notifier_chain_unregister(&panic_notifier_list,
1227 &wdog_panic_notifier);
1228 unregister_reboot_notifier(&wdog_reboot_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 printk(KERN_WARNING PFX "can't register smi watcher\n");
1230 return rv;
1231 }
1232
Corey Minyard1fdd75b2005-09-06 15:18:42 -07001233 printk(KERN_INFO PFX "driver initialized\n");
1234
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 return 0;
1236}
1237
Corey Minyardb2c03942006-12-06 20:41:00 -08001238static void __exit ipmi_wdog_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239{
Corey Minyardb2c03942006-12-06 20:41:00 -08001240 ipmi_smi_watcher_unregister(&smi_watcher);
1241 ipmi_unregister_watchdog(watchdog_ifnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001243#ifdef HAVE_NMI_HANDLER
Corey Minyardcc4673e2005-11-07 00:59:57 -08001244 if (nmi_handler_registered)
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001245 release_nmi(&ipmi_nmi_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246#endif
1247
Alan Sterne041c682006-03-27 01:16:30 -08001248 atomic_notifier_chain_unregister(&panic_notifier_list,
Corey Minyardb2c03942006-12-06 20:41:00 -08001249 &wdog_panic_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 unregister_reboot_notifier(&wdog_reboot_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251}
1252module_exit(ipmi_wdog_exit);
1253module_init(ipmi_wdog_init);
1254MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07001255MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
1256MODULE_DESCRIPTION("watchdog timer based upon the IPMI interface.");