aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/ipmi/ipmi_poweroff.c
diff options
context:
space:
mode:
authorCorey Minyard <minyard@acm.org>2005-06-24 01:01:42 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-24 03:05:23 -0400
commit3b6259432dee81f928c22c48c080d5f6325ed92e (patch)
tree4b22a1a9a547a6e3da9d1a45cd83d210d9398fcd /drivers/char/ipmi/ipmi_poweroff.c
parent8f43f84f13a49fe5f0f7d1595082b6d7ec6daa85 (diff)
[PATCH] ipmi: add power cycle capability
This patch to adds "power cycle" functionality to the IPMI power off module ipmi_poweroff. It also contains changes to support procfs control of the feature. The power cycle action is considered an optional chassis control in the IPMI specification. However, it is definitely useful when the hardware supports it. A power cycle is usually required in order to reset a firmware in a bad state. This action is critical to allow remote management of servers. The implementation adds power cycle as optional to the ipmi_poweroff module. It can be modified dynamically through the proc entry mentioned above. During a power down and enabled, the power cycle command is sent to the BMC firmware. If it fails either due to non-support or some error, it will retry to send the command as power off. Signed-off-by: Christopher A. Poblete <Chris_Poblete@dell.com> Signed-off-by: Corey Minyard <minyard@acm.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char/ipmi/ipmi_poweroff.c')
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c112
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? */
45extern void (*pm_power_off)(void); 47extern 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 */
55static int poweroff_control = IPMI_CHASSIS_POWER_DOWN;
56
57/* parameter definition to allow user to flag power cycle */
58module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN);
59MODULE_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. */
48static unsigned int mfg_id; 62static unsigned int mfg_id;
49static unsigned int prod_id; 63static 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 */
541static 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 */
549static 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 */
515static int ipmi_poweroff_init (void) 578static 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) {