aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorCorey Minyard <minyard@acm.org>2005-09-06 18:18:41 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-07 19:57:48 -0400
commit3ae0e0f9b15b95a2c3e64088d2a85e3f4a707681 (patch)
tree9ed8fc89ce8e95125d28d2844161867794f4c774 /drivers/char
parent07766f241b54d67999907d529b99ffaa61d8b7d9 (diff)
[PATCH] ipmi: OEM flag handling and hacks for some Dell machines
The ipmi driver does not have a way to handle firmware-generated events which have the OEM[012] Data Available flags set. In such a case, the SMS_ATN bit may never get cleared by firmware, leaving the driver looping infinitely but never able to make any progress. This patch first simplifies storage and use of the data returned from an IPMI Get Device ID command. It then creates a new per-OEM handler hook, which should know how to handle events with the OEM[012] Data Available flags set. It then uses this to implement a workaround for IPMI 1.5-capable Dell PowerEdge servers which are susceptable to setting the OEM[012] Data Available flags when the driver can't handle it. 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/char')
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c117
1 files changed, 105 insertions, 12 deletions
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 60f2f968b689..4fb36d4142fb 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -110,6 +110,21 @@ enum si_type {
110 SI_KCS, SI_SMIC, SI_BT 110 SI_KCS, SI_SMIC, SI_BT
111}; 111};
112 112
113struct ipmi_device_id {
114 unsigned char device_id;
115 unsigned char device_revision;
116 unsigned char firmware_revision_1;
117 unsigned char firmware_revision_2;
118 unsigned char ipmi_version;
119 unsigned char additional_device_support;
120 unsigned char manufacturer_id[3];
121 unsigned char product_id[2];
122 unsigned char aux_firmware_revision[4];
123} __attribute__((packed));
124
125#define ipmi_version_major(v) ((v)->ipmi_version & 0xf)
126#define ipmi_version_minor(v) ((v)->ipmi_version >> 4)
127
113struct smi_info 128struct smi_info
114{ 129{
115 ipmi_smi_t intf; 130 ipmi_smi_t intf;
@@ -132,12 +147,24 @@ struct smi_info
132 void (*irq_cleanup)(struct smi_info *info); 147 void (*irq_cleanup)(struct smi_info *info);
133 unsigned int io_size; 148 unsigned int io_size;
134 149
150 /* Per-OEM handler, called from handle_flags().
151 Returns 1 when handle_flags() needs to be re-run
152 or 0 indicating it set si_state itself.
153 */
154 int (*oem_data_avail_handler)(struct smi_info *smi_info);
155
135 /* Flags from the last GET_MSG_FLAGS command, used when an ATTN 156 /* Flags from the last GET_MSG_FLAGS command, used when an ATTN
136 is set to hold the flags until we are done handling everything 157 is set to hold the flags until we are done handling everything
137 from the flags. */ 158 from the flags. */
138#define RECEIVE_MSG_AVAIL 0x01 159#define RECEIVE_MSG_AVAIL 0x01
139#define EVENT_MSG_BUFFER_FULL 0x02 160#define EVENT_MSG_BUFFER_FULL 0x02
140#define WDT_PRE_TIMEOUT_INT 0x08 161#define WDT_PRE_TIMEOUT_INT 0x08
162#define OEM0_DATA_AVAIL 0x20
163#define OEM1_DATA_AVAIL 0x40
164#define OEM2_DATA_AVAIL 0x80
165#define OEM_DATA_AVAIL (OEM0_DATA_AVAIL | \
166 OEM1_DATA_AVAIL | \
167 OEM2_DATA_AVAIL)
141 unsigned char msg_flags; 168 unsigned char msg_flags;
142 169
143 /* If set to true, this will request events the next time the 170 /* If set to true, this will request events the next time the
@@ -176,11 +203,7 @@ struct smi_info
176 interrupts. */ 203 interrupts. */
177 int interrupt_disabled; 204 int interrupt_disabled;
178 205
179 unsigned char ipmi_si_dev_rev; 206 struct ipmi_device_id device_id;
180 unsigned char ipmi_si_fw_rev_major;
181 unsigned char ipmi_si_fw_rev_minor;
182 unsigned char ipmi_version_major;
183 unsigned char ipmi_version_minor;
184 207
185 /* Slave address, could be reported from DMI. */ 208 /* Slave address, could be reported from DMI. */
186 unsigned char slave_addr; 209 unsigned char slave_addr;
@@ -323,6 +346,7 @@ static inline void enable_si_irq(struct smi_info *smi_info)
323 346
324static void handle_flags(struct smi_info *smi_info) 347static void handle_flags(struct smi_info *smi_info)
325{ 348{
349 retry:
326 if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) { 350 if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
327 /* Watchdog pre-timeout */ 351 /* Watchdog pre-timeout */
328 spin_lock(&smi_info->count_lock); 352 spin_lock(&smi_info->count_lock);
@@ -372,6 +396,10 @@ static void handle_flags(struct smi_info *smi_info)
372 smi_info->curr_msg->data, 396 smi_info->curr_msg->data,
373 smi_info->curr_msg->data_size); 397 smi_info->curr_msg->data_size);
374 smi_info->si_state = SI_GETTING_EVENTS; 398 smi_info->si_state = SI_GETTING_EVENTS;
399 } else if (smi_info->msg_flags & OEM_DATA_AVAIL) {
400 if (smi_info->oem_data_avail_handler)
401 if (smi_info->oem_data_avail_handler(smi_info))
402 goto retry;
375 } else { 403 } else {
376 smi_info->si_state = SI_NORMAL; 404 smi_info->si_state = SI_NORMAL;
377 } 405 }
@@ -1927,11 +1955,8 @@ static int try_get_dev_id(struct smi_info *smi_info)
1927 } 1955 }
1928 1956
1929 /* Record info from the get device id, in case we need it. */ 1957 /* Record info from the get device id, in case we need it. */
1930 smi_info->ipmi_si_dev_rev = resp[4] & 0xf; 1958 memcpy(&smi_info->device_id, &resp[3],
1931 smi_info->ipmi_si_fw_rev_major = resp[5] & 0x7f; 1959 min_t(unsigned long, resp_len-3, sizeof(smi_info->device_id)));
1932 smi_info->ipmi_si_fw_rev_minor = resp[6];
1933 smi_info->ipmi_version_major = resp[7] & 0xf;
1934 smi_info->ipmi_version_minor = resp[7] >> 4;
1935 1960
1936 out: 1961 out:
1937 kfree(resp); 1962 kfree(resp);
@@ -1992,6 +2017,72 @@ static int stat_file_read_proc(char *page, char **start, off_t off,
1992 return (out - ((char *) page)); 2017 return (out - ((char *) page));
1993} 2018}
1994 2019
2020/*
2021 * oem_data_avail_to_receive_msg_avail
2022 * @info - smi_info structure with msg_flags set
2023 *
2024 * Converts flags from OEM_DATA_AVAIL to RECEIVE_MSG_AVAIL
2025 * Returns 1 indicating need to re-run handle_flags().
2026 */
2027static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info)
2028{
2029 smi_info->msg_flags = (smi_info->msg_flags & ~OEM_DATA_AVAIL) |
2030 RECEIVE_MSG_AVAIL;
2031 return 1;
2032}
2033
2034/*
2035 * setup_dell_poweredge_oem_data_handler
2036 * @info - smi_info.device_id must be populated
2037 *
2038 * Systems that match, but have firmware version < 1.40 may assert
2039 * OEM0_DATA_AVAIL on their own, without being told via Set Flags that
2040 * it's safe to do so. Such systems will de-assert OEM1_DATA_AVAIL
2041 * upon receipt of IPMI_GET_MSG_CMD, so we should treat these flags
2042 * as RECEIVE_MSG_AVAIL instead.
2043 *
2044 * As Dell has no plans to release IPMI 1.5 firmware that *ever*
2045 * assert the OEM[012] bits, and if it did, the driver would have to
2046 * change to handle that properly, we don't actually check for the
2047 * firmware version.
2048 * Device ID = 0x20 BMC on PowerEdge 8G servers
2049 * Device Revision = 0x80
2050 * Firmware Revision1 = 0x01 BMC version 1.40
2051 * Firmware Revision2 = 0x40 BCD encoded
2052 * IPMI Version = 0x51 IPMI 1.5
2053 * Manufacturer ID = A2 02 00 Dell IANA
2054 *
2055 */
2056#define DELL_POWEREDGE_8G_BMC_DEVICE_ID 0x20
2057#define DELL_POWEREDGE_8G_BMC_DEVICE_REV 0x80
2058#define DELL_POWEREDGE_8G_BMC_IPMI_VERSION 0x51
2059#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
2060static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info)
2061{
2062 struct ipmi_device_id *id = &smi_info->device_id;
2063 const char mfr[3]=DELL_IANA_MFR_ID;
2064 if (!memcmp(mfr, id->manufacturer_id, sizeof(mfr)) &&
2065 id->device_id == DELL_POWEREDGE_8G_BMC_DEVICE_ID &&
2066 id->device_revision == DELL_POWEREDGE_8G_BMC_DEVICE_REV &&
2067 id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION) {
2068 smi_info->oem_data_avail_handler =
2069 oem_data_avail_to_receive_msg_avail;
2070 }
2071}
2072
2073/*
2074 * setup_oem_data_handler
2075 * @info - smi_info.device_id must be filled in already
2076 *
2077 * Fills in smi_info.device_id.oem_data_available_handler
2078 * when we know what function to use there.
2079 */
2080
2081static void setup_oem_data_handler(struct smi_info *smi_info)
2082{
2083 setup_dell_poweredge_oem_data_handler(smi_info);
2084}
2085
1995/* Returns 0 if initialized, or negative on an error. */ 2086/* Returns 0 if initialized, or negative on an error. */
1996static int init_one_smi(int intf_num, struct smi_info **smi) 2087static int init_one_smi(int intf_num, struct smi_info **smi)
1997{ 2088{
@@ -2090,6 +2181,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
2090 if (rv) 2181 if (rv)
2091 goto out_err; 2182 goto out_err;
2092 2183
2184 setup_oem_data_handler(new_smi);
2185
2093 /* Try to claim any interrupts. */ 2186 /* Try to claim any interrupts. */
2094 new_smi->irq_setup(new_smi); 2187 new_smi->irq_setup(new_smi);
2095 2188
@@ -2123,8 +2216,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
2123 2216
2124 rv = ipmi_register_smi(&handlers, 2217 rv = ipmi_register_smi(&handlers,
2125 new_smi, 2218 new_smi,
2126 new_smi->ipmi_version_major, 2219 ipmi_version_major(&new_smi->device_id),
2127 new_smi->ipmi_version_minor, 2220 ipmi_version_minor(&new_smi->device_id),
2128 new_smi->slave_addr, 2221 new_smi->slave_addr,
2129 &(new_smi->intf)); 2222 &(new_smi->intf));
2130 if (rv) { 2223 if (rv) {