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

📄 sii.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
		MachEmptyWriteBuffer();#ifdef DEBUG		if (sii_logp > sii_log)			sii_logp[-1].cstat = cstat;		else			sii_log[NLOG - 1].cstat = cstat;#endif		/* check for a BUS RESET */		if (cstat & SII_RST) {			printf("sii%d: SCSI bus reset!!\n", sc - sii_softc);			/* need to flush disconnected commands */			for (i = 0; i < SII_NCMD; i++) {				if (!sc->sc_cmd[i])					continue;				sii_CmdDone(sc, i, EIO);			}			/* rearbitrate synchronous offset */			for (i = 0; i < SII_NCMD; i++)				sc->sc_st[i].dmaReqAck = 0;			sc->sc_target = -1;			return;		}#ifdef notdef		/*		 * Check for a BUS ERROR.		 * According to DEC, this feature doesn't really work		 * and to just clear the bit if it's set.		 */		if (cstat & SII_BER) {		}#endif		/* check for state change */		if (cstat & SII_SCH) {			sii_StateChg(sc, cstat);			comm = regs->comm;		}	}	/* check for DMA completion */	if (dstat & SII_DNE) {		u_short *dma;		char *buf;		/* check for a PARITY ERROR */		if (dstat & SII_IPE) {			printf("sii%d: Parity error!!\n", sc - sii_softc);			goto abort;		}		/*		 * There is a race condition with SII_SCH. There is a short		 * window between the time a SII_SCH is seen after a disconnect 		 * and when the SII_SCH is cleared. A reselect can happen		 * in this window and we will clear the SII_SCH without		 * processing the reconnect.		 */		if (sc->sc_target < 0) {			cstat = regs->cstat;			printf("sii%d: target %d DNE?? dev %d,%d cs %x\n",				sc - sii_softc, sc->sc_target,				regs->slcsr, regs->destat,				cstat); /* XXX */			if (cstat & SII_DST) {				sc->sc_target = regs->destat;				state->prevComm = 0;			} else				panic("sc_target 1");		}		state = &sc->sc_st[sc->sc_target];		/* dmalen = amount left to transfer, i = amount transfered */		i = state->dmalen;		state->dmalen = 0;		state->dmaCurPhase = -1;#ifdef DEBUG		if (sii_debug > 4) {			printf("DNE: amt %d ", i);			if (!(dstat & SII_TCZ))				printf("no TCZ?? (%d) ", regs->dmlotc);		} else if (!(dstat & SII_TCZ)) {			printf("sii%d: device %d: no TCZ?? (%d)\n",				sc - sii_softc, sc->sc_target, regs->dmlotc);			sii_DumpLog(); /* XXX */		}#endif		switch (comm & SII_PHASE_MSK) {		case SII_CMD_PHASE:			state->cmdlen -= i;			break;		case SII_DATA_IN_PHASE:			/* check for more data for the same phase */			dma = state->dmaAddr[state->dmaBufIndex];			buf = state->buf;			state->buf += i;			state->buflen -= i;			if (state->buflen > 0 && !(dstat & SII_MIS)) {				int len;				/* start reading next chunk */				len = state->buflen;				if (len > SII_MAX_DMA_XFER_LENGTH)					len = SII_MAX_DMA_XFER_LENGTH;				state->dmaBufIndex = !state->dmaBufIndex;				sii_StartDMA(regs,					state->dmaCurPhase = SII_DATA_IN_PHASE,					state->dmaAddr[state->dmaBufIndex],					state->dmalen = len);				dstat &= ~(SII_IBF | SII_TBE);			}			/* copy in the data */			CopyFromBuffer((volatile u_short *)dma, buf, i);			break;		case SII_DATA_OUT_PHASE:			state->dmaBufIndex = !state->dmaBufIndex;			state->buf += i;			state->buflen -= i;			/* check for more data for the same phase */			if (state->buflen <= 0 || (dstat & SII_MIS))				break;			/* start next chunk */			i = state->buflen;			if (i > SII_MAX_DMA_XFER_LENGTH) {				sii_StartDMA(regs, state->dmaCurPhase =					SII_DATA_OUT_PHASE,					state->dmaAddr[state->dmaBufIndex],					state->dmalen =					SII_MAX_DMA_XFER_LENGTH);				/* prepare for next chunk */				i -= SII_MAX_DMA_XFER_LENGTH;				if (i > SII_MAX_DMA_XFER_LENGTH)					i = SII_MAX_DMA_XFER_LENGTH;				CopyToBuffer((u_short *)(state->buf +					SII_MAX_DMA_XFER_LENGTH),					(volatile u_short *)					state->dmaAddr[!state->dmaBufIndex], i);			} else {				sii_StartDMA(regs, state->dmaCurPhase =					SII_DATA_OUT_PHASE,					state->dmaAddr[state->dmaBufIndex],					state->dmalen = i);			}			dstat &= ~(SII_IBF | SII_TBE);			break;		default:			printf("sii%d: device %d: unexpected DNE\n",				sc - sii_softc, sc->sc_target);#ifdef DEBUG			sii_DumpLog();#endif		}	}	/* check for phase change or another MsgIn/Out */	if (dstat & (SII_MIS | SII_IBF | SII_TBE)) {		/*		 * There is a race condition with SII_SCH. There is a short		 * window between the time a SII_SCH is seen after a disconnect 		 * and when the SII_SCH is cleared. A reselect can happen		 * in this window and we will clear the SII_SCH without		 * processing the reconnect.		 */		if (sc->sc_target < 0) {			cstat = regs->cstat;			printf("sii%d: target %d MIS?? dev %d,%d cs %x ds %x\n",				sc - sii_softc, sc->sc_target,				regs->slcsr, regs->destat,				cstat, dstat); /* XXX */			if (cstat & SII_DST) {				sc->sc_target = regs->destat;				state->prevComm = 0;			} else				panic("sc_target 2");		}		state = &sc->sc_st[sc->sc_target];		switch (dstat & SII_PHASE_MSK) {		case SII_CMD_PHASE:			if (state->dmaPrevPhase >= 0) {				/* restart DMA after disconnect/reconnect */				if (state->dmaPrevPhase != SII_CMD_PHASE) {					printf("sii%d: device %d: dma reselect phase doesn't match\n",						sc - sii_softc, sc->sc_target);					goto abort;				}				state->dmaCurPhase = SII_CMD_PHASE;				state->dmaPrevPhase = -1;				regs->dmaddrl = state->dmaAddrL;				regs->dmaddrh = state->dmaAddrH;				regs->dmlotc = state->dmaCnt;				if (state->dmaCnt & 1)					regs->dmabyte = state->dmaByte;				regs->comm = SII_DMA | SII_INXFER |					(comm & SII_STATE_MSK) | SII_CMD_PHASE;				MachEmptyWriteBuffer();#ifdef DEBUG				if (sii_debug > 4)					printf("Cmd dcnt %d dadr %x ",						state->dmaCnt,						(state->dmaAddrH << 16) |							state->dmaAddrL);#endif			} else {				/* send command data */				i = state->cmdlen;				if (i == 0) {					printf("sii%d: device %d: cmd count exceeded\n",						sc - sii_softc, sc->sc_target);					goto abort;				}				CopyToBuffer((u_short *)state->cmd,					(volatile u_short *)state->dmaAddr[0],					i);				sii_StartDMA(regs, state->dmaCurPhase =					SII_CMD_PHASE, state->dmaAddr[0],					state->dmalen = i);			}			/* wait a short time for XFER complete */			SII_WAIT_UNTIL(dstat, regs->dstat,				dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i);			if (dstat & (SII_CI | SII_DI)) {#ifdef DEBUG				if (sii_debug > 4)					printf("cnt %d\n", i);				else if (sii_debug > 0)					printf("sii_DoIntr: cmd wait ds %x cnt %d\n",						dstat, i);#endif				goto again;			}			break;		case SII_DATA_IN_PHASE:		case SII_DATA_OUT_PHASE:			regs->dmctrl = state->dmaReqAck;			if (state->cmdlen > 0) {				printf("sii%d: device %d: cmd %x: command data not all sent (%d) 1\n",					sc - sii_softc, sc->sc_target,					sc->sc_cmd[sc->sc_target]->cmd[0],					state->cmdlen);				state->cmdlen = 0;#ifdef DEBUG				sii_DumpLog();#endif			}			if (state->dmaPrevPhase >= 0) {				/* restart DMA after disconnect/reconnect */				if (state->dmaPrevPhase !=				    (dstat & SII_PHASE_MSK)) {					printf("sii%d: device %d: dma reselect phase doesn't match\n",						sc - sii_softc, sc->sc_target);					goto abort;				}				state->dmaCurPhase = state->dmaPrevPhase;				state->dmaPrevPhase = -1;				regs->dmaddrl = state->dmaAddrL;				regs->dmaddrh = state->dmaAddrH;				regs->dmlotc = state->dmaCnt;				if (state->dmaCnt & 1)					regs->dmabyte = state->dmaByte;				regs->comm = SII_DMA | SII_INXFER |					(comm & SII_STATE_MSK) |					state->dmaCurPhase;				MachEmptyWriteBuffer();#ifdef DEBUG				if (sii_debug > 4)					printf("Data %d dcnt %d dadr %x ",						state->dmaDataPhase,						state->dmaCnt,						(state->dmaAddrH << 16) |							state->dmaAddrL);#endif				break;			}			if (state->dmaDataPhase != (dstat & SII_PHASE_MSK)) {				printf("sii%d: device %d: cmd %x: dma phase doesn't match\n",					sc - sii_softc, sc->sc_target,					sc->sc_cmd[sc->sc_target]->cmd[0]);				goto abort;			}#ifdef DEBUG			if (sii_debug > 4) {				printf("Data %d ", state->dmaDataPhase);				if (sii_debug > 5)					printf("\n");			}#endif			i = state->buflen;			if (i == 0) {				printf("sii%d: device %d: data count exceeded\n",					sc - sii_softc, sc->sc_target);				goto abort;			}			if (i > SII_MAX_DMA_XFER_LENGTH)				i = SII_MAX_DMA_XFER_LENGTH;			if ((dstat & SII_PHASE_MSK) == SII_DATA_IN_PHASE) {				sii_StartDMA(regs,					state->dmaCurPhase = SII_DATA_IN_PHASE,					state->dmaAddr[state->dmaBufIndex],					state->dmalen = i);				break;			}			/* start first chunk */			if (state->flags & FIRST_DMA) {				state->flags &= ~FIRST_DMA;				CopyToBuffer((u_short *)state->buf,					(volatile u_short *)					state->dmaAddr[state->dmaBufIndex], i);			}			sii_StartDMA(regs,				state->dmaCurPhase = SII_DATA_OUT_PHASE,				state->dmaAddr[state->dmaBufIndex],				state->dmalen = i);			i = state->buflen - SII_MAX_DMA_XFER_LENGTH;			if (i > 0) {				/* prepare for next chunk */				if (i > SII_MAX_DMA_XFER_LENGTH)					i = SII_MAX_DMA_XFER_LENGTH;				CopyToBuffer((u_short *)(state->buf +					SII_MAX_DMA_XFER_LENGTH),					(volatile u_short *)					state->dmaAddr[!state->dmaBufIndex], i);			}			break;		case SII_STATUS_PHASE:			if (state->cmdlen > 0) {				printf("sii%d: device %d: cmd %x: command data not all sent (%d) 2\n",					sc - sii_softc, sc->sc_target,					sc->sc_cmd[sc->sc_target]->cmd[0],					state->cmdlen);				state->cmdlen = 0;#ifdef DEBUG				sii_DumpLog();#endif			}			/* read amount transfered if DMA didn't finish */			if (state->dmalen > 0) {				i = state->dmalen - regs->dmlotc;				state->dmalen = 0;				state->dmaCurPhase = -1;				regs->dmlotc = 0;				regs->comm = comm &					(SII_STATE_MSK | SII_PHASE_MSK);				MachEmptyWriteBuffer();				regs->dstat = SII_DNE;				MachEmptyWriteBuffer();#ifdef DEBUG				if (sii_debug > 4)					printf("DMA amt %d ", i);#endif				switch (comm & SII_PHASE_MSK) {				case SII_DATA_IN_PHASE:					/* copy in the data */					CopyFromBuffer((volatile u_short *)					    state->dmaAddr[state->dmaBufIndex],					    state->buf, i);				case SII_CMD_PHASE:				case SII_DATA_OUT_PHASE:					state->buflen -= i;				}			}			/* read a one byte status message */			state->statusByte = msg =				sii_GetByte(regs, SII_STATUS_PHASE);			if (msg < 0) {				dstat = regs->dstat;				goto again;			}#ifdef DEBUG			if (sii_debug > 4)				printf("Status %x ", msg);			if (sii_logp > sii_log)				sii_logp[-1].msg = msg;			else				sii_log[NLOG - 1].msg = msg;#endif			/* do a quick wait for COMMAND_COMPLETE */			SII_WAIT_UNTIL(dstat, regs->dstat,				dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i);			if (dstat & (SII_CI | SII_DI)) {#ifdef DEBUG				if (sii_debug > 4)					printf("cnt2 %d\n", i);#endif				goto again;			}			break;		case SII_MSG_IN_PHASE:			/*			 * Save DMA state if DMA didn't finish.			 * Be careful not to save state again after reconnect			 * and see RESTORE_POINTER message.			 * Note that the SII DMA address is not incremented			 * as DMA proceeds.			 */			if (state->dmaCurPhase > 0) {				/* save dma registers */				state->dmaPrevPhase = state->dmaCurPhase;				state->dmaCurPhase = -1;				state->dmaCnt = i = regs->dmlotc;				if (dstat & SII_OBB)					state->dmaByte = regs->dmabyte;				if (i == 0)					i = SII_MAX_DMA_XFER_LENGTH;				i = state->dmalen - i;				/* note: no carry from dmaddrl to dmaddrh */				state->dmaAddrL = regs->dmaddrl + i;				state->dmaAddrH = regs->dmaddrh;				regs->comm = comm &					(SII_STATE_MSK | SII_PHASE_MSK);				MachEmptyWriteBuffer();				regs->dstat = SII_DNE;				MachEmptyWriteBuffer();#ifdef DEBUG				if (sii_debug > 4) {					printf("SavP dcnt %d dadr %x ",						state->dmaCnt,						(state->dmaAddrH << 16) |						state->dmaAddrL);					if (((dstat & SII_OBB) != 0) ^					    (state->dmaCnt & 1))						printf("OBB??? ");				} else if (sii_debug > 0) {					if (((dstat & SII_OBB) != 0) ^					    (state->dmaCnt & 1)) {						printf("sii_DoIntr: OBB??? ds %x cnt %d\n",							dstat, state->dmaCnt);						sii_DumpLog();					}				}#endif			}			/* read a one byte message */			msg = sii_GetByte(regs, SII_MSG_IN_PHASE);			if (msg < 0) {				dstat = regs->dstat;				goto again;			}#ifdef DEBUG			if (sii_debug > 4)				printf("MsgIn %x ", msg);			if (sii_logp > sii_log)				sii_logp[-1].msg = msg;			else				sii_log[NLOG - 1].msg = msg;#endif			/* process message */			switch (msg) {			case SCSI_COMMAND_COMPLETE:				msg = sc->sc_target;				sc->sc_target = -1;				/*				 * Wait a short time for disconnect.				 * Don't be fooled if SII_BER happens first.				 * Note: a reselect may happen here.				 */				SII_WAIT_UNTIL(cstat, regs->cstat,					cstat & (SII_RST | SII_SCH),					SII_WAIT_COUNT, i);				if ((cstat & (SII_RST | SII_SCH |				    SII_STATE_MSK)) == SII_SCH) {					regs->cstat = SII_SCH | SII_BER;					regs->comm = 0;					MachEmptyWriteBuffer();					/*					 * Double check that we didn't miss a					 * state change between seeing it and					 * clearing the SII_SCH bit.					 */					i = regs->cstat;					if (!(i & SII_SCH) &&					    (i & SII_STATE_MSK) !=					    (cstat & SII_STATE_MSK))						sii_StateChg(sc, i);				}#ifdef DEBUG				if (sii_debug > 4)					printf("cs %x\n", cstat);#endif				sii_CmdDone(sc, msg, 0);				break;			case SCSI_EXTENDED_MSG:				/* read the message length */				msg = sii_GetByte(regs, SII_MSG_IN_PHASE);				if (msg < 0) {					dstat = regs->dstat;					goto again;				}				if (msg == 0)					msg = 256;				sii_StartDMA(regs, SII_MSG_IN_PHASE,					(u_short *)SII_BUF_ADDR, msg);				/* wait a short time for XFER complete */				SII_WAIT_UNTIL(dstat, regs->dstat,					(dstat & (SII_DNE | SII_TCZ)) ==					(SII_DNE | SII_TCZ),					SII_WAIT_COUNT, i);				if ((dstat & (SII_DNE | SII_TCZ | SII_IPE)) !=				    (SII_DNE | SII_TCZ)) {#ifdef DEBUG					if (sii_debug > 4)						printf("cnt0 %d\n", i);					else if (sii_debug > 0)						printf("sii_DoIntr: emsg in ds %x cnt %d\n",							dstat, i);#endif					printf("sii: ds %x cm %x i %d lotc %d\n",						dstat, comm, i, regs->dmlotc); /* XXX */					sii_DumpLog(); /* XXX */					goto again;				}				/* clear the DNE, other errors handled later */				regs->dstat = SII_DNE;				MachEmptyWriteBuffer();				CopyFromBuffer((volatile u_short *)SII_BUF_ADDR,					sii_buf + 2, msg);				switch (sii_buf[2]) {				case SCSI_MODIFY_DATA_PTR:					i = (sii_buf[3] << 24) |						(sii_buf[4] << 16) |						(sii_buf[5] << 8) |						sii_buf[6];					if (state->dmaPrevPhase >= 0) {						state->dmaAddrL += i;						state->dmaCnt -= i;					}					break;				case SCSI_SYNCHRONOUS_XFER:					sii_DoSync(regs, state);					break;				case SCSI_EXTENDED_IDENTIFY:				case SCSI_WIDE_XFER:				default:				reject:

⌨️ 快捷键说明

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