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

📄 uda.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
 * This routine is broken into two so that the internal version * udastrat1() can be called by the (nonexistent, as yet) bad block * revectoring routine. */udastrategy(bp)	register struct buf *bp;{	register int unit;	register struct uba_device *ui;	register struct ra_info *ra;	struct partition *pp;	int p;	daddr_t sz, maxsz;	/*	 * Make sure this is a reasonable drive to use.	 */	if ((unit = udaunit(bp->b_dev)) >= NRA ||	    (ui = udadinfo[unit]) == NULL || ui->ui_alive == 0 ||	    (ra = &ra_info[unit])->ra_state == CLOSED) {		bp->b_error = ENXIO;		goto bad;	}	/*	 * If drive is open `raw' or reading label, let it at it.	 */	if (ra->ra_state < OPEN) {		udastrat1(bp);		return;	}	p = udapart(bp->b_dev);	if ((ra->ra_openpart & (1 << p)) == 0) {		bp->b_error = ENODEV;		goto bad;	}	/*	 * Determine the size of the transfer, and make sure it is	 * within the boundaries of the partition.	 */	pp = &udalabel[unit].d_partitions[p];	maxsz = pp->p_size;	if (pp->p_offset + pp->p_size > ra->ra_dsize)		maxsz = ra->ra_dsize - pp->p_offset;	sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;	if (bp->b_blkno + pp->p_offset <= LABELSECTOR &&#if LABELSECTOR != 0	    bp->b_blkno + pp->p_offset + sz > LABELSECTOR &&#endif	    (bp->b_flags & B_READ) == 0 && ra->ra_wlabel == 0) {		bp->b_error = EROFS;		goto bad;	}	if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {		/* if exactly at end of disk, return an EOF */		if (bp->b_blkno == maxsz) {			bp->b_resid = bp->b_bcount;			biodone(bp);			return;		}		/* or truncate if part of it fits */		sz = maxsz - bp->b_blkno;		if (sz <= 0) {			bp->b_error = EINVAL;	/* or hang it up */			goto bad;		}		bp->b_bcount = sz << DEV_BSHIFT;	}	udastrat1(bp);	return;bad:	bp->b_flags |= B_ERROR;	biodone(bp);}/* * Work routine for udastrategy. */udastrat1(bp)	register struct buf *bp;{	register int unit = udaunit(bp->b_dev);	register struct uba_ctlr *um;	register struct buf *dp;	struct uba_device *ui;	int s = spl5();	/*	 * Append the buffer to the drive queue, and if it is not	 * already there, the drive to the controller queue.  (However,	 * if the drive queue is marked to be requeued, we must be	 * awaiting an on line or get unit status command; in this	 * case, leave it off the controller queue.)	 */	um = (ui = udadinfo[unit])->ui_mi;	dp = &udautab[unit];	APPEND(bp, dp, av_forw);	if (dp->b_active == 0 && (ui->ui_flags & UNIT_REQUEUE) == 0) {		APPEND(dp, &um->um_tab, b_forw);		dp->b_active++;	}	/*	 * Start activity on the controller.  Note that unlike other	 * Unibus drivers, we must always do this, not just when the	 * controller is not active.	 */	udastart(um);	splx(s);}/* * Start up whatever transfers we can find. * Note that udastart() must be called at spl5(). */udastart(um)	register struct uba_ctlr *um;{	register struct uda_softc *sc = &uda_softc[um->um_ctlr];	register struct buf *bp, *dp;	register struct mscp *mp;	struct uba_device *ui;	struct udadevice *udaddr;	struct partition *pp;	int i, sz;#ifdef lint	i = 0; i = i;#endif	/*	 * If it is not running, try (again and again...) to initialise	 * it.  If it is currently initialising just ignore it for now.	 */	if (sc->sc_state != ST_RUN) {		if (sc->sc_state == ST_IDLE && udainit(um->um_ctlr))			printf("uda%d: still hung\n", um->um_ctlr);		return;	}	/*	 * If um_cmd is nonzero, this controller is on the Unibus	 * resource wait queue.  It will not help to try more requests;	 * instead, when the Unibus unblocks and calls udadgo(), we	 * will call udastart() again.	 */	if (um->um_cmd)		return;	sc->sc_flags |= SC_INSTART;	udaddr = (struct udadevice *) um->um_addr;loop:	/*	 * Service the drive at the head of the queue.  It may not	 * need anything, in which case it might be shutting down	 * in udaclose().	 */	if ((dp = um->um_tab.b_actf) == NULL)		goto out;	if ((bp = dp->b_actf) == NULL) {		dp->b_active = 0;		um->um_tab.b_actf = dp->b_forw;		if (ra_info[dp - udautab].ra_openpart == 0)			wakeup((caddr_t)dp); /* finish close protocol */		goto loop;	}	if (udaddr->udasa & UDA_ERR) {	/* ctlr fatal error */		udasaerror(um, 1);		goto out;	}	/*	 * Get an MSCP packet, then figure out what to do.  If	 * we cannot get a command packet, the command ring may	 * be too small:  We should have at least as many command	 * packets as credits, for best performance.	 */	if ((mp = mscp_getcp(&sc->sc_mi, MSCP_DONTWAIT)) == NULL) {		if (sc->sc_mi.mi_credits > MSCP_MINCREDITS &&		    (sc->sc_flags & SC_GRIPED) == 0) {			log(LOG_NOTICE, "uda%d: command ring too small\n",				um->um_ctlr);			sc->sc_flags |= SC_GRIPED;/* complain only once */		}		goto out;	}	/*	 * Bring the drive on line if it is not already.  Get its status	 * if we do not already have it.  Otherwise just start the transfer.	 */	ui = udadinfo[udaunit(bp->b_dev)];	if ((ui->ui_flags & UNIT_ONLINE) == 0) {		mp->mscp_opcode = M_OP_ONLINE;		goto common;	}	if ((ui->ui_flags & UNIT_HAVESTATUS) == 0) {		mp->mscp_opcode = M_OP_GETUNITST;common:if (ui->ui_flags & UNIT_REQUEUE) panic("udastart");		/*		 * Take the drive off the controller queue.  When the		 * command finishes, make sure the drive is requeued.		 */		um->um_tab.b_actf = dp->b_forw;		dp->b_active = 0;		ui->ui_flags |= UNIT_REQUEUE;		mp->mscp_unit = ui->ui_slave;		*mp->mscp_addr |= MSCP_OWN | MSCP_INT;		sc->sc_flags |= SC_STARTPOLL;#ifdef POLLSTATS		sc->sc_ncmd++;#endif		goto loop;	}	pp = &udalabel[ui->ui_unit].d_partitions[udapart(bp->b_dev)];	mp->mscp_opcode = (bp->b_flags & B_READ) ? M_OP_READ : M_OP_WRITE;	mp->mscp_unit = ui->ui_slave;	mp->mscp_seq.seq_lbn = bp->b_blkno + pp->p_offset;	sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;	mp->mscp_seq.seq_bytecount = bp->b_blkno + sz > pp->p_size ?		(pp->p_size - bp->b_blkno) >> DEV_BSHIFT : bp->b_bcount;	/* mscp_cmdref is filled in by mscp_go() */	/*	 * Drop the packet pointer into the `command' field so udadgo()	 * can tell what to start.  If ubago returns 1, we can do another	 * transfer.  If not, um_cmd will still point at mp, so we will	 * know that we are waiting for resources.	 */	um->um_cmd = (int)mp;	if (ubago(ui))		goto loop;	/*	 * All done, or blocked in ubago().  If we managed to	 * issue some commands, start up the beast.	 */out:	if (sc->sc_flags & SC_STARTPOLL) {#ifdef POLLSTATS		udastats.cmd[sc->sc_ncmd]++;		sc->sc_ncmd = 0;#endif		i = ((struct udadevice *)um->um_addr)->udaip;	}	sc->sc_flags &= ~(SC_INSTART | SC_STARTPOLL);}/* * Start a transfer. * * If we are not called from within udastart(), we must have been * blocked, so call udastart to do more requests (if any).  If * this calls us again immediately we will not recurse, because * that time we will be in udastart().  Clever.... */udadgo(um)	register struct uba_ctlr *um;{	struct uda_softc *sc = &uda_softc[um->um_ctlr];	struct mscp *mp = (struct mscp *)um->um_cmd;	um->um_tab.b_active++;	/* another transfer going */	/*	 * Fill in the MSCP packet and move the buffer to the	 * I/O wait queue.  Mark the controller as no longer on	 * the resource queue, and remember to initiate polling.	 */	mp->mscp_seq.seq_buffer = UBAI_ADDR(um->um_ubinfo) |		(UBAI_BDP(um->um_ubinfo) << 24);	mscp_go(&sc->sc_mi, mp, um->um_ubinfo);	um->um_cmd = 0;		um->um_ubinfo = 0;	/* tyke it awye */	sc->sc_flags |= SC_STARTPOLL;#ifdef POLLSTATS	sc->sc_ncmd++;#endif	if ((sc->sc_flags & SC_INSTART) == 0)		udastart(um);}udaiodone(mi, bp, info)	register struct mscp_info *mi;	struct buf *bp;	int info;{	register struct uba_ctlr *um = udaminfo[mi->mi_ctlr];	um->um_ubinfo = info;	ubadone(um);	biodone(bp);	if (um->um_bdp && mi->mi_wtab.av_forw == &mi->mi_wtab)		ubarelse(um->um_ubanum, &um->um_bdp);	um->um_tab.b_active--;	/* another transfer done */}static struct saerr {	int	code;		/* error code (including UDA_ERR) */	char	*desc;		/* what it means: Efoo => foo error */} saerr[] = {	{ 0100001, "Eunibus packet read" },	{ 0100002, "Eunibus packet write" },	{ 0100003, "EUDA ROM and RAM parity" },	{ 0100004, "EUDA RAM parity" },	{ 0100005, "EUDA ROM parity" },	{ 0100006, "Eunibus ring read" },	{ 0100007, "Eunibus ring write" },	{ 0100010, " unibus interrupt master failure" },	{ 0100011, "Ehost access timeout" },	{ 0100012, " host exceeded command limit" },	{ 0100013, " unibus bus master failure" },	{ 0100014, " DM XFC fatal error" },	{ 0100015, " hardware timeout of instruction loop" },	{ 0100016, " invalid virtual circuit id" },	{ 0100017, "Eunibus interrupt write" },	{ 0104000, "Efatal sequence" },	{ 0104040, " D proc ALU" },	{ 0104041, "ED proc control ROM parity" },	{ 0105102, "ED proc w/no BD#2 or RAM parity" },	{ 0105105, "ED proc RAM buffer" },	{ 0105152, "ED proc SDI" },	{ 0105153, "ED proc write mode wrap serdes" },	{ 0105154, "ED proc read mode serdes, RSGEN & ECC" },	{ 0106040, "EU proc ALU" },	{ 0106041, "EU proc control reg" },	{ 0106042, " U proc DFAIL/cntl ROM parity/BD #1 test CNT" },	{ 0106047, " U proc const PROM err w/D proc running SDI test" },	{ 0106055, " unexpected trap" },	{ 0106071, "EU proc const PROM" },	{ 0106072, "EU proc control ROM parity" },	{ 0106200, "Estep 1 data" },	{ 0107103, "EU proc RAM parity" },	{ 0107107, "EU proc RAM buffer" },	{ 0107115, " test count wrong (BD 12)" },	{ 0112300, "Estep 2" },	{ 0122240, "ENPR" },	{ 0122300, "Estep 3" },	{ 0142300, "Estep 4" },	{ 0, " unknown error code" }};/* * If the error bit was set in the controller status register, gripe, * then (optionally) reset the controller and requeue pending transfers. */udasaerror(um, doreset)	register struct uba_ctlr *um;	int doreset;{	register int code = ((struct udadevice *)um->um_addr)->udasa;	register struct saerr *e;	if ((code & UDA_ERR) == 0)		return;	for (e = saerr; e->code; e++)		if (e->code == code)			break;	printf("uda%d: controller error, sa=0%o (%s%s)\n",		um->um_ctlr, code, e->desc + 1,		*e->desc == 'E' ? " error" : "");	if (doreset) {		mscp_requeue(&uda_softc[um->um_ctlr].sc_mi);		(void) udainit(um->um_ctlr);	}}/* * Interrupt routine.  Depending on the state of the controller, * continue initialisation, or acknowledge command and response * interrupts, and process responses. */udaintr(ctlr)	int ctlr;{	register struct uba_ctlr *um = udaminfo[ctlr];	register struct uda_softc *sc = &uda_softc[ctlr];	register struct udadevice *udaddr = (struct udadevice *)um->um_addr;	register struct uda *ud;	register struct mscp *mp;	register int i;#ifdef QBA	splx(sc->sc_ipl);	/* Qbus interrupt protocol is odd */#endif	sc->sc_wticks = 0;	/* reset interrupt watchdog */	/*	 * Combinations during steps 1, 2, and 3: STEPnMASK	 * corresponds to which bits should be tested;	 * STEPnGOOD corresponds to the pattern that should	 * appear after the interrupt from STEPn initialisation.	 * All steps test the bits in ALLSTEPS.	 */#define	ALLSTEPS	(UDA_ERR|UDA_STEP4|UDA_STEP3|UDA_STEP2|UDA_STEP1)#define	STEP1MASK	(ALLSTEPS | UDA_IE | UDA_NCNRMASK)#define	STEP1GOOD	(UDA_STEP2 | UDA_IE | (NCMDL2 << 3) | NRSPL2)#define	STEP2MASK	(ALLSTEPS | UDA_IE | UDA_IVECMASK)#define	STEP2GOOD	(UDA_STEP3 | UDA_IE | (sc->sc_ivec >> 2))#define	STEP3MASK	ALLSTEPS#define	STEP3GOOD	UDA_STEP4	switch (sc->sc_state) {	case ST_IDLE:		/*		 * Ignore unsolicited interrupts.		 */		log(LOG_WARNING, "uda%d: stray intr\n", ctlr);		return;	case ST_STEP1:		/*		 * Begin step two initialisation.		 */		if ((udaddr->udasa & STEP1MASK) != STEP1GOOD) {			i = 1;initfailed:			printf("uda%d: init step %d failed, sa=%b\n",				ctlr, i, udaddr->udasa, udasr_bits);			udasaerror(um, 0);			sc->sc_state = ST_IDLE;			if (sc->sc_flags & SC_DOWAKE) {				sc->sc_flags &= ~SC_DOWAKE;				wakeup((caddr_t)sc);			}			return;		}		udaddr->udasa = (int)&sc->sc_uda->uda_ca.ca_rspdsc[0] |			(cpu == VAX_780 || cpu == VAX_8600 ? UDA_PI : 0);		sc->sc_state = ST_STEP2;		return;	case ST_STEP2:		/*		 * Begin step 3 initialisation.		 */		if ((udaddr->udasa & STEP2MASK) != STEP2GOOD) {			i = 2;			goto initfailed;		}		udaddr->udasa = ((int)&sc->sc_uda->uda_ca.ca_rspdsc[0]) >> 16;		sc->sc_state = ST_STEP3;		return;	case ST_STEP3:		/*		 * Set controller characteristics (finish initialisation).		 */		if ((udaddr->udasa & STEP3MASK) != STEP3GOOD) {			i = 3;			goto initfailed;		}		i = udaddr->udasa & 0xff;		if (i != sc->sc_micro) {

⌨️ 快捷键说明

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