Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 3053
b: refs/heads/master
c: 3b62594
h: refs/heads/master
i:
  3051: 808c0f1
v: v3
  • Loading branch information
Corey Minyard authored and Linus Torvalds committed Jun 24, 2005
1 parent 09b2fdd commit be9b49a
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 12 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8f43f84f13a49fe5f0f7d1595082b6d7ec6daa85
refs/heads/master: 3b6259432dee81f928c22c48c080d5f6325ed92e
20 changes: 20 additions & 0 deletions trunk/Documentation/IPMI.txt
Original file line number Diff line number Diff line change
Expand Up @@ -594,3 +594,23 @@ an event generator, the event receiver from the local management
controller will be queried and the events sent to the SEL on that
device. Otherwise, the events go nowhere since there is nowhere to
send them.


Poweroff
--------

If the poweroff capability is selected, the IPMI driver will install
a shutdown function into the standard poweroff function pointer. This
is in the ipmi_poweroff module. When the system requests a powerdown,
it will send the proper IPMI commands to do this. This is supported on
several platforms.

There is a module parameter named "poweroff_control" that may either be zero
(do a power down) or 2 (do a power cycle, power the system off, then power
it on in a few seconds). Setting ipmi_poweroff.poweroff_control=x will do
the same thing on the kernel command line. The parameter is also available
via the proc filesystem in /proc/ipmi/poweroff_control. Note that if the
system does not support power cycling, it will always to the power off.

Note that if you have ACPI enabled, the system will prefer using ACPI to
power off.
29 changes: 27 additions & 2 deletions trunk/drivers/char/ipmi/ipmi_msghandler.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ static int ipmi_init_msghandler(void);

static int initialized = 0;

static struct proc_dir_entry *proc_ipmi_root = NULL;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_ipmi_root = NULL;
#endif /* CONFIG_PROC_FS */

#define MAX_EVENTS_IN_QUEUE 25

Expand Down Expand Up @@ -124,11 +126,13 @@ struct ipmi_channel
unsigned char protocol;
};

#ifdef CONFIG_PROC_FS
struct ipmi_proc_entry
{
char *name;
struct ipmi_proc_entry *next;
};
#endif

#define IPMI_IPMB_NUM_SEQ 64
#define IPMI_MAX_CHANNELS 8
Expand Down Expand Up @@ -156,10 +160,13 @@ struct ipmi_smi
struct ipmi_smi_handlers *handlers;
void *send_info;

#ifdef CONFIG_PROC_FS
/* A list of proc entries for this interface. This does not
need a lock, only one thread creates it and only one thread
destroys it. */
spinlock_t proc_entry_lock;
struct ipmi_proc_entry *proc_entries;
#endif

/* A table of sequence numbers for this interface. We use the
sequence numbers for IPMB messages that go out of the
Expand Down Expand Up @@ -1470,8 +1477,9 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
read_proc_t *read_proc, write_proc_t *write_proc,
void *data, struct module *owner)
{
struct proc_dir_entry *file;
int rv = 0;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *file;
struct ipmi_proc_entry *entry;

/* Create a list element. */
Expand All @@ -1497,10 +1505,13 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
file->write_proc = write_proc;
file->owner = owner;

spin_lock(&smi->proc_entry_lock);
/* Stick it on the list. */
entry->next = smi->proc_entries;
smi->proc_entries = entry;
spin_unlock(&smi->proc_entry_lock);
}
#endif /* CONFIG_PROC_FS */

return rv;
}
Expand All @@ -1509,6 +1520,7 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
{
int rv = 0;

#ifdef CONFIG_PROC_FS
sprintf(smi->proc_dir_name, "%d", num);
smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
if (!smi->proc_dir)
Expand All @@ -1531,14 +1543,17 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
rv = ipmi_smi_add_proc_entry(smi, "version",
version_file_read_proc, NULL,
smi, THIS_MODULE);
#endif /* CONFIG_PROC_FS */

return rv;
}

static void remove_proc_entries(ipmi_smi_t smi)
{
#ifdef CONFIG_PROC_FS
struct ipmi_proc_entry *entry;

spin_lock(&smi->proc_entry_lock);
while (smi->proc_entries) {
entry = smi->proc_entries;
smi->proc_entries = entry->next;
Expand All @@ -1547,7 +1562,9 @@ static void remove_proc_entries(ipmi_smi_t smi)
kfree(entry->name);
kfree(entry);
}
spin_unlock(&smi->proc_entry_lock);
remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
#endif /* CONFIG_PROC_FS */
}

static int
Expand Down Expand Up @@ -1694,6 +1711,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
new_intf->seq_table[j].seqid = 0;
}
new_intf->curr_seq = 0;
#ifdef CONFIG_PROC_FS
spin_lock_init(&(new_intf->proc_entry_lock));
#endif
spin_lock_init(&(new_intf->waiting_msgs_lock));
INIT_LIST_HEAD(&(new_intf->waiting_msgs));
spin_lock_init(&(new_intf->events_lock));
Expand Down Expand Up @@ -3085,13 +3105,15 @@ static int ipmi_init_msghandler(void)
ipmi_interfaces[i] = NULL;
}

#ifdef CONFIG_PROC_FS
proc_ipmi_root = proc_mkdir("ipmi", NULL);
if (!proc_ipmi_root) {
printk(KERN_ERR PFX "Unable to create IPMI proc dir");
return -ENOMEM;
}

proc_ipmi_root->owner = THIS_MODULE;
#endif /* CONFIG_PROC_FS */

init_timer(&ipmi_timer);
ipmi_timer.data = 0;
Expand Down Expand Up @@ -3129,7 +3151,9 @@ static __exit void cleanup_ipmi(void)
atomic_inc(&stop_operation);
del_timer_sync(&ipmi_timer);

#ifdef CONFIG_PROC_FS
remove_proc_entry(proc_ipmi_root->name, &proc_root);
#endif /* CONFIG_PROC_FS */

initialized = 0;

Expand Down Expand Up @@ -3170,4 +3194,5 @@ EXPORT_SYMBOL(ipmi_get_my_address);
EXPORT_SYMBOL(ipmi_set_my_LUN);
EXPORT_SYMBOL(ipmi_get_my_LUN);
EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
EXPORT_SYMBOL(proc_ipmi_root);
EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
112 changes: 103 additions & 9 deletions trunk/drivers/char/ipmi/ipmi_poweroff.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#include <asm/semaphore.h>
#include <linux/kdev_t.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/ipmi.h>
#include <linux/ipmi_smi.h>
Expand All @@ -44,6 +46,18 @@
/* Where to we insert our poweroff function? */
extern void (*pm_power_off)(void);

/* Definitions for controlling power off (if the system supports it). It
* conveniently matches the IPMI chassis control values. */
#define IPMI_CHASSIS_POWER_DOWN 0 /* power down, the default. */
#define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */

/* the IPMI data command */
static int poweroff_control = IPMI_CHASSIS_POWER_DOWN;

/* parameter definition to allow user to flag power cycle */
module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN);
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.");

/* Stuff from the get device id command. */
static unsigned int mfg_id;
static unsigned int prod_id;
Expand Down Expand Up @@ -349,26 +363,38 @@ static void ipmi_poweroff_chassis (ipmi_user_t user)
smi_addr.channel = IPMI_BMC_CHANNEL;
smi_addr.lun = 0;

printk(KERN_INFO PFX "Powering down via IPMI chassis control command\n");
powercyclefailed:
printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n",
((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle"));

/*
* Power down
*/
send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST;
send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD;
data[0] = 0; /* Power down */
data[0] = poweroff_control;
send_msg.data = data;
send_msg.data_len = sizeof(data);
rv = ipmi_request_in_rc_mode(user,
(struct ipmi_addr *) &smi_addr,
&send_msg);
if (rv) {
printk(KERN_ERR PFX "Unable to send chassis powerdown message,"
" IPMI error 0x%x\n", rv);
goto out;
switch (poweroff_control) {
case IPMI_CHASSIS_POWER_CYCLE:
/* power cycle failed, default to power down */
printk(KERN_ERR PFX "Unable to send chassis power " \
"cycle message, IPMI error 0x%x\n", rv);
poweroff_control = IPMI_CHASSIS_POWER_DOWN;
goto powercyclefailed;

case IPMI_CHASSIS_POWER_DOWN:
default:
printk(KERN_ERR PFX "Unable to send chassis power " \
"down message, IPMI error 0x%x\n", rv);
break;
}
}

out:
return;
}

Expand Down Expand Up @@ -430,7 +456,8 @@ static void ipmi_po_new_smi(int if_num)
if (ready)
return;

rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, &ipmi_user);
rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL,
&ipmi_user);
if (rv) {
printk(KERN_ERR PFX "could not create IPMI user, error %d\n",
rv);
Expand Down Expand Up @@ -509,21 +536,84 @@ static struct ipmi_smi_watcher smi_watcher =
};


#ifdef CONFIG_PROC_FS
/* displays properties to proc */
static int proc_read_chassctrl(char *page, char **start, off_t off, int count,
int *eof, void *data)
{
return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n",
poweroff_control);
}

/* process property writes from proc */
static int proc_write_chassctrl(struct file *file, const char *buffer,
unsigned long count, void *data)
{
int rv = count;
unsigned int newval = 0;

sscanf(buffer, "%d", &newval);
switch (newval) {
case IPMI_CHASSIS_POWER_CYCLE:
printk(KERN_INFO PFX "power cycle is now enabled\n");
poweroff_control = newval;
break;

case IPMI_CHASSIS_POWER_DOWN:
poweroff_control = IPMI_CHASSIS_POWER_DOWN;
break;

default:
rv = -EINVAL;
break;
}

return rv;
}
#endif /* CONFIG_PROC_FS */

/*
* Startup and shutdown functions.
*/
static int ipmi_poweroff_init (void)
{
int rv;
int rv;
struct proc_dir_entry *file;

printk ("Copyright (C) 2004 MontaVista Software -"
" IPMI Powerdown via sys_reboot version "
IPMI_POWEROFF_VERSION ".\n");

switch (poweroff_control) {
case IPMI_CHASSIS_POWER_CYCLE:
printk(KERN_INFO PFX "Power cycle is enabled.\n");
break;

case IPMI_CHASSIS_POWER_DOWN:
default:
poweroff_control = IPMI_CHASSIS_POWER_DOWN;
break;
}

rv = ipmi_smi_watcher_register(&smi_watcher);
if (rv)
if (rv) {
printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
goto out_err;
}

#ifdef CONFIG_PROC_FS
file = create_proc_entry("poweroff_control", 0, proc_ipmi_root);
if (!file) {
printk(KERN_ERR PFX "Unable to create proc power control\n");
} else {
file->nlink = 1;
file->read_proc = proc_read_chassctrl;
file->write_proc = proc_write_chassctrl;
file->owner = THIS_MODULE;
}
#endif

out_err:
return rv;
}

Expand All @@ -532,6 +622,10 @@ static __exit void ipmi_poweroff_cleanup(void)
{
int rv;

#ifdef CONFIG_PROC_FS
remove_proc_entry("poweroff_control", proc_ipmi_root);
#endif

ipmi_smi_watcher_unregister(&smi_watcher);

if (ready) {
Expand Down
5 changes: 5 additions & 0 deletions trunk/include/linux/ipmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ struct kernel_ipmi_msg
#include <linux/list.h>
#include <linux/module.h>

#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
extern struct proc_dir_entry *proc_ipmi_root;
#endif /* CONFIG_PROC_FS */

/* Opaque type for a IPMI message user. One of these is needed to
send and receive messages. */
typedef struct ipmi_user *ipmi_user_t;
Expand Down

0 comments on commit be9b49a

Please sign in to comment.