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

📄 sii.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
					/* send a reject message */					regs->data = SCSI_MESSAGE_REJECT;					regs->comm = SII_INXFER | SII_ATN |						(regs->cstat & SII_STATE_MSK) |						SII_MSG_OUT_PHASE;					MachEmptyWriteBuffer();					/* wait for XFER complete */					SII_WAIT_UNTIL(dstat, regs->dstat,						(dstat &						(SII_DNE | SII_PHASE_MSK)) ==						(SII_DNE | SII_MSG_OUT_PHASE),						SII_WAIT_COUNT, i);					if ((dstat &					    (SII_DNE | SII_PHASE_MSK)) !=					    (SII_DNE | SII_MSG_OUT_PHASE))						break;					regs->dstat = SII_DNE;					MachEmptyWriteBuffer();				}				break;			case SCSI_SAVE_DATA_POINTER:			case SCSI_RESTORE_POINTERS:				/* wait a short time for another msg */				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);#endif					goto again;				}				break;			case SCSI_DISCONNECT:				state->prevComm = comm;#ifdef DEBUG				if (sii_debug > 4)					printf("disconn %d ", sc->sc_target);#endif				/*				 * 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) {#ifdef DEBUG					if (sii_debug > 4)						printf("cnt %d\n", i);#endif					dstat = regs->dstat;					goto again;				}				regs->cstat = SII_SCH | SII_BER;				regs->comm = 0;				MachEmptyWriteBuffer();				sc->sc_target = -1;				/*				 * 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);				break;			case SCSI_MESSAGE_REJECT:				printf("sii%d: device %d: message reject.\n",					sc - sii_softc, sc->sc_target);				goto abort;			default:				if (!(msg & SCSI_IDENTIFY)) {					printf("sii%d: device %d: couldn't handle message 0x%x... ignoring.\n",						sc - sii_softc, sc->sc_target,						msg);#ifdef DEBUG					sii_DumpLog();#endif					break;				}				/* may want to check LUN some day */				/* wait a short time for another msg */				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);#endif					goto again;				}			}			break;		case SII_MSG_OUT_PHASE:#ifdef DEBUG			if (sii_debug > 4)				printf("MsgOut\n");#endif			regs->data = SCSI_NO_OP;			regs->comm = SII_INXFER | (comm & SII_STATE_MSK) |				SII_MSG_OUT_PHASE;			MachEmptyWriteBuffer();			/* wait a short time for XFER complete */			SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE,				SII_WAIT_COUNT, i);#ifdef DEBUG			if (sii_debug > 4)				printf("ds %x i %d\n", dstat, i);#endif			/* just clear the DNE bit and check errors later */			if (dstat & SII_DNE) {				regs->dstat = SII_DNE;				MachEmptyWriteBuffer();			}			break;		default:			printf("sii%d: Couldn't handle phase %d... ignoring.\n",				   sc - sii_softc, dstat & SII_PHASE_MSK);		}	}#ifdef DEBUG	if (sii_debug > 3)		printf("\n");#endif	/*	 * Check to make sure we won't be interrupted again.	 * Deglitch dstat register.	 */	msg = regs->dstat;	while (msg != (dstat = regs->dstat))		msg = dstat;	if (dstat & (SII_CI | SII_DI))		goto again;	if (sc->sc_target < 0) {		/* look for another device that is ready */		for (i = 0; i < SII_NCMD; i++) {			/* don't restart a disconnected command */			if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm)				continue;			sii_StartCmd(sc, i);			break;		}	}	return;abort:	/* jump here to abort the current command */	printf("sii%d: device %d: current command terminated\n",		sc - sii_softc, sc->sc_target);#ifdef DEBUG	sii_DumpLog();#endif	if ((cstat = regs->cstat) & SII_CON) {		/* try to send an abort msg for awhile */		regs->dstat = SII_DNE;		regs->data = SCSI_ABORT;		regs->comm = SII_INXFER | SII_ATN | (cstat & SII_STATE_MSK) |			SII_MSG_OUT_PHASE;		MachEmptyWriteBuffer();		SII_WAIT_UNTIL(dstat, regs->dstat,			(dstat & (SII_DNE | SII_PHASE_MSK)) ==			(SII_DNE | SII_MSG_OUT_PHASE),			2 * SII_WAIT_COUNT, i);#ifdef DEBUG		if (sii_debug > 0)			printf("Abort: cs %x ds %x i %d\n", cstat, dstat, i);#endif		if (dstat & (SII_DNE | SII_PHASE_MSK) ==		    (SII_DNE | SII_MSG_OUT_PHASE)) {			/* disconnect if command in progress */			regs->comm = SII_DISCON;			MachEmptyWriteBuffer();			SII_WAIT_UNTIL(cstat, regs->cstat,				!(cstat & SII_CON), SII_WAIT_COUNT, i);		}	} else {#ifdef DEBUG		if (sii_debug > 0)			printf("Abort: cs %x\n", cstat);#endif	}	regs->cstat = 0xffff;	regs->dstat = 0xffff;	regs->comm = 0;	MachEmptyWriteBuffer();	i = sc->sc_target;	sc->sc_target = -1;	sii_CmdDone(sc, i, EIO);#ifdef DEBUG	if (sii_debug > 4)		printf("sii_DoIntr: after CmdDone target %d\n", sc->sc_target);#endif}static voidsii_StateChg(sc, cstat)	register struct siisoftc *sc;	register unsigned cstat;{	register SIIRegs *regs = sc->sc_regs;	register State *state;	register int i;#ifdef DEBUG	if (sii_debug > 4)		printf("SCH: ");#endif	switch (cstat & SII_STATE_MSK) {	case 0:		/* disconnect */		i = sc->sc_target;		sc->sc_target = -1;#ifdef DEBUG		if (sii_debug > 4)			printf("disconn %d ", i);#endif		if (i >= 0 && !sc->sc_st[i].prevComm) {			printf("sii%d: device %d: spurrious disconnect (%d)\n",				sc - sii_softc, i, regs->slcsr);			sc->sc_st[i].prevComm = 0;		}		break;	case SII_CON:		/* connected as initiator */		i = regs->slcsr;		if (sc->sc_target == i)			break;		printf("sii%d: device %d: connect to device %d??\n",			sc - sii_softc, sc->sc_target, i);		sc->sc_target = i;		break;	case SII_DST:		/*		 * Wait for CON to become valid,		 * chip is slow sometimes.		 */		SII_WAIT_UNTIL(cstat, regs->cstat,			cstat & SII_CON, SII_WAIT_COUNT, i);		if (!(cstat & SII_CON))			panic("sii resel");		/* FALLTHROUGH */	case SII_CON | SII_DST:		/*		 * Its a reselection. Save the ID and wait for		 * interrupts to tell us what to do next		 * (should be MSG_IN of IDENTIFY).		 * NOTE: sc_target may be >= 0 if we were in		 * the process of trying to start a command		 * and were reselected before the select		 * command finished.		 */		sc->sc_target = i = regs->destat;		regs->comm = SII_CON | SII_DST | SII_MSG_IN_PHASE;		MachEmptyWriteBuffer();		state = &sc->sc_st[i];		if (!state->prevComm) {			printf("sii%d: device %d: spurrious reselection\n",				sc - sii_softc, i);			break;		}		state->prevComm = 0;#ifdef DEBUG		if (sii_debug > 4)			printf("resel %d ", sc->sc_target);#endif		break;#ifdef notyet	case SII_DST | SII_TGT:	case SII_CON | SII_DST | SII_TGT:		/* connected as target */		printf("sii%d: Selected by device %d as target!!\n",			sc - sii_softc, regs->destat);		regs->comm = SII_DISCON;		MachEmptyWriteBuffer();		SII_WAIT_UNTIL(!(regs->cstat & SII_CON),			SII_WAIT_COUNT, i);		regs->cstat = 0xffff;		regs->dstat = 0xffff;		regs->comm = 0;		break;#endif	default:		printf("sii%d: Unknown state change (cs %x)!!\n",			sc - sii_softc, cstat);#ifdef DEBUG		sii_DumpLog();#endif	}}/* * Read one byte of data. */static intsii_GetByte(regs, phase)	register SIIRegs *regs;	int phase;{	register unsigned dstat;	register unsigned state;#ifdef PROGXFER	register unsigned data;	dstat = regs->dstat;	state = regs->cstat & SII_STATE_MSK;	regs->dmctrl = 0;	if (!(dstat & SII_IBF) || (dstat & SII_MIS)) {		regs->comm = state | phase;		MachEmptyWriteBuffer();		/* wait a short time for IBF */		SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_IBF,			SII_WAIT_COUNT, i);#ifdef DEBUG		if (!(dstat & SII_IBF))			printf("status no IBF\n");#endif	}	data = regs->data;	if (regs->dstat & SII_DNE) { /* XXX */		printf("sii_GetByte: DNE set 5\n");		sii_DumpLog();		regs->dstat = SII_DNE;	}	regs->comm = SII_INXFER | state | phase;	MachEmptyWriteBuffer();	/* wait a short time for XFER complete */	SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE,		SII_WAIT_COUNT, i);	if ((dstat & (SII_DNE | SII_IPE)) != SII_DNE) {#ifdef DEBUG		if (sii_debug > 4)			printf("cnt0 %d\n", i);#endif		printf("MsgIn %x ?? ds %x cm %x i %d\n",			data, dstat, comm, i); /* XXX */		sii_DumpLog(); /* XXX */		panic("status"); /* XXX */		goto again;	}	/* clear the DNE, other errors handled later */	regs->dstat = SII_DNE;	MachEmptyWriteBuffer();	return (data);#else /* PROGXFER */	register int i;	state = regs->cstat & SII_STATE_MSK;	regs->dmctrl = 0;	if (regs->dstat & SII_DNE) {		printf("sii_GetByte: DNE cs %x ds %x cm %x\n",			regs->cstat, regs->dstat, regs->comm); /* XXX */		regs->dstat = SII_DNE;	}	regs->dmaddrl = ((u_short)SII_BUF_ADDR >> 1);	regs->dmaddrh = ((u_short)SII_BUF_ADDR >> 17) & 03;	regs->dmlotc = 1;	regs->comm = SII_DMA | SII_INXFER | state | phase;	MachEmptyWriteBuffer();	/* 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)) {		printf("sii_GetByte: cs %x ds %x cm %x i %d lotc %d\n",			regs->cstat, dstat, regs->comm, i,			regs->dmlotc); /* XXX */		sii_DumpLog(); /* XXX */		return (-1);	}	/* clear the DNE, other errors handled later */	regs->dstat = SII_DNE;	MachEmptyWriteBuffer();	/* return one byte of data (optimized CopyFromBuffer()) */	return (*(volatile u_short *)SII_BUF_ADDR & 0xFF);#endif /* PROGXFER */}/* * Exchange messages to initiate synchronous data transfers. */static voidsii_DoSync(regs, state)	register SIIRegs *regs;	register State *state;{	register unsigned dstat;	register int i;	unsigned len;	printf("sii_DoSync: per %d req/ack %d\n",		sii_buf[3], sii_buf[4]); /* XXX */	len = sii_buf[4];	if (len > 3)		len = 3;	/* SII chip can only handle 3 max */	sii_buf[0] = SCSI_EXTENDED_MSG;	sii_buf[1] = 3;		/* message length */	sii_buf[2] = SCSI_SYNCHRONOUS_XFER;	sii_buf[4] = len;	CopyToBuffer((u_short *)sii_buf, (volatile u_short *)SII_BUF_ADDR, 5);	regs->dmaddrl = ((u_short)SII_BUF_ADDR >> 1);	regs->dmaddrh = ((u_short)SII_BUF_ADDR >> 17) & 03;	regs->dmlotc = 5;	regs->comm = SII_DMA | SII_INXFER | SII_ATN |		(regs->cstat & SII_STATE_MSK) | SII_MSG_OUT_PHASE;	MachEmptyWriteBuffer();	/* 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_DNE | SII_TCZ)) {		printf("sii_DoSync: ds %x cm %x i %d lotc %d\n",			dstat, regs->comm, i, regs->dmlotc); /* XXX */		sii_DumpLog(); /* XXX */		return;	}	/* clear the DNE, other errors handled later */	regs->dstat = SII_DNE;	regs->comm = regs->comm & SII_STATE_MSK;	MachEmptyWriteBuffer();	state->dmaReqAck = len;}/* * Issue the sequence of commands to the controller to start DMA. * NOTE: the data buffer should be word-aligned for DMA out. */static voidsii_StartDMA(regs, phase, dmaAddr, size)	register SIIRegs *regs;	/* which SII to use */	int phase;		/* phase to send/receive data */	u_short *dmaAddr;	/* DMA buffer address */	int size;		/* # of bytes to transfer */{	if (regs->dstat & SII_DNE) { /* XXX */		printf("sii_StartDMA: DNE set\n");		sii_DumpLog();		regs->dstat = SII_DNE;	}	regs->dmaddrl = ((unsigned)dmaAddr >> 1);	regs->dmaddrh = ((unsigned)dmaAddr >> 17) & 03;	regs->dmlotc = size;	regs->comm = SII_DMA | SII_INXFER | (regs->cstat & SII_STATE_MSK) |		phase;	MachEmptyWriteBuffer();#ifdef DEBUG	if (sii_debug > 5) {		printf("sii_StartDMA: cs 0x%x, ds 0x%x, cm 0x%x, size %d\n", 			regs->cstat, regs->dstat, regs->comm, size);	}#endif}/* * Call the device driver's 'done' routine to let it know the command is done. * The 'done' routine may try to start another command. * To be fair, we should start pending commands for other devices * before allowing the same device to start another command. */static voidsii_CmdDone(sc, target, error)	register struct siisoftc *sc;	/* which SII to use */	int target;			/* which device is done */	int error;			/* error code if any errors */{	register ScsiCmd *scsicmd;	register int i;	scsicmd = sc->sc_cmd[target];#ifdef DIAGNOSTIC	if (target < 0 || !scsicmd)		panic("sii_CmdDone");#endif	sc->sc_cmd[target] = (ScsiCmd *)0;#ifdef DEBUG	if (sii_debug > 1) {		printf("sii_CmdDone: %s target %d cmd %x err %d resid %d\n",			scsicmd->sd->sd_driver->d_name, target,			scsicmd->cmd[0], error, sc->sc_st[target].buflen);	}#endif	/* look for another device that is ready */	for (i = 0; i < SII_NCMD; i++) {		/* don't restart a disconnected command */		if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm)			continue;		sii_StartCmd(sc, i);		break;	}	(*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, error,		sc->sc_st[target].buflen, sc->sc_st[target].statusByte);}#ifdef DEBUGsii_DumpLog(){	register struct sii_log *lp;	printf("sii: cmd %x bn %d cnt %d\n", sii_debug_cmd, sii_debug_bn,		sii_debug_sz);	lp = sii_logp;	do {		printf("target %d cs %x ds %x cm %x msg %x\n",			lp->target, lp->cstat, lp->dstat, lp->comm, lp->msg);		if (++lp >= &sii_log[NLOG])			lp = sii_log;	} while (lp != sii_logp);}#endif#endif

⌨️ 快捷键说明

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