Hiroshi Shimamoto wrote: > Corey Minyard wrote: > >> This is fine. Can you write a program to reconstruct the log from the SEL? >> > > Sure, will do. BTW, I'm not sure, which package will contain this program? > In the kernel doc? ipmiutil? > It would probably be best to tie into OpenIPMI or ipmitool, as that way you can support LAN connections, and connections through BMCs to other MCs, too.
-corey > Thanks, > Hiroshi > > >> -corey >> >> Hiroshi Shimamoto wrote: >> >>> From: Hiroshi Shimamoto <[email protected]> >>> >>> Console messages on oops or panic are very important to investigate problem. >>> Logging oops or panic messages to SEL is useful because SEL is a non >>> volatile memory. >>> >>> Implement a console driver to log messages to SEL when oops_in_progress is >>> not zero. The first message just after oops, panic or every 10 seconds from >>> last timestamp are logged as OEM event with timestamp, others are logged as >>> OEM event without timestamp. >>> >>> Enable config IPMI_OOPS_CONSOLE and add console=ttyIPMI to kernel command >>> line to log panic or oops messages to IPMI SEL. >>> >>> The number of entries for this output is limited by msg_limit paramter, >>> and the default value is 100. >>> >>> Signed-off-by: Hiroshi Shimamoto <[email protected]> >>> --- >>> v2 -> v3: Use timestamp in first recode and every 10 seconds. >>> v1 -> v2: Add msg_limit to limit output size. >>> >>> drivers/char/ipmi/Kconfig | 7 + >>> drivers/char/ipmi/Makefile | 1 + >>> drivers/char/ipmi/ipmi_oops_console.c | 256 >>> +++++++++++++++++++++++++++++++++ >>> 3 files changed, 264 insertions(+), 0 deletions(-) >>> create mode 100644 drivers/char/ipmi/ipmi_oops_console.c >>> >>> diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig >>> index 0baa8fa..4bca2b3 100644 >>> --- a/drivers/char/ipmi/Kconfig >>> +++ b/drivers/char/ipmi/Kconfig >>> @@ -61,4 +61,11 @@ config IPMI_POWEROFF >>> This enables a function to power off the system with IPMI if >>> the IPMI management controller is capable of this. >>> >>> +config IPMI_OOPS_CONSOLE >>> + tristate 'IPMI oops console' >>> + help >>> + This enables the IPMI oops console. IPMI oops console logs oops or >>> + panic console messsages to SEL. The number of entries for this usage >>> + is limited by msg_limit, default is 100 entries. >>> + >>> endif # IPMI_HANDLER >>> diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile >>> index eb8a1a8..cbbac18 100644 >>> --- a/drivers/char/ipmi/Makefile >>> +++ b/drivers/char/ipmi/Makefile >>> @@ -9,3 +9,4 @@ obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o >>> obj-$(CONFIG_IPMI_SI) += ipmi_si.o >>> obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o >>> obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o >>> +obj-$(CONFIG_IPMI_OOPS_CONSOLE) += ipmi_oops_console.o >>> diff --git a/drivers/char/ipmi/ipmi_oops_console.c >>> b/drivers/char/ipmi/ipmi_oops_console.c >>> new file mode 100644 >>> index 0000000..437955f >>> --- /dev/null >>> +++ b/drivers/char/ipmi/ipmi_oops_console.c >>> @@ -0,0 +1,256 @@ >>> +/* >>> + * ipmi_oops_console.c >>> + * >>> + * IPMI Oops Console >>> + * Logging console message to SEL on oops >>> + * >>> + * Author: Hiroshi Shimamoto <[email protected]> >>> + * >>> + * Copyright (C) 2008 NEC Corporation >>> + * >>> + * This program is free software; you can redistribute it and/or modify it >>> + * under the terms of the GNU General Public License as published by the >>> + * Free Software Foundation; either version 2 of the License, or (at your >>> + * option) any later version. >>> + * >>> + * >>> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED >>> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF >>> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. >>> + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, >>> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, >>> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS >>> + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND >>> + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR >>> + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE >>> + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH >>> DAMAGE. >>> + * >>> + * You should have received a copy of the GNU General Public License along >>> + * with this program; if not, write to the Free Software Foundation, Inc., >>> + * 675 Mass Ave, Cambridge, MA 02139, USA. >>> + */ >>> + >>> +#include <linux/module.h> >>> +#include <linux/moduleparam.h> >>> +#include <linux/ipmi.h> >>> +#include <linux/ipmi_smi.h> >>> +#include <linux/console.h> >>> +#include <linux/jiffies.h> >>> +#include <asm/atomic.h> >>> + >>> +#define PFX "IPMI oops_console: " >>> + >>> +static ipmi_user_t oops_user; >>> +static int oops_intf = -1; >>> + >>> +static atomic_t oops_counter; >>> + >>> +#define SEL_MSGSIZE_TIMESTAMP (6U) >>> +#define SEL_MSGSIZE (13U) >>> +#define DEF_LIMIT (100) >>> +#define TIMESTAMP_INTERVAL (10 * HZ) >>> + >>> +static char oops_msg[SEL_MSGSIZE_TIMESTAMP + SEL_MSGSIZE]; >>> +static char *msg_ptr = oops_msg; >>> +static unsigned int msg_len; >>> +static unsigned long msg_jiffies; >>> +static int msg_count, msg_limit = DEF_LIMIT; >>> + >>> +module_param(msg_limit, int, 0644); >>> +MODULE_PARM_DESC(msg_limit, "Message limit. Default: 100 entries."); >>> + >>> +static void oops_smi_msg_done(struct ipmi_smi_msg *msg) >>> +{ >>> + atomic_dec(&oops_counter); >>> +} >>> +static struct ipmi_smi_msg oops_smi_msg = { >>> + .done = oops_smi_msg_done >>> +}; >>> + >>> +static void oops_recv_msg_done(struct ipmi_recv_msg *msg) >>> +{ >>> + atomic_dec(&oops_counter); >>> +} >>> +static struct ipmi_recv_msg oops_recv_msg = { >>> + .done = oops_recv_msg_done >>> +}; >>> + >>> +static void ipmi_oops_console_log_to_sel(int timestamp) >>> +{ >>> + struct ipmi_system_interface_addr si; >>> + struct kernel_ipmi_msg msg; >>> + unsigned int len; >>> + unsigned char data[16]; >>> + unsigned char my_addr; >>> + >>> + if (!oops_user || !msg_len || msg_count >= msg_limit) >>> + return; >>> + >>> + len = min((timestamp ? SEL_MSGSIZE_TIMESTAMP : SEL_MSGSIZE), msg_len); >>> + >>> + si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; >>> + si.channel = IPMI_BMC_CHANNEL; >>> + si.lun = 0; >>> + >>> + msg.netfn = IPMI_NETFN_STORAGE_REQUEST; >>> + msg.cmd = IPMI_ADD_SEL_ENTRY_CMD; >>> + msg.data = data; >>> + msg.data_len = 16; >>> + >>> + memset(data, 0, sizeof(data)); >>> + if (timestamp) { >>> + len = min(SEL_MSGSIZE_TIMESTAMP, msg_len); >>> + data[2] = 0xd1; /* OEM event with timestamp */ >>> + memcpy(data + 10, msg_ptr, len); >>> + msg_jiffies = jiffies; /* save jiffies at timestamp */ >>> + } else { >>> + len = min(SEL_MSGSIZE, msg_len); >>> + data[2] = 0xf1; /* OEM event without timestamp */ >>> + memcpy(data + 3, msg_ptr, len); >>> + } >>> + >>> + preempt_disable(); >>> + >>> + if (ipmi_get_my_address(oops_user, 0, &my_addr)) >>> + goto out; >>> + >>> + atomic_set(&oops_counter, 2); >>> + if (ipmi_request_supply_msgs(oops_user, (struct ipmi_addr *)&si, >>> + 0, &msg, NULL, &oops_smi_msg, >>> + &oops_recv_msg, 1) < 0) >>> + goto out; >>> + while (atomic_read(&oops_counter) > 0) { >>> + ipmi_poll_interface(oops_user); >>> + cpu_relax(); >>> + } >>> + >>> + ++msg_count; >>> + msg_len -= len; >>> + msg_ptr = msg_len ? &oops_msg[len] : oops_msg; >>> +out: >>> + preempt_enable(); >>> +} >>> + >>> +static void ipmi_oops_console_sync(void) >>> +{ >>> + if (!oops_user || !msg_len || msg_count >= msg_limit) >>> + return; >>> + >>> + if (jiffies > (msg_jiffies + TIMESTAMP_INTERVAL)) { >>> + if (msg_ptr != oops_msg) >>> + ipmi_oops_console_log_to_sel(0); >>> + if (msg_len >= SEL_MSGSIZE_TIMESTAMP) >>> + ipmi_oops_console_log_to_sel(1); >>> + return; >>> + } >>> + if (msg_len >= SEL_MSGSIZE) >>> + ipmi_oops_console_log_to_sel(0); >>> +} >>> + >>> +static void >>> +ipmi_oops_console_write(struct console *con, const char *s, unsigned int >>> count) >>> +{ >>> + unsigned int size; >>> + >>> + if (likely(!oops_in_progress)) { >>> + ipmi_oops_console_log_to_sel(0); >>> + return; >>> + } >>> + >>> + if (unlikely(!oops_user)) >>> + return; >>> + >>> + while (msg_count < msg_limit && count > 0) { >>> + size = min(SEL_MSGSIZE - msg_len, count); >>> + memcpy(msg_ptr + msg_len, s, size); >>> + msg_len += size; >>> + s += size; >>> + count -= size; >>> + ipmi_oops_console_sync(); >>> + } >>> +} >>> + >>> +static struct console oops_console = { >>> + .name = "ttyIPMI", >>> + .write = ipmi_oops_console_write, >>> + .unblank = ipmi_oops_console_sync, >>> + .index = -1, >>> +}; >>> + >>> +static void ipmi_oops_recv(struct ipmi_recv_msg *msg, void *data) >>> +{ >>> + ipmi_free_recv_msg(msg); >>> +} >>> + >>> +static struct ipmi_user_hndl ipmi_handler = { >>> + .ipmi_recv_hndl = ipmi_oops_recv, >>> +}; >>> + >>> +static void ipmi_register_oops_console(int intf) >>> +{ >>> + int ret; >>> + >>> + ret = ipmi_create_user(intf, &ipmi_handler, NULL, &oops_user); >>> + if (ret < 0) { >>> + printk(KERN_ERR PFX "unable to create user\n"); >>> + return; >>> + } >>> + >>> + oops_intf = intf; >>> + >>> + register_console(&oops_console); >>> + >>> + printk(KERN_INFO PFX "ready\n"); >>> +} >>> + >>> +static void ipmi_unregister_oops_console(int intf) >>> +{ >>> + unregister_console(&oops_console); >>> + >>> + ipmi_destroy_user(oops_user); >>> + oops_user = NULL; >>> + oops_intf = -1; >>> +} >>> + >>> +static void ipmi_new_smi(int if_num, struct device *dev) >>> +{ >>> + ipmi_register_oops_console(if_num); >>> +} >>> + >>> +static void ipmi_smi_gone(int if_num) >>> +{ >>> + ipmi_unregister_oops_console(if_num); >>> +} >>> + >>> +static struct ipmi_smi_watcher smi_watcher = { >>> + .owner = THIS_MODULE, >>> + .new_smi = ipmi_new_smi, >>> + .smi_gone = ipmi_smi_gone, >>> +}; >>> + >>> +static int __init ipmi_oops_console_init(void) >>> +{ >>> + int ret; >>> + >>> + ret = ipmi_smi_watcher_register(&smi_watcher); >>> + if (ret) { >>> + printk(KERN_ERR PFX "unable to register smi watcher\n"); >>> + return ret; >>> + } >>> + >>> + printk(KERN_INFO PFX "driver initialized\n"); >>> + >>> + return ret; >>> +} >>> +module_init(ipmi_oops_console_init); >>> + >>> +static void __exit ipmi_oops_console_exit(void) >>> +{ >>> + if (oops_intf >= 0) >>> + ipmi_unregister_oops_console(oops_intf); >>> +} >>> +module_exit(ipmi_oops_console_exit); >>> + >>> +MODULE_LICENSE("GPL"); >>> +MODULE_AUTHOR("Hiroshi Shimamoto <[email protected]>"); >>> +MODULE_DESCRIPTION("oops console handler based upon the IPMI interface."); >>> >>> >> > > > ------------------------------------------------------------------------------ > _______________________________________________ > Openipmi-developer mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/openipmi-developer > > ------------------------------------------------------------------------------ _______________________________________________ Openipmi-developer mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openipmi-developer
