Trailing-Edge
-
PDP-10 Archives
-
bb-bt99q-bb
-
tapser.x23
There is 1 other file named tapser.x23 in the archive. Click here to see a list.
TITLE TAPSER - COMMON MAGTAPE PHYSICAL IO DRIVER V1111
SUBTTL L.BOSACK/TAH/TW/DPM 28-MARCH-89
SEARCH F,S,DEVPRM
$RELOC
$HIGH
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
; OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION
; 1974,1975,1976,1977,1978,1979,1980,1982,1984,1986,1988.
;ALL RIGHTS RESERVED.
.CPYRT<1974,1988>
XP VTAPSR,1111 ;FOR LINKEDIT MAP
SALL
TAPSER::ENTRY TAPSER
;BIT DEFINITIONS
;IN TKBSTS & TUBSTS
TKSOFL==:(1B17) ;OFFLINE
TKSSEL==:(1B16) ;SELECTED
TKSSTD==:(1B15) ;STARTED
TKSSCH==:(1B14) ;REQUESTED SCHED INTERUPT
TKSSIL==:(1B13) ;REQUEST SILENCE ABT OFF-LINE CONDITION
TKSMNT==:(1B12) ;CTL IS IN MAINT MODE
TKSCHE==(1B11) ;JOB HAS SWEPT CACHE FOR QUEUED REQUEST
TKSCHX==:(1B10) ;NOT YET SWEPT FOR (CPU0)
TKSCHA==(77B10) ;TKSCHX BITS FOR ALL CPUS
;IN TUBSTS
TUSNS==:(1B0) ;DO NOT SCHEDULE THIS UNIT (SIGN BIT)
TUSBOT==:(1B1) ;BEGINNING OF TAPE
TUSWTL==:(1B2) ;WRITE LOCKED
TUSREW==:(1B3) ;TAPE REWINDING
TUSFLT==:(1B4) ;TAPE UNIT FAULT (BROKEN DRIVE)
TUSBOF==:TUSBOT!TKSOFL
;IN TKBSTS
TKSNS==:(1B3) ;DON'T SCHEDULE THIS KONTROLLER (DIAG.)
;IN TUBCNF
TUC7TK==:1B18 ;SEVEN TRACK
TUCIRD==:1B19 ;INTERUPTS WHEN REWIND DONE
TUCDMS==:1B20 ;DIAG MODE SET
TUCSNS==:1B21 ;FORCE SENSE
;TUCD??==:1B22 ;THIS BIT LEFT FOR EXPANSION
TUCD62==:1B23 ;DRIVE CAN DO 6250 BPI
TUCD16==:1B24 ;DRIVE CAN DO 1600 BPI
TUCD80==:1B25 ;DRIVE CAN DO 800 BPI
TUCD55==:1B26 ;DRIVE CAN DO 556 BPI
TUCD20==:1B27 ;DRIVE CAN DO 200 BPI
; THE FOLLOWING SYMBOLS ARE FOR THE CONVENIENCE OF MACRO V50
TUCDR8==:TUCD20+TUCD55+TUCD80 ;TM10 9 TRACK DENSITIES
TUCDR7==:TUC7TK+TUCDR8 ;7 TRACK TAPE + DENSITIES
TUCDR6==:TUCD80+TUCD16 ;TM02 AND TU70 DENSITIES
TUCDR5==:TUCD16+TUCD62 ;TU72 DENSITIES
TUCDIG==:1B28 ;DIAG. UUO ON THIS DRIVE
TUCFOI==:1B29 ;FILE OPERATIONS ILLEGAL
;IN TUBERR
NXTLSE==:(1B0) ;NEXT TO LAST ERROR RETRY
;ERROR RECOVERY PARAMETERS
ERPNCS==5 ;NUMBER OF BACKSPACE/SPACE OP IN TAPE CLEANER SEQ.
IOSCP2==:(1B11) ;MUST BE SAME AS TKSCHE
;TAPSBF DETERMINES WHETHER REAL FILE POSITIONING IS DONE OR MULTIPLE
; SKIP/BACKSPACE RECORD OPERATIONS ARE USED TO SIMULATE FILE POSITIONING.
TAPSBF: EXP MTFILE## ;DEFAULT TO MONGEN'ED VALUE
;BYTE POINTERS
;INTO UDB
TUYKTP::POINT 4,TUBCNF(U),35 ;CONTROLLER TYPE
TUYECT: POINT ERCCTS,TUBERR(U),17 ;POINTER TO RETRY COUNTER
TUYEC1: POINT ERCCTS,TUBERR(U),17-ERCCTS ;SECONDARY RETRY COUNTER
;INTO IORB
PRBRQS:: POINT RB.RQS,TRBFNC(T1),RB.RQP ;REQUEST STATUS
PRBMOD:: POINT RB.MDS,TRBFNC(T1),RB.MDP ;REQUEST MODE
PRBMD2:: POINT RB.MDS,TRBFNC(P1),RB.MDP
PRBFCN:: POINT RB.FNS,TRBFNC(T1),RB.FNP ;REQUEST FUNCTION
PRBDEN:: POINT RB.DNS,TRBFNC(T1),RB.DNP ;DENSITY
PRBBYT:: POINT RB.BYS,TRBFNC(T1),RB.BYP ;REQUEST INFO
SUBTTL PROTOTYPE INTERRUPT ROUTINE
TAPICD::PHASE 0
IFN FTKL10,<
CONSO 000,0 ;(00) NEED SERVICE?
JRST . ;(01) TRY NEXT DEVICE ON CHAIN
TAPCNI::!CONI 000,21 ;(02) GET CONI BITS
JSR PIERR## ;(03) SAVE ACS
SKIPA W,.+1 ;(04) SETUP DATA BLOCK POINTER
EXP 0 ;(05) DATA BLOCK ADDRESS
XJRST .+1 ;(06) GO SERVICE INTERRUPT
EXP 0 ;(07) INTERRUPT HANDLER ADDRESS
EXP 0 ;(10) OLD PC FLAGS
EXP 0 ;(11) OLD PC
EXP IC.UOU ;(12) NEW PC FLAGS
EXP .+1 ;(13) NEW PC
XCT 2 ;(14) GET CONI BITS
XCT 3 ;(15) SAVE ACS
DMOVE T1,10 ;(16) COPY OLD PC DOUBLE WORD
DMOVEM T1,-1 ;(17) FAKE UP PI CHANNEL INTERRUPT
JRST 4 ;(20) GO CALL INTERRUPT HANDLER
TAPCII::!EXP -1 ;(21) CONI BITS AT INTTERUPT
> ;END FTKL10
IFN FTKS10,<
CONSO 000,0 ;(00) NEED SERVICE?
JRST . ;(01) TRY NEXT DEVICE ON CHAIN
JSR PIERR## ;(02) SAVE ACS
SKIPA W,.+1 ;(03) SETUP DATA BLOCK POINTER
EXP 0 ;(04) DATA BLOCK ADDRESS
JRST @.+1 ;(05) GO SERVICE INTERRUPT
EXP 0 ;(06) INTERRUPT HANDLER ADDRESS
EXP 0 ;(07) OLD PC FLAGS
EXP 0 ;(10) OLD PC
EXP IC.UOU ;(11) NEW PC FLAGS
EXP .+1 ;(12) NEW PC
XCT 2 ;(13) SAVE ACS
DMOVE T1,7 ;(14) COPY OLD PC DOUBLE WORD
DMOVEM T1,-1 ;(15) FAKE UP PI CHANNEL INTERRUPT
JRST 3 ;(16) GO CALL INTERRUPT HANDLER
> ;END FTKS10
DEPHASE
TAPICL==:.-TAPICD ;LENGTH OF CODE
SUBTTL AUTOCONFIGURATION
;ROUTINE TO SETUP CONI ADDRESS IN CONTROLLER'S CSO (TAPICD) BLOCK
;CALL: MOVE W, KDB ADDRESS
; PUSHJ P,TAPCSA
; <ALWAYS RETURN HERE>
;DESTROYS T1,T2
IFN FTKL10,<
TAPCSA::MOVE T1,KDBCSO(W) ;GET CSO BLOCK ADDRESS
MOVEI T2,TAPCII(T1) ;GET CONI DESTINATION ADDRESS
HRRM T2,TAPCNI(T1) ;PUT ADDRESS IN RH OF INSTRUCTION
SETZM TAPCII(T1) ;CLEAR THE CONI DESTINATION
POPJ P,
>
;ROUTINE TO DO COMMON TAPE DRIVE AUTOCONFIGURATION
;CALL: MOVE T1, PHYSICAL DRIVE #,,UDB TABLE INDEX
; MOVE T2, TUBCNF WORD
; MOVE T3, HUMG TIMER TABLE ADDRESS
; MOVE T4, SIXBIT DRIVE MODEL
; PUSHJ P,TAPDRV
; <NON-SKIP> ;NO CORE FOR UDB OR DDB
; <SKIP> ;DATA STRUCTURES CREATED AND LINKED UP
TAPDRV::PUSH P,T2 ;SAVE TUBCNF BITS
PUSH P,T3 ;SAVE HUNG TIMER TABLE ADDRESS
PUSH P,T4 ;SAVE DRIVE MODEL
PUSHJ P,AUTUDB## ;BUILD A UDB
JRST [POP P,(P) ;PHASE STACK
JRST TTPOPJ##] ;FAILURE RETURN
POP P,TUBMDL(U) ;STORE SIXBIT DRIVE MODEL
POP P,T1 ;GET HUNG TIMER TABLE ADDRESS
MOVE T2,-1(T1) ;GET MAXIMUM TIMEOUT VALUE
MOVEM T2,TUBMTV(U) ;SAVE INCASE NO ACCESS TO SOME PORT
DMOVE T2,0(T1) ;WORDS 0 & 1
DMOVEM T2,TUBHTT(U) ;SAVE THEM
DMOVE T2,2(T1) ;WORDS 2 & 3
DMOVEM T2,TUBHTT+2(U) ;DITTO
POP P,TUBCNF(U) ;STORE CONFIGURATION WORD
SKIPE F,UDBDDB(U) ;ALREADY HAVE A DDB?
JRST TAPDR1 ;DON'T CREATE ANOTHER
HLLZ T1,KDBNAM(W) ;GENERIC DEVICE NAME,,LOCAL DEVICE
HRR T1,P1 ;GET PHYSICAL DRIVE NUMBER
SETZ T2, ;LOCAL DEVICE
PUSHJ P,AUTDDB## ;CREATE A DDB
SKIPA T1,.CPDRV## ;NO CORE
JRST TAPDR1 ;ONWARD
MOVE T1,DRVULN(T1) ;UDB LENGTH
MOVE T2,U ;UDB ADDRESS
PJRST GIVWDS## ;RELEASE CORE AND RETURN
TAPDR1: MOVEM F,UDBDDB(U) ;LINK UDB TO DDB
MOVEM U,TDVUDB##(F) ;LINK DDB TO UDB
MOVE T1,KDBDSP(W) ;DRIVER DISPATCH
MOVEM T1,DEVDRV(F) ;SO WE CAN FIND IT GIVEN A DDB
MOVSI T1,TUBQUE(U) ;INIT QUEUE HEAD
MOVEM T1,TUBQUE(U) ; TO POINT TO EMPTY QUEUE
MOVE T1,UDBPDN(U) ;PHYSICAL DRIVE NUMBER
MOVEI T2,KDBNUM ;STATE,,MASK WORD OFFSET
PUSHJ P,AUTMSK## ;CLEAR NEW UNIT FOR THIS DRIVE
JFCL ;CAN'T FAIL HERE
MOVE T1,UDBPDN(U) ;PHYSICAL DRIVE NUMBER
MOVEI T2,KDBIUM ;STATE,,MASK WORD OFFSET
PUSHJ P,AUTMSK## ;CLEAR IGNORE UNIT FOR THIS DRIVE
JFCL ;CAN'T FAIL HERE
SYSPIF ;INTERLOCK
MOVSI T1,TKSNS ;DIAG BIT
TDNN T1,TKBSTS(W) ;KONTROLLER STOPPED?
TDZA T1,T1 ;NO DIAG JOB
HLRZ T1,TKBJOB(W) ;GET MAINTENANCE JOB NUMBER
SYSPIN ;RELEASE INTERLOCK
JUMPN T1,TAPDR2 ;CAN'T ATTACH IF DIAG
LDB T1,PJOBN## ;GET DDB OWNER
MOVEI T2,ASSCON ;BIT TO TEST
TDNE T2,DEVMOD(F) ;ASSIGNED TO JOB ZERO?
JUMPN T1,TAPDR2 ;NO, DON'T NEED TO ATTACH IT
PUSHJ P,DDBATT## ;MAKE SURE ATTACHED
POPJ P, ;FAILED
IFN FTMDA,<PUSHJ P,TAPMPA> ;INDICATE TAPE DRIVE ATTACHED
TAPDR2: PUSHJ P,SAVE3## ;SAVE P1-3
PUSH P,W ;SAVE W
HLLZ P1,TUBIEP(U) ;GET INITIAL ERROR POINTER LENGTH
HLLZ P2,TUBFEP(U) ;GET FINAL ERROR POINTER LENGTH
LDB P3,[POINTR KDBSTS(W),KD.MPT] ;GET OUR MAXIMUM PORT COUNT
XMOVEI T1,UDBKDB(U) ;POINT TO KDB TABLE FOR DRIVE
MOVSI T2,-MXPORT ;AOBJN POINTER
TAPDR3: SKIPE W,(T1) ;GET A KDB
CAMN W,(P) ;FOUND OURSELVES?
JRST TAPDR4 ;IGNORE IT
MOVE T3,KDBDSP(W) ;GET DISPATCH
MOVE T3,DRVUDB(T3) ;AND PROTOTYPE UDB
HLLZ T4,TUBIEP(T3) ;GET INITIAL (PROTOTYPE) ERROR POINTER
CAMLE P1,T4 ;CURRENT THE LARGER OF THE TWO?
MOVE P1,T4 ;NO--MAKE IT SO
HLLZ T4,TUBFEP(T3) ;GET FINAL (PROTOTYPE) ERROR POINTER
CAMLE P2,T4 ;CURRENT THE LARGER OF THE TWO?
MOVE P2,T4 ;NO--MAKE IT SO
LDB T3,[POINTR KDBSTS(W),KD.MPT] ;GET THIS KDB'S MAX. PORT COUNT
CAIGE T3,(P3) ;IF HIS IS BETTER,
MOVE P3,T3 ;UPDATE OUR VALUE
DPB P3,[POINTR KDBSTS(W),KD.MPT] ;SAVE POSSIBLY UPDATED VALUE IN KDB
TAPDR4: AOS T1 ;ADVANCE POINTER
AOBJN T2,TAPDR3 ;LOOP FOR ALL KDBS
HLLM P1,TUBIEP(U) ;UPDATE INITIAL ERROR POINTER
HLLM P2,TUBFEP(U) ;UPDATE FINAL ERROR POINTER
POP P,W ;RESTORE OUR KDB ADDRESS
DPB P3,[POINTR KDBSTS(W),KD.MPT] ;SAVE BEST VALUE IN OUR KDB
JRST CPOPJ1## ;RETURN SUCCESS
IFN FTMDA,<
;SEND A DEVICE ATTACHED MESSAGE TO [SYSTEM]MDA
TAPMPA::MOVE T1,UDBNAM(U) ;PRIMARY PORT NAME
SETZ T2, ;NO SECONDARY PORT NAME
PJRST ATTMPA## ;INFORM [SYSTEM]MDA
;SEND A DEVICE DETACHED MESSAGE TO [SYSTEM]MDA
TAPMPD::SETZ T1, ;NO NEW PRIMARY PORT NAME
PJRST DETMPA## ;INFORM [SYSTEM]MDA
> ;END IFN FTMDA
SUBTTL INTERRUPT SERVICE.
;HERE WITH AC'S SAVED AND PDL SETUP.
;C(W) := KDB ADDRESS
;AFTER CALL TO DEVICE DEPENDENT ROUTINE OR ERROR PROCESSOR
;C(T1) := IORB ADDRS IF COMPLETED
; 0 IF ANOTHER INTERUPT COMING - NO FURTHER PROCESSING
; -1 IF SCHED CYCLE REQUESTED
;C(TUBERR) NON-ZERO IF ERROR RECOVERY IN PROGRESS
TAPINT::SKIPG KDBUNI(W) ;MULTIPLE KONTROLLERS ON A SINGLE CHANNEL?
JRST TAPIN3 ;NO
IFN FTKL10,<
MOVE T1,KDBCHN(W) ;GET ADDRESS OF CHANNEL DATA BLOCK
MOVE T1,CHNTYP(T1) ;GET CHANNEL TYPE BITS
TLNE T1,(CP.SAX) ;NON-SA10 CHANNEL?
JRST TAPIN3 ;SA10 DOESN'T HAVE RH10/20 CONI BITS
MOVE T1,KDBCSO(W) ;GET TAPICD BLOCK ADDRESS
MOVE T1,TAPCII(T1) ;GET CONI BITS AT INTERRUPT
TRNE T1,CI.DON ;IS DONE IS ON?
JRST TAPIN3 ;YES, THE INTERRUPT IS FOR THIS KDB
PUSH P,T1 ;SAVE INTERRUPT CONI BITS FOR THE RIGHT KDB
MOVSI T2,(.DIASR) ;ATTEN INTERRUPT. READ ATTN SUMMARY
XCT KDBDTO(W) ; REGISTER
IMULI P,1
IMULI P,1 ;STALL IN CASE AN RH10
XCT KDBDTI(W) ;READ ATTENTION BITS
> ;END IFN FTKL10
IFN FTKS10,<
MOVE T2,KDBDVC(W) ;CSR ADDRESS
RDIO T1,.DOSR(T2) ;READ DRIVE STATUS REGISTER
TRNN T1,DS.ATA ;ATTENTION BITS AVAILABLE?
JRST TAPIN3 ;NO--INTERRUPT FOR INTERRUPTING KDB
RDIO T2,.DOAS(T2) ;READ ATTENTION BITS
> ;END IFN FTKS10
ANDI T2,377 ;GET JUST ATTENTION BITS
MOVE T1,KDBCHN(W) ;POINT TO CHANNEL DATA BLOCK
MOVE T1,CHNTBP(T1) ;AND TO THE TABLE OF KDBS ON THIS CHN
TAPIN1: SKIPN W,(T1) ;GET A KDB ADDRESS
JRST TAPIN2 ;NOTHING THERE??
TDNE T2,KDBUNI(W) ;INTERRUPT FOR THIS KDB?
IFN FTKS10,<JRST TAPIN3> ;YES. HANDLE IT
IFN FTKL10,<
JRST [MOVE T1,KDBCSO(W) ;GET TAPICD BLOCK ADDRESS
POP P,TAPCII(T1) ;PUT IN CORRECT CONI BITS
JRST TAPIN3]
> ;END IFN FTKL10
TAPIN2: AOBJN T1,TAPIN1 ;TRY ANOTHER KDB
IFN FTKL10,<
HRLI T2,(.DIASR!DO.LDR!DO.DRE) ;NOT FOR ANY KDB WE KNOW OF
XCT KDBDTO(W) ; SO CLEAR THE INTERRUPT
POP P,(P) ;SYNCH STACK
> ;END IFN FTKL10
IFN FTKS10,<
MOVE T1,KDBDVC(W) ;GET CSR ADDRESS FOR CONTROLLER
WRIO T2,.DOAS(T1) ;CLEAR ATTENTION BITS
> ;END IFN FTKS10
POPJ P, ;AND GO AWAY
TAPIN3: MOVE T1,KDBDSP(W) ;GET XFER VECTOR
PUSHJ P,@TPKISR(T1) ;CALL DEV DEP INT RTN
TAPAGO: JUMPE T1,CPOPJ## ;IF ZERO, ANOTHER INT IS COMING
JUMPL T1,TAPIN4 ;NO COMPLETION - DO SCHED CYCLE
MOVSI T2,TKSSTD ;CHANNEL NO LONGER STARTED
ANDCAM T2,TKBSTS(W) ;SO CLEAR STATUS
ANDCAM T2,TUBSTS(U) ;AND UNIT STATUS
SKIPE T2,TUBERR(U) ;IS ERP IN PROGRESS?
PUSHJ P,ERPINT ;YES - CALL INTERRUPT PART
JUMPE T1,CPOPJ## ;TERMINATE NOW?
JUMPL T1,TAPIN4 ;NO COMPLETION
MOVEI T2,RB.DUN ;MARK IORB AS DONE
DPB T2,PRBRQS ;...
MOVSI T2,TUSREW ;BIT TO TEST
TDNN T2,TUBSTS(U) ;REWIND OR UNLOAD INTERRUPT PENDING?
PUSHJ P,TAPCTM ;CLEAR HUNG TIMER FOR ALL OTHER OPERATIONS
PUSHJ P,TPMDON## ;YES - NOTIFY UPPER LEVEL
HRRZ T2,TKBSTS(W) ;SEE IF A SCHED CYCLE IS DUE
JUMPG T2,CPOPJ## ;NO - DISMISS
PUSHJ P,TAPDSL ;DE-SELECT KONTROLLER
TAPIN4: SETZB S,F ;MAKE SURE IOSCP2 IS OFF
MOVSI T2,TUSREW ;BIT TO TEST
TDNN T2,TUBSTS(U) ;REWIND OR UNLOAD INTERRUPT PENDING?
PUSHJ P,TAPCTM ;CLEAR HUNG TIMER FOR ALL OTHER OPERATIONS
PUSHJ P,TAPSCH ;SEE IF THERE IS MORE WORK
POPJ P, ;NO MORE TO DO
PJRST TPMSIO## ;START IO
;ROUTINE TO DE-SELECT A KONTROLLER AND CLEAR I/O
TAPDSL::MOVE T1,KDBDSP(W) ;GET XFER VECTOR
PUSHJ P,@TPKIDL(T1) ;MARK IDLE
HLLZS TKBSTS(W) ;SET QUANTUM TO ZERO
MOVSI T1,TKSSEL ;CLEAR SELECTION BITS
ANDCAM T1,TUBSTS(U) ; IN UDB
ANDCAM T1,TKBSTS(W) ; AND KDB
SETOM T1,@KDBCHN(W) ;INDICATE CHANNEL IS IDLE
POPJ P, ;RETURN
;GENERAL INTERUPT ERROR HALT
TAPIFI::STOPCD .,STOP,IFI, ;++ ILLEGAL FUNCTION AT INTERUPT
SUBTTL CHANNEL SCHEDULER
;W/ KDB TO CONTINUE SCANNING.
;SKIP RETURNS WITH W AND U SETUP IF ANOTHER REQUEST IS FOUND
;NON SKIP RETURN IF NOTHING TO DO
TAPSCH: TAPOFF ;TRY TO DEFEND AGAINST RACES
PUSH P,W ;SAVE INITIAL KDB
HRRZS (P) ;SAVING ONLY RIGHT HALF
MOVE T4,KDBCUN(W) ;INDEX INTO UNIT TABLE
PUSH P,T4 ;SAVE START
MOVSI T2,TKSOFL!TKSMNT!TKSNS ;CHECK IF HE IS AMOUNG US
TDNE T2,TKBSTS(W) ;...
JRST TPSCH2 ;NO, DON'T SCHEDULE FOR HIM
CAML T4,KDBFUN(W) ;FINAL UDB?
JRST TPSCH2 ;YES
AOS T4 ;START LOOKINT AT NEXT UDB
TPSCH1: SKIPN U,(T4) ;GET UDB
JRST TPSCHN ;NONE PRESENT
HRRZ T1,TUBQUE(U) ;GET QUEUE POINTER
JUMPE T1,TPSCHN ;GO IF NONE
SKIPL T2,TUBAKA(U) ;GET ACTIVE KDB ADDRESS
CAMN W,T2 ;KONTROLLER ALREADY PICKED?
CAIA ;FOUND RIGHT KDB OR NONE PICKED YET
JRST TPSCHN ;IGNORE THIS TUB
IFE FTMP,<SKIPL T2,TUBSTS(U)> ;NO SCHED?
IFN FTMP,<
SKIPGE T2,TUBSTS(U) ;NO SCHED ON THIS CPU
TLNE T2,TKSCHE
>
TLNE T2,TKSSEL!TKSCHA ;OR SELECTED BY ANOTHER?
JRST TPSCHN ;YES
IFN FTMP,<
MOVE T3,TRBFNC(T1) ;GET IORB FLAGS
TLNN T2,TKSCHE ;QUEUED REQUEST ON UDB?
TLNN T3,RB.PCL ;YES, QUEUED IORB REQUEST?
TDCA T2,S ;CLEAR IOSCP2(=TKSCHE) IF REQUEST TYPES MATCH
JRST TPSCHN ;CANT DO IT IF CHE=0, PCL=1
TLNN T2,IOSCP2 ;CP2=CHE=PCL?
>
JRST TPSCH3 ;FOUND 1 - USE IT
TPSCHN: CAMN T4,(P) ;BACK TO ORIGINAL UNIT?
JRST TPSCHY ;NOTHING TO DO - NON SKIP RETURN
CAMGE T4,KDBFUN(W) ;FINAL UDB?
AOJA T4,TPSCH1 ;LOOP FOR MORE
TPSCH2: MOVSI T2,TKSSCH
ANDCAM T2,TKBSTS(W)
TPSC2A: PUSHJ P,NXTKDB ;ADVANCE TO NEXT KDB ON CHANNEL
JFCL ;IGNORE WRAP AROUND
MOVSI T4,TKSOFL!TKSMNT!TKSNS ;BE SURE HE'S REALLY HERE
TDNE T4,TKBSTS(W) ;IS HE?
JRST [CAMN W,-1(P) ;NO, BACK TO ORIGINAL KDB ALREADY?
JRST TPSCHY ;YES, EXIT
JRST TPSC2A ];NO, STEP ON
IFN FTMP,<
MOVE T1,KDBCAM(W) ;GET ACCESSABILITY BIT
TDNN T1,.CPBIT## ;CAN WE DO I/O FOR THIS KDB?
JRST TPSC2A ;NO, LOOK FOR ANOTHER CANDIDATE
> ;END IFN FTMP
IORM T2,TKBSTS(W)
MOVE T4,KDBIUN(W) ;RESET POINTER
JRST TPSCH1 ;CONTINUE SEARCH
;HERE WHEN A REQUEST IS FOUND
TPSCH3:
IFN FTMP,<
SKIPE T3,CPUTPQ ;ANY QUEUED REQUESTS?
MOVSI T3,TKSCHE ;YES
TDNE T3,TKBSTS(W) ;REQUEST FOR THIS CONTROL?
SOS T3,TKBFCT(W) ;YES, TIME TO BE FAIR?
JUMPL T3,TPSCHY ;YES, LET TAPTIC HAVE IT
>
MOVSI T2,RB.AIO ;IS THIS REQUEST SPECIAL?
TDNE T2,TRBFNC(T1) ;?
PUSHJ P,UUOLVL## ;YES, ARE WE AT UUO LEVEL?
JRST TPSCH4 ;AT INTERRUPT LEVEL OR NOT SPECIAL
PUSH P,F ;SAVE F
MOVE F,TUBCUR(U) ;GET DDB ADDR
LDB T2,PJOBN## ;GET JOB NUMBER
POP P,F ;RESTORE F
CAMN T2,.CPJOB## ;CURRENT JOB (CURRENTLY SWAPPED USER)?
JRST TPSCH4 ;YES, OK TO START IT
MOVE T2,KDBDSP(W) ;CAN'T START NOW, CLANK THE
PUSHJ P,@TPKSCH(T2) ;SCHEDULER TO COME BACK @INTERRUPT LEVEL
JRST TPSCHY ;FIX STACK AND RETURN
TPSCH4: MOVEM T4,KDBCUN(W) ;STORE CURRENT UNIT
MOVSI T2,TKSSEL ;FLAG AS SELECTED
IORM T2,TKBSTS(W) ;IN KDB
IORM T2,TUBSTS(U) ;AND IN UDB
AOS T2,@KDBCHN(W) ;INDICATE CHANNEL IS BUSY
MOVEI T2,MQUANT## ;SET SLICE
HRRM T2,TKBSTS(W) ; ..
MOVE T3,UDBPDN(U) ;GET PHYSICAL DRIVE NUMBER
MOVEM W,TUBAKA(U) ;STORE AS ACTIVE KDB ADDRESS
AOS -2(P) ;SET FOR SKIP RETURN
TPSCHY: POP P,(P)
POP P,(P)
TPSCHX: MOVSI T2,TKSSCH ;CLEAR FACT THAT WE SCHEDULED
ANDCAM T2,TKBSTS(W) ; FOR THIS KDB
JRST TPONPJ ;RESTORE INTERRUPTS AND RETURN
NXTKDB: PUSHJ P,SAVE1## ;SAVE P1
MOVE P1,KDBCHN(W) ;POINT TO THE CHANNEL DATA BLOCK
MOVE P1,CHNTBP(P1) ;AND GET THE AOBJN POINTER TO KDBS
NXTKD1: CAME W,(P1) ;FOUND THE CURRENT KDB YET?
AOBJN P1,.-1 ;KEEP SEARCHING
JUMPGE P1,CPOPJ## ;NOT THERE??
AOBJN P1,NXTKD2 ;ADVANCE TO NEXT SLOT
MOVE P1,KDBCHN(W) ;RAN OUT SO MUST RESET W TO THE
SKIPA P1,CHNTBP(P1) ;FIRST KDB ON THE CHANNEL
NXTKD2: AOS (P) ;FORCE SKIP
MOVE W,(P1) ;PICK UP A KDB ADDRESS
POPJ P, ;AND RETURN
SUBTTL CHECK FILE OPERATIONS
;ROUTINE TO SEE IF IT IS LEGAL TO USE A FILE OPERATION
;CALL: MOVE U, UDB ADDRESS
; PUSHJ P,TAPFOL
; <NON-SKIP> ;LEGAL
; <SKIP> ;ILLEGAL
TAPFOL::PUSH P,T1 ;SAVE T1
MOVE T1,TUBCNF(U) ;GET DRIVE CONFIG WORD
ANDI T1,TUCFOI ;KEEP ONLY "FILE OPERATIONS ILLEGAL" BIT
SKIPE TAPSBF ;TAPSER SAY OK?
JUMPE T1,TPOPJ## ;YES, BUT ONLY IF DRIVER AGREES
JRST TPOPJ1## ;ELSE DO MULTIPLE RECORD OPS
SUBTTL HUNG TIMER CONTROL
;SET HUNG TIMER
;CALL: MOVE U, UDB ADDRESS
; PUSHJ P,TAPSTM
;
;ALL ACS PRESERVED
TAPSTM::PUSH P,T1 ;SAVE T1
MOVE T1,KDBSTS(W) ;GET STATUS WORD
TLNN T1,(KD.APC) ;ALL PORTS CONFIGURED (KNOWN)?
TLNN T1,(KD.MPD) ;NO, BUT IS IT A MULTI-PORTED DEVICE?
JRST TAPST2 ;NORMAL HUNG TIMER WILL DO
PUSH P,T2 ;SAVE T2
XMOVEI T1,UDBKDB(U) ;POINT TO DRIVE'S KDB TABLE
MOVSI T2,-MXPORT ;AOBJN POINTER
PUSH P,[EXP 0] ;INIT A COUNTER
TAPST1: SKIPE (T1) ;HAVE A KDB ADDRESS?
AOS (P) ;COUNT IT
AOS T1 ;ADVANCE POINTER
AOBJN T2,TAPST1 ;LOOP FOR ALL KDBS
POP P,T1 ;GET COUNT
LDB T2,[POINTR (KDBSTS(W),KD.MPT)] ;AND MAXIMUM NUMBER OF PORTS
CAIE T1,(T2) ;ALL PORTS KNOWN?
JRST TAPST3 ;NO, USE MAXIMUM HUNG TIMER
POP P,T2 ;RESTORE T2
MOVSI T1,(KD.APC) ;HERE IF ALL PORTS ARE KNOWN
IORM T1,KDBSTS(W) ;UPDATE TO MINIMIZE OVERHEAD NEXT TIME
TAPST2: HRRZ T1,TUBQUE(U) ;GET CURRENT IORB
LDB T1,PRBFCN ;AND THE FUNCTION CODE
ADJBP T1,[POINT 9,TUBHTT(U),8] ;INDEX TO THE PROPER BYTE
LDB T1,T1 ;GET THE FUNCTION-SPECIFIC TIMER VALUE
JRST TAPST4 ;GO STORE
TAPST3: POP P,T2 ;RESTORE T2
MOVE T1,TUBMTV(U) ;GET MAXIMUM HUNG TIMER VALUE
TAPST4: MOVEM T1,TUBTIM(U) ;STORE IN THE TUB
JRST TPOPJ## ;RESTORE T1 AND RETURN
;CLEAR HUNG TIMER
;CALL: MOVE U, UDB ADDRESS
; PUSHJ P,TAPCTM
;
;ALL ACS PRESERVED
TAPCTM::PUSH P,T1 ;SAVE T1
SETZM TUBTIM(U) ;CLEAR TIMER WORD IN THE TUB
MOVSI T1,(1B0) ;GET A BIT
IORM T1,TUBAKA(U) ;MARK ACTIVE KONTROLLER INVALID
JRST TPOPJ## ;RESTORE ACS AND RETURN
SUBTTL START IO
;HERE WHEN UPPER LEVEL WANTS TO START IO. THE USER JOB IS LOCKED
;AND THE IORB HAS A VALID DATA XFR LIST IF ONE IS NEEDED
TAPSIO::
IFN FTMP,<
MOVE T2,KDBCAM(W) ;GET CPU ACCESSIBILITY MASK FOR KONTROLLER
TDNN T2,.CPBIT## ;ON THE RIGHT CPU?
STOPCD .,STOP,TIO, ;++ TAPE I/O TO WRONG CPU
> ;END IFN FTMP
TAPOFF ;GUARD AGAINST
MOVE T2,TKBSTS(W) ;KONTROLLER STATUS
TLNE T2,TKSOFL ;CONTROLLER INTERRUPTS
JRST TPONPJ ;WHICH SET CONTROLLER OFFLINE
TLOE T2,TKSSEL ;SELECTED?
TLZE T2,TKSSTD ;AND NOT STARTED
STOPCD TAPSI3,INFO,KSW, ;++KONTROLLER STATUS WRONG
TAPSI1: MOVE T2,TUBSTS(U) ;UNIT STATUS
TLOE T2,TKSSEL ;SELECTED?
TLZE T2,TKSSTD ;AND NOT STARTED (ON ANOTHER KONTROL)?
STOPCD TAPSI4,INFO,USW, ;++UNIT STATUS WRONG
TAPSI2: MOVEI T2,RB.ACT ;SET IORB STATUS TO ACTIVE
DPB T2,PRBRQS ; ...
IFN FTMP,<
LDB T2,DEYPCL## ;DON'T SET NON-ZERO IF
JUMPE T2,TPSI2A ;IT WASN'T
SKIPN T2,.CPCPN## ;TELL THW WORLD
MOVEI T2,PCLCP0## ; WHAT CPU IS DOING THE IO
DPB T2,DEYPCL##
TPSI2A:>
PUSHJ P,TAPFLT ;CHECK IF FORCING HUNG DEVICE
JRST TAPSI5 ;WILL HANG, DON'T START THE IORB
;FOR ERROR LOGGING, RECORD SOME DATA IN THE TUB
SKIPGE T2,KDBUNI(W) ;MASSBUS UNIT NUMBER
TDZA T2,T2 ;NOT A MULTI-UNIT DEVICE
HLRZS T2 ;PUT IN RH
ROT T2,-3 ;POSITION IN BITS 0-2
IOR T2,KDBDVC(W) ;INCLUDE THE DEVICE CODE/UNIBUS ADDRESS
MOVEM T2,TUBDVC(U) ;SAVE
MOVE T2,KDBDSP(W) ;DRIVER DISPATCH
LDB T2,[POINTR (DRVCF2(T2),DR.KTY)] ;KONTROLLER TYPE
MOVEM T2,TUBKTY(U)
MOVSI T2,TKSSTD ;MARK AS STARTED
IORM T2,TKBSTS(W) ;IN KDB
IORM T2,TUBSTS(U) ;AND UDB
PUSHJ P,TAPSTM ;SET HUNG TIMER
MOVE T2,KDBDSP(W) ;GET KONTROLLER DISPATCH
PUSHJ P,@TPKSIO(T2) ;CALL START IO
TAPSI5: TAPON ;SAFE NOW
POPJ P,0
;HERE AFTER KSW STOPCD, TRY TO RECOVER
TAPSI3: MOVEM T2,TKBSTS(W) ;STORE REASONABLE STAUS
JRST TAPSI1 ;GO CHECK UNIT STAUS
;HERE AFTER USW STOPCD
TAPSI4: MOVEM T2,TUBSTS(U) ;STORE REASONABLE STATUS
JRST TAPSI2 ;GO START THE IO
;HERE TO SETUP FOR HUNG DEVICE.
;SKIP IF OPERATION OK, NON-SKIP IF FORCING DEVHNG.
TAPFLT::MOVSI T2,TUSFLT ;TU FAULT BIT
TDNN T2,TUBSTS(U) ;IS THE DRIVE BROKEN?
JRST CPOPJ1## ;NO, GIVE OK RETURN
LDB T2,PRBFCN ;GET THE IORB FUNCTION
CAIE T2,RB.FRW ;IS IT REWIND?
CAIN T2,RB.FRU ;OR UNLOAD?
JRST CPOPJ1## ;YES, THIS IS SAFE
MOVEI T2,1 ;A SMALL HUNG TIME LIMIT
MOVEM T2,TUBTIM(U) ;LIMIT FOR TAPSEC
POPJ P, ;GIVE FORCED DEVHNG RETURN
SUBTTL CHECK FOR KONTROLLER BUSY
;THIS IS COMMON CODE TO SUPPORT THOSE KONTROLLERS WHICH ARE INCAPABLE
;OF HANDLING NON-BLOCKING FUNCTION. THAT IS, A GIVEN FUNCTION TIES UP
;THE KONTROLLER UNTIL AN INTERRUPT IS RECEIVED.
;CALL: MOVE W, KDB ADDRESS
; MOVE U, UDB FOR DRIVE TRYING TO SCHEDULE
; PUSHJ P,TX1BSY
; <NON-SKIP> ;BUSY
; <SKIP> ;NOT-BUSY
;
;USES T1 AND T2
TAPBSY::MOVSI T1,TKSOFL!TKSMNT!TKSNS ;INTERESTING BITS
TDNE T1,TKBSTS(W) ;OFFLINE, MAINTENANCE MODE, OR NOT SCHEDULING?
POPJ P, ;RETURN BUSY
MOVE T1,KDBDSP(W) ;POINT TO DRIVER DISPATCH
PUSHJ P,@TPKBSY(T1) ;IS KONTROLLER BUSY?
POPJ P, ;IT IS
JRST CPOPJ1## ;KONTROLLER IS FREE
;HERE IF FOR DUMB KONTROLLERS TO DO TRADITIONAL CHECKING
MOVSI T1,TKSSEL!TKSSTD!TKSSCH ;BITS TO TEST
SKIPGE @KDBCHN(W) ;CHANNEL IN USE (USER MODE DIAG)?
TDNE T1,TKBSTS(W) ;OR CHANNEL ALREADY GOING?
POPJ P, ;THEN IT'S BUSY
JRST CPOPJ1## ;ELSE RETURN CHANNEL FREE
SUBTTL ONLINE CHECK
;HERE ONCE A SECOND/MINUTE.. GROVEL THROUGH THE KDBS AND SEE IF THERE ARE
;ANY OFFLINE. IF SO, COMPLAIN THROUGH TPMOFL. IF ANY CLAIM TO BE OFFLINE
;AND ARE NOW ONLINE, INITIALIZE AND OPERATE A SCHEDULE CYCLE.
CHKKON: SKIPN W,KDBTAB##+.TYMTA ;GET FIRST KDB
JRST CPOPJ1## ;NO TAPES
CHKKO1: MOVSI T1,TKSMNT ;BIT TO TEST
IFN FTMP,<
MOVE T2,KDBCAM(W) ;CPU ACCESSIBILITY MASK
TDNE T2,.CPBIT## ;ON OUR CPU?
>
TDNE T1,TKBSTS(W) ;SEE IF WE SHOULD CHECK
JRST CHKKO7 ; IF HE IS ONLINE
MOVSI T1,TKSSEL!TKSSTD!TKSSCH ;BITS TO TEST
SKIPGE @KDBCHN(W) ;CHANNEL IN USE (USER MODE DIAG)?
TDNE T1,TKBSTS(W) ;OR CHANNEL ALREADY GOING?
JRST CHKKO2 ;THEN IT'S ONLINE
MOVE T1,KDBDSP(W) ;GET XFR VECTOR
PUSHJ P,@TPKONL(T1) ;SEE IF ONLINE
JRST CHKKO4 ;NOT ON LINE - COMPLAIN
CHKKO2: MOVSI T1,TKSOFL ;NOW ONLINE - SEE IF
TDNN T1,TKBSTS(W) ;IF FORMERLY OFFLINE.
JRST CHKKO7 ;NO
TLO T1,TKSSCH!TKSSTD!TKSSEL!TKSSIL!IFN FTMP,<TKSCHE!TKSCHA>
ANDCAM T1,TKBSTS(W) ;CLEAR LOTS OF BITS
MOVSI T2,TKSSTD!TKSSEL!IFN FTMP,<TKSCHE!TKSCHA> ;BITS TO CLEAR IN UDB
MOVE T3,KDBIUN(W) ;POINTER TO UDB TABLE
SETZ U, ;FLAG FOR CALLING TPKRES ROUTINE
;KONTROLLER WAS OFFLINE BEFORE, BUT IT'S ONLINE NOW, SO FIXUP UDBS
CHKKO3: SKIPE 0(T3) ;UNIT PRESENT?
SKIPA U,(T3) ;YES, GET ITS ADDRESS
CAIA ;NO, SKIP THIS ONE
ANDCAM T2,TUBSTS(U) ;YES - CLEAR BITS
CAMGE T3,KDBFUN(W) ;FINAL UDB?
AOJA T3,CHKKO3 ;LOOP FOR MORE
JUMPE U,CHKKO7 ;IF NO UNITS, THEN NO ACTIVE I/O TO RESET
MOVE T1,KDBDSP(W) ;GET XFR VECTOR
PUSHJ P,@TPKRES(T1) ;RESET CONTROLLER
JRST CHKKO7 ;GO FINISH THIS ONE
;KONTROLLER HAS BEEN NOTICED OFFLINE FOR THE FIRST TIME
CHKKO4: MOVE T1,KDBIUN(W) ;IF A KON BUT NO UNITS
CHKKO5: SKIPN (T1) ;HAVE A UDB?
JRST CHKKO6 ;YES
CAMGE T1,KDBFUN(W) ;FINAL UDB?
AOJA T1,CHKKO5 ;LOOP 'TIL A UDB IS FOUND
JRST CHKKO7 ;ONTO THE NEXT KONTROLLER
CHKKO6: PUSHJ P,@0(P) ;CALL CO-ROUTINE
JRST CHKKO7 ;CONTINUE LOOP
;END OF KONTROLLER LOOP
CHKKO7:
IFN FTMP,<
MOVEI T1,TKBICT## ;INITIAL FAIRNESS COUNT
SKIPGE TKBFCT(W) ;FAIRNESS COUNT GONE OFF?
MOVEM T1,TKBFCT(W) ;ABJECT PARANOIA
>
SKIPE W,KDBNXT(W) ;GET NEXT KDB
JRST CHKKO1 ;IF THERE IS ONE, CHECK IT
JRST CPOPJ1## ;ELSE SKIP OVER ARG
;ONCE A SECOND - JUST CHECK AND UPDATE INFO
TAPSEC::MOVSI T1,(CR.ATO) ;BIT TO TEST
TDNE T1,.CPRUN## ;WAITING FOR AUTCON TO RUN?
POPJ P, ;THEN DO NOTHING
PUSHJ P,CHKKON ;CRAWL THROUGH DATA BASE
JRST SETOFL ;WHERE TO GO FOR OFFLINE CTL
SKIPN W,KDBTAB##+.TYMTA ;START AT FIRST KONTROLLER
POPJ P, ;NO TAPES
PUSHJ P,SAVE1## ;SAVE P1
TAPSE1:
IFN FTMP,<
MOVE T1,KDBCAM(W) ;CPU ACCESSIBILITY MASK
TDNN T1,.CPBIT## ;OUR CPU?
JRST TAPSE3 ;NO
> ;END IFN FTMP
MOVE P1,KDBIUN(W) ;GET START ADDR OF DRIVE TABLE
TAPSE2: SKIPE U,(P1) ;GET A TUB
PUSHJ P,UTIMER ;CHECK ITS HUNG TIMER
CAMGE P1,KDBFUN(W) ;LOOKED AT ALL TUBS YET?
AOJA P1,TAPSE2 ;LOOP BACK FOR ANOTHER
TAPSE3: SKIPE W,KDBNXT(W) ;STEP TO NEXT KONTROLLER
JRST TAPSE1 ;GO CHECK IT
POPJ P, ;DONE - RETURN
SETOFL: MOVSI T1,TKSOFL
TDNE T1,TKBSTS(W) ;ON LINE?
POPJ P, ;NO - JUST RETURN
MOVE T1,KDBDSP(W) ;GET DISPATCH TABLE ADDRESS
PUSHJ P,@TPKLOD(T1) ;TRY TO LOAD MICROCODE
SKIPA ;CAN'T OR WON'T LOAD
POPJ P, ;KONTROLLER BACK ON-LINE
MOVSI T1,TKSOFL ;BIT TO SET
IORM T1,TKBSTS(W) ;MARK IT OFF-LINE
PJRST TPMOFL## ;TELL WORLD AND RETURN
;ONCE A MINUTE - SEE IF STILL OFF LINE
TAPMIN::PUSHJ P,CHKKON ;LOOK AT THINGS
JRST TPMOFL## ;JUST COMPLAIN IF OFF LINE
POPJ P, ;RETURN
IFN FTMP,<
;HERE ONCE A TICK
TAPTIC::SKIPN W,KDBTAB##+.TYMTA ;START AT 1ST KDB
POPJ P, ;NO TAPES
SKIPN CPUTPQ ;ANY QUEUED REQUESTS FROM ANY CPU?
JRST TAPTI4 ;NO
TAPTI1: MOVSI T2,TKSCHE ;USE 1 BIT PER CPU
MOVE T1,KDBCAM(W) ;CPU ACCESSIBILITY MASK
TDNE T1,.CPBIT## ;ON THIS CPU?
TDNN T2,TKBSTS(W) ;YES, DOES IT HAVE A QUEUED REQUEST?
JRST TAPTI3 ;NO, TRY NEXT KDB
MOVE T3,.CPQPC## ;YES, CLEAR THE DOORBELL
ANDCAM T3,DOORBL## ; SINCE WE HAVE SERVICED THE REQUEST
TLO S,IOSCP2 ;INDICATE WE ARE LOOKING FOR A QUEUED REQUEST
MOVEI T2,TKBICT## ;IF FAIRNESS HAS GONE OFF
SKIPGE TKBFCT(W)
MOVEM T2,TKBFCT(W) ;RESET IT
PUSHJ P,CKSIO2 ;TRY TO SELECT SOME UNIT ON KDB
MOVSI T1,TKSCHE
MOVE T2,KDBIUN(W) ;POINTER TO UDB TABLE
SYSPIF
TLNN S,IOSCP2 ;DID WE SELECT A UNIT?
ANDCAM T1,TUBSTS(U) ;YES, CLEAR THE QUEUED REQUEST BIT
TAPT1A: SKIPE T3,(T2) ;GET A UDB
TDNN T1,TUBSTS(T3) ;DOES IT HAVE A QUEUED REQUEST?
JRST TAPT1B ;NO, TRY NEXT
HRRZ T4,TUBQUE(T3) ;MAYBE
JUMPN T4,TAPT1C ;IS THERE AN IORB?
ANDCAM T1,TUBSTS(T3) ;NO. IT GOT DESELECTED
TAPT1B: CAMGE T2,KDBFUN(W) ;FINAL UDB?
AOJA T2,TAPT1A ;LOOP FOR MORE
ANDCAM T1,TKBSTS(W) ;NO, CLEAR BIT IN THE KDB
TAPT1C: SYSPIN
TLZN S,IOSCP2 ;DID WE SELECT A UDB?
SOSA CPUTPQ ;YES, DECREMENT NO OF OUTSTANDING REQUESTS
JRST TAPTI3 ;NO, TRY NEXT KDB
HRRZ T1,TUBQUE(U) ;POINT AT IORB
MOVE F,TUBCUR(U) ;SET UP NEEDED ACS
MOVE S,DEVIOS(F)
LDB J,PJOBN## ;JOB WHICH OWNS THE UDB
MOVE T2,TRBFNC(T1) ;GET IORB FLAGS
TLNE T2,RB.PCL ;THERE IS A RACE WITH ^C WHICH COULD GET
JRST TAPTI2 ; US HERE FOR A NON-QUEUED REQUEST
MOVE T1,J ;THE JOB IS WAITING AT KONWAT
PUSHJ P,EWAKE## ;SO JUST TAKE IT OUT OF EW
JRST TAPTI3 ;AND KEEP ON
TAPTI2: PUSHJ P,TAPTIX ;"REGULAR" ROUTE - GO START UP THE IO
TAPTI3: SKIPE W,KDBNXT(W) ;STEP TO NEXT KDB
JRST TAPTI1 ;AND GO TEST IT
;HERE AFTER STARTING WHAT WE COULD
TAPTI4: SKIPN T1,.CPTAP## ;ANY REQUEST FOR THIS CPU
POPJ P, ;NO, GO AWAY
IFN FTKL10,<
SKIPG T1 ;YES, DID FILIO ALREADY SWEEP?
PUSHJ P,CSDMP## ;NO, SWEEP CACHE NOW
>
MOVE W,KDBTAB##+.TYMTA ;START AT BEGINNING
MOVE T1,.CPCHX## ;NEEDS-A-SWEEP BIT
MOVSI T2,TKSCHE ;SWEEP-WAS-DONE BIT
TAPTI5: TDNN T1,TKBSTS(W) ;DOES THIS KDB NEED A SWEEP?
JRST TAPTI8 ;NO
ANDCAM T1,TKBSTS(W) ;YES, CLEAR THAT BIT
SYSPIF
IORM T2,TKBSTS(W) ;AND LIGHT SWEEP-DONE
MOVE T3,KDBIUN(W) ;POINTER TO UDB TABLE
TAPTI6: SKIPE T4,(T3)
TDNN T1,TUBSTS(T4) ;CLEAR SWEEP-NEEDED, SET SWEEP-DONE
JRST TAPTI7
ANDCAM T1,TUBSTS(T4) ; FOR ALL UDBS WHICH NEEDED A SWEEP
IORM T2,TUBSTS(T4)
TAPTI7: CAMGE T3,KDBFUN(W) ;FINAL UDB?
AOJA T3,TAPTI6 ;LOOP FOR MORE
SYSPIN
TAPTI8: SKIPE W,KDBNXT(W) ;STEP TO NEXT KDB
JRST TAPTI5 ;GO SWITCH THE BITS FOR IT TOO
MOVM T1,.CPTAP## ;GET NO OF REQUESTS WE JUST SATISFIED
ADDM T1,CPUTPQ ;AND ADD TO REQUESTS FOR ALL CPUS
SETZM .CPTAP## ;CLEAR THIS-CPU-NEEDS-A-SWEEP
POPJ P, ;AND EXIT
;HERE TO GET A QUEUED REQUEST STARTED
;WILL GET TO START THE IO VIA TPMDON
TAPTIX: PUSHJ P,SVEUB## ;MAKE ADDRESSABLE
PUSHJ P,SPCS## ;AND SET PCS
JRST TAPAGO ;CALL TAPAGO TO GET TO TPMDON TO START IO
>;END IFN FTKL10
SUBTTL CHECK HUNG TIMERS
UTIMER: CAMN W,TUBAKA(U) ;CURRENTLY ACTIVE KDB?
PUSHJ P,CHKIRB ;GET IORB (ONLY REALLY CHECKING ACTIVE STATE)
SKIPA T2,TUBAKA(U) ;NOT ACTIVE, GET KDB
JRST UTIMR1 ;GO CHECK THE TIMER
TLZ T2,(1B0) ;IN CASE KDB WAS INACTIVE
MOVSI T3,TUSREW ;REWIND/UNLOAD BIT
CAMN T2,W ;WAS THIS THE LAST ACTIVE KDB?
TDNN T3,TUBSTS(U) ;AND IS THE DRIVE REWINDING NOW?
POPJ P, ;NO TO EITHER
UTIMR1: DDBSRL ;PREVENT LABEL DDBS FROM BEING DELETED
SKIPN F,TUBCUR(U) ;PICK UP CURRENT DDB
MOVE F,UDBDDB(U) ;OR THE "REAL" DDB IF NONE
JUMPE F,UTIMR6 ;AND PUNT IF IMPOSSIBLE HAPPENS
MOVE S,DEVIOS(F) ;GET I/O STATUS WORD
MOVSI T1,DVOFLN ;BIT TO TEST
HRRZ T2,DEVSER(F) ;UUO-LEVEL DISPATCH TABLE ADDRESS
TDNE T1,DEVCHR(F) ;DRIVE OFFLINE?
PUSHJ P,DOFL(T2) ;YES, SEE IF ITS STILL OFFLINE
JRST UTIMR2 ;IT IS
MOVSI T1,DVOFLN ;GET THE BIT AGAIN
ANDCAM T1,DEVCHR(F) ;CLEAR OFFLINE STATE SINCE IT'S ONLINE NOW
PUSHJ P,PSIONL## ;TELL THE USER ITS ONLINE IF HE'S INTERESTED
UTIMR2: HRRZ T1,TUBQUE(U) ;GET IORB BACK
MOVE T2,TUBTIM(U) ;GET THE TIMER
SOJL T2,UTIMR3 ;ZERO MEANS IGNORE THE DEVICE
MOVEM T2,TUBTIM(U) ;UPDATE COUNTER
JUMPN T2,UTIMR6 ;JUMP IF COUNTER NOT EXPIRED YET
JUMPN T1,UTIMR4 ;ELSE IF AN IORB, THEN SOME OPERATION HUNG
UTIMR3: MOVSI T3,TUSREW ;BIT TO TEST
TDNE T3,TUBSTS(U) ;REWIND OR UNLOAD INTERRUPT PENDING?
JRST [PUSHJ P,REWDON ;MISSED AN INTERRUPT, CLEAR REW/UNL, ETC.
JRST UTIMR6] ;DON'T STOP JOB FOR REWIND OR UNLOAD
JUMPL T2,UTIMR6 ;IGNORE DEVICE IF TIMER WAS ZERO
UTIMR4: JUMPE T1,UTIMR6 ;CAN DO NOTHING WITHOUT AN IORB NOW
MOVSI T2,RB.AIO ;IF ASYNCHRONOUS I/O, THEN THERE'S NO TIMER
TDNE T2,TRBFNC(T1) ; TO COUNT DOWN SINCE THE USER'S PROGRAM IS
JRST UTIMR6 ; TIMING THE I/O (IF IT CARES)
MOVSI T1,TUSFLT ;FAULTY DRIVE BIT
TDNE T1,TUBSTS(U) ;DID THE DRIVE GO BAD?
JRST UTIMR5 ;YES, IGNORE SPECIAL CASE FOR SCHEDULE
MOVSI T1,TKSSCH ;GET SCHEDULER BIT
TDNN T1,TKBSTS(W) ;HUNG TRYING TO FORCE A SCHEDULE?
JRST UTIMR5 ;NO, MUST BE A REAL TAPE OPERATION
PUSHJ P,TAPSTM ;SET HUNG TIMER
MOVE T1,KDBDSP(W) ;TRY AGAIN
PUSHJ P,@TPKSCH(T1) ;BY REQUESTING ANOTHER INTERRUPT
JRST UTIMR6 ;FINISH UP
UTIMR5: PUSH P,U ;SAVE TUB ADDRESS
PUSH P,W ;AND KDB ADDRESS
HRRZ T1,DEVSER(F) ;UUO-LEVEL DISPATCH TABLE
PUSHJ P,DHNG(T1) ;CALL TAPUUO TO UNHANG THE DEVICE
PUSHJ P,DEVHNG## ;PRINT ERROR MESSAGE AND STOP JOB
POP P,W ;RESTORE TKB
POP P,U ;RESTORE TUB ADDRESS
UTIMR6: DDBSRU ;RESUME DDB SCANNING
POPJ P, ;RETURN
SUBTTL HUNG DEVICE
TAPHNG::TAPOFF ;WHO KNOWS WHAT EVIL...
MOVE W,TUBAKA(U) ;GET ACTIVE KDB ADDRESS
TLZ W,(1B0) ;CLEAR POSSIBLY INACTIVE BIT
MOVE T2,KDBDSP(W) ;CALL KON RESET ENTRY
MOVSI T1,TKSSTD
TDNN T1,TUBSTS(U) ;IF TAPE HAS BEEN STARTED
JRST TAPHN1
PUSHJ P,@TPKRES(T2) ; ...
MOVSI T1,(1B2)
IORM T1,TUBTRY(U) ;TELL DAEMON ITS A HUNG
HRRZ P1,TUBQUE(U) ;SETUP FOR TPEMOV
PUSHJ P,TPEMOV## ;PUT STATS IN DAEMON'S PART OF TUB
PUSHJ P,TPELOG## ;AND GO LOG IT
TAPHN1: MOVSI T1,TKSSTD!TUSREW ;CLEAR STARTED AND REWIND
ANDCAM T1,TUBSTS(U) ;IN UDB
TLC T1,TKSSCH^!TUSREW ;ALSO CLEAR SCH AND STARTED
ANDCAM T1,TKBSTS(W) ;IN KDB
IFN FTMP,<
MOVSI T1,TKSCHE ;SWEEP-NEEDED OR SWEEP-DONE
IOR T1,.CPCHX##
TDNE T1,TUBSTS(U) ;IF EITHER IS ON
SOS CPUTPQ ;DECREMENT NO OF OUTSTANDING QUEUED REQUESTS
ANDCAM T1,TUBSTS(U) ;AND CLEAR THE BITS IN THE TUB
> ;END IFN FTMP
CAIA ;PRUNE QUEUE, DESELECT,PION
TAPKIL::TAPOFF ;FIGHT RACE
MOVE W,TUBAKA(U) ;GET ACTIVE KDB ADDRESS
TLZ W,(1B0) ;CLEAR POSSIBLY INACTIVE BIT
HRRZ T1,TUBQUE(U) ;RETURN HEAD OF LIST
MOVSI T2,TUBQUE(U) ;RESET POINTERS
MOVEM T2,TUBQUE(U) ; ...
SETZM TUBERR(U) ;STOP ERROR RECOV
MOVSI T2,TUSNS ;CLEAR HOLD
ANDCAM T2,TUBSTS(U)
PUSH P,T1 ;SAVE PNTR
PUSHJ P,TPCSEL ;DESELECT IF NECESSARY
POP P,T1 ;RESTORE PNTR
PUSHJ P,TAPCTM ;CLEAR HUNG TIMER
PJRST TPONPJ ;TURN ON PI AND EXIT
SUBTTL HOLD/CONTINUE
;HERE TO SET NS BIT ON A UNIT
TAPHLD::MOVSI T1,TUSNS ;SET NO SCHEDULE
IORM T1,TUBSTS(U) ;...
IFN FTMP,<
PUSHJ P,CHKCPI##
JRST [MOVEI T1,1
HRRM T1,TKBSTS(W)
POPJ P,]
>
MOVSI T1,TKSSTD ;SEE IF STARTED
TDNE T1,TUBSTS(U) ;...
JRST [HLLZS TKBSTS(W) ;GRNTEE NO MORE
POPJ P,] ;RETURN
TPCSEL: MOVSI T1,TKSSEL ;SEE IF SELECTED
TDNN T1,TUBSTS(U)
POPJ P, ;NOT SELECTED - EXIT
PUSHJ P,TAPDSL ;YES - DESELECT
PJRST CKSIO1 ;CLANK SCHED IF NECESSARY
;ROUTINE CALLED TO ALLOW UNIT TO SCHEDULE AGAIN
TAPCNT::MOVSI T1,TUSNS
ANDCAM T1,TUBSTS(U) ;CLEAR NS BIT
PUSHJ P,TPMACC## ;KDB/UDB ACCESSIBILE?
SKIPA ;NO
JRST CKSIO2 ;WE CAN DO I/O OURSELVES
CKSIO1: JUMPE W,CPOPJ## ;IF NONE, PUNT
IFN FTMP,<
MOVE T1,KDBCAM(W) ;CPU ACCESSIBILITY MASK
PUSHJ P,CAMCPU## ;FIND ANY (HOPFULLY RUNNING) CPU
CAME T1,.CPCPN## ;IS IT US?
PJRST PCLTAP ;MUST QUEUE THE REQUEST
> ;END IFN FTMP
TLZ S,IOSCP2 ;MAKE SURE IOSCP2 IS OFF
CKSIO2: MOVSI T2,TKSSEL!TKSSCH!TKSOFL
SYSPIF
SKIPGE @KDBCHN(W) ;IS CHANNEL BUSY?
TDNE T2,TKBSTS(W) ; ARE ANY OF THESE ON?
JRST ONPOPJ## ;YES - SOMETHING WILL HAPPEN
MOVSI T2,TKSSCH ;SET SCHED REQUESTED
IORM T2,TKBSTS(W) ;...
AOS @KDBCHN(W) ;INDICATE CHANNEL IS BUSY
SYSPIN
PUSH P,U ;SAVE U
PUSHJ P,TAPSCH ;TRY TO START SOMETHING
JRST CKSIO3 ;NOTHING TO DO, RETURN FOR NOW
IFN FTMP,<
TLZE S,IOSCP2
JRST CKSIO4
>
PUSH P,F ;SAVE F
HRRZ T1,TUBQUE(U) ;CURRENT IORB
PUSHJ P,TPMSIO## ;CRANKUP THE I/O
MOVE U,-1(P) ;WHICH UDB WE WERE USING
PUSHJ P,TAPACC ;RESTORE KDB ADDRESS
JFCL ;IGNORE OFF-CPU RETURN
JRST FUPOPJ## ;RESTORE F,U,AND RETURN
CKSIO3: MOVE U,(P) ;RESTORE U
PUSHJ P,TAPACC ;AND KDB ADDRESS
JFCL ;IGNORE OFF-CPU RETURN
CKSIO4: SOS T1,@KDBCHN(W) ;INDICATE CHANNEL IS NOT BUSY
JRST TPOPJ## ;MAKE STACK RIGHT AND RETURN
;SUPPORT FOR THE TAPOFF MACRO
TAPLOK::CONO PI,PI.OFF ;TURN OFF THE PI SYSTEM WHILE TESTING
AOSE .CPTPN## ;BUMP LEVEL OF NESTING
JRST [CONO PI,PI.ON ;JUST NESTING, RETURN, ALREADY HAVE INTERLOCK
POPJ P,] ;...
CONI PI,.CPTPP## ;SAVE CHANNEL ENABLES
; CONO PI,PI.ON+TAPPIF## ;TURN PI SYSTEM ON LEAVING TAPCHN OFF
CONO PI,PI.ON+TPIOFF## ;TURN TAPCHN AND LOWER CHANNELS OFF
IFN FTMP,<
SKIPGE INTRTP## ;GIVE OTHER CPUS A CHANCE
AOSE INTRTP## ;WAIT FOR THE SYSTEM-WIDE INTERLOCK
JRST .-2 ;WAIT
APRID INTOTP## ;INFORM THE WORLD WHO OWNS THIS
>; END IFN FTMP
POPJ P, ;RETURN
;SUPPORT ROUTINE FOR THE TAPON MACRO
TAPULK::PUSH P,T1 ;SAVE A REGISTER
SOSL T1,.CPTPN## ;DECREMENT LEVEL OF NESTING, SEE IF DONE
PJRST TPOPJ## ;STILL NESTING, JUST RETURN
EXCH T1,.CPTPP## ;GET CHANNEL ENABLE STATES
ANDI T1,177 ;KEEP JUST THE CHANNELS WHICH WERE ON
TRO T1,PI.TNP ;TURN THEM BACK ON
EXCH T1,.CPTPP## ;RESTORE T1 AND SAVE ARGUMENT FOR CONO PI,
IFN FTMP,<
SETOM INTOTP## ;CLEAR INTERLOCK OWNER
EXCH T1,INTRTP## ;RESET THE INTERLOCK
SKIPGE T1 ;MAKE SURE IT WAS OWNED
STOPCD .,CPU,TIU, ;++ TAPE INTERLOCK UNOWNED
>; END IFN FTMP
CONO PI,@.CPTPP## ;PUT THE PI SYSTEM BACK THE WAY IT WAS
PJRST TPOPJ## ;RESTORE T1 AND RETURN
IFN FTMP,<
PCLTAP: HRRZ T1,TUBQUE(U) ;GET IORB ADDRESS
JUMPE T1,CPOPJ## ;NONE??????
MOVE T1,TRBFNC(T1) ;GET IORB FLAGS
TLNE T1,RB.PCL ;IS THIS A QUEUED REQUEST?
JRST PCLTP1 ;YES
PUSHJ P,TSLEE1## ;NO, LET THE NON-QUEUED STUFF FINISH
JRST CKSIO1 ; BEFORE GETTING INTO QUEUED REQUESTS
PCLTP1: MOVE T1,UDBCAM(U) ;GET ACCESSABILITY MASK
PUSHJ P,CPUOK## ;RETURN CDB OFFSET
JRST [PUSHJ P,HNGSTP## ;"PROBLEM ON DEVICE"
JRST PCLTAP] ;TRY AGAIN
IMULI T1,.CPLEN## ;GET CPU OFFSET
MOVE T2,.CPCHX## ;INDICATE WE NEED CACHE SWEEP
SYSPIF
IORM T2,TUBSTS(U) ;DONT SCHED UNIT TILL SWEEP
IORM T2,TKBSTS(W)
SKIPLE .CPTAP## ;COUNT UP A REQUEST
AOSA .CPTAP##
SOS .CPTAP## ; (.CPTAP COULD BE NEGATIVE)
SYSPIN
PJRST SETQP1## ;RING THE DOORBELL ON THE OWNING CPU
;SUBROUTINE TO GET JOB ONTO ANY CPU WHICH CAN ACCESS THE DEVICE
;CALL: MOVE U, UDB ADDRESS
; PUSHJ P,TAPCPU
TAPCPU::PUSHJ P,SAVT## ;SAVE SOME ACS
TAPCP1: PUSHJ P,TAPACC ;FIND CPU--KDB--UDB PATH
JUMPE W,TAPCP2 ;IF NO KDB, THEN HUNG DEVICE
HLRZS T1 ;ELSE GET ACCESSIBILE CPU NUMBER
PUSHJ P,ONCPUS## ;GET US ONTO THAT CPU
JRST TAPCP2 ;CPU DEAD??
POPJ P, ;RETURN
TAPCP2: PUSH P,F ;SAVE F
SKIPN F,TUBCUR(U) ;GET CURRENT DDB
MOVE F,UDBDDB(U) ;POINT AT USER IF NONE
PUSHJ P,HNGSTP## ;CALL IT A HUNG DEVICE
POP P,F ;RESTORE F
JRST TAPCP1 ;TRY AGAIN
> ;END IFN FTMP
;ROUTINE TO CHECK FOR KDB/UDB ACCESSIBILITY ON THE CURRENT CPU
;CALL: MOVE U, UDB ADDRESS
; PUSHJ P,TAPACC
; <NON-SKIP> ;KDB OR UDB INACCESSIBLE
; <SKIP> ;W POINTS TO THE KDB WHICH CAN DO I/O
;
;NOTE: THE NON-SKIP RETURN MIGHT BE TAKEN IF THE KONTROLLER IS OFFLINE
TAPACC::PUSHJ P,SAVE4## ;SAVE SOME ACS
SETZB P3,P4 ;CLEAR OFFLINE KDB AND BEST KDB
MOVSI P1,-1 ;ASSUME ACTIVE KDB
SKIPLE W,TUBAKA(U) ;GET THE KDB
JRST TAPAC2 ;ENTER LOOP WITH ACTIVE KDB SETUP
MOVSI P1,-MXPORT ;ELSE SCAN ALL DRIVE'S KDBS
XMOVEI P2,UDBKDB(U) ;POINT TO KDB TABLE IN UDB
TAPAC1: SKIPN W,(P2) ;GET A KDB
JRST TAPAC3 ;SLOT EMPTY
TAPAC2: MOVE T1,KDBCAM(W) ;GET ASSESSIBILITY BITS
TDNN T1,UDBCAM(U) ;CAN IT TALK TO THE DRIVE IN QUESTION?
JRST TAPAC3 ;NO, MUST TRY ANOTHER KDB
MOVSI T1,TKSOFL ;OFFLINE BIT
TDNE T1,TKBSTS(W) ;IS KONTROLLER OFFLINE?
JRST TAPAC3 ;YES, TRY ANOTHER KDB
IFE FTMP,<HRRZ T1,KDBCAM(W)> ;GET CPU0,,MASK
IFN FTMP,<
MOVE T1,KDBCAM(W) ;GET KONTROLLER'S CPU ACCESSIBILITY MASK
PUSHJ P,CPUOK## ;FIND A RUNNING CPU
JRST TAPAC3 ;CAN'T DO I/O FROM THIS KONTROLLER
HRLZS T1 ;PUT OWNING CPU IN LH
HRR T1,KDBCAM(W) ;GET CPU MASK
TDNN T1,.CPBIT## ;OUR CPU?
JRST TAPAC4 ;NO, KEEP LOOKING
> ;END IFN FTMP
JRST CPOPJ1## ;RETURN WITH USABLE KDB ADDRESS IN W
TAPAC3: SKIPN P3 ;ALREADY HAVE A KDB INCASE ALL OFFLINE?
MOVE P3,W ;NO, SAVE OFFLINE KDB ADDRESS
SKIPA ;THIS ONE'S NOT ONLINE
TAPAC4: MOVE P4,W ;SAVE BEST ONLINE KDB SO FAR
AOS P2 ;ADVANCE POINTER TO NEXT KDB SLOT
AOBJN P1,TAPAC1 ;LOOP BACK AND CHECK IT OUT
SKIPN W,P4 ;SEE IF WE FOUND AN ACCESSIBLE ONLINE KDB
JRST TAPAC5 ;THERE AREN'T ANY
IFE FTMP,<HRRZ T1,KDBCAM(W)> ;GET CPU0,,MASK
IFN FTMP,<
MOVE T1,KDBCAM(W) ;GET KONTROLLER'S CPU ACCESSIBILITY MASK
PUSHJ P,CAMCPU## ;TRANSLATE TO CPU NUMBER
TSO T1,KDBCAM(W) ;ALL IS WELL, PUT MASK IN LH
MOVSS T1 ;SET RETURNED VALUE TO CPU,,MASK
> ;END IFN FTMP
JRST CPOPJ1## ;RETURN GOODNESS
;HERE WHEN THERE ARE NO ONLINE KDBS
TAPAC5: SKIPE W,P3 ;GET OFFLINE KDB
POPJ P, ;TAKE "NO ACCESS" RETURN
MOVSI P1,-MXPORT ;AOBJN POINTER TO FIND ANY KDB
XMOVEI P2,UDBKDB(U) ;POINT TO KDB TABLE IN UDB
TAPAC6: SKIPE W,(P2) ;PICK ANY EXISTANT KONTROLLER
POPJ P, ;TAKE OFFLINE RETURN
AOS P2 ;ADVANCE PONTER
AOBJN P1,TAPAC6 ;LOOP 'TILL WE FIND ONE
POPJ P, ;RETURN
;ROUTINE TO RETURN AN ACCESSIBILITY MASK FOR A GIVEN DDB
;MUST PRESERVE T2, T3, & W!
TAPCPI::SETZ T1, ;JUST IN CASE
SKIPN TDVUDB##(F) ;CHECK FOR PROTOTYPE
POPJ P, ;IT IS
SE1ENT ;ENTER SECTION ONE
PUSH P,U ;SAVE U
PUSH P,T2 ;AND POSSIBLE BUFFER ADDRESS
PUSH P,W ;AND UUOCON'S SAVED IOACT
MOVE U,TDVUDB##(F) ;POINT TO UDB
PUSHJ P,TAPACC ;CAN WE GET TO IT?
JRST TAPPI1 ;NO
MOVE T1,KDBCAM(W) ;GET MASK
TDNE T1,.CPBIT## ;IF WE CAN USE IT,
AOS -3(P) ;SKIP
SKIPA ;RETURN THE MASK
TAPPI1: SETZ T1, ;NOT ACCESSIBLE
POP P,W ;RESTORE FOR UUOCON
POP P,T2 ;RESTORE POSSIBLE BUFFER ADDRESS
POP P,U ;RESTORE U
POPJ P, ;AND RETURN
SUBTTL QUEUE MANIPULATION
;HERE TO INSERT AN IORB AT THE HEAD OF A UNIT QUEUE
;U/ UDB, T1/ IORB
CPURQH::
IFN FTMP,<PUSHJ P,TAPCPU> ;GET ON THE RIGHT CPU
TAPRQH::MOVEI T2,RB.RPN ;SET IORB TO PENDING
DPB T2,PRBRQS ; ...
TAPOFF ;FIGHT RACE
HRRZ T2,TUBQUE(U) ;GET HEAD POINTER
HRRM T2,IRBLNK(T1) ;FORWARD LINK
HRRM T1,TUBQUE(U) ;NEW HEAD
MOVEM F,TUBCUR(U) ;POINT AT THE RIGHT CULPRIT
PUSHJ P,TAPCNT ;POSSIBLY SCHEDULE I/O
PJRST TPONPJ ;RESTORE INTS AND EXIT
;HERE TO INSERT AN IORB AT THE TAIL OF A UNIT QUEUE
;U/UDB, T1/IORB
CPURQT::
IFN FTMP,<PUSHJ P,TAPCPU> ;GET ON THE RIGHT CPU
TAPRQT::MOVEI T2,RB.RPN ;SET IORB AS PENDING
DPB T2,PRBRQS ; ...
TAPOFF ;FIGHT RACE
HLRZ T2,TUBQUE(U) ;GET TAIL POINTER
HRRM T1,IRBLNK(T2) ;FORWARD LINK AT OLD TAIL
HRLM T1,TUBQUE(U) ;NEW TAIL POINTER
CAIN T2,TUBQUE(U) ;IF FIRST IN Q,
MOVEM F,TUBCUR(U) ;TELL TPMSIO WHO WE ARE
PUSHJ P,TAPCNT ;POSSIBLY SCHEDULE I/O
PJRST TPONPJ ;RETURN
;HERE TO REMOVE THE IORB FROM THE HEAD OF A UNIT QUEUE
TAPREM::TAPOFF ;FIGHT RACE
HRRZ T1,TUBQUE(U) ;GET CURRENT HEAD
JUMPE T1,TPONPJ ;EXIT IF NONE
MOVE T2,IRBLNK(T1) ;FOLLOW FORWARD LINK
HRRM T2,TUBQUE(U) ;NEW HEAD POINTER
HLRZ T3,TUBQUE(U) ;CHECK IF QUEUE ONLY HAD ONE ELEMENT
CAIE T3,(T1) ;...
JRST TAPRM1 ;NO - LEAVE
MOVSI T2,TUBQUE(U) ;MAKE TAIL POINT TO QUEUE HEAD
MOVEM T2,TUBQUE(U) ; ...
SETZM TUBCUR(U) ;NO CURRENT DDB
JRST TPONPJ ;NO DDB TO FIND IF NO NEXT IORB
TAPRM1: SKIPE T3,TUBDDL(U) ;SEE IF HAVE A LABEL DDB
CAME T2,TDVIOR##(T3) ;IS THIS THE RIGHT DDB FOR THIS IORB?
MOVE T3,UDBDDB(U) ;NO, POINT AT USER
CAMN T2,TDVIOR##(T3) ;LAST CHANCE TO GET IT WRONG
MOVEM T3,TUBCUR(U) ;FOR TPMSIO TO FIND THE RIGHT JOB
TPONPJ: TAPON ;ALLOW INTS
POPJ P,
;HERE WHEN UPPER LEVEL DECIDES THAT A SELECTED IORB IS NOT TO
;BE INITIATED AFTER ALL
TAPFLS::PUSHJ P,TAPDSL ;FLUSH HDWRE
PUSHJ P,TAPREM ;AND PRUNE QUEUE
PUSHJ P,UUOLVL## ;IF NOT ON UUO LEVEL (DIAG)
POPJ P, ; RETURN WITHOUT STARTING ANYTHING
PUSH P,T1 ;SAVE T1
PUSHJ P,CKSIO1 ;SEE IF SCHED CYCLE NEEDED
MOVSI T1,TKSSEL
TDNN T1,TUBSTS(U) ;DID THIS UNIT GET SELECTED AGAIN?
TDON T1,TKBSTS(W) ;NO, DID SOME OTHER UNIT GET SEL'D?
JRST TPOPJ## ;NO, RETURN
TLNE T1,TKSSTD ;YES, WAS IT ACTUALLY STARTED?
JRST TPOPJ## ;YES, RETURN
PUSH P,U ;NO, SAVE U
MOVE U,@KDBCUN(W) ;SET U TO RIGHT UNIT
MOVSI T1,TKSSEL ;NO UNIT IS ACTUALLY STARTED
ANDCAM T1,TUBSTS(U) ; NOW
MOVSI T1,TKSSCH ;INDICATE WE'RE REQUESTING A SCHEDULE
IORM T1,TKBSTS(W) ;FOR THIS KONTROLLER
IFN FTMP,<
MOVEI T1,TKBICT## ;CALL BACK ROUTINE
MOVEM T1,TKBFCT(W) ;ENSURE TAPSCH FINDS IT
> ;END IFN FTMP
SETOM @KDBCHN(W) ;MARK CHANNEL AVAILABLE
MOVE T1,KDBDSP(W)
PUSHJ P,@TPKSCH(T1) ;GO CAUSE AN INTERRUPT ON THAT UNIT
POP P,U ;RESTORE U
JRST TPOPJ## ;RESTORE T1 AND EXIT
SUBTTL NOTIFY OPERATOR OF KONTROLLERS WITH DOWN-LEVEL MICROCODE
;HERE TO TYPE OUT MESSAGE FOR WRONG MICROCODE
;CALL WITH T1/ MICROCODE VERSION,,[ASCIZ PREFIX STRING]
;OR WITH T1/ -1,,[ASCIZ TEXT]
TAPREV::PUSHJ P,SAVT## ;SAVE ACS FOR OUR CALLERS
PUSHJ P,SAVE1## ;FREE UP A PRESERVED AC
MOVE P1,T1 ;COPY TEXT POINTER THERE
PUSHJ P,CTYERM## ;SET FOR ERROR MESSAGE TO CTY
PUSHJ P,INLMES## ;TYPE MESSAGE
ASCIZ /
%Tape controller / ;SAY WHAT DEVICE
MOVE T2,KDBNAM(W) ;GET KON NAME
PUSHJ P,PRNAME## ;TELL OPERATOR
PUSHJ P,INLMES## ;FINISH THIS LINE
ASCIZ / is below required microcode revision levels
% / ;AND FLAG THE NEXT LINE
HRRZ T1,P1 ;RETRIEVE CALLER'S TEXT POINTER
PUSHJ P,CONMES## ;TYPE THAT TOO
JUMPL P1,TAPRV1 ;JUMP IF VERSION NOT GIVEN
PUSHJ P,PRSPC## ;SPACE OVER FOR NUMBER
HLRZ T1,P1 ;GET REVISION NUMBER
PUSHJ P,PRTDI8## ;TYPE THE NUMBER (OCTAL)
TAPRV1: PJRST CRLF## ;TYPE THE CRLF AND RETURN
SUBTTL ERROR RECOVERY PROCEDURE.
;CALL HERE FROM TPMDON WHEN ERROR RECOVERY IS TO BE INITIATED
;SELECT MUST BE ON FOR KDB AND UDB. IORB IN T1.
TAPERP::MOVSI T1,(1B0) ;KDB IS NOT INVALID DURING ERROR PROCESSING
ANDCAM T1,TUBAKA(U) ;CLEAR FLAG
MOVEI T1,TKBERB(W) ;ENQUEUE ERP IORB
HLLOS TKBSTS(W) ;SET INFINITE QUANTUM
PUSHJ P,TAPRQH ;THIS IS CHEATING SLIGHTLY
MOVE T1,IRBLNK+TKBERB(W) ;RECOVER ORIGINAL IORB
LDB T2,PRBFCN ;GET FUNCTION CODE
LDB T3,ERYCNT ;GET INITIAL RETRY COUNT
DPB T3,TUYECT ;SET IN TUBERR
SETZM TUBTRY(U) ;CLEAR ATTEMPT COUNTER
PUSHJ P,ERPCMV ;CHECK IF TAPE MOVED
TDZA T4,T4 ;NO MOVE
MOVNI T4,1 ;MOVED - ADJUST POSITION
SKIPL ERCTAB(T2) ;WAS OP FORWARD MOTION?
MOVNS T4 ;NO - FIX COUNT
ADD T4,TUBREC(U) ;GET CORRECTED COUNT
JUMPL T4,[SETOM TUBPBE(U) ;IF NEG REC COUNT
JRST ERP0] ;THEN WE WON'T POS CHECK RIGHT
HRL T4,TUBFIL(U) ;ALSO COMPARE FILE POSITION
MOVEM T4,TUBPBE(U) ;STORE POSITION BEFORE ERROR
JRST ERP0 ;START ERP
;HERE ON AN INTERRUPT WHILE THE ERP IS RUNNING
ERPINT: CAIE T1,TKBERB(W) ;BE REAL SURE ALL IS WELL
STOPCD .,STOP,ERF, ;++ERP REALLY FOULED UP
HRRZ T2,TUBERR(U) ;GET DISPATCH ADDR
SKIPE T2 ;CODE ZERO IS ILLEGAL
CAIL T2,XERPMX ;SMALLER THAN MAX?
STOPCD .,STOP,RFU, ;++RECOVERY FOULED UP
MOVE F,TUBCUR(U) ;SET UP F AND S
MOVE S,DEVIOS(F)
JRST @ERPSTB(T2) ;THE LEAP OF FAITH
;HERE TO SEE IF ANYTHING OFFENSIVE HAS HAPPENED TO
;THE IORB IN T1
ANYERR: SKIPL TRBFNC(T1) ;IS EXCEPTION UP?
POPJ P, ;NO - ALL IS WELL.
MOVE T2,TRBSTS(T1) ;GET STATUS WORD
TLNN T2,RB.SER!RB.SED!RB.SLK!RB.SOL!RB.STL ;...
POPJ P, ;NOTHING TO OFFEND
JRST CPOPJ1## ;LOSE
;HERE TO COPY NEEDED THINGS TO THE ERP IORB
SETERB: MOVE T1,TKBERB+IRBLNK(W) ;GET OLD IORB
MOVE T3,TRBFNC(T1) ;GET MODE ETC
TLZ T3,RB.EXC ;CLEAR EXCEPTION BIT
MOVEM T3,TKBERB+TRBFNC(W)
XMOVEI T3,TKBERB+IRBCCW(W) ;ERP BASE ADDR OF CCW LIST
MOVEM T3,TKBERB+IRBACC(W) ;SAVE TEMPORARILY
MOVEI T3,IRBCCW(T1) ;IORB BASE ADDR OF CCW LIST
SUB T3,IRBACC(T1) ;COMPUTE OFFSET INTO LIST
IFN FTXMON,<HRRZS T3> ;AVOID XADDR DISASTER
ADDM T3,TKBERB+IRBACC(W) ;RELOCATE ERP CCW POINTER
MOVSI T3,IRBCCW(T1) ;POINT TO ADDRS OF CCWS
HRRI T3,TKBERB+IRBCCW(W) ;AND TO DESTINATION
BLT T3,TKBERB+IRBCCW+MXPORT-1(W) ;COPY
MOVE T3,TRBRCT(T1) ;COPY WORD COUNT
MOVEM T3,TRBRCT+TKBERB(W)
POPJ P,
;HERE TO SETUP ERP IORB FOR A NON DATA XFR OP
STERBS: PUSHJ P,SETERB ;SETUP ERB
MOVEI T1,1 ;SET OP COUNT
MOVEM T1,@TKBERB+IRBACC(W) ;SET OP COUNT
XMOVEI T1,TKBERB(W) ;ERR REC IORB
POPJ P,
;HERE TO CLEAN UP WHEN LEAVING THE ERP FOR THE LAST TIME
ERPDON: MOVE T2,IRBLNK+TKBERB(W) ;PNTR TO ACTUAL IORB
MOVE T3,TRBRCT+TKBERB(W) ;LAST BYTE COUNT
MOVEM T3,TRBRCT(T2) ;INTO IORB
PUSHJ P,TAPREM ;REMOVE ERP IORB
MOVE T2,TUBERR(U) ;SAVE STATE WORD AT TERMINATION
MOVEM T2,TUBFES(U) ;AS FINAL ERROR STATE
SETZM TUBERR(U) ;CLEAR STATE INFO
HLLZS TKBSTS(W) ;CLEAR CHANNEL QUANTUM
POPJ P,
;ERP ACTION 0 - REPOSITION IF NEEDED. IORB IN T1
;FCN CODE IN T2
ERP0: PUSHJ P,ERPCMV ;CHECK MOVEMENT
JRST ERP2 ;NO - NO NEED TO REPOSITION
MOVSI T3,(ERCRPS) ;SHOULD REPOSITIONING BE DONE?
TDNN T3,ERCTAB(T2) ; ...
JRST ERP2 ;NO - GO RETRY
PUSHJ P,STERBS ;YES - SETUP ERP IORB
MOVEI T4,RB.FBR ;ASSUME FORWARD MOTION, REPOS W/ BS
SKIPL ERCTAB(T2) ;WAS OP FORWARD MOTION?
MOVEI T4,RB.FSR ;NO-REPOS WITH FWD SPACE
DPB T4,PRBFCN ;STORE FUNCTION CODE
MOVEI T2,XERP1 ;SET NEXT STATE
;HERE TO EXIT AND START IO ON ERP IORB
ERPX0: HRRM T2,TUBERR(U) ;STORE NEXT STATE
MOVEI T1,TKBERB(W) ;GET ERP IORB
PUSHJ P,TAPSIO ;GO INITIATE OP
SETZ T1, ;RETURN ZERO
POPJ P,
;HERE AT TERMINATION OF A REPOSITION
ERP1: MOVSI T2,RB.SNM!RB.SOL ;MOVED OR OFF-LINE?
TDNN T2,TRBSTS(T1)
JRST ERP1A ;SEE IF SPECIAL ACTION
;HERE WHEN RECOVERY HAS FAILED
ERP4: MOVE T3,IRBLNK+TKBERB(W) ;ORIG IORB
MOVSI T2,RB.SOL ;OFFLINE BIT
TDNE T2,TRBSTS(T1) ;CHECK STATUS
IORM T2,TRBSTS(T3) ;COPY BIT TO ORIG. IORB
PUSHJ P,ERPDON ;CLEAN UP
HRRZ T1,TUBQUE(U) ;GET FORMER IORB
MOVSI T2,RB.SER ;FLAG NON REC ERROR
IORM T2,TRBSTS(T1) ;IN IORB
POPJ P, ;RETURN FAILING IORB
;SEE IF THE LAST OP SHOULD BE ERASED.
ERP1A: MOVE T1,IRBLNK+TKBERB(W) ;GET ORIGINAL OP
LDB T2,PRBFCN ; ...
CAIE T2,RB.FWT ;WRITE?
CAIN T2,RB.FTM ;OR WRITE TAPE MARK?
JRST ERP5 ;YES
JRST ERP2 ;NO - DO RETRY NOW.
;MORE ERROR RECOVERY PROCEDURE
;HERE TO RETRY A FAILING OPERATION. THE TAPE HAS BEEN
;REPOSITIONED IF NECESSARY
ERP2: MOVE T3,TUBPBE(U) ;GET POSITION BEFORE ERROR
JUMPL T3,ERP2A ;SKIP CHECK IF NEG.
MOVE T2,TUBREC(U) ;CHECK THAT REPOSITIONING
HRL T2,TUBFIL(U) ;HAS BROUGHT US
CAME T2,T3 ;BACK TO BEFORE THE ERROR
JRST ERP4
ERP2A: PUSHJ P,SETERB ;COPY NEEDED GOODIES
MOVE T1,IRBLNK+TKBERB(W) ;GET OLD IORB
LDB T2,PRBFCN ;GET FUNCTION
LDB T3,ERYFCN ;GET FUNCTION TO RETRY
MOVEI T1,TKBERB(W) ;GET ERP IORB
DPB T3,PRBFCN ;STORE NEW OP.
AOS TUBTRY(U) ;INCREMENT ATTEMPT COUNT
MOVEI T2,XERP3 ;SET NEXT STATE
JRST ERPX0
;HERE ON THE TERMINATION OF A RETRY OPERATION
ERP3: PUSHJ P,ANYERR ;ANY ERRORS TO SPEAK OF?
JRST ERP3B ;NO - WIN WIN WIN
MOVSI T2,RB.SOL!RB.SER ;OFFLINE OR NON-RECOVERABLE
TDNE T2,TRBSTS(T1) ;???
JRST ERP4 ;YES - LOSAGE
LDB T2,TUYECT ;GET RETRY COUNTER
SUBI T2,1 ;DECREMENT
JUMPLE T2,ERP4 ;SIGH - LOSE
DPB T2,TUYECT ;RESTORE COUNT
MOVSI T1,NXTLSE ;GET NEXT TO LAST RETRY BIT
ANDCAM T1,TUBERR(U) ;CLEAR IT
CAIN T2,2 ;IS THIS NEXT TO LAST RETRY?
IORM T1,TUBERR(U) ;YES--THEN SET IT
MOVE T1,IRBLNK+TKBERB(W) ;GET OLD IORB
LDB T2,PRBFCN ;GET FUNCTION
MOVE T4,TUBTRY(U) ;RE-TRY COUNTER
MOVSI T3,(ERCTCS) ;THIS OP USE TCS?
TDNE T3,ERCTAB(T2) ;??
TRNE T4,3 ;TCS EVERY 4 RE-TRIES
JRST ERP3A ;NO TCS NOW
JRST ERP7 ;TCS TIME NOW
;HERE TO PERFORM REPOS/RETRY
ERP3A: MOVEI T1,TKBERB(W) ;SET UP ERROR IORB
LDB T2,PRBFCN ;AND FUNCTION
JRST ERP0 ;AND TRY THE WHOLE THING AGAIN
;HERE WHEN THE ERROR IS RECOVERED. THE WORLD IS AMAZED.
ERP3B: MOVSI T2,RB.SNM ;CHECK MOVEMENT
TDNE T2,TRBSTS(T1) ;DID IT?
JRST ERP3C ;NO - TRY AGAIN
PUSHJ P,ERPDON ;GO CLEAN UP
HRRZ T1,TUBQUE(U) ;GET OLD IORB
MOVSI T2,RB.SRE ;RECOVERY SUCCEEDED
IORM T2,TRBSTS(T1) ;SET IN IORB
POPJ P, ;RETURN AND REJOICE
;HERE WHEN RETRY DIDN'T MOVE TAPE TRY AGAIN
ERP3C: LDB T2,TUYECT ;GET COUNTER
SUBI T2,1 ;DECREMENT
JUMPLE T2,ERP4 ;ALL THROUGH IF ZERO
DPB T2,TUYECT ;PUT COUNT BACK
JRST ERP2 ;AND RETRY OP
;HERE TO DO AN ERG BEFORE RETRY
ERP5: PUSHJ P,STERBS ;SETUP ERB
MOVEI T2,RB.FLG ;GET ERG FUNCTION
DPB T2,PRBFCN ;STORE IN ERP IORB
MOVEI T2,XERP6 ;NEXT STATE
JRST ERPX0 ;EXIT AND SET STATE
;HERE AT THE TERMINATION OF AN OP BEFORE RETRY.
ERP6: PUSHJ P,ANYERR ;ERRORS?
JRST ERP2 ;NO - DO RETRY
JRST ERP4 ;YES - FAIL
;ERROR RECOVERY TAPE CLEANER SEQUENCE (TCS)
;FCN CODE IN T2
;HERE TO STARTUP TCS
ERP7: MOVEI T1,TKBERB(W) ;GET RETRY IORB
MOVSI T3,RB.SBT!RB.SAP ;AT BOT OR ALREADY REPOSITIONED?
TDNE T3,TRBSTS(T1) ; ???
JRST ERP3A ;YES - NO TCS
MOVEI T4,ERPNCS ;NUMBER OF SPACE OPS IN TCS
SKIPL ERCTAB(T2) ;WAS OP FORWARD MOTION?
SUBI T4,1 ;NO - USE ONE LESS BACKSPACE
DPB T4,TUYEC1 ;STORE IN SECONDARY COUNTER
;HERE TO DO A BACKSPACE AS PART OF A TAPE CLEANER SEQ
ERP8: PUSHJ P,STERBS ;SETUP IORB
MOVEI T2,RB.FBR ;BACKSPACE FUNCTION
DPB T2,PRBFCN ;STORE
MOVEI T2,XERP9 ;NEXT STATE
JRST ERPX0 ;LEAVE
;HERE WHEN A TCS BACKSPACE HAS COMPLETED
ERP9: LDB T2,TUYEC1 ;GET COUNT
SOSL T2 ;DECREMENT
DPB T2,TUYEC1 ;SAVE NEW VALUE
HLRZ T3,TRBSTS(T1) ;GET STATUS
TRNE T3,RB.SBT ;DONE?
JRST ERP9B ;YES - RECOMPUTE SPACE COUNT
TRNE T3,RB.SNM ;DID IT MOVE AT ALL
JRST ERP4 ;NO -******SHOULD FIX POSITION****
JUMPG T2,ERP8 ;TRY AGAIN IF STILL MORE TO GO
MOVEI T4,ERPNCS-1 ;NUMBER OF SPACE OPS
JRST ERP9C
ERP9B: MOVEI T4,ERPNCS-2 ;COMPUTE NUMBER OF SPACE OPS
LDB T2,TUYEC1 ; ...
SUB T4,T2 ; ...
ERP9C: MOVE T1,IRBLNK+TKBERB(W) ;GET ORIG IORB
LDB T2,PRBFCN ;ORIG FCN
MOVEI T1,TKBERB(W) ;RESTORE ERROR IORB
SKIPL ERCTAB(T2) ;WAS OP FORWARD MOTION?
ADDI T4,1 ;NO - ONE MORE THEN
DPB T4,TUYEC1 ;STORE COUNT
JUMPLE T4,ERP2 ;NONE - GO TRY AGAIN
;FALL THROUGH INTO ERP10.
;FALL THROUGH HERE FROM ERP9C.
;HERE TO DO A SPACE RECORD AS PART OF A TCS
ERP10: PUSHJ P,STERBS ;SETUP IORB
MOVEI T2,RB.FSR ;SPACE OP
DPB T2,PRBFCN ;STORE
MOVEI T2,XERP11 ;NEXT STATE
JRST ERPX0 ;START IO AND EXIT
;HERE ON THE TERMINATION OF A TCS SPACE OP
ERP11: HLRZ T2,TRBSTS(T1) ;GET STATUS
TRNE T2,RB.SNM ;MOVED?
JRST ERP4 ;NO ****SHOULD FIX POSN****
LDB T2,TUYEC1 ;GET COUNT
SUBI T2,1 ;DECREMENT
DPB T2,TUYEC1 ;RESTORE
JUMPLE T2,ERP2 ;CONTINUE RETRY
JRST ERP10 ;MORE SPACES TO DO
;TABLE RELATING STATE CODES TO ROUTINE ADDRS.
ERPSTB: PHASE 0
XWD 0,-1 ;ILLEGAL
XERP1:! IFIW ERP1 ;REPOSITION TERMINATION
XERP3:! IFIW ERP3 ;RETRY TERMINATION
XERP6:! IFIW ERP6 ;ERASE GAP TERMINATION
XERP9:! IFIW ERP9 ;TCS BACKSPACE TERMINATION
XERP11:!IFIW ERP11 ;TCS SPACE TERMINATION
XERPMX:! ;HIGHEST STATE
DEPHASE
;TABLE USED TO GUIDE THE ERROR RECOVERY PROCEDURE
;BITS
ERCFWD==1B0 ;OPERATION MOVES TAPE FOREWARD
ERCRPS==1B1 ;OPERATION NEEDS REPOSITION BEFORE RETRY
ERCCSZ==1B2 ;THIS OP IGNORE "NOISE" RECORDS
ERCTCS==1B3 ;THIS OP USES TCS
;BYTES AND BYTE POINTERS
ERCCTP==^D17 ;INITIAL RETRY COUNT POSITION
ERCCTS==6 ;INITIAL RETRY COUNT SIZE
ERYCNT: POINT ERCCTS,ERCTAB(T2),ERCCTP
ERCFNP==^D35 ;RETRY FUNCTION POSITION
ERCFNS==5 ;RETRY FUNCTION SIZE
ERYFCN: POINT ERCFNS,ERCTAB(T2),ERCFNP
;MACRO TO BUILD ERCTAB ENTRY
DEFINE X(FLGS,CNT,FCN) <
EXP FLGS+<CNT>B<ERCCTP>+<FCN>B<ERCFNP>
>
;THE TABLE
ERCTAB: EXP -1 ;ILLEGAL
X(ERCFWD+ERCRPS+ERCCSZ+ERCTCS,^D40,RB.FCR) ;READ FORWARD
X(ERCFWD+ERCRPS,^D14,RB.FWT) ;WRITE
X(ERCRPS+ERCCSZ+ERCTCS,^D40,RB.FRB) ;READ BACKWARDS
X(ERCFWD+ERCRPS,6,RB.FSR) ;SKIP RECORD
X(ERCRPS,6,RB.FBR) ;BACKSPACE RECORD
X(ERCFWD+ERCRPS,6,RB.FSF) ;SKIP FILE
X(ERCRPS,6,RB.FBF) ;BACKSPACE FILE
X(ERCFWD,6,RB.FLG) ;ERASE GAP
X(ERCFWD,6,RB.FSE) ;DATA SECURITY ERASE
X(0,6,RB.FRW) ;REWIND
X(0,6,RB.FRU) ;REWIND AND UNLOAD
X(ERCFWD+ERCRPS,^D14,RB.FTM) ;TAPE MARK
X(ERCFWD,1,RB.FYB) ;YELLOW BALL
X(ERCFWD+ERCRPS+ERCCSZ,6,RB.FCR) ;CORRECTION READ (ONLY IF USER REQD)
X(ERCFWD+ERCRPS+ERCCSZ+ERCTCS,^D40,RB.FCR) ;READ LOW THRESHOLD
;ROUTINE CHECK IF TAPE MOVED OR ERROR ON NOISE RECORD
;CALL: MOVE T1,IORB
; MOVE T2,FCN
; PUSHJ P,ERPCMV
; RETURN IF NO MOVEMENT
; RETURN IF MOVEMENT
ERPCMV: MOVE T4,TRBRCT(T1) ;GET BYTE COUNT
MOVSI T3,(ERCCSZ) ;SIZE CHECK?
TDNN T3,ERCTAB(T2) ;...
JRST ERPCM1 ;NO - PROCEED
CAIGE T4,NOISE## ;IS THIS A NOISE RECORD
JUMPGE T4,CPOPJ## ;NOISE IF NOT AN IOWD - DIDN'T MOVE
ERPCM1: MOVSI T3,RB.SNM!RB.SAP ;NO - CHECK PHYSICAL MOVEMENT
TDNN T3,TRBSTS(T1) ;...
AOS 0(P) ;OK
POPJ P, ;RETURN
SUBTTL COMMON ROUTINES
;ROUTINES COMMON TO ALL KONTROLLER DEPENDENT CODE
;HERE ON REWIND DONE
REWDON::MOVSI T2,TUSREW!TUSFLT ;NO LONGER REWINDING
ANDCAM T2,TUBSTS(U) ;...
UNIBOT::MOVSI T2,TUSBOT ;ALSO NOW AT BOT
IORM T2,TUBSTS(U) ; ...
SETZM TUBREC(U) ; ...
SETZM TUBFIL(U) ; ...
PJRST TAPCTM ;CLEAR HUNG TIMER AND RETURN
;HERE TO VERIFY THAT TUBQUE POINTS TO A REASONABLE IORB
CHKIRB::HRRZ T1,TUBQUE(U) ;GET HEAD IORB
JUMPE T1,CPOPJ## ;EXIT IF NOT REQUEST BLOCK
LDB T2,PRBRQS ;GET REQUEST STATUS
CAIN T2,RB.ACT ;ACTIVE?
AOS (P) ;YES - GIVE GOOD RETURN
POPJ P,
;ROUTINE TO HANDLE SPURIOUS INTERRUPTS
TAPDIS::MOVE T1,KDBDSP(W) ;GET DISPATCH
PUSHJ P,@TPKIDL(T1) ;SET CTRL IDLE (USER WILL GET HUNG DEVICE)
MOVSI T2,TKSSCH ;TEST SCHED REG. BIT
MOVEI T1,0 ;ASSUME IGNORE INT.
TDNE T2,TKBSTS(W) ;WANT SCHED. CYCLE?
MOVNI T1,1 ;YES- INFORM WORLD
POPJ P, ; AND EXIT
;ROUTINE TO SET UP U TO POINT TO UDB MENTIONED IN T2
;C(T2) = UNIT # , C(W) = KDB ADDRS
;NON-SKIP RETURN IF NON-EX UNIT
;SKIP RETURN IF UNIT IS OK
SETUDB::MOVE U,KDBIUN(W) ;POINTER TO UDB TABLE
ADD U,T2 ;PLUS OFFSET
SKIPN U,0(U) ;SEE IF ONE EXISTS
POPJ P,
PJRST CPOPJ1##
;TABLE USED TO CONVERT IORB MODE TO CHARS/WORD
TMODTB::0 ;0 - ILLEGAL
5 ;1 - 9-TK CORE DUMP
4 ;2 - 9-TK INDUSTRY COMPAT.
6 ;3 - TU70 SIXBIT
5 ;4 - TU70 MARVELOUS ASCII
6 ;5 - 7-TK CORE DUMP
;TABLE TO CONVERT IORB MODE TO FRAME SIZE
TMODFS::0 ;0 - ILLEGAL
0 ;1 - CORE DUMP (N/A)
8 ;2 - 9 TK INDUSTRY COMPATIBLE
6 ;3 - SIXBIT
7 ;4 - ASCII
0 ;5 - 7 TK CORE DUMP (N/A)
LIT
$LOW
IFN FTMP,<
CPUTPQ::BLOCK 1 ;COUNT OF CPUS WAITING FOR SWEEP
>
TPSEND: END