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

📄 cy.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
		 * This special check is because B_BUSY never		 * gets cleared in the non-waiting rewind case.		 */		if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE))			break;		bp->b_flags |= B_WANTED;		sleep((caddr_t)bp, PRIBIO);	}	bp->b_flags = B_BUSY|B_READ;	splx(s);	bp->b_dev = dev;	bp->b_repcnt = count;	bp->b_command = com;	bp->b_blkno = 0;	cystrategy(bp);	/*	 * In case of rewind from close; don't wait.	 * This is the only case where count can be 0.	 */	if (count == 0)		return;	biowait(bp);	if (bp->b_flags&B_WANTED)		wakeup((caddr_t)bp);	bp->b_flags &= B_ERROR;}cystrategy(bp)	register struct buf *bp;{	int ycunit = YCUNIT(bp->b_dev);	register struct vba_ctlr *vm;	register struct buf *dp;	int s;	/*	 * Put transfer at end of unit queue.	 */	dlog((LOG_INFO, "cystrategy(%o, %x)\n", bp->b_dev, bp->b_command));	dp = &ycutab[ycunit];	bp->av_forw = NULL;	vm = ycdinfo[ycunit]->ui_mi;	/* BEGIN GROT */	if (bp->b_flags & B_RAW) {		if (bp->b_bcount >= CYMAXIO) {			uprintf("cy%d: i/o size too large\n", vm->um_ctlr);			bp->b_error = EINVAL;			bp->b_resid = bp->b_bcount;			bp->b_flags |= B_ERROR;			biodone(bp);			return;		}	}	/* END GROT */	s = spl3();	if (dp->b_actf == NULL) {		dp->b_actf = bp;		/*		 * Transport not already active...		 * put at end of controller queue.		 */		 dp->b_forw = NULL;		 if (vm->um_tab.b_actf == NULL)			vm->um_tab.b_actf = dp;		else			vm->um_tab.b_actl->b_forw = dp;	} else		dp->b_actl->av_forw = bp;	dp->b_actl = bp;	/*	 * If the controller is not busy, get it going.	 */	if (vm->um_tab.b_active == 0)		cystart(vm);	splx(s);}/* * Start activity on a cy controller. */cystart(vm)	register struct vba_ctlr *vm;{	register struct buf *bp, *dp;	register struct yc_softc *yc;	register struct cy_softc *cy;	int ycunit;	daddr_t blkno;	dlog((LOG_INFO, "cystart()\n"));	/*	 * Look for an idle transport on the controller.	 */loop:	if ((dp = vm->um_tab.b_actf) == NULL)		return;	if ((bp = dp->b_actf) == NULL) {		vm->um_tab.b_actf = dp->b_forw;		goto loop;	}	ycunit = YCUNIT(bp->b_dev);	yc = &yc_softc[ycunit];	cy = &cy_softc[CYUNIT(bp->b_dev)];	/*	 * Default is that last command was NOT a write command;	 * if we do a write command we will notice this in cyintr().	 */	yc->yc_lastiow = 0;	if (yc->yc_openf < 0 ||	    (bp->b_command != CY_SENSE && (cy->cy_tpb.tpstatus&CYS_OL) == 0)) {		/*		 * Have had a hard error on a non-raw tape		 * or the tape unit is now unavailable (e.g.		 * taken off line).		 */		dlog((LOG_INFO, "openf %d command %x status %b\n",		   yc->yc_openf, bp->b_command, cy->cy_tpb.tpstatus, CYS_BITS));		bp->b_flags |= B_ERROR;		goto next;	}	if (bp == &ccybuf[CYUNIT(bp->b_dev)]) {		/*		 * Execute control operation with the specified count.		 *		 * Set next state; give 5 minutes to complete		 * rewind or file mark search, or 10 seconds per		 * iteration (minimum 60 seconds and max 5 minutes)		 * to complete other ops.		 */		if (bp->b_command == CY_REW) {			vm->um_tab.b_active = SREW;			yc->yc_timo = 5*60;		} else if (bp->b_command == CY_FSF ||		    bp->b_command == CY_BSF) {			vm->um_tab.b_active = SCOM;			yc->yc_timo = 5*60;		} else {			vm->um_tab.b_active = SCOM;			yc->yc_timo = imin(imax(10*(int)bp->b_repcnt,60),5*60);		}		cy->cy_tpb.tprec = htoms(bp->b_repcnt);		dlog((LOG_INFO, "bpcmd "));		goto dobpcmd;	}	/*	 * For raw I/O, save the current block	 * number in case we have to retry.	 */	if (bp->b_flags & B_RAW) {		if (vm->um_tab.b_errcnt == 0) {			yc->yc_blkno = bp->b_blkno;			yc->yc_nxrec = yc->yc_blkno + 1;		}	} else {		/*		 * Handle boundary cases for operation		 * on non-raw tapes.		 */		if (bp->b_blkno > yc->yc_nxrec) {			/*			 * Can't read past known end-of-file.			 */			bp->b_flags |= B_ERROR;			bp->b_error = ENXIO;			goto next;		}		if (bp->b_blkno == yc->yc_nxrec && bp->b_flags&B_READ) {			/*			 * Reading at end of file returns 0 bytes.			 */			bp->b_resid = bp->b_bcount;			clrbuf(bp);			goto next;		}		if ((bp->b_flags&B_READ) == 0)			/*			 * Writing sets EOF.			 */			yc->yc_nxrec = bp->b_blkno + 1;	}	if ((blkno = yc->yc_blkno) == bp->b_blkno) {		caddr_t addr;		int cmd;		/*		 * Choose the appropriate i/o command based on the		 * transfer size, the estimated block size,		 * and the controller's internal buffer size.		 * If the request length is longer than the tape		 * block length, a buffered read will fail,		 * thus, we request at most the size that we expect.		 * We then check for larger records when the read completes.		 * If we're retrying a read on a raw device because		 * the original try was a buffer request which failed		 * due to a record length error, then we force the use		 * of the raw controller read (YECH!!!!).		 */		if (bp->b_flags&B_READ) {			if (yc->yc_blksize <= cy->cy_bs &&			    vm->um_tab.b_errcnt == 0)				cmd = CY_BRCOM;			else				cmd = CY_RCOM;		} else {			/*			 * On write error retries erase the			 * inter-record gap before rewriting.			 */			if (vm->um_tab.b_errcnt &&			    vm->um_tab.b_active != SERASED) {				vm->um_tab.b_active = SERASE;				bp->b_command = CY_ERASE;				yc->yc_timo = 60;				goto dobpcmd;			}			cmd = (bp->b_bcount > cy->cy_bs) ? CY_WCOM : CY_BWCOM;		}		vm->um_tab.b_active = SIO;		addr = (caddr_t)vbasetup(bp, &cy->cy_rbuf, 1);		cy->cy_tpb.tpcmd = cmd;		cy->cy_tpb.tpcontrol = yc->yc_dens;		if (cmd == CY_RCOM || cmd == CY_WCOM)			cy->cy_tpb.tpcontrol |= CYCW_LOCK;		cy->cy_tpb.tpstatus = 0;		cy->cy_tpb.tpcount = 0;		cyldmba(cy->cy_tpb.tpdata, (caddr_t)addr);		cy->cy_tpb.tprec = 0;		if (cmd == CY_BRCOM)			cy->cy_tpb.tpsize = htoms(imin(yc->yc_blksize,			    (int)bp->b_bcount));		else			cy->cy_tpb.tpsize = htoms(bp->b_bcount);		cyldmba(cy->cy_tpb.tplink, (caddr_t)0);		do			uncache(&cy->cy_ccb.cbgate);		while (cy->cy_ccb.cbgate == GATE_CLOSED);		cyldmba(cy->cy_ccb.cbtpb, (caddr_t)&cy->cy_tpb);		cy->cy_ccb.cbcw = CBCW_IE;		cy->cy_ccb.cbgate = GATE_CLOSED;		dlog((LOG_INFO, "CY_GO(%x) cmd %x control %x size %d\n",		    vm->um_addr, cy->cy_tpb.tpcmd, cy->cy_tpb.tpcontrol,		    htoms(cy->cy_tpb.tpsize)));		CY_GO(vm->um_addr);		return;	}	/*	 * Tape positioned incorrectly; set to seek forwards	 * or backwards to the correct spot.  This happens 	 * for raw tapes only on error retries.	 */	vm->um_tab.b_active = SSEEK;	if (blkno < bp->b_blkno) {		bp->b_command = CY_SFORW;		cy->cy_tpb.tprec = htoms(bp->b_blkno - blkno);	} else {		bp->b_command = CY_SREV;		cy->cy_tpb.tprec = htoms(blkno - bp->b_blkno);	}	yc->yc_timo = imin(imax((int)(10 * htoms(cy->cy_tpb.tprec)), 60), 5*60);dobpcmd:	/*	 * Do the command in bp.  Reverse direction commands	 * are indicated by having CYCW_REV or'd into their	 * value.  For these we must set the appropriate bit	 * in the control field.	 */	if (bp->b_command&CYCW_REV) {		cy->cy_tpb.tpcmd = bp->b_command &~ CYCW_REV;		cy->cy_tpb.tpcontrol = yc->yc_dens | CYCW_REV;dlog((LOG_INFO, "cmd %x control %x\n", cy->cy_tpb.tpcmd, cy->cy_tpb.tpcontrol));	} else {		cy->cy_tpb.tpcmd = bp->b_command;		cy->cy_tpb.tpcontrol = yc->yc_dens;dlog((LOG_INFO, "cmd %x control %x\n", cy->cy_tpb.tpcmd, cy->cy_tpb.tpcontrol));	}	cy->cy_tpb.tpstatus = 0;	cy->cy_tpb.tpcount = 0;	cyldmba(cy->cy_tpb.tplink, (caddr_t)0);	do		uncache(&cy->cy_ccb.cbgate);	while (cy->cy_ccb.cbgate == GATE_CLOSED);	cyldmba(cy->cy_ccb.cbtpb, (caddr_t)&cy->cy_tpb);	cy->cy_ccb.cbcw = CBCW_IE;	cy->cy_ccb.cbgate = GATE_CLOSED;	dlog((LOG_INFO, "CY_GO(%x) cmd %x control %x rec %d\n",	    vm->um_addr, cy->cy_tpb.tpcmd, cy->cy_tpb.tpcontrol,	    htoms(cy->cy_tpb.tprec)));	CY_GO(vm->um_addr);	return;next:	/*	 * Done with this operation due to error or the	 * fact that it doesn't do anything.	 * Dequeue the transfer and continue	 * processing this slave.	 */	vm->um_tab.b_errcnt = 0;	dp->b_actf = bp->av_forw;	biodone(bp);	goto loop;}/* * Cy interrupt routine. */cyintr(cyunit)	int cyunit;{	struct buf *dp;	register struct buf *bp;	register struct vba_ctlr *vm = cyminfo[cyunit];	register struct cy_softc *cy;	register struct yc_softc *yc;	int err;	register state;	dlog((LOG_INFO, "cyintr(%d)\n", cyunit));	/*	 * First, turn off the interrupt from the controller	 * (device uses Multibus non-vectored interrupts...yech).	 */	cy = &cy_softc[vm->um_ctlr];	cy->cy_ccb.cbcw = CBCW_CLRINT;	cyldmba(cy->cy_ccb.cbtpb, (caddr_t)&cy->cy_nop);	cy->cy_ccb.cbgate = GATE_CLOSED;	CY_GO(vm->um_addr);	if ((dp = vm->um_tab.b_actf) == NULL) {		dlog((LOG_ERR, "cy%d: stray interrupt", vm->um_ctlr));		return;	}	bp = dp->b_actf;	cy = &cy_softc[cyunit];	cyuncachetpb(cy);	yc = &yc_softc[YCUNIT(bp->b_dev)];	/*	 * If last command was a rewind and tape is	 * still moving, wait for the operation to complete.	 */	if (vm->um_tab.b_active == SREW) {		vm->um_tab.b_active = SCOM;		if ((cy->cy_tpb.tpstatus&CYS_RDY) == 0) {			yc->yc_timo = 5*60;	/* 5 minutes */			return;		}	}	/*	 * An operation completed...record status.	 */	yc->yc_timo = INF;	yc->yc_control = cy->cy_tpb.tpcontrol;	yc->yc_status = cy->cy_tpb.tpstatus;	yc->yc_resid = bp->b_bcount - htoms(cy->cy_tpb.tpcount);	dlog((LOG_INFO, "cmd %x control %b status %b resid %d\n",	    cy->cy_tpb.tpcmd, yc->yc_control, CYCW_BITS,	    yc->yc_status, CYS_BITS, yc->yc_resid));	if ((bp->b_flags&B_READ) == 0)		yc->yc_lastiow = 1;	state = vm->um_tab.b_active;	vm->um_tab.b_active = 0;	/*	 * Check for errors.	 */	if (cy->cy_tpb.tpstatus&CYS_ERR) {		err = cy->cy_tpb.tpstatus&CYS_ERR;		dlog((LOG_INFO, "error %d\n", err));		/*		 * If we hit the end of tape file, update our position.		 */		if (err == CYER_FM) {			yc->yc_status |= CYS_FM;			state = SCOM;		/* force completion */			cyseteof(bp);		/* set blkno and nxrec */			goto opdone;		}		/*		 * Fix up errors which occur due to backspacing over		 * the beginning of the tape.		 */		if (err == CYER_BOT && cy->cy_tpb.tpcontrol&CYCW_REV) {			yc->yc_status |= CYS_BOT;			goto ignoreerr;		}		/*		 * If we were reading raw tape and the only error was that the		 * record was too long, then we don't consider this an error.		 */		if ((bp->b_flags & (B_READ|B_RAW)) == (B_READ|B_RAW) &&		    err == CYER_STROBE) {			/*			 * Retry reads with the command changed to			 * a raw read if necessary.  Setting b_errcnt			 * here causes cystart (above) to force a CY_RCOM.			 */			if (cy->cy_tpb.tpcmd == CY_BRCOM &&			    vm->um_tab.b_errcnt++ == 0) {				yc->yc_blkno++;				goto opcont;			} else				goto ignoreerr;		}		/*		 * If error is not hard, and this was an i/o operation		 * retry up to 8 times.		 */		if (state == SIO && (CYMASK(err) &		    ((bp->b_flags&B_READ) ? CYER_RSOFT : CYER_WSOFT))) {			if (++vm->um_tab.b_errcnt < 7) {

⌨️ 快捷键说明

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