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

📄 st.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	/*	 * If we are opening the tape for writing, check	 * to make sure that the tape can be written.	 */	if (flag & FWRITE) {		err = 0;		if (un->un_mspl->wp)  {			un->un_status = KEY_WRITE_PROTECT;			un->un_laststate = un->un_state;			un->un_state = ST_STATE_CLOSED;			/* restore resid for status reporting */			un->un_err_resid = resid;			return (EACCES);		} else {			un->un_read_only = 0;		}	} else {		un->un_read_only = 1;	}	/*	 * If we're opening the tape write-only, we need to	 * write 2 filemarks on the HP 1/2 inch drive, to	 * create a null file.	 */	if (flag == FWRITE && un->un_dp->options & ST_REEL)		un->un_fmneeded = 2;	else if (flag == FWRITE)		un->un_fmneeded = 1;	else		un->un_fmneeded = 0;	/*	 * Now this is sort of stupid, but we need to check	 * whether or not, independent of doing any I/O,	 * whether or not we can set the requested density	 * unless the device being opened is the 'generic'	 * device open (the 'lowest' density) device.	 *	 * If we can, fine. If not, we have to bounce the	 * open with EIO. We use the B_WRITE flag here	 * becuase in this case we are not searching for	 * the right density- we are taking the user	 * specified density and seeing whether or not	 * setting that density (for writing) would	 * work.	 *	 * Later on this might get done again.	 */	if ((un->un_fileno < 0 || (un->un_fileno == 0 && un->un_blkno == 0)) &&	    MT_DENSITY(dev) != 0) {		if (st_determine_density(devp, B_WRITE)) {			/* restore resid for status reporting */			un->un_err_resid = resid;			un->un_status = KEY_ILLEGAL_REQUEST;			un->un_laststate = un->un_state;			un->un_state = ST_STATE_CLOSED;			return (EIO);		}		/*		 * Destroy the knowledge that we have 'determined'		 * density so that a later read at BOT comes along		 * does the right density determination.		 */		un->un_density_known = 0;	}	/* restore resid for status reporting */	un->un_err_resid = resid;	/*	 * Okay, the tape is loaded and either at BOT or somewhere past.	 * Mark the state such that any I/O or tape space operations	 * will get/set the right density, etc..	 */	un->un_laststate = un->un_state;	un->un_state = ST_STATE_OPEN_PENDING_IO;	/*	 *  Set test append flag if writing.	 *  First write must check that tape is positioned correctly.	 */	un->un_test_append = (flag & FWRITE);	return (0);}intstclose(dev, flag)dev_t dev;int flag;{	int err = 0;	register struct scsi_device *devp;	register struct scsi_tape *un;	int unit, norew, count;	unit = MTUNIT(dev);	if (DEBUGGING_ALL) {		printf("st%d:\tstclose dev 0x%x flag %d\n", unit, dev, flag);	}	/*	 * validate arguments	 */	if ((unit = MTUNIT(dev)) >= ST_MAXUNIT) {		return (ENXIO);	}	if (!(devp = stunits[unit]) || !(un = UPTR)) {		return (ENXIO);	}	/*	 * a close causes a silent span to the next file if we've hit	 * an EOF (but not yet read across it).	 */	if (un->un_eof == ST_EOF) {		if (un->un_fileno >= 0) {			un->un_fileno++;			un->un_blkno = 0;		}		un->un_eof = ST_NO_EOF;	}	/*	 * set state to indicate that we are in process of closing	 */	un->un_laststate = un->un_state;	un->un_state = ST_STATE_CLOSING;	/*	 * rewinding?	 */	norew = (minor(dev) & MT_NOREWIND);	/*	 * For performance reasons (HP 88780), the driver should	 * postpone writing the second tape mark until just before a file	 * positioning ioctl is issued (e.g., rewind).  This means that	 * the user must not manually rewind the tape because the tape will	 * be missing the second tape mark which marks EOM.	 * However, this small performance improvement is not worth the risk.	 */	/*	 * We need to back up over the filemark we inadvertently popped	 * over doing a read in between the two filemarks that constitute	 * logical eot for 1/2" tapes. Note that ST_EOT_PENDING is only	 * set while reading.	 *	 * If we happen to be at physical eot (ST_EOM) (writing case),	 * the writing of filemark(s) will clear the ST_EOM state, which	 * we don't want, so we save this state and restore it later.	 */	if (un->un_eof == ST_EOT_PENDING) {		if (norew) {			if (stcmd(devp, SCMD_SPACE, Fmk((-1)), SYNC_CMD)) {				err = EIO;			} else {				un->un_blkno = 0;				un->un_eof = ST_EOT;			}		} else {			un->un_eof = ST_NO_EOF;		}	} else if (((flag & FWRITE) &&	    (un->un_lastop == ST_OP_WRITE || un->un_fmneeded > 0)) ||	    ((flag == FWRITE) && (un->un_lastop == ST_OP_NIL))) {		/* save ST_EOM state */		int was_at_eom = (un->un_eof == ST_EOM)? 1: 0;		/*		 * Do we need to write a file mark?		 *		 * Note that we will write a filemark if we had opened		 * the tape write only and no data was written, thus		 * creating a null file.		 *		 * For HP (1/2 inch tape), un_fmneeded tells us how many		 * filemarks need to be written out.  If the user		 * already wrote one, we only have to write one more.		 * If they wrote two, we don't have to write any.		 */		count = (un->un_dp->options & ST_REEL) ? un->un_fmneeded : 1;		if (count > 0) {			if (stcmd(devp, SCMD_WRITE_FILE_MARK,			    count, SYNC_CMD)) {				err = EIO;			}			if ((un->un_dp->options & ST_REEL) && norew) {				if (stcmd(devp, SCMD_SPACE, Fmk((-1)),				    SYNC_CMD)) {					err = EIO;				}				un->un_eof = ST_NO_EOF;				/* fix up block number */				un->un_blkno = 0;			}		}		/*		 * If we aren't going to be rewinding, and we were at		 * physical eot, restore the state that indicates we		 * are at physical eot. Once you have reached physical		 * eot, and you close the tape, the only thing you can		 * do on the next open is to rewind. Access to trailer		 * records is only allowed without closing the device.		 */		if (norew == 0 && was_at_eom)			un->un_eof = ST_EOM;	}	/*	 * Do we need to rewind? Can we rewind?	 */	if (norew == 0 && un->un_fileno >= 0 && err == 0) {		/*		 * We'd like to rewind with the		 * 'immediate' bit set, but this		 * causes problems on some drives		 * where subsequent opens get a		 * 'NOT READY' error condition		 * back while the tape is rewinding,		 * which is impossible to distinguish		 * from the condition of 'no tape loaded'.		 *		 * Also, for some targets, if you disconnect		 * with the 'immediate' bit set, you don't		 * actually return right away, i.e., the		 * target ignores your request for immediate		 * return.		 *		 * Instead, we'll fire off an async rewind		 * command. We'll mark the device as closed,		 * and any subsequent open will stall on		 * the first TEST_UNIT_READY until the rewind		 * completes.		 *		 */		(void) stcmd(devp, SCMD_REWIND, 0, ASYNC_CMD);	}	/*	 * clear up state	 */	un->un_laststate = un->un_state;	un->un_state = ST_STATE_CLOSED;	un->un_lastop = ST_OP_NIL;	/*	 * any kind of error on closing causes all state to be tossed	 */	if (err && un->un_status != KEY_ILLEGAL_REQUEST) {		un->un_density_known = 0;		/* stintr already set un_fileno to -1 */	}	return (err);}/* * These routines perform raw i/o operations. */intstread(dev, uio)dev_t dev;struct uio *uio;{	return (strw(dev, uio, B_READ));}intstwrite(dev, uio)dev_t dev;struct uio *uio;{	return (strw(dev, uio, B_WRITE));}/* * Perform max. record blocking.  For variable-length devices: * if greater than 64KB -1, block into 64 KB -2 requests; otherwise, * let it through unmodified. * For fixed-length record devices: 63K is max (default minphys). */static voidstminphys(bp)struct buf *bp;{	struct scsi_device *devp = stunits[MTUNIT(bp->b_dev)];	if (UPTR->un_dp->options & ST_VARIABLE) {		if (bp->b_bcount > ST_MAXRECSIZE_VARIABLE)			bp->b_bcount = ST_MAXRECSIZE_VARIABLE_LIMIT;	} else {		if (bp->b_bcount > ST_MAXRECSIZE_FIXED)			bp->b_bcount = ST_MAXRECSIZE_FIXED;	}}static intstrw(dev, uio, flag)dev_t dev;struct uio *uio;int flag;{	struct scsi_device *devp;	struct scsi_tape *un;	register int rval, len = uio->uio_iov->iov_len;	if (MTUNIT(dev) >= ST_MAXUNIT) {		return (ENXIO);	}	devp = stunits[MTUNIT(dev)];	un = UPTR;	if ((un->un_dp->options & ST_VARIABLE) == 0) {		if (uio->uio_iov->iov_len & (un->un_dp->bsize-1)) {			printf("%s%d:  %s: not modulo %d block size\n",			    DNAME, DUNIT, (flag == B_WRITE) ? "write": "read",			    un->un_dp->bsize);			return (EINVAL);		}	}	rval = physio(ststrategy, un->un_rbufp, dev, flag, stminphys, uio);	/*	 * if we hit logical EOT during this xfer and there is not a	 * full residue, then set un_eof back  to ST_EOM to make sure that	 * the user will see at least one zero write	 * after this short write	 */	if (un->un_eof == ST_WRITE_AFTER_EOM &&	    uio->uio_resid != len)		un->un_eof = ST_EOM;	return (rval);}intststrategy(bp)register struct buf *bp;{	register s;	register struct scsi_device *devp;	register struct scsi_tape *un;	int unit = MTUNIT(bp->b_dev);	/*	 * validate arguments	 */	devp = stunits[unit];	if (!devp || !(un = UPTR)) {		bp->b_flags |= B_ERROR;		bp->b_resid = bp->b_bcount;		bp->b_error = ENXIO;		iodone(bp);		return;	}	if (bp != un->un_sbufp) {		char reading = bp->b_flags & B_READ;		int wasopening = 0;		/*		 * Check for legal operations		 */		if (un->un_fileno < 0) {			DPRINTF(devp, "strategy with un->un_fileno < 0");			goto b_done_err;		}		/*		 * Process this first. If we were reading, and we're pending		 * logical eot, that means we've bumped one file mark too far.		 */		if (un->un_eof == ST_EOT_PENDING) {			if (stcmd(devp, SCMD_SPACE, Fmk((-1)), SYNC_CMD)) {				un->un_fileno = -1;				un->un_density_known = 0;				goto b_done_err;			}			un->un_blkno = 0; /* fix up block number.. */			un->un_eof = ST_EOT;		}		/*		 * If we are in the process of opening, we may have to		 * determine/set the correct density. We also may have		 * to do a test_append (if QIC) to see whether we are		 * in a position to append to the end of the tape.		 *		 * If we're already at logical eot, we transition		 * to ST_NO_EOF. If we're at physical eot, we punt		 * to the switch statement below to handle.		 */		if ((un->un_state == ST_STATE_OPEN_PENDING_IO) ||		    (un->un_test_append && (un->un_dp->options & ST_QIC))) {			if (un->un_state == ST_STATE_OPEN_PENDING_IO) {				if (st_determine_density(devp, (int) reading)) {					goto b_done_err;				}			}			DPRINTF(devp,			    "pending_io@fileno %d rw %d qic %d eof %d",			    un->un_fileno, (int) reading,			    (un->un_dp->options & ST_QIC)? 1: 0,			    un->un_eof);			if (!reading && un->un_eof != ST_EOM) {				if (un->un_eof == ST_EOT) {					un->un_eof = ST_NO_EOF;				} else if (un->un_fileno > 0 &&				    (un->un_dp->options & ST_QIC)) {					/*					 * st_test_append() will do it all					 */					st_test_append(bp);					return;				}			}			if (un->un_state == ST_STATE_OPEN_PENDING_IO)				wasopening = 1;			un->un_laststate = un->un_state;			un->un_state = ST_STATE_OPEN;		}		/*		 * Process rest of END OF FILE and END OF TAPE conditions		 */		DPRINTF(devp, "un_eof=%x, wasopening=%x",		    un->un_eof, wasopening);		switch (un->un_eof) {		case ST_EOM:			/*			 * This allows writes to proceed past physical			 * eot. We'll *really* be in trouble if the			 * user continues blindly writing data too			 * much past this point (unwind the tape).			 * Physical eot really means 'early warning			 * eot' in this context.			 *			 * Every other write from now on will succeed			 * (if sufficient  tape left).			 * This write will return with resid == count			 * but the next one should be successful			 *			 * Note that we only transition to logical EOT			 * if the last state wasn't the OPENING state.			 * We explicitly prohibit running up to physical			 * eot, closing the device, and then re-opening			 * to proceed. Trailer records may only be gotten			 * at by keeping the tape open after hitting eot.			 *			 * Also note that ST_EOM cannot be set by reading-			 * this can only be set during writing. Reading			 * up to the end of the tape gets a blank check			 * or a double-filemark indication (ST_EOT_PENDING),			 * and we prohibit reading after that point.			 *			 */			DPRINTF(devp, "EOM");			if (wasopening == 0)				/*				 * this allows strw() to reset it back to				 * ST_EOM to make sure that the application				 * will see a zero write				 */				un->un_eof = ST_WRITE_AFTER_EOM;			un->un_status = SUN_KEY_EOT;			goto b_done;		case ST_WRITE_AFTER_EOM:		case ST_EOT:			DPRINTF(devp, "EOT");			un->un_status = SUN_KEY_EOT;			if (reading) {				goto b_done;			}			un->un_eof = ST_NO_EOF;			break;		case ST_EOF_PENDING:			DPRINTF(devp, "EOF PENDING");		case ST_EOF:			DPRINTF(devp, "EOF");			un->un_status = SUN_KEY_EOF;			un->un_eof = ST_NO_EOF;			un->un_fileno += 1;			un->un_blkno = 0;			if (reading) {				DPRINTF(devp, "now file %d (read)",				    un->un_fileno);				goto b_done;			}			DPRINTF(devp, "now file %d (write)", un->un_fileno);			break;		default:			un->un_status = 0;			break;		}	}	bp->b_flags &= ~(B_DONE|B_ERROR);	bp->av_forw = 0;	bp->b_resid = 0;	if (bp != un->un_sbufp) {		BP_PKT(bp) = 0;	}	s = splr(stpri);	if (un->un_quef) {		un->un_quel->av_forw = bp;	} else		un->un_quef = bp;	un->un_quel = bp;	if (un->un_runq == NULL)		ststart(devp);	(void) splx(s);	return;b_done_err:	bp->b_flags |= B_ERROR;	bp->b_error = EIO;b_done:	un->un_err_resid = bp->b_resid = bp->b_bcount;	iodone(bp);}/* * this routine spaces forward over filemarks * XXX space_fmks and find_eom should be merged */static intspace_fmks(dev, count)dev_t dev;int count;

⌨️ 快捷键说明

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