Index: oldkernel/linux/Documentation/Configure.help
diff -u linux/Documentation/Configure.help:1.7 linux/Documentation/Configure.help:1.8
--- linux/Documentation/Configure.help:1.7	Thu Jun  1 16:52:14 2000
+++ linux/Documentation/Configure.help	Thu Jun  1 17:01:59 2000
@@ -9240,6 +9240,17 @@
   many of the newer IBM Thinkpads.  If you experience hangs when you
   suspend, try setting this to Y.  Otherwise, say N.
 
+Intelligent Platform Management Interface Support
+CONFIG_IPMI_KCS
+  Enables support for the Keyboard Controller Style (KCS) interface to
+  the Baseboard Management Controller (BMC) which allows a user program
+  to send and receive IPMI commands. The BMC is a next generation style
+  server management co-processor which exists on many Intel based
+  server boards (Qlogic also has a chip which is compatible which is
+  available on a few other vendors boards). For documentation and
+  utilities to access the watchdog, temperature sensor, and other
+  data, see http://valinux.com/projects.
+                            
 Watchdog Timer Support 
 CONFIG_WATCHDOG
   If you say Y here (and to one of the following options) and create a
Index: oldkernel/linux/arch/i386/kernel/traps.c
diff -u linux/arch/i386/kernel/traps.c:1.2 linux/arch/i386/kernel/traps.c:1.3
--- linux/arch/i386/kernel/traps.c:1.2	Thu Jun  1 15:05:19 2000
+++ linux/arch/i386/kernel/traps.c	Thu Jun  1 17:01:59 2000
@@ -333,8 +333,122 @@
 		mem_parity_error(reason, regs);
 	if (reason & 0x40)
 		io_check_error(reason, regs);
+	if (reason & 0x20)
+		{
+		bmc_nmi_error(reason, regs);
+		return;
+		}
 	if (!(reason & 0xc0))
 		unknown_nmi_error(reason, regs);
+}
+
+/* 
+ * The IPMI KCS NMI watchdog handler stuff
+ */ 
+#include <linux/config.h>
+
+#define IO 0xca2
+#define ISA_BMC_STATUS    (IO + 1)
+#define ISA_BMC_COMMAND   (IO + 1)
+#define ISA_BMC_DATA_IN       (IO + 0)
+#define ISA_BMC_DATA_OUT      (IO + 0)
+#define ISA_STATE_MASK        0xC0
+#define ISA_IDLE_STATE        0x00
+#define ISA_READ_STATE        0x40
+#define ISA_WRITE_STATE       0x80
+#define ISA_ERROR_STATE       0xC0
+#define ISA_S1_FLAG           0x80
+#define ISA_S0_FLAG           0x40
+#define ISA_CD_FLAG           0x08
+#define ISA_SMS_MSG_FLAG      0x04
+#define ISA_IBF_FLAG          0x02
+#define ISA_OBF_FLAG          0x01
+#define ISA_GET_STATUS_ABORT   0x60
+#define ISA_WRITE_START        0x61
+#define ISA_WRITE_END          0X62
+#define ISA_READ               0X68
+#define MAX_ISA_LENGTH  35
+#define ISA_TIMEOUT 1000
+
+static void bmc_nmi_error(unsigned char reason, struct pt_regs * regs)
+{
+  struct cmd
+    {
+    unsigned char lun   :2;
+    unsigned char netfn :6;
+
+    unsigned char cmd;
+    } pkt;
+
+  memset(&pkt, 0, sizeof(pkt));
+
+  pkt.netfn=0x06;
+  pkt.lun=0x00;
+  pkt.cmd=0x55;
+  kcs_send_message(&pkt, sizeof(pkt));
+}
+
+static int wait_while_ibf(int timeout)
+{
+  unsigned int master_timeout=5;
+  unsigned char status_byte;
+
+  status_byte = (inb_p(ISA_BMC_STATUS) & 0xFF);
+  while(status_byte & ISA_IBF_FLAG)
+    {
+    master_timeout--;
+    if (!master_timeout)
+      return(-1);
+    udelay(100);
+    status_byte = (inb_p(ISA_BMC_STATUS) & 0xFF);
+    }
+  return(0);
+}
+
+static int kcs_send_message(unsigned char *buf, int length)
+{
+  int           status;
+  int           i;
+  unsigned char chipstatus;
+
+  if ((status = wait_while_ibf(ISA_TIMEOUT)) <0)
+    return(-EIO);
+
+  outb_p(ISA_WRITE_START, ISA_BMC_COMMAND);
+
+  if ((status = wait_while_ibf(ISA_TIMEOUT)) <0)
+    return(-EIO);
+
+  for (i=0; i <length -1; i++)
+    {
+    chipstatus = inb_p(ISA_BMC_STATUS);
+
+    if (chipstatus & ISA_OBF_FLAG)
+      inb_p(ISA_BMC_DATA_IN);
+
+    if ((chipstatus & ISA_STATE_MASK) != ISA_WRITE_STATE)
+      {
+      printk("write state fault (0x%x)\n",chipstatus);
+      return(-EIO);
+      }
+    outb_p(buf[i], ISA_BMC_DATA_OUT);
+    if ((status = wait_while_ibf(ISA_TIMEOUT)) <0)
+      return(-EIO);
+    }
+  outb_p(ISA_WRITE_END, ISA_BMC_COMMAND);
+  if ((status = wait_while_ibf(ISA_TIMEOUT)) <0)
+    return(-EIO);
+  outb_p(buf[i], ISA_BMC_DATA_OUT);
+  if ((status = wait_while_ibf(ISA_TIMEOUT)) <0)
+    return(-EIO);
+
+  chipstatus = inb_p(ISA_BMC_STATUS);
+  if ((chipstatus & ISA_STATE_MASK) !=ISA_READ_STATE)
+    {
+    printk("read state fault (0x%x)\n",chipstatus);
+    return (-EIO);
+    }
+  return(0);
 }
 
 /*
Index: oldkernel/linux/drivers/char/Config.in
diff -u linux/drivers/char/Config.in:1.1.1.1 linux/drivers/char/Config.in:1.2
--- linux/drivers/char/Config.in:1.1.1.1	Wed May 31 12:33:51 2000
+++ linux/drivers/char/Config.in	Thu Jun  1 17:01:59 2000
@@ -90,6 +90,8 @@
   fi
 fi
 
+tristate 'IPMI KCS Interface' CONFIG_IPMI_KCS
+
 bool 'Watchdog Timer Support'	CONFIG_WATCHDOG
 if [ "$CONFIG_WATCHDOG" != "n" ]; then
   mainmenu_option next_comment
Index: oldkernel/linux/drivers/char/Makefile
diff -u linux/drivers/char/Makefile:1.2 linux/drivers/char/Makefile:1.3
--- linux/drivers/char/Makefile:1.2	Thu Jun  1 13:06:16 2000
+++ linux/drivers/char/Makefile	Thu Jun  1 17:01:59 2000
@@ -296,6 +296,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_IPMI_KCS),y)
+L_OBJS += ipmi_kcs.o
+else
+  ifeq ($(CONFIG_IPMI_KCS),m)
+  M_OBJS +=ipmi_kcs.o
+  endif
+endif
+
 ifeq ($(CONFIG_AMIGAMOUSE),y)
 L_OBJS += amigamouse.o
 else
Index: oldkernel/linux/drivers/char/ipmi_kcs.c
diff -u /dev/null linux/drivers/char/ipmi_kcs.c:1.1
--- /dev/null	Mon Jul 31 21:14:41 2000
+++ linux/drivers/char/ipmi_kcs.c	Thu Jun  1 17:01:59 2000
@@ -0,0 +1,619 @@
+/*
+ *	Intelligent Platform Management Interface  driver for Linux 2.1.x
+ *
+ *	(c) Copyright 1999 San Mehat <nettwerk@valinux.com>,All Rights Reserved.
+ *				http://www.valinux.com
+ *
+ *	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.
+ *	
+ *	Neither San Mehat nor VA Linux Systems admit liability nor provide 
+ *	warranty for any of this software. This material is provided 
+ *	"AS-IS" and at no charge.	
+ *
+ *	(c) Copyright 1999    San Mehat <nettwerk@valinux.com>
+ *
+ *	Release 0.04.   - Initial Release
+ *	
+ *	Release 0.05.   - Fixed ring buffer bugs... better buffer handling
+ *
+ *	Release 0.06.   - Changed polling freq to 1/10 sec
+ *
+ *  Release 0.07.   - Integrated watchdog commands into IOCTL's and added
+ *                    support for blinking front panel LED
+ *
+ *  Release 0.08.   - Sensor read commands added as ioctl
+ *
+ *  Release 0.09.   - Changed polling freq back to 1 second
+ *                  - Fixed possible bug where a chip status variable was
+ *                    not declared volatile.
+ *                  - Fixed buffer memory leak
+ *                  - Fixed ioctl return value problem
+ *                  - Changed architecture so that applications calling
+ *                    driver ioctl()'s are put to sleep after request
+ *                    is sent. The reply is handled by the normal
+ *                    driver polling timer queue and ring buffer
+ *
+ *  Release 0.10.   - Modified kcs_write routine so once a write is complete
+ *                    if the interface isn't in a 'READ STATE' it's okay.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include "ipmi_kcs.h"
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/ipmi_kcs_ioctls.h>
+
+/* function prototypes */
+static int kcs_send_message(unsigned char *buf, int length);
+static int kcs_read_message(int *msglen, unsigned char *buf);
+static int wait_while_ibf(int timeout);
+static int ipmi_kcs_dispatch_internal(void *data, int size, void *reply);
+
+static int add_data_to_ringbuffer(unsigned char *data, int length);
+static int remove_data_from_ringbuffer(unsigned char *data, int length);
+static int watchdog_set(unsigned char args);
+static int watchdog_ping(void);
+static int panel_set(unsigned char state);
+static int read_sensor(struct sensor_request *sensor);
+
+void ipmi_kcs_poll(unsigned long nothing);
+int ipmi_kcs_init(void);
+
+static int kcs_open(struct inode *inode, struct file *file);
+static int kcs_release(struct inode *inode, struct file *file);
+static ssize_t kcs_read(struct file *file, char *buf, size_t count, loff_t *ptr);
+static ssize_t kcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos);
+static long long kcs_llseek(struct file *file, long long offset, int origin);
+static int kcs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+										 unsigned long arg);
+
+/* static globals */
+static struct timer_list	poll_timer;
+static int 								kcs_is_open=0;
+static struct wait_queue	*wq = NULL;
+static int								head;
+static int								tail;
+static unsigned char			*buffer;
+
+static struct file_operations kcs_fops = {
+	kcs_llseek,
+	kcs_read,
+	kcs_write,
+	NULL,		/* No Readdir */
+	NULL,		/* No Select */
+	kcs_ioctl,
+	NULL,		/* No mmap */
+	kcs_open,
+	NULL,		/* flush */
+	kcs_release
+};
+
+static struct miscdevice kcs_miscdev=
+{
+	IPMI_KCS_MINOR,
+	"ipmi_kcs",
+	&kcs_fops
+};
+
+#define POLL_FREQ ((HZ/10))
+
+/***************/
+
+static long long kcs_llseek(struct file *file, long long offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static ssize_t kcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	unsigned char tmp_buffer[MAX_ISA_LENGTH];
+	int						rc;
+
+	if (!count)
+		return(0);
+	if (count > MAX_ISA_LENGTH)
+		return -EFBIG;
+	copy_from_user(&tmp_buffer[0], buf, count);
+	if ((rc = kcs_send_message(&tmp_buffer[0],count))<0)
+		{
+		printk("kcs_write(): Unable to send message\n");
+		return(rc);
+		}
+	return(0);
+}
+
+static ssize_t kcs_read(struct file *file, char *buf, size_t count, loff_t *ptr)
+{
+	unsigned char tmp_buffer[MAX_ISA_LENGTH];
+	int						rc;
+
+	/*  Can't seek (pread) on this device  */
+	if (ptr != &file->f_pos)
+		return -ESPIPE;
+
+	if (count > MAX_ISA_LENGTH)
+		count = MAX_ISA_LENGTH;
+
+	switch(MINOR(file->f_dentry->d_inode->i_rdev))
+		{
+		case IPMI_KCS_MINOR:
+			/* Check to see if theres any data to be read */
+			if (head == tail)
+				{
+				if (file->f_flags & O_NONBLOCK)
+					{
+					return -EAGAIN;
+					}
+				else
+					{
+					interruptible_sleep_on(&wq);
+					}
+				}
+			/* If we're here theres data to be read */
+			if ((rc = remove_data_from_ringbuffer(&tmp_buffer[0], count))<0)
+				{
+				printk("kcs_read(): ring buffer remove failure\n");
+				return -EIO;
+				}
+			copy_to_user(buf, &tmp_buffer[0], rc);
+			return(rc);
+			break;
+		default:
+			return -EINVAL;
+		}
+}
+
+static int kcs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	unsigned char argument;
+
+	switch(cmd)
+		{
+		case IOCTL_WATCHDOG_SET:
+			if (!arg)
+				return(-EINVAL);
+			if (copy_from_user(&argument, (void *) arg, sizeof(unsigned char)))
+				return(-EFAULT);
+			return(watchdog_set(argument));
+			break;
+		case IOCTL_WATCHDOG_PING:
+			if (arg)
+				return(-EINVAL);
+			return(watchdog_ping());
+			break;
+		case IOCTL_PANEL_LED_SET_BLINK:
+			if (!arg)
+				return(-EINVAL);
+			if (copy_from_user(&argument, (void *) arg, sizeof(unsigned char)))
+				return(-EFAULT);
+			if ((argument != 0x00) && (argument != 0x01))
+				return(-EINVAL);
+			return(panel_set(argument));
+			break;
+		case IOCTL_READ_SENSOR:
+			{
+			struct sensor_request	req;
+			int										rc;
+
+			if (!arg)
+				return(-EINVAL);
+			if (copy_from_user(&req, (void *) arg, sizeof(req)))
+				return(-EFAULT);
+			rc = read_sensor(&req);
+			if (copy_to_user((struct sensor_request *)arg, &req, sizeof(req)))
+				return(-EFAULT);
+			return(rc);
+			}
+		default:
+			return -EINVAL;
+		}
+	return (0);
+}
+
+static int read_sensor(struct sensor_request *sensor)
+{
+	SENSOR_CMD		pkt;
+
+	memset(&pkt, 0, sizeof(pkt));
+	pkt.netfn=0x04;
+	pkt.lun=0x00;
+	pkt.cmd=0x2d;
+	pkt.sensor_number=sensor->sensor_number;
+	
+	if ((sensor->result_length =ipmi_kcs_dispatch_internal((void *) &pkt,
+																			 sizeof(pkt), 
+																			(void *) &sensor->result_buffer[0]))<0)
+		{
+		printk("read_sensor(): IPMI command timed out for reply\n");
+		return -EIO;
+		}
+	if (sensor->result_buffer[2] != 0x00)
+		{
+		printk("read_sensor(): IPMI command failed (rc = 0x%.2x)\n",
+						sensor->result_buffer[2]);
+		return -EIO;
+		}
+	return(0);
+}
+
+static int watchdog_set(unsigned char args)
+{
+	IPMI_KCS_SET_WATCHDOG	pkt;
+	unsigned char					reply[MAX_ISA_LENGTH];
+
+	memset(&pkt, 0, sizeof(pkt));
+	pkt.netfn=0x06;
+	pkt.lun=0x0;
+	pkt.cmd=0x24;
+	pkt.timer_use = 0x04;
+
+	if (args & WATCHDOG_ACTION_REBOOT)
+		pkt.timeout_action = 0x03;
+	if (args & WATCHDOG_ACTION_NMI)
+		pkt.pre_irq = 0x02;
+
+	pkt.pretimeout_interval = 10;
+	pkt.tuefc_biosfrb2=0x00;
+	pkt.tuefc_biospost=0x0;
+	pkt.tuefc_osload=0x00;
+	pkt.tuefc_smsos=0x01;
+	pkt.initial_count = (30 * 10);
+	if (ipmi_kcs_dispatch_internal((void *) &pkt, sizeof(pkt), (void *) &reply)<0)
+		{
+		printk("watchdog_set(): IPMI command timed out for reply\n");
+		return(-EIO);
+		}
+	if (reply[2] != 0x00)
+		{
+		printk("watchdog_set(): IPMI command failed (rc = 0x%.2x)\n",reply[2]);
+		return(-EIO);
+		}
+	return(0);
+}
+
+static int watchdog_ping(void)
+{
+	IPMI_KCS_RESET_WATCHDOG	pkt;
+	unsigned char	reply[MAX_ISA_LENGTH];
+
+	memset(&pkt, 0, sizeof(pkt));
+	pkt.netfn = 0x06;
+	pkt.lun = 0x00;
+	pkt.cmd = 0x22;
+
+	if (ipmi_kcs_dispatch_internal((void *) &pkt, sizeof(pkt), (void *) &reply)<0)
+		{
+		printk("watchdog_ping(): IPMI command timed out for reply\n");
+		return(-EIO);
+		}
+	if (reply[2] != 0x00)
+		{
+		printk("watchdog_ping(): IPMI command failed (rc = 0x%.2x)\n",reply[2]);
+		return(-EIO);
+		}
+	return(0);
+}
+
+static int panel_set(unsigned char state)
+{
+	unsigned char	reply[MAX_ISA_LENGTH];
+	struct blinky_cmd
+		{
+		unsigned char	lun		:2;
+		unsigned char	netfn	:6;
+
+		unsigned char	cmd;
+		} pkt;
+
+	memset(&pkt, 0, sizeof(pkt));
+	pkt.netfn= 0x06;
+	pkt.lun= 0x00;
+	if (state == PANEL_LED_BLINK)
+		pkt.cmd= 0x55;
+	else
+		pkt.cmd= 0x56;
+
+	if (ipmi_kcs_dispatch_internal((void *) &pkt, sizeof(pkt), (void *) &reply)<0)
+		{
+		printk("panel_set(): IPMI command timed out for reply\n");
+		return(-EIO);
+		}
+	if (reply[2] != 0x00)
+		{
+		printk("panel_set(): IPMI command failed (rc = 0x%.2x)\n",reply[2]);
+		return(-EIO);
+		}
+	return(0);
+}
+
+static int ipmi_kcs_dispatch_internal(void *data, int size, void *reply)
+{
+	volatile unsigned char	status;
+	int											rc;
+	int											msglen;
+	unsigned int						jiffystart;
+	int											i;
+
+	if ((rc =kcs_send_message((unsigned char *) data, size))<0)
+		{
+		printk("[IPMI_KCS] Message dispatch failed. (rc %d)\n",rc);
+		return(-EIO);
+		}
+
+	interruptible_sleep_on(&wq);
+	if ((rc = remove_data_from_ringbuffer((unsigned char *) reply,
+																				MAX_ISA_LENGTH))<0)
+		{
+		printk("[IPMI_KCS] Ring buffer remove failure\n");
+		return -EIO;
+		}
+	return(rc);
+}
+
+static int kcs_open(struct inode *inode, struct file *file)
+{
+	switch(MINOR(inode->i_rdev))
+		{
+		case IPMI_KCS_MINOR:
+			{
+			if(kcs_is_open)
+				return -EBUSY;
+			MOD_INC_USE_COUNT;
+	 
+			kcs_is_open=1;
+			return 0;
+			}
+		default:
+			return -ENODEV;
+		}
+}
+
+static int kcs_release(struct inode *inode, struct file *file)
+{
+	if(MINOR(inode->i_rdev)==IPMI_KCS_MINOR)
+		kcs_is_open=0;
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+#ifdef MODULE
+#define kcs_init init_module
+
+__initfunc(int kcs_init(void))
+{
+	return(ipmi_kcs_init());
+}
+
+void cleanup_module(void)
+{
+	printk("[IPMI_KCS] Driver shutting down.\n");
+	kfree(buffer);
+	del_timer(&poll_timer);
+	misc_deregister(&kcs_miscdev);
+	release_region(IO,16);
+}
+#endif
+
+static int add_data_to_ringbuffer(unsigned char *data, int length)
+{
+	int i;
+	int diff;
+
+	/* Make sure we have room in the ringbuffer */
+	diff = tail - head;
+	if (diff <0)
+		diff = PAGE_SIZE - head + tail;
+	diff = PAGE_SIZE - diff;
+	if (length > diff)
+		{
+		printk("[IPMI_KCS] Not enough room in ringbuffer\n");
+		printk("[IPMI_KCS] len = %d, head = %d, tail = %d\n",length, head, tail);
+		return(-1); /* Not enough room */
+		}
+
+	for (i = 0; i < length; i++)
+		{
+		buffer[tail] = data[i];
+		tail++;
+		tail &= (PAGE_SIZE -1);
+		}
+	return(0);
+}
+
+static int remove_data_from_ringbuffer(unsigned char *data, int length)
+{
+	int i;
+
+	if (head == tail)
+		return(0); /* No data to be read */
+
+	for (i = 0; i < length; i++)
+		{
+		*data++ = buffer[head++];
+		head &= (PAGE_SIZE -1);
+		if (head == tail)
+			{
+			i++;
+			return(i);
+			}
+		}
+	i++;
+	return(i);
+}
+
+void ipmi_kcs_poll(unsigned long nothing)
+{
+	volatile unsigned char	status;
+	unsigned char						data[MAX_ISA_LENGTH];
+	int											rc;
+	int											msglen;
+
+	poll_timer.expires = jiffies + POLL_FREQ;
+	add_timer(&poll_timer);
+
+	status = inb_p(ISA_BMC_STATUS);
+	if ((!(status & ISA_SMS_MSG_FLAG)) && ((status & ISA_STATE_MASK) !=ISA_READ_STATE))
+		return;
+	/* Something in the queue */
+	if ((rc = kcs_read_message(&msglen, &data[0]))<0)
+		{
+		printk("ipmi_kcs_poll(): Read Message failed\n");
+		return;
+		}
+	if (!kcs_is_open)
+		return; /* Dont store it if nobody is listening.. */
+	if (add_data_to_ringbuffer(&data[0],msglen)<0)
+		{
+		printk("ipmi_kcs_poll(): ring buffer overflow. Dropping newest frame\n");
+		return;
+		}
+	wake_up_interruptible(&wq);
+}
+
+
+static int kcs_send_message(unsigned char *buf, int length)
+{
+	volatile unsigned char	chipstatus;
+	int 										status;
+	int											i;
+
+	if ((status = wait_while_ibf(ISA_TIMEOUT)) <0)
+		return(-1);
+
+	outb_p(ISA_WRITE_START, ISA_BMC_COMMAND);
+
+	if ((status = wait_while_ibf(ISA_TIMEOUT)) <0)
+		return(-2);
+
+	for (i=0; i <length -1; i++)
+		{
+		chipstatus = inb_p(ISA_BMC_STATUS);
+
+		if (chipstatus & ISA_OBF_FLAG)
+			{
+			printk("[IPMI_KCS] WARNING: Out of Band data flag set\n");
+			printk("[IPMI_KCS] Email nettwerk@valinux.com\n");
+			inb_p(ISA_BMC_DATA_IN);
+			}
+	
+		if ((chipstatus & ISA_STATE_MASK) != ISA_WRITE_STATE)
+			return(-3);
+		outb_p(buf[i], ISA_BMC_DATA_OUT);
+		if ((status = wait_while_ibf(ISA_TIMEOUT)) <0)
+			return(-4);
+		}
+	outb_p(ISA_WRITE_END, ISA_BMC_COMMAND);
+	if ((status = wait_while_ibf(ISA_TIMEOUT)) <0)
+		return(-5);
+	outb_p(buf[i], ISA_BMC_DATA_OUT);
+	if ((status = wait_while_ibf(ISA_TIMEOUT)) <0)
+		return(-6);
+	
+	chipstatus = inb_p(ISA_BMC_STATUS);
+	if ((chipstatus & ISA_STATE_MASK) ==ISA_WRITE_STATE)
+		return (-7);
+	return(0);
+}
+
+static int kcs_read_message(int *msglen, unsigned char *buf)
+{
+	int											i;
+	unsigned char						state;
+	volatile unsigned char	status;
+
+	for (i=0; i < MAX_ISA_LENGTH; i++)
+		{
+		status = inb_p(ISA_BMC_STATUS);
+		while(!(status & ISA_OBF_FLAG))
+			{
+			status = inb_p(ISA_BMC_STATUS);
+			state = (unsigned char) (status & ISA_STATE_MASK);
+
+			if (state == ISA_ERROR_STATE)
+				{
+				printk("kcs_read_message(): BAD ISA state\n");
+				return (-EIO);
+				}
+			else if (state == ISA_IDLE_STATE)
+				{
+				*msglen = i;
+				return(0);
+				}
+			}
+		buf[i] = inb_p(ISA_BMC_DATA_IN);
+		if (wait_while_ibf(ISA_TIMEOUT))
+			{
+			printk("kcs_read_message(): ISA timeout in IBF\n");
+			return(-EIO);
+			}
+		outb_p(ISA_READ, ISA_BMC_DATA_OUT);
+		}
+	printk("kcs_read_message(): ISA Message overflow\n");
+	return (-EIO);
+}
+
+static int wait_while_ibf(int timeout)
+{
+	unsigned int master_timeout=5;
+	unsigned char status_byte;
+
+	status_byte = (inb_p(ISA_BMC_STATUS) & 0xFF);
+	while(status_byte & ISA_IBF_FLAG)
+		{
+		master_timeout--;
+		if (!master_timeout)
+			return(-1);
+		udelay(100);
+		status_byte = (inb_p(ISA_BMC_STATUS) & 0xFF);
+		}
+	return(0);
+}
+
+int ipmi_kcs_init()
+{
+	printk("IPMI KCS driver (San Mehat nettwerk@valinux.com) v0.10 at io 0x%x\n",IO);
+	if (!(buffer = kmalloc(PAGE_SIZE, GFP_KERNEL)))
+		{
+		printk("--Unable to allocate 1 page ring buffer\n");
+		return(-ENOMEM);
+		}
+	printk("--Using %d byte ring buffer for incomming IPMI data\n",PAGE_SIZE);
+	printk("--Polling frequency set to %d ticks\n",POLL_FREQ);
+	request_region(IO, 16, "ipmi_kcs");
+	if ((inb_p(ISA_BMC_STATUS) == 0xFF) &&
+			(inb_p(ISA_BMC_DATA_IN) == 0xFF))
+		{
+		printk("--IPMI ISA window not present. Driver exiting\n");
+		release_region(IO,16);
+		kfree(buffer);
+		return(-ENXIO);
+		}
+	misc_register(&kcs_miscdev);
+	head = tail = 0;
+
+	/* Set up a periodic timer to check if theres unsolicited data to be read */
+	memset(&poll_timer, 0, sizeof(poll_timer));
+	poll_timer.function = ipmi_kcs_poll;
+	poll_timer.expires = jiffies + POLL_FREQ;
+	add_timer(&poll_timer);
+	return(0);
+}
Index: oldkernel/linux/drivers/char/ipmi_kcs.h
diff -u /dev/null linux/drivers/char/ipmi_kcs.h:1.1
--- /dev/null	Mon Jul 31 21:14:41 2000
+++ linux/drivers/char/ipmi_kcs.h	Thu Jun  1 17:01:59 2000
@@ -0,0 +1,96 @@
+/*
+ *  Intelligent Platform Management Interface driver for Linux 2.x
+ *
+ *  (c) Copyright 1999  San Mehat & VA Linux Systems
+ *        1382 Bordeaux Dr.
+ *        Sunnyvale, California
+ *        94089
+ *
+ *  http://www.valinux.com
+ *
+ *  This driver is provided under the GNU public license, incorporated
+ *  herein by reference. The driver is provided without warranty or
+ *  support.
+ *
+ *
+ */
+
+#include <linux/config.h>
+
+#define IO 0xca2
+#define ISA_BMC_STATUS    (IO + 1)
+#define ISA_BMC_COMMAND   (IO + 1)
+#define ISA_BMC_DATA_IN       (IO + 0)
+#define ISA_BMC_DATA_OUT      (IO + 0)
+
+/* State bits based on S1 & S0 below */
+#define ISA_STATE_MASK        0xC0
+#define ISA_IDLE_STATE        0x00
+#define ISA_READ_STATE        0x40
+#define ISA_WRITE_STATE       0x80
+#define ISA_ERROR_STATE       0xC0
+
+/* Status Register Bits */
+#define ISA_S1_FLAG           0x80
+#define ISA_S0_FLAG           0x40
+#define ISA_CD_FLAG           0x08
+#define ISA_SMS_MSG_FLAG      0x04
+#define ISA_IBF_FLAG          0x02
+#define ISA_OBF_FLAG          0x01
+
+/* SMS Transfer Stream Control Codes */
+#define ISA_GET_STATUS_ABORT   0x60
+#define ISA_WRITE_START        0x61
+#define ISA_WRITE_END          0X62
+#define ISA_READ               0X68
+
+#define MAX_ISA_LENGTH  35
+
+#define ISA_TIMEOUT 1000
+
+typedef struct ipmi_ksc_set_watchdog
+	{
+  unsigned char lun               :2;
+  unsigned char netfn             :6;
+
+  unsigned char cmd;
+
+  unsigned char timer_use         :3;
+  unsigned char res1              :4;
+  unsigned char dontlog           :1;
+
+  unsigned char timeout_action    :3;
+  unsigned char res2              :1;
+  unsigned char pre_irq           :3;
+  unsigned char res3              :1;
+
+  unsigned char   pretimeout_interval;
+
+  unsigned char tuefc_res1        :1;
+  unsigned char tuefc_biosfrb2    :1;
+  unsigned char tuefc_biospost    :1;
+  unsigned char tuefc_osload      :1;
+  unsigned char tuefc_smsos       :1;
+  unsigned char tuefc_oem         :1;
+  unsigned char tuefc_res2        :1;
+  unsigned char tuefc_res3        :1;
+
+  unsigned short initial_count;
+  } IPMI_KCS_SET_WATCHDOG;
+
+typedef struct ipmi_ksc_reset_watchdog
+  {
+  unsigned char lun               :2;
+  unsigned char netfn             :6;
+
+  unsigned char cmd;
+  } IPMI_KCS_RESET_WATCHDOG;
+
+typedef struct sensor_cmd
+  {
+  unsigned char lun               :2;
+  unsigned char netfn             :6;
+
+  unsigned char cmd;
+  unsigned char sensor_number;
+  } SENSOR_CMD;
Index: oldkernel/linux/include/linux/ipmi_kcs_ioctls.h
diff -u /dev/null linux/include/linux/ipmi_kcs_ioctls.h:1.1
--- /dev/null	Mon Jul 31 21:14:42 2000
+++ linux/include/linux/ipmi_kcs_ioctls.h	Thu Jun  1 17:01:59 2000
@@ -0,0 +1,39 @@
+/*
+ *  Intelligent Platform Management Interface driver for Linux 2.x
+ *
+ *  (c) Copyright 1999  San Mehat & VA Linux Systems
+ *        1382 Bordeaux Dr.
+ *        Sunnyvale, California
+ *        94089
+ *
+ *  http://www.valinux.com
+ *
+ *  This driver is provided under the GNU public license, incorporated
+ *  herein by reference. The driver is provided without warranty or
+ *  support.
+ *
+ *  IOCTL definitions for IPMI KCS driver
+ */
+
+#ifndef _IPMI_KCS_IOCTLS_H
+#define _IPMI_KCS_IOCTLS_H
+
+	
+#define	IOCTL_WATCHDOG_SET					0x01
+	#define WATCHDOG_ACTION_REBOOT	0x01
+	#define WATCHDOG_ACTION_NMI			0x02
+
+#define IOCTL_WATCHDOG_PING					0x02
+
+#define IOCTL_PANEL_LED_SET_BLINK		0x03
+	#define PANEL_LED_NORMAL						0x00
+	#define PANEL_LED_BLINK							0x01
+
+#define IOCTL_READ_SENSOR						0x04
+struct sensor_request
+	{
+	unsigned char sensor_number;
+	unsigned char	result_buffer[64];
+	int						result_length;
+	};
+#endif
Index: oldkernel/linux/include/linux/miscdevice.h
diff -u linux/include/linux/miscdevice.h:1.1.1.1 linux/include/linux/miscdevice.h:1.2
--- linux/include/linux/miscdevice.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/miscdevice.h	Thu Jun  1 17:01:59 2000
@@ -18,6 +18,7 @@
 #define NVRAM_MINOR 144
 #define I2O_MINOR 166
 #define MISC_DYNAMIC_MINOR 255
+#define IPMI_KCS_MINOR  173
 
 #define SGI_GRAPHICS_MINOR   146
 #define SGI_OPENGL_MINOR     147
