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

📄 tm.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 2 页
字号:
#ifndef lintstatic char *sccsid = "@(#)tm.c	4.1      ULTRIX  7/2/90";#endif	lint/************************************************************************ *									* *			Copyright (c) 1984, 1986, 1989 by		* *		Digital Equipment Corporation, Maynard, MA		* *			All rights reserved.				* *									* *   This software is furnished under a license and may be used and	* *   copied  only  in accordance with the terms of such license and	* *   with the  inclusion  of  the  above  copyright  notice.   This	* *   software  or  any	other copies thereof may not be provided or	* *   otherwise made available to any other person.  No title to and	* *   ownership of the software is hereby transferred.			* *									* *   This software is  derived	from  software	received  from	the	* *   University    of	California,   Berkeley,   and	from   Bell	* *   Laboratories.  Use, duplication, or disclosure is	subject  to	* *   restrictions  under  license  agreements  with  University  of	* *   California and with AT&T.						* *									* *   The information in this software is subject to change  without	* *   notice  and should not be construed as a commitment by Digital	* *   Equipment Corporation.						* *									* *   Digital assumes no responsibility for the use  or	reliability	* *   of its software on equipment which is not supplied by Digital.	* *									* ************************************************************************//* * tm.c    6.3	   09/26/83 * * Modification history * * TM11/TE10 tape driver * *  6-Aug-85 - ricky palmer *	Derived from 4.2BSD labeled: tm.c	6.3	83/09/26. *	Added new ioctl functionality as well as new code to handle *	EOT correctly. Driver now supports new minor number convention *	to allow for more than 4 tape devices. V2.0 * * 18-Mar-86  -- jaw * *	br/cvec changed to NOT use registers. * * 19-Mar-86 - ricky palmer * *	Added new DEVIOCGET ioctl request code. V2.0 * * 16-Apr-86 - darrell * *	badaddr is now called via the macro BADADDR. * * 11-Jul-86 - ricky palmer * *	Added adpt and nexus fields to DEVIOCGET code. * * 26-Aug-86 - rsp (Ricky Palmer) * *	Cleaned up devioctl code to (1) zero out devget structure *	upon entry and (2) use strlen instead of fixed storage *	for bcopy's. * * 05-Jun-89 - Tim Burke *	Added a new MTIOCTOP called MTFLUSH.  This is used on caching drives *	to force a flush of the controller's write back cache.  Since this  *	is not a caching drive the MTFLUSH always returns ENXIO. */#include "te.h"#if NTE > 0 || defined(BINARY)#include "../data/tm_data.c"u_short tmstd[] = { TMSTD, 0 };int	tmprobe(), tmslave(), tmattach(), tmdgo(), tmintr(), tmtimer();struct	uba_driver tmdriver = { tmprobe, tmslave, tmattach, tmdgo,				tmstd, "te", tedinfo, "tm",				tmminfo, 0 };/* * Determine if there is a controller for * a tm at address reg.  Our goal is to make the * device interrupt. */tmprobe(reg)	caddr_t reg;{#ifdef lint	tmintr(0);#endif lint	((struct tmdevice *)reg)->tmcs = TM_IE;	/*	 * If this is a tm11, it ought to have interrupted	 * by now, if it isn't (ie: it is a ts04) then we just	 * hope that it didn't interrupt, so autoconf will ignore it.	 * Just in case, we will reference one	 * of the more distant registers, and hope for a machine	 * check, or similar disaster if this is a ts.	 *	 * Note: on an 11/780, BADADDR will just generate	 * a uba error for a ts; but our caller will notice that	 * so we won't check for it.	 */	if (BADADDR((caddr_t)&((struct tmdevice *)reg)->tmrd, 2))		return (0);	return (sizeof (struct tmdevice));}/* * Due to a design flaw, we cannot ascertain if the tape * exists or not unless it is on line - ie: unless a tape is * mounted. This is too servere a restriction to bear, * so all units are assumed to exist. */tmslave(ui, reg)	struct uba_device *ui;	caddr_t reg;{	if (ui->ui_slave)	/* non-zero slave not allowed */		return(0);	return (1);}/* * Record attachment of the unit to the controller. */tmattach(ui)	struct uba_device *ui;{	register struct te_softc *sc = &te_softc[ui->ui_unit];	/*	 * Tetotm is used to index the ctmbuf and rtmbuf	 * arrays given a te unit number.	 */	tetotm[ui->ui_unit] = ui->ui_mi->um_ctlr;	bcopy(DEV_UNKNOWN,sc->sc_device,strlen(DEV_UNKNOWN));}/* * Open the device.  Tapes are unique open * devices, so we refuse if it is already open. * We also check that a tape is available, and * don't block waiting here; if you want to wait * for a tape you should timeout in user code. */tmopen(dev, flag)	register dev_t dev;	register int flag;{	register struct uba_device *ui;	register struct te_softc *sc;	register struct tmdevice *tmaddr;	register int sel = SEL(dev);	int unit = UNIT(dev);	int s;	if (unit >= nNTE || (sc = &te_softc[unit])->sc_openf ||	    (ui = tedinfo[unit]) == 0 || ui->ui_alive == 0) {		return (ENXIO);	}	tmaddr = (struct tmdevice *)ui->ui_addr;	if ((tmaddr->tmer & TMER_EOT) && (dis_eot_te[unit] != DISEOT)) {		sc->sc_flags &= DEV_EOM;	} else {		sc->sc_flags = 0;	}	sc->sc_category_flags = 0;	sc->sc_dens = (((sel == MTHR) || (sel == MTHN)) ?			      (TM_IE | TM_GO | (ui->ui_slave << 8)):			      (TM_IE | TM_GO | (ui->ui_slave << 8) |			       TM_D800));	if((sel == MTHR) || (sel == MTHN)) {		sc->sc_category_flags |= DEV_1600BPI;	} else {		sc->sc_category_flags |= DEV_800BPI;	}get:	tmcommand(dev, TM_SENSE, 1);	if (sc->sc_erreg & TMER_SDWN) {		sleep((caddr_t)&lbolt, PZERO+1);		goto get;	}	if ((sc->sc_erreg & (TMER_SELR|TMER_TUR)) !=	    (TMER_SELR|TMER_TUR)) {		sc->sc_flags |= DEV_OFFLINE;		if(!(flag & FNDELAY)) {			DEV_UGH(sc->sc_device,unit,"offline");			return(EIO);		}	}	if ((flag & FWRITE) && (sc->sc_erreg & TMER_WRL)) {		sc->sc_flags |= DEV_WRTLCK;		if(!(flag & FNDELAY)) {			DEV_UGH(sc->sc_device,unit,"write locked");			return(EIO);		}	}	sc->sc_openf = 1;	sc->sc_blkno = (daddr_t)0;	sc->sc_nxrec = INF;	s = spl6();	if (sc->sc_tact == 0) {		sc->sc_timo = INF;		sc->sc_tact = 1;		timeout(tmtimer, (caddr_t)dev, 5*hz);	}	splx(s);	return (0);}/* * Close tape device. * * If tape was open for writing or last operation was * a write, then write two EOF's and backspace over the last one. * Unless this is a non-rewinding special file, rewind the tape. * Make the tape available to others. */tmclose(dev, flag)	register dev_t dev;	register int flag;{	register struct te_softc *sc = &te_softc[UNIT(dev)];	register int unit = UNIT(dev);	register int sel = SEL(dev);	sc->sc_flags &= ~DEV_EOM;	if (flag == FWRITE || (flag & FWRITE) &&	    (sc->sc_flags & DEV_WRITTEN)) {		tmcommand(dev, TM_WEOF, 1);		sc->sc_flags &= ~DEV_EOM;		tmcommand(dev, TM_WEOF, 1);		sc->sc_flags &= ~DEV_EOM;		tmcommand(dev, TM_SREV, 1);		sc->sc_flags &= ~DEV_EOM;	}	if ((sel == MTLR) || (sel == MTHR)) {		/*		 * 0 count means don't hang waiting for rewind complete		 * rather ctmbuf stays busy until the operation		 * completes preventing further opens from completing		 * by preventing a TM_SENSE from completing.		 */		tmcommand(dev, TM_REW, 0);	}	sc->sc_openf = 0;	if ((sc->sc_erreg & TMER_EOT) && (dis_eot_te[unit] != DISEOT)) {		sc->sc_flags |= DEV_EOM;	}}/* * Execute a command on the tape drive * a specified number of times. */tmcommand(dev, com, count)	register dev_t dev;	register int com;	register int count;{	register struct buf *bp = &ctmbuf[TMUNIT(dev)];	register int s = spl5();	while (bp->b_flags&B_BUSY) {		/*		 * 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;	tmstrategy(bp);	/*	 * In case of rewind from close, don't wait.	 * This is the only case where count can be 0.	 */	if (count == 0)		return;	iowait(bp);	if (bp->b_flags&B_WANTED)		wakeup((caddr_t)bp);	bp->b_flags &= B_ERROR;}/* * Queue a tape operation. */tmstrategy(bp)	register struct buf *bp;{	register struct uba_ctlr *um;	register struct te_softc *sc = &te_softc[UNIT(bp->b_dev)];	register struct buf *dp;	register int s;	register int unit = UNIT(bp->b_dev);	if ((sc->sc_flags & DEV_EOM) && !((sc->sc_flags & DEV_CSE) ||	    (dis_eot_te[unit] & DISEOT))) {		bp->b_resid = bp->b_bcount;		bp->b_error = ENOSPC;		bp->b_flags |= B_ERROR;		iodone(bp);		return;	}	sc->sc_category_flags &= ~DEV_TPMARK;	/*	 * Put transfer at end of unit queue	 */	dp = &teutab[unit];	bp->av_forw = NULL;	s = spl5();	um = tedinfo[unit]->ui_mi;	if (dp->b_actf == NULL) {		dp->b_actf = bp;		/*		 * Transport not already active...		 * put at end of controller queue.		 */		dp->b_forw = NULL;		if (um->um_tab.b_actf == NULL)			um->um_tab.b_actf = dp;		else			um->um_tab.b_actl->b_forw = dp;		um->um_tab.b_actl = dp;	} else		dp->b_actl->av_forw = bp;	dp->b_actl = bp;	/*	 * If the controller is not busy, get	 * it going.	 */	if (um->um_tab.b_active == 0)		tmstart(um);	splx(s);}/* * Start activity on a tm controller. */tmstart(um)	register struct uba_ctlr *um;{	register struct tmdevice *addr = (struct tmdevice *)um->um_addr;	register struct buf *bp, *dp;	register struct te_softc *sc;	register struct uba_device *ui;	int cmd, tmunit, unit;	daddr_t blkno;	/*	 * Look for an idle transport on the controller.	 */loop:	if ((dp = um->um_tab.b_actf) == NULL)		return;	if ((bp = dp->b_actf) == NULL) {		um->um_tab.b_actf = dp->b_forw;		goto loop;	}	tmunit = TMUNIT(bp->b_dev);	unit = UNIT(bp->b_dev);	ui = tedinfo[unit];	sc = &te_softc[unit];	addr->tmcs = (ui->ui_slave << 8);	sc->sc_dsreg = addr->tmcs;	sc->sc_erreg = addr->tmer;	sc->sc_resid = addr->tmbc;	if ((sc->sc_flags & DEV_EOM) && !((sc->sc_flags & DEV_CSE) ||	    (dis_eot_te[unit] & DISEOT))) {		bp->b_resid = bp->b_bcount;		bp->b_error = ENOSPC;		bp->b_flags |= B_ERROR;		goto next;	}	if ((sc->sc_category_flags & DEV_TPMARK) && 	    (bp->b_flags & B_READ)) {		bp->b_resid = 0;		bp->b_error = EIO;		bp->b_flags |= B_ERROR;		goto next;	}	/*	 * Default is that last command was NOT a write command;	 * if we do a write command we will notice this in tmintr().	 */	sc->sc_flags &= ~DEV_WRITTEN;	if (sc->sc_openf < 0 || (addr->tmcs & TM_CUR) == 0) {		/*		 * Have had a hard error on a non-raw tape		 * or the tape unit is now unavailable		 * (e.g. taken off line).		 */		bp->b_flags |= B_ERROR;		goto next;	}	if (bp == &ctmbuf[tmunit]) {		/*		 * Execute control operation with the specified count.		 */		if (bp->b_command == TM_SENSE)			goto next;		/*		 * Set next state; give 5 minutes to complete		 * rewind, or 10 seconds per iteration (minimum 60		 * seconds and max 5 minutes) to complete other ops.		 */		if (bp->b_command == TM_REW) {			um->um_tab.b_active = SREW;			sc->sc_timo = 5 * 60;		} else {			um->um_tab.b_active = SCOM;			sc->sc_timo =			    imin(imax(10*(int)-bp->b_repcnt,60),5*60);		}		if (bp->b_command == TM_SFORW ||		    bp->b_command == TM_SREV)			addr->tmbc = bp->b_repcnt;		goto dobpcmd;	}	if (sc->sc_blkno != bdbtofsb(bp->b_blkno) &&	    !um->um_tab.b_errcnt)		sc->sc_blkno = bdbtofsb(bp->b_blkno);	sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1;	/*	 * If the data transfer command is in the correct place,	 * set up all the registers except the csr, and give	 * control over to the UNIBUS adapter routines, to	 * wait for resources to start the i/o.	 */	if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {		addr->tmbc = -bp->b_bcount;		if ((bp->b_flags&B_READ) == 0) {			if (um->um_tab.b_errcnt)				cmd = TM_WIRG;			else				cmd = TM_WCOM;		} else			cmd = TM_RCOM;		um->um_tab.b_active = SIO;		um->um_cmd = sc->sc_dens|cmd;		sc->sc_timo = 60;		(void) ubago(ui);		return;	}	/*	 * Tape positioned incorrectly;	 * set to seek forwards or backwards to the correct spot.	 * This happens for raw tapes only on error retries.	 */	um->um_tab.b_active = SSEEK;	if (blkno < bdbtofsb(bp->b_blkno)) {		bp->b_command = TM_SFORW;		addr->tmbc = blkno - bdbtofsb(bp->b_blkno);	} else {		bp->b_command = TM_SREV;		addr->tmbc = bdbtofsb(bp->b_blkno) - blkno;	}	sc->sc_timo = imin(imax(10 * -addr->tmbc, 60), 5 * 60);dobpcmd:	/*	 * Do the command in bp.	 */	addr->tmcs = (sc->sc_dens | bp->b_command);	return;next:	/*	 * Done with this operation due to error or	 * the fact that it doesn't do anything.	 * Release UBA resources (if any), dequeue

⌨️ 快捷键说明

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