aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--Documentation/IPMI.txt20
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c29
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c112
-rw-r--r--include/linux/ipmi.h5
4 files changed, 155 insertions, 11 deletions
diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt
index 2f99fe6299ab..84d3d4d10c17 100644
--- a/Documentation/IPMI.txt
+++ b/Documentation/IPMI.txt
@@ -594,3 +594,23 @@ an event generator, the event receiver from the local management
594controller will be queried and the events sent to the SEL on that 594controller will be queried and the events sent to the SEL on that
595device. Otherwise, the events go nowhere since there is nowhere to 595device. Otherwise, the events go nowhere since there is nowhere to
596send them. 596send them.
597
598
599Poweroff
600--------
601
602If the poweroff capability is selected, the IPMI driver will install
603a shutdown function into the standard poweroff function pointer. This
604is 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
606several platforms.
607
608There is a module parameter named "poweroff_control" that may either be zero
609(do a power down) or 2 (do a power cycle, power the system off, then power
610it on in a few seconds). Setting ipmi_poweroff.poweroff_control=x will do
611the same thing on the kernel command line. The parameter is also available
612via the proc filesystem in /proc/ipmi/poweroff_control. Note that if the
613system does not support power cycling, it will always to the power off.
614
615Note that if you have ACPI enabled, the system will prefer using ACPI to
616power off.
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index ed75e96d0035..1813d0d198f1 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -54,7 +54,9 @@ static int ipmi_init_msghandler(void);
54 54
55static int initialized = 0; 55static int initialized = 0;
56 56
57static struct proc_dir_entry *proc_ipmi_root = NULL; 57#ifdef CONFIG_PROC_FS
58struct proc_dir_entry *proc_ipmi_root = NULL;
59#endif /* CONFIG_PROC_FS */
58 60
59#define MAX_EVENTS_IN_QUEUE 25 61#define MAX_EVENTS_IN_QUEUE 25
60 62
@@ -124,11 +126,13 @@ struct ipmi_channel
124 unsigned char protocol; 126 unsigned char protocol;
125}; 127};
126 128
129#ifdef CONFIG_PROC_FS
127struct ipmi_proc_entry 130struct ipmi_proc_entry
128{ 131{
129 char *name; 132 char *name;
130 struct ipmi_proc_entry *next; 133 struct ipmi_proc_entry *next;
131}; 134};
135#endif
132 136
133#define IPMI_IPMB_NUM_SEQ 64 137#define IPMI_IPMB_NUM_SEQ 64
134#define IPMI_MAX_CHANNELS 8 138#define IPMI_MAX_CHANNELS 8
@@ -156,10 +160,13 @@ struct ipmi_smi
156 struct ipmi_smi_handlers *handlers; 160 struct ipmi_smi_handlers *handlers;
157 void *send_info; 161 void *send_info;
158 162
163#ifdef CONFIG_PROC_FS
159 /* A list of proc entries for this interface. This does not 164 /* A list of proc entries for this interface. This does not
160 need a lock, only one thread creates it and only one thread 165 need a lock, only one thread creates it and only one thread
161 destroys it. */ 166 destroys it. */
167 spinlock_t proc_entry_lock;
162 struct ipmi_proc_entry *proc_entries; 168 struct ipmi_proc_entry *proc_entries;
169#endif
163 170
164 /* A table of sequence numbers for this interface. We use the 171 /* A table of sequence numbers for this interface. We use the
165 sequence numbers for IPMB messages that go out of the 172 sequence numbers for IPMB messages that go out of the
@@ -1470,8 +1477,9 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1470 read_proc_t *read_proc, write_proc_t *write_proc, 1477 read_proc_t *read_proc, write_proc_t *write_proc,
1471 void *data, struct module *owner) 1478 void *data, struct module *owner)
1472{ 1479{
1473 struct proc_dir_entry *file;
1474 int rv = 0; 1480 int rv = 0;
1481#ifdef CONFIG_PROC_FS
1482 struct proc_dir_entry *file;
1475 struct ipmi_proc_entry *entry; 1483 struct ipmi_proc_entry *entry;
1476 1484
1477 /* Create a list element. */ 1485 /* Create a list element. */
@@ -1497,10 +1505,13 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1497 file->write_proc = write_proc; 1505 file->write_proc = write_proc;
1498 file->owner = owner; 1506 file->owner = owner;
1499 1507
1508 spin_lock(&smi->proc_entry_lock);
1500 /* Stick it on the list. */ 1509 /* Stick it on the list. */
1501 entry->next = smi->proc_entries; 1510 entry->next = smi->proc_entries;
1502 smi->proc_entries = entry; 1511 smi->proc_entries = entry;
1512 spin_unlock(&smi->proc_entry_lock);
1503 } 1513 }
1514#endif /* CONFIG_PROC_FS */
1504 1515
1505 return rv; 1516 return rv;
1506} 1517}
@@ -1509,6 +1520,7 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
1509{ 1520{
1510 int rv = 0; 1521 int rv = 0;
1511 1522
1523#ifdef CONFIG_PROC_FS
1512 sprintf(smi->proc_dir_name, "%d", num); 1524 sprintf(smi->proc_dir_name, "%d", num);
1513 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root); 1525 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1514 if (!smi->proc_dir) 1526 if (!smi->proc_dir)
@@ -1531,14 +1543,17 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
1531 rv = ipmi_smi_add_proc_entry(smi, "version", 1543 rv = ipmi_smi_add_proc_entry(smi, "version",
1532 version_file_read_proc, NULL, 1544 version_file_read_proc, NULL,
1533 smi, THIS_MODULE); 1545 smi, THIS_MODULE);
1546#endif /* CONFIG_PROC_FS */
1534 1547
1535 return rv; 1548 return rv;
1536} 1549}
1537 1550
1538static void remove_proc_entries(ipmi_smi_t smi) 1551static void remove_proc_entries(ipmi_smi_t smi)
1539{ 1552{
1553#ifdef CONFIG_PROC_FS
1540 struct ipmi_proc_entry *entry; 1554 struct ipmi_proc_entry *entry;
1541 1555
1556 spin_lock(&smi->proc_entry_lock);
1542 while (smi->proc_entries) { 1557 while (smi->proc_entries) {
1543 entry = smi->proc_entries; 1558 entry = smi->proc_entries;
1544 smi->proc_entries = entry->next; 1559 smi->proc_entries = entry->next;
@@ -1547,7 +1562,9 @@ static void remove_proc_entries(ipmi_smi_t smi)
1547 kfree(entry->name); 1562 kfree(entry->name);
1548 kfree(entry); 1563 kfree(entry);
1549 } 1564 }
1565 spin_unlock(&smi->proc_entry_lock);
1550 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root); 1566 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
1567#endif /* CONFIG_PROC_FS */
1551} 1568}
1552 1569
1553static int 1570static int
@@ -1694,6 +1711,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
1694 new_intf->seq_table[j].seqid = 0; 1711 new_intf->seq_table[j].seqid = 0;
1695 } 1712 }
1696 new_intf->curr_seq = 0; 1713 new_intf->curr_seq = 0;
1714#ifdef CONFIG_PROC_FS
1715 spin_lock_init(&(new_intf->proc_entry_lock));
1716#endif
1697 spin_lock_init(&(new_intf->waiting_msgs_lock)); 1717 spin_lock_init(&(new_intf->waiting_msgs_lock));
1698 INIT_LIST_HEAD(&(new_intf->waiting_msgs)); 1718 INIT_LIST_HEAD(&(new_intf->waiting_msgs));
1699 spin_lock_init(&(new_intf->events_lock)); 1719 spin_lock_init(&(new_intf->events_lock));
@@ -3085,6 +3105,7 @@ static int ipmi_init_msghandler(void)
3085 ipmi_interfaces[i] = NULL; 3105 ipmi_interfaces[i] = NULL;
3086 } 3106 }
3087 3107
3108#ifdef CONFIG_PROC_FS
3088 proc_ipmi_root = proc_mkdir("ipmi", NULL); 3109 proc_ipmi_root = proc_mkdir("ipmi", NULL);
3089 if (!proc_ipmi_root) { 3110 if (!proc_ipmi_root) {
3090 printk(KERN_ERR PFX "Unable to create IPMI proc dir"); 3111 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
@@ -3092,6 +3113,7 @@ static int ipmi_init_msghandler(void)
3092 } 3113 }
3093 3114
3094 proc_ipmi_root->owner = THIS_MODULE; 3115 proc_ipmi_root->owner = THIS_MODULE;
3116#endif /* CONFIG_PROC_FS */
3095 3117
3096 init_timer(&ipmi_timer); 3118 init_timer(&ipmi_timer);
3097 ipmi_timer.data = 0; 3119 ipmi_timer.data = 0;
@@ -3129,7 +3151,9 @@ static __exit void cleanup_ipmi(void)
3129 atomic_inc(&stop_operation); 3151 atomic_inc(&stop_operation);
3130 del_timer_sync(&ipmi_timer); 3152 del_timer_sync(&ipmi_timer);
3131 3153
3154#ifdef CONFIG_PROC_FS
3132 remove_proc_entry(proc_ipmi_root->name, &proc_root); 3155 remove_proc_entry(proc_ipmi_root->name, &proc_root);
3156#endif /* CONFIG_PROC_FS */
3133 3157
3134 initialized = 0; 3158 initialized = 0;
3135 3159
@@ -3170,4 +3194,5 @@ EXPORT_SYMBOL(ipmi_get_my_address);
3170EXPORT_SYMBOL(ipmi_set_my_LUN); 3194EXPORT_SYMBOL(ipmi_set_my_LUN);
3171EXPORT_SYMBOL(ipmi_get_my_LUN); 3195EXPORT_SYMBOL(ipmi_get_my_LUN);
3172EXPORT_SYMBOL(ipmi_smi_add_proc_entry); 3196EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
3197EXPORT_SYMBOL(proc_ipmi_root);
3173EXPORT_SYMBOL(ipmi_user_set_run_to_completion); 3198EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
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) {
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
index 2ec265e1045f..596ca6130159 100644
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -209,6 +209,11 @@ struct kernel_ipmi_msg
209#include <linux/list.h> 209#include <linux/list.h>
210#include <linux/module.h> 210#include <linux/module.h>
211 211
212#ifdef CONFIG_PROC_FS
213#include <linux/proc_fs.h>
214extern struct proc_dir_entry *proc_ipmi_root;
215#endif /* CONFIG_PROC_FS */
216
212/* Opaque type for a IPMI message user. One of these is needed to 217/* Opaque type for a IPMI message user. One of these is needed to
213 send and receive messages. */ 218 send and receive messages. */
214typedef struct ipmi_user *ipmi_user_t; 219typedef struct ipmi_user *ipmi_user_t;