aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorCorey Minyard <minyard@acm.org>2005-11-07 03:59:59 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-07 10:53:44 -0500
commitea94027b92dd0d02d238d5984cd9089343c1d6cc (patch)
tree89af59134162852ad8863b8b64e7c7ab6c4c0026 /drivers
parentd5a2b89a4943b423b5b0a07783fee4e08424b0b2 (diff)
[PATCH] ipmi: si start transaction hook
Some commands, on some system BMCs, don't respond at at all. This is seen on Dell PowerEdge x6xx and x7xx systems with IPMI 1.0 BT controllers when a "Get SDR" command is issued, with a length field of 0x3A, which happens to be the length of about SDR entries. If another length is passed, this command succeeds. This patch adds general infrastructure for receiving commands before they're passed down to the low-level drivers, such that they can be completed immediately, or modified, prior to being sent to ->start_transaction(). Signed-off-by: Matt Domsch <Matt_Domsch@dell.com> Signed-off-by: Corey Minyard <minyard@acm.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index df7dbbff57ae..2ace62b1d326 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -51,6 +51,7 @@
51#include <linux/list.h> 51#include <linux/list.h>
52#include <linux/pci.h> 52#include <linux/pci.h>
53#include <linux/ioport.h> 53#include <linux/ioport.h>
54#include <linux/notifier.h>
54#include <asm/irq.h> 55#include <asm/irq.h>
55#ifdef CONFIG_HIGH_RES_TIMERS 56#ifdef CONFIG_HIGH_RES_TIMERS
56#include <linux/hrtime.h> 57#include <linux/hrtime.h>
@@ -222,6 +223,12 @@ struct smi_info
222 unsigned long incoming_messages; 223 unsigned long incoming_messages;
223}; 224};
224 225
226static struct notifier_block *xaction_notifier_list;
227static int register_xaction_notifier(struct notifier_block * nb)
228{
229 return notifier_chain_register(&xaction_notifier_list, nb);
230}
231
225static void si_restart_short_timer(struct smi_info *smi_info); 232static void si_restart_short_timer(struct smi_info *smi_info);
226 233
227static void deliver_recv_msg(struct smi_info *smi_info, 234static void deliver_recv_msg(struct smi_info *smi_info,
@@ -281,6 +288,11 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
281 do_gettimeofday(&t); 288 do_gettimeofday(&t);
282 printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec); 289 printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
283#endif 290#endif
291 err = notifier_call_chain(&xaction_notifier_list, 0, smi_info);
292 if (err & NOTIFY_STOP_MASK) {
293 rv = SI_SM_CALL_WITHOUT_DELAY;
294 goto out;
295 }
284 err = smi_info->handlers->start_transaction( 296 err = smi_info->handlers->start_transaction(
285 smi_info->si_sm, 297 smi_info->si_sm,
286 smi_info->curr_msg->data, 298 smi_info->curr_msg->data,
@@ -291,6 +303,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
291 303
292 rv = SI_SM_CALL_WITHOUT_DELAY; 304 rv = SI_SM_CALL_WITHOUT_DELAY;
293 } 305 }
306 out:
294 spin_unlock(&(smi_info->msg_lock)); 307 spin_unlock(&(smi_info->msg_lock));
295 308
296 return rv; 309 return rv;
@@ -2080,6 +2093,71 @@ static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info)
2080 } 2093 }
2081} 2094}
2082 2095
2096#define CANNOT_RETURN_REQUESTED_LENGTH 0xCA
2097static void return_hosed_msg_badsize(struct smi_info *smi_info)
2098{
2099 struct ipmi_smi_msg *msg = smi_info->curr_msg;
2100
2101 /* Make it a reponse */
2102 msg->rsp[0] = msg->data[0] | 4;
2103 msg->rsp[1] = msg->data[1];
2104 msg->rsp[2] = CANNOT_RETURN_REQUESTED_LENGTH;
2105 msg->rsp_size = 3;
2106 smi_info->curr_msg = NULL;
2107 deliver_recv_msg(smi_info, msg);
2108}
2109
2110/*
2111 * dell_poweredge_bt_xaction_handler
2112 * @info - smi_info.device_id must be populated
2113 *
2114 * Dell PowerEdge servers with the BT interface (x6xx and 1750) will
2115 * not respond to a Get SDR command if the length of the data
2116 * requested is exactly 0x3A, which leads to command timeouts and no
2117 * data returned. This intercepts such commands, and causes userspace
2118 * callers to try again with a different-sized buffer, which succeeds.
2119 */
2120
2121#define STORAGE_NETFN 0x0A
2122#define STORAGE_CMD_GET_SDR 0x23
2123static int dell_poweredge_bt_xaction_handler(struct notifier_block *self,
2124 unsigned long unused,
2125 void *in)
2126{
2127 struct smi_info *smi_info = in;
2128 unsigned char *data = smi_info->curr_msg->data;
2129 unsigned int size = smi_info->curr_msg->data_size;
2130 if (size >= 8 &&
2131 (data[0]>>2) == STORAGE_NETFN &&
2132 data[1] == STORAGE_CMD_GET_SDR &&
2133 data[7] == 0x3A) {
2134 return_hosed_msg_badsize(smi_info);
2135 return NOTIFY_STOP;
2136 }
2137 return NOTIFY_DONE;
2138}
2139
2140static struct notifier_block dell_poweredge_bt_xaction_notifier = {
2141 .notifier_call = dell_poweredge_bt_xaction_handler,
2142};
2143
2144/*
2145 * setup_dell_poweredge_bt_xaction_handler
2146 * @info - smi_info.device_id must be filled in already
2147 *
2148 * Fills in smi_info.device_id.start_transaction_pre_hook
2149 * when we know what function to use there.
2150 */
2151static void
2152setup_dell_poweredge_bt_xaction_handler(struct smi_info *smi_info)
2153{
2154 struct ipmi_device_id *id = &smi_info->device_id;
2155 const char mfr[3]=DELL_IANA_MFR_ID;
2156 if (! memcmp(mfr, id->manufacturer_id, sizeof(mfr)) &&
2157 smi_info->si_type == SI_BT)
2158 register_xaction_notifier(&dell_poweredge_bt_xaction_notifier);
2159}
2160
2083/* 2161/*
2084 * setup_oem_data_handler 2162 * setup_oem_data_handler
2085 * @info - smi_info.device_id must be filled in already 2163 * @info - smi_info.device_id must be filled in already
@@ -2093,6 +2171,11 @@ static void setup_oem_data_handler(struct smi_info *smi_info)
2093 setup_dell_poweredge_oem_data_handler(smi_info); 2171 setup_dell_poweredge_oem_data_handler(smi_info);
2094} 2172}
2095 2173
2174static void setup_xaction_handlers(struct smi_info *smi_info)
2175{
2176 setup_dell_poweredge_bt_xaction_handler(smi_info);
2177}
2178
2096/* Returns 0 if initialized, or negative on an error. */ 2179/* Returns 0 if initialized, or negative on an error. */
2097static int init_one_smi(int intf_num, struct smi_info **smi) 2180static int init_one_smi(int intf_num, struct smi_info **smi)
2098{ 2181{
@@ -2188,6 +2271,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
2188 goto out_err; 2271 goto out_err;
2189 2272
2190 setup_oem_data_handler(new_smi); 2273 setup_oem_data_handler(new_smi);
2274 setup_xaction_handlers(new_smi);
2191 2275
2192 /* Try to claim any interrupts. */ 2276 /* Try to claim any interrupts. */
2193 new_smi->irq_setup(new_smi); 2277 new_smi->irq_setup(new_smi);