⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipmi_bt_sm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (bt_debug & BT_DEBUG_MSG) {    		printk(KERN_WARNING "BT: write %d bytes seq=0x%02X",			bt->write_count, bt->seq);		for (i = 0; i < bt->write_count; i++)			printk (" %02x", bt->write_data[i]);		printk ("\n");	}	for (i = 0; i < bt->write_count; i++)	       HOST2BMC(bt->write_data[i]);}static inline int read_all_bytes(struct si_sm_data *bt){	unsigned char i;	bt->read_data[0] = BMC2HOST;	bt->read_count = bt->read_data[0];	if (bt_debug & BT_DEBUG_MSG)    		printk(KERN_WARNING "BT: read %d bytes:", bt->read_count);	/* minimum: length, NetFn, Seq, Cmd, cCode == 5 total, or 4 more	   following the length byte. */	if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) {		if (bt_debug & BT_DEBUG_MSG)			printk("bad length %d\n", bt->read_count);		bt->truncated = 1;		return 1;	/* let next XACTION START clean it up */	}	for (i = 1; i <= bt->read_count; i++)	       bt->read_data[i] = BMC2HOST;	bt->read_count++;	/* account for the length byte */	if (bt_debug & BT_DEBUG_MSG) {	    	for (i = 0; i < bt->read_count; i++)			printk (" %02x", bt->read_data[i]);	    	printk ("\n");	}	if (bt->seq != bt->write_data[2])	/* idiot check */		printk(KERN_DEBUG "BT: internal error: sequence mismatch\n");	/* per the spec, the (NetFn, Seq, Cmd) tuples should match */	if ((bt->read_data[3] == bt->write_data[3]) &&		/* Cmd */        	(bt->read_data[2] == bt->write_data[2]) &&	/* Sequence */        	((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8)))			return 1;	if (bt_debug & BT_DEBUG_MSG)	       printk(KERN_WARNING "BT: bad packet: "		"want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n",		bt->write_data[1], bt->write_data[2], bt->write_data[3],		bt->read_data[1],  bt->read_data[2],  bt->read_data[3]);	return 0;}/* Modifies bt->state appropriately, need to get into the bt_event() switch */static void error_recovery(struct si_sm_data *bt, char *reason){	unsigned char status;	char buf[40]; /* For getting status */	bt->timeout = BT_NORMAL_TIMEOUT; /* various places want to retry */	status = BT_STATUS;	printk(KERN_DEBUG "BT: %s in %s %s\n", reason, STATE2TXT,	       STATUS2TXT(buf));	(bt->error_retries)++;	if (bt->error_retries > BT_RETRY_LIMIT) {		printk(KERN_DEBUG "retry limit (%d) exceeded\n", BT_RETRY_LIMIT);		bt->state = BT_STATE_HOSED;		if (!bt->nonzero_status)			printk(KERN_ERR "IPMI: BT stuck, try power cycle\n");		else if (bt->error_retries <= BT_RETRY_LIMIT + 1) {			printk(KERN_DEBUG "IPMI: BT reset (takes 5 secs)\n");        		bt->state = BT_STATE_RESET1;		}	return;	}	/* Sometimes the BMC queues get in an "off-by-one" state...*/	if ((bt->state == BT_STATE_B2H_WAIT) && (status & BT_B2H_ATN)) {    		printk(KERN_DEBUG "retry B2H_WAIT\n");		return;	}	printk(KERN_DEBUG "restart command\n");	bt->state = BT_STATE_RESTART;}/* Check the status and (possibly) advance the BT state machine.  The   default return is SI_SM_CALL_WITH_DELAY. */static enum si_sm_result bt_event(struct si_sm_data *bt, long time){	unsigned char status;	char buf[40]; /* For getting status */	int i;	status = BT_STATUS;	bt->nonzero_status |= status;	if ((bt_debug & BT_DEBUG_STATES) && (bt->state != bt->last_state))		printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n",			STATE2TXT,			STATUS2TXT(buf),			bt->timeout,			time);	bt->last_state = bt->state;	if (bt->state == BT_STATE_HOSED)	       return SI_SM_HOSED;	if (bt->state != BT_STATE_IDLE) {	/* do timeout test */		bt->timeout -= time;		if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) {			error_recovery(bt, "timed out");			return SI_SM_CALL_WITHOUT_DELAY;		}	}	switch (bt->state) {    	case BT_STATE_IDLE:	/* check for asynchronous messages */		if (status & BT_SMS_ATN) {			BT_CONTROL(BT_SMS_ATN);	/* clear it */			return SI_SM_ATTN;		}		return SI_SM_IDLE;	case BT_STATE_XACTION_START:		if (status & BT_H_BUSY) {			BT_CONTROL(BT_H_BUSY);			break;		}    		if (status & BT_B2H_ATN)		       break;		bt->state = BT_STATE_WRITE_BYTES;		return SI_SM_CALL_WITHOUT_DELAY;	/* for logging */	case BT_STATE_WRITE_BYTES:		if (status & (BT_B_BUSY | BT_H2B_ATN))		       break;		BT_CONTROL(BT_CLR_WR_PTR);		write_all_bytes(bt);		BT_CONTROL(BT_H2B_ATN);	/* clears too fast to catch? */		bt->state = BT_STATE_WRITE_CONSUME;		return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */	case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */        	if (status & (BT_H2B_ATN | BT_B_BUSY))		       break;		bt->state = BT_STATE_B2H_WAIT;		/* fall through with status */	/* Stay in BT_STATE_B2H_WAIT until a packet matches.  However, spinning	   hard here, constantly reading status, seems to hold off the	   generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */	case BT_STATE_B2H_WAIT:    		if (!(status & BT_B2H_ATN))		       break;		/* Assume ordered, uncached writes: no need to wait */		if (!(status & BT_H_BUSY))		       BT_CONTROL(BT_H_BUSY); /* set */		BT_CONTROL(BT_B2H_ATN);		/* clear it, ACK to the BMC */		BT_CONTROL(BT_CLR_RD_PTR);	/* reset the queue */		i = read_all_bytes(bt);		BT_CONTROL(BT_H_BUSY);		/* clear */		if (!i)				/* Try this state again */		       break;		bt->state = BT_STATE_READ_END;		return SI_SM_CALL_WITHOUT_DELAY;	/* for logging */    	case BT_STATE_READ_END:		/* I could wait on BT_H_BUSY to go clear for a truly clean		   exit.  However, this is already done in XACTION_START		   and the (possible) extra loop/status/possible wait affects		   performance.  So, as long as it works, just ignore H_BUSY */#ifdef MAKE_THIS_TRUE_IF_NECESSARY		if (status & BT_H_BUSY)		       break;#endif		bt->seq++;		bt->state = BT_STATE_IDLE;		return SI_SM_TRANSACTION_COMPLETE;	case BT_STATE_RESET1:    		reset_flags(bt);    		bt->timeout = BT_RESET_DELAY;		bt->state = BT_STATE_RESET2;		break;	case BT_STATE_RESET2:		/* Send a soft reset */		BT_CONTROL(BT_CLR_WR_PTR);		HOST2BMC(3);		/* number of bytes following */		HOST2BMC(0x18);		/* NetFn/LUN == Application, LUN 0 */		HOST2BMC(42);		/* Sequence number */		HOST2BMC(3);		/* Cmd == Soft reset */		BT_CONTROL(BT_H2B_ATN);		bt->state = BT_STATE_RESET3;		break;	case BT_STATE_RESET3:		if (bt->timeout > 0)		       return SI_SM_CALL_WITH_DELAY;		bt->state = BT_STATE_RESTART;	/* printk in debug modes */		break;	case BT_STATE_RESTART:		/* don't reset retries! */		reset_flags(bt);		bt->write_data[2] = ++bt->seq;		bt->read_count = 0;		bt->nonzero_status = 0;		bt->timeout = BT_NORMAL_TIMEOUT;		bt->state = BT_STATE_XACTION_START;		break;	default:	/* HOSED is supposed to be caught much earlier */		error_recovery(bt, "internal logic error");		break;  	}  	return SI_SM_CALL_WITH_DELAY;}static int bt_detect(struct si_sm_data *bt){	/* It's impossible for the BT status and interrupt registers to be	   all 1's, (assuming a properly functioning, self-initialized BMC)	   but that's what you get from reading a bogus address, so we	   test that first.  The calling routine uses negative logic. */	if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF))	       return 1;	reset_flags(bt);	return 0;}static void bt_cleanup(struct si_sm_data *bt){}static int bt_size(void){	return sizeof(struct si_sm_data);}struct si_sm_handlers bt_smi_handlers ={	.init_data         = bt_init_data,	.start_transaction = bt_start_transaction,	.get_result        = bt_get_result,	.event             = bt_event,	.detect            = bt_detect,	.cleanup           = bt_cleanup,	.size              = bt_size,};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -