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

📄 esp.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
		sc->sc_dmaaddr += i;		sc->sc_resid -= i;		if ((sc->sc_espintr & ESPINTR_SVC) == 0) {			esperror(sc, "no bus service req");			return (ACT_RESET);		}		break;	case S_STAT:		/*		 * The last thing we did was tell it `initiator complete'		 * and so we expect to have gotten both the status byte		 * and the final message byte.  It is possible that we		 * got something else....		 *		 * Apparently, BUS SERVICE is set if we got just status,		 * while FUNCTION COMPLETE is set if we got both.		 */		if ((reg & (ESPINTR_SVC|ESPINTR_CMP)) != ESPINTR_CMP) {			esperror(sc, "bad status interrupt state");			return (ACT_RESET);		}		reg = ESP_NFIFO(sc->sc_espfflags);		if (reg < 2) {			printf(		"%s: command done but fifo count = %d; must be >= 2\n",			    sc->sc_dev.dv_xname, reg);			return (ACT_RESET);		}		/*		 * Read the status and the first msg byte.		 * It should be CMD_COMPLETE.  Eventually we		 * may handle IDENTIFY, DISCONNECT, etc., as well.		 */		sc->sc_stat[0] = esp->esp_fifo;		sc->sc_msg[0] = reg = esp->esp_fifo;		esp->esp_cmd = ESPCMD_MSG_ACCEPT;		if (reg == MSG_CMD_COMPLETE) {			sc->sc_state = S_FI;			return (ACT_CONT);		}		if (SCSIMSGLEN(reg) != 1) {			printf("%s: target %d is naughty\n",			    sc->sc_dev.dv_xname, sc->sc_targ);			return (ACT_RESET);		}		printf("%s: warning: target %d returned msg 0x%x\n",		    sc->sc_dev.dv_xname, sc->sc_targ, reg);		sc->sc_state = S_FI;		return (ACT_CONT);	case S_MI:		if ((reg & ESPINTR_SVC) == 0) {			esperror(sc, "missing phase after msg in");			return (ACT_RESET);		}		reg = ESP_NFIFO(sc->sc_espfflags);		for (i = 0; i < reg; i++)			sc->sc_msg[i] = esp->esp_fifo;		break;	case S_FI:		esperror(sc, "target did not disconnect");		return (ACT_RESET);	}	/*	 * Things are still moving along.  The phase tells us	 * what the device wants next.  Do it.	 */	switch (sc->sc_espstat & ESPSTAT_PHASE) {	case ESPPHASE_DATA_OUT:if (!sc->sc_sentcmd) esperror(sc, "DIAG: data out without command");		if (sc->sc_dmactl & DMA_READ) {			esperror(sc, "wrong phase (want to read)");			return (ACT_RESET);		}		newstate = S_DO;		goto do_data_xfer;	case ESPPHASE_DATA_IN:if (!sc->sc_sentcmd) esperror(sc, "DIAG: data in without command");		if (!(sc->sc_dmactl & DMA_READ)) {			esperror(sc, "wrong phase (want to write)");			return (ACT_RESET);		}		newstate = S_DI;do_data_xfer:		if (sc->sc_resid == 0) {			esperror(sc, "data count error");			return (ACT_RESET);		}		/*		 * Compute DMA count based on chip limits.		 * Set DMA address and load transfer count into		 * ESP via DMA NOP, then set DMA control, and		 * then we can start the DMA.		 */		sc->sc_state = newstate;		i = min(sc->sc_resid, ESPMAX);		i = min(i, DMAMAX(sc->sc_dmaaddr));		sc->sc_dmasize = i;		dma->dma_addr = sc->sc_dmaaddr;		esp->esp_tch = i >> 8;		esp->esp_tcl = i;		esp->esp_cmd = ESPCMD_DMA | ESPCMD_NOP;		dma->dma_csr = sc->sc_dmactl;		sc->sc_dmaactive = 1;		esp->esp_cmd = ESPCMD_DMA | ESPCMD_XFER_INFO;		return (ACT_IO);	case ESPPHASE_CMD:		/*		 * Silly thing wants the command again.		 * Load it into the FIFO and go to SVC state.		 */printf("%s: redoing command\n", sc->sc_dev.dv_xname);		cdb = sc->sc_curcdb;		reg = SCSICMDLEN(cdb->cdb_bytes[0]);		for (i = 0; i < reg; i++)			esp->esp_fifo = cdb->cdb_bytes[i];		sc->sc_state = S_SVC;		esp->esp_cmd = ESPCMD_XFER_INFO;		return (ACT_CONT);	case ESPPHASE_STATUS:		sc->sc_state = S_STAT;		esp->esp_cmd = ESPCMD_INIT_COMP;		return (ACT_CONT);	case ESPPHASE_MSG_IN:printf("%s: accepting (& ignoring) msg from target %d\n",    sc->sc_dev.dv_xname, sc->sc_targ);		sc->sc_state = S_MI;		esp->esp_cmd = ESPCMD_MSG_ACCEPT;		return (ACT_CONT);	default:		esperror(sc, "bad phase");		return (ACT_RESET);	}	/* NOTREACHED */}/* * Clear out target state by doing a special TEST UNIT READY. * Note that this calls espicmd (possibly recursively). */voidespclear(sc, targ)	register struct esp_softc *sc;	register int targ;{	/* turn off needclear immediately since this calls espicmd() again */	sc->sc_needclear &= ~(1 << targ);	sc->sc_clearing = 1;	(void) scsi_test_unit_ready(&sc->sc_hba, targ, 0);	sc->sc_clearing = 0;}/* * THIS SHOULD BE ADJUSTABLE */	/* name		howlong		purpose */#define	SELECT_WAIT	300000		/* wait for select to complete */#define	CMD_WAIT	100000		/* wait for next phase, generic */#define	DATA_WAIT	100000		/* time to xfer data in/out *//* * Send an `immediate' command, i.e., poll until the whole thing is done. * Return the status byte from the device, or -1 if we timed out.  We use * DMA to transfer the data as the fifo only moves one byte at a time. */intespicmd(hba, targ, cdb, buf, len, rw)	struct hba_softc *hba;	int targ;	struct scsi_cdb *cdb;	caddr_t buf;	int len, rw;{	register struct esp_softc *sc = (struct esp_softc *)hba;	register volatile struct espreg *esp = sc->sc_esp;	register volatile struct dmareg *dma = sc->sc_dma;	register int r, wait;	/*	 * Clear the target if necessary.	 */	if (sc->sc_needclear & (1 << targ) && !sc->sc_probing)		espclear(sc, targ);	/*	 * Set up DMA transfer control (leaving interrupts disabled).	 */	sc->sc_dmactl = rw & B_READ ? DMA_ENA | DMA_READ : DMA_ENA;	sc->sc_dmaaddr = (u_long)buf;	sc->sc_resid = len;	/*	 * Disable hardware interrupts and start select sequence,	 * then loop, calling espact() after each ``interrupt''.	 */	DMAWAIT(dma);		/* ??? */	dma->dma_csr = 0;	espselect(sc, targ, cdb);	wait = SELECT_WAIT;	for (;;) {		r = dma->dma_csr;		if (!DMA_INTR(r)) {			if (--wait < 0) {				esperror(sc, "timeout");				goto reset;			}			DELAY(1);			continue;		}		sc->sc_espstat = esp->esp_stat;		sc->sc_espstep = esp->esp_step & ESPSTEP_MASK;		sc->sc_espintr = esp->esp_intr;		sc->sc_espfflags = esp->esp_fflags;		sc->sc_dmacsr = r;		switch (r = espact(sc)) {		case ACT_CONT:		case ACT_QUICKINTR:			wait = CMD_WAIT;			break;		case ACT_IO:			wait = DATA_WAIT;			break;		case ACT_RESET:			sc->sc_state = S_IDLE;			goto reset;		case ACT_DONE:			sc->sc_state = S_IDLE;			return (sc->sc_stat[0]);		case ACT_ERROR:			sc->sc_state = S_IDLE;			return (-1);		default:			panic("espicmd action");		}	}reset:	espreset(sc, RESET_ESPCHIP);		/* ??? */	return (-1);}/* * Dump (write memory, possibly physmem). * SPARC higher-level dump code always provides virtual addresses, * so we need not do any I/O mapping here. */intespdump(hba, targ, cdb, buf, len)	register struct hba_softc *hba;	int targ;	struct scsi_cdb *cdb;	caddr_t buf;	register int len;{	return (espicmd(hba, targ, cdb, buf, len, B_WRITE));}/* * Allocate resources (SCSI bus and DVMA space) for the given transfer. * Must be called at splbio(). * * THIS SHOULD RETURN SUCCESS/FAIL INDICATION */voidespstart(self, sq, bp, dgo, dev)	struct device *self;	register struct sq *sq;	struct buf *bp;	scdgo_fn dgo;	struct device *dev;{	register struct esp_softc *sc = (struct esp_softc *)self;	if (sc->sc_hba.hba_busy == 0) {		/*		 * Bus not busy, nothing to do here, just tell		 * this target or unit that it has the SCSI bus.		 */		sc->sc_hba.hba_busy = 1;		(*dgo)(dev, &sc->sc_cdbspace);	} else {		/*		 * Bus is busy; just enqueue.		 */		sq->sq_dgo = dgo;		sq->sq_dev = dev;		sq->sq_forw = NULL;		if (sc->sc_hba.hba_head == NULL)			sc->sc_hba.hba_head = sq;		else			sc->sc_hba.hba_tail->sq_forw = sq;		sc->sc_hba.hba_tail = sq;	}}/* * Start buffered I/O. * Return 0 on success, 1 on failure. */intespgo(self, targ, intr, dev, bp, pad)	struct device *self;	int targ;	scintr_fn intr;	struct device *dev;	register struct buf *bp;	int pad;{	register struct esp_softc *sc = (struct esp_softc *)self;	if (sc->sc_needclear & (1 << targ))		espclear(sc, targ);	/* Set up dma control for espact(). */	sc->sc_dmactl = bp->b_flags & B_READ ?	    DMA_ENA | DMA_READ | DMA_IE : DMA_ENA | DMA_IE;	sc->sc_dmaaddr = (u_long)bp->b_un.b_addr;	sc->sc_resid = bp->b_bcount;	/*	 * Enable interrupts and start selection.	 * The rest is done in espintr() and espact().	 */	sc->sc_hba.hba_intr = intr;	/* remember dev done function */	sc->sc_hba.hba_intrdev = dev;	/* and its first arg */	sc->sc_dma->dma_csr = DMA_IE;	espselect(sc, targ, &sc->sc_cdbspace);	return (0);}/* * Handle interrupt.  Return 1 if taken. */intespintr(sc0)	void *sc0;{	register struct esp_softc *sc = (struct esp_softc *)sc0;	register volatile struct espreg *esp = sc->sc_esp;	register volatile struct dmareg *dma = sc->sc_dma;	register int r, wait;	register struct sq *sq;	r = dma->dma_csr;	if (!DMA_INTR(r))		return (0);		/* not ours */	sc->sc_intrcnt.ev_count++;again:	sc->sc_espstat = esp->esp_stat;	sc->sc_espstep = esp->esp_step & ESPSTEP_MASK;	sc->sc_espintr = esp->esp_intr;	sc->sc_espfflags = esp->esp_fflags;	sc->sc_dmacsr = r;	if (sc->sc_state == S_IDLE) {		printf("%s: stray interrupt\n", sc->sc_dev.dv_xname);		dma->dma_csr &= ~DMA_IE;	/* ??? */		return (1);	}	switch (r = espact(sc)) {	case ACT_CONT:		/* just return */	case ACT_IO:		break;	case ACT_RESET:		/* please reset esp */reset:		espreset(sc, RESET_ESPCHIP);	/* ??? */		/* FALLTHROUGH */	case ACT_DONE:		/* this one is done, successfully */	case ACT_ERROR:		/* this one is done due to `severe' error */		sc->sc_state = S_IDLE;		if (!sc->sc_hba.hba_busy)			panic("espintr sq");		/*		 * This transaction is done.		 * Call the driver's intr routine,		 * then start the next guy if any.		 */		(*sc->sc_hba.hba_intr)(sc->sc_hba.hba_intrdev,		    r == ACT_DONE ? sc->sc_stat[0] : -1, sc->sc_resid);		if ((sq = sc->sc_hba.hba_head) != NULL) {			sc->sc_hba.hba_head = sq->sq_forw;			(*sq->sq_dgo)(sq->sq_dev, &sc->sc_cdbspace);		} else			sc->sc_hba.hba_busy = 0;		break;	case ACT_QUICKINTR:	/* wait a short while for another interrupt */printf("%s: quickintr: ", sc->sc_dev.dv_xname);		wait = 100;		do {			r = dma->dma_csr;			if (DMA_INTR(r)) {printf("got one, wait=%d\n", wait);				goto again;			}		} while (--wait > 0);printf("did not get one\n");		break;	default:		panic("espintr action");	}	return (1);}/* * Target or unit decided to let go of the bus early. */voidesprel(self)	struct device *self;{	register struct esp_softc *sc = (struct esp_softc *)self;	register struct sq *sq;	/* if there is someone else waiting, give them a crack at it */	if ((sq = sc->sc_hba.hba_head) != NULL)		(*sq->sq_dgo)(sq->sq_dev, &sc->sc_cdbspace);	else		sc->sc_hba.hba_busy = 0;}

⌨️ 快捷键说明

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