diff options
Diffstat (limited to 'drivers/char/ipmi/ipmi_poweroff.c')
-rw-r--r-- | drivers/char/ipmi/ipmi_poweroff.c | 112 |
1 files changed, 103 insertions, 9 deletions
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index cb5cdc6f14bf..61329b55c4a9 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c | |||
@@ -34,6 +34,8 @@ | |||
34 | #include <asm/semaphore.h> | 34 | #include <asm/semaphore.h> |
35 | #include <linux/kdev_t.h> | 35 | #include <linux/kdev_t.h> |
36 | #include <linux/module.h> | 36 | #include <linux/module.h> |
37 | #include <linux/moduleparam.h> | ||
38 | #include <linux/proc_fs.h> | ||
37 | #include <linux/string.h> | 39 | #include <linux/string.h> |
38 | #include <linux/ipmi.h> | 40 | #include <linux/ipmi.h> |
39 | #include <linux/ipmi_smi.h> | 41 | #include <linux/ipmi_smi.h> |
@@ -44,6 +46,18 @@ | |||
44 | /* Where to we insert our poweroff function? */ | 46 | /* Where to we insert our poweroff function? */ |
45 | extern void (*pm_power_off)(void); | 47 | extern void (*pm_power_off)(void); |
46 | 48 | ||
49 | /* Definitions for controlling power off (if the system supports it). It | ||
50 | * conveniently matches the IPMI chassis control values. */ | ||
51 | #define IPMI_CHASSIS_POWER_DOWN 0 /* power down, the default. */ | ||
52 | #define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */ | ||
53 | |||
54 | /* the IPMI data command */ | ||
55 | static int poweroff_control = IPMI_CHASSIS_POWER_DOWN; | ||
56 | |||
57 | /* parameter definition to allow user to flag power cycle */ | ||
58 | module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN); | ||
59 | MODULE_PARM_DESC(poweroff_control, " Set to 2 to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down."); | ||
60 | |||
47 | /* Stuff from the get device id command. */ | 61 | /* Stuff from the get device id command. */ |
48 | static unsigned int mfg_id; | 62 | static unsigned int mfg_id; |
49 | static unsigned int prod_id; | 63 | static unsigned int prod_id; |
@@ -349,26 +363,38 @@ static void ipmi_poweroff_chassis (ipmi_user_t user) | |||
349 | smi_addr.channel = IPMI_BMC_CHANNEL; | 363 | smi_addr.channel = IPMI_BMC_CHANNEL; |
350 | smi_addr.lun = 0; | 364 | smi_addr.lun = 0; |
351 | 365 | ||
352 | printk(KERN_INFO PFX "Powering down via IPMI chassis control command\n"); | 366 | powercyclefailed: |
367 | printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n", | ||
368 | ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle")); | ||
353 | 369 | ||
354 | /* | 370 | /* |
355 | * Power down | 371 | * Power down |
356 | */ | 372 | */ |
357 | send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST; | 373 | send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST; |
358 | send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; | 374 | send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; |
359 | data[0] = 0; /* Power down */ | 375 | data[0] = poweroff_control; |
360 | send_msg.data = data; | 376 | send_msg.data = data; |
361 | send_msg.data_len = sizeof(data); | 377 | send_msg.data_len = sizeof(data); |
362 | rv = ipmi_request_in_rc_mode(user, | 378 | rv = ipmi_request_in_rc_mode(user, |
363 | (struct ipmi_addr *) &smi_addr, | 379 | (struct ipmi_addr *) &smi_addr, |
364 | &send_msg); | 380 | &send_msg); |
365 | if (rv) { | 381 | if (rv) { |
366 | printk(KERN_ERR PFX "Unable to send chassis powerdown message," | 382 | switch (poweroff_control) { |
367 | " IPMI error 0x%x\n", rv); | 383 | case IPMI_CHASSIS_POWER_CYCLE: |
368 | goto out; | 384 | /* power cycle failed, default to power down */ |
385 | printk(KERN_ERR PFX "Unable to send chassis power " \ | ||
386 | "cycle message, IPMI error 0x%x\n", rv); | ||
387 | poweroff_control = IPMI_CHASSIS_POWER_DOWN; | ||
388 | goto powercyclefailed; | ||
389 | |||
390 | case IPMI_CHASSIS_POWER_DOWN: | ||
391 | default: | ||
392 | printk(KERN_ERR PFX "Unable to send chassis power " \ | ||
393 | "down message, IPMI error 0x%x\n", rv); | ||
394 | break; | ||
395 | } | ||
369 | } | 396 | } |
370 | 397 | ||
371 | out: | ||
372 | return; | 398 | return; |
373 | } | 399 | } |
374 | 400 | ||
@@ -430,7 +456,8 @@ static void ipmi_po_new_smi(int if_num) | |||
430 | if (ready) | 456 | if (ready) |
431 | return; | 457 | return; |
432 | 458 | ||
433 | rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, &ipmi_user); | 459 | rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, |
460 | &ipmi_user); | ||
434 | if (rv) { | 461 | if (rv) { |
435 | printk(KERN_ERR PFX "could not create IPMI user, error %d\n", | 462 | printk(KERN_ERR PFX "could not create IPMI user, error %d\n", |
436 | rv); | 463 | rv); |
@@ -509,21 +536,84 @@ static struct ipmi_smi_watcher smi_watcher = | |||
509 | }; | 536 | }; |
510 | 537 | ||
511 | 538 | ||
539 | #ifdef CONFIG_PROC_FS | ||
540 | /* displays properties to proc */ | ||
541 | static int proc_read_chassctrl(char *page, char **start, off_t off, int count, | ||
542 | int *eof, void *data) | ||
543 | { | ||
544 | return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n", | ||
545 | poweroff_control); | ||
546 | } | ||
547 | |||
548 | /* process property writes from proc */ | ||
549 | static int proc_write_chassctrl(struct file *file, const char *buffer, | ||
550 | unsigned long count, void *data) | ||
551 | { | ||
552 | int rv = count; | ||
553 | unsigned int newval = 0; | ||
554 | |||
555 | sscanf(buffer, "%d", &newval); | ||
556 | switch (newval) { | ||
557 | case IPMI_CHASSIS_POWER_CYCLE: | ||
558 | printk(KERN_INFO PFX "power cycle is now enabled\n"); | ||
559 | poweroff_control = newval; | ||
560 | break; | ||
561 | |||
562 | case IPMI_CHASSIS_POWER_DOWN: | ||
563 | poweroff_control = IPMI_CHASSIS_POWER_DOWN; | ||
564 | break; | ||
565 | |||
566 | default: | ||
567 | rv = -EINVAL; | ||
568 | break; | ||
569 | } | ||
570 | |||
571 | return rv; | ||
572 | } | ||
573 | #endif /* CONFIG_PROC_FS */ | ||
574 | |||
512 | /* | 575 | /* |
513 | * Startup and shutdown functions. | 576 | * Startup and shutdown functions. |
514 | */ | 577 | */ |
515 | static int ipmi_poweroff_init (void) | 578 | static int ipmi_poweroff_init (void) |
516 | { | 579 | { |
517 | int rv; | 580 | int rv; |
581 | struct proc_dir_entry *file; | ||
518 | 582 | ||
519 | printk ("Copyright (C) 2004 MontaVista Software -" | 583 | printk ("Copyright (C) 2004 MontaVista Software -" |
520 | " IPMI Powerdown via sys_reboot version " | 584 | " IPMI Powerdown via sys_reboot version " |
521 | IPMI_POWEROFF_VERSION ".\n"); | 585 | IPMI_POWEROFF_VERSION ".\n"); |
522 | 586 | ||
587 | switch (poweroff_control) { | ||
588 | case IPMI_CHASSIS_POWER_CYCLE: | ||
589 | printk(KERN_INFO PFX "Power cycle is enabled.\n"); | ||
590 | break; | ||
591 | |||
592 | case IPMI_CHASSIS_POWER_DOWN: | ||
593 | default: | ||
594 | poweroff_control = IPMI_CHASSIS_POWER_DOWN; | ||
595 | break; | ||
596 | } | ||
597 | |||
523 | rv = ipmi_smi_watcher_register(&smi_watcher); | 598 | rv = ipmi_smi_watcher_register(&smi_watcher); |
524 | if (rv) | 599 | if (rv) { |
525 | printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); | 600 | printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); |
601 | goto out_err; | ||
602 | } | ||
603 | |||
604 | #ifdef CONFIG_PROC_FS | ||
605 | file = create_proc_entry("poweroff_control", 0, proc_ipmi_root); | ||
606 | if (!file) { | ||
607 | printk(KERN_ERR PFX "Unable to create proc power control\n"); | ||
608 | } else { | ||
609 | file->nlink = 1; | ||
610 | file->read_proc = proc_read_chassctrl; | ||
611 | file->write_proc = proc_write_chassctrl; | ||
612 | file->owner = THIS_MODULE; | ||
613 | } | ||
614 | #endif | ||
526 | 615 | ||
616 | out_err: | ||
527 | return rv; | 617 | return rv; |
528 | } | 618 | } |
529 | 619 | ||
@@ -532,6 +622,10 @@ static __exit void ipmi_poweroff_cleanup(void) | |||
532 | { | 622 | { |
533 | int rv; | 623 | int rv; |
534 | 624 | ||
625 | #ifdef CONFIG_PROC_FS | ||
626 | remove_proc_entry("poweroff_control", proc_ipmi_root); | ||
627 | #endif | ||
628 | |||
535 | ipmi_smi_watcher_unregister(&smi_watcher); | 629 | ipmi_smi_watcher_unregister(&smi_watcher); |
536 | 630 | ||
537 | if (ready) { | 631 | if (ready) { |