xref: /linux/drivers/char/ipmi/ipmi_bt_sm.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  *  ipmi_bt_sm.c
3*1da177e4SLinus Torvalds  *
4*1da177e4SLinus Torvalds  *  The state machine for an Open IPMI BT sub-driver under ipmi_si.c, part
5*1da177e4SLinus Torvalds  *  of the driver architecture at http://sourceforge.net/project/openipmi
6*1da177e4SLinus Torvalds  *
7*1da177e4SLinus Torvalds  *  Author:	Rocky Craig <first.last@hp.com>
8*1da177e4SLinus Torvalds  *
9*1da177e4SLinus Torvalds  *  This program is free software; you can redistribute it and/or modify it
10*1da177e4SLinus Torvalds  *  under the terms of the GNU General Public License as published by the
11*1da177e4SLinus Torvalds  *  Free Software Foundation; either version 2 of the License, or (at your
12*1da177e4SLinus Torvalds  *  option) any later version.
13*1da177e4SLinus Torvalds  *
14*1da177e4SLinus Torvalds  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
15*1da177e4SLinus Torvalds  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16*1da177e4SLinus Torvalds  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17*1da177e4SLinus Torvalds  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18*1da177e4SLinus Torvalds  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19*1da177e4SLinus Torvalds  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
20*1da177e4SLinus Torvalds  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21*1da177e4SLinus Torvalds  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
22*1da177e4SLinus Torvalds  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23*1da177e4SLinus Torvalds  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24*1da177e4SLinus Torvalds  *
25*1da177e4SLinus Torvalds  *  You should have received a copy of the GNU General Public License along
26*1da177e4SLinus Torvalds  *  with this program; if not, write to the Free Software Foundation, Inc.,
27*1da177e4SLinus Torvalds  *  675 Mass Ave, Cambridge, MA 02139, USA.  */
28*1da177e4SLinus Torvalds 
29*1da177e4SLinus Torvalds #include <linux/kernel.h> /* For printk. */
30*1da177e4SLinus Torvalds #include <linux/string.h>
31*1da177e4SLinus Torvalds #include <linux/ipmi_msgdefs.h>		/* for completion codes */
32*1da177e4SLinus Torvalds #include "ipmi_si_sm.h"
33*1da177e4SLinus Torvalds 
34*1da177e4SLinus Torvalds #define IPMI_BT_VERSION "v33"
35*1da177e4SLinus Torvalds 
36*1da177e4SLinus Torvalds static int bt_debug = 0x00;	/* Production value 0, see following flags */
37*1da177e4SLinus Torvalds 
38*1da177e4SLinus Torvalds #define	BT_DEBUG_ENABLE	1
39*1da177e4SLinus Torvalds #define BT_DEBUG_MSG	2
40*1da177e4SLinus Torvalds #define BT_DEBUG_STATES	4
41*1da177e4SLinus Torvalds 
42*1da177e4SLinus Torvalds /* Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds,
43*1da177e4SLinus Torvalds    and 64 byte buffers.  However, one HP implementation wants 255 bytes of
44*1da177e4SLinus Torvalds    buffer (with a documented message of 160 bytes) so go for the max.
45*1da177e4SLinus Torvalds    Since the Open IPMI architecture is single-message oriented at this
46*1da177e4SLinus Torvalds    stage, the queue depth of BT is of no concern. */
47*1da177e4SLinus Torvalds 
48*1da177e4SLinus Torvalds #define BT_NORMAL_TIMEOUT	2000000	/* seconds in microseconds */
49*1da177e4SLinus Torvalds #define BT_RETRY_LIMIT		2
50*1da177e4SLinus Torvalds #define BT_RESET_DELAY		6000000	/* 6 seconds after warm reset */
51*1da177e4SLinus Torvalds 
52*1da177e4SLinus Torvalds enum bt_states {
53*1da177e4SLinus Torvalds 	BT_STATE_IDLE,
54*1da177e4SLinus Torvalds 	BT_STATE_XACTION_START,
55*1da177e4SLinus Torvalds 	BT_STATE_WRITE_BYTES,
56*1da177e4SLinus Torvalds 	BT_STATE_WRITE_END,
57*1da177e4SLinus Torvalds 	BT_STATE_WRITE_CONSUME,
58*1da177e4SLinus Torvalds 	BT_STATE_B2H_WAIT,
59*1da177e4SLinus Torvalds 	BT_STATE_READ_END,
60*1da177e4SLinus Torvalds 	BT_STATE_RESET1,		/* These must come last */
61*1da177e4SLinus Torvalds 	BT_STATE_RESET2,
62*1da177e4SLinus Torvalds 	BT_STATE_RESET3,
63*1da177e4SLinus Torvalds 	BT_STATE_RESTART,
64*1da177e4SLinus Torvalds 	BT_STATE_HOSED
65*1da177e4SLinus Torvalds };
66*1da177e4SLinus Torvalds 
67*1da177e4SLinus Torvalds struct si_sm_data {
68*1da177e4SLinus Torvalds 	enum bt_states	state;
69*1da177e4SLinus Torvalds 	enum bt_states	last_state;	/* assist printing and resets */
70*1da177e4SLinus Torvalds 	unsigned char	seq;		/* BT sequence number */
71*1da177e4SLinus Torvalds 	struct si_sm_io	*io;
72*1da177e4SLinus Torvalds         unsigned char	write_data[IPMI_MAX_MSG_LENGTH];
73*1da177e4SLinus Torvalds         int		write_count;
74*1da177e4SLinus Torvalds         unsigned char	read_data[IPMI_MAX_MSG_LENGTH];
75*1da177e4SLinus Torvalds         int		read_count;
76*1da177e4SLinus Torvalds         int		truncated;
77*1da177e4SLinus Torvalds         long		timeout;
78*1da177e4SLinus Torvalds         unsigned int	error_retries;	/* end of "common" fields */
79*1da177e4SLinus Torvalds 	int		nonzero_status;	/* hung BMCs stay all 0 */
80*1da177e4SLinus Torvalds };
81*1da177e4SLinus Torvalds 
82*1da177e4SLinus Torvalds #define BT_CLR_WR_PTR	0x01	/* See IPMI 1.5 table 11.6.4 */
83*1da177e4SLinus Torvalds #define BT_CLR_RD_PTR	0x02
84*1da177e4SLinus Torvalds #define BT_H2B_ATN	0x04
85*1da177e4SLinus Torvalds #define BT_B2H_ATN	0x08
86*1da177e4SLinus Torvalds #define BT_SMS_ATN	0x10
87*1da177e4SLinus Torvalds #define BT_OEM0		0x20
88*1da177e4SLinus Torvalds #define BT_H_BUSY	0x40
89*1da177e4SLinus Torvalds #define BT_B_BUSY	0x80
90*1da177e4SLinus Torvalds 
91*1da177e4SLinus Torvalds /* Some bits are toggled on each write: write once to set it, once
92*1da177e4SLinus Torvalds    more to clear it; writing a zero does nothing.  To absolutely
93*1da177e4SLinus Torvalds    clear it, check its state and write if set.  This avoids the "get
94*1da177e4SLinus Torvalds    current then use as mask" scheme to modify one bit.  Note that the
95*1da177e4SLinus Torvalds    variable "bt" is hardcoded into these macros. */
96*1da177e4SLinus Torvalds 
97*1da177e4SLinus Torvalds #define BT_STATUS	bt->io->inputb(bt->io, 0)
98*1da177e4SLinus Torvalds #define BT_CONTROL(x)	bt->io->outputb(bt->io, 0, x)
99*1da177e4SLinus Torvalds 
100*1da177e4SLinus Torvalds #define BMC2HOST	bt->io->inputb(bt->io, 1)
101*1da177e4SLinus Torvalds #define HOST2BMC(x)	bt->io->outputb(bt->io, 1, x)
102*1da177e4SLinus Torvalds 
103*1da177e4SLinus Torvalds #define BT_INTMASK_R	bt->io->inputb(bt->io, 2)
104*1da177e4SLinus Torvalds #define BT_INTMASK_W(x)	bt->io->outputb(bt->io, 2, x)
105*1da177e4SLinus Torvalds 
106*1da177e4SLinus Torvalds /* Convenience routines for debugging.  These are not multi-open safe!
107*1da177e4SLinus Torvalds    Note the macros have hardcoded variables in them. */
108*1da177e4SLinus Torvalds 
109*1da177e4SLinus Torvalds static char *state2txt(unsigned char state)
110*1da177e4SLinus Torvalds {
111*1da177e4SLinus Torvalds 	switch (state) {
112*1da177e4SLinus Torvalds 		case BT_STATE_IDLE:		return("IDLE");
113*1da177e4SLinus Torvalds 		case BT_STATE_XACTION_START:	return("XACTION");
114*1da177e4SLinus Torvalds 		case BT_STATE_WRITE_BYTES:	return("WR_BYTES");
115*1da177e4SLinus Torvalds 		case BT_STATE_WRITE_END:	return("WR_END");
116*1da177e4SLinus Torvalds 		case BT_STATE_WRITE_CONSUME:	return("WR_CONSUME");
117*1da177e4SLinus Torvalds 		case BT_STATE_B2H_WAIT:		return("B2H_WAIT");
118*1da177e4SLinus Torvalds 		case BT_STATE_READ_END:		return("RD_END");
119*1da177e4SLinus Torvalds 		case BT_STATE_RESET1:		return("RESET1");
120*1da177e4SLinus Torvalds 		case BT_STATE_RESET2:		return("RESET2");
121*1da177e4SLinus Torvalds 		case BT_STATE_RESET3:		return("RESET3");
122*1da177e4SLinus Torvalds 		case BT_STATE_RESTART:		return("RESTART");
123*1da177e4SLinus Torvalds 		case BT_STATE_HOSED:		return("HOSED");
124*1da177e4SLinus Torvalds 	}
125*1da177e4SLinus Torvalds 	return("BAD STATE");
126*1da177e4SLinus Torvalds }
127*1da177e4SLinus Torvalds #define STATE2TXT state2txt(bt->state)
128*1da177e4SLinus Torvalds 
129*1da177e4SLinus Torvalds static char *status2txt(unsigned char status, char *buf)
130*1da177e4SLinus Torvalds {
131*1da177e4SLinus Torvalds 	strcpy(buf, "[ ");
132*1da177e4SLinus Torvalds 	if (status & BT_B_BUSY) strcat(buf, "B_BUSY ");
133*1da177e4SLinus Torvalds 	if (status & BT_H_BUSY) strcat(buf, "H_BUSY ");
134*1da177e4SLinus Torvalds 	if (status & BT_OEM0) strcat(buf, "OEM0 ");
135*1da177e4SLinus Torvalds 	if (status & BT_SMS_ATN) strcat(buf, "SMS ");
136*1da177e4SLinus Torvalds 	if (status & BT_B2H_ATN) strcat(buf, "B2H ");
137*1da177e4SLinus Torvalds 	if (status & BT_H2B_ATN) strcat(buf, "H2B ");
138*1da177e4SLinus Torvalds 	strcat(buf, "]");
139*1da177e4SLinus Torvalds 	return buf;
140*1da177e4SLinus Torvalds }
141*1da177e4SLinus Torvalds #define STATUS2TXT(buf) status2txt(status, buf)
142*1da177e4SLinus Torvalds 
143*1da177e4SLinus Torvalds /* This will be called from within this module on a hosed condition */
144*1da177e4SLinus Torvalds #define FIRST_SEQ	0
145*1da177e4SLinus Torvalds static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io)
146*1da177e4SLinus Torvalds {
147*1da177e4SLinus Torvalds 	bt->state = BT_STATE_IDLE;
148*1da177e4SLinus Torvalds 	bt->last_state = BT_STATE_IDLE;
149*1da177e4SLinus Torvalds 	bt->seq = FIRST_SEQ;
150*1da177e4SLinus Torvalds 	bt->io = io;
151*1da177e4SLinus Torvalds 	bt->write_count = 0;
152*1da177e4SLinus Torvalds 	bt->read_count = 0;
153*1da177e4SLinus Torvalds 	bt->error_retries = 0;
154*1da177e4SLinus Torvalds 	bt->nonzero_status = 0;
155*1da177e4SLinus Torvalds 	bt->truncated = 0;
156*1da177e4SLinus Torvalds 	bt->timeout = BT_NORMAL_TIMEOUT;
157*1da177e4SLinus Torvalds 	return 3; /* We claim 3 bytes of space; ought to check SPMI table */
158*1da177e4SLinus Torvalds }
159*1da177e4SLinus Torvalds 
160*1da177e4SLinus Torvalds static int bt_start_transaction(struct si_sm_data *bt,
161*1da177e4SLinus Torvalds 				unsigned char *data,
162*1da177e4SLinus Torvalds 				unsigned int size)
163*1da177e4SLinus Torvalds {
164*1da177e4SLinus Torvalds 	unsigned int i;
165*1da177e4SLinus Torvalds 
166*1da177e4SLinus Torvalds 	if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH)) return -1;
167*1da177e4SLinus Torvalds 
168*1da177e4SLinus Torvalds 	if ((bt->state != BT_STATE_IDLE) && (bt->state != BT_STATE_HOSED))
169*1da177e4SLinus Torvalds 		return -2;
170*1da177e4SLinus Torvalds 
171*1da177e4SLinus Torvalds 	if (bt_debug & BT_DEBUG_MSG) {
172*1da177e4SLinus Torvalds     		printk(KERN_WARNING "+++++++++++++++++++++++++++++++++++++\n");
173*1da177e4SLinus Torvalds 		printk(KERN_WARNING "BT: write seq=0x%02X:", bt->seq);
174*1da177e4SLinus Torvalds 		for (i = 0; i < size; i ++) printk (" %02x", data[i]);
175*1da177e4SLinus Torvalds 		printk("\n");
176*1da177e4SLinus Torvalds 	}
177*1da177e4SLinus Torvalds 	bt->write_data[0] = size + 1;	/* all data plus seq byte */
178*1da177e4SLinus Torvalds 	bt->write_data[1] = *data;	/* NetFn/LUN */
179*1da177e4SLinus Torvalds 	bt->write_data[2] = bt->seq;
180*1da177e4SLinus Torvalds 	memcpy(bt->write_data + 3, data + 1, size - 1);
181*1da177e4SLinus Torvalds 	bt->write_count = size + 2;
182*1da177e4SLinus Torvalds 
183*1da177e4SLinus Torvalds 	bt->error_retries = 0;
184*1da177e4SLinus Torvalds 	bt->nonzero_status = 0;
185*1da177e4SLinus Torvalds 	bt->read_count = 0;
186*1da177e4SLinus Torvalds 	bt->truncated = 0;
187*1da177e4SLinus Torvalds 	bt->state = BT_STATE_XACTION_START;
188*1da177e4SLinus Torvalds 	bt->last_state = BT_STATE_IDLE;
189*1da177e4SLinus Torvalds 	bt->timeout = BT_NORMAL_TIMEOUT;
190*1da177e4SLinus Torvalds 	return 0;
191*1da177e4SLinus Torvalds }
192*1da177e4SLinus Torvalds 
193*1da177e4SLinus Torvalds /* After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE
194*1da177e4SLinus Torvalds    it calls this.  Strip out the length and seq bytes. */
195*1da177e4SLinus Torvalds 
196*1da177e4SLinus Torvalds static int bt_get_result(struct si_sm_data *bt,
197*1da177e4SLinus Torvalds 			   unsigned char *data,
198*1da177e4SLinus Torvalds 			   unsigned int length)
199*1da177e4SLinus Torvalds {
200*1da177e4SLinus Torvalds 	int i, msg_len;
201*1da177e4SLinus Torvalds 
202*1da177e4SLinus Torvalds 	msg_len = bt->read_count - 2;		/* account for length & seq */
203*1da177e4SLinus Torvalds 	/* Always NetFn, Cmd, cCode */
204*1da177e4SLinus Torvalds 	if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH) {
205*1da177e4SLinus Torvalds 		printk(KERN_WARNING "BT results: bad msg_len = %d\n", msg_len);
206*1da177e4SLinus Torvalds 		data[0] = bt->write_data[1] | 0x4;	/* Kludge a response */
207*1da177e4SLinus Torvalds 		data[1] = bt->write_data[3];
208*1da177e4SLinus Torvalds 		data[2] = IPMI_ERR_UNSPECIFIED;
209*1da177e4SLinus Torvalds 		msg_len = 3;
210*1da177e4SLinus Torvalds 	} else {
211*1da177e4SLinus Torvalds 		data[0] = bt->read_data[1];
212*1da177e4SLinus Torvalds 		data[1] = bt->read_data[3];
213*1da177e4SLinus Torvalds 		if (length < msg_len) bt->truncated = 1;
214*1da177e4SLinus Torvalds 		if (bt->truncated) {	/* can be set in read_all_bytes() */
215*1da177e4SLinus Torvalds 			data[2] = IPMI_ERR_MSG_TRUNCATED;
216*1da177e4SLinus Torvalds 			msg_len = 3;
217*1da177e4SLinus Torvalds 		} else memcpy(data + 2, bt->read_data + 4, msg_len - 2);
218*1da177e4SLinus Torvalds 
219*1da177e4SLinus Torvalds 		if (bt_debug & BT_DEBUG_MSG) {
220*1da177e4SLinus Torvalds 			printk (KERN_WARNING "BT: res (raw)");
221*1da177e4SLinus Torvalds 			for (i = 0; i < msg_len; i++) printk(" %02x", data[i]);
222*1da177e4SLinus Torvalds 			printk ("\n");
223*1da177e4SLinus Torvalds 		}
224*1da177e4SLinus Torvalds 	}
225*1da177e4SLinus Torvalds 	bt->read_count = 0;	/* paranoia */
226*1da177e4SLinus Torvalds 	return msg_len;
227*1da177e4SLinus Torvalds }
228*1da177e4SLinus Torvalds 
229*1da177e4SLinus Torvalds /* This bit's functionality is optional */
230*1da177e4SLinus Torvalds #define BT_BMC_HWRST	0x80
231*1da177e4SLinus Torvalds 
232*1da177e4SLinus Torvalds static void reset_flags(struct si_sm_data *bt)
233*1da177e4SLinus Torvalds {
234*1da177e4SLinus Torvalds 	if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY);
235*1da177e4SLinus Torvalds 	if (BT_STATUS & BT_B_BUSY) BT_CONTROL(BT_B_BUSY);
236*1da177e4SLinus Torvalds 	BT_CONTROL(BT_CLR_WR_PTR);
237*1da177e4SLinus Torvalds 	BT_CONTROL(BT_SMS_ATN);
238*1da177e4SLinus Torvalds 	BT_INTMASK_W(BT_BMC_HWRST);
239*1da177e4SLinus Torvalds #ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION
240*1da177e4SLinus Torvalds 	if (BT_STATUS & BT_B2H_ATN) {
241*1da177e4SLinus Torvalds 		int i;
242*1da177e4SLinus Torvalds 		BT_CONTROL(BT_H_BUSY);
243*1da177e4SLinus Torvalds 		BT_CONTROL(BT_B2H_ATN);
244*1da177e4SLinus Torvalds 		BT_CONTROL(BT_CLR_RD_PTR);
245*1da177e4SLinus Torvalds 		for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) BMC2HOST;
246*1da177e4SLinus Torvalds 		BT_CONTROL(BT_H_BUSY);
247*1da177e4SLinus Torvalds 	}
248*1da177e4SLinus Torvalds #endif
249*1da177e4SLinus Torvalds }
250*1da177e4SLinus Torvalds 
251*1da177e4SLinus Torvalds static inline void write_all_bytes(struct si_sm_data *bt)
252*1da177e4SLinus Torvalds {
253*1da177e4SLinus Torvalds 	int i;
254*1da177e4SLinus Torvalds 
255*1da177e4SLinus Torvalds 	if (bt_debug & BT_DEBUG_MSG) {
256*1da177e4SLinus Torvalds     		printk(KERN_WARNING "BT: write %d bytes seq=0x%02X",
257*1da177e4SLinus Torvalds 			bt->write_count, bt->seq);
258*1da177e4SLinus Torvalds 		for (i = 0; i < bt->write_count; i++)
259*1da177e4SLinus Torvalds 			printk (" %02x", bt->write_data[i]);
260*1da177e4SLinus Torvalds 		printk ("\n");
261*1da177e4SLinus Torvalds 	}
262*1da177e4SLinus Torvalds 	for (i = 0; i < bt->write_count; i++) HOST2BMC(bt->write_data[i]);
263*1da177e4SLinus Torvalds }
264*1da177e4SLinus Torvalds 
265*1da177e4SLinus Torvalds static inline int read_all_bytes(struct si_sm_data *bt)
266*1da177e4SLinus Torvalds {
267*1da177e4SLinus Torvalds 	unsigned char i;
268*1da177e4SLinus Torvalds 
269*1da177e4SLinus Torvalds 	bt->read_data[0] = BMC2HOST;
270*1da177e4SLinus Torvalds 	bt->read_count = bt->read_data[0];
271*1da177e4SLinus Torvalds 	if (bt_debug & BT_DEBUG_MSG)
272*1da177e4SLinus Torvalds     		printk(KERN_WARNING "BT: read %d bytes:", bt->read_count);
273*1da177e4SLinus Torvalds 
274*1da177e4SLinus Torvalds 	/* minimum: length, NetFn, Seq, Cmd, cCode == 5 total, or 4 more
275*1da177e4SLinus Torvalds 	   following the length byte. */
276*1da177e4SLinus Torvalds 	if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) {
277*1da177e4SLinus Torvalds 		if (bt_debug & BT_DEBUG_MSG)
278*1da177e4SLinus Torvalds 			printk("bad length %d\n", bt->read_count);
279*1da177e4SLinus Torvalds 		bt->truncated = 1;
280*1da177e4SLinus Torvalds 		return 1;	/* let next XACTION START clean it up */
281*1da177e4SLinus Torvalds 	}
282*1da177e4SLinus Torvalds 	for (i = 1; i <= bt->read_count; i++) bt->read_data[i] = BMC2HOST;
283*1da177e4SLinus Torvalds 	bt->read_count++;	/* account for the length byte */
284*1da177e4SLinus Torvalds 
285*1da177e4SLinus Torvalds 	if (bt_debug & BT_DEBUG_MSG) {
286*1da177e4SLinus Torvalds 	    	for (i = 0; i < bt->read_count; i++)
287*1da177e4SLinus Torvalds 			printk (" %02x", bt->read_data[i]);
288*1da177e4SLinus Torvalds 	    	printk ("\n");
289*1da177e4SLinus Torvalds 	}
290*1da177e4SLinus Torvalds 	if (bt->seq != bt->write_data[2])	/* idiot check */
291*1da177e4SLinus Torvalds 		printk(KERN_WARNING "BT: internal error: sequence mismatch\n");
292*1da177e4SLinus Torvalds 
293*1da177e4SLinus Torvalds 	/* per the spec, the (NetFn, Seq, Cmd) tuples should match */
294*1da177e4SLinus Torvalds 	if ((bt->read_data[3] == bt->write_data[3]) &&		/* Cmd */
295*1da177e4SLinus Torvalds         	(bt->read_data[2] == bt->write_data[2]) &&	/* Sequence */
296*1da177e4SLinus Torvalds         	((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8)))
297*1da177e4SLinus Torvalds 			return 1;
298*1da177e4SLinus Torvalds 
299*1da177e4SLinus Torvalds 	if (bt_debug & BT_DEBUG_MSG) printk(KERN_WARNING "BT: bad packet: "
300*1da177e4SLinus Torvalds 		"want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n",
301*1da177e4SLinus Torvalds 		bt->write_data[1], bt->write_data[2], bt->write_data[3],
302*1da177e4SLinus Torvalds 		bt->read_data[1],  bt->read_data[2],  bt->read_data[3]);
303*1da177e4SLinus Torvalds 	return 0;
304*1da177e4SLinus Torvalds }
305*1da177e4SLinus Torvalds 
306*1da177e4SLinus Torvalds /* Modifies bt->state appropriately, need to get into the bt_event() switch */
307*1da177e4SLinus Torvalds 
308*1da177e4SLinus Torvalds static void error_recovery(struct si_sm_data *bt, char *reason)
309*1da177e4SLinus Torvalds {
310*1da177e4SLinus Torvalds 	unsigned char status;
311*1da177e4SLinus Torvalds 	char buf[40]; /* For getting status */
312*1da177e4SLinus Torvalds 
313*1da177e4SLinus Torvalds 	bt->timeout = BT_NORMAL_TIMEOUT; /* various places want to retry */
314*1da177e4SLinus Torvalds 
315*1da177e4SLinus Torvalds 	status = BT_STATUS;
316*1da177e4SLinus Torvalds 	printk(KERN_WARNING "BT: %s in %s %s ", reason, STATE2TXT,
317*1da177e4SLinus Torvalds 	       STATUS2TXT(buf));
318*1da177e4SLinus Torvalds 
319*1da177e4SLinus Torvalds 	(bt->error_retries)++;
320*1da177e4SLinus Torvalds 	if (bt->error_retries > BT_RETRY_LIMIT) {
321*1da177e4SLinus Torvalds 		printk("retry limit (%d) exceeded\n", BT_RETRY_LIMIT);
322*1da177e4SLinus Torvalds 		bt->state = BT_STATE_HOSED;
323*1da177e4SLinus Torvalds 		if (!bt->nonzero_status)
324*1da177e4SLinus Torvalds 			printk(KERN_ERR "IPMI: BT stuck, try power cycle\n");
325*1da177e4SLinus Torvalds 		else if (bt->seq == FIRST_SEQ + BT_RETRY_LIMIT) {
326*1da177e4SLinus Torvalds 			/* most likely during insmod */
327*1da177e4SLinus Torvalds 			printk(KERN_WARNING "IPMI: BT reset (takes 5 secs)\n");
328*1da177e4SLinus Torvalds         		bt->state = BT_STATE_RESET1;
329*1da177e4SLinus Torvalds 		}
330*1da177e4SLinus Torvalds 	return;
331*1da177e4SLinus Torvalds 	}
332*1da177e4SLinus Torvalds 
333*1da177e4SLinus Torvalds 	/* Sometimes the BMC queues get in an "off-by-one" state...*/
334*1da177e4SLinus Torvalds 	if ((bt->state == BT_STATE_B2H_WAIT) && (status & BT_B2H_ATN)) {
335*1da177e4SLinus Torvalds     		printk("retry B2H_WAIT\n");
336*1da177e4SLinus Torvalds 		return;
337*1da177e4SLinus Torvalds 	}
338*1da177e4SLinus Torvalds 
339*1da177e4SLinus Torvalds 	printk("restart command\n");
340*1da177e4SLinus Torvalds 	bt->state = BT_STATE_RESTART;
341*1da177e4SLinus Torvalds }
342*1da177e4SLinus Torvalds 
343*1da177e4SLinus Torvalds /* Check the status and (possibly) advance the BT state machine.  The
344*1da177e4SLinus Torvalds    default return is SI_SM_CALL_WITH_DELAY. */
345*1da177e4SLinus Torvalds 
346*1da177e4SLinus Torvalds static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
347*1da177e4SLinus Torvalds {
348*1da177e4SLinus Torvalds 	unsigned char status;
349*1da177e4SLinus Torvalds 	char buf[40]; /* For getting status */
350*1da177e4SLinus Torvalds 	int i;
351*1da177e4SLinus Torvalds 
352*1da177e4SLinus Torvalds 	status = BT_STATUS;
353*1da177e4SLinus Torvalds 	bt->nonzero_status |= status;
354*1da177e4SLinus Torvalds 
355*1da177e4SLinus Torvalds 	if ((bt_debug & BT_DEBUG_STATES) && (bt->state != bt->last_state))
356*1da177e4SLinus Torvalds 		printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n",
357*1da177e4SLinus Torvalds 			STATE2TXT,
358*1da177e4SLinus Torvalds 			STATUS2TXT(buf),
359*1da177e4SLinus Torvalds 			bt->timeout,
360*1da177e4SLinus Torvalds 			time);
361*1da177e4SLinus Torvalds 	bt->last_state = bt->state;
362*1da177e4SLinus Torvalds 
363*1da177e4SLinus Torvalds 	if (bt->state == BT_STATE_HOSED) return SI_SM_HOSED;
364*1da177e4SLinus Torvalds 
365*1da177e4SLinus Torvalds 	if (bt->state != BT_STATE_IDLE) {	/* do timeout test */
366*1da177e4SLinus Torvalds 
367*1da177e4SLinus Torvalds 		/* Certain states, on error conditions, can lock up a CPU
368*1da177e4SLinus Torvalds 		   because they are effectively in an infinite loop with
369*1da177e4SLinus Torvalds 		   CALL_WITHOUT_DELAY (right back here with time == 0).
370*1da177e4SLinus Torvalds 		   Prevent infinite lockup by ALWAYS decrementing timeout. */
371*1da177e4SLinus Torvalds 
372*1da177e4SLinus Torvalds     	/* FIXME: bt_event is sometimes called with time > BT_NORMAL_TIMEOUT
373*1da177e4SLinus Torvalds               (noticed in ipmi_smic_sm.c January 2004) */
374*1da177e4SLinus Torvalds 
375*1da177e4SLinus Torvalds 		if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) time = 100;
376*1da177e4SLinus Torvalds 		bt->timeout -= time;
377*1da177e4SLinus Torvalds 		if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) {
378*1da177e4SLinus Torvalds 			error_recovery(bt, "timed out");
379*1da177e4SLinus Torvalds 			return SI_SM_CALL_WITHOUT_DELAY;
380*1da177e4SLinus Torvalds 		}
381*1da177e4SLinus Torvalds 	}
382*1da177e4SLinus Torvalds 
383*1da177e4SLinus Torvalds 	switch (bt->state) {
384*1da177e4SLinus Torvalds 
385*1da177e4SLinus Torvalds     	case BT_STATE_IDLE:	/* check for asynchronous messages */
386*1da177e4SLinus Torvalds 		if (status & BT_SMS_ATN) {
387*1da177e4SLinus Torvalds 			BT_CONTROL(BT_SMS_ATN);	/* clear it */
388*1da177e4SLinus Torvalds 			return SI_SM_ATTN;
389*1da177e4SLinus Torvalds 		}
390*1da177e4SLinus Torvalds 		return SI_SM_IDLE;
391*1da177e4SLinus Torvalds 
392*1da177e4SLinus Torvalds 	case BT_STATE_XACTION_START:
393*1da177e4SLinus Torvalds 		if (status & BT_H_BUSY) {
394*1da177e4SLinus Torvalds 			BT_CONTROL(BT_H_BUSY);
395*1da177e4SLinus Torvalds 			break;
396*1da177e4SLinus Torvalds 		}
397*1da177e4SLinus Torvalds     		if (status & BT_B2H_ATN) break;
398*1da177e4SLinus Torvalds 		bt->state = BT_STATE_WRITE_BYTES;
399*1da177e4SLinus Torvalds 		return SI_SM_CALL_WITHOUT_DELAY;	/* for logging */
400*1da177e4SLinus Torvalds 
401*1da177e4SLinus Torvalds 	case BT_STATE_WRITE_BYTES:
402*1da177e4SLinus Torvalds 		if (status & (BT_B_BUSY | BT_H2B_ATN)) break;
403*1da177e4SLinus Torvalds 		BT_CONTROL(BT_CLR_WR_PTR);
404*1da177e4SLinus Torvalds 		write_all_bytes(bt);
405*1da177e4SLinus Torvalds 		BT_CONTROL(BT_H2B_ATN);	/* clears too fast to catch? */
406*1da177e4SLinus Torvalds 		bt->state = BT_STATE_WRITE_CONSUME;
407*1da177e4SLinus Torvalds 		return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */
408*1da177e4SLinus Torvalds 
409*1da177e4SLinus Torvalds 	case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */
410*1da177e4SLinus Torvalds         	if (status & (BT_H2B_ATN | BT_B_BUSY)) break;
411*1da177e4SLinus Torvalds 		bt->state = BT_STATE_B2H_WAIT;
412*1da177e4SLinus Torvalds 		/* fall through with status */
413*1da177e4SLinus Torvalds 
414*1da177e4SLinus Torvalds 	/* Stay in BT_STATE_B2H_WAIT until a packet matches.  However, spinning
415*1da177e4SLinus Torvalds 	   hard here, constantly reading status, seems to hold off the
416*1da177e4SLinus Torvalds 	   generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */
417*1da177e4SLinus Torvalds 
418*1da177e4SLinus Torvalds 	case BT_STATE_B2H_WAIT:
419*1da177e4SLinus Torvalds     		if (!(status & BT_B2H_ATN)) break;
420*1da177e4SLinus Torvalds 
421*1da177e4SLinus Torvalds 		/* Assume ordered, uncached writes: no need to wait */
422*1da177e4SLinus Torvalds 		if (!(status & BT_H_BUSY)) BT_CONTROL(BT_H_BUSY); /* set */
423*1da177e4SLinus Torvalds 		BT_CONTROL(BT_B2H_ATN);		/* clear it, ACK to the BMC */
424*1da177e4SLinus Torvalds 		BT_CONTROL(BT_CLR_RD_PTR);	/* reset the queue */
425*1da177e4SLinus Torvalds 		i = read_all_bytes(bt);
426*1da177e4SLinus Torvalds 		BT_CONTROL(BT_H_BUSY);		/* clear */
427*1da177e4SLinus Torvalds 		if (!i) break;			/* Try this state again */
428*1da177e4SLinus Torvalds 		bt->state = BT_STATE_READ_END;
429*1da177e4SLinus Torvalds 		return SI_SM_CALL_WITHOUT_DELAY;	/* for logging */
430*1da177e4SLinus Torvalds 
431*1da177e4SLinus Torvalds     	case BT_STATE_READ_END:
432*1da177e4SLinus Torvalds 
433*1da177e4SLinus Torvalds 		/* I could wait on BT_H_BUSY to go clear for a truly clean
434*1da177e4SLinus Torvalds 		   exit.  However, this is already done in XACTION_START
435*1da177e4SLinus Torvalds 		   and the (possible) extra loop/status/possible wait affects
436*1da177e4SLinus Torvalds 		   performance.  So, as long as it works, just ignore H_BUSY */
437*1da177e4SLinus Torvalds 
438*1da177e4SLinus Torvalds #ifdef MAKE_THIS_TRUE_IF_NECESSARY
439*1da177e4SLinus Torvalds 
440*1da177e4SLinus Torvalds 		if (status & BT_H_BUSY) break;
441*1da177e4SLinus Torvalds #endif
442*1da177e4SLinus Torvalds 		bt->seq++;
443*1da177e4SLinus Torvalds 		bt->state = BT_STATE_IDLE;
444*1da177e4SLinus Torvalds 		return SI_SM_TRANSACTION_COMPLETE;
445*1da177e4SLinus Torvalds 
446*1da177e4SLinus Torvalds 	case BT_STATE_RESET1:
447*1da177e4SLinus Torvalds     		reset_flags(bt);
448*1da177e4SLinus Torvalds     		bt->timeout = BT_RESET_DELAY;
449*1da177e4SLinus Torvalds 		bt->state = BT_STATE_RESET2;
450*1da177e4SLinus Torvalds 		break;
451*1da177e4SLinus Torvalds 
452*1da177e4SLinus Torvalds 	case BT_STATE_RESET2:		/* Send a soft reset */
453*1da177e4SLinus Torvalds 		BT_CONTROL(BT_CLR_WR_PTR);
454*1da177e4SLinus Torvalds 		HOST2BMC(3);		/* number of bytes following */
455*1da177e4SLinus Torvalds 		HOST2BMC(0x18);		/* NetFn/LUN == Application, LUN 0 */
456*1da177e4SLinus Torvalds 		HOST2BMC(42);		/* Sequence number */
457*1da177e4SLinus Torvalds 		HOST2BMC(3);		/* Cmd == Soft reset */
458*1da177e4SLinus Torvalds 		BT_CONTROL(BT_H2B_ATN);
459*1da177e4SLinus Torvalds 		bt->state = BT_STATE_RESET3;
460*1da177e4SLinus Torvalds 		break;
461*1da177e4SLinus Torvalds 
462*1da177e4SLinus Torvalds 	case BT_STATE_RESET3:
463*1da177e4SLinus Torvalds 		if (bt->timeout > 0) return SI_SM_CALL_WITH_DELAY;
464*1da177e4SLinus Torvalds 		bt->state = BT_STATE_RESTART;	/* printk in debug modes */
465*1da177e4SLinus Torvalds 		break;
466*1da177e4SLinus Torvalds 
467*1da177e4SLinus Torvalds 	case BT_STATE_RESTART:		/* don't reset retries! */
468*1da177e4SLinus Torvalds 		bt->write_data[2] = ++bt->seq;
469*1da177e4SLinus Torvalds 		bt->read_count = 0;
470*1da177e4SLinus Torvalds 		bt->nonzero_status = 0;
471*1da177e4SLinus Torvalds 		bt->timeout = BT_NORMAL_TIMEOUT;
472*1da177e4SLinus Torvalds 		bt->state = BT_STATE_XACTION_START;
473*1da177e4SLinus Torvalds 		break;
474*1da177e4SLinus Torvalds 
475*1da177e4SLinus Torvalds 	default:	/* HOSED is supposed to be caught much earlier */
476*1da177e4SLinus Torvalds 		error_recovery(bt, "internal logic error");
477*1da177e4SLinus Torvalds 		break;
478*1da177e4SLinus Torvalds   	}
479*1da177e4SLinus Torvalds   	return SI_SM_CALL_WITH_DELAY;
480*1da177e4SLinus Torvalds }
481*1da177e4SLinus Torvalds 
482*1da177e4SLinus Torvalds static int bt_detect(struct si_sm_data *bt)
483*1da177e4SLinus Torvalds {
484*1da177e4SLinus Torvalds 	/* It's impossible for the BT status and interrupt registers to be
485*1da177e4SLinus Torvalds 	   all 1's, (assuming a properly functioning, self-initialized BMC)
486*1da177e4SLinus Torvalds 	   but that's what you get from reading a bogus address, so we
487*1da177e4SLinus Torvalds 	   test that first.  The calling routine uses negative logic. */
488*1da177e4SLinus Torvalds 
489*1da177e4SLinus Torvalds 	if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) return 1;
490*1da177e4SLinus Torvalds 	reset_flags(bt);
491*1da177e4SLinus Torvalds 	return 0;
492*1da177e4SLinus Torvalds }
493*1da177e4SLinus Torvalds 
494*1da177e4SLinus Torvalds static void bt_cleanup(struct si_sm_data *bt)
495*1da177e4SLinus Torvalds {
496*1da177e4SLinus Torvalds }
497*1da177e4SLinus Torvalds 
498*1da177e4SLinus Torvalds static int bt_size(void)
499*1da177e4SLinus Torvalds {
500*1da177e4SLinus Torvalds 	return sizeof(struct si_sm_data);
501*1da177e4SLinus Torvalds }
502*1da177e4SLinus Torvalds 
503*1da177e4SLinus Torvalds struct si_sm_handlers bt_smi_handlers =
504*1da177e4SLinus Torvalds {
505*1da177e4SLinus Torvalds 	.version           = IPMI_BT_VERSION,
506*1da177e4SLinus Torvalds 	.init_data         = bt_init_data,
507*1da177e4SLinus Torvalds 	.start_transaction = bt_start_transaction,
508*1da177e4SLinus Torvalds 	.get_result        = bt_get_result,
509*1da177e4SLinus Torvalds 	.event             = bt_event,
510*1da177e4SLinus Torvalds 	.detect            = bt_detect,
511*1da177e4SLinus Torvalds 	.cleanup           = bt_cleanup,
512*1da177e4SLinus Torvalds 	.size              = bt_size,
513*1da177e4SLinus Torvalds };
514