📄 mscp_tape.c
字号:
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 + -