1 2 3/* 4 * RTAS watchdog driver 5 * 6 * (C) Copyright IBM Corp. 2005 7 * device driver to exploit watchdog RTAS functions 8 * 9 * Authors : Utz Bacher <utz.bacher@de.ibm.com> 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2, or (at your option) 14 * any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 */ 25 26#include <linux/fs.h> 27#include <linux/init.h> 28#include <linux/kernel.h> 29#include <linux/miscdevice.h> 30#include <linux/module.h> 31#include <linux/notifier.h> 32#include <linux/reboot.h> 33#include <linux/types.h> 34#include <linux/watchdog.h> 35#include <linux/uaccess.h> 36 37#include <asm/rtas.h> 38 39#define WDRTAS_MAGIC_CHAR 42 40#define WDRTAS_SUPPORTED_MASK (WDIOF_SETTIMEOUT | \ 41 WDIOF_MAGICCLOSE) 42 43MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>"); 44MODULE_DESCRIPTION("RTAS watchdog driver"); 45MODULE_LICENSE("GPL"); 46MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 47MODULE_ALIAS_MISCDEV(TEMP_MINOR); 48 49static int wdrtas_nowayout = WATCHDOG_NOWAYOUT; 50static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0); 51static char wdrtas_expect_close; 52 53static int wdrtas_interval; 54 55#define WDRTAS_THERMAL_SENSOR 3 56static int wdrtas_token_get_sensor_state; 57#define WDRTAS_SURVEILLANCE_IND 9000 58static int wdrtas_token_set_indicator; 59#define WDRTAS_SP_SPI 28 60static int wdrtas_token_get_sp; 61static int wdrtas_token_event_scan; 62 63#define WDRTAS_DEFAULT_INTERVAL 300 64 65#define WDRTAS_LOGBUFFER_LEN 128 66static char wdrtas_logbuffer[WDRTAS_LOGBUFFER_LEN]; 67 68 69/*** watchdog access functions */ 70 71/** 72 * wdrtas_set_interval - sets the watchdog interval 73 * @interval: new interval 74 * 75 * returns 0 on success, <0 on failures 76 * 77 * wdrtas_set_interval sets the watchdog keepalive interval by calling the 78 * RTAS function set-indicator (surveillance). The unit of interval is 79 * seconds. 80 */ 81 82static int wdrtas_set_interval(int interval) 83{ 84 long result; 85 static int print_msg = 10; 86 87 /* rtas uses minutes */ 88 interval = (interval + 59) / 60; 89 90 result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL, 91 WDRTAS_SURVEILLANCE_IND, 0, interval); 92 if (result < 0 && print_msg) { 93 printk(KERN_ERR "wdrtas: setting the watchdog to %i " 94 "timeout failed: %li\n", interval, result); 95 print_msg--; 96 } 97 98 return result; 99} 100 101#define WDRTAS_SP_SPI_LEN 4 102 103/** 104 * wdrtas_get_interval - returns the current watchdog interval 105 * @fallback_value: value (in seconds) to use, if the RTAS call fails 106 * 107 * returns the interval 108 * 109 * wdrtas_get_interval returns the current watchdog keepalive interval 110 * as reported by the RTAS function ibm,get-system-parameter. The unit 111 * of the return value is seconds. 112 */ 113static int wdrtas_get_interval(int fallback_value) 114{ 115 long result; 116 char value[WDRTAS_SP_SPI_LEN]; 117 118 spin_lock(&rtas_data_buf_lock); 119 memset(rtas_data_buf, 0, WDRTAS_SP_SPI_LEN); 120 result = rtas_call(wdrtas_token_get_sp, 3, 1, NULL, 121 WDRTAS_SP_SPI, __pa(rtas_data_buf), 122 WDRTAS_SP_SPI_LEN); 123 124 memcpy(value, rtas_data_buf, WDRTAS_SP_SPI_LEN); 125 spin_unlock(&rtas_data_buf_lock); 126 127 if (value[0] != 0 || value[1] != 2 || value[3] != 0 || result < 0) { 128 printk(KERN_WARNING "wdrtas: could not get sp_spi watchdog " 129 "timeout (%li). Continuing\n", result); 130 return fallback_value; 131 } 132 133 /* rtas uses minutes */ 134 return ((int)value[2]) * 60; 135} 136 137/** 138 * wdrtas_timer_start - starts watchdog 139 * 140 * wdrtas_timer_start starts the watchdog by calling the RTAS function 141 * set-interval (surveillance) 142 */ 143static void wdrtas_timer_start(void) 144{ 145 wdrtas_set_interval(wdrtas_interval); 146} 147 148/** 149 * wdrtas_timer_stop - stops watchdog 150 * 151 * wdrtas_timer_stop stops the watchdog timer by calling the RTAS function 152 * set-interval (surveillance) 153 */ 154static void wdrtas_timer_stop(void) 155{ 156 wdrtas_set_interval(0); 157} 158 159/** 160 * wdrtas_log_scanned_event - logs an event we received during keepalive 161 * 162 * wdrtas_log_scanned_event prints a message to the log buffer dumping 163 * the results of the last event-scan call 164 */ 165static void wdrtas_log_scanned_event(void) 166{ 167 int i; 168 169 for (i = 0; i < WDRTAS_LOGBUFFER_LEN; i += 16) 170 printk(KERN_INFO "wdrtas: dumping event (line %i/%i), data = " 171 "%02x %02x %02x %02x %02x %02x %02x %02x " 172 "%02x %02x %02x %02x %02x %02x %02x %02x\n", 173 (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16), 174 wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1], 175 wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3], 176 wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5], 177 wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7], 178 wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9], 179 wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11], 180 wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13], 181 wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]); 182} 183 184/** 185 * wdrtas_timer_keepalive - resets watchdog timer to keep system alive 186 * 187 * wdrtas_timer_keepalive restarts the watchdog timer by calling the 188 * RTAS function event-scan and repeats these calls as long as there are 189 * events available. All events will be dumped. 190 */ 191static void wdrtas_timer_keepalive(void) 192{ 193 long result; 194 195 do { 196 result = rtas_call(wdrtas_token_event_scan, 4, 1, NULL, 197 RTAS_EVENT_SCAN_ALL_EVENTS, 0, 198 (void *)__pa(wdrtas_logbuffer), 199 WDRTAS_LOGBUFFER_LEN); 200 if (result < 0) 201 printk(KERN_ERR "wdrtas: event-scan failed: %li\n", 202 result); 203 if (result == 0) 204 wdrtas_log_scanned_event(); 205 } while (result == 0); 206} 207 208/** 209 * wdrtas_get_temperature - returns current temperature 210 * 211 * returns temperature or <0 on failures 212 * 213 * wdrtas_get_temperature returns the current temperature in Fahrenheit. It 214 * uses the RTAS call get-sensor-state, token 3 to do so 215 */ 216static int wdrtas_get_temperature(void) 217{ 218 int result; 219 int temperature = 0; 220 221 result = rtas_get_sensor(WDRTAS_THERMAL_SENSOR, 0, &temperature); 222 223 if (result < 0) 224 printk(KERN_WARNING "wdrtas: reading the thermal sensor " 225 "failed: %i\n", result); 226 else 227 temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */ 228 229 return temperature; 230} 231 232/** 233 * wdrtas_get_status - returns the status of the watchdog 234 * 235 * returns a bitmask of defines WDIOF_... as defined in 236 * include/linux/watchdog.h 237 */ 238static int wdrtas_get_status(void) 239{ 240 return 0; /* TODO */ 241} 242 243/** 244 * wdrtas_get_boot_status - returns the reason for the last boot 245 * 246 * returns a bitmask of defines WDIOF_... as defined in 247 * include/linux/watchdog.h, indicating why the watchdog rebooted the system 248 */ 249static int wdrtas_get_boot_status(void) 250{ 251 return 0; /* TODO */ 252} 253 254/*** watchdog API and operations stuff */ 255 256/* wdrtas_write - called when watchdog device is written to 257 * @file: file structure 258 * @buf: user buffer with data 259 * @len: amount to data written 260 * @ppos: position in file 261 * 262 * returns the number of successfully processed characters, which is always 263 * the number of bytes passed to this function 264 * 265 * wdrtas_write processes all the data given to it and looks for the magic 266 * character 'V'. This character allows the watchdog device to be closed 267 * properly. 268 */ 269static ssize_t wdrtas_write(struct file *file, const char __user *buf, 270 size_t len, loff_t *ppos) 271{ 272 int i; 273 char c; 274 275 if (!len) 276 goto out; 277 278 if (!wdrtas_nowayout) { 279 wdrtas_expect_close = 0; 280 /* look for 'V' */ 281 for (i = 0; i < len; i++) { 282 if (get_user(c, buf + i)) 283 return -EFAULT; 284 /* allow to close device */ 285 if (c == 'V') 286 wdrtas_expect_close = WDRTAS_MAGIC_CHAR; 287 } 288 } 289 290 wdrtas_timer_keepalive(); 291 292out: 293 return len; 294} 295 296/** 297 * wdrtas_ioctl - ioctl function for the watchdog device 298 * @file: file structure 299 * @cmd: command for ioctl 300 * @arg: argument pointer 301 * 302 * returns 0 on success, <0 on failure 303 * 304 * wdrtas_ioctl implements the watchdog API ioctls 305 */ 306 307static long wdrtas_ioctl(struct file *file, unsigned int cmd, 308 unsigned long arg) 309{ 310 int __user *argp = (void __user *)arg; 311 int i; 312 static const struct watchdog_info wdinfo = { 313 .options = WDRTAS_SUPPORTED_MASK, 314 .firmware_version = 0, 315 .identity = "wdrtas", 316 }; 317 318 switch (cmd) { 319 case WDIOC_GETSUPPORT: 320 if (copy_to_user(argp, &wdinfo, sizeof(wdinfo))) 321 return -EFAULT; 322 return 0; 323 324 case WDIOC_GETSTATUS: 325 i = wdrtas_get_status(); 326 return put_user(i, argp); 327 328 case WDIOC_GETBOOTSTATUS: 329 i = wdrtas_get_boot_status(); 330 return put_user(i, argp); 331 332 case WDIOC_GETTEMP: 333 if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) 334 return -EOPNOTSUPP; 335 336 i = wdrtas_get_temperature(); 337 return put_user(i, argp); 338 339 case WDIOC_SETOPTIONS: 340 if (get_user(i, argp)) 341 return -EFAULT; 342 if (i & WDIOS_DISABLECARD) 343 wdrtas_timer_stop(); 344 if (i & WDIOS_ENABLECARD) { 345 wdrtas_timer_keepalive(); 346 wdrtas_timer_start(); 347 } 348 /* not implemented. Done by H8 349 if (i & WDIOS_TEMPPANIC) { 350 } */ 351 return 0; 352 353 case WDIOC_KEEPALIVE: 354 wdrtas_timer_keepalive(); 355 return 0; 356 357 case WDIOC_SETTIMEOUT: 358 if (get_user(i, argp)) 359 return -EFAULT; 360 361 if (wdrtas_set_interval(i)) 362 return -EINVAL; 363 364 wdrtas_timer_keepalive(); 365 366 if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) 367 wdrtas_interval = i; 368 else 369 wdrtas_interval = wdrtas_get_interval(i); 370 /* fallthrough */ 371 372 case WDIOC_GETTIMEOUT: 373 return put_user(wdrtas_interval, argp); 374 375 default: 376 return -ENOTTY; 377 } 378} 379 380/** 381 * wdrtas_open - open function of watchdog device 382 * @inode: inode structure 383 * @file: file structure 384 * 385 * returns 0 on success, -EBUSY if the file has been opened already, <0 on 386 * other failures 387 * 388 * function called when watchdog device is opened 389 */ 390static int wdrtas_open(struct inode *inode, struct file *file) 391{ 392 /* only open once */ 393 if (atomic_inc_return(&wdrtas_miscdev_open) > 1) { 394 atomic_dec(&wdrtas_miscdev_open); 395 return -EBUSY; 396 } 397 398 wdrtas_timer_start(); 399 wdrtas_timer_keepalive(); 400 401 return nonseekable_open(inode, file); 402} 403 404/** 405 * wdrtas_close - close function of watchdog device 406 * @inode: inode structure 407 * @file: file structure 408 * 409 * returns 0 on success 410 * 411 * close function. Always succeeds 412 */ 413static int wdrtas_close(struct inode *inode, struct file *file) 414{ 415 /* only stop watchdog, if this was announced using 'V' before */ 416 if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR) 417 wdrtas_timer_stop(); 418 else { 419 printk(KERN_WARNING "wdrtas: got unexpected close. Watchdog " 420 "not stopped.\n"); 421 wdrtas_timer_keepalive(); 422 } 423 424 wdrtas_expect_close = 0; 425 atomic_dec(&wdrtas_miscdev_open); 426 return 0; 427} 428 429/** 430 * wdrtas_temp_read - gives back the temperature in fahrenheit 431 * @file: file structure 432 * @buf: user buffer 433 * @count: number of bytes to be read 434 * @ppos: position in file 435 * 436 * returns always 1 or -EFAULT in case of user space copy failures, <0 on 437 * other failures 438 * 439 * wdrtas_temp_read gives the temperature to the users by copying this 440 * value as one byte into the user space buffer. The unit is Fahrenheit... 441 */ 442static ssize_t wdrtas_temp_read(struct file *file, char __user *buf, 443 size_t count, loff_t *ppos) 444{ 445 int temperature = 0; 446 447 temperature = wdrtas_get_temperature(); 448 if (temperature < 0) 449 return temperature; 450 451 if (copy_to_user(buf, &temperature, 1)) 452 return -EFAULT; 453 454 return 1; 455} 456 457/** 458 * wdrtas_temp_open - open function of temperature device 459 * @inode: inode structure 460 * @file: file structure 461 * 462 * returns 0 on success, <0 on failure 463 * 464 * function called when temperature device is opened 465 */ 466static int wdrtas_temp_open(struct inode *inode, struct file *file) 467{ 468 return nonseekable_open(inode, file); 469} 470 471/** 472 * wdrtas_temp_close - close function of temperature device 473 * @inode: inode structure 474 * @file: file structure 475 * 476 * returns 0 on success 477 * 478 * close function. Always succeeds 479 */ 480static int wdrtas_temp_close(struct inode *inode, struct file *file) 481{ 482 return 0; 483} 484 485/** 486 * wdrtas_reboot - reboot notifier function 487 * @nb: notifier block structure 488 * @code: reboot code 489 * @ptr: unused 490 * 491 * returns NOTIFY_DONE 492 * 493 * wdrtas_reboot stops the watchdog in case of a reboot 494 */ 495static int wdrtas_reboot(struct notifier_block *this, 496 unsigned long code, void *ptr) 497{ 498 if (code == SYS_DOWN || code == SYS_HALT) 499 wdrtas_timer_stop(); 500 501 return NOTIFY_DONE; 502} 503 504/*** initialization stuff */ 505 506static const struct file_operations wdrtas_fops = { 507 .owner = THIS_MODULE, 508 .llseek = no_llseek, 509 .write = wdrtas_write, 510 .unlocked_ioctl = wdrtas_ioctl, 511 .open = wdrtas_open, 512 .release = wdrtas_close, 513}; 514 515static struct miscdevice wdrtas_miscdev = { 516 .minor = WATCHDOG_MINOR, 517 .name = "watchdog", 518 .fops = &wdrtas_fops, 519}; 520 521static const struct file_operations wdrtas_temp_fops = { 522 .owner = THIS_MODULE, 523 .llseek = no_llseek, 524 .read = wdrtas_temp_read, 525 .open = wdrtas_temp_open, 526 .release = wdrtas_temp_close, 527}; 528 529static struct miscdevice wdrtas_tempdev = { 530 .minor = TEMP_MINOR, 531 .name = "temperature", 532 .fops = &wdrtas_temp_fops, 533}; 534 535static struct notifier_block wdrtas_notifier = { 536 .notifier_call = wdrtas_reboot, 537}; 538 539/** 540 * wdrtas_get_tokens - reads in RTAS tokens 541 * 542 * returns 0 on success, <0 on failure 543 * 544 * wdrtas_get_tokens reads in the tokens for the RTAS calls used in 545 * this watchdog driver. It tolerates, if "get-sensor-state" and 546 * "ibm,get-system-parameter" are not available. 547 */ 548static int wdrtas_get_tokens(void) 549{ 550 wdrtas_token_get_sensor_state = rtas_token("get-sensor-state"); 551 if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) { 552 printk(KERN_WARNING "wdrtas: couldn't get token for " 553 "get-sensor-state. Trying to continue without " 554 "temperature support.\n"); 555 } 556 557 wdrtas_token_get_sp = rtas_token("ibm,get-system-parameter"); 558 if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) { 559 printk(KERN_WARNING "wdrtas: couldn't get token for " 560 "ibm,get-system-parameter. Trying to continue with " 561 "a default timeout value of %i seconds.\n", 562 WDRTAS_DEFAULT_INTERVAL); 563 } 564 565 wdrtas_token_set_indicator = rtas_token("set-indicator"); 566 if (wdrtas_token_set_indicator == RTAS_UNKNOWN_SERVICE) { 567 printk(KERN_ERR "wdrtas: couldn't get token for " 568 "set-indicator. Terminating watchdog code.\n"); 569 return -EIO; 570 } 571 572 wdrtas_token_event_scan = rtas_token("event-scan"); 573 if (wdrtas_token_event_scan == RTAS_UNKNOWN_SERVICE) { 574 printk(KERN_ERR "wdrtas: couldn't get token for event-scan. " 575 "Terminating watchdog code.\n"); 576 return -EIO; 577 } 578 579 return 0; 580} 581 582/** 583 * wdrtas_unregister_devs - unregisters the misc dev handlers 584 * 585 * wdrtas_register_devs unregisters the watchdog and temperature watchdog 586 * misc devs 587 */ 588static void wdrtas_unregister_devs(void) 589{ 590 misc_deregister(&wdrtas_miscdev); 591 if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) 592 misc_deregister(&wdrtas_tempdev); 593} 594 595/** 596 * wdrtas_register_devs - registers the misc dev handlers 597 * 598 * returns 0 on success, <0 on failure 599 * 600 * wdrtas_register_devs registers the watchdog and temperature watchdog 601 * misc devs 602 */ 603static int wdrtas_register_devs(void) 604{ 605 int result; 606 607 result = misc_register(&wdrtas_miscdev); 608 if (result) { 609 printk(KERN_ERR "wdrtas: couldn't register watchdog misc " 610 "device. Terminating watchdog code.\n"); 611 return result; 612 } 613 614 if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) { 615 result = misc_register(&wdrtas_tempdev); 616 if (result) { 617 printk(KERN_WARNING "wdrtas: couldn't register " 618 "watchdog temperature misc device. Continuing " 619 "without temperature support.\n"); 620 wdrtas_token_get_sensor_state = RTAS_UNKNOWN_SERVICE; 621 } 622 } 623 624 return 0; 625} 626 627/** 628 * wdrtas_init - init function of the watchdog driver 629 * 630 * returns 0 on success, <0 on failure 631 * 632 * registers the file handlers and the reboot notifier 633 */ 634static int __init wdrtas_init(void) 635{ 636 if (wdrtas_get_tokens()) 637 return -ENODEV; 638 639 if (wdrtas_register_devs()) 640 return -ENODEV; 641 642 if (register_reboot_notifier(&wdrtas_notifier)) { 643 printk(KERN_ERR "wdrtas: could not register reboot notifier. " 644 "Terminating watchdog code.\n"); 645 wdrtas_unregister_devs(); 646 return -ENODEV; 647 } 648 649 if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) 650 wdrtas_interval = WDRTAS_DEFAULT_INTERVAL; 651 else 652 wdrtas_interval = wdrtas_get_interval(WDRTAS_DEFAULT_INTERVAL); 653 654 return 0; 655} 656 657/** 658 * wdrtas_exit - exit function of the watchdog driver 659 * 660 * unregisters the file handlers and the reboot notifier 661 */ 662static void __exit wdrtas_exit(void) 663{ 664 if (!wdrtas_nowayout) 665 wdrtas_timer_stop(); 666 667 wdrtas_unregister_devs(); 668 669 unregister_reboot_notifier(&wdrtas_notifier); 670} 671 672module_init(wdrtas_init); 673module_exit(wdrtas_exit); 674