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

📄 mscp_tape.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 5 页
字号:
		mprintf("tmscp driver error: online timed out\n");	}	if( !up->flags.online ){		/* Unit did not come online.		 * If the NO DELAY flag is not set return an error to the user.		 * otherwise NO DELAY says return success even if it failed.		 */		if( !(flag & FNDELAY)) {			Dprint8("open: ENXIO return, dev did not come online\n");			up->Tflags.tms_inuse = 0;			return( EIO );		}		/*		 * In this case the unit was opened with the FNDELAY flag set		 * and the unit failed to come online.  Hopefully no user		 * programs really do anything with the tape when it is opened		 * with the FNDELAY flag because they'd have no way of 		 * knowing if the tape was brought online correctly.		 */		else {			Dprint8("open: FNDELAY, dev did not come online\n");		}	}	return( 0 );}/* * *   Name:	tmscpclose	- Close Tape Unit * *   Abstract:	 * *   Inputs: * *   Outputs: * * *   Return	NONE *   Values: */int tmscpclose(dev, flag)    dev_t	dev;    int		flag;{    UNITB	*up;    REQB	*rp;    int		retries;	Dprint6("tmscp_close\n");    /* If there is no known unit corresponding to the device     * number, return an error.     */	if(( up = Dev_to_Tunitb( dev )) == NULL ) {		Dprint8("close: ENXIO return, unit unknown\n");		return( ENXIO );	}	/*	 * If caching is being used, the utility should have issued a flush	 * command before attempting to close the device to insure that all	 * records in the controller's write back cache have been placed onto	 * the physical media.  	 */	if (up->Tflags.tms_cach_on && up->Tflags.tms_cach_write) {		mprintf("tms warning - close without cache flush\n");		Dprint2("tms - close without cache flush\n");		/*		 * An irresponsible utility is being used.  Force a cache		 * flush operation to gain status of the write back cache.		 */		up->Tflags.tms_wait = 1;		rp = (REQB *) mscp_alloc_reqb( up, NULL, tmscp_flu_states, 			(u_long) 0, (u_long) 0 );		retries = RETRY_COUNT;		while( up->Tflags.tms_wait  && ( --retries >= 0 ) ) {			timeout( wakeup, ( caddr_t )rp, hz );			( void )sleep(( caddr_t )rp, PSWP+1 );			untimeout(wakeup, ( caddr_t )rp, hz );		}		Time_Check(up->Tflags.tms_wait, retries, "close cache flush");		up->Tflags.tms_wait = 0;              		/*		 * Check status of flush on controller's write-back cache.		 */		if ( up->tms_status == MSCP_ST_SUCC) {			Dprint3("close: successful cache flush\n");		}		else {			/*			 * This is a serious condition!  The controller's			 * write-back cache has failed to flush.  This 			 * implies that some records written to the tape may			 * not have been placed on the physical media.  Not 			 * only that, by the writes will have received a			 * success end message if the records were successfuly			 * placed in the controller's write back cache.			 *			 * The problem now is that there is really no way to			 * notify the utility of this since it is not feisable			 * to fail the close.  The only thing to do is to log			 * this error.			 *			 * Any utility which enables caching is taking chances			 * with data integrity if they don't do an explicit			 * ioctl(MTFLUSH).			 *			 * At this point the unit should be in the serious 			 * exception state.  Don't clear the serious exception			 * because the unit is suspect and other tape operations			 * should not be allowed until the exception is			 * explicitly cleared.  If the "rewind device" is being			 * used then the available command will clear the 			 * serious exception.			 *			 * Clear tms_cach_write to allow the WTM's, REWIND and			 * available commands to succeed.			 */			up->Tflags.tms_cach_write = 0;			printf("tms - unit %d cache flush failure.\n",up->unit);			printf("tms - unit %d potential data loss.\n",up->unit);		}	}	/* If the tape unit is write enabled and the tape has been written	 * on, write two (2) EOF's and then back space one (1) record.	 * If the end of media (EOM) was detected, allow EOF's to be written	 * but remember that tape is past EOM and the next command will fail.	 */	up->Tflags.tms_bufmark = 0;	up->tms_flags &= ~DEV_CSE;        if ( up->Tflags.tms_write == 1) {        	up->Tflags.tms_write = 0;		/* Write the first tape mark		 */		(void) mscp_alloc_reqb( up, NULL, tmscp_wtm_states, (u_long) 0, (u_long) 0 );		/* Write the second tape mark		 */		(void) mscp_alloc_reqb( up, NULL, tmscp_wtm_states, (u_long) 0, (u_long) 0 );		/* Now reposition back over the last tape mark 		 */		(void) mscp_alloc_reqb( up, NULL, tmscp_rpo_states, (u_long) (MSCP_MD_OBJCT | MSCP_MD_REVRS), (u_long) 1 );	}	up->Tflags.tms_write = 0;	/* If the tape unit is a 	 * no-rewind device then mark the unit available for other hosts.  The	 * available mscp command will rewind the tape therefor the unit	 * should not go available if the unit is not a rewind device. 	 */	if (up->sel & NO_REWIND) {		/* Mark the unit NOT in use so opens will work for the next user		 * that wants the tape drive.		 */		up->Tflags.tms_inuse = 0;		return( 0);	}		/* Start the rewind.  The rewind is done	 * this way because the availble command has caused the path to crash	 * due to a hardware problem.  By doing the rewind this way we can wait	 * for it to complete before allowing another process to get in the	 * driver.	*/	up->Tflags.tms_wait = 1;	rp = (REQB *)mscp_alloc_reqb( up, NULL, tmscp_rpo_states, (u_long) MSCP_MD_REWND, (u_long) 0 );	/* Here is where we wait for the rewind to finish.  We almost, if after	 * 20 min. we give up, that way we will never hang the driver if a drive	 * fails to go to reposition end message, paranoia I guess.	 */	retries = RETRY_COUNT;	while( up->Tflags.tms_wait  && ( --retries >= 0 ) ) {		timeout( wakeup, ( caddr_t )rp, hz );		( void )sleep(( caddr_t )rp, PSWP+1 );		untimeout(wakeup, ( caddr_t )rp, hz );	}	Time_Check(up->Tflags.tms_wait, retries, "rew in close");	up->Tflags.tms_wait = 0;	/* Allocate a request block and make the unit available.  	 */	rp = (REQB *) mscp_alloc_reqb( up, ( struct buf * )NULL, tmscp_avl_states, (u_long) 0, (u_long) 0 );	/* Wait for the unit to go available.  This may take a little time	 * if it waits for a rewind.	 */	retries = RETRY_COUNT;	while( up->Tflags.tms_inuse  && ( --retries >= 0 ) ) {		timeout( wakeup, ( caddr_t )rp, hz );		( void )sleep(( caddr_t )rp, PSWP+1 );		untimeout(wakeup,(caddr_t)rp);   /* to be sure*/	}	Time_Check(up->Tflags.tms_inuse, retries, "avl in close");	/* The unit went off line; clear error conditions to insure	 * correct values when the unit comes back online.	 */	up->Tflags.tms_lost = 0;	up->Tflags.tms_clserex = 0;	up->Tflags.tms_serex = 0;	up->Tflags.tms_inuse = 0;	return( 0 );}/* * *   Name:	tmscpstrategy - rtn description * *   Abstract:	 * *   Inputs: * *   Outputs: * * *   Return	NONE *   Values: */int tmscpstrategy( bp )	struct buf 	*bp;{	register UNITB	*up;	/* Check to make sure that the unit corresponding to the device number	 * exists and is online.	 */	if(( up = Dev_to_Tunitb( bp->b_dev )) != ( UNITB * )NULL && 	up->flags.online ) {		/* In an effort to make tar work with nbuffered I/O and EOM		 * this code fragment is placed here.  If the EOM handling 		 * is enabled AND a clear serious exception has NOT 		 * been done AND the EOM has been seen then return ENOSPC		 * to the user.		 */		if ( (up->Tflags.tms_eom == 0) &&		    !(up->tms_flags & DEV_CSE) &&		     (up->tms_flags & DEV_EOM)) {			bp->b_resid = bp->b_bcount;			bp->b_error = ENOSPC;			bp->b_flags |= B_ERROR;			Dprint8("strategy: ENOSPC in buf\n");			(void)iodone(bp);			return;		}		/* Make sure that the request transfer size is within		 * the limits of the controller.  This limit is known		 * by "online" or "set unit char" commands.		 */		if ((bp->b_flags == B_WRITE) && 		( up->tms_bcount < bp->b_bcount) ){			Dprint8("strategy: I/O to big\n");			Dprint8("strategy: OK count 0x%x request count 0x%x\n",up->tms_bcount,bp->b_bcount);			bp->b_error = EIO;			bp->b_flags |= B_ERROR;			( void )iodone( bp );			return;		} 		/* If the action to be done is a READ and a tape mark		 * has been seen return with an I/O error.  This is done		 * because buffered I/O may have outstanding READS which 		 * should fail.  If not n-buff I/O then allow the read to		 * proceed to read in the first record of the next file.		 * because buffered I/O may have outstanding READS which should fail.		 */		if( (up->Tflags.tms_bufmark) && 		(bp->b_flags == B_READ) && 		(bp->b_flags & B_RAWASYNC)) {			bp->b_error = EIO;			bp->b_flags |= B_ERROR;			Dprint8("strategy: EIO 1 Berror\n");			( void )iodone( bp );			return;		}			/* Allocate a request block and start the data transfer.		 */		(void) mscp_alloc_reqb( up, bp, tmscp_xfr_states, (u_long) 0, (u_long) 0 );		/* Unit number is out of range or unit is not online.		 */ 	} else {		Dprint8("strategy:offline ENXIO in buf\n");		bp->b_error = ENXIO;		bp->b_flags |= B_ERROR;		( void )iodone( bp );	}	return;}/* * *   Name:	tmscpread -  * *   Abstract:	 * *   Inputs: * *   Outputs: * * *   Return	NONE *   Values: */int tmscpread( dev, uio )	dev_t		dev;	struct uio	*uio;{	register UNITB	*up;	/* If there is no known unit corresponding to the device	 * number, return an error.	 */	if(( up = Dev_to_Tunitb( dev )) == NULL ) {		Dprint8("read: ENXIO return, unknown unit\n");		return( ENXIO );	}	/* Invoke physio to fire off the strategy routine and return	 * the resulting status.	 */	return( physio( tmscpstrategy, &up->rawbuf, dev, B_READ, minphys, uio ));}/* * *   Name:	tmscpwrite -  * *   Abstract:	Raw I/O read routine. * *   Inputs:	Device minor number and user i/o buffer * *   Outputs:	NONE * *

⌨️ 快捷键说明

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