!TITLE Magnetic Tape Facilities
!<DMAGCLAIM
externalintegerfn  DMAG CLAIM(string (6)TSN, integername  SNO,
      integer  REQ, MODE)
!
! The magnetic tape volume labelled TSN is either claimed (REQ=0) or
! released (REQ=1).  MODE should be set to 1 to allow read access to the
! tape, 2 if write access is required, or 3 for either read or write
! access.   If a CLAIM call is successful, SNO is set with a number to be
! used in subsequent calls of DMAG IO.
!
! If TSN is null in a RELEASE call, then all claimed tapes are released.
!
! Possible error results from Volumes:
!           101  Bad parameters
!           102  Duplicate request
!           103  Request lists full
!           104  Volume not available (Operators have said "NO <val id>")
!           105  Volume request list full
!           106  No tapes in tape list (A, B, S or E)
!           107  Device not claimed when a "release" is done.
!>
INTEGER  J, K, L
      K = IN2(256 + 37)
      -> OUT UNLESS  K = 0
!
      K = 45
      -> OUT IF  VAL(ADDR(SNO), 4, 1, DCALLERS PSR) = 0
!
      K = 8
      -> OUT UNLESS  0<=REQ<=1
      L = LENGTH(TSN)
      -> OUT UNLESS  (L=0 OR  L=6)
      UCTRANSLATE(ADDR(TSN)+1, 6) IF  L = 6
!
      IF  REQ=0 START 
          ! CLAIM
         -> OUT UNLESS  L = 6
!
         K = 90; ! MAX TAPES ALREADY CLAIMED
         -> OUT IF  TAPES CLAIMED > TOP ENT
         -> OUT IF  UINF_REASON = BATCH AND  TAPES CLAIMED >= UINF_DECKS
!
         K = 92; ! INTERACTIVE USE OF TAPES NOT ALLOWED
         -> OUT IF  UINF_REASON = INTER AND  DTRYING << 16 >= 0
!
         K=VOL REQ(TSN,SNO,REQ,MODE)
         IF  K=0 START 
            CYCLE  J=0,1,TOP ENT
               IF  CLAIMED(J)_TSN="" START 
                  CLAIMED(J)_TSN=TSN
                  CLAIMED(J)_SNO=SNO
                  TAPES CLAIMED=TAPES CLAIMED + 1
                  -> OUT
               FINISH 
            REPEAT 
            K=73; ! SHOULD NOT ARRIVE HERE !
         FINISH 
      FINISH  ELSE  START 
          ! RELEASE
         K=0
         CYCLE  J=0,1,TOP ENT
            IF  TSN = "" # CLAIMED(J)_TSN C 
                  OR  (""#CLAIMED(J)_TSN=TSN) C 
            START 
               K=VOL REQ(CLAIMED(J)_TSN,CLAIMED(J)_SNO,1,0)
               IF  K=0 START 
                  CLAIMED(J)=0
                  TAPES CLAIMED=TAPES CLAIMED - 1
               FINISH 
            FINISH 
         REPEAT 
      FINISH 
!
OUT:
      RESULT  = OUT(K, "SJII")
END ; ! DMAG CLAIM
!
!-----------------------------------------------------------------------
!
!<DMAGIO
externalintegerfn  DMAG IO(integername  REPLY FLAG, CONTROL, LEN,
      integer  TYPE, SNO, ADR)
!
! The parameter TYPE determines the action of the procedure:
!   TYPE = 0 erase
!          1 read
!          2 write
!          3 check-write (not implemented)
!          4 check-read (no data transfer)
!          5 private chain (not implemented)
!          6 rewind to BT
!          7 spare
!          8 file position
!          9 tape position
!         10 write tape-mark
!
! SNO should be set with the value returned by a previous CLAIM
! (procedure DMAG CLAIM).  ADR and LEN specify the area from or to which
! data is to be transferred (if relevant).  In the case of TYPE = 1
! (read) LEN is set on return to be the number of bytes transferred.
!
! Bits in parameter CONTROL are used to specify detailed actions by the
! tape handler routine, as follows:
!
!        2**0  -
!        2**1  suppress error re-try
!        2**2  ignore short-block indication
!        2**3  ignore long-block indication
!
! Bits in CONTROL on return are used to indicate the occurrence of
! conditions during execution of a request, as follows:
!
!        2**0  short-block indication
!        2**1  long-block indication
!
! These bits will not be set on return if the respective bits for
! "ignore short/long-block indication" were specified in the request.
! REPLY FLAG (valid when the result of the function is zero) is set
! to zero for a successful operation, or
!
!        1   failure (parity etc.)
!        2   request rejected
!        4   beginning of tape, end of tape or unexpected tape
!            mark found, but operation otherwise successful
!
!
! TYPE=8
!
! For request TYPE=8 (file position), LEN specifies the number of blocks
! to be skipped: negative means backwards, positive forwards, zero is
! invalid. If a tape-mark is found (REPLY FLAG=4) then a skip back of one
! block is performed before the reply is given.  It is thus impossible
! to pass a tape-mark except by the use of a "tape position" request.
!
! TYPE=9
! For request TYPE=9 (tape position), LEN is the number of (notional)
! files to be skipped, and CONTROL is the number of tape-marks in a
! notional file, CONTROL must be positive.  If LEN is negative the skip
! is backwards, if positive then it is forwards, zero is invalid.
! CONTROL*LEN tape-marks are skipped.  A backwards skip will stop at BT.
! A forward skip will stop if the first block within a (notional) file is
! a tape-mark, the tape will then be positioned before the tape-mark and
! REPLY FLAG=4 will be returned.  Thus if CONTROL=1 and LEN="very large",
! the tape will be positioned between the first double tape-mark
! encountered.
!>
!                       09876543210
CONSTINTEGER  VALMASK=B'11111010111'
! DATA TRAN MASK has bits set for operations for which:
!        data transfer is to be done
!        hence validate to be done on the area
!        the area is to be locked down, and
!        OUT 18 is to be done.
!                              09876543210
CONSTINTEGER  DATA TRAN MASK=B'00000001110'
CONSTINTEGER  OUT11MASK     =B'10000010001'
! Other operations get OUT 7 (an ordinary OUT) unless OUT11MASK has a bit set,
! when they get an OUT 11.
INTEGER  ENTRY,LLEN, LCONTROL
INTEGER  READWRITE,OUT18,K,DUM,EPAGE BYTES,TIMES,SAVID
INTEGER  FLAG
RECORD  (PARMF)Q
RECORD (PARMF)NAME  P
!
      LLEN = 0
      LCONTROL = 0
!
      FLAG = IN2(256 + 38)
      -> OUT UNLESS  FLAG = 0
!
      FLAG = 45
      -> OUT IF  VAL(ADDR(REPLY FLAG),4,1,DCALLERS PSR)=0
      -> OUT IF  VAL(ADDR(CONTROL),4,1,DCALLERS PSR)=0
      -> OUT IF  VAL(ADDR(LEN),4,1,DCALLERS PSR)=0
!
      FLAG=8
      UNLESS  (1<<TYPE)&VALMASK#0 THEN  -> OUT
!
      CYCLE  ENTRY=0,1,TOPENT
         IF  CLAIMED(ENTRY)_SNO=SNO AND  CLAIMED(ENTRY)_TSN#""  C 
         THEN  -> GOTT
      REPEAT 
      FLAG=67; ! TAPE NOT CLAIMED
      -> OUT
GOTT:
      LLEN = LEN
      LCONTROL = CONTROL
      Q = 0
!
      IF  TYPE = 7 START 
                                        ! PASS REQUEST ON TO TAPE FOR SENSE ETC
                                        ! INPUT: SNO AND ADR
                                        ! OUTPUT: 5 WORDS IN ADR, ADR+4, ETC
         P == RECORD(OUTPAD)
         P = 0
         P_P1 = SNO
         P_DEST = X'310009'
         *OUT_11
         FLAG = 45
         -> OUT IF  VAL(ADR, 20, 1, DCALLERS PSR) = 0
         MOVE(20, ADDR(P_P2), ADR)
         FLAG = 0
         -> OUT
      FINISH 
!
      IF  TYPE=6 THEN  TYPE=17
      OUT18=0; ! SAYS WHETHER OR NOT TO USE THE SPECIAL OUT 18
      IF  (1<<TYPE)&DATA TRAN MASK#0 START 
         ! DATA AREA MUST BE READ-MODE FOR WRITING TO TAPE, AND WRITE MODE FOR
         ! READING FROM TAPE
         READWRITE=0; ! FOR READ-ACCESS CHECK
         IF  TYPE=1 THEN  READWRITE=1; ! FOR WRITE ACCESS CHECK
         FLAG=45; ! AREA NOT AVAILABLE
         -> OUT IF  VAL(ADR,LLEN,READWRITE,DCALLERS PSR)=0
         ! ALSO THE DATA AREA MUST NOT CROSS A SEG BOUNDARY, AS THE GPC
         ! CANNOT COPE WITH THIS.
         FLAG=56; ! CROSSES SEG BOUNDARY
         IF  ADR>>18 # (ADR+LLEN-1)>>18 THEN  -> OUT; ! crosses seg bdy
         OUT18=1
      FINISH 
! FOR A DATA TRANSFER WE REFERENCE ALL THE PAGES IN THE DATA AREA, TO GET THEM INTO
! MAIN STORE. IF THEY ARE NOT STILL THERE AT THE TIMEOF THE OUT 18, THEN
! P_DEST WILL BE SET TO -1, AND WE TRY AGAIN, UP TO FOUR TIMES (SAY).
      TIMES=0
      P==RECORD(OUTPAD)
      UNTIL  OUT18=0 C 
            OR  (OUT18#0 AND  (TIMES>4 OR  P_DEST#-1)) C 
       CYCLE 
         ! PASS REQUEST TO THE TAPE ROUTINE
         Q_DEST=CLAIMED(ENTRY)_SNO
         !Q_P1=ID - NOT REQUIRED
         Q_P2=LCONTROL<<8 ! TYPE
         Q_P3=ADR
         Q_P4=LLEN
         Q_P5=LLEN ! (DCALLERS ACR<<24)
         ! SET TOP BIT FOR A READ SO THAT SUPVR CAN MAKE SURE THAT
         ! THE WRITTEN BITS ARE SET - THE GPC DOESN'T DO IT!
         IF  TYPE=1 THEN  Q_P5=Q_P5 ! (1<<31)
         Q_P6=ADR
         IF  OUT18=0 START 
            SRCE ID=(SRCE ID + 1)&X'FFFF'
            SAVID=SRCE ID
            Q_SRCE=SAVID
            LOUTP=Q
            P=Q
MOUT AGAIN:
            IF  (1<<TYPE)&OUT11MASK#0 START 
               LOUTP STATE="DMAG IO DOUT 11"
               *OUT_11
            FINISH  ELSE  START 
               LOUTP STATE="DMAG IO OUT 7"
               *OUT_7; ! PON AND SUSPEND
            FINISH 
            IF  P_DEST#-1 AND  P_DEST&X'FFFF'#SAVID START 
               Q=P
               PRINTSTRING("NREQ: ")
               DDUMP(ADDR(Q),ADDR(Q)+32,-1,-1)
               P_DEST=0; ! POFF
               -> MOUT AGAIN
            FINISH 
         FINISH  ELSE  START 
            ! NOW REFERENCE ALL THE PAGES
            EPAGE BYTES=EPAGE SIZE<<10
            K=ADR & (¬(EPAGE BYTES - 1))
            WHILE  K<ADR+LLEN CYCLE 
               DUM=BYTEINTEGER(K)
               K=K+EPAGE BYTES
            REPEAT 
            P=Q
            *OUT_18; ! SPECIAL PON AND SUSPEND
         FINISH 
         TIMES=TIMES+1
      REPEAT 
      IF  P_DEST = -1 START 
         PREC("DMAGIO, FLAG=68", P, 0)
         WRSN("TIMES ", TIMES)
         WRSN("OUT18 ", OUT18)
         FLAG = 68; ! Lock down fails
         -> OUT
      FINISH 
!
      FLAG=P_P2
! LEN is also used to return no. of tape marks passed, in the case of
! 'tape position', 'file position', etc.
!
!
      K = P_P3; ! length of data read, or almost anything else!
      IF  TYPE = 1 START ; ! READ
         IF  K < 0 START ; ! backward read
            K = -K
            MOVE(K, ADR+LLEN-K, ADR) IF  K < LLEN; ! need to move data down
         FINISH 
         LLEN = K
      FINISH 
      LLEN = K
!
      LCONTROL=P_P4
OUT:
      LOUTP STATE="DMAG IO exit"
!
      IF  45 # FLAG # 47 START 
         ! USER FIELDS ARE ACCESSIBLE
         REPLY FLAG = FLAG
         CONTROL = LCONTROL
         LEN = LLEN
      FINISH 
!
      RESULT  = OUT(FLAG, "")
END ; ! DMAG IO
!
!-------------------end-of-included-file---------------------------------
!