aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorey Minyard <minyard@acm.org>2005-09-06 18:18:46 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-07 19:57:49 -0400
commit8c702e16207c70119d03df924de35f8c3629a5c4 (patch)
treef2d8ae84df7fd510f135a8074e0da67592372138
parent877197ef89aa486c8eea369a9357af34381d11e0 (diff)
[PATCH] ipmi poweroff: fix chassis control
The IPMI power control function proc_write_chassctrl was badly written, it directly used userspace pointers, it assumed that strings were NULL terminated, and it used the evil sscanf function. This converts over to using the sysctl interface for this data and changes the semantics to be a little more logical. Signed-off-by: Corey Minyard <minyard@acm.org> Cc: <viro@parcelfarce.linux.theplanet.co.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--Documentation/IPMI.txt13
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c132
-rw-r--r--include/linux/sysctl.h6
3 files changed, 71 insertions, 80 deletions
diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt
index 84d3d4d10c17..bf1cf98d2a27 100644
--- a/Documentation/IPMI.txt
+++ b/Documentation/IPMI.txt
@@ -605,12 +605,13 @@ is in the ipmi_poweroff module. When the system requests a powerdown,
605it will send the proper IPMI commands to do this. This is supported on 605it will send the proper IPMI commands to do this. This is supported on
606several platforms. 606several platforms.
607 607
608There is a module parameter named "poweroff_control" that may either be zero 608There is a module parameter named "poweroff_powercycle" that may
609(do a power down) or 2 (do a power cycle, power the system off, then power 609either be zero (do a power down) or non-zero (do a power cycle, power
610it on in a few seconds). Setting ipmi_poweroff.poweroff_control=x will do 610the system off, then power it on in a few seconds). Setting
611the same thing on the kernel command line. The parameter is also available 611ipmi_poweroff.poweroff_control=x will do the same thing on the kernel
612via the proc filesystem in /proc/ipmi/poweroff_control. Note that if the 612command line. The parameter is also available via the proc filesystem
613system does not support power cycling, it will always to the power off. 613in /proc/sys/dev/ipmi/poweroff_powercycle. Note that if the system
614does not support power cycling, it will always do the power off.
614 615
615Note that if you have ACPI enabled, the system will prefer using ACPI to 616Note that if you have ACPI enabled, the system will prefer using ACPI to
616power off. 617power off.
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index 42ea9843b394..e82a96ba396b 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -52,11 +52,11 @@ extern void (*pm_power_off)(void);
52#define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */ 52#define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */
53 53
54/* the IPMI data command */ 54/* the IPMI data command */
55static int poweroff_control = IPMI_CHASSIS_POWER_DOWN; 55static int poweroff_powercycle;
56 56
57/* parameter definition to allow user to flag power cycle */ 57/* parameter definition to allow user to flag power cycle */
58module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN); 58module_param(poweroff_powercycle, int, 0);
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."); 59MODULE_PARM_DESC(poweroff_powercycles, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down.");
60 60
61/* Stuff from the get device id command. */ 61/* Stuff from the get device id command. */
62static unsigned int mfg_id; 62static unsigned int mfg_id;
@@ -385,37 +385,34 @@ static void ipmi_poweroff_chassis (ipmi_user_t user)
385 385
386 powercyclefailed: 386 powercyclefailed:
387 printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n", 387 printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n",
388 ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle")); 388 (poweroff_powercycle ? "cycle" : "down"));
389 389
390 /* 390 /*
391 * Power down 391 * Power down
392 */ 392 */
393 send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST; 393 send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST;
394 send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; 394 send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD;
395 data[0] = poweroff_control; 395 if (poweroff_powercycle)
396 data[0] = IPMI_CHASSIS_POWER_CYCLE;
397 else
398 data[0] = IPMI_CHASSIS_POWER_DOWN;
396 send_msg.data = data; 399 send_msg.data = data;
397 send_msg.data_len = sizeof(data); 400 send_msg.data_len = sizeof(data);
398 rv = ipmi_request_in_rc_mode(user, 401 rv = ipmi_request_in_rc_mode(user,
399 (struct ipmi_addr *) &smi_addr, 402 (struct ipmi_addr *) &smi_addr,
400 &send_msg); 403 &send_msg);
401 if (rv) { 404 if (rv) {
402 switch (poweroff_control) { 405 if (poweroff_powercycle) {
403 case IPMI_CHASSIS_POWER_CYCLE: 406 /* power cycle failed, default to power down */
404 /* power cycle failed, default to power down */ 407 printk(KERN_ERR PFX "Unable to send chassis power " \
405 printk(KERN_ERR PFX "Unable to send chassis power " \ 408 "cycle message, IPMI error 0x%x\n", rv);
406 "cycle message, IPMI error 0x%x\n", rv); 409 poweroff_powercycle = 0;
407 poweroff_control = IPMI_CHASSIS_POWER_DOWN; 410 goto powercyclefailed;
408 goto powercyclefailed;
409
410 case IPMI_CHASSIS_POWER_DOWN:
411 default:
412 printk(KERN_ERR PFX "Unable to send chassis power " \
413 "down message, IPMI error 0x%x\n", rv);
414 break;
415 } 411 }
416 }
417 412
418 return; 413 printk(KERN_ERR PFX "Unable to send chassis power " \
414 "down message, IPMI error 0x%x\n", rv);
415 }
419} 416}
420 417
421 418
@@ -561,39 +558,35 @@ static struct ipmi_smi_watcher smi_watcher =
561 558
562 559
563#ifdef CONFIG_PROC_FS 560#ifdef CONFIG_PROC_FS
564/* displays properties to proc */ 561#include <linux/sysctl.h>
565static int proc_read_chassctrl(char *page, char **start, off_t off, int count, 562
566 int *eof, void *data) 563static ctl_table ipmi_table[] = {
567{ 564 { .ctl_name = DEV_IPMI_POWEROFF_POWERCYCLE,
568 return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n", 565 .procname = "poweroff_powercycle",
569 poweroff_control); 566 .data = &poweroff_powercycle,
570} 567 .maxlen = sizeof(poweroff_powercycle),
568 .mode = 0644,
569 .proc_handler = &proc_dointvec },
570 { }
571};
571 572
572/* process property writes from proc */ 573static ctl_table ipmi_dir_table[] = {
573static int proc_write_chassctrl(struct file *file, const char *buffer, 574 { .ctl_name = DEV_IPMI,
574 unsigned long count, void *data) 575 .procname = "ipmi",
575{ 576 .mode = 0555,
576 int rv = count; 577 .child = ipmi_table },
577 unsigned int newval = 0; 578 { }
578 579};
579 sscanf(buffer, "%d", &newval);
580 switch (newval) {
581 case IPMI_CHASSIS_POWER_CYCLE:
582 printk(KERN_INFO PFX "power cycle is now enabled\n");
583 poweroff_control = newval;
584 break;
585
586 case IPMI_CHASSIS_POWER_DOWN:
587 poweroff_control = IPMI_CHASSIS_POWER_DOWN;
588 break;
589
590 default:
591 rv = -EINVAL;
592 break;
593 }
594 580
595 return rv; 581static ctl_table ipmi_root_table[] = {
596} 582 { .ctl_name = CTL_DEV,
583 .procname = "dev",
584 .mode = 0555,
585 .child = ipmi_dir_table },
586 { }
587};
588
589static struct ctl_table_header *ipmi_table_header;
597#endif /* CONFIG_PROC_FS */ 590#endif /* CONFIG_PROC_FS */
598 591
599/* 592/*
@@ -601,41 +594,32 @@ static int proc_write_chassctrl(struct file *file, const char *buffer,
601 */ 594 */
602static int ipmi_poweroff_init (void) 595static int ipmi_poweroff_init (void)
603{ 596{
604 int rv; 597 int rv;
605 struct proc_dir_entry *file;
606 598
607 printk ("Copyright (C) 2004 MontaVista Software -" 599 printk ("Copyright (C) 2004 MontaVista Software -"
608 " IPMI Powerdown via sys_reboot.\n"); 600 " IPMI Powerdown via sys_reboot.\n");
609 601
610 switch (poweroff_control) { 602 if (poweroff_powercycle)
611 case IPMI_CHASSIS_POWER_CYCLE: 603 printk(KERN_INFO PFX "Power cycle is enabled.\n");
612 printk(KERN_INFO PFX "Power cycle is enabled.\n");
613 break;
614 604
615 case IPMI_CHASSIS_POWER_DOWN: 605#ifdef CONFIG_PROC_FS
616 default: 606 ipmi_table_header = register_sysctl_table(ipmi_root_table, 1);
617 poweroff_control = IPMI_CHASSIS_POWER_DOWN; 607 if (!ipmi_table_header) {
618 break; 608 printk(KERN_ERR PFX "Unable to register powercycle sysctl\n");
609 rv = -ENOMEM;
610 goto out_err;
619 } 611 }
612#endif
620 613
614#ifdef CONFIG_PROC_FS
621 rv = ipmi_smi_watcher_register(&smi_watcher); 615 rv = ipmi_smi_watcher_register(&smi_watcher);
616#endif
622 if (rv) { 617 if (rv) {
618 unregister_sysctl_table(ipmi_table_header);
623 printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); 619 printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
624 goto out_err; 620 goto out_err;
625 } 621 }
626 622
627#ifdef CONFIG_PROC_FS
628 file = create_proc_entry("poweroff_control", 0, proc_ipmi_root);
629 if (!file) {
630 printk(KERN_ERR PFX "Unable to create proc power control\n");
631 } else {
632 file->nlink = 1;
633 file->read_proc = proc_read_chassctrl;
634 file->write_proc = proc_write_chassctrl;
635 file->owner = THIS_MODULE;
636 }
637#endif
638
639 out_err: 623 out_err:
640 return rv; 624 return rv;
641} 625}
@@ -646,7 +630,7 @@ static __exit void ipmi_poweroff_cleanup(void)
646 int rv; 630 int rv;
647 631
648#ifdef CONFIG_PROC_FS 632#ifdef CONFIG_PROC_FS
649 remove_proc_entry("poweroff_control", proc_ipmi_root); 633 unregister_sysctl_table(ipmi_table_header);
650#endif 634#endif
651 635
652 ipmi_smi_watcher_unregister(&smi_watcher); 636 ipmi_smi_watcher_unregister(&smi_watcher);
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index e82be96d4906..532a6c5c24e9 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -711,6 +711,7 @@ enum {
711 DEV_RAID=4, 711 DEV_RAID=4,
712 DEV_MAC_HID=5, 712 DEV_MAC_HID=5,
713 DEV_SCSI=6, 713 DEV_SCSI=6,
714 DEV_IPMI=7,
714}; 715};
715 716
716/* /proc/sys/dev/cdrom */ 717/* /proc/sys/dev/cdrom */
@@ -776,6 +777,11 @@ enum {
776 DEV_SCSI_LOGGING_LEVEL=1, 777 DEV_SCSI_LOGGING_LEVEL=1,
777}; 778};
778 779
780/* /proc/sys/dev/ipmi */
781enum {
782 DEV_IPMI_POWEROFF_POWERCYCLE=1,
783};
784
779/* /proc/sys/abi */ 785/* /proc/sys/abi */
780enum 786enum
781{ 787{