diff options
Diffstat (limited to 'kern/bmcpanic-2.5.62.patch')
-rw-r--r-- | kern/bmcpanic-2.5.62.patch | 830 |
1 files changed, 830 insertions, 0 deletions
diff --git a/kern/bmcpanic-2.5.62.patch b/kern/bmcpanic-2.5.62.patch new file mode 100644 index 0000000..44e9141 --- /dev/null +++ b/kern/bmcpanic-2.5.62.patch @@ -0,0 +1,830 @@ +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 <linux/notifier.h> + #include <linux/init.h> + ++#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; i<MAX_IPMI_INTERFACES; i++) { + intf = ipmi_interfaces[i]; +- if (intf == NULL) +- continue; +- ++ if (intf == NULL) continue; + intf->handlers->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 <arcress at users.sourceforge.net> ++ * ++ * 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 <linux/config.h> ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <asm/io.h> ++#include <asm/uaccess.h> ++#include <asm/system.h> ++#include <asm/semaphore.h> ++#include <linux/delay.h> ++ ++#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__ + { |