i91uscsi.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,185 行 · 第 1/5 页

C
2,185
字号
		}		/* Check pending SCB            */		if (tul_find_first_pend_scb(pCurHcb) == NULL) {			return 1;	/* return to OS, enable interrupt */		}	}			/* End of for loop */	/* statement won't reach here */}/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ *//***************************************************************************//***************************************************************************//***************************************************************************//***************************************************************************//***************************************************************************/void tulip_scsi(HCS * pCurHcb){	SCB *pCurScb;	TCS *pCurTcb;	/* make sure to service interrupt asap */	if ((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0)) & TSS_INT_PENDING) {		pCurHcb->HCS_Phase = pCurHcb->HCS_JSStatus0 & TSS_PH_MASK;		pCurHcb->HCS_JSStatus1 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1);		pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);		if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {	/* SCSI bus reset detected      */			int_tul_scsi_rst(pCurHcb);			return;		}		if (pCurHcb->HCS_JSInt & TSS_RESEL_INT) {	/* if selected/reselected interrupt */			if (int_tul_resel(pCurHcb) == 0)				tul_next_state(pCurHcb);			return;		}		if (pCurHcb->HCS_JSInt & TSS_SEL_TIMEOUT) {			int_tul_busfree(pCurHcb);			return;		}		if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {	/* BUS disconnection            */			int_tul_busfree(pCurHcb);	/* unexpected bus free or sel timeout */			return;		}		if (pCurHcb->HCS_JSInt & (TSS_FUNC_COMP | TSS_BUS_SERV)) {	/* func complete or Bus service */			if ((pCurScb = pCurHcb->HCS_ActScb) != NULL)				tul_next_state(pCurHcb);			return;		}	}	if (pCurHcb->HCS_ActScb != NULL)		return;	if ((pCurScb = tul_find_first_pend_scb(pCurHcb)) == NULL)		return;	/* program HBA's SCSI ID & target SCSI ID */	TUL_WR(pCurHcb->HCS_Base + TUL_SScsiId,	     (pCurHcb->HCS_SCSI_ID << 4) | (pCurScb->SCB_Target & 0x0F));	if (pCurScb->SCB_Opcode == ExecSCSI) {		pCurTcb = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];		if (pCurScb->SCB_TagMsg)			pCurTcb->TCS_DrvFlags |= TCF_DRV_EN_TAG;		else			pCurTcb->TCS_DrvFlags &= ~TCF_DRV_EN_TAG;		TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurTcb->TCS_JS_Period);		if ((pCurTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {	/* do wdtr negotiation          */			tul_select_atn_stop(pCurHcb, pCurScb);		} else {			if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {	/* do sync negotiation          */				tul_select_atn_stop(pCurHcb, pCurScb);			} else {				if (pCurScb->SCB_TagMsg)					tul_select_atn3(pCurHcb, pCurScb);				else					tul_select_atn(pCurHcb, pCurScb);			}		}		if (pCurScb->SCB_Flags & SCF_POLL) {			while (wait_tulip(pCurHcb) != -1) {				if (tul_next_state(pCurHcb) == -1)					break;			}		}	} else if (pCurScb->SCB_Opcode == BusDevRst) {		tul_select_atn_stop(pCurHcb, pCurScb);		pCurScb->SCB_NxtStat = 8;		if (pCurScb->SCB_Flags & SCF_POLL) {			while (wait_tulip(pCurHcb) != -1) {				if (tul_next_state(pCurHcb) == -1)					break;			}		}	} else if (pCurScb->SCB_Opcode == AbortCmd) {		ULONG srbp;		srbp = (ULONG) pCurScb->SCB_Srb;/* 08/03/98 */		if (tul_abort_srb(pCurHcb, srbp) != 0) {			tul_unlink_pend_scb(pCurHcb, pCurScb);			tul_release_scb(pCurHcb, pCurScb);		} else {			pCurScb->SCB_Opcode = BusDevRst;			tul_select_atn_stop(pCurHcb, pCurScb);			pCurScb->SCB_NxtStat = 8;		}/* 08/03/98 */	} else {		tul_unlink_pend_scb(pCurHcb, pCurScb);		pCurScb->SCB_HaStat = 0x16;	/* bad command */		tul_append_done_scb(pCurHcb, pCurScb);	}	return;}/***************************************************************************/int tul_next_state(HCS * pCurHcb){	int next;	next = pCurHcb->HCS_ActScb->SCB_NxtStat;	for (;;) {		switch (next) {		case 1:			next = tul_state_1(pCurHcb);			break;		case 2:			next = tul_state_2(pCurHcb);			break;		case 3:			next = tul_state_3(pCurHcb);			break;		case 4:			next = tul_state_4(pCurHcb);			break;		case 5:			next = tul_state_5(pCurHcb);			break;		case 6:			next = tul_state_6(pCurHcb);			break;		case 7:			next = tul_state_7(pCurHcb);			break;		case 8:			return (tul_bus_device_reset(pCurHcb));		default:			return (tul_bad_seq(pCurHcb));		}		if (next <= 0)			return next;	}}/***************************************************************************//* sTate after selection with attention & stop */int tul_state_1(HCS * pCurHcb){	SCB *pCurScb = pCurHcb->HCS_ActScb;	TCS *pCurTcb = pCurHcb->HCS_ActTcs;#if DEBUG_STATE	printk("-s1-");#endif	tul_unlink_pend_scb(pCurHcb, pCurScb);	tul_append_busy_scb(pCurHcb, pCurScb);	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);	/* ATN on */	if (pCurHcb->HCS_Phase == MSG_OUT) {		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, (TSC_EN_BUS_IN | TSC_HW_RESELECT));		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);		if (pCurScb->SCB_TagMsg) {			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagMsg);			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagId);		}		if ((pCurTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {			pCurTcb->TCS_Flags |= TCF_WDTR_DONE;			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 2);	/* Extended msg length */			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);	/* Sync request */			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);	/* Start from 16 bits */		} else if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {			pCurTcb->TCS_Flags |= TCF_SYNC_DONE;			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);	/* extended msg length */			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);	/* sync request */			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, tul_rate_tbl[pCurTcb->TCS_Flags & TCF_SCSI_RATE]);			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MAX_OFFSET);	/* REQ/ACK offset */		}		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);		if (wait_tulip(pCurHcb) == -1)			return (-1);	}	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));	return (3);}/***************************************************************************//* state after selection with attention *//* state after selection with attention3 */int tul_state_2(HCS * pCurHcb){	SCB *pCurScb = pCurHcb->HCS_ActScb;	TCS *pCurTcb = pCurHcb->HCS_ActTcs;#if DEBUG_STATE	printk("-s2-");#endif	tul_unlink_pend_scb(pCurHcb, pCurScb);	tul_append_busy_scb(pCurHcb, pCurScb);	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);	if (pCurHcb->HCS_JSStatus1 & TSS_CMD_PH_CMP) {		return (4);	}	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));	return (3);}/***************************************************************************//* state before CDB xfer is done */int tul_state_3(HCS * pCurHcb){	SCB *pCurScb = pCurHcb->HCS_ActScb;	TCS *pCurTcb = pCurHcb->HCS_ActTcs;	int i;#if DEBUG_STATE	printk("-s3-");#endif	for (;;) {		switch (pCurHcb->HCS_Phase) {		case CMD_OUT:	/* Command out phase            */			for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);			if (wait_tulip(pCurHcb) == -1)				return (-1);			if (pCurHcb->HCS_Phase == CMD_OUT) {				return (tul_bad_seq(pCurHcb));			}			return (4);		case MSG_IN:	/* Message in phase             */			pCurScb->SCB_NxtStat = 3;			if (tul_msgin(pCurHcb) == -1)				return (-1);			break;		case STATUS_IN:	/* Status phase                 */			if (tul_status_msg(pCurHcb) == -1)				return (-1);			break;		case MSG_OUT:	/* Message out phase            */			if (pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) {				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);		/* msg nop */				TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);				if (wait_tulip(pCurHcb) == -1)					return (-1);			} else {				pCurTcb->TCS_Flags |= TCF_SYNC_DONE;				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);	/* ext. msg len */				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);	/* sync request */				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, tul_rate_tbl[pCurTcb->TCS_Flags & TCF_SCSI_RATE]);				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MAX_OFFSET);	/* REQ/ACK offset */				TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);				if (wait_tulip(pCurHcb) == -1)					return (-1);				TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);				TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7));			}			break;		default:			return (tul_bad_seq(pCurHcb));		}	}}/***************************************************************************/int tul_state_4(HCS * pCurHcb){	SCB *pCurScb = pCurHcb->HCS_ActScb;#if DEBUG_STATE	printk("-s4-");#endif	if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_NO_XF) {		return (6);	/* Go to state 6                */	}	for (;;) {		if (pCurScb->SCB_BufLen == 0)			return (6);	/* Go to state 6                */		switch (pCurHcb->HCS_Phase) {		case STATUS_IN:	/* Status phase                 */			if ((pCurScb->SCB_Flags & SCF_DIR) != 0) {	/* if direction bit set then report data underrun */				pCurScb->SCB_HaStat = HOST_DO_DU;			}			if ((tul_status_msg(pCurHcb)) == -1)				return (-1);			break;		case MSG_IN:	/* Message in phase             */			pCurScb->SCB_NxtStat = 0x4;			if (tul_msgin(pCurHcb) == -1)				return (-1);			break;		case MSG_OUT:	/* Message out phase            */			if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {				pCurScb->SCB_BufLen = 0;				pCurScb->SCB_HaStat = HOST_DO_DU;				if (tul_msgout_ide(pCurHcb) == -1)					return (-1);				return (6);	/* Go to state 6                */			} else {				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);		/* msg nop */				TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);				if (wait_tulip(pCurHcb) == -1)					return (-1);			}			break;		case DATA_IN:	/* Data in phase                */			return (tul_xfer_data_in(pCurHcb));		case DATA_OUT:	/* Data out phase               */			return (tul_xfer_data_out(pCurHcb));		default:			return (tul_bad_seq(pCurHcb));		}	}}/***************************************************************************//* state after dma xfer done or phase change before xfer done */int tul_state_5(HCS * pCurHcb){	SCB *pCurScb = pCurHcb->HCS_ActScb;	long cnt, xcnt;		/* cannot use unsigned !! code: if (xcnt < 0) */#if DEBUG_STATE	printk("-s5-");#endif/*------ get remaining count -------*/	cnt = TUL_RDLONG(pCurHcb->HCS_Base, TUL_SCnt0) & 0x0FFFFFF;	if (TUL_RD(pCurHcb->HCS_Base, TUL_XCmd) & 0x20) {		/* ----------------------- DATA_IN ----------------------------- */		/* check scsi parity error */		if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {			pCurScb->SCB_HaStat = HOST_DO_DU;		}		if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) {	/* DMA xfer pending, Send STOP  */			/* tell Hardware  scsi xfer has been terminated */			TUL_WR(pCurHcb->HCS_Base + TUL_XCtrl, TUL_RD(pCurHcb->HCS_Base, TUL_XCtrl) | 0x80);			/* wait until DMA xfer not pending */			while (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND);		}	} else {/*-------- DATA OUT -----------*/		if ((TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1) & TSS_XFER_CMP) == 0) {			if (pCurHcb->HCS_ActTcs->TCS_JS_Period & TSC_WIDE_SCSI)				cnt += (TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F) << 1;			else				cnt += (TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F);		}		if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) {	/* if DMA xfer is pending, abort DMA xfer */			TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT);			/* wait Abort DMA xfer done */			while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & XABT) == 0);		}		if ((cnt == 1) && (pCurHcb->HCS_Phase == DATA_OUT)) {			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);			if (wait_tulip(pCurHcb) == -1) {				return (-1);			}			cnt = 0;		} else {			if ((TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1) & TSS_XFER_CMP) == 0)				TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);		}	}	if (cnt == 0) {		pCurScb->SCB_BufLen = 0;		return (6);	/* Go to state 6                */	}	/* Update active data pointer */	xcnt = (long) pCurScb->SCB_BufLen - cnt;	/* xcnt== bytes already xferred */	pCurScb->SCB_BufLen = (U32) cnt;	/* cnt == bytes left to be xferred */	if (pCurScb->SCB_Flags & SCF_SG) {		register SG *sgp;		ULONG i;		sgp = &pCurScb->SCB_SGList[pCurScb->SCB_SGIdx];		for (i = pCurScb->SCB_SGIdx; i < pCurScb->SCB_SGMax; sgp++, i++) {			xcnt -= (long) sgp->SG_Len;			if (xcnt < 0) {		/* this sgp xfer half done */				xcnt += (long) sgp->SG_Len;	/* xcnt == bytes xferred in this sgp */				sgp->SG_Ptr += (U32) xcnt;	/* new ptr to be xfer */

⌨️ 快捷键说明

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