diff -urpNX ../dontdiff linux-ia64/Documentation/Configure.help linux-generic/Documentation/Configure.help
--- linux-ia64/Documentation/Configure.help	Tue Aug 27 12:59:18 2002
+++ linux-generic/Documentation/Configure.help	Tue Aug 27 09:25:08 2002
@@ -3935,6 +3941,14 @@ CONFIG_ENVCTRL
   inserted in and removed from the running kernel whenever you want).
   The module will be called envctrl.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
+
+Baseboard Management Controller
+CONFIG_BMC
+  Support for the Baseboard Management Controller.  This controller
+  interprets IPMI commands which can do things like change your
+  fan speed, log information into NVRAM or report CPU temperature.
+
+  If you are unsure, say N
 
 # Choice: x86type
 Processor family
diff -urpNX ../dontdiff linux-ia64/arch/i386/config.in linux-generic/arch/i386/config.in
--- linux-ia64/arch/i386/config.in	Tue Aug 27 12:59:23 2002
+++ linux-generic/arch/i386/config.in	Tue Aug 27 09:25:10 2002
@@ -293,6 +293,8 @@ fi
 
 endmenu
 
+source drivers/misc/Config.in
+
 source drivers/mtd/Config.in
 
 source drivers/parport/Config.in
diff -urpNX ../dontdiff linux-ia64/arch/ia64/config.in linux-generic/arch/ia64/config.in
--- linux-ia64/arch/ia64/config.in	Tue Aug 27 12:59:24 2002
+++ linux-generic/arch/ia64/config.in	Tue Aug 27 09:25:10 2002
@@ -104,6 +98,8 @@ bool 'BSD Process Accounting' CONFIG_BSD
 bool 'Sysctl support' CONFIG_SYSCTL
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+
+source drivers/misc/Config.in
 
 if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
   define_bool CONFIG_ACPI y
diff -urpNX ../dontdiff linux-ia64/drivers/Makefile linux-generic/drivers/Makefile
--- linux-ia64/drivers/Makefile	Tue Aug 27 12:59:48 2002
+++ linux-generic/drivers/Makefile	Wed Aug 28 08:54:02 2002
@@ -8,7 +8,7 @@
 
 mod-subdirs :=	dio mtd sbus video macintosh usb input telephony sgi ide \
 		message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
-		fc4 net/hamradio i2c acpi bluetooth
+		fc4 net/hamradio i2c acpi bluetooth misc
 
 subdir-y :=	parport char block net sound misc media cdrom hotplug
 subdir-m :=	$(subdir-y)
diff -urpNX ../dontdiff linux-ia64/drivers/misc/Config.in linux-generic/drivers/misc/Config.in
--- linux-ia64/drivers/misc/Config.in	Fri Jan 25 13:11:21 2002
+++ linux-generic/drivers/misc/Config.in	Mon Aug 12 10:26:31 2002
@@ -4,4 +4,6 @@
 mainmenu_option next_comment
 comment 'Misc devices'
 
+tristate 'Baseboard Management Controller' CONFIG_BMC
+
 endmenu
diff -urpNX ../dontdiff linux-ia64/drivers/misc/Makefile linux-generic/drivers/misc/Makefile
--- linux-ia64/drivers/misc/Makefile	Fri Jan 25 13:11:21 2002
+++ linux-generic/drivers/misc/Makefile	Mon Aug 12 10:26:31 2002
@@ -9,8 +9,8 @@
 # parent makes..
 #
 
+obj-$(CONFIG_BMC) += bmc.o
+
 O_TARGET := misc.o
 
 include $(TOPDIR)/Rules.make
-
-fastdep:
diff -urpNX ../dontdiff linux-ia64/drivers/misc/bmc.c linux-generic/drivers/misc/bmc.c
--- linux-ia64/drivers/misc/bmc.c	Wed Dec 31 17:00:00 1969
+++ linux-generic/drivers/misc/bmc.c	Tue Aug 27 08:52:34 2002
@@ -0,0 +1,922 @@
+/*
+ * Copyright (c) 2002 Hewlett-Packard Inc., All Rights Reserved.
+ * Authors: Hamilton Coutinho, Matthew Wilcox, Al Viro
+ *
+ * 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 driver sends IPMI commands to the Management Controller found in
+ * many HP machines.
+ */
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/pagemap.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define MIN_BMC_REQUEST_SIZE    2
+#define MAX_BMC_BUFFER_SIZE     68	/* 68 for Zirconlite */
+#define MIN_BMC_RESPONSE_SIZE   3	/* nfLn, cmd, cCode */
+
+#define BMC_LUN			0	/* BMC only responds to this LUN */
+#define CCODE_UNKNOWN		0xff
+#define NETFN_OF(x)		(((x)>>2) & 0x3f) /* extract netFn from nfLn */
+
+#define WAIT_1_MS		1000            /* in uSecs */
+#define BMC_TIME_OUT            (5000 * WAIT_1_MS)	/* Maximum time the BMC can do its IO for an IRP */
+
+/* Values to pass to DelayRetryFunc() */
+
+#define KCS_READY_DELAY		(WAIT_1_MS)
+#define BMC_RESPONSE_DELAY	(10 * WAIT_1_MS) /* how long to wait for a response after sending req */
+#define BMC_RETRY_DELAY		(60 * WAIT_1_MS) /* how long to wait after an error before retrying */
+#define FORCE_DELAY		0xFFFFFFFF       /* if retryCount has this value, force a delay */
+
+struct bmc_request {
+	unsigned char nfLn;
+	unsigned char cmd;
+	unsigned char data[1]; /* actually a variable-length array */
+};
+
+struct bmc_response {
+	unsigned char nfLn;
+	unsigned char cmd;
+	unsigned char cCode;
+	unsigned char data[1]; /* actually a variable-length array */
+};
+
+struct filp_private {
+	unsigned int	len;
+	struct bmc_response	response;
+};
+
+/* Keyboard Controller Style Interface addresses and defines */
+
+#define MAX_INVALID_RESPONSE_COUNT	1	/* number of BMC request send retries. */
+
+/* Status register bit flags (from spec) */
+#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
+
+/* KCS commands (from spec) */
+#define WRITE_START		0x61
+#define WRITE_END		0x62
+#define READ_CMD		0x68
+
+/* State machine states */
+#define TRANSFER_INIT		1  /* initialize */
+#define TRANSFER_START		2  /* start the writing phase of the request */
+#define TRANSFER_NEXT		3  /* send the next byte of a request */
+#define TRANSFER_END		4  /* send last byte of request */
+#define RECEIVE_START		5  /* wait for BMC to transition to read state */
+#define RECEIVE_INIT		6  /* wait for first data byte to become available */
+#define RECEIVE_NEXT		7  /* collect data byte and ask for more */
+#define RECEIVE_INIT2		8  /* wait for next data byte to become available */
+#define RECEIVE_END		9  /* terminate the reading operation */
+#define MACHINE_END		10 /* quit and return to the user. */
+#define TRANSFER_ERROR		0
+
+/* status values */
+#define STATUS_SUCCESS		0 /* Operation ok */
+#define STATUS_FAILURE		1 /* Operation not ok */
+
+
+#if 0
+#define KdPrint( a ) printk a
+#else
+#define KdPrint( a )
+#endif
+
+static int iomem;		/* indicates whether to use writeb or outb */
+static unsigned long raw_addr;		/* physical address */
+static unsigned char *base_addr;	/* virtual address */
+static int base_port;			/* port address */
+
+static unsigned long mc_timeout;
+
+static void set_timeout(unsigned long microseconds)
+{
+	mc_timeout = jiffies + (microseconds * HZ) / 1000000;
+}
+
+static int is_timeout(void)
+{
+	return time_after(jiffies, mc_timeout);
+}
+
+/* DelayRetryFunc - inserts a delay into the execution of the current thread
+ * retryCount: A counter, incremented by the calling function, to be tested
+ *	  against the constant 0x50.  Up until it reaches that value,
+ *	  this function just does a return.  The net effect is that the
+ *	  calling function together with this function, spins on the CPU.
+ * delayTime: Delay interval to be used in uSec
+ */
+static void DelayRetryFunc(unsigned long retryCount, unsigned long delayTime)
+{
+	/* The following value is the number of times the DelayRetryFunc()
+	 * just returns instead of doing a real OS delay.  Intel chose this
+	 * number in its sample driver.
+	 */
+	const unsigned long NO_RETRY_DELAY_COUNT = 0x50;
+
+	if (retryCount < NO_RETRY_DELAY_COUNT && retryCount != FORCE_DELAY)
+		return;
+
+#if 1
+	if (delayTime < 2000) {
+		udelay(delayTime);
+	} else {
+		mdelay(delayTime / 1000);
+	}
+#else
+	set_current_state(TASK_INTERRUPTIBLE);	
+	schedule_timeout((delayTime * HZ)/1000000);
+#endif
+}
+
+static unsigned char read_bmc_data(void)
+{
+	if (iomem) {
+		return readb(base_addr);
+	} else {
+		return inb(base_port);
+	}
+}
+
+static void write_bmc_data(unsigned char data)
+{
+	if (iomem) {
+		writeb(data, base_addr);
+	} else {
+		outb(data, base_port);
+	}
+}
+
+static unsigned char read_bmc_status(void)
+{
+	if (iomem) {
+		return readb(base_addr + 1);
+	} else {
+		return inb(base_port + 1);
+	}
+}
+
+static void write_bmc_cmd(unsigned char cmd)
+{
+	if (iomem) {
+		writeb(cmd, base_addr + 1);
+	} else {
+		outb(cmd, base_port + 1);
+	}
+}
+
+/* get_bmc_state - returns the STATE bits of the STATUS register */
+static unsigned char get_bmc_state(void)
+{
+	return (read_bmc_status() & KCS_STATE_MASK);
+}
+
+/* OBFset - returns the value of the OBF flag */
+static int OBFset(void)
+{
+	return (read_bmc_status() & KCS_OBF) == KCS_OBF;
+}
+
+/* ClearOBF - Ensures OBF flag is clear */
+static void ClearOBF(void)
+{
+	read_bmc_data();
+}
+
+/* WaitOnOBF - Waits for Output Buffer Full Flag to be set.
+ * Returns false if we time out waiting.
+ */
+static int WaitOnOBF(void)
+{
+	unsigned long retryCount = 0;
+
+	while (!OBFset()) {
+		DelayRetryFunc(retryCount++, KCS_READY_DELAY);
+
+		if (is_timeout())
+			return 0;
+	}
+	return 1;
+}
+
+/* WaitOnIBF - Wait until the Input Buffer Flag is clear. */
+static void WaitOnIBF(void)
+{
+	unsigned long retryCount = 0;
+
+	while (!is_timeout()) {
+		unsigned char status = read_bmc_status();
+		if ((status & KCS_IBF) == 0) {
+			KdPrint(("IBF cleared!\n"));
+			break;
+		}
+
+ 		DelayRetryFunc(retryCount++, KCS_READY_DELAY);
+	}
+}
+
+
+/**
+ * __execute_bmc_command - sends an IPMI command to the BMC
+ * request: the input buffer.  Contains "raw" data for writing to the BMC
+ * request_length: amount of data in request to send.
+ * response: the output buffer.  "Raw" data from the BMC is put here.
+ * response_length: On entry contains the max number of bytes that can be
+ * 	written to response.  Updated to the number of bytes written on exit.
+ *
+ * returns 0 on success and -EIO on error.
+ *
+ *	Low level routine for executing any IPMI command.  Communicates
+ *	directly with the Baseboard Management Controller.
+ *	Refer to figures 8-2 and 8-3 of the IPMI Specification v1.0 (Document
+ *	revision 1.1, dated November 15, 1999).  Some tweaks were made to
+ *	these figures in the "IPMI Addenda, Errata and Clarifications"
+ *	revision 3 dated June 6, 2000.
+ */
+
+static long __execute_bmc_command(struct bmc_request *request,
+		unsigned long request_length, struct bmc_response *response,
+		int *response_length)
+{
+	int status, invalidRespCount = 0;
+	unsigned char *transmitBuf = (unsigned char *) request;
+	unsigned char *receiveBuf = (unsigned char *) response;
+	int machineState = TRANSFER_INIT;
+	unsigned long request_ctr=0, receive_ctr=0;
+
+	status = STATUS_SUCCESS;
+	response->cCode = CCODE_UNKNOWN;
+	
+	set_timeout(BMC_TIME_OUT);
+	
+	KdPrint(("Start state machine \n"));
+
+	while (1) {
+		/* The three cases below are the only exits from this loop */
+		if (is_timeout()) {
+			printk(KERN_ERR "bmcdev : bmc timeout\n");
+			status = STATUS_FAILURE;
+			break;
+		} else if (machineState == MACHINE_END) {
+			status = STATUS_SUCCESS;
+			KdPrint(("In MACHINE_END\n"));
+			break;
+		} else if (invalidRespCount > MAX_INVALID_RESPONSE_COUNT) {
+			/* Intel's sample driver doesn't change the variable
+			 * status to a failure in this case.  We do.
+			 */
+			status = STATUS_FAILURE;
+			KdPrint(("Too many bad responses!\n"));
+			break;
+		}
+
+		switch (machineState) {
+
+		case  TRANSFER_INIT:
+			KdPrint(("Entering TRANSFER_INIT!\n"));
+			
+			request_ctr = 0;
+
+			WaitOnIBF();
+			ClearOBF();
+	
+			machineState = TRANSFER_START;
+			/* fall through */
+
+		case  TRANSFER_START:
+			KdPrint(("Entering TRANSFER_START! Ready to write WRITE_START\n\n"));
+
+			write_bmc_cmd(WRITE_START);
+			WaitOnIBF();
+
+			KdPrint(("TRANSFER_START: after WaitonIBF\n"));
+
+			if (get_bmc_state() != KCS_WRITE_STATE) {
+				machineState = TRANSFER_ERROR;
+				break;
+			}
+			KdPrint(("TRANSFER_START: after get_bmc_state\n"));
+
+			ClearOBF();
+			KdPrint(("TRANSFER_START: after ClearOBF\n"));
+
+			machineState = TRANSFER_NEXT;
+			/* fall through, again */
+
+		case  TRANSFER_NEXT:
+			KdPrint(("Entering TRANSFER_NEXT!\n\n"));
+			/* check for end of request, transition to the END
+			 * state which will transfer our last byte
+			 */
+			if (request_ctr == (request_length - 1)) {
+				machineState = TRANSFER_END;
+				break;
+			}
+
+#if 0	/* Following was commented out in Intel IPMI driver.  We keep it
+	 * commented out even though the flowchart in the IPMI spec has it in.
+	 */
+			if (get_bmc_state() != KCS_WRITE_STATE) {
+				machineState = TRANSFER_ERROR;
+				break;
+			}
+#endif
+			write_bmc_data(transmitBuf[request_ctr++]);
+			KdPrint(("*** Sent data : %X ***\n", transmitBuf[request_ctr-1]));
+
+			WaitOnIBF();
+
+#if 0
+			if (get_bmc_state() != KCS_WRITE_STATE) {
+				machineState = TRANSFER_ERROR;
+				break;
+
+			}
+#endif
+			ClearOBF();
+
+			break;
+
+		case  TRANSFER_END:
+			KdPrint(("Entering TRANSFER_END!\n\n"));
+
+			/* Transfer the last byte of the request and
+			 * transition to Reading.
+			 */
+
+#if 0	/* Following was commented out in Intel reference driver. */
+			WaitOnIBF( context );
+			if (!ClearObf(context)) {
+				machineState = TRANSFER_ERROR;
+				break;
+			}
+#endif
+
+			write_bmc_cmd(WRITE_END);
+
+			WaitOnIBF();
+
+			if (get_bmc_state() != KCS_WRITE_STATE) {
+				machineState = TRANSFER_ERROR;
+				break;
+			}
+
+			ClearOBF();
+
+			KdPrint(("Write next byte\n"));
+			write_bmc_data(transmitBuf[request_ctr++]);
+			KdPrint(("*** Sent data : %X  ***\n", transmitBuf[request_ctr-1]));			
+
+			WaitOnIBF();
+
+    			machineState = RECEIVE_START;
+			/* fall through */
+
+		case  RECEIVE_START:
+			KdPrint(("Entering RECEIVE_START!\n\n"));
+
+			/* request ended, now listen for a response */
+			switch (get_bmc_state()) {
+				case KCS_ERROR_STATE:
+					machineState = TRANSFER_ERROR;
+					break;
+
+				case KCS_WRITE_STATE:
+				case KCS_IDLE_STATE:
+					/* response not ready, wait for it */
+					DelayRetryFunc( FORCE_DELAY, BMC_RESPONSE_DELAY );
+					break;
+
+				case KCS_READ_STATE:
+					/* response ready, setup to receive */
+					receive_ctr = 0; 
+					machineState = RECEIVE_INIT;
+					break;
+			}
+			break;
+
+		case  RECEIVE_INIT:
+			KdPrint(("Entering RECEIVE_INIT!\n\n"));
+			
+			/* wait for a data byte */
+			switch (get_bmc_state()) {
+				case KCS_ERROR_STATE:
+				case KCS_WRITE_STATE:
+					machineState = TRANSFER_ERROR;
+					break;
+
+				case KCS_IDLE_STATE:
+					/* BMC is done sending data */
+					machineState = RECEIVE_END;
+					break;
+
+				case KCS_READ_STATE:
+					/* The following was rewritten from
+					 * the IPMI reference driver to match
+					 * the flowchart in figure 8-3 of IPMI
+					 * Addenda, Errata and Clarifications
+					 */
+					if (WaitOnOBF())
+						machineState = RECEIVE_NEXT;
+					else
+						machineState = TRANSFER_ERROR;
+					break;
+
+				default:
+					DelayRetryFunc(FORCE_DELAY, KCS_READY_DELAY);
+			}
+			break;
+
+		case  RECEIVE_NEXT:
+			KdPrint(("Entering RECEIVE_NEXT!\n\n"));
+			
+			/* Read the next data byte from the BMC */
+
+			if (receive_ctr >= *response_length) {
+				machineState	= TRANSFER_ERROR;
+				break;
+			}
+
+			receiveBuf[receive_ctr++] = read_bmc_data();
+
+			KdPrint(("*** The data returned is %x *** \n", receiveBuf[receive_ctr-1]));
+			
+			write_bmc_data(READ_CMD);
+
+			WaitOnIBF();
+
+			machineState = RECEIVE_INIT2;
+
+			break;
+
+		case  RECEIVE_INIT2:
+			KdPrint(("Entering RECEIVE_INIT2!\n\n"));
+			
+			/* wait for a data byte */
+			switch (get_bmc_state()) {
+				case KCS_ERROR_STATE:
+				case KCS_WRITE_STATE:
+					machineState = TRANSFER_ERROR;
+					break;
+
+				case KCS_IDLE_STATE:
+					/* BMC is done sending data */
+					if (WaitOnOBF()) {
+						ClearOBF();
+						machineState = RECEIVE_END;
+					} else {
+						machineState = TRANSFER_ERROR;
+					}
+
+					break;
+
+				case KCS_READ_STATE:
+
+					if (WaitOnOBF()) {
+						machineState = RECEIVE_NEXT;
+					} else {
+						machineState = TRANSFER_ERROR;
+					}
+
+					break;
+			}
+			break;
+
+		case  RECEIVE_END:
+			KdPrint(("Entering RECEIVE_END!\n\n"));
+			
+			/* check for size, appropriate response netfun (which
+			 * should be the original netfun with last bit set),
+			 * and command
+			 */
+			if (receive_ctr < MIN_BMC_RESPONSE_SIZE ||
+					NETFN_OF(response->nfLn) != (NETFN_OF(request->nfLn) | 1) ||
+						response->cmd != request->cmd ) {
+				machineState = TRANSFER_ERROR;
+				break;
+			}
+
+			/* all done, return triumphant */
+			*response_length = receive_ctr;
+			machineState = MACHINE_END;
+
+			break;
+
+		case  TRANSFER_ERROR:
+			KdPrint(("Entering TRANSFER_ERROR!\n\n"));
+			
+		default:
+			/*
+			 * We've failed somehow, or maybe it was the BMC fault.
+			 * Try again, as per comm spec. allow 60 ms. for
+			 * controllers to recover
+			 */
+			DelayRetryFunc(FORCE_DELAY, BMC_RETRY_DELAY);
+			receive_ctr = request_ctr = 0;
+			++invalidRespCount;
+			machineState = TRANSFER_INIT;
+			
+			if (invalidRespCount <= MAX_INVALID_RESPONSE_COUNT)
+				printk(KERN_ERR "bmcdev: retrying command\n");
+			break;
+		} /* switch */
+	} /* while(TRUE) */
+
+	return (status == STATUS_SUCCESS) ? 0 : -EIO;
+}
+
+static DECLARE_MUTEX(chip_sem);
+
+static long execute_bmc_command(struct bmc_request *request,
+		unsigned long request_len, struct bmc_response *response,
+		int *response_len)
+{
+	long result;
+	down(&chip_sem);
+	result = __execute_bmc_command(request, request_len, response,
+			response_len);
+	up(&chip_sem);
+	return result;
+}
+
+#ifdef CONFIG_ACPI
+struct SPMITable {
+	s8	Signature[4];
+	u32	Length;
+	u8	Revision;
+	u8	Checksum;
+	s8	OEMID[6];
+	s8	OEMTableID[8];
+	s8	OEMRevision[4];
+	s8	CreatorID[4];
+	s8	CreatorRevision[4];
+	s16	InterfaceType;
+	s16	SpecificationRevision;
+	u8	InterruptType;
+	u8	GPE;
+	s16	Reserved;
+	u64	GlobalSystemInterrupt;
+	u8	BaseAddress[12];
+	u8	UID[4];
+} __attribute__ ((packed));
+
+static unsigned long acpi_find_bmc(void)
+{
+	acpi_status status;
+	acpi_table_header *spmi;
+	static unsigned long io_base = 0;
+
+	if (io_base != 0)
+		return io_base;
+
+	status = acpi_get_firmware_table("SPMI", 1,
+			ACPI_LOGICAL_ADDRESSING, &spmi);
+
+	if (status != AE_OK) {
+		printk(KERN_ERR "bmcdev : SPMI table not found.\n");
+		return 0;
+	}
+
+	memcpy(&io_base, ((struct SPMITable *)spmi)->BaseAddress,
+			sizeof(io_base));
+	
+	return io_base;
+}
+#endif
+
+static unsigned long pci_find_bmc(void)
+{
+	return 0;
+}
+
+static int isa_find_bmc(void)
+{
+	return 0;
+}
+
+static spinlock_t busy_lock;
+
+static int bmc_open(struct inode *inode, struct file *filp)
+{
+	filp->private_data = NULL;
+	return 0;
+}
+
+static int bmc_release(struct inode *inode, struct file *filp)
+{
+	kfree(filp->private_data);
+	return 0;
+}
+
+static ssize_t bmc_write(struct file *file, const char *buf, size_t count,
+			loff_t *ppos)
+{
+	int err, ccode;
+	struct bmc_request *request;
+	struct filp_private *private;
+	struct bmc_response *response;
+	int response_size = MAX_BMC_BUFFER_SIZE;
+
+	if (count >= MAX_BMC_BUFFER_SIZE || count < MIN_BMC_REQUEST_SIZE)
+		return -EINVAL;
+
+	private = kmalloc(MAX_BMC_BUFFER_SIZE + 1, GFP_KERNEL);
+	if (!private)
+		return -ENOMEM;
+	private->len = 0;
+	response = &private->response;
+
+	err = -EBUSY;
+	spin_lock(&busy_lock);
+	if (file->private_data)
+		goto out;
+	file->private_data = private;
+	spin_unlock(&busy_lock);
+
+	err = -ENOMEM;
+	request = kmalloc(count, GFP_KERNEL);
+	if (!request)
+		goto out1;
+	err = -EFAULT;
+	if (copy_from_user(request, buf, count))
+		goto out2;
+
+	err = -EIO;
+	if ((request->nfLn & 0x03) != BMC_LUN)
+		goto out2;
+	/* Ensure this is a request, not a response */
+	if ((request->nfLn & 0x04) != 0)
+		goto out2;
+
+	err = execute_bmc_command(request, count, response, &response_size);
+
+	if (err < 0)
+		goto out2;
+
+	/* Check the completion code */
+	err = -EINVAL;
+	ccode = response->cCode;
+	if ((response->cCode == 0x7f) || (response->cCode == 0xbf) ||
+			(response->cCode >= 0xd5 && response->cCode < 0xff))
+		goto out2;
+
+	private->len = response_size;
+
+	kfree(request);
+	return count;
+
+out2:
+	kfree(request);
+out1:
+	spin_lock(&busy_lock);
+	file->private_data = NULL;
+out:
+	spin_unlock(&busy_lock);
+	kfree(response);
+	return err;
+}
+
+static ssize_t bmc_read(struct file *filp, char *buf, size_t count,
+			loff_t *ppos)
+{
+	struct filp_private *p;
+	int len = 0;
+	loff_t offs = *ppos;
+
+	spin_lock(&busy_lock);
+	p = filp->private_data;
+	if (p) {
+		len = p->len;
+		filp->private_data = NULL;
+	}
+	spin_unlock(&busy_lock);
+	if (len == 0)
+		goto out;
+	if (offs >= 0 && offs <= len) {
+		if ((count > len) || (offs + count > len))
+			count = len - offs;
+		if (copy_to_user(buf, &p->response + offs, count))
+			count = -EFAULT;
+	} else {
+		count = 0;
+	}
+
+ out:
+	kfree(p);
+	return count;
+}
+
+static struct file_operations bmc_operations = {
+	open:		bmc_open,
+	release:	bmc_release,
+	read:		bmc_read,
+	write:		bmc_write,
+};
+
+static int bmc_statfs(struct super_block *sb, struct statfs *buf)
+{
+	buf->f_type = sb->s_magic;
+	buf->f_bsize = PAGE_CACHE_SIZE;
+	buf->f_namelen = 255;
+	return 0;
+}
+
+static struct super_operations s_ops = {
+	statfs:		bmc_statfs,
+	put_inode:	force_delete,
+};
+
+static struct super_block *bmc_read_super(struct super_block * sb, void * data, int silent)
+{
+	struct inode *inode;
+	sb->s_magic = 0x424d43;
+	sb->s_op = &s_ops;
+	inode = new_inode(sb);
+	if (!inode)
+		return NULL;
+	inode->i_mode = S_IFREG|0600;
+	inode->i_uid = 0;
+	inode->i_gid = 0;
+	inode->i_blksize = PAGE_CACHE_SIZE;
+	inode->i_blocks = 0;
+	inode->i_size = 0;
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	inode->i_fop = &bmc_operations;
+	sb->s_root = d_alloc_root(inode);
+	if (!sb->s_root) {
+		iput(inode);
+		return NULL;
+	}
+	return sb;
+}
+
+static DECLARE_FSTYPE(bmc_fs_type, "bmc", bmc_read_super, FS_SINGLE);
+
+#define MAX_DEVICE_OPEN_RETRIES  	1000
+#define SEL_ENTRY_SIZE 			16
+#define COMMAND_HEADER 			2
+#define RESPONSE_SIZE 			3
+#define MAX_RETRY_COUNT			30
+
+/* Write in SEL a event when System Panic occurs */
+static int WritePanicEvent(struct notifier_block *this, unsigned long command, void *ptr)
+{
+    	int err;
+	struct bmc_request *ibuffer;
+	struct bmc_response *obuffer;
+	unsigned int ilen, olen;
+	int RetryCount = 0;
+
+	ilen = SEL_ENTRY_SIZE + COMMAND_HEADER;
+	ibuffer = kmalloc(ilen, GFP_KERNEL);
+	if (!ibuffer)
+		goto out;
+
+	olen = RESPONSE_SIZE + COMMAND_HEADER;
+	obuffer = kmalloc(olen, GFP_KERNEL);
+	if (!obuffer)
+		goto out;
+
+	ibuffer->nfLn = 0x28;  /* STORAGE */
+	ibuffer->cmd = 0x44;
+	ibuffer->data[2]=0x02; /* SEL_RT_STANDARD2 */
+	ibuffer->data[7]=0x21; /* SEL_GI_NSA */
+	ibuffer->data[8]=0x00;
+	ibuffer->data[9]=0x03; /* SEL_EV_STANDARD3 */
+	ibuffer->data[10]=0x20; /* SENSOR_TYPE */
+	ibuffer->data[11]=0x00;
+	ibuffer->data[12]=0x6F; /* EVENT_TYPE */
+	ibuffer->data[13]=0x01;
+	ibuffer->data[14]=0xFF;
+	ibuffer->data[15]=0xFF;
+	err = __execute_bmc_command(ibuffer, ilen, obuffer, &olen);
+	while (err) {
+		/* Check Retry Count */
+		if (RetryCount < MAX_RETRY_COUNT)
+			RetryCount++;
+		else
+			break;
+		/* Sleep before retrying */
+		DelayRetryFunc(RetryCount, BMC_RETRY_DELAY);
+		err = __execute_bmc_command(ibuffer, ilen, obuffer, &olen);
+	}
+out:
+	return 0;
+}
+
+static void *reserve_bmc_memory(unsigned long address)
+{
+	if (!request_mem_region(address, 4, "bmcdev")) {
+		printk(KERN_ERR "bmcdev: bmc address already in use\n");
+		return 0;
+	}
+	return ioremap(address, 4);
+}
+
+static int reserve_bmc_port(int address)
+{
+	if (!request_region(address, 4, "bmcdev")) {
+		printk(KERN_ERR "bmcdev: bmc address already in use\n");
+		return 0;
+	}
+	return 1;
+}
+
+static void release_bmc_resources(void)
+{
+	if (iomem) {
+		release_mem_region(raw_addr, 4);
+		iounmap(base_addr);
+	} else {
+		release_region(base_port, 4);
+	}
+}
+
+/*
+ * There are three ways to find a BMC device.  It may be described in the
+ * ACPI tables, it may be a PCI device, or we may have to probe IO port space
+ * for it.  Disgusting.
+ */
+static int find_bmc(void)
+{
+#ifdef CONFIG_ACPI
+	raw_addr = acpi_find_bmc();
+	if (raw_addr) {
+		iomem = 1;
+		base_addr = reserve_bmc_memory(raw_addr);
+		return (base_addr != 0);
+	}
+#endif
+	raw_addr = pci_find_bmc();
+	if (raw_addr) {
+		iomem = 1;
+		base_addr = reserve_bmc_memory(raw_addr);
+		return (base_addr != 0);
+	}
+
+	base_port = isa_find_bmc();
+	if (base_port) {
+		iomem = 0;
+		return reserve_bmc_port(base_port);
+	}
+
+	return 0;
+}
+
+static struct notifier_block panic_block = { WritePanicEvent, NULL, 0 };
+
+static int __init bmc_init(void)
+{
+	int result;
+
+	printk(KERN_INFO "BMC module initialising\n");
+
+	if (!find_bmc())
+		return -EBUSY;
+
+	result = register_filesystem(&bmc_fs_type);
+	if (result < 0)
+		goto init_error;
+
+	/* WritePanicEvent(NULL,0,NULL); */
+	notifier_chain_register(&panic_notifier_list, &panic_block);
+
+	return 0;
+	
+ init_error:
+	release_bmc_resources();
+	return result;
+}
+
+static void __exit bmc_exit(void)
+{
+	notifier_chain_unregister(&panic_notifier_list, &panic_block);
+	unregister_filesystem(&bmc_fs_type);
+	release_bmc_resources();
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(bmc_init);
+module_exit(bmc_exit);
diff -urpNX ../dontdiff linux-ia64/kernel/ksyms.c linux-generic/kernel/ksyms.c
--- linux-ia64/kernel/ksyms.c	Tue Aug 27 13:00:49 2002
+++ linux-generic/kernel/ksyms.c	Tue Aug 27 09:26:33 2002
@@ -462,6 +462,7 @@ EXPORT_SYMBOL(nr_running);
 
 /* misc */
 EXPORT_SYMBOL(panic);
+EXPORT_SYMBOL_GPL(panic_notifier_list);
 EXPORT_SYMBOL(__out_of_line_bug);
 EXPORT_SYMBOL(sprintf);
 EXPORT_SYMBOL(snprintf);
