!***********************************************************************
!
!                          2900 TAPE HANDLER
!
!***********************************************************************
!
IF  SSERIES=NO START 
  !..........PSERIES..........PSERIES..........PSERIES..........PSERIES
  !
  CONSTINTEGER  TOP LBE=36
  !                                                                    { CH FN
  CONSTINTEGERARRAY  LBES(0:TOP LBE)= C 
  X'00000200',                                                         {  1 RF
  X'40001200',                                                         {  2 RR
  X'00000200',                                                         {  3 RF
  X'44C01200',X'86800D10',X'00006200',                                 {  4 RR,AS,RFEC
  X'40001200',                                                         {  5 RR
  X'04C00200',X'86800D10',X'40007200',                                 {  6 RF,AS,RREC
  X'04C00200',X'04805200',X'86800D10',X'00006200',                     {  7 RF,SR,AS,RFEC
  X'44C01200',X'04804200',X'86800D10',X'40007200',                     {  8 RR,SF,AS,RREC
  X'00000200',                                                         {  9 RF
  X'40001200',                                                         { 10 RR
  X'80000300',                                                         { 11 W
  X'80802300',                                                         { 12 WT
  X'04A05200',X'80C04300',                                             { 13 SR IGN TM,ER....FOR WRITE(TM) RETRY
  X'00804200',                                                         { 14 SF
  X'00805200',                                                         { 15 SR
  X'00802200',                                                         { 16 STF
  X'00803200',                                                         { 17 STR
  X'00803800',                                                         { 18 RW
  X'80C04300',                                                         { 19 ER
  X'00A04200',                                                         { 20 SF IGN TM....FOR FINAL POSITIONING
  X'00A05200',                                                         { 21 SR IGN TM....DITTO
  X'04A04200',X'00805200',                                             { 22 SF IGN TM,SR....FOR TM LOOK-AHEAD
  X'00805800',                                                         { 23 UNL....UNLOAD FLASH
  X'00000E00',                                                         { 24 SEND PROPS
  X'00001E00'                                                          { 25 QUALIFIED SPC FOR GTS
  !
  ! ALL LBES WHICH DO NOT INVOLVE A XFER REQUIRE IGNORE SHORT.
  !  ERASES HAVE SHORT/LONG MASKED OFF FOR GTS DECKS WHICH DO A FIXED LENGTH
  !  AND THEREFORE DO NOT DECREMENT THE BYTE COUNT
  !
FINISHELSESTART 
  !..........SSERIES..........SSERIES..........SSERIES..........SSERIES
  !
  CONSTINTEGER  TOP CW=36
  !                                                                    { CH FN
  CONSTINTEGERARRAY  CW(0:TOP CW)= C 
  X'2000C002',                                                         {  1 RF
  X'2000C012',                                                         {  2 RR
  X'2000C002',                                                         {  3 RF
  X'2C40C012',X'2840408D',X'20004062',                                 {  4 RR,AS,RFEC
  X'2000C012',                                                         {  5 RR
  X'2C40C002',X'2840408D',X'20004072',                                 {  6 RF,AS,RREC
  X'2C40C002',X'28404052',X'2840408D',X'20004062',                     {  7 RF,SR,AS,RFEC
  X'2C40C012',X'28404042',X'2840408D',X'20004072',                     {  8 RR,SF,AS,RREC
  X'2000C002',                                                         {  9 RF
  X'2000C012',                                                         { 10 RR
  X'2000C083',                                                         { 11 W
  X'2800C0A3',                                                         { 12 WT
  X'2A40C052',X'2C0040C3',                                             { 13 SR IGN TM,ER
  X'2800C042',                                                         { 14 SF
  X'2800C052',                                                         { 15 SR
  X'2800C022',                                                         { 16 STF
  X'2800C032',                                                         { 17 STR
  X'2800C038',                                                         { 18 RW
  X'2C00C0C3',                                                         { 19 ER
  X'2A00C042',                                                         { 20 SF IGN TM
  X'2A00C052',                                                         { 21 SR IGN TM
  X'2A40C042',X'28004052',                                             { 22 SF IG TM,SR
  X'2800C058',                                                         { 23 UNL
  X'2000C00E',                                                         { 24 SPC
  X'2000C01E'                                                          { 25 QSPC
  !
  ! DO WE NEED IGNORE SHORT FOR NON-XFER, IF WERE NOT GOING TO GIVE A
  ! A DUMMY DATA AREA. DCU TELLS FROM LACK OF FIXED BIT IN STE THAT NO
  ! AREA REQUIRED. LEAVE IGN SHORT IN ABOVE FOR NOW. IT CANT DO ANY HARM.
  ! SEE NOTE AFTER LBES ABOVE RE ERASE SHORT/LONG MASK
  !
FINISH ;!..............................................................
!
CONSTINTEGER  MAX CHAINS=25,PRIVATE=MAX CHAINS+1
!
CONSTBYTEINTEGERARRAY  STATMASK(1:MAX CHAINS)=C 
X'FE'(3),X'EC',X'FE',X'EC'(3),X'FE'(2),X'FC'(13),X'7C'(2)
! TERTIARY STATUS MASKS TO GO WITH EACH CHAIN ABOVE.
! FE=T0-T6. INCLUDES ADVISORY.
! EC=T0-T2,T4-T5. EXCLUDES MEDIA AND ADVISORY.
! 7C=T1-T5. EXCLUDES MANUAL/NA FOR SEND PROPS AT STARTUP
!
CONSTINTEGERARRAY  CHAIN START(1:MAX CHAINS+1)= C 
0,1,2,3,6,7,10,14,18,19,20,21,22,24,25,26,27,28,29,30,31,32,34,35,36,0
! THESE ARE THE LBE(CW) INDEX FOR CHAIN STARTS.
! CHAIN MAX+1 IS NOT REAL CHAIN.IT ACCOMMODATES PRIVATE CHAINS.
! SEE ROUTINE TERMINATE.
!
CONSTINTEGERARRAY  CHAIN LENGTH(1:MAX CHAINS+1)= C 
1,1,1,3,1,3,4,4,1,1,1,1,2,1,1,1,1,1,1,1,1,2,1,1,1,0
! THE NUMBER OF LBES(CWS) IN EACH CHAIN

CONSTINTEGER  LAST READ CHAIN=10;  ! JUST THAT
CONSTINTEGER  LAST RETRY CHAIN=12
!
CONSTINTEGER  POSMASK=X'5A5A5'; ! READ CHAINS ONLY. BIT 2** INDEX SET
! IF THAT LBE(CW) LEAVES US AFTER THE BLOCK, UNSET IF BEFORE.
CONSTINTEGER  REVMASK=X'A424A'; ! READ CHAINS ONLY. BIT 2** INDEX SET
! IF THAT LBE(CW) IS REVERSE READ.
!
IF  SSERIES=NO START 
  !..........PSERIES..........PSERIES..........PSERIES..........PSERIES
  !
  CONSTINTEGER  NODATA=X'20000000', MAX XFER=X'3FFFF'
  CONSTINTEGERARRAY  IGNSHORTLONG(0:3)= C 
                         0,X'00800000',X'00400000',X'00C00000'
FINISHELSESTART 
  !..........SSERIES..........SSERIES..........SSERIES..........SSERIES
  !
  CONSTINTEGER  NODATA=X'00000200', MAX XFER=X'FFFF'
  CONSTINTEGERARRAY  IGNSHORTLONG(0:3)= C 
                       0,X'08000000',X'04000000',X'0C000000'
FINISH ;!..............................................................
!
CONSTLONGINTEGER  LONG1=1
!
CONSTINTEGER  OK=0, NOTOK=-1
!
CONSTINTEGER  NOT AVAILABLE=0, MANUAL=1, LOADING=2, LOADED=3, CLAIMED=4
CONSTINTEGER  UNLOADING=5
CONSTSTRING (11)ARRAY  STATES(0:5)= C 
" na ",
" manual ",
" loading ",
" loaded ",
" claimed ",
" unloading "
! DRIVE STATES.
!
CONSTSTRING (5)ARRAY  OFFLINE SW(0:1)="stop","reset"
! THE NAME OF THE SWITCH ON THE DRIVE TO DO IT FOR MTS AND GTS RESPECTIVELY
!
CONSTBYTEINTEGER  TERM EXP=1, ATTN EXP=2
!
CONSTINTEGER  NRZI=2, PE=3, GCR=8
!*
CONSTINTEGER  ME=X'310000'
!
CONSTINTEGER  CONTROLLER=X'300000';  ! GPC OR DCU AS APPROPRIATE
CONSTINTEGER  ALLOC=11, DEALLOC=5, EXEC=12
!
CONSTINTEGER  ON=1, OFF=0
!
CONSTINTEGER  REJECT=2,BAD PARAMS=1,NOT CLAIMED=2,SNO NOT FOUND=4,BUSY=8
!
!------------------------------ FORMATS ------------------------------
!
RECORDFORMAT  PF(INTEGER  DEST,SRCE,P1,P2,P3,P4,P5,P6)
!
RECORDFORMAT  SHORTPF(INTEGER  DEST,SRCE,P1,P2,P3,P4)
!
RECORDFORMAT  CLF(INTEGER  DEST,SRCE,IDENT, (HALFINTEGER  H1,PERM,
  STRING (7) DSN OR  INTEGER  REPLY,SNO,BYTEINTEGER  D1,D2,D3,DEVID),
  STRING (3) MNEM,BYTEINTEGER  D4,D5,D6,MODE)
!
RECORDFORMAT  REQF(INTEGER  ADDR,LENGTH,LSL,LSTBA,
  BYTEINTEGER  STATE,CHAIN,FINAL CHAIN,
  (BYTEINTEGER  TARGET POS OR  BYTEINTEGER  TM),
  (INTEGER  READORS OR  INTEGER  SKIP TOT),
  (INTEGER  COUNT OR  INTEGER  PRIVATE ATTN),
  INTEGER  RETRIES,RETRY LIMIT,INTEGER  COUNT1)
!
IF  SSERIES=NO START 
  !..........PSERIES..........PSERIES..........PSERIES..........PSERIES
  !
  RECORDFORMAT  RCBF(INTEGER  LIMFLAGS,LSTBA,LB BYTES,LBA,AL BYTES,
    ALA,INITWORD)
  !
  RECORDFORMAT  TF(INTEGER  LINK,LAB1,LAB2,STRING (7)DSN,INTEGER  LBE1,
    LBE2,LBE3,LBE4,ALE1,ALE2,STREAMR0,STREAMR1,STRING (3)MNEM,
    RECORD (REQF)REQ,RECORD (RCBF)RCB,INTEGER  SNO,RECORD (SHORTPF)REP,
    (BYTEINTEGER  T0,T1,T2,T3,T4,T5,T6,T7 OR  LONGINTEGER  T07),
    BYTEINTEGER  T8,T9,T10,T11,T12,T13,T14,GTS,SSTAT,PROP1,PROP2,PROP3,
    INTEGER  FAULTS,OPS,BYTEINTEGER  STATE,MODE,LOAD STATE,UNLOAD PENDING)
  ! NOTE THAT TO OBTAIN ALIGNMENT OF RECORD 'REP' AND LONGINTEGER 'T07',
  ! 'SSTAT' IS FORCED OUT OF ITS NATURAL POSITION PRECEDING 'T0'.
  ! THE ABOVE RECORD IS MAPPED ONTO THE USER AREA IN THE DEVICE SLOT,
  ! AND MAY EXTEND UP TO 200 BYTES.
  ! CURRENT LENGTH OF ABOVE IS - 184 
  CONSTINTEGER  TFSIZE=184
FINISHELSESTART 
  !..........SSERIES..........SSERIES..........SSERIES..........SSERIES
  !
  RECORDFORMAT  TCBF(INTEGER  CW,STE,LENGTH,ADDR,NEXT TCB,
    BYTEINTEGER  PSTAT,RESPONSE,HALFINTEGER  REMBC,
    INTEGERARRAY  PREAMBLE,POSTAMBLE(1:4))
  !
  RECORDFORMAT  TF(INTEGER  LINK,STRING (3) MNEM,INTEGER  LAB1,LAB2,
    STRING (7)DSN,
    RECORD (REQF)REQ,RECORD (SHORTPF)REP,
    (BYTEINTEGER  T0,T1,T2,T3,T4,T5,T6,T7 OR  LONGINTEGER  T07),
    BYTEINTEGER  T8,T9,T10,T11,T12,T13,T14,GTS,SSTAT,PROP1,PROP2,PROP3,
    STATE,MODE,LOAD STATE,UNLOAD PENDING,
    INTEGER  STREAMR0,STREAMR1,
    RECORD (TCBF)ARRAY  TCBS(1:6),
    INTEGER  SNO,FAULTS,OPS)
  ! SEE NOTE RE ALIGNMENT IN PSERIES FORMAT ABOVE.
  ! ALSO NB THAT TCBS MUST BE DOUBLE WORD ALIGNED. H/W DOESNT CHECK
  ! THIS MAY EXTEND TO 480 BYTES. CURRENT LENGTH IS 468
  ! ONLY 4 OF THE 6 TCBS ARE USED HERE. UP TO 6 FOR PRIVATE CHAINS.
  CONSTINTEGER  TFSIZE=468
FINISH ;!..............................................................
!
RECORDFORMAT  DF(INTEGER  SER, PTSM, PROPADDR, TICKS SINCE,
  CAA, GRCB AD, LBA, ALA, STATE, RESP0, RESP1, SENSE1, SENSE2,
  SENSE3, SENSE4, REPSNO, BASE, ID, DLVN, MNEMONIC, ENTSIZE,
  PAW, USAW0, URCB AD, SENSDAT AD, LOGMASK, TRTAB AD, UA SIZE,
  UA AD, TIMEOUT, PROPS0, PROPS1)
!
!------------------------- EXTERNAL SPECS ---------------------------
!
IF  MULTIOCP=YES START 
  EXTERNALROUTINESPEC  RESERVELOG
  EXTERNALROUTINESPEC  RELEASELOG
FINISH 
EXTERNALROUTINESPEC  OPMESS(STRING (23) S)
EXTERNALLONGINTEGERSPEC  KMON
EXTERNALROUTINESPEC  PKMONREC(STRING (20)TXT,RECORD (PF)NAME  P)
EXTERNALROUTINESPEC  PON(RECORD (PF)NAME  P)
EXTERNALSTRINGFNSPEC  HTOS(INTEGER  VAL,PLACES)
EXTERNALROUTINESPEC  DUMPTABLE(INTEGER  TABNO,ADDR,L)
SYSTEMROUTINESPEC  MOVE(INTEGER  L,F,T)
SYSTEMROUTINESPEC  ETOI(INTEGER  A,L)
EXTERNALROUTINESPEC  PRHEX(INTEGER  N)
!
!=====================================================================
!
EXTERNALROUTINE  TAPE(RECORD (PF)NAME  P)
!
OWNINTEGER  FIRSTTP=0, VOLUMS=0, INITIALISED=0
OWNINTEGER  READ RETRIES=15,WRITE RETRIES=6
! WRITE RETRIES ARE LIMITED BY THE MAX INTERBLOCK GAP=300 INCHES. 
! 6 ASSUMES A MAX BLOCK SIZE OF @64K AT 1600 BPI(IE 40 INCHES).
! P SERIES BLOCKS CAN BE UP TO 256K, BUT WE CANT CATER FOR THAT WHICH
! WOULD GIVE US ONLY ONE RETRY! IT WOULD BE SMARTER TO MAKE THE RETRIES
! A FUNCTION OF THE WRITTEN LENGTH.
OWNINTEGER  RLEVEL=0
! REPORTING LEVEL:
!  2**0 - REPORT PARM RECORDS IN
!  2**1 - REPORT PARM RECORDS OUT
!  2**2 - DUMP TABLE AFTER CHAIN FIRED
OWNINTEGERNAME  LASTLINK
RECORD (DF)NAME  D
RECORD (TF)NAME  T
RECORD (REQF)NAME  REQ
RECORD (SHORTPF)NAME  REP
RECORD (PF)PP
INTEGERNAME  PREVLINK
INTEGER  I,NDECKS,MODE,ACT,SNO,TMON
STRING (4) M
SWITCH  ACTSW(1:13)
!
ROUTINESPEC  FIRE CHAIN
ROUTINESPEC  TERMINATE(INTEGER  N,B)
ROUTINESPEC  TELL VOLUMS(INTEGER  LOAD TYPE)
!
ROUTINE  MON(INTEGER  MODE,RECORD (PF)NAME  P)
CONSTSTRING (4)ARRAY  MODES(1:3)= C 
  "IN","OUT","IN??"
PKMONREC("
TAPE(".MODES(MODE)."): ",P)
END ;      ! ROUTINE MON
!
!
ROUTINE  MYPON(RECORD (PF)NAME  P)
IF  TMON#0 OR  RLEVEL&2#0 THEN  MON(2,P)
PON(P)
END ;      ! ROUTINE MYPON
!
!
ROUTINE  REPORT(STRING (255) MESS)
!***********************************************************************
! REPORTS ABNORMAL CONDITIONS TO LOG
!***********************************************************************
CONSTBYTEINTEGERARRAY  HX(0:15)=  C 
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
!
ROUTINE  PBYTE(BYTEINTEGER  N)
PRINTSYMBOL(HX(N>>4))
PRINTSYMBOL(HX(N&X'F'))
END ;     ! ROUTINE PBYTE
!
INTEGER  I,J,SIZE
T_FAULTS=T_FAULTS+1
RESERVELOG IF  MULTIOCP=YES
PRINTSTRING("
TAPE ERROR// ABNORMAL TERMINATION - ".MESS."
DECK ")
PBYTE(T_PROP2)
PRINTSTRING(" FAULTS (DECK/REQ) ")
PRHEX((T_FAULTS<<16)!REQ_RETRIES)
PRINTSTRING(" REQ ID ")
PRHEX(REP_P1)
SPACE
PRINTSTRING(T_DSN) UNLESS  3<=T_LOAD STATE<=4
! IT MIGHT BE JUNK IN THAT CASE.
IF  REQ_CHAIN<=10 START 
  MESS=" READ"
FINISHELSEIF  REQ_CHAIN<=12 START 
  MESS=" WRITE"
FINISHELSE  MESS=" OTHER"
PRINTSTRING(MESS)
PRINTSTRING("
SST  T0  T1  T2  T3  T4  T5  T6  T7  T8  T9 T10 T11
")
SPACE
PBYTE(T_SSTAT)
J = ADDR(T_T0)
FOR  I=0,1,11 CYCLE 
  SPACES(2)
  PBYTE(BYTEINTEGER(J+I))
REPEAT 
SIZE=TFSIZE
DUMP TABLE(61,ADDR(T),SIZE)
RELEASELOG IF  MULTIOCP=YES
END ;       ! ROUTINE REPORT
!
!
INTEGERFN  SEARCH TPS(INTEGER  SWIND,IMATCH,STRING (6) SMATCH)
!**********************************************************************
! CALLED TO SCAN T CHAIN MATCHING IMATCH OR SMATCH RETURNING OK
! OR NOTOK,LEAVING T MAPPED TO MATCHING RECORD.
! OR TO SCAN ENTIRE CHAIN WITHOUT MATCHING, WHEN RESULT IS IRRELEVANT
! AND T IS LEFT MAPPED TO LAST RECORD.
! SWIND=1 - SMATCH MNEMONIC
!      =2 - SMATCH DSN
!      =3 - IMATCH SNO
!      =4 - SCAN AND TELL VOLUMS
!      =5 - SCAN AND DISPLAY
!**********************************************************************
STRING (7) DSN
SWITCH  SW(1:5)
RESULT =NOTOK IF  FIRSTTP=0; ! CHAIN EMPTY
T==RECORD(FIRSTTP)
PREVLINK==FIRSTTP
!
CYCLE 
  ->SW(SWIND)
  !
SW(1):;   ! MATCH MNEM
  IF  T_MNEM=SMATCH THENRESULT =OK
  ->NEXT
  !
SW(2):;   ! MATCH DSN
  IF  T_DSN=SMATCH THENRESULT =OK
  ->NEXT
  !
SW(3):;   ! MATCH SNO
  IF  T_SNO=IMATCH THENRESULT =OK
  ->NEXT
  !
SW(4):;    ! TELL VOLUMS
IF  LOADED<=T_STATE<=CLAIMED THEN  TELL VOLUMS(1)
! COULD IT BE CLAIMED IF VOLUMS ONLY JUST HERE?
->NEXT
!
SW(5):;    ! TELL OPER
IF  LOADED<=T_STATE<=CLAIMED THEN  DSN=T_DSN ELSE  DSN=""
OPMESS(HTOS(T_SNO,4)." ".T_MNEM.STATES(T_STATE).DSN)
->NEXT
!
NEXT:
  RESULT =NOTOK IF  T_LINK=0
  PREVLINK==T_LINK
  T==RECORD(T_LINK)
REPEAT 
END ;       ! FN SEARCH TPS
!*
!*
ROUTINE  TELL VOLUMS(INTEGER  LOAD TYPE)
!***********************************************************************
! TELLS VOLUMS ABOUT LOAD OR UNLOAD OF DRIVE.
! LOAD TYPE=0(NOT LOADED), 1(LOADED)
! VOLUMS ALSO NEEDS TO KNOW LOADED WITH LABEL(1) OR NO LABEL(2)
!***********************************************************************
RECORDFORMAT  VF(INTEGER  DEST,SRCE,TYPE,LOAD,STRING (4)MNEM, C 
  STRING (7) DSN,BYTEINTEGER  D1,MODE,PERM)
RECORD (VF) V
IF  VOLUMS=0 THENRETURN ;  ! VOLUMS NOT THERE
IF  LOAD TYPE=1 AND  T_DSN="NOLABEL" THEN  LOAD TYPE=2
V=0
V_DEST=VOLUMS
V_SRCE=ME
V_TYPE=4
V_LOAD=LOAD TYPE
V_DSN=T_DSN UNLESS  LOAD TYPE=0
V_MNEM=T_MNEM
V_PERM=2-((T_PROP3>>6)&1)
V_MODE=T_MODE
MYPON(V)
END ;      ! ROUTINE TELL VOLUMS
!
!
ROUTINE  LOAD
!***********************************************************************
! ENTERED TO GET PROPS AND, IF APPROPRIATE, LOAD EACH DECK SUCCESSFULLY
! ALLOCATED AT START-UP, AND THEREAFTER FOR ANY DECK GIVING AN AUTO
! ATTENTION, AND
! TO UNLOAD OR RELEASE/REWIND A DECK WHEN USER RELEASES IT OR AT
! DISASTER.
!***********************************************************************
CONSTBYTEINTEGERARRAY  GTS MODES(0:3)=3,8,2,8
OWNINTEGER  VOL1=X'E5D6D3F1'
INTEGER  I,CH
STRING (7) DSN
STRING (40) S
SWITCH  LDSW(0:9)
!
->LDSW(T_LOAD STATE)
!
LDSW(0):;   ! GET PROP CODE.
REP=0
REQ=0
REQ_ADDR=ADDR(T_PROP1)
REQ_LENGTH=3
REQ_CHAIN=24+T_GTS;  ! IE 24 FOR MTS, 25 FOR GTS
T_MODE=PE
FIRE CHAIN
T_LOAD STATE=1
T_STATE=LOADING
RETURN 
!
LDSW(1):;   ! REPLY FROM SEND PROPS
IF  REP_P2#0 START 
  ! SEND PROPS FAILED. INOP MASKED OFF SO SOMETHING ELSE
  ->LOAD FAIL
FINISH 
! AT STARTUP, WE DONT HAVE ANY SENSE BYTES HERE TO TELL WHETHER NOTAVAIL,
! MANUAL OR LOADED.
! WE JUST PLOUGH ON AND DO A REWIND ANYWAY AND SORT IT OUT FROM THAT
! REP_P2=0
REQ=0
REQ_CHAIN=18
REQ_ADDR=X'81000000'
REQ_LENGTH=50;     ! STANDARD DUMMY ASL
FIRE CHAIN
T_LOAD STATE=2
RETURN 
!
LDSW(2):;    ! REPLY FROM INITIAL REWIND
IF  REP_P2#0 START 
  ! WE EXPECT IT TO FAIL FOR UNLOADED DECKS AT START-UP
  ! (THIS COULD BE DONE AFTER SPC ABOVE EXCEPT FOR GTS DECKS WHICH  DONT
  ! GIVE U/S FOR SPC IN MANUAL).
  IF  T_T0&X'C0'#0 START ;   ! UNAVAIL OR MANUAL
    IF  T_T0&X'40'#0 THEN  T_STATE=NOT AVAILABLE ELSE  T_STATE=MANUAL
    ->EXIT
  FINISHELSE  ->LOAD FAIL
FINISH 
! SO ITS LOADED.  LETS TRY TO READ SOMETHING LIKE A LABEL.
! FIRST IN PE. GTS DECKS WILL DO THE READ IN THE TAPE MODE AND SAY IF ITS 
! DIFFERENT. MTS DECKS WILL FAIL, WHEN IF NRZI IS FITTED, WE'LL TRY THAT.
SET UP READ:
! CAUTION*** COME HERE FROM LDSW(1) AND LDSW(4) ALSO
! REP_P2=0
REQ=0
REQ_ADDR=ADDR(T_LAB1)
REQ_LENGTH=16
REQ_CHAIN=1;    ! READ FORWARD
REQ_FINAL CHAIN=9;  ! STANDARD 
REQ_TARGET POS=1
REQ_READORS=IGNSHORTLONG(2);  ! IGNORE LONG SINCE IT SURELY WILL BE
REQ_RETRY LIMIT=4
! THIS ACUALLY ONLY GIVES US 2 GOES AT IT, SINCE REVERSE READS LONG
! ARE INEVITABLY FAILURES (SEE OK(1) IN 'TERMINATE')
FIRE CHAIN
T_LOAD STATE=3
RETURN 
!
LDSW(3):;    ! REPLY FROM LABEL READ
CH=0
IF  REP_P2#0 AND  T_GTS#0 AND  T_T6&64#0 START 
  ! GTS FAILED 'INCOMPATIBLE MODES'. THIS IS A WARNING ONLY, AND THE READ
  ! HAS BEEN DONE IN THE MODE OF THE TAPE, THE LATTER BEING ADVISED IN
  ! T13, BITS 104,105
  T_MODE=GTS MODES((T_T13>>6)&3)
  REP_P2=0;   ! MAKE IT LOOK SUCCESSFUL
FINISH 
IF  REP_P2#0 START ;  ! FAILED
  IF  T_T4&128#0 START ;  ! WRONG MODE
    ! FOR GTS, THIS MEANS NO RECOGNISABLE MODE. FOR MTS IT MAY MEAN
    ! A MODE RECOGNISED BUT NOT THE REQUESTED ONE.
    IF  T_GTS=0 AND  T_MODE=PE AND  T_PROP3&16#0 START 
      ! MTS. WE HAVE TO TRY EACH POSSIBLE MODE TO SEE IF ANY SUCCEEDS.
      ! THAT WAS PE, AND NRZI IS FITTED, SO TRY THAT
      ! FIRST A REWIND
      REP=0
      REQ_CHAIN=18
      ! PREV ADDR/LENGTH WILL DO IF REQD
      T_LOAD STATE=4
      FIRE CHAIN
      RETURN 
    FINISH 
    ! IF GTS, NO MODE ON TAPE.
    ! IF MTS, EITHER TRIED BOTH, OR NRZI NOT FITTED. SET MODE UNDEFINED.
    ! THE ONLY THING THAT CAN BE DONE TO THIS TAPE IS A WRITE AT BT,
    ! AFTER A MODE OVERRIDE IN 'CLAIM VOLUME'.
    T_MODE=0
    OPMESS(T_MNEM." undefined mode")
  FINISH 
  ! SO SOME ERROR OTHER THAN MODE, MAYBE NOISE. RETAIN IT AS 'NOLABEL'.
FINISHELSESTART ;      ! READ SUCCEEDED.
  ! IBM LABELS ARE 80 BYTES STARTING 'VOL1' IN EBCDIC.
  ! ICL MAY BE 86,96 OR GREATER IF IPL BLOCKS. EACH BEGINS WITH INTEGER
  ! BLOCK COUNT AND HALFINTEGER BYTE LENGTH.
  IF  T_LAB1=0 THEN  MOVE(10,ADDR(T_LAB1)+6,ADDR(T_LAB1))
  ! IE IT WAS A BLOCK COUNT, SO MOVE DATA FIELD DOWN.
  IF  T_LAB1=VOL1 START ;   ! FORMAT OK
    MOVE(6,ADDR(T_LAB1)+4,ADDR(DSN)+1)
    LENGTH(DSN)=6
    ETOI(ADDR(DSN)+1,6)
    ! NOW CHECK FOR VALID CHARS IN DSN
    FOR  I=1,1,6 CYCLE 
      CH=CHARNO(DSN,I)
      UNLESS  '0'<=CH<='9' OR  'A'<=CH<='Z' OR  CH=' ' START 
        OPMESS(T_MNEM." faulty dsn - ".DSN)
        CH=0
        EXIT 
      FINISH 
    REPEAT 
  FINISH 
FINISH 
! SO UNDEFINED MODE, OR READ FAILED OTHER THAN IDENTIFIER,
! OR AN INVALID FORMAT READ, OR AN INVALID DSN READ,
! ALL GET HERE WITH CH=0 AND ARE ALL TREATED AS NOLABEL.
! GET HERE WITH CH#0 ONLY IF GOOD DSN READ.
IF  CH#0 THEN  T_DSN=DSN ELSE  T_DSN="NOLABEL"
REP=0
REQ_CHAIN=18
! PREV ADDR AND LENGTH WILL DO FOR DUMMY IF NEEDED
FIRE CHAIN
T_LOAD STATE=5
RETURN 
!
LDSW(4):;    ! REWIND AFTER FAILED PE READ, FOR A TRY AT NRZI.
IF  REP_P2#0 THEN  ->LOAD FAIL
T_MODE=NRZI
->SET UP READ;     ! WITH REP_P2=0
!
LDSW(5):;     ! FINAL REWIND
IF  REP_P2#0 THEN  ->LOAD FAIL
!
LOAD OK:
T_STATE=LOADED
TELL VOLUMS(1)
OPMESS(T_MNEM." loaded ".T_DSN)
!
EXIT:
T_LOAD STATE=0
RETURN 
!
LOAD FAIL:
OPMESS(T_MNEM." load failed")
T_LOAD STATE=6
! AND DROP THRU' TO .......
!
UNLOAD:
LDSW(6):LDSW(8):;  ! ENTRY POINT FOR UNLOAD, RELEASE/REWIND
IF  LOADED<=T_STATE<=CLAIMED THEN  TELL VOLUMS(0)
T_DSN="";  ! JUST TO KEEP 'CLAIM VOLUME' TIDY
REP=0
REQ=0
IF  T_LOAD STATE=6 THEN  REQ_CHAIN=23 ELSE  REQ_CHAIN=18
!                        DISCONNECT         REWIND
REQ_ADDR=X'81000000'
REQ_LENGTH=50
FIRE CHAIN
T_LOAD STATE=T_LOAD STATE+1
T_STATE=UNLOADING
RETURN 
!
LDSW(7):;    ! REPLY FROM UNLOAD
IF  REP_P2#0 AND  T_T0&X'C0'=0 THENC 
       S=" unload fails. Press ".OFFLINE SW(T_GTS)."/unload" ELSE  S=" unloaded"
! IT MIGHT ALREADY BE UNLOADED IF PRIVATE CHAIN USER HAS DONE IT.
OPMESS(T_MNEM.S)
T_STATE=MANUAL
->EXIT
!
LDSW(9):;       ! REPLY FROM RLSR/RWND
IF  REP_P2#0 START 
  OPMESS(T_MNEM." rlse/rwnd fails")
  T_LOAD STATE=6
  ->UNLOAD
FINISH 
! NOW RE-READ LABEL. WE'RE AT BT AND REP_P2=0 SO GO STRAIGHT TO READ
T_MODE=PE
T_LOAD STATE=2
T_STATE=LOADING
->LDSW(2)
!
!
END ;     ! ROUTINE LOAD
!*
!*
ROUTINE  CLAIM VOLUME(RECORD (CLF)NAME  P)
!**********************************************************************
! ALLOCATES VOLUME TO REQUESTING USER.
! P_DSN IS REQUIRED VOLUME, OR P_MNEM IF P_DSN="NOLABEL".
! P_PERM IS REQUIRED PERM, 1=READ, 2=RITE
! P_MODE IS REQUIRED MODE:
!   MODE&B'1011'=8(GCR),OR 3(PE),OR 2(NRZI) OVERRIDES MODE ESTABLISHED IN LABEL READ,
!     (UNLESS NRZI SPECIFIED AND NOT FITTED, OR GCR AND NOT GTS DECK, WHEN REJECT).
!     IF NO OVERRIDE MODE SPECIFIED AND NO MODE ESTABLISHED AT LABEL
!     READ (SOME OTHER MODE RECORDED OR BLANK TAPE), THEN REJECT.
!   MODE&4 IS COMPRESS EXPAND AND IS ORED INTO TAPE MODE OR OVERRIDE
!     AS APPROPRIATE.
!   A MODE OF ZERO THUS USES CURRENT TAPE MODE AND NO CE.
!**********************************************************************
INTEGER  OVERMODE,I
IF  P_DSN="NOLABEL" THEN  I=SEARCH TPS(1,0,P_MNEM) C 
                    ELSE  I=SEARCH TPS(2,0,P_DSN)
OVERMODE=P_MODE&B'1011'
IF  I=NOTOK OR  T_STATE#LOADED START 
  ! IF SEARCH FAILS, THEN DSN NOT FOUND, OR MNEMONIC NOT PRESENT
  ! IF SEARCH SUCCEEDS, T MAPPED. IF STATE#LOADED THEN TAPE ALREADY
  ! CLAIMED. THIS LATTER CHECK IS DONE BY VOLUMS BEFORE COMING HERE,
  ! BUT WE DO IT HERE FOR CHOPSUPE (NO VOLUMS AROUND YET).
  P_REPLY=1
FINISHELSEIF  T_PROP3&X'40'#0 AND  P_PERM=2 START 
  ! N0 RING FITTED AND WRITE REQUESTED
  P_REPLY=2
FINISHELSEIF  OVERMODE=1 OR  OVERMODE>8  OR  (OVERMODE=0 AND  T_MODE=0) ORC 
              (OVERMODE=GCR AND  T_GTS=0) ORC 
              (OVERMODE=NRZI AND  (T_PROP3>>T_GTS)&X'10'=0) START 
                                  ! NRZI BIT IS AT X20 FOR GTS DECKS!!!!!
  ! INVALID OVERRIDE MODE, OR
  ! NO OVERRIDE MODE AND NONE ESTABLISHED AT LABEL READ, OR
  ! GCR OVERRIDE MODE AND NOT GTS DECK, OR
  ! NRZI OVERRIDE MODE AND NOT FITTED
  P_REPLY=3
FINISHELSESTART ; ! ALL OK
  T_STATE=CLAIMED
  IF  OVERMODE#0 THEN  T_MODE=OVERMODE
  T_MODE=T_MODE!(P_MODE&4);  ! INCLUDE CE BIT IF ANY
  T_SNO=(T_SNO+X'100')&X'FFFF'
  ! BOTTOM BYTE IS SNO PROVIDED BY CONTROLLER. TOP BYTE IS CYCLIC 0-255.
  ! SO IF WE LOSE A DECK AND DO NOT GET THE EXPECTED RELEASE FROM USER
  ! WE CAN REALLOCATE THE DECK WITHOUT FEAR OF THE OUTSTANDING SNO COMING.
  ! BUT CAUTION*** THE SNO (STREAM ACTUALLY) PROVIDED BY CONTROLLER IS NOT
  ! GUARANTEED TO BE ONLY A BYTE. IF THERE ARE ENOUGH DEVICES IT COULD
  ! GO OVER.
  P_SNO=ME!T_SNO
  P_DEVID=T_PROP2;  ! CONTROLLER/MECH ADDRESS. CAN BE USED BY USER
                    ! IF WRITING, TO SHOW LAST DECK WRITTEN ON.
  P_MODE=T_MODE
  P_REPLY=OK
FINISH 
END ;       ! ROUTINE CLAIM VOLUME
!
!
ROUTINE  ATTENTION
!***********************************************************************
! ENTERED TO DEAL WITH ATTENTIONS.
! IT IS REPUTEDLY POSSIBLE FOR MULTIPLE INDEPENDENT BITS TO BE SET
! IF SEVERAL STATE CHANGES OCCURRED IN THE DEVICE WHILE THE SYSTEM 
! WAS UNINTERRUPTIBLE (NORMALLY THE ONLY TWO WHICH WOULD BE EXPECTED
! TOGETHER ARE AUTO AND BT). THIS CODE ATTEMPTS TO DEAL WITH SUCH
! MULTIPLE OCCURENCES, BUT LACKING THE TIME SEQUENCE OF THE BITS
! THEY ARE NOT NECESSARILY UNAMBIGUOUS AND WE MAY END UP IN A STATE
! DIFFERENT FROM THE DEVICE. HOWEVER THIS SHOULD BE EXCEEDINGLY RARE
! AND IN MOST CASES REMEDIAL BY OPERATOR ACTION.
!
! MTS BITS:-
!     X80=AUTO
!     X40=BT
!     X20=ALWAYS SET
!     X10=TM
!     X08=ENGINEER
!     X04=AVAILABLE
!     X02=NOT AVAILABLE
!     X01=MANUAL REQUESTED
!
! GTS BITS:-
!     X80=AUTO
!     X40=BT
!     X20=SECONDARY ATTN
!     X10=TM
!     X08=ALWAYS ZERO
!     X04=AVAILABLE(CLUSTER)
!     X02=NOT AVAILABLE(CLUSTER)
!     X01=ALWAYS ZERO
!
! THE AVAILABLE/NOT AVAILABLE SWITCH AFFECTS ALL DECKS ON A GTS CLUSTER
! BUT ONLY ONE ATTN IS GENERATED BY THE H/W. THIS CODE RELIES ON DCU
! GENERATING ONE ATTN FOR EACH DECK ALLOCATED IN THAT CASE.
!***********************************************************************
CONSTINTEGER  AUTO=X'80',BT=X'40',SEC ATTN=X'20',TM=X'10',ENGINR=8,AVAIL=4,
  NOT AVAIL=2,HOLD=1
INTEGER  ATTN,I
SWITCH  SW(0:2)
!
ROUTINE  TELL USER
REQ_STATE=0
IF  REP_DEST#0 START ;  ! BY USER
  REP_P2=3
  MYPON(RECORD(ADDR(REP)));   ! MUST DO IT THIS WAY SINCE REP'S LENGTH IS < THAN PARAM SPEC
FINISHELSE  T_LOAD STATE=0
! IE ABORT LOAD OR UNLOAD
END 
!
ROUTINE  RELEASE
TELL VOLUMS(0) IF  LOADED<=T_STATE<=CLAIMED
TELL USER IF  REQ_STATE#0; ! IF TERM OR ATTN EXPECTED
T_DSN=""
T_UNLOAD PENDING=0;   ! IN CASE IT ISNT
END ;     ! ROUTINE RELEASE
!
ROUTINE  REPORT PRIVATE ATTN
IF  REQ_PRIVATE ATTN=0 THENRETURN 
P_DEST=REQ_PRIVATE ATTN
! THE REST IS AS RECEIVED FROM CONTROLLER. PASS IT ON
MYPON(P)
END ;     ! REPORT PRIVATE ATTN
!
ATTN=(T_STREAMR0>>8)&X'FF'
IF  T_GTS=0 THEN  ATTN=ATTN&X'DF';  ! X20 ALWAYS SET FOR MTS
IF  ATTN&ENGINR#0 THEN  ATTN=(ATTN&(¬ENGINR))!NOT AVAIL
! WE TREAT ENGINEER STATE AS SYNONYMOUS WITH NOT AVAILABLE?
!
AGAIN:
IF  ATTN=0 THENRETURN 
IF  T_STATE>1 THEN  I=2 ELSE  I=T_STATE
! THUS LOADING,LOADED,CLAIMED AND UNLOADING=AUTO
->SW(I)
!
SW(0):;   ! NOT AVAILABLE
IF  ATTN&AVAIL#0 START 
  T_STATE=MANUAL
  ATTN=ATTN&(¬AVAIL)
  OPMESS(T_MNEM." available")
  ->AGAIN
FINISH 
->SPURIOUS
!
SW(1):;    ! MANUAL
IF  ATTN&NOT AVAIL#0 START 
  T_STATE=NOT AVAILABLE
  ATTN=ATTN&(¬NOT AVAIL)
  OPMESS(T_MNEM." not available")
  ->AGAIN
FINISH 
IF  ATTN&AUTO#0 START 
  LOAD;  ! INITIATE LOAD (SETTING STATE TO LOADING)
  ATTN=ATTN&(¬AUTO)
  ATTN=ATTN&(¬BT)
  ! IF MTS, BT MAY BE SET IF PREVIOUS TAPE WAS UNLOADED BY STOP/UNLOAD
  ! RATHER THAN BY SOFTWARE. TO BE IN MANUAL HERE WE MUST ALSO
  ! HAVE GONE NOT AVAILABLE, AVAILABLE AS WELL SO NO ACTION IS
  ! REQUIRED ON THE BT.
  ->AGAIN
FINISH 
IF  ATTN&SEC ATTN#0 START 
  ! THIS IS SPURIOUS. GTS DECKS FREQUENTLY FAIL TO DELIVER THE ONLINE ATTN
  ! IF IT IS PRESSED WHILE LOADING. THE DECK DOES GO TO AUTO HOWEVER.
  ! OPS THEN DO RESET/ONLINE, AND WE GET THE RESET AS THIS.
  ATTN=ATTN&(¬SEC ATTN)
  ->AGAIN
FINISH 
->SPURIOUS
!
SW(2):;    ! AUTO
IF  ATTN&AUTO#0 START 
  ! THE DECK HAS GONE TO MANUAL BEHIND OUR BACK. EG STOP IF MTS.
  ! WE MUST ASSUME THAT A NEW TAPE HAS BEEN LOADED.
  ATTN=ATTN&(¬AUTO)
  ATTN=ATTN&(¬BT);   ! MIGHT BE FOR MTS
  RELEASE
  LOAD;  ! AND INITIATE A RELOAD
  ->AGAIN
FINISHELSEIF  ATTN&BT#0 START 
  ! BT WITHOUT AUTO
  IF  REQ_STATE=ATTN EXP OR  REQ_CHAIN=PRIVATE START 
    ATTN=ATTN&(¬BT)
    IF  REQ_STATE=ATTN EXP THEN  TERMINATE(-1,1) C 
                           ELSE  REPORT PRIVATE ATTN
    ->AGAIN
  FINISH 
FINISHELSEIF  ATTN&SEC ATTN#0 START 
  ! MUST BE GTS. THIS BIT IS KNOCKED OUT ABOVE FOR MTS
  ! GTS USES THIS TO REPORT
  !   1) RESET HAS BEEN PRESSED OR VACUUM LOST AND THE DECK IS NOW IN MANUAL
  !   2) THE OFFLINE PART OF A SKIP TM HAS FAILED BACUSE OF BLANK TAPE
  !      OR AN IDENTIFIER ERROR(IF INITIATED AT BT).
  ! WE DONT HAVE UPDATED STATUS BYTES AT THIS POINT TO TELL US WHICH IT
  ! WAS AND IT WOULD BE AN ALMIGHTY HASSLE TO FETCH THEM, SO, IF STATE IS
  ! CLAIMED AND AN ATTENTION EXPECTED, WE DON'T KNOW
  ! WHETHER THE DECK IS NOW IN MANUAL(CASE 1) OR STILL IN AUTO(2).
  ! WE MUST FORCE IT INTO A KNOWN STATE, IE UNLOAD IT. THIS IS PRETTY
  ! DRASTIC, BUT HOPEFULLY VERY VERY RARE.
  ATTN=ATTN&(¬SEC ATTN)
  IF  T_STATE=CLAIMED START 
    OPMESS(T_MNEM." manual when in use")
    IF  REQ_STATE=ATTN EXP START ;   ! THIS IS THE DOUBTFUL ONE
      TELL USER
      T_LOAD STATE=6
      LOAD;  ! EVEN IF IT IS ALREADY OFF, THIS RESETS THINGS AND TELLS VOLUMS
      ->AGAIN
    FINISH 
  FINISH 
  ! SO IF WE GET HERE, IT IS GENUINELY OFF LINE, SINCE 'SKIP TM' IS NOT
  ! DONE IN 'LOAD'.
  RELEASE
  T_STATE=MANUAL
  OPMESS(T_MNEM." unloaded")
  ->AGAIN
FINISHELSEIF  ATTN&TM#0 START 
  IF  REQ_STATE=ATTN EXP OR  REQ_CHAIN=PRIVATE START 
    ATTN=ATTN&(¬TM)
    IF  REQ_STATE=ATTN EXP THEN  TERMINATE(-1,0) C 
                           ELSE  REPORT PRIVATE ATTN
    ->AGAIN
  FINISH 
FINISHELSEIF  ATTN&NOT AVAIL#0 START 
  ATTN=ATTN&(¬NOT AVAIL)
  OPMESS(T_MNEM." not available")
  RELEASE
  T_STATE=NOT AVAILABLE
  ->AGAIN
FINISHELSEIF  ATTN&HOLD#0 START 
  IF  T_GTS=0 START ;  ! MTS ONLY
    ATTN=ATTN&(¬HOLD)
    OPMESS(T_MNEM." manual when in use") IF  T_STATE=CLAIMED
    IF  REQ_STATE=0 START 
      ! CLAIMED AND IDLE, OR LOADED. NOT LOADING OR UNLOADING.
      T_LOADSTATE=6
      LOAD;   ! UNLOAD ENTRY POINT
    FINISHELSESTART 
      ! CLAIMED AND IN USE, OR LOADING OR UNLOADING
      T_UNLOAD PENDING=1 UNLESS  T_STATE=UNLOADING
    FINISH 
    ->AGAIN
  FINISH 
FINISH 
! AND DROP THRU' TO..
!
SPURIOUS:
REPORT("SPURIOUS ATTENTION(S)")
END ;      ! ROUTINE ATTENTION
!
!
ROUTINE  TERMINATE(INTEGER  NORMAL,BT)
!**********************************************************************
! ENTERED ON CHAIN TERMINATION.
! NORMAL=0 FOR NORMAL TERMINATION,
!       >0 FOR ABNORMAL TERMINATION,
!       =-1 IF WE ENTERED VIA ATTENTION FOR EXPECTED BT OR TM,
!           WHEN BT=1 OR 0 RESPECTIVELY.
!           THIS ENTRY FOR CHAINS 16,17(SKIP TM FORE AND AFT),18(REWIND)
!           AND NOTIONAL CHAIN 0, SEE US(5) BELOW.
!**********************************************************************
CONSTINTEGER  ERROR CLASSES=7
!
CONSTSTRING (14)ARRAY  USMESS(1:ERROR CLASSES)= C 
  "LOST DEVICE",
  "LOST POSITION",
  "REV BT",
  "IRRECOVERABLE",
  "RECOVERABLE",
  "STIE/MTIE/RIPE",
  "UNDEFINED"
!
INTEGER  PSTAT,FINAL COMMAND,ERROR CLASS,SKIP,REMBC,FLAG
SWITCH  OK(0:MAX CHAINS),US(1:ERROR CLASSES),LS,TM(1:MAX CHAINS)
!
INTEGERFN  DIAGNOSE
! ENTERED ON ABTERM WITH UNSUCCESSFUL IN PSTAT TO DIAGNOSE ERROR BITS
! IN TERTIARY STATUS T0-T7
! RETURNS ERROR CLASS.
!
! THE INTERPRETATION OF THE TERTIARY STATUS BITS FOLLOWS, TOGETHER WITH
! THEIR ASSIGNMENT TO ONE OF SEVEN CLASSES. THE CLASSES ARE:
!
! 1 - LOST DEVICE
! 2 - EITHER LOST POSITION OR SHOULD NEVER HAPPEN SO WE HAVE A BUG.
! 3 - REVERSED INTO BT
! 4 - COMMAND FAILED AND THEIR IS NO POINT IN RETRYING, BUT POSITION
!     IS OK, AND THE USER MAY CONTINUE.
! 5 - COMMAND FAILED AND SHOULD BE RETRIED.
! 6 - ADVISORY (JUST LOG IT FOR ENGINEERS SAKE)
! 7 - UNDEFINED. SHOULD NEVER BE SET.
!
! SOME OF THE BITS INDICATE ERRORS IN THE STRUCTURE OF A BLOCK -
! EG 'NON VALID NRZI BLOCK', 'NO PREAMBLE', ETC.  
! IT MIGHT BE THOUGHT THAT SINCE A BLOCK, ALBEIT DEFORMED, WAS DETECTED
! IT IS SAFE TO SKIP BACK OVER IT FOR A RETRY. HOWEVER, THE BLOCK MIGHT
! NOT BE DETECTED IN REVERSE AND POSITION WOULD THUS BE LOST. ALL SUCH
! BITS ARE THEREFORE ASSIGNED TO CLASS 2. THIS MAY BE TOO SEVERE IN THE
! LIGHT OF EXPERIENCE.
! 'NO POSTAMBLE' HAS BEEN RECLASSIFIED FROM 2 TO 5. IT WAS FOUND TO OCCUR
! SPURIOUSLY VERY OFTEN WITH UTIE, AND SO FAR HAS BEEN FOUND SAFE TO RETRY.
! ON THE OTHER HAND, EXPERIENCE HAS SHOWN THAT 'NO PREAMBLE' MUST VERY 
! DEFINITELY NOT BE RETRIED.
!
! IN THE FOLLOWING CLASSIFICATIONS THE BITS IN LONGINTEGER T07 ARE
! NUMBERED FROM THE MOST SIGNIFICANT END A LA ICL.
!
! MTS TERTIARY STATUS BITS
! --- -------- ------ ----
!    N      CLASS   MEANING
!
!    0        1     MANUAL
!    1        1     NOT AVAILABLE
!    2-7      7     UNDEFINED
!    8        2     IPE                WE DONT KNOW WHETHER THE ERROR
!    9        2     2*RIPE             WAS ON THE COMMAND GOING OR DATA
!   10        2     SRNH               COMING, SO POSITION IS LOST.
!   11-15     7     UNDEF
!   16        2     ILLEGAL COMMAND    A BUG
!   17        2     ILLEGAL MODE       DITTO
!   18        4     ILLEGAL DATA       CE MODE ONLY
!   19        4     DOUBLE FILLER      ONLY WITH A18
!   20        3     REVERSED INTO BT
!   21        2     NO RING FOR WRITE  A BUG
!   22        2     DECK BUSY          SHOULD NEVER HAPPEN, SO BUG
!   23        7     UNDEF
!   24        5     VRC
!   25        2     NON VALID NRZI BLOCK
!   26        5     UTIE
!   27        5     SKEW
!   28        2     NO PREAMBLE(PE)
!             5     CRC(NRZI)
!   29        5     DATA SHORT(PE)     HAPPENS FOR PARTICULAR DATA PATTERN
!                                      AND STIE CORRECTION
!             5     LRC(NRZI)
!   30        5     NO POSTAMBLE(PE)
!             5     TIE(NRZI)
!   31        5     THRESHOLD
!   32        2     IDENTIFIER         A BUG(EXCEPT IN LOAD SEQUENCE
!   33        2     NO DATA WRITTEN    WHAT DOES THIS MEAN???
!   34        2     INVALID NRZI BLOCK OF A DIFFERENT KIND!!
!   35        7     UNDEF
!   36        2     25 FEET BLANK
!   37        2     RETURN FAILED. DEVICE TIME OUT
!   38        2     POOR ERASURE.      NOW YOU SEE IT, NOW YOU DONT
!   39-47     7     UNDEF
!   48        6     RIPE
!   49-50     7     UNDEF
!   51        6     STIE               ERROR RECOVERED ON FLY
!   52-63     7     UNDEF
!
! SINCE SOME BITS ARE ASSIGNED TO DIFFERENT CLASSES DEPENDING ON THE MODE
! WE NEED TWO SETS OF MASKS
!
CONSTLONGINTEGERARRAY  PE ERROR MASKS(1:ERROR CLASSES)= C 
  X'C000000000000000',
  X'00E0C608CE000000',
  X'0000080000000000',
  X'0000300000000000',
  X'000000B700000000',
  X'0000000000009000',
  X'3F1F014031FF6FFF'
CONSTLONGINTEGERARRAY  NRZI ERROR MASKS(1:ERROR CLASSES)= C 
  X'C000000000000000',
  X'00E0C640EE000000',
  X'0000080000000000',
  X'0000300000000000',
  X'000000BF00000000',
  X'0000000000009000',
  X'3F1F010011FF6FFF'
!
! GTS TERTIARY STATUS BITS:
! --- -------- ------ ----
!
!  N       CLASS   MEANING
!
!  0         1     MANUAL
!  1         1     NOT AVAILABLE
!  2-7       7     UNDEFINED
!  8         2     IPE
!  9         2     2*IPE
! 10         2     SRNH
! 11         2     BUFFER ERROR
! 12         2     FORMATTER ERROR
! 13         2     BUFFER PE
! 14-15      7     UNDEF
! 16         2     ILLEGAL COMMAND
! 17         2     ILLEGAL MODE
! 18         4     INCOMPLETE CE BURST
! 19         4     DITTO
! 20         3     REVERSED INTO BT
! 21         2     NO RING FOR WRITE
! 22         2     BUSY
! 23         7     UNDEF
! 24         5     ARA ERROR(GCR)
! 25         7     NRZ ERROR          THIS SHOULD ALWAYS QUALIFY OTHER BITS
!                                     IN THE MEDIA BYTE, SO WE DONT EXPECT TO
!                                     SEE IT ALONE. IF WE DO, LOG IT.
! 26         5     UNCORRECTABLE ERROR
! 27         7     UNDEF
! 28         5     DATA CHECK         THIS IS 'OR' OF 12 OTHER CONDITIONS.
!                  IE CRC ERROR       SOME OF THEM ARE MORE SEVERE THAN CLASS 5
!                     WTM CHECK       AND ARE SET ELSEWHERE AS WELL, SO WONT ARISE
!                     LRC ERR(NRZ)    HERE. THE REMAINDER ARE ALL CLASS 5. SOME
!                     MULTI TIE       OF THEN APPEAR ELSEWHERE AS WELL, BUT FOUR
!                     (GCR/PE)        CONDITIONS APPEAR ONLY IN STATUS BYTES BEYOND
!                                     7, SO WE USE THIS TO CATCH THEM. THEY ARE AS
!                                     SHOWN AT LEFT.
! 29         5     END DATA CHECK     A29 AND A30 GO TOGETHER TO GIVE:-
! 30         2     PARTIAL RECORD     10=NO PREAMBLE AND 11=NO POSTAMBLE.
!                  (GCR/PE)           WE WOULD LIKE TO TREAT THESE AS CLASS 2 AND
!                                     5 RESPECTIVELY BUT A30 IS THE WRONG WAY ROUND
!                                     FOR THIS TO WORK ON A 1 BIT MASK BASIS. SO
!                                     IF A29 IS SET, WE INVERT A30 BEFORE MASKING
! 31         5     CRC/ACRC ERROR(NRZ/GCR)
! 32         2     IDENTIFIER ERROR(GCR/PE)   NOT SAME AS MTS
! 33         2     NO DATA WRITTEN
! 34         2     CHARACTER IN GAP
! 35         2     VELOCITY ERROR
! 36         2     BLANK TAPE         25' PE/NRZ, 15' GCR
! 37         2     STEP TIMEOUT       BYTE 10 HAS REJECT CODES
! 38         2     POOR ERASURE
! 39-47      7     UNDEF
! 48         6     RIPE
! 49         2     INCOMPATIBLE MODE  THIS IS SAME AS MTS BIT A32. WE KEEP
!                                     CLOSE CONTROL OF THE MODE SO THIS IS A BUG
! 50         7     UNDEF
! 51         6     STIE(GCR/PE)
! 52         6     MTIE(GCR)
! 53-63      7     UNDEF
!
! BYTES 8-14 HAVE ADDITIONAL INFO, BUT THIS IS EITHER DUPLICATED ABOVE OR
! FOR ADVISORY PURPOSES ONLY AND IS NOT USED IN DIAGNOSIS.
!
! ALTHOUGH THE EXACT INTERPRETATION OF SOME BITS IS MODE DEPENDANT, THERE
! ARE NO DIFFERENCES IN THE RESULTING CLASS ASSIGNMENTS. 
! WE ONLE NEED ONE SET OF MASKS THEREFORE.
!
CONSTLONGINTEGERARRAY  GTS ERROR MASKS(1:ERROR CLASSES)= C 
  X'C000000000000000',
  X'00FCC602FE004000',
  X'0000080000000000',
  X'0000300000000000',
  X'000000AD00000000',
  X'0000000000009800',
  X'3F03015001FF27FF'
!
! SINCE ALL POSSIBLE CLASS 5 AND 6 ERRORS ARE MASKED OFF AT THE START
! OF EVERY MULTI-COMMAND READ RETRY CHAIN, EACH SUCH CHAIN CAN
! TERMINATE BEFORE THE LAST COMMAND, ONLY FOR CLASSES 1,2,3 AND 4.
! FOR CLASSES 1 AND 2, POSITION IS ALREADY LOST BY VIRTUE OF THE ERROR,
! SO THE POSITION OF THE FAILING LBE(CW) IS IRRELEVANT. IT LOOKS UNLIKELY
! THAT THE CURRENTLY DEFINED CLASS 4 ERRORS (CONCERNING THE DATA COUNT
! IN CE MODE) COULD ARISE OTHER THAN ON THE PRIMARY READ OF A SEQUENCE,
! BUT IT IS POSSIBLE IF SUCH ERRORS ARE MASKED AT THE DEVICE LEVEL BY
! OTHER ERRORS. IN ANY CASE, TO CATER FOR THE RECLASSIFICATION OF SOME
! BITS, WE ARE PREPARED TO DO A FINAL REPOSITIONING FROM A CLASS 4
! ERROR OCCURRING ANYWHERE THRU' A MULTI-COMMAND READ CHAIN. IN ALL
! CASES, HOWEVER, WE ASSUME THAT THE FAILING LBE(CW) WILL HAVE BEEN
! EFFECTIVE IN TRAVERSING ITS BLOCK.
!
! THE SAME PROBLEM DOES NOT ARISE FOR WRITE AND WRITE TM RETRIES
! WHICH ARE MUCH LESS COMPLEX.
!
!
LONGINTEGER  T07
INTEGER  I
LONGINTEGERARRAYNAME  ERROR MASKS
!
T07=T_T07
IF  T_GTS=0 START ;    ! MTS DECK
  IF  T_MODE&3=3 THEN  ERROR MASKS==PE ERROR MASKS C 
                ELSE  ERROR MASKS==NRZI ERROR MASKS
FINISHELSESTART 
  ERROR MASKS==GTS ERROR MASKS
  ! INVERT A30 IF A29 SET TO GET NO PREAMBLE AND NO POSTAMBLE RIGHT. WE DONT
  ! EXPECT TO SEE A30 ON ITS OWN BUT IF WE DO,THE EFFECT IS TO GIVE THE MORE SEVERE
  ! ERROR WHICH IS CORRECT.
  T07=T07!!((T07&X'0000000400000000')>>1)
FINISH 
!
FOR  I=1,1,ERROR CLASSES CYCLE 
  IF  T07&ERROR MASKS(I)#0 THENEXIT 
REPEAT 
! SO I HAS ERROR CLASS.
RESULT =I
END ;        ! FN DIAGNOSE
!
!********* TERMINATE STARTS HERE **********
!
IF  REQ_STATE=0 START 
  REPORT("SPURIOUS TERMINATION")
  RETURN 
FINISH 
IF  T_STREAMR1=-1 START ;  ! TIMEOUT
  REPORT("TIME-OUT")
  REP_P2=3
  ->REPLY
FINISHELSESTART ;   ! NOT TIMOUT
  IF  NORMAL=-1 THEN  ->OK(REQ_CHAIN)
  ! IE ENTERED VIA ATTENTION FOR EXPECTED, NON-PRIVATE, TM OR BT
  ! CHAINS 16,17,18 AND 0 ONLY.
  PSTAT=(T_STREAMR0>>8)&X'FF'
  REMBC=T_STREAMR1&X'3FFFF';  ! REMAINING BYTE COUNT.
  IF  NORMAL=0 START 
    FINAL COMMAND=CHAIN START(REQ_CHAIN)+CHAIN LENGTH(REQ_CHAIN)-1; ! THE LAST
    ! REP_P2=0
    ->OK(REQ_CHAIN) UNLESS  REQ_CHAIN=PRIVATE
    ! OTHERWISE DROP THRU' TO 'REPLY'.
  FINISHELSESTART ; ! ABTERM
    FINAL COMMAND=CHAIN START(REQ_CHAIN)+T_STREAMR0&X'FF'
    ! GET GPC SENSE DATA.
    ! IN DCU CASE, THE H/W SENSE INTO POSTAMBLE IS NOT DONE FOR UNMASKED
    ! L,S,X,Y, BUT WE DONT NEED IT IN THAT CASE.
    IF  P_P4&X'FF'=X'80' START ; ! SENSE OK
      MOVE(15,D_SENSDATAD+1,ADDR(T_T0))
      T_SSTAT=BYTEINTEGER(D_SENSDATAD)
    FINISHELSESTART 
      ! EITHER GPC SOFTWARE SENSE FAILED, OR DCU H/W SENSE FAILED
      REPORT("NONSENSE")
      ! NO IDEA WHAT DEVICE STATE IS. MAYBE LOST DEVICE OR POSITION.
      REP_P2=3
      ->REPLY
    FINISH 
    ! NOW CHECK FOR CONTROLLER ERRORS
    FLAG=(T_STREAMR0>>16)&X'FF'
    IF  FLAG=X'41' START 
      REPORT("CDE");   ! THIS IS ACTUALLY ACTIVATE FAILS FOR DCU
      ! PROBABLY HAVEN'T MOVED TAPE IF IT SHOULD HAVE BEEN. BETTER BAIL OUT
      REP_P2=3
      ->REPLY
    FINISHELSEIF  FLAG=X'42' START 
      ! THIS CASE ONLY ARISES FOR DCU
      REPORT("INITIALISE FAILURE")
      REP_P2=3
      ->REPLY
    FINISH 
    ! SO IT MUST BE EITHER U/S OR UNMASKED L,S,X,Y
    UNLESS  REQ_CHAIN=PRIVATE START ;  ! NO DIAGNOSES OR RETRYIES FOR PRIVATE
      IF  PSTAT&128#0 START ;   ! UNSUCCESSFUL
        ERROR CLASS=DIAGNOSE
        REPORT(USMESS(ERROR CLASS)) UNLESSC 
                                    (ERROR CLASS=1 AND  T_LOAD STATE=2) ORC 
                                    (T_LOAD STATE=3 ANDC 
                                     ((T_GTS=0 AND  T_T4&128#0) ORC 
                                      (T_GTS#0 AND  T_T6&64#0)))
        ! DONT REPORT NOTAVAIL OR MANUAL FOR INITIAL REWIND IN LOAD.
        ! WE EXPECT IT FOR DECKS UNLOADED AT START-UP.
        ! ALSO SUPPRESS REPORT FOR 'ILLEGAL MODE' WHILE ESTABLISHING IT
        ! DURING LABEL READ.
        ->US(ERROR CLASS)
      FINISHELSEIF  PSTAT&3#0 START ;   ! TM OR ET
        ->TM(REQ_CHAIN)
      FINISHELSEIF  PSTAT&12#0 START ;  ! LONG OR SHORT
        REP_P2=1
        ->LS(REQ_CHAIN)
      FINISHELSESTART ;  ! WHAT CAUSED IT THEN ????
        REPORT("SPURIOUS ABTERM")
        REP_P2=3
        ->REPLY
      FINISH 
    FINISH ;  ! NOT PRIVATE.  PRIVATE DROPS OUT TO 'REPLY'
  FINISH ;  ! ABTERM
FINISH ;   ! NOT TIMEOUT
!
! CAUTION. DROP THRU' HERE FOR PRIVATE CHAINS
!
REPLY:
IF  REQ_CHAIN=PRIVATE START 
  REP_P3=T_STREAMR0
  REP_P4=T_STREAMR1
FINISH 
! NOTOINAL P5 AND P6 ALWAYS GO BACK WITH T0-T7
REQ_STATE=0
MYPON(RECORD(ADDR(REP))) IF  REP_DEST#0;  ! REPLY TO USER IF NOT 'LOAD'
IF  T_UNLOAD PENDING#0 START 
  ! ONLY IF STATE IS LOADING OR CLAIMED
  T_UNLOAD PENDING=0
  T_LOAD STATE=6; ! UNLOAD ENTRY. IF WE WERE ABOUT TO REPLY TO LOAD
                  ! THIS TAKES THE PLACE OF THE REPLY.
  REP_DEST=0;    ! IF IT WAS A USER WE WANT TO GO TO 'LOAD AS WELL
FINISH 
LOAD IF  REP_DEST=0
RETURN 
!
!
!*********** OK *********** OK *********** OK *********** OK ***********
!
OK(0):
! WE COME HERE VIA 'ATTENTION' AFTER GETTING A REVERSE BT FAILURE AT
! US(5) BELOW, AND THE RESULTING ATTENTION HAS COME.
! THE REPLY IS ALL SET UP.
->REPLY
!
!------------------------------------------------------------------
!
OK(1):OK(2):OK(3):OK(4):OK(5):OK(6):OK(7):OK(8):OK(9):OK(10):;  ! ALL READS
LS(1):LS(2):LS(3):LS(4):LS(5):LS(6):LS(7):LS(8):LS(9):LS(10):
! LONG/SHORT ONLY ABTERM. GOES BACK TO USER WITH P2=1 AND P4 LONG/SHORT.
! THE LATTER DISTINGUISHING IT FROM MEDIA ERROR.
!
! ARE WE ON THE RIGHT SIDE OF THE BLOCK
SKIP=REQ_TARGET POS-((POSMASK>>FINAL COMMAND)&1)
! TARGET POS SET IN ACCEPT REQUEST. 2**FINAL LBE(CW) IN POSMASK SET IF THAT
! LBE(CW) LEFT US AFTER BLOCK, ELSE BEFORE.
! SO SKIP=1 MEANS A FORWARD SKIP REQUIRED
!        =0 MEANS POSITION CORRECT
!        =-1 MEANS A REVERSE SKIP REQUIRED
REP_P3=REQ_LENGTH
IF  PSTAT&4#0 START ;  ! LONG BLOCK
  IF  SKIP#0 START 
    ! IT WAS READ IN A DIRECTION OTHER THAN THE ORIGINAL REQUEST. THIS
    ! CANT BE COUNTED A SUCCESS SINCE WEVE FETCHED THE WRONG END. 
    ! SIMULATE A MEDIA ERROR AND CONTINUE WITH RETRIES.
    ->US(4)
  FINISH 
  ! SO WE READ IN THE RIGHT DIRECTION. TELL USER IT WAS LONG
  REP_P4=2
  ! LENGTH IS CORRECT
FINISHELSEIF  PSTAT&8#0 START ;  ! SHORT BLOCK
  REP_P3=REQ_LENGTH-REMBC;  ! LATTER IS UNEXPIRED COUNT
  IF  (REVMASK>>FINAL COMMAND)&1#0 AND  REQ_READORS&NODATA=0 START 
    ! NOT READCHECK AND READ IN REVERSE. DATA IS AT TOP OF BUFFER
    REP_P3=-REP_P3;  ! INDICATE THIS TO USER
  FINISH 
  REP_P4=1;   ! SHORT FOR USER
FINISH 
IF  REQ_READORS&NODATA#0 AND  REP_P2=0 THEN  REP_P4=REQ_RETRIES
! 'NO DATA' SET, SO IT WAS A READCHECK. TELL RETRIES.
UNLESS  REQ_RETRIES=0 START 
  IF  LENGTH(T_DSN)>7 THEN  LENGTH(T_DSN)=0
  ! MIGHT BE IF WERE IN LOAD SEQUENCE OF NON-STANDARD LABEL
  PRINTSTRING(T_MNEM." ".T_DSN." ".HTOS(REQ_RETRIES,3)." READ RETRY OK
")
FINISH 
!
! THATS THE REPLY ALL SET UP
TEST FINAL SKIP:
! CAUTION. WE COME HERE FROM US(4) ALSO
IF  SKIP=0 THEN  ->REPLY
!
! SO FINAL SKIP REQUIRED
! THE ORIGINAL USER'S ASL IS STILL SET UP IN REQ_ADDR ETC, SO NO NEED
! FOR A DUMMY.
DO FINAL SKIP:
! CAUTION*** WE COME HERE FROM TM(1) AND TM(2) ALSO.
IF  SKIP>0 THEN  REQ_CHAIN=20 ELSE  REQ_CHAIN=21
! THESE SKIPS IGNORE TMS
FIRE CHAIN
RETURN 
!
!------------------------------------------------------------------
!
OK(11):OK(12):; ! WRITE ,WRITE TM
UNLESS  REQ_RETRIES=0 START 
  REP_P4=REQ_RETRIES
  PRINTSTRING(T_MNEM." ".T_DSN." ".HTOS(REQ_RETRIES,3)." WRITE RETRY OK
")
FINISH 
->REPLY
!
!------------------------------------------------------------------
!
OK(13):;           ! REPOSITION AND ERASE FOR WRITE AND WRITE TM RETRY
! COME HERE FROM TM(13) ALSO
REQ_CHAIN=REQ_FINAL CHAIN;  ! SET UP IN 'ACCEPT REQUEST'
! EVERYTHING ELSE REMAINS OK
FIRE CHAIN
RETURN 
!
!------------------------------------------------------------------
!
OK(14):OK(15):;     ! SKIP BLOCKS, FORE AND AFT
TEST SKIP END:;     ! CAUTION. ALSO COME HERE FROM SKIP TM FORE AND AFT
IF  T_UNLOAD PENDING#0 START ;  ! HOLD HAS BEEN KEYED
  REP_P2=3
  ->REPLY
FINISH 
REQ_COUNT=REQ_COUNT+1
IF  REQ_COUNT<REQ_SKIPTOT START ;  ! NOT FINISHED
  IF  REQ_CHAIN=16 AND  REQ_TM#0 THEN  REQ_CHAIN=22;   ! TM LOOK-AHEAD
  FIRE CHAIN;     ! THE SAME ONE AGAIN
  RETURN 
FINISH 
! SO FINISHED
IF  REQ_CHAIN=16 AND  REQ_TM=0 THEN  REQ_TM=1;   ! IMPLIED
IF  REQ_CHAIN<16 THEN  REP_P3=REQ_COUNT ELSE  REP_P3=REQ_COUNT*REQ_TM
!                      BLOCKS                 TMS (COUNT1 MUST BE =0)
->REPLY
!
!------------------------------------------------------------------
!
OK(16):OK(17):;     ! SKIP TMS, FORE AND AFT
IF  REQ_STATE=TERM EXP THEN  REQ_STATE=ATTN EXP ANDRETURN 
! THAT WAS THE TAPE MOVEMENT BEGINNING. WE COME BACK HERE VIA
! ROUTINE ATTENTION WHEN WE HIT TM OR BT.
IF  BT#0 START ;  ! MUST HAVE NEEN REVERSE
  REP_P2=4
  REP_P3=REQ_COUNT*REQ_TM+REQ_COUNT1
  ->REPLY
FINISH 
! SO IT WAS A TM
IF  REQ_TM=0 THEN  ->TEST SKIP END
! SPECIAL FOR RESTORES. IMPLIES 1 TM/LOGICAL FILE AND NO TM LOOK-AHEAD
REQ_COUNT1=REQ_COUNT1+1
IF  REQ_COUNT1=REQ_TM START ;   ! ONE FILES WORTH
  REQ_COUNT1=0
  ->TEST SKIP END
FINISH 
FIRE CHAIN
RETURN 
!
!------------------------------------------------------------------
!
OK(18):;     ! REWIND
IF  REQ_STATE=TERM EXP THEN  REQ_STATE=ATTN EXP ANDRETURN 
! THAT WAS START OF MOVEMENT. COME BACK VIA ATTN AT BT.
->REPLY
!
!------------------------------------------------------------------
!
OK(19):;     ! ERASE
->REPLY
!
!------------------------------------------------------------------
!
OK(20):OK(21):;   ! FINAL POSITION SKIP. REPLY ALL SET UP
->REPLY
!
!------------------------------------------------------------------
!
OK(22):;      ! TEST FOR TM. SUCCESS MEANS TM NOT SEEN ON REVERSE SKIP
REQ_CHAIN=16;  ! REPLACE ORIGINAL CHAIN WHICH WAS SKIP FORE TO TM
FIRE CHAIN
RETURN 
!
!------------------------------------------------------------------
!
OK(23):OK(24):OK(25):;     ! UNLOAD, SPC, QSPC
->REPLY
!
!
!*********** US *********** US *********** US *********** US ***********
!
! ADMINISTRATIVE SKIPS COME HERE ALSO IF THEY FAIL. THEY SHOULD ONLY APPEAR
! AS CLASSES 1 OR 2.
!
US(1):;        ! OFFLINE
! WE GET HERE FOR MANUAL/NOTAVAIL DURING A CHAIN. WE COULD DO THE STATE
! CHANGE HERE, BUT FOR CONSISTENCY WE LEAVE IT TO BE DEALT WITH BY
! 'ATTENTION' WHEN THE STATE CHANGE COMES.
! IN THE MEANTIME THE USER WILL CONTINUE TO GET REPLIES OF 3 FROM HERE
! IF HE PERSISTS.
! DROP THRU' TO .....
!
!------------------------------------------------------------------
!
US(2):;         ! LOST POSITION
! CAUTION***. COME HERE FROM US(1) ALSO
REP_P2=3;    ! DISASTER
->REPLY
!
!------------------------------------------------------------------
!
US(3):;      ! REVERSED INTO BT. READ REV OR SKIP REV ONLY
! THERE IS NOW A BT ATTN TO COME IF NOT GTS
IF  REQ_CHAIN=2 OR  REQ_CHAIN=15 START 
  ! OK. SET UP REPLY COMPLETELY.
  REP_P2=4
  IF  REQ_CHAIN=15 THEN  REP_P3=REQ_COUNT;  ! NUMBER SKIPPED BEFORE HERE
FINISHELSESTART 
  PRINTSTRING(T_MNEM."***UNEXPECTED REV BT ***
")
  REP_P2=3;   ! WE HAVEN'T CATERED FOR THIS. ALL HELL MAY NOW BREAK LOOSE
FINISH 
IF  T_GTS=0 START ;   ! MTS. SET UP TO WAIT FOR ATTN
  REQ_CHAIN=0;  ! JUST TO WAIT FOR 'NORMAL' TERM FROM 'ATTENTION'
  REQ_STATE=ATTN EXP
  RETURN 
FINISHELSE  ->REPLY
!
!------------------------------------------------------------------
!
US(4):;        ! STRAIGHT BACK
! CAUTION***. COME HERE FROM US(5) ALSO
REP_P2=1
IF  T_T2&X'30'#0 THEN  REP_P4=4;   ! BAD CE DATA COUNT
! NOW A FINAL REPOSITION MAY BE REQUIRED IF IT WAS A READ
IF  REQ_CHAIN<=LAST READ CHAIN START 
  SKIP=REQ_TARGET POS-((POSMASK>>FINAL COMMAND)&1)
  ->TEST FINAL SKIP
FINISH 
->REPLY
!
!------------------------------------------------------------------
!
US(5):;       ! RETRIABLE
! WE DO NOT EXPECT TO GET CLASS 5 ERRORS OM COMMANDS OTHER THAN READS
! WRITE AND WRITE TM, FOR ALL OF WHICH RETRIES ARE DEFINED (AND FOR
! WHICH THE EMBEDDED SKIPS INVOLVED IN MULTIPLE RETRY CHAINS HAVE
! CLASS 5 ERRORS MASKED OFF). IF THIS INTERPRETATION OF THE ERROR
! BITS IS INCORRECT AND A CLASS 5 ERROR OCCURS ON A STRAIGHT SKIP, REWIND,
! ERASE, ETC. WE WILL LOG IT HERE AND GIVE THE USER A DISASTER(3) REPLY,
! SINCE WE MAY HAVE LOST POSITION. IN THE LIGHT OF EXPERIENCE WE MAY
! HAVE TO RECLASSIFY THE BITS TAKING INTO ACCOUNT THE ACTUAL DEVICE
! COMMAND IN EXECUTION AT FAILURE.
!
IF  REQ_CHAIN<=LAST RETRY CHAIN START ;  ! ALL THE ONES WE EXPECT
  REQ_RETRIES=REQ_RETRIES+1
  IF  REQ_RETRIES>REQ_RETRY LIMIT START 
    IF  LENGTH(T_DSN)>7 THEN  LENGTH(T_DSN)=0
    ! MIGHT BE FOR LOAD OF NON-STANDARD LABELLED
    PRINTSTRING(T_MNEM." UNRECOVERED ERROR ".T_DSN."
")
    ->US(4)
  FINISH 
  ! IE, TEST FOR FINAL SKIP IF READ, OTHERWISE STRAIGHT BACK
  IF  REQ_CHAIN<=LAST READ CHAIN START 
    IF  REQ_CHAIN=REQ_FINAL CHAIN THEN  REQ_CHAIN=REQ_CHAIN-7 C 
                                  ELSE  REQ_CHAIN=REQ_CHAIN+1
    ! SET BACK TO START+1, ELSE NEXT IN BASIC SEQUENCE
  FINISHELSESTART ;   ! WRITE OR WRITE TM
    REQ_CHAIN=13;     ! SKIP REV AND ERASE WRITTEN LENGTH
  FINISH 
  FIRE CHAIN
  RETURN 
FINISH 
!
! SO WE SHOULDN'T BE HERE.
REP_P2=3
PRINTSTRING(T_MNEM."*** UNEXPECTED RECOVERABLE ERROR ***
");   ! ITS 'REPORTED' ABOVE
->REPLY
!
!------------------------------------------------------------------
!
US(6):;     ! ADVISORY ONLY(SHOULD ONLY BE READS)
US(7):;     ! UNDEFINED
! HAS BEEN 'REPORTED' ABOVE. TREAT AS SUCCESS OTHERWISE
->OK(REQ_CHAIN)
!
!
!
!*********** TM *********** TM *********** TM *********** TM ***********
!
TM(1):TM(2):;      ! READ FORE AND AFT
IF  REQ_RETRIES=0 START 
  ! JUST TO MAKE SURE WE ARE ON THE PRIMARY READ OF A SEQUENCE
  IF  REQ_CHAIN=1 THEN  SKIP=-1 ELSE  SKIP=1
  REP_P2=4
  ->DO FINAL SKIP
FINISH 
! ELSE DROP THRU' TO......
!
!------------------------------------------------------------------
!
TM(3):TM(4):TM(5):TM(6):TM(7):TM(8):TM(9):TM(10):
TM(16):TM(17):TM(18):TM(20):TM(21):TM(23):TM(24):TM(25):
! READ RETRIES,SKIP TM FORE AND AFT,REWIND,POSITIONING SKIPS,
! UNLOAD,SEND PROPS, QUALIFIED SPC
REPORT("UNEXPECTED TM")
REP_P2=3
->REPLY
!
!------------------------------------------------------------------
!
TM(11):TM(12):TM(19):;   ! MUST BE ET AFTER WRITE, WRITE TM OR ERASE
! THE WRITE WAS OTHERWISE OK.
REP_P2=4
->REPLY
!
!------------------------------------------------------------------
!
TM(13):;          ! ET ON ERASE DURING WRITE(TM) RETRY 'SKIPREV,ERASE'
REP_P2=4;  ! THIS REMAINS THE REPLY IF IT FINALLY SUCCEEDS
->OK(13)
!
!------------------------------------------------------------------
!
TM(14):TM(15):;    ! SKIP FORE AND AFT
IF  REQ_TM#0 THEN ->TEST SKIP END
! IE EXACTLY AS SUCCESS IF TMS TO BE TREATED AS BLOCKS
IF  REQ_CHAIN=14 THEN  SKIP=-1 ELSE  SKIP=1
REP_P2=4
REP_P3=REQ_COUNT
->DO FINAL SKIP
!
!------------------------------------------------------------------
!
! TM(16,17,18) DEFINED AT TM(3) ABOVE
!
!------------------------------------------------------------------
!
! TM(19) DEFINED AT TM(11) ABOVE
!
!------------------------------------------------------------------
!
! TM(20,21) DEFINED AT TM(3) ABOVE
!
!------------------------------------------------------------------
!
TM(22):;        ! LOOK-AHEAD FOR TM AFTER SKIP TM FORE. FOUND ONE
REP_P2=4
REP_P3=REQ_COUNT*REQ_TM
->REPLY
!
!------------------------------------------------------------------
!
! TM(23,24,25) DEFINED AT TM(3) ABOVE
!
!------------------------------------------------------------------
!
!*********** LS *********** LS *********** LS *********** LS ***********
!
! LS(1-10) DEFINED AT OK(1) ABOVE
!
!------------------------------------------------------------------
!
LS(11):LS(12):LS(13):LS(14):LS(15):LS(16):LS(17):LS(18):LS(19):LS(20):
LS(21):LS(22):LS(23):LS(24):LS(25):
REPORT("SPURIOUS LONG/SHORT")
REP_P3=3;  ! FOR NOW TREAT THIS AS DISASTER SINCE IT SHOULD NEVER HAPPEN
->REPLY;   ! AND IF IT DOES THERE MAY BE SOMETHING FUNDAMENTALLY WRONG.
!
!
!
END ;        ! ROUTINE TERMINATE
!
!
INTEGERFN  ACCEPT REQUEST
!**********************************************************************
! CHECKS USER REQUEST AND REFORMATS IT FOR USE BY 'FIRE CHAIN'.
! SINCE WE'VE GOT HERE WITH T AND REQ MAPPED VIA THE SNO FROM THE USER
! WE KNOW THE DECK IS LOADED AND CLAIMED.
!**********************************************************************
! DEFINED REQUESTS (HISTORICALLY QUAINT) ARE:
!   0=ERASE
!   1=READ
!   2=WRITE
!   3=UNDEF
!   4=READ CHECK
!   5=PRIVATE
!   6=READ REV
!   7=UNDEF
!   8=SKIP BLOCKS
!   9=SKIP TMS
!  10=WRITE TM
!  11-16=UNDEF
!  17=REWIND
CONSTINTEGER  TOP REQ=17
CONSTBYTEINTEGERARRAY  CHAIN(0:TOP REQ)= C 
19,1,11,0,1,PRIVATE,2,0,14,16,12,0(6),18
! THESE ARE THE PRIMARY CHAINS TO EFFECT THE REQUEST.(SEE ARRAYS LBE(CW) ABOVE).
CONSTBYTEINTEGERARRAY  FINAL CHAIN(0:TOP REQ)= C 
0,9,11,0,9,0,10,0,0,0,12,0(6),0
! THESE ARE THE FINAL CHAINS FOR THOSE WHICH CAN BE RETRIED
!
CONSTINTEGER  READMASK=X'52';  ! READ,READ REV,READ CHECK
CONSTINTEGER  WRITEMASK=X'405';! WRITE,ERASE,WRITETM
CONSTINTEGER  XFERMASK=X'57';  ! ALL READS,WRITE,ERASE
CONSTINTEGER  SKIPMASK=X'300'; ! SKIP BLOCK,SKIP TM
CONSTINTEGER  SPADDRMASK=X'11'; ! ERASE, READ CHECK
!
INTEGER  TYPE,TYPE BIT,CTRL
!
IF  SSERIES=YES START 
  !..........SSERIES.........SSERIES..........SSERIES..........SSERIES
  !
  INTEGER  I
  INTEGERNAME  LINK
  RECORD (TCBF)NAME  TCB
FINISH ;!..............................................................
!
INTEGERFN  COPY CONTROL BLOCK(INTEGER  VADDR,LEN,STL,STB,TOADDR)
!
! VADDR IS THE VIRTUAL ADDR OF THE USER CONTROL BLOCK. THIS IS SUPPOSED
! TO BE IN A LOCKED AREA (DLOCK), AND STL,STB ARE SUPPOSED TO CONTAIN
! THE ST DELIVERED BY THAT DLOCK, IE A VM CONSISTING SOLELY OF LOCKED SPACE.
! WE WISH TO COPY THE CONTROL BLOCK INTO THE DEVICE RECORD.
! SINCE THE USERS LST IS NOT LOCKED WE NEED TO ACCESS THE CONTROL BLOCK VIA
! THIS STB.
! IF WE VALIDATE THE CONTROL BLOCK VIA THE STB AND IT SUCCEEDS, THEN THE
! FORMER MUST BE IN LOCKED SPACE, AND WE CAN PROCEED TO COPY IT WITHOUT FEAR
! OF A VS ERROR. HOWEVER IT IS POSSIBLE THAT THE STB ITSELF IS RUBBISH
! SO TO CHECK THE EXISTENCE OF THE ST ENTRY ADDRESS WHICH THE CONTROL BLOCK
! VALIDATE WILL GO FOR, WE FIRST VALIDATE IT AS A PUBLIC ADDRESS. IF
! THIS SUCCEEDS THEN THE STE ALL EXISTS AND IN THE SAME SMAC. WE CAN 
! THEREFORE GO AHEAD WITH THE CONTROL BLOCK VALIDATE WITHOUT FEAR OF A STORE
! TIMEOUT.
! THE CONTROL BLOCK VALIDATE MAY FAIL EITHER IF ITS SEGMENT IS OUTSIDE THE
! SUPPLIED STB LIMIT(EITHER ONE OR BOTH RUBBISH), OR IF THE CONTROL BLOCK IS
! NOT CONTAINED IN THE LOCKED SPACE DEFINED BY THE STB.
! NONE OF THIS GUARANTEES THAT WE ACTUALLY COPY THE USERS CONTROL BLOCK. ALL
! THE ABOVE CHECKS COULD SUCCEED ON GARBAGE ADDRESSES. HOWEVER, WE WILL NOT 
! FALL OVER SETTING IT UP, AND WHAT HAPPENS AFTER DEPENDS ON WHAT THE DEVICE
! CONTROLLER MAKES OF THE SUPPOSED CONTROL BLOCK.
RECORDFORMAT  COMF(INTEGER  OCPTYPE,IPLDEV,SBLKS,SEPGS,NDISCS,  C 
         DDTADDR,GPCTABSIZE,GPCA,SFCTABSIZE,SFCA,SFCK,DIRSITE,  C 
         DCODEDA,SUPLVN,KLOKCORRECT,DATE0,DATE1,DATE2,  C 
         TIME0,TIME1,TIME2,EPAGESIZE,USERS,PROCMON,DQADDR,  C 
         SACPORT,OCPPORT,ITINT,CONTYPEA,GPCCONFA,FPCCONFA,SFCCONFA, C 
         BLKADDR,DPTADDR,SMACS,TRANS,LONGINTEGER  KMON,  C 
         INTEGER  SPDRQ,SMACPOS,SUPVSN,PSTVA,SECSFRMN,SECSTOCD, C 
         SYNC1DEST,SYNC2DEST,ASYNCDEST,MAXPROCS,INSPERSEC,ELAPHEAD, C 
         COMMSRECA,INTEGERARRAY  SP(0:13), INTEGER   C 
         LSTL,LSTB,PSTL,PSTB,HKEYS,HOOT,SIM,CLKX,CLKY,CLKZ,  C 
         HBIT,SLAVEOFF,INHSSR,SDR1,SDR2,SDR3,  C 
         SDR4,SESR,HOFFBIT,S2,S3,S4,END)
CONSTRECORD (COMF)NAME  COM=X'80C00000'
INTEGER  VSEG,STEA,LSTL,LSTB,RES,I
LONGINTEGER  DR
IF  VADDR<0 THEN  MOVE(LEN,VADDR,TOADDR) ANDRESULT =0
! IE IT WAS IN PUBLIC SO NO HASSLE
!
VSEG=VADDR&X'7FFC0000'
IF  STB&X'F0000000'#0 THENRESULT =1
STEA=STB+(VSEG>>15);  ! REAL ADDR OF ST ENTRY
DR=X'1800000881000000'+STEA;  ! STE, LENGTH 8 VIA PST
*LD_DR; *VAL_(LNB +1); *JCC_14,<VALID>
RESULT =1;    ! VAL GAVE 3, IE INVALID
VALID:
! SO STEA EXISTS. NOW VALIDATE CONTROL BLOCK. FIRST SAVE LSTBR
I=COM_LSTL
*LB_I; *LSS_(0+B ); *ST_LSTL; *LSS_STL; *ST_(0+B )
I=COM_LSTB
*LB_I; *LSS_(0+B ); *ST_LSTB; *LSS_STB; *ST_(0+B )
! NOW DO VALIDATE
RES=1
DR=LEN
DR=X'1800000000000000'!(DR<<32)!VADDR;   ! LEN BYTES
*LD_DR; *VAL_(LNB +1); *JCC_3,<RESET LSTBR>
! SO OK.
RES=0
MOVE(LEN,VADDR,TOADDR)
RESET LSTBR:
I=COM_LSTL
*LB_I; *LSS_LSTL; *ST_(0+B )
I=COM_LSTB
*LB_I; *LSS_LSTB; *ST_(0+B )
RESULT =RES
END ;      ! FN COPY CONTROL BLOCK
!
! ********** ACCEPT REQUEST STARTS HERE **********
REQ=0
REP=0;  ! REPLY RECORD
REP_DEST=P_SRCE
REP_SRCE=P_DEST
REP_P1=P_P1;   ! IDENT
!
REQ_LSL=P_P5
REQ_LSTBA=P_P6
!
TYPE=P_P2&X'FF'
IF  TYPE>TOP REQ THENRESULT =NOTOK; ! NOT DEFINED
REQ_CHAIN=CHAIN(TYPE)
IF  REQ_CHAIN=0 THENRESULT =NOTOK;  ! DITTO
IF  TYPE=5 START ;  ! PRIVATE CHAIN
  IF  SSERIES=NO START 
    !........PSERIES..........PSERIES..........PSERIES..........PSERIES
    !
    ! P_P3=VADDR RCB, P5-P6=STL-STB. RCB IS 28 LONG
    IF  COPY CONTROL BLOCK(P_P3,28,P_P5,P_P6,ADDR(T_RCB))#0 THENRESULT =NOTOK
  FINISHELSESTART 
    !........SSERIES..........SSERIES..........SSERIES..........SSERIES
    !
    ! P_P3=VADDR OF FIRST OF UP TO 6 CHAINED TCBS. P5-P6=STL-STB.
    ! EACH TCB IS 56 LONG
    LINK==P_P3
    FOR  I=1,1,6 CYCLE 
      TCB==T_TCBS(I)
      IF  COPY CONTROL BLOCK(LINK,56,P_P5,P_P6,ADDR(TCB))#0 THENRESULT =NOTOK
      LINK=ADDR(TCB)!X'80000000';  ! INTO PREVIOUS
      LINK==TCB_NEXT TCB;     ! THE USERS LINK TO NEXT
      IF  LINK=0 THENEXIT ;   ! END
    REPEAT 
    UNLESS  LINK=0 THENRESULT =NOTOK;  ! NOT TERMINATED IN 6
  FINISH ;!............................................................
  REQ_PRIVATE ATTN=P_P4;   ! ATTN DEST
  RESULT =OK
FINISH 
REQ_FINAL CHAIN=FINAL CHAIN(TYPE)
REQ_RETRY LIMIT=WRITE RETRIES
! THIS IS OVERWRITTEN IF IT IS A READ, AND IRRELEVANT FOR OTHERS
TYPE BIT=1<<TYPE
REQ_LENGTH=P_P2>>16
IF  REQ_LENGTH&X'8000'#0 THEN  REQ_LENGTH=REQ_LENGTH!X'FFFF0000'
IF  REQ_LENGTH=0 THEN  REQ_LENGTH=P_P4
CTRL=(P_P2>>8)&X'FF'
IF  TYPE BIT&WRITEMASK#0 AND  T_PROP3&X'40'#0 THENRESULT =NOTOK; ! NO RING
IF  TYPE BIT&XFERMASK#0 START ;  ! READ,READREV,READCHECK,WRITE,ERASE
  IF  TYPE BIT&SPADDRMASK#0 THEN  REQ_ADDR=X'81000000' ELSEC 
                                                     REQ_ADDR=P_P3
  ! ERASE AND READ CHECK NEED A GENUINE FIXED ADDRESS, FOR CONTROLLER
  !  CHECKS EVEN WHEN NO DATA XFER.THIS IS START OF REAL CORE MAP IN PS 64.
  IF  TYPE BIT&READMASK#0 START ;  ! READ,READREV,READCHECK
    REQ_RETRY LIMIT=READ RETRIES
    IF  TYPE=4 START ;  ! READCHECK
      REQ_LENGTH=MAX XFER
      ! MAX. 256K-1 FOR PSERIES, 64K-1 FOR SSERIES.
      REQ_READORS=NODATA ! IGNSHORTLONG(1);   ! NO DATA, IGNORE SHORT
      REQ_TARGET POS=1
    FINISHELSESTART ;   ! READ OR READREV
      REQ_READORS=IGNSHORTLONG((CTRL>>2)&3); ! IGN NEITHER, SHORT, LONG OR BOTH
      IF  TYPE=1 THEN  REQ_TARGET POS=1 ELSE  REQ_TARGET POS=0
      !                READ                   READREV
    FINISH 
  FINISH ;   ! READMASK
  IF  CTRL&2#0 THEN  REQ_RETRY LIMIT=0
  ! NO ERROR RECOVERY. NOTE THAT WRITE TM RECOVERY IS NOT AFFECTED.
  UNLESS  0<REQ_LENGTH<=MAX XFER THENRESULT =NOTOK
FINISHELSESTART ;  ! NOT XFERMASK. IE SKIP BLOCK,SKIP TM,WRITETM,REWIND
  ! PSERIES:
  ! A DUMMY ASL REQUIRED FOR ALL THESE WITH LENGTH>0 AND GEN FIXED ADDR.
  ! HOWEVER, FOR WRITE TM RETRY (SKIPREV, ERASE), THE ERASED
  ! LENGTH SHOULD BE AT LEAST A TMS WORTH - IE 41 IN PE, 8 IN NRZI.
  ! SSERIES:
  ! DUMMY DESCRIPTOR NOT REQUIRED, SINCE ABSENCE OF FIXED BIT IN TCB_STE
  ! TELLS DCU THAT DESCRIPTOR IS NOT VALID. HOWEVER, AS FOR PSERIES,
  ! THE WRITE TM RETRY 'ERASE' REQUIRES A SUITABLE LENGTH, AND ITS
  ! SIMPLER JUST TO DO IT FOR THEM ALL. SKIPS AND REWIND WONT USE IT
  ! IN 'FIRE CHAIN'.
  ! FIRST SAVE USER SUPPLIED LENGTH AS THIS IS BLOCKS OR LOGICAL FILES
  ! FOR SKIP AND SKIP TM RESPECTIVELY.
  REQ_SKIPTOT=REQ_LENGTH
  REQ_LENGTH=50
  REQ_ADDR=X'81000000'
  IF  TYPE BIT&SKIPMASK#0 START ;  ! SKIP BLOCKS, SKIP TMS
    IF  REQ_SKIPTOT=0 THENRESULT =NOTOK
    IF  REQ_SKIPTOT<0 THEN  REQ_CHAIN=REQ_CHAIN+1 ANDC 
                                         REQ_SKIPTOT=-REQ_SKIPTOT
    IF  TYPE=8 START ;  ! SKIP BLOCK
      REQ_TM=CTRL&1;   ! TREAT TM AS BLOCK
    FINISHELSESTART ;   ! SKIP TMS
      ! CTRL IS NUMBER OF TMS/LOGICAL FILE
      ! ZERO IMPLIES 1/LOGICAL FILE WITH NO TM LOOKAHEAD
      REQ_TM=CTRL
    FINISH 
  FINISH 
FINISH 
RESULT =OK
END ;      ! FN ACCEPT REQ
!
!
ROUTINE  FIRE CHAIN
!**********************************************************************
! ENTERED WITH REQUEST SET UP IN T_REQ. SPECIFICALLY REQ_CHAIN IS TO
! BE FIRED.
! %IF PSERIES, SETS UP LBES, ALE AND RCB AND TELLS GPC.
! %ELSE, SETS UP TCBS AND TELLS DCU.
!**********************************************************************
CONSTINTEGER  READMASK=X'E66EF'; ! 2**N SET IF LBE(CW) IS READ
OWNINTEGER  DEST=CONTROLLER+EXEC,SRCE=ME+5,P1,P2,P3=X'11',
  P4,P5,P6
INTEGERNAME  INITWORD
INTEGER  MODE
MODE=T_MODE
IF  MODE=0 THEN  MODE=PE
! EG A BLANK TAPE BEING REWOUND OR UNLOADED WITHOUT HAVING BEEN CLAIMED.
!
IF  SSERIES=NO START 
  !..........PSERIES..........PSERIES..........PSERIES..........PSERIES
  !
  INTEGER  LBEN,CH START,I
  INTEGERNAME  LBEWORD
  RECORD (RCBF)NAME  RCB
  RCB==T_RCB
  INITWORD==RCB_INITWORD
  IF  REQ_CHAIN=PRIVATE THEN  ->FIRE;  ! PRIVATE RCB ALL SET UP
  RCB=0;    ! ******* CAUTION. PARTLY SET UP ONCE AT ALLOCATE ?
  CH START=CHAIN START(REQ_CHAIN)
  LBEN=CHAIN LENGTH(REQ_CHAIN)
  RCB_LB BYTES=LBEN<<2;  ! CAN WE SET THIS TO 4 LBES AT ALLOC REGARDLESS ???
  MOVE(RCB_LB BYTES,ADDR(LBES(CH START)),ADDR(T_LBE1))
  RCB_LBA=ADDR(T_LBE1); !**** DO THIS ONCE AT ALLOCATE
  IF  REQ_CHAIN<=LAST READ CHAIN START 
    FOR  I=0,1,LBEN-1 CYCLE 
      IF  (1<<(CH START+I)&READMASK)#0 START ; ! LBE IS READ
        ! OR IN BITS FOR 'NO DATA','IGNORE SHORT/LONG'
        ! THE FIRST READ IN MULTIPLE CHAINS ALREADY HAS LONG/SHORT
        ! MASKED OFF. HOWEVER SINCE WERE DOING THE 'NO DATA' HERE AS
        ! WELL, WE MUST DO THEM ALL.
        LBEWORD==INTEGER(ADDR(T_LBE1)+I<<2)
        LBEWORD=LBEWORD ! REQ_READORS
      FINISH 
    REPEAT 
  FINISH 
  IF  REQ_CHAIN<=LAST RETRY CHAIN THEN  T_OPS=T_OPS+1
  ! COUNT OF NON-POSITIONING OPERATIONS FOR JOURNAL
  !
  T_ALE1=REQ_LENGTH
  T_ALE2=REQ_ADDR
  RCB_AL BYTES=8
  RCB_ALA=ADDR(T_ALE1);  !*** DO THIS ONCE AT ALLOCATE
  IF  T_ALE2>0 START ;  ! LOCAL ADDR FOR DATA. PUT IN LSTB
    RCB_LIMFLAGS=REQ_LSL
    RCB_LSTBA=REQ_LSTBA
  FINISH ;  ! ELSE ALL IN PUBLIC. DO WE NEED ANYTHING HERE?
  RCB_LIMFLAGS=RCB_LIMFLAGS ! X'8000';  ! INITIALISE BIT IN FLAGS
  ! TELLS GPC TO USE THE FOLLOWING TO INIT THE DEVICE
  INITWORD=(STATMASK(REQ_CHAIN)<<8) ! MODE
  !         TERTIARY STAT MASK        MODE
  !
  FIRE:
  INITWORD=INITWORD ! ((T_PROP2&7)<<24);   ! MECHANISM
  P1=ADDR(RCB)
FINISHELSESTART 
  !..........SSERIES..........SSERIES..........SSERIES..........SSERIES
  !
  CONSTLONGINTEGER  NOADDRMASK=X'7DF608800'
  CONSTINTEGER  PAGE BIT=X'40000000'
  OWNBYTEINTEGER  ASBYTE=X'10';   ! ADD STATUS LITERAL BYTE
  RECORD (TCBF)NAME  TCB
  INTEGER  CWS,CWN,CWB,CH START,I,STAD,STEAD,LEN,ADR
  INITWORD==T_TCBS(1)_PREAMBLE(1)
  IF  REQ_CHAIN=PRIVATE THEN  ->FIRE;  ! TCBS ALL SET UP
  IF  REQ_CHAIN<=LAST RETRY CHAIN THEN  T_OPS=T_OPS+1
  CH START=CHAIN START(REQ_CHAIN)
  CWS=CHAIN LENGTH(REQ_CHAIN)
  FOR  I=1,1,CWS CYCLE 
    TCB==T_TCBS(I)
    TCB=0
    CWN=CH START+I-1
    TCB_CW=CW(CWN);    ! COMMAND WORD
    IF  (LONG1<<CWN)&NOADDRMASK=0 START 
      ! THIS COMMAND NEEDS A DATA DESCRIPTOR.
      ! IT MAY ALSO NEED READORS AND BACKWARDS BIT IF READ REVERSE.
      LEN=REQ_LENGTH
      ADR=REQ_ADDR
      IF  REQ_CHAIN<=LAST READ CHAIN START 
        ! TRY READORS AND BACKWARD
        CWB=1<<CWN
        IF  CWB&READMASK#0 START ;  ! A READ COMMAND
          TCB_CW=TCB_CW ! REQ_READORS;  ! NODATA AND LONG/SHORT
          IF  CWB&REVMASK#0 START ;     ! REVERSE
            TCB_LENGTH=X'04000000';     ! BACKWARDS BIT
            ADR=ADR+LEN-1
          FINISH 
        FINISHELSESTART 
          ! ITS IN A READ CHAIN, IE CW 0-19, AND ITS NOT A SKIP
          ! SINCE NOADDRMASK=0. SO IT MUST BE 'ADD STATUS'.
          ADR=ADDR(ASBYTE)
          LEN=1
        FINISH 
      FINISH ;    ! READ CHAIN
      ! IF ADDR IS LOCAL, WE HAVE THE REAL ADDRESS OF LST IN REQ_LSTBA
      IF  ADR>0 THEN  STAD=X'81000000'+REQ_LSTBA ELSE  STAD=PST VA
      ! PSTVA IS PUBLIC SEG VA. DEFINED IN CTOPT FILE
      STEAD=STAD+((ADR>>15)&X'FFF8'); ! ACTUALLY (>>18&X'1FFF')<<3
                                      ! TO YIELD BYTE DISPLACEMNT OF ENTRY
      TCB_STE=(INTEGER(STEAD+4)&X'0FFFFFF8')!1;  ! REAL ADDR+FIXED BIT
      IF  INTEGER(STEAD)&PAGE BIT#0 THEN  TCB_STE=TCB_STE!2
      TCB_LENGTH=TCB_LENGTH!LEN;  ! REMENBER BACKWARDS BIT MAY BE THERE
      TCB_ADDR=ADR&X'3FFFF'
    FINISH ;   ! THOSE REQUIRING DATA AREA
    UNLESS  I=CWS THEN  TCB_NEXT TCB=ADDR(T_TCBS(I+1))!X'80000000'
    ! CHAIN ON THE NEXT ONE
  REPEAT 
  INITWORD=(STATMASK(REQ_CHAIN)<<8)!MODE
  !          SECONDARY STATUS       MODE
  !
  !
  FIRE:
  INITWORD=INITWORD!((T_PROP2&7)<<24)
  P1=ADDR(T_TCBS(1))
FINISH ;!..............................................................
P2=T_SNO&X'FF'
REQ_STATE=TERM EXP
MYPON(RECORD(ADDR(DEST)))
IF  RLEVEL&4#0 THEN  DUMPTABLE(61,ADDR(T),TFSIZE)
END ;        ! ROUTINE FIRE CHAIN
!
!
!******************* TAPE STARTS HERE **********************************
!
IF  KMON&(LONG1<<49)#0 THEN  TMON=1 ELSE  TMON=0
IF  TMON#0 OR  RLEVEL&1#0 THEN  MON(1,P)
!
ACT=P_DEST&X'FFFF'
IF  ACT>64 THEN  SNO=ACT AND  ACT=1
UNLESS  (INITIALISED>0 OR  ACT=4) AND  1<=ACT<=13 THEN  ->FAULTY P
!
->ACTSW(ACT)
!
REPLY:
P_DEST=P_SRCE
P_SRCE=ME!ACT
MYPON(P)
RETURN 
!
!
ACTSW(7):;    ! USER RELEASE
SNO=P_P2&X'FFFF'
ACTSW(1):;    ! USER REQUEST, SNO SET FROM P_DEST ABOVE.
IF  SEARCH TPS(3,SNO,"")=OK START ;  ! FOUND SNO AND MAPPED T
  REQ==T_REQ
  REP==T_REP
  IF  T_STATE=CLAIMED START ;  ! THE DECK REMAINS ACCESSIBLE
    IF  REQ_STATE=0 START ;   ! IDLE
      IF  ACT=1 START ;    ! USER REQUEST
        IF  ACCEPT REQUEST=OK START ;   ! CHECKS OK
          FIRE CHAIN;   ! REPLY WHEN TERM COMES
          RETURN 
        FINISHELSE  P_P4=BAD PARAMS
      FINISHELSESTART ;    ! USER RELEASE, ACT 7
        T_LOAD STATE=6+P_P5<<1;   ! IE 6 FOR UNLOAD, 8 FOR RLSE/RWND
        LOAD
        P_P4=OK
      FINISH 
    FINISHELSE  P_P4=BUSY
  FINISHELSE  P_P4=NOT CLAIMED
FINISHELSE  P_P4=SNO NOT FOUND
IF  P_P4=OK THEN  P_P2=OK ELSE  P_P2=REJECT
!   ONLY SUCCESSFUL RLSE        ALL OTHERS
->REPLY
!
!
ACTSW(2):;     ! TERMINATION/ATTENTION FROM CONTROLLER
! P_P1=STREAMR0, _P2=STREAMR1
! P_P3=DEVICE ENTRY ADDRESS
! P_P4=RESPONSE ANAL FLAGS FROM CONTROLLER SENSE IF ORIGINAL REQUEST FAILED
D==RECORD(P_P3)
T==RECORD(D_UA AD)
REQ==T_REQ
REP==T_REP
T_STREAMR0=P_P1
T_STREAMR1=P_P2
I=(P_P1>>20)&15
IF  I=1 THEN  ATTENTION ELSE  TERMINATE(I&7,0)
!                             IE 0 FOR NORMAL, >0 FOR ABTERM
RETURN 
!
!
ACTSW(3):;     ! CONTROLLER ALLOCATE/DEALLOCATE REPLIES
! P_P1=0 SUCCESS
! P_P2=SNO (ALLOC ONLY)
! P_P3=DEVICE ENTRY ADDRESS
! P_P6=MNEMONIC(ALLOC ONLY)
D==RECORD(P_P3)
IF  P_SRCE&X'FF'=ALLOC START 
  IF  P_P1#OK THENRETURN ;  ! ALLOC FAILED. SEE COMMENT AT ACTSW(4)
  ! SO ALLOCATED OK. SET UP DEVICE RECORD
  I=P_P6!X'3000000';   ! STRING MNEM
  M=STRING(ADDR(I))
  IF  SEARCH TPS(1,0,M)=OK START 
    ! IT SHOULDNT ALREADY BE THERE
    OPMESS(M." allocate twice?")
    RETURN 
  FINISH 
  LASTLINK=D_UA AD
  T==RECORD(D_UA AD)
  T=0
  T_GTS=(¬(D_PROPS0>>10))&1;   ! 1=GTS, 0=MTS
  REQ==T_REQ
  REP==T_REP
  LASTLINK==T_LINK;  ! THIS IS NOW LAST
  T_MNEM=M
  T_PROP2=P_P6&X'FF'-X'30';  ! MECHANISM FROM MNEM TO DO SEND PROPS
  T_SNO=P_P2
  ! T_STATE=0, NOT AVAILABLE
  ! T_LOAD STATE=0, READY FOR LOAD
  LOAD;  ! GET PROPS AND SEE IF ANYTHING LOADED
FINISHELSESTART ;  ! DEALLOCATE
  IF  P_P1#OK START 
    OPMESS(" Deallocate fails ".HTOS(P_P1,8))
    RETURN 
  FINISH 
  T==RECORD(D_UA AD)
  ! DEALLOCS COME VIA VOLUMS WHICH DOESNT ALLOW THEM IF IN USE, SO THERE
  ! SHOULDNT BE ANY REQUEST OUTSTANDING. WE MIGHT BE IN A LOAD OR UNLOAD
  ! SEQUENCE BUT THATS IRRELEVANT. NOTHING TO DO BUT UNLINK IT.
  M=T_MNEM
  I=SEARCH TPS(1,0,M);  ! REALLY JUST TO SET UP 'PREVLINK'
  IF  I#OK START ;   ! DEAR DEAR. WHATS HAPPENED?
    OPMESS(M." dealloc srch fails?")
    RETURN 
  FINISH 
  PREVLINK=T_LINK;  ! UNLINK IT
  ! AND RESET LAST IF THIS WAS IT
  IF  T_LINK=0 THEN  LASTLINK==PREVLINK
FINISH 
RETURN 
!
!
ACTSW(4):;     ! ONCE/STREAM FROM CONTROLLER AT STARTUP
! P_P1=BASE MNEMONIC. CONTROLLER CREATES STREAMS FOR THE MAX DECKS FOR THE
! STREAM TYPE IE EITHER 8 OR 4. WE DONT KNOW WHICH TYPE, SO WE DO
! ALLOCATE REQUESTS FOR MAX OF THESE. THE EXCESS WILL FAIL FROM CONTROLLER.
! IN FACT, THE DECKS FOR THOSE SUCCESSFULLY ALLOCATED MAY NOT EXIST,
! BUT WE DONT FIND THAT OUT UNTIL WE GET NOT AVAILABLE AT START OF LOAD.
!
! THIS ENTRY ALSO USED BY VOLUMS TO MODE ON/OFF DECK OR CLUSTER.
!P_P1=BASE MNEMONIC, P2=ON/OFF(1/0), P3=NUMBER OF DECKS
!
IF  P_SRCE&X'FF0000'=CONTROLLER START 
  ! INITIALISING CALL
  IF  INITIALISED=0 START 
    LASTLINK==FIRSTTP
    INITIALISED=1
  FINISH 
  NDECKS=8
  MODE=ON
FINISHELSESTART 
  ! VOLUMS
  NDECKS=P_P3
  MODE=P_P2
FINISH 
IF  MODE=ON THEN  PP_DEST=CONTROLLER!ALLOC C 
            ELSE  PP_DEST=CONTROLLER!DEALLOC
PP_SRCE=ME!3;   ! WHERE CONTROLLER REPLIES COME
PP_P2=ME!2;  ! WHERE EVENTS ARE NOTIFIED
PP_P1=P_P1;     ! BASE MNEM
P_P1=0;         ! FOR REPLY TO VOLUMS, SEE BELOW
WHILE  NDECKS>0 CYCLE 
  I=PP_P1!X'3000000'
  I=SEARCH TPS(1,0,STRING(ADDR(I)));  ! IS IT THERE
  IF  (MODE=ON AND  I=OK) OR  (MODE=OFF AND  I=NOTOK) THENC 
      P_P1=P_P1+1 ELSE  MYPON(PP)
  ! IE IF ON AND ALREADY THERE, OR OFF AND NOT THERE, THEN INCREMENT
  ! COUNT OF 'NOT DONE' FOR VOLUMS. OTHERWISE DO IT
  PP_P1=PP_P1+1;  ! NEXT MNEM UP
  NDECKS=NDECKS-1
REPEAT 
IF  P_SRCE&X'FF0000'=CONTROLLER THENRETURN 
! SO IT WAS VOLUMS. REPLY. P1 ALREADY SET
->REPLY
!
!
ACTSW(5):;    ! EXECUTE REQUEST FAILS
! FAILURES ARE P1=1 - SNO OUT OF RANGE, IE UNKNOWN TO CONTROLLER
!                =2 - DEVICE NOT READY
!              P2=SNO
!              P3=DEVICE ENTRY ADDRESS UNLESS P1=1
! THE SNO IN P2 IS ONLY THE BOTTOM BYTE OF OUR FULL ONE(SEE FIRE CHAIN)
! SO WE CANNOT USE IT TO SEARCH FOR TP. FURTHER IF P1=1, CONTROLLER CLEARLY
! DOES NOT GIVE A DEVICE ADDR IN P3, SO WE HAVE NO WAY OF TELLING WHICH
! OF OUR ENTRIES WAS USED TO INITIATE THIS REQUEST
OPMESS("Controller rejects request")
PRINTSTRING("EXECUTE REQUEST FAILS - P1=".HTOS(P_P1,1). C 
                                                   " P2=".HTOS(P_P2,2))
IF  P_P1#1 START ;  ! WE CAN LOCATE IT
  DUMPTABLE(61,P_P3,TFSIZE)
  D==RECORD(P_P3)
  T==RECORD(D_UA AD)
  REQ==T_REQ
  REP==T_REP
  IF  REQ_STATE#0 START ;  ! TELL THE USER OR 'LOAD'
    REQ_STATE=0
    REP_P2=REJECT
    REP_P4=NOT CLAIMED
    IF  REP_DEST#0 THEN  MYPON(RECORD(ADDR(REP))) ELSE  LOAD
  FINISH 
FINISH 
RETURN 
!
!
ACTSW(6):;     ! VOLUMS REPORTING IN
VOLUMS=P_SRCE
I=SEARCH TPS(4,0,"");   ! REPORT ALL LOADED TO VOLUMS
RETURN 
!
!
! ACTSW(7) DEFINED AT ACTSW(1) ABOVE
!
!
ACTSW(8):;     ! SET REPORTING LEVEL
IF  P_P1<=7 START 
  RLEVEL=P_P1
FINISHELSEIF  0<=P_P2<=255 START 
  IF  P_P1=16 START 
    READ RETRIES=P_P2
  FINISHELSEIF  P_P1=17 START 
    WRITE RETRIES=P_P2
  FINISH 
FINISH 
RETURN 
!
!
ACTSW(9):;     ! SEND FAILURE DETAILS
IF  SEARCH TPS(3,P_P1&X'FFFF',"")=OK START 
  P_P1=0
  P_P2=T_STREAMR0
  P_P3=T_STREAMR1
  MOVE(12,ADDR(T_T0),ADDR(P_P4))
FINISHELSESTART 
  P_P1=REJECT
  P_P4=SNO NOT FOUND
FINISH 
->REPLY
!
!
ACTSW(10):;     ! DUMP TABLE, SNO IN P1
IF  SEARCH TPS(3,P_P1&X'FFFF',"")=OK START 
  DUMPTABLE(61,ADDR(T),TFSIZE)
FINISH 
RETURN 
! NO REPLY
!
!
ACTSW(11):;     ! DUMMY
RETURN 
!
!
ACTSW(12):;     ! CLAIM VOLUME
CLAIM VOLUME(P)
! REPLY SET UP
->REPLY
!
!
ACTSW(13):;     ! DISPLAY TPS STATUS
I=SEARCH TPS(5,0,"")
RETURN 
!
!
FAULTY P:
MON(3,P)
END ;      ! ROUTINE TAPE
!
!
ENDOFFILE