blob: 6c59baa887a8c7d1fc1352034303b07ba85eec05 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ipmi_bt_sm.c
3 *
4 * The state machine for an Open IPMI BT sub-driver under ipmi_si.c, part
5 * of the driver architecture at http://sourceforge.net/project/openipmi
6 *
7 * Author: Rocky Craig <first.last@hp.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
20 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
22 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 * You should have received a copy of the GNU General Public License along
26 * with this program; if not, write to the Free Software Foundation, Inc.,
27 * 675 Mass Ave, Cambridge, MA 02139, USA. */
28
29#include <linux/kernel.h> /* For printk. */
30#include <linux/string.h>
Corey Minyardc4edff12005-11-07 00:59:56 -080031#include <linux/module.h>
32#include <linux/moduleparam.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/ipmi_msgdefs.h> /* for completion codes */
34#include "ipmi_si_sm.h"
35
Corey Minyard4d7cbac2006-12-06 20:41:14 -080036#define BT_DEBUG_OFF 0 /* Used in production */
37#define BT_DEBUG_ENABLE 1 /* Generic messages */
38#define BT_DEBUG_MSG 2 /* Prints all request/response buffers */
39#define BT_DEBUG_STATES 4 /* Verbose look at state changes */
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
Corey Minyard4d7cbac2006-12-06 20:41:14 -080041static int bt_debug = BT_DEBUG_OFF;
42
Corey Minyardc4edff12005-11-07 00:59:56 -080043module_param(bt_debug, int, 0644);
44MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states");
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46/* Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds,
47 and 64 byte buffers. However, one HP implementation wants 255 bytes of
48 buffer (with a documented message of 160 bytes) so go for the max.
49 Since the Open IPMI architecture is single-message oriented at this
50 stage, the queue depth of BT is of no concern. */
51
Corey Minyard4d7cbac2006-12-06 20:41:14 -080052#define BT_NORMAL_TIMEOUT 5 /* seconds */
53#define BT_NORMAL_RETRY_LIMIT 2
54#define BT_RESET_DELAY 6 /* seconds after warm reset */
55
56/* States are written in chronological order and usually cover
57 multiple rows of the state table discussion in the IPMI spec. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
59enum bt_states {
Corey Minyard4d7cbac2006-12-06 20:41:14 -080060 BT_STATE_IDLE = 0, /* Order is critical in this list */
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 BT_STATE_XACTION_START,
62 BT_STATE_WRITE_BYTES,
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 BT_STATE_WRITE_CONSUME,
Corey Minyard4d7cbac2006-12-06 20:41:14 -080064 BT_STATE_READ_WAIT,
65 BT_STATE_CLEAR_B2H,
66 BT_STATE_READ_BYTES,
67 BT_STATE_RESET1, /* These must come last */
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 BT_STATE_RESET2,
69 BT_STATE_RESET3,
70 BT_STATE_RESTART,
Corey Minyard4d7cbac2006-12-06 20:41:14 -080071 BT_STATE_PRINTME,
72 BT_STATE_CAPABILITIES_BEGIN,
73 BT_STATE_CAPABILITIES_END,
74 BT_STATE_LONG_BUSY /* BT doesn't get hosed :-) */
Linus Torvalds1da177e2005-04-16 15:20:36 -070075};
76
Corey Minyard4d7cbac2006-12-06 20:41:14 -080077/* Macros seen at the end of state "case" blocks. They help with legibility
78 and debugging. */
79
80#define BT_STATE_CHANGE(X,Y) { bt->state = X; return Y; }
81
82#define BT_SI_SM_RETURN(Y) { last_printed = BT_STATE_PRINTME; return Y; }
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084struct si_sm_data {
85 enum bt_states state;
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 unsigned char seq; /* BT sequence number */
87 struct si_sm_io *io;
Corey Minyard4d7cbac2006-12-06 20:41:14 -080088 unsigned char write_data[IPMI_MAX_MSG_LENGTH];
89 int write_count;
90 unsigned char read_data[IPMI_MAX_MSG_LENGTH];
91 int read_count;
92 int truncated;
93 long timeout; /* microseconds countdown */
94 int error_retries; /* end of "common" fields */
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 int nonzero_status; /* hung BMCs stay all 0 */
Corey Minyard4d7cbac2006-12-06 20:41:14 -080096 enum bt_states complete; /* to divert the state machine */
97 int BT_CAP_outreqs;
98 long BT_CAP_req2rsp;
99 int BT_CAP_retries; /* Recommended retries */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100};
101
102#define BT_CLR_WR_PTR 0x01 /* See IPMI 1.5 table 11.6.4 */
103#define BT_CLR_RD_PTR 0x02
104#define BT_H2B_ATN 0x04
105#define BT_B2H_ATN 0x08
106#define BT_SMS_ATN 0x10
107#define BT_OEM0 0x20
108#define BT_H_BUSY 0x40
109#define BT_B_BUSY 0x80
110
111/* Some bits are toggled on each write: write once to set it, once
112 more to clear it; writing a zero does nothing. To absolutely
113 clear it, check its state and write if set. This avoids the "get
114 current then use as mask" scheme to modify one bit. Note that the
115 variable "bt" is hardcoded into these macros. */
116
117#define BT_STATUS bt->io->inputb(bt->io, 0)
118#define BT_CONTROL(x) bt->io->outputb(bt->io, 0, x)
119
120#define BMC2HOST bt->io->inputb(bt->io, 1)
121#define HOST2BMC(x) bt->io->outputb(bt->io, 1, x)
122
123#define BT_INTMASK_R bt->io->inputb(bt->io, 2)
124#define BT_INTMASK_W(x) bt->io->outputb(bt->io, 2, x)
125
126/* Convenience routines for debugging. These are not multi-open safe!
127 Note the macros have hardcoded variables in them. */
128
129static char *state2txt(unsigned char state)
130{
131 switch (state) {
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800132 case BT_STATE_IDLE: return("IDLE");
133 case BT_STATE_XACTION_START: return("XACTION");
134 case BT_STATE_WRITE_BYTES: return("WR_BYTES");
135 case BT_STATE_WRITE_CONSUME: return("WR_CONSUME");
136 case BT_STATE_READ_WAIT: return("RD_WAIT");
137 case BT_STATE_CLEAR_B2H: return("CLEAR_B2H");
138 case BT_STATE_READ_BYTES: return("RD_BYTES");
139 case BT_STATE_RESET1: return("RESET1");
140 case BT_STATE_RESET2: return("RESET2");
141 case BT_STATE_RESET3: return("RESET3");
142 case BT_STATE_RESTART: return("RESTART");
143 case BT_STATE_LONG_BUSY: return("LONG_BUSY");
144 case BT_STATE_CAPABILITIES_BEGIN: return("CAP_BEGIN");
145 case BT_STATE_CAPABILITIES_END: return("CAP_END");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 }
147 return("BAD STATE");
148}
149#define STATE2TXT state2txt(bt->state)
150
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800151static char *status2txt(unsigned char status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152{
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800153 /*
154 * This cannot be called by two threads at the same time and
155 * the buffer is always consumed immediately, so the static is
156 * safe to use.
157 */
158 static char buf[40];
159
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 strcpy(buf, "[ ");
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800161 if (status & BT_B_BUSY)
162 strcat(buf, "B_BUSY ");
163 if (status & BT_H_BUSY)
164 strcat(buf, "H_BUSY ");
165 if (status & BT_OEM0)
166 strcat(buf, "OEM0 ");
167 if (status & BT_SMS_ATN)
168 strcat(buf, "SMS ");
169 if (status & BT_B2H_ATN)
170 strcat(buf, "B2H ");
171 if (status & BT_H2B_ATN)
172 strcat(buf, "H2B ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 strcat(buf, "]");
174 return buf;
175}
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800176#define STATUS2TXT status2txt(status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800178/* called externally at insmod time, and internally on cleanup */
179
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io)
181{
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800182 memset(bt, 0, sizeof(struct si_sm_data));
183 if (bt->io != io) { /* external: one-time only things */
184 bt->io = io;
185 bt->seq = 0;
186 }
187 bt->state = BT_STATE_IDLE; /* start here */
188 bt->complete = BT_STATE_IDLE; /* end here */
189 bt->BT_CAP_req2rsp = BT_NORMAL_TIMEOUT * 1000000;
190 bt->BT_CAP_retries = BT_NORMAL_RETRY_LIMIT;
191 /* BT_CAP_outreqs == zero is a flag to read BT Capabilities */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 return 3; /* We claim 3 bytes of space; ought to check SPMI table */
193}
194
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800195/* Jam a completion code (probably an error) into a response */
196
197static void force_result(struct si_sm_data *bt, unsigned char completion_code)
198{
199 bt->read_data[0] = 4; /* # following bytes */
200 bt->read_data[1] = bt->write_data[1] | 4; /* Odd NetFn/LUN */
201 bt->read_data[2] = bt->write_data[2]; /* seq (ignored) */
202 bt->read_data[3] = bt->write_data[3]; /* Command */
203 bt->read_data[4] = completion_code;
204 bt->read_count = 5;
205}
206
207/* The upper state machine starts here */
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209static int bt_start_transaction(struct si_sm_data *bt,
210 unsigned char *data,
211 unsigned int size)
212{
213 unsigned int i;
214
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800215 if (size < 2)
216 return IPMI_REQ_LEN_INVALID_ERR;
217 if (size > IPMI_MAX_MSG_LENGTH)
218 return IPMI_REQ_LEN_EXCEEDED_ERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800220 if (bt->state == BT_STATE_LONG_BUSY)
221 return IPMI_NODE_BUSY_ERR;
222
223 if (bt->state != BT_STATE_IDLE)
224 return IPMI_NOT_IN_MY_STATE_ERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
226 if (bt_debug & BT_DEBUG_MSG) {
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800227 printk(KERN_WARNING "BT: +++++++++++++++++ New command\n");
228 printk(KERN_WARNING "BT: NetFn/LUN CMD [%d data]:", size - 2);
Corey Minyarde8b33612005-09-06 15:18:45 -0700229 for (i = 0; i < size; i ++)
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800230 printk (" %02x", data[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 printk("\n");
232 }
233 bt->write_data[0] = size + 1; /* all data plus seq byte */
234 bt->write_data[1] = *data; /* NetFn/LUN */
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800235 bt->write_data[2] = bt->seq++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 memcpy(bt->write_data + 3, data + 1, size - 1);
237 bt->write_count = size + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 bt->error_retries = 0;
239 bt->nonzero_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 bt->truncated = 0;
241 bt->state = BT_STATE_XACTION_START;
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800242 bt->timeout = bt->BT_CAP_req2rsp;
243 force_result(bt, IPMI_ERR_UNSPECIFIED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 return 0;
245}
246
247/* After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE
248 it calls this. Strip out the length and seq bytes. */
249
250static int bt_get_result(struct si_sm_data *bt,
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800251 unsigned char *data,
252 unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253{
254 int i, msg_len;
255
256 msg_len = bt->read_count - 2; /* account for length & seq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH) {
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800258 force_result(bt, IPMI_ERR_UNSPECIFIED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 msg_len = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 }
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800261 data[0] = bt->read_data[1];
262 data[1] = bt->read_data[3];
263 if (length < msg_len || bt->truncated) {
264 data[2] = IPMI_ERR_MSG_TRUNCATED;
265 msg_len = 3;
266 } else
267 memcpy(data + 2, bt->read_data + 4, msg_len - 2);
268
269 if (bt_debug & BT_DEBUG_MSG) {
270 printk (KERN_WARNING "BT: result %d bytes:", msg_len);
271 for (i = 0; i < msg_len; i++)
272 printk(" %02x", data[i]);
273 printk ("\n");
274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 return msg_len;
276}
277
278/* This bit's functionality is optional */
279#define BT_BMC_HWRST 0x80
280
281static void reset_flags(struct si_sm_data *bt)
282{
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800283 if (bt_debug)
284 printk(KERN_WARNING "IPMI BT: flag reset %s\n",
285 status2txt(BT_STATUS));
Corey Minyarde8b33612005-09-06 15:18:45 -0700286 if (BT_STATUS & BT_H_BUSY)
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800287 BT_CONTROL(BT_H_BUSY); /* force clear */
288 BT_CONTROL(BT_CLR_WR_PTR); /* always reset */
289 BT_CONTROL(BT_SMS_ATN); /* always clear */
290 BT_INTMASK_W(BT_BMC_HWRST);
291}
Corey Minyardc4edff12005-11-07 00:59:56 -0800292
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800293/* Get rid of an unwanted/stale response. This should only be needed for
294 BMCs that support multiple outstanding requests. */
295
296static void drain_BMC2HOST(struct si_sm_data *bt)
297{
298 int i, size;
299
300 if (!(BT_STATUS & BT_B2H_ATN)) /* Not signalling a response */
301 return;
302
303 BT_CONTROL(BT_H_BUSY); /* now set */
304 BT_CONTROL(BT_B2H_ATN); /* always clear */
305 BT_STATUS; /* pause */
306 BT_CONTROL(BT_B2H_ATN); /* some BMCs are stubborn */
307 BT_CONTROL(BT_CLR_RD_PTR); /* always reset */
308 if (bt_debug)
309 printk(KERN_WARNING "IPMI BT: stale response %s; ",
310 status2txt(BT_STATUS));
311 size = BMC2HOST;
312 for (i = 0; i < size ; i++)
313 BMC2HOST;
314 BT_CONTROL(BT_H_BUSY); /* now clear */
315 if (bt_debug)
316 printk("drained %d bytes\n", size + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317}
318
319static inline void write_all_bytes(struct si_sm_data *bt)
320{
321 int i;
322
323 if (bt_debug & BT_DEBUG_MSG) {
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800324 printk(KERN_WARNING "BT: write %d bytes seq=0x%02X",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 bt->write_count, bt->seq);
326 for (i = 0; i < bt->write_count; i++)
327 printk (" %02x", bt->write_data[i]);
328 printk ("\n");
329 }
Corey Minyarde8b33612005-09-06 15:18:45 -0700330 for (i = 0; i < bt->write_count; i++)
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800331 HOST2BMC(bt->write_data[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332}
333
334static inline int read_all_bytes(struct si_sm_data *bt)
335{
336 unsigned char i;
337
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800338 /* length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode.
339 Keep layout of first four bytes aligned with write_data[] */
340
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 bt->read_data[0] = BMC2HOST;
342 bt->read_count = bt->read_data[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) {
345 if (bt_debug & BT_DEBUG_MSG)
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800346 printk(KERN_WARNING "BT: bad raw rsp len=%d\n",
347 bt->read_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 bt->truncated = 1;
349 return 1; /* let next XACTION START clean it up */
350 }
Corey Minyarde8b33612005-09-06 15:18:45 -0700351 for (i = 1; i <= bt->read_count; i++)
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800352 bt->read_data[i] = BMC2HOST;
353 bt->read_count++; /* Account internally for length byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
355 if (bt_debug & BT_DEBUG_MSG) {
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800356 int max = bt->read_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800358 printk(KERN_WARNING "BT: got %d bytes seq=0x%02X",
359 max, bt->read_data[2]);
360 if (max > 16)
361 max = 16;
362 for (i = 0; i < max; i++)
363 printk (" %02x", bt->read_data[i]);
364 printk ("%s\n", bt->read_count == max ? "" : " ...");
365 }
366
367 /* per the spec, the (NetFn[1], Seq[2], Cmd[3]) tuples must match */
368 if ((bt->read_data[3] == bt->write_data[3]) &&
369 (bt->read_data[2] == bt->write_data[2]) &&
370 ((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 return 1;
372
Corey Minyarde8b33612005-09-06 15:18:45 -0700373 if (bt_debug & BT_DEBUG_MSG)
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800374 printk(KERN_WARNING "IPMI BT: bad packet: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 "want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n",
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800376 bt->write_data[1] | 0x04, bt->write_data[2], bt->write_data[3],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 bt->read_data[1], bt->read_data[2], bt->read_data[3]);
378 return 0;
379}
380
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800381/* Restart if retries are left, or return an error completion code */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800383static enum si_sm_result error_recovery(struct si_sm_data *bt,
384 unsigned char status,
385 unsigned char cCode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386{
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800387 char *reason;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800389 bt->timeout = bt->BT_CAP_req2rsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800391 switch (cCode) {
392 case IPMI_TIMEOUT_ERR:
393 reason = "timeout";
394 break;
395 default:
396 reason = "internal error";
397 break;
398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800400 printk(KERN_WARNING "IPMI BT: %s in %s %s ", /* open-ended line */
401 reason, STATE2TXT, STATUS2TXT);
402
403 /* Per the IPMI spec, retries are based on the sequence number
404 known only to this module, so manage a restart here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 (bt->error_retries)++;
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800406 if (bt->error_retries < bt->BT_CAP_retries) {
407 printk("%d retries left\n",
408 bt->BT_CAP_retries - bt->error_retries);
409 bt->state = BT_STATE_RESTART;
410 return SI_SM_CALL_WITHOUT_DELAY;
411 }
412
413 printk("failed %d retries, sending error response\n",
414 bt->BT_CAP_retries);
415 if (!bt->nonzero_status)
416 printk(KERN_ERR "IPMI BT: stuck, try power cycle\n");
417
418 /* this is most likely during insmod */
419 else if (bt->seq <= (unsigned char)(bt->BT_CAP_retries & 0xFF)) {
420 printk(KERN_WARNING "IPMI: BT reset (takes 5 secs)\n");
421 bt->state = BT_STATE_RESET1;
422 return SI_SM_CALL_WITHOUT_DELAY;
423 }
424
425 /* Concoct a useful error message, set up the next state, and
426 be done with this sequence. */
427
428 bt->state = BT_STATE_IDLE;
429 switch (cCode) {
430 case IPMI_TIMEOUT_ERR:
431 if (status & BT_B_BUSY) {
432 cCode = IPMI_NODE_BUSY_ERR;
433 bt->state = BT_STATE_LONG_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 }
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800435 break;
436 default:
437 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 }
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800439 force_result(bt, cCode);
440 return SI_SM_TRANSACTION_COMPLETE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441}
442
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800443/* Check status and (usually) take action and change this state machine. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444
445static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
446{
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800447 unsigned char status, BT_CAP[8];
448 static enum bt_states last_printed = BT_STATE_PRINTME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 int i;
450
451 status = BT_STATUS;
452 bt->nonzero_status |= status;
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800453 if ((bt_debug & BT_DEBUG_STATES) && (bt->state != last_printed)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n",
455 STATE2TXT,
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800456 STATUS2TXT,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 bt->timeout,
458 time);
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800459 last_printed = bt->state;
460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800462 /* Commands that time out may still (eventually) provide a response.
463 This stale response will get in the way of a new response so remove
464 it if possible (hopefully during IDLE). Even if it comes up later
465 it will be rejected by its (now-forgotten) seq number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800467 if ((bt->state < BT_STATE_WRITE_BYTES) && (status & BT_B2H_ATN)) {
468 drain_BMC2HOST(bt);
469 BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
470 }
471
472 if ((bt->state != BT_STATE_IDLE) &&
473 (bt->state < BT_STATE_PRINTME)) { /* check timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 bt->timeout -= time;
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800475 if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1))
476 return error_recovery(bt,
477 status,
478 IPMI_TIMEOUT_ERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 }
480
481 switch (bt->state) {
482
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800483 /* Idle state first checks for asynchronous messages from another
484 channel, then does some opportunistic housekeeping. */
485
486 case BT_STATE_IDLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 if (status & BT_SMS_ATN) {
488 BT_CONTROL(BT_SMS_ATN); /* clear it */
489 return SI_SM_ATTN;
490 }
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800491
492 if (status & BT_H_BUSY) /* clear a leftover H_BUSY */
493 BT_CONTROL(BT_H_BUSY);
494
495 /* Read BT capabilities if it hasn't been done yet */
496 if (!bt->BT_CAP_outreqs)
497 BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN,
498 SI_SM_CALL_WITHOUT_DELAY);
499 bt->timeout = bt->BT_CAP_req2rsp;
500 BT_SI_SM_RETURN(SI_SM_IDLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
502 case BT_STATE_XACTION_START:
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800503 if (status & (BT_B_BUSY | BT_H2B_ATN))
504 BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
505 if (BT_STATUS & BT_H_BUSY)
506 BT_CONTROL(BT_H_BUSY); /* force clear */
507 BT_STATE_CHANGE(BT_STATE_WRITE_BYTES,
508 SI_SM_CALL_WITHOUT_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 case BT_STATE_WRITE_BYTES:
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800511 if (status & BT_H_BUSY)
512 BT_CONTROL(BT_H_BUSY); /* clear */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 BT_CONTROL(BT_CLR_WR_PTR);
514 write_all_bytes(bt);
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800515 BT_CONTROL(BT_H2B_ATN); /* can clear too fast to catch */
516 BT_STATE_CHANGE(BT_STATE_WRITE_CONSUME,
517 SI_SM_CALL_WITHOUT_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800519 case BT_STATE_WRITE_CONSUME:
520 if (status & (BT_B_BUSY | BT_H2B_ATN))
521 BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
522 BT_STATE_CHANGE(BT_STATE_READ_WAIT,
523 SI_SM_CALL_WITHOUT_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800525 /* Spinning hard can suppress B2H_ATN and force a timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800527 case BT_STATE_READ_WAIT:
528 if (!(status & BT_B2H_ATN))
529 BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
530 BT_CONTROL(BT_H_BUSY); /* set */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800532 /* Uncached, ordered writes should just proceeed serially but
533 some BMCs don't clear B2H_ATN with one hit. Fast-path a
534 workaround without too much penalty to the general case. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800536 BT_CONTROL(BT_B2H_ATN); /* clear it to ACK the BMC */
537 BT_STATE_CHANGE(BT_STATE_CLEAR_B2H,
538 SI_SM_CALL_WITHOUT_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800540 case BT_STATE_CLEAR_B2H:
541 if (status & BT_B2H_ATN) { /* keep hitting it */
542 BT_CONTROL(BT_B2H_ATN);
543 BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
544 }
545 BT_STATE_CHANGE(BT_STATE_READ_BYTES,
546 SI_SM_CALL_WITHOUT_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800548 case BT_STATE_READ_BYTES:
549 if (!(status & BT_H_BUSY)) /* check in case of retry */
550 BT_CONTROL(BT_H_BUSY);
551 BT_CONTROL(BT_CLR_RD_PTR); /* start of BMC2HOST buffer */
552 i = read_all_bytes(bt); /* true == packet seq match */
553 BT_CONTROL(BT_H_BUSY); /* NOW clear */
554 if (!i) /* Not my message */
555 BT_STATE_CHANGE(BT_STATE_READ_WAIT,
556 SI_SM_CALL_WITHOUT_DELAY);
557 bt->state = bt->complete;
558 return bt->state == BT_STATE_IDLE ? /* where to next? */
559 SI_SM_TRANSACTION_COMPLETE : /* normal */
560 SI_SM_CALL_WITHOUT_DELAY; /* Startup magic */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800562 case BT_STATE_LONG_BUSY: /* For example: after FW update */
563 if (!(status & BT_B_BUSY)) {
564 reset_flags(bt); /* next state is now IDLE */
565 bt_init_data(bt, bt->io);
566 }
567 return SI_SM_CALL_WITH_DELAY; /* No repeat printing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
569 case BT_STATE_RESET1:
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800570 reset_flags(bt);
571 drain_BMC2HOST(bt);
572 BT_STATE_CHANGE(BT_STATE_RESET2,
573 SI_SM_CALL_WITH_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
575 case BT_STATE_RESET2: /* Send a soft reset */
576 BT_CONTROL(BT_CLR_WR_PTR);
577 HOST2BMC(3); /* number of bytes following */
578 HOST2BMC(0x18); /* NetFn/LUN == Application, LUN 0 */
579 HOST2BMC(42); /* Sequence number */
580 HOST2BMC(3); /* Cmd == Soft reset */
581 BT_CONTROL(BT_H2B_ATN);
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800582 bt->timeout = BT_RESET_DELAY * 1000000;
583 BT_STATE_CHANGE(BT_STATE_RESET3,
584 SI_SM_CALL_WITH_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800586 case BT_STATE_RESET3: /* Hold off everything for a bit */
Corey Minyarde8b33612005-09-06 15:18:45 -0700587 if (bt->timeout > 0)
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800588 return SI_SM_CALL_WITH_DELAY;
589 drain_BMC2HOST(bt);
590 BT_STATE_CHANGE(BT_STATE_RESTART,
591 SI_SM_CALL_WITH_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800593 case BT_STATE_RESTART: /* don't reset retries or seq! */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 bt->read_count = 0;
595 bt->nonzero_status = 0;
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800596 bt->timeout = bt->BT_CAP_req2rsp;
597 BT_STATE_CHANGE(BT_STATE_XACTION_START,
598 SI_SM_CALL_WITH_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800600 /* Get BT Capabilities, using timing of upper level state machine.
601 Set outreqs to prevent infinite loop on timeout. */
602 case BT_STATE_CAPABILITIES_BEGIN:
603 bt->BT_CAP_outreqs = 1;
604 {
605 unsigned char GetBT_CAP[] = { 0x18, 0x36 };
606 bt->state = BT_STATE_IDLE;
607 bt_start_transaction(bt, GetBT_CAP, sizeof(GetBT_CAP));
608 }
609 bt->complete = BT_STATE_CAPABILITIES_END;
610 BT_STATE_CHANGE(BT_STATE_XACTION_START,
611 SI_SM_CALL_WITH_DELAY);
612
613 case BT_STATE_CAPABILITIES_END:
614 i = bt_get_result(bt, BT_CAP, sizeof(BT_CAP));
615 bt_init_data(bt, bt->io);
616 if ((i == 8) && !BT_CAP[2]) {
617 bt->BT_CAP_outreqs = BT_CAP[3];
618 bt->BT_CAP_req2rsp = BT_CAP[6] * 1000000;
619 bt->BT_CAP_retries = BT_CAP[7];
620 } else
621 printk(KERN_WARNING "IPMI BT: using default values\n");
622 if (!bt->BT_CAP_outreqs)
623 bt->BT_CAP_outreqs = 1;
624 printk(KERN_WARNING "IPMI BT: req2rsp=%ld secs retries=%d\n",
625 bt->BT_CAP_req2rsp / 1000000L, bt->BT_CAP_retries);
626 bt->timeout = bt->BT_CAP_req2rsp;
627 return SI_SM_CALL_WITHOUT_DELAY;
628
629 default: /* should never occur */
630 return error_recovery(bt,
631 status,
632 IPMI_ERR_UNSPECIFIED);
633 }
634 return SI_SM_CALL_WITH_DELAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635}
636
637static int bt_detect(struct si_sm_data *bt)
638{
639 /* It's impossible for the BT status and interrupt registers to be
640 all 1's, (assuming a properly functioning, self-initialized BMC)
641 but that's what you get from reading a bogus address, so we
642 test that first. The calling routine uses negative logic. */
643
Corey Minyarde8b33612005-09-06 15:18:45 -0700644 if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF))
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800645 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 reset_flags(bt);
647 return 0;
648}
649
650static void bt_cleanup(struct si_sm_data *bt)
651{
652}
653
654static int bt_size(void)
655{
656 return sizeof(struct si_sm_data);
657}
658
659struct si_sm_handlers bt_smi_handlers =
660{
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800661 .init_data = bt_init_data,
662 .start_transaction = bt_start_transaction,
663 .get_result = bt_get_result,
664 .event = bt_event,
665 .detect = bt_detect,
666 .cleanup = bt_cleanup,
667 .size = bt_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668};