Commit f3fbbfcc authored by Corey Minyard's avatar Corey Minyard Committed by Linus Torvalds

[PATCH] IPMI base patch to fix channel handling and add polling

This patch fixes some problems with handling of channel detection in the
driver.  Some systems that are IPMI 1.5 do not implement the channel query
command.  Also, the interface has to be fully up before the command is
ready.

This patch also adds a polling interface; this is required for situations
where interrupts are not running, but the system must still issue IPMI
commands, like when taking a crash dump.

It also updates the driver version to v32.
Signed-off-by: default avatarCorey Minyard <minyard@acm.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 5e1c337d
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#include <linux/ipmi_msgdefs.h> /* for completion codes */ #include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h" #include "ipmi_si_sm.h"
#define IPMI_BT_VERSION "v31" #define IPMI_BT_VERSION "v32"
static int bt_debug = 0x00; /* Production value 0, see following flags */ static int bt_debug = 0x00; /* Production value 0, see following flags */
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <linux/init.h> #include <linux/init.h>
#define IPMI_DEVINTF_VERSION "v31" #define IPMI_DEVINTF_VERSION "v32"
struct ipmi_file_private struct ipmi_file_private
{ {
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
#include <linux/ipmi_msgdefs.h> /* for completion codes */ #include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h" #include "ipmi_si_sm.h"
#define IPMI_KCS_VERSION "v31" #define IPMI_KCS_VERSION "v32"
/* Set this if you want a printout of why the state machine was hosed /* Set this if you want a printout of why the state machine was hosed
when it gets hosed. */ when it gets hosed. */
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#define IPMI_MSGHANDLER_VERSION "v31" #define IPMI_MSGHANDLER_VERSION "v32"
struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
static int ipmi_init_msghandler(void); static int ipmi_init_msghandler(void);
...@@ -1648,6 +1648,22 @@ channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg) ...@@ -1648,6 +1648,22 @@ channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
/* It's the one we want */ /* It's the one we want */
if (msg->rsp[2] != 0) { if (msg->rsp[2] != 0) {
/* Got an error from the channel, just go on. */ /* Got an error from the channel, just go on. */
if (msg->rsp[2] == IPMI_INVALID_COMMAND_ERR) {
/* If the MC does not support this
command, that is legal. We just
assume it has one IPMB at channel
zero. */
intf->channels[0].medium
= IPMI_CHANNEL_MEDIUM_IPMB;
intf->channels[0].protocol
= IPMI_CHANNEL_PROTOCOL_IPMB;
rv = -ENOSYS;
intf->curr_channel = IPMI_MAX_CHANNELS;
wake_up(&intf->waitq);
goto out;
}
goto next_channel; goto next_channel;
} }
if (msg->rsp_size < 6) { if (msg->rsp_size < 6) {
...@@ -1671,10 +1687,20 @@ channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg) ...@@ -1671,10 +1687,20 @@ channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
wake_up(&intf->waitq); wake_up(&intf->waitq);
printk(KERN_WARNING "ipmi_msghandler: Error sending" printk(KERN_WARNING "ipmi_msghandler: Error sending"
"channel information: 0x%x\n", "channel information: %d\n",
rv); rv);
} }
} }
out:
return;
}
void ipmi_poll_interface(ipmi_user_t user)
{
ipmi_smi_t intf = user->intf;
if (intf->handlers->poll)
intf->handlers->poll(intf->send_info);
} }
int ipmi_register_smi(struct ipmi_smi_handlers *handlers, int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
...@@ -3154,6 +3180,7 @@ EXPORT_SYMBOL(ipmi_request); ...@@ -3154,6 +3180,7 @@ EXPORT_SYMBOL(ipmi_request);
EXPORT_SYMBOL(ipmi_request_settime); EXPORT_SYMBOL(ipmi_request_settime);
EXPORT_SYMBOL(ipmi_request_supply_msgs); EXPORT_SYMBOL(ipmi_request_supply_msgs);
EXPORT_SYMBOL(ipmi_request_with_source); EXPORT_SYMBOL(ipmi_request_with_source);
EXPORT_SYMBOL(ipmi_poll_interface);
EXPORT_SYMBOL(ipmi_register_smi); EXPORT_SYMBOL(ipmi_register_smi);
EXPORT_SYMBOL(ipmi_unregister_smi); EXPORT_SYMBOL(ipmi_unregister_smi);
EXPORT_SYMBOL(ipmi_register_for_cmd); EXPORT_SYMBOL(ipmi_register_for_cmd);
......
...@@ -76,7 +76,7 @@ static inline void add_usec_to_timer(struct timer_list *t, long v) ...@@ -76,7 +76,7 @@ static inline void add_usec_to_timer(struct timer_list *t, long v)
#include "ipmi_si_sm.h" #include "ipmi_si_sm.h"
#include <linux/init.h> #include <linux/init.h>
#define IPMI_SI_VERSION "v31" #define IPMI_SI_VERSION "v32"
/* Measure times between events in the driver. */ /* Measure times between events in the driver. */
#undef DEBUG_TIMING #undef DEBUG_TIMING
...@@ -712,6 +712,13 @@ static void set_run_to_completion(void *send_info, int i_run_to_completion) ...@@ -712,6 +712,13 @@ static void set_run_to_completion(void *send_info, int i_run_to_completion)
spin_unlock_irqrestore(&(smi_info->si_lock), flags); spin_unlock_irqrestore(&(smi_info->si_lock), flags);
} }
static void poll(void *send_info)
{
struct smi_info *smi_info = send_info;
smi_event_handler(smi_info, 0);
}
static void request_events(void *send_info) static void request_events(void *send_info)
{ {
struct smi_info *smi_info = send_info; struct smi_info *smi_info = send_info;
...@@ -851,7 +858,8 @@ static struct ipmi_smi_handlers handlers = ...@@ -851,7 +858,8 @@ static struct ipmi_smi_handlers handlers =
.owner = THIS_MODULE, .owner = THIS_MODULE,
.sender = sender, .sender = sender,
.request_events = request_events, .request_events = request_events,
.set_run_to_completion = set_run_to_completion .set_run_to_completion = set_run_to_completion,
.poll = poll,
}; };
/* There can be 4 IO ports passed in (with or without IRQs), 4 addresses, /* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
...@@ -1848,6 +1856,21 @@ static int init_one_smi(int intf_num, struct smi_info **smi) ...@@ -1848,6 +1856,21 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
atomic_set(&new_smi->req_events, 0); atomic_set(&new_smi->req_events, 0);
new_smi->run_to_completion = 0; new_smi->run_to_completion = 0;
new_smi->interrupt_disabled = 0;
new_smi->timer_stopped = 0;
new_smi->stop_operation = 0;
/* The ipmi_register_smi() code does some operations to
determine the channel information, so we must be ready to
handle operations before it is called. This means we have
to stop the timer if we get an error after this point. */
init_timer(&(new_smi->si_timer));
new_smi->si_timer.data = (long) new_smi;
new_smi->si_timer.function = smi_timeout;
new_smi->last_timeout_jiffies = jiffies;
new_smi->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
add_timer(&(new_smi->si_timer));
rv = ipmi_register_smi(&handlers, rv = ipmi_register_smi(&handlers,
new_smi, new_smi,
new_smi->ipmi_version_major, new_smi->ipmi_version_major,
...@@ -1857,7 +1880,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi) ...@@ -1857,7 +1880,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
printk(KERN_ERR printk(KERN_ERR
"ipmi_si: Unable to register device: error %d\n", "ipmi_si: Unable to register device: error %d\n",
rv); rv);
goto out_err; goto out_err_stop_timer;
} }
rv = ipmi_smi_add_proc_entry(new_smi->intf, "type", rv = ipmi_smi_add_proc_entry(new_smi->intf, "type",
...@@ -1867,7 +1890,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi) ...@@ -1867,7 +1890,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
printk(KERN_ERR printk(KERN_ERR
"ipmi_si: Unable to create proc entry: %d\n", "ipmi_si: Unable to create proc entry: %d\n",
rv); rv);
goto out_err; goto out_err_stop_timer;
} }
rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats", rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats",
...@@ -1877,7 +1900,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi) ...@@ -1877,7 +1900,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
printk(KERN_ERR printk(KERN_ERR
"ipmi_si: Unable to create proc entry: %d\n", "ipmi_si: Unable to create proc entry: %d\n",
rv); rv);
goto out_err; goto out_err_stop_timer;
} }
start_clear_flags(new_smi); start_clear_flags(new_smi);
...@@ -1886,34 +1909,40 @@ static int init_one_smi(int intf_num, struct smi_info **smi) ...@@ -1886,34 +1909,40 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
if (new_smi->irq) if (new_smi->irq)
new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ; new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ;
new_smi->interrupt_disabled = 0;
new_smi->timer_stopped = 0;
new_smi->stop_operation = 0;
init_timer(&(new_smi->si_timer));
new_smi->si_timer.data = (long) new_smi;
new_smi->si_timer.function = smi_timeout;
new_smi->last_timeout_jiffies = jiffies;
new_smi->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
add_timer(&(new_smi->si_timer));
*smi = new_smi; *smi = new_smi;
printk(" IPMI %s interface initialized\n", si_type[intf_num]); printk(" IPMI %s interface initialized\n", si_type[intf_num]);
return 0; return 0;
out_err_stop_timer:
new_smi->stop_operation = 1;
/* Wait for the timer to stop. This avoids problems with race
conditions removing the timer here. */
while (!new_smi->timer_stopped) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
}
out_err: out_err:
if (new_smi->intf) if (new_smi->intf)
ipmi_unregister_smi(new_smi->intf); ipmi_unregister_smi(new_smi->intf);
new_smi->irq_cleanup(new_smi); new_smi->irq_cleanup(new_smi);
/* Wait until we know that we are out of any interrupt
handlers might have been running before we freed the
interrupt. */
synchronize_kernel();
if (new_smi->si_sm) { if (new_smi->si_sm) {
if (new_smi->handlers) if (new_smi->handlers)
new_smi->handlers->cleanup(new_smi->si_sm); new_smi->handlers->cleanup(new_smi->si_sm);
kfree(new_smi->si_sm); kfree(new_smi->si_sm);
} }
new_smi->io_cleanup(new_smi); new_smi->io_cleanup(new_smi);
return rv; return rv;
} }
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
#include <linux/ipmi_msgdefs.h> /* for completion codes */ #include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h" #include "ipmi_si_sm.h"
#define IPMI_SMIC_VERSION "v31" #define IPMI_SMIC_VERSION "v32"
/* smic_debug is a bit-field /* smic_debug is a bit-field
* SMIC_DEBUG_ENABLE - turned on for now * SMIC_DEBUG_ENABLE - turned on for now
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
#include <asm/apic.h> #include <asm/apic.h>
#endif #endif
#define IPMI_WATCHDOG_VERSION "v31" #define IPMI_WATCHDOG_VERSION "v32"
/* /*
* The IPMI command/response information for the watchdog timer. * The IPMI command/response information for the watchdog timer.
...@@ -883,13 +883,11 @@ static int wdog_panic_handler(struct notifier_block *this, ...@@ -883,13 +883,11 @@ static int wdog_panic_handler(struct notifier_block *this,
/* On a panic, if we have a panic timeout, make sure that the thing /* On a panic, if we have a panic timeout, make sure that the thing
reboots, even if it hangs during that panic. */ reboots, even if it hangs during that panic. */
if (watchdog_user && !panic_event_handled && (panic_timeout > 0)) { if (watchdog_user && !panic_event_handled) {
/* Make sure the panic doesn't hang, and make sure we /* Make sure the panic doesn't hang, and make sure we
do this only once. */ do this only once. */
panic_event_handled = 1; panic_event_handled = 1;
timeout = panic_timeout + 120;
if (timeout > 255)
timeout = 255; timeout = 255;
pretimeout = 0; pretimeout = 0;
ipmi_watchdog_state = WDOG_TIMEOUT_RESET; ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
......
...@@ -372,6 +372,16 @@ int ipmi_request_supply_msgs(ipmi_user_t user, ...@@ -372,6 +372,16 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
struct ipmi_recv_msg *supplied_recv, struct ipmi_recv_msg *supplied_recv,
int priority); int priority);
/*
* Do polling on the IPMI interface the user is attached to. This
* causes the IPMI code to do an immediate check for information from
* the driver and handle anything that is immediately pending. This
* will not block in anyway. This is useful if you need to implement
* polling from the user like you need to send periodic watchdog pings
* from a crash dump, or something like that.
*/
void ipmi_poll_interface(ipmi_user_t user);
/* /*
* When commands come in to the SMS, the user can register to receive * When commands come in to the SMS, the user can register to receive
* them. Only one user can be listening on a specific netfn/cmd pair * them. Only one user can be listening on a specific netfn/cmd pair
......
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
#define IPMI_CC_NO_ERROR 0x00 #define IPMI_CC_NO_ERROR 0x00
#define IPMI_NODE_BUSY_ERR 0xc0 #define IPMI_NODE_BUSY_ERR 0xc0
#define IPMI_INVALID_COMMAND_ERR 0xc1
#define IPMI_ERR_MSG_TRUNCATED 0xc6 #define IPMI_ERR_MSG_TRUNCATED 0xc6
#define IPMI_LOST_ARBITRATION_ERR 0x81 #define IPMI_LOST_ARBITRATION_ERR 0x81
#define IPMI_ERR_UNSPECIFIED 0xff #define IPMI_ERR_UNSPECIFIED 0xff
......
...@@ -100,6 +100,10 @@ struct ipmi_smi_handlers ...@@ -100,6 +100,10 @@ struct ipmi_smi_handlers
out and that none are pending, and any new requests are run out and that none are pending, and any new requests are run
to completion immediately. */ to completion immediately. */
void (*set_run_to_completion)(void *send_info, int run_to_completion); void (*set_run_to_completion)(void *send_info, int run_to_completion);
/* Called to poll for work to do. This is so upper layers can
poll for operations during things like crash dumps. */
void (*poll)(void *send_info);
}; };
/* Add a low-level interface to the IPMI driver. */ /* Add a low-level interface to the IPMI driver. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment