blob: e736119b64970ab6175c161e91a95d4412197bb8 [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 */
Randy Dunlap0c8204b2006-12-10 02:19:06 -080040/* BT_DEBUG_OFF must be zero to correspond to the default uninitialized
41 value */
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
Randy Dunlap0c8204b2006-12-10 02:19:06 -080043static int bt_debug; /* 0 == BT_DEBUG_OFF */
Corey Minyard4d7cbac2006-12-06 20:41:14 -080044
Corey Minyardc4edff12005-11-07 00:59:56 -080045module_param(bt_debug, int, 0644);
46MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states");
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48/* Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds,
49 and 64 byte buffers. However, one HP implementation wants 255 bytes of
50 buffer (with a documented message of 160 bytes) so go for the max.
51 Since the Open IPMI architecture is single-message oriented at this
52 stage, the queue depth of BT is of no concern. */
53
Corey Minyard4d7cbac2006-12-06 20:41:14 -080054#define BT_NORMAL_TIMEOUT 5 /* seconds */
55#define BT_NORMAL_RETRY_LIMIT 2
56#define BT_RESET_DELAY 6 /* seconds after warm reset */
57
58/* States are written in chronological order and usually cover
59 multiple rows of the state table discussion in the IPMI spec. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
61enum bt_states {
Corey Minyard4d7cbac2006-12-06 20:41:14 -080062 BT_STATE_IDLE = 0, /* Order is critical in this list */
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 BT_STATE_XACTION_START,
64 BT_STATE_WRITE_BYTES,
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 BT_STATE_WRITE_CONSUME,
Corey Minyard4d7cbac2006-12-06 20:41:14 -080066 BT_STATE_READ_WAIT,
67 BT_STATE_CLEAR_B2H,
68 BT_STATE_READ_BYTES,
69 BT_STATE_RESET1, /* These must come last */
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 BT_STATE_RESET2,
71 BT_STATE_RESET3,
72 BT_STATE_RESTART,
Corey Minyard4d7cbac2006-12-06 20:41:14 -080073 BT_STATE_PRINTME,
74 BT_STATE_CAPABILITIES_BEGIN,
75 BT_STATE_CAPABILITIES_END,
76 BT_STATE_LONG_BUSY /* BT doesn't get hosed :-) */
Linus Torvalds1da177e2005-04-16 15:20:36 -070077};
78
Corey Minyard4d7cbac2006-12-06 20:41:14 -080079/* Macros seen at the end of state "case" blocks. They help with legibility
80 and debugging. */
81
82#define BT_STATE_CHANGE(X,Y) { bt->state = X; return Y; }
83
84#define BT_SI_SM_RETURN(Y) { last_printed = BT_STATE_PRINTME; return Y; }
85
Linus Torvalds1da177e2005-04-16 15:20:36 -070086struct si_sm_data {
87 enum bt_states state;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 unsigned char seq; /* BT sequence number */
89 struct si_sm_io *io;
Corey Minyard4d7cbac2006-12-06 20:41:14 -080090 unsigned char write_data[IPMI_MAX_MSG_LENGTH];
91 int write_count;
92 unsigned char read_data[IPMI_MAX_MSG_LENGTH];
93 int read_count;
94 int truncated;
95 long timeout; /* microseconds countdown */
96 int error_retries; /* end of "common" fields */
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 int nonzero_status; /* hung BMCs stay all 0 */
Corey Minyard4d7cbac2006-12-06 20:41:14 -080098 enum bt_states complete; /* to divert the state machine */
99 int BT_CAP_outreqs;
100 long BT_CAP_req2rsp;
101 int BT_CAP_retries; /* Recommended retries */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102};
103
104#define BT_CLR_WR_PTR 0x01 /* See IPMI 1.5 table 11.6.4 */
105#define BT_CLR_RD_PTR 0x02
106#define BT_H2B_ATN 0x04
107#define BT_B2H_ATN 0x08
108#define BT_SMS_ATN 0x10
109#define BT_OEM0 0x20
110#define BT_H_BUSY 0x40
111#define BT_B_BUSY 0x80
112
113/* Some bits are toggled on each write: write once to set it, once
114 more to clear it; writing a zero does nothing. To absolutely
115 clear it, check its state and write if set. This avoids the "get
116 current then use as mask" scheme to modify one bit. Note that the
117 variable "bt" is hardcoded into these macros. */
118
119#define BT_STATUS bt->io->inputb(bt->io, 0)
120#define BT_CONTROL(x) bt->io->outputb(bt->io, 0, x)
121
122#define BMC2HOST bt->io->inputb(bt->io, 1)
123#define HOST2BMC(x) bt->io->outputb(bt->io, 1, x)
124
125#define BT_INTMASK_R bt->io->inputb(bt->io, 2)
126#define BT_INTMASK_W(x) bt->io->outputb(bt->io, 2, x)
127
128/* Convenience routines for debugging. These are not multi-open safe!
129 Note the macros have hardcoded variables in them. */
130
131static char *state2txt(unsigned char state)
132{
133 switch (state) {
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800134 case BT_STATE_IDLE: return("IDLE");
135 case BT_STATE_XACTION_START: return("XACTION");
136 case BT_STATE_WRITE_BYTES: return("WR_BYTES");
137 case BT_STATE_WRITE_CONSUME: return("WR_CONSUME");
138 case BT_STATE_READ_WAIT: return("RD_WAIT");
139 case BT_STATE_CLEAR_B2H: return("CLEAR_B2H");
140 case BT_STATE_READ_BYTES: return("RD_BYTES");
141 case BT_STATE_RESET1: return("RESET1");
142 case BT_STATE_RESET2: return("RESET2");
143 case BT_STATE_RESET3: return("RESET3");
144 case BT_STATE_RESTART: return("RESTART");
145 case BT_STATE_LONG_BUSY: return("LONG_BUSY");
146 case BT_STATE_CAPABILITIES_BEGIN: return("CAP_BEGIN");
147 case BT_STATE_CAPABILITIES_END: return("CAP_END");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 }
149 return("BAD STATE");
150}
151#define STATE2TXT state2txt(bt->state)
152
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800153static char *status2txt(unsigned char status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154{
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800155 /*
156 * This cannot be called by two threads at the same time and
157 * the buffer is always consumed immediately, so the static is
158 * safe to use.
159 */
160 static char buf[40];
161
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 strcpy(buf, "[ ");
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800163 if (status & BT_B_BUSY)
164 strcat(buf, "B_BUSY ");
165 if (status & BT_H_BUSY)
166 strcat(buf, "H_BUSY ");
167 if (status & BT_OEM0)
168 strcat(buf, "OEM0 ");
169 if (status & BT_SMS_ATN)
170 strcat(buf, "SMS ");
171 if (status & BT_B2H_ATN)
172 strcat(buf, "B2H ");
173 if (status & BT_H2B_ATN)
174 strcat(buf, "H2B ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 strcat(buf, "]");
176 return buf;
177}
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800178#define STATUS2TXT status2txt(status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800180/* called externally at insmod time, and internally on cleanup */
181
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io)
183{
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800184 memset(bt, 0, sizeof(struct si_sm_data));
185 if (bt->io != io) { /* external: one-time only things */
186 bt->io = io;
187 bt->seq = 0;
188 }
189 bt->state = BT_STATE_IDLE; /* start here */
190 bt->complete = BT_STATE_IDLE; /* end here */
191 bt->BT_CAP_req2rsp = BT_NORMAL_TIMEOUT * 1000000;
192 bt->BT_CAP_retries = BT_NORMAL_RETRY_LIMIT;
193 /* BT_CAP_outreqs == zero is a flag to read BT Capabilities */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 return 3; /* We claim 3 bytes of space; ought to check SPMI table */
195}
196
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800197/* Jam a completion code (probably an error) into a response */
198
199static void force_result(struct si_sm_data *bt, unsigned char completion_code)
200{
201 bt->read_data[0] = 4; /* # following bytes */
202 bt->read_data[1] = bt->write_data[1] | 4; /* Odd NetFn/LUN */
203 bt->read_data[2] = bt->write_data[2]; /* seq (ignored) */
204 bt->read_data[3] = bt->write_data[3]; /* Command */
205 bt->read_data[4] = completion_code;
206 bt->read_count = 5;
207}
208
209/* The upper state machine starts here */
210
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211static int bt_start_transaction(struct si_sm_data *bt,
212 unsigned char *data,
213 unsigned int size)
214{
215 unsigned int i;
216
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800217 if (size < 2)
218 return IPMI_REQ_LEN_INVALID_ERR;
219 if (size > IPMI_MAX_MSG_LENGTH)
220 return IPMI_REQ_LEN_EXCEEDED_ERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800222 if (bt->state == BT_STATE_LONG_BUSY)
223 return IPMI_NODE_BUSY_ERR;
224
225 if (bt->state != BT_STATE_IDLE)
226 return IPMI_NOT_IN_MY_STATE_ERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
228 if (bt_debug & BT_DEBUG_MSG) {
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800229 printk(KERN_WARNING "BT: +++++++++++++++++ New command\n");
230 printk(KERN_WARNING "BT: NetFn/LUN CMD [%d data]:", size - 2);
Corey Minyarde8b33612005-09-06 15:18:45 -0700231 for (i = 0; i < size; i ++)
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800232 printk (" %02x", data[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 printk("\n");
234 }
235 bt->write_data[0] = size + 1; /* all data plus seq byte */
236 bt->write_data[1] = *data; /* NetFn/LUN */
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800237 bt->write_data[2] = bt->seq++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 memcpy(bt->write_data + 3, data + 1, size - 1);
239 bt->write_count = size + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 bt->error_retries = 0;
241 bt->nonzero_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 bt->truncated = 0;
243 bt->state = BT_STATE_XACTION_START;
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800244 bt->timeout = bt->BT_CAP_req2rsp;
245 force_result(bt, IPMI_ERR_UNSPECIFIED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 return 0;
247}
248
249/* After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE
250 it calls this. Strip out the length and seq bytes. */
251
252static int bt_get_result(struct si_sm_data *bt,
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800253 unsigned char *data,
254 unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255{
256 int i, msg_len;
257
258 msg_len = bt->read_count - 2; /* account for length & seq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH) {
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800260 force_result(bt, IPMI_ERR_UNSPECIFIED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 msg_len = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 }
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800263 data[0] = bt->read_data[1];
264 data[1] = bt->read_data[3];
265 if (length < msg_len || bt->truncated) {
266 data[2] = IPMI_ERR_MSG_TRUNCATED;
267 msg_len = 3;
268 } else
269 memcpy(data + 2, bt->read_data + 4, msg_len - 2);
270
271 if (bt_debug & BT_DEBUG_MSG) {
272 printk (KERN_WARNING "BT: result %d bytes:", msg_len);
273 for (i = 0; i < msg_len; i++)
274 printk(" %02x", data[i]);
275 printk ("\n");
276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 return msg_len;
278}
279
280/* This bit's functionality is optional */
281#define BT_BMC_HWRST 0x80
282
283static void reset_flags(struct si_sm_data *bt)
284{
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800285 if (bt_debug)
286 printk(KERN_WARNING "IPMI BT: flag reset %s\n",
287 status2txt(BT_STATUS));
Corey Minyarde8b33612005-09-06 15:18:45 -0700288 if (BT_STATUS & BT_H_BUSY)
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800289 BT_CONTROL(BT_H_BUSY); /* force clear */
290 BT_CONTROL(BT_CLR_WR_PTR); /* always reset */
291 BT_CONTROL(BT_SMS_ATN); /* always clear */
292 BT_INTMASK_W(BT_BMC_HWRST);
293}
Corey Minyardc4edff12005-11-07 00:59:56 -0800294
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800295/* Get rid of an unwanted/stale response. This should only be needed for
296 BMCs that support multiple outstanding requests. */
297
298static void drain_BMC2HOST(struct si_sm_data *bt)
299{
300 int i, size;
301
302 if (!(BT_STATUS & BT_B2H_ATN)) /* Not signalling a response */
303 return;
304
305 BT_CONTROL(BT_H_BUSY); /* now set */
306 BT_CONTROL(BT_B2H_ATN); /* always clear */
307 BT_STATUS; /* pause */
308 BT_CONTROL(BT_B2H_ATN); /* some BMCs are stubborn */
309 BT_CONTROL(BT_CLR_RD_PTR); /* always reset */
310 if (bt_debug)
311 printk(KERN_WARNING "IPMI BT: stale response %s; ",
312 status2txt(BT_STATUS));
313 size = BMC2HOST;
314 for (i = 0; i < size ; i++)
315 BMC2HOST;
316 BT_CONTROL(BT_H_BUSY); /* now clear */
317 if (bt_debug)
318 printk("drained %d bytes\n", size + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319}
320
321static inline void write_all_bytes(struct si_sm_data *bt)
322{
323 int i;
324
325 if (bt_debug & BT_DEBUG_MSG) {
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800326 printk(KERN_WARNING "BT: write %d bytes seq=0x%02X",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 bt->write_count, bt->seq);
328 for (i = 0; i < bt->write_count; i++)
329 printk (" %02x", bt->write_data[i]);
330 printk ("\n");
331 }
Corey Minyarde8b33612005-09-06 15:18:45 -0700332 for (i = 0; i < bt->write_count; i++)
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800333 HOST2BMC(bt->write_data[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335
336static inline int read_all_bytes(struct si_sm_data *bt)
337{
338 unsigned char i;
339
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800340 /* length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode.
341 Keep layout of first four bytes aligned with write_data[] */
342
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 bt->read_data[0] = BMC2HOST;
344 bt->read_count = bt->read_data[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) {
347 if (bt_debug & BT_DEBUG_MSG)
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800348 printk(KERN_WARNING "BT: bad raw rsp len=%d\n",
349 bt->read_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 bt->truncated = 1;
351 return 1; /* let next XACTION START clean it up */
352 }
Corey Minyarde8b33612005-09-06 15:18:45 -0700353 for (i = 1; i <= bt->read_count; i++)
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800354 bt->read_data[i] = BMC2HOST;
355 bt->read_count++; /* Account internally for length byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
357 if (bt_debug & BT_DEBUG_MSG) {
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800358 int max = bt->read_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800360 printk(KERN_WARNING "BT: got %d bytes seq=0x%02X",
361 max, bt->read_data[2]);
362 if (max > 16)
363 max = 16;
364 for (i = 0; i < max; i++)
365 printk (" %02x", bt->read_data[i]);
366 printk ("%s\n", bt->read_count == max ? "" : " ...");
367 }
368
369 /* per the spec, the (NetFn[1], Seq[2], Cmd[3]) tuples must match */
370 if ((bt->read_data[3] == bt->write_data[3]) &&
371 (bt->read_data[2] == bt->write_data[2]) &&
372 ((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 return 1;
374
Corey Minyarde8b33612005-09-06 15:18:45 -0700375 if (bt_debug & BT_DEBUG_MSG)
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800376 printk(KERN_WARNING "IPMI BT: bad packet: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 "want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n",
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800378 bt->write_data[1] | 0x04, bt->write_data[2], bt->write_data[3],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 bt->read_data[1], bt->read_data[2], bt->read_data[3]);
380 return 0;
381}
382
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800383/* Restart if retries are left, or return an error completion code */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800385static enum si_sm_result error_recovery(struct si_sm_data *bt,
386 unsigned char status,
387 unsigned char cCode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388{
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800389 char *reason;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800391 bt->timeout = bt->BT_CAP_req2rsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800393 switch (cCode) {
394 case IPMI_TIMEOUT_ERR:
395 reason = "timeout";
396 break;
397 default:
398 reason = "internal error";
399 break;
400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800402 printk(KERN_WARNING "IPMI BT: %s in %s %s ", /* open-ended line */
403 reason, STATE2TXT, STATUS2TXT);
404
405 /* Per the IPMI spec, retries are based on the sequence number
406 known only to this module, so manage a restart here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 (bt->error_retries)++;
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800408 if (bt->error_retries < bt->BT_CAP_retries) {
409 printk("%d retries left\n",
410 bt->BT_CAP_retries - bt->error_retries);
411 bt->state = BT_STATE_RESTART;
412 return SI_SM_CALL_WITHOUT_DELAY;
413 }
414
415 printk("failed %d retries, sending error response\n",
416 bt->BT_CAP_retries);
417 if (!bt->nonzero_status)
418 printk(KERN_ERR "IPMI BT: stuck, try power cycle\n");
419
420 /* this is most likely during insmod */
421 else if (bt->seq <= (unsigned char)(bt->BT_CAP_retries & 0xFF)) {
422 printk(KERN_WARNING "IPMI: BT reset (takes 5 secs)\n");
423 bt->state = BT_STATE_RESET1;
424 return SI_SM_CALL_WITHOUT_DELAY;
425 }
426
427 /* Concoct a useful error message, set up the next state, and
428 be done with this sequence. */
429
430 bt->state = BT_STATE_IDLE;
431 switch (cCode) {
432 case IPMI_TIMEOUT_ERR:
433 if (status & BT_B_BUSY) {
434 cCode = IPMI_NODE_BUSY_ERR;
435 bt->state = BT_STATE_LONG_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 }
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800437 break;
438 default:
439 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 }
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800441 force_result(bt, cCode);
442 return SI_SM_TRANSACTION_COMPLETE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443}
444
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800445/* Check status and (usually) take action and change this state machine. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
447static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
448{
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800449 unsigned char status, BT_CAP[8];
450 static enum bt_states last_printed = BT_STATE_PRINTME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 int i;
452
453 status = BT_STATUS;
454 bt->nonzero_status |= status;
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800455 if ((bt_debug & BT_DEBUG_STATES) && (bt->state != last_printed)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n",
457 STATE2TXT,
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800458 STATUS2TXT,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 bt->timeout,
460 time);
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800461 last_printed = bt->state;
462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800464 /* Commands that time out may still (eventually) provide a response.
465 This stale response will get in the way of a new response so remove
466 it if possible (hopefully during IDLE). Even if it comes up later
467 it will be rejected by its (now-forgotten) seq number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800469 if ((bt->state < BT_STATE_WRITE_BYTES) && (status & BT_B2H_ATN)) {
470 drain_BMC2HOST(bt);
471 BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
472 }
473
474 if ((bt->state != BT_STATE_IDLE) &&
475 (bt->state < BT_STATE_PRINTME)) { /* check timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 bt->timeout -= time;
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800477 if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1))
478 return error_recovery(bt,
479 status,
480 IPMI_TIMEOUT_ERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 }
482
483 switch (bt->state) {
484
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800485 /* Idle state first checks for asynchronous messages from another
486 channel, then does some opportunistic housekeeping. */
487
488 case BT_STATE_IDLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 if (status & BT_SMS_ATN) {
490 BT_CONTROL(BT_SMS_ATN); /* clear it */
491 return SI_SM_ATTN;
492 }
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800493
494 if (status & BT_H_BUSY) /* clear a leftover H_BUSY */
495 BT_CONTROL(BT_H_BUSY);
496
497 /* Read BT capabilities if it hasn't been done yet */
498 if (!bt->BT_CAP_outreqs)
499 BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN,
500 SI_SM_CALL_WITHOUT_DELAY);
501 bt->timeout = bt->BT_CAP_req2rsp;
502 BT_SI_SM_RETURN(SI_SM_IDLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
504 case BT_STATE_XACTION_START:
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800505 if (status & (BT_B_BUSY | BT_H2B_ATN))
506 BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
507 if (BT_STATUS & BT_H_BUSY)
508 BT_CONTROL(BT_H_BUSY); /* force clear */
509 BT_STATE_CHANGE(BT_STATE_WRITE_BYTES,
510 SI_SM_CALL_WITHOUT_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
512 case BT_STATE_WRITE_BYTES:
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800513 if (status & BT_H_BUSY)
514 BT_CONTROL(BT_H_BUSY); /* clear */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 BT_CONTROL(BT_CLR_WR_PTR);
516 write_all_bytes(bt);
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800517 BT_CONTROL(BT_H2B_ATN); /* can clear too fast to catch */
518 BT_STATE_CHANGE(BT_STATE_WRITE_CONSUME,
519 SI_SM_CALL_WITHOUT_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800521 case BT_STATE_WRITE_CONSUME:
522 if (status & (BT_B_BUSY | BT_H2B_ATN))
523 BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
524 BT_STATE_CHANGE(BT_STATE_READ_WAIT,
525 SI_SM_CALL_WITHOUT_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800527 /* Spinning hard can suppress B2H_ATN and force a timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800529 case BT_STATE_READ_WAIT:
530 if (!(status & BT_B2H_ATN))
531 BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
532 BT_CONTROL(BT_H_BUSY); /* set */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800534 /* Uncached, ordered writes should just proceeed serially but
535 some BMCs don't clear B2H_ATN with one hit. Fast-path a
536 workaround without too much penalty to the general case. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800538 BT_CONTROL(BT_B2H_ATN); /* clear it to ACK the BMC */
539 BT_STATE_CHANGE(BT_STATE_CLEAR_B2H,
540 SI_SM_CALL_WITHOUT_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800542 case BT_STATE_CLEAR_B2H:
543 if (status & BT_B2H_ATN) { /* keep hitting it */
544 BT_CONTROL(BT_B2H_ATN);
545 BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
546 }
547 BT_STATE_CHANGE(BT_STATE_READ_BYTES,
548 SI_SM_CALL_WITHOUT_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800550 case BT_STATE_READ_BYTES:
551 if (!(status & BT_H_BUSY)) /* check in case of retry */
552 BT_CONTROL(BT_H_BUSY);
553 BT_CONTROL(BT_CLR_RD_PTR); /* start of BMC2HOST buffer */
554 i = read_all_bytes(bt); /* true == packet seq match */
555 BT_CONTROL(BT_H_BUSY); /* NOW clear */
556 if (!i) /* Not my message */
557 BT_STATE_CHANGE(BT_STATE_READ_WAIT,
558 SI_SM_CALL_WITHOUT_DELAY);
559 bt->state = bt->complete;
560 return bt->state == BT_STATE_IDLE ? /* where to next? */
561 SI_SM_TRANSACTION_COMPLETE : /* normal */
562 SI_SM_CALL_WITHOUT_DELAY; /* Startup magic */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800564 case BT_STATE_LONG_BUSY: /* For example: after FW update */
565 if (!(status & BT_B_BUSY)) {
566 reset_flags(bt); /* next state is now IDLE */
567 bt_init_data(bt, bt->io);
568 }
569 return SI_SM_CALL_WITH_DELAY; /* No repeat printing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
571 case BT_STATE_RESET1:
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800572 reset_flags(bt);
573 drain_BMC2HOST(bt);
574 BT_STATE_CHANGE(BT_STATE_RESET2,
575 SI_SM_CALL_WITH_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
577 case BT_STATE_RESET2: /* Send a soft reset */
578 BT_CONTROL(BT_CLR_WR_PTR);
579 HOST2BMC(3); /* number of bytes following */
580 HOST2BMC(0x18); /* NetFn/LUN == Application, LUN 0 */
581 HOST2BMC(42); /* Sequence number */
582 HOST2BMC(3); /* Cmd == Soft reset */
583 BT_CONTROL(BT_H2B_ATN);
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800584 bt->timeout = BT_RESET_DELAY * 1000000;
585 BT_STATE_CHANGE(BT_STATE_RESET3,
586 SI_SM_CALL_WITH_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800588 case BT_STATE_RESET3: /* Hold off everything for a bit */
Corey Minyarde8b33612005-09-06 15:18:45 -0700589 if (bt->timeout > 0)
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800590 return SI_SM_CALL_WITH_DELAY;
591 drain_BMC2HOST(bt);
592 BT_STATE_CHANGE(BT_STATE_RESTART,
593 SI_SM_CALL_WITH_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800595 case BT_STATE_RESTART: /* don't reset retries or seq! */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 bt->read_count = 0;
597 bt->nonzero_status = 0;
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800598 bt->timeout = bt->BT_CAP_req2rsp;
599 BT_STATE_CHANGE(BT_STATE_XACTION_START,
600 SI_SM_CALL_WITH_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800602 /* Get BT Capabilities, using timing of upper level state machine.
603 Set outreqs to prevent infinite loop on timeout. */
604 case BT_STATE_CAPABILITIES_BEGIN:
605 bt->BT_CAP_outreqs = 1;
606 {
607 unsigned char GetBT_CAP[] = { 0x18, 0x36 };
608 bt->state = BT_STATE_IDLE;
609 bt_start_transaction(bt, GetBT_CAP, sizeof(GetBT_CAP));
610 }
611 bt->complete = BT_STATE_CAPABILITIES_END;
612 BT_STATE_CHANGE(BT_STATE_XACTION_START,
613 SI_SM_CALL_WITH_DELAY);
614
615 case BT_STATE_CAPABILITIES_END:
616 i = bt_get_result(bt, BT_CAP, sizeof(BT_CAP));
617 bt_init_data(bt, bt->io);
618 if ((i == 8) && !BT_CAP[2]) {
619 bt->BT_CAP_outreqs = BT_CAP[3];
620 bt->BT_CAP_req2rsp = BT_CAP[6] * 1000000;
621 bt->BT_CAP_retries = BT_CAP[7];
622 } else
623 printk(KERN_WARNING "IPMI BT: using default values\n");
624 if (!bt->BT_CAP_outreqs)
625 bt->BT_CAP_outreqs = 1;
626 printk(KERN_WARNING "IPMI BT: req2rsp=%ld secs retries=%d\n",
627 bt->BT_CAP_req2rsp / 1000000L, bt->BT_CAP_retries);
628 bt->timeout = bt->BT_CAP_req2rsp;
629 return SI_SM_CALL_WITHOUT_DELAY;
630
631 default: /* should never occur */
632 return error_recovery(bt,
633 status,
634 IPMI_ERR_UNSPECIFIED);
635 }
636 return SI_SM_CALL_WITH_DELAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637}
638
639static int bt_detect(struct si_sm_data *bt)
640{
641 /* It's impossible for the BT status and interrupt registers to be
642 all 1's, (assuming a properly functioning, self-initialized BMC)
643 but that's what you get from reading a bogus address, so we
644 test that first. The calling routine uses negative logic. */
645
Corey Minyarde8b33612005-09-06 15:18:45 -0700646 if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF))
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800647 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 reset_flags(bt);
649 return 0;
650}
651
652static void bt_cleanup(struct si_sm_data *bt)
653{
654}
655
656static int bt_size(void)
657{
658 return sizeof(struct si_sm_data);
659}
660
661struct si_sm_handlers bt_smi_handlers =
662{
Corey Minyard4d7cbac2006-12-06 20:41:14 -0800663 .init_data = bt_init_data,
664 .start_transaction = bt_start_transaction,
665 .get_result = bt_get_result,
666 .event = bt_event,
667 .detect = bt_detect,
668 .cleanup = bt_cleanup,
669 .size = bt_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670};