aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/ipmi/ipmi_poweroff.c
diff options
context:
space:
mode:
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) {