aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/ipmi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/ipmi')
-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);