[PATCH] ipmi: add full sysfs support

Add full driver model support for the IPMI driver.  It links in the proper
bus and device support.

It adds an "ipmi" driver interface that has each BMC discovered by the
driver (as a device).  These BMCs appear in the devices/platform directory.
 If there are multiple interfaces to the same BMC, the driver should
discover this and will only have one BMC entry.  The BMC entry will have
pointers to each interface device that connects to it.

The device information (statistics and config information) has not yet been
ported over to the driver model from proc, that will come later.

This work was based on work by Yani Ioannou.  I basically rewrote it using
that code as a guide, but he still deserves credit :).

[bunk@stusta.de: make ipmi_find_bmc_guid() static]
Signed-off-by: Corey Minyard <minyard@acm.org>
Signed-off-by: Yani Ioannou <yani.ioannou@gmail.com>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
index d6276e6..0a84b56 100644
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -36,6 +36,7 @@
 
 #include <linux/ipmi_msgdefs.h>
 #include <linux/compiler.h>
+#include <linux/device.h>
 
 /*
  * This file describes an interface to an IPMI driver.  You have to
@@ -397,7 +398,7 @@
 	   the watcher list.  So you can add and remove users from the
 	   IPMI interface, send messages, etc., but you cannot add
 	   or remove SMI watchers or SMI interfaces. */
-	void (*new_smi)(int if_num);
+	void (*new_smi)(int if_num, struct device *dev);
 	void (*smi_gone)(int if_num);
 };
 
diff --git a/include/linux/ipmi_msgdefs.h b/include/linux/ipmi_msgdefs.h
index 03bc64d..22f5e2a 100644
--- a/include/linux/ipmi_msgdefs.h
+++ b/include/linux/ipmi_msgdefs.h
@@ -47,6 +47,7 @@
 #define IPMI_NETFN_APP_RESPONSE			0x07
 #define IPMI_GET_DEVICE_ID_CMD		0x01
 #define IPMI_CLEAR_MSG_FLAGS_CMD	0x30
+#define IPMI_GET_DEVICE_GUID_CMD	0x08
 #define IPMI_GET_MSG_FLAGS_CMD		0x31
 #define IPMI_SEND_MSG_CMD		0x34
 #define IPMI_GET_MSG_CMD		0x33
diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h
index e36ee15..5357128 100644
--- a/include/linux/ipmi_smi.h
+++ b/include/linux/ipmi_smi.h
@@ -37,6 +37,9 @@
 #include <linux/ipmi_msgdefs.h>
 #include <linux/proc_fs.h>
 #include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/ipmi_smi.h>
 
 /* This files describes the interface for IPMI system management interface
    drivers to bind into the IPMI message handler. */
@@ -113,12 +116,52 @@
 	void (*dec_usecount)(void *send_info);
 };
 
+struct ipmi_device_id {
+	unsigned char device_id;
+	unsigned char device_revision;
+	unsigned char firmware_revision_1;
+	unsigned char firmware_revision_2;
+	unsigned char ipmi_version;
+	unsigned char additional_device_support;
+	unsigned int  manufacturer_id;
+	unsigned int  product_id;
+	unsigned char aux_firmware_revision[4];
+	unsigned int  aux_firmware_revision_set : 1;
+};
+
+#define ipmi_version_major(v) ((v)->ipmi_version & 0xf)
+#define ipmi_version_minor(v) ((v)->ipmi_version >> 4)
+
+/* Take a pointer to a raw data buffer and a length and extract device
+   id information from it.  The first byte of data must point to the
+   byte from the get device id response after the completion code.
+   The caller is responsible for making sure the length is at least
+   11 and the command completed without error. */
+static inline void ipmi_demangle_device_id(unsigned char *data,
+					   unsigned int  data_len,
+					   struct ipmi_device_id *id)
+{
+	id->device_id = data[0];
+	id->device_revision = data[1];
+	id->firmware_revision_1 = data[2];
+	id->firmware_revision_2 = data[3];
+	id->ipmi_version = data[4];
+	id->additional_device_support = data[5];
+	id->manufacturer_id = data[6] | (data[7] << 8) | (data[8] << 16);
+	id->product_id = data[9] | (data[10] << 8);
+	if (data_len >= 15) {
+		memcpy(id->aux_firmware_revision, data+11, 4);
+		id->aux_firmware_revision_set = 1;
+	} else
+		id->aux_firmware_revision_set = 0;
+}
+
 /* Add a low-level interface to the IPMI driver.  Note that if the
    interface doesn't know its slave address, it should pass in zero. */
 int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
 		      void                     *send_info,
-		      unsigned char            version_major,
-		      unsigned char            version_minor,
+		      struct ipmi_device_id    *device_id,
+		      struct device            *dev,
 		      unsigned char            slave_addr,
 		      ipmi_smi_t               *intf);