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

📄 esp.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
	 (bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit))	bp = sa->sa_ra.ra_bp;	if (bp != NULL && strcmp(bp->name, "esp") == 0 && SAME_ESP(bp, sa))		sc->sc_bp = bp + 1;	espdoattach(sc->sc_dev.dv_unit);}/* * `Final' attach of esp occurs once esp and dma chips have been found * and assigned virtual addresses.  Set up the ESP SCSI data structures * and probe the SCSI bus. */static voidespdoattach(unit)	int unit;{	register struct esp_softc *sc;	register struct dma_softc *dc;	register struct bootpath *bp;	register struct targ *t;	register int targ, u;	/* make sure we have both */	if (espcd.cd_ndevs <= unit ||	    dmacd.cd_ndevs <= unit ||	    (sc = espcd.cd_devs[unit]) == NULL ||	    (dc = dmacd.cd_devs[unit]) == NULL)		return;	sc->sc_dc = dc;	sc->sc_dma = dc->dc_dma;	sc->sc_hba.hba_driver = &esphbadriver;	sc->sc_dma->dma_csr = 0;	/* ??? */	espreset(sc, RESET_ESPCHIP);	/* MAYBE THIS SHOULD BE MOVED TO scsi_subr.c? */	for (targ = 0; targ < 8; targ++) {		if (targ == sc->sc_id)			continue;		sc->sc_probing = PROBE_TESTING;		sc->sc_clearing = 1;		(void)scsi_test_unit_ready(&sc->sc_hba, targ, 0);		if (sc->sc_probing != PROBE_NO_TARGET) {			sc->sc_probing = 0;			sc->sc_clearing = 0;			SCSI_FOUNDTARGET(&sc->sc_hba, targ);		}	}	sc->sc_probing = 0;	sc->sc_clearing = 0;	/*	 * See if we booted from a unit on this target.  We could	 * compare bp->name against the unit's name but there's no	 * real need since a target and unit uniquely specify a	 * scsi device.	 */	if ((bp = sc->sc_bp) != NULL && (u_int)(targ = bp->val[0]) < 8 &&	    (u_int)(u = bp->val[1]) < 8 &&	    (t = sc->sc_hba.hba_targets[targ]) != NULL && t->t_units[u] != NULL)		bootdv = t->t_units[u]->u_dev;}/* * We are not allowed to touch the DMA "flush" and "drain" bits * while it is still thinking about a request (DMA_RP). */#define	DMAWAIT(dma)	while ((dma)->dma_csr & DMA_RP) DELAY(1)/* * Reset the DMA chip. */static voiddmareset(sc)	struct esp_softc *sc;{	register volatile struct dmareg *dma = sc->sc_dma;	DMAWAIT(dma);	dma->dma_csr |= DMA_RESET;	DELAY(200);	dma->dma_csr &= ~DMA_RESET;	/* ??? */	sc->sc_state = S_IDLE;	sc->sc_dmaactive = 0;	if (sc->sc_dc->dc_dmarev == DMAREV_2 && sc->sc_esptype != ESP100)		dma->dma_csr |= DMA_TURBO;	dma->dma_csr |= DMA_IE;		/* enable interrupts */	DELAY(200);}/* * Reset the chip and/or SCSI bus (always resets DMA). */static voidespreset(sc, how)	register struct esp_softc *sc;	int how;{	register volatile struct espreg *esp = sc->sc_esp;	dmareset(sc);	if (how & RESET_ESPCHIP) {		esp->esp_cmd = ESPCMD_RESET_CHIP;		esp->esp_cmd = ESPCMD_NOP;		/*		 * Reload configuration registers (cleared by		 * RESET_CHIP command).  Reloading conf2 on an		 * ESP100 goofs it up, so out of paranoia we load		 * only the registers that exist.		 */		esp->esp_conf1 = sc->sc_conf1;		if (sc->sc_esptype > ESP100) {		/* 100A, 2XX */			esp->esp_conf2 = sc->sc_conf2;			if (sc->sc_esptype > ESP100A)	/* 2XX only */				esp->esp_conf3 = sc->sc_conf3;		}		esp->esp_ccf = sc->sc_ccf;		esp->esp_timeout = sc->sc_sel_timeout;		/* We set synch offset later. */	}	if (how & RESET_SCSIBUS) {		/*		 * The chip should retain most of its parameters		 * (including esp_ccf) across this kind of reset		 * (see section 3.5 of Emulex documentation).		 */		/* turn off scsi bus reset interrupts and reset scsi bus */		esp->esp_conf1 = sc->sc_conf1 | ESPCONF1_REPORT;		esp->esp_cmd = ESPCMD_RESET_BUS;		esp->esp_cmd = ESPCMD_NOP;		DELAY(100000);	/* ??? */		(void)esp->esp_intr;		esp->esp_conf1 = sc->sc_conf1;	}	sc->sc_needclear = 0xff;}/* * Reset the SCSI bus and, optionally, all attached targets. */voidesphbareset(hba, resetunits)	struct hba_softc *hba;	int resetunits;{	register struct esp_softc *sc = (struct esp_softc *)hba;	espreset(sc, RESET_SCSIBUS);	if (resetunits)		scsi_reset_units(&sc->sc_hba);}/* * Reset the esp, after an Sbus reset. * Also resets corresponding dma chip. * * THIS ROUTINE MIGHT GO AWAY */voidespsbreset(dev)	struct device *dev;{	struct esp_softc *sc = (struct esp_softc *)dev;	if (sc->sc_dc) {		printf(" %s %s", sc->sc_dc->dc_dev.dv_xname,		    sc->sc_dev.dv_xname);		esphbareset(&sc->sc_hba, 1);	}}/* * Log an error. */static voidesperror(sc, err)	register struct esp_softc *sc;	const char *err;{	int stat;	stat = sc->sc_espstat;	printf("%s target %d cmd 0x%x (%s): %s:\n\\tstat=%b (%s) step=%x dmacsr=%b fflags=%x intr=%b\n",	    sc->sc_dev.dv_xname, sc->sc_targ, sc->sc_curcdb->cdb_bytes[0],	    espstates[sc->sc_state], err,	    stat, ESPSTAT_BITS, espphases[stat & ESPSTAT_PHASE],	    sc->sc_espstep, sc->sc_dmacsr, sc->sc_dc->dc_dmafmt,	    sc->sc_espfflags, sc->sc_espintr, ESPINTR_BITS);}/* * Issue a select, loading command into the FIFO. * Return nonzero on error, 0 if OK. * Sets state to `selecting'; espact() will sequence state FSM. */voidespselect(sc, targ, cdb)	register struct esp_softc *sc;	register int targ;	register struct scsi_cdb *cdb;{	register volatile struct espreg *esp;	register int i, cmdlen;	sc->sc_targ = targ;	sc->sc_state = S_SEL;	sc->sc_curcdb = cdb;	sc->sc_sentcmd = 0;	sc->sc_stat[0] = 0xff;		/* ??? */	sc->sc_msg[0] = 0xff;		/* ??? */	/*	 * Try to talk to target.	 * Synch offset 0 => asynchronous transfer.	 */	esp = sc->sc_esp;	esp->esp_id = targ;	esp->esp_syncoff = 0;	/*	 * Stuff the command bytes into the fifo.	 * Select without attention since we do not do disconnect yet.	 */	cmdlen = SCSICMDLEN(cdb->cdb_bytes[0]);	for (i = 0; i < cmdlen; i++)		esp->esp_fifo = cdb->cdb_bytes[i];	esp->esp_cmd = ESPCMD_SEL_NATN;	/* the rest is done elsewhere */}/* * Sequence through the SCSI state machine.  Return the action to take. * * Most of the work happens here. * * There are three interrupt sources: *   -- ESP interrupt request (typically, some device wants something). *   -- DMA memory error. *   -- DMA byte count has reached 0 (we do not often want this one but *	can only turn it off in rev 2 DMA chips, it seems). *	DOES THIS OCCUR AT ALL HERE?  THERE IS NOTHING TO HANDLE IT! */static intespact(sc)	register struct esp_softc *sc;{	register volatile struct espreg *esp;	register volatile struct dmareg *dma;	register int reg, i, resid, newstate;	register struct scsi_cdb *cdb;	dma = sc->sc_dma;	/* check various error conditions, using as little code as possible */	if (sc->sc_dmacsr & DMA_EP) {		esperror(sc, "DMA error");		DMAWAIT(dma);		dma->dma_csr |= DMA_FLUSH;		return (ACT_ERROR);	}	reg = sc->sc_espstat;	if (reg & ESPSTAT_GE) {		/*		 * This often occurs when there is no target.		 * (See DSC code below.)		 */		if (sc->sc_espintr & ESPINTR_DSC &&		    sc->sc_state == S_SEL && sc->sc_probing) {			sc->sc_probing = PROBE_NO_TARGET;			return (ACT_RESET);		}esperror(sc, "DIAG: gross error (ignored)");	}	if (reg & ESPSTAT_PE) {		esperror(sc, "parity error");		return (ACT_RESET);	}	reg = sc->sc_espintr;#define ERR (ESPINTR_SBR|ESPINTR_ILC|ESPINTR_RSL|ESPINTR_SAT|ESPINTR_SEL)	if (reg & ERR) {		if (reg & ESPINTR_SBR)			esperror(sc, "scsi bus reset");		else if (reg & ESPINTR_ILC)			esperror(sc, "illegal command (driver bug)");		else {			printf("%s: target %d", sc->sc_dev.dv_xname,			    sc->sc_targ);			if (reg & ESPINTR_RSL)				printf(" tried to reselect;");			if (reg & ESPINTR_SAT)				printf(" selected with ATN;");			if (reg & ESPINTR_SEL)				printf(" selected us as target;");			printf("we do not allow this yet\n");		}		return (ACT_ERROR);	}#undef ERR	esp = sc->sc_esp;	/*	 * Disconnect currently only allowed in `final interrupt' states.	 */	if (reg & ESPINTR_DSC) {		if (sc->sc_state == S_FI)			return (ACT_DONE);		/*		 * If we were doing a select just to test the existence		 * of the target, note that it did not respond; otherwise		 * gripe.		 */		if (sc->sc_state == S_SEL) {			if (sc->sc_probing) {				sc->sc_probing = PROBE_NO_TARGET;				return (ACT_RESET);			}		}		/* flush fifo, in case we were selecting or sending data */		esp->esp_cmd = ESPCMD_FLUSH_FIFO;		DELAY(1);		printf("%s: target %d not responding\n",		    sc->sc_dev.dv_xname, sc->sc_targ);		return (ACT_ERROR);	}	/*	 * Okay, things are moving along.	 * What were we doing the last time we did something,	 * and did it complete normally?	 */	switch (sc->sc_state) {	case S_SEL:		/*		 * We were selecting.  Arbitration and select are		 * complete (because ESPINTR_DSC was not set), but		 * there is no guarantee the command went out.		 */		if ((reg & (ESPINTR_SVC|ESPINTR_CMP)) !=		    (ESPINTR_SVC|ESPINTR_CMP)) {			esperror(sc, "selection failed");			return (ACT_RESET);		}		if (sc->sc_espstep == ESPSTEP_DONE) {			sc->sc_sentcmd = 1;			break;		}		if (sc->sc_espstep == 2) {			/*			 * We got something other than command phase.			 * Just pretend things are normal; the			 * device will ask for the command later.			 */esperror(sc, "DIAG: esp step 2");		} else if (sc->sc_espstep == 3) {			/*			 * Device entered command phase and then exited it			 * before we finished handing out the command.			 * Let this happen iff we are trying to clear the			 * target state.			 */esperror(sc, "DIAG: esp step 3");			if (!sc->sc_clearing)				return (ACT_RESET);		} else {			printf("%s: mysterious esp step %d\n",			    sc->sc_dev.dv_xname, sc->sc_espstep);			return (ACT_RESET);		}		/*		 * Part of the command may still be lodged in the FIFO.		 */		if (ESP_NFIFO(sc->sc_espfflags)) {			esp->esp_cmd = ESPCMD_FLUSH_FIFO;			DELAY(1);		}		break;	case S_SVC:		/*		 * We were waiting for phase change after stuffing the command		 * into the FIFO.  Make sure it got out.		 */		if (ESP_NFIFO(sc->sc_espfflags)) {esperror(sc, "DIAG: CMDSVC, fifo not empty");			esp->esp_cmd = ESPCMD_FLUSH_FIFO;			DELAY(1);		} else			sc->sc_sentcmd = 1;		break;	case S_DI:		/*		 * We were doing DMA data in, and expecting a		 * transfer-count-zero interrupt or a phase change.		 * We got that; drain the pack register and handle		 * as for data out -- but ignore FIFO (it should be		 * empty, except for sync mode which we are not		 * using anyway).		 */		DMAWAIT(dma);		dma->dma_csr |= DMA_DRAIN;		DELAY(1);		resid = 0;		goto dma_data_done;	case S_DO:		/*		 * We were doing DMA data out.  If there is data in the		 * FIFO, it is stuff that got DMAed out but never made		 * it to the device, so it counts as residual.		 */		if ((resid = ESP_NFIFO(sc->sc_espfflags)) != 0) {			esp->esp_cmd = ESPCMD_FLUSH_FIFO;			DELAY(1);		}dma_data_done:		if (sc->sc_dmaactive == 0) {			esperror(sc, "dma done w/o dmaactive");			panic("espact");		}		sc->sc_dmaactive = 0;		/* Finish computing residual count. */		reg = esp->esp_tcl | (esp->esp_tch << 8);		if (reg == 0 && (sc->sc_espstat & ESPSTAT_TC) == 0)			reg = 65536;		resid += reg;		/* Compute xfer count (requested - resid). */		i = sc->sc_dmasize - resid;		if (i < 0) {			printf("%s: xfer resid (%d) > xfer req (%d)\n",			    sc->sc_dev.dv_xname, resid, sc->sc_dmasize);			i = sc->sc_dmasize;	/* forgiving... */		}		/* If data came in we must flush cache. */		if (sc->sc_state == S_DI)			cache_flush(sc->sc_dmaaddr, i);

⌨️ 快捷键说明

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