Trailing-Edge
-
PDP-10 Archives
-
bb-bt99q-bb
-
filio.x23
There is 1 other file named filio.x23 in the archive. Click here to see a list.
TITLE FILIO LEVEL-D DISK SERVICE ROUTINE V1350
SUBTTL DESIGNED BY T.HASTINGS,T.WACHS,C.WHITE CODED BY T.WACHS/TW 02-MAY-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
; 1973,1974,1975,1976,1977,1978,1979,1980,1982,1984,1986,1988.
;ALL RIGHTS RESERVED.
.CPYRT<1973,1988>
XP VFILIO,1350
;ASSEMBLY INSTRUCTIONS: FILIO,FILIO/C_S,FT50S,FILIO
ENTRY FILIO
FILIO::
;ASSEMBLY PARAMETER FOR FNDFIL INTERLOCK
;BITS IN THE ACCESS TABLE STATUS WORD
ACPCRE==:40
ACPSUP==:20
ACPUPD==:10
ACPREN==:200
ACRSUP==:2
ACPNIU==:400000
ACMCNT==:377400
ACPSMU==:4
IOSMON==400000 ;THIS FILE IS CURRENTLY DOING MONITOR IO
IOSAU==200000 ;THIS FILE HAS THE ALTER-UFD RESOURCE
IOSUPR==:100000 ;SUPER USETI/USETO DONE ON THIS CHAN
IOSDA==40000 ;THIS FIL HAS DISK ALLOCATION QUEUE
IOSRIB==20000 ;RIB IS IN MONITOR BUFFER
IOSRDC==10000 ;THIS USER CHANNEL HAS READ COUNT UP FOR FILE
IOSWLK==4000 ;FILE (WHOLE STR) IS SOFTWARE WRITE-=LOCKED
; EITHER FOR ALL JOBS OR FOR THIS JOB ONLY
IOSPBF==2000 ;PARTIAL BUFFER DONE
IOSFIR==1000 ;COMPUTE AND STORE OR CHECK THE CHECKSUM
;XXX==IOBEG ;(UNUSED)
IOSRST==IOFST ;RESET (RELEASE) WAS DONE ON A SPOOLED DEVICE
;THE FOLLOWING S BITS ARE DEFINED IN COMMON.MOD
;BECAUSE THEY WANT TO BE IN THE SAME POSITION IN S AS IN RIB STATUS WORD
;IOSHRE=100 ;HARD READ ERROR ENCOUNTERED
;IOSHWE=200 ;HARD WRITE ERROR ENCOUNTERED
;IOSSCE=400 ;SOFTWARE CHECKSUM ERROR ENCOUNTERED OR HARD POSITIONING ERROR
;IOSERR=IOSHRE+IOSHWE+IOSSCE
;IOSMER=-IOSERR
DEFINE NOSCHEDULE <>
DEFINE SCHEDULE <>
DEFINE CBDBUG<>
REPEAT 0,<
NOTE ABOUT STATES OF CHANNELS, KONTROLLERS, UNITS, FILES:
C K U F
IDLE I I I I I
SEEK WAIT SW SW
SEEK S S
POSITION WAIT PW PW PW
POSITION P P P
TRANSFER WAIT TW TW TW
TRANSFER(BUSY) T OR B B B T T
NOTE ABOUT QUEUES:
THERE ARE 2 QUEUES OF FILES
SW/PW QUEUE FOR EACH UNIT
TW QUEUE FOR CHANNEL
A FILE IS ONE AND ONLY ONE OF THE FOLLOWING CONDITIONS:WITH RESPECT TO QUEUES
A.THE ONLY FILE IN SW/PW QUEUE FOR A UNIT (UNIT IN SW STATE)
B.ONE OF PERHAPS MANY FILES IN PW QUEUE FOR A UNIT(UNIT IN PW,P,TW,OR T STATE)
C.ONE OF PERHAPS MANY IN TW QUEUE FOR CHANNEL(CHAN AND KONTROL IN B STATE)
D.NONE OF THE ABOVE (FILE IN I,P, OR T STATE)
NOTE: #MEANS INSTRUCTION IS EXECUTED WITH ALL DISK PI CHANNELS OFF
%MEANS INSTRUCTION IS EXECUTED WHILE .CPJOB## HAS CB RESOURCE
*MEANS INSTRUCTION MAY BE EXECUTED AT INTERRUPT LEVEL
(TO SAVE TYPING USED ONLY FOR INSTRUCTIONS NOT IN INTERRUPT MODULE ITSELF)
THE FOLLOWING TECO MACRO WILL PRODUCE A LISTING OF ONLY THE SUBROUTINE
NAMES AND COMMENTS PRIOR TO THEM:
ERDEV1:FILSER.MAC$EWDEV2:FILSER.SUB$
<_;SUBROUT$;0L.U1 !NTST! :S:$"GA ONTST$'.U20L1A-59"E LONTST$' Q2JI
$Q1,.PW 0,.K>EF
>
SUBTTL ALLOCATION/DEALLOCATION
CLASIZ==:^D23
TALSIZ==:^D36-CLASIZ
CLAPOS==:^D35
TALPOS==:^D35-CLASIZ
CLAMAX==1B<TALPOS>-1 ;MAX CLUSTER ADDR. (BYTE OF ALL 1'S)
DSKSCN==100000 ;SCANNING SATS FROM DISK
STRTAD==200000 ;ALLOCATE STARTING AT A SPECIFIED LOCATION
RELABP==40000 ;AOBJN POINTER MUST BE RELOCATED BY (R)
SATCHG==400000 ;SAT TABLE IN CORE DIFFERS FROM SAT TABLE ON DISK (SIGN BIT)
;SUBROUTINE TO GET A CHUNK OF BLOCKS (ANYWHERE IN STR)
;ENTER WITH T2=HOW MANY TO GET, U=PREFERRED UNIT
;EXIT CPOPJ1 IF GOT ALL (OR SOME) ON DESIRED UNIT
;EXIT CPOPJ IF GOT ALL (OR SOME) ON A DIFFERENT UNIT, WITH T3=UNIT-CHANGE POINTER
;EXIT CPOPJ WITH T3=0 IF GOT NONE (STR FULL).
;THIS ROUTINE GETS EITHER ALL, OR THE LARGEST AVAILABLE CHUNK IN STR
;RETURNS WITH T2=RETRIEVAL POINTER, T1=NUMBER OF BLOCKS OBTAINED
TAKCHK::PUSHJ P,SAVE2## ;SAVE P1,P2
MOVE P1,U ;FOR END-TEST
SETZ P2, ;INDICATE NO BEST UNIT YET
HRRZS T2 ;WANT EXACTLY C(T2) BLOCKS
;THE ABOVE INSTRUCTION WAS CHANGED FROM HRROS SINCE, WHEN THE DISKS GET FULL,
; THIS LOOP CONSUMES LOTS OF TIME. EVENTUALLY, WE WILL CHANGE IT SO THAT
; THE LARGEST HOLE IN A SAT GETS STORED IN CORE, AT WHICH POINT THIS
; WILL GO BACK THE WAY IT WAS
TAKCH1: SETZ T1, ;WANT THEM ANYWHERE ON UNIT
PUSHJ P,TAKBLK ;TRY TO GET THE BLOCKS
JRST TAKCH2 ;CANT GET THAT MANY ON THIS UNIT
CAIN U,(P1) ;GOT ALL WE ASKED FOR. SAME UNIT?
PJRST CPOPJ1## ;YES - SKIP RETURN
LDB T3,UNYLUN## ;NO. GET LOG. UNIT NO.
TRO T3,RIPNUB## ;MAKE A UNIT-CHANGE POINTER
POPJ P, ;AND NON-SKIP RETURN
;HERE ON NOT-AVAILABLE RETURN FROM TAKBLK
TAKCH2: CAIG T2,(P2) ;THIS UNIT BEST SO FAR?
JRST TAKCH3 ;NO
MOVE P2,T2 ;YES. SAVE SIZE OF LARGEST HOLE
HRL P2,U ;SAVE UNIT OF LARGEST HOLE
TAKCH3: HLRZ U,UNISTR(U) ;STEP TO NEXT UNIT IN STR
JUMPN U,TAKCH4 ;END OF STR CHAIN?
HRRZ U,UNISTR(P1) ;YES, STR DATA BLOCK LOC
HLRZ U,STRUNI##(U) ;1ST UNIT IN STR
TAKCH4: HRRZ T2,T1 ;RESTORE NUMBER OF BLOCKS TO GET
CAIE U,(P1) ;BACK WHERE WE STARTED?
JRST TAKCH1 ;NO, TRY THIS UNIT
JUMPE P2,CPOPJ## ;RETURN IF STR IS FULL
HLRZ U,P2 ;NOT FULL - SET BEST UNIT
HRRZ T2,P2 ;LARGEST CONTIGUOUS CHUNK AVAILABLE
JRST TAKCH1 ;GO SETTLE FOR LARGEST HOLE
;ROUTINE TO ALLOCATE BLOCKS FROM DISK
;ENTER WITH T1= WHERE TO START (OR 0 IF DONT CARE)
;T2= HOW MANY TO ALLOCATE
;LH(T2)=0 IF TAKE N OR LESS
;LH(T2)=-1 IF TAKE EXACTLY N
;RETURNS CPOPJ IF UNSUCCESSFUL WITH T2=LARGEST HOLE FOUND, T1= ORIGINAL T2, T3=0
;RETURNS CPOPJ1 IF OK, WITH T1= NUMBER OF BLOCKS TAKEN T2 = CLUSTER POINTER FOR GROUP
;T3 POINTS TO FILE STRUCTURE DATA BLOCK
TAKBLK::PUSHJ P,SAVE4## ;SAVE P1-P4
SE1ENT ;ENTER SECTION 1
PUSH P,W ;SAVE W
HLL W,T2 ;SAVE LH(T2) (=-1 IF EXACTLY N BLOCKS)
HRRZS T2 ;SET T2=POSITIVE NUMBER
SKIPN T2 ;MORE THAN 18 BITS WORTH?
MOVEI T2,-1 ;YES, ASK FOR MAX
SKIPN DINITF## ;IN ONCE-ONLY (REFRESHER)?
CAMG T2,UNITAL(U) ;NO, REQUESTING MORE THAN ARE AVAILABLE?
JRST TAKBL ;NO. GET SOME BLOCKS
MOVE T3,T2 ;YES. AMONT TO GET INTO T3
SKIPLE T2,UNITAL(U) ;ANY BLOCKS AT ALL?
JUMPGE W,TAKBL ;YES. REQUEST MAXIMUM OF UNITAL BLOCKS
MOVEI T2,0
TLNE F,OCLOSB ;NO. IS CLOSE HAPENING?
AOJA T2,TAKBL ;YES. TRY TO GET 1 BLOCK ANYWAY
;(THERE ARE BLOCKS IN SAT TABLES WHICH ARE NOT IN UNITAL, AND ARE ONLY
;GIVEN UP DURING A CLOSE UUO)
MOVE T1,T3 ;NOT CLOSE. INDICATE 0 SPACE FOUND
JRST TAKBLT ;AND TAKE ERROR RETURN
TAKBL: LDB T4,UNYBPC## ;NUMBER OF BLOCKS PER CLUSTER
HRRZ P3,T2 ;DESIRED NUMBER OF BLOCKS
ADDI P3,-1(T4) ;CONVERT TO NUMBER OF CLUSTERS
IDIV P3,T4
HRRZ P4,T2 ;SAVE DESIRED NUMBER OF BLOCKS A MOMENT
HRRZ T3,UNISTR(U)
SETO T2, ;COMPUTE LARGEST ALLOWED GROUP SIZE
LDB T2,STYCNP##(T3) ;LARGEST FIELD
CAIL T2,(P3) ;ASKING FOR TOO MUCH?
JRST TAKBL0 ;NO
SKIPE DINITF## ;IN ONCE-ONLY (REFRESHER)?
CAIE P4,-1 ;YES, DON'T REDUCE ALLOCATION IF -1 - REFSTR
; WANTS THIS CALL TO TAKBLK TO FAIL (HIALCU)
HRR P3,T2 ;YES, REDUCE REQUEST
TAKBL0: PUSHJ P,SUPDA ;QUEUE FOR DISK ALLOCATION IF DONT ALREADY HAVE (ENTER)
PUSHJ P,TSTGEN ;UNIT GENERATION NUMBERS CHANGE?
JRST TAKBLU
MOVE R,UNISAB(U) ;LOC OF FIRST SAT BUFFER
JUMPE T1,TAKBLA ;GO IF NO START ADDRESS SPECIFIED
;HERE WHEN A START ADDRESS SPECIFIED
SETZ T2,
JUMPL T1,TAKBLM ;NEGATIVE BLOCK NOS ARE ILL GOAL
CAML T1,UNIBPU(U) ;REQUESTED BLOCK ABOVE TOP OF UNIT?
JRST TAKBLM ;YES, ERROR RETURN
IDIV T1,T4 ;NO, CONVERT TO CLUSTER ADDRESS
PUSH P,T1 ;SAVE CLUSTER ADDRESS
PUSHJ P,CHKNEW ;TEST FOR NEWLY-MOUNTED STR
MOVE T1,(P) ;RESTORE ADR
PUSHJ P,FNSAT ;GET SAT BUFFER FOR THIS BLOCK
JRST [POP P,T1 ;SAT DOESN'T EXIST
JRST TAKBLM] ;GIVE ERROR RETURN
SKIPN DEVUNI##(F) ;IF UNIT WAS REMOVED,
PJRST TAKBL3 ; TAKE ERROR RETERN
MOVEM R,UNISAB(U) ;SAVE BUFFER LOC IN UNISAT
HLRE T1,SABSCN##(R) ;-LENGTH OF WHOLE SAT DATA AREA
MOVEI P1,SABBIT##(T2) ;SET RH(P1)=FIRST SAT WORD FOR ADDRESS
ADD T1,T2 ;T1=-NUMBER OF DATA WORDS AFTER THIS ONE
HRLM T1,P1 ;P1=AOBJN WORD TO SCAN TABLE
TAKBL1: MOVSI P2,400000+R ;INSTRUCTION FORMAT INDIRECT WORD
HRRM P1,P2 ;SET FOR INDIRECT
MOVE T1,@P2 ;FIRST WORD TO LOOK AT
MOVEI P2,0 ;P2 WILL CONTAIN LARGEST HOLE FOUND
LSH T1,(T3) ;POSITION TO RIGHT BIT
JUMPL T1,TAKBL3 ;HOLE=0 IF 1ST BIT SET
HRLM T2,P2 ;SAVE POSITION OF HOLE
DPB T3,[POINT 6,P3,17]
MOVNS T3
MOVEI T4,^D36(T3) ;SET NUMBER OF BITS LEFT IN WORD
JFFO T1,.+2 ;COMPUTE NUMBER OF LEADING 0'S
MOVEI T2,^D36(T3) ;REST OF WORD EMPTY
TLO P3,STRTAD+RELABP ;INDICATE START ADDR. SPECIFIED
PUSH P,P1 ;SAVE LOC OF 1ST DATA WORD
TLO P3,RELABP ;AOBJN POINTER IS RELATIVE TO THE TABLE
PUSHJ P,GETZR## ;TRY TO GET N 0'S
JRST TAKBL2 ;CANT GET ENOUGH
POP P,(P) ;FOUND THEM REMOVE GARBAGE FROM PD LIST
JRST TAKBLQ ;MARK BLOCKS, HOUSEKEEP AND EXIT
;HERE WHEN WE COULDNT GET N CONTIGUOUS BLOCKS
TAKBL2: POP P,P1 ;PICK UP DATA LOC AGAIN
JUMPL W,TAKBL3 ;GO IF EXACTLY N NEEDED
HRR P3,P2 ;WE CAN DO WITH LESS GET LARGEST AVAILABLE
LDB T3,[POINT 6,P3,17]
HLRZ T2,P2 ;RESTORE POSITION
JRST TAKBL1 ;GO GET THEM
;HERE WHEN N NOT AVAILABLE, WE NEEDED EXACTLY N BLOCKS
TAKBL3: POP P,T1 ;TAKE STUFF OFF PD LIST
HRRZ T2,P2 ;LARGEST HOLE AVAILABLE (CLUSTER COUNT)
JRST TAKBLM ;CONVERT TO BLOCK COUNT, ERROR RETURN
;HERE WHEN A STARTING ADDRESS WAS NOT SPECIFIED
TAKBLA: PUSHJ P,CHKNEW ;MAKE SURE SATS HAVE BEEN READ
TLZ P3,677777 ;LH(P3) WILL HAVE INDEX OF LARGEST HOLE FOUND
MOVEI P2,0 ;LH(P2) WILL HAVE SIZE OF LARGEST HOLE
;THE LEFT HALF OF ACS ARE BEING USED
;BECAUSE THE PD LIST GETS VERY LONG
;IF SAT BLOCKS MUST BE READ
MOVE T1,UNIDES(U)
TLNN T1,UNPMSB ;DOES THE UNIT HAVE ONLY 1 SAT TABLE?
JRST TAKBLC ;YES, SKIP THE FANCY STUFF
;TRY TO FIND A SAT BLOCK IN CORE CONTAINING ENOUGH CONSECUTIVE 0'S
TAKBLB: HRRZ T1,SABTAL##(R) ;FREE BLOCKS LEFT IN THIS SAT
CAIGE T1,(P3) ;ENOUGH TO SATISFY USER?
JRST TAKBLG ;NO. LOOK AT NEXT SAT BUFFER
;HERE WHEN THE CURRENT SAT TABLE MAY HAVE ENOUGH CONTIGUOUS CLUSTERS
;SCAN FIRST FROM WHERE THE SCAN LEFT OFF THE LAST TIME
TAKBLC: MOVE T1,SABHOL##(R) ;BIGGEST HOLE IN SAT
CAIG T1,(P3) ;TRYING FOR MORE THAN BIGGEST?
JUMPGE T1,[HRR P2,T1
JRST TAKBLF] ;YES, SKIP SCAN IF WE KNOW SIZE OF HOLE
; (SABHOL=-1 IF WE DONT KNOW THE SIZE)
MOVSI T1,SABBIT## ;SET UP AN AOBJN WORD FOR SCAN
HRLZ T2,SABSCN##(R) ;COMPUTE DISTANCE FROM START TO C(SABSCN)
SUB T2,T1 ;=+N
ADD T2,SABSCN##(R) ;LH=DISTANCE FROM C(SABSCN) TO TOP
;RH=WHERE TO START LOOKING
MOVE P1,T2 ;AOBJN WORD FOR SCAN
HRRI P2,0 ;SET BEST SO FAR TO 0
TLO P3,RELABP ;AOBJN POINTER IS RELATIVE TO THE TABLE
PUSHJ P,GETZ## ;AND TRY TO GET N 0'S
TAKBLD: SKIPA ;COULDN'T GET THEM
JRST TAKBLP ;FOUND THEM - UPDATE AND EXIT
;HERE WHEN N WERENT AVAILABLE FROM WHERE SCAN LAST LEFT OFF
;RESCAN TABLE FROM THE START
MOVEI P1,SABBIT## ;FIRST DATA LOC IN BUFFER
HLL P1,SABSCN##(R) ;-LENGTH OF ENTIRE DATA AREA
TLO P3,RELABP ;AOBJN POINTER IS RELATIVE TO THE TABLE
PUSHJ P,GETZ## ;SCAN WHOLE SAT TABLE
SKIPA ;STILL CANT FIND ENOUGH
JRST TAKBLP ;FOUND THEM - WRAP UP
;HERE WHEN THE CURRENT SAT BUFFER DOESN'T HAVE ENOUGH
TAKBLF: HRRZM P2,SABHOL##(R) ;SAVE SIZE OF LARGEST HOLE
HLRZ T1,P2 ;PREVIOUS MAXIMUM
CAIL T1,(P2) ;WAS THIS SAT TABLE BETTER?
JRST TAKBLG ;NO
HRLS P2 ;YES. SAVE SIZE IN LH(P2)
LDB T1,SAYNDX## ;GET INDEX OF SAT
DPB T1,[POINT 11,P3,17] ;SAVE INDEX IN LH(P3)
TAKBLG: MOVE T1,UNIDES(U) ;DOES THIS UNIT HAVE ONLY 1 SAT?
TLNN T1,UNPMSB
JRST TAKBLL ;YES. CANT GET ENOUGH
TLNE P3,DSKSCN ;NO. SCANNING SATS FROM DISK?
JRST TAKBLI ;YES. READ NEXT ONE
MOVE R,SABRNG##(R) ;NO. STEP TO NEXT IN-CORE SAT TABLE
MOVE T1,UNISAB(U) ;BACK WHERE WE STARTED?
CAME R,T1
JRST TAKBLB ;NO. TRY THIS SAT TABLE
;HERE WHEN ALL SAT TABLES IN CORE ARE THROUGH
;NOTICE THAT WHILE WE WERE LOOKING AT ONLY IN-CORE SAT TABLES WE
;SCANNED ONLY THOSE WHICH HAD A CHANCE OF SUCCESS.
;NOW ALL SAT'S WILL BE LOOKED AT SINCE WE WANT TO FIND
;THE MAXIMUM NUMBER OF CONTIGUOUS BITS IF WE CANT GET ENOUGH
TLO P3,DSKSCN ;INDICATE READING SATS FROM DISK
MOVE R,UNISAB(U) ;POINT R TO CURRENT SAT
SKIPA P4,[-1] ;START AT SAT TABLE 0
TAKBLI: LDB P4,SAYNDX## ;INDEX OF LAST SAT LOOKED AT
ADD P4,UNISPT(U) ;COMPUTE ABSOLUTE ADDR. OF ITS POINTER
TAKBLJ: SKIPN 1(P4) ;IS TABLE EXHAUSTED?
JRST TAKBLL ;YES. CANT GET ENOUGH
LDB T1,[POINT TALSIZ,1(P4),TALPOS] ;FREE COUNT OF THIS SAT
HLRZ T3,P2 ;LARGEST HOLE FOUND SO FAR
CAIG T1,(T3) ;THIS SAT HAVE AT LEAST THAT MANY FREE BITS?
AOJA P4,TAKBLJ ;NO. DONT BOTHER SCANNING IT
SUB P4,UNISPT(U) ;YES. COMPUTE INDEX OF SATSPT TABLE
ADDI P4,1
PUSHJ P,DWNDA ;UNQUEUE, REQUEUE FOR DISK ALLOCATION
PUSHJ P,UPDA ;SO ANY WAITING REQUEST WILL BE
; SATISFIED BEFORE WE DO IO
PUSHJ P,TSTGEN ;UNIT GENERATION NUMBERS CHANGE?
JRST TAKBLU
PUSHJ P,SATST ;GET THE CORRESPONDING SAT TABLE
MOVE T1,SABHOL##(R) ;SIZE OF BIGGEST HOLE IN SAT
HLRZ T2,P2 ;BIGGEST HOLE FOUND SO FAR
CAMG T1,T2 ;WORTH WHILE TO SCAN THE SAT?
JUMPGE T1,TAKBLI ;NOT IF WE REALLY KNOW (SABHOL POSITIVE)
HRRI P2,0 ;PRESET LARGEST HOLE IN SAT
JRST TAKBLD ;GO SCAN THE SAT (FROM BEGINNING)
;HERE WHEN ALL SATS SCANNED, NONE HAS ENOUGH
TAKBLL: TLNE P2,-1 ;FIND ANY AT ALL?
JUMPGE W,TAKBLN ;YES, NEED EXACTLY N?
HLRZ T2,P2 ;YES. T2=LARGEST HOLE FOUND
TAKBLM: HRRZ T1,P3 ;T1=SIZE REQUESTED
LDB T3,UNYBPC## ;CONVERT BOTH CLUSTER COUNTS
IMUL T1,T3 ;TO BLOCK NUMBERS
IMUL T2,T3
SETZ T3, ;T3=0 ON ERROR
POP P,W ;RESTORE W
PJRST DWNDA ;GIVE UP DA QUEUE AND RETURN ERROR
;HERE WHEN NOT ENOUGH WERE FOUND, BUT A LESSER AMOUNT WILL DO
TAKBLN: LDB P4,[POINT 11,P3,17] ;INDEX OF BEST SAT TABLE
PUSHJ P,SATST ;GET CORRESPONDING SAT BLOCK IN
HLRZ P3,P2 ;SIZE OF LARGEST HOLE
TAKBLO: HLL P1,SABSCN##(R) ;SETUP AN AOBJN POINTER FOR THE BUFFER
HRRI P1,SABBIT##
MOVEI P2,0 ;SET LARGEST HOLE TO 0
TLO P3,RELABP ;AOBJN POINTER IS RELATIVE TO THE TABLE
PUSHJ P,GETZ## ;GET THE BLOCKS
JRST TAKBLR ;SOMEBODY SNUCK IN!
;HERE WHEN A BUNCH OF BLOCKS HAVE BEEN OBTAINED
;THE BUFFER LOC IS IN R
TAKBLP: HRRZ T1,P4 ;POSITION OF HOLE
HRRM T1,SABSCN##(R) ;SET WHERE TO START NEXT TIME
SUBI T1,SABBIT## ;CONVERT TO A CLUSTER NUMBER
IMULI T1,^D36
HLRZ T2,P4
MOVNS T2 ;-BIT POSITION IN WORD
ADDI T1,^D36(T2) ;CLUSTER NO RELATIVE TO START OF SAT
LDB T2,[POINT CLASIZ,SABFIR##(R),CLAPOS] ;FIRST ADDRESS IN SAT
ADD T1,T2 ;COMPUTE ACTUAL CLUSTER NUMBER (RELATIVE TO UNIT)
PUSH P,T1 ;SAVE IT ON THE LIST
;HERE WITH CLUSTER ADDRESS ON PD LIST
TAKBLQ: TLO P3,RELABP ;AOBJN POINTER IS RELATIVE TO THE SAT
PUSHJ P,SETOS## ;MARK THE BLOCKS IN THE SAT TABLE
STOPCD .+1,DEBUG,BAO, ;++BIT ALREADY ONE
HRRZS P3 ;P3=PLUS NUMBER OF CLUSTERS GOTTEN
PUSHJ P,FIXCNT ;UPDATE COUNTS
POP P,T2 ;RESTORE CLUSTER ADDRESS
HRRZ T3,UNISTR(U) ;LOC OF STRUCTURE DB
DPB P3,STYCNP##(T3) ;SAVE CLUSTER COUNT IN T2
PUSHJ P,DWNDA ;GIVE UP DA
JRST WPOPJ1## ;AND TAKE GOOD RETURN
;HERE WHEN THE BEST-SO-FAR WHICH WE CAREFULLY COMPUTED IS NO LONGER
;THERE - SOMEONE HAS SNUCK IN WHEN WE UNQUEUED AND GRABBED A CHUNK
;OUT OF THE HOLE WE REMEMBERED
TAKBLR: MOVE R,UNISAB(U)
JUMPE P2,TAKBLS ;START ALL OVER IF NOTHING LEFT IN SAT
MOVE P3,P2 ;SOMETHING LEFT - SETTLE FOR IT
JRST TAKBLO ;GO TAKE THE BLOCKS
TAKBLS: SKIPLE T2,UNITAL(U) ;ANY BLOCKS AT ALL IN UNIT?
JRST TAKBLA ;YES. TRY OVER FROM BEGINNING
HRRZ T1,P3 ;NO. RESTORE AMOUNT REQUESTED
TAKBLT: POP P,W ;RESTORE W
PUSH P,T1 ;SAVE ACS
PUSH P,T2
TLNE S,IOSDA
PUSHJ P,DWNDA ;GIVE UP THE DA RESOURCE
MOVEI T4,.ERFUL ;STR - FULL ERROR
HRRZ T1,UNISTR(U) ;STR DB LOC
SKIPG STRTAL##(T1) ;STR FULL?
PUSHJ P,SETINJ ;YES, SET UP FOR INTERCEPT
JFCL ;NOT ENABLED OR STR NOT FULL
SETZ T3, ;T3=0 ON ERROR
POP P,T2 ;RESTORE ACS
PJRST TPOPJ## ;AND EXIT
;HERE IF THE UNIT WAS YANKED (DEVUNI=0)
TAKBLU: SETZB T2,T3 ;INDICATE NO ROOM
PUSHJ P,DWNDA ;GIVE UP DA
PJRST TPOPJ## ;AND REURN
;ROUTINE TO CALL SETINT
SETINJ::PUSHJ P,PSIJBI## ;PSI INSTEAD
JRST CPOPJ1## ;YES, WANTS TRAP
PUSH P,J ;SAVE J
PUSH P,M ;SETINT CLOBBERS M
LDB J,PJOBN## ;JOB NUMBER
SKIPE J ;SKIP IF SWAP I/O
PUSHJ P,SETINT## ;TEST INTERCEPT
SOS -2(P) ;SET FOR NON-SKIP RETURN
POP P,M ;RESTORE M
PJRST JPOPJ1## ;INTERCEPT SET
;SUBROUTINE TO RETURN BLOCKS (DEALLOCATE)
;ENTER WITH T1= DISK ADDRESS T2= HOW MANY TO DEALLOCATE
GIVBLK::CAMLE T1,UNIBPU(U) ;LEGAL?
POPJ P, ;NO. SOME ONE IS COMFUSED
PUSHJ P,SAVE4## ;SAVE P1-P4
PUSHJ P,UPDA ;GET DA RESOURCE
SE1ENT
MOVE R,UNISAB(U) ;LOC OF FIRST SAT TABLE
LDB T4,UNYBPC## ;NUMBER OF BLOCKS PER CLUSTER
ADDI T2,-1(T4) ;CONVERT BLOCK COUNT TO CLUSTERS
IDIV T2,T4
MOVNM T2,P1 ;P3=-N FOR UPDATING COUNTS
IDIV T1,T4 ;CONVERT TO CLUSTER ADDRESS
PUSHJ P,FNSAT ;FIND THE SAT FOR THIS ADDRESS
STOPCD GIVBLR,DEBUG,SDE, ;SAT DOESN'T EXIST
MOVEI T4,SABBIT##(T2) ;POSITION IN TABLE
MOVEI T1,^D36
SUBI T1,(T3) ;POSITION
MOVN T3,P1 ;COUNT
MOVSI P3,RELABP ;INDICATE AOBJN POINTER IS RELATIVE TO THE SAT
PUSHJ P,CLRBTS## ;CLEAR THE BITS
STOPCD GIVBLR,DEBUG,BAZ, ;++BIT ALREADY ZERO
MOVE P3,P1 ;SET P3 FOR UPDATING COUNTS
SETOM SABHOL##(R) ;INDICATE SIZE OF LARGEST HOLE IN SAT UNKNOWN
PUSHJ P,FIXCNT ;UPDATE SOME COUNTS
GIVBLR: XJRST [0,,DWNDA] ;GIVE UP THE DA RESOURCE AND RETURN
;SUBROUTINE TO UPDATE SOME COUNTS
;ENTER WITH P3 = HOW MANY CLUSTERS (PLUS-ALLOCATION, NEG - DEALLOCATION)
; R=LOC OF SAT BUF.
;RETURNS WITH T1=NUMBER OF BLOCKS
FIXCNT:
IFN FTXMON,<
PUSH P,F ;SAVE F
HRRZS F ;SHOULD HAVE THE SIGN BIT ON BUT DOESN'T ALWAYS
>
MOVN T1,P3 ;-NUMBER OF CLUSTERS
LDB T4,UNYBPC##
IMUL T1,T4 ;-NUMBER OF BLOCKS
SKIPE DINITF## ;IF IN ONCE-ONLY
JRST FIXCN2 ;JUST SET SATCHG BIT
MOVN T2,P3 ;-NUMBER OF CLUSTERS
ADDM T1,UNITAL(U) ;UPDATE UNIT FREE-TALLY
HRRZ T3,UNISTR(U) ;UPDATE STR FREE-TALLY
JUMPE T3,FIXCN3 ;IF SUPER I/O
ADDM T1,STRTAL##(T3)
MOVE T3,DEVUFB##(F) ;UPDATE USERS QUOTA
JUMPE T3,FIXCN1 ;CANT UPDATE QUOTA IF NO UFD
MOVE T4,UFBTAL##(T3)
ADDM T1,UFBTAL##(T3)
JUMPLE T1,FIXCN1 ;IF INCREASING UFBTAL,
JUMPL T4,FIXCN1 ; UFBTAL WAS POSITIVE
HRLOI T4,377777
SKIPGE UFBTAL##(T3) ; AND UFBTAL HAS OVERFLOWED
MOVEM T4,UFBTAL##(T3) ; MAKE IT INFINITY AGAIN
FIXCN1: HRRZ T3,DEVACC##(F) ;UPDATE HIGHEST BLOCK ALLOCATED
JUMPE T3,FIXCN3
MOVNS T1
MOVEI T4,DEPALC##
TDNN T4,DEVALC##(F) ;LEAVE ACCALC ALONE IF BIT IS ON
ADDM T1,ACCALC##(T3)
FIXCN3: ADD T2,SABTAL##(R)
TRNE T2,400000 ;COUNT GO NEGATIVE?
MOVEI T2,0 ;YES, SET TO 0
HRRM T2,SABTAL##(R)
LDB T3,SAYNDX## ;AND IN SATSPT TABLE
ADD T3,UNISPT(U)
DPB T2,[POINT TALSIZ,(T3),TALPOS]
FIXCN2: MOVSI T4,SATCHG ;INDICATE THAT THE SAT
IORM T4,SABFIR##(R) ; BLOCK HAS CHANGED
MOVMS T1
IFE FTXMON,<
POPJ P, ;AND RETURN
>
IFN FTXMON,<
JRST FPOPJ## ;RESTORE F AND RETURN
>
;SUBROUTINE TO FIND THE SAT BUFFER ASSOCIATED WITH A GIVEN DISK ADDRESS
;IT MAY WRITE OUT A CURRENT SAT AND READ IN A NEW ONE
;ENTER WITH R=LOC OF 1ST SAT BUFFER IN RING, T1 = DESIRED CLUSTER ADDRESS
;EXIT WITH T2=RELATIVE LOC IN SAT TABLE WITHIN SAT BLOCK
; T3=BIT POSITION R=BUFFER LOC
;P3,T1 UNCHANGED, R,P2, P4 CHANGED
FNSAT: HRRZ T2,UNICPS(U) ;NUMBER OF CLUSTERS/SAT TABLE
MOVE P2,R ;USE P2 FOR END TEST
;TRY TO FIND A SAT IN CORE FOR THIS CLUSTER ADDRESS
FNSA1: LDB T3,[POINT CLASIZ,SABFIR##(R),CLAPOS] ;FIRST DISK ADDRESS IN SAT BUFFER
CAMGE T1,T3 ;IN THIS SAT?
JRST FNSA2 ;NO
ADD T3,T2 ;MAYBE, CHECK IF OVER TOP
CAMGE T1,T3 ;THIS THE ONE?
JRST FNSA4 ;YES, COMPUTE POSITION
FNSA2: MOVE R,SABRNG##(R) ;STEP TO NEXT SAT BUFFER
CAME R,P2 ;THROUGH?
JRST FNSA1 ;NO. TEST IT
;HERE WHEN THE DESIRED SAT IS NOT IN CORE. READ IT FROM DISK
PUSH P,T1 ;SAVE CLUSTER ADDRESS
IDIV T1,T2 ;COMPUTE INDEX TO SATPFI TABLE
LDB T2,UNYSPU## ;SATS PER UNIT
CAMLE T1,T2 ;TOO HIGH?
POPJ P, ;YES, (LAST PARTIAL CLUSTER) NOT FOUND
MOVE P4,T1 ;STUFF IT IN P4
PUSHJ P,NEWSAT ;WRITE THE CURRENT SAT, READ IN NEW
POP P,T1 ;RESTORE CLUSTER ADDRESS
;HERE WHEN DESIRED SAT IS IN CORE
;T1=CLUSTER ADDRESS, R = LOC OF BUFFER
FNSA4: LDB T2,[POINT CLASIZ,SABFIR##(R),CLAPOS] ;1ST ADDRESS OF SAT
SUBM T1,T2 ;-DESIRED ADDRESS
IDIVI T2,^D36 ;COMPUTE WORD COUNT, SHIFT NUMBER
JRST CPOPJ1##
;SUBROUTINE TO ENTER REQUEST IN DISK-ALLOCATION QUEUE
;ALL ACS RESPECTED
;CALL SUPDA IF MIGHT ALREADY HAVE DA
SUPDA:: TLNN S,IOSDA ;IF HAVE DA JUST RETURN
UPDA:: SKIPE DINITF## ;IF IN ONCE, RETURN
POPJ P,
PUSH P,T1 ;SAVE SOME REGISTERS
PUSH P,J ;
IFN <FTDUAL!FTCIDSK>,<
PUSH P,U ;SAVE U (IN CASE THIS IS 2ND PORT)
>
MOVE J,.USJOB ;GET JOB NUMBER
UUOLOK ;CANT INTERRUPT HERE
IFN FTDUAL,<
SKIPGE UNI2ND(U) ;IS THIS THE PRIME PORT?
HRRZ U,UNIALT(U) ;NO, POINT TO PRIME PORT
>
IFN FTCIDSK,<
MOVEI T1,CPUMSK ;SEE IF PORT IS ACTIVE
TDNE T1,UDBCAM(U) ;BY SEEING IF ACCESSIBLE BY ANYONE
JRST UDCIOK ;IT IS, USE THIS PORT
HRRZ T1,UNIALT(U) ;GET SECOND PORT
JUMPE T1,UDCIOK ;NO SECOND PORT, JUST OFF-LINE
HRL T1,UDBCAM(T1) ;SEE IF THIS PORT ACCESSIBLE
TLNE T1,CPUMSK ;IS IT?
JRST [HRRZ U,T1 ;POINT TO ACTIVE PORT
JRST UDCIOK] ;CONTINUE
PUSH P,T2 ;NEED ONE MORE AC
HRRZS T1 ;CLEAR JUNK
PUSH P,T1 ;SAVE ALTERNATE PORT
LDB T1,UNYKNM## ;GET CI NODE NUMBER FOR UDB POINTED TO BY U
EXCH U,(P) ;ALSO FOR ALTERNATE PORT
LDB T2,UNYKNM## ;FOR ALTERNATE PORT
CAIL T2,(T1) ;DOESN'T MATTER WHICH PORT, BUT
HRRZ U,(P) ;ALWAYS BE THE SAME ONE
POP P,(P) ;FIX STACK
POP P,T2 ;RESTORE T2
UDCIOK:>
MOVSI T1,1 ;JUST INCREMENT LEFT HALF OF UNIAJB
HRLM U,JBTDAU##(J) ;SET DA USER WANTS
ADDB T1,UNIAJB(U) ;COUNT WAITERS
TLNE T1,-2 ;MORE THAN ONE?
JRST WAITDA ;MUST WAIT FOR IT
MOVE T1,JBTSTS##(J) ;GET JOB STATUS
TLNN T1,JXPN ;IF EXPANDING
CAMN J,FORCEF## ;OR BEING FORCED OUT
JRST WATDAF ;MUST DO MORE CHECKING
UPDA2: HRRM J,UNIAJB(U) ;WE ARE NOW USING DA
UUONLK ;UNINTERLOCK
UPDAX1:
IFN <FTDUAL!FTCIDSK>,<
POP P,U ;RESTORE U
>
POP P,J ;RESTORE REGISTERS
POP P,T1 ;
TLO S,IOSDA ;HAVE DA QUEUE,LIGHT BIT
PJRST STRIOS ;SAVE S AND RETURN
WATDAF: CAMN J,CBUSER## ;JOB OWN CB?
JRST UPDA2 ;YES. GIVE HIM DA
HRRZ T1,JBTDAU##(J) ;NO. HOW ABOUT AU?
JUMPE T1,WAITDA ;NOT IF ZERO
HRRZ T1,UFBAUJ##(T1) ;GET OWNER
CAIN T1,(J) ;IS IT US?
JRST UPDA2 ;YES. GIVE DA TOO
WAITDA: UUONLK ;UNINTERLOCK
MOVEI T1,DAQ## ;PUT JOB IN DAQ
DPB T1,PJBSTS## ;
PUSH P,R ;SWAPPER COULD CHANGE R
PUSHJ P,WSCHED## ;WAIT FOR SCHED1 TO GIVE IT TO US
POP P,R ;RESTORE ADDRESS OF SAT BUFFER
JRST UPDAX1 ;AND RETURN
;HERE FROM SCHEDULAR TO SEE IF DA IS FREE, RETURN DESIRED OWNING JOB
;IN T3 (OR ZERO IF NONE OR CAN'T FIND)
UNWDA:: HLRZ T3,JBTDAU##(J) ;DA DESIRED
JUMPE T3,CPOPJ## ;SOMEONE IS CONFUSED
IFN FTDUAL,<
SKIPGE UNI2ND(T3) ;PRIME PORT?
IFE FTCIDSK,<
HRRZ T3,UNIALT(T3) ;NO, POINT TO PRIME PORT
>
IFN FTCIDSK,<
JRST [HRRZ T3,UNIALT(T3) ;NO, POINT TO PRIME PORT
JRST UNWDA4 ] ;CONTINUE
>
> ;END FTDUAL
IFN FTCIDSK,<
PUSH P,T1
MOVEI T1,CPUMSK ;SEE IF PORT IS ACTIVE
TDNE T1,UDBCAM(T3) ;BY SEEING IF ACCESSIBLE BY ANYONE
JRST UNWDA3 ;IT IS, USE THIS PORT
HRRZ T1,UNIALT(T3) ;GET SECOND PORT
JUMPE T1,UNWDA3 ;NO SECOND PORT, JUST OFF-LINE
HRL T1,UDBCAM(T1) ;SEE IF THIS PORT ACCESSIBLE
TLNE T1,CPUMSK ;IS IT?
JRST [HRRZ T3,T1 ;POINT TO ACTIVE PORT
JRST UNWDA3] ;CONTINUE
PUSH P,T2 ;NEED ONE MORE AC
HRRZS T1 ;CLEAR JUNK
PUSH P,T1 ;SAVE ALTERNATE PORT
EXCH T3,U
LDB T1,UNYKNM## ;GET CI NODE NUMBER FOR UDB POINTED TO BY U
EXCH U,(P) ;ALSO FOR ALTERNATE PORT
LDB T2,UNYKNM## ;FOR ALTERNATE PORT
CAIL T2,(T1) ;DOESN'T MATTER WHICH PORT, BUT
HRRZ U,(P) ;MUST ALWAYS BE THE SAME ONE
EXCH T3,U ;WE NEED IT IN T3
POP P,(P) ;FIX STACK
POP P,T2
UNWDA3: POP P,T1 ;RESTORE T1
UNWDA4:>
HRRZ T3,UNIAJB(T3) ;OWNER
POPJ P,
;HERE FROM SCHEDULAR TO GIVE JOB IN J THE DA RESOURCE (IF POSSIBLE)
;RETURN CPOPJ1 IF WE GOT IT, CPOPJ OTHERWISE. USES T3
SCDDA:: HLRZ T3,JBTDAU##(J) ;WHICH DA?
JUMPE T3,CPOPJ## ;HUH?
UUOLOK
IFN FTDUAL,<
SKIPGE UNI2ND(T3) ;IS THIS THE PRIME PORT?
IFN FTCIDSK,<
JRST [HRRZ T3,UNIALT(T3)
JRST SCDDA4 ]
>
IFE FTCIDSK,<
HRRZ T3,UNIALT(T3) ;NO, DA IS ONLY ON THE PRIME PORT
>
> ;END FTDUAL
IFN FTCIDSK,<
PUSH P,T1
MOVEI T1,CPUMSK ;SEE IF PORT IS ACTIVE
TDNE T1,UDBCAM(T3) ;BY SEEING IF ACCESSIBLE BY ANYONE
JRST SCDDA3 ;IT IS, USE THIS PORT
HRRZ T1,UNIALT(T3) ;GET SECOND PORT
JUMPE T1,SCDDA3 ;NO SECOND PORT, JUST OFF-LINE
HRL T1,UDBCAM(T1) ;SEE IF THIS PORT ACCESSIBLE
TLNE T1,CPUMSK ;IS IT?
JRST [HRRZ T3,T1 ;POINT TO ACTIVE PORT
JRST SCDDA3] ;CONTINUE
PUSH P,T2 ;NEED ONE MORE AC
HRRZS T1 ;CLEAR JUNK
PUSH P,T1 ;SAVE ALTERNATE PORT
EXCH T3,U ;EASIER TO USE U HERE
LDB T1,UNYKNM## ;GET CI NODE NUMBER FOR UDB POINTED TO BY U
EXCH U,(P) ;ALSO FOR ALTERNATE PORT
LDB T2,UNYKNM## ;FOR ALTERNATE PORT
CAIL T2,(T1) ;DOESN'T MATTER WHICH PORT, BUT
HRRZ U,(P) ;ALWAYS BE THE SAME ONE
EXCH T3,U
POP P,(P) ;FIX STACK
POP P,T2 ;RESTORE T2
SCDDA3: POP P,T1 ;RESTORE T1
SCDDA4: HRLM T3,JBTDAU##(J) ;MAKE IT EASIER NEXT TIME
>
HRL T3,UNIAJB(T3) ;GET DA
TLNE T3,-1
JRST SCDDA1 ;OH WELL
HRRM J,UNIAJB(T3)
AOS (P) ;GOOD RETURN
SCDDA1: UUONLK
POPJ P,
;SUBROUTINE TO UNQUE A DA REQUEST
;ALL ACS RESPECTED
DWNDA:: SKIPE DINITF##
POPJ P,
TLZN S,IOSDA ;CLEAR THE BIT
STOPCD .+1,DEBUG,DHD, ;++ (S CLAIMS) DON'T HAVE DA
PUSH P,T1
MOVE T1,.USJOB ;JOB NUMBER RETURNING DA
SUB T1,UNIAJB(U) ;IS IT THE RIGHT ONE?
TRNN T1,-1
JRST DWNDA1 ;YES
IFN FTDUAL,<
PUSH P,U ;SAVE U
HRRZ U,UNIALT(U) ;IF WE ARE ON THE ALTERNATE PATH THIS IS OK
MOVE T1,.USJOB ;GO TO THE PRIME PORT
SUB T1,UNIAJB(U) ;OWN THE DA ON THE PRIME PORT?
SKIPE U ;(NO ALTERNATE PORT)
TRNE T1,-1
>
STOPCD DWNDA9,DEBUG,RWD, ;++ RETURNING WRONG UNIT'S DA
IFN FTDUAL,<
PUSHJ P,DWNDAD ;GIVE UP THE DA ON THE PRIME PORT
POP P,U
JRST TPOPJ## ;AND GO AWAY HAPPY
DWNDAD: PUSH P,T1
>
DWNDA1: PUSH P,J ;SAVE J
UUOLOK
MOVE J,.USJOB ;
HRRZS JBTDAU##(J) ;CLEAR DA WE HAVE/WANT
HLRZ T1,UNIAJB(U) ;GET NUMBER OF WAITERS
SOJL T1,.+2 ;PRECAUTIONARY
HRLM T1,UNIAJB(U) ;NOW ONE LESS
HLLZS UNIAJB(U) ;NO LONGER OWN IT
UUONLK ;UNINTERLOCK
SKIPE F ;IF FROM ADFREE, NO DDB
PUSHJ P,STRIOS ;STORE S IN DDB
PJRST SRFRDA## ;SPECIAL CODE IN CLOCK1. EXPECTS T1,J ON LIST
DWNDA9: JUMPE F,CPOPJ## ;RETURN IF NO DDB
PJRST STRIOS ;ELSE UPDATE DEVIOS AND RETURN
;SUBROUTINE TO GET THE FA RESOURCE
;RESPECTS ALL AC'S
UPFA:: PUSHJ P,SAVE2## ;SAVE P1, P2
HRRZ P1,DEVACC##(F) ;GET ADDRESS OF ACCESS TABLE
TRNN P1,DIFNAL## ;NOT ACC?
SKIPN P1 ;OR NOTHING?
JRST UPFAZ ;STOPCODE IF FUNNY
PUSHJ P,GETCB ;NEED CB TO LOOK AT ACC. TAB. LINKS
UPFA1: HLRZ P1,ACCNMB##(P1) ;%GET NEXT ADDRESS
TRZN P1,DIFNAL## ;%NMB?
JRST UPFA1 ;%NO, KEEP LOOKING
PUSHJ P,GVCBJ## ;%YES, GIVE UP CB
UPFA2: UUOLOK ;LOCK AGAINST UUO LEVEL ONLY NOW
HRRE P2,NMBFAJ##(P1) ;GET CURRENT USER - WAIT EXTENDED
JUMPN P2,UPFA3 ;JUMP IF IN USE
MOVE P2,.USJOB ;GET MY JOB NUMBER
HRRM P2,NMBFAJ##(P1) ;WE OWN IT NOW
HRRM P1,JBTFA##(P2) ;SAVE NMB ADDRESS FA OWNED FOR
UUONLK ;DONE WITH INTERLOCK
SETZM FAUSER## ;SO GIVRES DOESN'T TRY SOMETHING STUPID
TRO S,IOSFA ;FLAG WE OWN FA
PJRST STRIOS ;SAVE S AND RETURN
;IF FA IS NOT FREE FOR THIS NMB
UPFA3: JUMPL P2,UPFA4 ;ALREADY WAITERS (NMPFAW)?
MOVEI P2,NMPFAW## ;NO, GET THE FLAG
IORM P2,NMBFAJ##(P1) ;FLAG WAITERS FOR THIS NMB
UPFA4: UUONLK ;DONE WITH UUO LOCK
PUSHJ P,FAWAIT## ;PUT US IN FAQ
JRST UPFA2 ;GO SEE IF WE CAN GET FA NOW
UPFAZ: STOPCD STRIOS,DEBUG,FNU, ;++FA NOT OWNED BY US
;SUBROUTINE TO RELEASE FA RESOURCE
;RESPECTS ALL AC'S
DWNFA:: TRZN S,IOSFA ;CLEAR BIT IN S
STOPCD CPOPJ##,DEBUG,DHF, ;++DON'T HAVE FA
PUSHJ P,SAVE2## ;SAVE P1, P2
MOVE P2,.USJOB ;GET US
HRRZ P1,JBTFA##(P2) ;GET ADDRESS OF NMB
JUMPE P1,UPFAZ ;STOPCODE IF NONE
HRRZ P2,NMBFAJ##(P1) ;GET OWNER
TRZ P2,NMPFAW## ;CLEAR WAIT BIT
CAME P2,.USJOB ;ARE WE THE OWNER?
JRST UPFAZ ;NO, STOPCODE
DWNFA1: UUOLOK ;LOCK US
HLLZS JBTFA##(P2) ;CLEAR NMB ADDRESS
HRL P2,NMBFAJ##(P1) ;GET OLD IN CASE THERE ARE WAITERS
HLLZS NMBFAJ##(P1) ;INDICATE FA FREE FOR NMB
UUONLK ;DONE WITH LOCK
TLNE P2,NMPFAW## ;WAITERS?
PUSHJ P,FAFREE## ;YES, WAKE THEM ALL UP
PJUMPE F,CPOPJ## ;JUMP IF NO DDB
PJRST STRIOS ;SAVE S AND RETURN
;SUBROUTINE TO TEST IF JOB OWNS AU, DA, OR FA
;NON-SKIP IF NO, SKIP IF YES
;RESPECTS ALL AC'S
TSTFAD::PUSHJ P,SAVE2##
PUSHJ P,TSTFA ;JOB OWN AN FA?
CAIA ;NO, CHECK OTHERS
JRST CPOPJ1## ;YES, SKIP RETURN
PUSHJ P,TSTDA ;JOB OWN SOME DA?
PJRST TSTAU ;NO, SEE IF IT OWNS AN AU
JRST CPOPJ1## ;YES, SKIP
;SUBROUTINE TO TEST IF JOB OWNS DA RESOURCE
;RETURNS CPOPJ IF NO, CPOPJ1 IF YES
;CLOBBERS P1,P2 UNLESS CALLED AT OWNDA
OWNDA:: PUSHJ P,SAVE2##
TSTDA: HLRZ P1,JBTDAU##(J) ;DA UNIT
JUMPE P1,CPOPJ## ;NO. NONSKIP
HRRZ P2,UNIAJB(P1) ;MAYBE. GET OWNER
CAIN P2,(J) ;DO WE OWN IT?
IFN <FTDUAL!FTCIDSK>,<
JRST CPOPJ1## ;YES. SKIP RETURN
HRRZ P1,UNIALT(P1) ;HOW ABOUT ON ALTERNATE PORT
JUMPE P1,CPOPJ## ;NO ALTERNATE PORT
HRRZ P2,UNIAJB(P1)
CAIN P2,(J) ;OWN ON THIS PORT?
>
AOS (P) ;YES
POPJ P, ;NO, NON-SKIP
;SUBROUTINE TO TEST IF JOB OWNS AU RESOURCE
;RETURNS CPOPJ IF NO, CPOPJ1 IF YES
;CLOBBERS P1,P2 UNLESS CALLED AT OWNAU
OWNAU:: PUSHJ P,SAVE2##
TSTAU: HRRZ P1,JBTDAU##(J) ;AU UFB
JUMPE P1,CPOPJ## ;NO. NON-SKIP
HRRZ P2,UFBAUJ##(P1) ;MAYBE. GET OWNER
CAIN P2,(J) ;DO WE OWN IT?
AOS (P) ;YES. SKIP RETURN
POPJ P, ;NO, NON-SKIP
;SUBROUTINE TO TEST IF JOB OWNS AN FA RESOURCE
;RETURNS CPOPJ IF NO, CPOPJ1 IF YES
;CLOBBERS P1
TSTFA: HRRZ P1,JBTFA##(J) ;FA NMB
JUMPN P1,CPOPJ1## ;SKIP IF WE HAVE ONE
POPJ P, ;WE DON'T, NON-SKIP RETURN
;SUBROUTINE TO TEST IF JOB OWNS AU, DA, OR FA. IF SO IT RETURNS THEM
ADFREE::PUSHJ P,SAVE2##
SETZ F, ;NO DDB EXISTS
MOVE P2,J
PUSHJ P,TSTFA ;OWN FA?
CAIA ;NO
PUSHJ P,DWNFA1 ;YES, RETURN IT
PUSHJ P,TSTAU ;OWN AU?
CAIA ;NO
PUSHJ P,DWNAU1 ;YES, RETURN IT
PUSHJ P,TSTDA ;JOB OWN DA?
POPJ P, ;NO
EXCH P1,U ;GET U RIGHT
PUSHJ P,DWNDA1 ;RETURN DA
MOVE U,P1
POPJ P, ; AND RETURN
;SUBROUTINE TO GET THE AU RESOURCE
;ALL ACS RESPECTED
UPAU:: PUSHJ P,SAVE2##
HRRZ P1,DEVUFB##(F) ;GET UFB OF DDB
JUMPE P1,UPAUZ ;STOPCD IF NONE
PUSH P,J ;SAVE J
UPAU1: UUOLOK ;INTERLOCK
MOVE J,.CPJOB## ;SET TO UFB USER WANTS
HRRM P1,JBTDAU##(J) ;SO CAN UNWIND IN SCHED1
AOSE UFBWAT##(P1) ;COUNT UP THE WAITERS
JRST WAITAU ;MUST WAIT
SKIPE DINITF ;IN ONCE?
JRST UPAU2 ;YES
MOVE P2,JBTSTS##(J) ;GET JOB STATUS
TLNN P2,JXPN ;EXPANDING?
CAMN J,FORCEF ;OR BEING FORCED?
JRST WATAUF ;YES. DON'T GIVE IT UNLESS HAS OTHERS
UPAU2: MOVEM J,UFBAUJ##(P1) ;MARK WHO OWNS UFB
UUONLK ;UNLOCK THINGS
UPAUX1: POP P,J ;RESTORE J
TLO S,IOSAU ;HAVE IT NOW
PJRST STRIOS ;RETURN
WATAUF: CAMN J,CBUSER## ;USER HAVE CB?
JRST UPAU2 ;YES. GIVE HIM AU
HLRZ P2,JBTDAU##(J) ;NO. HOW ABOUT DA?
JUMPE P2,WAITAU ;NOT IF ZERO
HRRZ P2,UNIAJB(P2) ;GET OWNER OF DA
CAIN J,(P2) ;IS IT US?
JRST UPAU2 ;YES. GIVE HIM AU
WAITAU: UUONLK ;UNINTERLOCK
MOVEI P2,AUQ## ;PUT USER IN AU
DPB P2,PJBSTS## ;
PUSHJ P,WSCHED## ;AND WAIT FOR SCHED1 TO GIVE IT TO US
JRST UPAUX1 ;WE HAVE AU NOW
UPAUZ: STOPCD CPOPJ##,DEBUG,ANU, ;++AU NOT OWNED BY US,
;HERE FROM SCHEDULAR TO SEE WHO OWNS AU. RETURN OWNING JOB IN T3 OR
;ZERO IF NONE OR CAN'T FIND.
UNWAU:: HRRZ T3,JBTDAU##(J) ;UFB
JUMPE T3,CPOPJ##
HRRZ T3,UFBAUJ##(T3)
POPJ P, ;RETURN
;HERE FROM SCHEDULAR TO GIVE JOB THE AU. USES T3.
SCDAU:: HRRZ T3,JBTDAU##(J) ;WHICH AU?
JUMPE T3,CPOPJ## ;?
UUOLOK
HRL T3,UFBAUJ##(T3) ;CURRENT AU OWNER
TLNE T3,-1 ;REALLY AVAILABLE NOW?
JRST SCDAU1 ;NO, SOMEONE SNUCK IN
HRRZM J,UFBAUJ##(T3) ;GIVE IT TO HIM
AOS (P)
SCDAU1: UUONLK
POPJ P,
;SUBROUTINE TO RELEASE AU RESOURCE
;ALL ACS RESPECTED
DWNAU:: TLZN S,IOSAU ;CLEAR THE BIT
STOPCD CPOPJ##,DEBUG,DHA,;++DON'T HAVE AU
PUSHJ P,SAVE2##
HRRZ P1,DEVUFB##(F) ;GET UFB
JUMPE P1,UPAUZ ;STOPCD IF NONE
LDB P2,PJOBN## ;GET JOB NUMBER
CAME P2,UFBAUJ##(P1) ;ARE WE RETURNING WHAT WE OWN?
JRST UPAUZ ;NO, STOPCD
DWNAU1: PUSH P,T1 ;SET ACS FOR SRFRAU
UUOLOK
HRLZS UFBAUJ##(P1) ;SET PREVIOUS USER OF AU
HLLZS JBTDAU##(P2) ;MARK JOB DOESN'T HAVE/WANT AU
SOSGE T1,UFBWAT##(P1) ;DECREMENT NUMBER OF WAITERS
AOJN T1,DWNAUZ ;IF LESS THAN -1, WE HAVE PROBLEMS
SETZM UFBWAT##(P1) ;NEVER NEGATIVE
UUONLK
DWNAU2: SKIPE F ;IF FROM ADFREE, NO DDB
PUSHJ P,STOIOS## ;SAVE S
SKIPE DINITF## ;IN ONCE?
JRST TPOPJ## ;YES. RETURN
PUSH P,J ;WHICH EXPECTS T1,J ON STACK
MOVE J,P2 ;AND .CPJOB IN J
PJRST SRFRAU## ;
DWNAUZ: SETOM UFBWAT##(P1) ;SAY IT'S FREE (T1=WHAT IT WAS+1)
UUONLK ;FREE INTERLOCK
STOPCD DWNAU2,DEBUG,AWN ;++AU WAITERS NEGATIVE
;SUBROUTINE TO FIND A PARTICULAR SAT IN THE
;SAT-BUFFER RING. IF NOT FOUND, READ IT IN
;ENTER WITH R = LOC OF SAT BUFFER, P4 = INDEX OF SAT ADDRESS TABLE TO READ
;R ON EXIT CONTAINS THE BUFFER LOC. LH(P2) UNCHANGED.
SATST: MOVE T2,R ;LOC OF BUFFER (FOR END TEST)
SATS2: LDB T3,SAYNDX## ;INDEX OF THIS SAT
CAIN T3,(P4) ;RIGHT ONE?
POPJ P, ;YES. RETURN
MOVE R,SABRNG##(R) ;NO. STEP TO NEXT
CAME T2,R ;THROUGH?
JRST SATS2 ;NO. TEST THIS BUFFER
;YES. READ THE SAT
;SUBROUTINE TO (POSSIBLY) WRITE THIS SAT, READ IN NEW ONE
;ENTER WITH R = LOC OF SAT BUFFER, P4 = INDEX OF SAT ADDRESS TABLE TO READ
NEWSAT: SKIPG SABFIR##(R) ;CURRENT SAT BEEN CHANGED?
PUSHJ P,SATWRT ;YES. WRITE IT OUT
;READ NEW SAT
;SUBROUTINE TO READ A NEW SAT BLOCK INTO CORE
;THE SAT DISK ADDRESS IS SPECIFIED BY P4 (INDEX INTO ADDRESS TABLE)
;R POINTS TO THE IN-CORE BUFFER
SATRED::DPB P4,SAYNDX## ;SAVE INDEX TO SATPFI IN MON BUFFER
MOVE T4,P4 ;INDEX TO SATSPT INTO T4
IFN FTXMON,<
PUSH P,DEVISN(F) ;SAVE SECTION NUMBER FOR I/O
>
PUSHJ P,SATADR ;SET UP PARAMETERS TO READ
HRRM T3,SABTAL##(R) ;SAVE FREE SPACE FOR THIS SAT
IFN FTXMON,<
JRST @[0,,.+1] ;MUST BE IN SECTION 0
>
PUSH P,DEVUNI##(F) ;SAVE DEVUNI
PUSH P,R ;SAVE SAT ADDRESS (R IS NOT REALLY PRESERVED)
PUSHJ P,STOAU ;UNIT WE'RE TALKING TO
IFN FTMP,<
SKIPE DINITF## ;IF IN REFRESHER AND UNIT ON ANOTHER CPU
PUSHJ P,REFRED## ; LET ONCMOD DO THE READ
>
PUSHJ P,MONRED ;READ THE SAT
POP P,R ;RESTORE SAT ADDRESS
POP P,DEVUNI##(F) ;RESTORE DEVUNI
IFN FTXMON,<
POP P,DEVISN(F) ;RESTORE SECTION NUMBER FOR NEXT I/O OPERATION
XJRST [MCSEC1+.+1] ;MUST BE IN SECTION 1
>
LDB T4,SAYNDX## ;RESET INDEX
HRRZ T1,UNICPS(U) ;NO. OF CLUSTERS PER SAT
IMUL T1,T4 ;TIMES INDEX = FIRST ADDR OF SAT
DPB T1,[POINT CLASIZ,SABFIR##(R),CLAPOS] ;SAVE IN BUFFER
MOVEI T1,SABBIT## ;START SCAN AT 1ST LOC OF TABLE
HRRM T1,SABSCN##(R) ;SAVE IN SCAN LOC
SETOM SABHOL##(R) ;DONT KNOW SIZE OF LARGEST HOLE
SKIPE DINITF## ;IF IN ONCE-ONLY
PJRST SATW2 ;DONT CHECK FOR CONSISTENCY
MOVE T1,SABRNG##(R) ;STEP TO NEXT SAB IN RING
MOVEM T1,UNISAB(U) ;THIS WILL BE NEXT TO BE READ INTO
MOVE T1,SABSCN##(R) ;AOBJN WORD FOR SAT BITS
SKIPN T2,T3 ;CHECK FOR ERRORS DETECTED IN MONRED
PUSHJ P,SATCN ;COUNT 0'S IN SAT
HRRZ T1,SABTAL##(R) ;DONE. # OF 0'S WE EXPECT
CAIN T1,(T2) ;RIGHT?
PJRST SATW2 ;YES. ZERO SATCHG AND RETURN
MOVSI T2,UNPSER ;NO. COUNT NO OF SOFTWARE ERRS
ADDM T2,UNIMCT(U) ; UP BY ONE IN UNIT DB
MOVNS T1 ;DECREASE UNIT AND STR TALLIES
LDB T2,UNYBPC##
IMULI T1,(T2) ;CONVERT CLUSTERS TO BLOCKS
ADDM T1,UNITAL(U) ;BY THE AMOUNT WE EXPECTED
HRRZ T3,UNISTR(U)
ADDM T1,STRTAL##(T3)
SETZ T1, ;T1=0
ADD T4,UNISPT(U) ;POINT TO RIGHT SPT WORD
DPB T1,[POINT TALSIZ,(T4),TALPOS] ;SET COUNT IN THIS SAT TO 0
HRRM T1,SABTAL##(R) ;SET SABTAL FOR THIS SAT TO 0
MOVE T1,SABSCN##(R) ;SET ALL BITS IN THE SAT TO 1
MOVSI T2,400000+R ;INSTRUCTION FORMAT INDIRECT WORD
HRRM T1,T2 ;UPDATED AOBJN POINTER
SETOM @T2
AOBJN T1,.-2
PJRST SATW2 ;ZERO SATCHG (SO SAT WONT BE WRITTEN) AND EXIT
;ROUTINE TO COUNT 0 BITS IN A TABLE
;ARGS: T1=RELATIVE AOBJN POINTER TO TABLE, R=ADDRESS OF THE TABLE
;VALUES: T2=NO. OF 0-BITS IN TABLE
;RESPECTS T4
SATCN:: PUSHJ P,SAVE1## ;SAVE AN AC
SETZ T2, ;T2 WILL COUNT 0'S FOUND
PUSH P,T4
MOVSI P1,400000+R ;INSTRUCTION FORMAT INDIRECT POINTER
SATR1: HRRM T1,P1 ;POINT INDIRECT POINTER AT THE TABLE
MOVE T3,@P1 ;COUNT 0-BITS IN 0(T1)
SETCMB T4,T3 ;ITS EASIER TO COUNT 1'S
LSH T4,-1
AND T4,[333333,,333333]
SUB T3,T4
LSH T4,-1
AND T4,[333333,,333333]
SUBB T3,T4 ;EACH OCTAL DIGIT REPLACED BY NUMBER OF 1S IN IT
LSH T4,-3
ADD T3,T4
AND T3,[070707,,070707]
IDIVI T3,77 ;CASTING OUT 63'S
ADDI T2,(T4) ;ACCUMULATE ANSWER IN T2
AOBJN T1,SATR1 ;COUNT BITS IN NEXT WORD
PJRST T4POPJ## ;DONE, ANSWER IN T2
;SUBROUTINE TO WRITE OUT A SAT BLOCK
;THE BUFFER IS SPECIFIED BY R
SATWRT::TLNE S,IOSDA ;JOB HAVE DA RESOURCE?
JRST SATW1 ;YES
PUSHJ P,UPDA ;NO, GET IT (PROBABLY COMING FROM WTUSAT)
PUSHJ P,SATW1 ;WRITE THE SAT
PJRST DWNDA ;GIVE UP DA AND RETURN
SATW1: LDB T4,SAYNDX## ;INDEX TO SATPFI
IFN FTXMON,<
PUSH P,F ;SAVE F
HRRZS F ;SIGN BIT SHOULD BE ON BUT IT ISN'T ALWAYS
PUSH P,DEVISN(F) ;SAVE CURRENT SECTION NUMBER FOR I/O
>
PUSHJ P,SATADR ;SET PARAMETERS FOR WRITE
IFN FTXMON,<
JRST @[0,,.+1] ;MUST BE IN SECTION 0
>
PUSH P,DEVUNI##(F)
PUSH P,R ;SAVE SAT ADDRESS (R IS NOT REALLY PRESERVED)
PUSHJ P,STOAU ;UNIT WE'RE TALKING TO
IFN FTMP,<
SKIPE DINITF## ;IF IN REFRESHER, UNIT ON ANOTHER CPU
PUSHJ P,REFWRT## ; LET ONCMOD DO THE WRITE
>
PUSHJ P,MONWRT ;WRITE THE SAT
POP P,R ;RESTORE SAT ADDRESS
POP P,DEVUNI##(F)
IFN FTXMON,<
POP P,DEVISN(F) ;RESTORE SECTION NUMBER FOR I/O
POP P,F ;RESTORE F
XJRST [MCSEC1+.+1] ;MUST BE IN SECTION 1
>
SATW2: MOVSI T1,SATCHG ;ZERO SAT-CHANGED BIT
ANDCAM T1,SABFIR##(R)
IFE FTXMON,<
POPJ P, ;AND RETURN
>
IFN FTXMON,<
SKIPE .UONCE## ;IF THIS IS USER MODE
POPJ P, ;THEN A SIMPLE RETURN WILL DO
PJRST SPCS## ;PUT PCS BACK AND RETURN
>
;SUBROUTINE TO SET UP PARAMETERS FOR A SAT-BLOCK READ OR WRITE
;ENTER WITH T4=INDEX TO SATSPT TABLE R=BUFFER ADDRESS
;EXIT WITH T1=IOWD FOR THE SAT T2= DISK ADDRESS T3=NO. OF FREE CLUSTERS
SATADR: ADD T4,UNISPT(U) ;COMPUTE ADDRESS OF SATSPT ENTRY
LDB T2,[POINT CLASIZ,(T4),CLAPOS] ;GET DISK ADDRESS
LDB T3,UNYBPC## ;NO OF BLOCKS PER CLUSTER
IMUL T2,T3 ;CONVERT CLUSTER ADR TO BLOCK ADR
LDB T3,[POINT TALSIZ,(T4),TALPOS] ;GET FREE COUNT
IFN FTXMON,<
HLRZ T1,R ;SECTION NUMBER
MOVEM T1,DEVISN(F) ;STORE IT FOR THE I/O
>
MOVEI T1,SABBIT##-1(R);ADDRESS FOR IOWD
HLL T1,SABSCN##(R) ;LENGTH OF DATA
POPJ P, ;RETURN
;SUBROUTINE TO CHECK FOR VIRGIN SAB RING (NEWLY MOUNTED F/S)
; IF NEW RING (CLUST. ADR.=-1), READ SATS FROM DISK INTO ALL SABS
;CALL WITH R=1ST SAB ADR
CHKNEW: LDB T1,[POINT CLASIZ,SABFIR##(R),CLAPOS] ;CLUSTER ADDR.
CAME T1,[EXP CLAMAX] ;-1?
POPJ P, ;NO. OK
PUSHJ P,SAVE4## ;YES-THIS IS NEW F/S, NEED TO GET SATS
SETZM P4 ;P4=1ST INDEX (SABNDX)
MOVE P2,R ;P2=1ST SAB ADDR
CHKNE2: PUSHJ P,SATRED ;READ THE SAT
MOVE R,SABRNG##(R) ;STEP TO NEXT SAB
CAME P2,R ;BACK WHERE WE STARTED?
AOJA P4,CHKNE2 ;NO - BUMP INDEX AND READ NEXT SAT
POPJ P, ;YES - FINISHED
;SUBROUTINE TO CHECK THE AMOUNT OF SPACE A USER WANTS TO ALLOCATE AGAINST HIS QUOTA
;ALSO CHECKS TO SEE THAT THERE IS SPACE ON THE STR
;ENTER WITH T2= AMOUNT TO ALLOCATE, LH(T2)=-1 IF FROM OUTPUT
;EXIT WITH T2 = AMOUNT ALLOWED (MAY BE 0)
;IF 0 IOBKTL HAS BEEN SET IN S, DEVIOS
CHKQTA::PUSH P,T2 ;SAVE AMOUNT TO ALLOCATE
TLZ T2,400000 ;MAKE SURE ITS POSITIVE
MOVE T4,DEVUFB##(F) ;CHECK AGAINST QUOTA
HRRZ T3,UNISTR(U)
SKIPG STRTAL##(T3) ;ROOM ON STR?
JRST CHKQT1 ;NO, COMPLAIN TO USER
MOVE T1,UFBTAL##(T4)
TLNN F,OCLOSB ;DOING A CLOSE?
CAMG T2,T1 ; OR BELOW QUOTA?
PJRST TPOPJ## ;YES. OK
SUB T1,STROVR##(T3) ;CHECK MAX OVERDRAW ALLOWED IN STR
CAML T2,T1 ;TAKE LESSER OF KOYGRP, AMOUNT LEFT
SKIPLE T2,T1 ;IF 0 OVERDRAW USED UP
JRST CHKQT2 ;CHECK IF QUOTA JUST GOING NEGATIVE
;HERE IF QUOTA IS NOW EXHAUSTED OR STR IS FULL
CHKQT1: MOVEI T4,.ERFUL
PUSHJ P,SETINJ ;IS USER INTERCEPTING DISK FULL?
SKIPA ;NO, STOP JOB
JRST CHKQ1B ;YES, LIGHT AN ERROR BIT AND RETURN
MOVE T1,.CPJOB##
MOVE T1,JBTSTS##(T1) ;DOES JOB WANT TO STOP ON FULL?
TRNN T1,JS.SFL
JRST CHKQ1B ;NO, RETURN
PUSHJ P,SAVSTS ;YES, SAVE A RECORD OF RESOURCES JOB OWNS
SKIPGE -1(P) ;IF CAME FROM OUTPUT,
SOS DEVRET##(F)
PUSH P,S
TRO S,DR
PUSHJ P,DSKFUL ;COMPLAIN TO USER, STOP JOB
POP P,S
MOVEM S,DEVIOS(F)
POP P,T3 ;CONTINUED - RECORD OF RESOURCES
PUSHJ P,RESSTS ;GET BACK RESOURCES
POP P,T2 ;RESTORE AMOUNT TO GET
JUMPGE T2,CHKQTA
AOS DEVRET##(F)
JRST CHKQTA ;AND TEST AGAIN
;HERE FOR ERROR RETURN
CHKQ1B: POP P,(P) ;REMOVE AMOUNT TO GET FROM LIST
SETZ T2, ;INDICATE CANT GET ANY BLOCKS
PJRST ERRFUL ;LIGHT BIT AND RETURN
;HERE WHEN QUOTA IS NEGATIVE OR ABOUT TO GO NEGATIVE.
;IF QUOTA IS GT 0 TYPE A WARNING MESSAGE TO USER
CHKQT2: SKIPGE UFBTAL##(T4) ;QUOTA ALREADY NEG?
PJRST TPOPJ## ;YES. MESSAGE ALREADY TYPED
HRRM T2,(P) ;SAVE REDUCED AMOUNT
MOVEI T4,.ERQEX ;QUOT1 - EXHAUSTED ERROR
PUSHJ P,SETINJ ;SET INTERCEPT IF HE WANTS IT
SKIPA ;NO ENABLED - TYPE MESSAGE
JRST CHKQT4 ;INTERCEPTING - SKIP MESSAGE
PUSH P,S ;SAVE ACS WHICH SCNSER WILL USE
PUSH P,U
PUSH P,J
PUSH P,F
MOVEI U,0
PUSHJ P,TTYFNU## ;FIND TTY FOR CURRENT JOB; SET U,J,F
JUMPE U,CHKQT3
PUSHJ P,INLMES##
ASCIZ /
[Exceeding quota on /
MOVE T2,(P) ;DDB
MOVE T2,DEVACC##(T2) ;AT
LDB T1,ACYFSN## ;FSN
MOVE T1,TABSTR##(T1) ;STR DATA BLOCK LOC
MOVE T2,STRNAM##(T1) ;STR NAME
PUSHJ P,PRNAME## ;TYPE IT
PUSHJ P,INLMES##
ASCIZ /]
/
PUSHJ P,TTYSTR## ;START TTY TYPING (LEAVE JOB RUNNING, IN USER MODE)
CHKQT3: POP P,F ;RESTORE ACS
POP P,J
POP P,U
POP P,S
CHKQT4: HRRZ T2,(P)
PJRST TPOPJ## ;RETURN TO CALLER
;SUBROUTINE TO STOP JOB ON DISK FULL OR QUOTA EXHAUSTED
;TYPES "?DISK FULL OR QUOTA EXHAUSTED FOR XXX "
;CONTINUE RETRIES
DSKFUL::MOVEM S,DEVIOS(F) ;SAVE S FROM SCNSER
PUSH P,F ;SAVE F
PUSHJ P,TTYFUW## ;FIND USERS TTY
PUSHJ P,TSETBI## ;CLEAR TYPE-AHEAD
PUSHJ P,CRLF##
PUSHJ P,PRQM## ;"?"
PUSHJ P,INLMES## ;AND THE MESSAGE....
ASCIZ /Quota or storage exhausted on /
MOVE T1,(P) ;GET F
MOVE T1,DEVUNI##(T1) ;UNIT
HRRZ T1,UNISTR(T1) ;STR NAME
MOVE T2,STRNAM##(T1) ;TELL USER THE NAME
PUSHJ P,PRNAME## ;START TYPING
PUSHJ P,HOLD0##
POP P,F ;RESTORE F
MOVE S,DEVIOS(F) ;RELOAD S FROM DDB
PJRST WSCHED## ;AND RESCHEDULE
;SUBROUTINE TO SEE IF THE CURRENT POINTER CAN BE UPDATED
;ENTER WITH T2=NUMBER OF BLOCKS DESIRED
;DEVRET(F) POINTING TO CURRENT RETRIEVAL POINTER
;EXIT WITH T2= LESSER OF ORIGINAL VALUE, AMOUNT LEFT IN CURRENT POINTER
;T1= ORIGINAL T2 IF T2=0 THE CURRENT POINTER IS FULL
CHKADD::MOVE T1,DEVACC##(F) ;IF A SIM UPDATE FILE WITH MORE THAN 1 WRITER,
LDB T3,ACYWCT## ; IF A PNTR IS ADDED TO AND THE ADDING DDB CLOSES FIRST,
SOJG T3,CHKAD0 ; THE NEW PNTR WILL BE OVERWRITTEN, SO
; DONT ALLOW ADDING TO PNTRS IF GTR THAN 1 WRITER
MOVEM T2,T1 ;DESIRED AMOUNT
MOVE T2,@DEVRET##(F) ;CURRENT POINTER
HRRZ T4,UNISTR(U) ;STR ADR
LDB T3,STYCNP##(T4) ;NO OF CLUSTERS IN CURRENT POINTER
LDB T2,STYCLP##(T4) ;ADR OF 1ST CLUSTER
ADD T2,T3 ;HIGHEST ADR(+1) IN PNTR
HRRZ T3,UNICPS(U) ;NO OF CLUSTERS IN A SAT
IDIV T2,T3 ;LAST CLUSTER IN PNTR=LAST IN SAT?
JUMPE T3,CHKAD1 ;YES, CANT ADD TO CURRENT PNTR
;(ELSE PROBLEMS IN DELETING BLOCKS)
MOVEI T2,-1 ;NUMBER OF CLUSTERS DEVLFT WILL HOLD
LDB T3,UNYBPC##
IDIVM T2,T3
SETO T2, ;NUMBER OF CLUSTERS A PNTR WILL HOLD
LDB T2,STYCNP##(T4)
CAMLE T3,T2 ;TAKE THE SMALLER OF THE TWO
MOVE T3,T2
MOVE T2,@DEVRET##(F) ;CURRENT POINTER
LDB T2,STYCNP##(T4) ;CURRENT GROUP SIZE
SUBM T3,T2 ;MAX ADDITIONAL CLUSTERS
CAMLE T2,T1 ;SKIP IF REQUESTED TOO MUCH
MOVE T2,T1 ;CAN HAVE ALL WE REQUESTED
POPJ P, ;RETURN
;HERE IF BLOCK IS FIRST IN NEW SAT
CHKAD0: MOVE T1,T2 ;ORIGINAL T2 INTO T1
CHKAD1: SETZ T2, ;RETURN CANT ADD
POPJ P,
SUBTTL AUTCONFIGURATION - BUILD DISK KDB
;BUILD A KONTROLLER DATA BLOCK.
;CALL: T1/ MASSBUS UNIT NUMBER (MEANINGFUL FOR DX20/RP20 ONLY) OR -1
; T2/ KONTROLLER TYPE CODE (TYPXX)
; PUSHJ P,DSKKON
; <NON-SKIP> ;NO CORE FOR KDB
; <SKIP> ;AC J = NEW KDB ADDRESS
;NOTE: KDB ADDRESS ALSO RETURNED IN AC W (AUTCON CONVENTION)
DSKKON::PUSH P,T2 ;SAVE KONTROLLER TYPE CODE
PUSHJ P,AUTKDB## ;BUILD AND LINK A KDB
JRST TPOPJ## ;NO CORE
MOVE J,W ;PUT KDB ADDRESS IN J FOR KOYXXX BYTE POINTERS
POP P,T1 ;RESTORE KONTROLLER TYPE CODE
DPB T1,KOYKTP## ;SALT IT AWAY
LDB T1,[POINT 5,KDBNAM(J),17] ;GET KONTROLLER NUMBER
DPB T1,KOYKNM## ;SALT IT AWAY
MOVE T1,KDBIUN(J) ;GET AOBJN POINTER TO UNIT TABLE
HRRM T1,KONPTR(J) ;SET UP KONPTR
ADDM J,KONEBK(J) ;COMPUTE ADDRESS OF DRIVE REGISTER STORAGE
JRST CPOPJ1## ;SUCCESS RETURN
SUBTTL AUTOCONFIGURATION - BUILD DISK DRIVE UDB
;BUILD A DISK DRIVE UNIT DATA BLOCK.
;CALL: T1/ PHYSICAL UNIT NUMBER,,UDB TABLE OFFSET
; T2/ FLAGS,,UNIT TYPE CODE
; J/ KDB ADDRESS
; PUSHJ P,DSKDRV
; <NON-SKIP> ;NO CORE FOR UDB
; <SKIP> ;AC U = NEW UDB ADDRESS
;WHERE FLAGS ARE:
; 1B0 = NON-REMOVABLE MEDIA
DSKDRV::HRRZ U,KDBIUN(J) ;SEE IF THAT UNIT ALREADY EXISTS
ADDI U,(T1) ;ADD IN UDB TABLE OFFSET (UNIT NUMBER USUALLY)
SKIPE U,(U) ;IS THERE ALREADY A UDB THERE?
JRST DSKDR6 ;YES
PUSHJ P,SAVE1## ;WE'D LIKE THE CHN AVAILABLE IN P1
MOVE P1,KDBCHN(J)
PUSHJ P,SAVW## ;AUTCON WANTS THE KDB IN W
MOVE W,J ; SO LET'S BE ACCOMODATING
PUSH P,T1 ;SAVE PHYSICAL UNIT #,,UDB TABLE OFFSET
PUSH P,T2 ;SAVE FLAGS,,UNIT TYPE CODE
PUSHJ P,AUTUDB## ;BUILD A UDB
JRST TTPOPJ## ;NO CORE
POP P,T1 ;RESTORE FLAGS,,UNIT TYPE CODE
DPB T1,UNYUTP## ;SALT AWAY IN UDB
MOVSI T2,U2PNRM ;GET NON-REMOVABLE MEDIA FLAG
SKIPGE T1 ;SIGN BIT OF FLAGS WORD SET?
IORM T2,UNIDS2(U) ;YES
POP P,T1 ;GET PHYSICAL UNIT #,,UDB TABLE OFFSET
DPB T1,UNYKOF## ;SALT AWAY IN UDB
MOVEI T1,UNVNPM ;STATUS = NO PACK MOUNTED (INITIALLY)
DPB T1,UNYUST## ;(IN CASE AUTCON NOT RUNNING BEFORE ONCMOD)
LDB T1,KOYKTP## ;GET KONTROLLER TYPE
DPB T1,UNYKTP## ;COPY TO UDB
IFN FTCIDSK,<
MOVE T2,.CPBIT## ;GET BIT FOR THIS CPU
CAIN T1,TYPRA ;CI DISK PSEUDO-CONTROLLER?
ANDCAM T2,UDBCAM(U) ;CLEAR ACCESSIBILITY MASK UNTIL UNIT ONLINE
>; END IFN FTCIDSK
AOS T1,SYSGEN## ;GET A UNIQUE UNIT GENERATION NUMBER
HRRM T1,UNIGEN(U)
MOVSI T1,777 ;SET UP RANDOM UDB LOCS
MOVEM T1,UNICCT(U)
MOVE T1,[LBNHOM##,,LB2HOM##]
MOVEM T1,UNIHOM(U)
SETOM UNICYL(U)
SETOM UNIAJB(U)
;*** COMPATIBILITY WITH OLD PROGRAMS
LDB T1,CHYSCN## ;GET SOFTWARE CHANNEL NUMBER
DPB T1,[POINT 3,UNIDES(U),20] ;STORE IN UNIDES (DSKCHR UUO)
LDB T1,KOYKNM## ;GET KONTROLLER NUMBER
DPB T1,[POINT 3,UNIDES(U),29] ;STORE IN UNIDES (DSKCHR UUO)
MOVE T1,UDBPDN(U) ;GET PHYSICAL DRIVE NUMBER
DPB T1,[POINT 3,UNIDES(U),35] ;STORE IN UNIDES (DSKCHR UUO)
;SET UP UNICHN LINKS
SYSPIF ;PREVENT RACES AND FUMBLED LINKS
SETZB T1,T2 ;NO FIRST OR LAST UNIT
PUSH P,P1 ;PRESERVE P1
MOVE P1,CHNTBP(P1) ;GET AOBJN POINTER TO KDBS ON THIS CHN
DSKDR1: MOVE T4,(P1) ;GET A KDB ADDRESS
MOVE T4,KDBIUN(T4) ;GET AOBJN POINTER TO UNITS
PUSHJ P,FLUKN1 ;FIND FIRST AND LAST UNITS ON THAT KON
AOBJN P1,DSKDR1 ;LOOP FOR ANY OTHER KDBS ON THIS CHN
POP P,P1 ;DONE WITH P1
JUMPE T1,DSKDR2 ;JUMP IF NEW UNIT WAS ONLY UNIT
MOVEM T1,UNICHN(U) ;POINT NEW UNIT AT FIRST UNIT
MOVEM U,UNICHN(T2) ;POINT OLD LAST UNIT AT NEW UNIT
JRST DSKDR3 ;DONE
DSKDR2: MOVEM U,UNICHN(U) ;ONLY UNIT, IT POINTS TO ITSELF
;SET UP UNIKON LINKS
DSKDR3: PUSHJ P,FLUKON ;FIND FIRST AND LAST UNITS ON THIS KON
JUMPE T1,DSKDR4 ;JUMP IF NEW UNIT WAS ONLY UNIT
MOVEM T1,UNIKON(U) ;POINT NEW UNIT AT FIRST UNIT
MOVEM U,UNIKON(T2) ;POINT OLD LAST UNIT AT NEW UNIT
JRST DSKDR5 ;DONE
DSKDR4: MOVEM U,UNIKON(U) ;ONLY UNIT, IT POINTS TO ITSELF
DSKDR5: PUSHJ P,LNKSUN ;LINK UNIT INTO UNISYS CHAIN
SYSPIN ;THINGS ARE CONSISTENT AGAIN
DSKDR6: PUSH P,W ;SAVE W
MOVE W,J ;PUT KDB ADDRESS IN PROPER PLACE
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
POP P,W ;RESTORE W
LDB T1,UNYUST## ;GET UNIT STATE
CAIN T1,UNVDWN ;UNIT DOWN?
JRST DSKDR9 ;POSSIBLY DETACHED SO LEAVE ALONE
DSKDR7: SKIPGE KONCPY(J) ;CAN WE CALL CPY ROUTINE IF KONTROL BUSY?
SKIPL KONBSY(J) ;NO, IS KONTROLLER BUSY?
JRST DSKDR8 ;GO READ DATA
PUSHJ P,UUOLVL## ;CAN WE BLOCK?
TDZA T1,T1 ;MUST BE SPRINI
MOVEI T1,1 ;SLEEP TIME
PUSHJ P,SLEEPF## ;ZZZZZZ
JRST DSKDR7 ;TRY AGAIN
DSKDR8: SKIPN .UONCE## ;IF WE'RE IN USER MODE THEN JUST RETURN NICELY
SKIPE DINITF## ;DITTO FOR INITIALIZATION
JRST DSKDR9 ;DON'T BOTHER THE DRIVER DURING INITIALIZATION
S0PSHJ @KONCPY(J) ;SEE IF DRIVE EXISTS
JRST DSKDR9 ;CAN'T DETERMINE STATUS
MOVEM T1,UNIBPU(U) ;SAVE BLOCKS PER UNIT
MOVEM T2,UNIBPM(U) ;SAVE BLOCKS PER UNIT INCL. MAINT CYLS
MOVEM T3,UNIBUC(U) ;SAVE BLOCKS PER UNIT IN 10/11 COMPAT. MODE
DPB W,UNYBPY## ;SAVE BLOCKS PER CYLINDER
HLRZ T3,W ;NO OF BLOCKS PER TRACK
DPB T3,UNYBPT## ;BLOCKS/TRACK
DPB T4,UNYUTP## ;UNIT TYPE
MOVEI T1,UNVPIM ;ASSUME PACK IS MOUNTED
TLNE T4,KOPUHE ;UNIT HAD ERRORS (OFFLINE)?
MOVEI T1,UNVNPM ;YES--SAY NO PACK MOUNTED
TLNE T4,KOPNSU ;NO SUCH UNIT?
MOVEI T1,UNVDWN ;CALL IT A DOWN UNIT
DPB T1,UNYUST## ;UPDATE STATE
IFN FTMDA,<PUSHJ P,DSKMPA> ;INDICATE DISK DRIVE ATTACHED
DSKDR9: MOVE W,J ;FILSER HAS NO RESPECT FOR CONVENTIONS
JRST CPOPJ1## ;RETURN
IFN FTMDA,<
;SEND A DEVICE ATTACHED MESSAGE TO [SYSTEM]MDA
;CALL:
; U/ ADDRESS OF UDB JUST ATTACHED
DSKMPA: MOVE T2,U ;COPY ATTACHED UDB ADDRESS
IFE FTDUAL,<SETZ T3,> ;NO DUAL PORT IF FTDUAL IS OFF
IFN FTDUAL,<
SKIPGE T3,UNI2ND##(U) ;IS THIS THE ALTERNATE PORT?
EXCH T2,T3 ;YES, T2=PRIMARY UDB, T3=SECONDARY UDB
>; END IFN FTDUAL
MOVE T1,UDBNAM(T2) ;GET NAME OF PRIMARY PORT
SKIPE T2,T3 ;HAVE A SECONDARY PORT UDB?
MOVE T2,UDBNAM(T3) ;YES, GET THE NAME
PJRST ATTMPA## ;INFORM [SYSTEM]MDA
;SEND A DEVICE DETACHED MESSAGE TO [SYSTEM]MDA
;CALL:
; U/ ADDRESS OF UDB JUST DETACHED
; T1/ ADDRESS OF NEW PRIME PORT (IF ANY)
DSKMPD:
IFE FTDUAL,<SETZ T1,> ;NO NEW PRIMARY PORT NAME
IFN FTDUAL,<
SKIPE T1 ;DID UNIT HAVE AN ALTERNATE PORT?
MOVE T1,UDBNAM(T1) ;PICK UP NEW PRIMARY PORT NAME
> ;END IFN FTDUAL
PJRST DETMPA## ;INFORM [SYSTEM]MDA
> ;END IFN FTMDA
;ROUTINE TO FIND FIRST AND LAST UDBS ON A KDB
;CALL:
; J/ KDB ADDRESS
;RETURN:
; T1/ FIRST UNIT ON KDB (OR ZERO IF NO UNITS ON KDB)
; T2/ LAST UNIT ON KDB (OR ZERO IF NO UNITS ON KDB)
;ENTER AT FLUKN1 WITH AOBJN POINTER TO UNITS ON KDB ALREADY IN T4
FLUKON: SETZB T1,T2 ;NO FIRST OR LAST UNIT
MOVE T4,KDBIUN(J) ;GET AOBJN POINTER TO UNITS
FLUKN1: SKIPE T3,(T4) ;IS THERE A UDB THERE?
CAMN T3,U ;YES, IS IT NOT THE CURRENT ONE?
JRST FLUKN2 ;NO UDB OR CURRENT ONE, SKIP IT
MOVE T2,T3 ;REMEMBER LAST UNIT
SKIPN T1 ;DO WE HAVE A FIRST UNIT?
MOVE T1,T2 ;NO, SO THIS IS ALSO FIRST UNIT
FLUKN2: AOBJN T4,FLUKN1 ;LOOP FOR REMAINDER OF TABLE
POPJ P, ;RETURN
SUBTTL AUTOCONFIGURATION - PROTOTYPE INTERRUPT CODE
DSKICD::PHASE 0 ;AUTCON MUST FILL IN OFFSETS
;CONSO SKIP CHAIN CODE
IFN FTKL10,<
DICDIF::!CONSO 000,0 ;(0) TEST FOR INTERRUPT FLAGS
JRST . ;(1) NOT FOR THIS DEVICE
DICDAE::!JFCL ;(2) RH20-ONLY TEST ON ATTN INTERRUPTS DISABLED
CONSO 000,7 ;(3) MAKE SURE IT HAS A PIA (DIAG. FIDDLING?)
JRST 1 ;(4) NOT INTERESTED
JSR PIERR## ;(5) SAVE AC'S
SKIPA J,.+1 ;(6) LOAD KDB ADDRESS IN FILSER'S AC
EXP 0 ;(7) AUTCON FILLS IN KDB ADDRESS
XJRST .+1 ;(10) DISPATCH TO INTERRUPT HANDLER
EXP 0 ;(11) INTERRUPT HANDLER ADDRESS
>; END IFN FTKL10
;VECTORRED INTERRUPT CODE
IFN FTKS10,<
EXP 0 ;(0) OLD PC FLAGS
EXP 0 ;(1) OLD PC
EXP IC.UOU ;(2) NEW PC FLAGS
EXP .+1 ;(3) NEW PC
JSR PIERR## ;(4) SAVE ACS
DMOVE T1,0 ;(5) COPY OLD PC DOUBLE WORD
DMOVEM T1,-1 ;(6) FAKE UP PI CHANNEL INTERRUPT
SKIPA J,.+1 ;(7) LOAD KDB ADDRESS IN FILSER'S AC
EXP 0 ;(10) AUTCON FILLS IN KDB ADDRESS
XJRST .+1 ;(11) DISPATCH TO INTERRUPT HANDLER
EXP 0 ;(12) INTERRUPT HANDLER ADDRESS
>; END IFN FTKS10
DEPHASE
DSKICL==:.-DSKICD ;LENGTH OF CONSO SKIP CHAIN CODE
SUBTTL XCHNGE COMMAND
;HERE TO SWITCH TWO UNITS BUT LEAVE THE DATA BASE ALONE -
;EG TO PUT DSKB2 ON RPA5 WHEN RPA2 GOES DOWN, LEAVE SATS, ETC THE SAME
XCHDSK::PUSHJ P,SAVE3## ;SAVE SOME ACS
PUSHJ P,COMUNI ;SET UP U FOR FIRST UNIT
PJRST COMERA## ;NO UNIT OR LOGICAL-UNIT MATCH
MOVE P1,U ;SAVE FIRST UNIT
LDB P3,UNYKOF## ;GET KONTAB OFFSET
POP P,U ;RESTORE U FOR COMCON
PUSHJ P,COMUNI ;GET SECOND UNIT
PJRST COMERA## ;NONE OR LOGICAL MATCH
LDB P2,UNYKOF## ;GET KONTAB OFFSET
MOVE T1,UDBKDB(U) ;KONTROLLER
CAME T1,UDBKDB(P1) ;UNITS ON SAME KONTROLLER?
JRST XCHERR ;NO, CANT EXCHANGE THEM
MOVE T1,UNIBPU(U) ;IF UNIBPU DOESNT MATCH,
CAME T1,UNIBPU(P1)
JRST XCHERR ; THEN DIFFERENT TYPE UNITS, CANT EXCHANGE THEM
MOVSI T1,U2PNRM ;CAN'T EXCHANGE NON-REMOVABLE MEDIA
TDNN T1,UNIDS2(P1) ;...
TDNE T1,UNIDS2(U) ;...
JRST XCHERR ;GIVE ERROR
IFN FTDUAL,<
SKIPL UNI2ND(P1) ;DON'T ALLOW EXCHANGE OF ALTERNATE PORT
SKIPGE UNI2ND(U) ;...
JRST XCHERR ;GIVE ERROR
>; END IFN FTDUAL
DSKOFF ;CANT ALLOW DISK INTERRUPTS WHILE FIDDLING
SKIPE T1,UNISTS(U) ;UNIT IDLE
CAIL T1,OWCOD ; OR IN SOME OPR WAIT STATE?
SKIPA T1,UNISTS(P1) ;YES, 1ST UNIT IS OK
JRST XCHDSW ;NO, CANT EXCHANGE
CAIGE T1,OWCOD ;2ND UNIT IDLE OR IN OPR WAIT?
JUMPN T1,XCHDSW ;CANT EXCHANGE IF NOT
MOVEI T1,O2COD ;IF UNITS ARENT IN OPR WAIT
SKIPN UNISTS(U) ; PUT THEM THERE, ELSE A
MOVEM T1,UNISTS(U) ; WRONG PACK COULD BE WRITTEN
SKIPN UNISTS(P1)
MOVEM T1,UNISTS(P1)
DPB P3,UNYKOF## ;OK - EXCHANGE THE UNITS
MOVEM U,@KONPTR(T2) ;MAKE INTERRUPTS FOR 1 UNIT POINT
EXCH P1,U ; AT THE OTHER UDB,
DPB P2,UNYKOF## ;MAKE THE UDB POINT AT DIFFERENT
EXCH P2,P3 ; PHYSICAL UNITS,
MOVEM U,@KONPTR(T2)
MOVE T1,UDBNAM(U) ;CHANGE PHYSICAL NAMES IN THE UDBS
EXCH T1,UDBNAM(P1)
MOVEM T1,UDBNAM(U)
MOVE T1,UDBPDN(U) ;PHYSICAL DRIVE NUMBER FOR SECOND UNIT
EXCH P1,U ;SWAP UNITS
MOVE T2,UDBPDN(U) ;PHYSICAL DRIVE NUMBER FOR SECOND UNIT
MOVEM T1,UDBPDN(U) ;EXCHANGE THE UNITS
DPB T1,[POINT 3,UNIDES(U),35] ;OLD PLACE FOR DSKCHR UUO
EXCH P1,U ;SWAP UNITS
MOVEM T2,UDBPDN(U) ;...
DPB T2,[POINT 3,UNIDES(U),35] ;OLD PLACE FOR DSKCHR UUO
MOVEI T1,UNIHCT(U) ;MAKE THE ERROR STATE
MOVEI T2,UNIHCT(P1) ; STAY WITH THE DRIVE
HRLI T1,-3 ; EXCHANGE UNIHCT,SCT,MCT
XCHUN1: MOVE T3,(T1)
EXCH T3,(T2)
MOVEM T3,(T1)
ADDI T2,1
AOBJN T1,XCHUN1
IFN FTDUAL,<
DMOVE T1,UDBDSN(U) ;CHANGE UNIT SERIAL NUMBERS
EXCH T1,UDBDSN(P1) ;...
EXCH T2,UDBDSN+1(P1) ;...
DMOVEM T1,UDBDSN(U) ;...
MOVE T1,UNI2ND(U) ;GET ALTERNATE UNITS
MOVE T2,UNI2ND(P1)
MOVEM T2,UNI2ND(U) ;EXCHANGE THEM
MOVEM T1,UNI2ND(P1)
SKIPE T2
HRRM U,UNI2ND(T2) ;EXCHANGE THE BACKWARDS POINTERS
SKIPE T1
HRRM P1,UNI2ND(T1)
SKIPE T2,UNI2ND(U) ;IF SECOND UNIT NOW DUAL-PORTED,
PUSHJ P,CPYUD ; COPY NECESSARY DATA TO SECOND PORT
EXCH P1,U ;POINT AT FIRST UNIT
SKIPE T2,UNI2ND(U) ;IF FIRST UNIT NOW DUAL-PORTED,
PUSHJ P,CPYUD ; COPY NECESSARY DATA TO SECOND PORT
EXCH P1,U ;AS YOU WERE
>; END IFN FTDUAL
DSKON ;ALLOW DISK INTERRUPTS AGAIN
MOVE F,P1 ;GET 1ST UDB INTO F
MOVEI T1,.CSCXC ;CODE FOR XCH
PUSHJ P,DSKCSC ;CALL DAEMON
IFN FTMDA,<
SKIPN DINITF## ;DON'T DO THIS DURING INITIALIZATION
PUSHJ P,XCHMPA## ;NOTIFY MDA
>
JRST UPOPJ## ;RESTORE U AND RETURN TO COMCON
XCHERR: POP P,U ;RESTORE COMCON'S U
PJRST COMERA## ;GIVE ERROR
XCHDSW: DSKON
PJRST DLYCM1## ;DELAY COMMAND UNTIL WE CAN
SLPJIF: SETZ T1, ;SLEEP FOR A JIFFY
MOVE J,.CPJOB## ;CAN'T RELY ON J HAVING A JOB NUMBER
PJRST SLEEPF## ;ZZZZ AND RETURN
SUBTTL DETACH A KONTROLLER
;HERE TO TAKE A KONTROLLER OFF-LINE
;P1 = KDB ADDRESS
;RETURN CPOPJ IF SOME UNIT WOULDN'T DETACH, CPOPJ1 IF ALL UNITS WON
;CLOBBERS P1 & P2
DETKON::MOVE P1,KDBIUN(P1) ;GET POINTER TO UNITS
SETZ P2, ;COUNT UP UNITS THAT FAIL
DETKO1: SKIPN U,(P1) ;GET NEXT UNIT ON KON
JRST DETKO2 ;TRY AGAIN
PUSHJ P,DETCPD ;DETACH IT
JFCL ;ERROR
AOS P2 ;KEEP TRACK OF ERRORS
DETKO2: AOBJN P1,DETKO1 ;LOOP OVER ALL UNITS ON THIS KONTROLLER
JUMPE P2,CPOPJ1## ;WIN IF NO ERRORS
POPJ P, ;RETURN ERROR
SUBTTL DETACH A UNIT
;HERE TO TAKE A UNIT OFF-LINE
;RETURNS CPOPJ IF NOT A DSK
;RETURNS CPOPJ1 IF CANT DETACH (KON BUSY & NOT CALLED AT UUO LEVEL)
;RETURNS CPOPJ2 IF OK
DETCPD::PUSH P,U ;SAVE U
JRST DETDS1 ;JOIN COMMON CODE
DETDSK::PUSHJ P,COMUNT ;SET UP U (COMCON ALREADY HAS U PUSHED)
POPJ P, ;NO UNIT OR LOGICAL MATCH
DETDS1: HRRZ T2,UNISTR(U)
IFN FTDUAL,<
SKIPN T1,UNI2ND(U) ;IF NOT DUAL-PORTED
>
JUMPN T2,UPOPJ1## ; CAN'T BE IN A FILE STRUCTURE
IFN FTDUAL,<
SKIPE T2,UNISTS(U) ;UNIT IDLE
CAILE T2,TCOD ; OR SOME FLAVOR OF OPR WAIT?
TLZA T1,-1 ;YES, WE'RE OK
JRST [PUSHJ P,SLPJIF ;SLEEP FOR A JIFFY
JRST DETDS1] ;GO BACK AND TRY AGAIN
SETZM UDBDSN(U) ;INSURE NO DUAL PORT MATCHES
SETZM UDBDSN+1(U)
JUMPE T1,DETDS3 ;GO IF NOT DUAL-PORTED
CAIA ;U IS ALREADY ON STACK
DETMX: PUSH P,U ;SAVE U
MOVE T2,UNISTS(U) ;SHUT UP
MOVEI T3,O2COD
CAIN T2,OCOD
MOVEM T3,UNISTS(U)
MOVE T2,T1 ;COPY OTHER PORT TO T2
JUMPL U,DETD10 ;JUMP IF NOT DETACHING PRIMARY PORT
UUOLOK ;PREVENT DA RACE
PUSHJ P,CPYUD ;YES, COPY PARAMETERS TO SECOND PORT
DETD10: PUSH P,U ;PRESERVE UNIT BEING DETACHED
SKIPL U ;RE-LINK APPROPRIATE UNIT ONTO SYSUNI CHAIN
HRRZ U,UNI2ND(U) ;DETACHING PRIMARY PORT, GET 2ND PORT ADDRESS
PUSHJ P,LNKSUN ;LINK UNIT ONTO SYSUNI CHAIN
POP P,U ;RESTORE UNIT BEING DETACHED
SETZM UNILOG(U) ;CLEAR STUFF SO SYSTAT WONT DO WIERD THINGS
SETZM UNIHID(U)
HRRZ T1,UNI2ND(U)
SETZM UNI2ND(U) ;CLEAR INFO ABOUT DUAL-PORTEDNESS
SETZM UNI2ND(T1)
AOS T2,SYSGEN## ;MAKE CHEKU FAIL
HRRZM T2,UNIGEN(U)
JUMPL U,DETDS3 ;NO SWEAT IF DETACHING A 2ND PORT
UUONLK ;CAN LET UPDA THROUGH NOW
PUSHJ P,CSDELU ;INVALIDATE DISK CACHE FOR THIS UNIT
PUSHJ P,ADJUD ;ADJUST UNISTR, UNISWP LINKS
;FALL INTO DETDS3
> ;END IFN FTDUAL
;UNLINK FROM SYSUNI, LINK TO SYSDET
DETDS3:
IFN FTCIDSK,<
DETUDB:: ;ENTRY FROM ONCMOD FOR CI DISKS
>; END IFN FTCIDSK
PUSH P,T1 ;PRESERVE T1 (SECOND PORT ADDRESS)
PUSHJ P,UNLSUN ;UNLINK UNIT FROM SYSUNI CHAIN
PUSHJ P,LNKSDT ;LINK UNIT ONTO SYSDET CHAIN
POP P,T1 ;RESTORE T1
MOVEI T2,UNVDWN ;INDICATE DETACHED UNIT IS DOWN
DPB T2,UNYUST##
HRRZ T2,LASUNI ;LAST UNIT CONFIGURED
CAIN T2,(U) ;ONE WE'RE DETACHING?
SETZM LASUNI ;YES, LET AUTCON WORK HARDER
IFN FTCIDSK,<
SKIPE DINITF## ;ONCE-ONLY?
POPJ P, ;YES, RETURN NOW
>; END IFN FTCIDSK
IFN FTMDA,<PUSHJ P,DSKMPD> ;NOTIFY MDA OF LOSS
MOVEI T1,.CSCDT ;CODE TO SAY DETACH
PUSHJ P,DSKCSC ;CALL DAEMON
POP P,U
PJRST CPOPJ2## ;AND RETURN
SUBTTL ATTACH A KONTROLLER
;HERE TO PUT A KONTROLLER ON-LINE
;P1 = KDB ADDRESS
;RETURN CPOPJ1 ALWAYS
;CLOBBERS P1
ATTKON::MOVE P1,KDBIUN(P1) ;GET POINTER TO UNITS
ATTKO1: SKIPN U,(P1) ;GET NEXT UNIT ON KON
JRST ATTKO2 ;TRY AGAIN
PUSHJ P,ATTCPD ;ATTACH IT
JFCL ;ERROR
JFCL ;OTHER ERROR (DON'T CARE)
ATTKO2: AOBJN P1,ATTKO1 ;LOOP OVER ALL UNITS ON THIS KONTROLLER
JRST CPOPJ1## ;RETURN SUCCESS
SUBTTL ATTACH A UNIT
;HERE TO ATTACH A UNIT
;RETURNS NON-SKIP IF UNIT IS DOWN
;CPOPJ1 IF WE CANT CALL CPY ROUTINE NOW SINCE NOT AT UUO LEVEL (TRY LATER)
;CPOPJ2 IF ALL IS OK
ATTCPD::PUSH P,U ;SAVE U
JRST ATTUN0 ;JOIN COMMON CODE
ATTDSK::PUSHJ P,COMUNT ;SET UP U
JRST [TLO U,400000 ;NO MATCH
POPJ P,]
ATTUN0: LDB T1,UNYUST## ;GET UNIT STATUS
CAIN T1,UNVNPM ;ALREADY ATTACHED?
JRST [AOS -1(P) ;YES, SET FOR OK RETURN
JRST UPOPJ1##] ;DOUBLE SKIP RETURN
CAIE T1,UNVDWN ;DOWN?
JRST UPOPJ## ;NO, CANT ATTACH IT
PUSH P,J ;YES, SAVE J FOR COMCON
ATTUN3: MOVE J,UDBKDB(U) ;KONTROLLER DATA BLOCK
SKIPGE KONCPY(J) ;CAN WE CALL CPY ROUTINE IF KONTROL BUSY?
SKIPL KONBSY(J) ;NO, IS KONTROLLER BUSY?
SKIPA ;WE CAN TELL UNIT TYPE NOW
JRST [PUSHJ P,UUOLVL## ;CALLED FROM UUO (COMMAND) LEVEL?
JRST ATTUN7 ;NO, MUST BE CALL FROM SPRINI
PUSHJ P,SLPJIF ;SLEEP FOR A JIFFY
JRST ATTUN3] ;GO BACK AND TRY AGAIN
IFN FTMP,<
PUSHJ P,UUOLVL## ;CALLED FROM UUO (COMMAND) LEVEL?
JRST ATTUN6 ;NO, MUST BE CALL FROM SPRINI
MOVE T1,UDBCAM(U) ;CPU(S) UNIT IS ON
PUSHJ P,CPUOK## ;FIND A LIVE CPU
JRST ATTUN9 ;ALL DEAD
PUSHJ P,ONCPUS## ;PUT US ON THAT CPU
JRST ATTUN9 ;DEAD (CAN'T HAPPEN)
>
ATTUN6: PUSHJ P,@KONCPY(J) ;DETERMINE UNIT TYPE, CAPACITY
JRST ATTUN5 ;UNIT DOWN
MOVEM T1,UNIBPU(U) ;SAVE BLOCKS PER UNIT
MOVEM T2,UNIBPM(U) ;SAVE BLKS PER UNIT INCL. MAINT CYLS
MOVEM T3,UNIBUC(U) ;SAVE BLOCKS PER UNIT IN 10/11 COMPAT. MODE
DPB W,UNYBPY## ;SAVE # BLOCKS PER CYLINDER
HLRZ T3,W ;NO OF BLOCKS PER TRACK
DPB T3,UNYBPT## ;BLOCKS/TRACK
DPB T4,UNYUTP## ;UNIT TYPE
MOVSI T1,KOPDWN ;CLEAR KONTROL-IS-DOWN BIT
ANDCAM T1,KONDWN(J)
ATTUN1: AOS -2(P) ;CPOPJ2 IS GOODNESS
MOVEI T1,UNVNPM ;INDICATE NO PACK MOUNTED
DPB T1,UNYUST## ; (EG, UNIT IS UP)
MOVSI T1,UNPOFL!UNPWMD
ANDCAM T1,UNIUST(U)
SETZM UNISTS(U)
PUSHJ P,UNLSDT ;UNLINK UDB FROM SYSDET CHAIN
PUSHJ P,LNKSUN ;LINK UDB ONTO SYSUNI CHAIN
IFN FTDUAL,<
PUSHJ P,MATUN ;SEARCH FOR A MATCH
JRST ATTUN4 ;FINISH UP
JRST ATTUN8
ATTMX: PUSH P,U
PUSH P,J
PUSH P,T2 ;SAVE SECOND PORT
PUSHJ P,UNLSDT ;UNLINK UDB FROM SYSDET CHAIN
PUSHJ P,LNKSUN ;LINK UDB ONTO SYSUNI CHAIN
POP P,T2 ;RESTORE SECOND PORT
ATTUN8: PUSHJ P,LN2ND ;SETUP UNI2ND LINKS FOR THIS DRIVE
; AND UNLINK SECOND PORT FROM UNISYS CHAIN
>; END FTDUAL
ATTUN4: PUSHJ P,CSDELU ;INVALIDATE DISK CACHE FOR THIS UNIT
;(SHOULDNT HAVE ANY, BUT..)
IFN FTMDA,<PUSHJ P,DSKMPA> ;INDICATE DISK DRIVE ATTACHED
POP P,J ;RESTORE J
MOVEI T1,.CSCAT ;CODE TO SAY ATTACH
PUSHJ P,DSKCSC ;CALL DAEMON
JRST UPOPJ1## ;RESTORE U AND RETURN
ATTUN5: MOVEI T1,UNVDWN ;UNIT IS STILL DOWN - SET THE BYTE
DPB T1,UNYUST## ;IN UNISTS AGAIN
POP P,J
JRST UPOPJ## ;NON-SKIP RETURN
;HERE IF CONTROLLER BUSY - TRY AGAIN LATER
ATTUN7: AOS -2(P) ;SET FOR CPOPJ1 RETURN
;FALL INTO ATTUN9
;HERE IF THE CPU IS DEAD
ATTUN9: POP P,J
POP P,U
TLO U,400000
POPJ P,
;ROUTINE TO SET UP U FOR THE COMMAND
;RETURNS WITH ORIGINAL U ON PD LIST
COMUNI: PUSHJ P,SETLGL## ;PRIV'D JOB?
POPJ P, ;NO, ERROR RETURN
PUSHJ P,CTXDEV## ;YES, GET DEVICE TYPED BY USER
MOVE T1,T2 ;DEVICE INTO T1 FOR DEVSRC
COMUNT: EXCH U,(P) ;SAVE U ON LIST
PUSH P,U
SETO T2, ;NEED A COMPLETE MATCH ON UNIT NAME
PUSHJ P,SRUNA## ;FIND MATCHING UNIT
JFCL ;NO SUCH UNIT
CAIA ;LOGICAL MATCH
JRST CPOPJ1## ;PHYSICAL MATCH - GOOD RETURN
MOVE U,(P) ;RESTORE U
EXCH U,-1(P)
JRST T2POPJ## ;TAKE GARBAGE OFF STACK AND BADNESS-RETURN
;ROUTINE TO CALL DAEMON FOR DISK CONFIGURATION STATUS CHANGE
;CALL WITH CODE FOR ATT, DET, XCH IN RH(T1), F + U SETUP
DSKCSC: SKIPE DINITF## ;DON'T DO THIS DURING INITIALIZATION
POPJ P, ;QUIT NOW
MOVSI T4,(T1) ;GET LH SUB-CODE FOR DAEMON
CAIE T1,.CSCXC ;IF NOT EXCHANGE,
TDZA T3,T3 ;THEN NO SECOND UNIT TO REPORT
MOVE T3,UDBNAM(F) ;ELSE GET NAME OF SECOND UNIT
XMOVEI T2,CSCBEG ;POINT TO OUR TRANSFER TABLE
SETZ T1, ;WE HAVE NOT ALLOCATED THE ERROR BLOCK
PUSHJ P,XFRSEB## ;MAKE AN ERROR ENTRY
POPJ P, ;PUNT IF NO CORE
POPJ P, ;ALREADY GAVE IT TO DAEMON--JUST RETURN
CSCBEG: SEBTBL(.ERCSC,CSCEND,EX.QUE!EX.SYE!EX.AVL)
MOVE UDBNAM(U) ;(R00) FIRST UNIT NAME
MOVE T3 ;(R01) SECOND UNIT NAME OR ZERO
MOVE T4 ;(R02) SUB-CODE,,0
CSCEND:!
IFN FTDUAL,< ;GOES ON FOR SEVERAL PAGES
;ROUTINE TO TEST IF MATCHING SERIAL-NUMBERS (EG DUAL-PORTED DRIVES) EXIST
;CALL WITH U=UNIT
;RETURNS CPOPJ IF NO MATCH
;RETURNS CPOPJ1 IF A MATCH, T2= MATCHING UNIT
;PRESERVES T4
MATUN:: SKIPN UDBDSN(U) ;NO MATCH IF NO SERIAL NUMBER
SKIPE UDBDSN+1(U) ;...
SKIPA ;A SERIAL NUMBER, GO FOR IT
POPJ P, ;NO SERIAL NUMBER, NO MATCH
HLRZ T2,SYSUNI## ;START AT FIRST UNIT IN SYSTEM
MATUN1: MOVE T1,UDBDSN(U) ;GET FIRST WORD OF SERIAL NUMBER
MOVE T3,UDBDSN+1(U) ;AND SECOND WORD
CAMN T1,UDBDSN(T2) ;MATCH?
CAME T3,UDBDSN+1(T2) ;BOTH WORDS?
JRST MATUN2 ;NO MATCH
CAIE T2,(U) ;FOR A DIFFERENT UNIT?
JRST MATUN3 ;FOUND A MATCH.
MATUN2: HLRZ T2,UNISYS(T2) ;STEP TO NEXT UNIT
JUMPN T2,MATUN1 ;AND TEST IT
POPJ P, ;NO MATCH, NON-SKIP
MATUN3: LDB T1,UNYUTP## ;GET UNIT TYPE
EXCH T2,U ;SWAP UDB ADDRESSES A MOMENT
LDB T3,UNYUTP## ;GET UNIT TYPE
EXCH T2,U ;UDB ADDRESSES BACK AS THEY WERE
CAME T1,T3 ;SAME UNIT TYPE?
JRST MATUN2 ;NO, NOT REALLY DUAL PORTED
MOVE T3,UDBPDN(U) ;UNIT NO OF 1ST PORT
XOR T3,UDBPDN(T2) ;DOES IT MATCH UNIT NO OF 2ND PORT?
TRNE T3,-1 ;CHECK FOR DIFFERENCE IN PHYSICAL UNIT NUMBER
JRST MATUN2 ;NO, NOT REALLY DUAL PORTED
HRRM T2,UNIALT(U) ;SET UP UNIALT LINK NOW
HRRM U,UNIALT(T2) ;...
IFN FTCIDSK,<
LDB T1,UNYKTP## ;GET KONTROLLER TYPE
CAIN T1,TYPRA ;CI DISK?
POPJ P, ;YES, NOT REALLY DUAL PORTED
>; END IFN FTCIDSK
JRST CPOPJ1## ;NO, MATCH
;ROUTINE TO SETUP THE UNI2ND LINKS FOR A DRIVE THAT IS DUAL PORTED.
;ALSO COPIES THE NEEDED INFORMATION TO THE SECOND PORT OF THE UNIT
;AND UNLINKS THE SECOND PORT FROM THE UNISYS CHAIN.
;CALL WITH U=UDB ADDRESS OF SECOND PORT, T2=UDB ADDRESS OF 1ST PORT.
; J=KDB ADDRESS CORRESPONDING TO U
;RETURNS CPOPJ ALWAYS
;PRESERVES U, T1-T4
LN2ND:: DSKOFF
PUSHJ P,SAVT## ;SAVE T1-T4
PUSH P,U ;SAVE UDB ADDRESS
EXCH U,T2 ;MAKE U=SOURCE, T2=DESTINATION
PUSHJ P,CPYUD ;COPY NEEDED DATA TO 2ND PORT
EXCH U,T2 ;PUT THEM BACK
HRRZM U,UNI2ND(T2) ;POINT MAIN UNIT AT THIS ONE
TLO T2,(1B0)
MOVEM T2,UNI2ND(U) ;POINT THIS UNIT AT MAIN UNIT
PUSHJ P,UNLSUN ;UNLINK FROM SYSUNI CHAIN
DSKON
JRST UPOPJ## ;RESTORE U AND RETURN
;ROUTINE TO ADJUST THE STRUCTURE AND ACTIVE SWAPPING LINKED LISTS
;WHEN THE OTHER PORT OF A DUAL PORTED UNIT BECOMES THE PRIME PORT.
;CALL WITH U=ADDRESS OF SOURCE UDB, T1=ADDRESS OF DESTINATION UDB.
;PRESERVES ALL AC'S
ADJUD: PUSHJ P,SAVT## ;SAVE THE T AC'S
MOVEI U,(U) ;MAKE SURE LH OF U IS ZERO
HRRZ T2,UNISTR(U) ;GET THE STR DATA BLOCK ADDRESS
JUMPE T2,ADJUD2 ;NOTHING TO DO IF NOT IN A STRUCTURE
SUBI T2,UNISTR-STRUNI## ;OFFSET FOR INDEX BELOW
ADJUD1: HRRZ T3,T2 ;COPY THE CURRENT UDB ADDRESS
HLRZ T2,UNISTR(T2) ;STEP TO THE NEXT ONE
JUMPE T2,ADJUD2 ;QUIT AT END OF LIST
CAIE T2,(U) ;FIND THE ONE BEING DETACHED?
JRST ADJUD1 ;NO, KEEP TRYING
HRLM T1,UNISTR(T3) ;POINT IT AT THE NEW UDB
ADJUD2: MOVSI T4,MSWPMX## ;BUILD AOBJN POINTER TO SWPTAB
ADJUD3: CAME U,SWPTAB##(T4) ;FIND A MATCH?
AOBJN T4,ADJUD3 ;NO, TRY NEXT
MOVEI T2,SWPUNI##-UNISWP ;START AT BEGINNING OF SWAPING LIST
ADJUD4: HRRZ T3,T2 ;COPY CURRENT UDB ADDRESS
HLRZ T2,UNISWP(T2) ;STEP TO NEXT ONE
JUMPE T2,ADJUD5 ;QUIT AT END OF LIST
CAIE T2,(U) ;FIND A MATCH?
JRST ADJUD4 ;NO, TRY NEXT
HRLM T1,UNISWP(T3) ;STORE NEW UDB ADDRESS IN PREVIOUS
SKIPGE T4 ;FIND A MATCH IN SWPTAB
HRRZM T1,SWPTAB##(T4) ;YES, PUT OTHER UDB THERE
HRLM T1,NXTSUN## ;ENSURE NO PNTR TO OTHER PORT
ADJUD5: HLRZ T2,SWPUN2## ;GET FIRST OF SLOW SWAPPING UNITS?
CAIN T2,(U) ;IS IT THE ONE BEING DETACHED?
HRLM T1,SWPUN2## ;YES, STORE NEW UDB ADDRESS
POPJ P, ;RETURN
;UNIT FAILOVER ROUTINE
;CALL WITH U = NEW UDB
;THIS ROUTINE WILL ATTACH THE NEW UNIT AND DETACH THE OLD ONE
IFN FTCIDSK,<
FLPUDB::HRRZ T2,UNIALT(U) ;T2=OLD UDB
JUMPE T2,CPOPJ## ;NONE
LDB T1,UNYUST## ;STATUS OF NEW UNIT
LDB T3,UNXUST## ;STATUS OF OLD UNIT
CAIE T3,UNVDWN ;OLD UNIT MUST BE UP
CAIN T1,UNVPIM ;NEW UNIT MUST BE NOT 'PACK IS MOUNTED'
POPJ P, ;NO, IT'S ALREADY THE PRIME PORT
MOVE T1,UNISTS(T2) ;PUT NEW UDB IN OW
MOVEM T1,UNISTS(U)
PUSHJ P,ATTMX ;ATTACH NEW UDB
JFCL
HRRZ T1,UNIALT(U) ;T1=OLD UDB
EXCH T1,U ;U=OLD, T1=NEW
PUSHJ P,DETMX ;DETACH OLD UDB
JFCL
JFCL
MOVEI T1,ACTDRB##-DRBLNK## ;PRESET PRED
DSKOFF
FLUDB1: HRRZ T1,DRBLNK##(T1) ;#STEP TO THE NEXT DRB
CAIN T1,ACTDRB##
JRST DOPOPJ ;#NONE
MOVE T2,DRBSTS##(T1) ;#WAITING FOR RETRY?
HRRZ T3,DRBCDA##(T1) ;#AND SWAPPER?
TRNE T2,DRPTRY##
CAIE T3,SWPDDB##
JRST FLUDB1 ;#NO, TRY NEXT DRB
HLRZ T2,DRBCUR##(T1) ;#UNIT OF DRB
CAME T2,U ;#DRB IS FOR OLD UNIT?
JRST FLUDB1 ;#NO, NEXT DRB
HRRZ T3,UNIALT(U) ;#YES, NEW UNIT
HRLM T3,DRBCUR##(T1) ;#SWITCH DRB TO NEW UNIT
IFN FTMP,<
LDB T2,DRYCPU## ;#ORIGINAL CPU
MOVEI T4,1 ;#BIT MASK
LSH T4,(T2)
TDNE T4,UDBCAM(T3) ;#CAN ORIGINAL CPU DO IT?
JRST FLUDB1 ;#YES, NO PROBLEM
PUSH P,T1 ;#NO, FIND A CPU THAT CAN
MOVE T1,UDBCAM(T3)
PUSHJ P,CAMCPU##
MOVE T2,T1 ;GET CPU NUMBER
POP P,T1
DPB T2,DRYCPU## ;#RESWP WILL WAIT FOR CACHE TO BE RIGHT
>; END IFN FTMP
JRST FLUDB1 ;#NEXT DRB
>; END IFN FTCIDSK
;ROUTINES TO COPY INFORMATION FROM ONE UDB OF A DUAL PORTED DISK DRIVE
;TO THE OTHER. CPYUD COPIES ALL NECESSARY INFORMATION. CPYST ONLY
;COPIES STRUCTURE RELATED INFORMATION.
;CALL WITH U=SOURCE UDB ADDRESS, T2=DESTINATION UDB ADDRESS.
;DESTROYS T1
CPYST:: SKIPA T1,[-CSTTBL,,CSTTAB] ;GET AOBJN POINTER FOR CSTTAB
CPYUD:: MOVE T1,[-CUDTBL,,CUDTAB] ;DITTO FOR CUDTAB
PUSH P,T3 ;SAVE T3
CPYUD1: LDB T3,(T1) ;GET NEXT BYTE FROM SOURCE UDB
EXCH U,T2 ;EXCHANGE UDB ADDRESSES
DPB T3,(T1) ;STORE IN DESTINATION UDB
EXCH U,T2 ;PUT THEM BACK
AOBJN T1,CPYUD1 ;LOOP FOR ALL
JRST T3POPJ## ;RESTORE T3 AND RETURN
;THE FOLLOWING TABLE DEFINES THE FIELDS IN THE UDB THAT MUST BE
;COPIED TO THE SECOND PORT OF A DISK WHEN A UNIT IS DUAL PORTED OR
;WHEN THE STATUS OF A UDB CHANGES, E.G., DETACH. CUDTAB IS USED WHEN
;ALL PARAMETERS ARE TO BE COPIED, CSTTAB IS USED TO COPY ONLY STRUCTURE
;RELATED PARAMETERS.
CUDTAB: POINT 36,UNISWP(U),35
POINT 36,UNIFKS(U),35
POINT 36,UNIHOM(U),35
POINT 18,UNIGRP(U),17
; POINT 36,UNIBPU(U),35 ;SETUP BY RETURN FROM KONCPY
; POINT 36,UNIBPM(U),35 ; DITTO
POINT 36,UNICPS(U),35
POINT 36,UNISAB(U),35
POINT 36,UNISPT(U),35
POINT 36,UNITAL(U),35
POINT 18,UNIDES(U),17
POINT 36,UNIPTR(U),35
POINT 36,UNISLB(U),35
POINT 36,UNIBUC(U),35
POINT 36,UNIAJB(U),35
IFN FTXMON,<
POINT 9,UNISNS(U),8
>; END IFN FTXMON
POINT 36,UNIGEN(U),35
CSTTAB: POINT 36,UNILOG(U),35
POINT 36,UNIHID(U),35
POINT 36,UNISTR(U),35
POINT 18,UNISYS(U),35
POINT 36,UNIBPC(U),35
CUDTBL==.-CUDTAB
CSTTBL==.-CSTTAB
>; END IFN FTDUAL
SUBTTL ROUTINES TO MANIPULATE SYSUNI AND SYSDET CHAINS
;ROUTINE TO UNLINK A UNIT FROM THE SYSUNI OR SYSDET CHAIN.
;ENSURES UNIT IS ALREADY ON CHAIN BEFORE UNLINKING IT.
;CALL WITH UDB ADDRESS IN U.
UNLSUN: SKIPA T1,[SYSUNI##-UNISYS] ;SET PREDECESSOR
UNLSDT: MOVEI T1,SYSDET##-UNISYS ;SET PREDECESSOR
UNLSY1: HLRZ T2,UNISYS(T1) ;GET LINK TO NEXT UNIT
JUMPE T2,CPOPJ## ;RETURN IF NOT LINKED ONTO THIS CHAIN
CAIN T2,(U) ;FOUND DESIRED UNIT?
JRST UNLSY2 ;YES
MOVE T1,T2 ;RESET PREDECESSOR
JRST UNLSY1 ;KEEP LOOKING
UNLSY2: MOVE T2,UNISYS(U) ;GET LINK TO NEXT UNIT
HLLM T2,UNISYS(T1) ;LINK NEXT UNIT TO PREDECESSOR
HRRZS UNISYS(U) ;CLEAR OUT ANY LINKS IN THIS UDB
POPJ P, ;RETURN
;ROUTINE TO LINK A UNIT ONTO THE SYSUNI OR SYSDET CHAIN.
;ENSURES UNIT IS NOT ALREADY LINKED ONTO THE CHAIN.
;CALL WITH UDB ADDRESS IN U.
LNKSUN: SKIPA T1,[SYSUNI##-UNISYS] ;SET PREDECESSOR
LNKSDT: MOVEI T1,SYSDET##-UNISYS ;SET PREDECESSOR
MOVE T2,T1 ;COPY PREDECESSOR FOR ACTUAL LINKING
LNKSY1: HLRZ T1,UNISYS(T1) ;GET LINK TO NEXT UNIT
JUMPE T1,LNKSY2 ;IF NOT FOUND, OK TO PROCEED
CAIN T1,(U) ;FOUND DESIRED UNIT?
POPJ P, ;YES, ALREADY ON CHAIN, DO NOTHING
CAIG T1,(U) ;GONE PAST THE DESIRED UDB?
MOVE T2,T1 ;NO, RESET PREDECESSOR
JRST LNKSY1 ;KEEP LOOKING
LNKSY2: HLLZ T1,UNISYS(T2) ;GET LINK TO NEXT UNIT OF PREDECESSOR
HLLM T1,UNISYS(U) ;LINK NEXT UNIT TO THE DESIRED UDB
HRLM U,UNISYS(T2) ;NOW LINK DESIRED UDB TO PREDECESSOR
POPJ P, ;DONE
SUBTTL USETI/USETO
USETI0::SKIPGE DEVSPL(F) ;IF THIS IS A SPOOLED DDB,
POPJ P, ;USETI IS A NO-OP
PUSHJ P,NULTST## ;USETI NUL: WINS
POPJ P,
PUSHJ P,WAIT1## ;MAKE SURE ALL I/O IS DONE
TLNN F,LOOKB ;LOOKUP DONE?
JRST SETSUP ;NO. SUPER USETI IF PRIVILEGED
PUSHJ P,SETU ;SET UP U FROM DDB
POPJ P, ;UNIT WAS REMOVED
PUSHJ P,CLSNAM## ;SET RIGHT NAME IN DDB FOR RIBCHK
; (FILE MIGHT BE RENAMED)
HRRZ T1,DEVACC##(F) ;YES. LOC OF ACCESS TABLE
PUSHJ P,SAVE1## ;SAVE P1
MOVE P1,W ;GET USETI ARGUMENT TO P1
CAMGE P1,MUSTMX## ;SKIP IF RH(M) POSSIBLE EXTEDNED RIB
JRST USETI4 ;NOT LOOKING FOR EXTENDED RIBS
AOJGE P1,USETI4 ;IF -1 OR POSITIVE, NOT EXTENDED
HRRZ U,DEVUNI##(F) ;GET CURRENT UNIT
PUSHJ P,PTRTST ;READ POINTERS, RE-WRITE IF CHANGED
POPJ P, ;ERROR READING RIB
SKIPL DEVRIB##(F) ;PRIME RIB?
JRST USETI2 ;YES, GET EXTENDED
PUSHJ P,REDRIB ;NO, READ PRIME RIB
POPJ P, ;ERROR READING RIB
USETI2: PUSHJ P,PTRNXT ;GET EXTENDED RIB
JRST USETI3 ;EITHER RIB ERROR OR NONE
AOJN P1,USETI2 ;JUMP BACK IF NOT THIS RIB
MOVE U,T2 ;(NEW) UNIT
PUSHJ P,STORU ;PUT IN DDB
PUSHJ P,PTRBLT ;GET POINTERS TO DDB
MOVE T1,.USMBF ;IOWD TO MONITOR BUFFER
MOVE T2,RIBFLR##+1(T1) ;GET RELATIVE BLOCK NUMBER OF RIB
MOVE T3,T2 ;ALSO GET TOT3 FOR SCNPTR
MOVEI T1,DEVRB1##(F) ;ADDRESS OF IN CORE POINTERS
HRLI T1,MPTRLN## ;MAKE AOBJN WORD
PUSHJ P,SCNPTR ;SET UP DEVBLK, DEVREL, DEVLFT
POPJ P, ;REALLY OUGHT TO BE A STOPCD
MOVNS DEVREL##(F) ;FLAG SO OUTPUT NEXT IS ILLEGAL
TLZ S,IOSFIR ;RIBS AREN'T CHECKSUMMED
JRST USETI7 ;AND EXIT.
USETI3: JUMPN T3,CPOPJ## ;GO IF RIB ERROR
TRO S,IOBKTL ;NON-EXISTANT RIB, GIVE HIMM ERROR
PJRST INPSW8## ;POINT AT BLOCK ONE
USETI4: MOVE P1,ACCWRT##(T1) ;HIGHEST RELATIVE BLOCK WITH DATA IN THE FILE
JUMPL W,USETI5 ;OK UNLESS USETI -1
CAML P1,W ;ASKING FOR A BLOCK PAST EOF?
TLOA P1,400000 ;NO, SET P1 NEGATIVE AS A SWITCH
USETI5: MOVE W,P1 ;YES, INITIALLY SCAN FOR LAST BLOCK
PUSHJ P,USET00 ;FIND THE PNTR TO THE BLOCK
POPJ P, ;RIB ERROR
SKIPL DEVBLK##(F)
JRST USETI6
MOVEM W,DEVREL##(F)
PUSHJ P,FNDPTR
POPJ P,
USETI6: JUMPL P1,USETI7 ;GO IF NOT PAST EOF
AOS DEVBLK##(F) ;PAST EOF - UPDATE PNTRS IN DDB
AOS DEVREL##(F) ;SO NEXT INPUT/OUTPUT WILL GET LAST BLOCK
SOS DEVLFT##(F) ; OF FILE PLUS 1
TLZ S,IOSFIR
TDOA S,[XWD IOEND,IODEND] ;INDICATE USETI PAST EOF
USETI7: TDZ S,[XWD IOEND,IODEND] ;OK - ZERO EOF BITS
PUSHJ P,EXTCKS ;LIGHT IOSFIR IF 1ST BLOCK IN EXT. RIB
PJRST STOIOS## ;STORE S AND TAKE GOOD RETURN
USETO0::SKIPGE DEVSPL(F) ;IF THIS IS A SPOOLED DDB,
POPJ P, ; USETO IS A NOOP
PUSHJ P,NULTST##
POPJ P, ;NUL WINS
PUSHJ P,WAIT1## ;WAIT FOR I/O TO FINISH
TLNN F,ENTRB ;ENTER BEEN DONE?
JRST SETSUP ;NO. (FIRST) SUPER USETO IF LEGAL
MOVE T1,W ;YES, ARGUMENT
AOJN T1,USETO2 ;USETO -1 MEANS LAST BLOCK XFERRED
MOVE T1,DEVREL##(F) ;IS THERE A LAST BLOCK?
SOJG T1,USETO1 ;YES, DO A USETO TO IT
MOVE T1,DEVACC##(F) ;NO, UPDATE FILE?
HRLZ T1,ACCSTS##(T1)
TLNE T1,ACPUPD
HLRZ T1,DEVLRL##(F) ;YES. GET DEVREL BEFORE ENTER
USETO1: MOVE W,T1 ;DO USETO TO THAT BLOCK
USETO2: MOVE T1,DEVACC##(F) ;LOC OF A.T
MOVE T1,ACCWRT##(T1) ;HIGHEST WRITTEN BLOCK
CAML T1,W ;TRY TO SETO PAST HIGHEST.
JRST USETO3 ;NO, OK
PUSH P,W ;YES. FIRST FIND HIGHEST
MOVE W,T1 ;SO THAT LAST RIB WILL BE
PUSHJ P,USET00 ;READ AND DEYRBC SET RIGHT
PJRST TPOPJ## ;RIB ERROR
POP P,W ;RESTORE W
PUSHJ P,GETALC ;GET ADJUSTED ACCALC
CAMG T1,W ;WANT ONE BELOW HIGHEST?
JRST USET11 ;NO. HAVE TO ALLOCATE
USETO3: PUSHJ P,USET00 ;YES. SET UP CORRECT POINTERS
POPJ P, ;RIB ERROR
AOSE DEVBLK(F) ;IF DEVBLK=-1, CAN'T FIND BLOCK
JRST USETO4 ;USETO TO ALLOCATED BLOCKS
PUSHJ P,GETALC ;SINCE ANOTHER JOB MAY HAVE ALLOCATED,
CAMG T1,W ; AND ACCWRT ISN'T YET TO ITS FINAL VALUE,
JRST USET11 ; WE MUST REPEAT THE TEST (DEVRIB NOW POINTS TO LAST RIB)
;HERE IF DOING A USETO TO LAST BLOCK IN RIB
PUSHJ P,USETO5 ;ZERO ALLOCATED, UNWRITTEN BLOCKS
SUBI W,1 ;POINT W TO LAST "REAL" BLOCK
PUSHJ P,USET00 ;GET POINTERS INTO CORE (SHOULD ALSO GET HIGHEST)
POPJ P, ;RIB ERROR
MOVE T3,DEVLPC##(F) ;GET LAST POINTER IN CORE FLAG
TLZN T3,DEPLPC## ;CLEAR IT TO FOOL SCNPTR
STOPCD CPOPJ##,DEBUG,DBZ, ;++DEPLPC BIT ZERO
MOVEM T3,DEVLPC##(F) ;RETURN TO DDB
MOVE T3,W ;GET LAST BLOCK ALLOCATED
ADDI T3,1
MOVE T2,DEVFLR##(F) ;INITIAL BLOCK IN DDB
MOVEI T1,DEVRB1##(F) ;SCAN POINTERS IN DDB
HRLI T1,MPTRLN## ;STARTING AT DEVRB1
PUSHJ P,SCNPTR ;FIND THE POINTER
STOPCD .+1,DEBUG,HIF, ;++HOLE IN FILE
HRRZM T1,DEVRET##(F) ;SET DEVRET TO LAST POINTER
HRROS DEVRSU##(F) ;SET DEVRSU TO -1
HLLZS DEVLFT##(F) ;CLEAR DEVLFT SO NXTBLK WILL NOT FIND
MOVSI T1,DEPLPC## ;LIGHT DEPLPC AGAIN
IORM T1,DEVLPC##(F) ;IN DDB
POPJ P, ;AND EXIT
USETO4: SOS DEVBLK##(F) ;RETURN DEVBLK TO PROPER VALUE
PUSHJ P,EXTCKS ;SET IOSFIR IF FIRST BLOCK IN EXTENDED RIB
MOVEM S,DEVIOS(F) ;SAVE S
;CHECK TO SEE IF A USETO IS SETTING OUTOUT PAST THE LAST BLOCK WRITTEN
; IF SO, WRITE 0'S IN THE INTERVENING BLOCKS
USETO5: SKIPN T1,W ;SETTING BLOCK 0?
POPJ P, ;YES. THIS IS NON-ALLOCATING
SUBI T1,1 ;LAST BLOCK TO ZERO
HRRZ T2,DEVACC##(F) ;LOC OF A.T.
CAMG T1,ACCWRT##(T2) ;PAST HIGHEST BLOCK WRITTEN?
POPJ P, ;NO, OK
PUSHJ P,SAVE2## ;YES, SAVE SOME ACS
HRRZ P1,DEVACC##(F) ;LOC OF A.T.
MOVE P2,T1 ;HIGHEST BLOCK TO ZERO
MOVE T1,.USMBF ;MAKE SURE WE ZERO MONITOR BUFFER
SETOM 1(T1)
USETO6: MOVE T1,ACCWRT##(P1) ;BLOCK-1 TO ZERO
AOS W,T1 ;BLOCK WE WANT TO ZERO
PUSHJ P,USET00 ;SET DEVBLK FOR THIS BLOCK
POPJ P, ;RIB ERROR
SKIPGE DEVBLK##(F) ;SEMI-GOOD RETURN!
POPJ P, ;SHOUD NEVER HAPPEN, BUT....
IFN FTKL10,<
MOVE T1,UDBKDB(U)
MOVE T1,KDBCHN(T1)
MOVE T1,CHNTYP(T1)
HRR T1,ACCSTS##(P1)
TLNE T1,CP.RH2 ;IF THE DEVICE IS NOT ON AN RH20
TRNE T1,ACPSMU ; OR IS SIMULTANEOUS ACCESS
JRST USETO8 ;DON'T TRY TO ZERO MULTIPLE BLOCKS AT ONCE
IFN FTDUAL,<
SKIPN T1,UNI2ND(U) ;IF A DUAL-PORTED DISK
JRST USETO7
MOVE T1,UDBKDB(T1) ; IF THE 2ND PORT IS ON AN RH10
MOVE T1,KDBCHN(T1)
MOVE T1,CHNTYP(T1) ; DO IT 1 BLOCK AT A TIME
TLNN T1,CP.RH2 ; BECAUSE THE RH10 WON'T SUPPORT THE HACK
JRST USETO8 ; WE WANT TO USE (WRITE 0'S THROUGH MANY BLOCKS)
> ;END IFN FTDUAL
USETO7: HRRZ T1,DEVLFT##(F) ;SHOULD BE EASY TO DO MULTIPLE
MOVE T2,P2
ADDI T2,1 ;HIGHEST BLOCK TO ZERO
SUB T2,DEVREL##(F) ;MINUS WHERE WE NOW ARE
CAMLE T1,T2
MOVE T1,T2 ;JUST DO THIS MUCH
CAILE T1,LIMUSZ## ;MORE BLOCKS THAN THE MAX?
MOVEI T1,LIMUSZ## ;YES, USE MAX
MOVNS T1
LSH T1,^D18+BLKLSH## ;TURN IT INTO AN IOWD WHICH WILL ZERO-FILL
JRST USETO9 ;LET THE HARDWARE ZERO 15 BLOCKS IN 1 FELL SWOOP...
USETO8:> ;END IFN FTKL10
MOVE T1,.USMBF
SKIPN 1(T1) ;IS MON BUF ZERO? (USTRIB COULD READ)
JRST USETO9 ;DONT NEED TO DO ANYTHING MORE
MOVSI T2,1(T1) ;1ST WORD IN MON BUF
HRRI T2,2(T1) ;SET TO ZERO MON BUF
SETZM 1(T1)
BLT T2,BLKSIZ##(T1) ;ZERO THE BUFFER
;FALL INTO USETO9
;DROPS INTO HERE FROM PREVIOUS PAGE
USETO9: MOVE T2,DEVBLK##(F) ;BLOCK TO WRITE
CAMG W,ACCWRT##(P1) ;SOMEBODY JUST WRITE THE BLOCK?
JRST USET10 ;YES, WE'RE DONE
MOVSI T3,DEPUWZ## ;INDICATE USETO WRITING ZEROES
IORM T3,DEVUWZ##(F) ; IN CASE ANOTHER DDB IS CURRENTLY
; WRITING THIS BLOCK, ACCWRT NOT YET UPDATED
PUSHJ P,MONWRU ;WRITE A BLOCK OF 0'S (DONT GO THROUGH DISK CACHE)
TRNN S,IOIMPM+IOBKTL+IODTER+IODERR ;DID AN I/O ERROR OCCUR?
JRST USET9A ;NO
IFE FTKL10,<
POPJ P, ;NO RETRY IF NO RH20
>; END IFE FTKL10
IFN FTKL10,<
TRNE T1,-1 ;WAS I/O DONE VIA A CHANNEL SKIP?
POPJ P, ;NO, WE'VE ALREADY TRIED RECOVERY, QUIT
TRZ S,IOIMPM+IOBKTL+IODTER+IODERR ;CLEAR ERROR BITS FOR RETRY
JRST USETO8 ;TRY ACTUALLY WRITING THE BLOCKS
>; END IFN FTKL10
USET9A: LDB T1,DEYNBB## ;GET NUMBER OF BLOCKS ACTUALLY WRITTEN
SUBI T1,1 ;FILINT UPDATED THINGS ON THE BASIS OF A 1-BLOCK
ADDM T1,DEVBLK##(F) ; TRANSFER, SO UPDATE FOR THE OTHER BLOCKS DONE
ADDM T1,DEVREL##(F)
ADDM T1,ACCWRT##(P1)
MOVNS T1
ADDM T1,DEVLFT##(F)
MOVSI T3,DEPUWZ## ;USETO NOT NOW WRITING ZEROES
ANDCAM T3,DEVUWZ##(F)
MOVE T1,DEVREL##(F) ;IF THIS WRITE DIDN'T HAPPEN (REAL WRITER SNUCK IN)
CAMLE T1,ACCWRT##(P1) ; THEN DON'T CHANGE ACCWRT
AOS ACCWRT##(P1) ;BUMP NUMBER OF BLOCKS WRITTEN
LDB J,PJOBN## ;JOB NUMBER
MOVE T1,JBTSTS##(J) ;JBTSTS
TLNN T1,CNTRLC ;JOB TYPED ^C?
JRST USET10 ;NO
PUSH P,F
PUSHJ P,STOP1## ;RETURN TO MONITOR MODE
POP P,F ;RESTORE ACS WIPED BY STOP,
MOVE S,DEVIOS(F)
PUSHJ P,WSCHED## ;STOP JOB
;CONTINUE TYPED
;FALL INTO USET10
USET10: CAMLE P2,ACCWRT##(P1) ;HAVE WE FINISHED YET?
JRST USETO6 ;NO, WRITE NEXT BLOCK
AOS W,P2 ;YES, SET M FOR BLOCK WE ORIGINALLY WANTED
PUSHJ P,USET00 ;SET DDB POINTERS
POPJ P, ;RIB ERROR
MOVEM S,DEVIOS(F) ;SAVE S (NEW IOSFIR)
MOVE T2,DEVACC##(F) ;GET LOC OF A.T.
MOVEI T1,BLKSIZ## ;GET SIZE OF BLOCK
DPB T1,ACYLBS## ;FORCE AS FINAL BLOCK'S WORD COUNT
POPJ P, ;THROUGH - RETURN
;SUBROUTINE TO OBTAIN THE HIGHEST BLOCK ALLOCATED
;RETURNS WITH NUMBER IN T1
GETALC::MOVE T1,DEVACC##(F) ;LOC OF A.T
MOVE T1,ACCALC##(T1) ;ACCALC
LDB T2,DEYRBC## ;CURRENT RIB NUMBER
LSH T2,1 ;2 NON-DATA BLOCKS PER RIB
SUB T1,T2 ;ADJUST ACCALC
POPJ P, ;AND RETURN
UDSD==100 ;USER WANTS TO WRITE FORMAT
UDSX==200 ;FILIO WANTS TO WRITE FORMATS
IOSFA==:400 ;FILE HAS FA RESOURCE
MNTCYL==100000 ;ON IF USER WANTS MAINTENANCE CYLS
;HERE ON SUSET. UUO
USUSET::PUSHJ P,SAVE1##
MOVE W,M ;SAVE AC BYTE
MOVE M,T1 ;SAVE ARGUMENT
LDB P1,[POINT 9,M,12]
PUSHJ P,VALUUO ;DSK INITED ON THIS CHAN?
PJRST IOIERR## ;"IO TO UNASSIGNED CHAN"
PUSHJ P,WAIT1## ;WAIT FOR I/O TO COMPLETE (IOACT TO CLEAR)
TLO M,400000 ;INDICATE SUSET.
AOS (P) ;SET FOR SKIP (GOOD) RETURN
JRST SETSU1 ;AND DO SUPER USETI/O
SETSUP: MOVSI T1,DEPSIO## ;DEVICE OPENED FOR SUPER I/O?
TDNE T1,DEVPTB##(F)
JRST SETSU0 ;YES, BYPASS ILLEGAL INSTRUCTION PATCH
SKIPE DISSIO## ;WANT TO DISABLE SUPER USETI/USETOS?
JRST ILLINS## ;YES
SETSU0: TLNE F,ENTRB+LOOKB ;FILE OPEN?
JRST SETIMP## ;YES, GIVE HIM AN ERROR
SETSU1: HRRZ U,TABST0## ;LOC OF 1ST FS
HLRZ U,STRUNI##(U) ;U=LOC OF 1ST UNIT IN 1ST STR
MOVE T1,DEVNAM(F) ;NAME USER INITED
PUSHJ P,ALIASD## ;IS NAME AN ALIAS FOR "DSK"?
JRST SETIMP## ;YES, GIVE THE USER IO.IMP
PUSHJ P,SRSTR## ;NO. AN STR NAME?
SKIPA ;NO
JRST SETSU3 ;YES.
PUSHJ P,SRUNI## ;A UNIT NAME?
POPJ P, ;NO - RETURN WITHOUT DOING ANYTHING
JFCL
PUSHJ P,PRVJB## ;YES. PRIVILEGED?
JRST SETS15 ;NO. ILLEGAL
SETSU2: SKIPL T1,M ;BLOCK NOT IN M IF SUSET.
PUSHJ P,GETWDU## ;UNIT NAME - GET BLOCK NUMBER
TLZ T1,777740
PUSHJ P,STORU ;SAVE UNIT IN DDB
SETOM DEVREL##(F) ;INDICATE UNIT WAS INITED(NOT STR)
TRNN S,UDSD ;WRITE FORMAT?
TRZA S,UDSX ;NO, CLEAR THE BIT
TRO S,UDSX ;YES, INDICATE WRITING FORMATS
JRST SETSU7 ;AND CONTINUE
SETSU3: TRZ S,UDSX ;INDICATE NOT WRITING FORMATS
PUSHJ P,PRVJB## ;PRIV'D
JRST SETS11 ;NO. ILLEGAL
JUMPG M,SETSU4 ;GO IF SUPER USET
MOVE T1,M ;GET BLOCK NO
TLZ T1,777740 ;CLEAR UNWANTED BITS
CAMN T1,[37,,-1] ;SUSET. TO LAST BLOCK XFERRED?
SETO T1, ;YES, MAKE IT -1
JRST SETSU5
SETSU4: PUSHJ P,GETWDU## ;GET BLOCK NUMBER
SETSU5: CAME T1,[-1] ;USETO TO LAST BLOCK XFERRED?
JRST SETSU6 ;NO
HRRZ U,DEVUNI##(F) ;YES, GET RIGHT UNIT
SOS T1,DEVBLK##(F) ;GET BLOCK NUMBER
JRST SETSU8 ;AND CONTINUE
SETSU6: PUSHJ P,ADR2UN## ;SET U TO RIGHT UNIT IN STR FOR THIS BLOCK
JRST SETS10 ;ILLEGAL BLOCK NUMBER - LIGHT IOBKTL
SETSU7: CAML T1,UNIBPU(U) ;HIGHER THAN HIGHEST BLOCK ON UNIT?
JRST SETS13 ;YES. LIGHT IOBKTL
JUMPL T1,SETS10
TLNE M,MNTCYL ;WANT MAINT CYL?
JRST SETS10 ;YES, ERROR (THIS BLOCK NOT IN MAINT CYLS)
MOVEM T1,DEVBLK##(F) ;NO, SAVE BLOCK NO IN DDB
SETSU8: SUB T1,UNIBPU(U) ;-DISTANCE TO END OF UNIT
SETSU9: MOVNS T1 ;NO OF BLOCKS LEFT TO END OF UNIT
TLNE T1,-1 ;MORE THAN 256 K BLOCKS?
MOVEI T1,-1 ;YES, MAX TRANSFER IS 256K
HRRM T1,DEVLFT##(F) ;SAVE IN DEVLFT
TLZ S,IOSFIR ;MAKE SURE IOSFIR=0
TLOA S,IOSUPR ;INDICATE SUPER USETI/USETO
ERRFUL:
SETS10: TRO S,IOBKTL ;INDICATE TOO HIGH A BLOCK NUMBER
PJRST STOIOS## ;SAVE S AND RETURN
SETS11: JUMPGE M,SETS10 ;GO IF SUPER USETI/O
SETS12: SOS (P) ;SUSET, - NON-SKIP RETURN
MOVE M,W ;RESTORE AC (PUUOAC)
PJRST RTM1##
;HERE IF BLOCK ABOVE HIGHEST BLOCK ON UNIT
SETS13: MOVSI T2,DEPCPT## ;COMPATABILITY MODE?
TDNN T2,DEVCPT##(F)
JRST SETS14 ;NO
CAMLE T1,UNIBUC(U) ;YES, IS IT A LEGAL BLOCK?
JRST SETS10 ;NO, LIGHT AN ERROR BIT
MOVEM T1,DEVBLK##(F) ;YES, SAVE BLOCK NUMBER
SUB T1,UNIBUC(U) ;DISTANCE TO END OF UNIT
JRST SETSU9 ; AND FINISH UP
SETS14: CAMG T1,UNIBPM(U) ;MAINT CYL?
SKIPL DEVREL##(F) ;YES, UNIT (NOT STR) INITED?
JRST SETS10 ;NO - IOBKTL
TLNN M,MNTCYL ;WANT MAINT CYL (OR SUPER USET)?
JRST SETS10 ;NO, ERROR
MOVEM T1,DEVBLK##(F) ;YES, SAVE BLOCK
SUB T1,UNIBPM(U) ;DISTANCE TO END OF MAINT CYL
JRST SETSU9 ;FINISH UP
;HERE IF UNPRIU'S SUSET/USET TO A UNIT
SETS15: JUMPGE M,SETS10 ;ERROR IF SUPER USET
MOVE T1,.CPJOB## ;SUSET.
MOVE T1,JBTPPN##(T1) ;PPN OF REGISTER
CAMN T1,UMDPPN## ;USER-MODE DIAGNOSTICS? [6,6]
TLNN M,MNTCYL ;TO MAINT CYL?
JRST SETS12 ;NO, ERROR
JRST SETSU2 ;YES, OK
;HERE IF THE REQUESTED BLOCK IS HIGHER THAN THE HIGHEST ALLOCATED
USET11: PUSHJ P,SAVE2##
MOVE P1,W ;SAVE REQUESTED BLOCK
MOVE P2,T1 ;SAVE 1ST UNALLOCATED BLOCK NUMBER
SOS W,T1 ;SET RH(M) TO HIGHEST ALLOCATED
PUSHJ P,USET00 ;GET POINTERS INTO CORE FOR HIGHEST BLOCK
POPJ P, ;RIB ERROR
SKIPL DEVBLK##(F) ;FIND THE BLOCK?
JRST USET12 ;YES
MOVSI T1,DEPLPC## ;NO, IS IT REALLY THERE?
TDNN T1,DEVLPC##(F)
STOPCD CPOPJ##,DEBUG,PLP,;++ PAST LAST POINTER
HRROS DEVRSU##(F) ;YES, SET DEVRSU TO EXTEND THE RIB
USET12: MOVE T2,P1 ;TOP BLOCK TO ALLOCATE
MOVE T1,P2 ;FIRST BLOCK TO ALLOCATE
SUB T2,T1 ;TOTAL NUMBER TO ALLOCATE
ADDI T2,1
PUSH P,T2 ;SAVE NUMBER REQUESTED
PUSHJ P,CHKQTA ;CAN WE GET THAT MANY?
JUMPLE T2,TPOPJ## ;NO. ERROR RETURN (IOBKTL SET)
CAMGE T2,(P) ;DID WE GET ALL WE ASKED FOR?
TRO S,IOBKTL ;NO, TELL THE USER HE ONLY GOT SOME
MOVEM P1,DEVREL##(F) ;SAVE REQUESTED BLOCK IN DDB
MOVEM T2,P2 ;NUMBER TO GET
POP P,T1 ;NUMBER REQUESTED
SUBM T2,T1 ;MINUS NUMBER ALLOWED
ADDM T1,DEVREL##(F) ;ADJUST REQUESTED BLOCK BY NO. OBTAINED
MOVE T1,DEVACC##(F)
MOVE T1,ACCSMU##(T1) ;SIM UPDATE FILE?
TRNN T1,ACPSMU
JRST USET13 ;NO, CONTINUE
PUSHJ P,GTMB2 ;YES, GET MON BUF NOW TO AVOID DEADLY EMBRACE
PUSHJ P,UPFA ;GET FA TO PROTECT RIB
PUSHJ P,GETALC ;GET CURRENT NO OF BLOCKS ALLOCATED
AOS W ;HAS IT CHANGED (ANOTHER USETO ALLOCATING)
CAMN T1,W
SOJA W,USET13 ;NO, WE'RE OK
MOVE W,P1 ;YES, EXTRICATE OURSELVES
POP P,(P)
POP P,P2
POP P,P1 ;MAKE STACK RIGHT
PUSHJ P,DWNFA ;GIVE UP RESOURCES
JRST USETO2 ;AND TRY AGAIN
USET13: MOVE P1,P2 ;RESTORE NUMBER TO GET
MOVE T2,P2 ;HERE ALSO FOR CHKADD
PUSHJ P,CHKADD ;CAN WE ADD TO CURRENT POINTER?
JUMPLE T2,USET15 ;NO. GET SPACE ANYWHERE
AOSE T1,DEVBLK##(F) ;YES SET T1= 1ST BLOCK
PUSHJ P,TAKBLK ;GET BLOCKS AT PREVIOUS END
JRST USET15 ;CANT GET ANY THERE
PUSHJ P,ADDPTR ;GOT SOME - ADD TO CURRENT POINTER
USET14: SUB P1,T1 ;DECREMENT AMOUNT TO GET
JUMPLE P1,USET21 ;FINISH UP IF GOT ENOUGH
;HERE TO GET BLOCKS ANYWHERE
USET15: MOVSI T3,1 ;DECREMENT TOTAL NO. OF POINTERS
ADDB T3,DEVRSU##(F) ;TOO MANY?
JUMPGE T3,USET17 ;YES, TRY TO GET AN EXTENDED RIB
SETZ T3,
AOS T1,DEVRET##(F) ;POINT DEVRET TO 1ST EMPTY POINTER LOC
CAILE T1,DEVRBN##(F) ;FILLED THE DDB?
PUSHJ P,WRTPTR ;YES. WRITE THE POINTERS
JUMPN T3,USET18 ;RETURN WITH IOBKTL IF RIB ERR
MOVE T2,P1 ;NUMBER TO GET
MOVEI T1,0 ;ANYWHERE
PUSHJ P,TAKBLK ;GET SOME BLOCKS
SKIPA ;NOT AVAILABLE ON THIS UNIT
JRST USET16 ;GOT THEM
HLRE T1,DEVRSU##(F) ;IF 1 SLOT LEFT,
AOJGE T1,USET20 ;CANT EXTEND RIB,
PUSHJ P,NEXTUN ;STEP TO ANOTHER UNIT IN STR
JRST USET20 ;ALL UNITS FULL - SETTLE FOR WHAT WE GOT SO FAR
USET16: PUSHJ P,PTSTO ;SAVE POINTER (OR UNIT-CHANGE) IN DDB
HRRZ T3,DEVACC##(F) ;LOC OF A.T.
MOVEI T4,ACP1PT## ;ENSURE THAT 1PT IS OFF
ANDCAM T4,ACCUN1##(T3) ;SINCE WE JUST GENERATED A NEW POINTER
TLO S,IOSFIR ;INDICATE CHECKSUM MUST BE COMPUTED
JRST USET14 ;GET MORE BLOCKS IF NEEDED
USET17: MOVSI T3,-1
ADDM T3,DEVRSU##(F)
MOVN T1,P1 ;GET -NUMBER OF BLOCKS LEFT TO GET
ADDM T1,DEVREL##(F) ;SET DEVREL TO END OF RIB FOR EXTRIB
PUSHJ P,EXTRIB ;CREATE AN EXTENDED RIB
JRST [PUSHJ P,USET19
PJRST DWNIFA] ;GIVE UP FA RESOURCE IF OWNED
ADDM P1,DEVREL##(F) ;RESET DEVREL TO BLOCK TO GET
ADDI P1,2 ;ACCOUNT FOR REDUNDANT AND EXTENDED RIB
SUB P1,T1 ;DECREMENT AMOUNT TO GET
ADDI P1,2 ;ACCOUNT FOR 2 RIBS
PUSHJ P,CPYEXT## ;SET UP THE DDB
PJRST DWNIFA ;RETURN FA IF OWNED
JUMPLE P1,USET21 ;FINISH UP IF GOT ENOUGH
JRST USET15 ;NOT ENOUGH, GO GET MORE
USET18: PUSHJ P,DWNIFA ;RETURN FA IF OWNED
USET19: PUSHJ P,ERRFUL ;TOO MANY POINTERS,LIGHT IOBKTL
MOVNS P1 ;AMOUNT WE WERE UNABLE TO GET
ADDM P1,DEVREL##(F) ;ADJUST DEVREL
POPJ P, ;AND RETURN TO USER
;HERE IF UNIT OR RIB FULL
USET20: PUSHJ P,USET19 ;LIGHT AN ERROR BIT, ADJUST DEV REL
SOS DEVRET##(F) ;ADJUST DEVRET
MOVSI T1,-1
ADDM T1,DEVRSU##(F) ; AND DEVRSU (INCR'D AT USET15)
;HERE WHEN ALL BLOCKS HAVE BEEN ALLOCATED
USET21: MOVE W,DEVREL##(F) ;RESET W TO REQUESTED BLOCK
SKIPLE P1 ;IF COULDN'T GET ALL WE REQUESTED,
SUB W,P1 ;ADJUST BLOCK NUMBER
PUSHJ P,CHEKU ;UNIT OK?
JRST USET19 ;REMOVED-ERROR
PUSHJ P,WRTPTR ;WRITE OUT RET POINTERS LEFT IN DDB
JUMPN T3,USET18 ;RETURN WITH IOBKTL IF RIB ERR
PUSHJ P,DWNIFA ;RETURN FA IF WE OWN IT
PUSH P,DEVRSU##(F) ;SAVE DEVRSU (USETO4 MAY CHANGE IT)
PUSHJ P,USETO3 ;ZERO ALLOCATED, UNWRITTEN BLOCKS
POP P,DEVRSU##(F) ;RESTORE DEVRSU
HRRZ T1,DEVRET##(F) ;WERE EXTRA (OVERHEAD) BLOCKS ALLOCATED?
MOVSI T2,-1
USET22: CAIGE T1,DEVRBN##(F)
SKIPN 1(T1)
PJRST STRIOS
ADDM T2,DEVRSU##(F) ;YES, ACCOUNT FOR THEM IN DEVRSU
AOJA T1,USET22
;SUBROUTINE TO GIVE UP THE FA RESOURCE IF WE OWN IT
;ALWAYS RETURN CPOPJ - RESPECTS ALL AC'S
DWNIFA::TRNE S,IOSFA ;HAVE FA?
PJRST DWNFA ;YES, RETURN IT
POPJ P,
;SUBROUTINE TO ADD TO CURRENT POINTER
;ENTER WITH ACS SET AS IN GOOD RETURN FROM TAKBLK-
;T2=CLUSTER POINTER FOR NEW GROUP, T3=ADDRESS OF STRUCTURE DB
;EXIT WITH T1= NUMBER OF NEW BLOCKS GOTTEN
;AND UPDATED POINTER IN @DEVRET AND T2
ADDPTR::PUSH P,T1 ;SAV NO. OF BLOCKS GOTTEN
LDB T1,STYCNP##(T3) ;NO. OF CLUSTERS GOTTEN (AT END)
MOVE T2,@DEVRET##(F) ;CURRENT POINTER
LDB T4,STYCNP##(T3) ;CLUSTER COUNT
ADD T4,T1 ;PLUS NEW AMOUNT
HRRZ T1,DEVACC##(F) ;LOC OF A.T.
CAME T2,ACCPT1##(T1) ;IS THIS PNTR THE 1ST?
SETZ T1, ;NO. INDICATE BY T1=0
DPB T4,STYCNP##(T3) ;SAVE NEW CLUSTER COUNT
PUSHJ P,PTSTO ;SAVE POINTER
JUMPE T1,TPOPJ## ;IS THIS 1ST PNTR?
MOVEM T2,ACCPT1##(T1) ;YES. SAVE IT IN A.T.
JRST TPOPJ## ;RESTORE T1 AND RETURN
;SUBROUTINE TO STEP TO NEXT UNIT IN FILE STRUCTURE WHICH HAS SPACE LEFT
;IF ALL SPACE IS GONE, RETURN CPOPJ WITH IOBKTL SET
;GOOD RETURN WITH U=DEVUNI= LOC OF NEW UNIT, AND T1=0
;AND A CHANGE-UNIT POINTER STORED IN @DEVRET AND LEFT IN T2
NEXTUN::HRRZ T1,UNISTR(U) ;LOC OF STR DB
HLRZ T1,STRUNI##(T1) ;LOC OF 1ST UNIT IN STR
SKIPA ;TEST IF IT HAS ANY SPACE
NEXTU1: HLRZ T1,UNISTR(T1) ;STEP TO NEXT UNIT IN STR
JUMPE T1,ERRFUL ;STR IS FULL IF AT END OF UNITS
SKIPG UNITAL(T1) ;NO. UNIT HAVE ANY SPACE?
JRST NEXTU1 ;NO. TRY NEXT UNIT
TLNN S,IOSDA ;YES, DO WE HAVE THE DA?
JRST NEXTU2 ;NO, CARRY ON
HRRZ U,DEVUNI##(F) ;YES, GIVE IT UP FOR OLD UNIT
PUSHJ P,DWNDA
MOVE U,T1 ;AND GET IT AGAIN FOR NEW UNIT
PUSHJ P,UPDA
NEXTU2: MOVE U,T1 ;SET UP U
PUSHJ P,STORU ;AND DEVUNI
LDB T2,UNYLUN## ;GET LOGICAL UNIT NUMBER
TRO T2,RIPNUB## ;MAKE SURE NON-0
PUSHJ P,PTSTO ;SAVE IN DDB
SETZ T1, ;MAKE SURE T1=0
JRST CPOPJ1## ;AND TAKE GOOD RETURN
;SUBROUTINE TO DO THE WORK FOR USETO/USETI
;HALTS IF NO POINTERS TO THE BLOCK
;RETURNS CPOPJ IF THERE IS A RIB ERROR
;SKIP - RETURN IF EVERYTHING IS OK
;ENTER WITH RH(M)=DESIRED BLOCK
;EXIT WITH DEVRET, DEVBLK, DEVLFT, DEVREL SET UP
USET00: PUSHJ P,SETU ;SET UP U FROM DDB
POPJ P, ;UNIT WAS REMOVED
HRRZ U,DEVFUN##(F) ;UNIT FOR 1ST POINTER IN DDB
PUSHJ P,STORU ;SAVE IN DEVUNI (WILL CHANGE IF UNIT-CHANGE IS READ)
MOVE T2,DEVFLR##(F) ;LOWEST REL BLOCK OF POINTERS IN DDB
MOVE T3,W ;BLOCK NUMBER TO GET
CAML T2,T3 ;IS DESIRED BLOCK BELOW THIS FLOOR?
JRST USTRIB ;YES. READ IN WHOLE RIB
MOVEI T1,DEVRB1##(F) ;NO. SCAN THE POINTERS IN CORE
HRLI T1,MPTRLN## ; STARTING AT DEVRB1
PUSHJ P,SCNPTR ;TRY TO FIND POINTER TO BLOCK
JRST USTRIB ;NOT THERE - READ WHOLE RIB
;FOUND IT. DEVBLK,DEVREL,DEVLFT ARE SET UP
HRRZ T2,DEVRET##(F) ;CURRENT POINTER LOC
CAIN T2,DEVRBN##(F) ;POINTING TO LAST PNTR SLOT?
SKIPE DEVRB2##(F) ;YES, IS 2ND PTR 0? (YES IF SET DDB FROM
;A.T., MORE PNTRS LEFT IN RIB)
CAIA ;NO, CONTINUE
JRST CPOPJ1## ;YES, DON'T CHANGE DEVRET OR DEVRSU
HRRM T1,DEVRET##(F) ;SET DEVRET TO THIS POINTER
SUB T1,T2 ;DISTANCE BY WHICH WE CHANGED DEVRET
HRLZS T1 ;IN LH
ADDM T1,DEVRSU##(F) ;UPDATE DEVRSU BY THAT AMOUNT
JRST CPOPJ1## ;AND TAKE GOOD RETURN
;SUBROUTINE TO TURN ON IOSFIR FOR FIRST BLOCK IN EXTENDED RIB
EXTCKS: MOVE T2,DEVRIB##(F) ;POINTER TO (EXTENDED) RIB
PUSHJ P,GRPAD ;GET BLOCK NUMBER OF RIB
ADDI T2,1 ;FIRST BLOCK PAST RIB?
CAME T2,DEVBLK##(F)
POPJ P, ;NO
MOVE T1,DEVUNI##(F) ;NEWUX WIPES RH (DEVUNI)
LDB T2,DEYRBU## ;UNIT OF RIB
IFN FTMP,<
MOVE T3,DEVCPU##(F)
>
PUSHJ P,NEWUX
JFCL
IFN FTMP,<
MOVEM T3,DEVCPU##(F)
>
EXCH T1,DEVUNI##(F) ;RESET DEVUNI GET RIB UNIT
CAMN T1,DEVUNI##(F) ;YES, RIGHT UNIT?
TLO S,IOSFIR ;YES, CHECKSUM TIME
PJRST STOIOS##
;HERE IF THE POINTERS IN THE DDB DON'T ENCOMPASS THE DESIRED BLOCK
;READ IN THE RIB, AND SCAN IT FROM THE BEGINNING
USTRIB: PUSHJ P,CHEKU ;UNIT OK
JRST ERRFUL ;REMOVED-ERROR
PUSHJ P,PTRTST ;READ POINTERS, REWRITE RIB IF POINTERS HAVE CHANGED
POPJ P, ;ERROR READING RIB
PUSHJ P,SAVE1##
SETO P1,
USTRB1: LDB T2,DEYRBU## ;GET UNIT OF CURRENT RIB
PUSHJ P,NEWUX ;SET U
STOPCD CPOPJ,DEBUG,NSU, ;++NO SUCH UNIT
MOVE T2,.USMBF ;IOWD FOR MONITOR BUFFER
MOVE T2,RIBFLR##+1(T2) ;FIRST WORD OF CURRENT RIB
SKIPL DEVRIB##(F) ;IF POSITIVE COULD BE OLD TYPE RIB
MOVEI T2,0 ;WHICH HAS NO RIBFLR WORD
MOVE T3,W ;BLOCK NUMBER TO GET
CAML T2,T3 ;BLOCK BELOW FLOOR OF CURRENT RIB?
JUMPN T2,USTRB2 ;JUMP IF PRIME RIB
PUSHJ P,SCNPT0 ;SCAN THE CURRENT RIB
JRST USTRB3 ;NOT HERE, LOOK IN NEXT RIB
MOVEM T2,DEVFLR##(F) ;SET LOWEST RELATIVE BLOCK IN DDB
HRRM U,DEVFUN##(F) ;SET CORRESPONDING UNIT
PUSHJ P,PTRBLT ;BLT POINTERS TO DDB
AOS (P) ;SET FOR SKIP RETURN
POPJ P, ;RETURN MONITOR BUFFER AND EXIT
;HERE WHEN WE MUST START LOOKING AT THE PRIME RIB
USTRB2: AOJN P1,CPOPJ##
PUSHJ P,REDRIB ;READ THE PRIME RIB
POPJ P, ;ERROR READING THE RIB
PUSHJ P,SPTRW ;SET UP AOBJN WORD FOR THE RIB
JRST USTRB4 ;SET UP TO SCAN THE PRIME RIB
;HERE TO GET THE NEXT RIB IN THE CHAIN
USTRB3: PUSHJ P,PTRNXT ;GET THE NEXT RIB IN THE CHAIN
;IF MULTIPLE RIBS
JRST USTRB5 ;EITHER ERROR OR COULDN'T FIND THE BLOCK
USTRB4: MOVE T3,W ;BLOCK NUMBER TO GET
JRST USTRB1 ;SCAN THE RIB
;HERE ON NON-SKIP RETURN FROM PTRNXT, EITHER RIB ERROR OR NO NEXT RIB
USTRB5: PJUMPN T3,CPOPJ## ;RETURN CPOPJ IF RIB ERROR
SETOM DEVBLK##(F) ;SET DEVBLK TO -1 AS A FLAG
HLLZS DEVLFT##(F) ; CLEAR BLOCK COUNT
PUSHJ P,DDBZRO## ;ZERO DDB PNTR SPACE SINCE DEYRLC IS WRONG
JRST CPOPJ1## ;TAKE A SEMI-GOOD RETURN
;SUBROUTINE TO READ THE POINTERS INTO CORE, COMPARE THE OLD POINTERS IN THE
;RIB WITH THE NEW POINTERS IN THE DDB, AND REWRITE THE RIB IF THEY DIFFER
;SUBROUTINE GETS A MONITOR BUFFER AND RETURNS WITH THE RIB IN IT
;RETURNS WITH T1=AOBJN WORD FOR WHOLE GROUP OF PNTRS IN RIB
;RETURNS CPOPJ IF ERROR READING RIB (STILL WITH MON BUF
;RETURNS CPOPJ1 NORMALLY
PTRTST: HRRZ T1,DEVACC##(F)
JUMPE T1,PTRTS0
MOVE T1,ACCSTS##(T1) ;SIM UPDATE FILE?
TRNE T1,ACPSMU
PUSHJ P,UPFA ;GET FA TO PREVENT RACE IF WE WRITE RIB
PTRTS0: PUSHJ P,PTRCUR ;READ THE POINTERS INTO CORE
JUMPN T3,DWNIFA ;JUMP IF RIB ERROR
HLRZ T3,DEVEXT(F) ;EXTENSION
PUSH P,T1
PUSHJ P,JDAADR##
MOVE T4,(T1) ;WAS AN ENTER DONE ON THIS CHAN?
POP P,T1
TLNE T4,ENTRB+OUTPB ; (IF NOT THIS DDB DIDN'T CHANGE THE PNTRS)
CAIN T3,(SIXBIT /UFD/) ;"UFD"?
JRST USTR10 ;YES, PNTRS IN THE RIB ARE RIGHT
;HERE WHEN THERE ARE PNTRS IN THE DDB WHICH MAY NOT BE IN THE RIB - CHECK THEM
HRRZ T3,UNISTR(U) ;GET ADDRESS OF STRUCTURE DATA BLOCK
SETO T2, ;PUT ONE'S IN T2
LDB T4,STYCLP##(T3) ;CREATE MASK FOR CLUSTER POINTER
;PART OF RETRIEVAL POINTER
LDB T2,DEYRLC## ;POINTER LOC IN THE RIB
ADD T1,T2 ;POINT TO 1ST RIB PNTR - CORRESPONDING TO DEVRB1
MOVEI T2,DEVRB1##(F) ;POINT T2 TO DDB POINTERS
HRRZ T3,DEVCPY##(F)
SKIPE T3 ;IF THERE IS AN IN-CORE COPY
MOVEI T2,PTRDAT##(T3) ; USE IT (CHECKSUMS MAY BE NEWER)
HRLI T2,MPTRLN## ;MAKE T2 AN AOBJN WORD
USTRB6: SKIPN T3,(T2) ;GET A PNTR FROM DDB
JRST USTRB9 ;ALL DONE
CAMN T3,(T1) ;SAME AS PNTR IN RIB?
JRST USTRB8 ;YES
EXCH T3,(T1) ;NO. SAVE PNTR IN MON BUF
JUMPE T3,USTRB7 ;IF OLD PNTR=0, OK
XOR T3,(T1) ;XOR RIB WITH MON BUF
TDNE T3,T4 ;IF PNTR PARTS EQUAL, SKIP
STOPCD .+1,DEBUG,PNE, ;++POINTERS NOT EQUAL
USTRB7: TLZ T1,-1 ;ZERO LH(T1) - WAS MRIBLN
USTRB8: AOBJP T2,USTRB9 ;SKIP IF ALL DDB PNTRS LOOKED AT
AOJA T1,USTRB6 ;LOOK AT NEXT POINTER
;HERE WHEN ALL POINTERS HAVE BEEN COMPARED, CHANGED PNTRS STORED IN MON BUF
USTRB9: MOVE T4,DEVRRC##(F) ;DID ACCWRT ETC CHANGE?
TLNN T4,DEPRHC## ;IF SO, ALWAYS REWRITE RIB
SKIPL T1 ;T1 NEG IF ALL PNTRS COMPARED
PUSHJ P,WRTRIB ;WRITE THE MON BUF AS 1ST RIB
USTR10: PUSHJ P,DWNIFA ;RETURN FA IF WE OWN IT
PUSHJ P,SPTRW ;SET T1 AS AN AOBJN WD FOR PNTRS AGAIN
JRST CPOPJ1## ;AND TAKE GOOD-RETURN
;SUBROUTINE TO SCAN A BLOCK OF RETRIEVAL POINTERS TO FIND THE GROUP POINTER
;FOR A PARTICULAR BLOCK
;ENTER WITH:
;T1=AOBJN WORD FOR THE SET OF POINTERS
;T2=INITIAL RELATIVE BLOCK OF THE SET OF POINTERS
;T3=DESIRED RELATIVE BLOCK
;ENTER AT SCNPT0 TO SCAN WHOLE RIB (IN MON BUF)
;EXIT WITH:
;T1=ADDRESS OF THE POINTER, LH=-NUMBER OF POINTERS LEFT
;T2=RELATIVE BLOCK NUMBER OF POINTER
;DEVLFT,DEVBLK,DEVREL SET IN THE DDB
;EXIT CPOPJ IF THE POINTER WAS NOT FOUND
;SKIP-RETURN IF THE POINTER WAS FOUND
SCNPT0::PUSHJ P,SPTRW ;SET T1=AOBJN WORD FOR WHOLE RIB
SCNPTR::PUSHJ P,SAVE2## ;SAVE P1,P2
LDB T4,UNYBPC## ;NUMBER OF BLOCKS PER CLUSTER
PUSH P,T3 ;SAVE DESIRED BLOCK
SUB T3,T2 ;T3=RELATIVE BLOCK NUMBER IN SET
IDIV T3,T4 ;T3=DESIRED CLUSTER
HRRZ T2,UNISTR(U) ;LOC OF FILE STRUCTURE DB
HLLZ P1,STYCNP##(T2) ;SET UP POS, SIZE OF POINTER COUNT FIELD
TLO P1,T1 ;POINTER TO CLUSTER COUNT
SETZ P2, ;CLEAR REGISTER TO ACCUMULATE BLOCK COUNT
SCNPT1: LDB T2,P1 ;GET NUMBER OF CLUSTERS IN THIS POINTER
JUMPN T2,SCNPT3 ;REAL POINTER IF NON-0
SKIPN T2,(T1) ;UNIT CHANGE OR END OF POINTERS
PJRST TPOPJ## ;END OF POINTERS. ERROR RETURN
TRZE T2,RIPNUB## ;REMOVE BIT 18 (REST IS A LOGICAL UNIT NUMBER)
PUSHJ P,NEWUNI ;SET UP U, DEVUNI(F)
SKIPA U,DEVUNI##(F) ;INVALID UNIT -NOT FOUND RETURN
SCNPT2: AOBJN T1,SCNPT1 ;GO BACK TO TEST NEXT POINTER
JRST TPOPJ## ;RAN OUT OF POINTERS, ERROR RETURN
;HERE WHEN A REAL POINTER HAS BEEN FOUND
SCNPT3: ADD P2,T2 ;PLUS LENGTH OF GROUP
CAML T3,P2 ;IS DESIRED CLUSTER IN THIS POINTER?
JRST SCNPT2 ;NO, STEP TO NEXT
LDB P1,UNYBPC## ;YES. NUMBER OF BLOCKS PER CLUSTER
SUB P2,T2 ;SET P2 BACK TO BEGINNING OF GROUP
SUB T3,P2 ;T3=CLUSTER IN GROUP
IMUL T3,P1 ;T3=BLOCK NUMBER IN GROUP
ADD T3,T4 ;T3= DISTANCE OF BLOCK FROM START OF PNTR
POP P,T4 ;BLOCK NUMBER TO GET
SKIPE T3 ;AT 1ST BLOCK OF A GROUP?
CAIN T4,1 ;IS IT BLOCK 1?
TLOA S,IOSFIR ;YES, SET CHECKSUM BIT
TLZ S,IOSFIR ;NO, CLEAR CHECHSUM BIT
IMUL T2,P1 ;T2=RELATIVE BLOCK NUMBER OF START OF PNTR
SUB T2,T3 ;COMPUTE NUMBER OF BLOCKS LEFT IN GROUP
HRRM T2,DEVLFT##(F) ;SAVE IN DDB
HRRZ T2,T1 ;GET ADDRESS PORTION OF POINTER
CAIG T2,DEVRBN##(F) ;SKIP IF NOT POINTING TO DDB
CAIGE T2,DEVRB1##(F) ;SKIP IF POINTING TO DDB
JRST SCNPT4 ;NOT IN DDB, MUST BE IN MONITOR BUFFER
MOVE T2,DEVLPC##(F) ;GET WORD CONTAINING LAST POINTER FLAG
TLNN T2,DEPLPC## ;IS POINTER IN DDB?
JRST SCNPT7 ;NO, PROCEED
HRRZ T2,T1 ;GET ADDRESS PORTION OF POINTER
CAIE T2,DEVRBN##(F) ;SKIP IF THIS IS THE LAST SLOT
SKIPE 1(T1) ;IS NEXT SLOT EMPTY?
JRST SCNPT4 ;NO, CHECK TO SEE IF THIS IS LAST SLOT
HRRZ T2,DEVLFT##(F) ;IS LAST, MAKE LAST BLOCK UNAVAILABLE
SOJE T2,SCNPT9 ;JUMP IF NO BLOCKS AVAILABLE
JRST SCNPT6 ;STORE THE NEW VALUE OF DEVLFT
SCNPT4: HRRZ T2,DEVLFT##(F) ;RETURN DEVLFT TO T4
AOBJN T1,SCNPT5 ;ABOUT TO RUN OUT OF POINTERS?
SOJE T2,SCNPT8 ;YES, MAKE LAST BLOCK UNAVAILABLE
SCNPT5: SUB T1,[XWD 1,1] ;RESTORE AOBJN WORD
SCNPT6: HRRM T2,DEVLFT##(F) ;STORE IN DDB
SCNPT7: MOVEM T4,DEVREL##(F) ;=CURRENT RELATIVE BLOCK
MOVE T2,T4 ;GET DEVREL INTO T2
SUB T2,T3 ;SET TO RELATIVE BLOCK OF START OF GROUP
SKIPN T4 ;USETI/O TO BLOCK 0?
TLZ S,IOSFIR ;YES. DONT COMPUTE CHECKSUM (ITS FOR BLOCK 1)
HRRZ T4,UNISTR(U)
MOVE T4,STYCLP##(T4) ;SET T4=POINTER TO CLUSTER ADDRESS
HRRI T4,(T1)
LDB T4,T4 ;T4=CLUSTER ADDRESS
IMUL T4,P1 ;1ST LOGICAL BLOCK ADR. IN POINTER
ADD T3,T4 ;+DISTANCE TO DESIRED BLOCK
MOVEM T3,DEVBLK##(F) ;=LOGICAL ADR. OF DESIRED BLOCK
JRST CPOPJ1## ;TAKE GOOD RETURN
SCNPT8: MOVSI T1,DEPLPC## ;TELL CALLER WHY HE LOST
IORM T1,DEVLPC##(F)
SCNPT9: HLLZS DEVLFT##(F) ;NOTHING LEFT IN THIS POINTER
POPJ P,
;SUBROUTINE TO READ A RIB BLOCK, AND STORE THE POINTERS IN THE DDB
RDPTRS::PUSHJ P,PTRGET ;READ THE RIB BLOCK INTO A MON BUF
PJRST PTRCPY ;COPY CURRENT POINTERS FROM MON BUF TO DDB
;SUBROUTINE TO WRITE POINTERS
WRTPTR: PUSHJ P,PTRCUR ;READ THE RIB
SKIPN T3 ;DONT TRUST ANYTHING IF RIB ERR
PUSHJ P,PTRWRT ;BLT POINTERS INTO MON BUF, WRITE THEM
POPJ P, ;AND RETURN
;SUBROUTINE TO GET THE CURRENT POINTERS INTO CORE
;RETURNS T3=0 IF OK, NON-0 IF RIB ERROR
PTRCUR::PUSHJ P,GTMNBF ;GET MON BUF IF DON'T YET HAVE IT
PUSHJ P,RIBCUR ;READ THE CURRENT RIB
PJRST SPTRW ;SET UP A POINTER AND RETURN
;SUBROUTINE TO COPY POINTERS INTO MON BUF AND WRITE IT
;ENTER WITH T1=AOBJN WORD FOR ENTIRE MONITOR BUFFER
PTRWRT::PUSHJ P,DD2MN ;COPY DDB POINTERS INTO MONITOR BUF
STOPCD .+1,DEBUG,TMP, ;++TOO MANY POINTERS
;SHOULDN'T HAPPEN SINCE DEVRSU DIDNT GO POSITIVE
HRRZ T2,T1 ;SAVE CURRENT POINTER LOC
PUSHJ P,SPTRW ;MINUS ORIGINAL POINTER LOC
SUBI T2,-1(T1)
DPB T2,DEYRLC## ;=CURRENT POSITION IN MON BUF
PJRST WRTRIB ;WRITE THE RIB AND RETURN
;SUBROUTINE TO FIND WRITERS ASSOCIATED WITH A FILE
;CALL FNDDDB THE FIRST TIME, TO FIND OTHER WRITERS CALL FNDDDN WITH
; T2 AS RETURNED FROM THE FIRST CALL
;CALL WITH T1= L(AT)
;RETURNS CPOPJ IF NO MORE (OR NONE) WRITERS
;RETURNS CPOPJ1 NORMALLY, WITH T2=ADR OF IN-CORE COPY OF NEXT WRITER
FNDDDB: MOVEI T2,SYSPTR##-PTRSYS## ;INITIALIZE PREDECESSOR
FNDDDN: HRRZ T4,DEVCPY##(F) ;DONT FIND OUR OWN COPY
FNDDD1: HLRZ T2,PTRSYS##(T2) ;STEP TO NEXT IN-CORE COPY
JUMPE T2,CPOPJ## ;DONE OF 0
HRRZ T3,PTRAT##(T2) ;A.T IT POINTS AT
CAIE T4,(T2) ;IGNORE IT IF IT IS OURS
CAIE T3,(T1) ;POINTING AT OUR AT?
JRST FNDDD1 ;NO, TRY NEXT
JRST CPOPJ1## ;FOUND, RETURN WITH ADDR IN T2
;SUBROUTINE TO FIND CURRENT POINTERS FOR A FILE IN SOME DDB
;CALLED WHEN THE ACCESS TABLE INDICATES POINTERS SHOULD BE THERE,
; BUT THE POINTERS ARE NOT IN THE DDB
;SOME DDB HAS ALLOCATED NEW BLOCKS, THE NEW POINTERS AREN'T YET IN THE RIB
;NON-SKIP RETURN IF COULDN'T FIND THE BLOCK
;NORMAL RETURN IS CPOPJ1
FNDPTR: HRRZ T1,DEVACC##(F) ;LOC OF A.T.
MOVE T2,ACCCNT##(T1) ;STATUS OF FILE
TRNN T2,ACPUPD ;UPDATE?
JRST FIXDDB ;NO, CANT FIND A WRITING DDB
PUSHJ P,FNDDDB ;FIND THE WRITER
JRST FIXDDB ;NONE THERE - REREAD THE RIB
;HERE WHEN THE RIGHT DDB HAS BEEN FOUND
MOVSI T1,PTRDAT##(T2) ;COPY THE CURRENT PNTRS INTO DDB
HRRI T1,DEVRB1##(F) ; (MAY INCLUDE POINTERS WHICH ARE ALREADY
BLT T1,DEVRBN##(F) ; IN THE RIB)
MOVE T1,DEVLPC##(F) ;SET UP ALL THE DDB PARAMETERS
MOVE T3,PTRRLC##(T2)
TRNE T3,PTPLPC##
TLOA T1,DEPLPC##
TLZ T1,DEPLPC##
MOVEM T1,DEVLPC##(F)
HRLM T3,DEVFUN##(F)
DPB T3,DEYRLC##
LDB T3,PTYRSU##
MOVNS T3
HRLM T3,DEVRSU##(F)
MOVEI T3,DEVRB1##(F)
HRRM T3,DEVRET##(F)
MOVE T1,PTRFLR##(T2)
MOVEM T1,DEVFLR##(F)
MOVE T1,PTRRIB##(T2)
MOVEM T1,DEVRIB##(F)
PUSHJ P,CPYPTR
;DDB IS ALL SET (IF WE FOUND THE WRITER). CALL USETI TO SET FOR THE RIGHT BLOCK
; WILL FIND IT IN THE DDB POINTERS IF THERE, IF THE UPDATER CLOSED THEY SHOULD
; HAVE BEEN WRITTEN BACK INTO THE RIB (COULDN'T FIND THE RIGHT DDB)
FIXDDB: PUSH P,W ;SAVE W
MOVE W,DEVREL##(F) ;BLOCK WE'RE LOOKING FOR
PUSHJ P,USET00 ;GO SET UP FOR IT
CAIA
SKIPG DEVBLK##(F) ;SEMI-GOOD RETURN?
SOS -1(P) ;STILL COULDN'T FIND THEM (SYSTEM ERROR?)
POP P,W ;RESTORE W
PJRST CPOPJ1## ;EVERYTHING WORKED!
;SUBROUTINE TO READ THE CURRENT RIB
;RETURNS CPOPJ, IF T3 NON-ZERO, ERROR READING RIB
;RETURNS UNIT OF RIB IN T2
RIBCUR::PUSH P,U ;SAVE CURRENT UNIT
LDB T2,DEYRBU## ;GET CURRENT RIB LOGICAL UNIT NUMBER
PUSHJ P,NEWUNI ;SET UP U,DEVUNI
STOPCD UDEERR,DEBUG,UDE, ;++UNIT DOESN'T EXIST
LDB T2,DEYRBA## ;GET CURRENT RIB CLUSTER ADDRESS
LDB T3,UNYBPC## ;BLOCKS PER CLUSTER FOR THIS UNIT
IMUL T2,T3 ;BLOCK NUMBER IN T2
MOVE T1,.USMBF ;GET IOWD FOR MONITOR BUFFER
PUSHJ P,MONRED ;READ THE BLOCK
PUSHJ P,RIBCHK ;MAKE SURE ITS A VALID RIB
UDEERR: SKIPA T3,[-1] ;RIB ERROR, SET T3=-1
SETZ T3, ;T3=0 INDICATES RIB OK
MOVE T2,U ;RIB-UNIT IN T2
POP P,U ;RESTORE CURRENT UNIT
PUSHJ P,STORU ;AND SAVE IN DDB
JUMPN T3,DDBZR## ;CLEAR OUT RETRIEVAL POINTERS IF READ ERROR
POPJ P, ;AND RETURN
;SUBROUTINE TO GET THE NEXT RIB IN A CHAIN INTO CORE
;RETURNS CPOPJ1 WITH NEXT RIB IN CORE, CPOPJ IF NONE OR ERROR
;IF CPOPJ RETURN AND T3 NON-0, ERROR,T3=0,NO NEXT RIB
;RETURNS UNIT OF RIB IN T2
PTRNXT::SETZ T3, ;T3=0 INDICATES NO RIB ERROR
MOVE T2,.USMBF ;IOWD FOR MONITOR BUFFER
SKIPL DEVRIB##(F) ;IS CURRENT RIB EXTENDED
SKIPN RIBFLR##+1(T2) ;NO, IS THIS AN EXTENDABLE FILE
SKIPN T2,RIBXRA##+1(T2) ;GET THE NEXT RIB ADDRESS
POPJ P, ;NONE, END OF CHAIN
MOVEM T2,DEVRIB##(F) ;MAKE NEXT RIB CURRENT RIB
PUSHJ P,PTRCUR ;READ THE RIB
JUMPN T3,CPOPJ## ;NON-SKIP RETURN IF ERROR
JRST CPOPJ1## ;GOOD RETURN
SUBTTL MISCELLANEOUS FUNCTIONS
;UNLOAD A DRIVE
UNLOAD::PUSHJ P,GETWDU## ;GET USERS ARGUMENT
MOVNI T2,1 ;WHOLE WORD MUST MATCH
PUSHJ P,SRUNI## ;IS IT A UNIT NAME?
PJRST ECOD1## ;NO - ERROR 1
JFCL
SKIPN UNILOG(U) ;YES, IS IT IN A FILE STRUCTURE?
SKIPE UNISTS(U) ;NO, IS IT IDLE?
PJRST ECOD2## ;NOT IDLE OR IN AN STR - ERROR 2
MOVE J,UDBKDB(U) ;KONTROLLER DATA BLOCK
SKIPGE KONUNL(J) ;DOES DEVICE UNLOAD?
PJRST ECOD3## ;NO, ERROR 3
SKIPGE UNIDS2(U) ;NON-REMOVABLE MEDIUM?
JRST CPOPJ1## ;YES, UNLOAD WON'T DO ANYTHING
IFN FTMP,<
MOVE T1,UDBCAM(U) ;CPU(S) UNIT IS ON
PUSHJ P,CPUOK## ;FIND A LIVE CPU
JRST CPOPJ1## ;ALL DEAD
PUSHJ P,ONCPUS##
PJRST CPOPJ1## ;CPU NOT RUNNING
>
PUSHJ P,@KONUNL(J) ;YES, UNLOAD IT
JFCL ;IGNORE IF UNIT NOT READY
MOVEI T2,O2COD ;MARK UNIT AS DOWN,
MOVEM T2,UNISTS(U) ; NO ONCE-A-MINUTE TYPOUT
IFN FTDUAL,<
SKIPE T1,UNI2ND(U)
MOVEM T2,UNISTS(T1)
>
PJRST CPOPJ1## ;AND TAKE GOOD RETURN
SETCPT::SKIPA T1,[IORM T1,DEVCPT##(F)]
CLRCPT::MOVE T1,[ANDCAM T1,DEVCPT##(F)]
PUSHJ P,SAVE1## ;SAVE P1
MOVE P1,T1 ;SET TO CLEAR/SET THE BIT
PUSHJ P,GETWDU## ;GET USERS ARG
PUSHJ P,DVCNSG## ;FIND THE DDB
PJRST ECOD1## ;NONE SUCH - ERROR 1
PUSHJ P,VALUUX ;LEGAL?
PJRST ECOD1## ;NO, ERROR 1
MOVE U,DEVUNI##(F) ;YES, GET UNIT (IF SET UP)
JUMPE U,SETCP1
MOVE J,UDBKDB(U) ;KONTROLLER DATA BLOCK LOC
SKIPG KONRDC(J) ;DOES DEVICE HAVE COMPAT. MODE?
PJRST ECOD2## ;NO, ERROR 2
SETCP1: MOVSI T1,DEPCPT## ;YES, GET THE BIT
CAIE F,DSKDDB## ;DON'T WIPE OUT PROTOTYPE
XCT P1 ;SET/CLEAR BIT IN DDB
PJRST CPOPJ1## ;AND TAKE GOOD RETURN
SUBTTL DIAG UUO INTERFACE
DSKDIA::EXP DSKPPR ;PREPROCESSOR ROUTINE
DIAFNC (CTC,DIACTC,CPOPJ##) ;MONITOR ENTRY ON ^C
DIAFNC (ASU,DIAASU,CPOPJ##) ;ASSIGN SINGLE UNIT
DIAFNC (AAU,DIAALL,CPOPJ##) ;ASSIGN ALL UNITS
DIAFNC (RAU,DIARAU,CPOPJ##) ;RELEASE CHAN AND ALL UNITS
DIAFNC (SCP,DIASCP,CPOPJ##) ;SPECIFY CHANNEL PROGRAM
DIAFNC (RCP,DIARCP,CPOPJ##) ;RELEASE CHAN PROGRAM
DIAFNC (GCS,DIACST,CPOPJ##) ;GET CHAN STATUS
DIAFNC (AKU,DIAAKU,DIAAKU) ;GET KONTROLLER AND UNIT
DIAFNC (SCR,DIASCR,CPOPJ##) ;SPECIFY CHAN PROGRAM FOR REVERSE
DIAFNC (ELD,DIAELD,DIAELD) ;ENABLE MICROCODE LOADING
DIAFNC (DLD,DIADLD,DIADLD) ;DISABLE MICROCODE LOADING
DIAFNC (LOD,DIALOD,DIALOD) ;LOAD MICROCODE
DIAFNC (SDS,DIASDS,DIASDS) ;SET DEVICE STATUS
DIAFNC ;TERMINATE TABLE
;PREPROCESSOR ROUTINE
DSKPPR:
IFN FTXMON,<PUSHJ P,SSEC0##> ;ENTER SECTION ZERO
JRST (P3) ;GO HANDLE DIAG FUNCTION
; ENABLE/DISABLE MICROCODE LOADING
DIADLD: TDZA T1,T1 ;DISABLE
DIAELD: MOVEI T1,1 ;ENABLE
PUSHJ P,SAVJW## ;SAVE J & W
MOVE J,W ;BRAIN DAMAGED FILSER LIKES IT HERE
PUSHJ P,@KONEDL(J) ;DISPATCH
JRST DIAANM## ;MICROCODE NOT AVAILABLE
JRST CPOPJ1## ;RETURN
; LOAD MICROCODE
DIALOD: PUSHJ P,SAVJW## ;SAVE J AND W
MOVE J,W ;BRAIN DAMAGED FILSER LIKES IT HERE
PUSHJ P,@KONRLD(J) ;LOAD MICROCODE
JRST DIAARF## ;COULDN'T
JRST CPOPJ1##
;SET DEVICE STATUS
DIASDS:
IFN FTMP,<
MOVE T1,KDBCAM(W) ;FETCH CPU MASK
PUSHJ P,CPUOK## ;FIND A RUNNING CPU
JRST DIAANR## ;CPU NOT RUNNING
PUSHJ P,ONCPUS## ;TRY TO GET THERE
JRST DIAANR## ;CPU NOT RUNNING
> ;END IFN FTMP
PUSHJ P,GETWD1## ;GET NEXT ARGUMNET
CAIL T1,0 ;RANGE
CAILE T1,SDSLEN ; CHECK
JRST DIAABA## ;BAD ARGUMENT LIST
PUSHJ P,SAVE3## ;SAVE SOME ACS
MOVE P2,T1 ;SAVE SUB-FUNCTION CODE
SETZB P1,P3 ;ASSUME DOING ONLY ONE UNIT
JUMPGE U,DIASD1 ;ROMP THROUGH LOOP ONLY ONCE
MOVNI P3,1 ;REMEMBER DOING THE WHOLE KONTROLLER
PUSHJ P,@SDSTAB(P2) ;DO KONT STUFF BEFORE LOOPING THROUGH DRIVES
POPJ P, ;PROPAGATE ERROR BACK
MOVE T1,KDBDSP(W) ;POINT TO DRIVER DISPATCH
LDB P1,[POINTR (DRVCF2(T1),DR.HDN)] ;GET HIGHEST DRIVE ON KONT
SETZ U, ;START WITH FIRST DRIVE
DIASD1: MOVE T1,KDBIUN(W) ;DRIVE TABLE
DIASD2: SKIPN T2,(T1) ;GET A UDB
JRST DIASD3 ;NONE THERE
CAMN U,UDBPDN(T2) ;FOUND THE UDB?
JRST DIASD4 ;YES
DIASD3: CAMGE T1,KDBFUN(W) ;END OF TABLE?
AOJA T1,DIASD2 ;KEEP SEARCHING
HRROS U ;FLAG A NON-EXISTANT DRIVE
DIASD4: PUSHJ P,@SDSTAB(P2) ;DISPATCH
POPJ P, ;PROPAGATE ERROR BACK
HRRZS U ;INCASE LAST DRIVE DIDN'T EXIST
AOS U ;ADVANCE TO NEXT
SOJGE P1,DIASD1 ;LOOP FOR ANOTHER
JRST CPOPJ1## ;RETURN
SDSTAB: IFIW SDSIGN ;SET IGNORE
IFIW SDSCLR ;CLEAR IGNORE
IFIW SDSDET ;SET DETACHE
IFIW SDSATT ;SET ATTACHED
SDSLEN==.-SDSTAB ;LENGTH OF TABLE
;SET IGNORE
SDSIGN: CAMN U,[EXP -1] ;KONTROLLER?
JRST CPOPJ1## ;MEANINGLESS
JUMPGE U,CPOPJ1## ;CAN'T IGNORE AN KNOWN DRIVE
MOVE T1,U ;COPY PHYSICAL DRIVE NUMBER
MOVE T2,[1,,KDBIUM] ;STATE,,MASK WORD OFFSET
PUSHJ P,AUTMSK## ;SET DRIVE IGNORED
JRST DIAAIU## ;ILLEGAL UNIT
JRST CPOPJ1## ;RETURN
;CLEAR IGNORE
SDSCLR: CAMN U,[EXP -1] ;KONTROLLER?
JRST CPOPJ1## ;MEANINGLESS
HRRZ T1,U ;GET DRIVE NUMBER
MOVEI T2,KDBIUM ;STATE,,MASK WORD OFFSET
PUSHJ P,AUTMSK## ;CLEAR DRIVE IGNORED
JRST DIAAIU## ;ILLEGAL UNIT
JRST CPOPJ1## ;RETURN
;SET DETACHED
SDSDET: CAMN U,[EXP -1] ;DETACH KONTROLLER?
JRST CPOPJ1## ;DO NOTHING (WILL GET CALLED PER DRIVE)
JUMPL U,CPOPJ1## ;CANNOT DETACH AN UNKNOWN DRIVE
MOVE T1,KDBIUN(W) ;DRIVE TABLE
SDSDE1: MOVE T2,(T1) ;GET A UDB
CAMN U,UDBPDN(T2) ;FOUND THE UDB?
JRST SDSDE2 ;YES
CAMGE T1,KDBFUN(W) ;END OF TABLE?
AOJA T1,SDSDE1 ;KEEP SEARCHING
JRST CPOPJ1## ;NOT THERE???
SDSDE2: PUSH P,U ;SAVE U
MOVE U,T2 ;COPY UDB ADDRESS
PUSHJ P,DETCPD ;DETACH DRIVE
JFCL ;NOT A DISK?
JRST [POP P,U ;CLEAN STACK
JRST DIAADF##] ;ATTACH/DETACH FAILED
MOVE U,UDBPDN(U) ;GET DRIVE NUMBER
PUSHJ P,SDSCLR ;MAKE SURE IGNORE IS CLEARED
JFCL ;ALWAYS SKIPS
JRST UPOPJ1## ;RESTORE U AND RETURN
;SET ATTACHED
SDSATT: CAMN U,[EXP -1] ;ATTACH KONTROLLER?
JRST CPOPJ1## ;DO NOTHING (WILL GET CALLED PER DRIVE)
MOVE T1,KDBIUN(W) ;DRIVE TABLE
SDSAT1: MOVE T2,(T1) ;GET A UDB
CAMN U,UDBPDN(T2) ;FOUND THE UDB?
JRST SDSAT2 ;YES
CAMGE T1,KDBFUN(W) ;END OF TABLE?
AOJA T1,SDSAT1 ;KEEP SEARCHING
JRST CPOPJ1## ;NOT THERE???
SDSAT2: PUSH P,U ;SAVE U
MOVE U,T2 ;COPY UDB ADDRESS
PUSHJ P,ATTCPD ;ATTACH IT
JFCL ;UNIT DOWN
CAIA ;CAN'T CALL CPY ROUTINE CUZ NOT AT UUO LEVEL
JRST SDSAT3 ;CONTINUE IF SUCCESSFUL
POP P,U ;RESTORE U
SKIPGE U ;SKIP IF DRIVE EXISTS BUT ATTACH FAILED
JUMPL P3,CPOPJ1## ;RETURN IF NON-EXISTANT DRIVE & ATTACHING KONT
JRST DIAAAF## ;ELSE TAKE ERROR RETURN
SDSAT3: PUSHJ P,SDSCLR ;MAKE SURE IGNORE CLEARED
JFCL ;ALWAYS SKIPS
JRST UPOPJ1## ;RESTORE U AND RETURN
IFN FTKL10,<
;HERE TO ASSIGN SOME UNIT
DIAASU: PUSHJ P,FNDPDS## ;SET UP PDB
JUMPN F,DIAAAA## ;ALREADY HAVE SOME UNITS ASS'D
HLRZ T1,UNIDIA(U) ;JOB WHICH OWNS THIS UNIT
CAME T1,.CPJOB## ;SOME OTHER JOB HAVE IT?
JUMPN T1,DIAAAJ## ;UNIT ASS'D TO ANOTHER JOB
JUMPN T1,DIAHVF ;HAVE A DDB SET IF F NON-0
PUSHJ P,FAKDDB## ;GET A DDB
JRST DIAAFC## ;NOT ENOUGH "FREE" CORE
HRL F,.CPJOB## ;SET UNIDIA=JOB,,DDB
MOVEM F,UNIDIA(U)
JRST DIAHVF ;AND CONTINUE
;HERE TO ASSIGN ALL UNITS ON A CHANNEL
DIAALL: PUSHJ P,FNDPDS## ;SET UP PDB
JUMPN F,DIAAAA## ;ALREADY HAVE SOME UNITS ASS'D
HRRZ T1,U ;SAVE STARTING-POINT
DIAAL1: HLRZ T2,UNIDIA(T1) ;UNIT IN DIAG FOR SOME OTHER JOB?
CAME T2,.CPJOB##
JUMPN T2,DIAAAJ## ;UNIT ASS'D TO ANOTHER JOB
SKIPE T2 ;HAVE A DDB SET UP ALREADY?
HRRZ F,UNIDIA(T1) ;YES, SAVE IT
MOVE T1,UNICHN(T1) ;STEP TO NEXT UNIT ON CHAN
CAIE T1,(U) ;BACK WHERE WE STARTED?
JRST DIAAL1 ;NO, TEST IT
JUMPN F,DIAAL2 ;GO IF WE HAVE A DDB
PUSHJ P,FAKDDB## ;NONE, GET ONE
JRST DIAAFC## ;NOT ENOUGH CORE
DIAAL2: HRL F,.CPJOB## ;SET JOB,,DDB IN EVERY UNIT
HRRZ T1,U ; ON THE CHANNEL
DIAAL3: SKIPN UNIDIA(T1)
MOVEM F,UNIDIA(T1) ;(IF NONE THERE ALREADY)
MOVE T1,UNICHN(T1)
CAIE T1,(U)
JRST DIAAL3
DIAHVF: HRRZ F,UNIDIA(U) ;MAKE SURE F IS RIGHT
PUSHJ P,STOAU ;SAVE U IN DDB
MOVEM F,.PDDIA##(W) ;SAVE DDB IN PDB
MOVE J,.CPJOB## ;STOAU SMASHES J
DIAHV1: SKIPE DIADWT## ;ANOTHER JOB WAITING FOR DIAG?
JRST DIAHV2 ;YES, CAUSE THIS JOB TO BLOCK
SKIPN T1,DIADSK## ;NO, SOME OTHER JOB IN DIAG ALREADY?
JRST DIASCH ;NO
DIAHV2: SKIPN DIADSK## ;IF WE'RE HERE BECAUSE ANOTHER JOB IS WAITING
AOSE DIADWT## ; TOGGLE WAIT FLAG SO NEXT CALL TO DIAHVF WILL WIN
SETOM DIADWT## ;INDICATE THAT WE'RE WAITING
MOVEI T1,0 ;SLEEP FOR A WHILE
PUSHJ P,SLEEPF## ;AND THEN TRY AGAIN
JRST DIAHV1
;STILL IN FTDHIA CONDITIONAL
DIASCH: HRRZM F,DIADSK## ;INDICATE WE WANT TO STOP IO
MOVE J,.CPJOB##
HRLM J,DIADSK## ;SAVE JOB NO
MOVEI T1,6 ;IF THINGS DON'T START UP IN 30 SECONDS
DPB T1,PDVTIM## ; WE ARE IN TROUBLE, SO CALL HNGDSK
MOVSI T1,NSWP!NSHF ;SO SCHEDULER WONT TRY TO
IORM T1,JBTSTS##(J) ; SWAP US (STORE JOB IN FORCE)
PUSHJ P,SETACT## ;SET DDB IOACT
MOVE T2,UDBKDB(U) ;SAY WHAT CHANNEL WE WANT TO STOP IO ON
MOVE T2,KDBCHN(T2)
MOVEM T2,DIACHN##
DSKOFF
PUSHJ P,WINDWN ;ANY IO GOING?
JRST [DSKON ;YES, WAIT FOR IT TO STOP
PUSHJ P,WAIT1##
DSKOFF
JRST .+1]
;HERE WHEN ALL IO IS STOPPED ON THE DESIRED CHANNEL.
HRROS DIADSK## ;INDICATE WE'RE IN MIDDLE OF TEST
SETZM @DIACHN## ;CHAN IS BUSY
PUSHJ P,DIAKDB ;SET ALL KDBS BUSY
IORM T1,KONBSY(T3) ;INSTR TO EXECUTE
CAIGE P1,3 ;TIME LIMIT GIVEN?
TDZA T1,T1 ;NO, SET FOR 1 MINUTE
PUSHJ P,GETWD1## ;YES, GET IT
IDIVI T1,^D1000 ;CONVERT TO SECS
SKIPN T1 ;IF LESS THAN 1 SEC (OR NONE),
MOVEI T1,^D60 ; SET TIMER FOR 1 MINUTE
MOVEM T1,UNITIM(U) ;SET TIME IN UDB
MOVEM J,UNIJOB(U)
MOVSI T1,TCOD
HLRZM T1,UNISTS(U) ;SET UNIT ACTIVE SO HUNG LOGIVC WILL CHECK
DPB T1,PDVTIM##
PUSHJ P,SETACT## ;MAKE SURE IOACT IS ON
DSKON
PUSHJ P,GETWDU##
HLLZ T2,T1 ;GET KONTROLLER DEVICE CODE
LSH T2,-3
TLO T2,(CONO) ;MAKE A CONO DEV,0
XCT T2 ; AND EXECUTE IT
PJRST CPOPJ1## ;AND TAKE GOOD RETURN
;SUBROUTINE TO SET/CLEAR THE BUSY BIT IN ALL KDBS ASSOCIATED WITH A UNIT
;CALL PUSHJ P,DIAKDB
; ANDCAM T1,KONBSY(T3) (OR IORM T1,....)
DIAKDB: MOVSI T1,KOPBSY ;BUSY BIT
HRRZ T2,U ;WHERE TO START
DIAKD1: MOVE T3,UDBKDB(T2) ;POINT AT KDB
XCT @(P) ;SET/CLEAR THE BIT
MOVE T2,UNICHN(T2) ;STEP TO NEXT UDB
CAIE T2,(U) ;BACK WHERE WE STARTED?
JRST DIAKD1 ;NO, DO THIS ONE TOO
IFN FTDUAL,<
SKIPN T3,UNI2ND(U) ;DUAL-PORTED?
JRST CPOPJ1 ;NO. DONE
MOVE T3,UDBKDB(T3) ;YES, POINT TO KDB
XCT @(P) ;SET/CLEAR
> ;END IFN FTDUAL
JRST CPOPJ1 ;AND RETURN
;STILL IN FTDHIA CONDITIONAL
;HERE ON ^C, EXIT, HALT, ...
DIACTC: PUSHJ P,FNDPDS## ;SET UP PDB
MOVE U,DEVUNI##(F) ;SET UP U
MOVE P3,UDBKDB(U) ; AND P3
TLOA F,-1 ;INDICATE FROM DIACTC
;FALL INTO DIARAU
;HERE TO RELEASE ALL UNITS
DIARAU: JUMPE F,CPOPJ1## ;EXIT IF NO DIAG SET UP
PUSHJ P,DIARCX ;GIVE UP IOWD BLOCK IF ONE EXISTS
PUSHJ P,FNDPDS## ;SET UP PDB
PUSH P,U ;SAVE U
DIARA1: HRRZ T1,UNIDIA(U) ;DDB WHICH HAS UNIT
CAME T1,.PDDIA##(W) ;OURS?
JRST DIARA2 ;NO
SETOM UNICYL(U) ;YES, SET SO WE'LL SEEK ON IT
SETZM UNIDIA(U) ;NOW NO DIAG FOR IT
SETZM UNISTS(U) ;UNIT IS AGAIN IDLE
DIARA2: HRR U,UNICHN(U) ;STEP TO NEXT UNIT
CAME U,(P) ;BACK WHERE WE STARTED?
JRST DIARA1 ;NO, TEST IT
PUSHJ P,DIAKDB ;SET ALL KDBS IDLE
ANDCAM T1,KONBSY(T3) ;INSTR TO EXECUTE
SETZM .PDDIA##(W) ;DONT HAVE A DIAG GOING
SETZM DIADSK##
SETOM @DIACHN## ;CHAN IS FREE
SKIPL F
PUSHJ P,DIANUI## ;CLEAR SOME BITS
PUSH P,F
PUSHJ P,CLRDDB## ;RETURN DDB SPACE
POP P,F
IFN FTMP,<
MOVE T1,.CPCPN## ;CURRENT CPU NUMBER
DPB T1,[POINT 3,U,3] ;FOR CLOCK QUEUE REQUEST
TLO U,400000 ;FLAG A CPU NUMBER
> ;END IFN FTMP
MOVE T1,[CRNKUP,,1] ;CAUSE CANT START IO ON UUO LEVEL
SYSPIF
IDPB T1,CLOCK## ; SO COME BACK WITH PD LIST NOT MAPPED
IDPB U,CLOCK## ;SAY WHICH UNIT (CHAN)
SYSPIN
IFN FTMP,<
MOVE T1,.CPCPN## ;CURRENT CPU AGAIN
SETZM CLKMIN##(T1) ;FORCE LOOK AT CLOCK QUEUE
> ;END IFN FTMP
IFE FTMP,<SETOM CLKNEW##>
JUMPL F,TPOPJ## ;NON-SKIP IF CALLED FROM DIACTC
SETZB T1,F ;MAKE SURE CRNKUP IS CALLED BEFORE JOB CAN
PUSHJ P,SLEEP## ; DO ANOTHER DIAG.
JRST TPOPJ1## ;AND TAKE SKIP-RETURN
;STILL IN FTDHIA CONDITIONAL
;HERE TO SET UP A REVERSE IO LIST
DIASCR: JUMPE F,DIAAAU## ;NO ASS'D UNITS
TLO F,-1 ;SET REVERSE FLAG AND FALL INTO DIASCP
;HERE TO SET UP A CHANNEL PROGRAM
DIASCP: JUMPE F,DIAAAU## ;NO ASS'D UNITS
PUSHJ P,DIARCX ;RETURN ANY IOWD
PUSHJ P,GETWD1## ;GET IOWD
HLRE T2,T1 ;LENGTH OF IOWD
JUMPE T2,DIAACP## ;TOO BIG IF 0
SKIPGE F ;REVERSE?
ADD T1,T2 ;YES, COMPUTE 1ST ADDR (-1)
MOVEM T1,DEVDMP##(F) ;UNRELOCATED IOWD
MOVEI T1,1(T1) ;START ADDRESS
MOVNS T2 ;+LENGTH
ADDI T2,-1(T1) ;TOP ADDRESS
PUSHJ P,ZRNGE## ;MAKE SURE THE PAGES ARE OK
JRST [SETZM DEVDMP(F) ;PAGE NOT THERE
JRST DIAACP##] ;BOMB HIM OUT
MOVE P3,UDBKDB(U) ;CHAN (FOR MAPIO)
MOVE P3,KDBCHN(P3)
SETZB P1,P4 ;SAY FIRST CALL, NOT A DX10
MOVE T2,DEVDMP##(F) ;GET IOWD
PUSHJ P,MAPIO## ;RELOCATE THE IOWD
JRST [SETZM DEVDMP##(F)
JRST DIAAFC##] ;NO LOW-CORE BLOCKS
SETZM (P1) ;TERMINATE LIST
MOVE T1,UDBKDB(U) ;LOC OF KDB
MOVE T1,KDBICP(T1) ;INITIAL CONTROL WD ADDR
MOVE T2,CHNTYP(P3) ;IS IT AN RH20 ?
TLNE T2,CP.RH2
TLO P2,(INSVL.(.CCJMP,CC.OPC)) ;YES, MAKE ICWA BE A JUMP
MOVEM P2,(T1) ;POINT ICWA AT CORE-BLOCK
PUSHJ P,STOTAC## ;TELL USER ICWA
JUMPGE F,DIASC1 ;REVERSE?
TLNN P2,(INSVL.(.CCJMP,CC.OPC)) ;YES, RH20?
JRST DIASC1 ;CAN'T REVERSE IT
HRRZ T3,P2 ;OK - SET IO LIST ADDRESS
HLRZ T2,DEVDMP##(F) ;AND WORDCOUNT
PUSHJ P,REVCCW## ;REVERSE THE IOWDS
DIASC1: PUSHJ P,CSDMP## ;SWEEP CACHE
JRST CPOPJ1## ;AND TAKE GOOD RETURN
;HERE TO RETURN A CHAN PROGRAM
DIARCP: JUMPE F,CPOPJ1## ;NOTHING TO DO IF NO DDB
AOS (P)
DIARCX: SKIPN DEVDMP##(F) ;NOTHING TO DO IF NO IOWD
POPJ P,
SETZM DEVDMP##(F) ;NOW NO IOWD
MOVE T1,@KDBICP(W) ;GET LOC OF CORE-BLOCK
PJRST RTNIOW## ;RETURN THE SPACE
;HERE TO TELL USER FINAL CHAN STATS
DIACST: JUMPE F,CPOPJ1## ;NOTHING TO DO IF NO DDB
MOVE P2,KDBICP(W) ;GET ICWA
PJRST DIAGCS## ;FINISH UP IN UUOCON
;STILL IN FTDHIA CONDITIONAL
;HERE TO TEST IF IO IS GOING ON A CHANNEL
;RETURNS NON-SKIP IF YES, SKIPS IF CHAN IS NOW IDLE
WINDWN: SKIPL @DIACHN## ;#IO XFER HAPPENING?
POPJ P, ;#YES, NON-SKIP
MOVE T2,U ;#NO, TEST UNITS FOR POSITIONING
WINDW1: HRRZ T1,UNISTS(T2) ;#UNIT SEEKING?
CAIN T1,PCOD
POPJ P, ;#YES, NON-SKIP
HRR T2,UNICHN(T2) ;#NO, TEST NEXT UNIT
CAME T2,U ;#BACK WHERE WE STARTED?
JRST WINDW1 ;#NO
JRST CPOPJ1## ;#YES, ALL IS NOW QUIET
;ROUTINE TO START UP IO ON A CHANNEL AGAIN
;CALLED ON PI7 SINCE CANT START IO FOR DIFFERENT JOB ON UUO LEVEL
CRNKUP: PUSHJ P,SAVE1##
PUSHJ P,SSEUB##
MOVE U,T1
MOVE P1,DIACHN## ;POINT P1 AT CHANNEL
PUSH P,U
SETOM @DIACHN ;SO VMSER WILL START IO
SETZ J, ;INDICATE "UUO" LEVEL
MOVEI F,SWPDDB##
PUSHJ P,SWPSCN## ;CRANK UP SWAPPER
MOVE U,(P) ;RESET U
SETZM @DIACHN## ;SO ON-CYLINDER UNITS WONT START IO
CRNKU1: HRR U,UNICHN(U) ;NEXT UNIT
PUSHJ P,CRNPOS ;#NO, START THE SEEK GOING
CAME U,(P) ;#BACK WHERE WE STARTED?
JRST CRNKU1 ;#NO, TEST NEXT UNIT
POP P,(P) ;#YES, REMOVE JUNK FROM PDL
MOVE J,UDBKDB(U) ;#GO START AN XFER IF CHNQUE NOT EMPTY
DSKOFF ;#FIGHT RACE
SKIPL KONBSY(J) ;#DID A SEEK FINISH?
PJRST PIKTR0 ;#NO, START IO IF CHNQUE NOT EMPTY
PJRST DOPOPJ ;#YES, FORGET IT
;# SINCE IO IS ALREADY GOING
> ;END IFN FTKL10 FROM WAY BACK
;STILL IN FTDHIA CONDITIONAL
;HERE TO GET KONTROLLER/UNIT
DIAAKU: CAIE F,DSKDDB## ;NO, SOME FLAVOR OF DISK
MOVE T1,DEVNAM(F)
PUSHJ P,MSKUNI## ;SET UP A MASK
PUSHJ P,SRUNA## ;FIND UDB
JRST DIAAIU## ;NOT A DISK UNIT
JFCL
DIAAK1: PUSH P,J ;SAVE J
MOVE J,UDBKDB(U) ;KONTROLLER
MOVE T2,KDBDVC(J) ;GET KONTROLLER CODE
MOVE T1,UDBPDN(U) ;GET PHYSICAL DRIVE NUMBER
LDB T3,UNYKTP## ;GET CONTROLLER TYPE
CAIE T3,TYPRN ;IS IT AN RP20?
JRST DIAAK2 ;NO, CONTINUE
HLRZ T3,KDBUNI(J) ;GET DX20 ADDRESS (MASSBUS UNIT NUMBER)
LSH T3,3 ;MAKE ROOM FOR UNIT NUMBER
IORI T3,(T1) ;OR WITH UNIT NUMBER
SKIPA T1,T3 ;MOVE TO T1 AND SKIP LSH
DIAAK2: LSH T1,3 ;POSITION IT
LSH T2,2 ;POSITION KONTROLLER DEVICE CODE
HRL T1,T2
POP P,J ;RESTORE J
AOS (P) ;SET FOR SKIP-RETURN
PJRST STOTAC## ;TELL USER KON,,UNIT AND RETURN
SUBTTL MONITOR MODE IO ROUTINES
;SUBROUTINE TO COPY POINTERS FROM DDB TO MONITOR BUFFER
;ENTER WITH T1=AOBJN WORD FOR ENTIRE MONITOR BUFFER
;EXIT CPOPJ IF MON BUF IS FULL AND THERE ARE MORE POINTERS IN DDB
;EXIT CPOPJ1 NORMALLY, WITH T1=LOC OF LAST PNTR STORED
;PRESERVES T4
DD2MN:: PUSH P,T4
HRRZ T3,UNISTR(U) ;GET ADDR OF STR DATA BLOCK
SETO T2, ;CREATE MASK FOR
LDB T2,STYCLP##(T3) ;CLUSTER POINTER
MOVEM T2,T4 ;STORE IT FOR LATER
HRRZ T2,DEVCPY##(F) ;IN-CORE COPY
JUMPE T2,DD2MN6 ;EASY IF THERE ISNT ONE
SKIPN DEVRB1##(F) ;DEVRET POINTING AT DEVRBN?
SKIPA T3,[PTRLEN##-1] ;YES, JUST COPY LAST PNTR
MOVSI T3,MPTRLN## ;NO, SET TO COPY ALL
ADDI T3,DEVRB1##(F) ;POINT AT START OF DDB-POINTERS
DD2MN5: MOVE T1,PTRDAT##(T2) ;GET A POINTER FROM IN-CORE COPY
EXCH T1,(T3) ;STORE IN DDB
XOR T1,(T3) ;MAKE SURE WE DIDNT MESS UP
TDNE T1,T4
STOPCD .+1,DEBUG,CDA, ;++IN-CORE COPY DOESN'T AGGREE
SETZM PTRDAT##(T2) ;CLEAR IN-CORE COPY
ADDI T2,1
AOBJN T3,DD2MN5 ;AND STEP TO NEXT
PUSHJ P,SPTRW ;RESET T1 TO POINT AT RIB POINTERS
DD2MN6: MOVSI T2,DEPLPC## ;LAST POINTER IN CORE BIT
ANDCAM T2,DEVLPC##(F) ;CLEAR THE BIT IF IT WAS ON
LDB T2,DEYRLC## ;CURRENT POINTER LOC
HRLS T2
ADD T1,T2 ;UPDATE AOBJN WORD
MOVSI T2,MPTRLN## ;LENGTH OF A BUNCH OF POINTERS
HRRI T2,DEVRB1##(F) ;LOC OF 1ST POINTER
HRRM T2,DEVRET(F) ;SET DEVRET=DEVRB1
SKIPE (T2) ;FIRST POINTER EMPTY
JUMPGE T1,T4POPJ## ;NO, POPJ IF NO SLOTS
DD2MN2: SKIPN T3,(T2) ;GET A POINTER FROM DDB
JRST DD2MN4 ;ALL POINTERS COPIED - RETURN
EXCH T3,(T1) ;STUFF IT IN MON BUF
JUMPE T3,DD2MN3 ;IF OLD PNTR=0, OK
XOR T3,(T1) ;XOR RIB & MON BUF
TDNE T3,T4 ;IF PNTRS EQUAL, SKIP
STOPCD .+1,DEBUG,PDA, ;++POINTERS WITH DIFFERENT ADDRESSES
DD2MN3: SETZM (T2) ;ZERO THE WORD IN DDB
AOBJP T2,[AOJA T1,DD2MN4] ;THROUGH WHEN DDB RUNS OUT
AOBJN T1,DD2MN2 ;DO ANOTHER
SKIPE (T2) ;MON BUF FULL. MORE POINTERS?
JRST T4POPJ## ;MON BUF FULL AND MORE TO
DD2MN4: AOS -1(P) ;SET FOR SKIP-RETURN
SOJA T1,T4POPJ## ;GOOD RETURN
;SUBROUTINE TO READ RIB POINTERS INTO CORE
;GETS A MONITOR BUFFER AND READS THE RIB INTO IT
;RETURNS T3=0 IF OK, T3=-1 IF ERROR; AND T1=AOBJN WORD FOR THE POINTERS
PTRGET::PUSHJ P,BUFRIB ;GET MON BUF, READ RIB INTO IT
SKIPA T3,[-1] ;RIB ERROR - RETURN T3=-1
TWOLOC: SETZ T3,2 ;OK - T3=0
PJRST SPTRW ;SET T1=AOBJN WORD AND RETURN
;SUBROUTINE TO COPY CURRENT POINTERS FROM MON BUF TO DDB
;ENTER WITH RIB IN MON BUF, T1=AOBJN WORD FOR POINTERS
;EXIT WITH POINTERS COPIED INTO DDB, DEYRLC UPDATED
PTRCPY::LDB T2,DEYRLC## ;PREVIOUS POINTER RELATIVE LOC
SKIPN DEVRB2(F) ;DEVRB2=0?(PNTR CAME FROM A.T. IF YES)
SKIPA T2,TWOLOC ;YES. START AT 3RD ENTRY IN PNTRS
ADDI T2,PTRLEN## ;+LENGTH OF A BUNCH OF POINTERS
HRLS T2
ADD T1,T2 ;UPDATE AOBJN WORD (WAS FOR WHOLE POINTER AREA)
;SUBROUTINE TO BLT POINTERS FROM MONITOR BUFFER TO DDB
;ENTER WITH T1=AOBJN WORD FOR CURRENT POINTERS IN MONITOR BUFFER
PTRBLT::MOVE T3,T1 ;SAVE CURRENT AOBJN WRD
PUSHJ P,SPTRW ;GET AOBJN WRD FOR WHOLE MON BUF
HRRZ T2,T3 ;CURRENT PNTR LOC
SUBI T2,(T1) ;-ORIGINAL PNTR LOC=NEW DEYRLC
MOVE T1,T3 ;RESTORE CURRENT AOBJN WORD
;SUBROUTINE TO COPY POINTERS FROM MON BUF TO DDB
; STORE DEVRLC WITHOUT COMPUTING
;ENTER T1=AOBJN WORD FOR POINTERS
PTRBL1::DPB T2,DEYRLC## ;SAVE IN DDB
HLLM T1,DEVRSU##(F) ;-NO OF PNTRS LEFT
MOVSI T2,MPTRLN##
HRRI T2,DEVRB1##(F) ;AOBJN WORD FOR DDB
HRRM T2,DEVRET##(F)
PTRBL2: SKIPA T3,(T1) ;NEXT POINTER
PTRBL3: SETZ T3, ;POINTERS DONE-ZERO
MOVEM T3,(T2) ;SAVE IN DDB
AOBJP T2,PTRBL4 ;COUNT DDB WORD
AOBJN T1,PTRBL2 ;GET NEXT POINTER
JRST PTRBL3 ;THOUGH WITH MON BUF
PTRBL4: MOVE T3,DEVLPC##(F) ;GET LAST POINTER IN CORE WORD
AOBJN T1,PTRBL5 ;JUMP IF MORE POINTER SLOTS IN RIB
PUSHJ P,GTLPT## ;GET LAST RIB POINTER
SKIPE T2 ; DONT LIGHT DEPLPC IF 0
TLOA T3,DEPLPC## ;NO MORE LEFT, LAST POINTER IS IN CORE
PTRBL5: TLZ T3,DEPLPC## ;LAST IS NOT IN CORE
MOVEM T3,DEVLPC##(F) ;RESTORE THE FLAG
PUSHJ P,CPYPTR ;COPY POINTERS TO IN-CORE COPY
;FALL INTO NEXT PAGE
;IF ACYWCT .GTR. 0 ,ACPSBC=1, THEN IF A WRITER CHANGES A CHECKSUM
; AND THE NEW PNTR ISNT IN SOME OTHER WRITER'S DDB, IF THE 2ND WRITER
; THEN CHANGES THE CHECKSUM OF THAT PNTR AND CLOSES BEFORE THE 1ST WRITER
; (ORIGINAL ALLOCATER), THEN WHEN THE 1ST WRITER CLOSE WE HAVE A
; CHECKSUM ERROR IN THE FILE.
;HENCE, WE HAVE TO SCAN DDBS FOR A WRITER WITH THIS PNTR, USE THE PNTER
; FROM THE FOUND DDB.
HRRZ T1,DEVACC##(F) ;LOC OF A.T.
JUMPE T1,CPOPJ##
LDB T2,ACYWCT## ;ARE THERE MULTIPLE WRITERS?
SOJLE T2,CPOPJ##
MOVE T2,ACCSBC##(T1) ;YES, HAS CHECKSUM CHANGED?
TRNN T2,ACPSBC##
JRST CPOPJ## ;NO
PUSHJ P,SAVE3##
HRRZ T3,UNISTR(U) ;YES, SET UP A MASK FOR
SETO T2, ; ADDR PORTION OF RETRIEVAL POINTERS
LDB T2,STYCLP##(T3)
MOVEM T2,P1 ;AND SAVE IT AWAY
PUSHJ P,FNDDDB ;FIND A WRITING DDB FOR THE FILE
POPJ P, ;NONE (DDB COULD BE IN EXTRIB)
PTRBL6: HLRZ T1,PTRFUN##(T2) ;SET UP 1ST UNIT IN FOUND-POINTERS
LDB P3,UNYLN1## ;UNIT NUMBER
TRO P3,RIPNUB## ;FAKE UP A UNIT-CHANGE PNTR FOR IT
HRRZ T1,DEVFUN##(F) ;1ST UNIT IN OUR DDB
LDB P2,UNYLN1##
TRO P2,RIPNUB## ;FAKE A UNIT-CHANGE FOR DDB POINTERS
MOVEI T3,DEVRB1##(F) ;YES, SET AN AOBJN WORD FOR OUR DDB
HRRZ T1,DEVCPY##(F) ;IN-CORE COPY?
SKIPE T1 ; (MIGHT HAVE RUN OUT OF FREE-CORE)
MOVEI T3,PTRDAT##(T1) ;YES, USE THOSE PNTRS INSTEAD
HRLI T3,MPTRLN##
PTRBL7: MOVEI T1,PTRDAT##(T2) ;SET AOBJN WORD FOR POINTERS
HRLI T1,MPTRLN## ; FOR THE FOUND-DDB
PTRBL8: MOVE T4,(T1) ;GET A DDB POINTER
JUMPE T4,PTRBL9 ;KEEP GOING IF 0 (PNTR MIGHT BE IN DEVRBN)
TLNN T4,-1 ;UNIT-CHANGE?
SKIPA P3,T4 ;YES, RESET P3
CAME P2,P3 ;NO, ARE POINTERS FOR SAME UNIT?
JRST PTRBL9 ;NO, TRY NEXT
XOR T4,(T3) ;YES, IS IT IN OUR DDB?
TDNN T4,P1
JRST PTRBLA ;YES, COPY PNTRS TO OUR DDB
PTRBL9: AOBJN T1,PTRBL8 ;NO, TRY NEXT PNTR
SKIPN T4,1(T3) ;ANY MORE PNTRS IN OUR DDB?
JRST PTRBLB ;NO MATCH - TRY NEXT DDB
TLNN T4,-1 ;ANOTHER POINTER, IS IT A UNIT-CHANGE?
SKIPA P2,T4 ;YES, RESET P2
TLNN T4,-1 ;IF THIS IS A UNIT-CHANGE
AOBJN T3,.+1 ;DON'T TRY TO MATCH IT AGAINST FOUND DDB
AOBJN T3,PTRBL7 ;TEST NEXT PNTR IN OUR DDB
JRST PTRBLB ;NO MATCH, TRY NEXT DDB
;HERE WHEN WE FOUND A MATCH BETWEEN THE WRITING DDB AND OUR DDB
PTRBLA: MOVE T4,(T1) ;GET PNTR FROM THE FOUND DDB
MOVEM T4,(T3) ;AND STUFF IT IN OURS
AOBJP T3,CPOPJ## ;THROUGH IF OUR DDB FULL
SKIPN (T3) ; OR IF NO MORE PNTRS IN OUR DDB
POPJ P,
SKIPE 1(T1) ;IS THERE ANOTHER PNTR IN FOUND DDB?
AOBJN T1,PTRBLA ;YES, COPY INTO OUR DDB
PTRBLB: HRRZ T1,DEVACC##(F) ;RESET T1 FOR FNDDDN
PUSHJ P,FNDDDN ;NO, FIND ANOTHER WRITING DDB
POPJ P, ;NO - DONE
JRST PTRBL6 ;FOUND ANOTHER - TEST ITS PNTRS
;SUBROUTINE TO SET AN AOBJN WORD FOR POINTERS IN THE MONITOR BUFFER
;ENTER WITH LOC OF MON BUF IN .UPMBF, EXIT WITH T1=AOBJN WORD
;T2-T4 RESPECTED
SPTRW:: HRRZ T1,.USMBF ;LOC OF MON BUF (-1)
ADD T1,RIBFIR##+1(T1) ;AOBJN WORD (-1)
AOJA T1,CPOPJ## ;MAKE REAL AOBJN WORD AND RETURN
;SUBROUTINE TO GET A MONITOR BUFFER
;RETURNS WITH T1=AN IOWD FOR THE BUFFER
;PRESERVES T2
GTMB2: PUSH P,T2 ;SAVE T2
PUSHJ P,GTMNBF ;GET THE MON BUF
PJRST T2POPJ## ;RESTORE T2 AND RETURN
GTMNBF::SKIPN T1,.USSBF ;.UPMBF WRONG?
JRST GTMNB1
MOVEM T1,.USMBF ;YES (FROM RETRD8). FIX IT
SETZM .USSBF
PUSHJ P,RMVLBF## ;AND RETURN THE EXTRA PAGE
JFCL
GTMNB1::SKIPE T1,.USMBF ;ALREADY HAVE MON BUF?
POPJ P, ;YES
MOVEI T2,BLKSIZ## ;NO OF WORDS TO GET
PUSH P,T3
PUSHJ P,GFWDCD## ;GET THE SPACE IN FUNNY SPACE
STOPCD T3POPJ##,JOB,MNA, ;++MONITOR-BUFFER NOT AVAILABLE
SUBI T1,1 ;LOC-1 IN RH
HRLI T1,MBLKSZ## ;-200 IN LH
MOVEM T1,.USMBF ;SAVE IN UPMP
JRST T3POPJ##
;SUBROUTINE TO GET THE MONITOR BUFFER, READ RIB INTO IT
;RETURNS CPOPJ IF ERROR, CPOPJ1 NORMALLY, T1=IOWD
BUFRIB::PUSHJ P,GTMNBF ;GET MONITOR BUFFER
;AND FALL INTO REDRIB
;SUBROUTINE TO READ THE PRIME RIB, T1=IOWD
;RETURNS CPOPJ IF ERROR, CPOPJ1 NORMALLY
REDRIB::JSP T4,SAVUN ;PUSH U, SET UP U FOR RIB
PUSHJ P,PRMRIB ;SET UP TO READ THE PRIME RIB
SKIPN T1,.USMBF ;IOWD FOR MONITOR BUFFER
PUSHJ P,GTMB2 ;NONE YET, GET MON BUF
PUSHJ P,MONRED ;READ THE RIB INTO MON BUF
PUSHJ P,RIBCHK ;CHECK RIB
JRST RESUNI ;RIB ERR - NON SKIP RETURN
AOS -1(P) ;GOOD RIB - SET FOR SKIP RETURN
;FALL INTO RESUNI AND RETURN
;SUBROUTINE TO RESTORE DEVUNI
;ENTER WITH CURRENT U SAVE ON PD LIST
RESUNI: POP P,U ;CURRENT U
SKIPE DEVUNI##(F) ;UNLESS UNIT(STR) WAS REMOVED
PJRST STORU ;SAVE IN DDB AND RETURN
;SUBROUTINE TO WRITE THE RIB IF IT HAS CHANGED
WTRBIC::SKIPA T1,DEVRRC##(F) ;HERE FROM OUTPUT
FWRBIC::SKIPA T1,DEVRRC##(F) ;HERE FROM FILOP
TLNE T1,DEPRRC## ;USER WANT TO REWRITE IF RIB CHANGES?
TLNN T1,DEPRHC## ;YES, HAS RIB CHANGED?
POPJ P, ;NO, GO AWAY
HRRZ T1,DEVACC##(F) ;YES, IS THE FILE AN UPDATE FILE
JUMPE T1,CPOPJ##
MOVE T1,ACCSTS##(T1)
TRNE T1,ACPUPD
TLNN F,OUTPB ; AND HAS THIS USER UPDATED IT?
POPJ P, ;NO, DON'T DO ANYTHING
PUSHJ P,SETU ;NOT SET IF FILOP
POPJ P,
PUSHJ P,WAIT1##
PUSHJ P,PTRTST ;UPDATE POINTERS ETC
JFCL ;WE TRIED
POPJ P,
;SUBROUTINE TO WRITE A RIB
;RETURNS T3=0 IF WRITTEN OK, NON-0 IF BAD
WRTRIB::PUSHJ P,SAVE1##
PUSH P,U ;SAVE CURRENT UNIT
HRRZ T1,DEVACC##(F) ;LOC OF A.T.
JUMPE T1,WRTRB1
MOVE P1,ACCSTS##(T1) ;STATUS OF FILE
TRNN P1,ACPUPD ;UPDATE?
JRST WRTRB1 ;NO
MOVE T4,.USMBF ;MON BUF
SKIPE T3,ACCWRT##(T1) ;NO OF BLOCKS IN FILE
SUBI T3,1
LSH T3,BLKLSH## ;CONVERT TO WORDS
HRRZ T2,T1
LDB T1,ACYLBS## ;SIZE OF LAST BLOCK
ADD T3,T1 ;NO OF WORDS IN FILE
MOVEM T3,RIBSIZ##+1(T4) ;SAVE IN RIB
MOVE T1,ACCALC##(T2) ;NO OF BLOCKS ALLOCATED
EXCH T1,RIBALC##+1(T4) ;SAVE IN RIB
CAMN T1,RIBALC##+1(T4) ;DID THE SIZE CHANGE?
JRST WRTRB1 ;NO
SETZ P1, ;YES, SET P1=0 AS A FLAG
PUSHJ P,RIBSAT## ;WRITE CHANGED SATS (IN CASE OF A CRASH)
;HERE WITH SATS WRITTEN IF NECCESSARY
WRTRB1: LDB T2,DEYRBU## ;GET CURRENT RIB LOGICAL UNIT NUMBER
PUSHJ P,NEWUNI ;SET UP U,DEVUNI
STOPCD RESUNI,DEBUG,NXU, ;++NON X UNIT
LDB T2,DEYRBA## ;GET CURRENT RIB CLUSTER ADDRESS
LDB T3,UNYBPC## ;BLOCKS PER CLUSTER, THIS UNIT
IMUL T2,T3 ;BLOCK NUMBER IN T2
MOVE T1,.USMBF ;GET IOWD TO MONITOR BUFFER
MOVEM T2,RIBSLF##+1(T1) ;SAVE BLOCK NUMBER
MOVEI T3,CODRIB##
MOVEM T3,RIBCOD##+1(T1) ;INDICATE BLOCK IS A RIB
PUSHJ P,MONWRT ;WRITE THE MON BUF
JUMPN P1,WRTRB3 ;IF AN UPDATE FILE
SKIPL P1,DEVRIB##(F) ; AND IN EXTENDED RIB
JRST WRTRB3
PUSH P,RIBALC##+1(T1) ;SAVE RIBSIZ, RIBALC
PUSH P,RIBSIZ##+1(T1)
PUSHJ P,REDRIB ;READ THE PRIME RIB
JRST [POP P,(P) ;RIB ERROR
POP P,(P)
JRST WRTRB2]
POP P,RIBSIZ##+1(T1)
POP P,RIBALC##+1(T1) ;RESTORE RIBSIZ, RIBALC
PUSHJ P,RIBAD ; FOR USE IN CASE OF CRASH
JSP T4,RIBUN
PUSHJ P,MONWRT ;REWRITE PRIME RIB
WRTRB2: PUSH P,T3 ;SAVE ERROR BITS
MOVEM P1,DEVRIB##(F)
PUSHJ P,RIBCUR ;REREAD EXTENDED RIB
JFCL
POP P,T3
WRTRB3: POP P,U ;RESTORE CURRENT UNIT
MOVSI T1,DEPRHC## ;CLEAR RIB HAS CHANGED BIT
ANDCAM T1,DEVRRC##(F)
PJRST STORU ;SAVE IN DDB AND RETURN
;SUBROUTINE TO SET UP TO READ THE PRIME RIB
;RETURNS CPOPJ WITH DEVRIB SET UP IN DDB
PRMRIB::PUSHJ P,RIBAD ;COMPUTE ADR OF RIB
SETZM DEVRIB##(F) ;CLEAR DEVRIB FOR DPB'S
LDB T3,UNYLUN## ;GET RPIME RIB LOGICAL UNIT NUMBER
DPB T3,DEYRBU## ;DEPOSIT IN DDB
PUSH P,T2 ;SAVE T2
HRRZ T2,DEVACC##(F) ;GET ADDRESS OF A.T.
MOVE T2,ACCPT1##(T2) ;GET FIRST POINTER FOR FILE
LDB T3,STYCLP##(T4) ;GET CLUSTER ADDRESS
DPB T3,DEYRBA## ;DEPOSIT IN DDB
PJRST T2POPJ## ;RESTORE T2 AND RETURN
;SUBROUTINE TO SAVE CURRENT DEVUNI
;U CHANGED, ALL OTHER ACS RESPECTED
;SAVES THE CURRENT U ON THE PUSH DOWN LIST
;ENTER AT SAVUN TO SAVE CURRENT U, AT RIBUN JUST TO SET U FOR RIB UNIT
;CALLED WITH JSP T4
SAVUN:: PUSH P,U ;SAVE CURRENT U
RIBUN:: HLRZ U,DEVUNI##(F) ;UNIT OF RIB
PUSHJ P,STORU ;SAVE AS CURRENT UNIT
JRST (T4) ;AND RETURN
;SUBROUTINE TO COMPUTE A RIB ADDRESS FROM THE ACCESS TABLE
;EXIT WITH T2=BLOCK NUMBER, T4=LOC OF STR DATA BLOCK
;T1 RESPECTED
RIBAD:: HRRZ T2,DEVACC##(F) ;LOC OF ACCESS TABLE
MOVE T2,ACCPT1##(T2) ;GET 1ST POINTER FROM A.T.
;SUBROUTINE TO COMPUTE A DISK ADDRESS FROM A GROUP POINTER
;ENTER WITH GROUP POINTER IN T2
;EXIT WITH T2=BLOCK NUMBER, T4=LOC OF STR DATA BLOCK
;T1 RESPECTED
GRPAD:: HRRZ T4,UNISTR(U) ;GET BYTE POINTER FOR ADDRESS OF CLUSTER
LDB T2,STYCLP##(T4) ;CLUSTER ADDRESS
LDB T3,UNYBPC## ;COMPUTE BLOCK ADDRESS (NOTE THAT
IMUL T2,T3 ; RELATIVE BLOCK 0 OF 1ST POINTER IS RIB LOC)
POPJ P, ;AND RETURN
;SUBROUTINE TO READ A UFD RIB
;ENTER WITH T2=BLOCK NUMBER
;RETURNS CPOPJ IF ERROR, CPOPJ1 NORMALLY WITH T1=IOWD, T2=BLOCK
UFDRED::MOVE T1,.USMBF ;IOWD FOR MONITOR BUFFER
PUSHJ P,MONRED ;READ THE RIB
MOVE T4,T2 ;BLOCK NUMBER (FOR RIBERR)
JUMPN T3,RIBERR ;CHECK FOR ERRORS DETECTED IN MONRED
CAME T2,RIBSLF##+1(T1) ;CHECK BLOCK NUMBER
JRST RIBERR ;BAD
MOVEI T3,CODRIB## ;OK. CHECK RIB CODE WORD
CAME T3,RIBCOD##+1(T1)
JRST RIBERR ;BAD
HLRZ T3,RIBEXT##+1(T1) ;OK. CHECK EXT="UFD"
CAIN T3,(SIXBIT .UFD.)
SKIPA T3,RIBNAM##+1(T1) ;OK, GET PPN
JRST UFDRE2 ;NOT "UFD", CHECK IF "SFD"
CAME T3,DEVPPN(F) ;UFD, CHECK PPN
CAMN T3,DEVFIL(F)
SKIPA T3,RIBSTS##+1(T1) ;OK, GET STATUS WD
JRST RIBERR ;BAD
TROE T3,RIPABC## ;RIPABC ON?
PJRST CPOPJ1## ;YES
MOVEM T3,RIBSTS##+1(T1) ;NO, LIGHT IT (UFD WRITTEN BY OLDER MON)
PUSHJ P,MONWRT ;REWRITE THE UFD RIB
JRST CPOPJ1## ;OK, RETURN
;HERE IF EXTENSION ISN'T "UFD"
UFDRE2: CAIE T3,(SIXBIT .SFD.) ;IS IT "SFD"?
JRST RIBERR ;NO, BAD RIB
HRRZ T3,DEVSFD##(F) ;YES, GET NAME OF SFD
MOVE T3,NMBNAM##(T3) ; FROM ITS ACCESS TABLE
CAMN T3,RIBNAM##+1(T1) ;CHECK NAME IN RIB
JRST CPOPJ1## ;OK, SKIP-RETURN
JRST RIBERR ;ERROR
;SUBROUTINE TO READ A RIB INTO THE MONITOR BUFFER
;ENTER WITH T2 = DISK ADDRESS OF RIB
;RETURNS CPOPJ IF ERROR, CPOPJ1 NORMALLY
RIBRED::SKIPN T1,.USMBF ;T1=IOWD FOR THE DATA
PUSHJ P,GTMB2
PUSHJ P,MONRED ;READ THE RIB
;AND FALL INTO RIBCHK
;SUBROUTINE TO CHECK THE VALIDITY OF A RIB
;ENTER WITH T1 = IOWD, T2 = DISK ADDRESS
;RETURNS CPOPJ IF ERROR, CPOPJ1 NORMALLY, T1=IOWD
RIBCHK: MOVE T4,T2 ;BLOCK (FOR RIBERR)
TRNN T3,IOIMPM+IODTER+IODERR+IOBKTL ;ERROR BIT FORM READ?
CAME T2,RIBSLF##+1(T1) ;BLOCK NUMBER IN RIB RIGHT?
JRST RIBERR ;NO. ERROR
MOVEI T2,CODRIB## ;YES. IS THIS BLOCK A RIB?
CAME T2,RIBCOD##+1(T1)
JRST RIBERR ;NO. ERROR
MOVE T2,DEVFIL(F) ;YES. FILE NAME
CAME T2,RIBNAM##+1(T1) ;MATCH NAME IN RIB?
JRST RIBERR ;NO. ERROR
HLLZ T2,DEVEXT(F) ;YES. FILE EXTENSION
HLLZ T3,RIBEXT##+1(T1) ;EXT STORED IN RIB
CAME T2,T3 ;MATCH?
JRST RIBERR ;NO. ERROR
HRRZ T3,RIBFIR##+1(T1) ;YES. REL LOC OF 1ST PNTR IN RIB
CAILE T3,BLKSIZ##-2 ;LEGAL?
JRST RIBERR ;NO. ERROR
MOVE T2,DEVPPN(F) ;YES. PPN OF FILE
CAME T2,RIBPPN##+1(T1) ;MATCH PPN IN RIB?
JRST RIBERR ;NO,RIB ERR
TLNN F,RENMB ;DON'T CHECK RIBUFD ON RENAME
; ONLY ON RENAME FOR EXTENDED RIBS
PUSHJ P,GTUFR## ;YES, COMPUTE RIBUFD WORD
PJRST CPOPJ1## ;NOT YET SET UP, ASSUME OK
CAMN T2,RIBUFD##+1(T1) ;MATCH?
PJRST CPOPJ1## ;YES, OK RETURN
ADDI T2,1 ;THE OLD REFRESHER PUT THIS NUMBER 1 TOO LOW
CAMN T2,RIBUFD##+1(T1) ; SO ALLOW THAT CASE TO WIN
PJRST CPOPJ1##
MOVE T4,RIBSLF##+1(T1) ;RESTORE BLOCK NUMBER
;HERE WHEN THE RIB INFORMATION IS NOT CORRECT.
RIBERR::TDO S,[XWD IOSSCE##,IOIMPM] ;LIGHT ERROR BITS
JUMPE U,RIBER1 ;SKIP THE REST OF THIS IF U=0 (NEWUNI)
MOVEI T1,UNPRER ;SET UP A BIT
ADDM T1,UNIMCT(U) ;COUNT IN SOFTWARE-ERROR WORD FOR UNIT
SKIPGE UNIECT(U) ;IF NOT IN ERROR RECOVERY
MOVEM T4,UNIHBN(U) ; SAVE BLOCK FOR DAEMON
MOVEI T1,.FIRBE ;FILIO-DETECTED RIB ERROR
PUSHJ P,FILELG ;LOG THE ERROR
PUSHJ P,SAVE2## ;SLFND USES P-ACS
HRRZ T1,UNISTR(U) ;STR LOC
MOVE T1,STRNAM##(T1) ;STR NAME
MOVE P1,U ;SRSTR WIPES U
PUSHJ P,SRSTR## ;FIND STR NUMBER
JRST STRIOS ;WHAT???
MOVE U,P1 ;RESTORE U
HRRZ T1,T4 ;STR NUMBER
MOVE P2,SYSSRC## ;THIS STR IN SYS SEARCH-LIST?
PUSHJ P,SLFNA##
PJRST STRIOS ;NO
RIBER1: AOS T1,RIBTOT## ;YES, COUNT AN ERROR
CAMG T1,RIBECT## ;ABOVE THE THRESHOLD?
PJRST STRIOS ;NO, DONT TELL OPR
PUSH P,U ;YES, INFORM THE OPR
MOVE U,OPRLDB## ;WHERE TO TYPE THE MESSAGE
PUSHJ P,INLMES##
ASCIZ /
RIB error on /
PUSHJ P,PRTDDB## ;"STR:NAM.EXT[PPN]"
PUSHJ P,PCRLF##
POP P,U ;RESTORE U
PJRST STRIOS ;STORE S AND RETURN
;SUBROUTINE TO READ AND VERIFY THE BAT BLOCKS ON A UNIT.
;ENTER WITH T1=IOWD, U=UDB ADDRESS
;RETURNS CPOPJ IF BOTH BLOCKS ARE BAD, CPOPJ1 NORMALLY WITH T1=IOWD
; AND BLOCK IN BUFFER POINTED TO BY IOWD
REDBAT::PUSHJ P,SAVE1## ;GET AN AC TO USE
MOVE P1,UNIHOM(U) ;GET HOME BLOCK ADDRESSES FOR THIS UNIT
REDBA1: JUMPE P1,CPOPJ## ;GO IF TRIED BOTH BLOCKS
MOVEI T2,LBOBAT##(P1) ;PUT ADDRESS OF BAT BLOCK IN T2
PUSHJ P,MONRED ;READ THE BLOCK
MOVS T2,BAFNAM##+1(T1) ;GET SIXBIT CODE FROM BLOCK
TRNN T3,IODTER+IODERR+IOIMPM ;ANY READ ERRORS?
CAIE T2,'BAT' ;NO, SIXBIT CODE CONSISTENT?
JRST REDBA2 ;NO, TRY OTHER BLOCK
MOVEI T2,CODBAT## ;GET UNLIKELY CODE
MOVEI T3,LBOBAT##(P1) ;AND THE BLOCK NUMBER THAT WE READ
CAMN T3,BAFSLF##+1(T1) ;SELF POINTER CONSISTENT?
CAME T2,BAFCOD##+1(T1) ;YES, UNLIKELY CODE MATCH?
CAIA ;NO, TRY NEXT
JRST CPOPJ1## ;YES, THIS BLOCK IS OK
REDBA2: HLRZS P1 ;SETUP TO TRY OTHER BLOCK
JRST REDBA1 ;AND DO SO
UCACHE==1 ;**TEMP FOR NOW**
;SUBROUTINE TO WRITE A BLOCK (OR SERIES OF BLOCKS)
;ENTER WITH T1= IOWD T2=BLOCK NUMBER
;ENTER AT MONWRS TO STORE BLOCK NUMBER INTO BLKSLF WORD OF FIRST BLOCK
;ENTER AT MONWRU TO DO MONWRT BUT NOT TO USE DISK CACHE
MONWRS::MOVEM T2,BLKSLF##+1(T1) ;MAKE SELF BLOCK NUMBER CONSISTENT
MONWRT::TLZA F,UCACHE ;BE SURE WE GO THROUGH DISK CACHE
MONWRU::TLO F,UCACHE ;DONT GO THROUGH DISK CACHE
PUSH P,S ;SAVE S
TLO S,IO ;INDICATE WRITING
PJRST MONIOY ;DO IO
;SUBROUTINE TO READ A BLOCK (OR SERIES OF BLOCKS)
;ENTER WITH T1 = IOWD FOR THE DATA T2= BLOCK NUMBER
;RETURNS WITH T2 = BLOCK NUMBER READ, T1 = IOWD,
; AND T3=ERROR BITS SET ON THIS OPERATION
;INSTEAD OF ERROR RETURN - S SET WITH ERROR BITS IN RH. U AND F SET UP
;ENTER AT MONRDU TO NOT GO THROUGH DISK CACHE
MONRED::TLZA F,UCACHE ;BE SURE TO USE CACHE
MONRDU::TLO F,UCACHE ;DO NOT USE DISK CACHE
SKIPN .UONCE## ;NOT IN ONCE?
CAMN T1,.USMBF ;READING INTO MONITOR BUFFER?
TLZ S,IOSRIB ;YES, IF RIB WAS THERE BEFORE IT ISN'T NOW
PUSH P,S ;SAVE S BEFORE UUOPWQ DOES ITS THING
MOVEM S,DEVIOS(F)
TLZ S,IO ;INDICATE READING
PJRST MONIOY ;JOIN COMMON CODE
;CALLED FROM SPRIO, REDSWP/WRTSWP
MONIOU::TLO F,UCACHE ;DONT GO THROUGH CACHE
PUSH P,S ;SAVE S
;FALL INTO MONIOY
MONIOY: TRNE S,IOACT ;IO IN PROGRESS?
STOPCD .,STOP,IIP, ;++ IO IN PROGRESS - ERROR
SKIPGE T2
STOPCD .,STOP,BIN, ;IO TO A NEGATIVE BLOCK #
MOVEI T3,IODTER ;SET FOR ERROR
CAML T2,UNIBPU(U) ;REQUESTED BLOCK ABOVE HIGHEST ON UNIT?
JRST MONIO2 ;YES. ERROR RETURN
TDZ S,[IOSTBL,,IOIMPM+IOBKTL+IODTER+IODERR] ;ZERO THE TEMP ERR BITS
TLO S,IOSMON ;INDICATE MONITOR IO
MOVEM S,DEVIOS(F) ;STORE NEW S IN DDB
IFN FTXMON,<
PUSH P,DEVISN(F) ;SAVE CURRENT SECTION NUMBER FOR I/O
SKIPN DINITF## ;IF IN ONCE ONLY,
CAME T1,.USMBF ;OR NOT A MONITOR BUFFER,
JRST .+2 ;LEAVE DEVISN ALONE
SETZM DEVISN(F) ;A MONITOR BUFFER, ALWAYS IN SECTION 0
>
PUSH P,DEVDMP##(F) ;SAVE CURRENT DEVDMP
MOVEM T1,DEVDMP##(F) ;IOWD TO READ THE DATA
PUSH P,DEVBLK##(F) ;SAVE CURRENT BLOCK NUMBER
MOVEM T2,DEVBLK##(F) ;BLOCK WE WANT TO READ
MONIO9: PUSHJ P,CHEKU ;WAS UNIT YANKED?
JRST MONIO1 ;YES, HE LOSES
PUSHJ P,UNICHK ;MAKE SURE UNIT IS OKAY.
JRST MONIO1 ;NO GOOD - WRITING FROM MON-BUF, UNIT OFF LINE
IFE FTMP,<
MOVE J,UDBKDB(U) ;LOC OF KONTROLLER DATA BLOCK
>
PUSHJ P,CSHIO ;TRY TO READ BLOCK FROM DISK CACHE
TLZE S,IOSTBL ;TROUBLE?
JRST MONIO9 ;YES, RETRY AT UUO LEVEL
;FALL INTO MONIO1
MONIO1: ANDI S,IOIMPM+IODERR+IODTER+IOBKTL ;GET ERROR BITS FROM S
MOVE T3,S ;AND SAVE IN T3
MOVE T2,DEVBLK##(F) ;RESTORE BLOCK NO. TO T2
MOVE T1,DEVDMP##(F) ;AND IOWD TO T1
IFN FTDUAL,<
HRRZ U,DEVUNI##(F) ;RESET U
>
POP P,DEVBLK##(F) ;RESTORE THE CHANGED STUFF TO THE DDB
POP P,DEVDMP##(F)
IFN FTXMON,<
POP P,DEVISN(F) ;RESTORE SECTION NUMBER FOR I/O
>
MONIO2: POP P,S
OR S,T3 ;SET ANY ERROR BITS INTO S
TLZ F,UCACHE ;BE SURE WE DONT STORE UCACHE BIT
STRIOS::MOVEM S,DEVIOS(F)
POPJ P, ;AND RETURN TO CALLER
SUBTTL ONCE PER SECOND CODE FOR DISK
DSKSEC::MOVSI T1,(CR.ATO) ;BIT TO TEST
TDNE T1,.CPRUN## ;WAITING FOR AUTCON TO RUN?
POPJ P, ;THEN DO NOTHING
PUSHJ P,SAVE4##
PUSHJ P,SSEUB## ;SAVE CURRENT UBR
IFN FTMP,<
PUSHJ P,DSKRQT ;TEST FOR DEAD CPU
>
MOVEI T1,ACTDRB##-DRBLNK##
DSKOFF ;#PREVENT RACES
DSKS0A: HRRZ T1,DRBLNK##(T1) ;#GET LINK TO NEXT DRB
CAIN T1,ACTDRB## ;#END OF CHAIN?
JRST DSKS0B ;#YES
IFN FTMP,<
LDB T2,DRYCPU## ;#GET CPU WHICH STARTED THIS I/O
CAMN T2,.CPCPN## ;#ON CORRECT CPU?
>; END IFN FTMP
IFN FTCIDSK,<
SOSE DRBTIM##(T1) ;#COUNT DOWN HUNG TIMER
JRST DSKS0A ;#NOT TIMED OUT YET
MOVEI T2,DRPTRY## ;#BIT TO SET
IORM T2,DRBSTS##(T1) ;#RETRY THIS OPERATION
MOVEI T2,4*DSKTIM## ;#HUNG TIMER
MOVEM T2,DRBTIM##(T1) ;#RESET IT
JRST DSKS0A ;#ONTO THE NEXT DRB
>; END IFN FTCIDSK
DSKS0B: DSKON ;#OK TO INTERRUPT
IFN FTCIDSK,< PUSHJ P,RESWP> ;RETRY OFF-LINE SWAPS
MOVEI J,KDBTAB##+.TYDSK-KDBNXT ;POINT TO START OF KDB CHAIN
DSKSE1: SKIPN J,KDBNXT(J) ;STEP TO NEXT KDB
POPJ P, ;DONE
PUSHJ P,DSPWQ ;CHECK PWQ (BEFORE KONCAM TEST)
IFN FTMP,<
MOVE T1,KDBCAM(J) ;CPU(S) WHICH OWN KONTROLLER
TDNN T1,.CPBIT## ;IS IT US?
JRST DSKSE1 ;NO, GO TO NEXT KONTROL
>
IFN FTCIDSK,<
MOVSI T1,KOPCNA ;CREDIT NOT AVAILABLE BIT
SKIPGE KONMX(J) ;CAN KONTROLLER DO MULTIPLE TRANSFERS?
ANDCAM T1,KONCNA(J) ;YES, CLEAR CREDIT NOT AVAILABLE
>; END IFN FTCIDSK
PUSHJ P,@KONSEC(J) ;CALL THE ONCE PER SECOND CODE IF IT EXISTS
DSKOFF ;INTERLOCK THIS
IFE FTKS10,<
SKIPN DIADSK## ;DON'T BLAST KON IF IN USE BY DIAG.
PUSHJ P,@KONALV(J) ;MAKE SURE DISK HAS PI,IVI
>
SKIPGE KONDRB(J) ;KONTROLLER USE DRBS?
JRST DSKS10 ;YES, DON'T TWIDDLE WITH UNITS HERE
SKIPN U,KONCUA(J) ;GET CURRENT TRANSFERRING UNIT
JRST DSKSE2 ;NONE, SKIP THIS
MOVE T1,UNISTS(U)
CAIN T1,TCOD ;IS IT IN TRANSFER STATE?
SOSE UNITIM(U) ;YES, COUNT DOWN HUNG-TIMER
JRST DSKSE2
PUSHJ P,DSKS11 ;TIMER WENT TO 0 - IT IS HUNG
DSKOFF ;MIGHT HAVE COME BACK ON
DSKSE2: MOVE T1,KDBCHN(J) ;GET CURRENT CHAN
SKIPGE DIADSK## ;IF DIAG IS GOING
CAME T1,DIACHN## ; ON THIS CHAN
CAIA
JRST DSKS10 ;LEAVE OTHER UNITS ALONE
SKIPE P4,CHNCUA(T1) ;GET BUSY UNIT ON CHAN
MOVE P4,UNISTS(P4) ;GET THE UNITS STATE
SUBI P4,TCOD ;P4=0 IF UNIT CAN BE IN TW
HLRE P3,KDBIUN(J) ;START AT LAST UNIT ON CHAN
SETCA P3,P3
DSKSE3: SKIPE U,@KONPTR(J) ;GET UDB
SKIPN T1,UNISTS(U) ;GET STATE OF UNIT
JRST DSKSE9 ;DOESN'T EXIST OR IDLE
SKIPN P4 ;IF SOME UNIT IS BUSY ON CHAN
CAIE T1,TCOD ; THEN T IS OK (HANDLED EARLIER)
CAIN T1,PWCOD ;PW IS OK
JRST DSKSE0 ;SO IGNORE THESE
CAIN T1,TCOD ;ILLEGALLY IN T?
SETZ T1, ;YES, FIDDLE AROUND
CAIE T1,TWCOD ;(HERE FOR NOT I, PW, OR T)
JUMPN T1,DSKSE5 ;NOT TW OR T
JUMPE P4,DSKSE9 ;TW, IS THIS STATE LEGAL?
;HERE IF TW ILLEGALLY OR T ILLEGALLY
IFN FTDUAL,<
SKIPN T2,UNI2ND(U) ;IS THERE AN ALTERNATE PATH?
JRST DSKS3A ;NO. THIS UNIT SHOULDN'T BE IN TW
MOVE T2,UDBKDB(T2) ;YES. IS OTHER CHAN BUSY?
MOVE T2,KDBCHN(T2)
SKIPL (T2) ; IF SO, ALTERNATE PATH MIGHT REALLY BE TW
JRST DSKSE9 ;SO DON'T CHANCE ZAPPING THIS UNIT
DSKS3A:>
MOVE P1,UDBKDB(U) ;GET CHANNEL DATA BLOCK
MOVE P1,KDBCHN(P1)
JUMPN T1,DSKSE4 ;ILLEGAL T?
HRRZ F,UNICDA(U) ;YES, GET DDB
JUMPE F,DSKSE6 ;IF NONE, SET IDLE
HRRM U,CHNCUA(P1) ;POINT CHAN TO UNIT
SETZB P4,(P1) ;INSURE CHAN IS BUSY
HRRM U,KONCUA(J) ;POINT KON TO UNIT
MOVSI T1,KOPBSY ;INSURE KON IS BUSY
IORM T1,KONBSY(J)
MOVE T1,UNISTS(U) ;GET STATUS BACK
JRST DSKSE8
;HERE IF TW ILLEGALLY
DSKSE4: SKIPN CHNQUE(P1) ;ANYTHING TO DO?
JRST DSKSE6 ;NO, SET UNIT IDLE
SETZB P4,(P1) ;INSURE CHAN IS BUSY
PUSHJ P,PIKTRX ;START UP SOMETHING
JRST DSKSEZ ;AND TEST NEXT
DSKSE5: SOSE UNITIM(U) ;NOT I,PW,T,TW. COUNT TIMER
JRST DSKSE9 ;NOT YET HUNG
HRRZS T1 ;SIGN BIT ON IF POSITION-HUNG RECOVERY
CAIN T1,PCOD ;HUNG. POSITION?
JRST DSKSE8 ;YES, CALL HNGSEC
JRST DSKSE9
DSKSE6: PUSHJ P,IDLEPW ;SET IDLE OR PW
JRST DSKSE9 ;AND TEST NEXT UNIT
DSKSE8: PUSHJ P,DSKS11 ;HUNG, TRY TO FIX IT UP
JRST DSKSEZ
DSKSE0: PUSHJ P,CRNPOS ;START PWQ IF KON IDLE
MOVE J,UDBKDB(U) ;GET KON BACK
DSKSEZ: DSKOFF ;MIGHT HAVE COME BACK ON
DSKSE9: SOJGE P3,DSKSE3 ;GO TO NEXT UDB
DSKS10: DSKON
JRST DSKSE1 ;DONE WITH KONTROL, TRY NEXT KDB
;HERE WHEN THE UNIT IS HUNG. CALL HNGDSK FROM HERE
DSKS11:
IFN FTCIDSK,<
PUSHJ P,CIBAD ;CI SHOULDN'T GET HERE
>
HRRZ F,UNICDA(U) ;DDB UNIT IS TALKING TO
JUMPE F,CPOPJ## ;FORGET IT IF NO DDB
HRRZ J,UNIJOB(U) ;SET UP J
JUMPE J,DSKS12 ;GO IF SWAPPER
HRRZ T2,JBTUPM##(J)
JUMPE T2,DSKS14 ;AVOID IME IF JOB IS GONE
DSKS12: PUSHJ P,MKADD## ;MAKE JOB ADDRESSABLE
DPB T1,DEYCOD##
MOVE S,DEVIOS(F)
CAIN F,SWPDDB##
TRO S,IOACT
IFN FTDUAL,<
HRRZ T1,DEVCUR##(F)
CAIE F,SWPDDB##
CAIN T1,(U) ;IS IT RIGHT UNIT
>
TRNN S,IOACT ;IS DDB IO ACTIVE?
JRST DSKS13
PUSH P,U ;ERRCON ZAPS U
PUSHJ P,HNGSEC ;HAVE HNGDSK TRY TO RECOVER
PUSHJ P,DEVHNG## ;CAN'T RECOVER - ERROR FOR USER
POP P,U ;MIGHT BE RECOVERING
DSKS13: MOVEI T1,DSKTIM## ;RESET HUNG TIMER TO TRY AGAIN
MOVEM T1,UNITIM(U) ; IF RECOVERY DOESN'T WORK
DSKS14: MOVE J,UDBKDB(U)
POPJ P, ;AND EXIT
;TROUBLE IN THE POSITION WAIT QUEUE
;WAKE UP ALL THE JOBS IN THE QUEUE AND FORCE THEM
;TO EXECUTE UNICHK AT UUO LEVEL
TBLPWQ: PUSHJ P,SAVE2## ;SAVE P2
TBLPW1: DSKOFF ;MAKE SURE NO INTS
MOVEI P2,UNIQUE-DEVQUE##(U);#PRESET PRED
MOVS F,DEVQUE##(P2) ;#GET 1ST DDB
JUMPE F,CPOPJ## ;#NONE
PUSHJ P,UNQUER ;#UNLINK IT
POPJ P, ;#SYSTEM ERROR?
SOS UNIQUL(U) ;#COUNT IT
DSKON
MOVSI S,IOSTBL ;LIGHT TROUBLE BIT
IORB S,DEVIOS(F)
PUSHJ P,STDIOD## ;WAKE HIM UP
PUSHJ P,CLRACT##
JRST TBLPW1 ;MORE
;ROUTINE TO CHECK THE POSITION WAIT QUEUE
DSPWQ: HLRE P3,KDBIUN(J) ;START AT LAST UNIT ON CHAN
SETCA P3,P3
DSKOFF
DSPWQ3: SKIPN U,@KONPTR(J) ;#GET UDB
JRST DSPWQ9
MOVE T1,UNISTS(U) ;#GET STATE OF UNIT
CAIGE T1,OWCOD ;#SOME FLAVOR OF OPR WAIT?
JRST DSPWQ9 ;#NO
;#HERE IF OPR WAIT
SKIPL KONPOS(J) ;#DOES KONTROLLER POSITION?
JRST DSPWQ7 ;#YES
IFN FTMP,<
MOVE T1,UDBCAM(U) ;#ONLY COUNT TIMER ON ONE CPU
TDNN T1,.CPBIT## ;#KONS THAT DON'T POSITION ALWAYS
JRST DSPWQ9 ;#HAVE ONE KONCAM BIT ON
>
SOSN UNITIM(U) ;#TIMER RUN OUT?
PUSHJ P,IDLEPW ;#YES, SET BOTH PORTS IDLE
JRST DSPWQ9 ;# AS THERE WON'T EVER BE A FREE INTERRUPT
DSPWQ7: SKIPE UNIQUE(U) ;#ANYBODY WAITING?
PUSHJ P,TBLPWQ ;#SEND EVERYBODY TO UNICHK
DSPWQ9: SOJGE P3,DSPWQ3 ;#NEXT UNIT
JRST DOPOPJ
HNGSEC:
IFE FTKS10,<
PUSHJ P,FNDPDB## ;SET UP W
JRST HNGDS1 ;MUST BE SWAPPER
CAMN F,.PDDIA##(W) ;IN DIAG?
JRST DIACTC ;YES, RESTART THE IO ON THE CHANNEL
HNGDS1:
>
MOVE J,UDBKDB(U) ;KONTROLLER DB
;HERE IF UNIT MAY BE IN TRANSFER OR POSITION STATE
PUSHJ P,SAVE1## ;SAVE P1
AOS T1,UNIRCV(U) ;COUNT NUMBER OF ATTEMPTS AT RECOVERY
CAIG T1,10 ;TRIED ENOUGH?
JRST HNGD12 ;NO, TRY AGAIN
SKIPL DEVSWP##(F) ;YES, SWAPPER?
JRST HNGD99 ;TOO MANY TIMES AND NOT SWAPPER, GIVE UP
IDIVI T1,^D60/DSKTIM ;TIME TO COMPLAIN AGAIN?
CAIN T2,1
PUSHJ P,TELOPR ;YES, HELP!
JRST HNGD12 ;SWAPPER NEVER GIVES UP, TRY AGAIN
HNGD99: PUSHJ P,@KONSTP(J) ;STOP THE KONTROLLER
JFCL
HNGD11: MOVSI S,IOSMON
ANDCAB S,DEVIOS(F) ;MAKE SURE IOSMON=0
TLO T1,UNPFIR+UNPHNG ;TELL DAEMON HUNG DISK
MOVEM T1,UNIECT(U)
PUSHJ P,FLPJOB ;FLIP UNIJOB AND UNICDA
SKIPE DEVRHB##(F) ;IF NOT REREADING HOME BLOCKS,
SOS (P) ; LET USER GET HUNG DEVICE MESSAGE
;REREADING HOME BLOCKS.
MOVE P1,KDBCHN(J) ;YES, SET UP P1
MOVEI T1,KOPOFL ;TELL BADUN1 TO GRUMBLE AT OPR
PUSH P,U
PUSHJ P,BADUN1 ;GIVE UP, SHOUT AT OPR OVER THIS UNIT
POP P,U
PJRST CPOPJ1## ;DONT GIVE ERROR MESSAGE IF REREADING HOME BLOCKS
HNGD12: MOVSI T1,UNPHNG ;TELL DAEMON IT IS HUNG
IORM T1,UNIECT(U)
SKIPL UNIECT(U) ;IN ERROR RECOVERY?
JRST HNGD13 ;YES, LEAVE REGS ALONE
MOVEM T1,UNIECT(U) ;NO, SET SO DAEMON WILL BE CALLED ON RECOVERY
SETZM UNIERR(U)
PUSHJ P,@KONRRG(J) ;GO READ ALL DRIVE REGISTERS NOW
PUSHJ P,FSTREG ;COPY REGISTERS TO UDB
HNGD13: AOS UNIECT(U)
MOVE T1,UNISTS(U) ;RESET T1=UNIT STATUS
CAIE T1,TCOD ;IS UNIT IN TRANSFER STATE?
JRST HNGD14 ;NO
MOVSI P1,UNPHRC ;ASSUME WE'LL RECOVER
PUSHJ P,@KONSTP(J) ;STOP UNIT AND CAUSE AN INTERRUPT
MOVSI P1,UNPHNR ;COUNT NOT-RECOVERED INSTEAD
MOVEM T2,UNISOF(U) ;STORE (BEFORE) CONI STATUS
MOVEM T3,UNISDI(U) ;STORE (BEFORE) DATAI STATUS
MOVE T1,UDBKDB(U) ;SET FLAG SO WE REMEMBER
MOVE T1,KDBCHN(T1)
SETOM CHNECT(T1) ; TO DO A RECAL
ADDM P1,UNIHNG(U)
PUSHJ P,SETHNG## ;RESTORE HUNG-TIME
PJRST CPOPJ1## ;SKIP RETURN - NO ERROR MESSAGE
;STILL IN FTDHNG CONDITIONAL
HNGD14: HRRZ T2,T1 ;IGNORE SIGN BIT
CAIE T2,PCOD ;POSITIONING?
PJRST CPOPJ1## ;NO, RETURN WITH NO ERROR MESSAGE
;(UNIT PROBABLY HUNG, THIS JOB IN QUEUE)
HRRZM T1,UNISTS(U) ;RESET SIGN BIT IF ON
SKIPL DEVSWP##(F) ;SWAPPER NEVER GIVES UP
JUMPL T1,HNGD11 ;GIVE UP IF DIDN'T RECOVER
MOVEI T2,UNPHPS ;YES, INCREMENT HUNG POSITION COUNT
ADDM T2,UNIHNG(U)
DSKOFF
MOVE T2,KONPOS(J)
SKIPGE KONBSY(J) ;#KONTROLLER BUSY?
TLNE T2,KOPPWX ;#YES, CAN WE RECAL ANYWAY?
CAIA ;#IDLE OR DOESN'T MATTER
JRST HNGD15 ;#CAN'T RECAL NOW, DO IT LATER
MOVSI T1,400000 ;#INDICATE PHUNG RECOVERY
IORM T1,UNISTS(U)
PUSHJ P,SETHNG##
PUSHJ P,@KONRCL(J) ;#TRY A RECAL
PUSHJ P,PUTOW ;#PUT IN OW
DOPJ1: DSKON ;#
PJRST CPOPJ1## ;AND RETURN WITH NO ERR MESSAGE
;HERE IF WE CAN'T RECAL BECAUSE KONTROLLER IS BUSY
HNGD15: SKIPGE DEVSWP##(F) ;#SWAPPER?
JRST DOPJ1 ;#YES, KEEP TRYING TILL KON IDLE
PUSHJ P,FLPJOB ;#FLIP UNIJOB AND UNICDA
PUSHJ P,UUOPW5 ;#LINK TO PWQ
PJRST CPOPJ1## ;AND RETURN W/ NO MSG
;ROUTINE TO PUT UNIT INTO OPERATOR WAIT
PUTOW: SKIPGE DEVSWP##(F) ;#SWAPPER?
POPJ P, ;#DON'T PUT SWAPPER IN OPR WAIT
MOVEI T1,OCOD
MOVEM T1,UNISTS(U)
PUSHJ P,FLPJOB ;#FLIP UNIJOB AND UNICDA
PJRST UUOPW2 ;#LINK TO PWQ
;ROUTINE TO FLIP UNIJOB AND UNICDA
;PRESERVES ALL BUT T2
FLPJOB: HRLZS UNIJOB(U)
IFN FTDUAL,<
SKIPE T2,UNI2ND(U)
HRLZS UNIJOB(T2)
>
;FLIP ONLY UNICDA
FLPCDA: HRLZS UNICDA(U)
IFN FTDUAL,<
SKIPE T2,UNI2ND(U)
HRLZS UNICDA(T2)
>
POPJ P,
SUBTTL JOB HANGING LOGIC
;SUBROUTINE TO REMOVE FROM UNIT QUEUES ALL DDBS BELONGING TO C(J)
ZAPDSK::PUSHJ P,SAVE2## ;SAVE SOME AC'S
PUSHJ P,SVEUB## ;SAVE EUBR
DSKOFF ;PREVENT RACES
PUSH P,U ;#SAVE U
PUSH P,F ;#SAVE F
PUSH P,J ;#SAVE JOB NUMBER
HLRZ U,SYSUNI## ;#GET FIRST UNIT IN SYSTEM
ZPDSK1: MOVEI P2,UNIQUE-DEVQUE##(U) ;#SET PREDECESSOR
ZPDSK2: MOVS F,DEVQUE##(P2) ;#GET NEXT DDB IN QUEUE
JUMPE F,ZPDSK4 ;#JUMP IF NONE
HLRZ J,F ;#OWNED BY THIS JOB?
CAME J,(P) ;#...
JRST ZPDSK3 ;#NO
PUSHJ P,UNQUER ;#REMOVE FROM UNIT QUEUE
JRST ZPDSK1 ;#PREDECESSOR CHANGED?
SOSA UNIQUL(U) ;#DECREMENT LENGTH OF PW QUEUE
ZPDSK3: MOVE P2,F ;#MAKE PREDECESSOR THIS
HLRZ J,P2 ;#JOB NUMBER OF PREDECESSOR
PUSHJ P,MKADD## ;#MAKE IT ADDRESSABLE
JRST ZPDSK2 ;#CONTINUE
ZPDSK4: HLRZ U,UNISYS(U) ;#STEP TO NEXT UNIT
JUMPN U,ZPDSK1 ;#LOOP FOR ALL DISKS
HLRZ P1,SYSCHN## ;#ADDRESS OF FIRST CHN
ZPDSK5: MOVEI P2,CHNQUE-DEVQUE##(P1) ;#SET PREDECESOR
ZPDSK6: MOVS F,DEVQUE##(P2) ;#STEP TO NEXT ENTRY IN QUEUE
JUMPE F,ZPDSK8 ;#GO IF QUEUE IS EMPTY
HLRZ J,F ;#GET JOB NUMBER
CAME J,(P) ;#BELONGS TO THIS JOB?
JRST ZPDSK7 ;#NO
PUSHJ P,UNQUER ;#YES, REMOVE FROM QUEUE
JRST ZPDSK5 ;#PREDECESSOR CHANGED, TRY AGAIN
SOSA CHNQUL(P1) ;#REDUCE QUEUE LENGTH BY 1
ZPDSK7: MOVE P2,F ;#SET NEW PREDECESSOR
HLRZ J,P2 ;#THIS JOB NUMBER
PUSHJ P,MKADD## ;#MAKE IT ADDRESSABLE
JRST ZPDSK6 ;#CONTINUE
ZPDSK8: HLRZ P1,CHNSYS(P1) ;#STEP TO NEXT CHN
JUMPN P1,ZPDSK5 ;#GO IF THERE IS ONE
DSKON ;#ALLOW DISK INTERRUPTS
;NOW HANDLE CPUQUE
IFN FTMP,<
DSKOFF ;PREVENT RACES
ZPDSK9: MOVEI P2,CPUDSQ##-DEVQUE## ;#SET PREDECESSOR
ZPDS10: MOVS F,DEVQUE##(P2) ;#GET NEXT IN QUEUE
JUMPE F,ZPDS12 ;#ALL DONE IF NO NEXT
HLRZ J,F ;#GET JOB NUMBER
CAME J,(P) ;#BELONG TO JOB WE ARE WORRYING ABOUT?
JRST ZPDS11 ;#NO, LOOK AT NEXT
PUSHJ P,UNQUER ;#REMOVE DDB FROM QUEUE
JRST ZPDSK9 ;#PREDECESSOR CHANGED
SKIPA ;#CONTINUE, PREDECESSOR WAS UPDATED
;HERE TO MOVE TO NEXT ITEM IN QUEUE
ZPDS11: MOVE P2,F ;#SET NEW PREDECESSOR
HLRZ J,P2 ;#THIS JOB NUMBER
PUSHJ P,MKADD## ;#MAKE IT ADDRESSABLE
JRST ZPDS10 ;#CONTINUE
ZPDS12: DSKON ;#ALLOW DISK INTERRUPTS
>; END IFN FTMP
POP P,J ;RESTORE J
PJRST FUPOPJ## ;RESTORE F AND U AND RETURN
;ROUTINE TO RETURN ANY RESOURCES A DDB HAS
;ENTER WITH JOB NUMBER IN J; EXITS WITH IOACT OFF IN DDB
RETRES::MOVE U,DEVUNI##(F)
RETRSX: TLNE S,IOSDA ;HAVE DA?
PUSHJ P,DWNDA
TRNE S,IOSFA ;HAVE FA?
PUSHJ P,DWNFA ;YES, RETURN IT
TLNE S,IOSAU ;HAVE AU?
PUSHJ P,DWNAU
JUMPE J,CLRACT##
CAME J,CBUSER## ;HAVE CB?
PJRST CLRACT## ;RESET IOACT + POPJ
SKIPN DINITF## ;DON'T DURING ONCE-ONLY
PUSHJ P,CBFREE## ;FREE CB (ALREADY CHECKED IF WE OWNED IT)
;(PREVENTS DOC IF CALLED FROM HNGSTP/GIVRSC)
PJRST CLRACT## ;RESET IOACT + POPJ
;SUBROUTINE TO CALL WAIT1
;THIS IS NEEDED SINCE WAIT1 CLOBBERS P1-P4
;THIS INSTRUCTION IS USED TO RESTORE PWAIT1 AFTER RESTART (SEE WTSATS)
PWAITZ::PJRST WAIT1##
PWAIT1:: PJRST WAIT1## ;GO TO WAIT1
IFN FTMP,<
;SUBROUTINE TO SET UP DDB LOCS FOR MULTI CPUS
;ENTER WITH U SET UP
;RETURNS T1=FIRST CPU UNIT IS ON
CPUDDB: MOVE J,UDBKDB(U) ;SET UP J
MOVEI T1,CPFBIT## ;USE THE BIT MASK
DPB T1,DEYCPF##
POPJ P,
REPEAT 0,< ;THE OLD WAY
CPUDDB::MOVE J,UDBKDB(U) ;SET UP J
LDB T1,KOYCPU## ;GET CPU WHICH OWNS UNIT/KONTROL
DPB T1,DEYCPF## ;TELL REST OF THE WORLD
IFN FTDUAL,<
MOVSI T2,DEPCPS
ANDCAM T2,DEVCPU(F) ;ASSUME NOT DUAL-PORTED TO 2 CPUS
SKIPL T3,UNI2ND(U)
POPJ P,
MOVE T3,UDBKDB(T3) ;KONTROLER FOR 2ND PORT
LDB T3,KOZCPU## ;CPU FOR 2ND PORT
CAIN T3,(T1) ;MATCH?
POPJ P, ;YES, IT ISNT ON 2 CPUS
IORM T2,DEVCPU(F) ;NO, TELL WORLD DDB IS ON 2 CPUS
DPB T3,DEYCPS## ;CPU NUMBER FOR 2ND PORT
>;END IFN FTDUAL
POPJ P,
> ;END OF REPEAT 0
;STILL IN FTMP CONDITIONAL
;HERE FOR DSKOFF MACRO
DSKLOK::CONO PI,DSKPIF## ;TURN OFF DSK PI
DSKLO1: AOSE INTRDS## ;TRY TO GET INTERLOCK
JRST DSKLO2
SETZM .CPDLK## ;GOT IT, INDICATE SO
IFN FTMP,<
APRID INTODS##
>
POPJ P,
DSKLO2: SKIPN .CPDLK## ;DIDN'T GET IT. DO WE ALREADY OWN IT?
POPJ P, ;YES
SKIPL INTRDS## ;DON'T TRY IF NOT POSSIBLE TO GET IT
JRST .-1 ; SINCE IT SUCKS UP RMW MEMORY CYCLES
JRST DSKLO1 ;NO, WAIT A WHILE
;HERE ON DSKON MACRO
DSKULK::SKIPE .CPDLK## ;DO WE OWN IT?
POPJ P, ;NO, GO AWAY
SETOM .CPDLK## ;YES, NOW WE DON'T
SETOM INTRDS##
IFN FTMP,<
SETOM INTODS##
>
CONO PI,DSKPIN##
POPJ P,
;STILL IN FTMP CONDITIONAL
;HERE FOR AN IO REQUEST ON ANOTHER CPU
;HERE WITH T1=CPU BIT MASK
PCLDSK: PUSHJ P,CPUOK## ;IS ONE OF THESE RUNNING?
JRST PCLOFL ;NO, CALL HNGSTP
MOVS T2,F ;PUT THIS DDB AT FRONT OF QUEUE
HRR T2,.CPJOB## ; FOR ONCE-A-SECOND STUFF
SKIPN T1,.CPQUE## ;IF THIS 1ST ENTRY IN QUEUE,
MOVEM T2,.CPQND## ; ALSO MARK DDB AS LAST IN QUEUE
MOVEM T2,.CPQUE##
MOVEM T1,DEVQUE##(F) ;LINK FORMER FIRST TO THIS DDB
MOVE T1,.CPQPC## ;GET THIS CPUS QP BIT
IORM T1,DOORBL## ;SERVICE FASTER IF ONLY THE NUL JOB LEFT
MOVEI T1,PCLDKY## ;SET TO NON-EXISTANT CPU
DPB T1,DEYPCL## ;UNTIL WE KNOW WHICH CPU
;WILL DO THE REQUEST
PJRST SETACT## ;SET IOACT AND RETURN
;HERE IF CPU IS DEAD
PCLOFL: JUMPN T1,PCLOF1 ;JUMP IF CPU/KDB/UDB PATH IS OK
SKIPE T1,UNIALT(U) ;IS THERE AN ALTERNATE PORT?
SKIPN T1,UNIKON(U) ;AND A KON FOR THAT PORT?
JRST PCLOF1 ;NO--GIVE UP
SKIPN T1,KDBCAM(T1) ;GET ACCESSIBILITY BITS FOR THAT KON
JRST PCLOF1 ;THERE ARE NONE
MOVE U,UNIALT(U) ;SWITCH I/O TO ALTERNATE PORT
HRRM U,DEVUNI##(F) ; AND START TO USE IT INSTEAD
MOVE J,UNIKON(U) ; AND USE ALT KON TOO
PJRST UUOPWQ ;TRY TO START I/O WITH NEW UNIT
PCLOF1: SKIPGE DEVSWP##(F) ;SWAPPER?
JRST PCLOF2 ;YES, CAN'T CALL HNGSTP
PUSHJ P,SAVSTS ;NO, SAVE WHAT RESOURCES JOB OWNS
PUSHJ P,HNGSTP## ;TELL THE USER
POP P,T3 ;HE TYPED CONTINUE
PUSHJ P,RESSTS ;GET BACK RESOURCES HE HAD
PUSHJ P,CHKCPI## ;GET BIT MASK BACK
JFCL
JRST PCLDSK ;AND TRY THE OPERATION AGAIN
PCLOF2: TRO S,IODERR ;SWAPPER - INDICATE WE LOST
POPJ P,
;STILL IN FTMP CONDITIONAL
;HERE ONCE A TICK
DSKTIC::SKIPE .CPSWP## ;HAVE SWAP REQUESTS?
PUSHJ P,SWPIO2 ;YES, TRY TO START THE SWAPPER
SKIPN T1,CPUDSQ## ;NO, ANYTHING TO DO?
SKIPE .CPQUE##
CAIA
POPJ P, ;NO
IFN FTKL10,<
SETOM .CPSWD##
>
PUSHJ P,SSEUB## ;YES, PRESERVE UBR
PUSHJ P,SAVE3##
MOVE T2,.CPQPC## ;CLEAR DOORBELL WORD
ANDCAM T2,DOORBL## ; SINCE WE'VE ANSWERED IT
JUMPE T1,DSKTI6 ;#GO IF ALL CPU QUEUE EMPTY
DSKTI1: DSKOFF ;#PREVENT RACES
MOVEI P2,CPUDSQ##-DEVQUE## ;#PRESET PREDECESSOR
DSKTI2: MOVS F,DEVQUE##(P2) ;#STEP TO NEXT IN QUEUE
JUMPE F,DSKTI6 ;#GO IF DONE
HLRZ J,F ;#JOB FOR THE NEXT DDB
PUSHJ P,MKADD## ;#MAKE IT ADDRESSABLE
PUSHJ P,SETU ;#SET UP U FROM DDB
SETZ U, ;#UNIT WAS REMOVED
JUMPE U,DSKTI3 ;#GO IF UNIT WAS REMOVED
PUSHJ P,CHKCPI## ;#DEVICE ON THIS CPU?
JRST DSKTI5 ;#NO
IFN FTDUAL,<
;WE COULD INSERT CODE HERE TO SEE IF THIS CPU HAS ANY CREDITS
;OUTSTANDING, BUT IT PROBABLY WOULDN'T BE WORTH IT.
SKIPE UNI2ND(U) ;#GO IF SINGLE PORTED
CAMN T1,.CPBIT## ;#GO IF WE'RE THE ONLY CPU
JRST DSKTI3 ;#DO IT ON THIS CPU
MOVE J,UDBKDB(U) ;#POINT U AT THIS CPU'S PORT
MOVE T1,UDBCAM(U)
TDNN T1,.CPBIT##
HRRZ U,UNI2ND(U)
MOVE J,UDBKDB(U) ;#POINT J AT THIS CPU'S KDB
SKIPN UNIQUE(U) ;#IF THIS PORT ALREADY HAS A QUEUE,
;# THEN MAKE THE QUEUE LONGER.
;# THIS WILL MAKE THE LATENCY OPTIMIZER
;# WORK BETTER (MORE TO CHOOSE FROM).
SKIPL KONBSY(J) ;#KON BUSY?
JRST DSKTI3 ;#IDLE, DO IT HERE
HRRZ T4,UNI2ND(U) ;#OTHER CPU'S PORT
MOVE T3,UDBKDB(T4) ;#OTHER CPU'S KDB
MOVE T1,UDBCAM(T4) ;#MASK OF OTHER CPU'S
SKIPN UNIQUE(T4) ;#MAKE OTHER QUEUE LONGER
SKIPL KONBSY(T3) ;#OTHER KON BUSY?
PUSHJ P,CPUOK## ;#OTHER CPU OK?
JRST DSKTI3 ;#BOTH BUSY OR OTHER CPU DEAD
JRST DSKTI5 ;#OTHER CPU ALIVE AND IDLE
;# LEAVE IT FOR THE OTHER CPU
>
DSKTI3: PUSHJ P,UNQUER ;#UNLINK DDB FROM QUEUE
JRST DSKTI1 ;#RACE, TRY AGAIN
MOVE S,DEVIOS(F) ;#SET S
JUMPE U,DSKTI7
PUSHJ P,UUOPWR ;#GO START OR QUEUE THE IO REQUEST
JRST DSKTI1 ;#AND LOOK FOR SOMETHING ELSE TO DO
DSKTI5: MOVE P2,F ;#RESET PREDECESSOR
JRST DSKTI2 ;#AND LOOK AT NEXT IN QUEUE
;HERE WHEN ALL REQUESTS ARE PROCESSED
DSKTI6: DSKON ;LET THE CHANNEL BREATH AGAIN
IFN FTKL10,<
SKIPN .CPSWD## ;IF WE SWEPT
MOVMS .CPTAP## ; TELL TAPSER IT DOESNT HAVE TO
>
SKIPN .CPQUE## ;ANYTHING IN OUR CPU QUEUE?
POPJ P, ;NO
IFN FTKL10,<
SKIPE .CPSWD## ;YES, NO NEED TO SWEEP IF WE JUST DID
PUSHJ P,CSDMP## ;SWEEP CACHE
>
MOVE T2,.CPQUE## ;START OF QUEUE
MOVS T1,.CPQND## ;GET END OF CPU QUEUE
HLRZ J,T1 ;JOB NUMBER OF THE DDB
PUSHJ P,MKADD## ;MAKE THE DDB ADDRESSABLE
DSKOFF ;#PREVENT RACES
MOVE T3,CPUDSQ## ;#GET ALL-CPU QUEUE
MOVEM T3,DEVQUE##(T1) ;#INSERT CPU-QUEUE AT FRONT OF ALL-QUEUE
MOVEM T2,CPUDSQ## ;#INSERT ALL-QUEUE AT END OF CPU-QUEUE
DSKON
MOVE T3,.CPQPS## ;GET QUEUED PROTOCOL BITS FOR OTHERS
IORM T3,DOORBL## ;RING EVERYBODY ELSE'S DOORBELL
SETZM .CPQUE## ;OUR QUEUE IS NOW EMPTY
POPJ P, ;ALL DONE
;HERE IF UNIT WAS REMOVED
DSKTI7: PUSHJ P,STDIOD## ;WAKE JOB UP
JRST DSKTI1 ;AND TRY NEXT IN QUEUE
;STILL IN FTMP CONDITIONAL
;HERE AFTER ALL QUEUED PROTOCOL IS HANDLED
;LOOK FOR DISKS ON A DEAS CPU WHICH ARE DUAL-PORTED TO OUR CPU
;IF FOUND, SWITCH THE UDB TO THIS CPU
DSKRQT: MOVE T3,.CPSCC## ;BIT TO TEST
MOVEI T2,.C0CDB## ;WHERE TO START
DSKRQ1: TDNE T3,.CPDRQ##-.CPCDB##(T2) ;CPU DEAD?
JRST DSKRQ2 ;YES, REQUE REQUESTS FOR DISKS ON THAT CPU
HLRZ T2,(T2) ;NO, STEP TO NEXT CDB
JUMPN T2,DSKRQ1 ;TEST THIS ONE
POPJ P, ;ALL DONE - EXIT
;HERE (ONCE) WHEN A CPU DIES
DSKRQ2: ANDCAM T3,.CPDRQ##-.CPCDB##(T2) ;SO WE WON'T GET HERE AGAIN
MOVE P1,T2 ;SAVE CDB LOC
PUSHJ P,RCDRB ;RESCUE DRBS WHICH ARE IN PROGRESS
MOVE J,KDBTAB##+.TYDSK ;1ST KDB IN SYSTEM
DSKRQ4: MOVE T1,KDBCAM(J) ;CPU(S) WHICH OWN THIS KDB
IFN FTCIDSK,<
SKIPGE KONMX(J) ;CAN THIS CPU ACCESS THE KDB?
TDNE T1,.CPBIT##
>
TDNN T1,.CPBIT##-.CPCDB##(P1) ;IS KDB ON THE DEAD CPU?
JRST DSKR11 ;NO, TRY NEXT
HLRE P3,KDBIUN(J) ;START AT LAST UNIT ON CHAN
SETCA P3,P3
DSKRQ5: SKIPN U,@KONPTR(J) ;UNIT THERE?
JRST DSKR10 ;NO
IFN FTCIDSK,<
SKIPGE KONMX(J) ;MULTIPLE XFERS?
PUSHJ P,DSKRCI ;SPECIAL STUFF FOR CI
>
IFN FTDUAL,<
SKIPN T1,UNISTS(U) ;YES, IDLE?
JRST DSKR10 ;YES, NOTHING SPECIAL TO DO
CAIGE T1,MDACOD ;NO, IN A WAIT STATE?
SKIPN T2,UNI2ND(U) ;YES, DUAL-PORTED?
JRST DSKR10 ;NO, CAN'T RESCUE IT
MOVE T3,UDBCAM(T2) ;IS 2ND PORT ON THIS CPU?
TDNN T3,.CPBIT##
JRST DSKR10 ;NO, CAN'T HELP
MOVE P2,KDBCHN(J) ;YES. POINT AT CDB (FOR DSKRQ6)
CAIE T1,PCOD ;IS THE UNIT IN T OR P?
CAIN T1,TCOD
CAIA ;YES. GO "RESCUE" THE CURRENT IO
JRST DSKRQ6 ;NO, JUST OPERATE ON THE QUEUES
HRRZ J,UNIJOB(U)
SKIPE J ;MAKE THE JOB ADDRESSABLE
PUSHJ P,MKADD##
HRRZ F,UNICDA(U) ;DDB ADDR
MOVE T1,DEVCUR##(F) ;WAS IT STARTED ON THE DEAD CPU?
CAIN U,(T1)
PUSHJ P,DSKRSI ;YES. RESCUE IT
;FALL INTO DSKRQ6
;HERE TO UNQUEUE REQUESTS FOR THE DISK ON THE DEAD CPU
DSKRQ6: DSKON
MOVEI F,CHNQUE-DEVQUE##(P2) ;PRESET PREDECESSOR
DSKRQ7: MOVE P2,F ;CURRENT FORMER IS PREDECESSOR
MOVS F,DEVQUE##(P2) ;STEP TO NEXT QUEUE ENTRY
JUMPE F,DSKRQ8 ;DONE IF 0
HLRZ J,F ;JOB NUMBER
PUSHJ P,MKADD## ;MAKE IT ADDRESSABLE
HRRZ T2,DEVCUR##(F) ;CURRENT UNITT
CAIE T2,(U) ;THE ONE WE'RE RESCUING?
JRST DSKRQ7 ;NO, STEP TO NEXT
DSKOFF
PUSHJ P,UNQUER ;REMOVE IT FROM QUEUE
JRST DSKRQ6 ;RACE, TRY AGAIN
MOVE T3,UDBKDB(U) ;COUNT IT
MOVE T3,KDBCHN(T3)
SOS CHNQUL(T3)
DSKON
PUSHJ P,DSKRSQ ;START IO OR QUEUE IT TO OTHER PORT
MOVE F,P2 ;POINT BACK AT PRED
JRST DSKRQ7 ;GET NEXT QUEUE ENTRY
;HERE AFTER ALL ENTRIES FOR UNIT HAVE BEEN REMOVED FROM CHAN QUEUE
DSKRQ8: MOVS F,UNIQUE(U) ;1ST DDB
JUMPE F,DSKRQ9 ;GO IF QUEUE EMPTY
MOVEI P2,UNIQUE-DEVQUE##(U) ;SET PREDECESSOR
PUSHJ P,UNQUER ;REMOVE DDB FROM POSITION QUEUE
JRST DSKRQ9 ;AVOID A KAF
SOS UNIQUL(U) ;COUNT IT
PUSHJ P,DSKRSQ ;START NEW SEEK OR QUEUE IT ON 2ND PORT
JRST DSKRQ8 ;AND TEST NEXT UNIT-QUEUE ENTRY
;HERE AFTER ALL ENTRIES HAVE BEEN REMOVED FROM UNIT QUEUE
DSKRQ9: SETZM UNISTS(U) ;CLEAN UNIT STATE
MOVE J,UDBKDB(U) ;RESET J
AOS .CPNBI##-.CPCDB##(P1) ;MAKE SURE THE CPU CAN'T BE CONTINUED
> ;END IFN FTDUAL
DSKR10: SOJGE P3,DSKRQ5 ;TEST NEXT UNIT ON KDB
DSKR11: SKIPE J,KDBNXT(J) ;STEP TO NEXT KDB
JRST DSKRQ4
POPJ P, ;DONE
IFN FTDUAL,<
;HERE TO RESCUE A DISK - START THE IO OR QUEUE IT ON THE OTHER PORT
DSKRSI: MOVE S,DEVIOS(F)
MOVE T2,UNISTS(U) ;SAVE UNISTS
SKIPE T1,UNI2ND(U) ;2ND PORT
SETZM UNISTS(T1) ;MAKE UNIT IDLE SINCE IO WONT COMPLETE ON
SETZM UNISTS(U) ; UDB ON THE DEAD CPU
MOVE J,UDBKDB(U) ;DUMP MODE XFER. HAVE TO RESET DEVDMP
CAIN T2,TCOD ;WAS A TRANSFER IN PROGRESS?
PUSHJ P,UNLST ;UNDO SETLST
DSKRSQ: MOVE S,DEVIOS(F) ;SET UP S
TRNN S,IOACT ;PARANOIA
POPJ P,
LDB J,PJOBN## ;WRITING. SEE IF OK
IFN FTKL10,<
PUSHJ P,RWRTCH## ;JOB RUNNABLE WITH RESPECT TO CACHE?
>
SKIPA U,UNI2ND(U) ;YES. DO THE IO
JRST DSKRS2 ;NO, GIVE AN ERROR RETURN
MOVE J,UDBKDB(U) ;SET UP NEEDED ACS
PUSHJ P,UUOPWR ;DO IT OR QUEUE IT
MOVE U,UNI2ND(U) ;RESET ACS TO FAILED UNIT
MOVE J,UDBKDB(U)
POPJ P, ;AND RETURN
DSKRS2: TRO S,IOIMPM ;TOO BAD
DSKRS3: PUSHJ P,STDIOD## ;TEST IOW, RESTART JOB
PJRST CLRACT## ;CLEAR IOACT AND RETURN
> ;END IFN FTDUAL
IFN FTCIDSK,<
;HERE TO RESCUE THE POSITION WAIT QUEUE FOR A CI DISK
DSKRCI: PUSHJ P,SAVJW## ;SAVE J
DSKRC4: MOVEI F,UNIQUE-DEVQUE##(U);PRESET PRED
DSKRC2: DSKON ;INTERRUPTS OK
MOVE P2,F ;SAVE PRED
MOVS F,DEVQUE##(P2) ;STEP TO NEXT DDB
JUMPE F,CPOPJ ;NONE
HLRZ J,F ;MAKE DDB ADDRESSABLE
PUSHJ P,MKADD
DSKOFF ;NO INTERRUPTS
LDB T1,DEYPCL## ;#INTENDED FOR DEAD CPU?
CAIN T1,PCLCP0##
SETZ T1,
CAME T1,.CPCPN##-.CPCDB##(P1)
JRST DSKRC2 ;#NO, TRY NEXT DDB
PUSHJ P,RWRTCH## ;#STUFF IN DEAD CPU'S CACHE?
JRST DSKRC3 ;#NO, WE CAN DO IT HERE
PUSHJ P,UNQUER ;#UNLINK THE DDB
JRST DSKRC4 ;#RACE, START OVER
SOS UNIQUL(U) ;#COUNT IT
PUSHJ P,RCERR ;#GIVE HIM AN ERROR RETURN
JRST DSKRC4 ;NEXT DDB
;HERE IF THE I/O CAN BE DONE ON THIS CPU
DSKRC3: SKIPN T1,.CPCPN## ;#SWITCH CPU NUMBER
MOVEI T1,PCLCP0##
DPB T1,DEYPCL##
JRST DSKRC2 ;#WAIT FOR DSKSEC TO START IT
;ROUTINE TO HIM THE USER AN ERROR RETURN
RCERR: DSKON ;#INTERRUPTS OK AGAIN
MOVE S,DEVIOS(F) ;GIVE THE GUY AN ERROR RETURN
TRO S,IOIMPM
PUSHJ P,STDIOD ;WAKE HIM UP
PJRST CLRACT
;ROUTINE TO RESCUE DRBS WHICH ARE IN PROGRESS
;P1 PASSES THE CDB FOR THE CPU WHICH HAS FAILED
RCDRB: MOVEI P3,ACTDRB##-DRBLNK##;PRESET PRED
DSKOFF
RCDRB1: HRRZ P3,DRBLNK##(P3) ;#STEP TO NEXT DRB
CAIN P3,ACTDRB##
JRST DOPOPJ ;#NONE LEFT
MOVE T2,DRBSTS##(P3) ;#NOT FILLED IN?
TRNE T2,DRPNFI##
JRST RCDRB1
LDB T2,DRZCPU## ;#I/O ON FAILED CPU?
CAME T2,.CPCPN##-.CPCDB##(P1)
JRST RCDRB1 ;#NO
HLRZ U,DRBCUR##(P3) ;#UNIT
MOVE J,UDBKDB(U) ;#KON
MOVE T2,UDBCAM(U) ;#IS THIS CPU ALSO PORTED TO THE DISK?
TDNN T2,.CPBIT##
JRST RCDRB1 ;#NO
HRRZ F,DRBCDA##(P3) ;#DDB
LDB J,DRZJOB## ;#JOB NUMBER
JUMPE J,RCDRB2 ;#SWAPPER, RESWP WILL WAIT FOR CACHE TO BE RIGHT
PUSHJ P,MKADD## ;#MAKE DDB ADDRESSABLE
PUSHJ P,RWRTCH## ;#STUFF IN DEAD CPU'S CACHE?
JRST RCDRB2 ;#NO, DO I/O ON THIS CPU
MOVE J,UDBKDB(U) ;#YES, GET KON BACK
PUSHJ P,RTNDRB ;#RETURN THE DRB
PUSHJ P,RCERR ;#GIVE HIM AN ERROR
JRST RCDRB ;START OVER
;HERE IF THIS CPU CAN DO THE I/O INSTEAD
RCDRB2: MOVE T1,.CPCPN## ;#STORE NEW CPU NUMBER
DPB T1,DRZCPU##
SKIPN T1
MOVEI T1,PCLCP0##
DPB T1,DEYPCL##
PUSHJ P,RTNTRY ;#LIGHT "TRY AGAIN"
JRST RCDRB1 ;#DO NEXT DRB
> ;END IFN FTCIDSK
> ;END IFN FTMP
IFN FTMP,<
SWPIO2: DSKOFF
SKIPN SQREQ## ;THERE IS A RACE
JRST [SETZM .CPSWP## ; WHICH ALLOWS THIS TO HAPPEN
JRST DOPOPJ]
MOVEI F,SWPDDB##
PUSHJ P,SSEUB##
>
;HERE TO PUT A SWAPPING REQUEST IN THE QUEUE
SWAPIO::SKIPE SQREQ## ;ANY REQUESTS?
SKIPL DEVSWP##(F) ;YES, IS THIS THE SWAPPER?
STOPCD .+1,DEBUG,SFU, ;++SWAPPER FOULED UP
MOVE S,[IOSMON,,IOACT] ;OK, INDICATE ACTIVE MONITOR IO
MOVEM S,DEVIOS(F)
MOVEI J,0 ;INDICATE ON UUO LEVEL
PJRST SWPSCN## ;GO CRANK THINGS UP
SUBTTL UUO LEVEL MODULE
;SUBROUTINE TO ENSURE THAT A CALLI IS FOR A DSK CHAN
;RETURNS CPOPJ IF NOT, CPOPJ1 IF SO
VALUUO::HRLM P1,.USCTA
PUSHJ P,SETUF##
JRST IOIERR## ;NO, "IO TO UNASSIGNED CHAN"
VALUUX: MOVE T1,DEVMOD(F) ;IS DEVICE A DSK?
TLNN T1,DVDSK
POPJ P, ;NO, IMMEDIATE RETURN
MOVE S,DEVIOS(F)
PJRST CPOPJ1## ;YES, SKIP RETURN
UUOPWQ::SKIPE .UONCE## ;USER MODE?
PJRST USRDIO## ;YES
PUSHJ P,UUOSET ;CHECK IF STR YANKED, SET UP ACS
POPJ P, ;EOF OR QUOTA EXHAUSTED
; AND FALL INTO UUOPWR
UUOPWR::MOVE T1,DEVPRI##(F) ;DISK - PRIORITY WORD
TRNE T1,DEPUUO ;PRIORITY SET BY UUO?
JRST UUOPWS ;YES
LDB T1,PJOBN## ;NO, GET DISK-PRIORITY OF JOB
LDB T1,JBXPRI##
DPB T1,DEYPRI## ;AND SAVE IT IN DDB
UUOPWS: TLNN S,IOSUPR ;SUPER USETI/USETO?
SKIPE DEVBLK##(F) ;NO. 0 BLOCK REQUESTED?
JRST UUOPWZ ;NO. OK
SKIPN DINITF## ;RP04 READS BLOCK 0 TO CHECK FORMAT ERROR
SKIPN DEVUNI##(F) ;STR BEEN REMOVED?
JRST UUOPWZ ;YES, DON'T HALT
MOVE T1,DEVPPN(F) ;REQUESTING BLOCK 0 -
CAME T1,SYSPPN## ;[1,4]?
JRST UUOPWY ;NO - ERROR
MOVE T2,DEVFIL(F) ;SINCE HOME BLOCKS ARE WRITTEN AT THE FRONT OF
CAME T2,[SIXBIT .HOME.] ; THE DISK, CHECK FOR HOME[1,4]
UUOPWY: STOPCD .,JOB,IBZ, ;++I/O TO BLOCK ZERO
UUOPWZ:
IFN FTMP,<
PUSHJ P,CHKCPI## ;RIGHT CPU?
PJRST PCLDSK ;NO, QUEUE IT
IFN FTDUAL,<
MOVE T1,UDBCAM(U) ;BUT WHICH PORT IS ON THIS CPU?
TDNE T1,.CPBIT## ;PRIME PORT?
JRST UUOPWD ;YES, USE PRIME PORT
UUOPWW: HRRZ U,UNI2ND(U) ;SET UP ACS FOR OTHER PORT
PUSHJ P,UNICHK ;MAKE SURE THIS PORT IS OK
POPJ P, ; CAN'T HAPPEN
MOVE J,UDBKDB(U)
UUOPWD: SKIPN T1,.CPCPN## ;SET DEYPCL BYTE FOR CPU WHICH STARTED IO
MOVEI T1,PCLCP0## ;ENSURE NON-0
DPB T1,DEYPCL## ;SAVE CPU FOR REST OF WORLD TO SEE
>>
PUSHJ P,SAVE1## ;SAVE P1
UUOPW0: MOVE P1,KDBCHN(J) ;SET P1 = CHANNEL DB
TRON S,IOACT ;SET FILE ACTIVE(IO ACT=1)
MOVEM S,DEVIOS(F) ;CANT USE SETACT-IOW MAY BE ON
NOSCHEDULE
DSKOFF ;#TURN OFF ALL DSK CONTROLLER PI CHANS.
IFN FTCIDSK,<
SKIPGE KONCNA(J) ;#OUT OF CREDITS?
JRST UUOPW2 ;#YES, PW
>
SKIPG T2,KONPOS(J) ;#DOES KONTROL POSITION?
PJRST UUOTWQ ;#NO, PUT FILE TW OR T
SKIPN T1,UNISTS(U) ;#IS UNIT IDLE?
JRST UUOPW1 ;#YES,GO SET PW,P,TW, OR T
IFN FTMDA,<
LDB T3,PJOBN## ;NO, IS UNIT IN MDA WAIT?
CAIN T1,MDACOD ; (AFTER FREE INTERRUPT, MDA SHOULD REREAD HOME BLOCKS)
CAME T3,TLPJOB## ;YES, IS THIS MDA?
CAIA ;NO
JRST UUOTWQ ;YES, LET IT HAPPEN
>
IFN FTDUAL,<
CAIN T1,PWCOD ;#POSITION WAIT?
SKIPE UNIQUE(U) ;#BUT QUEUE EMPTY ON THIS PORT?
>
JRST UUOPW2 ;#SET FILE PW
IFN FTDUAL,<
;HERE IF POSITIONS WAITING ON OTHER PORT.
;OTHER KON MUST BE BUSY.
;START SOMETHING ON THIS PORT IF WE CAN.
SETZM UNISTS(U) ;#FORCE NEW UNISTS TO BE STORED
PUSHJ P,SECCOD
MOVE T2,KONPOS(J) ;#SECCOD CLOBBERS T2
>
UUOPW1: SKIPN DIADSK## ;TRYING TO SHUT DOWN IO?
JRST UUOPW4
CAMN P1,DIACHN## ;YES, FOR THIS CHAN?
JRST UUOPW2 ;YES, JUST QUEUE THIS REQUEST
TLZA T2,KOPPWX ;NO, BUT DON'T START SEEK IF KDB ACTIVE
UUOPW4: TLNN T2,KOPPWX ;UNIT/KONTROLLER POSITION WHILE TRANFERRING?
SKIPL KONBSY(J) ;#IS KONTROL BUSY?
JRST UUOPOS ;#NO, PUT FILE P, TW OR T
IFN FTDUAL,<
SKIPE T1,UNI2ND(U) ;IS THERE AN ALTERNATE PATH?
SKIPE UNISTS(T1) ;YES, IS THE UNIT USEABLE?
JRST UUOPW2 ;NO
MOVE T2,UDBKDB(T1) ;YES, T1=UNIT T2=KON
IFN FTMP,<
MOVE T3,UDBCAM(T1) ;IS OTHER PORT ON THIS CPU?
TDNN T3,.CPBIT##
JRST UUOPW2 ;NO, QUEUE REQUEST
>
MOVE T3,KDBCHN(T2) ;ALTERNATE CHAN
SKIPE DIADSK## ;DIAG IN PROGRESS FOR IT?
CAME T3,DIACHN##
SKIPGE KONBSY(T2) ;KONTROLLER IDLE?
JRST UUOPW2 ;NO
SKIPL (T3) ;IS CHAN IDLE? (2ND CONTROLLER ON DUAL PORTED RP20)
JRST UUOPW2 ;NO, THE KON REALLY ISNT IDLE EITHER
PUSHJ P,STORF ;YES, 1ST UNIT ALSO IS THIS DDB
HRRZ U,T1 ;SET UP NEEDED ACS
HRRZ J,T2
MOVE P1,KDBCHN(J)
JRST UUOPOS ;AND GO START SEEK (OR MAYBE XFER)
>
;HERE TO PUT FILE IN POSITION WAIT (ALWAYS STORE UNISTS)
UUOPW5: SETZM UNISTS(U) ;#FORCE UNITSTS TO BE STORED
;HERE TO PUT FILE IN POSITION WAIT (SOMETIMES STORE UNISTS)
UUOPW2: MOVEI T1,PWCOD ;#PUT FILE PW
DPB T1,DEYCOD## ;#SET FILE PW
IFE FTDUAL,<
SKIPN UNISTS(U) ;#UNIT IDLE?
MOVEM T1,UNISTS(U) ;#YES SET UNIT PW
>
IFN FTDUAL,<
SKIPE UNISTS(U) ;#UNIT IDLE?
JRST UUOPW9 ;#NO, BUSY
MOVEM T1,UNISTS(U) ;#YES, SET UNIT PW
PUSHJ P,SECCOD ;#BOTH PORTS EQUAL
UUOPW9:
>
MOVEI T1,UNIQUE(U) ;#QUEUE ON WHICH TO INSERT FILE
PJRST PUTQUE ;#PUT FILE ON PWQ AND RETURN
UUOPOS: PUSHJ P,RHBP ;#NEED TO REREAD HOME BLOCKS?
JRST UUOPW2 ;#YES, QUEUE THIS REQUEST FOR LATER
PUSHJ P,CYLCOM ;#IS UNIT ALREADY POSITIONED?
JUMPN T1,STRPOS ;#NO, START POSITIONING IF 0
PJRST UUOTWQ ;#YES, SET FILE+UNIT TO T, KONCHN TO B
;# OR FILE+UNIT TO TW AND ADD TO TWQ
;ROUTINE TO TEST IF HOME BLOCKS NEED TO BE REREAD
;RETURNS CPOPJ IF REREAD NEEDED
;NORMAL RETURN IS CPOPJ1
;DESTROYS ONLY T2 AND T3
RHBP:: MOVSI T2,UNPRHB
IFN FTDUAL,<
SKIPE T3,UNI2ND(U)
TDNN T2,UNIDES(T3)
>
TDNE T2,UNIDES(U)
POPJ P,
JRST CPOPJ1##
;SUBROUTINE TO CHECK STATUS OF A UNIT
;RETURNS CPOPJ1 IF OK (MAY HAVE HAD TO CALL HNGSTP)
;RETURNS CPOPJ IF NG - UNIT OFF-LINE, DDB HAS MON-BUF TO WRITE
UNICHK: MOVSI T1,DEPUWL## ;WRITE LOCK?
TDNE T1,DEVPTB##(F)
JRST UNICK1 ;YES
SKIPL T1,DINITF## ;KEEP GOING IF ONCE ONLY
SKIPE T1,UNISTS(U) ;STATUS OF UNIT
CAIGE T1,MDACOD ;OKAY ?
PJRST CPOPJ1## ;YES
UNICK1:
IFN FTMP,<
PUSHJ P,INTLVL## ;POINT CALL HNGSTP IF CALLED FROM DSKTIC
>
SKIPN J,.CPJOB## ;NO, IS UNIT IN MDA WAIT
JRST CPOPJ1## ;REALLY STILL IN ONCE
IFN FTMDA,<
CAMN J,TLPJOB## ;AND THIS JOB=MDA?
CAIE T1,MDACOD ;IF SO, LET MDA DO THE IO
>
SKIPGE DEVSWP##(F) ;IS IT THE SWAPPER?
PJRST CPOPJ1## ;YES, LET IT TRY ANYWAY
MOVSI T1,DEPUWL## ;CLEAR WRITE LOCK
ANDCAM T1,DEVPTB##(F)
PUSHJ P,SAVSTS ;SAVE A RECORD OF JOB'S RESOURCES
IFN FTMP,<
MOVE T1,.CPCPN##
PUSHJ P,SETCPN## ;COME BACK ON SAME CPU
PUSH P,DEVUNI##(F) ; TO TYPE RIGHT UNIT
HRRM U,DEVUNI##(F)
>
PUSHJ P,HNGSTP## ;TELL OPR AND USER ABOUT THE PROBLEM
IFN FTMP,<
POP P,DEVUNI##(F)
>
POP P,T3 ;RECORD OF RESOURCES
PUSHJ P,RESST1 ;GET THEM AGAIN
PUSHJ P,CHEKU ;LET SWITCH TO ALTERNATE PORT HAPPEN
JFCL ;...
JRST UNICHK ;AND TRY AGAIN
;SUBROUTINE TO MAKE A RECORD OF RESOURCES JOB OWNS
;RETURNS WITH THE RECORD ON THE PD LIST AND NO RESOURCES
SAVSTS::MOVE J,.CPJOB## ;GET JOB NUMBER
HLRZ T1,S ;SAVE IOSDA,IOSAU BITS
CAMN J,CBUSER## ;JOB HAVE CB?
TLO T1,1 ;YES, LIGHT A BIT
TRNE S,IOSFA ;HAVE FA?
TLO T1,2 ;YES, FLAG IT
PUSH P,T1 ;SAVE RECORD OF RESOURCES
PUSHJ P,RETRSX ;GIVE UP ALL RESOURCES JOB OWNS
POP P,T1 ;RECORD
EXCH T1,(P) ;PUT BACK ON STACK
PJRST (T1) ;AND TAKE RETURN
;SUBROUTINE TO GET BACK THE RESOURCES
;ENTER WITH T3 = THE RECORD AS SET BY SAVSTS
;PRESERVES T2
RESTS::
RESSTS: HRRZ U,DEVUNI##(F) ;RESET U
RESST1: MOVE S,DEVIOS(F) ;AND S
TRNE T3,IOSDA ;GET DA IF NEEDED
PUSHJ P,UPDA
TLNE T3,2 ;GET FA IF NEEDED
PUSHJ P,UPFA
TRNE T3,IOSAU ;GET AU IF NEEDED
PUSHJ P,UPAU
TLNE T3,1 ;WANT CB?
PUSHJ P,GETCB##
POPJ P, ;AND RETURN TO CALLER
;SUBROUTINE TO SET UP U AND J, EXIT TO NXTBLK (WHICH RETURNS CPOPJ
;OR CPOPJ1 DEPENDING ON WHETHER ANOTHER BLOCK OF THE FILE EXISTS
UUOSET::PUSHJ P,SETU ;SET U FROM DEVUNI
POPJ P, ;F/S WAS YANKED FROM UNDER US
PUSHJ P,UNICHK ;MAKE SURE UNIT IS OKAY.
POPJ P, ;UNIT IS DOWN
MOVE J,UDBKDB(U) ;SET J(KONTROL DATA BLOCK)
;FALL INTO NXTBLK, GET THE NEXT BLOCK OF THE FILE AND RETURN
;SUBROUTINE TO OBTAIN THE NEXT BLOCK ADDRESS
;ENTER WITH J,F,U,S SET UP
;INTERRUPT LEVEL CHECKS BEFORE CALLING TO MAKE SURE STILL POINTERS IN CORE SO NO IO
;RETURNS CPOPJ IF EOF OR DISK FULL OR PNTR BLOCK FULL
;RETURNS CPOPJ1 IF OK
NXTBLK: JUMPL S,CPOPJ1## ;*RETURN IF A MONITOR READ
MOVMS DEVREL##(F) ;NEGATIVE DEVREL IS FLAG FROM USETI -N
HRRZ T1,DEVLFT##(F) ;*NO, NUMBER OF BLOCKS LEFT IN CURRENT GROUP
HRRZ T2,DEVACC##(F) ;*YES. LOC OF A.T.
MOVE T2,ACCWRT##(T2) ;*ACTUAL NUMBER OF BLOCKS WRITTEN
TLNE S,IO+IOSUPR ;*READING?
JRST NXTBL1 ;*NO
CAMGE T2,DEVREL##(F) ;*TRYING TO READ MORE THAN WAS WRITTEN?
POPJ P, ;*YES. TAKE EOF RETURN
JRST NXTBL2 ;NO, CONTINUE
NXTBL1: LDB T3,DEYFNC## ;WRITING, FILE APPEND ONLY ?
TLNN S,IOSUPR ;AND NOT SUPER USETO ?
CAIE T3,FNCAPP##
JRST NXTBL2 ;NO
CAMLE T2,DEVREL##(F) ;YES. WRITING IN THE MIDDLE ?
POPJ P,0 ;YES, RETURN IOBKTL
NXTBL2: SOJGE T1,CPOPJ1## ;*NO, IF BLOCKS LEFT, RETURN (THIS PNTR OK)
TLNN S,IOSUPR ;SUPER USETI/USETO?
JRST NXTBL4 ;NO
;FALL INTO NXTBL3
;HERE WHEN DEVLFT RAN OUT. THERE MAY ACTUALLY BE MORE BLOCKS LEFT.
;IN WHICH CASE WE JUST FILL DEVLFT UP AGAIN.
NXTBL3: MOVE T1,UNIBPU(U) ;NUMBER OF BLOCKS ON THE UNIT
MOVSI T2,DEPCPT## ;IN COMPATIBILITY MODE?
TDNE T2,DEVCPT##(F)
MOVE T1,UNIBUC(U) ;YES, AN 11 DISK HAS MORE BLOCKS
SUB T1,DEVBLK##(F) ;NUMBER OF BLOCKS TILL END
TLNE T1,-1 ;BUT NO MORE THAN 18 BITS WORTH
MOVEI T1,-1
HRRM T1,DEVLFT##(F) ;FILL DEVLFT UP AGAIN
SOJGE T1,CPOPJ1## ;RETURN IF BLOCKS LEFT ON UNIT
MOVE T1,DEVNAM(F) ;DID HE OPEN A UNIT OR A STR?
PUSHJ P,SRSTR##
POPJ P, ;A UNIT, NONE LEFT ON THIS UNIT
HRRZ U,DEVUNI##(F) ;A STR, GET CURRENT UNIT BACK
HLRZ U,UNISTR(U) ;GET NEXT UNIT IN STR
JUMPE U,CPOPJ## ;QUIT IF NO MORE UNITS
HRRM U,DEVUNI##(F) ;POINT DDB AT NEW UNIT
MOVE J,UDBKDB(U) ;NEW UNIT COULD BE DIFFERNT KON
SETZM DEVBLK##(F) ;START WITH BLOCK 0 OF THAT UNIT
JRST NXTBL3 ;GO FILL DEVLFT UP
NXTBL4: MOVSI T2,1 ;*DECREMENT NO. OF POINTERS
SKIPG DEVRSU##(F) ;* IF RIB WASNT ALREADY FULL
ADDB T2,DEVRSU##(F) ;*RIB NOW FULL?
JUMPGE T2,NXTBL6 ;*YES, LIGHT IOBKTL
AOS T1,DEVRET##(F) ;*STEP TO NEXT POINTER IN CORE
CAIG T1,DEVRBN##(F) ;*RUN OUT OF IN-CORE POINTERS?
JRST NXTB11 ;*NO, CONTINUE
MOVE T1,DEVREL##(F) ;YES, UPDATE RELATIVE BLOCK NUMBER
MOVEM T1,DEVFLR##(F) ;OF LOWEST BLOCK IN DDB POINTERS
HRRM U,DEVFUN##(F) ;AND UNIT OF 1ST PNTR IN DDB
TLNN S,IO ;READING?
JRST NXTB10 ;YES
;HERE WHEN WRITING AND THE DDB POINTER SPACE IS FULL
TLNN F,OCLOSB ;OUTPUT CALLED BY CLOSE?
JRST NXTBL8 ;NO. CONTINUE
;HERE IF THE OUTPUT IS FROM CLOSE
PUSHJ P,RIBCUR ;READ THE CURRENT RIB
JUMPN T3,CPOPJ## ;NON-ZERO T3 MEANS ERROR READING RIB
PUSHJ P,SPTRW ;SET AOBJN WORD FOR POINTERS
MOVE T4,T1 ;SAVE ORIGINAL POINTER WORD
PUSHJ P,DD2MN ;COPY POINTERS INTO MON BUF
JFCL
SUBM T1,T4 ;COMPUTE NEW FREE-POINTER COUNT
AOS T2,T4
DPB T4,DEYRLC## ;AND SAVE IT IN DDB
AOBJN T1,.+1 ;POINT T1 AT NEXT GROUP OF POINTERS
SKIPE (T1) ;MORE POINTERS? (PRE-ALLOCATED SPACE)
PUSHJ P,PTRBL1 ;YES, COPY THEM TO DDB
MOVEI T2,DEVRB1##(F) ;RESET DEVRET
HRRM T2,DEVRET##(F)
HLRE T2,DEVRSU##(F) ;NUMBER OF PNTRS LEFT
AOJGE T2,NXTBL5 ;GO IF LAST PNTR
SKIPL DEVRIB##(F) ;NOT LAST, PRIME RIB?
TLOA S,IOSRIB ;YES, SET FLAG TO INDICATE TO CLOSE CODE
NXTBL5: TLZ S,IOSRIB ;RIB NOT PRIME, BETTER WRITE IT OUT
PUSHJ P,WRTRIB ;WRITE OUT THE RIB
JRST NXTBL9 ;AND CONTINUE
;HERE IF THE CURRENT RIB IS FULL
NXTBL6: TLNE S,IO ;READING?
JRST NXTBL7 ;NO
PUSHJ P,PTRTST ;READ NEW POINTERS, WRITE THESE IF CHANGED (CHECKSUM)
POPJ P, ;RIB ERROR
PUSHJ P,PTRNXT ;GET THE NEXT RIB
POPJ P, ;RIB ERROR
PUSHJ P,CPYEXT## ;COPY FIRST POINTERS FROM EXTENDED RIB
POPJ P, ;RIB ERROR
HRRZ T1,DEVLFT##(F) ;GET COUNT OF NUMBER OF BLOCKS LEFT IN PNTR
JRST NXTB14 ;AND CONTINUE
;IF NO MULTIPLE RIBS, FALL INTO POPJ AT NXTBID
;HERE WHEN WRITING AND WE'VE RUN OUT OF ROOM IN THE CURRENT RIB
NXTBL7: PUSHJ P,EXTRIB ;YES, ALLOCATE ANOTHER RIB
PJRST DWNIFA ;ERROR - RETURN FA AND EXIT
PUSHJ P,DWNIFA ;OK - GIVE UP FA IF WE HAVE IT
PUSHJ P,CPYEXT## ;SET UP THE DDB
POPJ P, ;RIB ERROR
JRST NXTBLK ;USE THE NEW BLOCKS ACQUIRED
;HERE IF THE OUTPUT IS NOT FROM CLOSE
NXTBL8: PUSHJ P,PTRCUR ;GET THE RIB
JUMPN T3,CPOPJ## ;ERROR IN RIB KILLS US
PUSHJ P,PTRWRT ;SAVE POINTERS AND WRITE (KEEP THE MON BUF)
PUSHJ P,SPTRW ;SET T1 TO AN AOBJN WORD FOR ALL THE PNTRS
LDB T2,DEYRLC## ;NEW POINTER LOC
HRLS T2 ;SET TO ADD TO AOBJN WORD
ADD T1,T2
SKIPE (T1) ;POINTERS (PRE-ALLOCATED SPACE)?
PUSHJ P,PTRBLT ;COPY THE NEW POINTERS INTO DDB
PUSHJ P,CPXPTR ;SET UP PTRFUN, PTRFLR, ETC
NXTBL9: SETZM DEVBLK##(F) ;INDICATE NO CONTIGUITY
AOS UNIPGT(U) ;COUNT A PAGE-TURN
JRST NXTB11 ;AND CONTINUE
;HERE WHEN THE POINTERS RAN OUT ON INPUT
NXTB10: PUSHJ P,CLSNAM## ;MAKE SURE NAME IN DDB IS RIGHT
; (FILE MIGHT BE RENAMED)
MOVSI T1,1
SKIPE DEVRB2##(F) ;FULL DDB?
AOSA UNIPGT(U) ;YES, COUNT A PAGE-TURN
ADDM T1,UNIPGT(U) ;NO, COUNT A QUARTER-TURN
PUSHJ P,PTRTST ;READ NEW POINTERS, WRITE THESE IF CHANGED (CHECKSUM)
POPJ P, ;RIB ERROR
PUSHJ P,PTRCPY ;COPY NEW SET OF POINTERS INTO DDB
SKIPE DEVRB1##(F) ;GET NEW POINTERS?
JRST NXTB11 ;YES
PUSHJ P,FNDPTR ;NO, FIND THEM IN A DDB
POPJ P, ;COULDN'T FIND THEM
;HERE WITH DEVRET POINTING TO NEXT RETRIEVAL POINTER (OR 0)
NXTB11: SKIPE T2,@DEVRET##(F) ;*IS THERE ANOTHER POINTER?
JRST NXTB13 ;*YES
MOVE T1,DEVACC##(F) ;NO, ARE WE UP TO END OF FILE?
TLNN S,IO ;IF READING,
SKIPA T1,ACCWRT##(T1) ;USE NUMBER OF BLOCKS WRITTEN
PUSHJ P,GETALC ;ELSE USE NUMBER OF BLOCKS ALLOCATED
CAMG T1,DEVREL##(F)
JRST NXTB12 ;YES, RETURN EOF OR ALLOCATE BLOCKS
TLNN S,IO ;NOT AT EOF. READING?
JRST FNDPTR ;YES, FIND POINTERS IN SOME DDB
JRST FIXDDB ;NO, FIND NEWLY-ALLOCATED PNTRS IN RIB
;HERE IF WE ARE UP TO THE END OF THE FILE
NXTB12: TLNN S,IO ;READING?
POPJ P, ;YES - EOF
;NO, FALL INTO OUTPUT ALLOCATION
;HERE TO ALLOCATE SOME MORE SPACE FOR AN OUTPUT FILE
OUTGRP: HRRZ T1,UNISTR(U) ;LOC OF STR DATA BLOCK
HLRZ T2,UNIGRP(U) ;NUMBER OF CLUSTERS TO ALLOCATE
TLO T2,400000 ;TELL CHKQTA THAT THE CALL IS FROM OUTPUT
PUSHJ P,CHKQTA ;CHECK USERS QUOTA OR DISK FULL
JUMPLE T2,OUTG11 ;CAN'T GET ANY MORE RETURN (IOBKTL SET)
;HERE WITH T2 = AMOUNT TO ALLOCATE, STR HAS SOME SPACE
MOVE T1,DEVACC##(F) ;IF SIMULT UPDATE FILE
MOVE T3,ACCSMU##(T1) ; GET MON BUF NOW
TRNN T3,ACPSMU
JRST OUTGR2
MOVE T3,ACCALC##(T1) ;CURRENT LENGTH OF FILE
PUSHJ P,UPFA ;WAIT FOR FA
CAMN T3,ACCALC##(T1) ;DID ANOTHER JOB EXTEND FILE?
JRST OUTGR1 ;NO, CARRY ON
PUSHJ P,DWNFA ;YES, BACK OUT GRACEFULLY
JRST NXTB11 ;AND USE THE NEW BLOCKS
OUTGR1: PUSHJ P,GTMB2
OUTGR2: SKIPN T1,DEVBLK##(F) ;CONTIGUITY ALLOWED?
JRST OUTGR4 ;NO. GET SPACE ANYWHERE
SOS DEVRET##(F) ;YES. POINT TO CURRENT RETRIEVAL PTR
PUSHJ P,CHKADD ;ROOM LEFT IN POINTER?
JUMPLE T2,OUTGR3 ;NO. GET SPACE ANYWHERE
MOVE T1,DEVBLK##(F) ;YES. GET SPACE PAST 1ST UNALLOCATED BLOCK
PUSHJ P,TAKBLK ;YES. GET SPACE AT END
JRST OUTGR3 ;TRY FOR SPACE ANYWHERE ON UNIT
PUSHJ P,ADDPTR ;ADD NEW BLOCKS TO CURRENT POINTER
MOVSI T2,-1 ;DEVRSU WAS INCREMENTED AT NXTBL4,
ADDM T2,DEVRSU##(F) ; SO DECREMENT IT BACK DOWN
TRNE S,IOSFA ;IF A SIM UPDATE FILE,
JRST OUTGR7 ; REWRITE RIB WITH NEW POINTERS IN IT
JRST NXTB15 ;STORE NEW DEVLFT AND CONTINUE
;HERE WHEN CANT GET SPACE CONTIGUOUS WITH THE OLD SPACE
OUTGR3: AOS DEVRET##(F) ;POINT TO NEW POINTER LOC
MOVE T2,T1 ;RESTORE AMOUNT TO GET
OUTGR4: MOVEI T4,TAKCHK ;SET TO TAKE N BLOCKS ON ANY UNIT
HLRE T1,DEVRSU##(F) ;UNLESS THERE IS ONLY ROOM FOR 1 POINTER
CAMLE T1,[EXP -2] ;IN WHICH CASE, SET TO STAY ON THIS UNIT
MOVEI T4,TAKBLK
AOJN T1,OUTGR5 ;JUMP IF NOT LAST POINTER
MOVSI T1,DEPLPC## ;IS LAST, SET LAST POINTER IN CORE BIT
IORM T1,DEVLPC##(F) ;SO BLOCK WILL BE RESERVED FOR REDUNDANT RIB
OUTGR5: SETZ T1, ;GET BLOCKS ANYWHERE
PUSHJ P,(T4) ;GET SOME BLOCKS
JRST OUTGR9 ;ON NEW UNIT
OUTGR6: PUSHJ P,PTSTO ;GOT SPACE ON SAME UNIT - SAVE POINTER IN DDB
TRNN S,IOSFA ;SIM UPDATE FILE?
JRST OUTGR8 ;NO, CONTINUE
OUTGR7: PUSHJ P,WRTPTR ;REWRITE RIB WITH NEW PNTRS
PUSHJ P,DWNFA ;GIVE UP FA NOT THAT RIB WRITTEN
PJRST FIXDDB ;CALL USETI TO GET PNTRS BACK INTO CORE
; (DD2MN ZEROES THE DDB)
OUTGR8: HRRZ T3,DEVACC##(F) ;LOC OF A.T.
MOVEI T4,ACP1PT## ;MAKE SURE THAT 1PT
ANDCAM T4,ACCUN1##(T3) ; IS OFF IN THE UN1 WORD
JRST NXTB13 ;AND CONTINUE
;GOT SOME SPACE ON A NEW UNIT, OR STR FULL
OUTGR9: JUMPE T3,OUTG12 ;IF GOT ANY
MOVSI T1,1
ADDB T1,DEVRSU##(F) ;UPDATE DEVRSU
JUMPGE T1,OUTG12 ;ERROR IF ALL SLOTS TAKEN (SHOULD NEVER HAPPEN)
AOBJN T1,OUTG10
MOVSI T1,DEPLPC##
IORM T1,DEVLPC##(F)
OUTG10: MOVE T1,T2 ;SAVE RETRIEVAL POINTER
MOVE T2,T3 ;PICK UP UNIT-CHANGE
PUSHJ P,PTSTO ;SAVE UNIT-CHANGE IN DDB
MOVE T2,T1 ;RESTORE "REAL" POINTER
PUSHJ P,STORU ;SAVE NEW UNIT IN DDB
AOS T1,DEVRET##(F) ;POINT TO NEXT PNTR SLOT
CAIG T1,DEVRBN##(F) ;DDB FULL?
JRST OUTGR6 ;NO, STORE REAL POINTER IN DDB
PUSH P,T2 ;YES, SAVE PNTR
PUSHJ P,WRTPTR ;COPY PNTRS TO RIB, WRITE
POP P,T2 ;RESTORE NEW RETRIEVAL POINTER
JUMPE T3,OUTGR6 ;CONTINUE IF NO RIB ERR
PUSHJ P,CNVPTR ;RIB ERR- GIVE BACK THE BLOCKS
JFCL ;BAD UNIT!
STOPCD OUTG12,DEBUG,LNP, ;++LAST POINTER NOT A POINTER
MOVE T2,T1 ;SET TO GIVE BACK THE BLOCKS
MOVE T1,DEVBLK##(F)
PUSHJ P,GIVBLK ;RETURN THE BLOCKS, UPDATE COUNTS
JRST OUTG12 ;UPDATE DEVRSO AND ERROR RETURN
;HERE WHEN STRUCTURE IS FULL, RETURN DEVRSU TO PRE-CALL STATE
OUTG11: MOVEI T4,.ERFUL ;STR FULL INTERCEPT
PUSHJ P,SETINJ ;LET JOB KNOW
JFCL ;DON'T CARE IF NOT ENABLED
;HERE WHEN THERE ARE NO FREE BLOCKS LEFT IN THE STR
OUTG12: SOS DEVRET##(F) ;POINT DEVRET BACK TO LAST REAL POINTER
MOVSI T1,-1 ;DECR DEVSRU
ADDM T1,DEVRSU##(F) ;(INCREMENTED AT NXTBL4)
PUSHJ P,DWNIFA ;GIVE UP FA IF SIM UPDATE
PJRST ERRFUL ;LIGHT AN ERROR BIT AND RETURN
;HERE WHEN WE HAVE A POINTER IN T2 (MAY BE UNIT CHANGE)
NXTB13: PUSHJ P,CNVPTR ;*CONVERT POINTER TO BLK, COUNT
JRST OUTG12 ;BAD UNIT-CHANGE PTR-LOSE
JRST NXTBL4 ;*WAS A UNIT-CHANGE. TRY NEXT
;HERE WITH T1=BLOCK COUNT, DEVBLK SET UP
TLO S,IOSFIR ;*INDICATE CHECKSUM MUST BE COMPUTED
MOVEM S,DEVIOS(F) ;*SAVE S IN DDB
TLNE S,IO ;*READING?
JRST NXTB15 ;*NO, ANY ALLOCATED BLOCK IS OK
NXTB14: HRRZ T2,DEVACC##(F) ;*YES, MAKE SURE THESE BLOCKS ARE ALL WRITTEN IN
MOVE T2,ACCWRT##(T2) ;*HIGHEST BLOCK WRITTEN
SUB T2,DEVREL##(F) ;*-1ST RELATIVE BLOCK OF GROUP
AOJLE T2,CPOPJ## ;*EOF IF NO BLOCKS LESS THAN HIGHEST WRITTEN
NXTB15: MOVE T2,DEVLPC##(F) ;GET WORD TO TEST FOR LAST POINTER
TLNN T2,DEPLPC## ;LAST POINTER IN CORE?
JRST NXTB16 ;NO, NO NEED TO WORRY
HRRZ T2,DEVRET##(F) ;GET ADDRESS OF CURRENT POINTER IN DDB
CAIE T2,DEVRBN##(F) ;POINTING TO LAST SLOT IN DDB?
SKIPN 1(T2) ;NO, NEXT SLOT EMPTY?
SOJE T1,NXTBL4 ;YES, JUMP IF CURRENT POINTER EXHAUSTED
NXTB16: HRRM T1,DEVLFT##(F) ;*AND SAVE IN DDB
MOVE J,UDBKDB(U) ;*RIB MIGHT BE ON ANOTHER KONTROLLER
JRST CPOPJ1## ;*AND TAKE SKIP RETURN
;SUBROUTINE TO CREATE AN EXTENDED RIB
; RETURNS CPOPJ IF ERROR OR RIB NOT EXTENDABLE
; RETURNS CPOPJ1 WITH NEW RIB IN THE MONITOR BUFFER AND T1=NUMBER OF NEW BLOCKS ADDED
EXTRIB::MOVE T1,DEVACC##(F)
MOVE T1,ACCSMU##(T1) ;SIM UPDATE FILE?
TRNN S,IOSFA ;AND DDB WITHOUT FA (OR MON BUF)?
TRNN T1,ACPSMU
JRST EXTRB0
PUSHJ P,GTMNBF ;YES, GET DA BEFORE READING RIB
PUSHJ P,UPFA ;CAUSE ANOTHER JOB MIGHT TRY TO EXTEND RIB
EXTRB0: PUSHJ P,PTRCUR ;GET CURRENT RIB INTO CORE
JUMPN T3,CPOPJ## ;RIB ERROR IF T3 NON-0
PUSHJ P,DD2MN ;COPY POINTERS FROM DDB TO RIB
STOPCD CPOPJ##,DEBUG,NPD, ;++NO POINTERS IN DDB
MOVE T1,.USMBF ;IOWD TO MONITOR BUFFER
SKIPG DEVRIB##(F) ;CURRENT RIB EXTENDED?
JRST EXTRB1 ;YES, CAN EXTEND AGAIN
SKIPE RIBFLR+1(T1) ;PRIME RIB. RIBFLR=0?
PJRST EXTRB3 ;NO, CANNOT EXTEND THIS RIB
EXTRB1: SKIPE T2,RIBXRA##+1(T1) ;RIB ALREADY EXTENDED?
JRST EXTRB2 ;YES, GO GET THE NEXT RIB
PUSHJ P,SAVE1##
MOVEI T1,DEPWRT## ;MAKE SURE FNDDDB DOESN'T
ANDCAM T1,DEVWRT##(F) ; FIND THIS DDB WHILE NUMBERS ARE CHANGING
PUSHJ P,GETALC ;GET "REAL" ACCALC
MOVE P1,T1 ;RIBFLR=ACCALC - 2 RIB BLOCKS
SUBI P1,2
PUSHJ P,GTLPT## ;GET LAST RIB POINTER
PUSHJ P,CNVPTR ;DECODE THE POINTER
JFCL
STOPCD CPOPJ##,DEBUG,UPI, ;++UNIT POINTER ILL.
;STILL IN FTDMRB CONDITIONAL
SOJ T1, ;DECREMENT NUMBER OF BLOCKS LEFT
ADDM T1,DEVBLK##(F) ;NOW DEVBLK IS LAST BLOCK IN THE RIB
MOVE T1,.USMBF ;IOWD FOR MONITOR BUFFER
MOVE T2,DEVBLK##(F) ;GET ABSOLUTE BLOCK NUMBER OF REDUNDANT RIB
MOVEM T2,RIBSLF##+1(T1);STORE IN THE RIB
MOVEI T2,CODRIB## ;RIB IDENTIFICATION CODE
MOVEM T2,RIBCOD##+1(T1);STORE IN THE RIB
SETZ T1, ;TELL TAKBLK TO GET BLOCKS ANYWHERE
HRROI T2,3 ;LOOK FOR 2 BLOCKS (RIBS + 1 DATA)
LDB T3,UNYLUN## ;GET LOGICAL UNIT NUMBER
TRO T3,RIPNUB## ;FORM A UNIT CHANGE POINTER
MOVEM T3,DEVRB1##(F) ;STORE IN DDB TEMPORARILY
; (ASSUME WE'LL GET BLOCKS ON SAME UNIT)
PUSH P,U ;SAVE CURRENT UNIT
PUSHJ P,TAKCHK ;ALLOCATE BLOCKS ANYWHERE
MOVEM T3,DEVRB1##(F) ;DIFFERENT UNIT, STORE UNIT CHANGE POINTER
POP P,U ;RESTORE UNIT
SKIPN T3,DEVRB1##(F) ;DID WE GET ANY BLOCKS?
PJRST EXTRB3 ;ERROR, COULDN'T GET THE BLOCKS
PUSH P,T1 ;SAVE NUMBER OF BLOCKS JUST TAKEN
MOVEM T2,DEVRB2##(F) ;STORE NEW POINTER IN DDB
PUSH P,DEVRIB##(F) ;SAVE CURRENT RIB POINTER
LDB T4,DEYRBC## ;NUMBER OF CURRENT RIB
MOVSI T1,400000 ;TURN ON BIT 0 IN T1
MOVEM T1,DEVRIB##(F) ;NEGATIVE DEVRIB MEANS CURRENT RIB IS EXTENDED
ADDI T4,1 ;INCREMENT RIB NUMBER
DPB T4,DEYRBC## ;AND SAVE IN DDB
HRRZ T4,UNISTR(U) ;GET ADDRESS OF SDB FOR CURRENT RIB UNIT
LDB T1,STYCLP##(T4) ;EXTRACT CLUSTER ADDRESS FROM POINTER
DPB T1,DEYRBA## ;SAVE IN DEVRIB
DPB T3,DEYRBU## ;INSERT EXTENDED RIB LOGICAL UNIT NUMBER
;STILL IN FTDMRB CONDITIONAL
MOVE T1,.USMBF ;IOWD TO MONITOR BUFFER
MOVE T2,DEVRIB##(F) ;POINTER TO NEXT RIB ON CHAIN
MOVEM T2,RIBXRA##+1(T1) ;SAVE IN CURRENT RIB
POP P,DEVRIB##(F) ;RESTORE POINTER TO CURRENT RIB
MOVE T2,RIBSLF##+1(T1) ;GET BLOCK NUMBER FOR REDUNDANT RIB WRITE
PUSHJ P,MONWRT ;WRITE THE REDUNDANT RIB
PUSHJ P,WRTRIB ;WRITE THE WORKING COPY OF THE RIB
MOVE T1,.USMBF ;GET THAT IOWD AGAIN
MOVE T2,RIBXRA##+1(T1) ;POINTER TO EXTENDED RIB
MOVEM T2,DEVRIB##(F) ;NEW CURRENT RIB
PUSHJ P,SPTRW ;SET UP POINTER TO RIB
MOVE T4,T1 ;MOVE POINTER TO T4
SETZM (T1) ;CLEAR THE POINTER LOCATION
AOBJN T1,.-1 ;CLEAR ALL POINTERS IN THE RIB
MOVE T1,.USMBF ;GET IOWD TO MONITOR BUFFER
MOVEM P1,RIBFLR##+1(T1) ;SET UP RIBFLR TO FIRST BLOCK NUMBER IN RIB
SETZM RIBXRA##+1(T1) ;CLEAR POINTER TO NEXT(NON-EXISTANT) RIB
MOVE T2,DEVRB1##(F) ;GET FIRST POINTER IN RIB
MOVEM T2,(T4) ;SAVE FIRST POINTER IN RIB
SETZM DEVRB1##(F) ;CLEAR THE POINTER LOCATION
MOVE T2,DEVRB2##(F) ;GET SAVED SECOND POINTER
MOVEM T2,1(T4) ;(FIRST WAS CHANGE OF UNIT POINTER)
SETZM DEVRB2##(F) ;FORGET SAVED POINTER
PUSHJ P,GRPAD ;COMPUTE DISK ADDRESS FROM POINTER
MOVEM T2,RIBSLF##+1(T1) ;SAVE IN THE RIB
PUSHJ P,WRTRIB ;WRITE THE RIB
MOVEI T1,DEPWRT## ;ITS OK FOR FNDDDB TO
IORM T1,DEVWRT##(F) ; SEE US AGAIN
JRST TPOPJ1## ;GOOD RETURN
;HERE WHEN THIS RIB ALREADY IS EXTENDED
EXTRB2: PUSH P,T2
PUSHJ P,WRTRIB ;WRITE CURRENT RIB (NEW CHECKSUMS
POP P,DEVRIB##(F) ;SET UP POINTER TO NEXT RIB
PUSHJ P,RIBCUR ;READ THE NEXT RIB
PJUMPN T3,CPOPJ## ;ERROR READING RIB IF T3 NON-ZERO
JRST CPOPJ1## ;HAPPY RETURN
;HERE WHEN THE RIB CAN'T BE EXTENDED
EXTRB3: PUSHJ P,WRTRIB ;WRITE THE RIB (WITH NEW PNTRS)
MOVEI T1,DEPWRT## ;ITS OK FOR FNDDDB TO
IORM T1,DEVWRT##(F) ; SEE US AGAIN
PJRST DWNIFA ;GIVE UP FA IT WE OWN IT AND RETURN
;SUBROUTINE TO CONVERT A RETRIEVAL POINTER
;ENTER WITH T2=POINTER
;EXIT CPOPJ LF BAD UNIT-CHANGE PNTR
;EXIT CPOPJ1 (WITH NEW U SET UP) IF CHANGE-UNIT POINTER
;EXIT CPOPJ2 WITH DEVBLK SET AND T1=COUNT IF A REAL POINTER
CNVPTR::TLNE T2,-1 ;*REAL POINTER?
JRST CNVPT2 ;*YES
TRZ T2,RIPNUB## ;*CHANGE UNIT. REMOVE BIT 18
CNVPT1: PUSHJ P,NEWUNI ;*SET U, DEVUNI
TDZA T2,T2 ;*INVALID U - SET TO 0
JRST CPOPJ1## ;*OK - RETURN
HRRZ U,DEVUNI##(F)
SOS (P)
JRST CNVPT1 ;*SET U TO 1ST UNIT IN STR AND RETURN
CNVPT2: HRRZ T4,UNISTR(U) ;*STR DB LOCATION
LDB T1,STYCLP##(T4) ;*CLUSTER ADDRESS
LDB T3,UNYBPC## ;*BLOCKS PER CLUSTER
IMUL T1,T3 ;*BLOCK ADDR
MOVEM T1,DEVBLK##(F) ;*SAVE IN DDB
LDB T1,STYCNP##(T4) ;*GROUP COUNT FIELD
IMUL T1,T3 ;*BLOCK COUNT
JRST CPOPJ2## ;*RETURN
;SUBROUTINE TO RESET U, DEVUNI(F) TO A NEW VALUE
;ENTER WITH LOGICAL UNIT NUMBER IN T2
;EXIT WITH U, DEVUNI SET TO NEW VALUE
;RETURNS CPOPJ IF NO SUCH UNIT, CPOPJ1 NORMALLY
;NEWUX SAME, PRESERVES T1,T3,T4
NEWUX:
NEWUNI::HRRZ U,UNISTR(U) ;*LOC OF FILE STRUCTURE DB
JUMPE U,CPOPJ## ;*RETURN NON-SKIP IF NOT IN A F/S
HLRZ U,STRUNI##(U) ;*LOC OF UNIT 0 IN STRUCTURE
;SUBROUTINE TO RESET U,DEVUNI(F) TO A NEW VALUE
;ENTER WITH POINTING TO 1ST UNIT IN STR
;EXIT WITH U,DEVUNI(F) SET TO NEW VALUE
;T1,T3,T4 RESPECTED
NEWUN:: SOJL T2,NEWUN2 ;*DONE IF T2 COUNTS OUT
HLRZ U,UNISTR(U) ;*STEP TO NEXT UNIT OF STRUCTURE
JUMPN U,NEWUN ;*TRY NEXT
JRST NEWUN3 ;*DESIRED UNIT WAS HIGHER THAN LAST UNIT IN STRUCTURE
NEWUN2: PUSHJ P,STORU ;*SET DDB
MOVE J,UDBKDB(U) ;*SET UP J
JRST CPOPJ1## ;*AND EXIT
NEWUN3: TRO S,IOBKTL ;*ILLEGAL UNIT - LIGHT ERROR BIT
JRST STRIOS ;*SAVE S AND ERROR RETURN
;SUBROUTINE TO SET U IN DDB, SET UP DEVGEN
;RESPECTS ALL ACS
STOAU:: HLLM U,DEVUNI##(F) ;SAVE ALL OF U IN DDB
STORU:: HRRM U,DEVUNI##(F) ;SAVE RH OF U IN DDB
PUSH P,T1
MOVE T1,UNIGEN(U) ;CURRENT GENERATION
HRLM T1,DEVGEN##(F) ;INTO DDB
IFN FTMP,<
PUSHJ P,CPUDDB ;SET CPU SPECIFICATION
>
JRST TPOPJ## ;AND RETURN
;SUBROUTINE TO SET U FROM DDB
;NON-SKIP RETURN IF F/S WAS YANKED OUT, CPOPJ1 NORMALLY
;RESPECTS ALL ACS
SETU:: HRRZ U,DEVUNI##(F) ;SET UP U
CHEKU:: TRNN U,-1 ;REALLY A UDB THERE?
STOPCD SETIMP,DEBUG,UDBAIZ, ;++UDB ADDRESS IS ZERO
PUSHJ P,TSTGEN ;GENERATION CHANGED?
CAIA ;YES
JRST CPOPJ1 ;NO
IFN FTDUAL,<
PUSHJ P,SAVT## ;WE'LL CALL CPUDDB AT THE END
HRRZ T1,UNIALT(U) ;LOOKS LIKE IT, GET ALTERNATE UDB ADDRESS
JUMPE T1,GONEU ;IF NO ALTERNATE, UNIT WAS YANKED
HLRZ T2,DEVGEN##(F) ;YES. IS OTHER UDB SAME GENERATION?
CAME T2,UNIGEN(T1)
JRST GONEU ;NO. UNIT WAS YANKED
EXCH U,T1 ;YES, SWITCH TO ALTERNATE UNIT
HRLS T1
HRRZ T2,T1
XOR T1,DEVUNI##(F) ;SWITCH DEVUNI
TLNN T1,-1
HRLM U,DEVUNI##(F) ;SWITCH UNIT OF RIB
TRNN T1,-1
HRRM U,DEVUNI##(F) ;SWITCH CURRENT UNIT
HRRZ T1,DEVFUN##(F)
CAME T1,T2
JRST CHEKU1
HRRM U,DEVFUN##(F) ;SWITCH 1ST UNIT IN DDB POINTERS
HRRZ T1,DEVCPY##(F)
SKIPE T1
HRLM U,PTRFUN##(T1) ;SWITCH 1ST UNIT IN IN-CORE COPY
CHEKU1: MOVE T1,UNIGEN(U) ;SAVE CURRENT GENERATION
HRLM T1,DEVGEN##(F) ; IN DDB
IFN FTMP,<
PUSHJ P,CPUDDB ;SET WHICH CPU'S THE DISK LIVES ON
>
JRST CPOPJ1## ;AND GO AWAY HAPPY
> ;END FTDUAL
;HERE IF UNIT WAS YANKED
GONEU: HLLZS DEVACC##(F) ;A.T. WAS RETURNED
PJRST SETIMP## ;SET IOIMPM AND RETURN
;ROUTINE TO TEST IF UNIT GENERATION NUMBER HAS CHANGED
;SKIP IF STILL THE SAME
TSTGEN: PUSH P,T1 ;SAVE AN AC
HLRZ T1,DEVGEN##(F) ;GENERATION WE STARTED WITH
CAME T1,UNIGEN(U) ;SAME AS CURRENT?
SKIPGE DEVSWP##(F) ;OR SWAPPER?
AOS -1(P) ;YES
PJRST TPOPJ##
;SUBROUTINE TO SET UP F, MAKE JOB ADRESSABLE
;PRESERVES ALL ACS
SETF: HRRZ F,UNICDA(U) ;GET F FROM UDB
JUMPE F,CPOPJ##
PUSH P,J
HRRZ J,UNIJOB(U) ;MAKE JOB ADDRESSABLE
PUSHJ P,MKADD##
IFN FTDUAL,<
CAIG F,FYSORG+FYSSIZ ;DDB LIVE WITHIN
CAIGE F,FYSORG ; FUNNY SPACE?
SKIPA ;YES, BETTER HAVE A JOB NUMBER
JUMPE J,SETF0 ;LOW CORE DDB
HLL F,DINITF##
HRRZ J,DEVCUR##(F)
CAIN J,(U) ;IF DDB IS POINTING AT THIS UDB
IFE FTXMON,<
JRST JPOPJ## ; EVERYTHING IS FINE
>
IFN FTXMON,<
JRST SETF1 ; EVERYTHING IS FINE
>
CAIN F,SWPDDB## ;MANY SWAPS CAN BE GOING ON SIMULTANEOUSLY
SKIPL UNICDA(U) ;UNICDA IS ONLY NEG FOR PORT DOING ACTUAL IO
SETF0: MOVEI F,0 ; THIS IS A SPURIOUS INTERRUPT
>
IFN FTXMON,<
SKIPE F ;DON'T TRY TO SET PCS IF F IS BAD
SETF1: PUSHJ P,SPCS## ;SET PCS FROM DEVISN (DEPENDS ON STEUB TO RESTORE IT)
>
JRST JPOPJ## ;AND RETURN
;SUBROUTINE TO STORE F IN UDB, SET UP HUNG TIMER.
;RETURNS T3=JOB NUMBER
;PRESERVES ALL ACS EXCEPT T3
STORF: HRRM F,UNICDA(U) ;SAVE F
IFN FTDUAL,<
SKIPE T3,UNI2ND(U) ;DUAL PORTED?
SETZM UNIJOB(T3) ;CLEAR JOB NO ON 2ND PORT
>
MOVEI T3,DSKTIM## ;SET UP HUNG TIMER
MOVEM T3,UNITIM(U)
LDB T3,PJOBN## ;POINT UDB AT JOB
MOVEM T3,UNIJOB(U)
POPJ P, ;AND RETURN
;COPY POINTER TO DEVRBN OR @DEVRET
;RESPECTS T1,T2
PTSTOX: SKIPE @DEVRET##(F) ;"REGULAR" POINTER?
JRST PTSTO ;YES, DO IT THE OTHER WAY
MOVEM T2,DEVRB1##(F) ;NO, SAVE THE PNTR IN DEVRB1
SETZ T3, ;STORE IN 1ST IN-CORE PNTR SLOT
JRST PTSTO1
;RESPECTS T1, T2
PTSTO:: MOVEM T2,@DEVRET##(F) ;SAVE THE POINTER IN DDB
HRRZ T3,DEVRET##(F) ;LOC OF CURRENT PNTR
SUBI T3,DEVRB1##(F) ;COMPUTE RELATIVE LOC
SKIPL T3 ;IF RELATIVE LOC IS WRONG
CAIL T3,PTRLEN## ;(POINTS AT MONBUF @CLSOU3)
POPJ P, ; JUST RETURN
PTSTO1: HRRZ T4,DEVCPY##(F) ;LOC OF IN-CORE COPY
JUMPE T4,CPOPJ## ;GO IF NONE
ADDI T4,PTRDAT##(T3) ;WHERE THIS PNTR GOES
MOVEM T2,(T4)
POPJ P,
;COPY POINTERS FROM DDB TO IN-CORE COPY
;ENTER T3=DEVLPC WORD
CPZPTR::MOVE T3,DEVLPC##(F) ;LAST POINTER IN CORE
CPYPTR::HRRZ T1,DEVCPY##(F) ;IN-CORE COPY
JUMPE T1,CPOPJ## ;GO IF NONE
HRLI T1,DEVRB1##(F) ;POINT AT 1ST RET. POINTER IN DDB
MOVEI T2,(T1)
ADDI T1,PTRDAT## ;POINT T2 AT 1ST RET PNTR IN COPY
BLT T1,PTRDND##(T2) ;SAVE PNTRS IN IN-CORE COPY
CPXPTR: HRRZ T2,DEVCPY##(F)
JUMPE T2,CPOPJ## ;NOTHING TO DO IF NO IN-CORE COPY
MOVE T1,DEVFLR##(F) ;GET INFO FROM DDB
MOVEM T1,PTRFLR##(T2) ; AND SAVE IN IN THE IN-CORE COPY
MOVE T1,DEVRIB##(F)
MOVEM T1,PTRRIB##(T2)
MOVE T1,DEVFUN##(F)
HRLM T1,PTRFUN##(T2)
LDB T1,DEYRLC##
TLNE T3,DEPLPC##
TRO T1,PTPLPC##
HRRM T1,PTRRLC##(T2)
HLRE T1,DEVRSU##(F)
MOVNS T1
DPB T1,PTYRSU##
POPJ P, ;AND RETURN
SUBTTL FILINT - INTERRUPT HANDLING MODULE
FILINT::HLLZ T4,T1 ;CONVERT TO NEW FORMAT ARGS
TLZ T4,1777
TLZ T1,776000
FLHTID::PUSHJ P,SSEUB## ;SAVE UBR
PUSHJ P,SAVE4## ;SAVE P1-P4
PUSH P,T3 ;SAVE DATAI WORD
PUSH P,T2 ;SAVE CONI WORD
PUSH P,T1 ;SAVE COMMUNICATION WORD
;SET UP P1 AS A GLOBAL IN FILINT MODULE = ADDRESS OF CHAN DATA BLOCK
MOVE P1,KDBCHN(J) ;SET UP P1=LOC OF CHAN DB
MOVE P2,T4 ;GET INTERRUPT BITS
SETZM P4 ;P4 WILL KEEP THE DRIVE NUMBER
DSKOFF ;PREVENT RACES
POSTST: JFFO P2,.+2 ;ANY MORE POSITIONS?
JRST POSDON ;NO, CLEAN UP TRANSFER
LSH P2,1(P3) ;YES. SET P2 FOR NEXT DRIVE TEST
ADDB P4,P3 ;COMPUTE THE DRIVE
SKIPN U,@KONPTR(J) ;SET U=UNIT BLOCK ADR
JRST FINPS3 ;NO UNIT BLOCK - IGNORE THE INTERRUPT
IFN FTDUAL,<
MOVE T1,UNICYL(U) ;IF THIS IS PART OF DUAL-PORT DRIVE
SKIPE T2,UNI2ND(U)
MOVEM T1,UNICYL(T2) ;THEN BOTH UNITS ARE ON SAME CYL
>
SETZM UNITIM(U)
SKIPE T1,UNISTS(U) ;GET STATE OF UNIT
CAIL T1,OWCOD ;OPERATOR WAIT?
JRST FREINT ;IDLE OR OPR WAIT
JUMPL T1,RECALH ;IF NEGATIVE WE'RE IN PHUNG RECOVERY
CAIN T1,TCOD ;IS UNIT IN TRANSFER STATE?
JRST RECALR ;YES - POSITIONING INT. FROM XFERRING DRIVE
JRST FINPS1 ;NO,
;HERE ON AN UNSOLICITED INTERRUPT, UNIT IDLE OR OPR WAIT
FREINT: SKIPG KONPOS(J) ;DOES UNIT DO POSITIONING?
STOPCD FINPS3,DEBUG,FDP, ;++FIXED-HEAD DEVICE POSITION
MOVSI T2,UNPUNO ;CLEAR 'OFF-LINE' AND FILE UNSAFE BITS
ANDCAM T2,UNIDES(U)
IFN FTDUAL,<
SKIPE T3,UNI2ND(U)
ANDCAM T2,UNIDES(T3)
>
CAIE T1,OW2COD
CAIN T1,OWCOD
STOPCD .,DEBUG,NOW, ;++NO OPR WAIT (OBSOLETE)
SKIPE DINITF## ;IF STILL IN ONCE-ONLY
JRST FINPS3 ; DON'T DO ANYTHING FANCY
IFN FTDUAL,<
HRRZ T1,(P) ;COMMUNICATION WORD
TRZE T1,IODTER+IODERR;IS AN ERROR UP?
CAIE T1,OPPOS ; AND JUST A POSITION COMPLETE?
JRST FREIN5 ;NO, "REAL" FREE INTERRUPT
LDB T1,[POINT 9,(P),17];YES, DID THIS DRIVE HAVE THE ERROR?
CAIN T1,(P4)
JRST FINPS3 ;YES, IT ISN'T THE INTERRUPT WE WANT
FREIN5: SKIPE T2,UNI2ND(U)
SKIPN UNILOG(T2)
>
SKIPE UNILOG(U) ;IS THIS PACK KNOWN TO THE SYSTEM?
JRST FREIN2 ;YES, REREAD HOME BLOCKS
IFN FTMDA,<
PUSHJ P,CALMDA ;NO, TELL MOUNTABLE DEVICE ALLOCATOR
JRST FREIN3 ;NOT RUNNING, CONTINUE
PUSHJ P,SET4MD ;SET SO ONLY MDA CAN READ DRIVE
AOJA P4,POSTST ;AND TEST NEXT DRIVE
>
IFE FTMDA,<
JRST FREIN3
>
;HERE IF PACK KNOWN TO SYSTEM
FREIN2: MOVSI T2,UNPRHB ;ALREADY GOTTEN AN INTERRUPT FROM DRIVE?
TDNN T2,UNIDES(U)
AOS HOMFLG## ;NO, COUNT UP NO OF HOMES TO READ
IORM T2,UNIDES(U) ;INDICATE THIS UNIT NEEDS REREADING
FREIN3: PUSHJ P,IDLEPW ;SET IDLE OR PW
AOJA P4,POSTST ;AND GO TEST NEXT UNIT
;HERE FOR POSITION INTERRUPT, DRIVE NOT IN S OR T STATE
FINPS1: TRNE T1,1 ;IS UNIT CURRENTLY IN A WAIT STATE?
JRST FREINT ;YES, FREE INTERRUPT
IFN FTCIDSK,<
PUSHJ P,CIBAD ;CI CAN'T GET HERE
>
PUSHJ P,SETF
JUMPE F,FINPS3 ;GO IF SPURIOUS INTERRUPT
MOVE S,DEVIOS(F)
TLNE S,IOSMON ;MONITOR OR SWAPPER IO?
AOSA UNIMSC(U) ;YES. COUNT 1 MORE MONITOR OR SWAP SEEK
AOS UNIUSC(U) ;NO. COUNT 1 MORE USER SEEK
IFN FTDUAL,<
PUSH P,U
>
CAIN T1,PCOD ;IF UNIT WAS IN POSITION,
PUSHJ P,SETTTW ;SET FILE TO TW, OR T AND START TRANSFER
IFN FTDUAL,<
POP P,U ;IF WE STARTED IO ON ALTERNATE UNIT
MOVE J,UDBKDB(U) ;THEN U, J AND P1 WERE CHANGED
MOVE P1,KDBCHN(J) ;SO RESET THEM
>
FINPS3: AOJA P4,POSTST ;GO TEST NEXT POSITION INTERRUPT
;HERE FOR POSITION INTERRUPT, DRIVE IN TRANSFER STATE
;THIS HAPPENS ON RECALIBRATE AFTER DATA ERROR
RECALR: PUSHJ P,SETF ;CURRENT DDB
JUMPE F,FINPS3 ;IGNORE IF SPURIOUS INTERRUPT
MOVE S,DEVIOS(F) ;S WORD (SO STARTE WILL KNOW IF READ OR WRITE)
SKIPGE DEVSWP##(F) ;IF THE SWAPPER
PUSHJ P,SWPINS## ;UMAKE SURE IO IS RIGHT
SKIPL T1,CHNECT(P1) ;RECALIBRATE INTERRUPT?
JRST RECAL1 ;NO - START DATA AGAIN
SETZM CHNECT(P1) ;YES - REPOSITION DRIVE
AOJN T1,RECAL1 ;IF CHNECT=-1,,0 OFFSET COMPLETED
RECALH: HRRZS UNISTS(U) ;CLEAR SIGN BIT (PHUNG RECOVERY)
PUSHJ P,@KONPOS(J) ;START POSITION
PUSHJ P,BADUNI ;DRIVE IS NOW DOWN
MOVEI T1,DSKTIM## ;RESET HUNG TIMER
MOVEM T1,UNITIM(U)
AOJA P4,POSTST ;GO HANDLE OTHER ATTENTION INTERRUPTS
RECAL1: PUSHJ P,STARTE ;START DATA TRANSFER
AOJA P4,POSTST ;AND TEST NEXT ATTENTION BIT
;CALLED BY KON ROUTINE WHEN A UNIT GOES OFF-LINE
;PRESERVES T1
FILDN:: MOVEI T2,O2COD ;IF IDLE SAY OFF-LINE, NO MESSAGE
IFN FTCIDSK,<
SKIPL KONMX(J) ;CAN UNIT DO MULTIPLE TRANSFERS?
>; END IFN FTCIDSK
SKIPN UNISTS(U) ; (IF BUSY HNGDSK WILL CATCH IT)
MOVEM T2,UNISTS(U) ; AND RETURN
IFE FTCIDSK,<
POPJ P,
>; END IFE FTCIDSK
IFN FTCIDSK,<
JFCL CPOPJ## ;NEUTERABLE CODE
SKIPL KONMX(J) ;CAN UNIT DO MULTIPLE TRANSFERS?
POPJ P, ;NO
PUSHJ P,SAVT## ;BE SUPERSTITIOUS
FILDN2: MOVEI T3,ACTDRB##-DRBLNK## ;GET PREDECESSOR
DSKOFF ;PREVENT RACES
FILDN3: HRRZ T3,DRBLNK##(T3) ;GET LINK TO NEXT DRB
CAIN T3,ACTDRB## ;AT END?
JRST DOPOPJ ;YES, RETURN
MOVE T1,DRBSTS##(T3) ;NOT FILLED IN?
TRNE T1,DRPNFI##+DRPTRY##
JRST FILDN3
HLRZ T1,DRBCUR##(T3) ;DRB FOR THIS UNIT?
CAIE T1,(U) ;...
JRST FILDN3 ;NO
DSKON ;WE'RE RACE FREE NOW
MOVEI T1,KOPOFL ;LIGHT ERROR FLAG
IORM T1,DRBSTS##(T3) ;...
MOVS T1,UDBPDN(U) ;FAKE UP THINGS FOR CALL TO FLHTID
SETZB T2,T4 ;NO UNITS HAVE POSITIONED
PUSH P,U ;SAVE U
PUSHJ P,FLHTID ;REQUEUE REQUESTS FOR THIS UNIT
POP P,U ;RESTORE U
JRST FILDN2 ;LOOP THROUGH UNTIL END
>; END IFN FTCIDSK
;SUBROUTINE TO SET THINGS UP SUCH THAT ONLY MDA CAN READ A UNIT
SET4MD: MOVEI T1,MDACOD
MOVEM T1,UNISTS(U) ;SET SO ONLY MDA CAN READ THE DRIVE
MOVSI T1,UNPWMD ;SET THAT UNIT IS WAITING FOR MDA
IORM T1,UNIDES(U) ; SO WILL GO BACK TO MDA WAIT AFTER A READ
IFE FTDUAL,<
POPJ P, ;AND RETURN
>
IFN FTDUAL,<
SKIPE T2,UNI2ND(U)
IORM T1,UNIDES(T2)
PJRST SECCOD
>
;SUBROUTINE TO PUT THE DRIVE POINTED TO BY U IN T OR TW
;P1= CHAN DATA BLOCK ADR.
;IF PUT THE DRIVE IN T1, START TRANSFERRING DATA
;UUOTWQ IS CALLED FROM UUO LEVEL
SETTTW: DSKOFF ;TURN ALL DISK PI'S OFF
HRRZ F,UNICDA(U) ;*SET F TO FILE
MOVE T1,UNIBLK(U) ;IN CASE OF SWAPPING ON 2 DF10'S
SKIPL DEVSWP##(F)
JRST UUOTWQ
MOVEM T1,DEVBLK##(F) ; DEVBLK MAY BE TIMESHARED
PUSHJ P,SWPCHK## ;CAN WE START IO NOW?
JRST SETTW0 ;NO, QUEUE TILL LATER
UUOTWQ: SKIPE DIADSK## ;SHUTTING DOWN IO
CAME P1,DIACHN## ; FOR THIS CHANNEL?
JRST UUOTWR ;NO
CONSO PI,PIPROG## ;YES, ON UUO LEVEL?
JRST SETTW0 ;YES, PUT REQUEST IN TW QUEUE
UUOTWR:
IFN FTCIDSK,<
SKIPGE KONMX(J) ;#IF MULTIPLE XFERS THEN
JRST UUOTWX ;#DON'T SET CHAN BUSY
>
SKIPL KONBMX(J) ;#IF BLOCK MUX KONTROLLER DON'T SET CHAN BUSY
AOSG @KDBCHN(J) ;#CHAN AVAILABLE?
UUOTWX:
IFN FTDUAL,<
JRST UUOTWS ;#YES, START IO
SKIPE T1,UNI2ND(U) ;#NO, IS THIS A DUAL-PORTED DRIVE?
SKIPE UNISTS(T1) ;#YES, IS THE 2ND DRIVE USEABLE?
JRST SETTW0 ;#NO, QUEUE THE REQUEST ON 1ST CHAN
MOVE T2,UDBKDB(T1) ;#YES, T1=UNIT T2=KON
IFN FTMP,<
MOVE T3,UDBCAM(T1) ;#IS OTHER PORT ON THIS CPU?
TDNN T3,.CPBIT##
JRST SETTW0 ;#NO, QUEUE REQUEST
>
SKIPL KONBSY(T2) ;KONTROLLER IDLE?
AOSE @KDBCHN(T2) ;#YES, CHAN IDLE?
JRST SETTW0 ;CANT START IT NOW
PUSHJ P,STORF ;SAVE DDB IN MAIN UDB
HRRZ J,T2 ;WE CAN START THE IO ON THE ALTERNATE UNIT
HRRZ U,T1 ; SO SET UP NEEDED ACS
MOVE P1,KDBCHN(J)
UUOTWS:
>;END OF IFN FTDUAL
PJRST SETBS1 ;#HAVE TO CHECK FOR WRITE/USETO RACE
SETTW0: MOVEI T1,TWCOD ;#TRANSFER WAIT STATE CODE
DPB T1,DEYCOD## ;MAKE DDB TW
SKIPL DEVSWP##(F) ;#IF THIS IS THE SWAPPER,
JRST SETTW1
PUSHJ P,IDLEPW ;#SET IDLE OR PW
SKIPN CHNCFS(P1) ;#DO AT LEAST ONE TRANSFER BEFORE
AOS CHNCFS(P1) ;# MOVING HEADS AGAIN
JRST DOPOPJ ;#DON'T PUT IN CHAN QUEUE (START IT AT SWPPIK ONLY)
SETTW1: CONSO PI,PI.IPA-PI.IP7 ;IF ON UUO LEVEL,
SKIPN UNISTS(U) ; DON'T CHANGE UNISTS IF NON-0
MOVEM T1,UNISTS(U) ;ELSE MAKE UNIT TW STATE
IFN FTDUAL,<
PUSHJ P,SECCOD ;#MAKE OTHER UNIT STATE = THIS ONE
>
MOVEI T1,CHNQUE(P1) ;#T1= QUEUE ON WHICH TO PUT FILE
IFN FTDUAL,<
REPEAT 0,< ;NOT NEEDED UNTIL WE GET A FIXED-HEAD DUAL-PORTED DRIVE
SKIPLE T2,UNI2ND(U) ;IF A MAIN-UNIT
SKIPN UNISTS(T2)
JRST PUTQUX ; WHICH HAS AN ALTERNATE UNIT
MOVE T1,UDBKDB(T2) ;IF THE ALTERNATE UNIT IS BUSY THE REQUEST
MOVE T1,KDBCHN(T1)
MOVEI T1,CHNQUE(T1) ; SHOULD BE PUT ON THE ALTERNATE CHAN QUEUE
> ;END REPEAT 0
> ;END FTDUAL
;AND FALL INTO PUTQUX
;SUBROUTINE TO ENTER A FILE IN A QUEUE
; PUTQUX FOR CHANNEL (XFER WAIT) QUEUES
; P1=ADDR. CHAN. DATA BLOCK
; PUTQUE FOR UNIT (POSITION WAIT) QUEUES
; U=ADDR. UNIT DATA BLOCK
;C(T1)=LOC OF QUEUE POINTER F POINTS TO FILE
;LH OF QUEUE POINTER CONTAINS FIRST FILE (DDB) ADR., RH=0
;THESE ARE REALLY LISTS NOT QUEUES, SINCE ARE REMOVED IN RANDOM ORDER
PUTQUX: AOSA CHNQUL(P1) ; INCREMENT XFER QUEUE LENGTH
PUTQUE: AOS UNIQUL(U)
LDB T2,PJOBN## ;JOB NUMBER
HRL T2,F ;DDB
EXCH T2,(T1) ;MAKE THIS DDB FIRST, GET CURRENT FIRST
MOVEM T2,DEVQUE##(F) ;POINT THIS DDB AT FORMER FIRST
IFN FTDUAL,<
HRRM U,DEVCUR##(F) ;#SAVE CURRENT UNIT IN DDB
>
DSKON ;#TURN ALL DISK PI'S BACK ON
SCHEDULE
POPJ P, ;AND RETURN
;SUBROUTINE TO COMPUTE PRIORITY OF A DISK FILE
;EXIT WITH T2=PRIORITY. RESPECTS ALL ACS EXCEPT T2
DFPRI: LDB T2,DEYPRI## ;INDEX=
TRZE T2,MINDPR ;PRIORITY NEGATIVE?
MOVNS T2 ;YES, MAKE T2 NEGATIVE
POPJ P, ;AND RETURN
;ROUTINE TO CHECK THAT JOB IS IN CORE (POSSIBLY AN INTERRUPT LEVEL)
ADRINT: LDB T1,PJOBN## ;JOB NUMBER
SKIPN JBTADR##(T1) ;GET ADDRESS
SKIPGE DEVSWP##(F) ;NONE - SWAPPER
POPJ P, ;JOB IN CORE OR SWAPPER
SKIPE DEVRHB##(F) ;REREADING HOME BLOCKS?
SKIPE DINITF## ;NOTHING - ONCE CODE?
POPJ P, ;YES, OK RETURN
STOPCD CPOPJ##,DEBUG,JNC, ;++JOB NOT IN CORE
;SUBROUTINE TO START IO ON FILE POINTED TO BY F
;P1= CHAN. DATA BLOCK ADR.
;ALSO CALLED AT UUO LEVEL
STRTIO::
IFN FTDUAL,<
HRRM U,DEVCUR##(F) ;#SAVE CURRENT UNIT IN DDB
>
SKIPL KONDRB(J) ;#NEED AN IORB?
JRST STRTI9 ;#NO
PUSHJ P,GETDRB ;#YES, ALLOCATE ONE
POPJ P, ;#NONE LEFT
MOVEM T1,DEVDRB##(F) ;#SAVE ADDR OF IORB
IFN FTCIDSK,<
SKIPL KONMX(J) ;#MULTI XFERS?
JRST STRTIA ;#NO
MOVEI T1,TCOD ;#SET DDB TO TRANSFER
DPB T1,DEYCOD##
JRST STRTI8 ;#DON'T SET UNISTS
>; END IFN FTCIDSK
IFE FTCIDSK,<
JRST STRTIA ;#DON'T CLEAR DEVDRB
>; END IFE FTCISK
STRTI9: SKIPL DEVSWP##(F)
SETZM DEVDRB##(F) ;#NO IORB
STRTIA: MOVSI T1,KOPBSY ;#SET KONTROL BUSY
SKIPL KONBMX(J) ;#UNLESS BLOCK MULTIPLEX KONTROLLER
IORM T1,KONBSY(J)
MOVEI T1,TCOD ;#SET FILE AND UNIT TO TCOD
PUSHJ P,FILCOD
IFN FTDUAL,<
PUSHJ P,SECCOD ;#MAKE OTHER UNIT STATE = THIS ONE
>
STRTI8: PUSHJ P,SETPAR ;#SET KONCUA,UNICDA,UNIBLK
PUSHJ P,DRSAVE ;#SAVE VOLATILE STUFF IN IORB
DSKON ;#TURN ALL DISK PI'S BACK ON
SCHEDULE
MOVE S,DEVIOS(F) ;S WORD
PUSHJ P,ADRINT ;SET UP R FROM JBTADR
PUSHJ P,SETLST ;SET UP IOLST, NUMBER OF BLOCKS
IFN FTKS10,<
TLNN S,IO ;SINCE KS HAS WRITE-THRU CACHE, NO NEED TO-
>
PUSHJ P,CFDMP ;INVALIDATE CACHE, VALIDATE MEMORY
SETZM CHNECT(P1) ;ZERO ERROR COUNT LOC
SETZM CHNRCT(P1) ;ZERO RECALIBRATE-COUNT
SETZM UNIRCV(U) ;ZERO HUNG UNIT RETRY-COUNTER
MOVSI T1,UNPFIR ;SET SIGN BIT IN UNIECT
IORM T1,UNIECT(U) ; TO INDICATE NO ERRORS YET
MOVSI T1,UNPHNG!UNPECC ;CLEAR THE HUNG AND ECC BITS TO INSURE WE
ANDCAM T1,UNIECT(U) ; DON'T REPORT INFINITE HANGS OR THINK AN
; ECC-CORRECTABLE ERROR WAS SEEN DURING RETRY
JUMPL S,STARTE ;NO CHECKSUMS IF MONITOR IO
TLNE S,IO ;DATA - READING?
TLZN S,IOSFIR ;WRITING DATA - CHECKSUM TIME?
JRST STARTE ;NO
PUSHJ P,STORS7## ;YES, SAVE S IN DDB
PUSHJ P,CHKSUM ;COMPUTE CHECKSUM
HRRZ T2,DEVCPY##(F)
JUMPE T2,STRTI1 ;GO IF NO IN-CORE COPY
HRRZ T3,DEVRET##(F) ;HAS AN IN-CORE COPY, COMPUTE
SUBI T3,DEVRB1##(F) ; RELATIVE LOCATION OF CURRENT POINTER
SKIPN @DEVRET##(F) ;SINCE THE CHECKSUM MIGHT HAVE
SETZ T3, ; HAVE CHANGED FROM ANOTHER WRITER,AND THE
ADDI T3,PTRDAT##(T2) ; DDB-COPY WASN'T CHANGED, WE NEED TO LOOK AT
MOVE T2,(T3) ; THE IN-CORE COPY FOR THE REAL THING
JRST STRTI2
STRTI1: SKIPN T2,@DEVRET##(F) ;GET RETRIEVAL PNTR
MOVE T2,DEVRB1##(F) ;JUST 1 PNTR IN DDB, STORED IN DEVRB1
STRTI2: HRRZ T3,UNISTR(U) ;LOC OF STR DB
MOVE T4,T2 ;SAVE OLD POINTER
DPB T1,STYCKP##(T3) ;SAVE CHKSUM IN PNTR
CAMN T4,T2 ;DID CHECKSUM CHANGE?
JRST STARTE ;NO, CRANK UP THE IO
PUSHJ P,PTSTOX ;SAVE POINTER BACK OVER OLD (DEVRB1 OR @DEVRET)
HRRZ T1,DEVACC##(F) ;ACCESS TABLE
MOVE T3,DEVREL##(F) ;RELATIVE BLOCK OF FILE
SOJN T3,STRTI3 ;IF 1ST BLOCK,
MOVEM T2,ACCPT1##(T1) ; SO ANOTHER JOB CAN READ THIS FILE (UPDATE)
STRTI3: MOVE T3,ACCSTS##(T1) ;FILE STATUS
TRNN T3,ACPUPD ;FILE BEING UPDATED?
JRST STARTE ;NO
MOVEI T4,ACPSBC## ; SO DDBS WHICH HAVE POINTER IN CORE ALREADY
IORM T4,ACCSBC##(T1) ; WON'T GET SPURIOUS CHECKSUM ERRORS
PUSHJ P,RBCHD ;RIB HAS CHANGED
;MIGHT GET A WRONG CHECKSUM INTO THE RIB OF A SIM-UPDATE FILE IF WE
; LEAVE A BAD CHECKSUM IN SOME OTHER DDB, SO FIND ALL WRITERS OF THE FILE
; AND CHANGE THE CHKSUMS IN THEIR IN-CORE COPIES
MOVE T1,DEVACC##(F)
LDB T3,ACYWCT## ;IF WE'RE THE ONLY WRITER,
SOJLE T3,STARTE ; FORGET IT
PUSHJ P,.+2 ;SO CAN CALL SAVE3 WITHOUT PDL OV
JRST STARTE ;NO GO START THE IO
PUSHJ P,SAVE3##
MOVE P1,T2 ;P1 = NEW POINTER
LDB P3,UNYLUN##
TRO P3,RIPNUB## ;P3 = NEEDED UNIT-CHANGE PTR
HRRZ T3,UNISTR(U) ;SET UP A MASK FOR PNTR ADDRESSES
SETO T2,
LDB P2,STYCLP##(T3)
PUSHJ P,FNDDDB ;FIND A WRITING DDB
POPJ P, ;NONE THERE (SYSTEM ERROR?)
;FALL INTO STRTI4
;HERE WHEN WE FOUND A WRITING DDB
STRTI4: HLRZ T1,PTRFUN##(T2) ;GET 1ST UNIT IN FOUND DDB
LDB T4,UNYLN1## ;FAKE UP A UNIT CHANGE POINTER
TRO T4,RIPNUB## ; FOR THIS WRITING DDB
;HERE WHEN WE FOUND A WRITING DDB
MOVEI T1,PTRDAT##(T2) ;SET A POINTER FOR THE
HRLI T1,MPTRLN## ;RETRIEVAL PNTRS OF FOUND DDB
STRTI5: SKIPN T3,(T1) ;GET A RET PNTR FROM THE DDB
JRST STRTI6
TLNN T3,-1 ;UNIT-CHANGE?
MOVE T4,T3 ;YES
XOR T3,P1 ;DOES IT MATCH NEW PNTR?
CAMN T4,P3 ;RIGHT UNIT?
TDNE T3,P2
JRST STRTI6 ;NO, TRY NEXT PNTR
MOVEM P1,(T1) ;IN THE FOUND DDB
JRST STRTI7 ;AND TEST FOR ANOTHER WRITER
STRTI6: AOBJN T1,STRTI5 ;TES NEXT PNTR IN FOUND DDB
STRTI7: HRRZ T1,DEVACC##(F) ;RESET T1 FOR FNDDDN
PUSHJ P,FNDDDN ;LOOK FOR ANOTHER WRITER
POPJ P, ;NONE THERE, DONE
JRST STRTI4 ;FOUND ONE, LOOK FOR PNTR IN THIS DDB
STARTE: MOVE T1,DEVDRB##(F) ;GET DRB
;HERE WITH T1=DRB
STARTG: MOVEI T3,KONRDS(J) ;SET TO READ - STOP ON ERROR FOR F.S.
; ALL BUT LAST TRY SO KNOW BAD BLOCK+WORD
TLNE S,IO
MOVEI T3,KONWTS(J) ; WRITE DATA - STOP ON ERROR FOR F.S.
; ALL BUT LAST TRY SO KNOW BAD BLOCK+WORD
TLNN S,IOSUPR ;SUPER I/O MODE?
JRST STARTF ;NO, START THE IO
TRNE S,UDSX ;YES, READ/WRITE HEADERS AND DATA?
AOJA T3,STARTF ;YES, RDF/WTF = RDS/WTS +1
MOVSI T2,DEPCPT## ;NO, COMPATABILITY MODE?
TDNE T2,DEVCPT##(F)
ADDI T3,KONRDC-KONRDS ;YES, ENTRY POINT = RDS(WTS)+2
STARTF: PUSHJ P,STORS7## ;STORE S
DSKOFF ;MAKE SURE NO INTERRUPTS HAPPEN
PUSHJ P,DRRST ;#RESTORE VOLATILE STUFF
IFN FTCIDSK,<
MOVEI T2,4*DSKTIM## ;#SET HUNG TIMER
SKIPE T1 ;#NOT IF THERE ISN'T A DRB
MOVEM T2,DRBTIM##(T1)
>; END IFN FTCIDSK
PUSH P,T1 ;#SAVE DRB
MOVEI T2,DSKTIM## ;RESET HUNG TIMER
MOVEM T2,UNITIM(U)
PUSHJ P,@(T3) ;#START READ OR WRITE
JRST BADUNC ;#UNIT NOT OK
POP P,T1 ;#PRUNE STACK
MOVS T2,UNIECT(U)
CAIE T2,UNPFIR+UNPHNG ;BUSY ON WHEN WE STARTED
PJRST DOPOPJ
PUSHJ P,FSTREG ;YES, COPY REGS TO UDB
MOVEI T1,.FIBOS ;FILIO-DETECTED "BUSY ON WHEN STARTED"
PUSHJ P,FILELG ;TELL DAEMON
MOVE J,UDBKDB(U)
PJRST DOPOPJ
;ROUTINE TO SET THE UNIT EITHER IDLE OR POSITION WAIT
;DEPENDING ON THE VALUE OF UNIQUE
;CLOBBERS T1 AND T2
IDLEPW::
IFN FTDUAL,<
SKIPE T1,UNI2ND(U) ;#POSITIONS WAITING ON EITHER PORT?
SKIPN UNIQUE(T1)
>
SKIPE T1,UNIQUE(U)
MOVEI T1,PWCOD ;#YES, SET TO PW
MOVEM T1,UNISTS(U) ;#NO, SET IDLE
IFN FTDUAL,<
PUSHJ P,SECCOD ;#SET BOTH PORTS
>
POPJ P,
;SUBROUTINE TO SET STATE OF FILE,UNIT TO C(T1)
;THIS ROUTINE RESPECTS AC T1
FILCOD: DPB T1,DEYCOD## ;#SET STATE OF FILE
MOVEM T1,UNISTS(U) ;#SET STATE OF UNIT
POPJ P, ;#AND RETURN
;HERE TO STORE THE STATUS IN BOTH PORTS
;T1 PASSES THE STATUS
BTHSTS::MOVEM T1,UNISTS(U) ;PRIME PORT
IFN FTDUAL,<
;ROUTINE TO SET 2ND UNIT'S STATE CODE = THIS UNIT'S
SECCOD::MOVSI T1,U2PPGA ;2ND PORT DISAPPEAR FROM UNDER US?
TDNN T1,UNIDS2(U) ; IF SO LEAVE 2ND PORT UNISTS ALONE
SKIPN T1,UNI2ND(U) ;IS THIS AN ALTERNATE UNIT?
POPJ P, ;NO
MOVE T2,UNISTS(U) ;YES, GET STATE WORD OF UNIT
MOVEM T2,UNISTS(T1) ;AND SAVE IN UDB FOR PRIME UNIT
>
POPJ P, ;AND RETURN
;SUBROUTINE TO CALL WHEN RIB HAS CHANGED
;SETS BIT IN DDB, CALLS PSISER IF ENABLED
;PRESERVES ALL ACS EXCEPT T1
RBCHD: MOVSI T1,DEPRHC## ;INDICATE RIB HAS CHANGED
IORM T1,DEVRRC##(F)
MOVEI T1,IR.RHC ;SIGNAL-BIT FOR PSISER
TSNE T1,DEVPSI(F) ;DOES HE WANT THE PSI?
PJRST PSIDVB## ;YES, LET PSISER TELL HIM
POPJ P,
;SUBROUTINE TO SET UP AN IOLIST BLOCK
;ENTER WITH J,U,F AND S SET UP
;P1=CHAN.DATA BLOCK ADR.
;ALSO CALLED AT UUO LEVEL
;RETURNS WITH THE LIST IN CORE, POINTED TO BY @KDBICP(J)
SETLST: PUSHJ P,NXTBLK ;GET NEXT BLOCK OF FILE
STOPCD .,JOB,BWA, ;++BLOCK WENT AWAY
PUSHJ P,SAVE4## ;YES, SAVE P1-P4
HRROI P3,(P1) ;TELL MAPIO TO STORE EXPECTED TERM WD
SETZB P1,P2 ;P1=FREE CORE LOC
PUSH P,U ;SAVE U
PUSH P,W
PUSH P,R
MOVE T2,DEVBLK##(F) ;BLOCK TO START AT
HRRZ T1,UNIBPY(U) ;NUMBER OF BLOCKS PER CYLINDER
IDIVI T2,(T1) ;T3=RELATIVE BLOCK IN CYL
SUBI T1,(T3) ;T1=DISTANCE TO END OF CYLINDER
CAMLE T1,MAXTRN## ;GTR THAN THE MAX NUMBER OF BLOCKS ALLOWED?
MOVE T1,MAXTRN## ;YES, REDUCE COUNT (SO HIGH PRIORITY REQUESTS
; WONT GET LOCKED OUT TOO LONG)
IFN FTCIDSK,<
LDB T3,UNYKTP## ;GET KONTROLLER TYPE
CAIN T3,TYPRA ;IS IT AN HSC CONTROLLER?
MOVEI T1,^D50 ;YES, LIMIT MAXIMUM TRANSFER SIZE TO APPROX.
; ONE-FOURTH OF TOTAL NUMBER OF BSDS IN KLPSER
>; END IFN FTCIDSK
HRRZ T3,DEVLFT##(F) ;NO OF BLOCKS LEFT IN CURRENT GROUP
IFN FTKL10,<
MOVE T2,CHNTYP(P3)
TLNE T2,CP.RH2 ;RH20?
CAIG T1,1777 ;YES. MAX TRANSFER=1777 BLOCKS
CAIA ; (10 BITS IN PTCR)
MOVEI T1,1777 ;TOO BIG, REDUCE IT
>
SKIPL S ;ASSUME ALL BLOCKS TO EOL OK IF MON MODE
CAMLE T3,T1 ;MORE THAN TO END OF CYLINDER?
MOVE T3,T1 ;YES, REDUCE COUNT
TLNE S,IO+IOSUPR+IOSMON ;READING DATA?
JRST SETLS1 ;NO. USE ALL OF GROUP
MOVE T2,DEVACC##(F) ;YES. GET LOC OF A.T.
MOVE T2,ACCWRT##(T2) ;NO OF DATA BLOCKS IN FILE
SUB T2,DEVREL##(F) ;NO OF DATA BLOCKS LEFT (FROM CURRENT POSITION)
CAIGE T2,-1(T3) ;MORE IN GROUP THAN HAVE DATA?
MOVEI T3,1(T2) ;YES, ONLY READ BLOCKS WITH DATA
SETLS1: JUMPL S,SETDMP ;SAME AS DUMP IF MONITOR MODE
LDB T1,PIOMOD##
CAIL T1,SD ;NO, DUMP MODE?
JRST SETDMP ;YES
TLNE S,IO ;READING?
SKIPA T2,DEVOAD(F) ;NO
MOVE T2,DEVIAD(F) ;YES
HRRZS T2 ;ZERO LEFT HALF STUFF
EXCTUX <HLRZ T2,(T2)> ;GET BUFFER LENGTH
TRZ T2,400177 ;CLEAR EXTRANEOUS BITS
SKIPE T2
CAILE T2,LIMBBW## ;BUFFER TOO LARGE?
SETZ T3, ;YES, DON'T DO ANYTHING
HRLZ W,T2 ;SAVE BUFFER SIZE IN LH(W)
MOVN U,W ;WILL USE FOR PROTECTION CHECK
LSH T2,MBKLSH## ;COMPUTE NO OF BLOCKS PER BUFFER
HRR W,T2 ;W=WDS/BUF,,BLOCKS/BUF
DPB T2,DEYNBB## ;SAVE FOR BUFAD
IFN FTKL10&FTMP,<
TLNN S,IO ;IF READING
JRST SETLS2 ; DO AS MUCH AS POSSIBLE
PUSHJ P,CHKNB##
HLRZ T1,DEVNBF(F) ;NO OF BUFS SWEPT FOR
IMULI T1,(W)
TLNN S,IOSPBF ;PARTIAL BUFFER?
JRST SETLS0 ;NO
HRRZ T2,DEVOAD(F) ;YES, GET NUMBER BLOCKS SO FAR
EXCTUX <HLRZ T2,1(T2)>
LSH T2,MBKLSH
CAIL T2,(W) ;PARANOIA
SETZB T3,T2
SUB T1,T2 ;DON'T COUNT THESE BLOCKS
SETLS0: CAMLE T3,T1 ;DONT LOOK AT BUFFERS WHICH
MOVE T3,T1 ; HAVENT BEEN SWEPT BACK TO MEMORY
SETLS2:>
;FALL INTO NEXT PAGE
HRLZ T1,T3 ;BUFFERRED MODE. NUMBER OF BLOCKS LEFT IN GROUP
MOVNS T1 ;SET FOR AOBJN POINTER
TLNN S,IO ;READING?
SKIPA T2,DEVIAD(F) ;YES. USE DEVIAD
MOVE T2,DEVOAD(F) ;WRITING, USE DEVOAD
HLL T2,U
LDB T3,PJOBN## ;JOB NUMBER
ADD U,JBTADR##(T3) ;SET U TO USERS PROTECTION - BUFFER SIZE
HLRZS U ;IN RH FOR PROTECTION CHECK
MOVEI T3,1(T2) ;STARTING BUFFER LOC
HRLM T3,DEVUVA##(F) ;SAVE UVA-1 OF CHKSUM WORD
SUBI T3,1
SETZB T4,R ;T4 COUNTS NUMBER OF BUFFERS, R USED IN PARTIALS
DPB T4,DEYNB1## ;ASSUME WE START AT 1ST WORD IN BUFFER
JUMPE T1,SETLS9 ;GET OUT QUICKLY IF BUFFERS ARE TOO LARGE
SETLS3: PUSH P,T1 ;SAVE AOBJN POINTER
HRRZ T1,T2
PUSHJ P,IADRCK## ;BUFFER LEAGAL?
JFCL ;NO, UUOCON CAN GIVE ADDRESS CHECK
JRST [POP P,T1 ;PAGED OUT, LET UUOCON BRING IT IN
JRST SETLS9]
POP P,T1 ;RESTORE T1
PUSHJ P,TSTBUF ;MAKE SURE ENTIRE BUFFER IS IN CORE
JRST SETLS9 ;PAGE FAILURE WILL OCCURR, TERMINATE THE IO LIST
TLNN S,IO
JRST SETLS4
EXCTUX <SKIPL (T2)> ;WRITING - IS NEXT BUFFER FULL?
JRST SETLS8 ;NO, DONE
JRST SETLS5 ;YES. SET IOWORD FOR BUFFER
SETLS4:
IFE FTKL10&FTMP,<
EXCTUX <SKIPG (T2)> ;READING - IS NEXT BUFFER FREE?
JRST SETLS8 ;NO. DONE
>
IFN FTKL10&FTMP,<
EXCTUX <SKIPL (T2)> ;IS NEXT BUFFER FREE?
PUSHJ P,[PUSHJ P,SAVT## ;AND OK WITH RESPECT TO CACHE?
HRRZ T1,T2
PJRST BUFSSN##]
JRST SETLS8 ;NO DON'T DO ANY MORE BUFFERS
>
SETLS5: ADDI T2,1 ;INCREMENT BY 1 FOR WORDCOUNT WORD
HRRZ P4,W ;BLOCKS PER BUFFER
TLZN S,IOSPBF ;PARTIAL BUFFER WE STARTED BEFORE?
JRST SETLS6 ;NO
EXCTUX <HRLZ R,(T2)> ;YES, GET PARTIAL WORDCOUNT
TLNE S,IO ;IF WRITING,
EXCTUX <HLLZ R,(T2)> ; GET PARTIAL WORDCOUNT ALREADY DONE
TLNE S,IOSFIR ;CHECKSUM BLOCK?
ADDM R,DEVUVA##(F) ;YES, POINT AT 1ST WORD OF THIS BLOCK
LSH R,-^D18-BLKLSH##;CONVERT TO BLOCKS ALREADY DONE
SUB P4,R ;ADJUST NO OF BLOCKS TO DO BY PART ALREADY DONE
DPB R,DEYNB1## ;SAVE STARTING BLOCK OF THE BUFFER
LSH R,BLKLSH## ;NO OF WORDS TO DO IN THIS BUFFER
HRLS R
ADD T2,R ;ADJUST IOWD FOR PART ALREADY DONE
SETLS6: HRLS P4 ;BLOCKS DONE IN BOTH HALVES
ADDB T1,P4 ;COMPUTE NO BLOCKS LEFT,,NO DONE
JUMPL T1,SETLS7 ;GO IF WE CAN DO THE ENTIRE BUFFER
TLNN T1,-1 ;EXACT FIT?
JRST SETLS7 ;YES, CAN DO THE WHOLE BUFFER
HLRS P4 ;NO OF BLOCKS WE CAN'T DO IN BOTH HALVES
SUB T1,P4 ;MAKE T1=0,,NO WE'RE DOING
HLLZS P4 ;LH
LSH P4,BLKLSH## ;NO OF WORDS WE CAN'T DO
ADD T2,P4 ;ADJUST IOWD BY THAT AMOUNT
SUB W,P4 ;NO OF WORDS WE WILL DO IN LH(W)
ADD T4,[1,,0] ;ACCOUNT FOR SUB A LITTLE LATER
TLO S,IOSPBF ;INDICATE A PARTIAL BUFFER
SETLS7: MOVEI P4,0 ;NO FRAME-COUNT
IFN FTXMON,<DPB P4,DEYISN##> ;NO CARRY BETWEEN SECTIONS FOR BUFFERED MODE
PUSHJ P,MAPIO## ; STORE THE IOWD IN FREE-CORE
JRST PUNTB ;NOT ENOUGH MONITOR FREE-CORE
SUB T2,R ;RESET T2 FOR A WHOLE BUFFER IF ENDING A PARTIAL
TLNN S,IO ;IF READING
EXCTXU <HLRZM W,(T2)> ; SAVE WDCNT IN BUFFER WORD 0
TLNE S,IO ;IF WRITING
EXCTUU <HLLM W,(T2)> ; SAVE AMOUNT DONE SO FAR IN LH OF WORD 0
SUB T4,[1,,0] ;COUNT A BUFFER
IFN FTKS10,<
SETZ R, ;NOT ENDING A PARTIAL NOW
JRST SETLS9 ;ONE BLOCK AT A TIME FOR KS10
>
PUSH P,T1
MOVEI T1,-1(T2) ;WHAT TO OUCHE
EXCTUX <HRR T2,-1(T2)> ;STEP TO NEXT BUFFER
JUMPN R,[SETZ R, ;NOT ENDING A PARTIAL NOW
IFN FTKL10&FTMP,<
PUSHJ P,OUCHE## ;GET OUT OF CACHE SINCE WON'T BE IN IOWD LIST
ADDI T1,1 ;POINT AT NEXT WORD
TRNN T1,3 ;IN THE SAME CACHE LINE?
PUSHJ P,OUCHE## ;NO, GET IT OUT OF THE CACHE AS WELL
>
JRST .+1] ;AND CONTINUE
POP P,T1 ;RESTORE T1
CAIE T3,(T2) ;BACK TO THE BUFFER WE STARTED AT?
TRNE S,IOCON ;OR DISCONTINUOUS MODE?
JRST SETLS9 ;YES, IOWDS ARE ALL SET
JUMPL T1,SETLS3 ;DO ANOTHER IF STILL HAVE BLOCKS AVAILABLE
;ALL SET, FALL INTO SETLS9
;HERE WHEN THE IOLIST IS COMPLETELY SET UP
SETLS8:
IFN FTKL10&FTMP,<
EXCH T1,T2 ;WE'VE TOUCHED THE T2-BUFFER,
PUSHJ P,OUCHE## ; WONT GET IT OUT OF CACHE BELOW,
MOVE T1,T2 ; SO REMOVE IT FROM CACHE NOW
>
SETLS9:
IFN FTKL10&FTMP,<
LDB T3,PIOMOD
TLNE S,IO ;IF WRITING
CAIL T3,SD ;IN NON-DUMP MODE
JRST SETL10
ADDM T4,DEVNBF(F) ;UPDATE DEVNBF BY NO OF BUFFERS WE'RE ABOUT TO DO
>
SETL10: MOVEM T2,KONCNT(J) ;SAVE ACTUAL WRDCNT IF DUMP-MODE
HRRZS P2 ;JUST ADDRESS (DF10-STYLE JUMP)
IFN FTKL10,<
JUMPE P2,SETL11 ;ALL ZERO IF NO IOWDS
MOVE T2,CHNTYP(P3) ;RH20?
TLNE T2,CP.RH2
TLO P2,(INSVL.(.CCJMP,CC.OPC)) ;YES, MAKE IT THAT FLAVOR OF JUMP
>
SETL11:
IFE FTKS10,<
SKIPGE KONDRB(J) ;HAVE A DRB?
SKIPN T2,DEVDRB##(F) ;MAYBE, DO WE?
SKIPA T2,KDBICP(J) ;NO, PUT IN KDB
ADDI T2,DRBPRG## ;YES, PUT IN DRB
MOVEM P2,(T2) ;STORE ICCW
>
SKIPGE DEVSWP##(F) ;SWAPPER?
JRST SETL12 ;YES, THIS ALREADY FIXED THINGS
IFN FTKL10,<
TLNE P2,-1 ;RH20?
PUSHJ P,RH2ND## ;YES, FINISH THE LIST
>
SKIPE DINITF## ;IN ONCE-ONLY?
JRST SETL12 ;YES, ONLY COUNT DURING TIMESHARING
HRRZS T1
TLNN S,IO
ADDM T1,.CPFBI## ;UPDATE TOTAL FILE BLOCKS TRANSFERRED
TLNE S,IO
ADDM T1,.CPFBO##
SETL12: MOVE P1,P3 ;RESET CHN ADDRESS
SKIPGE KONDRB(J) ;HAVE A DRB?
SKIPN T2,DEVDRB##(F) ;MAYBE, DO WE?
MOVEI T2,CHNNUM-DRBNUM##(P1) ;NO, PUT IN CHN
HRRZM T1,DRBNUM##(T2) ;YES, PUT IN DRB
POP P,R
POP P,W
IFN FTKL10&FTMP,<
JUMPE P2,UPOPJ## ;DONE IF NO LIST
SETL15: SKIPN T1,(P2) ;GET NEXT IOWD
JRST UPOPJ## ;DONE IF 0
TLNN T1,577777 ;IS IT A GOTO?
JRST [HRR P2,T1 ;YES, POINT AT WHERE IT GOES
JRST SETL15] ;AND GO TEST THAT IOWD
TLNN P2,-1 ;POINT T1 AT 1ST DATA LOC -2
SOSA T1 ; (POINTER TO NEXT BUFFER)
SUBI T1,2 ;GET THAT LOC OUT OF THE CACHE
PUSHJ P,OUCHE## ;SINCE WE WONT SWEEP WE MUST CLEAR VALID BIT
ADDI T1,1 ;POINT AT WORDCOUNT WORD
TRNN T1,3 ;IN SAME LINE AS POINTER?
PUSHJ P,OUCHE## ;NO, GET RID OF THAT LINE TOO
AOJA P2,SETL15 ; FOR THAT CACHE LINE
>
IFE FTKL10&FTMP,<
JRST UPOPJ## ;EASY IF THERE ISN'T A CACHE TO CLEAR
>
;SUBROUTINE TO TEST IF THE ENTIRE BUFFER IS IN CORE
;RETURNS CPOPJ IF NOT, CPOPJ1 IF ALL IN CORE
;PRESERVES ALL ACS
TSTBUF: PUSHJ P,SAVT## ;SAVE ACS
MOVEI T1,-1(T2) ;START OF BUFFER
HLR T3,W ;SIZE OF BUFFER
ADDI T2,1(T3) ;TOP OF BUFFER
TRO T1,PG.BDY-1 ;TOP OF PAGE
TSTBU1: PUSHJ P,FLTST## ;PAGE THERE?
POPJ P, ;NO, NON-SKIP RETURN
PUSHJ P,CHKWLP## ;ALSO MAKE SURE ITS WRITE ENABLED
CAIL T1,(T2) ;PAST TOP OF BUFFER?
JRST CPOPJ1##
ADDI T1,PAGSIZ ;NO, STEP TO NEXT PAGE
JRST TSTBU1 ;ENSURE THIS PAGE IS THERE TOO
;HERE TO SET UP A DUMP-MODE LIST
;ASSUMES THE CURRENT IOWD (RELOCATED) IS IN DEVDMP(F)
;UPDATES DEVDMP(F) BY NUMBER OF WORDS TRANSFERRED
;IF THE IOWD IS FINISHED, DEVDMP WILL BE POSITIVE
SETDMP: SKIPGE DEVSWP##(F) ;IS IT THE SWAPPER?
JRST SETSWP ;YES, DO IT DIFFERENTLY
HLLZ T1,DEVDMP##(F) ;NUMBER OF WORDS IN IOWD
MOVNS T1 ;+N
HRLZ T2,T3 ;NUMBER OF BLOCKS LEFT IN GROUP
LSH T1,MBKLSH## ;NUMBER OF BLOCKS IN IOWD
JUMPE T2,SETDM1 ;0 IS OK
TDC S,[IOSUPR,,UDSX]
TDCN S,[IOSUPR,,UDSX] ;FORMATTING?
JRST SETDM1 ;YES, ASSUME HE REALLY KNOWS
CAMLE T1,T2 ;MORE REQUESTED THAN IN GROUP?
MOVE T1,T2 ;YES, TAKE LESSER AMOUNT
SETDM1: LSH T1,BLKLSH## ;CONVERT BACK TO WORDS
MOVNM T1,T3 ;SAVE N
MOVE T2,DEVDMP##(F) ;CURRENT IOWD
SKIPGE KONDRB(J) ;HAVE A DRB?
SKIPN P4,DEVDRB##(F) ;MAYBE, DO WE?
MOVEI P4,KONDMP-DRBDMP##(J) ;NO, PUT IT KDB
SKIPN DINITF## ;IF NOT IN ONCE-ONLY,
MOVEM T2,DRBDMP##(P4) ;SAVE IOWD IN KDB
HLL T2,T3 ;SET LH OF IOWD
MOVEI P4,0 ;NO FRAME COUNT
PUSHJ P,MAPIO## ;SAVE THE IOWD IN FREE-CORE
JRST PUNTD ;NOT ENOUGH FREE CORE
SETDM2: JUMPL S,SETDM3 ;GO IF MONITOR MODE
ADDM T1,DEVDMP##(F) ;UPDATE WDCNT
HLRZ T2,T1
ADD T2,DEVDMP##(F) ;UPDATE ADDRESS
HRRM T2,DEVDMP##(F) ; (DON'T PROPOGATE CARRY)
TLNE T1,BLKSIZ##-1 ;EVEN NUMBER OF WRDS FOR BLOCK?
TLNN S,IO ;NO. WRITING?
JRST SETDM3 ;NO. OK
LDB T2,UNYKTP## ;TYPE OF KONTROLLER
CAIE T2,TYPDP ;DOES KONTROL ZERO-FILL TO END OF BLOCK?
CAIN T2,TYPRP ;...
JRST SETDM3 ;YES
IFN FTCIDSK,<
CAIE T2,TYPRA ;...
>; END IFN FTCIDSK
CAIN T2,TYPRN ;...
JRST SETDM3 ;YES
;*** I BELIEVE THERE IS A PROBLEM WITH USING THE MONITOR BUFFER HERE.
;*** IT LOOKS LIKE THE CLOSE CODE MIGHT EXPECT THE RIB TO STAY IN THE
;*** MONITOR BUFFER EVEN THOUGH IOSRIB ISN'T LIT. STILL CHECKING - JAD
PUSHJ P,SETDM4 ;DO THE ZERO-FILL BY HAND
JRST PUNTD
SETDM3: HLRZ T2,T1 ;SAVE ORIGINAL WRDCNT (RH20 MAY NEED IT)
ADD T1,[XWD BLKSIZ##-1,0] ;ACCOUNT FOR PARTIAL BLOCKS
LSH T1,MBKLSH##-^D18 ;CONVERT T1 TO BLOCKS
DPB T1,DEYNBB## ;TELL DIRSCN HOW MANY BLOCKS WE ACTUALLY READ
AOJA T4,SETL10 ;ZERO IOLIST+1, SET CHNNUM AND RETURN
;HERE TO DO ZERO-FILL BY HAND
SETDM4: LDB T3,[POINT 7,T1,17] ;GET PARTIAL-BLOCK WORD COUNT
MOVSS T3 ;IN LH
ADD T3,[XWD MBLKSZ##,0] ;-NO OF WDS LEFT
HRRZ T2,.USMBF ;MAKE AN IOWD FOR 0'S
ADD T2,T3
TLO S,IOSMON ;SO MAPIO WON'T UNRELOCATE THE IOWD
PUSH P,DEVISN(F)
SETZM DEVISN(F) ;SO DON'T CHECK MON BUF IN SECT 3 ETC.
PUSHJ P,MAPIO## ;SAVE IT
SOS -1(P)
TLZ S,IOSMON
POP P,DEVISN(F) ;RESTORE DEVISN
MOVE T2,.USMBF ;NOW ZERO THE MONITOR BUFFER
MOVEI T3,1(T2)
HRLI T3,1(T3)
SETZM (T3)
MOVSS T3
BLT T3,BLKSIZ##(T2)
JRST CPOPJ1## ;RETURN
;HERE TO SET UP AN IO LIST FOR THE SWAPPER
SETSWP: PUSHJ P,SWPP1 ;POINT P1 AT THE SWPLST ENTRY
;T3=MAXIMUM NUMBER OF BLOCKS TO DO
PUSHJ P,THIS## ;GO SET THE IO LIST
;RETURNS T1= NO OF BLOCKS, P3=L(LIST)
MOVE J,UDBKDB(U) ;THIS CLOBBERS J
JRST SETL10 ;GO FINISH UP THE IO LIST STUFF
;HERE WHEN NO MONITOR FREE-CORE LEFT
PUNTB: MOVE P4,T2 ;SAVE ORIGINAL IOWD SO WE CAN STORE WORD COUNT
TLZA P2,400000 ;CLEAR FLAG AND SKIP
PUNTD: TLO P2,400000 ;SET FLAG TO INDICATE DUMP MODE ENTRY
JUMPE P1,PUNTXX ;NO FREE-CORE IF 0
IFE FTKS10,<
PUSH P,T4 ;SAVE COUNT OF BUFFERS WE THOUGHT WE DID
SETZB T1,T4 ;T1 ACCUMULATES WORDCOUNT
HLLZ T4,CHNTYP(P3) ;SET T4 FOR TYPE OF CHANNEL
TLNN T4,CP.RH2!CP.KLP ;T4=2 FOR RH20
TDZA T4,T4 ;SET T4=0 FOR DF10C-STYLE CHANNEL
MOVEI T4,2 ;SET T4=2 FOR RH20
SKIPA T3,P2 ;START AT BEGINING OF IOLIST
PUNTE: HRR T3,(T3) ;PICK UP ADDR OF GOTO WORD
PUNTF: SKIPN T2,(T3) ;END?
JRST PUNTG ;YES
LDB T2,CNTPT3##(T4)
JUMPE T2,PUNTE ;GOTO IF 0
CAIE T4,2 ;RH20?
TDOA T2,CNTFIL## ;NO, MAKE IT "REAL"
MOVNS T2 ;YES, MAKE IT NEGATIVE
SUB T1,T2 ;ACCUMULATE WORDCOUNT
AOJA T3,PUNTF ;AND TRY NEXT
PUNTG: HRLZS T1 ;PUT WORDCOUNT WHERE SETDMP NEEDS IT
TLNN T1,BLKSIZ##-1 ;SKIP IF NOT AN INTEGRAL NUMBER OF BLOCKS
JRST PUNTX ;WE GOT LUCKY TODAY
;AT THIS POINT P1 POINTS AT THE 4TH WORD OF A FOUR WORD BLOCK, WHICH WILL
;CONTAIN ZERO (SINCE THE LINK WORD TO THE NEXT FOUR WORD BLOCK WOULD HAVE
;GONE THERE, AND THERE WERE NO MORE FOUR WORD BLOCKS). WE CAN SAFELY BACK
;UP 2 WORDS TO FLUSH THE LAST PARTIAL BLOCK FROM THE IO LIST. WE CAN
;TRUST THE LAST PARTIAL BLOCK WILL NOT SPAN MORE THAN 2 IOWDS SINCE THE
;USER'S IOWD (OR BUFFER) CAN'T CROSS MORE THAN 1 PAGE BOUNDARY.
LDB T3,[POINT 7,T1,17] ;PICK UP THE NUMBER OF WORDS TO DROP
MOVNS T3 ;MAKE IT NEGATIVE
PUNTH: SUB P1,[XWD 1,1] ;POINT AT THE LAST VALID IOWD STORED
LDB T2,WDCPNT##(T4) ;GET THE WORD COUNT
CAIE T4,2 ;RH20?
TDOA T2,CNTFIL## ;NO, SMEAR IN THE BITS TO MAKE COUNT -VE
MOVNS T2 ;YES, NEGATE THE +VE COUNT
CAMN T2,T3 ;DROPPING THE WHOLE IOWD?
JRST PUNTJ ;YES
CAML T3,T2 ;MORE WORDS TO DROP THAN IOWD CONTAINS?
JRST PUNTI ;NO
SETZM (P1) ;THIS IOWD IS NOW USELESS
SUB T3,T2 ;BACK OFF BY NUMBER OF WORDS IN THAT IOWD
ADDM T2,CHNTCW(P3) ;ADJUST COUNT HERE ALSO
JRST PUNTH ;BACK UP AND HANDLE PREVIOUS IOWD
PUNTI: SUB T2,T3 ;REDUCE THE IOWD
CAIN T4,2 ;RH20?
MOVNS T2 ;YES, MAKE IT POSITIVE AGAIN
DPB T2,WDCPNT##(T4) ;STORE WORD COUNT BACK
ADD P1,[XWD 1,1] ;POINT AT FIRST UNUSED WORD
JRST PUNTK ;QUIT
;THE LAST IOWD CONTAINED THE PARTIAL BLOCK, WE CAN ZAP THE ENTIRE IOWD
PUNTJ: SETZM (P1) ;ZOT IT OUT
PUNTK: ADDM T3,CHNTCW(P3) ;MAKE WORD COUNT HERE REFLECT OUR DAMAGE
TLZ T1,BLKSIZ##-1 ;FIX WORDCOUNT TO REFLECT REALITY
PUNTX: POP P,T4 ;RESTORE NUMBER OF BUFFERS DONE
TLZE P2,400000 ;CLEAR FLAG, WAS THIS DUMP MODE?
JRST SETDM2 ;YES, FIX IOLIST AND START IO
LSH T1,-BLKLSH##-^D18 ;CONVERT TO BLOCK COUNT
MOVE T2,P4 ;GET ORIGINAL IOWD BACK
SUB T2,R ;RESET T2 FOR A WHOLE BUFFER IF ENDING PARTIAL
TLNN S,IO ;IF READING
EXCTXU <HLRZM W,(T2)> ; SAVE WDCNT IN BUFFER WORD 0
TLNE S,IO ;IF WRITING
EXCTUU <HLLM W,(T2)> ; SAVE AMOUNT DONE SO FAR IN LH OF WORD 0
JRST SETLS8 ;FINISH UP BUFFERED MODE
>;END IFE FTKS10
;HERE IF COULDN'T GET ANY FREE CORE
PUNTXX: SETZB T1,P2 ;NO IO LIST, CHNNUM=0 (SO
JRST SETLS9 ; IOBKTL WILL LIGHT AT INTERRUPT)
;SUBROUTINE TO POINT P1 AT SWPLST ENTRY
;PRESERVES T1,T3
SWPP1: SKIPGE KONDRB(J) ;HAVE A DRB?
SKIPN T2,DEVDRB##(F) ;MAYBE, DO WE?
SKIPA P1,UNISWA(U) ;NO, GET FROM UDB
MOVE P1,DRBSWA##(T2) ;YES, GET FROM DRB
POPJ P,
;SUBROUTINE TO FIND A UNIT WHICH NEEDS HOME BLOCKS REREAD
;NON-SKIP RETURN IF NO SUCH UNITS
;SKIP RETURN IF FOUND, U POINTS AT UNIT
UNIRHB: SKIPG HOMFLG## ;ANY UNITS NEED REREADING?
POPJ P, ;NO
MOVE T1,KDBIUN(J) ;YES, SET TO LOOK FOR UNIT
UNIRH1: SKIPN T3,(T1) ;GET A UNIT DATA BLOCK
JRST UNIRH2 ;NONE
IFN FTCIDSK,<
MOVEI T2,UNPRHP
TDNE T2,UNIRHP(T3) ;ALREADY READING HOME?
SKIPL KONMX(J) ;AND MULTIPLE XFERS?
SKIPA T2,UNIDES(T3)
JRST UNIRH2 ;YES, DON'T DO IT TWICE
>
IFE FTCIDSK,<
MOVE T2,UNIDES(T3) ;NEED REREADING (ON THIS PORT)?
>
IFN FTDUAL,<
MOVE T3,UNISTS(T3) ;ALREADY REREADING ON OTHER PORT?
CAIE T3,TCOD
>
TLNN T2,UNPRHB
JRST UNIRH2 ;DON'T REREAD ON THIS PORT
MOVE U,(T1) ;SET U TO UDB TO REREAD
JRST CPOPJ1## ;AND SKIP
UNIRH2: AOBJN T1,UNIRH1 ;LOOP
POPJ P, ;NOT FOUND (MUST BE DIFFERENT KONTROLLER)
;SUBROUTINE TO SEE IF ANY UNIT NEEDS HOME BLOCKS READ
;STARTS IO TO READ HOME BLOCKS IF ANY UNITS ON THIS KONTROL NEED IT
;OTHERWISE RETURNS (DISMISSING INTERRUPT)
TSTRHB: SKIPGE @KDBCHN(J) ;DON'T REREAD IF CHANNEL ALREADY BUSY
PUSHJ P,UNIRHB ;ANY UNIT NEED REREADING?
JRST POSDN2 ;NO
PUSHJ P,FAKDDX ;YES, GET A DDB
JRST POSDN2 ;NO FREE CORE, TRY LATER
TSTRHX: PUSHJ P,STORU ;SAVE U
HLRZ T1,UNIHOM(U) ;1ST HOME BLOCK NUMBER
TSTRH1: MOVEM T1,DEVBLK##(F)
SETZM DEVRHB##(F) ;WHOLE WORD=0 INDICATES REREADING HOME BLOCKS
MOVE T1,RHBIOW## ;IOWD TO READ 1ST 10 WORDS
MOVEM T1,DEVDMP##(F) ; INTO A BUFFER
MOVE S,[IOSMON,,IOACT] ;SET S
MOVEM S,DEVIOS(F)
DSKOFF
IFN FTCIDSK,<
MOVEI T1,UNPRHP ;REREAD NOW IN PROGRESS
IORM T1,UNIRHP(U)
SKIPGE KONMX(J) ;DON'T SET CHANNEL BUSY IF MULTI XFERS
PJRST STRTIO ;START THE READ AND RETURN
>
SKIPL KONBMX(J) ;DON'T SET CHANNEL BUSY IF BLOCK MUX KONTROLLER
AOS @KDBCHN(J) ;MARK CHANNEL BUSY
PJRST STRTIO ;START THE READ AND RETURN
;HERE WHEN ALL POSITIONING INTERRUPTS HAVE BEEN HANDLED
POSDON: DSKON ;GIVE UP THE INTERLOCK
POP P,P2 ;LH=UNIT #, RH = FUNCTION
POP P,P4 ;CONI WORD
POP P,P3 ;DATAI WORD (THE DRB)
SKIPL KONDRB(J) ;IORB?
JRST POSDNZ ;NO
TRNE P2,OPPOS ;POSITIONING ONLY?
JRST TSTRHB ;YES
HLRZ U,DRBCUR##(P3) ;GET UDB
HRRZ F,DRBCDA##(P3) ;DDB
PUSH P,J ;MAKE DDB ADDRESSABLE
LDB J,DRZJOB##
PUSHJ P,MKADD##
IFN FTXMON,<
PUSHJ P,SPCS## ;SET PCS
>
POP P,J
MOVE S,DEVIOS(F)
MOVE T1,DRBSTS##(P3) ;OFF-LINE?
ANDI T1,KONERM
JUMPN T1,BADUN1
JRST POSDNY ;JOIN COMMON CODE
POSDNZ: HRRZ U,KONCUA(J) ;SET U TO UNIT ADDRESS
JUMPE U,CPOPJ## ;MIGHT BE SPURIOUS INTERRUPT FROM WRONG KONTROLLER
PUSHJ P,SETF ;SET F TO FILE ADDRESS
JUMPE F,TSTRHB ;FREE INT IF 0 OR UNSOLICITED
MOVE T1,UNISTS(U) ;IF THE UNIT IS IN
CAILE T1,MDACOD ; SOME FLAVOR OF WAIT
JRST TSTRHB ;INTERRUPT IS SPURIOUS
MOVE S,DEVIOS(F) ;AND S TO S
POSDNY: SKIPL KONDRB(J) ;HAVE A DRB?
SKIPA T1,P4 ;NO, LOAD CONI FROM AC
MOVE T1,DRBCNI##(P3) ;YES, LOAD CONI FROM DRB
MOVEM T1,DEVSTS(F) ;SAVE CONI WORD IN DDB
TRNE P2,OPPOS ;POSITIONING INTERRUPT ONLY?
;THE FOLLOWING INSTRUCTION COUNTS ON THE FACT THAT RP10 DISKS
;DONT GET ERRORS ON SEEKS (EXCEPT SEEK INCOMPLETE, AND DPXKON LIES ABOUT THAT)
;AND THAT RP04 DISKS HAVE IMPLIED SEEKS IF OFF-CYLINDER WHEN IO IS STARTED
POSDN2: POPJ P, ;YES
SOS CHNCFT(P1) ;NO, DECREASE FAIRNESS COUNTS
SOS CHNCFP(P1)
PUSHJ P,ADRINT ;SET UP R
HRRZ T4,P2 ;ERROR BITS FROM DRIVER
MOVE T1,UDBPDN(U) ;PHYSICAL DRIVE NUMBER
HLRZ T2,P2 ;UNIT NUMBER THE DEVICE CODE RETURNED
CAME T1,T2 ;DO THEY AGREE?
TROA P2,IOBKTL ;NO - LIGHT IOBKTL
TRZ P2,IOBKTL ;YES - ZERO IOBKTL
HRRZS P2 ;SET LH(P2)=0 FOR BUFFERRED MODE
LDB T1,PIOMOD## ; P2 NEGATIVE IF MONITOR MODE OR DUMP MODE
SKIPL S
CAIL T1,SD
TLO P2,400000 ;MONITOR OR DUMP
SKIPL KONDRB(J) ;HAVE A DRB?
SKIPA T2,CHNNUM(P1) ;NO, GET FROM CHN
MOVE T2,DRBNUM##(P3) ;YES, GET FROM DRB
JUMPN T2,POSDN3 ;GO IF NOT ZERO BLOCKS TRANSFERRED
;(ERROR SETS LH -1 EVEN IF RH IS 0)
;IF DUMP MODE CHNNUM=0
CAIL T1,SD ; IFF WE RAN OUT OF LOW-CORE BLOCKS
JUMPGE S,POSDN8 ; AND WE WILL RECOVER AT DUMPG5
TRO S,IOBKTL ;YES, 1ST BUFFER HEADER ZAPPED BY USER
PUSHJ P,STDIOD## ;WAKE THE JOB
JRST POSE19 ;FINISH UP
POSDN3: TRNE P2,IOIMPM+IODTER+IODERR+IOBKTL ;ERROR?
JRST POSERR ;YES, RECOVER
IFN FTCIDSK,<
SKIPGE KONMX(J) ;MULTIPLE XFERS?
JRST POSDN4 ;YES, THERE ISN'T A TERM WORD
>
MOVE T1,KDBICP(J) ;GET ADDR OF INAD PAIR
IFN FTKL10,<
MOVE T2,CHNTYP(P1)
TLNE T2,CP.RH2 ;IS IT AN RH20?
SKIPA T1,2(T1) ;YES, TERMINATION WORD IS ELSEWHERE
>
IFE FTKS10,<
MOVE T1,1(T1) ;GET TERMINATION CONTROL WORD
>
CAMN T1,CHNTCW(P1) ;IS IT WHAT WE EXPECT
JRST POSDN4 ;YES, CONTINUE
AOS UNICCT(U) ;NO, INCREMENT TERMINATION ERROR COUNT
TRO P2,IODTER ;SET AS DATA ERROR TO GET INFO TO ERROR.SYS
;FALL INTO ERROR HANDLING
;HERE ON ANY ERROR RETURN FROM THE DEVICE DEPENDENT ROUTINE
POSERR: SKIPGE CHNECT(P1) ;ARE WE SUPPOSED TO RECAL?
SKIPG KONPOS(J) ;I.E. RECOVERING FROM THUNG?
JRST POSERZ ;NO, IT'S NORMAL ERROR
SETOM CHNECT(P1) ;YES, SET RH
PUSHJ P,@KONRCL(J) ;START A RECAL
JFCL
MOVEI T1,DSKTIM## ;SET TIMER
MOVEM T1,UNITIM(U)
POPJ P,
POSERZ: SKIPL KONDRB(J) ;HAVE A DRB?
JRST POSERY ;NO
DSKOFF ;YES, DISABLE INTERRUPTS
MOVE T1,P3 ;#ADDR OF IORB
PUSHJ P,DRRST ;#RESTORE ALL THE VOLATILE STUFF
;#LEAVE INTERRUPTS OFF SO VOLATILE
;#STUFF STAYS PUT
POSERY: SKIPL DEVSWP##(F) ;SWAPPER?
JRST POSERX ;NO
DSKOFF ;#YES, DISABLE INTERRUPTS
PUSHJ P,STORU ;#SWPDDB MIGHT HAVE CHANGED SO PUT IT BACK
MOVE T1,UNIBLK(U)
MOVEM T1,DEVBLK##(F)
PUSHJ P,SWPINS## ;#RESTORE IO BIT
;#LEAVE INTERRUPTS OFF
POSERX: HRRZ T1,DEVDMP##(F) ;ADR OF (POSSIBLE) DUMP IOWD
TLNE S,IOSMON ;MONITOR CALL?
JUMPE T1,POSE99 ;YES. NO ERR RECOVERY IF CHAN SKIP IOWD
SKIPGE UNIECT(U) ;FIRST ERROR (UNPFIR)?
JRST FSTERR ;YES
TRNN P2,IOECCX ;ECC-CORRECTABLE ERROR?
JRST POSER2 ;NO
MOVSI T1,UNPECC ;INDICATE ECC-CORRECTABLE ERROR
IORB T1,UNIECT(U) ;SET AND GET CURRENT BITS
SKIPL KONECA(J) ;SKIP IF KONTROLLER CAN DO ECC FIRST
TLNE T1,UNPECE ;ECC-CORRECTION ENABLED?
JRST POSER1 ;YES, COMPUTE THE NUMBER OF GOOD BLOCKS PASSED
JRST POSER2 ;NO, EXHAUST ALL RETRIES BEFORE ECC IS USED
;HERE ON FIRST ERROR (DON'T KNOW WHETHER IT WILL BE SOFT OR HARD)
FSTERR: SETZM UNIERR(U) ;YES, ZERO LAST ERROR CONI STATUS
SKIPL KONDRB(J) ;HAVE A DRB?
DMOVE T1,P3 ;NO, LOAD DATA FROM ACS
SKIPGE KONDRB(J) ;HAVE A DRB?
DMOVE T1,DRBDTI##(P3) ;YES, LOAD DATA FROM DRB
MOVEM T2,UNISOF(U) ;SAVE FIRST CONI IN UNIT DB
MOVEM T1,UNISDI(U) ;SAVE FIRST DATAI
TRNN T4,IOBKTL+IODTER+IODERR ;IF NOT DEVICE DETECTED,
PUSHJ P,@KONRRG(J) ; READ THE MASSBUS REGISTERS
PUSHJ P,FSTREG ;COPY REGISTERS TO RH OF UDB
TRNN P2,IOCHMP!IOCHNX ;CHANNEL DETECTED ERROR?
JRST FSTER1 ;NO--CONTINUE
TRNE P2,IOCHMP ;YES--IS IT A MEMORY PARITY ERROR?
MOVEI T2,CHEMPE## ;YES, SET FOR MEM PAR ERR
TRNE P2,IOCHNX ;NO--IS IT A NXM ERROR?
MOVEI T2,CHENXM## ;YES, NXM ERROR
MOVE T1,KDBICP(J) ;INITIAL CONTROL WORD ADR
PUSHJ P,(T2) ;GO STORE CHANNEL DATA FOR F.S. ON SOFT+HARD ERRORS
FSTER1:
IFN FTCIDSK,<
SKIPL KONMX(J) ;LEAVE SIGN BIT ON
>
SETZM UNIECT(U) ;SET RETRY COUNT TO 0
;(FIRST ERROR FLAG -UNPFIR AND HARD ERROR FLAG -UNPHRD)
TRC P2,IODTER!IODERR ;IODERR AND IODTER BOTH ON
TRCE P2,IODTER!IODERR ; MEAN FORMAT ERROR
JRST FSTER2 ;NOT FORMAT ERROR
SKIPGE DEVSWP##(F) ;IF SWAPPER
JRST FSTER3 ;NOT A REAL FMT ERROR
HRRZ T1,DEVACC##(F) ;FORMAT - IF A FILE IS OPEN,
JUMPE T1,FMTERR
MOVE T1,DEVREL##(F) ; AND WE ARE NOT AT FIRST BLOCK OF FILE,
SOJLE T1,FMTERR
FSTER3: TRZ P2,IODERR ;THEN CALL IT A DATA ERROR,
JRST FSTER2 ; AND ATTEMPT RECOVERY
FMTERR: TRO S,IODERR!IODTER ;FORMAT ERR, NO FILE OR AT 1ST BLOCK
JRST POSE18 ;INDICATE FORMAT ERR AND DON'T RETRY
FSTER2: MOVEI T1,DEPDER ;ERROR-RETRY DISABLED?
TDNN T1,DEVSTA(F) ;BY OPEN UUO
JRST POSER1 ;NO
AOS UNISCT(U) ;YES, COUNT A SOFT ERROR
PUSHJ P,CTGOOD ;COMPUTE BAD BLOCK
ADD T1,DEVBLK##(F)
MOVEM T1,UNIHBN(U) ;SAVE IN UDB
JRST POSE11 ;NO RETRY
POSER1: PUSHJ P,CTGOOD ;COMPUTE THE NUMBER OF GOOD DATA BLOCKS
HRLM P2,CHNNUM(P1) ;STORE ERROR BITS IN CASE CHN MEM PAR
; SO CAN CALL SWEEP AFTER LAST TRY
ADD T1,DEVBLK##(F) ;FIRST LOGICAL BLOCK OF THIS TRANSFER
MOVEM T1,UNIHBN(U) ;STORE LOGICAL BLOCK OF ERROR FOR F.S.
; TELL LATER IF HARD OR SOFT
POSER2: MOVEI T4,1 ;SET BIT FOR ERR COUNTER, ASSUME DATA ERR
TRNE P2,IODERR ;DEVICE ERROR?
MOVSI T4,1 ;YES, COUNT AS DEVICE ERROR
IFN FTCIDSK,<
SKIPL KONMX(J) ;LEAVE IT STATIC
>
ADDM T4,UNIECT(U) ;ACCUMULATE ERROR COUNT
TLNN S,IO ;IF READING
TRNN P2,IOECCX ;AND AN ECC-CORRECTABLE ERROR
JRST NOECC1
MOVSI T1,UNPECE ;ECC CORRECTION ENABLED?
SKIPL KONECA(J) ;CAN KONTROLLER DO ECC FIRST?
TDNE T1,UNIECT(U) ;(HAVE WE EXHAUSTED ALL RETRIES/RECALS?)
SKIPA ;ECC IS PERMISSIBLE NOW
JRST NOECC1 ;CAN'T USE ECC YET
IFN FTCIDSK,<
PUSHJ P,CIBAD ;CI SHOULDN'T GET HERE
>
MOVE T1,UNIHBN(U) ;GET BAD BLOCK
SUB T1,DEVBLK##(F) ;COMPUTE NUMBER OF GOOD BLOCKS
HRLS CHNNUM(P1) ;SAVE IN CASE NOT ECC - RECOVERABLE
JUMPL T1,NOECC2 ;CHAN GOOFED IF NO BLOCKS XFERRED
HRRM T1,CHNNUM(P1) ;SAVE NUMBER OF GOOD BLOCKS
AOS CHNNUM(P1) ;+1 FOR THE BLOCK WE'LL CORRECT
SKIPGE DEVSWP##(F) ;IF SWAPPER
IFN FTKL10,<
JRST ECCSWP
>
IFN FTKS10,<
JRST NOECC2
>
PUSH P,DEVDMP##(F) ;SAVE DEVDMP
PUSH P,DEVISN(F) ;SAVE I/O SECTION
JUMPGE P2,ECC1 ;IF DUMP MODE OR MONITOR IO
LSH T1,BLKLSH## ;CONVERT TO WORDS
HRRZ T2,KONDMP(J) ;HANDLE HALVES INDEPENDENTLY
ADDI T2,(T1) ;FIRST WORD OF LAST BLOCK OF XFER
HRLZS T1 ;NOW INCREMENT COUNT FOR GOOD BLOCKS
ADD T1,KONDMP(J) ;..
EXCH T1,T2 ;COUNT IN T2, ADDR IN T1
HLRES T2 ;COUNT IN RH(T2)
JUMPL S,ECC2 ;DON'T UPDATE DEVDMP IF MON IO
PUSH P,T1 ;CONSTRUCT IOWD FOR LAST
HRLM T2,(P) ;..
ADDI T1,BLKSIZ## ;FIRST WORD OF NEW TRANSFER
ADDI T2,BLKSIZ## ;COUNT FOR NEW TRANSFER
AOS T1 ;FIRST WORD OF NEW TRANSFER
MOVSS T1 ;SET DEYISN
DPB T1,DEYISN## ;..
MOVSS T1
MOVSS T2 ;COUNT IN LEFT HALF
HRRI T2,-1(T1) ;IOWD FOR DEVDMP
MOVEM T2,DEVDMP##(F) ;..
POP P,T1 ;IOWD FOR LAST BLOCK
CAMLE T1,[MBLKSZ##,,0] ;IF LESS THAN 1 BLOCK IN IOWD
TLOA T1,400000 ; SET A FLAG
TLZ T1,-1
JRST ECC2 ;AND CONTINUE
;STILL IN FTRP04 CONDITIONAL
;HERE IF ERROR WAS IN BUFFERED MODE
ECC1: HRRZ T4,DEVIAD(F) ;LOC OF 1ST BUFFER
PUSHJ P,PARTDN ;ADJUST THINGS SINCE ONLY PART OF THE XFER GOT DONE
EXCTUU <HRRM T2,1(T4)> ;TELL WORLD HOW FAR WE GOT IN THIS BUFFER
;HERE WITH T1=UVA-1 OF START OF BAD BLOCK (OR EVA-1 IF MONITOR BUFFER)
ECC2: PUSH P,T1 ;SAVE LOC
PUSHJ P,@KONECC(J) ;GET RELATIVE POSITION OF BAD WORD
JRST ECC9 ;OOPS
CAILE T1,BLKSIZ##-1 ;IF THE ERROR IS IN THE ECC BYTE,
JRST [POP P,T1
ADJSP P,-2
JUMPGE T1,ECC8 ;IF AT END OF SHORT IOWD
HRRZS DEVDMP##(F) ; ENSURE WE TERMINATE
JRST ECC8] ;NO CORRECTION NEEDED
CAIN T1,BLKSIZ##-1 ;IF SECOND HALF IS IN THE ECC BYTE,
SETZ T3, ;DON'T CORRECT THE SECOND HALF
JUMPGE P2,ECC3
HLRE T4,DEVDMP##(F) ;WORD COUNT OF IOWD
SKIPL S
SUBI T4,BLKSIZ## ; PRIOR TO BAD BLOCK
ADDI T4,1(T1) ;+ POSITION OF ERROR BURST
SKIPGE (P) ;IF AT END OF IOWD
HRRZS DEVDMP##(F) ; MAKE SURE WE TERMINATE
JUMPL T4,ECC3 ;CONTINUE IF HE'S READING THAT PART OF BLOCK
MOVEI T3,0 ;NO CORRECTION FOR 2ND PART, HE'S NOT READING IT
SKIPE T4 ;READING 1ST WORD OF ERROR BURST?
MOVEI T2,0 ;NO, DON'T CORRECT 1ST PART EITHER
ECC3: POP P,T4 ;RESTORE START OF BLOCK
ADJSP P,-2 ;REMOVE SAVED DEVISN & DEVDMP FROM STACK
ADDI T1,1(T4) ;POINT T1 AT 1ST BAD WORD
JUMPL S,ECC5 ;IF NOT MONITOR IO,
JUMPE T2,ECC4 ;NO, 1ST PART IF T2=0
EXCTUX <MOVS T4,(T1)> ;THIS WILL HAVE TO BE MODIFIED IF WE GET
; OTHER HARDWARE WHICH DOES ECC DIFFERENTLY
XOR T4,T2 ;APPLY MASK
EXCTXU <MOVSM T4,(T1)> ;AND SAVE RESULT
ECC4: ADDI T1,1
JUMPE T3,ECC8 ;NO 2ND PART IF T3=0
EXCTUX <MOVS T4,(T1)> ;GET 2ND WORD
XOR T4,T3 ;APPLY MASK
EXCTXU <MOVSM T4,(T1)> ;AND SAVE RESULT
JRST ECC8 ;LOG A RECOVERED ERROR AND CONTINUE
;STILL IN FTRP04 CONDITIONAL
;HERE IF ERROR IN MONITOR IO (INTO MON BUF)
ECC5: JUMPE T2,ECC6 ;NO 1ST PART IF T2=0
MOVS T4,(T1) ;GET 1ST BAD WORD
XOR T4,T2 ;APPLY MASK
MOVSM T4,(T1) ;AND SAVE
ECC6: JUMPE T3,ECC7 ;NO 2ND PART IF T3=0
MOVS T4,1(T1) ;GET 2ND BAD WORD
XOR T4,T3 ;CORRECT
MOVSM T4,1(T1) ;AND SAVE
ECC7: MOVE T1,CHNNUM(P1) ;RESET NUMBER OF BLOCKS DONE
DPB T1,DEYNBB## ; (IN CASE IN DIRSCN FOR A LARGE UFD)
ECC8:
IFN FTKL10&FTMP,<
PUSHJ P,CSDMP## ;DONT LEAVE FUNNY VALID BITS IN CACHE
>
JRST POSDN4 ;AND CONTINUE
IFN FTKL10,<
;HERE ON ECC ERROR DETECTED BY SWAPPER
ECCSWP: PUSH P,T2 ;SAVE CORRECTION DATA
PUSH P,T3 ;SAVE RH10/RH20,,L(IOWD)
PUSHJ P,@KONECC(J) ;GET CORRECTION DATA
ECCSW0: JRST [POP P,(P) ;IT REALLY WASN'T ECC CORRECTABLE
POP P,(P)
JRST NOECC2]
CAILE T1,BLKSIZ##-1 ;LEGAL POSITION OF ECC BYTE?
JRST ECCSW2 ;NO, FORGET IT
CAIN T1,BLKSIZ##-1 ;IF SECOND HALF IS IN THE ECC BYTE,
SETZ T3, ;DON'T CORRECT THE SECOND HALF
MOVE T4,(P) ;GET IOWD
MOVE T4,(T4)
ADD T4,-1(P) ;ADD POSITION OF ERROR
SUBI T4,BLKSIZ ;RELATIVE TO START OF BLOCK
TLZ T4,777760 ;JUST ADDRESS
SKIPL (P) ;RH20?
ADDI T4,1 ;ADJUST FOR ADDR-1
TRNE T4,BLKSIZ-1
JRST ECCSW0 ;WRDCNT LIED
ADDB T1,T4 ;T1=PHYSICAL ADDRESS OF 1ST BAD WORD
LSH T1,W2PLSH
PUSHJ P,SWPAD## ;MAKE IT ADDRESSABLE IN EVM
ANDI T4,PG.BDY
ADD T1,T4
MOVS T4,(T1) ;CORRECT THE DATA
XOR T4,T2
MOVSM T4,(T1)
JUMPE T3,ECCSW2 ;NO 2ND PART IF T3 ZERO
MOVS T4,1(T1) ;GURANTEED TO BE IN SAME PAGE
XOR T4,T3
MOVSM T4,1(T1)
;HERE AFTER WE CORRECTED THE DATA
ECCSW2: AOS T1,UNIHBN(U) ;BLOCK AFTER THE ONE WE FIXED
SUB T1,DEVBLK##(F) ;-WHERE WE STARTED
ADDM T1,DEVBLK##(F) ;WHERE WE SHOULD RESTART
ADDM T1,UNIBLK(U)
HLRZ T1,CHNNUM(P1) ;ORIGINAL COUNT
HRRZS CHNNUM(P1) ;CLEAR BITS FROM LH
SUB T1,CHNNUM(P1)
MOVEM T1,CHNNUM(P1) ;NUMBER OF BLOCKS LEFT TO GO
POP P,T3
POP P,T2
MOVE T4,@KDBICP(J) ;NOW FIX UP THE IOWD TO RESTART THE XFER
ADD T2,(T3)
TLNN T2,077760
JUMPL T3,ECCSW3
TLNE T2,777760 ;DONE WITH THIS IOWD?
JRST ECCSW4 ;NO, RESTARTT ON THIS ONE
ECCSW3: MOVEI T1,1(T3) ;YES, POINT AT NEXT IOWD
SKIPN (T1) ;COMPLETELY DONE?
JRST POSDN4 ;YES
JUMPGE T3,ECCSW5 ;HAVE A GOTO WORD ALREADY IF RH10
HRLI T1,(INSVL.(.CCJMP,CC.OPC)) ;RH20 - MAKE A GOTO WORD
JRST ECCSW5 ;AND START AT THAT IOWD
ECCSW4: MOVEM T2,(T3) ;CONTINUE IN THIS IOWD - SAVE UPDATED IOWD
HRRZ T1,T3 ;IS THIS 1ST IOWD?
CAIN T1,(T4)
JRST STARTE ;YES, RESTART
HLL T1,T4 ;NO, MAKE A GOTO THIS IOWD
ECCSW5: MOVEM T1,(T4)
JRST STARTE ;AND RESTART THE IO
> ;END IFN FTKL10
;HERE IF WE REALLY COULDNT RECOVER THOUGH WE THOUGHT WE COULD
ECC9:
IFN FTKL10&FTMP,<
PUSHJ P,CSDMP##
>
NOECC: POP P,(P) ;REMOVE RELATIVE ADDR FROM LIST
POP P,DEVISN(F) ;RESTORE ORIGINAL I/O SECTION TO THE DDB
POP P,DEVDMP##(F) ;RESTORE ORIGINAL DEVDMP TO THE DDB
MOVE S,DEVIOS(F) ;RESET S (IOSPBF WAS CHANGED ERRONEOUSLY)
NOECC2: MOVEI T4,1 ;COUNT DATA ERROR
HLRZS CHNNUM(P1) ;RESTORE ORIGINAL CHNNUM
NOECC1: AOS T1,CHNECT(P1) ;UPDATE COUNT OF TRIES
CAIN T1,1 ;FIRST RETRY OR 1ST AFTER RECAL?
CAME T1,CHNRCT(P1) ;YES, THIS 1ST RECAL?
JRST POSER3 ;NO
SKIPL KONDRB(J) ;HAVE A DRB?
DMOVE T1,P3 ;NO, LOAD DATA FROM ACS
SKIPGE KONDRB(J) ;HAVE A DRB?
DMOVE T1,DRBDTI##(P3) ;YES, LOAD DATA FROM DRB
MOVEM T2,UNIERR(U) ;YES. SAVE 2ND ("HARD") CONI WORD
MOVEM T1,UNIHDI(U) ;SAVE "HARD" DATAI WORD
PUSHJ P,LSTER ;SAVE THE DRIVE REGISTERS NOW
POSER3: MOVE P4,T4 ;SAVE ERROR-COUNT WORD
IFN FTCIDSK,<
SKIPGE KONMX(J) ;MULTIPLE XFERS?
JRST POSER4 ;UNISTS IS IDLE
>
MOVE T2,UNISTS(U) ;STATE OF UNIT
CAIE T2,TCOD ;IGNORE IF POSITIONING,
POPJ P, ;RETRY IF XFER (ERROR RECOVERY)
IFN FTKL10,<
LDB T2,UNYKTP## ;GET KONTROLLER TYPE
CAIN T2,TYPRN ;RP20?
JRST POSER4 ;YES, ALWAYS CALL ERR ROUTINE
>
TRNN P2,IOHDER ;HEADER ERROR?
TRNN P2,IODERR ; OR DATA ERROR? (AND NOT FMT)
POSER4: SKIPG T2,KONERR(J) ;YES, WILL KONTROL ROUTINE TELL US WHAT TO DO?
JRST NOOFST ;NO
HLRZ T1,UNIECT(U) ;USE LH(UNIECT) IF HEADER ERROR
ADD T1,UNIECT(U) ; OR RH IF DATA ERROR
HRRZS T1 ;ONE HALF MUST HAVE COUNTED UP
PUSHJ P,(T2) ;ASK THE KONTROLLER ROUTINE
JRST @ERRTBL(T1) ;AND GO DO WHAT IT SAID
ERRTBL: STARTE ;(0) RETRY
OFFSET ;(1) OFFSET
POSER7 ;(2) LAST TIME
POSER8 ;(3) GIVE UP
POSER5 ;(4) RECAL
NOOFST: HRRZ T2,UNISTR(U) ;LOC OF STR DATA BLOCK
LDB T3,STYTRY## ;NO OF TIMES TO RETRY
TRNE P2,IODERR ;DEVICE (POSITIONING) ERROR?
LDB T3,STYSER## ;YES. USE A DIFFERENT PARAMETER
SKIPN T2 ;UNIT IN AN STR?
MOVEI T3,^D10 ;NO, USE 10
SUB T1,T3 ;HAVE WE TRIED ENOUGH?
JUMPL T1,STARTE ;RETRY IF NEGATIVE
TRNE P2,IOBKTL ;WRONG UNIT?
JRST POSER9 ;YES, DONT TRY RECAL
AOS T4,CHNRCT(P1) ;UPDATE RECALIBRATE-COUNTER
LDB T3,STYRCL## ;NO OF TIMES TO RECAL
SKIPN T2 ;UNIT IN AN STR?
MOVEI T3,^D10 ;NO, USE 10
SUB T4,T3 ;TRIED ENOUGH?
JUMPGE T4,POSER6 ;TRIED ENOUGH IF T4=0
POSER5: SETOM CHNECT(P1) ;NO. SET A SWITCH FOR RECALR
PUSHJ P,@KONRCL(J) ;DO A RECALIBRATE
JRST POSER6 ;NOT A PACK OR UNIT DOWN
DSKON ;ALLOW INTERRUPTS AGAIN
PJRST STOIOS## ;RECALIBRATING - RESET HUNG TIME, DISMISS INTERRUPT
POSER6: JUMPG T1,POSE10 ;GO IF NOT LAST TIME
POSER7: MOVEI T3,KONRED(J) ;LAST TIME - SET TO NO STOPPING
TLNE S,IO ; ON ERROR SO ALL OF DATA IS ATTEMPTED
; TO BE TRANSFERRED ON LAST RETRY
MOVEI T3,KONWRT(J)
MOVSI T2,DEPCPT## ;IF IN 10/11 COMPAT MODE,
TDNE T2,DEVCPT##(F)
ADDI T3,KONWTC-KONWRT ;ENTRY POINT = RED(WRT)+3
MOVE T1,P3 ;COPY THE DRB ADDRESS
PUSHJ P,@(T3) ;CALL DEVICE DEPENDENT ROUTINE
PJRST BADUN1 ;UNIT NOT UP
PJRST DOPOPJ ;TURN INTERRUPTS ON AND RETURN
;HERE WHEN ERROR IS DECLARED HARD FOR AN ERROR-PROGRAM KONTROLLER
POSER8: PUSHJ P,LSTER ;READ ALL DRIVE REGISTERS
JRST POSE10 ;AND GO DECLARE HARD ERROR
OFFSET: HRROS CHNECT(P1) ;CHNECT=-1,,N TO INDICATE OFFSET IN PROGRESS
DSKON ;ALLOW INTERRUPTS AGAIN
PJRST STOIOS##
;ROUTINE TO RETURN BAD BLOCK NUMBER RELATIVE TO BEGINNING
;OF TRANSFER. RETURNS RELATIVE BLOCK NUMBER IN T1.
;RETURNS T2, T3 AS SET UP BY WRDCNT
CTGOOD: SKIPL KONDRB(J) ;HAVE A DRB?
JRST CTGOD1 ;NO
MOVE T1,DEVDRB##(F) ;GET IT FROM IORB
MOVE T1,DRBGOD##(T1)
POPJ P,
CTGOD1: HRRZ T1,KDBICP(J) ;INITIAL CONTROL WORD ADDRESS
PUSHJ P,WRDCNT## ;COMPUTE NO. OF GOOD WORDS TRANSFERRED
TRNE P2,IODTER ;IS THIS EITHER
TRNN P2,IODERR!IOHDER ; FORMAT OR SEARCH ERROR?
SUBI T1,1 ;NO, ENSURE WE GET THE RIGHT NUMBER OF BLOCKS
;(DEVBLK(F) + THIS NUMBER = BAD BLOCK NUMBER)
LSH T1,MBKLSH## ;CONVERT TO RELATIVE BLOCK NUMBER
POPJ P,
;SUBROUTINE TO FIX THINGS UP WHEN ONLY A PART OF THE TRANSFER GETS DONE (ECC, HARD ERROR)
;CALLED ONLY FOR BUFFERRED MODE
;T1 PASSES NUM GOOD BLOCKS (I.E. NOT COUNTING THE ECC BLOCK)
;T4 PASSES DEVIAD OR DEVOAD
;T4 RETURNS ECC BUFFER
;T1 RETURNS ADDR-1 OF ECC BLOCK
;T2 RETURNS WORDS TRANSFERED SO FAR THIS BUF (INCLUDING THE ECC BLOCK)
PARTDN: LDB T2,DEYNB1## ;NO OF BLOCKS FROM START OF BUFFER
ADD T1,T2 ;TOTAL GOOD (NOT COUNT ECC)
LDB T3,DEYNBB## ;NO OF BLOCKS PER BUFFER
IDIVI T1,(T3) ;NO OF BUFFERS BEFORE BAD BLOCK
JUMPE T1,PARTD1
EXCTUX <HRR T4,(T4)> ;ADVANCE THE NUMBER OF GOOD BUFFERS
SOJG T1,.-1
PARTD1: MOVEI T1,1(T4) ;POINT T1 AT LOC-1 OF BAD BUFFER
SUBI T3,1(T2) ;NO OF BLOCKS LEFT IN CURRENT BUFFER
LSHC T2,BLKLSH## ;NO OF GOOD WORDS AT FRONT
ADD T1,T2 ;POINT AT EVA-1 OF BAD BLOCK
SKIPN T3 ;PARTIAL BUFFER?
TLZA S,IOSPBF ;IN CASE IT WAS ON AND WE STOPPED AT END OF BUFFER
TLO S,IOSPBF ;PARTIAL - TELL REST OF WORLD
ADDI T2,BLKSIZ## ;HOW FAR WE'VE GONE
POPJ P, ;NON-SKIP RETURN
;SUBROUTINE TO COPY THE DRIVE REGISTERS INTO THE RH OF THE UDB
;CALLED ON FIRST ERROR, WIPES OUT LH OF UDB REG'S
FSTREG::SKIPN T2,KONREG(J) ;GET NUMBER OF DRIVE REGISTERS TO STORE
POPJ P, ;NONE - NOT A MASSBUS DEVICE
ADDI T2,UNIEBK(U) ;POINT TO TOP OF BLOCK
HRLZ T1,KONEBK(J) ;WHERE THEY WERE SAVED
HRRI T1,UNIEBK(U) ;WHERE THEY ARE TO GO
BLT T1,-1(T2) ;SAVE THEM
MOVE T1,UNILAS(U) ;LAST DATAO
MOVEM T1,(T2) ;SAVE IN THE UDB
MOVE T1,KONECR(J) ;GET KONTROLLER
MOVEM T1,UNISCR(U) ; CONTROL REG & DATA REG
MOVE T1,KONEDB(J) ;AND SAVE IN UDB
MOVEM T1,UNISDR(U)
POPJ P, ;AND RETURN
;SUBROUTINE TO SAVE THE DRIVE REGISTERS IN THE UDB
; RESPECTS T1,T4
LSTER:: PUSH P,T1
MOVN T1,KONREG(J) ;NUMBER OF REGISTERS TO SAVE
JUMPE T1,TPOPJ##
HRLS T1 ;MAKE AN AOBJN WORD
HRR T1,KONEBK(J)
MOVEI T2,UNIEBK(U) ;WHERE TO STORE
IFN FTKL10,<
LDB T3,UNYKTP## ;GET KONTROLLER TYPE
CAIE T3,TYPRN ;IS IT AN RP20?
JRST LSTER1 ;NO, CONTINUE
MOVE T1,[-RNVNMR##,,RNVSMR##] ;AOBJN POINTER
ADD T1,KONEBK(J) ;RELOCATE
MOVEI T2,UNIEBK+RNVSMR##(U) ;WHERE TO STORE THEM
>
LSTER1: MOVE T3,(T1)
HRLM T3,(T2) ;SAVE A DRIVE REGISTER IN LH OF UDB WORD
ADDI T2,1
AOBJN T1,LSTER1 ;GET ANOTHER WORD
MOVE T2,KONREG(J) ;GET NUMBER OF REGISTERS BACK
ADDI T2,UNIEBK(U) ;COMPUTE WHERE TO STORE LAST DATAO
MOVE T1,UNILAS(U) ;LAST DATAO TO THE DRIVE
HRLM T1,(T2) ;SAVE IN UDB
MOVE T1,KONECR(J) ;SAVE KONTROLLER (RH10)
MOVEM T1,UNIHCR(U) ; CONTROL REG & DATA REG
MOVE T1,KONEDB(J) ;IN UDB
MOVEM T1,UNIHDR(U)
JRST TPOPJ## ;AND RETURN
;HERE ON HARD WRONG-UNIT
POSER9: TLNE S,IO ;IF READING, CONTINUE
STOPCD .,JOB,HWU, ;++HARD WRONG UNIT
;HERE ON HARD DEVICE OR DATA ERRORS
POSE10: SOJE T1,STARTE ;LAST RETRY, STOP ON ERROR, IF 1
MOVE T1,UNIECT(U) ;GET INTERESTING BITS
TLC T1,UNPECC ;COMPLEMENT ECC-CORRECTABLE ERROR FLAG
TLNN T1,UNPECC!UNPECE ;IF ECC WOULD HELP, AND WE HAVEN'T TRIED,
JRST POSE20 ;GO SET UP FOR SECOND PASS
DSKON ;ALLOW INTERRUPTS AGAIN
ADDM P4,UNIHCT(U) ;UPDATE HARD-ERROR WORD
IFN FTCIDSK,<
SKIPGE KONMX(J) ;MULTIPLE XFERS?
SETZ P4, ;YES, LEAVE UNIECT STATIC
>
TLNE P4,-1 ;BEEN COUNTING IN LH (POSITION ERRS)?
HLRZS UNIECT(U) ;YES. SAVE COUNT IN RH (UNIECT)
MOVSI T1,UNPHRD ;HARD ERROR FLAG ON LAST ERROR ON THIS UNIT
IORM T1,UNIECT(U) ;SET FOR DAEMON AND SYSERR
PUSHJ P,CHKCMP ;CHECK IF CHN MEM PAR ERR
; IF YES, FLAG CPU MEM SWEEP
AOS T1,HERCNT## ;BUMP HARD ERR COUNT
TRNE S,IODTER+IODERR ;HRDWRE ERROR?
CAMGE T1,HERLIM## ;YES. TIME TO TELL OPR?
JRST POSE11 ;NO
SETZM HERCNT## ;YES. RESET FOR NEXT CYCLE
MOVE T1,[TELDER,,1] ;CANT TYPE ON PI LEVEL
SYSPIF ; SO WAIT TILL NEXT TICK
PUSHJ P,SKPCLQ## ;ROOM IN CLOCK QUEUE FOR MESSAGE?
JRST POS10A ;NO, PROBABLY LOTS OF ERRORS, LET IT GO
IDPB T1,CLOCK## ;SET SO WE WILL TELL OPR
IDPB U,CLOCK##
SETOM CLKNEW##
POS10A: SYSPIN
POSE11: JUMPL P2,POSE12
PUSHJ P,CTGOOD ;GET RELATIVE BAD BLOCK NUMBER
AOS T1 ;CONVERT TO NUMBER OF BLOCKS XFERRED
HRRZ T2,CHNNUM(P1) ;ORIGINAL NUM OF BLOCKS XFERRED
HRRM T1,CHNNUM(P1) ;SAVE FOR BUFAD
SUBI T2,(T1) ;NUMBER OF BLOCKS AFTER THE LAST GOOD ONE
;FALL INTO POSE12
;HERE IF USER AVOIDING ALL RETRIES
POSE12: TLNN S,IO ;IF INPUT,
PUSHJ P,CFDMPX ;FLUSH CACHE SO BAD DATA WILL BE SEEN
POSE99: PUSH P,P3 ;SAVE ADDR OF IORB
JUMPL S,POSE14 ;ONLY 1 IOWD IF MONITOR IO
JUMPL P2,POSE13 ;IF BUFFERRED MODE,
PUSH P,T2 ;SAVE NUMBER OF BLOCKS PAST LAST GOOD ONE
TLNE S,IO ;GET LOC OF BUFFER
SKIPA T4,DEVOAD(F)
MOVE T4,DEVIAD(F)
HRRZS T4 ;CLEAR POSSIBLE LEFT HALF JUNK
;WE NOW PRETEND THAT THERE WAS AN ECC CORRECTABLE BAD SPOT IN THE
;BLOCK BEFORE THE BAD BLOCK. WE ADVANCE OVER ALL THE BUFFERS UP TO
;AND INCLUDING THE "ECC" BLOCK (I.E. ALL THE GOOD DATA).
;WE THEN LIGHT ERROR BITS IN ALL THE REMAINING BUFFERS.
HRRZ T1,CHNNUM(P1) ;GET GOOD BLOCKS BACK
SOJL T1,POSE14 ;GO IF BAD BLOCK IS 1ST IN TRANSFER
PUSHJ P,PARTDN ;SET IOSPBF, NO OF WORDS DONE IN BUFFER
HRLM T2,(P) ;SAVE NO OF WORDS DONE SO FAR
POSE13: HRRZ P4,CHNNUM(P1) ;GET # OF GOOD BLOCKS FOR BUFAD
PUSHJ P,BUFAD ;ADVANCE THE GOOD BUFFERS
JFCL
POSE14: PUSH P,P2 ;SAVE ALL ERROR BITS
ANDI P2,IOIMPM+IODTER+IODERR+IOBKTL+IOCHMP+IOCHNX ;P2=ERROR BITS
TRNN P2,IOCHMP+IOCHNX ;CHAN-DETECTED ERROR?
JRST POSE15 ;NO
SKIPL DEVSWP##(F) ;SWAPPER?
TRZ P2,IOCHMP+IOCHNX ;NO, DON'T KEEP THESE ERR BITS
POSE15: OR S,P2 ;STORE ERROR BITS IN S
POP P,P2
JUMPL P2,POSE16 ;GO IF MONITOR IO
POP P,T2 ;NO GOOD WDS IN BUF,,NO OF EXTRA BLOCKS
HRRM T2,CHNNUM(P1) ;SAVE ADDITIONAL NO OF BUFS
HRRZ P4,T2 ;BUFAD WANTS IT IN P4
LSH T2,-^D18-BLKLSH## ;NO OF BLOCKS INTO BUFFER
LDB T3,DEYNBB## ;NO OF BLOCKS PER BUFFER
CAIN T3,(T2) ;IF AT TOP OF BUFFER
SETZ T2, ;DEYNB1 SHOULD BE 0
DPB T2,DEYNB1## ;SAVE IN DDB FOR BUFAD
SKIPE P4 ;IN CASE RH SCREWED UP
PUSHJ P,BUFAD ;ADVANCE THE REST OF THE BLOCKS
JFCL
POSE16: POP P,P3 ;RESTORE ADDR OF IORB
TRNN S,IODTER ;PARITY ERROR?
JRST POSE17 ;NO
TLNE S,IO ;YES. LIGHT ERR BIT IN LH(S)
TLOA S,IOSHWE## ; BECAUSE USER CAN CLEAR RH OF S (SETSTS)
TLO S,IOSHRE##
POSE17: TRNE S,IODERR ;DEVICE (POSITIONING) ERROR?
TLO S,IOSSCE## ;YES. LIGHT A BIT IN LH(S) SOFTWARE CHECKSUM
; OR DEVICE ERROR
SKIPE DEVELB##(F) ;IF NOT ALREADY A BAD BLOCK,
JRST POSE18
MOVE T1,UNIHBN(U) ;BAD BLOCK NO. STORED ON FIRST ERROR
TRNE P2,IODTER ;GET ERROR CODE
TLO T1,BAPDTR## ; (DATA ERR,HEADER ERR, OR OTHER)
TRNE P2,IOHDER ;HEADER ERR?
TLO T1,BAPHDR## ;YES
TRNN P2,IODTER+IOHDER ;NOT HEADER OR DATA?
TLO T1,BAPOTR## ;"OTHER"
TRNN P2,IOCHNX+IOCHMP ;CHANNEL ERRORS?
MOVEM T1,DEVELB##(F) ;STORE BLOCK + CODE IN DDB
LDB T1,UNYLUN## ;AND SAVE THE LOGICAL UNIT NUMBER
DPB T1,DEYEUN## ;FOR ERRFIN
POSE18: PUSHJ P,STDIOD## ;YES. WAKE IT UP
MOVEI T1,.FIER3 ;FILIO-DETECTED DISK ERROR
SKIPN DINITF## ;DON'T TRY TO WAKE DAEMON IF IN ONCE-ONLY
PUSHJ P,FILELG ;MAKE AN ERROR ENTRY
POSE19: PUSHJ P,RTNDRB ;RETURN CHANNEL PROGRAM AND IORB
PJRST SETID3 ;SET THIS FILE IDLE AND LOOK FOR ANOTHER
;HERE WHEN RETRIES EXHAUSTED BUT ECC CORRECTION WAS INDICATED AS
;BEING POSSIBLE DURING ONE OF THE RETRIES. RETRY ALLOWING ECC
;CORRECTION THIS TIME.
POSE20: MOVSI T1,UNPECE ;GET THE ONLY USEFUL BIT
MOVEM T1,UNIECT(U) ;INDICATE ECC CORRECTION PERMITTED
JRST POSERZ ;START THE RETRIES OVER AGAIN
;HERE WHEN THERE WAS NO HARDWARE ERROR ON THE DATA TRANSFER
POSDN4: SKIPG T1,UNIECT(U) ;NO. IS THIS A RECOVERED ERROR (UNPFIR)?
JRST POSDN6 ;NO - NO ERROR AT ALL (USUAL)
MOVSI T2,1 ;YES, FOR POSSIBLE UPDATE OF LH
TLNN T1,-1 ;DEVICE ERROR?
AOSA UNISCT(U) ;NO, DATA ERROR UPDATE RH(UNISCT)
ADDM T2,UNISCT(U) ;YES, UPDATE LH(UNISCT)
TLNE T1,-1 ;WERE WE COUNTING IN LH (POSITION ERRS)?
HLRZS T1,UNIECT(U) ;YES, SET UNIECT= NUMBER IN RH
MOVE T2,CHNNUM(P1) ;IF AN OVERRUN
TLNE T2,IOVRUN ; RECOVERED ON 1ST RETRY,
SOJE T1,[SKIPN ALLOVR## ;DON'T CALL DAEMON
JRST POSDN5 ; IF ALLOVR = 0
JRST .+1]
MOVEI T1,.FIER4 ;FILIO-DETECTED DISK ERROR
SKIPN DINITF## ;DON'T TRY TO WAKE DAEMON IF IN ONCE-ONLY
PUSHJ P,FILELG ;MAKE AN ERROR ENTRY
PUSHJ P,CHKCMP ;CHECK IF THIS WAS A CHN MEM PAR
; IF YES, FLAG FOR CPU SWEEP
POSDN5: SKIPE UNIERR(U) ;IS THIS BEFORE FIRST RECAL?
JRST POSDN6 ;NO, "HARD" CONI STUFF ALREADY STORED
SKIPL KONDRB(J) ;HAVE A DRB?
DMOVE T1,P3 ;NO, LOAD DATA FROM ACS
SKIPGE KONDRB(J) ;HAVE A DRB?
DMOVE T1,DRBDTI##(P3) ;YES, LOAD DATA FROM DRB
MOVEM T2,UNIERR(U) ;YES, SAVE "HARD" CONI
MOVEM T1,UNIHDI(U) ;SAVE "HARD" DATAI
PUSHJ P,LSTER ;SAVE THE DRIVE REGISTERS AT END (THEY PROBABLY ARE
; MEANINGLESS AT THIS POINT SINCE THEY ARE ONLY
; STORED AT ERROR TIME, BUT ITS BETTER THAN NOTHING
POSDN6: TLNN S,IO+IOSMON
TLZN S,IOSFIR ;TIME FOR CHECKSUMS?
JRST .+2 ;NOT TIME FOR CHECKSUMS, SO WE DON'T HAVE
; TO SWEEP YET.
JRST POSDN7 ;CHECKSUM TIME, SWEEP IMMEDIATELY
MOVSI T1,CP.SWF ;GET READY TO SET THE BIT
TLNN S,IO ;READING?
IORM T1,CHNTYP(P1) ;YES, INDICATE THAT A SWEEP MUST BE
; DONE BEFORE INTERRUPT EXIT TIME.
JRST POSDN8 ;CONTINUE.
POSDN7: PUSHJ P,CFDMPX ;CHECKSUM TIME, SO SWEEP THAT WE MAY SEE
; THE DATA NOW.
PUSHJ P,CHKSUM ;YES. COMPUTE CHECKSUM
SKIPN T2,@DEVRET##(F) ;PICK UP RETRIEVAL PNTR
MOVE T2,DEVRB1##(F) ;1ST PNTR, MORE IN RIB
HRRZ T3,UNISTR(U) ;LOC OF STR DB
LDB T2,STYCKP##(T3) ;GET CHECKSUM
CAMN T2,T1 ;DOES IT MATCH COMPUTED CHECKSUM?
JRST POSDN8 ;YES. OK
MOVE T2,DEVACC##(F) ;LOC OF A.T.
MOVE T4,ACCNCK##(T2) ;ALWAYS-BAD-CHECKSUM WORD
TRNE T4,ACPNCK## ;FILE A DIRECTORY OR HAVE ABC?
JRST POSDN8 ;YES. IGNORE ERROR
MOVE T4,DEVREL##(F) ;NO. RELATIVE BLOCK NUMBER
MOVE T2,ACCPT1##(T2) ;CURRENT 1ST POINTER
LDB T2,STYCKP##(T3) ;CHECKSUM BYTE
CAMN T2,T1 ;MATCH?
SOJE T4,POSDN8 ;YES, IF 1ST BLOCK FILE IS A UFD WHOSE
;CHECKSUM HAS CHANGED BETWEEN LOOKUP AND INPUT
AOS UNIMCT(U) ;REAL CHKSUM ERR. COUNT SOFTWARE ERROR
TDO S,[XWD IOSSCE##,IOIMPM];LIGHT ERROR BIT (LH SINCE USER CAN CLEAR IOIMPM)
MOVE T1,DEVBLK##(F) ;FIRST LOGICAL BLOCK OF TRANSFER
MOVEM T1,UNIHBN(U) ;STORE BAD BLOCK NO. FOR ERROR REPORTING
MOVEI T1,.FICKE ;FILIO-DETECTED CHECKSUM ERROR
PUSHJ P,FILELG ;MAKE AN ERROR ENTRY
POSDN8: MOVEM S,DEVIOS(F) ;SAVE S IN DDB
PUSHJ P,RTNDRB ;RETURN THE IORB (IF ANY)
LDB T1,PJOBN## ;JOB NUMBER
; HRRZ T1,JBTPDB##(T1) ;ADDR OF PDB FOR JOB
TLNN S,IO ;READING?
ADDM P4,JBTRCT##(T1) ;YES. UPDATE JOB READ COUNT
TLNE S,IO ;WRITING?
ADDM P4,JBTWCT##(T1) ;YES, INCREMENT NO BLOCKS WRITTEN BY THIS JOB
JUMPL S,SETMDL ;MONITOR IO? YES IF S NEG
PUSHJ P,BUFAD ;NO. UPDATE DDB, ADVANCE BUFFERS
JRST SETID2 ;NEXT BUFFER NOT USABLE, OR DUMP MODE
;AT LEAST 1 BUFFER IS AVAILABLE
SKIPE DIADSK## ;IF WAITING FOR IO TO STOP
CAME P1,DIACHN## ; LET THE UNIT GO IDLE NOW
PUSHJ P,CHKNXT ;ANY MORE BLOCKS ON DISK NOW?
JRST SETID1 ;NO. SET FILE, UNIT TO IDLE
TLNE P3,-1
PUSHJ P,STDIOD## ;WAKE JOB IF WAITING
DSKOFF
IFN FTCIDSK,<
SKIPGE KONMX(J) ;MULTIPLE XFERS?
JRST SETBS1 ;YES, JUST START IT
>
PUSHJ P,FLPJOB ;#FLIP UNICDA (IN CASE SWPSCN)
SKIPL KONPOS(J) ;YES. DOES KONTROLLER POSITION?
JRST SETPW ;YES. SET FILE TO PW STATE
PUSHJ P,SETTW0 ;NO, SET FILE TO TW STATE
JRST PIKTRN ;AND LOOK FOR NEXT TRANSFER OPERATION
;ROUTINE TO INITIATE CPU MEM PAR OR NXM SWEEP AFTER ALL RETRIES DONE
;CALL: MOVE P1,CHANNEL DATA BLOCK ADDRESS
; PUSHJ P,CHKCMP
; RETURN
CHKCMP: MOVE T1,CHNNUM(P1) ;LH=IO STATUS ERR BITS ON RETRIES
TLNN T1,IOCHNX!IOCHMP ;ANY ERRORS
POPJ P, ;NO
HLLZ T2,CHNCSR(P1) ;FLAG FOR THIS CHANNEL TO REQUEST CPU0 SWEEP
TRO T2,UE.PEF ;CAUSE PARITY (NOT NXM) SWEEP
TLNE T1,IOCHNX ;DID CHAN DETECT NXM
TRC T2,UE.PEF!UE.NXM ;YES -- SET NXM SWEEP
IORM T2,.CPAEF## ;FLAG CPU TO DO A CORE SWEEP
POPJ P, ;RETURN
;ROUTINE TO LOG DISK I/O ERRORS
;CALL:
; MOVE J,KDB-ADDRESS
; MOVE U,UDB-ADDRESS
; MOVE F,DDB-ADDRESS
; MOVEI T1,SOFT-SUB-CODE (.FI???)
; PUSHJ P,FILELG
;RETURN:
; NON-SKIP ALWAYS, CLOBBERING ONLY T1-T4
FILELG: JUMPE F,CPOPJ## ;GET OUT NOW IF NO DDB
JUMPE U,CPOPJ## ;OR IF NO UNIT
MOVEI T2,DEPDEL ;DISABLE-ERROR-LOGGING BIT
TDNE T2,DEVSTA(F) ;IS IT SET?
AOSA DELCNT## ;YES--FLAG UNLOGGED ERROR
AOSA SYSERR## ;NO--COUNT THE SYSTEM ERROR
POPJ P, ;ALL DONE IF NO LOGGING
PUSHJ P,SAVJW## ;SAVE KONTROLLER POINTERS
MOVE T4,T1 ;COPY SOFT CODE
MOVE W,J ;MOVE KDB POINTER
LDB J,PJOBN## ;GET THE JOB NUMBER FOR LOGGING ROUTINES
SETZ T1, ;WE HAVE NO SEB YET (FOR XFRSEB)
PUSHJ P,@KONELG(W) ;CALL THE DRIVER'S LOGGING ROUTINE
JFCL ;ALLOW FOR PEOPLE WHO INSIST ON SKIP RETURNS
POPJ P, ;DONE LOGGING
;ROUTINE TO LOG A MASSBUS DEVICE ERROR
;CALL:
; MOVE W,KDB ADDRESS
; MOVE U,UDB ADDRESS
; MOVE F,DDB ADDRESS
; LDB J,PJOBN
; MOVEI T4,.FI???
; SETZ T1,
; PUSHJ P,@KONELG(W)
;RETURN:
; NON-SKIP ALWAYS, CLOBBERING ONLY T1-T4
MDEELG::MOVEI T1,45 ;LENGTH OF .ERMDE ENTRY FOR DAEMON/SPEAR
PUSH P,T4 ;SAVE THE SOFT ERROR CODE
PUSHJ P,ALCSEB## ;GET A SYSTEM ERROR BLOCK
JRST TPOPJ## ;PUNT IF NO CORE
POP P,.EBHDR+44(T1) ;SAVE THE SOFT CODE IN THE LAST WORD
XMOVEI T2,MDEBEG ;POINT TO OUR TRANSFER TABLE
PUSHJ P,XFRSEB## ;MOVE SOME DATA
JFCL ;CAN'T FAIL HERE
MOVE T3,UNILAS(U) ;LAST COMMAND ON ERROR
MOVEM T3,.EBHDR+42(T1) ;(R42) SAVE FOR DAEMON
MOVE T3,UNICCT(U) ;BAT BLOCK POINTER
MOVEM T3,.EBHDR+43(T1) ;(R43) SAVE FOR DAEMON
MOVE T3,KDBDVC(W) ;GET DEVICE CODE/4
DPB T3,[POINT 7,.EBHDR+04(T1),11] ;SAVE IN (R04)
MOVE T3,KDBCHN(W) ;GET CHANNEL DATA BLOCK ADDRESS
MOVE T3,CHNTYP(T3) ;GET ITS BITS
MOVEI T2,1 ;ASSUME AN RH10/DF10C
TLNE T3,CP.RH2 ;IF AN RH20,
MOVEI T2,2 ;THEN USE THIS CODE
TLNE T3,CP.R11 ;IF AN RH11,
MOVEI T2,3 ;THEN USE THIS CODE
DPB T2,[POINT 3,.EBHDR+04(T1),14] ;STORE IN (R04)
SETZM .EBHDR+22(T1) ;(R22-R41) CLEAR REGISTER WORDS IN CASE NOT USED
IFN FTXMON,<
MOVEI T2,17 ;MAX. NUMBER OF REGISTERS MINUS ONE
XMOVEI T3,.EBHDR+22(T1) ;SOURCE ADDRESS
XMOVEI T4,1(T3) ;DESTINATION ADDRESS
EXTEND T2,[XBLT] ;MOVE THE DATA
>
IFE FTXMON,<
MOVSI T2,.EBHDR+22(T1) ;SOURCE ADDRESS
HRRI T2,.EBHDR+23(T1) ;DESITINATION ADDRESS
BLT T2,.EBHDR+41(T1) ;CLEAR THE WORDS
>
SKIPN T2,KONREG(W) ;IF NO REGISTERS WERE SAVED,
JRST MDEEL1 ;THEN SKIP TRYING TO MOVE THEM
CAILE T2,20 ;MAX. NUMBER OF REGISTERS WE CAN COPY
MOVEI T2,20 ;RESTRICT THE DEVICE
IFE FTXMON,<
ADDI T2,.EBHDR+22(T1) ;GET END+1 POINTER
MOVSI T3,UNIEBK(U) ;SOURCE ADDRESS
HRRI T3,.EBHDR+22(T1) ;DESTINATION ADDRESS
BLT T3,-1(T2) ;COPY THE DRIVE REGISTERS
>
IFN FTXMON,<
XMOVEI T3,UNIEBK(U) ;SOURCE ADDRESS
XMOVEI T4,.EBHDR+22(T1) ;DESTINATION ADDRESS
EXTEND T2,[XBLT] ;COPY THE DRIVE REGISTERS
>
MDEEL1: PJRST QUESEB## ;GIVE THE ENTRY TO DAEMON AND RETURN
MDEBEG: SEBTBL(.ERMDE,MDEEND,) ;START OUR TRANSFER TABLE
MOVE UDBNAM(U) ;(R00) PHYSICAL UNIT NAME
MOVE UNIHID(U) ;(R01) PACK (HOME BLOCK) ID
MOVE UNILOG(U) ;(R02) LOGICAL UNIT NAME
MOVE UNIHBN(U) ;(R03) BLOCK OF LAST (HARD?) ERROR
MOVE UNIECT(U) ;(R04) RETRY COUNT
MOVE UNISOF(U) ;(R05) 1CONI - ERROR CONI AFTER INITIAL ATTEMPT
MOVE UNIERR(U) ;(R06) 2CONI - ERROR CONI AFTER 1ST RECAL.
MOVE UNIMCT(U) ;(R07) SOFTWARE DETECTED ERROR COUNTS
MOVE UNIPCT(U) ;(R10) SEEK INCOMPLETE ERRORS
MOVE UNIHNG(U) ;(R11) HUNG COUNTS
MOVE DEVFIL(F) ;(R12) FILE NAME
HLLZ DEVEXT(F) ;(R13) FILE EXTENSION
MOVE JBTPPN##(J) ;(R14) USER'S PPN
MOVE JBTNAM##(J) ;(R15) USER'S PROGRAM NAME
MOVE UNISCR(U) ;(R16) INITIAL CONTROL WORD AT ERROR
MOVE UNIHCR(U) ;(R17) FINAL CONTROL WORD AT ERROR
MOVE UNISDR(U) ;(R20) INITIAL DATA WORD AT ERROR
MOVE UNIHDR(U) ;(R21) FINAL DATA WORD AT ERROR
MDEEND:! ;END OF OUR TRANSFER TABLE
;ROUTINE TO RETURN THE CHANNEL PROGRAM AND IORB
;P3 PASSES THE ADDRESS OF THE IORB
;P4 RETURNS THE NUMBER OF BLOCKS
;P3 RETURNS SWPLST ADDRESS
RTNDRB: SKIPL KONDRB(J) ;HAVE A DRB?
JRST RTNDR1 ;NO
IFN FTKL10,<
SKIPE T1,DRBPRG##(P3) ;RETURN CHANNEL PROGRAM
PUSHJ P,RTNIOW##
SETZM DRBPRG##(P3) ;ERASE MEMORY OF IT
>
IFN FTCIDSK,<
PUSHJ P,RTNBHD ;RETURN BHD AND BSD(S)
>; END IFN FTCIDSK
HRRZ P4,DRBNUM##(P3) ;NUMBER OF BLOCKS
MOVE T1,P3 ;ADDR OF IORB
MOVE P3,DRBSWA##(T1) ;SWPLST ADDRESS
DSKOFF
SKIPL DEVSWP##(F)
SETZM DEVDRB##(F)
PUSHJ P,GIVDRB ;RETURN THE IORB
JRST DOPOPJ
RTNDR1:
IFN FTKL10,<
SKIPE T1,@KDBICP(J) ;RETURN THE FREE-CORE BLOCKS
PUSHJ P,RTNIOW##
SETZM @KDBICP(J) ;ERASE MEMORY OF IT
>
HRRZ P4,CHNNUM(P1) ;NO OF BLOCKS TRANSFERRED
MOVE P3,UNISWA(U) ;SWPLST ADDRESS
POPJ P,
IFN FTCIDSK,<
;ROUTINE TO LIGHT THE "TRY AGAIN" BIT
;P3 PASSES ADDR OF DRB
RTNTRY: MOVEI T1,DRPTRY## ;LIGHT "TRY AGAIN"
IORM T1,DRBSTS##(P3)
RTNBHD: SKIPE T1,DRBBHD##(P3) ;GET BUFFER NAME
PUSHJ P,PPDRHD## ;RETURN BHD AND BSD(S)
SETZM DRBBHD##(P3) ;DON'T DO THIS TWICE
POPJ P,
>
;ROUTINE TO SAVE ALL THE VOLATILE STUFF
;U PASSES UDB
;J PASSES KDB
;F PASSES DDB
;YOU MUST DISABLE DISK INTERRUPTS BEFORE CALLING THIS ROUTINE
DRSAVE: SKIPE T1,DEVDRB##(F) ;GET ADDR OF IORB
SKIPL KONDRB(J) ;MIGHT WE HAVE A DRB?
POPJ P, ;NO
PUSHJ P,SAVE2## ;SAVE AC
MOVE P1,KDBCHN(J) ;CHANNEL DATA BLOCK
MOVE P2,CHNNUM(P1)
MOVEM P2,DRBNUM##(T1)
MOVE P2,@KDBICP(J)
MOVEM P2,DRBPRG##(T1)
MOVE P2,KONDMP(J)
MOVEM P2,DRBDMP##(T1)
MOVE P2,UNIBLK(U)
MOVEM P2,DRBBLK##(T1)
HRLM U,DRBCUR##(T1)
HRRM F,DRBCDA##(T1)
MOVE P2,UNISWA(U)
MOVEM P2,DRBSWA##(T1)
IFN FTMP,<
MOVE P2,.CPCPN##
DPB P2,DRYCPU##
>
MOVE P2,UNIJOB(U)
DPB P2,DRYJOB##
POPJ P,
;ROUTINE TO RESTORE THE VOLATILE STUFF
;U PASSES UDB
;J PASSES KDB
;F PASSES DDB (THE DDB MUST BE ADDRESSABLE)
;YOU MUST DISABLE DISK INTERRUPTS BEFORE CALLING THIS ROUTINE
DRREST: SKIPE T1,DEVDRB##(F) ;GET ADDR OF IORB
;ENTER HERE WITH T1=IORB
DRRST: SKIPL KONDRB(J) ;MIGHT WE HAVE A DRB?
POPJ P, ;NO
PUSHJ P,SAVE2## ;SAVE AC
MOVE P1,KDBCHN(J) ;CHANNEL DATA BLOCK
MOVE P2,DRBNUM##(T1)
MOVEM P2,CHNNUM(P1)
REPEAT 0,<
MOVE P2,DRBPRG##(T1)
MOVEM P2,@KDBICP(J)
>
MOVE P2,DRBDMP##(T1)
MOVEM P2,KONDMP(J)
MOVE P2,DRBBLK##(T1)
MOVEM P2,UNIBLK(U)
HRRZM F,UNICDA(U)
MOVE P2,DRBSWA##(T1)
MOVEM P2,UNISWA(U)
LDB P2,DRYJOB##
MOVEM P2,UNIJOB(U)
MOVEI P2,DRPNFI## ;WORTH RESTORING, IT MUST BE FILLED IN
ANDCAM P2,DRBSTS##(T1)
POPJ P,
;ROUTINE TO ALLOCATE A DRB
;YOU MUST DISABLE DISK INTERRUPTS BEFORE CALLING THIS ROUTINE
;RETURNS CPOPJ1 WITH T1=DRB
;RETURNS CPOPJ IF NO DRBS (THE DDB HAS ALREADY BEEN QUEUED,
;AND INTERRUPTS ARE BACK ON)
GETDRB: MOVEI T2,SIZDRB## ;#SIZE OF A DRB
PUSHJ P,GETWDS## ;#GET SPACE FOR IT
JRST GTDRBE ;#NO FREE SPACE
SETZM (T1) ;#ZERO THE DRB
MOVS T2,T1
HRRI T2,1(T1)
BLT T2,SIZDRB##-1(T1)
MOVEI T2,DRPNFI## ;#NOT FILLED IN YET
MOVEM T2,DRBSTS##(T1)
HLRZ T2,ACTDRB## ;#LINK TO END OF ACTIVE LIST
HRLM T1,ACTDRB##
HRRM T1,DRBLNK##(T2)
HRLI T2,ACTDRB##
MOVSM T2,DRBLNK##(T1)
JRST CPOPJ1##
GTDRBE: SKIPE DINITF## ;#DURING INITIALIZATION?
STOPCD .,STOP,NODRB, ;++CAN'T ALLOCATE DISK IORB DURING ONCE
AOS ROODRB## ;#COUNT IT
MOVSI T1,KOPCNA ;#LIE ABOUT CREDITS SO CRNPOS DOESN'T KAF
IORM T1,KONCNA(J)
SKIPL DEVSWP##(F) ;#SWAPPER?
JRST UUOPW2 ;#NO, POSITION WAIT
JRST DOPOPJ ;#YES, DON'T QUEUE SWPDDB
;ROUTINE TO RETURN A DRB TO THE FREE POOL
;YOU MUST DISABLE DISK INTERRUPTS BEFORE CALLING THIS ROUTINE
;T1 PASSES ADDR OF DRB
GIVDRB: HLRZ T2,DRBLNK##(T1) ;#PRED
HRRZ T3,DRBLNK##(T1) ;#SUC
HRRM T3,DRBLNK##(T2) ;#UNLINK FROM ACTIVE LIST
HRLM T2,DRBLNK##(T3)
MOVEI T2,SIZDRB## ;#SIZE OF A DRB
EXCH T1,T2 ;#SWAP FOR CALL TO GIVWDS
PUSHJ P,GIVWDS## ;#RETURN THE DRB SPACE
IFE FTCIDSK,<
POPJ P, ;#RETURN
>; END IFE FTCIDSK
IFN FTCIDSK,<
SKIPN DINITF## ;#DON'T SCREW AROUND DURING ONCE
PUSHJ P,INTLVL## ;#AT INTERRUPT LEVEL?
POPJ P, ;#DON'T CHANGE UBR AT UUO LEVEL
DSKON
PUSHJ P,SSEUB ;SAVE UBR
PUSH P,F ;SAVE DDB
PUSH P,U ;SAVE UNIT
MOVEI U,SYSUNI##-UNISYS
GVDRB1: HLRZ U,UNISYS(U) ;GET NEXT UNIT
JUMPE U,GVDRB2 ;NONE LEFT
MOVE J,UDBKDB(U) ;MULTIPLE XFERS?
SKIPL KONMX(J)
JRST GVDRB1 ;NO
PUSHJ P,CRNPOS ;WAKE ANYBODY IN PW
JRST GVDRB1
GVDRB2: POP P,U ;RESTORE ORIGINAL UNIT
MOVE J,UDBKDB(U) ;ORIGINAL KON
MOVE P1,KDBCHN(J) ;ORIGINAL CHAN
JRST FPOPJ## ;RESTORE DDB
>; END IFN FTCIDSK
IFN FTCIDSK,<
CIBAD: SKIPL KONMX(J) ;MULTIPLE XFERS?
POPJ P, ;NO
STOPCD CPOPJ##,JOB,HSF,;++HSC50 NOT FANCY
>
IFN FTCIDSK,<
;ROUTINE TO RETRY SWAP REQUESTS THAT WENT OFF-LINE
;THIS IS NORMALLY DONE VIA UNITIM, BUT CI DISKS CAN
;HAVE MULTIPLE XFERS IN PROGRESS AT THE SAME TIME, AND UNITIM
;CAN ONLY TIME ONE OF THEM.
RESWP: MOVE T1,LOCSEC## ;TIME TO TRY AGAIN?
IDIVI T1,DSKTIM##
JUMPN T2,CPOPJ##
RESWP4: MOVEI P3,ACTDRB##-DRBLNK##;PRESET PRED
RESWP2: DSKOFF
RESWP1: HRRZ P3,DRBLNK##(P3) ;#STEP TO THE NEXT DRB
JUMPE P3,DOPOPJ ;#PARANOIA
CAIN P3,ACTDRB##
JRST DOPOPJ ;#NONE
MOVE T3,DRBSTS##(P3) ;#NEED TO RETRY THIS ONE?
TRNN T3,DRPTRY##
JRST RESWP1 ;#NO
HRRZ F,DRBCDA##(P3) ;#DDB
IFN FTMP,<
LDB T2,DRZCPU## ;#THIS CPU?
CAME T2,.CPCPN##
JRST RESWP1 ;#NO
IFN FTKL10,<
MOVE P1,DRBSWA##(P3) ;#SWPLST ADDR
CAIN F,SWPDDB## ;#IS THIS A SWAP?
TLNE P1,-1 ;#PAGES CAN'T BE FRAGMENTED
JRST RESWP3 ;#NOT A PAGE SWAP
MOVE T1,SWPLST##(P1) ;#GET SWPLST ENTRY
TLNE T1,(SL.DIO) ;#OUTPUT?
TLNE T1,(SL.SIO) ;#AND PAGING?
JRST RESWP3 ;#NO
PUSHJ P,SW2LC## ;#COMPUTE SWPLST OFFSET
HRRZ J,SW3LST##(T1) ;#GET JOB NUMBER
PUSHJ P,SBCCSH## ;#DOES JOB HAVE STUFF IN CACHE?
JRST RESWP3 ;#CACHE IS OK
MOVSI T1,(CR.DET)
SKIPL .CPOK##-.CPCDB##(T4);#IS THAT CPU RUNNING?
TDNN T1,.CPRUN##-.CPCDB##(T4);#NO, IS IT DETACHED?
JRST RESWP1 ;#WAIT FOR CPU TO SWEEP
MOVEI T1,OPWRT##+IODERR;#NOT RUNNING AND DETACHED,
MOVE T3,P3 ;#GIVE HIM A SWAP READ ERROR
SETZ T4,
PUSHJ P,FLHTID
JRST RESWP4
RESWP3:
>
>
MOVEI T2,KONERM+DRPTRY##;#ANCIENT HISTORY
ANDCAM T2,DRBSTS##(P3)
LDB J,DRZJOB## ;#JOB NUMBER
PUSHJ P,MKADD## ;#MAKE IT ADDRESSABLE
MOVE S,DEVIOS(F) ;#I/O BIT
HLRZ U,DRBCUR##(P3)
MOVE J,UDBKDB(U)
MOVE P1,KDBCHN(J)
MOVE T1,P3
PUSH P,F ;#SAVE DDB
PUSHJ P,STARTG ;#DO THE TRANSFER
POP P,F
CAIE F,SWPDDB## ;SWAPPER?
JRST RESWP4 ;IF FILE GOT TO BADUNI THEN DRB IS GONE
JRST RESWP2
>
;HERE IF FILE IS ON A POSITIONING DEVICE
;SET FILE TO PW STATE, ADD TO PWQ
SETPW: MOVEI T1,PWCOD ;#SET FILE, UNIT TO PW
PUSHJ P,FILCOD
IFN FTDUAL,<
PUSHJ P,SECCOD ;#SET STATE OF PRIME UNIT IF THIS ALTERNATE
>
MOVEI T1,UNIQUE(U) ;#SET T1=UNI PWQ
PUSHJ P,PUTQUE ;#PUT FILE ON Q
JRST SETI12 ;#AND LOOK FOR ANY POSITIONING TO DO
;HERE WHEN MONITOR IO DONE - SET FILE TO IDLE
SETMDL: MOVEI T1,UNIMRC(U) ;SET TO UPDATE UNIMRC (UNIMWC)
PUSHJ P,UPSTAT ;UPDATE STATISTICS FOR UNIT
SKIPE DEVRHB##(F) ;IF NOT REREADING HOME BLOCKS
SKIPGE DEVSWP##(F) ; AND NOT THE SWAPPER
JRST SETID3
JRST SETID2
SETID1: TLNN P3,-1 ;COMPLETE ANY BUFFERS?
TLO S,IOSTBL ;NO, GET BACK TO UUO LEVEL WITH PARTIAL BUFFER
SETID2: TRZ S,IOACT ;FIGHT RACE
PUSHJ P,STDIOD## ;WAKE JOB IF IN IOWAIT
PUSHJ P,CLRACT## ;GET IOACT OFF IN DDB NOW (DUAL CPU RACE)
;HERE TO SET FILE TO IDLE
SETID3: SKIPL DEVSWP##(F) ;IF NOT THE SWAPPER
TLZ S,IOSMON ;MAKE SURE IOSMON IS OFF
SKIPE DEVRHB##(F)
JRST SETID4
SOSL HOMFLG##
JRST RERED0 ;COUNT IS STILL REASONABLE
STOPCD .+1,DEBUG,RHN, ;++REREAD-HOMEBLOCK-COUNT NEGATIVE
SETZM HOMFLG## ;MAKE IT REASONABLE
JRST RERED1 ;THIS DIDN'T HAPPEN
RERED0: MOVSI T2,UNPRHB ;CLEAR REREAD HOME BLOCKS
ANDCAM T2,UNIDES(U) ; FROM UDB
MOVEI T2,UNPRHP
ANDCAM T2,UNIRHP(U)
TRNE S,IOIMPM ;READ GO OK?
JRST RERED1 ;WENT OFF-LINE AGAIN
MOVS T1,HOMBUF##
TRNN S,IODERR+IODTER ;ANY DATA ERRORS
CAIE T1,'HOM' ;AND IS FIRST WORD HOME?
JRST RERED2 ;NO, READ DIDN'T GO OK
MOVE T1,UNIHID(U) ;READ OK, IS IT WHAT WE EXPECT?
CAME T1,HOMBUF##+HOMHID##
JRST REREDA ;NO, HOME BLOCKS DONT MATCH
PUSHJ P,FJCONT## ;YES, FORCE A JCONT
RERED1: PUSHJ P,CLRDDB## ;ALL IS WELL, GIVE UP DDB
SETZB F,UNISTS(U) ;SET UNIT IDLE (ONLY THIS PORT)
JRST SETID5 ;AND CONTINUE
;HERE IF CANT READ HOME BLOCKS OR NO MATCH
REREDA: MOVE T2,DEVBLK##(F) ;GET BLOCK WE READ
SOJN T2,RERED2 ;IF IT WASN'T FIRST HOME BLOCK,BOTH ARE BAD
PUSH P,F ;SAVE F AND U
PUSH P,U
MOVE U,OPRLDB## ;TALK TO OPR
PUSHJ P,INLMES##
BYTE (7)7,7,7,7,7 ;SOME BELLS
ASCIZ /
Error trying to reread 1st HOME block,
Attempting to read 2nd HOME block on /
MOVE T2,(P) ;UDB
MOVE T2,UDBNAM(T2) ;PHYSICAL UNIT
PUSHJ P,PRNAME## ;TYPE IT OUT
PUSHJ P,CRLF## ;CARRIAGE RETURN
POP P,U ;RESTORE U AND F
POP P,F
AOS HOMFLG## ;SET TO READ 2ND HOME BLOCK
HRRZ T1,UNIHOM(U) ;2ND HOME BLOCK NUMBER
JRST TSTRH1 ;START THE READ AND RETURN
;HERE WHEN BOTH HOME BLOCKS ARE BAD OR NO MATCH
RERED2:
IFN FTMDA,<
SKIPGE UNIPTR(U) ;IF UNIT HAS SWAPPING SPACE
JRST RERED3 ; COMPLAIN TO THE OPERATOR
PUSHJ P,CALMDA ;OTHERWISE LET MDA HANDLE IT
JRST RERED3 ;NO MDA, COMPLAIN
PUSHJ P,CLRDDB## ;MDA IS RUNNING, RETURN DDB
PUSHJ P,SET4MD ;SET SO ONLY MDA CAN READ DRIVE
JRST SETID9 ;AND GO FIND SOMETHING ELSE TO DO
RERED3:>
;HERE IF UNIT HAD SWAPPING SPACE OR IF MDE ISNT RUNNING. COMPLAIN ABOUT UNIT
PUSH P,F ;SAVE F AND U
PUSH P,U
MOVE U,OPRLDB## ;TALK TO OPR
MOVS T2,HOMBUF##
TRNN S,IODTER+IODERR ;WAS IT AN I/O ERROR?
CAIE T2,'HOM' ;OR HOME BLOCK BAD?
JRST RERED4 ;YES,THEN WHO KNOWS WHAT PACK IT IS?
PUSHJ P,INLMES## ;NO, HOME BLOCKS DON'T MATCH, WRONG PACK UP
BYTE (7)7,7,7,7,7 ;SOME BELLS
ASCIZ /
Wrong pack powered up on /
JRST RERED5
RERED4: PUSHJ P,INLMES## ;ERROR IN HOME BLOCKS
BYTE (7)7,7,7,7,7 ;SOME BELLS
ASCIZ /
Error trying to reread HOME blocks on /
MOVSI T2,'???' ;WHAT WE READ
MOVEM T2,HOMBUF##+HOMHID##
RERED5: MOVE T2,(P) ;UDB
PUSH P,UNIHID(T2) ;SAVE WHAT WE THINK IT IS
MOVE T2,UDBNAM(T2) ;PHYSICAL NAME
PUSHJ P,PRNAME##
PUSHJ P,INLMES##
ASCIZ / is /
MOVE T2,HOMBUF##+HOMHID## ;WHAT WE READ
PUSHJ P,PRNAME##
PUSHJ P,INLMES##
ASCIZ /, should be /
POP P,T2 ;WHAT WE EXPECT
PUSHJ P,PRNAME##
MOVS T2,HOMBUF##
TRNN S,IODTER+IODERR ;NO I/O ERRORS?
CAIE T2,'HOM' ;HOME BLOCK OK?
JRST [PUSHJ P,CRLF## ;NO,THEN CORRECT PACK IS ALREADY MOUNTED
JRST RERED6] ;EXIT
PUSHJ P,INLMES##
ASCIZ /
Please dismount it and mount the correct pack
/
RERED6: POP P,U
POP P,F ;RESTORE ACS
MOVEI T1,OCOD ;SET FOR ONCE-A-MINUTE GRUMP AT OPR
MOVEM T1,UNISTS(U) ; AND NO IO TO START WHEN IT COMES UP
PUSHJ P,CLRDDB## ;RETURN THE FAKE DDB
JRST SETID9 ;AND FIND SOMETHING ELSE TO DO
IFN FTMDA,<
;SUBROUTINE TO SEND A MESSAGE TO THE MOUNTABLE DEVICE ALLOCATOR
CALMDA: MOVE T1,UDBNAM(U) ;SIXBIT /DEV NAME/
MOVEI T2,.TYDSK ;ITS A DSK
PUSHJ P,SNDMDC## ;TELL MDC
POPJ P, ;MDC ISNT THERE
JRST CPOPJ1## ;MDC IS THERE
>
;HERE FROM BADUN1 TO SET THE FILE IDLE. DON'T CLEAR IOSMON
SETID4:
IFN FTMP,<
DSKOFF
>
IFE FTCIDSK,<
MOVEI T1,ICOD ;SET FILE AND UNIT IDLE
PUSHJ P,FILCOD
>
IFN FTCIDSK,<
MOVE T1,UNISTS(U) ;OPR WAIT?
CAIE T1,OCOD
CAIN T1,O2COD
SKIPL KONMX(J) ;AND MULTIPLE XFERS?
MOVEI T1,ICOD ;NO, SET IT IDLE
MOVEM T1,UNISTS(U) ;YES, LEAVE IT ALONE
MOVEI T1,ICOD ;ALWAYS SET DDB IDLE
DPB T1,DEYCOD##
>
SETID5:
IFN FTDUAL,<
SKIPN UNIQUE(U) ;THIS UNIT GOING IDLE?
SKIPN T3,UNI2ND(U) ;YES, IS THERE A PRIME UNIT?
JRST SETID8 ;NO
SKIPN UNIQUE(T3) ;YES, PUT POS. QUEUE OF PRIME UNIT
JRST SETID8 ;PRIME UNIT IDLE - NO PROBLEMS
IFN FTKL10&FTMP,<
MOVE T1,UDBCAM(T3) ;IS THE OTHER PORT ON THIS CPU?
CAMN T1,.CPBIT## ;BOTH PORTS ON SAME CPU?
JRST SETID7 ;YES
PUSHJ P,CPUOK## ;NO, IS OTHER CPU ALIVE?
JRST SETID8 ;NO, WAIT FOR DSKRQT
IFN FTCIDSK,<
;THIS CODE ISN'T VERY EFFICIENT FOR AN HSC50.
;IF WE EVER GET AN HSC50 WITH DISKS WHICH ARE TRUELY DUAL PORTED,
;THEN WE MIGHT WANT TO REWRITE THIS CODE.
>
;HERE IF THIS PORT IDLE, OTHER PORT HAS A POSITION QUEUE, OTHER PORT ON ANOTHER CPU
; WE CAN'T SIMPLY SWITCH QUEUE TO OTHER PORT SINCE THE IO ISN'T RIGHT WRT OUR CACHE
PUSHJ P,PWQSP ;QUEUE A CLOCK REQUEST FOR SECOND PORT
JRST SETID8
SETID7: > ;END FTKL10&FTMP
HRRZ T3,UNI2ND(U) ;SECOND PORT
MOVE T2,UNIQUE(T3) ;1ST DDB
MOVEM T2,UNIQUE(U) ; ONTO THIS UNIT INSTEAD, TO START SEEK
SETZB T2,UNIQUE(T3) ; ON THIS UNIT NOW. PRIME UNIT HAS NO QUEUE NOW
EXCH T2,UNIQUL(T3)
MOVEM T2,UNIQUL(U)
SKIPL DEVSWP##(F)
JRST SETID8
HRRZS UNICDA(T3) ;INDICATE OTHER PORT IS ACTIVE
HRROS UNICDA(U) ; (FOR SPURIOUS INTERRUPT TEST)
SETID8:> ;END FTDUAL
IFN FTCIDSK,<
SKIPL KONMX(J) ;LEAVE UNISTS ALONE
>
SKIPN UNIQUE(U) ;POSITIONS WAITING?
SKIPA T1,UNISTS(U) ;NO, LEAVE UNISTS ALONE
MOVEI T1,PWCOD ;YES, SET STATUS
MOVEM T1,UNISTS(U)
IFN FTMDA,<
SKIPE UNIQUE(U) ;UNIT GOING IDLE?
JRST SETID9 ;NO
MOVE T1,UNIDES(U) ;YES. ONLY READABLE BY MDA?
MOVEI T2,MDACOD
TLNE T1,UNPWMD
MOVEM T2,UNISTS(U) ;YES. RESET UNISTS
>
SETID9:
IFN FTDUAL,<
SKIPN UNIQUE(U) ;IF PORT B OF DUAL-PORTED DRIVE
; LEAVE THE A-SIDE IN T STATE
; TO PREVENT SWPSCN FROM STARTING
PUSHJ P,SECCOD
>
PUSHJ P,FLPJOB ;FLIP UNIJOB AND UNICDA
SETZM UNITIM(U)
JUMPE F,SETI12
SKIPGE DEVSWP##(F) ;SWAPPER?
JRST SETI11 ;YES, TELL VMSER ABOUT THE REQUEST
TRNE S,IOACT ;NO, DID WE ALREADY CLEAR IOACT?
PUSHJ P,CLRACT## ;CLEAR IOACT
JRST SETI12 ;CONTINUE
IFN FTMP&<FTKL10&FTDUAL!FTCIDSK>,<
;HERE WHEN THE OWNING CPU HITS THE NEXT CLOCK TICK. CRANK THE UNIT UP IF IDLE
SETI10: MOVE U,T1 ;UNIT WE WANT TO START
PUSHJ P,SSEUB##
PUSHJ P,SAVE1##
MOVE P1,UDBKDB(U) ;POINT AT CHAN IN CASE ON CYLINDER
MOVE P1,KDBCHN(P1)
DSKOFF
MOVEI T1,UNPPWQ ;CLOCK REQUEST NOT OUTSTANDING
ANDCAM T1,UNIPWQ(U)
SKIPE DIADSK## ;TRYING TO SHUT DOWN I/O
CAME P1,DIACHN## ;YES, FOR THIS CHANNEL?
CAIA ;NO
JRST DOPOPJ ;YES, DON'T START ANYTHING
PUSHJ P,CRNPOS ;YES, START THE SEEK NOW
PJRST DOPOPJ ;PION AND RETURN
;ROUTINE TO SEND A CLOCK REQUEST TO THE OTHER CPU.
;THE OTHER CPU WILL PROCESS THE POSITION WAIT QUEUE.
;HERE WITH T1=CPU
IFN FTCIDSK,<
PWQPP: SKIPA T3,U ;PRIME PORT
>
PWQSP: HRRZ T3,UNI2ND(U) ;SECOND PORT
MOVEI T2,UNPPWQ ;ALREADY QUEUED A CLOCK REQUEST?
TDNE T2,UNIPWQ(T3)
POPJ P, ;YES, DON'T OVERFLOW THE QUEUE
IORM T2,UNIPWQ(T3) ;NO, WILL QUEUE ONE
MOVEI T2,SETI10 ;ROUTINE ADDR
;JRST QUECLK ;QUEUE IT
> ;END FTMP&<FTKL10&FTDUAL!FTCIDSK>
IFN FTMP,<
;ROUTINE TO QUEUE A CLOCK REQUEST
;T1 PASSES CPU NUMBER
;T2 PASSES ROUTINE ADDR
;T3 PASSES DATA
QUECLK::DPB T1,[POINT 3,T3,3];CPU
TLO T3,(1B0) ;ONLY THIS CPU WILL DO
HRLZS T2 ;ROUTINE IN LH
HRRI T2,1 ;ONE TICK
SYSPIF ;NO INTERRUPTS
IDPB T2,CLOCK## ;INSERT QUEUE ENTRY
IDPB T3,CLOCK##
SETZM CLKMIN##(T1) ;RE-SCAN CLOCK QUEUE
PJRST ONPOPJ## ;RE-ENABLE INTERRUPTS AND RETURN
>
SETI11: HRRZ T1,P4 ;NUMBER OF BLOCKS
MOVE P1,P3 ;SWPLST ADDRESS
PUSH P,U
PUSHJ P,DONE##
MOVEI F,SWPDDB##
POP P,U
MOVE J,UDBKDB(U) ;DONE ZAPS EVERYBODY
MOVE P1,KDBCHN(J)
MOVSI T1,UNPUNO
ANDCAM T1,UNIDES(U)
SETI12:
IFN FTMP,<
DSKON
>
MOVEI F,SWPDDB## ;MAKE SURE F POINTS TO THE SWAPPER
SKIPN SQREQ## ;SWAPPER GOING?
JRST SETI13 ;NO
SKIPN P1 ;AT UUO LEVEL?
AOSA .CPSWP## ;YES, FORCE SWPSCN TO BE CALLED AT UUO LEVEL
PUSHJ P,SWPSCN## ;YES, START SWAP SEEKS FIRST
SETI13: JUMPE P1,CHNIDX ;DONT START IO (CHANGE UBR) AT UUO LEVEL
SKIPG KONPOS(J) ;DOES KONTROL POSITION?
JRST PIKTRX ;NO, LOOK FOR BEST TRANSFER
;YES. START ANY WAITING POSITIONS
;HERE TO PICK THE BEST FILE ON EACH UNIT TO START POSITIONING
PIKPOS: SKIPLE DIADSK## ;IF WAITING FOR DIAG
CAME P1,DIACHN## ; FOR THIS CHANNEL
CAIA
JRST PIKTRX ;DON'T START ANOTHER SEEK
PUSH P,U ;SAVE U (LAST UNIT TO LOOK AT)
KONLUP: HRR U,UNIKON(U) ;STEP TO NEXT UNIT IN RING
PUSHJ P,UNIPOS ;START UNIT POSITIONING
CAME U,(P) ;WAS THIS LAST UNIT ON KONTROL?
JRST KONLUP ;NO, STEP TO NEXT UNIT
POP P,T1 ;YES, REMOVE U FROM PD LIST
MOVE J,UDBKDB(U) ;GET KON BACK
JRST PIKTRX ;GO LOOK FOR A FILE TO START XFER ON
;SUBROUTINE TO GET A DDB
FAKDDX: PUSH P,J ;FAKDDB WIPES OUT J
PUSHJ P,FAKDDB## ;GET ONE
JRST JPOPJ## ;NO FREE CORE
SETZ J, ;CANT BLAME THIS READ ON ANY JOB,
DPB J,PJOBN## ; SO SET PJOBN = 0
JRST JPOPJ1## ;RESTORE J AND GOODNESS-RETURN
;ROUTINE TO START POSITIONING DURING CRANK-UP
CRNPOS: MOVE J,UDBKDB(U) ;KDB
MOVE P1,KDBCHN(J) ;CHAN
SKIPGE KONBSY(J) ;KONTROLLER BUSY?
POPJ P, ;YES, WAIT TILL XFER DONE
;SUBROUTINE TO PICK A FILE ON A UNIT AND START POSITIONING FOR THAT FILE
;ENTER WITH U=LOC OF UNIT DATA BLOCK
;EXIT CPOPJ, A FILE IS NOW POSITIONING ON THE UNIT
UNIPOS: SKIPE T1,UNIQUE(U) ;POSITIONS WAITING?
SKIPE T1,UNISTS(U) ;AND EITHER IDLE OR PW?
CAIN T1,PWCOD
PUSHJ P,RHBP ;AND DON'T NEED TO REREAD HOME BLOCKS?
POPJ P,
IFN FTCIDSK,<
SKIPGE KONCNA(J) ;MUST HAVE CREDITS
POPJ P,
>
PUSHJ P,SAVE4##
UNIPS1: DSKON
PUSH P,S ;SAVE S
HRLOI P3,377777 ;SET P3 (BEST DISTANCE) TO PLUS INFINITY
MOVEI F,UNIQUE-DEVQUE##(U) ;ADDR OF 1ST LINK
IFE FTMP&FTCIDSK,<SETZ P4,> ;NONE SO FAR
IFN FTMP&FTCIDSK,<
TDZA P4,P4
PWQLP6: PUSHJ P,PWQPP ;TELL THE OTHER CPU
>
PWQLP8: MOVE S,F ;SAVE PRED
MOVS F,DEVQUE##(F) ;STEP TO NEXT DDB
JUMPE F,PWQLP7 ;GO IF NONE LEFT
HLRZ J,F ;JOB NUMBER WHICH OWNS DDB
PUSHJ P,MKADD## ;MAKE IT ADDRESSABLE
IFN FTMP&FTCIDSK,<
LDB T1,DEYPCL## ;CAN WE DO IT ON THIS CPU?
CAIN T1,PCLCP0##
SETZ T1,
CAME T1,.CPCPN##
JRST PWQLP6 ;NO
>
PUSHJ P,CYLCMJ ;COMPUTE DISTANCE TO TARGET CYLINDER
MOVMS T2,T1 ;ABSOLUTE VALUE
TLO T1,20000 ;THIS BIT MEANS OFF CYL
JUMPN T2,PWQLP9 ;GO IF REALLY IS OFF CYL
MOVE T1,DEVBLK##(F) ;GET BLOCK NUMBER BACK
PUSHJ P,@KONLTM(J) ;GET ROTATIONAL LATENCY
SETZ T1,
PWQLP9: PUSHJ P,DFPRI
MOVNI T2,MXNDPR##(T2)
TLNE T1,20000
DPB T2,[POINT 3,T1,3]
SKIPLE CHNCFP(P1) ;IS IT TIME TO BE FAIR?
CAMG T1,P3 ;NO, IS THIS BEST SO FAR?
PUSHJ P,SVBST ;YES, SAVE POINTERS TO IT
;P4=BEST F,P3=DIST TO BEST P2=PRED. F
JRST PWQLP8 ;LOOP
PWQLP7: POP P,S ;RESTORE S
JUMPE P4,CPOPJ## ;NOTHING TO DO
DSKOFF
IFN FTMP,<
;#SWPSCN AT CLOCK LEVEL ON OTHER CPU
MOVE T2,UNISTS(U) ;# COULD START AN OPERATION ON UNIT
CAIE T2,PWCOD ;# SO INTERLOCK AND CHECK
JUMPN T2,DOPOPJ ;WE DON'T OWN UNIT ANYMORE.
>
;HERE P4 HAS POINTER TO BEST FILE, P2=PREDECESSOR, P3=DISTANCE
MOVE F,P4 ;#SET F TO FILE
PUSHJ P,UNQUER ;#REMOVE FILE FROM Q
JRST UNIPS1 ;#RACE, TRY AGAIN
SOS UNIQUL(U) ;#COUNT IT
TLNE P3,20000 ;#ALREADY ON CYLINDER?
PUSHJ P,TSTGEN ;#OR FILE STR REMOVED?
JRST PWQOK ;#YES, SET TO TW
MOVE T1,KONPOS(J) ;#OK TO POSITION?
TLNN T1,KOPPWX
SKIPL KONBSY(J)
JRST STRPOS ;#YES, START POSITION GOING
CONSZ PI,PI.IPA-PI.IP7;#AT INTERRUPT LEVEL?
JRST STRPOS ;#YES, IGNORE BUSY BIT
;RACE: WE WERE AT CLOCK LEVEL WITH INTERRUPTS ON, WE GOT A POSITION DONE
;INTERRUPT (ON SOME OTHER DRIVE) AND STARTED A TRANSFER.
JRST UUOPW2 ;#BACK INTO THE QUEUE
;HERE IF A FILE IS ALREADY ON CYLINDER
PWQOK: PUSH P,S ;#SAVE S
PUSHJ P,STORF ;SO SWAPPER WILL KNOW
IFN FTDUAL,<
PUSH P,U
HRRM U,DEVCUR##(F) ;#IN CASE OF SETID7
>
PUSHJ P,UUOTWQ ;#PW STATE - ADD FILE TO TWQ,SET STATE TO TW
;(UNLESS THERE WAS A SEEK WHICH WE FORGOT
;BECAUSE OF A POSITION REQUEST, AND THE POSITION
;IS ALREADY ON-CYLINDER. IN THAT CASE, I/O
;WILL BE STARTED)
IFN FTDUAL,<
POP P,U ;IF WE STARTED IO ON ALTERNATE UNIT
MOVE J,UDBKDB(U) ;THEN U, J AND P1 WERE CHANGED
MOVE P1,KDBCHN(J) ;SO RESET THEM
>
POP P,S ;RESTORE S
IFN FTCIDSK,<
SKIPL KONCNA(J) ;CREDITS AVAILABLE?
SKIPL KONMX(J) ;AND MULTIPLE XFERS?
POPJ P, ;NO
JRST UNIPS1 ;TRY TO START ANOTHER
;NOTE THAT WE DELIBERATELY TAKE THE OLDEST GUY OUT OF THE QUEUE.
;THIS WILL INSURE FAIRNESS IF WE ARE SITTING RIGHT ON THE CREDIT LIMIT.
;NOTE THAT FOR A CI DISK, THE CREDIT CONSTRAINT IS PROBABLY THE REASON
;THE GUY WAS PUT IN PW TO BEGIN WITH.
>
POPJ P,
;SUBROUTINE TO UPDATE DDB, ADVANCE BUFFERS AFTER A DATA TRANSFER
;ENTER WITH P4=CHNNUM= NUMBER OF BLOCKS TO ADVANCE
;RETURNS WITH P3=ADVBFE OR ADVBFF DEPENDING ON INPUT OR OUTPUT
; AND LH(P3)=NUMBER OF BUFFERS DONE
;CHANGES P3,P4
BUFAD: PUSH P,P4 ;SAVE NUMBER OF BLOCKS
MOVNM P4,T1 ;DECREASE NUMBER OF BLOCKS LEFT
ADDM T1,DEVLFT##(F) ;BY NUMBER OF BLOCKS XFERRED
ADDM P4,DEVBLK##(F) ;UPDATE FILE CURRENT BLOCK NUMBER
TLNE S,IOSUPR ;IO FROM SUPER USETI/USETO?
JRST BUFAD2 ;YES. DONT TOUCH A.T.
MOVE T1,DEVACC##(F) ;NO, GET A.T.
ADDB P4,DEVREL##(F) ;UPDATE CURRENT RELATIVE BLOCK NUMBER
IFN FTCIDSK,<
SKIPL KONMX(J)
>
SETZM KONDMP(J) ;INDICATE WE'RE DONE
SOJN P4,BUFAD1 ;-1=HIGHEST BLOCK WRITTEN
TLO S,IOSFIR ;NEXT BLOCK = 1 - SET FOR CHKSUM
MOVEM S,DEVIOS(F) ;SAVE S IN DDB
BUFAD1: MOVE T3,ACCWRT##(T1) ;SET T3 NEGATIVE IF NEW
SUB T3,P4 ; LAST BLOCK, 0 IF OLD LAST
CAMLE P4,ACCWRT##(T1) ;THIS BLOCK HIGHER THAN FORMER HIGHEST?
MOVEM P4,ACCWRT##(T1) ;YES, SAVE NEW HIGHEST WRITTEN
SKIPE ACCWRT##(T1) ;IF RIB, NOT LAST BLOCK
CAME P4,ACCWRT##(T1) ;LAST BLOCK?
BUFAD2: TLZA P3,-1 ;NO, LH(P3)=0
HRL P3,T1 ;YES, LH(P3)=LOC OF A.T.
POP P,P4 ;NUMBER OF BLOCKS TRANSFERRED AGAIN
JUMPGE P2,BUFAD3 ;GO IF NOT DUMP MODE
SKIPGE T3 ;DUMP MODE. HAS LENGTH INCREASED
PUSHJ P,RBCHD ;YES, SET FOR PSI/REWRITE RIB
MOVEI T1,UNIDRC(U) ;SET FOR DUMP-MODE STATS
PJRST UPSTA ;UPDATE UNIDRC(DWC) AND RETURN
;HERE TO ADVANCE BUFFERS
BUFAD3: MOVEI T1,UNIBRC(U) ;SET TO UPDATE BUFFERRED-MODE STATS
PUSHJ P,UPSTAT ;UPDATE UNIBRC(BWC)
HRRI P3,ADVBFO## ;SET TO ADVANCE BUFFERS
TLNE S,IO
JRST BUFAD4
HRRI P3,ADVBFI##
TLNE P3,-1 ;IF READING AT END
TLZ S,IOSPBF ;ITS AN EOF, NOT A PARTIAL
BUFAD4: LDB T1,DEYNB1## ;NUMBER OF BLOCKS IN BUFFER BEFORE START
ADD T1,P4 ;PLUS NUMBER DONE IN THIS OPERATION
LDB T2,DEYNBB## ;NO OF BLOCKS PER BUFFER
IDIVI T1,(T2) ;COMPUTE NO OF BUFFERS FINISHED
SKIPN T2 ;EVEN NUMBER OF BUFFERS?
TLZA S,IOSPBF ;YES. MAKE SURE PBF=0 (HARD ERROR COULD HAVE IT ON)
TLNE S,IOSPBF ;NO, FINISH A PREVIOUS PARTIAL?
SOS T1 ;EVEN OR A PREVIOUS PARTIAL
MOVEM S,DEVIOS(F)
AOSE P4,T1 ;P4=NUMBER OF BUFFERS WE FINISHED
JRST BUFAD5 ;GO IF AT LEAST 1
;HERE WITH NO COMPLETED BUFFERS
TLZE P3,-1 ;AT EOF?
TLNN S,IO ;NOT EOF. WRITING
JRST CPOPJ1## ;EOF OR PARTIAL WHILE READING
PUSH P,P4 ;PARTIAL BUFFER WHILE WRITING AT EOF
MOVE T2,DEVACC##(F) ;MAKE STACK, ACS RIGHT
SOJA P4,BUFAD7 ;SET P4 NEGATIVE AND FIX UP A.T.
;HERE WITH AT LEAST 1 FINISHED BUFFER
BUFAD5: PUSH P,P4
IFN FTKL10&FTMP,<
TLNE S,IO ;WRITING?
JRST BUFAD6 ;YES, CONTINUE
PUSHJ P,STONBF## ;NO, UPDATE NUMBER OF BUFS WE'VE SWEPT FOR
ADDM P4,DEVNBF(F) ;UPDATE NUMBER NOT YET SWEPT FOR
>
BUFAD6: SOJN P4,BUFA11 ;GO IF NOT LAST BUFFER
HLRZ T2,P3 ;LAST - LOC OF ACC IF I/O TO LAST BLOCK OF FILE
JUMPE T2,BUFA11 ;NOT LAST BLOCK IF 0
;HERE WHEN DOING I/O TO LAST BLOCK OF THE FILE
TLNE S,IO ;WRITING?
JRST BUFAD7 ;YES, COMPUTE LBS
LDB T2,ACYLBS## ;READING LAST BLOCK - GET ITS SIZE
SUBI T2,BLKSIZ## ;NOT-FILLED AMOUNT IN LAST BLOCK
HRRZ T1,DEVIAD(F) ;GET LOC OF BUFFER
EXCTUU <ADDM T2,1(T1)> ;ADJUST LAST BUFFER'S WORDCOUNT
JRST BUFA10 ;AND FINISH UP
;HERE WHEN WRITING LAST BLOCK OF A FILE - COMPUTE LAST BLOCK SIZE
BUFAD7: HRRZ T1,DEVOAD(F) ;ADDRESS OF LAST BUFFER
EXCTUX <HRRZ T4,1(T1)>;GET WRDCNT OF LAST BUFFER
TLNE S,IOSPBF ;PARTIAL BUFFER WRITTEN?
EXCTUX <HLRZ T4,1(T1)> ;YES, GET AMOUNT DONE SO FAR
JUMPE T4,BUFAD8 ;WHOLE THING IF EMPTY BUF
EXCTUX <HLRZ T1,(T1)> ;GET LENGTH OF BUFFER
TRZ T1,400177 ;CLEAR EXTRANEOUS BITS
CAMLE T4,T1 ;LEGAL?
MOVE T4,T1 ;USER SMASHED RING. ASSUME FULL BUF
SUB T1,T4 ;NOT-FILLED LENGTH OF LAST BUFFER
LSH T1,MBKLSH## ;CONVERT TO BLOCKS
MOVNS T1 ;NOT-FILLED BLOCKS IN LAST BUFFER
ADDM T1,ACCWRT##(T2) ;ADJUST A.T. (BUT LEAVE DEVREL AT EOF)
TRNE T4,BLKSIZ##-1 ;NON-INTEGRAL NO OF WORDS?
TRZ T4,MBLKSZ## ;YES, MAKE SURE .LT 200
CAILE T4,BLKSIZ## ;TOO MANY WORDS?
MOVEI T4,BLKSIZ## ;YES, REDUCE COUNT
BUFAD8: JUMPL T3,BUFAD9 ;NEW LAST BLOCK IF NEGATIVE
MOVE T3,ACCSTS##(T2) ;STATUS WORD
TRNN T3,ACPUPD ;UPDATE MODE?
TDZA T3,T3 ;NO
LDB T3,ACYLBS## ;YES, GET PREVIOUS LAST-BLOCK LENGTH
CAILE T3,BLKSIZ## ;TOO MANY WORDS?
MOVEI T3,BLKSIZ## ;REDUCE COUNT
CAMG T3,T4 ;CURRENT LENGTH LESS THAN PREVIOUS LENGTH?
TRZA T3,-1 ;NO, NO NEED TO REWRITE RIB
MOVE T4,T3 ;YES, SET CURRENT=PREVIOUS LENGTH
BUFAD9: DPB T4,ACYLBS## ;SAVE IN ACC
SKIPE T3 ;IF SIZE CHANGED
PUSHJ P,RBCHD ; SET TO REWRITE RIB
JUMPL P4,BUFA13 ;EXIT IF ONLY PARTIAL AT EOF
HRRZ T1,DEVOAD(F) ;GET LOC OF BUFFER
;FALL INTO BUFA10
BUFA10:
IFN FTKL10&FTMP,<
ADDI T1,1
PUSHJ P,OUCHE## ;GET STUFF OUT OF CACHE
>
BUFA11: PUSHJ P,(P3) ;ADVANCE BUFFERS
JRST BUFA14 ;RAN OUT OR ERROR
TRZ S,IOIMPM ;CLEAR CHKSUM ERROR
JUMPG P4,BUFAD6 ;ADVANCE MORE IF NOT LAST BUFFER
PUSHJ P,ADVSWP## ;SWAPPER WANTS US TO STOP?
JRST BUFA14 ;YES, PLEASE STOP
IFN FTKL10&FTMP,<
TLNN S,IO ;WRITING?
JRST BUFA12
PUSHJ P,CHKNB## ;YES, SEE IF ANY MORE TO DO
HLRZ T1,DEVNBF(F) ;IF BUFS HAVENT BEEN SWEPT FOR
JUMPE T1,BUFA14 ; DONT CONTINUE (JOB IN OTHER CPU'S CACHE)
JRST BUFA13 ;KEEP ON
BUFA12: HRRZ T1,DEVIAD(F) ;GET ADDRESS OF NEXT BUFFER
PUSHJ P,BUFSSN## ;SEE IF IT IS OK WITH RESPECT TO THE CACHE
JRST BUFA14 ;NO, CAN'T FILL IT NOW
>
BUFA13: AOS -1(P)
BUFA14: HRL P3,(P)
MOVE S,DEVIOS(F)
JRST TPOPJ##
;SUBROUTINE TO COMPUTE A FOLDED CHECKSUM FROM THE FIRST DATA WORD
;CALL WHEN THE IO LIST HAS BEEN SET UP IN THE KONTROLLER DATA BLOCK
CHKSUM:
IFN FTXMON,<
HRRZ T1,DEVISN(F) ;GET CURRENT SECTION FOR I/O, SET PCS FOR
PUSHJ P,SVPCS## ; FETCHING CHECKSUM (MAPIO COULD HAVE CHANGED IT)
>
PUSH P,J ;SAVE J
PUSH P,M ; AND M
LDB J,PJOBN## ;GET NEW JOB #
HLRZ M,DEVUVA##(F) ;GET L(1ST WORD)-1
MOVEI M,1(M) ;=ACTUAL I/O ADDRESS
IFN FTXMON,<HRL M,DEVISN(F)> ;MAKE IT THE GLOBAL ADDRESS
PUSHJ P,GETEWD## ;GET WORD FROM USER AREA
STOPCD .,STOP,CSE, ;++CHECKSUM ERROR
MOVE T2,T1 ;MOVE IT
IFN FTKL10&FTMP,<
MOVE T1,M ;CHASE WORD FROM CACHE
PUSHJ P,OUCHE## ; IN CASE IT RUNS ON OTHER CPU
>
POP P,M ;RESTORE STUFF
POP P,J ;...
;SUBROUTINE TO COMPUTE A CHECKSUM FROM T2
;ENTER WITH T2=WORD TO BE CHECKSUMMED
;EXIT WITH T1 = CHECKSUM
CHKST1::HRRZ T4,UNISTR(U) ;LOC OF STR DB
JUMPE T4,SETIMP## ;ERROR IF UNIT WAS YANKED
MOVE T4,STYCKP##(T4) ;CHECKSUM POINTER
LDB T3,[POINT 6,T4,11] ;SIZE FIELD OF CHKSUM PNTR
MOVNS T3 ;SET FOR LSH
TLZA T4,770000 ;SET TO BIT 35
CHKSM1: ADD T2,T1 ;NOT DONE. ADD BYTE TO REST OF WORD (FOLD CHKSUM)
LDB T1,T4 ;GET A BYTE OF CHKSUM SIZE
LSH T2,(T3) ;THROW AWAY THE BYTE
JUMPN T2,CHKSM1 ;FINISHED WHEN NO MORE OF ORIGINAL WORD
POPJ P, ;DONE - RETURN
;SUBROUTINE TO UPDATE UNIT STATISTICS AFTER IO
;ENTER WITH P4=NUMBER OF BLOCKS, T1=UNIXRC(U) (X=M,B OR D)
;UPSTA = UPSTAT,PRESERVES T3
UPSTA:
UPSTAT: TLNE S,IO ;WRITING?
ADDI T1,1 ;YES. UNIXWC=UNIXRC+1
ADDM P4,(T1) ;UPDATE WORD IN UNIT BLOCK
SKIPL DEVRIB##(F) ;IO TO FILE CURRENTLY USING EXTENDED RIB?
POPJ P, ;NO, RETURN
HRRZ T1,P4 ;NUMBER OF BLOCKS TRANSFERRED
TLNE S,IO ;WRITING?
HRLZ T1,T1 ;YES, MOVE NUMBER OF BLOCKS TO LEFT HALF
ADDM T1,UNIXRA(U) ;AND STORE IN UNIT DATA BLOCK
POPJ P, ;AND RETURN
;SUBROUTINE TO COMPUTE DISTANCE TO TARGET CYLINDER
;ENTER WITH TARGET BLOCK IN DEVBLK(F)
;ENTER AT CYLCMJ TO SETUP KDB ADDRESS FROM UNIKON(U)
;ENTER AT CYLCM WITH T1=BLOCK NUMBER, T4 PRESERVED
;EXIT WITH T1 =DISTANCE FROM CURRENT CYLINDER TO TARGET CYLINDER
CYLCMJ: MOVE J,UDBKDB(U) ;GET KDB ADDRESS
CYLCOM: MOVE T1,DEVBLK##(F) ;#TARGET BLOCK
PJRST @KONCCM(J) ;GO TO KONTROLLER SPECIFIC CODE
; (CYLCM FOR ALL BUT RP20)
CYLCM:: LDB T3,UNYBPY## ;#NUMBER OF BLOCKS PER CYLINDER
IDIV T1,T3 ;#COMPUTE CYLINDER
SUB T1,UNICYL(U) ;#-PRESENT CYLINDER
POPJ P, ;#EXIT T1=DISTANCE
;SUBROUTINE TO REMOVE A FILE FROM A QUEUE
;F PASSES JOB,,DDB OF CURRENT DDB
;P2 PASSES JOB,,DDB OF PREDECESSOR
UNQUER: HLRZ J,F ;JOB NUMBER OF THIS DDB
PUSHJ P,MKADD## ; MAKE IT ADDRESSABLE
MOVE T2,DEVQUE##(F) ;Q WORD OF FILE
HLRZ J,P2
SKIPE J ;SAVE TIME IF QUEUE HEADER
PUSHJ P,MKADD## ;MAKE PREDECESSOR ADDRESSABLE
MOVS J,DEVQUE##(P2) ;IS IT WHAT WE EXPECT?
CAME J,F
POPJ P, ;RACE
MOVEM T2,DEVQUE##(P2) ;SAVE IN Q WORD OF PREDECESSOR
HLRZ J,F
PUSHJ P,MKADD## ;RETURN WITH THIS DDB ADDRESSABLE
SETZM DEVQUE##(F) ;CLEAR QUEUE-WORD
MOVE J,UDBKDB(U) ;RESET J TO KONTROLLER DATA BLOCK
JRST CPOPJ1## ;AND RETURN
;SUBROUTINE TO START UNIT POSITIONING
STRPOS::MOVEI T1,PCOD ;#PUT FILE AND UNIT INTO P STATE
PUSHJ P,FILCOD ;#
IFN FTDUAL,<
PUSHJ P,SECCOD ;SET MAIN UNIT TO SAME STATE
HRRM U,DEVCUR##(F)
>
STRPS1: PUSHJ P,SETPRS ;#SET KONCUA, UNICDA, UNIBLK
PUSHJ P,@KONPOS(J) ;#GO TO DEPENDENT ROUTINE
JRST STRPS2 ;UNIT NOT OK - PUT IT INTO T OR TW
; (UNLESS CALLED FROM HNGDSK)
;SO THAT STARTIO WILL CALL BADUN1
SCHEDULE
DOPOPJ::DSKON ;# TURN ALL DISK PI'S BACK ON
POPJ P, ;AND RETURN
;HERE IF UNIT NOT READY WHEN TRYING TO START POSITIONING
STRPS2: SETZM UNISTS(U) ;SO WE'LL STORE NEW UNISTS
IFE FTDUAL,<
PJRST SETTTW ;TRY TO START I/O
>
IFN FTDUAL,<
PUSH P,U
PUSHJ P,SETTTW
POP P,U ;IF WE STARTED IO ON ALTERNATE UNIT
MOVE J,UDBKDB(U) ;THEN U, J AND P1 WERE CHANGED
MOVE P1,KDBCHN(J) ;SO RESET THEM
POPJ P,
>
;SUBROUTINE TO SAVE POINTERS TO BEST FILE SO FAR
;P1-P3 CHANGED
SVBST: MOVEM F,P4 ;P4 = BEST FILE SO FAR
MOVEM T1,P3 ;P3 = DISTANCE TO BEST
MOVEM S,P2 ;P2 = PREDECESSOR IN QUEUE
POPJ P,
;SUBROUTINE TO SET UP PARAMETERS FOR DEPENDENT ROUTINE
SETPAR: HRRM U,CHNCUA(P1) ;#SAVE CURRENT UNIT IN USE ON CHAN
JRST SETPR2
SETPRS: SKIPL KONBSY(J) ;#DONT STORE NEW KONCUA IF THIS IS A POSITION
; STARTED WHILE XFER IS ACTIVE
SETPR2: HRRM U,KONCUA(J) ;#SAVE CURRENT UNIT ADDR
PUSHJ P,STORF ;#SAVE FILE ADDR
IFN FTDUAL,<
SKIPN T2,UNI2ND(U) ;IF DUAL-PORTED
JRST SETPR1 ; AND WE ARE TALKING TO ALTERNATE PATH
HRRM F,UNICDA(T2) ;SET UNICDA, UNIJOB ON MAIN PATH
MOVEM T3,UNIJOB(T2) ; FOR THIS OPERATION
SETPR1:>
MOVE T2,DEVBLK##(F) ;# SAVE LOGICAL BLOCK NR WITHIN UNIT
MOVEM T2,UNIBLK(U) ;#IN UNIT DATA BLOCK
MOVE S,DEVIOS(F) ;#GET S
PJRST SETHNG## ;# RESET HUNG TIME AND EXIT
;SUBROUTINE TO DETERMINE IF A POINTER TO THE NEXT BLOCK OF A FILE IS IN CORE
;ENTER WITH J,U,F SET UP
;RETURN CPOPJ IF NEXT BLOCK NOT AVAILABLE
;RETURN CPOPJ1 IF THE NEXT BLOCK HAS A POINTER ALREADY IN CORE
CHKNXT: HRRZ T1,DEVLFT##(F) ;NUMBER OF BLOCKS LEFT IN CURRENT GROUP
SOJGE T1,CHKNX2 ;CPOPJ1 IF ANY LEFT AND WRITING
MOVE T1,DEVRET##(F) ;LOOK AT NEXT POINTER
CAIGE T1,DEVRBN##(F) ;IF END OF POINTER BLOCK
SKIPN T2,1(T1) ; OR ZERO (EOF)
POPJ P, ;NONE LEFT IN CORE
HLRE T1,DEVRSU##(F) ;DEVRSU
CAMGE T1,[-2] ;NO MORE IF MIGHT GET REDUNDANT RIB
TLNN T2,-1 ;CHANGE OF LOGICAL UNITS?
POPJ P, ;NOT AVAILABLE SINCE IT IS ON ANOTHER UNIT
;(CANT SWITCH UNITS ON INTERRUPT LEVEL SINCE STATE
; OF OTHER UNITIS INDEPENDENT OF THIS ONE)
PUSHJ P,NXTBLK ;STORE NEW DEVBLK IN CASE THIS UNIT PUT BACK
; IN PW AND NEW PNTR IS FOR A NEW CYLINDER
POPJ P, ;NEW BLOCK PAST WRITTEN DATA - RETURN
CHKNX2: HRRZ T2,DEVACC##(F) ;SAME UNIT. LOC OF A.T.
JUMPE T2,CPOPJ## ;UNAVAILABLE IF F/S WAS JERKED
MOVE T2,ACCWRT##(T2) ;NUMBER OF BLOCKS WRITTEN
TLNN S,IO ;IF READING,
CAML T2,DEVREL##(F) ;IS NEXT READ PAST THE EOF?
AOS (P) ;NO. OK
POPJ P, ;RETURN CPOPJ OR CPOPJ1
;HERE WHEN THE UNIT IS NOT READY
BADUNI: PUSHJ P,SETF ;SET F TO CURRENT DDB
JUMPE F,CPOPJ## ;NONE????
BADUN1: PUSH P,P3 ;ADDR OF DRB
;HERE WITH ADDR OF DRB ON THE STACK
BADUNC: HRRZS UNISTS(U) ;#CLEAR SIGN BIT (PHUNG)
MOVEM T2,UNIERR(U) ;#YES, SAVE CONI, DATAI
MOVEM T3,UNIHDI(U) ;#
IFN FTCIDSK,<
MOVSI T3,KOPCNA ;#GET THE "NO CREDITS" BIT
TRNE T1,KOPNOC ;#NOT ENOUGH CREDITS?
IORM T3,KONCNA(J) ;#YES, SET SO CRNPOS DOESN'T START ANYTHING
>; END IFN FTCIDSK
DSKON
SKIPGE DEVSWP##(F) ;DON'T RETURN IOWD'S IF THE SWAPPER
JRST BADUN2
PUSH P,P3
MOVE T3,UNISTS(U) ;HAS SETLST RUN YET?
CAIE T3,TCOD
IFN FTCIDSK,<
SKIPGE KONMX(J) ;HSC50 DOESN'T POSITION
SKIPA P3,-1(P) ; THEREFORE SETLST HAS RUN
>
JRST BADUNB ;SETLST NOT RUN YET
PUSH P,T1
PUSH P,P4
PUSHJ P,UNLST ;UNDO SETLST
PUSHJ P,RTNDRB ;RETURN THE CHANNEL PROGRAM
POP P,P4
POP P,T1
BADUNB: POP P,P3
BADUN2:
IFN FTCIDSK,<
SKIPL DEVSWP##(F) ;SWAPPER?
POP P,T4 ;NO, WE DON'T NEED DRB ANYMORE
TRNN T1,KOPNOC ;NOT ENOUGH CREDITS?
JRST BADUNE ;ENOUGH
SKIPGE DEVSWP##(F) ;SWAPPER?
JRST BADUNA ;YES
DSKOFF
JRST BADUNF ;PUT INTO PW
BADUNE:
>
MOVSI T4,UNPOFL
TRNE T1,KOPFUS ;UNIT GO FILE-UNSAFE?
TLO T4,UNPFUS ;YES, LIGHT ANOTHER BIT TOO
TRNE T1,KOPUSI
TLO T4,UNPUSI
TRNN T1,KOPOFL ;UNIT OFF-LINE?
JRST BADUN5 ;NO, CALL HNGSTP
IORM T4,UNIDES(U) ;YES - LIGHT UNIDES BIT
SKIPE DEVRHB##(F) ;IF REREADING HOME BLOCKS,
SKIPE DINITF## ;OR IF IN ONCE-ONLY CODE,
JRST BADUN7 ;DONT DO THIS OPR-WAIT STUFF
MOVE T2,UNIBLK(U) ;
MOVEM T2,UNIHBN(U) ;SAVE BLOCK NUMBER
AOS UNIHCT(U) ;BUMP ERROR COUNT
SKIPGE UNIECT(U) ;IN ERROR RECOVERY?
PUSHJ P,FSTREG ;NO, COPY INITIAL REGISTERS
PUSHJ P,LSTER ;COPY REGISTERS FROM KDB TO UDB
MOVEI T1,.FIUOF ;FILIO-DETECTED UNIT OFFLINE
PUSHJ P,FILELG ;CALL DAEMON
LDB T1,UNYUST## ;UNIT STATE
CAIG T1,UNVPBM ;A PACK MOUNTED?
JRST BADLP1 ;YES, TELL THE OPERATOR
MOVEI T1,O2COD ;NO, THE OPERATOR DOESN'T WANT TO KNOW ABOUT IT
DSKOFF
MOVEM T1,UNISTS(U) ;#SO NO MESSAGES
PUSHJ P,FLPJOB ;#FLIP UNIJOB AND UNICDA
MOVE S,DEVIOS(F) ;#GET CURRENT DEVIOS
TDO S,[IOW,,IODERR] ;#LIGHT IOW SO STDIOD DOES SOMETHING
TRZ S,IOACT ;#CLEAR IOACT
PUSHJ P,STDIOD## ;#GET OUT OF I/O WAIT
JRST BADUNG ;#GO FIND SOMETHING ELSE TO DO
BADLP1: MOVE T1,[XWD TELOPC,1];SET FOR CLOCK REQUEST
CONSO PI,PIPROG##-PI.IP7 ;ON PI LEVEL?
JRST BADLP2 ;NO
SYSPIF ;SET TO STORE IN THE CLOCK QUEUE
PUSHJ P,SKPCLQ## ;ROOM IN CLOCK QUEUE FOR MESSAGE?
JRST BADL1A ;NO, PROBABLY LOTS OF OTHER ERRORS, LET IT GO
IDPB T1,CLOCK## ;YES, TELL OPR ON NEXT TICK
IDPB U,CLOCK## ;SAVE ADR OF UDB
SETOM CLKNEW##
BADL1A: SYSPIN ;IN ORDER TO TYPE MESSAGE TO OPR
CAIA ;DONT TELL OPR NOW IF ON PI LEVEL
BADLP2: PUSHJ P,TELOPR ;NOT ON PI LEVEL - TYPE MESSAGE NOW
SKIPGE DEVSWP##(F) ;IF THE SWAPPER,
PJRST BADUNA ; LET SWPHNG RECOVER
MOVEI T1,OCOD ;MESSAGE
DSKOFF
MOVEM T1,UNISTS(U) ;#STORE UNIT STATUS
IFN FTDUAL,<
SKIPN T2,UNI2ND(U) ;SECOND PORT?
JRST BADLP3 ;NO
MOVE T3,UNISTS(T2) ;YES, GET UNIT STATUS
CAIGE T3,OWCOD ;ALREADY IN SOME FLAVOR OF OPR WAIT?
MOVEM T1,UNISTS(T2) ;PREVENT TRANSFERS VIA ALTERNATE PORT
BADLP3:
>; END IFN FTDUAL
PUSHJ P,FLPJOB ;#FLIP UNIJOB AND UNICDA
;#WE SHOULDN'T CHANGE THE UBR AT UUO LEVEL SO PUT
;#THE GUY IN POSITION WAIT AND LET DSKSEC MOVE THE PWQ
;#TO UNICHK
BADUNF: PUSHJ P,UUOPW2 ;#ADD DDB TO PWQ
BADUNG: PUSH P,F ;#SAVE F
PUSHJ P,INTLVL## ;#IF ON UUO LEVEL AND A SEEK FINISHED
SETZ P1, ;# CAN'T START IT - CANT CALL SVEUB
MOVE J,UDBKDB(U)
PUSHJ P,SETI12 ;#GO FIND SOMETHING ELSE TO DO
;#THIS (UNIT WONT BE USED TILL COMES OUT OF OW)
POP P,F ;RESTORE F
PJRST DOPOPJ
;HERE WHEN THE UNIT DID NOT GO OFF-LINE (PROBABLY WRITE-LOCK)
BADUN5: SKIPGE DEVSWP##(F) ;SWAPPER NEVER GIVES UP
JRST BADUNA
PUSHJ P,FLPJOB ;FLIP UNIJOB AND UNICDA
MOVSI T1,DEPUWL## ;TELL UNICHK IT FAILED BECAUSE
IORM T1,DEVPTB##(F) ; OF WRITE LOCK
TLO S,IOSTBL ;RETRY AT UUO LEVEL
PUSHJ P,STDIOD## ;UNWAIT HIM
PUSH P,F ;MUST PRESERVE F IF AT UUO LEVEL
PUSHJ P,INTLVL## ;AT INTERRUPT LEVEL?
SETZ P1, ;NO, FLAG NOT TO CHANGE UBR
PUSHJ P,SETID4 ;START SOMETHING ELSE
JRST FPOPJ##
;HERE ON INTERRUPT LEVEL OR DURING ONCE-ONLY
;LIGHT AN ERROR BIT AND RETURN TO CALLER
BADUN7: MOVE S,DEVIOS(F) ;GET CURRENT DEVIOS
TRO S,IOIMPM ;LIGHT IOIMPM
;IN IO WAIT?
PUSHJ P,STDIOD## ;YES. TAKE OUT
PUSH P,F ;SAVE F
CONSO PI,PIPROG## ;CANT CHANGE UBR IF
SETZ P1, ; AT UUO LEVEL
PUSHJ P,SETID3 ;SET UNIT IDLE,START NEXT OPERATION
JRST FPOPJ## ;RETURN
;HERE IF IT'S THE SWPDDB
BADUNA:
IFN FTCIDSK,<
EXCH P3,(P) ;RESTORE ADDR OF DRB
SKIPGE KONMX(J) ;MULTIPLE XFERS?
PUSHJ P,RTNTRY ;YES, TRY AGAIN
POP P,P3
>
POPJ P,
;ROUTINE TO UNDO SETLST
;P3 PASSES DRB (IF ANY)
UNLST: JUMPL S,CPOPJ## ;GO IF MONITOR I/O
LDB T2,PIOMOD## ;MODE
CAIL T2,SD ;DUMP OR BUFFERED?
JRST UNLST1 ;DUMP
LDB T1,DEYNB1## ;BUFFERED, RESTORE IOSPBF
SKIPN T1
TLZA S,IOSPBF
TLO S,IOSPBF
MOVEM S,DEVIOS(F)
IFN FTMP,<
TLNN S,IO ;OUTPUT?
JRST UNLST2 ;INPUT, DEVNBF IS OK
MOVE T2,KDBCHN(J) ;GET CHNNUM
SKIPGE KONDRB(J) ;HAVE A DRB?
MOVEI T2,DRBNUM##-CHNNUM(P3) ;YES, GET FROM DRB
HRRZ T2,CHNNUM(T2) ;NO, GET FROM CHN
ADD T2,T1 ;PLUS PORTION OF 1ST BUFFER
LDB T3,DEYNBB## ;BLOCKS PER BUFFER
IDIV T2,T3 ;COMPLETED BUFS
HRLZS T2 ;ADJUST DEVNBF
ADDM T2,DEVNBF(F)
UNLST2:
>
JUMPE T1,CPOPJ## ;GO UNLESS STARTED BUF IN MIDDLE
TLNN S,IO ;RESET COUNT IN BUF
SKIPA T2,DEVIAD(F)
MOVE T2,DEVOAD(F)
HRRZS T2
LSH T1,BLKLSH##
TLNN S,IO
EXCTXU <HRRZM T1,1(T2)>
TLNE S,IO
EXCTUU <HRLM T1,1(T2)>
POPJ P,
UNLST1: SKIPGE KONDRB(J) ;HAVE A DRB?
SKIPA T1,DRBDMP##(P3) ;YES, GET IT FROM DRB NOT KDB
MOVE T1,KONDMP(J) ;GET IOWD BACK
MOVEM T1,DEVDMP##(F) ;RESET DEVDMP IN CASE "CONT" IS TYPED
POPJ P,
;ROUTINE TO TYPE A MESSAGE TO THE OPR WHEN A DRIVE GOES OFF-LINE
;ENTER AT TELOPC FROM THE CLOCK, T1=UDB
;ENTER AT TELOPR WITH U SET CORRECTLY
TELOPC: MOVE U,T1
SETZ J, ;SET J=0 AS A SWITCH
HRRZ T1,UNICDA(U) ;IF THE SWAPPER
CAIE T1,SWPDDB##
MOVE T1,UNISTS(U) ;GET STATUS OF UNIT
CAIGE T1,OWCOD ;HAS UNIT ALREADY BEEN POWERED DOWN AND UP?
POPJ P, ;YES, DONT TYPE ANYTHING
;NO, TELL OPR ABOUT BAD UNIT
JRST TELOP1 ;SAVE ONLY U, AND TYPE
TELOPR: PUSH P,F
TELOP1: PUSH P,U
MOVEI T1,UNPMSG ;UNIT OFF-LINE MSG BEEN PRINTED THIS MINUTE?
TDNE T1,UNIMSG(U) ;...
JRST TELOP8 ;YES
IORM T1,UNIMSG(U) ;REMEMBER IT WAS
MOVE U,OPRLDB## ;TYPE MESSAGE ON OPR'S TTY
PUSHJ P,INLMES##
BYTE (7) 7,7,7,7,7 ;SOME BELLS
ASCIZ /
Unit /
MOVE T2,(P) ;UNIT
MOVE T2,UDBNAM(T2) ;PHYSICAL UNIT NAME
PUSHJ P,PRNAME## ;TYPE IT
IFN FTDUAL&FTMP,<
MOVE T2,(P) ;UDB ADDR
MOVE T1,UDBCAM(T2)
SKIPL T2,UNI2ND(T2) ;IS THIS AN ALTERNATE PATH?
JRST TELOP2 ;NO
MOVE T3,UDBCAM(T2)
CAME T1,T3 ;SAME CPU?
JRST TELOP2 ;NO
PUSH P,UDBNAM(T2) ;SAVE ITS NAME
PUSHJ P,INLMES## ;TELL OPR THE NAME HE KNOWS
ASCIZ . / .
POP P,T2
PUSHJ P,PRNAME##
TELOP2:>
MOVE T2,(P)
MOVSI T1,UNPUSI
TDNE T1,UNIDES(T2)
JRST TELOP3
PUSHJ P,INLMES## ;AND THE MESSAGE:
ASCIZ / went OFF-LINE/
JRST TELOP4
TELOP3: ANDCAM T1,UNIDES(T2)
PUSHJ P,INLMES##
ASCIZ / status inconsistent/
TELOP4: MOVE T2,(P) ;UNIT
MOVE T2,UNIDES(T2) ;UNIDES WORD
TLNN T2,UNPFUS ;FILE UNSAFE?
JRST TELOP5
PUSHJ P,INLMES## ;YES
ASCIZ / (File unsafe)/
TELOP5: MOVE T2,0(P) ;GET UDB BACK
MOVE T2,UDBKDB(T2) ;GET KDB ADDRESS
MOVE T2,KONMPS(T2) ;GET WORD CONTAINING KOPMPS
TLNN T2,KOPMPS ;MICROPROCESSOR STOPPED?
JRST TELOP6 ;NO, ISSUE STANDARD MESSAGE
PUSHJ P,INLMES##
ASCIZ /
Disk controller microprocessor stopped.
/
PUSH P,J ;SAVE J
HRRZ J,-1(P) ;GET THE UDB ADDRESS BACK
MOVE J,UDBKDB(J) ;GET THE KDB ADDRESS
PUSHJ P,@KONRLD(J) ;TRY TO RELOAD THE CONTROLLER
CAIA ;FAILED
JRST [POP P,J ;RELOAD SUCCEEDED, RESTORE J
JRST TELOP6] ; AND CONTINUE
POP P,J ;RESTORE J
PUSHJ P,INLMES## ;TYPE REST OF MESSAGE
ASCIZ /
Please reload the controller microcode./
;FALL INTO TELOP6
TELOP6: PUSHJ P,INLMES## ;YES, ASK HIM TO
ASCIZ /
Operator intervention is required for this unit.
/
TELOP8: POP P,U ;RESTORE ACS
JUMPE J,CPOPJ## ;DIDN'T SAVE ACS IF J=0
POP P,F
MOVE S,DEVIOS(F) ;RESTORE S
POPJ P, ;AND RETURN
TELDER: MOVE U,OPRLDB## ;OPR LDB
PUSHJ P,INLMES##
BYTE (7) 7,7,7,7,7
ASCIZ /
Excessive disk hardware errors
/
POPJ P,
;ROUTINE CALLED ONCE A MINUTE
CHKUNI::SETZM F
SETOM J
HLRZ U,SYSUNI## ;FIRST UNIT IN SYSTEM
CHKUN1: MOVEI T1,UNPMSG ;CLEAR UNIT OFF-LINE MSG PRINTED FLAG
ANDCAM T1,UNIMSG(U) ;...
MOVE T1,UNISTS(U) ;STATUS OF UNIT
CAIN T1,OCOD ;WAITING FOR OPR?
PUSHJ P,[MOVE T2,STATES## ;YES
TRNE T2,ST.NOP ;OPR IN ATTENDANCE?
ADDI T1,2 ;NO, DON'T REPEAT MESSAGE
MOVEM T1,UNISTS(U)
JRST TELOPR] ;REMIND HIM
HLRZ U,UNISYS(U) ;STEP TO NEXT UNIT
JUMPN U,CHKUN1 ;AND TEST IT
POPJ P, ;DONE - RETURN
;HERE TO START TRANSFER OF BEST (LATENCY DETERMINED) FILE IN TW
PIKTRN: MOVEI F,SWPDDB## ;MAKE SURE WE'RE POINTING AT SWAPPER
SKIPE SQREQ## ;SWAPPER WANT SERVICE?
PUSHJ P,SWPSCN## ;YES, LET IT DO PART 1 (SET ASL UNITS IN TW STATE)
PIKTRX: SKIPN SQREQ## ;SWAPPER WAITING?
JRST PIKTR2 ;NO
MOVEI F,SWPDDB## ;YES, POINT F AT SWAPPER DDB
PUSHJ P,SWPPIK## ;GO FIND SOMETHING TO DO
CAIA ;COULDN'T, DO A FILE IO
POPJ P, ;SWAPPER IS GOING, EXIT
PIKTR2: PUSHJ P,UNIRHB ;SEE IF ANY UNIT NEEDS REREADING HOME BLOCKS
JRST PIKTR0 ;NO, GO LOOK FOR FILE TO START DATA ON
PUSHJ P,FAKDDX ;YES, GET A DDB
JRST PIKTR0 ;NO SPACE NOW, PUSH ON AND TRY LATER
PJRST TSTRHX ;GOT 1, GO START TO READ HOME BLOCK
PIKTR0: PUSHJ P,SAVE4## ;#
DSKOFF
MOVSI T1,KOPBSY ;#SET OLD KONTROL IDLE
ANDCAM T1,KONBSY(J) ;#
PIKTR1: MOVS F,CHNQUE(P1) ;#FIRST FILE DDB IN TW QUEUE FOR THIS CHAN
JUMPE F,CHNIDL ;#IF QUEUE EMPT, SET CHAN IDLE AND EXIT
DSKON ;#
;HERE TO FIND THE BEST FILE TO START TRANSFERRING
HRLOI P3,377777 ;PRESET BEST LATENCY TIME
PUSH P,S ;SAVE S
MOVEI S,CHNQUE-DEVQUE##(P1) ;PRESET PREDECESSOR
TWQLUP: HLRZ J,F ;JOB NUMBER WHICH OWNS DDB
PUSHJ P,MKADD## ;MAKE DDB ADDRESSABLE
MOVE T1,DEVBLK##(F) ;BLOCK FILE NEEDS
IFE FTDUAL,<
HRRZ U,DEVUNI##(F)
>
IFN FTDUAL,<
HRRZ U,DEVCUR##(F)
>
SKIPN U
STOPCD .,CPU,NUT, ;++NO UNIT FOR TRANSFER
SKIPN T2,UNISTS(U) ;STATUS OF UNIT
JRST TWQLP2
CAIE T2,MDACOD ;IDLE
CAIN T2,TWCOD ;TW?
TWQLP2: SKIPA J,UDBKDB(U) ;MDA WAIT OR TW - SET J=KONTROLLER FOR UNIT
JRST TWQLP1 ;UNIT NOT IN TW - GET ANOTHER FILE
PUSHJ P,RHBP ;NEED TO REREAD HOME BLOCKS?
JRST TWQLP1 ;YES, DON'T START XFER
PUSHJ P,@KONLTM(J) ;COMPUTE LATENCY
MOVEI T1,0 ;UNIT NOT OK- SET LATENCY=0
PUSHJ P,DFPRI
MOVNI T2,MXNDPR##(T2)
SKIPE T1
HRL T1,T2
; SO UNIT WILL BE GOTTEN RID OF IMMEDIATELY
SKIPLE CHNCFT(P1) ;TIME TO BE FAIR?
CAMG T1,P3 ;NO. BEST SO FAR?
PUSHJ P,SVBST ;YES, SAVE POINTERS TO FILE
; P4=BEST F, P3=DIST TO BEST, P2=PRED.F
TWQLP1: MOVEM F,S ;SAVE F AS PREDECESSOR
MOVS F,DEVQUE##(F) ;STEP TO NEXT FILE
JUMPN F,TWQLUP ;TEST NEXT FILE
TLNN P3,777770 ;WAS ANY FILE FOUND TO START DATA?
PJRST SETBSY ;YES. GO
POP P,S ;NOTHING TO DO. RETORE S
MOVE J,UDBKDB(U)
PJRST CHNIDL ;SET CHAN IDLE
;HERE WHEN BEST FILE IS FOUND START IO
SETBSY: POP P,S ;RESTORE S
MOVE F,P4 ;SET F TO FILE
HLRZ J,F
PUSHJ P,MKADD## ;MAKE DDB WE WANT TO START ADDRESSABLE
IFE FTDUAL,<
HRRZ U,DEVUNI##(F)
>
IFN FTDUAL,<
HRRZ U,DEVCUR##(F)
>
DSKOFF ;#TURN ALL DISK PI'S OFF
PUSHJ P,UNQUER ;#REMOVE FILE FROM TWQ
JRST PIKTR1 ;#RACE, TRY AGAIN
SOS CHNQUL(P1) ;#COUNT IT
SETBS1: PUSHJ P,TSTGEN ;UNIT BEEN DETACHED?
JRST NXTTBL ;YES, LIGHT TROUBLE
MOVE T1,DEVUWZ##(F) ;ZEROING BLOCKS IN USETO CODE?
TLNN T1,DEPUWZ##
JRST SETBS2
MOVE T1,DEVACC##(F) ;YES, IS CURRENT BLOCK WRITTEN?
MOVE T1,ACCWRT##(T1) ; (IF USETO DECIDED TO ZERO BLOCK N WHILE
CAML T1,DEVREL##(F) ; ANOTHER JOB WAS IN DIOW FOR BLOCK N)
JRST NXTIO ;BLOCK NOW HAS GOOD DATA IN IT - GET OUT
SETBS2:
IFN FTXMON,<
SKIPGE S ;IF MONITOR I/O, ALSO SAVE PCS
PUSHJ P,SSPCS## ; DEVISN WILL BE ZERO IF LOOKUP/ENTER
PUSHJ P,SPCS## ;SET PCS FROM DEVISN (DEPENDS ON STEUB TO RESTORE IT)
>
PUSHJ P,STRTIO ;#SET FILE+UNIT TO T1, KONTROL TO B(CHAN ALREADY B)
;COMPUTE CHAN COMMAND LIST AND START TRANSFER
JRST INTXIT ;AND DISMISS THE INTERRUPT
;HERE FROM BADUN1 ON UUO LEVEL
CHNIDX: MOVSI T1,KOPBSY
ANDCAM T1,KONBSY(J)
;HERE WHEN ALL PROCESSING FOR DATA INTERRUPT IS DONE
;RESET FAIRNESS COUNTS IF THEY ARE NEGATIVE AND DISMISS
;P1 IS STILL CHAN. DB ADR. WHICH CAUSED THIS DATA INTERRUPT
CHNIDL: SKIPGE DIADSK## ;IF TRYING TO SET DIAG CHAN IDLE
CAME P1,DIACHN## ; (CALL FROM CRNK UP)
CAIA
PJRST DOPOPJ ;JUST RETURN
SETOB T2,@KDBCHN(J) ;#SET CHAN IDLE
DSKON ;#
JUMPE P1,CPOPJ## ;DONE IF SETID3 CALLED BY
; BADUN1 AT UUO LEVEL
SETZM CHNCUA(P1) ;NO CURRENT UNIT ACTIVE ON CHAN
MOVSI T1,CP.SWF ;GET SWEEP FLAG
TDNE T1,CHNTYP(P1) ;DO WE HAVE TO DO A SWEEP BEFORE DISMISSING?
PUSHJ P,CFDMPX ;YES, SO DO IT NOW SINCE NO I/O WILL
; BE STARTED, AS WE ARE AT CHNIDL
PUSH P,U ;SAVE U FOR END TEST
CHNID1: MOVE T1,UNISTS(U) ;STATUS OF UNIT
CAIE T1,TCOD ;(PI'S ARE ON NOW)
CAIN T1,PCOD ;IF ANY UNIT IS STILL DOING SOMETHING,
AOJA T2,CHNID2 ; BUMP T2
SKIPGE SCNCNT## ;UNITS ARE IN FUNNY STATE IF
; IN SWPSCN ON UUO LEVEL
CAIE T1,TWCOD ;IS UNIT IN TW?
JRST CHNID2 ;NO
IFN FTDUAL,<
SKIPE T1,UNI2ND(U) ;IF AN ALTERNATE UNIT,
SKIPN UNISTS(T1) ; WHICH ISNT IDLE
CAIA
JRST CHNID2 ;IT'S OK
>
SKIPE T1,UNIQUE(U) ;YES (STRANGE RACE)
MOVEI T1,PWCOD ;PUT UNIT INTO PW OR IDLE
MOVEM T1,UNISTS(U) ; SO SYSTEM WONT HANG
CHNID2: HRR U,UNICHN(U) ;STEP TO NEXT UNIT ON CHAN
CAME U,(P) ;BACK WHERE WE STARTED?
JRST CHNID1 ;NO, TEST THIS UNIT
POP P,U ;YES, REMOVE JUNK FROM PD LIST
SKIPLE F,DIADSK## ;TRYING TO SHUT DOWN IO?
CAME P1,DIACHN## ;YES, FOR THIS CHAN?
JRST CHNID4 ;NO
JUMPGE T2,INTXIT ;YES, DISMISS IF ANY UNIT BUSY
CHNID3: HLRZ J,F
PUSHJ P,MKADD##
MOVE S,DEVIOS(F) ;NO UNITS BUSY, SET UP S
PUSHJ P,STDIOD## ;AND WAKE UP THE JOB (TO START DIAGNOSTIC)
PUSHJ P,CLRACT##
IFN FTDUAL,<
JRST INTXIT
CHNID4: JUMPLE F,INTXIT ;GO IF NO DIAG WAITING
MOVE U,KONCUA(J) ;UNIT WE JUST TALKED TO
SKIPN T1,UNI2ND(U) ;DIAG - DUAL PORTED DRIVE?
JRST INTXIT
MOVE T2,UDBKDB(T1) ;YES, IS 2ND PORT ON RIGHT CHAN?
MOVE T2,KDBCHN(T2)
SKIPGE (T2) ; AND S THAT CHAN IDLE?
CAME T2,DIACHN##
JRST INTXIT ;NO, CANT START THE DIAG JOB
HRRZ T2,T1
MOVEI T3,PCOD ;YES, ARE ALL UNITS ON THE CHAN IDLE?
CHNID5: CAMN T3,UNISTS(T1)
JRST INTXIT ;NO, CAN'T START THE DIAG JOB
MOVE T1,UNICHN(T1)
CAME T1,T2
JRST CHNID5
JRST CHNID3 ;YES, TAKE DIAG JOB OUT OF DIOW QUEUE
>
IFE FTDUAL,<
CHNID4:
>
INTXIT: JUMPE P1,CPOPJ## ;EXIT NOW IF NO CDB (BADUNI AT UUO LEVEL)
MOVSI T1,CP.SWF ;CLEAR SWEEP FLAG
ANDCAM T1,CHNTYP(P1) ;FOR NEXT INTERRUPT
HRRZ T1,CHNIFP(P1) ;RESET FAIRNESS COUNTS IF THEY HAVE GONE NEGATIVE
SKIPG CHNCFP(P1) ;CURRENT FAIRNESS COUNT FOR POSITIONING OPTIMIZATION
MOVEM T1,CHNCFP(P1)
HRRZ T1,CHNIFT(P1)
SKIPG CHNCFT(P1) ;CURRENT FAIRNESS COUNT FOR TRANSFER OPTIMIZATION
MOVEM T1,CHNCFT(P1)
POPJ P, ;AND DISMISS THE INTERRUPT
;SUBROUTINE TO SWEEP CACHE
;CALL WITH P1=LOC OF CHANNEL DATA BLOCK
;PRESERVES ALL ACS EXCEPT T1
CFDMPX:
IFN FTMP,<
LDB T1,DEYCPU## ;IF DDB WE JUST DID IO FOR
CAME T1,.CPCPN## ; IS ON A DEFFERENT CPU
POPJ P, ;THERE IS NO NEED TO SWEEP ON THIS CPU
>
CFDMP: MOVE T1,CHNTYP(P1)
IFE FTKS10,<
SKIPN DINITF## ;ARE WE IN ONCE-ONLY?
>; END IFN FTKS10
TLNE T1,CP.RH2+CP.KLP ;INTERNAL CHANNEL?
POPJ P, ;YES, NO NEED TO SWEEP
IFN FTMP,<
SETZM .CPSWD## ;TELL DSKTIC WE SWEPT
>
PJRST CSDMP## ;NO, SWEEP CACHE
;HERE TO DO RETRY AT UUO LEVEL
NXTTBL: MOVSI S,IOSTBL ;LIGHT TROUBLE
IORM S,DEVIOS(F)
;HERE TO EXIT WITHOUT WRITING THE DISK
NXTIO: MOVE S,DEVIOS(F) ;SET UP S FOR STDIOD
PUSHJ P,STDIOD## ;WAKE UP JOB
PUSHJ P,CLRACT## ;NO LONGER IO ACTIVE
DSKOFF
CONSO PI,PIPROG## ;#IF ON UUO LEVEL,
JRST [SETOM @KDBCHN(J) ;#INDICATE CHAN IS IDLE
PJRST DOPOPJ] ;#TURN ON DSK PI
;#AND RETURN WITHOUT WIPING IT
PUSHJ P,IDLEPW ;#SET IDLE OR PW
SKIPN UNISTS(U) ;#PW?
JRST PIKTR1 ;#IDLE, LOOK FOR A TRANSFER TO START
SETOM UNICYL(U) ;#ENSURE A SEEK HAPPENS (ELSE COULD PDL OV)
JRST PIKPOS ;# AND START A SEEK GOING
SUBTTL CSHSER -- ALGORITHM OVERVIEW
COMMENT |
THE DISK CACHE ALGORITHM WAS DESIGNED AND IMPLEMENTED BY BILL MEIER,
WITH HELP FROM PETER VATNE.
THE BASIC DATA STRUCTURE CONSISTS OF TWO DOUBLY LINKED LISTS, A LIST
HEADER, AND A HASH TABLE. EACH NODE IN THE LIST CONTAINS FORWARD AND
BACKWARD POINTERS FOR EACH OF THE TWO LISTS ITS LINKED INTO, (.CBNHB,
.CBPHB, .CBNAB, .CBPAB), A UDB ADDRESS (.CBUDB), A BLOCK NUMBER
(.CBBLK), AND A POINTER TO THE ADDRESS IN FRECOR WHERE THE BLOCK IS
(.CBDAT). FOR STATISTICS ONLY, THE NODE ALSO CONTAINS A COUNT OF THE
NUMBER OF TIMES THIS BLOCK HAS BEEN HIT SINCE IT WAS IN THE CACHE
(.CBHIT).
THE LIST HEADER POINTS TO THE TWO LINKED LISTS. THE FIRST LINKED LIST
IS THE "ACCESS" LIST. THE MOST RECENTLY ACCESSED BLOCK IS AT THE HEAD
OF THE LIST; THE LEAST RECENTLY ACCESSED BLOCK IS AT THE TAIL. THIS
LIST IS LINKED THROUGH THE .CBNAB/.CBPAB WORDS. THE SECOND LINKED LIST
IS THE "FREE" LIST. IT CONTAINS A LIST OF ALL BLOCKS THAT ARE NOT
CURRENTLY IN USE, AND AS SUCH DO NOT APPEAR IN THE HASH LIST DESCRIBED
BELOW. THIS LIST IS LINKED THROUGH THE .CBNHB/.CBPHB WORDS.
THE HASH TABLE CONSISTS OF POINTERS INTO THE .CBNHB/.CBPHB LIST FOR THE
CORROSPONDING LIST FOR BLOCKS THAT HASH TO THE SAME POSITION. THUS, THE
HASH TABLE IS REALLY N SEPARATE LIST HEADS FOR THE LISTS OF BLOCKS THAT
HASH TO THAT POSITION IN THE HASH TABLE.
AT INITIALIZATION TIME (CSHINI) ALL THE BLOCKS ARE ALLOCATED, AND LINKED
INTO THE FREE LIST. THEY ARE ALSO LINKED INTO THE ACCESS LIST. THE
HASH TABLE ENTRIES ARE ALL LINKED TO THEMSELVES, AS THE TABLE IS EMPTY.
TO FIND AN ENTRY, GIVEN ITS UDB AND BLOCK NUMBER, YOU SIMPLY HASH THE
BLOCK INTO THE HASH TABLE, AND USING THAT ENTRY AS A LIST HEAD, FOLLOW
THE LIST UNTIL YOU EITHER FIND A MATCH, OR RETURN TO THE HEADER. THIS
IS DONE WITH THE ROUTINE CSHFND. IT SHOULD BE NOTED THAT IN GENERAL,
THESE LISTS ARE VERY SMALL, MOST LIKELY ONLY 1 OR 2 BLOCKS.
THE MAIN CACHE HANDLING ROUTINE IS CSHIO, WHICH WILL SIMULATE I/O FROM
THE CACHE, DOING THE NECCESSARY PHYSICAL I/O TO FILL AND WRITE THE CACHE.
IT SHOULD BE NOTED THAT THIS IS A WRITE-THROUGH CACHE, SO NO SWEEPS
ARE REQUIRED, SO THE DATA IN THE CACHE ALWAYS REFLECTS THE BLOCKS ON
DISK.
|
SUBTTL CSHSER -- PICTORIAL DATA STRUCTURES
;FORMAT OF CBHEAD LIST HEADER:
;
; !=======================================================!
; .CBNHB: ! POINTER TO FIRST BLOCK IN "FREE" LIST !
; !-------------------------------------------------------!
; .CBPHB: ! POINTER TO LAST BLOCK IN "FREE" LIST !
; !-------------------------------------------------------!
; .CBNAB: ! POINTER TO FIRST BLOCK IN ACCESS LIST !
; !-------------------------------------------------------!
; .CBPAB: ! POINTER TO LAST BLOCK IN ACCESS LIST !
; !=======================================================!
;FORMAT OF TWO WORD CBHSHT HASH TABEL ENTRY:
;
; !=======================================================!
; .CBNHB: ! POINTER TO FIRST HASH BLOCK IN THIS CHAIN !
; !-------------------------------------------------------!
; .CBPHB: ! POINTER TO LAST HASH BLOCK IN THIS CHAIN !
; !=======================================================!
;FORMAT OF EACH LIST ENTRY:
;
; !=======================================================!
; .CBNHB: ! POINTER TO NEXT HASH BLOCK IN THIS CHAIN !
; !-------------------------------------------------------!
; .CBPHB: ! POINTER TO PREVIOUS HASH BLOCK IN THIS CHAIN !
; !-------------------------------------------------------!
; .CBNAB: ! POINTER TO NEXT ACCESSED BLOCK !
; !-------------------------------------------------------!
; .CBPAB: ! POINTER TO PREVIOUS ACCESSED BLOCK !
; !-------------------------------------------------------!
; .CBUDB: ! UDB OF UNIT CONTAINING THIS BLOCK !
; !-------------------------------------------------------!
; .CBBLK: ! BLOCK NUMBER !
; !-------------------------------------------------------!
; .CBDAT: ! POINTER TO 128. WORDS FOR THIS DISK BLOCK !
; !=======================================================!
SUBTTL CSHSER -- DATA STRUCTURES
.CBNHB==0 ;NEXT HASH BLOCK
.CBPHB==1 ;PREVIOUS HASH BLOCK
.CBNAB==2 ;NEXT ACCESSED BLOCK
.CBPAB==3 ;PREVIOUS ACCESS BLOCK
.CBUDB==4 ;RH=UDB OF UNIT
.CBBLK==5 ;THE BLOCK NUMBER
.CBDAT==6 ;ADDRESS OF BLOCK IN CORE
.CBHIT==7 ;COUNT OF HITS THIS BLOCK
.CBLEN==10 ;LENGTH
EXTERN CBHSHT ;CACHE HASH TABLE
;ROUTINE TO GET THE INTERLOCK
UPPDC: PUSHJ P,UPDC ;GET IT
STOPCD .,DEBUG,IUI, ;++ILLEGAL USE OF UPPDC AT INTERRUPT LEVEL
POPJ P,
;ROUTINE TO GET THE INTERLOCK (IF POSSIBLE)
;NOSKIP IF INTERLOCK WAS NOT AVAILABLE
UPDC1: PUSHJ P,UUOLVL## ;AT UUO LEVEL?
POPJ P, ;NO, INTERLOCK NOT AVAILABLE
;ENTER HERE
UPDC: SKIPGE INTRDC## ;INTERLOCK AVAILABLE?
AOSE INTRDC##
JRST UPDC1 ;NO
IFN FTMP,<APRID INTODC##> ;YES, REMEMBER WHICH CPU
PUSHJ P,NOWDU ;PARANOIA
JRST CPOPJ1## ;WE GOT IT
;ROUTINE TO GIVE UP THE INTERLOCK
DWNDC: PUSHJ P,NOWDU ;DO CSDELU NOW
IFN FTMP,<SETOM INTODC##> ;NOT US
SETOM INTRDC## ;OPEN THE FLOOD GATE
POPJ P,
;ROUTINE TO DELETE A UNIT FROM THE CACHE (BECAUSE DELETION WAS DELAYED
;FROM A POINT EARLIER IN TIME)
NOWDU: SKIPN NOWDUC## ;ANY DELAYED?
POPJ P, ;NO
SOS NOWDUC## ;YES, COUNT IT
PUSHJ P,NWDU ;SEARCH AND DESTROY
JRST NOWDU ;AGAIN (PARANOID ABOUT RACES)
;ROUTINE TO SEARCH FOR A UNIT THAT WANTS TO BE DELETED FROM CACHE
NWDU: PUSHJ P,SAVE2##
PUSH P,U
MOVEI P1,UNPNDU ;THE BIT WE ARE SEARCHING FOR
MOVEI U,SYSUNI##-UNISYS ;PRESET PRED
NWDU1: HLRZ U,UNISYS(U) ;GET NEXT UNIT
JUMPE U,UPOPJ## ;NONE
IFN FTDUAL,<
HRRZ P2,UNIALT(U) ;EITHER PORT
SKIPE P2
TDNN P1,UNINDU(P2)
>
TDNE P1,UNINDU(U) ;WANT TO DELETE THIS UNIT?
PUSHJ P,CSDUN ;YES, DO IT
JRST NWDU1 ;NO, KEEP SEARCHING
SUBTTL CSHINI - INITIALIZE THE CACHE, HASH TABLES, AND LINKS
;CALL:
; PUSHJ P,CSHINI
; <RETURN>
CSHINI::MOVSI T1,-CBHSHL## ;LENGTH OF TABLE
;LINK ALL HASH ENTRIES TO THEMSELVES
CSHIN1: MOVEI T2,CBHSHT(T1) ;ADDRESS OF SELF
MOVEM T2,CBHSHT+.CBNHB(T1) ;STORE NEXT
MOVEM T2,CBHSHT+.CBPHB(T1) ;AND PREVIOUS TO SELF
AOBJN T1,.+1 ;ADVANCE TO NEXT
AOBJN T1,CSHIN1 ;AND LOOP FOR ALL
;LINK HEADER ENTRY LINKS TO THEMSELVES
MOVEI T1,CBHEAD ;ADDRESS OF HEADER
MOVEM T1,CBHEAD+.CBNAB ;STORE NEXT
MOVEM T1,CBHEAD+.CBPAB ;AND PREVIOUS TO SELF
MOVEM T1,CBHEAD+.CBNHB ;STORE NEXT IN INVALID LIST
MOVEM T1,CBHEAD+.CBPHB ;AND PREVIOUS TO SELF
;ALLOCATE THE INITIAL SIZE OF THE CACHE
SETZM %LDCSZ## ;NO ENTRIES IN CACHE
MOVE T1,%LDOCS## ;MAXIMUM SIZE (PATCHABLE)
PUSHJ P,CSHSSZ ;INITIALIZE CACHE SIZE
JFCL ;CANT MAKE IT THAT BIG
POPJ P, ;RETURN
SUBTTL CSHFND - FIND ENTRY IN CACHE
;CALL:
; T1/ BLOCK NUMBER
; U/ UDB ADDRESS
; PUSHJ P,CSHFND
; <ERROR> ;BLOCK NOT IN CACHE T2/ ADDRESS TO INSERT
; <NORMAL> ;BLOCK IN CACHE T2/ ADDRESS OF ENTRY
CSHFND: MOVE T2,T1 ;COPY BLOCK NUMBER
XOR T2,U ;SPRINKLE MORE BITS
IDIVI T2,CBHSHL##/2 ;HASH INTO TABLE
LSH T3,1 ;DOUBLE REMAINDER
MOVEI T4,CBHSHT(T3) ;REMEMBER START OF LIST
MOVE T2,T4 ;COPY POINTER TO START
AOS %LDHSF## ;COUNT PROBES
;LOOP THROUGH HASH CHAIN FROM INITIAL PROBE
CSHFN1: CAMN T4,.CBNHB(T2) ;SEE IF LOOPED AROUND
POPJ P, ;YES, NOT IN TABLE
MOVE T2,.CBNHB(T2) ;COPY CURRENT BLOCK
HRRZ T3,.CBUDB(T2) ;UNIT DATA BLOCK
CAMN T1,.CBBLK(T2) ;MATCH THIS BLOCK?
CAME U,T3 ;AND THIS UNIT?
AOSA %LDHSC## ;NO, COUNT COLLISIONS
JRST CPOPJ1## ;YES, SKIP RETURN
JRST CSHFN1 ;AND LOOP
SUBTTL CSHIO - DISPATCH ON READ OR WRITE REQUEST
;CALL:
; F/ DDB ADDRESS
; PUSHJ P,CSHIO
; <RETURN>
;IF A READ, WILL READ DATA FROM DISK OR GET FROM CACHE USING IOWD IN DEVDMP
;IF A WRITE, WILL WRITE DATA AND FIX CACHE FROM IOWD IN DEVDMP
;IN ALL CASES, S HAS ERROR BITS (0 IF CAME FROM CACHE), AND DEVBLK INDICATES
;THE BLOCK TO READ OR WRITE
CSHIO:: TLZE F,UCACHE ;WANT UNCACHED I/O?
JRST CSHIOU ;YES--DO NOTHING HERE
PUSHJ P,UPPDC ;GET INTERLOCK
SKIPG %LDCSZ## ;ANY BLOCKS ALLOCATED?
JRST CSHION ;NO--CANT CACHE ANYTHING!
;SETUP U TO PRIMARY PORT UDB AND INTERLOCK US
PUSH P,U
PUSHJ P,CSSETU ;SET U TO PRIMARY PORT
MOVSI T1,U2PNOC ;NON-CACHED UNIT (STRUCTURE)?
TDNE T1,UNIDS2(U)
JRST CSHIO3 ;YES
MOVE T1,DEVBLK##(F) ;GET BLOCK NUMBER
;DISPATCH ON READ OR WRITE
TLNE S,IO ;WRITING?
JRST CSHIOW ;YES
;READ - SEE IF DATA IN THE CACHE ALREADY
AOS %LDRDC## ;NO--COUNT TOTAL READ CALLS
AOS UNICRC(U) ;AND PER UDB
PUSHJ P,CSHFND ;SEE IF BLOCK IN CACHE
JRST CSHIO0 ;NOT FOUND
;READ - DATA FOUND IN CACHE, UPDATE BLOCK TO TOP OF ACCESS LIST
;BLT DATA TO MONITOR BUFFER, AND RETURN
AOS %LDRDH## ;COUNT TOTAL READ HITS
AOS UNICRH(U) ;AND PER UDB
PUSHJ P,CSHMRU ;MOVE TO TOP OF LIST
PUSHJ P,CSHC2B ;MOVE DATA FROM CACHE TO BUFFER
MOVEI S,0 ;CLEAR ANY ERROR BITS
JRST CSHDMM ;POP U AND RETURN
;READ - DATA NOT IN CACHE, READ IT INTO MONITOR BUFFER
CSHIO0: EXCH U,(P) ;GET ORIGINAL U BACK
PUSHJ P,DWNDC ;GIVE UP INTERLOCK
PUSHJ P,UUOPWQ ;SETUP FOR READ
PUSHJ P,PWAIT1 ;WAIT FOR THE DATA
PUSHJ P,UPPDC ;GET INTERLOCK
;READ - CHECK TO BE SURE BLOCK DIDNT REAPPEAR IN THE CACHE WHILE
;WHILE WE DROPPED MM AND BLOCKED
EXCH U,(P) ;SAVE ORIGINAL U, GET CSSETU BACK
MOVE T1,DEVBLK##(F) ;GET BLOCK NUMBER BACK
PUSHJ P,CSHFND ;SEE IF SNUCK BACK IN CACHE
JRST CSHIO1 ;NO--CONTINUE
;READ - BLOCK APPEARED IN CACHE WHILE WE BLOCKED. PREFER THAT BLOCK
;AND BLT IT TO OUR BUFFER, DISCARDING WHAT WE READ
PUSHJ P,CSHMRU ;YES!!--MOVE TO TOP OF LIST
PUSHJ P,CSHC2B ;COPY DATA FROM CACHE TO BUFFER
MOVEI S,0 ;CLEAR ANY ERROR BITS
JRST CSHDMM ;POP U AND RETURN
;READ - HERE WHEN BLOCK DIDNT APPEAR BACK IN CACHE WHEN WE BLOCKED
;(THIS SHOULD USALLY BE THE CASE). BLT DATA INTO CACHE
;AND REPLACE THE LRU BLOCK WITH THIS ONE
CSHIO1: SKIPLE %LDCSZ## ;CACHE SIZE MAY HAVE CHANGED TO ZERO
TDNE S,[IOSTBL,,IOERR] ;ANY I/O ERRORS?
JRST CSHDMM ;YES--DONT PUT BLOCK IN CACHE
MOVE T1,CBHEAD+.CBPAB ;GET LAST BLOCK
SKIPE T1,.CBUDB(T1) ;SEE IF UDB IN USE
SOS UNICBK(T1) ;YES--DECR BLOCKS FOR PREVIOUS UNIT
AOS UNICBK(U) ;INCR BLOCKS FOR CURRENT UNIT
MOVE T1,DEVBLK##(F) ;GET BLOCK NUMBER
PUSHJ P,CSHINS ;INSERT NEW BLOCK IN CACHE
PUSHJ P,CSHB2C ;MOVE DATA FROM BUFFER TO CACHE
JRST CSHDMM ;POP U AND RETURN
;WRITE - SEE IF WRITING A BLOCK THAT ALREADY EXISTS IN THE CACHE
CSHIOW: AOS %LDWRC## ;COUNT TOTAL WRITE CALLS
AOS UNICWC(U) ;AND PER UDB
PUSHJ P,CSHFND ;SEE IF BLOCK IN CACHE
JRST CSHIO3 ;NOT FOUND
;WRITE - DATA FOUND IN CACHE, REPLACE BLOCK WITH DATA WE WERE ABOUT
;(OR NO BLOCKS ALLOCATED TO CACHE)
;TO WRITE, AND MOVE BLOCK TO TOP OF ACCESSED LIST
AOS %LDWRH## ;COUNT TOTAL WRITE HITS
AOS UNICWH(U) ;AND PER UDB
PUSHJ P,CSHMRU ;MOVE TO TOP OF LIST
PUSHJ P,CSHB2C ;UPDATE DATA IN CACHE
CSHIO3: POP P,U ;GET U BACK
;WRITE - DATA NOT IN CACHE, JUST WRITE IT OUT, AND LEAVE CACHE ALONE
CSHION: PUSHJ P,DWNDC ;GIVE UP INTERLOCK
CSHIOU: PUSHJ P,UUOPWQ ;SETUP FOR WRITE
PJRST PWAIT1 ;WAIT FOR COMPLETION AND RETURN
CSHDMM: PUSHJ P,DWNDC ;GIVE UP INTERLOCK
PJRST UPOPJ## ;POP U AND RETURN
SUBTTL CSHC2B - MOVE DATA FROM CACHE TO BUFFER
;CALL:
; T2/ POINTER TO LIST ENTRY
; F/ POINTER TO DDB (DEVDMP SETUP)
; PUSHJ P,CSHC2B
; <RETURN>
CSHC2B: PUSHJ P,CSSETL ;SETUP LENGTH FOR BLT
JUMPE T1,CPOPJ## ;NO WORK IF NO DATA
IFN FTXMON,<
SE1ENT ;ENTER SECTION 1
PUSH P,T2 ;SAVE T2
MOVE T2,.CBDAT(T2) ;START
PUSH P,F ;SAVE F
HRRZS F ;GET JUST ADDRESS
HRRZ T3,DEVDMP##(F) ;GET DESTINATION (IOWD)
ADDI T3,1 ;FIX UP
HRL T3,DEVISN(F) ;SECTION NUMBER
POP P,F ;RESTORE F
EXTEND T1,[XBLT] ;MOVE THE DATA
POP P,T2 ;RESTORE T2
>;END IFN FTXMON
IFE FTXMON,<
HRRZ T3,DEVDMP##(F) ;GET IOWD START
ADDI T3,1 ;REMOVE -1 OFFSET
ADDI T1,(T3) ;COMPUTE DESTINATION END
HRL T3,.CBDAT(T2) ;GET START
BLT T3,-1(T1) ;MOVE THE DATA TO BUFFER
>;END IFE FTXMON
POPJ P, ;AND RETURN
SUBTTL CSHB2C - MOVE DATA FROM BUFFER TO CACHE
;CALL:
; T2/ POINTER TO LIST ENTRY
; F/ POINTER TO DDB (DEVDMP SETUP)
; PUSHJ P,CSHB2C
; <RETURN>
CSHB2C: PUSHJ P,CSSETL ;SETUP LENGTH FOR BLT
JUMPE T1,CPOPJ## ;NO WORK IF NO DATA
IFN FTXMON,<
SE1ENT ;ENTER SECTION 1
PUSH P,T2 ;SAVE T2
MOVE T3,.CBDAT(T2) ;DESTINATION
PUSH P,F ;SAVE F
HRRZS F ;GET JUST ADDRESS
HRRZ T2,DEVDMP##(F) ;START (IOWD)
ADDI T2,1 ;FIX UP
HRL T2,DEVISN(F) ;SECTION NUMBER
POP P,F ;RESTORE F
EXTEND T1,[XBLT] ;MOVE THE DATA
POP P,T2 ;RESTORE T2
>;END IFN FTXMON
IFE FTXMON,<
HRRZ T3,DEVDMP##(F) ;GET IOWD START
MOVSI T3,1(T3) ;REMOVE -1, SWITCH HALVES
HRR T3,.CBDAT(T2) ;POINT TO BUFFER
ADD T1,.CBDAT(T2) ;INCLUDE LENGTH IN T1 FOR DEST
BLT T3,-1(T1) ;MOVE THE DATA
>;END IFE FTXMON
POPJ P, ;AND RETURN
SUBTTL CSSETL - SET LENGTH OF BLT
;CALL:
; F/ DDB ADDRESS (DEVDMP SETUP)
; PUSHJ P,CSSETL
; <RETURN> ;T1/ LENGTH FOR BLT
CSSETL: HLRE T1,DEVDMP##(F) ;GET -SIZE
MOVMS T1 ;GET +SIZE
CAILE T1,BLKSIZ## ;WITHIN A BLOCK?
STOPCD .,STOP,WSM ;++WRONG SIZE MOVED
POPJ P, ;AND RETURN
SUBTTL CSHSIZ - SET SIZE OF CACHE
;CALL: (FROM SETUUO)
; T2/ NEW SIZE OF CACHE IN BLOCKS
; PUSHJ P,CSHSIZ
; <ERROR> ;CANT ALLOCATE MORE SPACE
; <NORMAL> ;CACHE EXPANDED/CONTRACTED
;CALL: (FROM CSHINI)
; T1/ NEW SIZE OF CACHE IN BLOCKS
; PUSHJ P,CSHSSZ
; <ERROR> ;CANT ALLOCATE MORE SPACE
; <NORMAL> ;CACHE EXPANDED/CONTRACTED
CSHSIZ::MOVE T1,T2 ;SETUUO HAD ARG IN T2
PUSHJ P,CSHSSZ ;SET THE CACHE SIZE
JRST ECOD0##
JRST CPOPJ1## ;HAPPINESS
CSHSSZ: JUMPL T1,CPOPJ## ;NEGATIVE SIZE IS BAD
SKIPG [M.CBMX##] ;ANY BLOCKS ALLOCATED AT SYSINI?
POPJ P, ;NO--CANT MAKE ANY NOW EITHER
PUSHJ P,SAVE1## ;SAVE P1
MOVE P1,T1 ;COPY SIZE
;COMPUTE NEW SIZE, SEE IF INCREASING OR DECREASING ALLOCATION
SUB P1,%LDCSZ## ;MINUS CURRENT SIZE
JUMPE P1,CPOPJ1## ;RETURN IF NO CHANGE
JUMPG P1,CSHSZ1 ;EXPAND CACHE
;DECREASING, DEALLOCATE BLOCKS UNTIL REQUESTED SIZE REARCHED
CSHSZ2: PUSHJ P,CSHDEA ;DEALLOCATE A BLOCK
AOJL P1,CSHSZ2 ;LOOP FOR ALL
JRST CPOPJ1## ;AND EXIT
;INCREASING, ALLOCATE BLOCKS UNTIL REQUESTED SIZE IS REACHED
CSHSZ1: PUSHJ P,CSHALC ;ALLOCATE A BLOCK
POPJ P, ;CANT--RETURN
SOJG P1,CSHSZ1 ;LOOP FOR ALL
JRST CPOPJ1## ;AND SKIP RETURN
SUBTTL CSHALC - ALLOCATE ANOTHER BLOCK FOR THE CACHE
;CALL:
; PUSHJ P,CSHALC
; <ERROR> ;CANT ALLOCATE ANOTHER BLOCK
; <NORMAL> ;ANOTHER BLOCK ALLOCATED
CSHALC: MOVEI T2,.CBLEN ;GET LENGTH
PUSHJ P,GETWDS## ;GET CORE FOR NEW BLOCK
POPJ P, ;RETURN W/O INCREASING CACHE
PUSH P,T1 ;SAVE ENTRY ADDRESS
MOVEI T2,BLKSIZ## ;GET SIZE OF A BLOCK
IFN FTXMON,<PUSHJ P,GFWNZS##> ;GET CORE FROM SECTION 3
IFE FTXMON,<PUSHJ P,GETWDS##> ;GET CORE FROM FRECOR POOL
JRST TPOPJ## ;CANT
POP P,T2 ;RESTORE ENTRY ADDRESS
MOVEM T1,.CBDAT(T2) ;STORE ADDRESS OF BLOCK
PUSHJ P,UPPDC ;GET INTERLOCK
AOS %LDCSZ## ;COUNT BLOCKS INSERTED
;LINK NEW BLOCK AT BEGINNING OF "FREE" HASH LIST
MOVE T3,CBHEAD+.CBNHB ;GET FORWARD FROM HEADER
MOVE T4,.CBPHB(T3) ;AND PREVIOUS FROM TOP
MOVEM T2,CBHEAD+.CBNHB ;INSERT US AT THE TOP
MOVEM T2,.CBPHB(T3) ;PREVIOUS OF OLD TOP IS US
MOVEM T3,.CBNHB(T2) ;NEXT OF US IS OLD TOP
MOVEM T4,.CBPHB(T2) ;PREVIOUS OF US IS HEADER
;CLEAR OUT ANY TRASH
SETZM .CBBLK(T2) ;CLEAR BLOCK
SETZM .CBUDB(T2) ;AND UDB TO BE SAFE
SETZM .CBHIT(T2) ;AND COUNT OF HITS THIS BLOCK
;LINK NEW BLOCK AT END OF ACCESSED LIST
MOVE T3,CBHEAD+.CBPAB ;GET FORWARD FROM HEADER
MOVE T4,.CBNAB(T3) ;AND NEXT FROM TOP
MOVEM T2,CBHEAD+.CBPAB ;INSERT US AT THE TOP
MOVEM T2,.CBNAB(T3) ;NEXT OF OLD TOP IS US
MOVEM T3,.CBPAB(T2) ;PREVIOUS OF US IS OLD TOP
MOVEM T4,.CBNAB(T2) ;NEXT OF US IS HEADER
PUSHJ P,DWNDC ;GIVE UP INTERLOCK
JRST CPOPJ1## ;AND SKIP RETURN
SUBTTL CSHDEA - DEALLOCATE A BLOCK FROM THE CACHE
;CALL:
; PUSHJ P,CSHDEA
; <RETURN>
CSHDEA: PUSHJ P,UPPDC ;GET INTERLOCK
MOVE T2,CBHEAD+.CBPAB ;LAST BLOCK IN CACHE
MOVE T3,.CBNAB(T2) ;GET NEXT
MOVE T4,.CBPAB(T2) ;GET PREVIOUS
MOVEM T3,.CBNAB(T4) ;REMOVE FROM FORWARD CHAIN
MOVEM T4,.CBPAB(T3) ;REMOVE FROM PREVIOUS CHAIN
;DELETE FROM HASH CHAIN
MOVE T3,.CBNHB(T2) ;GET NEXT
MOVE T4,.CBPHB(T2) ;GET PREVIOUS
MOVEM T3,.CBNHB(T4) ;REMOVE FROM FORWARD CHAIN
MOVEM T4,.CBPHB(T3) ;REMOVE FROM PREVIOUS CHAIN
;RETURN CORE, FIX UP CACHE SIZE
SKIPE T1,.CBUDB(T2) ;ASSOCIATED UDB?
SOS UNICBK(T1) ;YES--ONE LESS BLOCK CACHED
SOS %LDCSZ## ;CACHE IS 1 BLOCK SMALLER
PUSHJ P,DWNDC ;GIVE UP INTERLOCK
PUSH P,T2 ;SAVE ENTRY ADDRESS
MOVEI T1,BLKSIZ## ;SIZE OF BLOCK
MOVE T2,.CBDAT(T2) ;ADDRESS OF BLOCK
IFN FTXMON,<PUSHJ P,GVFWDS##>
IFE FTXMON,<PUSHJ P,GIVWDS##>
POP P,T2 ;RESTORE ENTRY ADDRESS
MOVEI T1,.CBLEN ;GET LENGTH
PJRST GIVWDS## ;RETURN CORE AND RETURN
SUBTTL CSHINS - INSERT (REPLACE) NEW BLOCK IN CACHE
;CALL:
; T1/ BLOCK NUMBER
; U/ UDB ADDRESS
; T2/ ENTRY TO ADD AFTER
; PUSHJ P,CSHINS
; <RETURN>
CSHINS: CAMN T2,CBHEAD+.CBPAB ;SAME AS ENTRY WE FIDDLE
JRST [MOVEM T1,.CBBLK(T2) ;STORE NEW BLOCK
MOVEM U,.CBUDB(T2) ;AND NEW UDB ADDRESS
SETZM .CBHIT(T2) ;CLEAR HITS THIS BLOCK
PJRST CSHMRU] ;AND MOVE TO TOP
;STORE BLOCK NUMBER AND UDB, REPLACE LAST BLOCK IN ACCESS CHAIN
PUSH P,T2 ;SAVE ENTRY TO ADD
MOVE T2,CBHEAD+.CBPAB ;GET LAST IN CHAIN
MOVEM T1,.CBBLK(T2) ;STORE NEW BLOCK
MOVEM U,.CBUDB(T2) ;AND NEW UDB ADDRESS
SETZM .CBHIT(T2) ;CLEAR HITS THIS BLOCK
;UNLINK FROM OLD HASH CHAIN
MOVE T3,.CBNHB(T2) ;GET NEXT
MOVE T4,.CBPHB(T2) ;GET PREVIOUS
MOVEM T3,.CBNHB(T4) ;REMOVE FROM FORWARD CHAIN
MOVEM T4,.CBPHB(T3) ;REMOVE FROM PREVIOUS CHAIN
;LINK THIS BLOCK INTO CORRECT HASH CHAIN
MOVE T1,T2
POP P,T2 ;RESTORE ENTRY TO ADD
MOVE T4,.CBNHB(T2) ;AND NEXT LINK
MOVEM T1,.CBNHB(T2) ;INSERT AFTER PREVIOUS
MOVEM T1,.CBPHB(T4) ;AND AS PREVIOUS OF OLD
MOVEM T2,.CBPHB(T1) ;STORE PREVIOUS OF OLD AS OURS
MOVEM T4,.CBNHB(T1) ;STORE NEXT OF OLD AS OURS
MOVE T2,T1
;MOVE ENTRY TO "MOST RECENTLY USED" AND RETURN
PJRST CSHMRU ;AND MOVE ENTRY TO TOP OF LIST
SUBTTL CSHMRU - MOVE ENTRY TO BEGINNING OF ACCESS LIST
;CALL:
; T2/ ENTRY TO MOVE TO TOP OF ACCESS LIST
; PUSHJ P,CSHMRU
; <RETURN>
CSHMRU: AOS .CBHIT(T2) ;COUNT HITS THIS BLOCK
CAMN T2,CBHEAD+.CBNAB ;WE AT THE TOP?
POPJ P, ;YES--SAVE SOME WORK
;DELETE FROM CURRENT ACCESS CHAIN POSITION
MOVE T3,.CBNAB(T2) ;GET NEXT
MOVE T4,.CBPAB(T2) ;GET PREVIOUS
MOVEM T3,.CBNAB(T4) ;REMOVE FROM FORWARD CHAIN
MOVEM T4,.CBPAB(T3) ;REMOVE FROM PREVIOUS CHAIN
;RELINK INTO "MOST RECENTLY USED" POSITION
MOVE T3,CBHEAD+.CBNAB ;GET FORWARD FROM HEADER
MOVE T4,.CBPAB(T3) ;AND PREVIOUS FROM TOP
MOVEM T2,CBHEAD+.CBNAB ;INSERT US AT THE TOP
MOVEM T2,.CBPAB(T3) ;PREVIOUS OF OLD TOP IS US
MOVEM T3,.CBNAB(T2) ;NEXT OF US IS OLD TOP
MOVEM T4,.CBPAB(T2) ;PREVIOUS OF US IS HEADER
POPJ P, ;AND RETURN
SUBTTL CSHLRU - MOVE ENTRY TO END OF ACCESS LIST
;CALL:
; T2/ ENTRY TO MOVE TO END OF ACCESS LIST
; PUSHJ P,CSHLRU
; <RETURN>
CSHLRU: CAMN T2,CBHEAD+.CBPAB ;WE AT THE END?
POPJ P, ;YES--SAVE SOME WORK
;DELETE FROM CURRENT ACCESS CHAIN POSITION
MOVE T3,.CBNAB(T2) ;GET NEXT
MOVE T4,.CBPAB(T2) ;GET PREVIOUS
MOVEM T3,.CBNAB(T4) ;REMOVE FROM FORWARD CHAIN
MOVEM T4,.CBPAB(T3) ;REMOVE FROM PREVIOUS CHAIN
;RELINK INTO "LEAST RECENTLY USED" POSITION
MOVE T3,CBHEAD+.CBPAB ;GET FORWARD FROM HEADER
MOVE T4,.CBNAB(T3) ;AND NEXT FROM TOP
MOVEM T2,CBHEAD+.CBPAB ;INSERT US AT THE TOP
MOVEM T2,.CBNAB(T3) ;NEXT OF OLD TOP IS US
MOVEM T3,.CBPAB(T2) ;PREVIOUS OF US IS OLD TOP
MOVEM T4,.CBNAB(T2) ;NEXT OF US IS HEADER
POPJ P, ;AND RETURN
SUBTTL CSHDEL - DELETE ENTRY, MOVE TO FREE LIST
;CALL:
; T2/ ENTRY TO DELETE
; PUSHJ P,CSHDEL
; <RETURN>
CSHDEL: MOVE T3,.CBNHB(T2) ;GET NEXT
MOVE T4,.CBPHB(T2) ;GET PREVIOUS
MOVEM T3,.CBNHB(T4) ;REMOVE FROM FORWARD CHAIN
MOVEM T4,.CBPHB(T3) ;REMOVE FROM PREVIOUS CHAIN
;LINK INTO FREE CHAIN
MOVE T3,CBHEAD+.CBNHB ;GET FORWARD FROM HEADER
MOVE T4,.CBPHB(T3) ;AND PREVIOUS FROM TOP
MOVEM T2,CBHEAD+.CBNHB ;INSERT US AT THE TOP
MOVEM T2,.CBPHB(T3) ;PREVIOUS OF OLD TOP IS US
MOVEM T3,.CBNHB(T2) ;NEXT OF US IS OLD TOP
MOVEM T4,.CBPHB(T2) ;PREVIOUS OF US IS HEADER
;ADJUST COUNTERS
SKIPE T3,.CBUDB(T2) ;GET UDB
SOS UNICBK(T3) ;ONE LESS BLOCK IN CACHE
SETZM .CBBLK(T2) ;CLEAR BLOCK NUMBER
SETZM .CBUDB(T2) ;AND UDB TO BE SAFE
;MOVE ENTRY TO "LEAST RECENTLY USED" AND RETURN
PJRST CSHLRU ;AND SET LEAST RECENTLY USED
SUBTTL CSDELB - DELETE BLOCK IF IN CACHE
;CALL:
; T1/ BLOCK NUMBER
; U/ UDB ADDRESS
; PUSHJ P,CSDELB
; <RETURN>
;U/ UDB ADDRESS
CSDELB::PUSHJ P,UPPDC ;GET INTERLOCK
SKIPG %LDCSZ## ;ANY BLOCKS IN CACHE?
JRST DWNDC ;NO, DON'T BOTHER
PUSH P,U ;SAVE U
PUSHJ P,CSSETU ;SETUP U TO PRIMARY PORT
PUSHJ P,CSHFND ;FIND IN CACHE
CAIA ;NOT FOUND--SKIP THE DELETE
PUSHJ P,CSHDEL ;FOUND--GO DELETE FROM CACHE
PJRST CSHDMM ;GIVE UP INTERLOCK AND POP U
SUBTTL CSDELR - DELETE A RANGE OF BLOCKS
;CALL:
; T1/ STARTING BLOCK NUMBER
; T2/ NUMBER OF BLOCKS
; U/ UDB ADDRESS
; PUSHJ P,CSDELR
; <RETURN>
CSDELR::PUSHJ P,SAVE2## ;SAVE P1,P2
DMOVE P1,T1 ;COPY ARGS
CSDLR1: MOVE T1,P1 ;GET A BLOCK
PUSHJ P,CSDELB ;DELETE IF IN CACHE
ADDI P1,1 ;ADVANCE TO NEXT BLOCK
SOJLE P2,CPOPJ## ;RETURN WHEN DONE
TRNN P2,77 ;CALL SCDCHK EVERY
PUSHJ P,SCDCHK## ; 64 CALLS TO CSDELB
JRST CSDLR1 ;LOOP FOR MORE
SUBTTL CSDELI - DELETE AN IOWD LIST OF BLOCKS
;CALL:
; F/ DDB ADDRESS (DEVDMP, DEVBLK SETUP)
; PUSHJ P,CSDELI
; <RETURN>
CSDELI::PUSHJ P,SAVT## ;DONT TOUCH ANY AC'S
HRRZ T2,UNISTR(U) ;MOUNTED AS A STR?
JUMPE T2,CPOPJ## ;NO, DON'T NEED TO
HLRE T2,DEVDMP##(F) ;GET -SIZE
MOVMS T2 ;GET +SIZE
ADDI T2,BLKSIZ##-1 ;ROUND UP
IDIVI T2,BLKSIZ## ;COMPUTE NUMBER OF BLOCKS
MOVE T1,DEVBLK##(F) ;GET STARTING BLOCK
SUB T1,T2
JUMPL T1,CPOPJ## ;DEVDMP IS FUNNY DURING FORMATING
PJRST CSDELR ;DELETE THAT RANGE AND RETURN
SUBTTL CSDELU - DELETE ALL BLOCKS ON SPECIFIED UNIT FROM CACHE
;CALL:
; U/ UDB ADDRESS
; PUSHJ P,CSDELU
; <RETURN>
CSDELU::PUSHJ P,UPDC ;GET INTERLOCK
JRST CSDU9 ;NOT AVAILABLE
PUSHJ P,CSDUN ;DELETE IT
PJRST DWNDC ;GIVE AWAY INTERLOCK
;HERE IF YOU ALREADY HAVE THE INTERLOCK
CSDUN: SKIPG %LDCSZ## ;ANY BLOCKS IN CACHE?
POPJ P, ;NO
PUSHJ P,SAVE2##
PUSHJ P,SAVT## ;BETTER SAFE THAN SORRY
PUSH P,U ;SAVE UNIT
TLZ U,-1 ;PARANOIA
IFN FTDUAL,<
PUSHJ P,CSDU0 ;DELETE 1ST PORT
HRRZ U,UNIALT(U) ;DELETE 2ND PORTS
JUMPE U,UPOPJ##
PUSHJ P,CSDU0
JRST UPOPJ##
>
CSDU0: MOVEI P1,UNPNDU ;CLEAR BIT
ANDCAM P1,UNINDU(U)
MOVSI P1,-CBHSHL## ;GET LENGTH OF TABLE
;STEP THROUGH EACH ENTRY IN THE HASH TABLE
CSDU1: MOVEI P2,CBHSHT(P1) ;GET AN ENTRY
MOVE T2,.CBNHB(P2) ;GET FIRST ENTRY
;STEP THROUGH EACH HASH CHAIN FOR THIS ENTRY
CSDU2: CAMN P2,T2 ;LOOPED BACK?
JRST CSDU3 ;YES
PUSH P,.CBNHB(T2) ;SAVE POINTER TO NEXT BLOCK
CAMN U,.CBUDB(T2) ;MATCH THIS UNIT
PUSHJ P,CSHDEL ;YES--DELETE IT
POP P,T2 ;RESTORE NEXT BLOCK
JRST CSDU2 ;AND LOOP
CSDU3: AOBJN P1,.+1 ;ADVANCE TO NEXT
AOBJN P1,CSDU1 ;LOOP FOR WHOLE TABLE
IFE FTDUAL,<JRST UPOPJ##>
IFN FTDUAL,<POPJ P,>
;HERE IF INTERLOCK IS NOT AVAILABLE
;DELAY THE CACHE SWEEP TILL LATER
CSDU9: PUSHJ P,SAVE1##
MOVEI P1,UNPNDU ;LIGHT THE BIT
IORM P1,UNINDU(U)
AOS NOWDUC## ;COUNT IT
POPJ P,
REPEAT 0,<
SUBTTL CSDELA - DELETE ALL BLOCKS FROM CACHE
;CALL:
; PUSHJ P,CSDELA
; <RETURN>
CSDELA::PUSHJ P,UPPDC ;GET INTERLOCK
SKIPG %LDCSZ## ;ANY BLOCKS IN CACHE?
JRST CSDA4 ;NO--DONT BOTHER
PUSHJ P,SAVE2## ;SAVE P1,P2
MOVSI P1,-CBHSHL## ;GET LENGTH OF TABLE
;STEP THROUGH EACH ENTRY IN THE HASH TABLE
CSDA1: MOVEI P2,CBHSHT(P1) ;GET AN ENTRY
MOVE T2,.CBNHB(P2) ;POINT TO FIRST ENTRY
;STEP THROUGH EACH HASH CHAIN FOR THIS ENTRY
CSDA2: CAMN P2,T2 ;LOOPED BACK?
JRST CSDA3 ;YES
PUSH P,.CBNHB(T2) ;SAVE POINTER TO NEXT BLOCK
PUSHJ P,CSHDEL ;DELETE THIS BLOCK
POP P,T2 ;RESTORE NEXT BLOCK
JRST CSDA2 ;AND LOOP
CSDA3: AOBJN P1,.+1 ;ADVANCE TO NEXT
AOBJN P1,CSDA1 ;LOOP FOR WHOLE TABLE
CSDA4: PUSHJ P,DWNDC ;GIVE UP INTERLOCK
POPJ P, ;AND RETURN
>
SUBTTL CSSETU - SETUP U TO PRIMARY PORT
;CALL:
; U/ UDB ADDRESS
; PUSHJ P,CSSETU
; <RETURN> ;U/ PRIMARY PORT UDB ADDRESS
CSSETU:
IFN FTDUAL,<
SKIPGE T3,UNI2ND(U) ;2ND PORT?
HRRZ U,UNI2ND(U) ;YES, GET PRIME PORT
>;END IF FTDUAL
TLZ U,-1 ;BE SURE JUST RH ADDRESS
POPJ P, ;AND RETURN
$LIT
$LOW
LASUNI: BLOCK 1 ;LAST DISK UDB BUILT
CBHEAD::BLOCK .CBLEN ;CACHE BLOCK LIST HEADER
FILEND: END