This is fine.  Can you write a program to reconstruct the log from the SEL?

-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

Reply via email to