ipmi: Make IPMI panic strings always available

They were set by config items, but people complained that they were
never turned on.  So have them always available and enabled by a
module parameter.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
This commit is contained in:
Corey Minyard 2017-08-18 17:32:03 -05:00
parent b72fce52a1
commit 1c9f98d1bf
3 changed files with 98 additions and 24 deletions

View File

@ -81,7 +81,9 @@ If you want the driver to put an event into the event log on a panic,
enable the 'Generate a panic event to all BMCs on a panic' option. If
you want the whole panic string put into the event log using OEM
events, enable the 'Generate OEM events containing the panic string'
option.
option. You can also enable these dynamically by setting the module
parameter named "panic_op" in the ipmi_msghandler module to "event"
or "string". Setting that parameter to "none" disables this function.
Basic Design
------------

View File

@ -25,21 +25,28 @@ if IPMI_HANDLER
config IPMI_PANIC_EVENT
bool 'Generate a panic event to all BMCs on a panic'
help
When a panic occurs, this will cause the IPMI message handler to
generate an IPMI event describing the panic to each interface
registered with the message handler.
When a panic occurs, this will cause the IPMI message handler to,
by default, generate an IPMI event describing the panic to each
interface registered with the message handler. This is always
available, the module parameter for ipmi_msghandler named
panic_op can be set to "event" to chose this value, this config
simply causes the default value to be set to "event".
config IPMI_PANIC_STRING
bool 'Generate OEM events containing the panic string'
depends on IPMI_PANIC_EVENT
help
When a panic occurs, this will cause the IPMI message handler to
generate IPMI OEM type f0 events holding the IPMB address of the
panic generator (byte 4 of the event), a sequence number for the
string (byte 5 of the event) and part of the string (the rest of the
event). Bytes 1, 2, and 3 are the normal usage for an OEM event.
You can fetch these events and use the sequence numbers to piece the
string together.
When a panic occurs, this will cause the IPMI message handler to,
by default, generate IPMI OEM type f0 events holding the IPMB
address of the panic generator (byte 4 of the event), a sequence
number for the string (byte 5 of the event) and part of the
string (the rest of the event). Bytes 1, 2, and 3 are the normal
usage for an OEM event. You can fetch these events and use the
sequence numbers to piece the string together. This config
parameter sets the default value to generate these events,
the module parameter for ipmi_msghandler named panic_op can
be set to "string" to chose this value, this config simply
causes the default value to be set to "string".
config IPMI_DEVICE_INTERFACE
tristate 'Device interface for IPMI'

View File

@ -46,6 +46,7 @@
#include <linux/proc_fs.h>
#include <linux/rcupdate.h>
#include <linux/interrupt.h>
#include <linux/moduleparam.h>
#define PFX "IPMI message handler: "
@ -61,6 +62,74 @@ static int handle_one_recv_msg(ipmi_smi_t intf,
static int initialized;
enum ipmi_panic_event_op {
IPMI_SEND_PANIC_EVENT_NONE,
IPMI_SEND_PANIC_EVENT,
IPMI_SEND_PANIC_EVENT_STRING
};
#ifdef CONFIG_IPMI_PANIC_STRING
#define IPMI_PANIC_DEFAULT IPMI_SEND_PANIC_EVENT_STRING
#elif defined(CONFIG_IPMI_PANIC_EVENT)
#define IPMI_PANIC_DEFAULT IPMI_SEND_PANIC_EVENT
#else
#define IPMI_PANIC_DEFAULT IPMI_SEND_PANIC_EVENT_NONE
#endif
static enum ipmi_panic_event_op ipmi_send_panic_event = IPMI_PANIC_DEFAULT;
static int panic_op_write_handler(const char *val,
const struct kernel_param *kp)
{
char valcp[16];
char *s;
strncpy(valcp, val, 16);
valcp[15] = '\0';
s = strstrip(valcp);
if (strcmp(s, "none") == 0)
ipmi_send_panic_event = IPMI_SEND_PANIC_EVENT_NONE;
else if (strcmp(s, "event") == 0)
ipmi_send_panic_event = IPMI_SEND_PANIC_EVENT;
else if (strcmp(s, "string") == 0)
ipmi_send_panic_event = IPMI_SEND_PANIC_EVENT_STRING;
else
return -EINVAL;
return 0;
}
static int panic_op_read_handler(char *buffer, const struct kernel_param *kp)
{
switch (ipmi_send_panic_event) {
case IPMI_SEND_PANIC_EVENT_NONE:
strcpy(buffer, "none");
break;
case IPMI_SEND_PANIC_EVENT:
strcpy(buffer, "event");
break;
case IPMI_SEND_PANIC_EVENT_STRING:
strcpy(buffer, "string");
break;
default:
strcpy(buffer, "???");
break;
}
return strlen(buffer);
}
static const struct kernel_param_ops panic_op_ops = {
.set = panic_op_write_handler,
.get = panic_op_read_handler
};
module_param_cb(panic_op, &panic_op_ops, NULL, 0600);
MODULE_PARM_DESC(panic_op, "Sets if the IPMI driver will attempt to store panic information in the event log in the event of a panic. Set to 'none' for no, 'event' for a single event, or 'string' for a generic event and the panic string in IPMI OEM events.");
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_ipmi_root;
#endif /* CONFIG_PROC_FS */
@ -4271,8 +4340,6 @@ void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
}
EXPORT_SYMBOL(ipmi_free_recv_msg);
#ifdef CONFIG_IPMI_PANIC_EVENT
static atomic_t panic_done_count = ATOMIC_INIT(0);
static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
@ -4320,7 +4387,6 @@ static void ipmi_panic_request_and_wait(ipmi_smi_t intf,
ipmi_poll(intf);
}
#ifdef CONFIG_IPMI_PANIC_STRING
static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
{
if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
@ -4347,7 +4413,6 @@ static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
}
}
#endif
static void send_panic_events(char *str)
{
@ -4357,6 +4422,9 @@ static void send_panic_events(char *str)
struct ipmi_system_interface_addr *si;
struct ipmi_addr addr;
if (ipmi_send_panic_event == IPMI_SEND_PANIC_EVENT_NONE)
return;
si = (struct ipmi_system_interface_addr *) &addr;
si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
si->channel = IPMI_BMC_CHANNEL;
@ -4385,20 +4453,19 @@ static void send_panic_events(char *str)
/* For every registered interface, send the event. */
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
if (!intf->handlers)
/* Interface is not ready. */
if (!intf->handlers || !intf->handlers->poll)
/* Interface is not ready or can't run at panic time. */
continue;
/* Send the event announcing the panic. */
ipmi_panic_request_and_wait(intf, &addr, &msg);
}
#ifdef CONFIG_IPMI_PANIC_STRING
/*
* On every interface, dump a bunch of OEM event holding the
* string.
*/
if (!str)
if (ipmi_send_panic_event != IPMI_SEND_PANIC_EVENT_STRING || !str)
return;
/* For every registered interface, send the event. */
@ -4507,9 +4574,7 @@ static void send_panic_events(char *str)
ipmi_panic_request_and_wait(intf, &addr, &msg);
}
}
#endif /* CONFIG_IPMI_PANIC_STRING */
}
#endif /* CONFIG_IPMI_PANIC_EVENT */
static int has_panicked;
@ -4547,12 +4612,12 @@ static int panic_event(struct notifier_block *this,
spin_unlock(&intf->waiting_rcv_msgs_lock);
intf->run_to_completion = 1;
intf->handlers->set_run_to_completion(intf->send_info, 1);
if (intf->handlers->set_run_to_completion)
intf->handlers->set_run_to_completion(intf->send_info,
1);
}
#ifdef CONFIG_IPMI_PANIC_EVENT
send_panic_events(ptr);
#endif
return NOTIFY_DONE;
}