xref: /linux/drivers/char/ipmi/ipmi_bt_sm.c (revision c86ba91be75702c013bbf7379542920b6920e98f)
1243ac210SCorey Minyard // SPDX-License-Identifier: GPL-2.0+
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  ipmi_bt_sm.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  The state machine for an Open IPMI BT sub-driver under ipmi_si.c, part
6631dd1a8SJustin P. Mattock  *  of the driver architecture at http://sourceforge.net/projects/openipmi
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  *  Author:	Rocky Craig <first.last@hp.com>
9243ac210SCorey Minyard  */
101da177e4SLinus Torvalds 
111da177e4SLinus Torvalds #include <linux/kernel.h> /* For printk. */
121da177e4SLinus Torvalds #include <linux/string.h>
13c4edff1cSCorey Minyard #include <linux/module.h>
14c4edff1cSCorey Minyard #include <linux/moduleparam.h>
151da177e4SLinus Torvalds #include <linux/ipmi_msgdefs.h>		/* for completion codes */
161da177e4SLinus Torvalds #include "ipmi_si_sm.h"
171da177e4SLinus Torvalds 
184d7cbac7SCorey Minyard #define BT_DEBUG_OFF	0	/* Used in production */
194d7cbac7SCorey Minyard #define BT_DEBUG_ENABLE	1	/* Generic messages */
204d7cbac7SCorey Minyard #define BT_DEBUG_MSG	2	/* Prints all request/response buffers */
214d7cbac7SCorey Minyard #define BT_DEBUG_STATES	4	/* Verbose look at state changes */
22c305e3d3SCorey Minyard /*
23c305e3d3SCorey Minyard  * BT_DEBUG_OFF must be zero to correspond to the default uninitialized
24c305e3d3SCorey Minyard  * value
25c305e3d3SCorey Minyard  */
261da177e4SLinus Torvalds 
270c8204b3SRandy Dunlap static int bt_debug; /* 0 == BT_DEBUG_OFF */
284d7cbac7SCorey Minyard 
29c4edff1cSCorey Minyard module_param(bt_debug, int, 0644);
30c4edff1cSCorey Minyard MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states");
311da177e4SLinus Torvalds 
32c305e3d3SCorey Minyard /*
33c305e3d3SCorey Minyard  * Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds,
34c305e3d3SCorey Minyard  * and 64 byte buffers.  However, one HP implementation wants 255 bytes of
35c305e3d3SCorey Minyard  * buffer (with a documented message of 160 bytes) so go for the max.
36c305e3d3SCorey Minyard  * Since the Open IPMI architecture is single-message oriented at this
37c305e3d3SCorey Minyard  * stage, the queue depth of BT is of no concern.
38c305e3d3SCorey Minyard  */
391da177e4SLinus Torvalds 
404d7cbac7SCorey Minyard #define BT_NORMAL_TIMEOUT	5	/* seconds */
414d7cbac7SCorey Minyard #define BT_NORMAL_RETRY_LIMIT	2
424d7cbac7SCorey Minyard #define BT_RESET_DELAY		6	/* seconds after warm reset */
434d7cbac7SCorey Minyard 
44c305e3d3SCorey Minyard /*
45c305e3d3SCorey Minyard  * States are written in chronological order and usually cover
46c305e3d3SCorey Minyard  * multiple rows of the state table discussion in the IPMI spec.
47c305e3d3SCorey Minyard  */
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds enum bt_states {
504d7cbac7SCorey Minyard 	BT_STATE_IDLE = 0,	/* Order is critical in this list */
511da177e4SLinus Torvalds 	BT_STATE_XACTION_START,
521da177e4SLinus Torvalds 	BT_STATE_WRITE_BYTES,
531da177e4SLinus Torvalds 	BT_STATE_WRITE_CONSUME,
544d7cbac7SCorey Minyard 	BT_STATE_READ_WAIT,
554d7cbac7SCorey Minyard 	BT_STATE_CLEAR_B2H,
564d7cbac7SCorey Minyard 	BT_STATE_READ_BYTES,
571da177e4SLinus Torvalds 	BT_STATE_RESET1,	/* These must come last */
581da177e4SLinus Torvalds 	BT_STATE_RESET2,
591da177e4SLinus Torvalds 	BT_STATE_RESET3,
601da177e4SLinus Torvalds 	BT_STATE_RESTART,
614d7cbac7SCorey Minyard 	BT_STATE_PRINTME,
624d7cbac7SCorey Minyard 	BT_STATE_LONG_BUSY	/* BT doesn't get hosed :-) */
631da177e4SLinus Torvalds };
641da177e4SLinus Torvalds 
65c305e3d3SCorey Minyard /*
66c305e3d3SCorey Minyard  * Macros seen at the end of state "case" blocks.  They help with legibility
67c305e3d3SCorey Minyard  * and debugging.
68c305e3d3SCorey Minyard  */
694d7cbac7SCorey Minyard 
704d7cbac7SCorey Minyard #define BT_STATE_CHANGE(X, Y) { bt->state = X; return Y; }
714d7cbac7SCorey Minyard 
724d7cbac7SCorey Minyard #define BT_SI_SM_RETURN(Y)   { last_printed = BT_STATE_PRINTME; return Y; }
734d7cbac7SCorey Minyard 
741da177e4SLinus Torvalds struct si_sm_data {
751da177e4SLinus Torvalds 	enum bt_states	state;
761da177e4SLinus Torvalds 	unsigned char	seq;		/* BT sequence number */
771da177e4SLinus Torvalds 	struct si_sm_io	*io;
78a5f2b3d6SChen Gang 	unsigned char	write_data[IPMI_MAX_MSG_LENGTH + 2]; /* +2 for memcpy */
791da177e4SLinus Torvalds 	int		write_count;
80a5f2b3d6SChen Gang 	unsigned char	read_data[IPMI_MAX_MSG_LENGTH + 2]; /* +2 for memcpy */
811da177e4SLinus Torvalds 	int		read_count;
821da177e4SLinus Torvalds 	int		truncated;
834d7cbac7SCorey Minyard 	long		timeout;	/* microseconds countdown */
844d7cbac7SCorey Minyard 	int		error_retries;	/* end of "common" fields */
851da177e4SLinus Torvalds 	int		nonzero_status;	/* hung BMCs stay all 0 */
864d7cbac7SCorey Minyard 	enum bt_states	complete;	/* to divert the state machine */
874d7cbac7SCorey Minyard 	long		BT_CAP_req2rsp;
884d7cbac7SCorey Minyard 	int		BT_CAP_retries;	/* Recommended retries */
891da177e4SLinus Torvalds };
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds #define BT_CLR_WR_PTR	0x01	/* See IPMI 1.5 table 11.6.4 */
921da177e4SLinus Torvalds #define BT_CLR_RD_PTR	0x02
931da177e4SLinus Torvalds #define BT_H2B_ATN	0x04
941da177e4SLinus Torvalds #define BT_B2H_ATN	0x08
951da177e4SLinus Torvalds #define BT_SMS_ATN	0x10
961da177e4SLinus Torvalds #define BT_OEM0		0x20
971da177e4SLinus Torvalds #define BT_H_BUSY	0x40
981da177e4SLinus Torvalds #define BT_B_BUSY	0x80
991da177e4SLinus Torvalds 
100c305e3d3SCorey Minyard /*
101c305e3d3SCorey Minyard  * Some bits are toggled on each write: write once to set it, once
102c305e3d3SCorey Minyard  * more to clear it; writing a zero does nothing.  To absolutely
103c305e3d3SCorey Minyard  * clear it, check its state and write if set.  This avoids the "get
104c305e3d3SCorey Minyard  * current then use as mask" scheme to modify one bit.  Note that the
105c305e3d3SCorey Minyard  * variable "bt" is hardcoded into these macros.
106c305e3d3SCorey Minyard  */
1071da177e4SLinus Torvalds 
1081da177e4SLinus Torvalds #define BT_STATUS	bt->io->inputb(bt->io, 0)
1091da177e4SLinus Torvalds #define BT_CONTROL(x)	bt->io->outputb(bt->io, 0, x)
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds #define BMC2HOST	bt->io->inputb(bt->io, 1)
1121da177e4SLinus Torvalds #define HOST2BMC(x)	bt->io->outputb(bt->io, 1, x)
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds #define BT_INTMASK_R	bt->io->inputb(bt->io, 2)
1151da177e4SLinus Torvalds #define BT_INTMASK_W(x)	bt->io->outputb(bt->io, 2, x)
1161da177e4SLinus Torvalds 
117c305e3d3SCorey Minyard /*
118c305e3d3SCorey Minyard  * Convenience routines for debugging.  These are not multi-open safe!
119c305e3d3SCorey Minyard  * Note the macros have hardcoded variables in them.
120c305e3d3SCorey Minyard  */
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds static char *state2txt(unsigned char state)
1231da177e4SLinus Torvalds {
1241da177e4SLinus Torvalds 	switch (state) {
1251da177e4SLinus Torvalds 	case BT_STATE_IDLE:		return("IDLE");
1261da177e4SLinus Torvalds 	case BT_STATE_XACTION_START:	return("XACTION");
1271da177e4SLinus Torvalds 	case BT_STATE_WRITE_BYTES:	return("WR_BYTES");
1281da177e4SLinus Torvalds 	case BT_STATE_WRITE_CONSUME:	return("WR_CONSUME");
1294d7cbac7SCorey Minyard 	case BT_STATE_READ_WAIT:	return("RD_WAIT");
1304d7cbac7SCorey Minyard 	case BT_STATE_CLEAR_B2H:	return("CLEAR_B2H");
1314d7cbac7SCorey Minyard 	case BT_STATE_READ_BYTES:	return("RD_BYTES");
1321da177e4SLinus Torvalds 	case BT_STATE_RESET1:		return("RESET1");
1331da177e4SLinus Torvalds 	case BT_STATE_RESET2:		return("RESET2");
1341da177e4SLinus Torvalds 	case BT_STATE_RESET3:		return("RESET3");
1351da177e4SLinus Torvalds 	case BT_STATE_RESTART:		return("RESTART");
1364d7cbac7SCorey Minyard 	case BT_STATE_LONG_BUSY:	return("LONG_BUSY");
1371da177e4SLinus Torvalds 	}
1381da177e4SLinus Torvalds 	return("BAD STATE");
1391da177e4SLinus Torvalds }
1401da177e4SLinus Torvalds #define STATE2TXT state2txt(bt->state)
1411da177e4SLinus Torvalds 
1424d7cbac7SCorey Minyard static char *status2txt(unsigned char status)
1431da177e4SLinus Torvalds {
1444d7cbac7SCorey Minyard 	/*
1454d7cbac7SCorey Minyard 	 * This cannot be called by two threads at the same time and
1464d7cbac7SCorey Minyard 	 * the buffer is always consumed immediately, so the static is
1474d7cbac7SCorey Minyard 	 * safe to use.
1484d7cbac7SCorey Minyard 	 */
1494d7cbac7SCorey Minyard 	static char buf[40];
1504d7cbac7SCorey Minyard 
1511da177e4SLinus Torvalds 	strcpy(buf, "[ ");
1524d7cbac7SCorey Minyard 	if (status & BT_B_BUSY)
1534d7cbac7SCorey Minyard 		strcat(buf, "B_BUSY ");
1544d7cbac7SCorey Minyard 	if (status & BT_H_BUSY)
1554d7cbac7SCorey Minyard 		strcat(buf, "H_BUSY ");
1564d7cbac7SCorey Minyard 	if (status & BT_OEM0)
1574d7cbac7SCorey Minyard 		strcat(buf, "OEM0 ");
1584d7cbac7SCorey Minyard 	if (status & BT_SMS_ATN)
1594d7cbac7SCorey Minyard 		strcat(buf, "SMS ");
1604d7cbac7SCorey Minyard 	if (status & BT_B2H_ATN)
1614d7cbac7SCorey Minyard 		strcat(buf, "B2H ");
1624d7cbac7SCorey Minyard 	if (status & BT_H2B_ATN)
1634d7cbac7SCorey Minyard 		strcat(buf, "H2B ");
1641da177e4SLinus Torvalds 	strcat(buf, "]");
1651da177e4SLinus Torvalds 	return buf;
1661da177e4SLinus Torvalds }
1674d7cbac7SCorey Minyard #define STATUS2TXT status2txt(status)
1681da177e4SLinus Torvalds 
1694d7cbac7SCorey Minyard /* called externally at insmod time, and internally on cleanup */
1704d7cbac7SCorey Minyard 
1711da177e4SLinus Torvalds static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io)
1721da177e4SLinus Torvalds {
1734d7cbac7SCorey Minyard 	memset(bt, 0, sizeof(struct si_sm_data));
174c305e3d3SCorey Minyard 	if (bt->io != io) {
175c305e3d3SCorey Minyard 		/* external: one-time only things */
1761da177e4SLinus Torvalds 		bt->io = io;
1774d7cbac7SCorey Minyard 		bt->seq = 0;
1784d7cbac7SCorey Minyard 	}
1794d7cbac7SCorey Minyard 	bt->state = BT_STATE_IDLE;	/* start here */
1804d7cbac7SCorey Minyard 	bt->complete = BT_STATE_IDLE;	/* end here */
181ccb3368cSXie XiuQi 	bt->BT_CAP_req2rsp = BT_NORMAL_TIMEOUT * USEC_PER_SEC;
1824d7cbac7SCorey Minyard 	bt->BT_CAP_retries = BT_NORMAL_RETRY_LIMIT;
1831da177e4SLinus Torvalds 	return 3; /* We claim 3 bytes of space; ought to check SPMI table */
1841da177e4SLinus Torvalds }
1851da177e4SLinus Torvalds 
1864d7cbac7SCorey Minyard /* Jam a completion code (probably an error) into a response */
1874d7cbac7SCorey Minyard 
1884d7cbac7SCorey Minyard static void force_result(struct si_sm_data *bt, unsigned char completion_code)
1894d7cbac7SCorey Minyard {
1904d7cbac7SCorey Minyard 	bt->read_data[0] = 4;				/* # following bytes */
1914d7cbac7SCorey Minyard 	bt->read_data[1] = bt->write_data[1] | 4;	/* Odd NetFn/LUN */
1924d7cbac7SCorey Minyard 	bt->read_data[2] = bt->write_data[2];		/* seq (ignored) */
1934d7cbac7SCorey Minyard 	bt->read_data[3] = bt->write_data[3];		/* Command */
1944d7cbac7SCorey Minyard 	bt->read_data[4] = completion_code;
1954d7cbac7SCorey Minyard 	bt->read_count = 5;
1964d7cbac7SCorey Minyard }
1974d7cbac7SCorey Minyard 
1984d7cbac7SCorey Minyard /* The upper state machine starts here */
1994d7cbac7SCorey Minyard 
2001da177e4SLinus Torvalds static int bt_start_transaction(struct si_sm_data *bt,
2011da177e4SLinus Torvalds 				unsigned char *data,
2021da177e4SLinus Torvalds 				unsigned int size)
2031da177e4SLinus Torvalds {
2041da177e4SLinus Torvalds 	unsigned int i;
2051da177e4SLinus Torvalds 
2064d7cbac7SCorey Minyard 	if (size < 2)
2074d7cbac7SCorey Minyard 		return IPMI_REQ_LEN_INVALID_ERR;
2084d7cbac7SCorey Minyard 	if (size > IPMI_MAX_MSG_LENGTH)
2094d7cbac7SCorey Minyard 		return IPMI_REQ_LEN_EXCEEDED_ERR;
2101da177e4SLinus Torvalds 
2114d7cbac7SCorey Minyard 	if (bt->state == BT_STATE_LONG_BUSY)
2124d7cbac7SCorey Minyard 		return IPMI_NODE_BUSY_ERR;
2134d7cbac7SCorey Minyard 
2144d7cbac7SCorey Minyard 	if (bt->state != BT_STATE_IDLE)
2154d7cbac7SCorey Minyard 		return IPMI_NOT_IN_MY_STATE_ERR;
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds 	if (bt_debug & BT_DEBUG_MSG) {
2184d7cbac7SCorey Minyard 		printk(KERN_WARNING "BT: +++++++++++++++++ New command\n");
2194d7cbac7SCorey Minyard 		printk(KERN_WARNING "BT: NetFn/LUN CMD [%d data]:", size - 2);
220e8b33617SCorey Minyard 		for (i = 0; i < size; i ++)
221e8b33617SCorey Minyard 			printk(" %02x", data[i]);
2221da177e4SLinus Torvalds 		printk("\n");
2231da177e4SLinus Torvalds 	}
2241da177e4SLinus Torvalds 	bt->write_data[0] = size + 1;	/* all data plus seq byte */
2251da177e4SLinus Torvalds 	bt->write_data[1] = *data;	/* NetFn/LUN */
2264d7cbac7SCorey Minyard 	bt->write_data[2] = bt->seq++;
2271da177e4SLinus Torvalds 	memcpy(bt->write_data + 3, data + 1, size - 1);
2281da177e4SLinus Torvalds 	bt->write_count = size + 2;
2291da177e4SLinus Torvalds 	bt->error_retries = 0;
2301da177e4SLinus Torvalds 	bt->nonzero_status = 0;
2311da177e4SLinus Torvalds 	bt->truncated = 0;
2321da177e4SLinus Torvalds 	bt->state = BT_STATE_XACTION_START;
2334d7cbac7SCorey Minyard 	bt->timeout = bt->BT_CAP_req2rsp;
2344d7cbac7SCorey Minyard 	force_result(bt, IPMI_ERR_UNSPECIFIED);
2351da177e4SLinus Torvalds 	return 0;
2361da177e4SLinus Torvalds }
2371da177e4SLinus Torvalds 
238c305e3d3SCorey Minyard /*
239c305e3d3SCorey Minyard  * After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE
240c305e3d3SCorey Minyard  * it calls this.  Strip out the length and seq bytes.
241c305e3d3SCorey Minyard  */
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds static int bt_get_result(struct si_sm_data *bt,
2441da177e4SLinus Torvalds 			 unsigned char *data,
2451da177e4SLinus Torvalds 			 unsigned int length)
2461da177e4SLinus Torvalds {
2471da177e4SLinus Torvalds 	int i, msg_len;
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds 	msg_len = bt->read_count - 2;		/* account for length & seq */
2501da177e4SLinus Torvalds 	if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH) {
2514d7cbac7SCorey Minyard 		force_result(bt, IPMI_ERR_UNSPECIFIED);
2521da177e4SLinus Torvalds 		msg_len = 3;
2534d7cbac7SCorey Minyard 	}
2541da177e4SLinus Torvalds 	data[0] = bt->read_data[1];
2551da177e4SLinus Torvalds 	data[1] = bt->read_data[3];
2564d7cbac7SCorey Minyard 	if (length < msg_len || bt->truncated) {
2571da177e4SLinus Torvalds 		data[2] = IPMI_ERR_MSG_TRUNCATED;
2581da177e4SLinus Torvalds 		msg_len = 3;
259e8b33617SCorey Minyard 	} else
260e8b33617SCorey Minyard 		memcpy(data + 2, bt->read_data + 4, msg_len - 2);
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 	if (bt_debug & BT_DEBUG_MSG) {
2634d7cbac7SCorey Minyard 		printk(KERN_WARNING "BT: result %d bytes:", msg_len);
264e8b33617SCorey Minyard 		for (i = 0; i < msg_len; i++)
265e8b33617SCorey Minyard 			printk(" %02x", data[i]);
2661da177e4SLinus Torvalds 		printk("\n");
2671da177e4SLinus Torvalds 	}
2681da177e4SLinus Torvalds 	return msg_len;
2691da177e4SLinus Torvalds }
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds /* This bit's functionality is optional */
2721da177e4SLinus Torvalds #define BT_BMC_HWRST	0x80
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds static void reset_flags(struct si_sm_data *bt)
2751da177e4SLinus Torvalds {
2764d7cbac7SCorey Minyard 	if (bt_debug)
2774d7cbac7SCorey Minyard 		printk(KERN_WARNING "IPMI BT: flag reset %s\n",
2784d7cbac7SCorey Minyard 					status2txt(BT_STATUS));
279e8b33617SCorey Minyard 	if (BT_STATUS & BT_H_BUSY)
2804d7cbac7SCorey Minyard 		BT_CONTROL(BT_H_BUSY);	/* force clear */
2814d7cbac7SCorey Minyard 	BT_CONTROL(BT_CLR_WR_PTR);	/* always reset */
2824d7cbac7SCorey Minyard 	BT_CONTROL(BT_SMS_ATN);		/* always clear */
2834d7cbac7SCorey Minyard 	BT_INTMASK_W(BT_BMC_HWRST);
2841da177e4SLinus Torvalds }
2854d7cbac7SCorey Minyard 
286c305e3d3SCorey Minyard /*
287c305e3d3SCorey Minyard  * Get rid of an unwanted/stale response.  This should only be needed for
288c305e3d3SCorey Minyard  * BMCs that support multiple outstanding requests.
289c305e3d3SCorey Minyard  */
2904d7cbac7SCorey Minyard 
2914d7cbac7SCorey Minyard static void drain_BMC2HOST(struct si_sm_data *bt)
2924d7cbac7SCorey Minyard {
2934d7cbac7SCorey Minyard 	int i, size;
2944d7cbac7SCorey Minyard 
2954d7cbac7SCorey Minyard 	if (!(BT_STATUS & BT_B2H_ATN)) 	/* Not signalling a response */
2964d7cbac7SCorey Minyard 		return;
2974d7cbac7SCorey Minyard 
2984d7cbac7SCorey Minyard 	BT_CONTROL(BT_H_BUSY);		/* now set */
2994d7cbac7SCorey Minyard 	BT_CONTROL(BT_B2H_ATN);		/* always clear */
3004d7cbac7SCorey Minyard 	BT_STATUS;			/* pause */
3014d7cbac7SCorey Minyard 	BT_CONTROL(BT_B2H_ATN);		/* some BMCs are stubborn */
3024d7cbac7SCorey Minyard 	BT_CONTROL(BT_CLR_RD_PTR);	/* always reset */
3034d7cbac7SCorey Minyard 	if (bt_debug)
3044d7cbac7SCorey Minyard 		printk(KERN_WARNING "IPMI BT: stale response %s; ",
3054d7cbac7SCorey Minyard 			status2txt(BT_STATUS));
3064d7cbac7SCorey Minyard 	size = BMC2HOST;
3074d7cbac7SCorey Minyard 	for (i = 0; i < size ; i++)
3084d7cbac7SCorey Minyard 		BMC2HOST;
3094d7cbac7SCorey Minyard 	BT_CONTROL(BT_H_BUSY);		/* now clear */
3104d7cbac7SCorey Minyard 	if (bt_debug)
3114d7cbac7SCorey Minyard 		printk("drained %d bytes\n", size + 1);
3121da177e4SLinus Torvalds }
3131da177e4SLinus Torvalds 
3141da177e4SLinus Torvalds static inline void write_all_bytes(struct si_sm_data *bt)
3151da177e4SLinus Torvalds {
3161da177e4SLinus Torvalds 	int i;
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 	if (bt_debug & BT_DEBUG_MSG) {
3191da177e4SLinus Torvalds 		printk(KERN_WARNING "BT: write %d bytes seq=0x%02X",
3201da177e4SLinus Torvalds 			bt->write_count, bt->seq);
3211da177e4SLinus Torvalds 		for (i = 0; i < bt->write_count; i++)
3221da177e4SLinus Torvalds 			printk(" %02x", bt->write_data[i]);
3231da177e4SLinus Torvalds 		printk("\n");
3241da177e4SLinus Torvalds 	}
325e8b33617SCorey Minyard 	for (i = 0; i < bt->write_count; i++)
326e8b33617SCorey Minyard 		HOST2BMC(bt->write_data[i]);
3271da177e4SLinus Torvalds }
3281da177e4SLinus Torvalds 
3291da177e4SLinus Torvalds static inline int read_all_bytes(struct si_sm_data *bt)
3301da177e4SLinus Torvalds {
331a94cdd1fSJiri Slaby 	unsigned int i;
3321da177e4SLinus Torvalds 
333c305e3d3SCorey Minyard 	/*
334c305e3d3SCorey Minyard 	 * length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode.
335c305e3d3SCorey Minyard 	 * Keep layout of first four bytes aligned with write_data[]
336c305e3d3SCorey Minyard 	 */
3374d7cbac7SCorey Minyard 
3381da177e4SLinus Torvalds 	bt->read_data[0] = BMC2HOST;
3391da177e4SLinus Torvalds 	bt->read_count = bt->read_data[0];
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 	if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) {
3421da177e4SLinus Torvalds 		if (bt_debug & BT_DEBUG_MSG)
3434d7cbac7SCorey Minyard 			printk(KERN_WARNING "BT: bad raw rsp len=%d\n",
3444d7cbac7SCorey Minyard 				bt->read_count);
3451da177e4SLinus Torvalds 		bt->truncated = 1;
3461da177e4SLinus Torvalds 		return 1;	/* let next XACTION START clean it up */
3471da177e4SLinus Torvalds 	}
348e8b33617SCorey Minyard 	for (i = 1; i <= bt->read_count; i++)
349e8b33617SCorey Minyard 		bt->read_data[i] = BMC2HOST;
3504d7cbac7SCorey Minyard 	bt->read_count++;	/* Account internally for length byte */
3511da177e4SLinus Torvalds 
3521da177e4SLinus Torvalds 	if (bt_debug & BT_DEBUG_MSG) {
3534d7cbac7SCorey Minyard 		int max = bt->read_count;
3541da177e4SLinus Torvalds 
3554d7cbac7SCorey Minyard 		printk(KERN_WARNING "BT: got %d bytes seq=0x%02X",
3564d7cbac7SCorey Minyard 			max, bt->read_data[2]);
3574d7cbac7SCorey Minyard 		if (max > 16)
3584d7cbac7SCorey Minyard 			max = 16;
3594d7cbac7SCorey Minyard 		for (i = 0; i < max; i++)
360c305e3d3SCorey Minyard 			printk(KERN_CONT " %02x", bt->read_data[i]);
361c305e3d3SCorey Minyard 		printk(KERN_CONT "%s\n", bt->read_count == max ? "" : " ...");
3624d7cbac7SCorey Minyard 	}
3634d7cbac7SCorey Minyard 
3644d7cbac7SCorey Minyard 	/* per the spec, the (NetFn[1], Seq[2], Cmd[3]) tuples must match */
3654d7cbac7SCorey Minyard 	if ((bt->read_data[3] == bt->write_data[3]) &&
3664d7cbac7SCorey Minyard 	    (bt->read_data[2] == bt->write_data[2]) &&
3671da177e4SLinus Torvalds 	    ((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8)))
3681da177e4SLinus Torvalds 			return 1;
3691da177e4SLinus Torvalds 
370e8b33617SCorey Minyard 	if (bt_debug & BT_DEBUG_MSG)
3714d7cbac7SCorey Minyard 		printk(KERN_WARNING "IPMI BT: bad packet: "
3721da177e4SLinus Torvalds 		"want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n",
3734d7cbac7SCorey Minyard 		bt->write_data[1] | 0x04, bt->write_data[2], bt->write_data[3],
3741da177e4SLinus Torvalds 		bt->read_data[1],  bt->read_data[2],  bt->read_data[3]);
3751da177e4SLinus Torvalds 	return 0;
3761da177e4SLinus Torvalds }
3771da177e4SLinus Torvalds 
3784d7cbac7SCorey Minyard /* Restart if retries are left, or return an error completion code */
3791da177e4SLinus Torvalds 
3804d7cbac7SCorey Minyard static enum si_sm_result error_recovery(struct si_sm_data *bt,
3814d7cbac7SCorey Minyard 					unsigned char status,
3824d7cbac7SCorey Minyard 					unsigned char cCode)
3831da177e4SLinus Torvalds {
3844d7cbac7SCorey Minyard 	char *reason;
3851da177e4SLinus Torvalds 
3864d7cbac7SCorey Minyard 	bt->timeout = bt->BT_CAP_req2rsp;
3871da177e4SLinus Torvalds 
3884d7cbac7SCorey Minyard 	switch (cCode) {
3894d7cbac7SCorey Minyard 	case IPMI_TIMEOUT_ERR:
3904d7cbac7SCorey Minyard 		reason = "timeout";
3914d7cbac7SCorey Minyard 		break;
3924d7cbac7SCorey Minyard 	default:
3934d7cbac7SCorey Minyard 		reason = "internal error";
3944d7cbac7SCorey Minyard 		break;
3954d7cbac7SCorey Minyard 	}
3961da177e4SLinus Torvalds 
3974d7cbac7SCorey Minyard 	printk(KERN_WARNING "IPMI BT: %s in %s %s ", 	/* open-ended line */
3984d7cbac7SCorey Minyard 		reason, STATE2TXT, STATUS2TXT);
3994d7cbac7SCorey Minyard 
400c305e3d3SCorey Minyard 	/*
401c305e3d3SCorey Minyard 	 * Per the IPMI spec, retries are based on the sequence number
402c305e3d3SCorey Minyard 	 * known only to this module, so manage a restart here.
403c305e3d3SCorey Minyard 	 */
4041da177e4SLinus Torvalds 	(bt->error_retries)++;
4054d7cbac7SCorey Minyard 	if (bt->error_retries < bt->BT_CAP_retries) {
4064d7cbac7SCorey Minyard 		printk("%d retries left\n",
4074d7cbac7SCorey Minyard 			bt->BT_CAP_retries - bt->error_retries);
4081da177e4SLinus Torvalds 		bt->state = BT_STATE_RESTART;
4094d7cbac7SCorey Minyard 		return SI_SM_CALL_WITHOUT_DELAY;
4101da177e4SLinus Torvalds 	}
4111da177e4SLinus Torvalds 
412c305e3d3SCorey Minyard 	printk(KERN_WARNING "failed %d retries, sending error response\n",
4134d7cbac7SCorey Minyard 	       bt->BT_CAP_retries);
4144d7cbac7SCorey Minyard 	if (!bt->nonzero_status)
4154d7cbac7SCorey Minyard 		printk(KERN_ERR "IPMI BT: stuck, try power cycle\n");
4164d7cbac7SCorey Minyard 
4174d7cbac7SCorey Minyard 	/* this is most likely during insmod */
4184d7cbac7SCorey Minyard 	else if (bt->seq <= (unsigned char)(bt->BT_CAP_retries & 0xFF)) {
4194d7cbac7SCorey Minyard 		printk(KERN_WARNING "IPMI: BT reset (takes 5 secs)\n");
4204d7cbac7SCorey Minyard 		bt->state = BT_STATE_RESET1;
4214d7cbac7SCorey Minyard 		return SI_SM_CALL_WITHOUT_DELAY;
4224d7cbac7SCorey Minyard 	}
4234d7cbac7SCorey Minyard 
424c305e3d3SCorey Minyard 	/*
425c305e3d3SCorey Minyard 	 * Concoct a useful error message, set up the next state, and
426c305e3d3SCorey Minyard 	 * be done with this sequence.
427c305e3d3SCorey Minyard 	 */
4284d7cbac7SCorey Minyard 
4294d7cbac7SCorey Minyard 	bt->state = BT_STATE_IDLE;
4304d7cbac7SCorey Minyard 	switch (cCode) {
4314d7cbac7SCorey Minyard 	case IPMI_TIMEOUT_ERR:
4324d7cbac7SCorey Minyard 		if (status & BT_B_BUSY) {
4334d7cbac7SCorey Minyard 			cCode = IPMI_NODE_BUSY_ERR;
4344d7cbac7SCorey Minyard 			bt->state = BT_STATE_LONG_BUSY;
4354d7cbac7SCorey Minyard 		}
4364d7cbac7SCorey Minyard 		break;
4374d7cbac7SCorey Minyard 	default:
4384d7cbac7SCorey Minyard 		break;
4394d7cbac7SCorey Minyard 	}
4404d7cbac7SCorey Minyard 	force_result(bt, cCode);
4414d7cbac7SCorey Minyard 	return SI_SM_TRANSACTION_COMPLETE;
4424d7cbac7SCorey Minyard }
4434d7cbac7SCorey Minyard 
4444d7cbac7SCorey Minyard /* Check status and (usually) take action and change this state machine. */
4451da177e4SLinus Torvalds 
4461da177e4SLinus Torvalds static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
4471da177e4SLinus Torvalds {
448*c86ba91bSCorey Minyard 	unsigned char status;
4494d7cbac7SCorey Minyard 	static enum bt_states last_printed = BT_STATE_PRINTME;
4501da177e4SLinus Torvalds 	int i;
4511da177e4SLinus Torvalds 
4521da177e4SLinus Torvalds 	status = BT_STATUS;
4531da177e4SLinus Torvalds 	bt->nonzero_status |= status;
4544d7cbac7SCorey Minyard 	if ((bt_debug & BT_DEBUG_STATES) && (bt->state != last_printed)) {
4551da177e4SLinus Torvalds 		printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n",
4561da177e4SLinus Torvalds 			STATE2TXT,
4574d7cbac7SCorey Minyard 			STATUS2TXT,
4581da177e4SLinus Torvalds 			bt->timeout,
4591da177e4SLinus Torvalds 			time);
4604d7cbac7SCorey Minyard 		last_printed = bt->state;
4611da177e4SLinus Torvalds 	}
4624d7cbac7SCorey Minyard 
463c305e3d3SCorey Minyard 	/*
464c305e3d3SCorey Minyard 	 * Commands that time out may still (eventually) provide a response.
465c305e3d3SCorey Minyard 	 * This stale response will get in the way of a new response so remove
466c305e3d3SCorey Minyard 	 * it if possible (hopefully during IDLE).  Even if it comes up later
467c305e3d3SCorey Minyard 	 * it will be rejected by its (now-forgotten) seq number.
468c305e3d3SCorey Minyard 	 */
4694d7cbac7SCorey Minyard 
4704d7cbac7SCorey Minyard 	if ((bt->state < BT_STATE_WRITE_BYTES) && (status & BT_B2H_ATN)) {
4714d7cbac7SCorey Minyard 		drain_BMC2HOST(bt);
4724d7cbac7SCorey Minyard 		BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
4734d7cbac7SCorey Minyard 	}
4744d7cbac7SCorey Minyard 
4754d7cbac7SCorey Minyard 	if ((bt->state != BT_STATE_IDLE) &&
476c305e3d3SCorey Minyard 	    (bt->state <  BT_STATE_PRINTME)) {
477c305e3d3SCorey Minyard 		/* check timeout */
4784d7cbac7SCorey Minyard 		bt->timeout -= time;
4794d7cbac7SCorey Minyard 		if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1))
4804d7cbac7SCorey Minyard 			return error_recovery(bt,
4814d7cbac7SCorey Minyard 					      status,
4824d7cbac7SCorey Minyard 					      IPMI_TIMEOUT_ERR);
4831da177e4SLinus Torvalds 	}
4841da177e4SLinus Torvalds 
4851da177e4SLinus Torvalds 	switch (bt->state) {
4861da177e4SLinus Torvalds 
487c305e3d3SCorey Minyard 	/*
488c305e3d3SCorey Minyard 	 * Idle state first checks for asynchronous messages from another
489c305e3d3SCorey Minyard 	 * channel, then does some opportunistic housekeeping.
490c305e3d3SCorey Minyard 	 */
4914d7cbac7SCorey Minyard 
4924d7cbac7SCorey Minyard 	case BT_STATE_IDLE:
4931da177e4SLinus Torvalds 		if (status & BT_SMS_ATN) {
4941da177e4SLinus Torvalds 			BT_CONTROL(BT_SMS_ATN);	/* clear it */
4951da177e4SLinus Torvalds 			return SI_SM_ATTN;
4961da177e4SLinus Torvalds 		}
4974d7cbac7SCorey Minyard 
4984d7cbac7SCorey Minyard 		if (status & BT_H_BUSY)		/* clear a leftover H_BUSY */
4994d7cbac7SCorey Minyard 			BT_CONTROL(BT_H_BUSY);
5004d7cbac7SCorey Minyard 
5014d7cbac7SCorey Minyard 		BT_SI_SM_RETURN(SI_SM_IDLE);
5021da177e4SLinus Torvalds 
5031da177e4SLinus Torvalds 	case BT_STATE_XACTION_START:
5044d7cbac7SCorey Minyard 		if (status & (BT_B_BUSY | BT_H2B_ATN))
5054d7cbac7SCorey Minyard 			BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
5064d7cbac7SCorey Minyard 		if (BT_STATUS & BT_H_BUSY)
5074d7cbac7SCorey Minyard 			BT_CONTROL(BT_H_BUSY);	/* force clear */
5084d7cbac7SCorey Minyard 		BT_STATE_CHANGE(BT_STATE_WRITE_BYTES,
5094d7cbac7SCorey Minyard 				SI_SM_CALL_WITHOUT_DELAY);
5101da177e4SLinus Torvalds 
5111da177e4SLinus Torvalds 	case BT_STATE_WRITE_BYTES:
5124d7cbac7SCorey Minyard 		if (status & BT_H_BUSY)
5134d7cbac7SCorey Minyard 			BT_CONTROL(BT_H_BUSY);	/* clear */
5141da177e4SLinus Torvalds 		BT_CONTROL(BT_CLR_WR_PTR);
5151da177e4SLinus Torvalds 		write_all_bytes(bt);
5164d7cbac7SCorey Minyard 		BT_CONTROL(BT_H2B_ATN);	/* can clear too fast to catch */
5174d7cbac7SCorey Minyard 		BT_STATE_CHANGE(BT_STATE_WRITE_CONSUME,
5184d7cbac7SCorey Minyard 				SI_SM_CALL_WITHOUT_DELAY);
5191da177e4SLinus Torvalds 
5204d7cbac7SCorey Minyard 	case BT_STATE_WRITE_CONSUME:
5214d7cbac7SCorey Minyard 		if (status & (BT_B_BUSY | BT_H2B_ATN))
5224d7cbac7SCorey Minyard 			BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
5234d7cbac7SCorey Minyard 		BT_STATE_CHANGE(BT_STATE_READ_WAIT,
5244d7cbac7SCorey Minyard 				SI_SM_CALL_WITHOUT_DELAY);
5251da177e4SLinus Torvalds 
5264d7cbac7SCorey Minyard 	/* Spinning hard can suppress B2H_ATN and force a timeout */
5271da177e4SLinus Torvalds 
5284d7cbac7SCorey Minyard 	case BT_STATE_READ_WAIT:
529e8b33617SCorey Minyard 		if (!(status & BT_B2H_ATN))
5304d7cbac7SCorey Minyard 			BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
531e8b33617SCorey Minyard 		BT_CONTROL(BT_H_BUSY);		/* set */
5321da177e4SLinus Torvalds 
533c305e3d3SCorey Minyard 		/*
53442b2aa86SJustin P. Mattock 		 * Uncached, ordered writes should just proceed serially but
535c305e3d3SCorey Minyard 		 * some BMCs don't clear B2H_ATN with one hit.  Fast-path a
536c305e3d3SCorey Minyard 		 * workaround without too much penalty to the general case.
537c305e3d3SCorey Minyard 		 */
5381da177e4SLinus Torvalds 
5394d7cbac7SCorey Minyard 		BT_CONTROL(BT_B2H_ATN);		/* clear it to ACK the BMC */
5404d7cbac7SCorey Minyard 		BT_STATE_CHANGE(BT_STATE_CLEAR_B2H,
5414d7cbac7SCorey Minyard 				SI_SM_CALL_WITHOUT_DELAY);
5421da177e4SLinus Torvalds 
5434d7cbac7SCorey Minyard 	case BT_STATE_CLEAR_B2H:
544c305e3d3SCorey Minyard 		if (status & BT_B2H_ATN) {
545c305e3d3SCorey Minyard 			/* keep hitting it */
5464d7cbac7SCorey Minyard 			BT_CONTROL(BT_B2H_ATN);
5474d7cbac7SCorey Minyard 			BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
5484d7cbac7SCorey Minyard 		}
5494d7cbac7SCorey Minyard 		BT_STATE_CHANGE(BT_STATE_READ_BYTES,
5504d7cbac7SCorey Minyard 				SI_SM_CALL_WITHOUT_DELAY);
5511da177e4SLinus Torvalds 
5524d7cbac7SCorey Minyard 	case BT_STATE_READ_BYTES:
553c305e3d3SCorey Minyard 		if (!(status & BT_H_BUSY))
554c305e3d3SCorey Minyard 			/* check in case of retry */
5554d7cbac7SCorey Minyard 			BT_CONTROL(BT_H_BUSY);
5564d7cbac7SCorey Minyard 		BT_CONTROL(BT_CLR_RD_PTR);	/* start of BMC2HOST buffer */
5574d7cbac7SCorey Minyard 		i = read_all_bytes(bt);		/* true == packet seq match */
5584d7cbac7SCorey Minyard 		BT_CONTROL(BT_H_BUSY);		/* NOW clear */
5594d7cbac7SCorey Minyard 		if (!i) 			/* Not my message */
5604d7cbac7SCorey Minyard 			BT_STATE_CHANGE(BT_STATE_READ_WAIT,
5614d7cbac7SCorey Minyard 					SI_SM_CALL_WITHOUT_DELAY);
5624d7cbac7SCorey Minyard 		bt->state = bt->complete;
5634d7cbac7SCorey Minyard 		return bt->state == BT_STATE_IDLE ?	/* where to next? */
5644d7cbac7SCorey Minyard 			SI_SM_TRANSACTION_COMPLETE :	/* normal */
5654d7cbac7SCorey Minyard 			SI_SM_CALL_WITHOUT_DELAY;	/* Startup magic */
5664d7cbac7SCorey Minyard 
5674d7cbac7SCorey Minyard 	case BT_STATE_LONG_BUSY:	/* For example: after FW update */
5684d7cbac7SCorey Minyard 		if (!(status & BT_B_BUSY)) {
5694d7cbac7SCorey Minyard 			reset_flags(bt);	/* next state is now IDLE */
5704d7cbac7SCorey Minyard 			bt_init_data(bt, bt->io);
5714d7cbac7SCorey Minyard 		}
5724d7cbac7SCorey Minyard 		return SI_SM_CALL_WITH_DELAY;	/* No repeat printing */
5731da177e4SLinus Torvalds 
5741da177e4SLinus Torvalds 	case BT_STATE_RESET1:
5751da177e4SLinus Torvalds 		reset_flags(bt);
5764d7cbac7SCorey Minyard 		drain_BMC2HOST(bt);
5774d7cbac7SCorey Minyard 		BT_STATE_CHANGE(BT_STATE_RESET2,
5784d7cbac7SCorey Minyard 				SI_SM_CALL_WITH_DELAY);
5791da177e4SLinus Torvalds 
5801da177e4SLinus Torvalds 	case BT_STATE_RESET2:		/* Send a soft reset */
5811da177e4SLinus Torvalds 		BT_CONTROL(BT_CLR_WR_PTR);
5821da177e4SLinus Torvalds 		HOST2BMC(3);		/* number of bytes following */
5831da177e4SLinus Torvalds 		HOST2BMC(0x18);		/* NetFn/LUN == Application, LUN 0 */
5841da177e4SLinus Torvalds 		HOST2BMC(42);		/* Sequence number */
5851da177e4SLinus Torvalds 		HOST2BMC(3);		/* Cmd == Soft reset */
5861da177e4SLinus Torvalds 		BT_CONTROL(BT_H2B_ATN);
587ccb3368cSXie XiuQi 		bt->timeout = BT_RESET_DELAY * USEC_PER_SEC;
5884d7cbac7SCorey Minyard 		BT_STATE_CHANGE(BT_STATE_RESET3,
5894d7cbac7SCorey Minyard 				SI_SM_CALL_WITH_DELAY);
5901da177e4SLinus Torvalds 
5914d7cbac7SCorey Minyard 	case BT_STATE_RESET3:		/* Hold off everything for a bit */
592e8b33617SCorey Minyard 		if (bt->timeout > 0)
593e8b33617SCorey Minyard 			return SI_SM_CALL_WITH_DELAY;
5944d7cbac7SCorey Minyard 		drain_BMC2HOST(bt);
5954d7cbac7SCorey Minyard 		BT_STATE_CHANGE(BT_STATE_RESTART,
5964d7cbac7SCorey Minyard 				SI_SM_CALL_WITH_DELAY);
5971da177e4SLinus Torvalds 
5984d7cbac7SCorey Minyard 	case BT_STATE_RESTART:		/* don't reset retries or seq! */
5991da177e4SLinus Torvalds 		bt->read_count = 0;
6001da177e4SLinus Torvalds 		bt->nonzero_status = 0;
6014d7cbac7SCorey Minyard 		bt->timeout = bt->BT_CAP_req2rsp;
6024d7cbac7SCorey Minyard 		BT_STATE_CHANGE(BT_STATE_XACTION_START,
6034d7cbac7SCorey Minyard 				SI_SM_CALL_WITH_DELAY);
6041da177e4SLinus Torvalds 
6054d7cbac7SCorey Minyard 	default:	/* should never occur */
6064d7cbac7SCorey Minyard 		return error_recovery(bt,
6074d7cbac7SCorey Minyard 				      status,
6084d7cbac7SCorey Minyard 				      IPMI_ERR_UNSPECIFIED);
6091da177e4SLinus Torvalds 	}
6101da177e4SLinus Torvalds 	return SI_SM_CALL_WITH_DELAY;
6111da177e4SLinus Torvalds }
6121da177e4SLinus Torvalds 
6131da177e4SLinus Torvalds static int bt_detect(struct si_sm_data *bt)
6141da177e4SLinus Torvalds {
615*c86ba91bSCorey Minyard 	unsigned char GetBT_CAP[] = { 0x18, 0x36 };
616*c86ba91bSCorey Minyard 	unsigned char BT_CAP[8];
617*c86ba91bSCorey Minyard 	enum si_sm_result smi_result;
618*c86ba91bSCorey Minyard 	int rv;
619*c86ba91bSCorey Minyard 
620c305e3d3SCorey Minyard 	/*
621c305e3d3SCorey Minyard 	 * It's impossible for the BT status and interrupt registers to be
622c305e3d3SCorey Minyard 	 * all 1's, (assuming a properly functioning, self-initialized BMC)
623c305e3d3SCorey Minyard 	 * but that's what you get from reading a bogus address, so we
624c305e3d3SCorey Minyard 	 * test that first.  The calling routine uses negative logic.
625c305e3d3SCorey Minyard 	 */
6261da177e4SLinus Torvalds 
627e8b33617SCorey Minyard 	if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF))
628e8b33617SCorey Minyard 		return 1;
6291da177e4SLinus Torvalds 	reset_flags(bt);
630*c86ba91bSCorey Minyard 
631*c86ba91bSCorey Minyard 	/*
632*c86ba91bSCorey Minyard 	 * Try getting the BT capabilities here.
633*c86ba91bSCorey Minyard 	 */
634*c86ba91bSCorey Minyard 	rv = bt_start_transaction(bt, GetBT_CAP, sizeof(GetBT_CAP));
635*c86ba91bSCorey Minyard 	if (rv) {
636*c86ba91bSCorey Minyard 		dev_warn(bt->io->dev,
637*c86ba91bSCorey Minyard 			 "Can't start capabilities transaction: %d\n", rv);
638*c86ba91bSCorey Minyard 		goto out_no_bt_cap;
639*c86ba91bSCorey Minyard 	}
640*c86ba91bSCorey Minyard 
641*c86ba91bSCorey Minyard 	smi_result = SI_SM_CALL_WITHOUT_DELAY;
642*c86ba91bSCorey Minyard 	for (;;) {
643*c86ba91bSCorey Minyard 		if (smi_result == SI_SM_CALL_WITH_DELAY ||
644*c86ba91bSCorey Minyard 		    smi_result == SI_SM_CALL_WITH_TICK_DELAY) {
645*c86ba91bSCorey Minyard 			schedule_timeout_uninterruptible(1);
646*c86ba91bSCorey Minyard 			smi_result = bt_event(bt, jiffies_to_usecs(1));
647*c86ba91bSCorey Minyard 		} else if (smi_result == SI_SM_CALL_WITHOUT_DELAY) {
648*c86ba91bSCorey Minyard 			smi_result = bt_event(bt, 0);
649*c86ba91bSCorey Minyard 		} else
650*c86ba91bSCorey Minyard 			break;
651*c86ba91bSCorey Minyard 	}
652*c86ba91bSCorey Minyard 
653*c86ba91bSCorey Minyard 	rv = bt_get_result(bt, BT_CAP, sizeof(BT_CAP));
654*c86ba91bSCorey Minyard 	bt_init_data(bt, bt->io);
655*c86ba91bSCorey Minyard 	if (rv < 8) {
656*c86ba91bSCorey Minyard 		dev_warn(bt->io->dev, "bt cap response too short: %d\n", rv);
657*c86ba91bSCorey Minyard 		goto out_no_bt_cap;
658*c86ba91bSCorey Minyard 	}
659*c86ba91bSCorey Minyard 
660*c86ba91bSCorey Minyard 	if (BT_CAP[2]) {
661*c86ba91bSCorey Minyard 		dev_warn(bt->io->dev, "Error fetching bt cap: %x\n", BT_CAP[2]);
662*c86ba91bSCorey Minyard out_no_bt_cap:
663*c86ba91bSCorey Minyard 		dev_warn(bt->io->dev, "using default values\n");
664*c86ba91bSCorey Minyard 	} else {
665*c86ba91bSCorey Minyard 		bt->BT_CAP_req2rsp = BT_CAP[6] * USEC_PER_SEC;
666*c86ba91bSCorey Minyard 		bt->BT_CAP_retries = BT_CAP[7];
667*c86ba91bSCorey Minyard 	}
668*c86ba91bSCorey Minyard 
669*c86ba91bSCorey Minyard 	dev_info(bt->io->dev, "req2rsp=%ld secs retries=%d\n",
670*c86ba91bSCorey Minyard 		 bt->BT_CAP_req2rsp / USEC_PER_SEC, bt->BT_CAP_retries);
671*c86ba91bSCorey Minyard 
6721da177e4SLinus Torvalds 	return 0;
6731da177e4SLinus Torvalds }
6741da177e4SLinus Torvalds 
6751da177e4SLinus Torvalds static void bt_cleanup(struct si_sm_data *bt)
6761da177e4SLinus Torvalds {
6771da177e4SLinus Torvalds }
6781da177e4SLinus Torvalds 
6791da177e4SLinus Torvalds static int bt_size(void)
6801da177e4SLinus Torvalds {
6811da177e4SLinus Torvalds 	return sizeof(struct si_sm_data);
6821da177e4SLinus Torvalds }
6831da177e4SLinus Torvalds 
68481d02b7fSCorey Minyard const struct si_sm_handlers bt_smi_handlers = {
6851da177e4SLinus Torvalds 	.init_data		= bt_init_data,
6861da177e4SLinus Torvalds 	.start_transaction	= bt_start_transaction,
6871da177e4SLinus Torvalds 	.get_result		= bt_get_result,
6881da177e4SLinus Torvalds 	.event			= bt_event,
6891da177e4SLinus Torvalds 	.detect			= bt_detect,
6901da177e4SLinus Torvalds 	.cleanup		= bt_cleanup,
6911da177e4SLinus Torvalds 	.size			= bt_size,
6921da177e4SLinus Torvalds };
693