* [PATCH] IPMI: driver model and sysfs support
@ 2005-08-30 10:56 Yani Ioannou
2005-08-30 13:22 ` Corey Minyard
0 siblings, 1 reply; 4+ messages in thread
From: Yani Ioannou @ 2005-08-30 10:56 UTC (permalink / raw)
To: Corey Minyard; +Cc: Martin Drab, openipmi-developer, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 3893 bytes --]
Hi Corey,
Here is a patch against 2.6.13 I've been working on (and mentioned to
you at OLS), that adds support for the 2.6 driver model, and sysfs to
the ipmi subsystem. It is loosely inspired by the USB driver model
system. There is a driver struct added for the ipmi_msghandler, and
one for each system interface 'driver' (for each state machine in
ipmi_si). A device struct is created for each system interface in the
system, and for each unique BMC on the system, with a symlink between
each system interface and the bmc it interfaces to. Each bmc has a set
of fundamental device attributes, and each of the drivers has a
version attribute reflecting the driver/state machine versions.
Furthermore each of these devices is registered as a class_device with
the ipmi class (moved to ipmi_msghandler) as bmcx and smix.
This in effect creates the following sysfs interface on a machine with
a single BMC and two interfaces:
/sys/
|-- block
|-- bus
| |-- platform
| | |-- devices
| | | |-- ipmi_bmc.0 -> ../../../devices/platform/ipmi_bmc.0
| | | |-- ipmi_si.0 -> ../../../devices/platform/ipmi_si.0
| | | |-- ipmi_si.1 -> ../../../devices/platform/ipmi_si.1
| | `-- drivers
| | |-- ipmi_bt_sm
| | | |-- bind
| | | |-- ipmi_si.1 -> ../../../../devices/platform/ipmi_si.1
| | | |-- unbind
| | | `-- version
| | |-- ipmi_kcs_sm
| | | |-- bind
| | | |-- ipmi_si.0 -> ../../../../devices/platform/ipmi_si.0
| | | |-- unbind
| | | `-- version
| | |-- ipmi_msghandler
| | | |-- bind
| | | |-- ipmi_bmc.0 -> ../../../../devices/platform/ipmi_bmc.0
| | | |-- unbind
| | | `-- version
|-- class
| |-- ipmi
| | |-- bmc0
| | | `-- device -> ../../../devices/platform/ipmi_bmc.0
| | |-- ipmi0
| | | `-- dev
| | |-- ipmi1
| | | `-- dev
| | |-- smi0
| | | `-- device -> ../../../devices/platform/ipmi_si.0
| | `-- smi1
| | `-- device -> ../../../devices/platform/ipmi_si.1
|-- devices
| |-- platform
| | |-- ipmi_bmc.0
| | | |-- bus -> ../../../bus/platform
| | | |-- device_id
| | | |-- driver -> ../../../bus/platform/drivers/ipmi_msghandler
| | | |-- firmware_revision
| | | |-- ipmi_version
| | | |-- power
| | | | `-- state
| | | |-- product_id
| | | `-- revision
| | |-- ipmi_si.0
| | | |-- bmc -> ../../../devices/platform/ipmi_bmc.0
| | | |-- bus -> ../../../bus/platform
| | | |-- driver -> ../../../bus/platform/drivers/ipmi_kcs_sm
| | | `-- power
| | | `-- state
| | |-- ipmi_si.1
| | | |-- bmc -> ../../../devices/platform/ipmi_bmc.0
| | | |-- bus -> ../../../bus/platform
| | | |-- driver -> ../../../bus/platform/drivers/ipmi_bt_sm
| | | `-- power
| | | `-- state
|-- kernel
|-- module
| |-- ipmi_devintf
| | |-- refcnt
| | `-- sections
| | `-- __param
| |-- ipmi_msghandler
| | |-- refcnt
| | `-- sections
| | |-- __ksymtab
| | `-- __ksymtab_strings
| |-- ipmi_si
| | |-- refcnt
| | `-- sections
| | `-- __param
`-- power
My motiviation for the patch is to have a device struct (bmc) to
register with the new hwmon class for my in-progress hwmon driver
ipmi_sensors. With this patch the driver can create device attributes
under bmc devices representing sensor readings for the
hwmon/lm_sensors interface.
I have tested the patch on two systems of mine with a single bmc, it
should however also work for a machine with multiple bmcs using the
guid/product+device id to differentiate.
Thanks,
Yani
Signed-off-by: Yani Ioannou <yani.ioannou@gmail.com>
[-- Attachment #2: patch-linux-2.6.13-ipmisys.diff --]
[-- Type: text/plain, Size: 34258 bytes --]
---
drivers/char/ipmi/ipmi_bt_sm.c | 28 +++
drivers/char/ipmi/ipmi_devintf.c | 11 -
drivers/char/ipmi/ipmi_kcs_sm.c | 28 +++
drivers/char/ipmi/ipmi_msghandler.c | 323 +++++++++++++++++++++++++++++++++++-
drivers/char/ipmi/ipmi_si_intf.c | 229 ++++++++++++++++++++++---
drivers/char/ipmi/ipmi_si_sm.h | 9 -
drivers/char/ipmi/ipmi_smic_sm.c | 29 +++
include/linux/ipmi.h | 108 ++++++++++++
include/linux/ipmi_msgdefs.h | 1
include/linux/ipmi_smi.h | 1
10 files changed, 722 insertions(+), 45 deletions(-)
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c
--- a/drivers/char/ipmi/ipmi_bt_sm.c
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
@@ -28,6 +28,7 @@
#include <linux/kernel.h> /* For printk. */
#include <linux/string.h>
+#include <linux/ipmi.h>
#include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h"
@@ -103,6 +104,31 @@ struct si_sm_data {
#define BT_INTMASK_R bt->io->inputb(bt->io, 2)
#define BT_INTMASK_W(x) bt->io->outputb(bt->io, 2, x)
+static ssize_t bt_driver_show_version(struct device_driver *drv, char *buf){
+ struct ipmi_si_driver *driver = to_ipmi_si_driver(drv);
+ return snprintf(buf, 10, "%s\n", driver->version);
+}
+
+/**
+ * The driver model view of the IPMI system interface state machine.
+ */
+static struct ipmi_si_driver bt_si_driver = {
+ .owner = THIS_MODULE,
+ .version = IPMI_BT_VERSION,
+ .driver = {
+ .name = "ipmi_bt_sm",
+ .bus = &platform_bus_type
+ },
+ .version_attr = {
+ .attr = {
+ .name = "version",
+ .owner = THIS_MODULE,
+ .mode = S_IRUGO,
+ },
+ .show = bt_driver_show_version,
+ },
+};
+
/* Convenience routines for debugging. These are not multi-open safe!
Note the macros have hardcoded variables in them. */
@@ -501,7 +527,7 @@ static int bt_size(void)
struct si_sm_handlers bt_smi_handlers =
{
- .version = IPMI_BT_VERSION,
+ .driver = &bt_si_driver,
.init_data = bt_init_data,
.start_transaction = bt_start_transaction,
.get_result = bt_get_result,
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -716,7 +716,7 @@ MODULE_PARM_DESC(ipmi_major, "Sets the m
" interface. Other values will set the major device number"
" to that value.");
-static struct class *ipmi_class;
+extern struct class *ipmi_class;
static void ipmi_new_smi(int if_num)
{
@@ -751,15 +751,8 @@ static __init int init_ipmi_devintf(void
printk(KERN_INFO "ipmi device interface version "
IPMI_DEVINTF_VERSION "\n");
- ipmi_class = class_create(THIS_MODULE, "ipmi");
- if (IS_ERR(ipmi_class)) {
- printk(KERN_ERR "ipmi: can't register device class\n");
- return PTR_ERR(ipmi_class);
- }
-
rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
if (rv < 0) {
- class_destroy(ipmi_class);
printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
return rv;
}
@@ -773,7 +766,6 @@ static __init int init_ipmi_devintf(void
rv = ipmi_smi_watcher_register(&smi_watcher);
if (rv) {
unregister_chrdev(ipmi_major, DEVICE_NAME);
- class_destroy(ipmi_class);
printk(KERN_WARNING "ipmi: can't register smi watcher\n");
return rv;
}
@@ -784,7 +776,6 @@ module_init(init_ipmi_devintf);
static __exit void cleanup_ipmi(void)
{
- class_destroy(ipmi_class);
ipmi_smi_watcher_unregister(&smi_watcher);
devfs_remove(DEVICE_NAME);
unregister_chrdev(ipmi_major, DEVICE_NAME);
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c
--- a/drivers/char/ipmi/ipmi_kcs_sm.c
+++ b/drivers/char/ipmi/ipmi_kcs_sm.c
@@ -39,6 +39,7 @@
#include <linux/kernel.h> /* For printk. */
#include <linux/string.h>
+#include <linux/ipmi.h>
#include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h"
@@ -111,6 +112,31 @@ struct si_sm_data
long obf_timeout;
};
+static ssize_t kcs_driver_show_version(struct device_driver *drv, char *buf){
+ struct ipmi_si_driver *driver = to_ipmi_si_driver(drv);
+ return snprintf(buf, 10, "%s\n", driver->version);
+}
+
+/**
+ * The driver model view of the IPMI system interface state machine.
+ */
+static struct ipmi_si_driver kcs_si_driver = {
+ .owner = THIS_MODULE,
+ .version = IPMI_KCS_VERSION,
+ .driver = {
+ .name = "ipmi_kcs_sm",
+ .bus = &platform_bus_type
+ },
+ .version_attr = {
+ .attr = {
+ .name = "version",
+ .owner = THIS_MODULE,
+ .mode = S_IRUGO,
+ },
+ .show = kcs_driver_show_version,
+ },
+};
+
static unsigned int init_kcs_data(struct si_sm_data *kcs,
struct si_sm_io *io)
{
@@ -489,7 +515,7 @@ static void kcs_cleanup(struct si_sm_dat
struct si_sm_handlers kcs_smi_handlers =
{
- .version = IPMI_KCS_VERSION,
+ .driver = &kcs_si_driver,
.init_data = init_kcs_data,
.start_transaction = start_kcs_transaction,
.get_result = get_kcs_result,
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -30,6 +30,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/*
+ * IPMI driver model/sysfs support.
+ * Copyright (C) 2005 Yani Ioannou <yani.ioannou@gmail.com>
+ */
#include <linux/config.h>
#include <linux/module.h>
@@ -301,6 +305,27 @@ struct ipmi_smi
unsigned int events;
};
+static struct class *ipmi_class;
+
+/**
+ * The driver model view of the IPMI messaging driver.
+ */
+static struct ipmi_driver ipmidriver = {
+ .owner = THIS_MODULE,
+ .version = IPMI_MSGHANDLER_VERSION,
+ .driver = {
+ .name = "ipmi_msghandler",
+ .bus = &platform_bus_type
+ }
+};
+
+static ssize_t ipmi_driver_show_version(struct device_driver *drv, char *buf){
+ struct ipmi_driver *driver = to_ipmi_driver(drv);
+ return snprintf(buf, 10, "%s\n", driver->version);
+}
+
+DRIVER_ATTR(version, S_IRUGO, ipmi_driver_show_version, NULL);
+
#define MAX_IPMI_INTERFACES 4
static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES];
@@ -318,6 +343,271 @@ static DEFINE_SPINLOCK(interfaces_lock);
static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
static DECLARE_RWSEM(smi_watchers_sem);
+static int __find_bmc_guid(struct device *dev, void *data)
+{
+ unsigned char *id = (unsigned char *) data;
+ struct ipmi_bmc_device *bmc =
+ to_ipmi_bmc_device(to_platform_device(dev));
+
+ return memcmp(bmc->guid, id, 16) == 0;
+}
+
+struct ipmi_bmc_device * ipmi_find_bmc_guid(struct ipmi_driver *drv,
+ unsigned char* guid)
+{
+ struct device *dev = driver_find_device(&drv->driver, NULL, guid,
+ __find_bmc_guid);
+ return (dev?to_ipmi_bmc_device(to_platform_device(dev)):NULL);
+}
+
+struct prod_dev_id{
+ unsigned char product_id[2];
+ unsigned char device_id;
+};
+
+static int __find_bmc_prod_dev_id(struct device *dev, void *data)
+{
+ struct prod_dev_id *id = (struct prod_dev_id *) data;
+ struct ipmi_bmc_device *bmc =
+ to_ipmi_bmc_device(to_platform_device(dev));
+
+ return memcmp(bmc->product_id, id->product_id, 2) == 0
+ && memcmp(&bmc->device_id, &id->device_id, 1) == 0;
+}
+
+struct ipmi_bmc_device * ipmi_find_bmc_prod_dev_id(struct ipmi_driver *drv,
+ unsigned char *product_id, unsigned char *device_id)
+{
+ struct prod_dev_id id = {
+ .product_id = {product_id[0], product_id[1]},
+ .device_id = *device_id,
+ };
+
+ struct device *dev = driver_find_device(&drv->driver, NULL, &id,
+ __find_bmc_prod_dev_id);
+ return (dev?to_ipmi_bmc_device(to_platform_device(dev)):NULL);
+}
+
+static void ipmi_bmc_release(struct device *dev){
+ printk(KERN_DEBUG "ipmi_bmc release\n");
+}
+
+static ssize_t device_id_show(struct device *dev, struct device_attribute *attr,
+ char *buf){
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 10, "%u\n", bmc->device_id);
+}
+
+static ssize_t product_id_show(struct device *dev, struct device_attribute *attr,
+ char *buf){
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 20, "%u%u\n", bmc->product_id[0],
+ bmc->product_id[1]);
+}
+
+static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
+ char *buf){
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 200, "%s\n", bmc->guid);
+}
+
+static ssize_t ipmi_version_show(struct device *dev, struct device_attribute *attr,
+ char *buf){
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 20, "%u.%u\n", bmc->version_major, bmc->version_minor);
+}
+
+static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
+ char *buf){
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 20, "%u\n", bmc->revision);
+}
+
+static ssize_t firmware_rev_show(struct device *dev, struct device_attribute *attr,
+ char *buf){
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 20, "%u.%u\n", bmc->firmware_rev_major,
+ bmc->firmware_rev_minor);
+}
+
+static void ipmi_bmc_unregister(struct ipmi_si_device *si,
+ struct ipmi_bmc_device *bmc){
+ if(--bmc->interfaces == 0){
+ class_device_unregister(bmc->class_dev);
+ device_remove_file(&bmc->dev.dev,
+ &bmc->device_id_attr);
+ device_remove_file(&bmc->dev.dev,
+ &bmc->product_id_attr);
+ device_remove_file(&bmc->dev.dev,
+ &bmc->version_attr);
+ device_remove_file(&bmc->dev.dev,
+ &bmc->revision_attr);
+ device_remove_file(&bmc->dev.dev,
+ &bmc->firmware_rev_attr);
+ platform_device_unregister(&bmc->dev);
+ }
+}
+
+static int ipmi_bmc_register(struct ipmi_si_device *si,
+ struct ipmi_bmc_device **bmcref){
+ int rv = 0;
+ struct ipmi_bmc_device *bmc = *bmcref;
+ struct ipmi_bmc_device *new_bmc;
+
+ /* Try to find if there is an ipmi_bmc_device struct
+ * representing the interfaced BMC already
+ */
+ if(bmc->guid_present){
+ new_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
+ }else{
+ new_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
+ bmc->product_id,
+ &bmc->device_id);
+ }
+ /* If there is already an ipmi_bmc_device, free the new one,
+ * otherwise register the new BMC device
+ */
+ if(new_bmc){
+ kfree(bmc);
+ *bmcref = new_bmc;
+ bmc = new_bmc;
+
+ bmc->interfaces++;
+
+ printk(KERN_INFO
+ "ipmi_si: interfacing existing BMC (guid: %x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x, prod_id: %u%u, dev_id: %u)\n",
+ bmc->guid[0],
+ bmc->guid[1],
+ bmc->guid[2],
+ bmc->guid[3],
+ bmc->guid[4],
+ bmc->guid[5],
+ bmc->guid[6],
+ bmc->guid[7],
+ bmc->guid[8],
+ bmc->guid[9],
+ bmc->guid[10],
+ bmc->guid[11],
+ bmc->guid[12],
+ bmc->guid[13],
+ bmc->guid[14],
+ bmc->guid[15],
+ bmc->product_id[0],
+ bmc->product_id[1],
+ bmc->device_id);
+ }else{
+ bmc->dev.name = "ipmi_bmc";
+ bmc->dev.id = bmc->device_id;
+ bmc->dev.dev.driver = &ipmidriver.driver;
+ bmc->dev.dev.release = ipmi_bmc_release;
+ bmc->interfaces = 1;
+
+ rv = platform_device_register(&bmc->dev);
+ if (rv) {
+ printk(KERN_ERR
+ "ipmi_si: Unable to register bmc device: %d\n",
+ rv);
+ goto out_err;
+ }
+
+ bmc->device_id_attr.attr.name = "device_id";
+ bmc->device_id_attr.attr.owner = THIS_MODULE;
+ bmc->device_id_attr.attr.mode = S_IRUGO;
+ bmc->device_id_attr.show = device_id_show;
+
+ bmc->product_id_attr.attr.name = "product_id";
+ bmc->product_id_attr.attr.owner = THIS_MODULE;
+ bmc->product_id_attr.attr.mode = S_IRUGO;
+ bmc->product_id_attr.show = product_id_show;
+
+ bmc->guid_attr.attr.name = "guid";
+ bmc->guid_attr.attr.owner = THIS_MODULE;
+ bmc->guid_attr.attr.mode = S_IRUGO;
+ bmc->guid_attr.show = guid_show;
+
+ bmc->version_attr.attr.name = "ipmi_version";
+ bmc->version_attr.attr.owner = THIS_MODULE;
+ bmc->version_attr.attr.mode = S_IRUGO;
+ bmc->version_attr.show = ipmi_version_show;
+
+ bmc->revision_attr.attr.name = "revision";
+ bmc->revision_attr.attr.owner = THIS_MODULE;
+ bmc->revision_attr.attr.mode = S_IRUGO;
+ bmc->revision_attr.show = revision_show;
+
+ bmc->firmware_rev_attr.attr.name = "firmware_revision";
+ bmc->firmware_rev_attr.attr.owner = THIS_MODULE;
+ bmc->firmware_rev_attr.attr.mode = S_IRUGO;
+ bmc->firmware_rev_attr.show = firmware_rev_show;
+
+ device_create_file(&bmc->dev.dev,
+ &bmc->device_id_attr);
+ device_create_file(&bmc->dev.dev,
+ &bmc->product_id_attr);
+ device_create_file(&bmc->dev.dev,
+ &bmc->version_attr);
+ device_create_file(&bmc->dev.dev,
+ &bmc->revision_attr);
+ device_create_file(&bmc->dev.dev,
+ &bmc->firmware_rev_attr);
+
+ if(bmc->guid_present)
+ device_create_file(&bmc->dev.dev,
+ &bmc->guid_attr);
+
+ bmc->class_dev =
+ kmalloc(sizeof(struct class_device), GFP_KERNEL);
+ if (!bmc->class_dev) {
+ printk(KERN_ERR "ipmi_msghandler: Could not allocate class_device memory\n");
+ rv = -ENOMEM;
+ goto out_err;
+ }
+ memset(bmc->class_dev, 0, sizeof(struct class_device));
+
+
+ bmc->class_dev->class = ipmi_class;
+ bmc->class_dev->dev = &bmc->dev.dev;
+ snprintf(bmc->class_dev->class_id, BUS_ID_SIZE, "bmc%d",
+ bmc->device_id);
+
+ class_device_register(bmc->class_dev);
+
+ printk(KERN_INFO
+ "ipmi_si: Found new BMC (guid: guid: %x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x, prod_id: %u%u, dev_id: %u)\n",
+ bmc->guid[0],
+ bmc->guid[1],
+ bmc->guid[2],
+ bmc->guid[3],
+ bmc->guid[4],
+ bmc->guid[5],
+ bmc->guid[6],
+ bmc->guid[7],
+ bmc->guid[8],
+ bmc->guid[9],
+ bmc->guid[10],
+ bmc->guid[11],
+ bmc->guid[12],
+ bmc->guid[13],
+ bmc->guid[14],
+ bmc->guid[15],
+ bmc->product_id[0],
+ bmc->product_id[1],
+ bmc->device_id);
+ }
+
+ /* create symlink from system interface device to bmc device */
+ rv = sysfs_create_link(&si->dev.dev.kobj,
+ &bmc->dev.dev.kobj, "bmc");
+ if (rv) {
+ printk(KERN_ERR
+ "ipmi_si: Unable to create bmc symlink: %d\n",
+ rv);
+ goto out_err;
+ }
+out_err:
+ return rv;
+}
+
int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
{
int i;
@@ -3093,11 +3383,29 @@ static struct notifier_block panic_block
static int ipmi_init_msghandler(void)
{
- int i;
+ int i, retval;
if (initialized)
return 0;
-
+
+ ipmi_class = class_create(THIS_MODULE, "ipmi");
+ if (IS_ERR(ipmi_class)) {
+ printk(KERN_ERR "ipmi: can't register device class\n");
+ return PTR_ERR(ipmi_class);
+ }
+
+ retval = driver_register(&ipmidriver.driver);
+ if (retval) {
+ printk(KERN_ERR PFX "Could'nt register IPMI driver\n");
+ return retval;
+ }
+
+ retval = driver_create_file(&ipmidriver.driver, &driver_attr_version);
+ if (retval) {
+ printk(KERN_ERR PFX "Could'nt register IPMI driver version attribute\n");
+ return retval;
+ }
+
printk(KERN_INFO "ipmi message handler version "
IPMI_MSGHANDLER_VERSION "\n");
@@ -3155,6 +3463,10 @@ static __exit void cleanup_ipmi(void)
remove_proc_entry(proc_ipmi_root->name, &proc_root);
#endif /* CONFIG_PROC_FS */
+ driver_unregister(&ipmidriver.driver);
+
+ class_destroy(ipmi_class);
+
initialized = 0;
/* Check for buffer leaks. */
@@ -3196,3 +3508,10 @@ EXPORT_SYMBOL(ipmi_get_my_LUN);
EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
EXPORT_SYMBOL(proc_ipmi_root);
EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
+EXPORT_SYMBOL(ipmidriver);
+EXPORT_SYMBOL(ipmi_find_bmc_guid);
+EXPORT_SYMBOL(ipmi_find_bmc_prod_dev_id);
+EXPORT_SYMBOL(ipmi_bmc_register);
+EXPORT_SYMBOL(ipmi_bmc_unregister);
+EXPORT_SYMBOL(ipmi_class);
+
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -38,6 +38,11 @@
* and drives the real SMI state machine.
*/
+/*
+ * IPMI driver model/sysfs support.
+ * Copyright (C) 2005 Yani Ioannou <yani.ioannou@gmail.com>
+ */
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -112,6 +117,7 @@ enum si_type {
struct smi_info
{
ipmi_smi_t intf;
+ struct ipmi_si_device *dev;
struct si_sm_data *si_sm;
struct si_sm_handlers *handlers;
enum si_type si_type;
@@ -175,12 +181,6 @@ struct smi_info
interrupts. */
int interrupt_disabled;
- unsigned char ipmi_si_dev_rev;
- unsigned char ipmi_si_fw_rev_major;
- unsigned char ipmi_si_fw_rev_minor;
- unsigned char ipmi_version_major;
- unsigned char ipmi_version_minor;
-
/* Slave address, could be reported from DMI. */
unsigned char slave_addr;
@@ -200,6 +200,13 @@ struct smi_info
unsigned long incoming_messages;
};
+extern struct ipmi_driver ipmidriver;
+extern struct class *ipmi_class;
+extern int ipmi_bmc_register(struct ipmi_si_device *si,
+ struct ipmi_bmc_device **bmcref);
+extern void ipmi_bmc_unregister(struct ipmi_si_device *si,
+ struct ipmi_bmc_device *bmc);
+
static void si_restart_short_timer(struct smi_info *smi_info);
static void deliver_recv_msg(struct smi_info *smi_info,
@@ -211,7 +218,6 @@ static void deliver_recv_msg(struct smi_
ipmi_smi_msg_received(smi_info->intf, msg);
spin_lock(&(smi_info->si_lock));
}
-
static void return_hosed_msg(struct smi_info *smi_info)
{
struct ipmi_smi_msg *msg = smi_info->curr_msg;
@@ -890,7 +896,6 @@ static irqreturn_t si_bt_irq_handler(int
return si_irq_handler(irq, data, regs);
}
-
static struct ipmi_smi_handlers handlers =
{
.owner = THIS_MODULE,
@@ -1351,8 +1356,9 @@ static int try_init_mem(int intf_num, st
info->io.regshift = regshifts[intf_num];
info->irq = 0;
info->irq_setup = NULL;
+
*new_info = info;
-
+
if (si_type[intf_num] == NULL)
si_type[intf_num] = "kcs";
@@ -1933,6 +1939,75 @@ static int try_init_plug_and_play(int in
return -ENODEV;
}
+static int try_get_dev_guid(struct smi_info *smi_info)
+{
+ unsigned char msg[2];
+ unsigned char *resp;
+ unsigned long resp_len;
+ enum si_sm_result smi_result;
+ int rv = 0;
+
+ smi_info->dev->bmc->guid_present = 0;
+
+ resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ /* Do a Get Device GUID command, since it might come back with a
+ * useful globally unique BMC ID. */
+ msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+ msg[1] = IPMI_GET_DEVICE_GUID_CMD;
+ smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
+
+ smi_result = smi_info->handlers->event(smi_info->si_sm, 0);
+ for (;;)
+ {
+ if (smi_result == SI_SM_CALL_WITH_DELAY) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ smi_result = smi_info->handlers->event(
+ smi_info->si_sm, 100);
+ }
+ else if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
+ {
+ smi_result = smi_info->handlers->event(
+ smi_info->si_sm, 0);
+ }
+ else
+ break;
+ }
+ if (smi_result == SI_SM_HOSED) {
+ /* We couldn't get the state machine to run, so whatever's at
+ the port is probably not an IPMI SMI interface. */
+ rv = -ENODEV;
+ goto gout;
+ }
+
+ /* Otherwise, we got some data. */
+ resp_len = smi_info->handlers->get_result(smi_info->si_sm,
+ resp, IPMI_MAX_MSG_LENGTH);
+ if (resp_len < 6) {
+ /* That's odd, it should be longer. */
+ rv = -EINVAL;
+ goto gout;
+ }
+
+ if ((resp[1] != IPMI_GET_DEVICE_GUID_CMD) || (resp[2] != 0)) {
+ /* That's odd, it shouldn't be able to fail. */
+ rv = -EINVAL;
+ goto gout;
+ }
+
+ /* Record info from the get device guid, if none returned, null
+ * terminate first char */
+ if(resp[2]){
+ memcpy(smi_info->dev->bmc->guid, &resp[3], 16);
+ smi_info->dev->bmc->guid_present = 1;
+ }
+ gout:
+ kfree(resp);
+ return rv;
+}
static int try_get_dev_id(struct smi_info *smi_info)
{
@@ -1992,11 +2067,14 @@ static int try_get_dev_id(struct smi_inf
}
/* Record info from the get device id, in case we need it. */
- smi_info->ipmi_si_dev_rev = resp[4] & 0xf;
- smi_info->ipmi_si_fw_rev_major = resp[5] & 0x7f;
- smi_info->ipmi_si_fw_rev_minor = resp[6];
- smi_info->ipmi_version_major = resp[7] & 0xf;
- smi_info->ipmi_version_minor = resp[7] >> 4;
+ smi_info->dev->bmc->device_id = resp[3];
+ memcpy(smi_info->dev->bmc->product_id, &resp[12], 2);
+ memcpy(smi_info->dev->bmc->manufacturer_id, &resp[9], 3);
+ smi_info->dev->bmc->revision = resp[4] & 0xf;
+ smi_info->dev->bmc->firmware_rev_major = resp[5] & 0x7f;
+ smi_info->dev->bmc->firmware_rev_minor = resp[6];
+ smi_info->dev->bmc->version_major = resp[7] & 0xf;
+ smi_info->dev->bmc->version_minor = resp[7] >> 4;
out:
kfree(resp);
@@ -2057,13 +2135,18 @@ static int stat_file_read_proc(char *pag
return (out - ((char *) page));
}
+static void ipmi_si_release(struct device *dev){
+ struct ipmi_si_device *si = to_ipmi_si_device(to_platform_device(dev));
+ ipmi_bmc_unregister(si, si->bmc);
+ printk(KERN_DEBUG "ipmi_si release\n");
+}
+
/* Returns 0 if initialized, or negative on an error. */
static int init_one_smi(int intf_num, struct smi_info **smi)
{
int rv;
struct smi_info *new_smi;
-
rv = try_init_mem(intf_num, &new_smi);
if (rv)
rv = try_init_port(intf_num, &new_smi);
@@ -2081,7 +2164,6 @@ static int init_one_smi(int intf_num, st
rv = try_init_plug_and_play(intf_num, &new_smi);
}
-
if (rv)
return rv;
@@ -2148,12 +2230,48 @@ static int init_one_smi(int intf_num, st
rv = -ENODEV;
goto out_err;
}
+
+ new_smi->dev = kmalloc(sizeof(struct ipmi_si_device), GFP_KERNEL);
+ if (!new_smi->dev) {
+ printk(KERN_ERR "ipmi_si: Could not allocate ipmi_si_device memory\n");
+ rv = -ENOMEM;
+ goto out_err;
+ }
+ memset(new_smi->dev, 0, sizeof(struct ipmi_si_device));
+ new_smi->dev->class_dev =
+ kmalloc(sizeof(struct class_device), GFP_KERNEL);
+ if (!new_smi->dev->class_dev) {
+ printk(KERN_ERR "ipmi_si: Could not allocate class_device memory\n");
+ rv = -ENOMEM;
+ goto out_err;
+ }
+ memset(new_smi->dev->class_dev, 0, sizeof(struct class_device));
+
+
+ /* Allocate a bmc device struct */
+ new_smi->dev->bmc = kmalloc(sizeof(struct ipmi_bmc_device), GFP_KERNEL);
+ if (!new_smi->dev->bmc) {
+ printk(KERN_ERR "ipmi_si: Could not allocate ipmi_bmc_device memory\n");
+ rv = -ENOMEM;
+ goto out_err;
+ }
+ memset(new_smi->dev->bmc, 0, sizeof(struct ipmi_bmc_device));
+
/* Attempt a get device id command. If it fails, we probably
don't have a SMI here. */
rv = try_get_dev_id(new_smi);
- if (rv)
+ if (rv){
+ printk(KERN_ERR "ipmi_si: Error while trying to get device id.\n");
+ goto out_err;
+ }
+
+ /* Attempt a get device guid command. */
+ rv = try_get_dev_guid(new_smi);
+ if (rv){
+ printk(KERN_ERR " Error while trying to get GUID.\n");
goto out_err;
+ }
/* Try to claim any interrupts. */
new_smi->irq_setup(new_smi);
@@ -2188,8 +2306,8 @@ static int init_one_smi(int intf_num, st
rv = ipmi_register_smi(&handlers,
new_smi,
- new_smi->ipmi_version_major,
- new_smi->ipmi_version_minor,
+ new_smi->dev->bmc->version_major,
+ new_smi->dev->bmc->version_minor,
new_smi->slave_addr,
&(new_smi->intf));
if (rv) {
@@ -2219,6 +2337,55 @@ static int init_one_smi(int intf_num, st
goto out_err_stop_timer;
}
+ rv = driver_register(&new_smi->handlers->driver->driver);
+ if (rv) {
+ printk(KERN_ERR
+ "ipmi_si: Unable to register driver: %d\n",
+ rv);
+ goto out_err_stop_timer;
+ }
+
+ rv = driver_create_file(&new_smi->handlers->driver->driver,
+ &new_smi->handlers->driver->version_attr);
+ if (rv) {
+ printk(KERN_ERR
+ "ipmi_si: Unable to register driver attribute: %d\n",
+ rv);
+ goto out_err_stop_timer;
+ }
+
+ new_smi->dev->smi = new_smi;
+
+ new_smi->dev->driver = new_smi->handlers->driver;
+ new_smi->dev->dev.name = "ipmi_si";
+ new_smi->dev->dev.id = intf_num;
+ new_smi->dev->dev.dev.driver = &new_smi->handlers->driver->driver;
+ new_smi->dev->dev.dev.release = ipmi_si_release;
+
+ rv = platform_device_register(&new_smi->dev->dev);
+ if (rv) {
+ printk(KERN_ERR
+ "ipmi_si: Unable to register system interface device: %d\n",
+ rv);
+ goto out_err_stop_timer;
+ }
+
+ new_smi->dev->class_dev->class = ipmi_class;
+ new_smi->dev->class_dev->dev = &new_smi->dev->dev.dev;
+ snprintf(new_smi->dev->class_dev->class_id, BUS_ID_SIZE, "smi%d",
+ intf_num);
+ class_device_register(new_smi->dev->class_dev);
+
+ /* register the attatched IPMI BMC */
+ rv = ipmi_bmc_register(new_smi->dev, &new_smi->dev->bmc);
+ if (rv) {
+ printk(KERN_ERR
+ "ipmi_si: Unable to register bmc: %d\n",
+ rv);
+ goto out_err_stop_timer;
+ }
+
+
*smi = new_smi;
printk(" IPMI %s interface initialized\n", si_type[intf_num]);
@@ -2248,7 +2415,9 @@ static int init_one_smi(int intf_num, st
if (new_smi->si_sm) {
if (new_smi->handlers)
+ {
new_smi->handlers->cleanup(new_smi->si_sm);
+ }
kfree(new_smi->si_sm);
}
new_smi->io_cleanup(new_smi);
@@ -2266,7 +2435,7 @@ static __init int init_ipmi_si(void)
if (initialized)
return 0;
initialized = 1;
-
+
/* Parse out the si_type string into its components. */
str = si_type_str;
if (*str != '\0') {
@@ -2284,12 +2453,12 @@ static __init int init_ipmi_si(void)
printk(KERN_INFO "IPMI System Interface driver version "
IPMI_SI_VERSION);
- if (kcs_smi_handlers.version)
- printk(", KCS version %s", kcs_smi_handlers.version);
- if (smic_smi_handlers.version)
- printk(", SMIC version %s", smic_smi_handlers.version);
- if (bt_smi_handlers.version)
- printk(", BT version %s", bt_smi_handlers.version);
+ if (kcs_smi_handlers.driver->version)
+ printk(", KCS version %s", kcs_smi_handlers.driver->version);
+ if (smic_smi_handlers.driver->version)
+ printk(", SMIC version %s", smic_smi_handlers.driver->version);
+ if (bt_smi_handlers.driver->version)
+ printk(", BT version %s", bt_smi_handlers.driver->version);
printk("\n");
#ifdef CONFIG_X86
@@ -2342,6 +2511,12 @@ static void __exit cleanup_one_si(struct
if (! to_clean)
return;
+ class_device_unregister(to_clean->dev->class_dev);
+ platform_device_unregister(&to_clean->dev->dev);
+ driver_remove_file(&to_clean->handlers->driver->driver,
+ &to_clean->handlers->driver->version_attr);
+ driver_unregister(&to_clean->handlers->driver->driver);
+
/* Tell the timer and interrupt handlers that we are shutting
down. */
spin_lock_irqsave(&(to_clean->si_lock), flags);
@@ -2382,7 +2557,7 @@ static void __exit cleanup_one_si(struct
}
to_clean->handlers->cleanup(to_clean->si_sm);
-
+
kfree(to_clean->si_sm);
to_clean->io_cleanup(to_clean);
diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h
--- a/drivers/char/ipmi/ipmi_si_sm.h
+++ b/drivers/char/ipmi/ipmi_si_sm.h
@@ -34,6 +34,8 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/ipmi.h>
+
/* This is defined by the state machines themselves, it is an opaque
data type for them to use. */
struct si_sm_data;
@@ -72,9 +74,10 @@ enum si_sm_result
/* Handlers for the SMI state machine. */
struct si_sm_handlers
{
- /* Put the version number of the state machine here so the
- upper layer can print it. */
- char *version;
+ /* The driver model view of the system interface state machine so it can be
+ registered/unregistered, also access to the version number so the upper
+ layer can print it. */
+ struct ipmi_si_driver *driver;
/* Initialize the data and return the amount of I/O space to
reserve for the space. */
diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c
--- a/drivers/char/ipmi/ipmi_smic_sm.c
+++ b/drivers/char/ipmi/ipmi_smic_sm.c
@@ -43,6 +43,7 @@
#include <linux/kernel.h> /* For printk. */
#include <linux/string.h>
+#include <linux/ipmi.h>
#include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h"
@@ -111,6 +112,32 @@ struct si_sm_data
long smic_timeout;
};
+static ssize_t smic_driver_show_version(struct device_driver *drv, char *buf){
+ struct ipmi_si_driver *driver = to_ipmi_si_driver(drv);
+ return snprintf(buf, 10, "%s\n", driver->version);
+}
+
+/**
+ * The driver model view of the IPMI system interface state machine.
+ */
+static struct ipmi_si_driver smic_si_driver = {
+ .owner = THIS_MODULE,
+ .version = IPMI_SMIC_VERSION,
+ .driver = {
+ .name = "ipmi_smic_sm",
+ .bus = &platform_bus_type
+ },
+ .version_attr = {
+ .attr = {
+ .name = "version",
+ .owner = THIS_MODULE,
+ .mode = S_IRUGO,
+ },
+ .show = smic_driver_show_version,
+ },
+
+};
+
static unsigned int init_smic_data (struct si_sm_data *smic,
struct si_sm_io *io)
{
@@ -588,7 +615,7 @@ static int smic_size(void)
struct si_sm_handlers smic_smi_handlers =
{
- .version = IPMI_SMIC_VERSION,
+ .driver = &smic_si_driver,
.init_data = init_smic_data,
.start_transaction = start_smic_transaction,
.get_result = smic_get_result,
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -30,10 +30,16 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/*
+ * IPMI driver model/sysfs support.
+ * Copyright (C) 2005 Yani Ioannou <yani.ioannou@gmail.com>
+ */
#ifndef __LINUX_IPMI_H
#define __LINUX_IPMI_H
+#include <linux/device.h>
+#include <linux/ipmi_smi.h>
#include <linux/ipmi_msgdefs.h>
/*
@@ -67,6 +73,108 @@
* interface is defined later in the file. */
+/**
+ * struct ipmi_si_driver - represents a ipmi system interface
+ * driver in the kernel.
+ * @owner: Pointer to the module owner of this driver; initialize
+ * it using THIS_MODULE.
+ * @version: The version of the system interface driver.
+ * @driver: the driver model core driver structure.
+ *
+ * An IPMI baseboard management controller (BMC) may be accessed directly by
+ * the host computer via a system interface of which there are many different
+ * types. This driver provides the interface defined by the general low level
+ * system interface driver.
+ */
+struct ipmi_si_driver
+{
+ struct module *owner;
+ const char *version;
+ struct device_driver driver;
+ /* driver attributes */
+ struct driver_attribute version_attr;
+};
+#define to_ipmi_si_driver(drv) container_of(drv, struct ipmi_si_driver, driver)
+
+/**
+ * struct ipmi_driver - represents the ipmi messaging interface
+ * driver in the kernel.
+ * @owner: Pointer to the module owner of this driver; initialize
+ * it using THIS_MODULE.
+ * @name: The version of the ipmi messaging interface driver.
+ * @driver: the driver model core driver structure.
+ */
+struct ipmi_driver
+{
+ struct module *owner;
+ const char *version;
+ struct device_driver driver;
+};
+#define to_ipmi_driver(drv) container_of(drv, struct ipmi_driver, driver)
+
+/**
+ * struct ipmi_si_device - represents ipmi an IPMI system interface in
+ * the kernel.
+ * @smi: the low level interface struct.
+ * @bmc: the IPMI BMC interfaced to.
+ * @driver: the IPMI system interface driver that is bound to this interface.
+ * @dev: driver model's view of this device.
+ * @class_dev: driver model's class view of this device.
+ *
+ * An IPMI baseboard management controller (BMC) may be accessed directly by
+ * the host computer via a system interface of which there are many different
+ * types. This device represents one such system interface.
+ */
+struct ipmi_si_device
+{
+ smi_info_t smi;
+ struct ipmi_bmc_device *bmc;
+ struct ipmi_si_driver *driver;
+ struct platform_device dev;
+ struct class_device *class_dev;
+};
+#define to_ipmi_si_device(device) \
+ container_of(device, struct ipmi_si_device, dev)
+
+/**
+ * struct ipmi_bmc_device - represents an IPMI baseboard management controller
+ * (BMC) attatched to one or more system interfaces.
+ * @product_id: OEM product id.
+ * @device_id: OEM per product device id (product_id+device_id unique).
+ * @guid: BMC's globally unique identifier (optional).
+ * @dev: driver model's view of this device.
+ * @version_major: the ipmi major version number of the BMC.
+ * @version_minor: the ipmi minor version number of the BMC.
+ * @revision: the ipmi BMC revision number.
+ * @firmware_rev_major: the BMC's firmware major version number.
+ * @firmware_rev_minor: the BMC's firmware minor version number.
+ */
+struct ipmi_bmc_device
+{
+ struct platform_device dev;
+ unsigned char device_id;
+ unsigned char product_id[2];
+ unsigned char manufacturer_id[3];
+ unsigned char guid[16];
+ int guid_present;
+ unsigned char version_major;
+ unsigned char version_minor;
+ unsigned char revision;
+ unsigned char firmware_rev_major;
+ unsigned char firmware_rev_minor;
+ int interfaces;
+ struct class_device *class_dev;
+ /* device attributes */
+ struct device_attribute device_id_attr;
+ struct device_attribute product_id_attr;
+ struct device_attribute manufacturer_id_attr;
+ struct device_attribute guid_attr;
+ struct device_attribute version_attr;
+ struct device_attribute revision_attr;
+ struct device_attribute firmware_rev_attr;
+};
+#define to_ipmi_bmc_device(device) \
+ container_of(device, struct ipmi_bmc_device, dev)
/*
* This is an overlay for all the address types, so it's easy to
diff --git a/include/linux/ipmi_msgdefs.h b/include/linux/ipmi_msgdefs.h
--- a/include/linux/ipmi_msgdefs.h
+++ b/include/linux/ipmi_msgdefs.h
@@ -45,6 +45,7 @@
#define IPMI_NETFN_APP_REQUEST 0x06
#define IPMI_NETFN_APP_RESPONSE 0x07
+#define IPMI_GET_DEVICE_GUID_CMD 0x08
#define IPMI_GET_DEVICE_ID_CMD 0x01
#define IPMI_CLEAR_MSG_FLAGS_CMD 0x30
#define IPMI_GET_MSG_FLAGS_CMD 0x31
diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h
--- a/include/linux/ipmi_smi.h
+++ b/include/linux/ipmi_smi.h
@@ -43,6 +43,7 @@
/* Structure for the low-level drivers. */
typedef struct ipmi_smi *ipmi_smi_t;
+typedef struct smi_info *smi_info_t;
/*
* Messages to/from the lower layer. The smi interface will take one
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] IPMI: driver model and sysfs support
2005-08-30 10:56 [PATCH] IPMI: driver model and sysfs support Yani Ioannou
@ 2005-08-30 13:22 ` Corey Minyard
2005-08-30 18:13 ` Yani Ioannou
0 siblings, 1 reply; 4+ messages in thread
From: Corey Minyard @ 2005-08-30 13:22 UTC (permalink / raw)
To: Yani Ioannou; +Cc: Martin Drab, openipmi-developer, linux-kernel
This is very good. I believe the structure is correct, but I'm not a
sysfs expert.
There are a few things we need to deal with, though.
* There are some significant changes to versioning in the
driver that are in the mm tree right now (you can pull them from
http://www.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.13-rc6/2.6.13-rc6-mm2/broken-out)
* There are some coding style problems. You have places like:
+static void ipmi_bmc_unregister(struct ipmi_si_device *si,
+ struct ipmi_bmc_device *bmc){
The '{' for functions and structures needs to be on it's own line.
Also, several:
+ if(bmc->guid_present){
that need spaces after the 'if' and before the '{'.
The patch also adds some trailing spaces to empty lines, the
following is a telltale sign:
-
+
There was also one place where you added unneeded braces to
a single statement and another where you deleted the empty line
between two functions.
These are all standard kernel coding style rules.
* I'd prefer to store the product id, device id, and manufacturer id
decoded. This makes it easier to handle (no need to use "memcmp"
to compare) and print. The printing of the product id, for instance,
will be rather unnatural in product_id_show().
* guids are not printable strings (see guid_show()).
* The printing of the guid in ipmi_bmc_register is, well, kind of ugly.
It should probably be moved to its own function that lets you pass in
the rest of the string.
-Corey
Yani Ioannou wrote:
>Hi Corey,
>
>Here is a patch against 2.6.13 I've been working on (and mentioned to
>you at OLS), that adds support for the 2.6 driver model, and sysfs to
>the ipmi subsystem. It is loosely inspired by the USB driver model
>system. There is a driver struct added for the ipmi_msghandler, and
>one for each system interface 'driver' (for each state machine in
>ipmi_si). A device struct is created for each system interface in the
>system, and for each unique BMC on the system, with a symlink between
>each system interface and the bmc it interfaces to. Each bmc has a set
>of fundamental device attributes, and each of the drivers has a
>version attribute reflecting the driver/state machine versions.
>Furthermore each of these devices is registered as a class_device with
>the ipmi class (moved to ipmi_msghandler) as bmcx and smix.
>
>This in effect creates the following sysfs interface on a machine with
>a single BMC and two interfaces:
>
>/sys/
>|-- block
>|-- bus
>| |-- platform
>| | |-- devices
>| | | |-- ipmi_bmc.0 -> ../../../devices/platform/ipmi_bmc.0
>| | | |-- ipmi_si.0 -> ../../../devices/platform/ipmi_si.0
>| | | |-- ipmi_si.1 -> ../../../devices/platform/ipmi_si.1
>| | `-- drivers
>| | |-- ipmi_bt_sm
>| | | |-- bind
>| | | |-- ipmi_si.1 -> ../../../../devices/platform/ipmi_si.1
>| | | |-- unbind
>| | | `-- version
>| | |-- ipmi_kcs_sm
>| | | |-- bind
>| | | |-- ipmi_si.0 -> ../../../../devices/platform/ipmi_si.0
>| | | |-- unbind
>| | | `-- version
>| | |-- ipmi_msghandler
>| | | |-- bind
>| | | |-- ipmi_bmc.0 -> ../../../../devices/platform/ipmi_bmc.0
>| | | |-- unbind
>| | | `-- version
>|-- class
>| |-- ipmi
>| | |-- bmc0
>| | | `-- device -> ../../../devices/platform/ipmi_bmc.0
>| | |-- ipmi0
>| | | `-- dev
>| | |-- ipmi1
>| | | `-- dev
>| | |-- smi0
>| | | `-- device -> ../../../devices/platform/ipmi_si.0
>| | `-- smi1
>| | `-- device -> ../../../devices/platform/ipmi_si.1
>|-- devices
>| |-- platform
>| | |-- ipmi_bmc.0
>| | | |-- bus -> ../../../bus/platform
>| | | |-- device_id
>| | | |-- driver -> ../../../bus/platform/drivers/ipmi_msghandler
>| | | |-- firmware_revision
>| | | |-- ipmi_version
>| | | |-- power
>| | | | `-- state
>| | | |-- product_id
>| | | `-- revision
>| | |-- ipmi_si.0
>| | | |-- bmc -> ../../../devices/platform/ipmi_bmc.0
>| | | |-- bus -> ../../../bus/platform
>| | | |-- driver -> ../../../bus/platform/drivers/ipmi_kcs_sm
>| | | `-- power
>| | | `-- state
>| | |-- ipmi_si.1
>| | | |-- bmc -> ../../../devices/platform/ipmi_bmc.0
>| | | |-- bus -> ../../../bus/platform
>| | | |-- driver -> ../../../bus/platform/drivers/ipmi_bt_sm
>| | | `-- power
>| | | `-- state
>|-- kernel
>|-- module
>| |-- ipmi_devintf
>| | |-- refcnt
>| | `-- sections
>| | `-- __param
>| |-- ipmi_msghandler
>| | |-- refcnt
>| | `-- sections
>| | |-- __ksymtab
>| | `-- __ksymtab_strings
>| |-- ipmi_si
>| | |-- refcnt
>| | `-- sections
>| | `-- __param
>`-- power
>
>My motiviation for the patch is to have a device struct (bmc) to
>register with the new hwmon class for my in-progress hwmon driver
>ipmi_sensors. With this patch the driver can create device attributes
>under bmc devices representing sensor readings for the
>hwmon/lm_sensors interface.
>
>I have tested the patch on two systems of mine with a single bmc, it
>should however also work for a machine with multiple bmcs using the
>guid/product+device id to differentiate.
>
>Thanks,
>Yani
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] IPMI: driver model and sysfs support
2005-08-30 13:22 ` Corey Minyard
@ 2005-08-30 18:13 ` Yani Ioannou
2005-11-26 12:04 ` Yani Ioannou
0 siblings, 1 reply; 4+ messages in thread
From: Yani Ioannou @ 2005-08-30 18:13 UTC (permalink / raw)
To: Corey Minyard; +Cc: Martin Drab, openipmi-developer, linux-kernel
On 8/30/05, Corey Minyard <minyard@acm.org> wrote:
> This is very good. I believe the structure is correct, but I'm not a
> sysfs expert.
>
> There are a few things we need to deal with, though.
>
> * There are some significant changes to versioning in the
> driver that are in the mm tree right now (you can pull them from
>
> http://www.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.13-rc6/2.6.13-rc6-mm2/broken-out)
Gah, ok :), I'll try to apply with the -mm changes.
> * There are some coding style problems. You have places like:
> +static void ipmi_bmc_unregister(struct ipmi_si_device *si,
> + struct ipmi_bmc_device *bmc){
> The '{' for functions and structures needs to be on it's own line.
> Also, several:
> + if(bmc->guid_present){
> that need spaces after the 'if' and before the '{'.
> The patch also adds some trailing spaces to empty lines, the
> following is a telltale sign:
> -
> +
> There was also one place where you added unneeded braces to
> a single statement and another where you deleted the empty line
> between two functions.
> These are all standard kernel coding style rules.
Yes, I should have caught those, thanks.
> * I'd prefer to store the product id, device id, and manufacturer id
> decoded. This makes it easier to handle (no need to use "memcmp"
> to compare) and print. The printing of the product id, for instance,
> will be rather unnatural in product_id_show().
I was under the impression that they were just OEM strings, and not
necessarily ASCII strings? I'll have a look at the specs again.
> * guids are not printable strings (see guid_show()).
guid_show, sounds useful!
Thanks,
Yani
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] IPMI: driver model and sysfs support
2005-08-30 18:13 ` Yani Ioannou
@ 2005-11-26 12:04 ` Yani Ioannou
0 siblings, 0 replies; 4+ messages in thread
From: Yani Ioannou @ 2005-11-26 12:04 UTC (permalink / raw)
To: Corey Minyard; +Cc: Martin Drab, openipmi-developer, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 494 bytes --]
Hi Corey,
On 8/30/05, Yani Ioannou <yani.ioannou@gmail.com> wrote:
> On 8/30/05, Corey Minyard <minyard@acm.org> wrote:
> > This is very good. I believe the structure is correct, but I'm not a
> > sysfs expert.
> >
> > There are a few things we need to deal with, though.
<snip>
Sorry it has been quite a while .. anyway I finally got around to
updating the patch with the changes you proposed, and attached is a
patch against the latest git (2.6.15-rc2-git6).
Thanks,
Yani
[-- Attachment #2: patch-linux-2.6.15-rc2-git6-ipmisysfs.diff --]
[-- Type: text/x-patch, Size: 34696 bytes --]
---
drivers/char/ipmi/ipmi_bt_sm.c | 13 +
drivers/char/ipmi/ipmi_devintf.c | 11 -
drivers/char/ipmi/ipmi_kcs_sm.c | 13 +
drivers/char/ipmi/ipmi_msghandler.c | 374 +++++++++++++++++++++++++++++++++++
drivers/char/ipmi/ipmi_si_intf.c | 200 ++++++++++++++++---
drivers/char/ipmi/ipmi_si_sm.h | 9 +
drivers/char/ipmi/ipmi_smic_sm.c | 13 +
include/linux/ipmi.h | 127 ++++++++++++
include/linux/ipmi_msgdefs.h | 1
include/linux/ipmi_smi.h | 1
10 files changed, 723 insertions(+), 39 deletions(-)
applies-to: 1f3b06d516dac26c976cedfc59cd48781b96f86d
93ace52e69e5cc5258abb14a8c6c8786ca7d209b
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c
index 58dcdee..648ab0b 100644
--- a/drivers/char/ipmi/ipmi_bt_sm.c
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
@@ -28,6 +28,7 @@
#include <linux/kernel.h> /* For printk. */
#include <linux/string.h>
+#include <linux/ipmi.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ipmi_msgdefs.h> /* for completion codes */
@@ -105,6 +106,17 @@ struct si_sm_data {
#define BT_INTMASK_R bt->io->inputb(bt->io, 2)
#define BT_INTMASK_W(x) bt->io->outputb(bt->io, 2, x)
+/**
+ * The driver model view of the IPMI system interface state machine.
+ */
+static struct ipmi_si_driver bt_si_driver = {
+ .owner = THIS_MODULE,
+ .driver = {
+ .name = "ipmi_bt_sm",
+ .bus = &platform_bus_type
+ },
+};
+
/* Convenience routines for debugging. These are not multi-open safe!
Note the macros have hardcoded variables in them. */
@@ -513,6 +525,7 @@ static int bt_size(void)
struct si_sm_handlers bt_smi_handlers =
{
+ .driver = &bt_si_driver,
.init_data = bt_init_data,
.start_transaction = bt_start_transaction,
.get_result = bt_get_result,
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index 7c0684d..c0e3cc5 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -789,7 +789,7 @@ MODULE_PARM_DESC(ipmi_major, "Sets the m
" interface. Other values will set the major device number"
" to that value.");
-static struct class *ipmi_class;
+extern struct class *ipmi_class;
static void ipmi_new_smi(int if_num)
{
@@ -823,15 +823,8 @@ static __init int init_ipmi_devintf(void
printk(KERN_INFO "ipmi device interface\n");
- ipmi_class = class_create(THIS_MODULE, "ipmi");
- if (IS_ERR(ipmi_class)) {
- printk(KERN_ERR "ipmi: can't register device class\n");
- return PTR_ERR(ipmi_class);
- }
-
rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
if (rv < 0) {
- class_destroy(ipmi_class);
printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
return rv;
}
@@ -845,7 +838,6 @@ static __init int init_ipmi_devintf(void
rv = ipmi_smi_watcher_register(&smi_watcher);
if (rv) {
unregister_chrdev(ipmi_major, DEVICE_NAME);
- class_destroy(ipmi_class);
printk(KERN_WARNING "ipmi: can't register smi watcher\n");
return rv;
}
@@ -856,7 +848,6 @@ module_init(init_ipmi_devintf);
static __exit void cleanup_ipmi(void)
{
- class_destroy(ipmi_class);
ipmi_smi_watcher_unregister(&smi_watcher);
devfs_remove(DEVICE_NAME);
unregister_chrdev(ipmi_major, DEVICE_NAME);
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c
index da15541..6e71315 100644
--- a/drivers/char/ipmi/ipmi_kcs_sm.c
+++ b/drivers/char/ipmi/ipmi_kcs_sm.c
@@ -41,6 +41,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/string.h>
+#include <linux/ipmi.h>
#include <linux/jiffies.h>
#include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h"
@@ -120,6 +121,17 @@ struct si_sm_data
unsigned long error0_timeout;
};
+/**
+ * The driver model view of the IPMI system interface state machine.
+ */
+static struct ipmi_si_driver kcs_si_driver = {
+ .owner = THIS_MODULE,
+ .driver = {
+ .name = "ipmi_kcs_sm",
+ .bus = &platform_bus_type
+ },
+};
+
static unsigned int init_kcs_data(struct si_sm_data *kcs,
struct si_sm_io *io)
{
@@ -509,6 +521,7 @@ static void kcs_cleanup(struct si_sm_dat
struct si_sm_handlers kcs_smi_handlers =
{
+ .driver = &kcs_si_driver,
.init_data = init_kcs_data,
.start_transaction = start_kcs_transaction,
.get_result = get_kcs_result,
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 6b302a9..1b4c9b8 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -30,6 +30,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/*
+ * IPMI driver model/sysfs support.
+ * Copyright (C) 2005 Yani Ioannou <yani.ioannou@gmail.com>
+ */
#include <linux/config.h>
#include <linux/module.h>
@@ -66,6 +70,13 @@ struct proc_dir_entry *proc_ipmi_root =
#define MAX_MSG_TIMEOUT 60000
+#define IPMI_DEVICE_MANUFACTURER_ID(man_id) \
+ ((long unsigned int) (man_id[2] << 16 | man_id[1] << 8 | man_id[0]))
+
+#define IPMI_DEVICE_PRODUCT_ID(product_id) \
+ ((long unsigned int) (product_id[1] << 8 | product_id[0]))
+
+
/*
* The main "user" data structure.
*/
@@ -319,6 +330,19 @@ struct ipmi_smi
#define IPMI_INVALID_INTERFACE(i) (((i) == NULL) \
|| (i == IPMI_INVALID_INTERFACE_ENTRY))
+struct class *ipmi_class;
+
+/**
+ * The driver model view of the IPMI messaging driver.
+ */
+static struct ipmi_driver ipmidriver = {
+ .owner = THIS_MODULE,
+ .driver = {
+ .name = "ipmi_msghandler",
+ .bus = &platform_bus_type
+ }
+};
+
#define MAX_IPMI_INTERFACES 4
static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES];
@@ -378,6 +402,330 @@ static void intf_free(struct kref *ref)
kfree(intf);
}
+static int __find_bmc_guid(struct device *dev, void *data)
+{
+ unsigned char *id = (unsigned char *) data;
+ struct ipmi_bmc_device *bmc =
+ to_ipmi_bmc_device(to_platform_device(dev));
+
+ return memcmp(bmc->guid, id, 16) == 0;
+}
+
+struct ipmi_bmc_device * ipmi_find_bmc_guid(struct ipmi_driver *drv,
+ unsigned char* guid)
+{
+ struct device *dev = driver_find_device(&drv->driver, NULL, guid,
+ __find_bmc_guid);
+ return (dev?to_ipmi_bmc_device(to_platform_device(dev)):NULL);
+}
+
+struct prod_dev_id{
+ unsigned char product_id[2];
+ unsigned char device_id;
+};
+
+static int __find_bmc_prod_dev_id(struct device *dev, void *data)
+{
+ struct prod_dev_id *id = (struct prod_dev_id *) data;
+ struct ipmi_bmc_device *bmc =
+ to_ipmi_bmc_device(to_platform_device(dev));
+
+ return bmc->id.product_id[0] == id->product_id[0]
+ && bmc->id.product_id[1] == id->product_id[1]
+ && bmc->id.device_id == id->device_id;
+}
+
+struct ipmi_bmc_device * ipmi_find_bmc_prod_dev_id(struct ipmi_driver *drv,
+ unsigned char *product_id, unsigned char *device_id)
+{
+ struct prod_dev_id id = {
+ .product_id = {product_id[0], product_id[1]},
+ .device_id = *device_id,
+ };
+
+ struct device *dev = driver_find_device(&drv->driver, NULL, &id,
+ __find_bmc_prod_dev_id);
+ return (dev?to_ipmi_bmc_device(to_platform_device(dev)):NULL);
+}
+
+static void ipmi_bmc_release(struct device *dev)
+{
+ printk(KERN_DEBUG "ipmi_bmc release\n");
+}
+
+static ssize_t device_id_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 10, "%u\n", bmc->id.device_id);
+}
+
+static ssize_t provides_dev_sdrs_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 10, "%u\n",
+ bmc->id.device_revision && 0x80 >> 7);
+}
+
+static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 20, "%u\n",
+ bmc->id.device_revision && 0x0F);
+}
+
+static ssize_t firmware_rev_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_rev_1,
+ bmc->id.firmware_rev_2);
+}
+
+static ssize_t ipmi_version_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 20, "%u.%u\n",
+ ipmi_version_major(&bmc->id),
+ ipmi_version_minor(&bmc->id));
+}
+
+static ssize_t add_dev_support_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 10, "0x%02x\n", bmc->id.additional_device_support);
+}
+
+static ssize_t manufacturer_id_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 20, "%lu\n",
+ IPMI_DEVICE_MANUFACTURER_ID(bmc->id.manufacturer_id));
+}
+
+static ssize_t product_id_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 10, "%lu\n",
+ IPMI_DEVICE_PRODUCT_ID(bmc->id.product_id));
+}
+
+static ssize_t aux_firmware_rev_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ bmc->id.aux_firmware_revision[3],
+ bmc->id.aux_firmware_revision[2],
+ bmc->id.aux_firmware_revision[1],
+ bmc->id.aux_firmware_revision[0]);
+}
+
+static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipmi_bmc_device *bmc = to_ipmi_bmc_device(to_platform_device(dev));
+ return snprintf(buf, 100, "%Lx%Lx\n",
+ (long long) bmc->guid[0],
+ (long long) bmc->guid[8]);
+}
+
+void ipmi_bmc_unregister(struct ipmi_si_device *si,
+ struct ipmi_bmc_device *bmc)
+{
+ if(--bmc->interfaces == 0){
+ class_device_unregister(bmc->class_dev);
+ device_remove_file(&bmc->dev.dev,
+ &bmc->device_id_attr);
+ device_remove_file(&bmc->dev.dev,
+ &bmc->provides_dev_sdrs_attr);
+ device_remove_file(&bmc->dev.dev,
+ &bmc->revision_attr);
+ device_remove_file(&bmc->dev.dev,
+ &bmc->firmware_rev_attr);
+ device_remove_file(&bmc->dev.dev,
+ &bmc->version_attr);
+ device_remove_file(&bmc->dev.dev,
+ &bmc->add_dev_support_attr);
+ device_remove_file(&bmc->dev.dev,
+ &bmc->manufacturer_id_attr);
+ device_remove_file(&bmc->dev.dev,
+ &bmc->product_id_attr);
+ device_remove_file(&bmc->dev.dev,
+ &bmc->aux_firmware_rev_attr);
+ if(bmc->guid_present)
+ device_remove_file(&bmc->dev.dev,
+ &bmc->guid_attr);
+ platform_device_unregister(&bmc->dev);
+ }
+}
+
+int ipmi_bmc_register(struct ipmi_si_device *si,
+ struct ipmi_bmc_device **bmcref)
+{
+ int rv = 0;
+ struct ipmi_bmc_device *bmc = *bmcref;
+ struct ipmi_bmc_device *new_bmc;
+
+ /* Try to find if there is an ipmi_bmc_device struct
+ * representing the interfaced BMC already
+ */
+ if(bmc->guid_present){
+ new_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
+ }else{
+ new_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
+ bmc->id.product_id,
+ &bmc->id.device_id);
+ }
+ /* If there is already an ipmi_bmc_device, free the new one,
+ * otherwise register the new BMC device
+ */
+ if(new_bmc){
+ kfree(bmc);
+ *bmcref = new_bmc;
+ bmc = new_bmc;
+
+ bmc->interfaces++;
+
+ printk(KERN_INFO
+ "ipmi_si: interfacing existing BMC (man_id: %lu, \
+prod_id: %lu, dev_id: %u)\n",
+ IPMI_DEVICE_MANUFACTURER_ID(bmc->id.manufacturer_id),
+ IPMI_DEVICE_PRODUCT_ID(bmc->id.product_id),
+ bmc->id.device_id);
+ }else{
+ bmc->dev.name = "ipmi_bmc";
+ bmc->dev.id = bmc->id.device_id;
+ bmc->dev.dev.driver = &ipmidriver.driver;
+ bmc->dev.dev.release = ipmi_bmc_release;
+ bmc->interfaces = 1;
+
+ rv = platform_device_register(&bmc->dev);
+ if (rv) {
+ printk(KERN_ERR
+ "ipmi_si: Unable to register bmc device: %d\n",
+ rv);
+ goto out_err;
+ }
+
+ bmc->device_id_attr.attr.name = "device_id";
+ bmc->device_id_attr.attr.owner = THIS_MODULE;
+ bmc->device_id_attr.attr.mode = S_IRUGO;
+ bmc->device_id_attr.show = device_id_show;
+
+ bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
+ bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE;
+ bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
+ bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
+
+
+ bmc->revision_attr.attr.name = "revision";
+ bmc->revision_attr.attr.owner = THIS_MODULE;
+ bmc->revision_attr.attr.mode = S_IRUGO;
+ bmc->revision_attr.show = revision_show;
+
+ bmc->firmware_rev_attr.attr.name = "firmware_revision";
+ bmc->firmware_rev_attr.attr.owner = THIS_MODULE;
+ bmc->firmware_rev_attr.attr.mode = S_IRUGO;
+ bmc->firmware_rev_attr.show = firmware_rev_show;
+
+ bmc->version_attr.attr.name = "ipmi_version";
+ bmc->version_attr.attr.owner = THIS_MODULE;
+ bmc->version_attr.attr.mode = S_IRUGO;
+ bmc->version_attr.show = ipmi_version_show;
+
+ bmc->add_dev_support_attr.attr.name = "additional_device_support";
+ bmc->add_dev_support_attr.attr.owner = THIS_MODULE;
+ bmc->add_dev_support_attr.attr.mode = S_IRUGO;
+ bmc->add_dev_support_attr.show = add_dev_support_show;
+
+ bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
+ bmc->manufacturer_id_attr.attr.owner = THIS_MODULE;
+ bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
+ bmc->manufacturer_id_attr.show = manufacturer_id_show;
+
+ bmc->product_id_attr.attr.name = "product_id";
+ bmc->product_id_attr.attr.owner = THIS_MODULE;
+ bmc->product_id_attr.attr.mode = S_IRUGO;
+ bmc->product_id_attr.show = product_id_show;
+
+ bmc->guid_attr.attr.name = "guid";
+ bmc->guid_attr.attr.owner = THIS_MODULE;
+ bmc->guid_attr.attr.mode = S_IRUGO;
+ bmc->guid_attr.show = guid_show;
+
+ bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
+ bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE;
+ bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
+ bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
+
+ device_create_file(&bmc->dev.dev,
+ &bmc->device_id_attr);
+ device_create_file(&bmc->dev.dev,
+ &bmc->provides_dev_sdrs_attr);
+ device_create_file(&bmc->dev.dev,
+ &bmc->revision_attr);
+ device_create_file(&bmc->dev.dev,
+ &bmc->firmware_rev_attr);
+ device_create_file(&bmc->dev.dev,
+ &bmc->version_attr);
+ device_create_file(&bmc->dev.dev,
+ &bmc->add_dev_support_attr);
+ device_create_file(&bmc->dev.dev,
+ &bmc->manufacturer_id_attr);
+ device_create_file(&bmc->dev.dev,
+ &bmc->product_id_attr);
+ device_create_file(&bmc->dev.dev,
+ &bmc->aux_firmware_rev_attr);
+
+ if(bmc->guid_present)
+ device_create_file(&bmc->dev.dev,
+ &bmc->guid_attr);
+
+ bmc->class_dev =
+ kmalloc(sizeof(struct class_device), GFP_KERNEL);
+ if (!bmc->class_dev) {
+ printk(KERN_ERR "ipmi_msghandler: Could not allocate class_device memory\n");
+ rv = -ENOMEM;
+ goto out_err;
+ }
+ memset(bmc->class_dev, 0, sizeof(struct class_device));
+
+
+ bmc->class_dev->class = ipmi_class;
+ bmc->class_dev->dev = &bmc->dev.dev;
+ snprintf(bmc->class_dev->class_id, BUS_ID_SIZE, "bmc%d",
+ bmc->id.device_id);
+
+ class_device_register(bmc->class_dev);
+
+ printk(KERN_INFO
+ "ipmi_si: Found new BMC (man_id: %lu, prod_id: %lu, \
+dev_id: %u)\n",
+ IPMI_DEVICE_MANUFACTURER_ID(bmc->id.manufacturer_id),
+ IPMI_DEVICE_PRODUCT_ID(bmc->id.product_id),
+ bmc->id.device_id);
+ }
+
+ /* create symlink from system interface device to bmc device */
+ rv = sysfs_create_link(&si->dev.dev.kobj,
+ &bmc->dev.dev.kobj, "bmc");
+ if (rv) {
+ printk(KERN_ERR
+ "ipmi_si: Unable to create bmc symlink: %d\n",
+ rv);
+ goto out_err;
+ }
+out_err:
+ return rv;
+}
+
int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
{
int i;
@@ -3194,11 +3542,23 @@ static struct notifier_block panic_block
static int ipmi_init_msghandler(void)
{
- int i;
+ int i, retval;
if (initialized)
return 0;
-
+
+ ipmi_class = class_create(THIS_MODULE, "ipmi");
+ if (IS_ERR(ipmi_class)) {
+ printk(KERN_ERR "ipmi: can't register device class\n");
+ return PTR_ERR(ipmi_class);
+ }
+
+ retval = driver_register(&ipmidriver.driver);
+ if (retval) {
+ printk(KERN_ERR PFX "Could'nt register IPMI driver\n");
+ return retval;
+ }
+
printk(KERN_INFO "ipmi message handler version "
IPMI_DRIVER_VERSION "\n");
@@ -3255,6 +3615,10 @@ static __exit void cleanup_ipmi(void)
remove_proc_entry(proc_ipmi_root->name, &proc_root);
#endif /* CONFIG_PROC_FS */
+ driver_unregister(&ipmidriver.driver);
+
+ class_destroy(ipmi_class);
+
initialized = 0;
/* Check for buffer leaks. */
@@ -3300,3 +3664,9 @@ EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
EXPORT_SYMBOL(proc_ipmi_root);
EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
EXPORT_SYMBOL(ipmi_free_recv_msg);
+EXPORT_SYMBOL(ipmidriver);
+EXPORT_SYMBOL(ipmi_find_bmc_guid);
+EXPORT_SYMBOL(ipmi_find_bmc_prod_dev_id);
+EXPORT_SYMBOL(ipmi_bmc_register);
+EXPORT_SYMBOL(ipmi_bmc_unregister);
+EXPORT_SYMBOL(ipmi_class);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 01a1f6b..d824597 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -38,6 +38,11 @@
* and drives the real SMI state machine.
*/
+/*
+ * IPMI driver model/sysfs support.
+ * Copyright (C) 2005 Yani Ioannou <yani.ioannou@gmail.com>
+ */
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -110,25 +115,11 @@ enum si_type {
SI_KCS, SI_SMIC, SI_BT
};
-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 char manufacturer_id[3];
- unsigned char product_id[2];
- unsigned char aux_firmware_revision[4];
-} __attribute__((packed));
-
-#define ipmi_version_major(v) ((v)->ipmi_version & 0xf)
-#define ipmi_version_minor(v) ((v)->ipmi_version >> 4)
-
struct smi_info
{
int intf_num;
ipmi_smi_t intf;
+ struct ipmi_si_device *dev;
struct si_sm_data *si_sm;
struct si_sm_handlers *handlers;
enum si_type si_type;
@@ -203,8 +194,6 @@ struct smi_info
interrupts. */
int interrupt_disabled;
- struct ipmi_device_id device_id;
-
/* Slave address, could be reported from DMI. */
unsigned char slave_addr;
@@ -232,6 +221,13 @@ static int register_xaction_notifier(str
return notifier_chain_register(&xaction_notifier_list, nb);
}
+extern struct ipmi_driver ipmidriver;
+extern struct class *ipmi_class;
+extern int ipmi_bmc_register(struct ipmi_si_device *si,
+ struct ipmi_bmc_device **bmcref);
+extern void ipmi_bmc_unregister(struct ipmi_si_device *si,
+ struct ipmi_bmc_device *bmc);
+
static void si_restart_short_timer(struct smi_info *smi_info);
static void deliver_recv_msg(struct smi_info *smi_info,
@@ -1934,6 +1930,75 @@ static int try_init_plug_and_play(int in
return -ENODEV;
}
+static int try_get_dev_guid(struct smi_info *smi_info)
+{
+ unsigned char msg[2];
+ unsigned char *resp;
+ unsigned long resp_len;
+ enum si_sm_result smi_result;
+ int rv = 0;
+
+ smi_info->dev->bmc->guid_present = 0;
+
+ resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ /* Do a Get Device GUID command, since it might come back with a
+ * useful globally unique BMC ID. */
+ msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+ msg[1] = IPMI_GET_DEVICE_GUID_CMD;
+ smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
+
+ smi_result = smi_info->handlers->event(smi_info->si_sm, 0);
+ for (;;)
+ {
+ if (smi_result == SI_SM_CALL_WITH_DELAY) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ smi_result = smi_info->handlers->event(
+ smi_info->si_sm, 100);
+ }
+ else if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
+ {
+ smi_result = smi_info->handlers->event(
+ smi_info->si_sm, 0);
+ }
+ else
+ break;
+ }
+ if (smi_result == SI_SM_HOSED) {
+ /* We couldn't get the state machine to run, so whatever's at
+ the port is probably not an IPMI SMI interface. */
+ rv = -ENODEV;
+ goto gout;
+ }
+
+ /* Otherwise, we got some data. */
+ resp_len = smi_info->handlers->get_result(smi_info->si_sm,
+ resp, IPMI_MAX_MSG_LENGTH);
+ if (resp_len < 6) {
+ /* That's odd, it should be longer. */
+ rv = -EINVAL;
+ goto gout;
+ }
+
+ if ((resp[1] != IPMI_GET_DEVICE_GUID_CMD) || (resp[2] != 0)) {
+ /* That's odd, it shouldn't be able to fail. */
+ rv = -EINVAL;
+ goto gout;
+ }
+
+ /* Record info from the get device guid, if none returned, null
+ * terminate first char */
+ if(resp[2]){
+ memcpy(smi_info->dev->bmc->guid, &resp[3], 16);
+ smi_info->dev->bmc->guid_present = 1;
+ }
+ gout:
+ kfree(resp);
+ return rv;
+}
static int try_get_dev_id(struct smi_info *smi_info)
{
@@ -1993,8 +2058,8 @@ static int try_get_dev_id(struct smi_inf
}
/* Record info from the get device id, in case we need it. */
- memcpy(&smi_info->device_id, &resp[3],
- min_t(unsigned long, resp_len-3, sizeof(smi_info->device_id)));
+ memcpy(&smi_info->dev->bmc->id, &resp[3],
+ min_t(unsigned long, resp_len-3, sizeof(struct bmc_device_id)));
out:
kfree(resp);
@@ -2100,7 +2165,7 @@ static int oem_data_avail_to_receive_msg
#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info)
{
- struct ipmi_device_id *id = &smi_info->device_id;
+ struct bmc_device_id *id = &smi_info->dev->bmc->id;
const char mfr[3]=DELL_IANA_MFR_ID;
if (! memcmp(mfr, id->manufacturer_id, sizeof(mfr))) {
if (id->device_id == DELL_POWEREDGE_8G_BMC_DEVICE_ID &&
@@ -2176,7 +2241,7 @@ static struct notifier_block dell_powere
static void
setup_dell_poweredge_bt_xaction_handler(struct smi_info *smi_info)
{
- struct ipmi_device_id *id = &smi_info->device_id;
+ struct bmc_device_id *id = &smi_info->dev->bmc->id;
const char mfr[3]=DELL_IANA_MFR_ID;
if (! memcmp(mfr, id->manufacturer_id, sizeof(mfr)) &&
smi_info->si_type == SI_BT)
@@ -2208,6 +2273,13 @@ static inline void wait_for_timer_and_th
del_timer_sync(&smi_info->si_timer);
}
+static void ipmi_si_release(struct device *dev)
+{
+ struct ipmi_si_device *si = to_ipmi_si_device(to_platform_device(dev));
+ ipmi_bmc_unregister(si, si->bmc);
+ printk(KERN_DEBUG "ipmi_si release\n");
+}
+
/* Returns 0 if initialized, or negative on an error. */
static int init_one_smi(int intf_num, struct smi_info **smi)
{
@@ -2295,12 +2367,48 @@ static int init_one_smi(int intf_num, st
rv = -ENODEV;
goto out_err;
}
+
+ new_smi->dev = kmalloc(sizeof(struct ipmi_si_device), GFP_KERNEL);
+ if (!new_smi->dev) {
+ printk(KERN_ERR "ipmi_si: Could not allocate ipmi_si_device memory\n");
+ rv = -ENOMEM;
+ goto out_err;
+ }
+ memset(new_smi->dev, 0, sizeof(struct ipmi_si_device));
+ new_smi->dev->class_dev =
+ kmalloc(sizeof(struct class_device), GFP_KERNEL);
+ if (!new_smi->dev->class_dev) {
+ printk(KERN_ERR "ipmi_si: Could not allocate class_device memory\n");
+ rv = -ENOMEM;
+ goto out_err;
+ }
+ memset(new_smi->dev->class_dev, 0, sizeof(struct class_device));
+
+
+ /* Allocate a bmc device struct */
+ new_smi->dev->bmc = kmalloc(sizeof(struct ipmi_bmc_device), GFP_KERNEL);
+ if (!new_smi->dev->bmc) {
+ printk(KERN_ERR "ipmi_si: Could not allocate ipmi_bmc_device memory\n");
+ rv = -ENOMEM;
+ goto out_err;
+ }
+ memset(new_smi->dev->bmc, 0, sizeof(struct ipmi_bmc_device));
+
/* Attempt a get device id command. If it fails, we probably
don't have a SMI here. */
rv = try_get_dev_id(new_smi);
- if (rv)
+ if (rv){
+ printk(KERN_ERR "ipmi_si: Error while trying to get device id.\n");
+ goto out_err;
+ }
+
+ /* Attempt a get device guid command. */
+ rv = try_get_dev_guid(new_smi);
+ if (rv){
+ printk(KERN_ERR " Error while trying to get GUID.\n");
goto out_err;
+ }
setup_oem_data_handler(new_smi);
setup_xaction_handlers(new_smi);
@@ -2342,8 +2450,8 @@ static int init_one_smi(int intf_num, st
rv = ipmi_register_smi(&handlers,
new_smi,
- ipmi_version_major(&new_smi->device_id),
- ipmi_version_minor(&new_smi->device_id),
+ ipmi_version_major(&new_smi->dev->bmc->id),
+ ipmi_version_minor(&new_smi->dev->bmc->id),
new_smi->slave_addr,
&(new_smi->intf));
if (rv) {
@@ -2373,6 +2481,46 @@ static int init_one_smi(int intf_num, st
goto out_err_stop_timer;
}
+ rv = driver_register(&new_smi->handlers->driver->driver);
+ if (rv) {
+ printk(KERN_ERR
+ "ipmi_si: Unable to register driver: %d\n",
+ rv);
+ goto out_err_stop_timer;
+ }
+
+ new_smi->dev->smi = new_smi;
+
+ new_smi->dev->driver = new_smi->handlers->driver;
+ new_smi->dev->dev.name = "ipmi_si";
+ new_smi->dev->dev.id = intf_num;
+ new_smi->dev->dev.dev.driver = &new_smi->handlers->driver->driver;
+ new_smi->dev->dev.dev.release = ipmi_si_release;
+
+ rv = platform_device_register(&new_smi->dev->dev);
+ if (rv) {
+ printk(KERN_ERR
+ "ipmi_si: Unable to register system interface device: %d\n",
+ rv);
+ goto out_err_stop_timer;
+ }
+
+ new_smi->dev->class_dev->class = ipmi_class;
+ new_smi->dev->class_dev->dev = &new_smi->dev->dev.dev;
+ snprintf(new_smi->dev->class_dev->class_id, BUS_ID_SIZE, "smi%d",
+ intf_num);
+ class_device_register(new_smi->dev->class_dev);
+
+ /* register the attatched IPMI BMC */
+ rv = ipmi_bmc_register(new_smi->dev, &new_smi->dev->bmc);
+ if (rv) {
+ printk(KERN_ERR
+ "ipmi_si: Unable to register bmc: %d\n",
+ rv);
+ goto out_err_stop_timer;
+ }
+
+
*smi = new_smi;
printk(" IPMI %s interface initialized\n", si_type[intf_num]);
@@ -2482,6 +2630,10 @@ static void __exit cleanup_one_si(struct
if (! to_clean)
return;
+ class_device_unregister(to_clean->dev->class_dev);
+ platform_device_unregister(&to_clean->dev->dev);
+ driver_unregister(&to_clean->handlers->driver->driver);
+
/* Tell the timer and interrupt handlers that we are shutting
down. */
spin_lock_irqsave(&(to_clean->si_lock), flags);
diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h
index bf3d496..c507c65 100644
--- a/drivers/char/ipmi/ipmi_si_sm.h
+++ b/drivers/char/ipmi/ipmi_si_sm.h
@@ -34,6 +34,8 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/ipmi.h>
+
/* This is defined by the state machines themselves, it is an opaque
data type for them to use. */
struct si_sm_data;
@@ -73,9 +75,10 @@ enum si_sm_result
/* Handlers for the SMI state machine. */
struct si_sm_handlers
{
- /* Put the version number of the state machine here so the
- upper layer can print it. */
- char *version;
+ /* The driver model view of the system interface state machine so it can be
+ registered/unregistered, also access to the version number so the upper
+ layer can print it. */
+ struct ipmi_si_driver *driver;
/* Initialize the data and return the amount of I/O space to
reserve for the space. */
diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c
index 39d7e5e..cf7ccaf 100644
--- a/drivers/char/ipmi/ipmi_smic_sm.c
+++ b/drivers/char/ipmi/ipmi_smic_sm.c
@@ -43,6 +43,7 @@
#include <linux/kernel.h> /* For printk. */
#include <linux/string.h>
+#include <linux/ipmi.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ipmi_msgdefs.h> /* for completion codes */
@@ -119,6 +120,17 @@ struct si_sm_data
long smic_timeout;
};
+/**
+ * The driver model view of the IPMI system interface state machine.
+ */
+static struct ipmi_si_driver smic_si_driver = {
+ .owner = THIS_MODULE,
+ .driver = {
+ .name = "ipmi_smic_sm",
+ .bus = &platform_bus_type
+ },
+};
+
static unsigned int init_smic_data (struct si_sm_data *smic,
struct si_sm_io *io)
{
@@ -595,6 +607,7 @@ static int smic_size(void)
struct si_sm_handlers smic_smi_handlers =
{
+ .driver = &smic_si_driver,
.init_data = init_smic_data,
.start_transaction = start_smic_transaction,
.get_result = smic_get_result,
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
index d6276e6..485a2c6 100644
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -30,10 +30,17 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/*
+ * IPMI driver model/sysfs support.
+ * Copyright (C) 2005 Yani Ioannou <yani.ioannou@gmail.com>
+ */
#ifndef __LINUX_IPMI_H
#define __LINUX_IPMI_H
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/ipmi_smi.h>
#include <linux/ipmi_msgdefs.h>
#include <linux/compiler.h>
@@ -68,6 +75,126 @@
* interface is defined later in the file. */
+/**
+ * struct ipmi_si_driver - represents a ipmi system interface
+ * driver in the kernel.
+ * @owner: Pointer to the module owner of this driver; initialize
+ * it using THIS_MODULE.
+ * @driver: the driver model core driver structure.
+ *
+ * An IPMI baseboard management controller (BMC) may be accessed directly by
+ * the host computer via a system interface of which there are many different
+ * types. This driver provides the interface defined by the general low level
+ * system interface driver.
+ */
+struct ipmi_si_driver
+{
+ struct module *owner;
+ struct device_driver driver;
+ /* driver attributes */
+};
+#define to_ipmi_si_driver(drv) container_of(drv, struct ipmi_si_driver, driver)
+
+/**
+ * struct ipmi_driver - represents the ipmi messaging interface
+ * driver in the kernel.
+ * @owner: Pointer to the module owner of this driver; initialize
+ * it using THIS_MODULE.
+ * @driver: the driver model core driver structure.
+ */
+struct ipmi_driver
+{
+ struct module *owner;
+ struct device_driver driver;
+};
+#define to_ipmi_driver(drv) container_of(drv, struct ipmi_driver, driver)
+
+/**
+ * struct ipmi_si_device - represents ipmi an IPMI system interface in
+ * the kernel.
+ * @smi: the low level interface struct.
+ * @bmc: the IPMI BMC interfaced to.
+ * @driver: the IPMI system interface driver that is bound to this interface.
+ * @dev: driver model's view of this device.
+ * @class_dev: driver model's class view of this device.
+ *
+ * An IPMI baseboard management controller (BMC) may be accessed directly by
+ * the host computer via a system interface of which there are many different
+ * types. This device represents one such system interface.
+ */
+struct ipmi_si_device
+{
+ smi_info_t smi;
+ struct ipmi_bmc_device *bmc;
+ struct ipmi_si_driver *driver;
+ struct platform_device dev;
+ struct class_device *class_dev;
+};
+#define to_ipmi_si_device(device) \
+ container_of(device, struct ipmi_si_device, dev)
+
+/**
+ * struct bmc_device_id - represents an IPMI BMC's response to an
+ * IPMI_GET_DEVICE_ID_CMD command.
+ * @device_id: OEM per product device id (product_id+device_id unique).
+ * @device_revision: the IPMI BMC revision number.
+ * @firmware_revision_1: the BMC's firmware major version number.
+ * @firmware_revision_2: the BMC's firmware minor version number.
+ * @ipmi_version: the ipmi version numbers of the BMC.
+ * @additional_device_support: additional device support.
+ * @manufacturer_id: the manufacturer ID of the BMC.
+ * @product_id: OEM product id.
+ * @aux_firmware_revision: auxilliarly firmware revision.
+ */
+struct bmc_device_id {
+ unsigned char device_id;
+ unsigned char device_revision;
+ unsigned char firmware_rev_1;
+ unsigned char firmware_rev_2;
+ unsigned char ipmi_version;
+ unsigned char additional_device_support;
+ unsigned char manufacturer_id[3];
+ unsigned char product_id[2];
+ unsigned char aux_firmware_revision[4];
+} __attribute__((packed));
+
+/* macros to extract major/minor version from IPMI version */
+#define ipmi_version_major(v) ((v)->ipmi_version & 0xf)
+#define ipmi_version_minor(v) ((v)->ipmi_version >> 4)
+
+/**
+ * struct ipmi_bmc_device - represents an IPMI baseboard management controller
+ * (BMC) attatched to one or more system interfaces.
+ * @dev: driver model's view of this device.
+ * @id: the BMC's device id response.
+ * @guid: BMC's globally unique identifier (optional).
+ * @guid_present: set iff a BMC GUID is available.
+ * @interfaces: the number of system interfaces currently interfacing
+ * to this BMC.
+ */
+struct ipmi_bmc_device
+{
+ struct platform_device dev;
+ struct bmc_device_id id;
+ unsigned char guid[16];
+ int guid_present;
+ int interfaces;
+ /* bmc class device */
+ struct class_device *class_dev;
+ /* bmc device attributes */
+ struct device_attribute device_id_attr;
+ struct device_attribute provides_dev_sdrs_attr;
+ struct device_attribute revision_attr;
+ struct device_attribute firmware_rev_attr;
+ struct device_attribute version_attr;
+ struct device_attribute add_dev_support_attr;
+ struct device_attribute manufacturer_id_attr;
+ struct device_attribute product_id_attr;
+ struct device_attribute guid_attr;
+ struct device_attribute aux_firmware_rev_attr;
+};
+#define to_ipmi_bmc_device(device) \
+ container_of(device, struct ipmi_bmc_device, dev)
/*
* This is an overlay for all the address types, so it's easy to
diff --git a/include/linux/ipmi_msgdefs.h b/include/linux/ipmi_msgdefs.h
index 03bc64d..f8572af 100644
--- a/include/linux/ipmi_msgdefs.h
+++ b/include/linux/ipmi_msgdefs.h
@@ -45,6 +45,7 @@
#define IPMI_NETFN_APP_REQUEST 0x06
#define IPMI_NETFN_APP_RESPONSE 0x07
+#define IPMI_GET_DEVICE_GUID_CMD 0x08
#define IPMI_GET_DEVICE_ID_CMD 0x01
#define IPMI_CLEAR_MSG_FLAGS_CMD 0x30
#define IPMI_GET_MSG_FLAGS_CMD 0x31
diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h
index e36ee15..96c2182 100644
--- a/include/linux/ipmi_smi.h
+++ b/include/linux/ipmi_smi.h
@@ -43,6 +43,7 @@
/* Structure for the low-level drivers. */
typedef struct ipmi_smi *ipmi_smi_t;
+typedef struct smi_info *smi_info_t;
/*
* Messages to/from the lower layer. The smi interface will take one
---
0.99.9j
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2005-11-26 12:04 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-08-30 10:56 [PATCH] IPMI: driver model and sysfs support Yani Ioannou
2005-08-30 13:22 ` Corey Minyard
2005-08-30 18:13 ` Yani Ioannou
2005-11-26 12:04 ` Yani Ioannou
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox