--- linux-2.4.2-virgin/drivers/char/misc.c	Sun Apr  8 18:22:17 2001
+++ linux-bmc/drivers/char/misc.c	Tue Oct 30 17:18:07 2001
@@ -273,6 +273,9 @@
 #ifdef CONFIG_TOSHIBA
 	tosh_init();
 #endif
+#ifdef CONFIG_IPMI_KCS
+	ipmi_kcs_init();
+#endif
 	if (devfs_register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
 		printk("unable to get major %d for misc devices\n",
 		       MISC_MAJOR);
--- linux-2.4.2-virgin/drivers/char/Config.in	Sun Apr  8 18:22:22 2001
+++ linux-bmc/drivers/char/Config.in	Tue Oct 30 17:18:07 2001
@@ -81,6 +81,11 @@
    dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
 fi
 
+tristate 'IPMI KCS Interface' CONFIG_IPMI_KCS
+if [ "$CONFIG_IPMI_KCS" != "n" ]; then
+   bool '  BMC watchdog timer support' CONFIG_BMC_WDT
+fi
+
 source drivers/i2c/Config.in
 
 source drivers/sensors/Config.in
--- linux-2.4.2-virgin/drivers/char/Makefile	Sun Apr  8 18:22:17 2001
+++ linux-bmc/drivers/char/Makefile	Tue Oct 30 17:18:08 2001
@@ -191,6 +191,8 @@
 obj-$(CONFIG_NWBUTTON) += nwbutton.o
 obj-$(CONFIG_NWFLASH) += nwflash.o
 
+obj-$(CONFIG_IPMI_KCS) += ipmi_kcs.o
+
 # Only one watchdog can succeed. We probe the hardware watchdog
 # drivers first, then the softdog driver.  This means if your hardware
 # watchdog dies or is 'borrowed' for some reason the software watchdog
--- linux-2.4.2-virgin/include/linux/miscdevice.h	Sun Apr  8 18:47:26 2001
+++ linux-bmc/include/linux/miscdevice.h	Tue Oct 30 17:32:42 2001
@@ -31,6 +31,9 @@
 #define SGI_STREAMS_KEYBOARD 150
 /* drivers/sgi/char/usema.c */
 #define SGI_USEMACLONE	     151
+#define IPMI_KCS_MINOR       173
+#define IPMI_BT_MINOR        210
+#define IPMI_SMIC_MINOR      211
 
 #define TUN_MINOR	     200
 
--- /dev/null	Fri Mar 23 23:37:44 2001
+++ linux-bmc/drivers/char/ipmi_kcs.c	Tue Oct 30 17:18:07 2001
@@ -0,0 +1,1211 @@
+/*
+ *  Intelligent Platform Management Interface driver for Linux 2.2.x
+ *
+ *  (c) Copyright 2000 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.
+ *
+ *  Release 0.12.   - Added Intel Nightshade MB fixups since NS boards don't
+ *                    support pre-timeout NMI support
+ *                  - FRU download support added
+ *                  - /proc/ipmi created with fru data and driver status
+ *  Release 0.13.   - Added ioctl for setting asset tag
+ *                  - Fixed bug in /proc
+ *                  - Added asset tag max length field
+ *  Release 1.00    - Added intelligent proc reading so that asset tag is
+ *                    refreshed whenever /proc/ipmi is read
+ *                  - Code cleanup
+ *                  - When asset tag is set with data whoes size is < maximum,
+ *                    pad the rest out with NULLs
+ *  Release 1.10    - Fixed SMP bug which was causing command failures when
+ *                    /proc/ipmi was being read while a command was being 
+ *                    executed (added semaphore)
+ *                  - Fixed /proc/ipmi so commands only get issued once
+ *  Release 1.20    - Removed a bunch of useless warning msgs
+ *  Release 1.30    - Added more stringent error checking when ISA state
+ *                    enters ERROR_STATE
+ *                  - Added better unexpected OBF handling on transactions
+ *                  - Explicitly set power sensor state to NO BLINKY on 
+ *                    startup
+ *  Release 2.0     - Re-wrote kcs state machine
+ *                  - Removed high level functions from driver
+ *                  - removed driver read() and write() capabilities
+ *                  - /proc/ipmi renamed to /proc/ipmi_kcs
+ *                  - /proc/ipmi_kcs now contains only BMC info
+ *                    
+ *  Release 2.1     - Added support of watchdog timer through /dev/watchdog
+ *  
+ */
+
+#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/smp_lock.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 <asm/semaphore.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/ipmi_ioctls.h>
+#include <linux/pci.h>
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+
+#ifdef CONFIG_BMC_WDT
+#include <linux/watchdog.h>
+#endif
+
+/* function prototypes */
+
+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);
+
+#ifdef CONFIG_BMC_WDT
+static int wdt_is_open;
+static int watchdog_set(int cmd);
+static int watchdog_reset(void);
+static int wdt_open(struct inode *inode, struct file *file);
+static int wdt_release(struct inode *inode, struct file *file);
+static ssize_t wdt_write(struct file *file, const char *buf, size_t count,
+			 loff_t * ppos);
+static int wdt_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg);
+
+static struct file_operations wdt_fops = {
+	owner:THIS_MODULE,
+	write:wdt_write,
+	ioctl:wdt_ioctl,
+	open:wdt_open,
+	release:wdt_release,
+};
+
+static struct miscdevice wdt_miscdev = {
+	WATCHDOG_MINOR,
+	"bmc_wdt",
+	&wdt_fops
+};
+
+/* module parameters */
+static int wdt_margin = 60;	/* watchdog timer interval in seconds */
+static int wdt_pre = 1;	/* watchdog pre-timeout interval in seconds */
+static int wdt_action = 0x03;	/* Default is no pre-timeout interrupt and power cycle upon timeout */
+
+MODULE_PARM(wdt_margin, "i");
+MODULE_PARM(wdt_pre, "i");
+MODULE_PARM(wdt_action, "i");
+
+#define WATCHDOG_ENABLE		0x01
+#define WATCHDOG_DISABLE	0x02
+#endif
+
+static unsigned char get_kcs_state(void);
+static unsigned char read_kcs_data(void);
+static void write_kcs_data(unsigned char data);
+static void write_kcs_cmd(unsigned char cmd);
+static int is_obf_set(void);
+static int clear_obf(void);
+static int wait_while_ibf(void);
+static int get_deviceid(void);
+static int kcs_do_xfer(BMC_REQUEST * request, int request_len,
+		       BMC_RESPONSE * response, int *response_len);
+static int old_kcs_do_xfer(BMC_REQUEST * request, int request_len,
+			   BMC_RESPONSE * response, int *response_len);
+static int new_kcs_do_xfer(BMC_REQUEST * request, int request_len,
+			   BMC_RESPONSE * response, int *response_len);
+
+#ifdef CONFIG_PROC_FS
+int ipmi_get_info(char *buf, char **start, off_t fpos, int length,
+		  int *eof, void *unused);
+#endif
+
+/* static globals */
+static int kcs_refcnt = 0;
+static int driver_major = 2;
+static int driver_minor = 1;
+static int kcs_machine = 0;
+
+static struct {
+	unsigned int tx_good;
+	unsigned int tx_bad;
+} kcs_stat;
+
+static DEVICE_ID_RESPONSE dev_id;
+DECLARE_MUTEX(kcs_sem);
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *ipmi_proc_entry;
+#endif
+
+static struct file_operations kcs_fops = {
+	owner:THIS_MODULE,
+	write:kcs_write,
+	ioctl:kcs_ioctl,
+	open:kcs_open,
+	release:kcs_release,
+	read:kcs_read,
+};
+
+static struct miscdevice kcs_miscdev = {
+	IPMI_KCS_MINOR,
+	"ipmi_kcs",
+	&kcs_fops
+};
+
+static struct ipmi_driver_info drv_inf;
+
+/***************/
+
+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)
+{
+	return (-ENOSYS);
+}
+
+static ssize_t kcs_read(struct file *file, char *buf, size_t count,
+			loff_t * ptr)
+{
+	return (-ENOSYS);
+}
+
+static int kcs_ioctl(struct inode *inode,
+		     struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+	case IOCTL_IPMI_XFER:
+		{
+			IPMI_XFER user_buffer;
+			int rc;
+			int response_len = sizeof(user_buffer.response);
+
+			if (!arg)
+				return (-EFAULT);
+			if (copy_from_user
+			    ((void *) &user_buffer, (void *) arg,
+			     sizeof(IPMI_XFER)))
+				return (-EFAULT);
+			if ((user_buffer.request_len < 2)
+			    || (user_buffer.response_len < 3))
+				return (-EINVAL);
+
+			rc = kcs_do_xfer((BMC_REQUEST *) & user_buffer.
+					 request, user_buffer.request_len,
+					 (BMC_RESPONSE *) & user_buffer.
+					 response, &response_len);
+			user_buffer.response_len = response_len;
+			copy_to_user((void *) arg, (void *) &user_buffer,
+				     sizeof(IPMI_XFER));
+			return (rc);
+		}
+	case IOCTL_DRIVER_INFO:
+		{
+			struct ipmi_driver_info user_buffer;
+
+			if (!arg)
+				return (-EFAULT);
+			if (copy_from_user
+			    ((void *) &user_buffer, (void *) arg,
+			     sizeof(user_buffer)))
+				return (-EFAULT);
+			copy_to_user((void *) arg, (void *) &drv_inf,
+				     sizeof(drv_inf));
+			return (0);
+		}
+	default:
+		return -EINVAL;
+	}
+	return (0);
+}
+
+static int get_deviceid()
+{
+	unsigned char request_buffer[MAX_BUFFER_SIZE];
+	unsigned char response_buffer[MAX_BUFFER_SIZE];
+	BMC_REQUEST *bmc_req;
+	BMC_RESPONSE *bmc_resp;
+	int rc, response_len;
+
+	memset(&dev_id, 0, sizeof(DEVICE_ID_RESPONSE));
+	memset(request_buffer, 0, sizeof(request_buffer));
+	memset(response_buffer, 0, sizeof(response_buffer));
+	bmc_req = (BMC_REQUEST *) request_buffer;
+	bmc_resp = (BMC_RESPONSE *) response_buffer;
+	response_len = sizeof(response_buffer);
+
+	bmc_req->lun = 0;
+	bmc_req->netfn = APP_REQUEST;
+	bmc_req->cmd = 0x01;	/* GET_DEVICE_ID */
+
+#if defined(__ia64__)
+	rc = new_kcs_do_xfer(bmc_req, 2, bmc_resp, &response_len);
+#else
+	rc = old_kcs_do_xfer(bmc_req, 2, bmc_resp, &response_len);
+#endif
+	if (bmc_resp->cc != 0x00) {
+		printk("[IPMI_KCS] get_deviceid() failed (0x%.2x)\n",
+		       bmc_resp->cc);
+		return (-EIO);
+	}
+	memcpy(&dev_id, bmc_resp->data, sizeof(DEVICE_ID_RESPONSE));
+	return (0);
+}
+
+static int kcs_open(struct inode *inode, struct file *file)
+{
+	switch (MINOR(inode->i_rdev)) {
+	case IPMI_KCS_MINOR:
+		{
+			MOD_INC_USE_COUNT;
+			kcs_refcnt++;
+			return 0;
+		}
+	default:
+		return -ENODEV;
+	}
+}
+
+static int kcs_release(struct inode *inode, struct file *file)
+{
+	if (MINOR(inode->i_rdev) == IPMI_KCS_MINOR) {
+		kcs_refcnt--;
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+#ifdef CONFIG_BMC_WDT
+static ssize_t wdt_write(struct file *file, const char *buf, size_t count,
+			 loff_t * ppos)
+{
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	/*
+	 * Stop and then restart the watchdog timer.
+	 */
+	if (count) {
+		if (watchdog_set(WATCHDOG_DISABLE))
+			return -EIO;
+		if (watchdog_set(WATCHDOG_ENABLE))
+			return -EIO;
+		if (watchdog_reset())
+			return -EIO;
+		return 1;
+	}
+	return 0;
+}
+
+static int wdt_ioctl(struct inode *inode,
+		     struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	static struct watchdog_info ident = {
+		WDIOF_KEEPALIVEPING, 1, "BMC WDT"
+	};
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		if (copy_to_user
+		    ((struct watchdog_info *) arg, &ident, sizeof(ident)))
+			return -EFAULT;
+		break;
+
+	case WDIOC_GETSTATUS:
+		if (copy_to_user((int *) arg, &wdt_is_open, sizeof(int)))
+			return -EFAULT;
+		break;
+
+	case WDIOC_KEEPALIVE:
+		if (watchdog_set(WATCHDOG_DISABLE))
+			return -EIO;
+		if (watchdog_set(WATCHDOG_ENABLE))
+			return -EIO;
+		if (watchdog_reset())
+			return -EIO;
+		break;
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static int watchdog_set(int cmd)
+{
+	unsigned char request_buffer[MAX_BUFFER_SIZE];
+	unsigned char response_buffer[MAX_BUFFER_SIZE];
+	BMC_REQUEST *bmc_req;
+	BMC_RESPONSE *bmc_resp;
+	int rc, response_len;
+	SET_WATCHDOG *set;
+	int fixup = 0;
+
+	memset(request_buffer, 0, sizeof(request_buffer));
+	memset(response_buffer, 0, sizeof(response_buffer));
+	bmc_req = (BMC_REQUEST *) request_buffer;
+	bmc_resp = (BMC_RESPONSE *) response_buffer;
+	response_len = sizeof(response_buffer);
+
+	bmc_req->lun = 0;
+	bmc_req->netfn = APP_REQUEST;
+	bmc_req->cmd = 0x24;	/* Set Watchdog Timer */
+
+	set = (SET_WATCHDOG *) bmc_req->data;
+
+	while (1) {
+		set->timer_use = 0x04;
+
+		set->timeout_action = wdt_action & 0x0F;
+		set->pre_irq = (wdt_action >> 4) & 0x0F;
+
+		if (cmd == WATCHDOG_DISABLE) {
+			set->timeout_action = 0x00;
+			set->pre_irq = 0x00;
+		}
+		set->pretimeout_interval = wdt_pre;
+
+		if (fixup) {
+			set->pre_irq = 0x00;
+			set->pretimeout_interval = 0;
+		}
+
+		set->tuefc_biosfrb2 = 0x00;
+		set->tuefc_biospost = 0x0;
+		set->tuefc_osload = 0x00;
+		set->tuefc_smsos = 0x01;
+		set->initial_count = wdt_margin * 10;
+
+		rc = kcs_do_xfer(bmc_req, 2 + sizeof(SET_WATCHDOG),
+				 bmc_resp, &response_len);
+
+		if (bmc_resp->cc == 0xcc) {
+			fixup++;
+			if (fixup == 2) {
+				printk
+				    ("[IPMI_KCS] Flakey NMI fixup failed\n");
+				return (-EIO);
+			}
+			printk("[IPMI_KCS] Flakey NMI fixup enabled\n");
+			continue;
+		} else if (bmc_resp->cc != 0x00) {
+			printk
+			    ("[IPMI_KCS] Set watchdog timer failed (rc = 0x%.2x)\n",
+			     bmc_resp->cc);
+			return (-EIO);
+		}
+		break;
+	}
+	return (0);
+}
+
+static int watchdog_reset()
+{
+	unsigned char request_buffer[MAX_BUFFER_SIZE];
+	unsigned char response_buffer[MAX_BUFFER_SIZE];
+	BMC_REQUEST *bmc_req;
+	BMC_RESPONSE *bmc_resp;
+	int rc, response_len;
+
+	memset(request_buffer, 0, sizeof(request_buffer));
+	memset(response_buffer, 0, sizeof(response_buffer));
+	bmc_req = (BMC_REQUEST *) request_buffer;
+	bmc_resp = (BMC_RESPONSE *) response_buffer;
+	response_len = sizeof(response_buffer);
+
+	bmc_req->lun = 0;
+	bmc_req->netfn = APP_REQUEST;
+	bmc_req->cmd = 0x22;	/* Reset Watchdog Timer */
+
+	rc = kcs_do_xfer(bmc_req, 2, bmc_resp, &response_len);
+	if (bmc_resp->cc != 0x00) {
+		printk("[IPMI_KCS] Reset Watchdog Timer failed (0x%.2x)\n",
+		       bmc_resp->cc);
+		return (-EIO);
+	}
+	return (0);
+}
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+	switch (MINOR(inode->i_rdev)) {
+	case WATCHDOG_MINOR:
+		if (wdt_is_open)
+			return -EBUSY;
+
+		MOD_INC_USE_COUNT;
+		/*
+		 * Activate 
+		 */
+		wdt_is_open = 1;
+		if (watchdog_reset())
+			return -EIO;
+		return 0;
+	default:
+		return -ENODEV;
+	}
+}
+
+static int wdt_release(struct inode *inode, struct file *file)
+{
+	lock_kernel();
+	if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+		if (watchdog_set(WATCHDOG_DISABLE))
+			return -EIO;
+#endif
+		wdt_is_open = 0;
+		MOD_DEC_USE_COUNT;
+	}
+	unlock_kernel();
+	return 0;
+}
+
+/*
+ *	Notifier for system down
+ */
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+			  void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT) {
+		/* Turn the timer off */
+		watchdog_set(WATCHDOG_DISABLE);
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ *	The BMC needs to learn about soft shutdowns in order to
+ *	turn the watchdog timer off. 
+ */
+
+static struct notifier_block wdt_notifier = {
+	wdt_notify_sys,
+	NULL,
+	0
+};
+#endif
+
+#ifdef MODULE
+int init_module(void)
+{
+	return (ipmi_kcs_init());
+}
+
+void cleanup_module(void)
+{
+	printk("[IPMI_KCS] Driver shutting down.\n");
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("ipmi_kcs", 0);
+#endif
+	misc_deregister(&kcs_miscdev);
+#ifdef CONFIG_BMC_WDT
+	misc_deregister(&wdt_miscdev);
+	unregister_reboot_notifier(&wdt_notifier);
+#endif
+	release_region(KCS_BASE, 16);
+}
+#endif
+
+int ipmi_kcs_init()
+{
+	printk
+	    ("IPMI KCS driver (San Mehat nettwerk@valinux.com) v%d.%d at io 0x%x\n",
+	     driver_major, driver_minor, KCS_BASE);
+	request_region(KCS_BASE, 16, "ipmi_kcs");
+	if ((inb_p(KCS_STATUS_REG) == 0xFF) &&
+	    (inb_p(KCS_DATAIN_REG) == 0xFF)) {
+		printk("--KCS ISA window not present. Driver exiting\n");
+		release_region(KCS_BASE, 16);
+		return (-ENXIO);
+	}
+
+	kcs_stat.tx_good = 0;
+	kcs_stat.tx_bad = 0;
+	memset(&drv_inf, 0, sizeof(drv_inf));
+	strcpy(drv_inf.driver_name, "ipmi_kcs");
+	drv_inf.major_ver = driver_major;
+	drv_inf.minor_ver = driver_minor;
+
+	misc_register(&kcs_miscdev);
+#ifdef CONFIG_BMC_WDT
+	misc_register(&wdt_miscdev);
+	register_reboot_notifier(&wdt_notifier);
+#endif
+	get_deviceid();
+	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_machine = KCS_LEGACY;
+		drv_inf.flags |= KCS_FLAG_LEGACY;
+	} else {
+		printk("--Using new KCS state machine\n");
+		kcs_machine = KCS_NEW;
+	}
+	if (!pci_present()) {
+		printk
+		    ("--PCIBIOS not present. Unable to determine chipset vendor\n");
+		drv_inf.flags |= KCS_FLAG_BLINKY;
+	} else {
+		int pci_index = 0;
+		unsigned char pci_bus, pci_device_fn;
+		unsigned short vendor, device;
+
+		for (; pci_index < 0xff; pci_index++) {
+			if (pcibios_find_class(PCI_CLASS_BRIDGE_HOST << 8,
+					       pci_index,
+					       &pci_bus,
+					       &pci_device_fn) !=
+			    PCIBIOS_SUCCESSFUL) {
+				break;
+			}
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+						 PCI_VENDOR_ID, &vendor);
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+						 PCI_DEVICE_ID, &device);
+			drv_inf.mb_chipset_vendor = vendor;
+			drv_inf.mb_chipset_device = device;
+			printk
+			    ("--Motherboard Chipset vendor 0x%.4x, device 0x%.4x\n",
+			     vendor, device);
+			if ((vendor == 0x8086) && (device == 0x71a0)) {
+				drv_inf.flags |= KCS_FLAG_BLINKY;
+			}
+		}
+	}
+	if (drv_inf.flags & KCS_FLAG_BLINKY) {
+		printk("--Intel Lancewood features enabled\n");
+	} else
+		printk("--No vendor specific features enabled\n");
+#ifdef CONFIG_PROC_FS
+	if (!(ipmi_proc_entry = create_proc_entry("ipmi_kcs", 0, 0)))
+		printk(KERN_ERR,
+		       "--ERROR: Unable to register /proc/ipmi_kcs\n");
+	else
+		ipmi_proc_entry->read_proc = ipmi_get_info;
+
+#endif
+	return (0);
+}
+
+static int kcs_do_xfer(BMC_REQUEST * request,
+		       int request_len,
+		       BMC_RESPONSE * response, int *response_len)
+{
+	int rc = 0;
+
+	down(&kcs_sem);
+	switch (kcs_machine) {
+	case KCS_LEGACY:
+		{
+			rc = old_kcs_do_xfer(request, request_len,
+					     response, response_len);
+			break;
+		}
+	case KCS_NEW:
+		{
+			rc = new_kcs_do_xfer(request, request_len,
+					     response, response_len);
+			break;
+		}
+	default:
+		{
+			printk
+			    ("[IPMI_KCS] Undefined or bad KCS state machine selected (%d)\n",
+			     kcs_machine);
+			get_deviceid();
+			if ((dev_id.ipmi_version_major == 0) &&
+			    (dev_id.ipmi_version_minor == 9)) {
+				printk
+				    ("Recalibrated to use legacy KCS state machine\n");
+				kcs_machine = KCS_LEGACY;
+			} else {
+				printk
+				    ("Recalibrated to use new KCS state machine\n");
+				kcs_machine = KCS_NEW;
+			}
+			rc = -EAGAIN;
+			break;
+		}
+	}
+	if (rc == 0)
+		kcs_stat.tx_good++;
+	else
+		kcs_stat.tx_bad++;
+	up(&kcs_sem);
+	return (rc);
+}
+
+static int new_kcs_do_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_KCS] Maximum retries exceeded. Aborting transfer\n");
+			rc = -EIO;
+			break;
+		}
+		switch (state) {
+		case SEND_INIT:
+			{
+				i = 0;
+				state = SEND_START;
+				wait_while_ibf();
+				if (clear_obf() != 0) {
+					state = ERROR;
+					break;
+				}
+			}
+		case SEND_START:
+			{
+				state = SEND_NEXT;
+				write_kcs_cmd(WRITE_START);
+				wait_while_ibf();
+				if (get_kcs_state() != KCS_WRITE_STATE) {
+					state = ERROR;
+					break;
+				}
+			}
+		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 (get_kcs_state() != KCS_WRITE_STATE) {
+					state = ERROR;
+					break;
+				}
+				if (clear_obf() != 0) {
+					state = ERROR;
+					break;
+				}
+				break;
+			}
+		case SEND_END:
+			{
+				write_kcs_cmd(WRITE_END);
+				wait_while_ibf();
+				if (get_kcs_state() != KCS_WRITE_STATE) {
+					state = ERROR;
+					break;
+				}
+				if (clear_obf() != 0) {
+					state = ERROR;
+					break;
+				}
+				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();
+				write_kcs_data(KCS_READ);
+				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 (wait_until_obf() == 0) {
+							clear_obf();
+							state = RECV_END;
+							break;
+						} else {
+							state = ERROR;
+							break;
+						}
+					}
+				case KCS_READ_STATE:
+					{
+						if (wait_until_obf() == 0)
+							state = RECV_NEXT;
+						else
+							state = ERROR;
+						break;
+					}
+				}
+				break;
+			}
+		case RECV_END:
+			{
+				if ((i < MIN_BMC_RESPONSE_SIZE) ||
+				    (response->netfn !=
+				     (request->netfn | 0x01))
+				    || (response->cmd != request->cmd)) {
+					mdelay(BMC_RETRY_DELAY);
+					bad++;
+					state = SEND_INIT;
+					printk
+					    ("[IPMI_KCS] Request/Response CMD/NETFN mismatch error\n");
+
+					printk
+					    ("           RQcmd/RQnetfn=0x%x/0x%x,RScmd/RSnetfn=0x%x/0x%x\n",
+					     request->cmd, request->netfn,
+					     response->cmd,
+					     response->netfn);
+					break;
+				}
+
+				*response_len = i;
+				rc = 0;
+				state = END;
+				break;
+			}
+		case ERROR:
+		default:
+			{
+				printk
+				    ("[IPMI_KCS] BMC in bad state. Retrying transfer\n");
+				mdelay(BMC_RETRY_DELAY);
+				bad++;
+				state = SEND_INIT;
+				break;
+			}
+		}
+	}
+	return (rc);
+}
+
+static int old_kcs_do_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_KCS] Maximum retries exceeded. Aborting transfer\n");
+			rc = -EIO;
+			break;
+		}
+		switch (state) {
+		case SEND_INIT:
+			{
+				i = 0;
+				state = SEND_START;
+				wait_while_ibf();
+			}
+		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();
+				break;
+			}
+		case SEND_END:
+			{
+				wait_while_ibf();
+				write_kcs_cmd(WRITE_END);
+				wait_while_ibf();
+				if (get_kcs_state() != KCS_WRITE_STATE) {
+					state = ERROR;
+					break;
+				}
+				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();
+				wait_while_ibf();
+				write_kcs_data(KCS_READ);
+				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:
+					{
+						state = RECV_END;
+						break;
+					}
+				case KCS_READ_STATE:
+					{
+						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)) {
+					mdelay(BMC_RETRY_DELAY);
+					bad++;
+					state = SEND_INIT;
+					printk
+					    ("[IPMI_KCS] Request/Response CMD/NETFN mismatch error\n");
+
+					printk
+					    ("           RQcmd/RQnetfn=0x%x/0x%x,RScmd/RSnetfn=0x%x/0x%x\n",
+					     request->cmd, request->netfn,
+					     response->cmd,
+					     response->netfn);
+					break;
+				}
+
+				*response_len = i;
+				rc = 0;
+				state = END;
+				break;
+			}
+		case ERROR:
+		default:
+			{
+				printk
+				    ("[IPMI_KCS] BMC in bad state. Retrying transfer\n");
+				mdelay(BMC_RETRY_DELAY);
+				bad++;
+				state = SEND_INIT;
+				break;
+			}
+		}
+	}
+	return (rc);
+}
+
+#ifdef CONFIG_PROC_FS
+int ipmi_get_info(char *buf, char **start, off_t fpos, int length,
+		  int *eof, void *unused)
+{
+	char *p;
+
+	if (get_deviceid() != 0) {
+		printk("[IPMI_KCS] Unable to get device ID\n");
+		memset(&dev_id, 0, sizeof(dev_id));
+	}
+
+	p = buf;
+	p += sprintf(p, "Driver Version\t: %d.%d\n",
+		     driver_major, driver_minor);
+	p += sprintf(p, "BMC Version\t: %x.%x\n",
+		     dev_id.major_firmware_revision,
+		     dev_id.minor_firmware_revision);
+	p += sprintf(p, "IPMI Version\t: %d.%d\n",
+		     dev_id.ipmi_version_major, dev_id.ipmi_version_minor);
+	p += sprintf(p, "\nTotal Good Transactions\t: %d\n",
+		     kcs_stat.tx_good);
+	p += sprintf(p, "Total Bad Transactions\t: %d\n", kcs_stat.tx_bad);
+
+	return p - buf;
+}
+#endif
+
+/*
+ * kcs chip mashing stuff
+ */
+static int wait_while_ibf()
+{
+	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 wait_until_obf()
+{
+	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()
+{
+	unsigned char cs;
+
+	cs = inb_p(KCS_STATUS_REG);
+	return (cs & KCS_STATE_MASK);
+}
+
+static unsigned char read_kcs_data()
+{
+	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 is_obf_set()
+{
+	unsigned char cs;
+
+	cs = inb_p(KCS_STATUS_REG);
+	return ((cs & KCS_OBF) == KCS_OBF);
+}
+
+static int clear_obf()
+{
+	read_kcs_data();
+	return (0);
+}
--- /dev/null	Fri Mar 23 23:37:44 2001
+++ linux-bmc/drivers/char/ipmi_kcs.h	Tue Oct 30 17:18:07 2001
@@ -0,0 +1,171 @@
+/*
+ *  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 KCS_LEGACY			1
+#define KCS_NEW				2
+
+#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 */
+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;
+
+typedef struct set_watchdog
+  {
+  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;
+  } SET_WATCHDOG;
+ 
+typedef struct get_watchdog_response
+  {
+  unsigned char timer_use    :3;
+  unsigned char res1         :3;
+  unsigned char timer_status :1;
+  unsigned char sel_log      :1;
+
+  unsigned char timeout_act  :3;
+  unsigned char res2         :1;
+  unsigned char pre_irq_act  :3;
+  unsigned char res3         :1;
+
+  unsigned char pre_timeout __attribute__ ((packed));
+
+  unsigned char timer_use_xp  __attribute__ ((packed));
+
+  unsigned short init_count  __attribute__ ((packed));
+  unsigned short current_count __attribute__ ((packed));
+  } GET_WATCHDOG_RESPONSE;
--- /dev/null	Fri Mar 23 23:37:44 2001
+++ linux-bmc/include/linux/ipmi_ioctls.h	Tue Oct 30 17:18:07 2001
@@ -0,0 +1,152 @@
+/*
+ *  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 drivers
+ */
+
+/*
+ * Note: The following macros should be used on the IPMI_XFER structure.
+ *       DO NOT try to muck with this structure directly.. use the macros
+ *       to ensure future compatibility:
+ *
+ *  INIT_XFER(IPMI_XFER *);  
+ *    -- Zero out a IPMI_XFER structure and initialize it for use
+ *
+ *  SET_REQUEST_LUN(IPMI_XFER *, unsigned char lun);
+ *    -- Set the request packet logical unit
+ *
+ *  SET_REQUEST_NETFN(IPMI_XFER *, unsigned char netfn);
+ *    -- Set the request packet network function code
+ *
+ *  SET_REQUEST_CMD(IPMI_XFER *, unsigned char cmd);
+ *    -- Set the request packet IPMI command code
+ *
+ *  SET_REQUEST_DATA(IPMI_XFER *, unsigned char *data, int length);
+ *    -- Set the request packet optional argument data field
+ * 
+ *  GET_RESPONSE_LUN(IPMI_XFER *, unsigned char lun);
+ *    -- Get the response packet logical unit
+ *
+ *  GET_RESPONSE_NETFN(IPMI_XFER *, unsigned char netfn);
+ *    -- Get the response packet network function code
+ * 
+ *  GET_RESPONSE_CMD(IPMI_XFER *, unsigned char cmd);
+ *    -- Get the response packet command
+ *
+ *  GET_RESPONSE_CC(IPMI_XFER *, unsigned char cc);
+ *    -- Get the response packet completion code
+ * 
+ *  GET_RESPONSE_DATA_LENGTH(IPMI_XFER *, int len);
+ *    -- Get the response packet data length
+ * 
+ *  GET_RESPONSE_DATA(IPMI_XFER *, unsigned char *buffer);
+ *    -- Copy the response packet data into local buffer
+ */
+
+#ifndef _IPMI_IOCTLS_H
+#define _IPMI_IOCTLS_H
+
+#define	IOCTL_IPMI_XFER		0x01
+#define	IOCTL_DRIVER_INFO	0x02
+
+typedef struct ipmi_xfer
+	{
+	unsigned char	request[64];
+	unsigned char	response[64];
+	int						request_len;
+	int						response_len;
+	} IPMI_XFER;
+
+struct ipmi_driver_info
+	{
+	char						driver_name[64];			/* Name of the driver */
+	int							major_ver;					
+	int							minor_ver;
+	unsigned short	mb_chipset_vendor;		/* PCI host bridge vendor tag */
+	unsigned short	mb_chipset_device;		/* PCI host bridge vendor device id */
+	unsigned int		flags;								/* driver specific flags */
+	unsigned int		reserved;
+	};
+
+/* flags definitions for the 'ipmi_kcs' driver */
+#define KCS_FLAG_BLINKY	0x01	/* Set if blinky works (only on Intel L440GX) */
+#define KCS_FLAG_LEGACY	0x02  /* Set if using legacy KCS interface ( < IPMI 1.0) */
+
+#define INIT_XFER(_xferp) \
+	memset(_xferp, 0, sizeof(IPMI_XFER)); \
+	_xferp->request_len = 2; \
+	_xferp->response_len = sizeof(_xferp->response);
+
+#define SET_REQUEST_LUN(_xferp, _lun) \
+	{ \
+	unsigned char _netfn_copy; \
+	\
+	_netfn_copy = (_xferp->request[0] & 0xFC); \
+	_xferp->request[0] = _lun; \
+	_xferp->request[0]|= _netfn_copy; \
+	}
+
+#define SET_REQUEST_NETFN(_xferp, netfn) \
+	{ \
+	unsigned char __lun_copy; \
+	\
+	__lun_copy = (_xferp->request[0] & 0x3); \
+	_xferp->request[0] = (netfn << 2); \
+	_xferp->request[0]|= __lun_copy; \
+	}
+
+#define SET_REQUEST_CMD(_xferp, _cmd) \
+	_xferp->request[1] = _cmd;
+
+#define SET_REQUEST_DATA(_xferp, datap, _len) \
+	{ \
+	memcpy(&_xferp->request[2], datap, _len); \
+	_xferp->request_len = (_len + 2); \
+	}
+
+#define GET_RESPONSE_LUN(_xferp, _lun) \
+	_lun = (_xferp->response[0] & 0x3);
+
+#define GET_RESPONSE_NETFN(_xferp, netfn) \
+	netfn = ((_xferp->response[0] & 0xFC) >> 2);
+
+#define GET_RESPONSE_CMD(_xferp, _cmd) \
+	_cmd = _xferp->response[1];
+
+#define GET_RESPONSE_CC(_xferp, cc) \
+	cc = _xferp->response[2];
+
+#define GET_RESPONSE_DATA_LENGTH(_xferp, _len) \
+	_len = (_xferp->response_len - 3);
+
+#define GET_RESPONSE_DATA(_xferp, datap) \
+	memcpy(datap, &_xferp->response[3], (_xferp->response_len -3));
+
+/*
+ * The Netfn codes
+ */
+#define CHASSIS_REQUEST   0x00
+#define CHASSIS_RESPONSE  0x01
+#define BRIDGE_REQUEST    0x02
+#define BRIDGE_RESPONSE   0x03
+#define SENSOR_REQUEST    0x04
+#define SENSOR_RESPONSE   0x05
+#define APP_REQUEST       0x06
+#define APP_RESPONSE      0x07
+#define FIRMWARE_REQUEST  0x08
+#define FIRMWARE_RESPONSE 0x09
+#define STORAGE_REQUEST   0x0A
+#define STORAGE_RESPONSE  0x0B
+
+#endif