Files
lm-sensors/kernel/busses/i2c-ipmi.c
T
Mark D. Studebaker 16f4429f8c (mds)
On 5/1/05, Sergey Vlasov <vsu@altlinux.ru> wrote:

>> Hello!
>>
>> http://openipmi.sourceforge.net/ provides patches for 2.4.x kernels
>> with updated IPMI code.  However, these patches change the IPMI driver
>> API by adding an additional argument to ipmi_request():
>>
>>  int ipmi_request(ipmi_user_t      user,
>>                  struct ipmi_addr *addr,
>>                  long             msgid,
>>                  struct ipmi_msg  *msg,
>> +                void             *user_msg_data,
>>                  int              priority);
>>
>> (user_msg_data is later returned in the struct ipmi_recv_msg field).
>> This API change breaks compilation of some lm_sensors drivers
>> (i2c-ipmb, i2c-ipmi).
>>
>> The patch below adds compatibility with the new IPMI API to i2c-ipmb
>> and i2c-ipmi drivers.  <linux/ipmi.h> does not provide a real
>> API-version #define, therefore IPMI_RESPONSE_RESPONSE_TYPE (also added
>> by the openipmi.sf.net patch) is (ab)used as a new API indicator.
>>
>> Compile tested only due to lack of hardware.

(Yani I.):

Hi Sergey,

Actually there was a patch to the 2.6 i2c-ipmi/bmcsensors for this
problem (after Bene Martin notified me of the problem and how to fix
it), but from what I understand Corey re-included the ipmi_request
method in the next version once he learned of a driver using it (it
was removed because there was thought to be no usage). He was eager to
learn when bmcsensors would make it into the kernel so that he could
stop being nagged by the 'unused function police' as he put it .

It might be wise to apply a patch like this in 2.4 to support the
openipmi that went 'wrong', I changed the 2.6 driver to use the
ipmi_request_settime function to no ill effect, but you should
consider that Corey notes that it is preferred to use the old one:

(extract from some e-mail between Corey, Martin and I about the problem):


>>>>>>Interestingly enough the ipmi_request_settime still has a comment in
>>>>>>the header "Don't use this unless you *really* have to.", making me
>>>>>>wonder if there is a reason not to be using it instead of ipmi_request
>>>>>>if its re-incorporated into the kernel.
>>>>>>
>>>>>>
>>
>>>>
>>>>I guess the only one qualified to answer that one would be corey.
>>>>
>>>>Bye, Martin
>>>>
>>>>
>
>>You wouldn't generally use it because it sets the timeouts and for most
>>purposes the timeouts are defined by the spec (sort of).
>>
>>Do you have any feeling when the BMC sensors package will go into the
>>mainstream kernel?  That would be the time to coordinate adding the
>>normal function back in so I'm not constantly fighting the unused
>>function police.
>>
>>-Corey


git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@2987 7894878c-1315-0410-8ee3-d5d059ff63e0
2005-05-04 20:21:01 +00:00

252 lines
6.5 KiB
C

/*
i2c-ipmi.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
This implements a "dummy" i2c adapter for clients to access the
BMC via IPMI messages. Supports only one BMC and one client for now!
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/ipmi.h>
#include "version.h"
static u32 i2c_ipmi_func(struct i2c_adapter *adapter);
static int bmcclient_i2c_send_message(struct i2c_adapter *, char *, int);
static void i2c_ipmi_inc_use(struct i2c_adapter *adapter)
{
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
}
static void i2c_ipmi_dec_use(struct i2c_adapter *adapter)
{
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
}
/* I2C Data */
static struct i2c_algorithm i2c_ipmi_algorithm = {
.name = "IPMI algorithm",
.id = I2C_ALGO_IPMI,
.slave_send = &bmcclient_i2c_send_message,
.functionality = &i2c_ipmi_func,
};
static struct i2c_adapter i2c_ipmi_adapter = {
.name = "IPMI adapter",
.id = I2C_ALGO_IPMI | I2C_HW_IPMI,
.algo = &i2c_ipmi_algorithm,
.inc_use = &i2c_ipmi_inc_use,
.dec_use = &i2c_ipmi_dec_use,
};
/* IPMI Data */
static ipmi_user_t i2c_ipmi_user;
static unsigned char ipmi_version_major;
static unsigned char ipmi_version_minor;
static const char msgdata[IPMI_MAX_ADDR_SIZE]; /* ?? */
static struct ipmi_addr address = {
IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
IPMI_BMC_CHANNEL,
{0}
}; /* send address */
static int interfaces; /* number of BMC's found */
/* Dummy adapter... */
static u32 i2c_ipmi_func(struct i2c_adapter *adapter)
{
return 0;
}
/************** Message Sending **************/
static int find_client(struct i2c_client * client)
{
int i;
for (i = 0; i < I2C_CLIENT_MAX; i++)
if (client == i2c_ipmi_adapter.clients[i])
return i;
return -1;
}
static void ipmi_i2c_send_message(int id, struct ipmi_msg * msg)
{
#ifdef IPMI_RESPONSE_RESPONSE_TYPE
ipmi_request(i2c_ipmi_user, &address, (long) id, msg, NULL, 0);
#else
ipmi_request(i2c_ipmi_user, &address, (long) id, msg, 0);
#endif
}
/* This is the message send function exported to the client
via the i2c_adapter struct.
We use the existing (but unused) slave_send function pointer.
Hence the ugly casts. */
static int bmcclient_i2c_send_message(struct i2c_adapter *clnt,
char * mesg, int id)
{
struct ipmi_msg *msg = (struct ipmi_msg *) mesg;
struct i2c_client *client = (struct i2c_client *) clnt;
int clientid;
#ifdef DEBUG
if(msg->data == NULL)
printk(KERN_INFO "i2c-ipmi.o: Send 0x%x\n", msg->cmd);
else
printk(KERN_INFO "i2c-ipmi.o: Send 0x%x 0x%x 0x%x\n", msg->cmd, msg->data[0], msg->data[1]);
#endif
/* save the client number in the upper 8 bits of the message id */
if((clientid = find_client(client)) < 0) {
printk(KERN_WARNING "i2c-ipmi.o: Request from unknown client\n");
return -1;
}
id = (id & 0xffffff) | (clientid << 24);
ipmi_i2c_send_message(id, msg);
return 0;
}
/************** Message Receiving **************/
static void ipmi_i2c_msg_handler(struct ipmi_recv_msg *msg,
void *handler_data)
{
int rcvid = msg->msgid & 0xffffff;
int clientid = (msg->msgid >> 24) & 0xff;
#ifdef DEBUG
if (msg->msg.data[0] != 0)
printk(KERN_WARNING "i2c-ipmi.o: Error 0x%x on cmd 0x%x/0x%x\n",
msg->msg.data[0], msg->msg.netfn, msg->msg.cmd);
#endif
/* Protect ourselves here; verify the client and its callback
since the client may have gone away since
the message was sent! */
if(clientid < I2C_CLIENT_MAX &&
i2c_ipmi_adapter.clients[clientid] != NULL &&
i2c_ipmi_adapter.clients[clientid]->driver->command != NULL)
(* i2c_ipmi_adapter.clients[clientid]->driver->command)
(i2c_ipmi_adapter.clients[clientid], rcvid, msg);
else {
printk(KERN_WARNING "i2c-ipmi.o: Response for unknown client\n");
ipmi_free_recv_msg(msg);
}
}
static struct ipmi_user_hndl ipmi_hndlrs =
{
.ipmi_recv_hndl = ipmi_i2c_msg_handler,
};
/**************** Initialization ****************/
/* callback for each BMC found */
static void ipmi_register_bmc(int ipmi_intf)
{
int error;
if(interfaces > 0) { /* 1 max for now */
printk(KERN_INFO
"i2c-ipmi.o: Additional IPMI interface %d not supported\n",
ipmi_intf);
return;
}
error = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &i2c_ipmi_user);
if (error < 0) {
printk(KERN_ERR "i2c-ipmi.o: Unable to register with ipmi\n");
return;
}
error = i2c_add_adapter(&i2c_ipmi_adapter);
if (error) {
printk(KERN_ERR "i2c-ipmi.o: Adapter registration failed, "
"module i2c-ipmi.o is not inserted\n.");
return;
}
ipmi_get_version(i2c_ipmi_user, &ipmi_version_major,
&ipmi_version_minor);
printk(KERN_INFO
"i2c-ipmi.o: Registered IPMI interface %d with version %d.%d\n",
ipmi_intf, ipmi_version_major, ipmi_version_minor);
interfaces++;
}
static void ipmi_new_smi(int if_num)
{
ipmi_register_bmc(if_num);
}
static void ipmi_smi_gone(int if_num)
{
if (interfaces >= 1) {
i2c_del_adapter(&i2c_ipmi_adapter);
ipmi_destroy_user(i2c_ipmi_user);
interfaces--;
}
}
static struct ipmi_smi_watcher smi_watcher =
{
.new_smi = ipmi_new_smi,
.smi_gone = ipmi_smi_gone
};
static int __init i2c_ipmi_init(void)
{
int rv;
printk(KERN_INFO "i2c-ipmi.o version %s (%s)\n", LM_VERSION, LM_DATE);
rv = ipmi_smi_watcher_register(&smi_watcher);
if (rv) {
printk(KERN_WARNING
"ipmi_watchdog: can't register smi watcher\n");
return rv;
}
printk(KERN_INFO "i2c-ipmi.o: BMC access for i2c modules initialized.\n");
return 0;
}
static void __exit i2c_ipmi_exit(void)
{
ipmi_smi_watcher_unregister(&smi_watcher);
ipmi_smi_gone(0);
}
MODULE_AUTHOR("M. D. Studebaker <mdsxyz123@yahoo.com>");
MODULE_DESCRIPTION("IPMI-BMC access through i2c");
MODULE_LICENSE("GPL");
module_init(i2c_ipmi_init);
module_exit(i2c_ipmi_exit);