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?

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

Reply via email to