Trailing-Edge
-
PDP-10 Archives
-
saio_sources
-
5sources/physat.mac
There are 3 other files named physat.mac in the archive. Click here to see a list.
;<5.ISI.MONITOR>PHYSAT.MAC.5160 1-Dec-82 12:16:26 Edit by SMITH
;#516 Change PHYSAT SYSERR entry to SEC%SM since DEC now using name SEC%ST
;<5.ISI.MONITOR>PHYSAT.MAC.5070 24-Nov-82 13:39:53 Edit by SMITH
;#507 Change skip file function to use same code as SEEK ... ran out of bits
;#507 for new function.
;<5.ISI.MONITOR>PHYSAT.MAC.5000 20-Nov-82 09:50:40 Edit by SMITH
;#500 UDBDDP replaced by UDBDDM
;#500 Init tapes in order. Choose dev addr based on unit. Find next
;#500 free MTCUTB slot.
;#500 Clear US.BOT at beginning of operations.
;#500 Fix function table (SATFTB) for new function codes.
;[USC-ISIC]<ISI.MONITOR>PHYSAT.MAC.3330, 27-Jul-81 16:15:47, Ed: KODA
;#333 In SATINI, set hardware determined density to unknown
;[USC-ISIC]<ISI.MONITOR>PHYSAT.MAC.3070, 27-Jul-81 16:08:21, Ed: KODA
;#307 Don't init a tape unit if someone else already did
;<4.ISI-MONITOR>PHYSAT.MAC.2440 16-Apr-81 19:45:40 Edit by SMITH
;#244 Bug fix in SETBOT - clear write-lock bit in UDBSTS
;<4.ISI-MONITOR>PHYSAT.MAC.260 31-Mar-81 13:08:59 Edit by SMITH
;#26 Support IBM-3420 compatible Tape drives on SA10 channel
SEARCH PROLOG,PHYPAR,SERCOD
TTITLE (PHYSAT,,< - Device dependent code for magtapes on SA-10>)
; Copyright 1982, All Rights Reserved
; University of Southern California
ENTRY SATDSP ; Dispatch entry
SUBTTL Device dependent table definitions
;UDB EXTENSIONS
TUXHDN==UDBDDM ;HARDWARE DETERMINED DENSITY
;NOTE: DONT CHANGE WITHOUT FIXING MAGTAP
U.XSTS==UDBDDM+1 ; Status and device address
UE.SNS==1B0 ; Sense in progress flag
MSKSTR U%DVADR,U.XSTS(P3),.RHALF ; IBM physical device address
MSKSTR UE%SNS,U.XSTS(P3),UE.SNS ; Sense in progress
U.STCH==U.XSTS+1 ; TCH to get sense byte program
U.EPOS==U.STCH+1 ;ERROR POSITION
U.EBP==U.EPOS+1 ;ERROR BYTE POINTER
E.EBC==U.EBP+1 ;ERROR BYTE COUNTER
U.ETCF==E.EBC+1 ;TAPE CLEANER FLAG / Initial SW2
U.ETIE==U.ETCF+1 ;TIE BYTE / Initial SW1
LU.SAT==U.ETIE+1 ;LENGTH OF UDB
UDB.NM==1B17 ;BIT SET IN UDBERR TO INDICATE
; A RECOVERABLE NO MOTION ERROR
;Offsets into sense byte buffer area for certain sense bytes
SB0.3==0 ; Sense bytes 0-3 are in word 0
SB4.7==1 ; Sense bytes 4-7 are in word 1
;BIT DEFINITIONS FOR SENSE BYTES 0-3
S0.CR==1B0 ;COMMAND REJECT
S0.IR==1B1 ;INTERVENTION REQUIRED
S0.BOC==1B2 ;BUS OUT CHECK
S0.EC==1B3 ;EQUIPMENT CHECK
S0.DC==1B4 ;DATA CHECK
S0.OR==1B5 ;OVERRUN
S0.WCZ==1B6 ;WORD COUNT ZERO
S0.DCC==1B7 ;CONVERTER CHECK
S1.NSE==1B8 ;NOISE
S1.TUA==1B9 ;TU STATUS A
S1.TUB==1B10 ;TU STATUS B
S1.7TK==1B11 ;7 TRACK FEATURE
S1.BOT==1B12 ;BOT - LOAD POINT
S1.WS==1B13 ;WRITE STATUS
S1.FP==1B14 ;WRITE PROTECTED
S1.NC==1B15 ;NOT CAPABLE
S2.TIE==377B23 ;TRACK IN ERROR REGISTER
S3.VRC==1B24 ;R/W VRC
S3.MTE==1B25 ;MTE/LRC
S3.SKW==1B26 ;SKEW ERROR
S3.CRC==1B27 ;CRC ERROR
S3.ENV==1B28 ;VRC ERROR
S3.D16==1B29 ;1600 BPI
S3.BKW==1B30 ;BACKWARD STATUS
S3.CPC==1B31 ;C COMPARE
;Bit definitions for sense byte 4
S4.TPI==1B2 ; Tape position indicator (EOT seen)
;BIT DEFINITIONS FOR SENSE BYTE 6
S6.7TK==1B16 ;7 TRACK DRIVE
S6.DD==1B18 ;DUAL DENSITY TAPE UNIT
; TU IS CAPABLE OF BOTH 1600 AND 6250
S6.TMI==7B23 ;MODEL ID FIELD
; S6M.70==1 ;TU70 (ONLY WHEN ONLINE)
; S6M.71==1 ;TU71 (ONLY WHEN ONLINE)
; S6M.72==3 ;TU72
; S6M.73==13 ;TU7x (200 IPS GCR DRIVE)
SUBTTL Error recovery definitions
;RETRY COUNTS:
CLNREC==5 ;SP REVERSE THIS NR RECORDS TO HIT CLEANER
RTYOP==4 ;RETRY OPERATION THIS MANY TIMES BEFORE TAPE CLEAN SEQUENCE
RTYCLN==^D10 ;RETRY CLEAN SEQUENCE THIS MANY TIMES ON READ
; BEFORE GIVING UP
; THE TOTAL NR OF RD RETRIES = RTYOP*(RTYCLN+1)
RTYWRT==^D14 ;# WRITE RETRIES MAXIMUM BEFORE ABORT
RTY.DN==16 ;CODE SIGNAL END OF RETRY
RTY.CP==17 ;CODE TO CHECK POSITION
;ERROR WORDS
; E.EBC ;ERR BYTE COUNTER (USED IF WE HIT BOT
;DURING TAPE CLEAN SEQUENCE)
; U.EBP ;ERR BYTE POINTER
; U.ETCF ;-1= IN TAPE CLN SEQUENCE, 0= NOT
; UDBERR(RH) ;CURRENT FUNCTION (1 - 17)
;ON RETRY OF ORIGINAL OPERATION, THIS LOC
;MUST BE SET TO THE ORIGINAL OPERATION
; UDBERC ;RETRY COUNT
;CONVERTED TO # RETRIES DONE AT END
; U.EPOS ;WE SHOULD BE HERE WHEN WE'RE
;READY TO RETRY OPERATION
SUBTTL Dispatch for SA-10 magtapes
SATDSP::JRST SATINI ;0 - INITIALIZATION
JRST SATSIO ;1 - START I/O
JRST SATINT ;2 - HANDLE INTERRUPT
JRST SATERR ;3 - ERROR RECOVERY
JRST SATHNG ;4 - HUNG DEVICE
RET ;5 - NOT USED
RET ;6 - Not used
JRST SATSIO ;7 - START POSITION OPERATION
JRST SATATN ;10 - ATTENTION INTERRUPT (CALLED AS MANY
; TIMES AS THERE ARE SAT0 DRAS BITS UP)
JRST SATPRQ ;11 - SKIP IF POSITION REQUIRED
RET ;12 - STACK SECOND COMMAND, ALWAYS FAILS
JRST EXTUDB ;13 - check legality of a unit
; Some dummy returns
SATATN: RET ; No attention interrupts
; Hung device
SATHNG: MOVX T1,<IS.DVE!IS.ERR!IS.NRT> ;SET FATAL BITS
IORM T1,IRBSTS(P4) ;AND REFRESH IT
MOVX T1,UE.SNS ; Reset sense in progress
ANDCAM T1,U.XSTS(P3) ; In extra status word
MOVE T1,SSACUB(P1) ; Get current active UDB
CAIN T1,(P3) ; This UDB?
SETOM SSACUB(P1) ; Yup - not active anymore
RET
;HERE TO DETERMINE IF THIS REQUEST SHOULD GO ON PWQ OR TWQ
SATPRQ: RET ; ###### Always on TWQ !!!!!!
SUBTTL Initialize a magtape drive
; Input:
; Q2/ Logical unit number
; P1/ CDB address
SATINI: SETZ P3, ; Say we don't have this unit
MOVE T1,SSASCI(P1) ; Get subchannel number
CAME T1,SMTSCN ;#500 We only have tapes on this subchannel
RET ; No - end of this routine
MOVE T3,[ XWD SATDSP,LU.SAT ] ; Dispatch address,,length of UDB
CALL PHYUDB ; Allocate a UDB
RET ; Return now if we failed
HRLOI T3,-MTAN-1 ;#500 search through MTCUTB
SATIN1: AOBJP T3,CPOPJ ;#500 return if all tapes done
SKIPE MTCUTB(T3) ;#500 this logical unit in use?
JRST SATIN1 ;#500 yes, try next
HRLM P1,MTCUTB(T3) ;#500 LH - CDB address
HRRM P3,MTCUTB(T3) ;#500 RH - UDB address
MOVEI T1,.IDMTA(Q2) ;#500 Get physical device address for this unit
STOR T1,U%DVADR ; Save it in UDB
HRL T1,CDBADR(P1) ; Channel #,,device address
MOVEM T1,UDBDSN(P3) ; Save as serial number of this drive
MOVEI T1,3 ; Allocated area for sense byte program
CALL SSAALC ; Has to be in low core area
BUG(SATINR) ; SATINI - Can't allocate necessary space
CALL SETSNP ; Set up channel program to get sense bytes
MOVEM T1,U.STCH(P3) ; Save TCH to the program for use later
SETZ T2, ; Reset this channel
CALL SAINGO ; and start get sense bytes program
JRST [ SETZB T2,T1 ; Zero bytes 0-3 and 4-7
DMOVEM T1,MTASEN ; Store fake info in sense byte area
JRST .+1 ] ; Continue with main stream
MOVX T3,US.TAP ; Tape unit associated with this UDB
HLLM T3,UDBSTS(P3) ; Save status info
MOVE T1,MTASEN+SB4.7 ; Get sense bytes 4-7
MOVX T2,.UTCT1 ; Assume we have Calcomp magtape drives
; which are the same as DEC TU70s
TXNE T1,S6.7TK ; 7 track drive present?
BUG(SATN7T) ; SATIUN - 7 track drive not implemented yet
STOR T2,USTYP,(P3) ; Store drive type number
MOVE T1,[ UC.800!UC.160!UC.CD!UC.AA!UC.IC!UC.HD ] ; Characteristics for
; this drive type
MOVEM T1,UDBCHR(P3) ; Save them in UDB
SETOM TUXHDN(P3) ;#333 Unknown density
RET ; End of SATIUN
; SETSNP - Set up channel program to read sense bytes
;
; Input:
; T1/ Address in low core to store channel program
; P1/ CDB address
; P3/ UDB address
;
; Output:
; T1/ Channel transfer word
SETSNP: MOVE T2,[ DCW <XCT,BYT>,.ICSNS,0 ] ; Execute, byte mode, get sense bytes ; and leave device address 0
LOAD T3,U%DVADR ; Get physical device address
STOR T3,SC%DEV,T2 ; Set device address in device command word
MOVEM T2,0(T1) ; Store command word in channel program
MOVE T3,[ IOW ^D24,MTASEN ] ; Create IOW for this command
MOVEM T3,1(T1) ; Store it in channel program
SETZM 2(T1) ; End channel program
TXO T1,TCH ; Set transfer
RET ; All done - sense byte program ready to go
SUBTTL Start magtape I/O
; SATSIO - Start I/O
;
; Input:
; P4/ IORB address
SATSIO: HRRZ Q1,UDBERR(P3) ; Get function if in error recovery
SKIPN Q1 ; Test if in error recovery
LDB Q1,IRYFCN ; If not error then load function from IORB
SKIPL IRBSTS(P4) ; Short IORB?
SKIPG Q1,SATFTB(Q1) ; Or illegal function
JRST BADSI1 ; Return error bits set
SKIPE UDBERR(P3) ; Error recovery SIO?
JRST [ LDB T1,IRYFCN ; Yes - get current function from IORB
HRRZ T2,UDBERR(P3) ; and recovery function from UDB
CAME T1,T2 ; If the same then start up original transfer
JRST .+1 ; To mainstream if no same
JRST STCHAN ] ; Start original channel program (already set up)
CALL SETMOD ; Set up mode set instruction
JRST BADSI1 ; Set error bits on error return
; Q3 has pointer into channel program area
CALL SETDCW ; Set up function instruction
JRST BADSI1 ; Error
MOVX T1,US.BOT ;#500 no longer at beginning of tape
ANDCAM T1,UDBSTS(P3) ;#500 .
SKIPE UDBERR(P3) ; Check if error recovery
JRST SATEIO ; Handle it
TXNN Q1,TB.DOP ; Is this a data operation?
JRST [ SETZM (Q3) ; Yes - then end program here
JRST STCHAN ] ; and start it
CALL PHYXFL ; Otherwise, get transfer list pointer
MOVE Q2,T1 ; Copy start address
SETZ T3, ; Zero last page number
LOAD T4,IRBDM,(P4) ; Get data mode from IORB
; AC usage in following loop to copy from transfer list in IORB to IOWs
; in channel program area:
;
; T3/ Last physical page number of transfer word
; T4/ Data mode for this transfer
; Q3/ Current pointer in channel program area
; Q2/ Current pointer in transfer list
XLMOV: SKIPN T2,(Q2) ; Get and test xfer list entry
JRST XLEND ; If 0 then end of list
LOAD T1,SC%PAG,T2 ; Get physical page number
CAIE T1,(T3) ; Same as last?
CALL CASHFP ; If not then flust this page
MOVEI T3,(T1) ; Save last page number
TXZ T2,SC%LST ; Not the last command
CAIE T4,IRM8BT ; Industry compatability mode?
JRST XLOAD ; No - count is correct
LOAD T1,SC%CNT,T2 ; Yes - we must change word count to byte count
LSH T1,2 ; by multiplying by 4.
STOR T1,SC%CNT,T2 ; Update it in IOW
XLOAD: MOVEM T2,(Q3) ; Copy in to channel area
ADDI Q3,1 ; Increment to next channel entry
AOJA Q2,XLMOV ; Next entry in xfer list also
XLEND: SETZM (Q3) ; End the channel program
MOVX T1,SC%LST ; Mark last IOW with last command in chain
IORM T1,-1(Q3) ; bit
STCHAN: MOVX T2,UE.SNS ; Reset sense byte wait flag
ANDCAM T2,U.XSTS(P3) ; in status word
STCHN0: MOVEI T1,MTCHCL ; Start of channel program
STCHN1: TXO T1,TCH ; Make it a transfer word
CALL SSAGO ; Start the channel going
SETOM SSACUB(P1) ; New I/O so no busy request outstanding
RETSKP ; Return success
; Here if anything is wrong with the I/O request.
BADSI1: MOVX T1,IS.ERR!IS.DVE!IS.NRT ; Set error bits
IORM T1,IRBSTS(P4) ; in IORB
RET ; Error return
; Here when we are in error recovery
SATEIO: SETZM (Q3) ; End recovery channel program
MOVEI T1,MTRECP ; Start of recovery program
JRST STCHN1 ; Start it
; SETMOD - Create the mode set command
;
; Output:
; Q3/ Pointer to place next channel instruction
;
; Returns:
; +1 Error - incorrect mode
; +2 Ok
SETMOD: MOVEI Q3,MTCHCL ; Get start of channel area for normal I/O
SKIPE UDBERR(P3) ; In error recovery?
MOVEI Q3,MTRECP ; Yes - use recovery channel area
TXNE Q1,TB.NFC ; If no word count needed then don't do a mode set
RETSKP ; Thats all
LOAD T1,IRBDN,(P4) ; Get density
CAIE T1,.SJDN8 ; Only 800 and
CAIN T1,.SJD16 ; 1600 BPI are acceptable
TRNA ; It was either 800 or 1600
RETBAD ; Error return
MOVX T2,.IC916 ; Assume 1600 BPI, load mode set command code
CAIE T1,.SJD16 ; 1600?
MOVX T2,.IC908 ; It was 800 BPI, load mode set command code
MOVE T1,[ DCW <XCT,NMX,CHN>,0,0 ] ; Execute, no memory xfer, chain
STOR T2,SC%CMD,T1 ; Store command code
LOAD T2,U%DVADR ; Get physical device address
STOR T2,SC%DEV,T1 ; Store it to complete DCW
MOVEM T1,(Q3) ; Place it in channel area
AOJA Q3,RSKP ; Success
; SETDCW - Set up Device Command Word for the I/O operation
;
; Input:
; Q3/ Pointer to next free entry in channel program area
;
; Output:
; Q3/ Updated channel program pointer
;
; Returns:
; +1 Error
; +2 Ok
SETDCW: LOAD T2,IRBDM,(P4) ; Get data mode
CAILE T2,IRMMAX ; Of illegal
RETBAD ; Error
MOVX T1,FLD(<.SCXCT!.SCNMX>,SC%CCF) ; Execute and no memory xfer
TXNE Q1,TB.DOP ; Data operation?
JRST [ TXZ T1,FLD(.SCNMX,SC%CCF) ; Want to have memory xfer
SKIPGE T2,MODSAT(T2) ; Convert software mode to hardware bits
RETBAD ; Error if illegal mode
IOR T1,T2 ; Set them in DCW
TXNE Q1,TB.WRD ; Writing on tape?
TXO T1,FLD(.SCILE,SC%CCF) ; Yes - suppress length error
JRST .+1 ] ; Back to mainstream
LOAD T2,U%DVADR ; Get physical device address
STOR T2,SC%DEV,T1 ; Store it
STOR Q1,SC%CMD,T1 ; Store command code also
MOVEM T1,(Q3) ; Place it where it will be executed
AOJA Q3,RSKP ; Success return
SUBTTL Interrupt handler for magtapes
; Input:
; P1/ CDB address
; P3/ UDB address
SATINT: SETZ P4, ; Assume no IORB
MOVE T4,CDBCS1(P1) ; Get status word 1
JUMPE P3,[ BUG(SATUUN,<<T4,SW1>>) ; SATINT - Interrupt from unknown unit
JRST NOACT1 ] ; Check if we can start I/O
MOVX T1,US.ACT ; See if this unit is active
TDNE T1,UDBSTS(P3) ; If not active don't get IORB
CALL SETIRB ; Need IORB address in P4
TXNE T4,FLD(<.S1BIP!.S1CSE!.S1PIF>,S1%CHS) ; Any funny bits on?
JRST [ BUG(SATFSB,<<T4,SW1>>) ; SATINT - Bad status in channel
RETSKP ] ; Dismis this interrupt
TXNE T4,FLD(.S1SER,S1%CHS) ; Select error?
JRST SELERR ; Handle it
JUMPE P4,NOACTV ; Handle the interrupt from non-active unit
HRRZ T1,UDBERR(P3) ; Load error function if any
SKIPN T1 ; Skip if no error recovery
LDB T1,IRYFCN ; Get function from IORB
MOVE Q1,SATFTB(T1) ; Get function table entry
LOAD T1,S1%DVS,T4 ; Get device status byte from status word
JN UE%SNS,,SATSNS ; Jump if sense bytes were requested
MOVX T2,IS.DTE!IS.DVE ; Get data and device error bits
ANDCAM T2,IRBSTS(P4) ; So we can reset them before checking errors
CAIE T1,.S1CHE!.S1DVE ; Normal end? (Channel and device end)
CAIN T1,.S1CHE!.S1DVE!.S1UEX ; Also ignore unit exception
TRNA ; This is the ok case of no error
JRST NOEASY ; Not a normal ending status
SATNDN: CALL UPDINF ; Updated info in UDB and IORB
SKIPE UDBERR(P3) ; See if in error recovery
RET ; If so let error recovery know
RETSKP ; All done with a normal end (end of I/O)
; Handle select error
SELERR: JUMPN P4,SATFER ; If IORB exists then mark it in error
BUG(SATSEN,<<UDBADR(P3),Unit>>) ; SATINT - Select error from non-active unit
RETSKP ; Dismis this interrupt
SATDIS: SETZ P4, ; Flag to dismis this interrupt
RETSKP ; Back to PHYINT
; This interrupt is from sense program
SATSNS: MOVX T2,UE.SNS ; Clear sense bit
ANDCAM T2,U.XSTS(P3) ; from UDB
TXNN T1,.S1CHE ; Channel end (got sense bytes)?
JRST SATFER ; No - error in getting sense bytes
TXNE Q1,TB.UNL ; From an unload?
RETSKP ; If so then thats the end of this operation
DMOVE T1,MTASEN ; Get sense bytes 0-3 and 4-7
TXNE T1,S1.BOT ; At BOT (load point)?
CALL SETBOT ; If so mark IORB and clear position counters
TXNE T1,S0.IR!S0.BOC ; Intervention req or bus parity
JRST HRDERR ; is a device error
TXNE T1,S0.CR ; Command reject?
JRST CMDREJ ; Look in it further
TXNE T1,S0.DC ; Data check?
JRST CKDATC ; Yes - check further
SKIPE UDBERR(P3) ; In error recovery?
JRST SATFER ; If so then make it a fatal data error
HRDERR: MOVX T1,IS.ERR!IS.DVE!IS.NRT ; %%%% Temp - handle as device error
IORM T1,IRBSTS(P4)
RETSKP
CMDREJ: TXNE T1,S1.FP ; File protected and
TXNE Q1,TB.WRT ; trying to write to tape?
TRNA ; Yes - can't write to protected tape
JRST HRDERR ; If not then device error
MOVX T1,IS.ERR!IS.WLK!IS.DVE!IS.NRT ; Set appropriate error bits
IORM T1,IRBSTS(P4) ; Set error in IORB
RETSKP ; End of I/O
CKDATC: MOVX T1,IS.ERR!IS.DTE ; Set data error bit
IORM T1,IRBSTS(P4) ; in IORB
RETSKP ; End of I/O
; Here is the case when we don't have channel and device end (maybe error)
NOEASY: CAIN T1,.S1CHE ; Only channel end?
JRST CKCHE ; Yes - check it out
TXNE T1,.S1DVE ; No - how about device end?
JRST DEVEND ; Yes - handle it
TXNE T1,.S1UCK ; No - unit check bit set?
JRST SATUCK ; Yes - handle error
TXNE T1,.S1BSY ; No - was TCU or TU busy?
JRST [ HRRZM P3,SSACUB(P1) ; Say that this UDB is active and waiting
JRST SATDIS ] ; for TCU or TU to be free
TXNE T1,.S1CUE ; Control unit end?
JRST SATCUE ; Yes - maybe able to start I/O
; Here is above tests don't make it.
SATFER: MOVX T1,IS.ERR!IS.DTE!IS.NRT ; Set error bits
IORM T1,IRBSTS(P4) ; in IORB
RETSKP ; End of I/O, had a fatal error
; Control unit end - means that the TCU is now able to accept a command.
NOACTV: JN UE%SNS,,SATONL ; Jump if we were asking for sense bytes
NOACT1: TXNE T4,FLD(.S1DVE,S1%DVS) ; See if device end (rewind complete)
JRST [ JUMPE P3,.+1 ; If unknown unit then back to mainstream
MOVX T1,US.REW ; Test if this unit was rewinding
TDNN T1,UDBSTS(P3) ;
JRST SATUC1 ; Must be new unit coming on-line, get sense bytes
CALL PHYRWD ; If rewinding then let PHYSIO know its done
JRST SATDIS ] ; Dismis this interrupt
TXNN T4,FLD(.S1CUE,S1%DVS) ; Must have Control Unit End
JRST NACTER ; If not then its an error
SATCUE: SKIPG T1,SSACUB(P1) ; Get UDB of active request
JRST NACTER ; If none then its an error
SATDV1: SAVEP ; Save some ACs
MOVE P3,T1 ; New UDB address
JRST STCHN0 ; Start request and dismis this interrupt
SATONL: MOVX T2,UE%SNS ; Clear sense bytes request flag
ANDCAM T2,U.XSTS(P3) ;
TXNN T4,FLD(.S1CHE,S1%DVS) ; See we have sense bytes
JRST [ BUG(SATSON,<<T4,SW1>>) ; PHYSAT - Can't get sense bytes for a unit coming on-line
JRST SATDIS ] ; Ignore this unit
MOVX T2,US.WLK ; Write lock bit
ANDCAM T2,UDBSTS(P3) ; Clear it in UDB
MOVE T1,MTASEN ; Get first 4 sense bytes
TXNE T1,S1.FP ; Write ring?
IORM T2,UDBSTS(P3) ; No - set write lock flag in UDB
CALL PHYONL ; Set unit online
JRST SATDIS ; Dismis now
NACTER: JUMPE P4,RSKP ; If no IORB then ignore this interrupt
BUG(SATUCE,<<T4,SW1>>) ; SATINT - Unexpected Control Unit End
JRST SATFER ; If active then abort this request
; Channel end seen
CKCHE: TXNN Q1,TB.REW ; Are we rewinding?
JRST SATDIS ; No - then dismis this interrupt (need device end)
MOVX T1,US.REW ; Yes - mark that this unit is busy
IORM T1,UDBSTS(P3) ; rewinding
CALL SETBOT ; Set BOT in IORB and clear position counters
RETSKP ; End of I/O
; Device end
DEVEND: SKIPLE T1,SSACUB(P1) ; Is there a request pending?
JRST SATDV1 ; Yes - start I/O again
TXNE T4,FLD(.S1UCK,S1%DVS) ; Unit check?
JRST SATUCK ; Handle error
CALL UPDINF ; Update UDB and IORB
RETSKP ; No errors all done
; Unit check - start error recovery procedure
SATUCK: TXNE Q1,TB.UNL ; Unloading a tape?
JRST [ CALL CLRPOS ; Clear tape position
JRST SATUC1 ] ; Merge to get sense bytes
MOVE T1,CDBCS1(P1) ; Get current status word
MOVEM T1,U.ETIE(P3) ; Save for error block
MOVE T1,CDBCS2(P1) ; Get current status word 2
MOVEM T1,U.ETCF(P3) ; Save for later error entry
CALL UPDINF ; Update UDB and IORB
; Unit check from a unit that has unloaded a tape will sometimes hang if
; no sense bytes are retrieved. Therefore the unload command handling
; will flow like error handling but will terminate when the sense bytes
; are read in.
SATUC1: MOVX T1,UE.SNS ; Get flag bit
IORM T1,U.XSTS(P3) ; Set flag requesting sense bytes
MOVE T1,U.STCH(P3) ; Tranfser word to sense byte program
CALL SSAGO ; Start it
JRST SATDIS ; Dismis this interrupt
; This routine set IS.BOT in the IORB and clear UDBPS1 and UDBPS2
SETBOT: MOVX T3,IS.BOT ; If rewind then set at BOT
IORM T3,IRBSTS(P4) ; in IORB
CALL CLRPOS ; Zero tape position
MOVX T1,US.WLK ;#244 Get write-lock bit
ANDCAM T1,UDBSTS(P3) ;#244 Clear it from UDB (assume its writeable)
RET ; End of SETBOT
; Routine to zero tape position
CLRPOS: SETZM UDBPS1(P3) ; Zero file position
SETZM UDBPS2(P3) ; and record position
RET ; End of routine
SUBTTL Miscellaneous routines needed for interrupt handling
; UPDINF - Update statistical information in UDB and IORB
;
; Input:
; T4/ Status word 1
; Q1/ Function entry from SATFTB
; P4/ IORB
UPDINF: TXNN T4,FLD(.S1LNE,S1%CHS) ; Length error reported?
JRST UPDNLE ; No - don't calculate bytes transferred
SKIPN UDBERR(P3) ; If in error recovery or
TXNE T4,FLD(.S1UCK,S1%DVS) ; unit check
JRST UPDNLE ; Then don't update transfer count
TXNN Q1,TB.DOP ; Must be a data operation
BUG(SATULE,<<T4,SW1>>) ; SATINT - Length error on a non-data request
CALL GTXFRC ; Get correct number of frames read
MOVEM T1,IRBCNT(P4) ; Save it in IORB
UPDNLE: TXNN Q1,TB.DOP ; Data operation?
JRST UPDIN1 ; No - don't update counters
MOVE T1,IRBCNT(P4) ; Get frames read/write for this operation
TXNE Q1,TB.RD ; Read?
ADDM T1,UDBRED(P3) ; Update frames read count
TXNE Q1,TB.WRD ; Write data?
ADDM T1,UDBWRT(P3) ; Update write count
UPDIN1: TXNE Q1,TB.ERA ; Erase gap?
JRST UPDIN2 ; If so then don't record position change
TXNE Q1,TB.REV ; Reverse?
SOSA UDBPS2(P3) ; Record position
AOS UDBPS2(P3) ;
UPDIN2: TXNN T4,FLD(.S1UEX,S1%DVS) ; Unit exception?
RET ; No, all done
SETZ T1, ; Zero status word
TXNE Q1,TB.RD!TB.SPC ; Read or space?
JRST [ TXO T1,IS.TPM ; Yes - must have hit a tape mark
TXNE Q1,TB.REV ; Reverse?
SOSA UDBPS1(P3) ; Yup - backup file count
AOS UDBPS1(P3) ; Foward - bump file count
JRST .+1 ] ; Back to mainstream
TXNE Q1,TB.WRT ; Writing?
TXO T1,IS.EOT ; Yes - hit End-of-Tape marker
IORM T1,IRBSTS(P4) ; Update info in IORB
RET ; All done
; GTXFRC - Get transfer count
;
; Input:
; P4/ IORB address
;
; Note: This routine is called only in the case of a Read operation with
; length error.
GTXFRC: PUSH P,T4 ; Save status word 1
MOVEI T4,MTCHCL+2 ; Point to to 1st IOW
HRRZ T3,CDBCS2(P1) ; Get where the channel program stopped
SUBI T3,(T4) ; # of IOWs executed
MOVNI T3,(T3) ; Need it negative
HRLI T4,(T3) ; We now have: -n,,pointer to 1st IOW
HLLZ T3,CDBCS2(P1) ; Get residual count
ASH T3,WCSIZ-^D35 ; Make it a negative count
MOVN T1,T3 ; Store as positive count since its number of
; of bytes/words left
GTXFR1: MOVE T3,(T4) ; Get IOW
TXO T3,SC%LST ; Make sure we get a negative number
ASH T3,WCSIZ-^D35 ; Get negative count
ADD T1,T3 ; Count this word
AOBJN T4,GTXFR1 ; Keep going until done
POP P,T4 ; Restore status word 1
MOVX T2,IS.TPM ; Set or clear Tape mark flag based on count
JUMPE T1,[ IORM T2,IRBSTS(P4) ; Zero count is a tape mark
RET ] ; Return to caller
ANDCAM T2,IRBSTS(P4) ; Clear TM seen
MOVN T1,T1 ; Return positive count
RET ; Thats all
SUBTTL Error recovery
; SATERR - Code to handle magtape errors
;
; Input:
; Q1/ Syserr block address
; P1/ CDB address
; P3/ UDB address
;
; Output:
; P4/ IORB address
;
; Returns:
; +1 Error recovery in progress
; +2 Done with error, fatal or soft error
SATERR: SAVEQ ; Need Q regs
CALL SETIRB ; Get IORB address in P4
HRRZ Q1,UDBERP(P3) ;GET ERROR BLOCK IF PRESENT
HLLZ T1,IRBSTS(P4) ;GET IORB STATUS
HRRZ T4,UDBERR(P3) ;GET FUNCTION IF ERROR RECOVERY
SKIPN T4 ;IN ERROR RECOVERY?
LDB T4,IRYFCN ;NO, GET FN FROM IORB
MOVE T4,SATFTB(T4) ;NOW TABLE ENTRY
TXNN T1,<IS.NRT!IS.IER> ;FATAL OR INHIBIT ERR RECOVERY?
JRST STERTY ;NO, RETRY THE ERROR
SKIPE U.EBP(P3) ;WAS FATAL ERR DURING RETRY?
JRST ABTNOS ;YES, WE ALREADY HAVE BEGIN DATA
AOS (P) ;SKIP RET FROM BEGLOD - DONE WITH IORB
JRST BEGLOD ;LOAD UP ERR BLK FOR FATAL ERR
;DO RETRY
STERTY: HLR T4,T4 ;COPY LH OF FNTBL
TRZ T4,777770 ;SAVE ONLY RETRY INDEX IN RH
SKIPE UDBERC(P3) ;1ST TIME FOR HERE?
JRST NOT1ST ;NO
CALL BEGLOD ;LOAD UP ERR BLK WITH BEGIN DATA
SETZM U.ETCF(P3) ;NOT DOING TAPE CLEAN
SKIPN T1,RTYBPT(T4) ;GET RETRY BYTE POINTER
JRST [ BUG(SATIDX) ; PHYSAT - ILLEGAL RETRY BYTE POINTER
JRST ABTNOS] ;CALL IT FATAL
MOVEM T1,U.EBP(P3) ;SAVE IT
MOVE T1,UDBPS2(P3) ;GET # RECORDS
SUBI T1,1 ;WHERE ERROR OCCURRED
TXNE T4,TB.REV ;IF IN FORWARD, WE WANT (CUR POSITION-1)
ADDI T1,2 ;IF REVERSE, WE WANT (CUR POSITION+1)
MOVEM T1,U.EPOS(P3) ;WHERE WE SHOULD BE SOMEDAY
MOVEI T1,RTYWRT+1 ;ON WRITE, THIS MANY RETRIES
TXNN T4,TB.WRT ;ARE WE RIGHT (WRITE)?
MOVE T1,[RTYCLN+1,,RTYOP+1] ;NO, THIS IS FOR READ
MOVEM T1,UDBERC(P3) ;THE RETRY COUNTER
JRST NXTBYT ;1ST TIME THRU SATERR
NOT1ST: MOVE T1,U.EBP(P3) ;GET RETRY BYTE POINTER
ILDB T1,T1 ;LOOK AT NEXT OPERATION
CAIE T1,RTY.DN ;END OF RETRY
JRST CKBOT ;NO
SKIPE Q1 ; Make sure we have error block pointer
AOS SEBDAT+MB%FEC(Q1) ; Count this retry
HLLZ T1,IRBSTS(P4) ;GET IORB STATUS
TXNN T1,IS.DTE ;WAS THERE DATA ERR?
JRST RTYNOE ;NO, WE'VE RECOVERED!
MOVE T1,RTYBPT(T4) ;GET BYTE POINTER
MOVEM T1,U.EBP(P3) ;RESET IT
SETZM U.ETCF(P3) ;NOT DOING TAPE CLN SEQUENCE
HRRZ T1,UDBERC(P3) ;GET ABORT COUNTER
SUBI T1,1 ;ANOTHER RETRY - SEE IF WE'VE LOST
HRRM T1,UDBERC(P3) ;SAVE IT
JUMPN T1,NXTBYT ;IF NOT 0, TRY AGAIN
TXNE T4,TB.DOP ;DATA OPERATION?
TXNN T4,TB.RD ;WRITE OR READ?
JRST ABTRTY ;NON DATA OR WRITE - WE'VE FAILED
HLRZ T1,UDBERC(P3) ;GET TAPE CLNR COUNTER
SOJE T1,ABTRTY ;RUN OUT OF RETRIES? - YES
HRLM T1,UDBERC(P3) ;NO, UPDATE CLN COUNTER
MOVX T1,RTYOP+1 ;NOW RESET (RH) COUNTER
HRRM T1,UDBERC(P3) ;FOR NEXT CLEAN RETRY
MOVE T1,UDBPS2(P3) ; Get current record #
CAIGE T1,6 ; Must have room to back up 6 records
JRST NXTBYT ; Otherwise no tape clean seq can be done
MOVE T1,RTYBPT+1(T4) ;GET CLEANER SEQ BYTE POINTER
MOVEM T1,U.EBP(P3) ;SAVE FOR USE LATER
SETZM E.EBC(P3) ;RESET COUNT FOR USE IF WE HIT BOT
SETOM U.ETCF(P3) ;WE ARE DOING A CLEAN
JRST NXTBYT ;NOW DO NEXT OPERATION
CKBOT: SKIPN U.ETCF(P3) ;DOING TAPE CLEAN?
JRST NXTBYT ;NO DON'T CHECK BOT
HLLZ T1,IRBSTS(P4) ;GET STATUS
TXNE T1,IS.BOT ;OR DID WE HIT BOT?
SKIPA T1,[CLNREC] ;YES, FIGURE OUT HOW TO FUDGE BYTE POINTER
JRST NXTBYT ;NO, CONTINUE NORM RETRY
LDB T3,IRYFCN ;GET ORIGINAL FN
MOVE T3,SATFTB(T3) ;GET FLAGS
TXNE T3,TB.WRT ;IS IT A WRITE?
JRST NXTBYT ;WRITE RETRY WON'T EVER HIT BOT SO NO FUDGE
TXNN T3,TB.REV ;ADD 1 IF FORWARD
ADDI T1,1 ;DO IT ON FORWARD
SUB T1,E.EBC(P3) ;SUBT # RECORDS SPACED
LSH T1,1 ;TIMES 2 (COMMENTS ASSUME CLNREC=5)
ADDI T1,1 ;ON FORWARD, SKIP (6-CNT)*2+1 BYTES
CAIL T1,1 ;ON REVERSE, SKIP (5-CNT)*2+1 BYTES
CAILE T1,^D9 ;RESULT MUST BE BETWEEN 1 AND 9
JSP CX,CNFERR ;BAD INCR, WE ARE CONFUSED
ADJBP T1,U.EBP(P3) ;ADJUST POINTER
MOVEM T1,U.EBP(P3) ; AND PUT ADJUSTED POINTER BACK
NXTBYT: AOS E.EBC(P3) ;ANOTHER BYTE FOR THE COUNTER
ILDB T3,U.EBP(P3) ;GET NEXT FUNCTION
CAIE T3,RTY.CP ;IS IT CHECK POSITION OPERATION?
JRST NOTCKP ;NO
MOVE T1,UDBPS2(P3) ;YES, GET OUR POSITION
CAMN T1,U.EPOS(P3) ;ARE WE WHERE WE WANT TO BE?
JRST NXTBYT ;YES, ALL OK
JSP CX,CNFERR ;POSITION CONFUSED,SIGNAL ERROR
JRST ABTNOS ;BOMB OUT
NOTCKP: CAIE T3,RTY.DN ;END OF RETRY?
SKIPG T3 ;IS FUNCTION VALID?
JRST [ BUG(SATIRF,<<T3,Function>>) ; PHYSAT - ILLEGAL FUNCTION DURING RETRY
JRST ABTNOS] ;IMAGINE FATAL
HRRM T3,UDBERR(P3) ;SAVE FUNCTION
HRRZ T1,CDBDSP(P1) ;GET CHANNEL DISPATCH
CALL CDSSIO(T1) ;START IO
JRST ABTNOS ;COULDN'T START UP RETRY OPERATION
RET ;AND WAIT
RTYNOE: TXNE T1,IS.NRT ;HARD ERRS SHOULDN'T EVER GET HERE
BUG(SATNRT) ; SATERR - IS.NRT SET ON SUCCESSFUL RETRY>)
MOVX T1,IS.ERR ;WE DID IT! CLEAR ERR BIT
ANDCAM T1,IRBSTS(P4) ;AND SKP RETURN
TXNN T4,TB.WRT ;ARE WE WRTING?
AOSA UDBSRE(P3) ;NO, A SOFT READ ERR
AOS UDBSWE(P3) ;YES, A SOFT WRITE ERR
JRST ABTNOS
;HERE WHEN ERROR RECOVERY GETS CONFUSED(FLAKEY HARDWARE W I L L DO IT)
CNFERR: BUG(SATRFU);(,<PHYSAT - ERROR RECOVERY CONFUSED>)
MOVSI T1,(IS.ERR!IS.NRT) ;INDICATE RATHER HARD ERR
IORM T1,IRBSTS(P4) ; ...
JRST ABTNOS ;AND ABORT
ABTRTY: ;WE RAN OUT OF RETRIES
TXNN T4,TB.WRT ;ARE WE WRTING?
AOSA UDBHRE(P3) ;NO, A HARD READ ERR
AOS UDBHWE(P3) ;YES, A HARD WRITE ERR
ABTNOS: AOS (P) ;SKIP RET FROM ENDLOD
HRRZ Q1,UDBERP(P3) ;GET ERROR BLOCK
SKIPN U.EBP(P3) ;DONE ANY RETRIES?
JRST ENDLOD ;NO, LOAD UP ERR BLK WITH END DATA
TXNN T4,TB.WRT ;YES, IN A WRITE?
JRST RDCNT ;NO
MOVEI T1,RTYWRT+1 ;YES, CALCULATE # RETRIES DONE
SUBM T1,UDBERC(P3) ;RESIDUE
JRST ENDLOD ;NOW LOAD UP ERR BLK
RDCNT: HLRZ T1,UDBERC(P3) ;GET CLN COUNTER
IMULI T1,RTYOP ;CONVRT JUST TO # RETRIES
ADD T1,UDBERC(P3) ;ADD IN REGULAR RETRIES
MOVEI T2,<RTYCLN+2>*RTYOP+1 ;COUNT AT START
SUB T2,T1
HRRZM T2,UDBERC(P3) ;SAVE # RETRIES
JRST ENDLOD ;NOW LOAD UP ERR BLK
;BEGLOD - ROUTINE TO LOAD UP THE ERROR BLOCK AT
; THE START OF THE ERROR
; Q1/ERROR BLOCK ADDRESS
; CALL BEGLOD
; RETURN+1: ALWAYS
BEGLOD: JUMPE Q1,R ;IF NO ERROR BLOCK, PUNT
PUSH P,T4 ; Save function word
MOVE T1,Q1 ;COPY ERROR BLOCK
MOVE T2,[-NITAB,,ITAB] ;POINTER TO INFORMATION TABLE
CALL SEBCPY ;COPY INFORMATION
JFCL
MOVS T1,UDBPS1(P3) ;GET FILE
HRR T1,UDBPS2(P3) ;AND RECORD (JUST AFTER ERROR)
MOVEM T1,SEBDAT+MB%LOC(Q1) ;AND SAVE AS LOCATION OF ERROR
LOAD T1,U%DVADR ; Get device address
MOVEM T1,SEBDAT+SM%DVA(Q1) ; Save for SYSERR
POP P,T4 ; Restore function word
RET
;ENDLOD - ROUTINE TO LOAD UP THE ERROR BLOCK AT
; THE END OF THE ERROR
; Q1/ERROR BLOCK ADDRESS IF ANY
; CALL ENDLOD
; RETURN+1: ALWAYS
ENDLOD: SETZM U.EBP(P3) ;ZERO, SO IF ERROR WITH IS.NRT
; SET ERROR DATA IS LOGGED AS
; BEGINNING DATA IN ERROR BLOCK
SETZM U.ETIE(P3) ;MAKE SURE TIE FLAG CLEAR
RET ; No status is stored at end of error recovery
SUBTTL Miscellaneous tables
REPEAT 0,< ;#500 no longer used
;Translation table from logical unit number to physical device address
MTPHY: .IDMTA+0 ; Logical 0
.IDMTA+1 ; Logical 1
.IDMTA+2 ; Logical 2
-1 ; Logical 3 is illegal
-1 ; Logical 4 is illegal
-1 ; Logical 5 is illegal
-1 ; Logical 6 is illegal
-1 ; Logical 7 is illegal
;;IFL <.-MTPHY>-MTAN,<PRINTX MTAN & MTPHY are inconsistent>
> ;#500 end of repeat 0
;EACH ENTRY MUST BE NON-0
;1B0 ;ILLEGAL FUNCTION
TB.WRT==1B1 ;THIS FUNCTION WRITES ON TAPE
TB.REV==1B2 ;THIS OPERATION MOVES TAPEIN REVERSE DIRECTION
TB.DOP==1B3 ;THIS IS A DATA OPERATION
TB.SPC==1B4 ;THIS IS A SPACE OPERATION
TB.RD==1B5 ;THIS IS A READ
TB.ERA==1B6 ;ERASE OPERATION
TB.TM==1B7 ;WRITE TAPE MARK
TB.NFC==1B8 ;DON'T LOAD FRM COUNT WHEN DOING OPERATION
TB.REW==1B9 ;OPERATION IS A REWIND
TB.WRD==1B10 ;THIS FUNCTION WRITES DATA ON TAPE
TB.UNL==1B11 ;UNLOAD COMMAND
;BITS 15,16,17 CONTAIN AN INDEX TO RTYBPT TO TELL US HOW
;TO RETRY AN OPERATION (0 IF NO RETRY)
;BITS 30-35 HAS MAJOR FUNCTION CODE (IBM codes)
SATFTB: 1B0 ;0- ILLEGAL
<TB.DOP!TB.RD>!2B17!.ICRDT ;1- READ FORWARD (IRFRED)
1B0 ;2- ILL (RD FMT)
<TB.WRT!TB.WRD!TB.DOP>!1B17!.ICWRT ;3- WRITE FORWARD (IRFWRT)
1B0 ;4- ILL (WRT FMT)
TB.SPC!.ICSKF ;5- Skip foward file ;#500 .
TB.SPC!.ICSKB ;6- SKIP FORWARD(BLOCK)
<TB.REV!TB.SPC>!.ICBSB ;7- SKIP REVERSE(BLOCK)
<TB.WRT!TB.TM>!6B17!.ICWEF ;10- WRITE TAPE MARK (EOF)
<TB.WRT!TB.ERA>!.ICERG ;11- ERASE GAP
<TB.NFC!TB.REW>!.ICREW ;12- REWIND
<TB.NFC!TB.UNL>!.ICRUN ;13- REWIND and UNLOAD
<TB.REV!TB.DOP!TB.RD>!4B17!.ICRDR ;14- READ REVERSE
1B0 ;15- ILL (RECOVERY RD)
1B0 ;16- ILL ;#500 .
1B0 ;17- ILL ;#500 .
; Convert software mode to mode bits in DCW for SA-10
; -1 = Illegal mode (not supported)
MODSAT: -1 ;(0) Default mode is illegal (not possible)
FLD(.SCCDM,SC%CCF) ;(1) Core dump (Tape compatibility mode)
-1 ;(2) Sixbit is illegal
-1 ;(3) ANSI ASCII is illegal
FLD(.SCICM,SC%CCF) ;(4) Industry compatible (Byte mode)
FLD(.SCHDM,SC%CCF) ;(5) High density (Natural mode)
; Table of items to copy into error block
ITAB: SEBPTR 0,SBTEVC,SEC%SM ; Block type (SA10 magtape error)
SEBPTR MB%CNI,SBTWD,CDBCNI(P1) ; Initial CONI
SEBPTR SM%ES1,SBTWD,U.ETIE(P3) ; Status word 1 (Base+1)
SEBPTR SM%ES2,SBTWD,U.ETCF(P3) ; Status word 2 (Base+2)
SEBPTR SM%SEN+0,SBTWD,MTASEN+0 ; Sense bytes (24 bytes = 6 words)
SEBPTR SM%SEN+1,SBTWD,MTASEN+1
SEBPTR SM%SEN+2,SBTWD,MTASEN+2
SEBPTR SM%SEN+3,SBTWD,MTASEN+3
SEBPTR SM%SEN+4,SBTWD,MTASEN+4
SEBPTR SM%SEN+5,SBTWD,MTASEN+5
NITAB==.-ITAB
;RETRY TABLES TO TELL HOW TO RETRY
RTYBPT: 0 ;ILLEGAL RETRY
POINT 4,TBRWRT ;WRITE RETRY
POINT 4,TBRRF ;READ FORWARD RETRY
POINT 4,TBRRFC ;READ FORWARD TAPE CLEAN
POINT 4,TBRRR ;READ REVERSE RETRY
POINT 4,TBRRRC ;READ REVERSE TAPE CLEAN
POINT 4,TBRWTM ;WRITE TAPE MARK
0 ;ILLEGAL
;THE FOLLOWING MACROS HELP ME GET AROUND SOME SHORTCOMINGS IN MACRO:
;NOTE: THE MACRO'S MUST BE FIXED IN THE UNLIKELY EVENT THAT
;SOMEBODY WANTS TO CHANGE TO A BYTE SIZE WHICH DOESN'T GO
;EVENLY INTO 36(10). RIGHT NOW IT'S 4.
DEFINE FOO (XXA) <
WD==0
BYC==0
ZZ==0 ;FLIP-FLOP
IRP XXA,<
IFE ZZ,<RP==XXA>
IFN ZZ,<FOO1 RP,XXA>
ZZ==ZZ+1
IFE ZZ-2,<ZZ==0>>
IFN BYC,<EXP WD>>
DEFINE FOO1 (A1,A2) <
REPEAT A1,<
WD==WD+<A2>B<4*BYC+3>
BYC==BYC+1
IFGE BYC-^D9, <
EXP WD
WD==0
BYC==0>>>
TBRWRT: BYTE (4) IRFBSB,IRFERG,RTY.CP,IRFWRT,RTY.DN
;WRITE RETRY - SPACE REVERSE, ERASE, CHECK POSITION, WRITE
TBRWTM: BYTE (4) IRFBSB,IRFERG,RTY.CP,IRFWTM,RTY.DN
;WRITE TM RETRY - SPACE REVERSE, ERASE, CHECK POS, WTM, EOR
TBRRF: BYTE (4) IRFBSB,RTY.CP,IRFRED,RTY.DN
;READ FORWARD RETRY - SPACE REVERSE, CHECK POSITION, READ FORWARD
TBRRR: BYTE (4) IRFFSB,RTY.CP,IRFRDR,RTY.DN
;READ REVERSE RETRY - SPACE FORWARD, CHECK POSITION, READ REVERSE
TBRRFC: FOO<CLNREC+1,IRFBSB, CLNREC,IRFFSB, 1,RTY.CP, 1,IRFRED, 1,RTY.DN>
;RD FORWARD TAPE CLEAN: 6 SP REVERSE, 5 SP FORWARD, CHECK POSITION, RD FORWARD
TBRRRC: FOO<CLNREC,IRFBSB, CLNREC+1,IRFFSB, 1,RTY.CP, 1,IRFRDR, 1,RTY.DN>
;RD REVERSE TAPE CLEAN: 5 SP REVERSE, 6 SP FORWARD, CHECK POSITION, RD REVERSE
TNXEND
END