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

📄 st.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
{	register struct scsi_device *devp;	register struct scsi_tape *un;	int rval = 0;	if ((devp = stunits[MTUNIT(dev)]) == 0) {		return (ENXIO); /* can't happen */	}	un = UPTR;	/*	 * the risk with doing only one space operation is that we	 * may accidentily jump in old data	 */	if (un->un_dp->options & ST_KNOWS_EOD) {		if (stcmd(devp, SCMD_SPACE, Fmk(count), SYNC_CMD)) {			rval = EIO;		}	} else {		while (count > 0) {			if (stcmd(devp, SCMD_SPACE, Fmk(1), SYNC_CMD)) {				rval = EIO;				break;			}			count -= 1;			/*			 * read a block to see if we have reached			 * end of medium (double filemark for reel or			 * medium error for others)			 */			if (count > 0) {				if (stcmd(devp, SCMD_SPACE, Blk(1),				    SYNC_CMD)) {					rval = EIO;					break;				}				if (un->un_eof >= ST_EOF_PENDING) {					un->un_status = SUN_KEY_EOT;					rval = EIO;					break;				}			}		}		un->un_err_resid = count;	}	return (rval);}/* * this routine spaces to to EOM * it keeps track of the current filenumber and returns the * filenumber after the last successful space operation */#define	MAX_SKIP	0x1000 /* somewhat arbitrary */static intfind_eom(dev)dev_t dev;{	register struct scsi_device *devp;	register struct scsi_tape *un;	int count, savefile = -1;	if ((devp = stunits[MTUNIT(dev)]) == 0)		return (savefile); /* this can't happen */	un = UPTR;	savefile = un->un_fileno;	/*	 * see if the drive is smart enough to do the skips in	 * one operation; 1/2" use two filemarks	 */	if (un->un_dp->options & ST_KNOWS_EOD)		count = MAX_SKIP;	else		count = 1;	while (stcmd(devp, SCMD_SPACE, Fmk(count), SYNC_CMD) == 0) {		savefile = un->un_fileno;		/*		 * If we're not EOM smart,  space a record		 * to see whether we're now in the slot between		 * the two sequential filemarks that logical		 * EOM consists of (REEL) or hit nowhere land		 * (8mm).		 */		if ((un->un_dp->options & ST_KNOWS_EOD) == 0) {			if (stcmd(devp, SCMD_SPACE, Blk((1)), SYNC_CMD))				break;			else if (un->un_eof >= ST_EOF_PENDING) {				un->un_status = KEY_BLANK_CHECK;				un->un_fileno++;				un->un_blkno = 0;				break;			}		}		else			savefile = un->un_fileno;	}	if (un->un_dp->options & ST_KNOWS_EOD) {		savefile = un->un_fileno;	}	DPRINTF_IOCTL(devp, "find_eom: %x\n", savefile);	return (savefile);}/* * this routine is frequently used in ioctls below; * it determines whether we know the density and if not will * determine it * if we have written the tape before, one or more filemarks are written * * depending on the stepflag, the head is repositioned to where it was before * the filemarks were written in order not to confuse step counts */#define	STEPBACK    0#define	NO_STEPBACK 1static intcheck_density_or_wfm(dev, wfm, mode, stepflag)dev_t dev;int wfm, mode, stepflag;{	register struct scsi_device *devp;	register struct scsi_tape *un;	if ((devp = stunits[MTUNIT(dev)]) == 0)		return (ENXIO);	un = UPTR;	/*	 * If we don't yet know the density of the tape we have inserted,	 * we have to either unconditionally set it (if we're 'writing'),	 * or we have to determine it. As side effects, check for any	 * write-protect errors, and for the need to put out any file-marks	 * before positioning a tape.	 *	 * If we are going to be spacing forward, and we haven't determined	 * the tape density yet, we have to do so now...	 */	if (un->un_state == ST_STATE_OPEN_PENDING_IO) {		if (st_determine_density(devp, mode)) {			return (EIO);		}		/*		 * Presumably we are at BOT. If we attempt to write, it will		 * either work okay, or bomb. We don't do a st_test_append		 * unless we're past BOT.		 */		un->un_laststate = un->un_state;		un->un_state = ST_STATE_OPEN;	} else if (un->un_fmneeded > 0 ||			(un->un_lastop == ST_OP_WRITE && wfm)) {		int blkno = un->un_blkno;		int fileno = un->un_fileno;		/*		 * We need to write one or two filemarks.		 * In the case of the HP, we need to		 * position the head between the two		 * marks.		 */		if (un->un_fmneeded > 0) {			wfm = un->un_fmneeded;			un->un_fmneeded = 0;		}		if (st_write_fm(dev, wfm)) {			un->un_fileno = -1;			un->un_density_known = 0;			return (EIO);		}		if (stepflag == STEPBACK) {			if (stcmd(devp, SCMD_SPACE, Fmk((-wfm)), SYNC_CMD)) {				return (EIO);			}			un->un_blkno = blkno;			un->un_fileno = fileno;		}	}	/*	 * Whatever we do at this point clears the state of the eof flag.	 */	un->un_eof = ST_NO_EOF;	/*	 * If writing, let's check that we're positioned correctly	 * at the end of tape before issuing the next write.	 */	if (!un->un_read_only) {		un->un_test_append = 1;	}	return (0);}/* * This routine implements the ioctl calls.  It is called * from the device switch at normal priority. *//*ARGSUSED*/stioctl(dev, cmd, data, flag)dev_t dev;register int cmd;register caddr_t data;int flag;{	register struct scsi_device *devp;	register struct scsi_tape *un;	struct mtop *mtop;	int savefile, tmp, rval;	if ((devp = stunits[MTUNIT(dev)]) == 0)		return (ENXIO);	un = UPTR;	/*	 * first and foremost, handle any ST_EOT_PENDING cases.	 * That is, if a logical eot is pending notice, notice it.	 */	mtop = (struct mtop *) data;	DPRINTF_IOCTL(devp, "stioctl: mt_op=%x", mtop->mt_op);	DPRINTF_IOCTL(devp, "         fileno=%x, blkno=%x, un_eof=%x\n",	    un->un_fileno, un->un_blkno, un->un_eof);	if (un->un_eof == ST_EOT_PENDING) {		int resid = un->un_err_resid;		int status = un->un_status;		int lastop = un->un_lastop;		if (stcmd(devp, SCMD_SPACE, Fmk((-1)), SYNC_CMD)) {			return (EIO);		}		un->un_lastop = lastop;	/* restore last operation */		if (status == SUN_KEY_EOF)			un->un_status = SUN_KEY_EOT;		else			un->un_status = status;		un->un_err_resid  = resid;		un->un_err_blkno = un->un_blkno = 0; /* fix up block number */		un->un_eof = ST_EOT;	/* now we're at logical eot */	}	/*	 * now, handle the rest of the situations	 */	if (cmd == MTIOCGET) {		/* Get tape status */		struct mtget *mtget = (struct mtget *) data;		mtget->mt_erreg = un->un_status;		mtget->mt_resid = un->un_err_resid;		mtget->mt_dsreg = un->un_retry_ct;		mtget->mt_fileno = un->un_err_fileno;		mtget->mt_blkno = un->un_err_blkno;		mtget->mt_type = un->un_dp->type;		mtget->mt_flags = MTF_SCSI | MTF_ASF;		if (un->un_dp->options & ST_REEL) {			mtget->mt_flags |= MTF_REEL;			mtget->mt_bf = 20;		} else {				/* 1/4" cartridges */			switch (mtget->mt_type) {			/* Emulex cartridge tape */			case MT_ISMT02:				mtget->mt_bf = 40;				break;			default:				mtget->mt_bf = 126;				break;			}		}		un->un_status = 0;		/* Reset status */		un->un_err_resid = 0;		return (0);	}	if (cmd != MTIOCTOP) {		return (ENOTTY);	}	rval = 0;	un->un_status = 0;	switch (mtop->mt_op) {	case MTERASE:		/*		 * MTERASE rewinds the tape, erase it completely, and returns		 * to the beginning of the tape		 */		if (un->un_dp->options & ST_REEL)			un->un_fmneeded = 2;		if (un->un_mspl->wp || un->un_read_only) {			un->un_status = KEY_WRITE_PROTECT;			un->un_err_resid = mtop->mt_count;			un->un_err_fileno = un->un_fileno;			un->un_err_blkno = un->un_blkno;			return (EACCES);		}		if (check_density_or_wfm(dev, 1, B_WRITE, NO_STEPBACK) ||		    stcmd(devp, SCMD_REWIND, 0, SYNC_CMD) ||		    stcmd(devp, SCMD_ERASE, 0, SYNC_CMD)) {			un->un_fileno = -1;			rval = EIO;		} else {			/* QIC and helical scan rewind after erase */			if (un->un_dp->options & ST_REEL)				(void) stcmd(devp, SCMD_REWIND, 0, ASYNC_CMD);		}		break;	case MTWEOF:		/*		 * write an end-of-file record		 */		if (un->un_mspl->wp || un->un_read_only) {			un->un_status = KEY_WRITE_PROTECT;			un->un_err_resid = mtop->mt_count;			un->un_err_fileno = un->un_fileno;			un->un_err_blkno = un->un_blkno;			return (EACCES);		}		if (mtop->mt_count == 0)			return (0);		un->un_eof = ST_NO_EOF;		if (!un->un_read_only) {			un->un_test_append = 1;		}		if (un->un_state == ST_STATE_OPEN_PENDING_IO) {			if (st_determine_density(devp, B_WRITE))				return (EIO);		}		if (st_write_fm(dev, (int) mtop->mt_count)) {			/*			 * Failure due to something other than illegal			 * request results in loss of state (stintr).			 */			rval = EIO;		} else if (un->un_dp->options & ST_REEL) {			/*			 * Check if user has written all the			 * filemarks we need.  If so,			 * back up over the last one.			 */#ifdef NOTNEEDED			if (un->un_fmneeded <= 0) {				if (stcmd(devp, SCMD_SPACE, Fmk((-1)),				    SYNC_CMD)) {					rval = EIO;				}			}#endif		}		break;	case MTRETEN:		/*		 * retension the tape		 * only for cartridge tape		 */		if ((un->un_dp->options & ST_QIC) == 0)		    return (ENOTTY);		if (check_density_or_wfm(dev, 1, 0, NO_STEPBACK) ||		    stcmd(devp, SCMD_LOAD, 3, SYNC_CMD)) {			un->un_fileno = -1;			rval = EIO;		}		break;	case MTREW:		/*		 * rewind  the tape		 */		if (check_density_or_wfm(dev, 1, 0, NO_STEPBACK)) {			return (EIO);		}		(void) stcmd(devp, SCMD_REWIND, 0, SYNC_CMD);		break;	case MTOFFL:		/*		 * rewinds, and, if appropriate, takes the device offline by		 * unloading the tape		 */		if (check_density_or_wfm(dev, 1, 0, NO_STEPBACK)) {			return (EIO);		}		(void) stcmd(devp, SCMD_REWIND, 0, SYNC_CMD);		(void) stcmd(devp, SCMD_LOAD, 0, SYNC_CMD);		un->un_eof = ST_NO_EOF;		break;	case MTNOP:		un->un_status = 0;		/* Reset status */		un->un_err_resid = 0;		break;	case MTEOM:		/*		 * positions the tape at a location just after the last file		 * written on the tape. For cartridge and 8 mm, this after		 * the last file mark; for reel, this is inbetween the two		 * last 2 file marks		 */		if (un->un_eof >= ST_EOT) {			/*			 * If the command wants to move to logical end			 * of media, and we're already there, we're done.			 * If we were at logical eot, we reset the state			 * to be *not* at logical eot.			 *			 * If we're at physical or logical eot, we prohibit			 * forward space operations (unconditionally).			 */			return (0);		}		if (check_density_or_wfm(dev, 1, B_READ, NO_STEPBACK)) {			return (EIO);		}		/*		 * find_eom() returns the last fileno we knew about;		 */		savefile = find_eom(dev);		if (un->un_status != KEY_BLANK_CHECK) {			un->un_fileno = -1;			rval = EIO;		} else {			/*			 * For 1/2" reel tapes assume logical EOT marked			 * by two file marks or we don't care that we may			 * be extending the last file on the tape.			 */			if (un->un_dp->options & ST_REEL) {				if (stcmd(devp, SCMD_SPACE, Fmk((-1)),				    SYNC_CMD)) {					un->un_fileno = -1;					rval = EIO;					break;				}				/*				 * Fix up the block number.				 */				un->un_blkno = 0;				un->un_err_blkno = 0;			}			un->un_err_resid = 0;			un->un_fileno = savefile;			un->un_eof = ST_EOT;		}		un->un_status = 0;		break;	case MTFSF:		/*		 * forward space over filemark		 *		 * For ASF we allow a count of 0 on fsf which means		 * we just want to go to beginning of current file.		 * Equivalent to "nbsf(0)" or "bsf(1) + fsf".		 */		if ((un->un_eof >= ST_EOT) && (mtop->mt_count > 0)) {			/* we're at EOM */			un->un_err_resid = mtop->mt_count; /* XXX added XXX */			un->un_status = KEY_BLANK_CHECK;			return (EIO);		}		/*		 * physical tape position may not be what we've been		 * telling the user; adjust the request accordingly		 */		if (mtop->mt_count && IN_EOF(un)) {			un->un_fileno++;			un->un_blkno = 0;			/*			 * For positive direction case, we're now covered.			 * For zero or negative direction, we're covered			 * (almost)			 */			mtop->mt_count--;		}		if (check_density_or_wfm(dev, 1, B_READ, STEPBACK)) {			return (EIO);		}		/*		 * Forward space file marks.		 * We leave ourselves at block zero		 * of the target file number.		 */		if (mtop->mt_count < 0) {			mtop->mt_count = -mtop->mt_count;			mtop->mt_op = MTNBSF;			goto bspace;		}fspace:		if ((tmp = mtop->mt_count) == 0) {			if (un->un_blkno == 0) {				un->un_err_resid = 0;				un->un_err_fileno = un->un_fileno;				un->un_err_blkno = un->un_blkno;				break;			} else if (un->un_fileno == 0) {				rval = stcmd(devp, SCMD_REWIND, 0, SYNC_CMD);			} else if (un->un_dp->options & ST_BSF) {				rval = (stcmd(devp, SCMD_SPACE, Fmk((-1)),				    SYNC_CMD) ||				    stcmd(devp, SCMD_SPACE, Fmk(1), SYNC_CMD));			} else {				tmp = un->un_fileno;				rval = (stcmd(devp, SCMD_REWIND, 0, SYNC_CMD) ||				    stcmd(devp, SCMD_SPACE, Fmk(tmp),				    SYNC_CMD));			}			if (rval) {				un->un_fileno = -1;				rval = EIO;			}		} else {			rval = space_fmks(dev, tmp);		}		break;	case MTFSR:		/*		 * forward space to inter-record gap		 *		 */		if (mtop->mt_count == 0) {			return (0);		}		if ((un->un_eof >= ST_EOT) && (mtop->mt_count > 0)) {			/* we're at EOM */			un->un_err_resid = mtop->mt_count;			un->un_status = KEY_BLANK_CHECK;			return (EIO);		}		/*

⌨️ 快捷键说明

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