diff -Naru linux-2.5.62/arch/i386/kernel/reboot.c linux-2.5.62p/arch/i386/kernel/reboot.c --- linux-2.5.62/arch/i386/kernel/reboot.c 2003-03-07 16:33:50.000000000 +0800 +++ linux-2.5.62p/arch/i386/kernel/reboot.c 2003-03-06 22:27:16.000000000 +0800 @@ -221,6 +221,10 @@ : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); } +#ifdef CONFIG_IPMI_PANIC_ACTION +extern void ipmi_reset(int mode); +#endif + void machine_restart(char * __unused) { #if CONFIG_SMP @@ -277,6 +281,9 @@ } } +#ifdef CONFIG_IPMI_PANIC_ACTION + ipmi_reset(1); +#endif machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); } @@ -288,5 +295,8 @@ { if (pm_power_off) pm_power_off(); +#ifdef CONFIG_IPMI_PANIC_ACTION + ipmi_reset(0); +#endif } diff -Naru linux-2.5.62/drivers/char/ipmi/ipmi_msghandler.c linux-2.5.62p/drivers/char/ipmi/ipmi_msghandler.c --- linux-2.5.62/drivers/char/ipmi/ipmi_msghandler.c 2003-03-07 16:34:18.000000000 +0800 +++ linux-2.5.62p/drivers/char/ipmi/ipmi_msghandler.c 2003-03-06 22:27:16.000000000 +0800 @@ -45,6 +45,14 @@ #include #include +#ifdef CONFIG_IPMI_PANIC_ACTION +#define uchar unsigned char +extern int ipmi_panic_init(void); +extern int ipmi_send_recv(uchar cmd, uchar netfn, uchar lun, + uchar *sbuf, int slen, uchar *rbuf, int rlen, + int *nret, uchar *cc); +#endif + struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); static int ipmi_init_msghandler(void); @@ -345,7 +353,7 @@ unsigned int i; for (i=intf->curr_seq; - i!=(intf->curr_seq-1); + (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq; i=(i+1)%IPMI_IPMB_NUM_SEQ) { if (! intf->seq_table[i].inuse) @@ -437,6 +445,7 @@ return rv; } +static int fIPMIok = 0; /* true if an IPMI interface is valid */ int ipmi_create_user(unsigned int if_num, struct ipmi_user_hndl *handler, @@ -480,6 +489,7 @@ goto out_unlock; } + fIPMIok = 1; /* at least one IPMI interface is valid */ new_user->handler = handler; new_user->handler_data = handler_data; new_user->intf = ipmi_interfaces[if_num]; @@ -906,8 +916,6 @@ probably, so abort. */ spin_unlock_irqrestore(&(intf->seq_lock), flags); - ipmi_free_recv_msg(recv_msg); - ipmi_free_smi_msg(smi_msg); goto out_err; } @@ -1794,8 +1802,13 @@ return rv; } +extern void machine_restart(char * __unused); +extern void machine_power_off(void); +extern char *panic_string; + #ifdef CONFIG_IPMI_PANIC_EVENT +#ifndef CONFIG_IPMI_PANIC_ACTION static void dummy_smi_done_handler(struct ipmi_smi_msg *msg) { } @@ -1828,12 +1841,9 @@ data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */ data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */ - /* These used to have the first three bytes of the panic string, - but not only is that not terribly useful, it's not available - any more. */ - data[3] = 0; - data[6] = 0; - data[7] = 0; + data[3] = panic_string[0]; + data[6] = panic_string[1]; + data[7] = panic_string[2]; smi_msg.done = dummy_smi_done_handler; recv_msg.done = dummy_recv_done_handler; @@ -1857,6 +1867,30 @@ intf->my_lun); } } +#endif + +void ipmi_reset(int mode) +{ +#ifdef CONFIG_IPMI_PANIC_ACTION + unsigned char imode; + unsigned char cc; + int rc, i; + + /* Input mode param: 0 = soft reset, 1 = power down, 2 = power cycle */ + if (!fIPMIok || mode == 0 || mode > 3) { + machine_restart(NULL); /* normal Linux reset (arch/i386/) */ + return; + } + /* + * IPMI Chassis Reset modes: + * 0 = power down, 1 = power up, 2 = power cycle, 3 = hard reset + */ + if (mode == 1) imode = 0; + else imode = mode; + rc = ipmi_send_recv(0x02,0x00,0,&imode,1,NULL,0,&i,&cc); +#endif + return; +} #endif /* CONFIG_IPMI_PANIC_EVENT */ static int has_paniced = 0; @@ -1875,14 +1909,55 @@ /* For every registered interface, set it to run to completion. */ for (i=0; ihandlers->set_run_to_completion(intf->send_info, 1); } #ifdef CONFIG_IPMI_PANIC_EVENT - send_panic_events(); + if (fIPMIok) { +#ifdef CONFIG_IPMI_PANIC_ACTION + unsigned char alarms, cc; + unsigned char obuf[16]; + unsigned char ibuf[16]; + int olen, rc; + + /* Get Alarm LED values */ + obuf[0] = 0x03; // PRIVATE_BUS_ID; + obuf[1] = 0x41; // ALARMS_PANEL_READ; + obuf[2] = 1; // one byte of alarms data + obuf[3] = 0; // initial alarms value + olen = 3; + rc = ipmi_send_recv(0x52,0x06,0,obuf,olen,ibuf,4,&i,&cc); + alarms = ibuf[0]; + printk("ipmi_panic: get alarms rc=%d cc=%x, alarms=%02x\n", + rc,cc,alarms); + if (alarms == 0) alarms = 0x0F; /* 0=err, fallback to default */ + if (rc == 0) { // valid, so ok to set alarm LED + /* Set Crit Alarm LED */ + obuf[0] = 0x03; // PRIVATE_BUS_ID; + obuf[1] = 0x40; // ALARMS_PANEL_WRITE; + obuf[2] = 1; // one byte of alarms data + obuf[3] = (alarms & 0x0D) | 0xF0; // turn on critical alarm + olen = 4; + rc = ipmi_send_recv(0x52,0x06,0,obuf,olen,NULL,0,&i,&cc); + printk("ipmi_panic: set crit alarm rc=%d cc=%x\n",rc,cc); + } + /* Log the OS Critical Stop to the SEL (BMC firmware log). */ + obuf[0] = 0x21; /* Kernel generator ID, IPMI table 5-4 */ + obuf[1] = 0x03; /* This is for IPMI 1.0. */ + obuf[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */ + obuf[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */ + obuf[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */ + obuf[3] = panic_string[0]; + obuf[6] = panic_string[1]; + obuf[7] = panic_string[2]; + olen = 8; + rc = ipmi_send_recv(0x02,0x04,0,obuf,olen,NULL,0,&i,&cc); + printk("ipmi_panic: log OS Critical Stop rc=%d cc=%x\n",rc,cc); +#else + send_panic_events(); +#endif + } #endif return NOTIFY_DONE; @@ -1914,6 +1989,9 @@ notifier_chain_register(&panic_notifier_list, &panic_block); +#ifdef CONFIG_IPMI_PANIC_ACTION + ipmi_panic_init(); +#endif initialized = 1; printk(KERN_INFO "ipmi: message handler initialized\n"); @@ -1971,3 +2049,6 @@ EXPORT_SYMBOL(ipmi_get_my_address); EXPORT_SYMBOL(ipmi_set_my_LUN); EXPORT_SYMBOL(ipmi_get_my_LUN); +#ifdef CONFIG_IPMI_PANIC_ACTION +EXPORT_SYMBOL(ipmi_reset); +#endif diff -Naru linux-2.5.62/drivers/char/ipmi/ipmi_panic.c linux-2.5.62p/drivers/char/ipmi/ipmi_panic.c --- linux-2.5.62/drivers/char/ipmi/ipmi_panic.c 1970-01-01 08:00:00.000000000 +0800 +++ linux-2.5.62p/drivers/char/ipmi/ipmi_panic.c 2003-03-06 22:27:16.000000000 +0800 @@ -0,0 +1,515 @@ +/* + * ipmi_panic.c + * + * This code is needed to run a streamlined IPMI KCS command when + * the rest of the system may be dead (panic time). It must wait + * for completion of the receive function also. + * There will be zero or one BMC, with KCS as a minimum and perhaps + * other interfaces, so doing KCS to a default BMC LUN is valid here. + * + * Note that CONFIG_IPMI_HANDLER should be =y (rather than =m) to + * ensure that this handler is loaded early enough to cover boot + * time panic conditions. CONFIG_IPMI_PANIC_ACTION can only be + * defined if CONFIG_IPMI_HANDLER=y. + * + * Author: Andy Cress + * + * Change History: + * 01/31/03 Andy Cress - created for kernel 2.5.44 with OpenIPMI + * + * Copyright 2003 Intel Corp. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define uchar unsigned char + +#define KCS_READY_DELAY 5 +#define BMC_RESPONSE_DELAY 5 +#define BMC_RETRY_DELAY 60 + +#if defined(__ia64__) +#define KCS_BASE 0x8a2 +#else +#define KCS_BASE 0xca2 +#endif +#define KCS_STATUS_REG (KCS_BASE + 1) +#define KCS_COMMAND_REG (KCS_BASE + 1) +#define KCS_DATAIN_REG (KCS_BASE + 0) +#define KCS_DATAOUT_REG (KCS_BASE + 0) + +/* State bits based on S1 & S0 below */ +#define KCS_STATE_MASK 0xC0 +#define KCS_IDLE_STATE 0x00 +#define KCS_READ_STATE 0x40 +#define KCS_WRITE_STATE 0x80 +#define KCS_ERROR_STATE 0xC0 + +#define KCS_IBF 0x02 +#define KCS_OBF 0x01 +#define KCS_SMS_ATN 0x04 + +#define SEND_INIT 1 +#define SEND_START 2 +#define SEND_NEXT 3 +#define SEND_END 4 +#define RECV_START 5 +#define RECV_INIT 6 +#define RECV_NEXT 7 +#define RECV_INIT2 8 +#define RECV_END 9 +#define END 10 +#define ERROR 0 + +/* SMS Transfer Stream Control Codes */ +#define GET_STATUS_ABORT 0x60 +#define WRITE_START 0x61 +#define WRITE_END 0x62 +#define KCS_READ 0x68 + +#define MAX_INVALID_RESPONSE_COUNT 2 +#define MIN_BMC_RESPONSE_SIZE 3 +#define MAX_IMB_PACKET_SIZE 33 +#define MAX_BMC_RESPONSE_SIZE (MIN_BMC_RESPONSE_SIZE + MAX_IMB_PACKET_SIZE) +#define MAX_XFER_LENGTH (MAX_IMB_PACKET_SIZE * 2) + +#define MAX_BUFFER_SIZE 64 + +typedef struct bmc_response + { + unsigned char lun :2; + unsigned char netfn :6; + unsigned char cmd; + unsigned char cc; + unsigned char data[1]; + }BMC_RESPONSE; + +typedef struct bmc_request + { + unsigned char lun :2; + unsigned char netfn :6; + unsigned char cmd; + unsigned char data[1]; + }BMC_REQUEST; + +/* GET_DEVICE_ID RESPONSE (11 bytes) */ +typedef struct device_id_response + { + unsigned char device_id; + + unsigned char device_revision :4; + unsigned char reserved :3; + unsigned char provides_sdr :1; + + unsigned char major_firmware_revision :7; + #define NORMAL_OPERATION 0 + #define DEVICE_BUSY 1 + unsigned char device_available :1; + + unsigned char minor_firmware_revision; + unsigned char ipmi_version_major :4; + unsigned char ipmi_version_minor :4; + + unsigned char supports_sensor_device :1; + unsigned char supports_sdr_device :1; + unsigned char supports_sel_device :1; + unsigned char supports_fru_device :1; + unsigned char supports_ipmb_receiver :1; + unsigned char supports_ipmb_generator :1; + unsigned char supports_bridge :1; + unsigned char supports_chassis_device :1; + + unsigned char manufacturer_id1; + unsigned char manufacturer_id2; + unsigned char manufacturer_id3; + unsigned short product_id; + } DEVICE_ID_RESPONSE; + +/*************************************/ + +#if defined(__ia64__) +static char kcs_new = 1; +#else +static char kcs_new = 0; +#endif +DECLARE_MUTEX(kcs_sem); + +/*************************************/ + +/* + * kcs chip mashing stuff + */ +static int wait_while_ibf(void) +{ + unsigned char status_byte; + + status_byte = inb_p(KCS_STATUS_REG); + if ((status_byte & KCS_IBF) == 0) return (0); + mdelay(KCS_READY_DELAY); + status_byte = inb_p(KCS_STATUS_REG); + if (status_byte & KCS_IBF) return (-1); + return (0); +} + +static int is_obf_set(void) +{ + unsigned char cs; + cs = inb_p(KCS_STATUS_REG); + return ((cs & KCS_OBF) == KCS_OBF); +} + +static int wait_until_obf(void) +{ + int retries = 0; + + while (retries < 2) { + if (is_obf_set()) return (0); + mdelay(KCS_READY_DELAY); + retries++; + } + return (-ETIMEDOUT); +} + +static unsigned char get_kcs_state(void) +{ + unsigned char cs; + + cs = inb_p(KCS_STATUS_REG); + return (cs & KCS_STATE_MASK); +} + +static unsigned char read_kcs_data(void) +{ + unsigned char data; + + data = inb_p(KCS_DATAOUT_REG); + return (data); +} + +static void write_kcs_data(unsigned char data) +{ + outb_p(data, KCS_DATAIN_REG); +} + +static void write_kcs_cmd(unsigned char cmd) +{ + outb_p(cmd, KCS_COMMAND_REG); +} + +static int clear_obf(void) +{ + read_kcs_data(); + return (0); +} + +static int kcs_xfer(BMC_REQUEST * request, int request_len, + BMC_RESPONSE * response, int *response_len) +{ + unsigned char *xmit_buffer, *recv_buffer; + int i = 0, rc = 0, state = SEND_INIT, bad = 0; + + xmit_buffer = (unsigned char *) request; + recv_buffer = (unsigned char *) response; + + while (1) { + if (state == END) + break; + else if (bad > 2) { + printk("[ipmi_panic] Maximum retries exceeded.\n"); + rc = -EIO; + break; + } + switch (state) { + case SEND_INIT: + { + i = 0; + state = SEND_START; + wait_while_ibf(); + if (kcs_new) clear_obf(); + } + case SEND_START: + { + state = SEND_NEXT; + write_kcs_cmd(WRITE_START); + wait_while_ibf(); + } + case SEND_NEXT: + { + if (i == (request_len - 1)) { + state = SEND_END; + break; + } + if (get_kcs_state() != KCS_WRITE_STATE) { + state = ERROR; + break; + } + write_kcs_data(xmit_buffer[i++]); + wait_while_ibf(); + if (kcs_new) clear_obf(); + break; + } + case SEND_END: + { + if (!kcs_new) wait_while_ibf(); + write_kcs_cmd(WRITE_END); + wait_while_ibf(); + if (get_kcs_state() != KCS_WRITE_STATE) { + state = ERROR; + break; + } + if (kcs_new) clear_obf(); + write_kcs_data(xmit_buffer[i++]); + wait_while_ibf(); + state = RECV_START; + } + case RECV_START: + { + switch (get_kcs_state()) { + case KCS_ERROR_STATE: + { + state = ERROR; + break; + } + case KCS_WRITE_STATE: + case KCS_IDLE_STATE: + { + mdelay(BMC_RESPONSE_DELAY); + break; + } + case KCS_READ_STATE: + { + i = 0; + memset(recv_buffer, 0, + *response_len); + state = RECV_INIT; + break; + } + } + break; + } + case RECV_INIT: + { + switch (get_kcs_state()) { + case KCS_ERROR_STATE: + case KCS_WRITE_STATE: + { + state = ERROR; + break; + } + case KCS_IDLE_STATE: + { + state = RECV_END; + break; + } + case KCS_READ_STATE: + { + if (is_obf_set()) + state = RECV_NEXT; + else mdelay(1); + break; + } + default: + { + mdelay(1); + break; + } + } + break; + } + case RECV_NEXT: + { + if (i >= *response_len) { + rc = -EOVERFLOW; + state = ERROR; + break; + } + recv_buffer[i++] = read_kcs_data(); + if (!kcs_new) wait_while_ibf(); + write_kcs_data(KCS_READ); + if (kcs_new) wait_while_ibf(); + state = RECV_INIT2; + break; + } + case RECV_INIT2: + { + switch (get_kcs_state()) { + case KCS_ERROR_STATE: + case KCS_WRITE_STATE: + { + state = ERROR; + break; + } + case KCS_IDLE_STATE: + { + if (kcs_new) { + if (wait_until_obf() == 0) { + clear_obf(); + state = RECV_END; + } else { + state = ERROR; + } + } else { + state = RECV_END; + } + break; + } + case KCS_READ_STATE: + { + if (kcs_new) { + if (wait_until_obf() == 0) + state = RECV_NEXT; + else state = ERROR; + } else { + if (is_obf_set()) + state = RECV_NEXT; + } + break; + } + } + break; + } + case RECV_END: + { + if ((i < MIN_BMC_RESPONSE_SIZE) || + (response->netfn != (request->netfn | 0x01)) + || (response->cmd != request->cmd)) { + if (request->cmd == 0x01 && + request->netfn == 0x06 && + response->netfn == 0x2b) /*ok*/; + else { /* flag the error */ + printk("[ipmi_panic] Request/Response CMD/NETFN mismatch error\n"); + + printk(" i=%d, RQcmd/RQnetfn=0x%x/0x%x,RScmd/RSnetfn=0x%x/0x%x\n", + i, request->cmd, request->netfn, + response->cmd, response->netfn); + mdelay(BMC_RETRY_DELAY); + bad++; + state = SEND_INIT; + break; + } + } + + *response_len = i; + rc = 0; + state = END; + break; + } + case ERROR: + default: + { + printk("[ipmi_panic] BMC in bad state. Retrying transfer\n"); + mdelay(BMC_RETRY_DELAY); + bad++; + state = SEND_INIT; + break; + } + } + } + return (rc); +} + +int ipmi_send_recv(uchar cmd, uchar netfn, uchar lun, uchar *sbuf, int slen, + uchar *rbuf, int rlen, int *nret, uchar *cc) +{ + uchar bmc_outbuf[MAX_BUFFER_SIZE]; + uchar bmc_inbuf[MAX_BUFFER_SIZE]; + BMC_REQUEST *bmc_req; + BMC_RESPONSE *bmc_resp; + int bmc_outlen; + int bmc_inlen; + int rc = 0; + + if (kcs_new == 2) return (-ENXIO); + + memset(bmc_outbuf,0, sizeof(bmc_outbuf)); + memset(bmc_inbuf,0, sizeof(bmc_inbuf)); + bmc_req = (BMC_REQUEST *)bmc_outbuf; + bmc_resp = (BMC_RESPONSE *)bmc_inbuf; + bmc_req->cmd = cmd; + bmc_req->netfn = netfn; + bmc_req->lun = lun; + bmc_outlen = slen + 2; + bmc_inlen = sizeof(bmc_inbuf); + if (slen > 0) memcpy(bmc_req->data,sbuf,slen); + + rc = kcs_xfer(bmc_req, bmc_outlen, bmc_resp, &bmc_inlen); + if (bmc_resp->cc == 0xcc) /* flaky NMI fixup */ + rc = kcs_xfer(bmc_req, bmc_outlen, bmc_resp, &bmc_inlen); /*retry*/ + + /* copy the response */ + *cc = bmc_resp->cc; + if (bmc_inlen > rlen) bmc_inlen = rlen; + *nret = bmc_inlen; + if (bmc_inlen > 0) memcpy(rbuf,bmc_resp->data,bmc_inlen); + + return(rc); +} + +int ipmi_panic_init(void) +{ + int i, rc; + uchar cc; + uchar bdev[16]; + DEVICE_ID_RESPONSE *dev_id; + + printk("ipmi_panic driver at io 0x%x\n", KCS_BASE); + if ((inb_p(KCS_STATUS_REG) == 0xFF) && + (inb_p(KCS_DATAIN_REG) == 0xFF)) { + printk("--KCS ISA window not present, exiting.\n"); + return (-ENXIO); + } + + /* Get Device ID */ + rc = ipmi_send_recv(0x01,0x06,0,NULL,0,bdev,sizeof(bdev),&i,&cc); + if (rc != 0) kcs_new = 2; /* bad */ + else if (cc != 0) kcs_new = 2; /* bad */ + else + { + dev_id = (DEVICE_ID_RESPONSE *)&bdev[0]; + printk("--BMC version %x.%x, IPMI version %d.%d\n", + dev_id->major_firmware_revision, + dev_id->minor_firmware_revision, + dev_id->ipmi_version_major, dev_id->ipmi_version_minor); + if ((dev_id->ipmi_version_major == 0) && + (dev_id->ipmi_version_minor == 9)) { + printk("--Using legacy KCS state machine\n"); + kcs_new = 0; + } else { + printk("--Using new KCS state machine\n"); + kcs_new = 1; + } + } + /* dont care about chipset vendor, but test Lancewood & IPF to be sure*/ + + return(rc); +} + +/* end ipmi_panic.c */ diff -Naru linux-2.5.62/drivers/char/ipmi/Kconfig linux-2.5.62p/drivers/char/ipmi/Kconfig --- linux-2.5.62/drivers/char/ipmi/Kconfig 2003-03-07 16:34:23.000000000 +0800 +++ linux-2.5.62p/drivers/char/ipmi/Kconfig 2003-03-06 22:46:58.000000000 +0800 @@ -7,8 +7,14 @@ tristate 'IPMI top-level message handler' help This enables the central IPMI message handler, required for IPMI - to work. Note that you must have this enabled to do any other IPMI - things. See IPMI.txt for more details. + to work. + + IPMI is a standard for managing sensors (temperature, + voltage, etc.) in a system. + + See Documentation/IPMI.txt for more details on the driver. + + If unsure, say N. config IPMI_PANIC_EVENT bool 'Generate a panic event to all BMCs on a panic' @@ -36,5 +42,11 @@ depends on IPMI_HANDLER help This enables the IPMI watchdog timer. +config IPMI_PANIC_ACTION + int 'Action after Panic (0=reset,1=power down,2=power cycle)' + requires IPMI_HANDLER=y + default "0" + help + Set the Action after Panic endmenu diff -Naru linux-2.5.62/drivers/char/ipmi/Makefile linux-2.5.62p/drivers/char/ipmi/Makefile --- linux-2.5.62/drivers/char/ipmi/Makefile 2003-03-07 16:34:54.000000000 +0800 +++ linux-2.5.62p/drivers/char/ipmi/Makefile 2003-03-06 22:27:16.000000000 +0800 @@ -4,7 +4,7 @@ ipmi_kcs_drv-objs := ipmi_kcs_sm.o ipmi_kcs_intf.o -obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o +obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o ipmi_panic.o obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o obj-$(CONFIG_IPMI_KCS) += ipmi_kcs_drv.o obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o diff -Naru linux-2.5.62/drivers/char/Kconfig linux-2.5.62p/drivers/char/Kconfig --- linux-2.5.62/drivers/char/Kconfig 2003-03-07 16:33:38.000000000 +0800 +++ linux-2.5.62p/drivers/char/Kconfig 2003-03-07 16:22:02.000000000 +0800 @@ -999,5 +999,6 @@ out to lunch past a certain margin. It can reboot the system or merely print a warning. + endmenu diff -Naru linux-2.5.62/kernel/panic.c linux-2.5.62p/kernel/panic.c --- linux-2.5.62/kernel/panic.c 2003-03-07 16:34:58.000000000 +0800 +++ linux-2.5.62p/kernel/panic.c 2003-03-06 22:27:07.000000000 +0800 @@ -20,6 +20,10 @@ asmlinkage void sys_sync(void); /* it's really int */ int panic_timeout; +char *panic_string; +#ifdef CONFIG_IPMI_PANIC_ACTION + extern void ipmi_reset(int mode); +#endif struct notifier_block *panic_notifier_list; @@ -53,6 +57,7 @@ va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); + panic_string = buf; printk(KERN_EMERG "Kernel panic: %s\n",buf); if (in_interrupt()) printk(KERN_EMERG "In interrupt handler - not syncing\n"); @@ -81,7 +86,11 @@ * choosing not too. It might crash, be corrupt or do * more harm than good for other reasons. */ +#ifdef CONFIG_IPMI_PANIC_ACTION + ipmi_reset(CONFIG_IPMI_PANIC_ACTION); +#else machine_restart(NULL); +#endif } #ifdef __sparc__ {