Trailing-Edge
-
PDP-10 Archives
-
cust_sup_cusp_bb-x130c-sb
-
10,7/unsmon/dsxkon.mac
There are 4 other files named dsxkon.mac in the archive. Click here to see a list.
TITLE DSXKON - CONTROLLER ROUTINE FOR 3330/3331 DISK - V5
SUBTTL JOSEPH A. DZIEDZIC/JAD (DEC) & JEFF GUNTER/JEG (ADP) 23-AUG-88
;OLD AUTHORS - CYPHERNETICS CORPORATION 18-MAR-76
SEARCH F, S, DEVPRM, SAXPRM
$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 1987,1988.
;ALL RIGHTS RESERVED.
.CPYRT<1987,1988>
XP VDSXKN,5 ;VERSION NUMBER FOR GLOB AND MAP
DSXKON::ENTRY DSXKON
EXTERN SAXSER ;FORCE LOAD OF SERVICE ROUTINES
;MISCELLANEY UNTIL ELSEWHERE
.UT330==0
.UT331==1
;COMPUTE SIZE OF CHANNEL PROGRAM FROM CYLINDER SIZE (342) BLOCKS
;TIMES THE SIZE OF A WRITE (4 WORDS+2 DATA=6 WORDS) + 25% (BECAUSE 1 BLOCK
;OUT OF EVERY PAGE MIGHT REQUIRE A SPLIT IOWD)
;PLUS THE OVERHEAD OF A SEEK COMMAND, A SET-SECTOR COMMAND, AND THEIR ARGS
;(2 SEEK+2DATA+2 SECTOR+1DATA=7 WORDS)+A HALT
CPAOVR==10 ;SEEK,IOWD,DATA(2); SECTOR,IOWD,DATA; HALT
CPAWRT==^D342*6 ;ENOUGH TO WRITE 342 BLOCKS
CPASPL==^D342/4+1 ; INCASE EVERY PAGE (IE: EVERY 4TH BLOCK) IS SPLIT
CPALEN==CPAOVR+CPAWRT+CPASPL+1 ;ENOUGH FOR MAXIMUM SIZED PROGRAM+A HALT
BLKBYT==<BLKSIZ##/2>*^D9 ;SIZE OF A DISK BLOCK IN BYTES (9 PER TWO WORDS)
;BYTE POINTERS
DSYDLO: POINT SASDLO,T1,SANDLO ;BYTE PTR TO STORE OPCODE IN DEVLST
DSYDLC: POINT SASDLC,T1,SANDLC ;POINTER TO ADDRESS FIELD
DSYDLD: POINT SASDLD,T1,SANDLD ;POINTER TO DEVICE-ADDRESS FIELD
UNYHNM: POINT UNSHNM,UNISCY+1(U),UNNHNM ;HEAD NUMBER (SEEK/SEARCH)
UNYRNM: POINT UNSRNM,UNISCY+1(U),UNNRNM ;RECORD NUMBER (SEEK/SEARCH)
UNYSSC: POINT UNSSEC,UNISEC(U),UNNSEC ;SECTOR NUMBER
;$$*** MAKE MORE EXTENSIVE USE OF THE ATTACH CODE SO THAT SENSE'S, LONG
;$$*** MULTI_TRACK XFERS AND THE LIKE CAN BELIEVE THAT THEY'RE DOING IT
;$$*** LINEARLY.
;$$***
;$$*** MAKE ECC CORRECTION WORK BY STASHING INFO AT INT LEVEL, AND THEN
;$$*** MAKE THE WORK HAPPEN AT xxxECC TIME, AND ALWAYS RETURNS 0S BACK TO
;$$*** FILIO SO HE DOESN'T DO ANYTHING ON HIS OWN.
;$$***
;$$*** MAKE DSXPOS DO A READ/WRITE OF RECORD ZERO AFTER THE SEEK SO THAT
;$$*** WE CAN SEE WRITE-LOCK STATUS. COPY INTERVENTION-REQUIRED AND LOCKED
;$$*** INTO UDB, AND THEN CHECK IT AT OPRED/OPWRT TIME SO WE DO A "CONECT"
;$$*** ROUTINE TO CATCH PROBLEMS AT "UUO LEVEL" ALA RPXKON ET AL.
SUBTTL DEVICE-DEPENDENT DEFINITIONS
;3330 DEVICE COMMANDS
O.SEEK==7 ;SEEK
O.SIE==61 ;SEARCH ID EQUAL
O.READ==6 ;READ
O.WRIT==5 ;WRITE
O.SNS==4 ;SENSE I/O
O.SFM==37 ;SET FILE MASK
O.RREL==244 ;READ, RESET ERROR LOG
O.SSEC==43 ;SET SECTOR
O.RCAL==23 ;RECALIBRATE
O.NOP==3 ;NO-OP
O.MTRD==206 ;MULTI-TRACK READ
O.MTOP==200 ;MULTI-TRACK OPERATION ('OR' WITH READ OR SEARCH)
FM.WRI==200 ;FILE MASK TO ALLOW WRITES AND SEEKS
FM.WRF==100 ;FILE MASK TO ALLOW WRITE HEADERS AND SEEKS
BLKMSK==777 ;THIS PART OF DEVICE COMMAND WORD IS IGNORED
;BY SA10 AND WE USE IT TO STORE RELATIVE BLOCK #,
;USED TO CALCULATE # BLOCKS XFER'ED UP TO ERROR PC
;THE FOLLOWING ARE NOT REALLY SENSE BITS, BUT ARE SET FOR SYSERR IN ERROR STATUS
SN.CDE==1B35 ;CHANNEL DETECTED ERROR (ERROR BUT NO SENSE)
SN.RTR==1B34 ;RETRY REQUESTED BY CHANNEL
SN.HNR==1B33 ;HUNG DISK RECOVERY - ASSUME ERROR
SN.COE==1B32 ;ERROR CORRECTED WITH ECC
SN.TWE==1B31 ;TERMINATION WORD ERROR
SUBTTL AUTOCONFIGURATION TABLES
SUBTTL DEFINITIONS
;PARAMETERS TO CONTROL XXKON MACRO:
DSFIX==0 ;NOT A FIXED-HEAD DEVICE
DSOFS==400000 ;NO OFFSET CAPABILITY
DSRDC==400000 ;NO 10/11 COMPATABILITY MODE
DSUNL==400000 ;NO UNLOAD CAPABILITY
DSCPY==0 ;CAN TELL UNIT TYPE EVEN IF KONTROLLER BUSY
DSMX==0 ;CANNOT DO MULTIPLE TRANSFERS
DSDRB==KOPDRB ;USES DISK I/O REQUEST BLOCKS
DSBMX==KOPBMX ;IS A BLOCK MULTIPLEX KONTROLLER
DSECA==KOPECA ;KONTROLLER CAN HANDLE ECC FIRST
DSERNO==0 ;NO DRIVE REGISTERS TO SAVE ON ERROR
DSXDMX==MAXUNS ;MAX DRIVES/KONTROLLER
DSXHDN==DSXDMX-1 ;HIGHEST DRIVE NUMBER
;DRIVER CHARACTERISTICS
; DSX = DSXCNF
; DSK = DISK
; TYPDS = KONTROLLER TYPE
; DSXDMX = MAXIMUM DRIVES PER KONTROLLER
; DSXHDN = HIGHEST DRIVE NUMBER
; MDSEC0 = SECTION FOR KDB/UDB
; MDSEC0 = SECTION FOR DDB
DRVCHR (DSX,DSK,0,TYPDS,DSXDMX,DSXHDN,MDSEC0,MDSEC0,<DR.MCD!DR.UCK!DR.UCU>)
SUBTTL KDB EXTENSIONS
.ORG KONUDB ;START OF 3330/3331 SPECIFIC DATA
DSXUTB:!BLOCK DSXDMX ;TABLE OF POINTERS TO UDBS
DSXEBK:!BLOCK 1 ;DUMMY ERROR BLOCK
DSXOVR:!BLOCK 1 ;COUNT OF OVERRUNS REPORTED IN STATISTICS
; LH=COMMAND RETRIES RH=DATA RETRIES
DSXUCC:!BLOCK 1 ;COUNT OF UNCORRECTABLE DATA CHECKS
DSXSCH:!BLOCK 1 ;LH = SA10 SUBCHANNEL IN CONO POSITION
;RH = SA10 SUBCHANNEL NUMBER
DSXGSN:!BLOCK 1 ;GLOBAL SUBCHANNEL NUMBER
DSXICW:!BLOCK 1 ;BASE ADDR FOR SUBCHANNEL THIS KONTROLLER IS ON
DSXCSW:!BLOCK 1 ;CHANNEL STATUS WORD ADDR FOR THIS KONTROLLER
DSXDVP:!BLOCK 1 ;POINT TO DEVICE LIST FOR UNIT 0
DSXPTR:!BLOCK 1 ;USED TO PICK UP UNIT DATA BLOCK ADDRESS
; GIVEN PHYSICAL UNIT NUMBER IN T3 (@ USED)
DSXIOB:! ;BEGINNING OF I/O INSTRUCTIONS IN KDB
DSXCO2:!BLOCK 1 ;CONO (T2)
DSXCI2:!BLOCK 1 ;CONI T2
DSXDTI:!BLOCK 1 ;DATAI T1
DSXIOE:! ;END OF I/O INSTRUCTIONS IN KDB
DSXIUM:! BLOCK DSXDMW ;IGNORE DRIVE MASK
DSXNUM:! BLOCK DSXDMW ;NEW DRIVE MASK
DSXKLN:! ;LENGTH OF KDB
.ORG
;PROTOTYPE KDB
DSXKDB: XXKON (DS)
SETWRD (DSXCO2,<CONO 000,(T2)>)
SETWRD (DSXCI2,<CONI 000,T2>)
SETWRD (DSXDTI,<DATAI 000,T1>)
SETWRD (DSXPTR,<DSXUTB(T3)>)
KDBEND
SUBTTL UDB EXTENSIONS
.ORG UNIEBK ;FOLLOW THE JUNK
UNIRCL:!BLOCK 1 ;RECALIBRATE
UNICHP:! ;BEGINNING OF CHANNEL PROGRAM
UNISEK:!BLOCK 2 ;SEEK PROGRAM(SEEK, IOWD TO DATA)
UNINOP:!BLOCK 1 ;NO-OP TO FORCE WAIT FOR DEV-END OF SEEK
UNISTP:!BLOCK 1 ;BMUX-HALT OR TIC.+1
UNISET:!BLOCK 2 ;SET-SECTOR, IOWD TO SECTOR-DATA
UNISIE:!BLOCK 1 ;SEARCH ID EQUALS
UNISID:!BLOCK 2 ;POINTER TO ID DATA, TIC TO UNISIE
UNIIOT:!BLOCK 1 ;TRANSFER TO XFER PART OF CHAN PROG
UNISNP:!BLOCK 3 ;SENSE I/O PROGRAM, BMXEND
UNIRWC:!BLOCK 1 ;PROTOTYPE DVW FOR CHANNEL PROGRAMS
UNISND:!BLOCK SNSLEN ;SENSE DATA
;UNIFMW:! ;FILE MASK IN BITS 0-7
; UNNFMW==^D7 ;RIGHTMOST BIT FOR FILE MASK
UNISEC:!BLOCK 1 ;SECTOR NUMBER IN BITS 16-23
UNSSEC==^D8 ;SIZE OF SECTOR NUMBER FIELD
UNNSEC==^D23 ;RIGHTMOST BIT
UNISCY:!BLOCK 2 ;CYLINDER, HEAD, RECORD NUMBER (SEEK, SEARCH)
SCYLSH==4 ;BITS TO SHIFT TO PUT CYLINDER NUMBER IN POSITION
UNSHNM==^D16 ;SIZE OF HEAD FIELD
UNNHNM==^D15 ;RIGHTMOST BIT (UNISCY+1)
UNSRNM==^D8 ;SIZE OF RECORD NUMBER FIELD
UNNRNM==^D23 ;RIGHTMOST BIT (UNISCY+1)
UNIFNC:!BLOCK 1 ;(RH) FILSER FUNCTION LAST ATTEMPTED
UNPSNS==1 ;(LH) BIT SET IF DOING SENSE I/O
UNPBSY==2 ; BIT SET IF GOT BUSY RESPONSE FOR UNIT
UNPHNS==4 ; BIT SET IF SET GO FLAG AFTER HUNG DISK
UNPCUE==10 ; BIT SET IF RECEIVE CONTROL-UNIT-END
; OTHER UNITS MAY HAVE RECEIVED BUSY
UNPONP==20 ; BIT SET IF POSITIONING FOR UNIT COMING ON-LINE
UNPCPY==40 ; BIT SET IF IN CPY ROUTINE FOR ATT CMD
UNPCPD==400000 ;(SIGN) BIT SET IF CPY ROUTINE DONE
UNIDRB:!BLOCK 1 ;ADDRESS OF DRB FOR THIS UNIT
UNINUM:!BLOCK 1 ;NUMBER OF BLOCKS TO TRANSFER (LIKE CHNNUM)
UNICSW:!BLOCK 1 ;SAVED COPY OF SACSW FOR DEBUGGING
UNITCA:!BLOCK 1 ;SAVED COPY OF SATCA FROM BEFORE SENSE COMMAND
UNICBN:!BLOCK 1 ;CURRENT BLOCK NUMBER (USED WHILE BUILDING PROGRAM)
UNIECN:!BLOCK 1 ;ERROR COUNTER BETWEEN RECALIBRATES
UNIRCT:!BLOCK 1 ;RECALIBRATE COUNTER
UNILPC:!BLOCK 1 ;PHYSICAL PC OF FAILING XFER CMD
UNICOE:!BLOCK 1 ;COUNT OF CORRECTABLE ERRORS CORRECTED WITH ECC
UNITCW:!BLOCK 1 ;EXPECTED TERMINAL COUNT,ADDR WORD
UNITNM:!BLOCK 1 ;NUMBER OF GOOD BLOCKS IN PREVIOUS PARTS OF XFER
; USED IF ECC APPLIED IN MIDDLE OF XFER
UNIDVL:!BLOCK 1 ;SAVED COPY OF DEVICE LIST ENTRY WHEN SET UP
UNIDVP:!BLOCK 1 ;POINTER TO DEVICE LIST ENTRY FOR THIS UNIT
UNIPCP:!BLOCK 1 ;PHYSICAL ADDRESS OF CHANNEL PROGRAM
UNISDA:!BLOCK 1 ;PHYSICAL ADDRESS OF SEARCH-ID DATA BUFFER
;THE NEXT 5 WORDS ARE USED DURING ATTACH/KONCPY CALL
UNICCF:!BLOCK 1 ;"ComCon Flag" NONZERO IF ATTACH CMD IN PROGRESS
UNICAD:!BLOCK 1 ;"Continue ADdress" where to go at next DSXINT time
UNIACP:!BLOCK 1 ;"Attach Channel Program" pointer to chan program
UNIPRU:!BLOCK 1 ;COPY OF BLKPRU DATA FOR THIS DRIVE
UNITYP:!BLOCK 1 ;FLAGS,,UNIT TYPE FOR ATTACH
DSXULN:!
.ORG
;PROTOTYPE UDB
DSXUDB: UDBBEG (UNI,DSXULN)
SETWRD (UNIRCL,<F.XEC!F.CC!F.NMT!<O.RCAL>B15!<000>B23>) ;*
SETWRD (UNISEK,<F.XEC!F.CC!F.BYTE!<O.SEEK>B15!<000>B23>) ;*
SETWRD (UNISEK+1,<BYTE (1)1(DCSSIZ)-6(DCSADR)UNISCY>) ;&
SETWRD (UNINOP,<F.XEC!F.CC!F.NMT!<O.NOP>B15>) ;*
SETWRD (UNISET,<F.XEC!F.CC!F.BYTE!F.OFP!<O.SSEC>B15!<000>B23>) ;*
SETWRD (UNISET+1,<BYTE (1)1(DCSSIZ)-1(DCSADR)UNISEC>) ;&
SETWRD (UNISIE,<F.XEC!F.CC!F.BYTE!F.OFP!<O.SIE>B15!<000>B23>) ;*
SETWRD (UNISID,<BYTE (1)1(DCSSIZ)-5(DCSADR)UNISCY>) ;&
SETWRD (UNISID+1,<TIC UNISIE>) ;&
SETWRD (UNIIOT,<TIC 0>)
SETWRD (UNISNP,<F.XEC!F.CC!F.BYTE!<O.SNS>B15!<000>B23>) ;*
SETWRD (UNISNP+1,<BYTE (1)1(DCSSIZ)-^D24(DCSADR)UNISND>) ;&
SETWRD (UNISNP+2,<BMXEND>)
SETWRD (UNIRWC,<F.XEC!F.CC!F.SLI!<O.MTRD>B15!<000>B23>) ;*
UDBEND
;ENTRIES TAGGED BY "*" HAVE THE DEVICE ADDRESS INSERTED BY DSXUNI (DSXCFG)
;ENTRIES TAGGED BY "&" HAVE THE UDB ADDRESS INSERTED BY DSXUNI (DSXCFG)
SUBTTL DRIVER DISPATCH TABLE
EQUATE (LOCAL,0,<DSXICD,DSXICL,DSXULP,DSXULB>)
EQUATE (LOCAL,CPOPJ##,<DSXINI,DSXRLD,DSXEDL>)
DSXATK==ATTKON## ;ATTACH DISK KONTROLLER
DSXDTK==DETKON## ;DETACH DISK KONTROLLER
DSXCCM==CYLCM##
DSXDSP::DRVDSP (DSX,DSKCHN##,DSKDDB##,DDBLEN##,DSKDIA##)
;DEFAULT MONGEN'ED DEVICE TABLE
DEFMDT: MDKL10 (7,274,0,0,<MD.KON>) ;SA10 DEVICE CODE 274
MDKL10 (7,270,0,0,<MD.KON>) ;SA10 DEVICE CODE 270
MDTERM ;TERMINATE TABLE
DSXCKT: EXP TYPDS, 0 ;COMPATIBLE KONTROLLER TABLE
SAXDSP (DSX)
SUBTTL START DRIVE POSITIONING
;ROUTINE TO CAUSE THE DRIVE TO DO A RECALIBRATE OPERATION.
;CALL:
; J/KDB ADDRESS
; U/UDB ADDRESS
; PUSHJ P,DSXRCL
;RETURN CPOPJ IF ERROR
; CPOPJ1 WITH RECAL STARTED
DSXRCL: SETZ T1, ;NO DRB HERE
MOVEI T4,OPCAL ;RE-CAL REQUEST
PJRST DSXGO ;START IT AND RETURN
;ROUTINE TO START A POSITION OPERATION GOING.
;CALL WITH UNIBLK(U) CONTAINING THE DESIRED BLOCK NUMBER.
;CALL:
; J/KDB ADDRESS
; U/UDB ADDRESS
; PUSHJ P,DSXPOS
;RETURN CPOPJ IF ERRORS
; CPOPJ1 WITH POSITION STARTED
DSXPOS: SETZ T1, ;NO DRB
MOVEI T4,OPPOS ;POSITION REQUEST
JRST DSXGO ;FINISH REQUEST
;ROUTINE TO CHECK FOR AND DO ECC CORRECTION
;CALLED FROM FILIO WITH:
; J/KDB ADDRESS
; U/UDB ADDRESS
; PUSHJ P,DSXECC
;RETURN CPOPJ IF ECC WASN'T POSSIBLE (EG: ECC BAD BITS NOT IN DATA FIELD)
; CPOPJ1 WITH ERROR ALREADY CORRECTED (BUT FILIO DOESN'T KNOW IT)
; AND WITH T1 = -1 SO FILIO THINKS ECC WASN'T REALLY REQUIRED
DSXECC: PUSHJ P,SAVE4## ;SAVE SOME ACS
LDB T1,[POINTR (UNISND+S07WRD(U),D07FMC)] ;GET FORMAT/MESSAGE CODE
CAIE T1,FMCECC ;SKIP IF ECC IS POSSIBLE AND APPLIES TO DATA
JRST DSXEC2 ;TELL FILIO EVERYTHING ISOK
LDB T1,[POINTR (UNISND+S15WRD(U),D15RD1)] ;GET 1ST BYTE OF RESTART
LDB P1,[POINTR (UNISND+S16WRD(U),D16RD2)] ;GET REST OF RESTART DISP
LSH T1,^D16 ;POSITION HIGH BYTE
IOR P1,T1 ;COMBINE TO GET RESTART-DISPLACEMENT IN P1
CAIE P1,BLKBYT ;SKIP IF #BYTES IS EXACTLY THAT FOR 200 WORDS
POPJ P, ;GIVE ERROR RETURN IF BLOCK SIZE ISN'T NORMAL
LDB P2,[POINTR (UNISND+S16WRD(U),D16ERD)] ;P2=ERROR DISPLACEMENT
CAILE P2,BLKBYT+3 ;SKIP IF ERROR BYTES ARE WITHIN DATA BYTES
JRST DSXEC2 ;BRANCH (WE WIN!) IF NO BAD DATA
LSH P1,1 ;P1=RESTART NIBBLES
LSH P2,1 ;P2=ERROR NIBBLES
SUB P1,P2 ;NOW P1=FORWARD NIBBLES
MOVEI P3,6 ;6 NIBBLES = 3 BYTES = #BYTES IN ERROR PATTERN
CAIGE P2,6 ;SKIP IF ALL PATTERN NIBBLES ARE SIGNIFICANT
MOVE P3,P2 ;...ELSE REDUCE # OF PATTERN NIBBLES TO USE
MOVE P4,[POINT 4,UNISND+S20WRD(U)] ;POINT AT PATTERN NIBBLES
DSXEC1: ILDB P2,P4 ;GET A CORRECTION NIBBLE
SKIPE P2 ;SKIP IF NO CHANGE REQUIRED
PUSHJ P,FIXNIB ;GO AND FIX A NIBBLE
SOJG P3,DSXEC1 ;LOOP FOR ALL NIBBLES NEEDING FIXING
DSXEC2: MOVEI T1,BLKSIZ##+1 ;MAKE FILIO BELIEVE ERROR IS OUTSIDE DATA
JRST CPOPJ1## ;THEN GIVE IT GOOD RETURN
;ROUTINE APPLY ECC ERROR CORRECTION TO A SINGLE NIBBLE
; P1/ NIBBLE NUMBER NEEDING NEXT CORRECTION
; P2/ CORRECTION NIBBLE
; P3/ NUMBER OF REMAINING NIBBLES NEEDING CORRECTION
; P4/ BYTE POINTER TO PATTERN NIBBLES
FIXNIB: PUSHJ P,NIBSET ;SETUP T3=PHYSICAL ADDRESS, T4=NIBBLE INDEX
POPJ P, ;...RETURN IF NIBBLE # NOT IN IOWD LIST (?)
PMOVE T1,T3 ;GET WHOLE WORD
ROT P2,@NIBTAB(T4) ;POSITION THE CORRECTION DATA
XOR T1,P2 ;CORRECT THE BROKEN NIBBLE
PMOVEM T1,T3 ;RESTORE THE CORRECTED WORD
POPJ P, ;RETURN
NIBTAB: EXP ^D32,^D28,^D24,^D20,^D16,^D12,^D8,^D4,^D0
;ROUTINE TO CALCULATE PHYSICAL ADDRESS OF A NIBBLE GIVEN:
;
; P1/ NIBBLE NUMBER NEEDING CORRECTION
; UNILPC(U) ;POINTER TO CMD,IOWD LIST IN 4 1/2 PACKED MODE
NIBSET: PUSHJ P,SAVE2## ;SAVE P1, P2
IDIVI P1,^D9 ;COMPUTE P1=WORD#, P2=NIBBLE INDEX
SETZ T1, ;T1=# WORDS SO FAR
MOVE T2,UNILPC(U) ;T2=POINTER TO CMD
ADDI T2,1 ;NOW T2=POINTER TO IOWD LIST
NIBSE1: PMOVE T3,T2 ;GET AN IOWD
MOVE T4,T3 ;SAVE A COPY
TLO T3,(1B0) ;MAKE SURE IT APPEARS -VE
ASH T3,-^D24 ;NOW T3=-VE WORDS IN THIS IOWD
MOVNS T3 ;NOW T3=+VE WORDS IN THIS IOWD
SUB P1,T3 ;COMPUTE P1=# WORDS REMAINING TO BE SKIPPED
JUMPL P1,NIBSE2 ;BRANCH IF WE FINALLY FOUND RELAVENT IOWD
JUMPG T4,[AOJA T2,NIBSE1] ;LOOP FOR NEXT IOWD, IF THERE IS ONE
POPJ P, ;GIVE ERROR RETURN IF NOT THERE
;HERE WHEN WE FIND THE RELAVENT IOWD
NIBSE2: ADD P1,T3 ;NOW P1=# WORDS INTO THIS IOWD
LDB T3,[POINT 22,T4,35] ;LOAD T3=BASE ADDRESS OF THIS IOWD
ADD T3,P1 ;COMPUTE AFFLICTED ADDRESS
MOVE T4,P2 ;LOAD UP NIBBLE NUMBER
JRST CPOPJ1## ;GIVE GOOD RETURN IF WE FIND IOWD
SUBTTL START DATA TRANSFERS
;ROUTINES TO START A DATA TRANSFER GOING ON A DRIVE. ENTRY POINTS
;ARE:
; DSXRED - READ DATA, DON'T STOP ON ERROR
; DSXRDS - READ DATA, STOP ON ERROR
; DSXRDF - READ FORMAT
; DSXWRT - WRITE DATA, DON'T STOP ON ERROR
; DSXWTS - WRITE DATA, STOP ON ERROR
; DSXWTF - WRITE FORMAT
;CALL:
; J/KDB ADDRESS
; U/UDB ADDRESS
; T1/ DRB ADDRESS
; P1/CHANNEL DATA BLOCK ADDRESS
; PUSHJ P,ROUTINE
;RETURN CPOPJ IF ERRORS WITH:
; T1/ERROR BITS
; CPOPJ1 IF TRANSFER STARTED SUCCESSFULLY
;HERE TO START TRANSFER TO READ/WRITE FORMATS.
DSXRDF:
DSXWTF: SETZ T1, ;CAN'T DO FORMATTING YET
POPJ P, ;BAD UNIT RETURN
;HERE TO START TRANSFER TO READ/WRITE DATA, NOT STOPPING ON ERRORS.
DSXRED: SKIPA T4,[OPRED] ;GET FILSER READ FUNCTION
DSXWRT: MOVEI T4,OPWRT ;GET FILSER WRITE FUNCTION
JRST DSXGO ;START THE I/O
;HERE TO START TRANSFER TO READ/WRITE DATA, STOPPING ON ERRORS.
DSXRDS: SKIPA T4,[OPRED] ;GET FILSER READ FUNCTION
DSXWTS: MOVEI T4,OPWRT ;GET FILSER WRITE FUNCTION
JRST DSXGO ;START THE I/O
;HERE TO START ALL OPERATIONS GOING
DSXGO: PUSH P,M ;SAVE UUO
PUSHJ P,SETCHP ;SET UP CHANNEL PROGRAM
POP P,M ;RESTORE UUO
DSXGO1: MOVEI T2,SO.GO ;GO FLAG
PUSHJ P,CNOSET ;SET FLAG AND DO THE CONO
MOVE T1,UNIDRB(U) ;RESTORE DRB, IF ANY
PJRST CPOPJ1## ;GIVE OK (SKIP) RETURN
CNOSET: TRO T2,SO.SET ;SET BIT TO SET THE DESIRED FLAG
CNOCLR: HLRZ T1,DSXSCH(J) ;GET SUBCHANNEL NUMBER IN CONO POSITION
IORI T2,DSKCHN##(T1) ;INCLUDE PI CHANNEL AND SUBCHANNEL NUMBER
XCT DSXCO2(J) ;DO THE CONO
POPJ P, ;RETURN
SUBTTL STOP TRANSFER FOR HUNG RECOVERY
;ROUTINE TO STOP THE CURRENT TRANSFER WHEN THE HUNG TIMER TIMES
;OUT.
;CALL:
; J/KDB ADDRESS
; PUSHJ P,DSXSTP
;RETURN CPOPJ IF COULDN'T GET BUSY TO CLEAR
; CPOPJ1 IF SUCCESSFUL
;SUBROUTINE TO STOP DEVICE FOR ERROR RECOVERY
DSXSTP: MOVSI T1,UNPHNS ;SEE IF ALREADY TRIED SETTING GO FLAG AGAIN
TDNE T1,UNIFNC(U) ;SKIP IF NO
JRST DSXST1 ;YES, DO THE RECOVERY THING
IORB T1,UNIFNC(U) ;NO, REMEMBER THAT WE HAVE
PUSHJ P,CUERS2 ;SET TO RESTART CHANNEL PROG
AOS (P) ;GIVE SKIP RETURN
PJRST DSXST4 ;SET GO FLAG, RETURN PROPER AC'S
;HERE WHEN SET GO FLAG AND TIMED OUT AGAIN IN HUNG RECOVERY
DSXST1: PMOVE T1,UNIDVP(U) ;GET DEVICE LIST ENTRY
PUSH P,T1 ;SAVE CURRENT DEVICE LIST ENTRY
MOVEI T2,BMXWRD ;GET ADDR OF NULL CHANNEL PROGRAM
PUSHJ P,SETDVL ;SET UP FOR THAT
MOVE T3,UNIFNC(U) ;RETURN UNIFNC AS DATAI WORD
POP P,T2 ;RESTORE PREVIOUS DEVICE LIST ENTRY
PMOVE T1,UNIDVP(U) ;GET CURRENT DEVICE LIST ENTRY
CAME T1,T2 ;SKIP IF DIDN'T CHANGE SINCE LAST TRY
JRST DSXST4 ;OK
;$$ HERE WHEN SA10 IS SO "HUNG" IT WON'T EVEN START ANY CHANNEL PROGRAM
;$$ COME HERE TO PICK UP SOME USEFULL INFO, TAKE STOPCODE DUMP,
;$$ AND THEN RESET THE AFFLICTED CHANNEL.
;$$ ITEMS WITH "**" ARE SAVED IN THE ACS IN THE DUMP.
;$$ (MIGHT BE WIPED OUT ON RESET OR DURING I/O TO SA10 DISK)
PUSHJ P,SAVE1## ;SAVE P1
;$$ THIS CODE HERE IS INTENDED TO LOAD P1 WITH DEVL ENTRY
;$$ FOR WHATEVER UNIT LAST TALKED TO THE SA10.
;$$ TO DO THIS RIGHT, WE MUST FIND BEGINNING OF DEVL LIST FOR THE
;$$ APPROPRIATE SUBCHANNEL AND SCAN THE CU ADDRESS FIELD BY HAND FOR A
;$$ MATCH (AND REMEMBER THAT THERE MIGHT NOT BE A MATCH)
;$$ MOVE T1,@DSXCSW(J) ;GET CHANNEL STATUS WORD
;$$ LDB T1,[POINT CSSUNI,T1,CSNUNI] ;GET UNIT NUMBER
;$$ MOVE P1,@DSXCHP(J) ;** P1=DEVICE LIST ENTRY FOR UNIT OF LAST INT
DSXST2: TRO T2,SO.CLK+SO.SDR+SO.DT0+DSKCHN## ;SA10 CONO TO STOP CLOCK
; AND SET TO READ MICRO-PC
XCT DSXCO2(J) ;DO THE CONO
XCT DSXDTI(J) ;** T1=DATAI=SA10 MICRO-PC
HLRZ T2,T1 ;T2=SUBCHANNEL NUMBER FROM DATAI
HRRZ T3,DSXSCH(J) ;T3=SUBCHANNEL WE WANT
CAME T2,T3 ;SKIP IF OUR SUBCHANNEL
JRST DSXST2 ;STEP CLOCK TILL GET TO OUR SUBCHANNEL
XCT DSXCI2(J) ;DO CONI INTO T2
MOVE T4,T2 ;** T4=SA10 CONI
TRO T2,SO.CLK+SO.SET+DSKCHN## ;CONO TO START CLOCK AGAIN
XCT DSXCO2(J) ;START SA10 CLOCK AGAIN
MOVEI T2,@DSXCSW(J) ;T2=ADDR OF CHANNEL STATUS WORD
MOVE T3,1(T2) ;** T3=TERMINATING COUNT,ADDR WORD
MOVE T2,(T2) ;** T2=CHANNEL STATUS WORD
STOPCD .+1,DEBUG,SAH, ;++ SA10 HUNG
MOVEI T2,SO.RCH ;FUNCTION TO RESET SUBCHANNEL
PUSHJ P,CNOCLR ;DO IT - SHOULD GET SA10 STARTED AGAIN
MOVE T2,DSXGSN(J) ;GET GLOBAL SA10 SUBCHANNEL
MOVE T2,SAXDVP##(T2) ;GET START OF DEVICE LIST FOR SUBCHANNEL
MOVEI T3,DL.TRM ;MARK EVERYTHING TERMINATED SO WONT RESET AGAIN RIGHT AWAY
DSXST3: PMOVE T1,T2 ;GET ANOTHER DEVICE LIST ENTRY
JUMPE T1,DSXST4 ;BRANCH IF OUT OF DEVICE LIST ENTRIES
DPB T3,DSYDLC ;STORE TERMINATED CODE
CAME T2,DSXDVP(U) ;SKIP IF THIS IS THE AFFLICTED UNIT
PMOVEM T1,T2 ;STORE CHANGED CODE BACK INTO DEVICE LIST
AOJA T2,DSXST3 ;LOOP FOR DEVICE LIST FOR THIS SUBCHANNEL
DSXST4: PUSHJ P,DSXGO1 ;SET GO FLAG - WILL GET DISK INTERRUPT
JFCL ;IGNORE SKIP RETURN
MOVE T2,UNISND(U) ;T2="CONI"=FIRST SENSE BYTES
MOVE T3,@DSXCSW(J) ;T3="DATAI"=CHANNEL STATUS WORD
POPJ P, ;GIVE NOT-RECOVERED RETURN
SUBTTL INTERRUPT HANDLER
;ROUTINE TO PROCESS SA10 INTERRUPTS.
;CALL:
; T3/ CONI STATUS BITS
; W/ KDB ADDRESS
; PUSHJ P,DSXINT
;EXITS CPOPJ ALWAYS THROUGH FILINT WITH:
; T1/ COMMUNICATIONS WORD (ATN BITS+DRIVE,,ERROR+FUNCTION)
; T2/ CONI
; T3/ ENDING STATUS,,ERROR REGISTER
;CALLED FROM SA10 INTERRUPT HANDLER WHEN AN INTERRUPT HAS
;OCCURRED FOR THE SUBCHANNEL TO WHICH THIS KDB IS CONNECTED.
DSXINT: SETZB S,F ;CLEAR ERROR FLAGS (S), ALSO "CONI" FLAGS (F)
MOVE J,W ;COPY KDB ADDRESS TO FILSER AC
TRNE T3,SI.PAR!SI.NXM ;SKIP UNLESS MEMORY ERRORS
JRST MEMERR ;HANDLE MEMORY ERRORS
MOVE T1,@DSXCSW(J) ;GET CHANNEL STATUS WORD
LDB T3,[POINT CSSUNI,T1,CSNUNI] ;GET UNIT NUMBER
MOVE U,@DSXPTR(J) ;GET ADDR OF UNIT IF EXISTS
JUMPE U,DSXIIN ;JUMP IF NO SUCH UNIT, IGNORE INTERRUPT
MOVE T2,UNIFNC(U) ;GET CURRENT FUNCTION BITS
TLNN T2,UNPONP ;SKIP IF POSITION FOR ON-LINE INTERRUPT
TLNE T2,UNPCPY ;OR SEE IF CALLING CPY ROUTINE
JRST DSXDCH ;DISPATCH TO CONTINUING HANDLER
TLNE T1,(S.SE) ;SKIP UNLESS SELECT ERROR
JRST DEVERR ;CONSIDER THAT A DEVICE ERROR
TLNE T1,(S.CUE) ;SKIP UNLESS CONTROL-UNIT-END
JRST HCUE ;GO HANDLE THAT
TLNE T1,(S.BUSY) ;SKIP UNLESS BUSY
JRST HBUSY ;GO HANDLE BUSY
TLNE T1,(S.UC) ;SKIP UNLESS UNIT CHECK
JRST HUC ;GO HANDLE THAT
TLNE T1,(S.CTLE) ;SKIP UNLESS CONTROL ERROR
JRST HCTLE ;GO HANDLE CONTROL ERROR
TLNN T2,UNPHNS ;SET AN ERROR IF HUNG RECOVERY
JRST DSXIN2 ;NO, OK
TRO S,IODERR ;HUNG RECOVERY
TRO F,SN.HNR ;NOTE HUNG RECOVERY
DSXIN2: TLNN T1,(S.BIPE+S.LE+S.PCI+S.ATN+S.UE) ;SKIP IF SA10 REPORTS ERRORS
JRST DSXRET ;NO, OK
CHNERR:
DEVERR: TRO S,IODERR ;SOME ERROR DECTECTED
TRO F,SN.CDE ;CHANNEL DETECTED ERROR
;FALL INTO DSXRET
DSXRET: MOVSI T1,UNPCUE ;GET CONTROL-UNIT-END BIT
TDNN T1,UNIFNC(U) ;SKIP IF CONTROL-UNIT-END AFTER BUSY
JRST NOTCUE ;NO, NORMAL CASE
ANDCAM T1,UNIFNC(U) ;CLEAR IT NOW THAT IT'S PROCESSED
PUSHJ P,CUECHK ;SET UP UNITS WAITING BECAUSE BUSY
JUMPE T1,NOTCUE ;JUMP IF NO SUCH UNITS
PUSHJ P,DSXGO1 ;RESTART THOSE UNITS
JFCL ;
NOTCUE: MOVE T1,UNIFNC(U) ;GET CURRENT FUNCTION
TLNE T1,UNPSNS ;SKIP IF NOT SENSE AFTER UNIT CHECK
JRST DSXSNS ;IT WAS
MOVE T2,@DSXCSW(J) ;GET CHANNEL STATUS WORD
MOVEM T2,UNICSW(U) ;SAVE FOR DEBUGGING
TLNE T2,(S.DE) ;SKIP UNLESS DEVICE END ON
TLNE T2,(S.CE) ;SKIP IF DEVICE END, NO CHANNEL END
JRST NOTCU1 ;OK, NO DEVICE END, OR DEV END AND CHN END
SKIPN UNISTS(U) ;SKIP UNLESS UNIT IDLE (PROBABLY COMING ON-LINE)
JRST NOTCU1 ;WAS IDLE, PROBABLY COMING ON-LINE
PUSHJ P,CUERES ;DEVICE END ALONE MAY BE AFTER UNIT BUSY
JRST HCUE1 ;UNIT WAS BUSY, RETRY
TRO S,IODERR ;FORCE RETRY
TRO F,SN.RTR ;RETRY REQUESTED BY CONTROLLER
NOTCU1: MOVEI T2,@DSXCSW(J) ;GET ADDR OF CHANNEL STATUS WORD
MOVE T2,1(T2) ;GET TERMINAL COUNT AND COMMAND ADDR
MOVEM T2,UNITCA(U) ;SAVE FOR LATER IN CASE ANOTHER UNIT FINISHES
PMOVE T1,UNIDVP(U) ;GET DEVICE LIST ENTRY INTO T1
LDB T4,DSYDLC ;GET TERMINATING ADDRESS FROM DEVICE LIST
CAME T4,T2 ;COMPARE WITH STATUS TERMINATING ADDR
JRST NOTCU2 ;SHOULD BE THE SAME
LDB T4,DSYDLO ;GET SA10 STATUS FROM DEVICE LIST
CAIE T4,DL.TRM ;SKIP IF MARKED TERMINATED
NOTCU2: AOS DSXFST ;COUNT FUNNY STATUS CONDITIONS
MOVE T2,@DSXICW(J) ;GET INITIAL COMMAND WORD
;*** WRONG?
;*** CAME T2,DSXSTA(J) ;SHOULDN'T HAVE CHANGED
;*** AOS DSXFST ;FUNNY STATUS
MOVE T1,UNIFNC(U) ;RESTORE T1 AGAIN
MOVE T2,UNIDES(U) ;GET UNIT DESCRIPTION
TLNE T2,UNPOFL ;SKIP UNLESS UNIT WAS OFF-LINE
JRST DSXRT4 ;MUST NOW BE ON-LINE
MOVE T2,UNISTS(U) ;GET UNIT STATUS
CAIL T2,OWCOD ;SKIP IF NOT OPERATOR WAIT
JRST DSXRT3 ;OPERATOR WAIT
JRST DSXRT2 ;SKIP THIS
DSXDCH: MOVEI T2,@UNICAD(U) ;ADDRESS TO CONTINUE
CAIL T2,DSXKON ;MUST BE IN DSXKON
CAILE T2,DSXEND ;SKIP IF VALID
STOPCD CPOPJ##,DEBUG,DND, ;++DISPATCH NOT IN DSXKON
JRST @T2 ;DISPATCH OK, DO IT
DSXRT4: MOVSI T1,UNPONP ;BIT TO MARK POSITION FOR ON-LINE INTERRUPT
MOVEM T1,UNIFNC(U) ;SET UNIFNC TO HANDLE NEXT INTERRUPT
MOVEI T1,^D411 ;GET A LARGE CYLINDER NUMBER
LSH T1,SCYLSH ;SHIFT INTO POSITION FOR SEEK ARGS
MOVEM T1,UNISCY(U) ;STORE FIRST WORD OF SEEK ARG
SETZM UNISCY+1(U) ;ZERO SECOND WORD OF SEEK ARG
MOVEI T1,UNISND-1(U) ;ADDR-1 OF PLACE TO PUT SEEK COMMAND
PUSH T1,UNISEK(U) ;PUT IN SEEK COMMAND
PUSH T1,UNISEK+1(U) ;AND DCW
PUSH T1,BMXWRD ;END OF CHAN PROG
MOVEI T2,UNISND(U) ;ADDR OF CHAN PROG
PUSHJ P,CPYWAT ;SET UP, START CHAN PROG, RETURN AFTER INT
;HERE AFTER SEEK
TLNN T1,(S.UC) ;SKIP IF UNIT CHECK CAME UP
JRST DSXR4L ;NO, MUST BE 3331 - GOOD THING WE CHECKED
MOVEI T2,UNISNP(U) ;ADDR OF SENSE CHAN PROG
PUSHJ P,CPYWAT ;SET UP, START CHAN PROG, RETURN AFTER INT
;HERE AFTER SENSE AFTER SEEK
MOVE T1,UNISND(U) ;GET SENSE DATA
TLNN T1,(S00REJ+S00IRQ) ;SKIP IF ILLEGAL SEEK
JRST DSXR4L ;MUST HAVE FAILED FOR SOME OTHER REASON
;HERE IF UNIT IS 3330
MOVEI T2,.UT330 ;UNIT TYPE FOR 3330
JRST DSXR4A ;SET IT UP
;HERE IF UNIT IS 3331
DSXR4L: MOVEI T2,.UT331 ;UNIT TYPE FOR 3331
DSXR4A: MOVE T1,BLKPRU(T2) ;GET BLOCKS/UNIT BASED ON UNIT TYPE
MOVEM T1,UNIBPU(U) ;STORE BLOCKS PER UNIT
MOVEM T1,UNIBPM(U) ;AND INCLUDING MAINTENANCE CYLINDERS
DPB T2,UNYUTP## ;STORE NEW UNIT TYPE
SETZM UNIFNC(U) ;MAKE SURE NEW INTS DONT DISPATCH
PUSHJ P,SNSCLR ;CLEAR OUT SENSE DATA TO PREVENT CONFUSION
DSXRT3: MOVEI T1,OPPOS ;MAKE LOOK LIKE FREE INTERUPT SINCE NOW ON-LINE
MOVEI T2,400000 ;GET SIGN BIT
MOVN T4,T3 ;MINUS UNIT NUMBER
LSH T2,(T4) ;POSITION AN ATTENTION FLAG
TRO T3,(T2) ;SO LOOKS LIKE RP10 FREE INTERRUPT
DSXRT2: MOVE T2,F ;NO SENSE DATA, USE INTERNAL FLAGS FOR "CONI"
JRST DSXRT1
$LOW
DSXFST: 0 ;COUNT OF TIMES FUNNY STATUS CAME UP
;EITHER DEVICE NOT MARKED TERMINATED, OR
;TERMINATING ADDR IN DEVICE LIST NOT SAME AS STATUS
;ALSO IF INITIAL COMMAND WORD CHANGES
LOWZRO: 0 ;A WORD CONTAINING ZERO
$HIGH
; HERE WHEN SENSE COMMAND DONE
DSXSNS: MOVSI T2,UNPSNS ;BIT MARKING SENSE COMMAND
ANDCAM T2,UNIFNC(U) ;CLEAR THE BIT SINCE THE SENSE IS DONE
MOVE T2,UNISND+S02WRD(U) ;GET WORD WITH CORRECTION BIT
TLNE T2,(D02COR) ;SKIP IF NOT A KNOWN CORRECTABLE ERROR
TRO S,IOECCX ;LET FILIO KNOW ECC CORRECTION WOULD WORK
MOVE T2,UNISND(U) ;GET SENSE DATA FOR "CONI"
TLNE T2,(S00DCK) ;SKIP IF NOT DATA CHECK
TROA S,IODTER ;NOTE DATA ERROR
TRO S,IODERR ;NOTE AN EQUIPMENT ERROR
DSXRT1: TLZ T1,-1 ;CLEAR LH JUNK
CAIE T1,OPRED ;READ OR
CAIN T1,OPWRT ; WRITE OPERATION?
PUSHJ P,FIXCWA ;YES, FIXUP DF10'S ICWA+1 WORD
HRL T1,T3 ;UNIT NUMBER TO LH T1
MOVE T3,@DSXCSW(J) ;T3=CHANNEL STATUS WORD FOR "DATAI"
;NOTE AFTER UNIT CHECK THIS WILL BE FROM AFTER THE SENSE COMMAND
IOR T1,S ;INCLUDE ERROR BITS IN T1 FOR FILSER
;*** SHOULDN'T DRREST DO THIS? DOES ANYONE CARE?
HRRM U,KONCUA(J) ;MUST TRUST HARDWARE SINCE ALL DRIVES MAY BE GOING
PUSH P,T1 ;SAVE T1
PUSH P,T2 ;SAVE CONI
PUSHJ P,STSCLR ;CLEAR STATUS FLAG
POP P,T2 ;RESTORE CONI
POP P,T1 ; AND INTERRUPTING UNIT,,FUNCTION
HLRZ T4,T1 ;GET UNIT WHICH INTERRUPTED
TRNE T1,OPPOS ;POSITIONING INTERRUPT?
SKIPA T4,BITTBL##(T4) ;YES, GET BIT FOR THAT (SINGLE) UNIT
SETZ T4, ;NO, NO UNITS HAVE POSITIONED
SKIPN UNIDRB(U) ;DRB PRESENT?
PJRST FLHTID## ;NO, KINDA EASY TO CALL FILINT
EXCH T3,UNIDRB(U) ;GET DRB ADDRESS, SAVE "DATAI" BITS
MOVEM T2,DRBCNI##(T3) ;SAVE "CONI"
MOVE T2,UNIDRB(U) ;GET "DATAI" BITS
MOVEM T2,DRBDTI##(T3) ;SAVE "DATAI"
SETZM UNIDRB(U) ;CLEAR MEMORY OF DRB
PJRST FLHTID## ;CALL FILINT
;HERE TO HANDLE UNIT CHECK - DO A SENSE I/O COMMAND
HUC: MOVSI T1,UNPSNS ;FLAG TO REMEMBER DOING A SENSE
IORM T1,UNIFNC(U) ;STORE IT
MOVEI T1,@DSXCSW(J) ;ADDR OF CHANNEL STATUS WORD
MOVE T1,1(T1) ;GET TERMINAL COUNT, ADDRESS WORD
MOVEM T1,UNITCA(U) ;SAVE FOR LATER SENSE PROCESSING
;SINCE SENSE COMMAND WILL DESTROY
MOVEI T2,UNISNP(U) ;ADDR OF SENSE CHANNEL PROGRAM
PUSHJ P,SETDVL ;SET UP DEVICE LIST
MOVEI T2,SO.GO ;SET GO FLAG
PUSHJ P,CNOSET ;SET IT UP AND DO THE CONO
STSCLR: MOVEI T2,SO.STS ;STATUS FLAG
PJRST CNOCLR ;CLEAR STATUS FLAG
;HERE TO HANDLY BUSY - SET A FLAG TO RETRY LATER
HBUSY: AOS CNTBSY ;COUNT NUMBER OF TIMES GOT BUSY
MOVSI T1,UNPBSY ;SET FLAG TO REMEMBER BUSY OCCURED
IORM T1,UNIFNC(U) ;STORE IT
PJRST STSCLR ;CLEAR STATUS FLAG AND DISMISS
$LOW
CNTBSY: 0
$HIGH
;HERE TO HANDLE CONTROL UNIT END - SET UP TO RETRY UNITS THAT GOT A BUSY
HCUE: AOS CNTCUE ;COUNT NUMBER OF TIMES GO CUE
MOVE T2,U ;SAVE ORIGINAL UNIT
TLNE T1,(S.UC) ;UNIT-CHECK ALSO?
JRST HUC ;CU END + UNIT CHECK MEANS ERROR AFTER CHAN END
TLNN T1,(S.BUSY) ;BUSY ALSO?
JRST HCUE5 ;NO, HANDLE CU END
MOVSI T1,UNPBSY ;YES, CU END + BUSY MEANS TEMPORARILY BUSY
IORM T1,UNIFNC(U) ;PRETEND NOT BUSY ANYMORE
HCUE5: LDB T1,UNYUST## ;GET STATE OF UNIT
CAIE T1,UNVDWN ;SKIP IF UNIT IS DOWN
JRST HCUE6 ;OK AS IS
MOVE U,UNIKON(U) ;DOWN UNITS NOT IN KONTROLLER RING
CAIE U,(T2) ;SKIP IF BACK TO ORIGINAL SOME HOW
JRST HCUE5 ;TRY TO FIND A UNIT IN THE RING
JRST HCUE7 ;OH WELL
HCUE6: PUSHJ P,UCCHK ;CHECK IF ANY UNIT WAITING FOR SENSE
JRST HCUE2 ;YES, START IT FIRST
MOVSI T1,UNPCUE ;BIT SET IF ALREADY GOT C-U-E
TDNN T1,UNIFNC(U) ;SKIP IF SECOND TIME AROUND
JRST HCUE3 ;NO, DO THE NORMAL THING
PUSHJ P,CUEONE ;TRY ONE OTHER UNIT IF ANY WAITING
JRST HCUE2 ;ONE UNIT SET UP
HCUE3: PUSHJ P,CUERES ;SET UP CHANNEL PROG FOR RESTART IF HAD BUSY
JRST HCUE1 ;YES, ONLY DO THIS UNIT NOW
HCUE4: PUSHJ P,CUECHK ;NO, SET UP ALL OTHERS
JUMPN T1,HCUE2 ;JUMP IF ANY OTHER UNITS HAD BUSY
HCUE7: AOS CNTCUN ;COUNT TIMES CUE FOUND NO UNITS
PJRST STSCLR ;NO, JUST CLEAR STATUS FLAG
$LOW
CNTCUE: 0 ;TIMES GOT CUE
CNTCUN: 0 ;TIMES CUE FOUND NO UNITS
$HIGH
HCUE1: MOVSI T1,UNPCUE ;GET CUE BIT
IORM T1,UNIFNC(U) ;NOTE CONTROL-UNIT-END
HCUE2: PUSHJ P,DSXGO1 ;START OPERATION AGAIN
JFCL ;FORGET PROBLEMS FOR NOW
PJRST STSCLR ;CLEAR STATUS FLAG AND DISMISS
;SUBROUTINE TO CHECK IF ANY UNIT WAITING FOR SENSE COMMAND
UCCHK: PUSH P,U ;SAVE FIRST UNIT
UCCHK1: MOVSI T1,UNPSNS ;GET BIT INDICATING WAITING FOR SENSE
PUSHJ P,CUERS1 ;SEE IF THIS UNIT WAITING FOR SENSE
JRST CUEON2 ;YES, NOTE OTHER UNITS MAY BE WAITING FOR CUE
MOVE U,UNIKON(U) ;STEP TO NEXT UNIT IN RING
CAME U,(P) ;SKIP IF BACK TO ORIGINAL UNIT
JRST UCCHK1 ;NO
PJRST UPOPJ1## ;YES, NO UNITS WAITING FOR SENSE
;SUBROUTINE TO SET UP ONE UNIT OTHER THAN THE ONE CAUSING THE INTERRUPT
CUEONE: PUSH P,U ;SAVE U
CUEON1: MOVE U,UNIKON(U) ;MOVE TO NEXT UNIT
CAMN U,(P) ;SKIP IF NOT BACK TO ORIGINAL UNIT
PJRST UPOPJ1## ;YES, NO OTHER UNITS
PUSHJ P,CUERES ;SEE IF WAITING
SKIPA ;YES
JRST CUEON1 ;NO, LOOP THROUGH UNITS ON CONTROLLER
CUEON2: MOVSI T1,UNPCUE ;GET CUE BIT
ORM T1,UNIFNC(U) ;SET FOR THAT UNIT
JRST UPOPJ## ;RESTORE U AND RETURN
;SUBROUTINE TO CHECK ALL UNITS AND SET UP TO RESTART
;VAL: T1=NUMBER OF UNITS SETUP TO RETRY BECAUSE BUSY
CUECHK: PUSH P,[0] ;PUT ZERO ON STACK
PUSH P,U ;SAVE U FOR END OF LOOP
BSYCHK: PUSHJ P,CUERES ;SKIP IF UNIT NOT WAITING FOR BUSY ELSE SET UP CH PRG
AOS -1(P) ;COUNT UNITS WAITING BECAUSE BUSY
MOVE U,UNIKON(U) ;STEP TO NEXT UNIT
CAME U,(P) ;SKIP IF BACK TO FIRST UNIT
JRST BSYCHK ;NO, CHECK ALL UNITS ON CONTROLLER
POP P,U ;RESTORE U
PJRST TPOPJ## ;GET COUNT AND RETURN
;SUBROUTINE TO CHECK IF UNIT HAD BUSY RESPONSE, AND SET CHAN PROG FOR RESTART
; NON-SKIP IF UNIT HAD BUSY RESPONSE, CHANNEL PROGRAM SET TO RESTART
; SKIP RETURN IF DID NOT HAVE BUSY
CUERES: MOVSI T1,UNPBSY ;BIT SET IN UNIFNC IF UNIT GOT BUSY RESPONSE
CUERS1: TDNN T1,UNIFNC(U) ;SKIP IF SET FOR THIS UNIT
JRST CPOPJ1## ;NO, UNIT NOT WAITING AFTER BUSY
ANDCAB T1,UNIFNC(U) ;CLEAR BIT AND GET THE OTHERS
CUERS2: MOVEI T2,UNICHP(U) ;NORMAL CHANNEL PROGRAM ADDR FOR THIS UNIT
TLNE T1,UNPSNS ;SKIP UNLESS WAS DOING A SENSE COMMAND
MOVEI T2,UNISNP(U) ;IN WHICH CASE CHANNEL PROG IS DIFFERENT
TLNN T1,UNPONP ;SKIP IF POSITION FOR ON-LINE INTERRUPT
TLNE T1,UNPCPY ;SKIP UNLESS WAS IN CPY ROUTINE
MOVE T2,UNIACP(U) ;GET ADDR REMEMBERED
PJRST SETDVL ;SET UP DEVICE LIST AGAIN
;HERE TO HANDLE MEMORY ERRORS
MEMERR: MOVEI T2,SO.CME ;CLEAR MEMORY ERRORS
PUSHJ P,CNOCLR ;DO THE CONO
MOVEI T2,SO.SRS ;SELECTIVE RESET COMMAND
PJRST CNOCLR ;DO SELECTIVE RESET, WILL CAUSE CONTROL ERROR
;NOTE NEXT REAL OP ON THIS UNIT WILL GET UNIT CHECK
;EQUIPMENT CHECK WILL BE UP, HOPEFULLY RETRY WILL WIN
;HERE TO HANDLE CONTROL ERROR
HCTLE: HRRZ T3,DSXGSN(J) ;GET GLOBAL SUBCHANNEL NUMBER
MOVE T2,SAMERR##(T3) ;GET MEMORY ERROR WORD
TRNN T2,SI.NXM!SI.PAR ;SKIP IF THIS IS AFTER MEMORY ERROR
JRST DEVERR ;NO, JUST RETURN ERROR
TRNN T2,SI.NXM ;SKIP IF WAS NXM
TROA S,IOCHMP!IODERR ;NO, MEMORY PARITY ERROR
TRO S,IOCHNX!IODERR ;YES, NXM
SETZM SAMERR##(T3) ;CLEAR FLAGS
JRST CHNERR ;RETURN CHANNEL ERROR
;HERE WHEN INTERRUPT FOR UNKNOWN UNIT - COUNT AND IGNORE
;UNIT NUMBER IN T3
DSXIIN: AOS CNTIIN ;COUNT TIMES GOT INT FOR UNKNOWN UNIT
MOVE T3,BITTBL##(T3) ;GET BIT FOR THE NEW UNIT
IORM T3,DSXNUM(J) ;SET IN BIT MASK
HRROS KDBNUM(J) ;FLAG FOR THE REST OF THE WORLD TO SEE
PJRST STSCLR ;CLEAR STATUS AND RETURN
$LOW
CNTIIN: 0 ;TIMES GOT INT FOR UNKNOWN UNIT
$HIGH
SUBTTL DETERMINE CAPACITY AND STATUS
;ROUTINE TO RETURN CAPACITY AND STATUS OF AN IBM DRIVE TO FILSER.
;CALL: J/KDB ADDRESS
; U/UDB ADDRESS
; PUSHJ P,DSXCPY
;RETURN CPOPJ IF ERROR
; CPOPJ1 IF DRIVE EXISTS AND IS OK TO USE WITH:
; T1/BLOCKS PER UNIT
; T2/BLOCKS PER UNIT INCLUDING MAINTENANCE CYLINDERS
; T3/BLOCKS PER UNIT IN 10/11 COMPATABILITY MODE
; T4/STATUS BITS (KOPUHE,KOPNSU),,UNIT TYPE
; W/BLOCKS PER TRACK,,BLOCKS PER CYLINDER
DSXCPY: MOVSI T1,UNPCPY ;BIT MARKING IN CPY ROUTINE
TDNE T1,UNIFNC(U) ;SKIP IF NOT HERE BEFORE
JRST DSXCPA ;YES, COMMAND TRIES EVERY TICK OR SO
MOVEM T1,UNIFNC(U) ;NOTE WE ARE IN CPY ROUTINE
SETOM UNICCF(U) ;SET COMCON FLAG SO HE KNOWS WE'RE STILL GOING
MOVE T1,UNISNP(U) ;GET SENSE COMMAND
AND T1,[<377>B23] ;ISOLATE DEVICE ADDR
TLO T1,(F.NMT!F.XEC!F.SLI!<O.NOP>B15) ;MAKE NO-OP
MOVEM T1,UNISND(U) ;STORE IN AVAILABLE PLACE FOR THIS UNIT
MOVE T1,BMXWRD ;END OF CHAN PROG
MOVEM T1,UNISND+1(U) ;STORE THAT
MOVEI T2,UNISND(U) ;ADDR OF CHAN PROG
PUSHJ P,CPYWAT ;START NO-OP, RETURN A SKIP TO COMCON
;HERE AFTER NO-OP
DSXCP1: TLNE T1,(S.SE) ;SKIP UNLESS SELECT ERROR
JRST DSXCPD ;STILL DOWN
MOVEI T2,UNISNP(U) ;ADDR OF SENSE CHAN PROG
PUSHJ P,CPYWAT ;SET UP, START CHAN PROG, RETURN AFTER INT
;HERE WHEN SENSE CMD DONE
SETZ T4, ;ZERO T4 IN CASE OFF-LINE
TLNE T1,(S.SE) ;SKIP UNLESS SELECT ERROR
JRST DSXCPD ;STILL DOWN
MOVE T1,UNISND(U) ;GET SENSE INFO
TLNE T1,(S00IRQ) ;SKIP IF UNIT OK
DSXCP2: TLO T4,KOPUHE ;NOTE UNIT OFF-LINE
JUMPN T4,DSXCPS ;ASSUME 3330 IF OFF-LINE
MOVEI T1,^D411 ;GET LARGE CYLINDER NUMBER
LSH T1,SCYLSH ;SHIFT INTO POSITION FOR SEEK CMD
MOVEM T1,UNISCY(U) ;STORE FIRST WORD OF SEEK ARGS
SETZM UNISCY+1(U) ;ZERO SECOND WORD OF SEEK ARGS
MOVEI T1,UNISND-1(U) ;ADDR-1 FOR PLACE TO PUT CHAN PROG
PUSH T1,UNISEK(U) ;STORE SEEK COMMAND
PUSH T1,UNISEK+1(U) ;AND DCW
PUSH T1,BMXWRD ;TERMINATE CHAN PROG
MOVEI T2,UNISND(U) ;ADDR OF CHAN PROG
PUSHJ P,CPYWAT ;SET UP, START CHAN PROG, RETURN AFTER INT
;HERE AFTER SEEK
SETZ T4, ;ZERO T4 SINCE NOT OFF-LINE
TLNN T1,(S.UC) ;SKIP IF UNIT CHECK
JRST DSXCPL ;NO, MUST BE 3331
MOVEI T2,UNISNP(U) ;ADDR OF SENSE CHAN PROG
PUSHJ P,CPYWAT ;SET UP, START CHAN PROG, RETURN AFTER INT
;HERE AFTER SENSE AFTER SEEK
SETZ T4, ;CLEAR T4 FOR ON-LINE UNIT
MOVE T1,UNISND(U) ;GET SENSE INFO
TLNN T1,(S00REJ+S00IRQ) ;SKIP IF ILLEGAL SEEK
JRST DSXCPL ;MUST HAVE FAILED FOR SOME OTHER REASON
;HERE IF 3330 UNIT
DSXCPS: HRRI T4,.UT330 ;UNIT TYPE
JRST DSXCPC ;RETURN VALUES
;HERE IF 3331 UNIT
DSXCPL: HRRI T4,.UT331 ;UNIT TYPE
DSXCPC: MOVE T1,BLKPRU(T4) ;GET BLOCKS/UNIT BASED ON UNIT TYPE
MOVEM T1,UNIPRU(U) ;SAVE VALUES
MOVEM T4,UNITYP(U)
SETZM UNICCF(U) ;CLEAR COMCON FLAG TO NOTE WE'RE FINISHED
PJRST STSCLR ;CLEAR THE STATUS FLAG AND RETURN
DSXCPD: MOVSI T4,KOPNSU ;UNIT IS DOWN
JRST DSXCP2 ;RETURN THAT
;HERE WHEN CALLED AGAIN FROM COMMAND - SEE IF FINISHED
DSXCPA: SKIPE UNICCF(U) ;SKIP IF FINISHED
JRST CPOPJ1## ;NO, STILL WAITING
MOVSI T1,UNPCPD ;FLAG TO NOTE CPY ROUTINE DONE
MOVEM T1,UNIFNC(U) ;SO COMMAND WILL CONTINUE
;ALSO PREVENT INTS FROM DISPATCHING
PUSHJ P,SNSCLR ;CLEAR OUT SENSE BYTES
MOVE T1,UNIPRU(U) ;GET SIZE OF UNIT
MOVE T2,T1 ;BLOCKS INCLUDING MAINT CYLS
SETZ T3, ;NO 10/11 COMPATIBILITY MODE
MOVE T4,UNITYP(U) ;AND UNIT TYPE
MOVE W,[^D18,,^D18*^D19] ;BLKS, PER TRK,,BLKS PER CYL
TLNN T4,-1 ;ANY ERRORS?
AOS (P) ;NO, SET FOR SKIP RETURN
POPJ P, ;GIVE DOWN RETURN
;SUBROUTINE TO SET UP CHAN PROG, SET GO FLAG, AND MARK RETURN AFTER INT
CPYWAT: MOVEM T2,UNIACP(U) ;SAVE ADDR OF CHAN PROG IN CASE BUSY
PUSHJ P,SETDVL ;SET UP DEVICE LIST ENTRY
POP P,UNICAD(U) ;SAVE RETURN ADDR FOR AFTER INT
IFN FTKL10,< ; IF KL10
SKIPN DINITF## ;NO NEED TO FLUSH CACHE IF ONCE ONLY
PUSHJ P,CSDMP## ;FLUSH CACHE
>;END IFN FTKL10
PUSHJ P,DSXGO1 ;SET GO FLAG
JFCL ;DONT CARE ABOUT THIS
PUSHJ P,STSCLR ;CLEAR STATUS FLAG
CONSO PI,PIPROG## ;SKIP IF PIS IN PROGRESS (CALLED AT INT LEVEL)
SKIPN DINITF## ;NOT INTERRUPT LEVEL, DURING ONCE-ONLY?
POPJ P, ;PIS IN PROGRESS OR NOT ONCE-ONLY, DISMISS
; INTERRUPT AND WAIT FOR COMPLETION
PJRST DSXWAT ;ONCE-ONLY, WAIT A WHILE FOR COMMAND TO COMPLETE
SNSCLR: SETZM UNISND(U) ;CLEAR FIRST WORD
MOVEI T2,UNISND+1(U)
HRLI T2,-1(T2) ;MAKE BLT PTR
BLT T2,UNISND+5(U) ;CLEAR SENSE DATA
POPJ P, ;RETURN
$INIT
;SUBROUTINE TO WAIT FOR DSX COMMAND FOR ONCE-ONLY
DSXWAT: MOVSI T1,ONCTIM## ;GET TIME TO WAIT FOR COMPLETION
SKIPE UNICCF(U) ;SEE IF CPY CHECK STILL IN PROGRESS
SOJG T1,.-1 ;KEEP LOOPING
JUMPG T1,DSXCPA ;IF COMPLETED, FETCH DATA FROM UDB AND RETURN
MOVSI T4,KOPNSU!KOPUHE ;GET THE ERROR FLAGS
POPJ P, ;RETURN TO ONCE CALLER
$HIGH
SUBTTL MISCELLANEOUS TO BE CLEANED UP
;*** TEST INTERRUPT ENABLED FLAG FOR SUBCHANNEL?
DSXALV: XCT KDBCNI(J) ;GET CONI
TRNE T1,7 ;ALIVE?
POPJ P, ;YES, JUST RETURN
MOVEI T1,SAXCHN## ;GET THE CHANNEL THE SA10 BELONGS ON
XCT KDBCNO(J) ;INSIST ON A NEW PI CHANNEL
STOPCD .+1,INFORM,DSXPIA, ;++ DSXKON NOTICES SA10 HAS NO PI-ASSIGNMENT
POPJ P, ;RETURN
DSXREG: POPJ P,
SUBTTL CHECK IF CONTROLLER IS UP/CHECK UNIT WRITE LOCK
$INIT
DSXHWP: POPJ P, ;WRITE-ENABLED FOR NOW
REPEAT 0,< ;*** TEMP
PUSHJ P,GTHOM## ;TRY TO READ A HOME BLOCK
POPJ P, ;IF BOTH BAD, DONT RISK WRITING, ASSUME OK
JUMPL T2,.+2 ;JUMP IF FIRST HOME BLOCK BAD, USE SECOND
SKIPA T2,UNIHOM(U) ;FIRST IS OK, REWRITE IT
HLRZ T2,UNIHOM(U) ;SECOND IS OK, REWRITE IT
HRRZS T2 ;JUST BLOCK NUMBER IN RH
PUSHJ P,OMNWRT## ;REWRITE THE GOOD BLOCK
SKIPA T2,UNISND(U) ;ERROR, GET SENSE DATA FOR UNIT
POPJ P, ;OK, MUST NOT BE WRITE-PROTECTED
TLNE T2,(D01WRL) ;SKIP IF WRITE-INHIBIT OFF
AOS (P) ;WRITE INHIBIT - SKIP RETURN
POPJ P, ;RETURN
>; *** TEMP
DSXUPA: PUSHJ P,SAVE1## ;SAVE P1
MOVEI T1,7 ;GET PI ASSIGNMENT
XCT KDBCNO(J) ;TRY TO GIVE IT ONE
XCT KDBCNI(J) ;READ IT BACK
TRNN T1,7 ;DID IT WORK?
POPJ P, ;NO, ASSUME DEAD
PUSHJ P,DSXENB ;ENABLE INTERRUPTS FOR THIS CONTROLLER
HRRZ T1,DSXSCH(J) ;GET SUBCHANNEL
MOVNS T1 ;NEGATIVE FOR RIGHT SHIFT
MOVEI T2,SI.ENB ;BIT FOR SUBCHAN ZERO
LSH T2,(T1) ;GET OUR INT ENABLE BIT
XCT KDBCNI(J) ;GET CONI STATUS
TRNN T1,(T2) ;INTERRUPTS ENABLED?
POPJ P, ;SA10 PROBABLY NOT WORKING
SJSP T1,CPOPJ1## ;FLAG WRITE-HEADER-LOCKOUT OK AND RETURN SUCCESS
$HIGH
DSXERR: MOVEI T1,3 ;GIVE UP
POPJ P, ;RETURN
DSXRDC:
DSXWTC:
DSXUNL: STOPCD .,STOP,DSX3IF, ;++ 3330 ISN'T FANCY
;SUBROUTINE TO CONSTRUCT CHANNEL PROGRAM
;ARGS: T1=ADDRESS OF DRB IF XFER, OR ZERO IF POS/RCL
; T4=FILSER OPCODE
; U=UNIT
; DATA CHAIN LIST ALREADY SET UP
SETCHP: HRRZM T4,UNIFNC(U) ;REMEMBER FILSER FUNCTION
MOVEM T1,UNIDRB(U) ;SAVE DRB ADDRESS (IF ANY)
MOVEI T2,UNICHP(U) ;ADDR OF NORMAL CHANNEL PROGRAM
PJUMPE T1,SETPOS ;SETUP A POSITIONING PROGRAM
PJRST SETXFR ;SETUP AN XFER PROGRAM
; ROUTINE TO SETUP A POSITION PROGRAM
SETPOS: MOVE T1,UNIBLK(U) ;PICK UP THE BLOCK NUMBER
PUSHJ P,SETSIE ;SETUP SEEK DATA
MOVE T1,[BMXEND] ;BMUX END
MOVEM T1,UNISTP(U) ;STOP PROGRAM AFTER SEEK
MOVEI T2,UNICHP(U) ;POINT AT SEEK PROGRAM
CAIN T4,OPCAL ;SKIP IF POSITION
MOVEI T2,UNIRCL(U) ;POINT AT RECAL PROGRAM
PJRST SETDVL ;SETUP TO RUN SEEK PROGRAM
; ROUTINE TO SETUP A DATA XFER PROGRAM
SETXFR:
;*** FROM DRB
MOVE T3,DRBNUM##(T1) ;T3=# OF BLOCKS TO XFER
SKIPN T3 ;SKIP IF WE FOUND SOMETHING TO DO
STOPCD SETDVL,INFORM,SETXF0, ;++ DRBNUM =0 IN DSXKON
PUSHJ P,MAPIO ;CALL LOCAL MAPIO TO CONVERT DF10C TO SA10B
MOVE T1,UNIPCP(U) ;GET ADDRESS OF CHANNEL PROGRAM AREA
TLO T1,(TIC) ;SET UP TRANSFER IN CHANNEL
MOVEM T1,UNIIOT(U) ;MAKE NORMAL CHANNEL PROGRAM BRANCH TO I/O PROG
MAP T1,UNISET(U) ;GET PHYSICAL ADDRESS OF SET-SECTOR CMD
TLZ T1,(MP.NAD) ;TURN OFF MAP ATTRIBUTE BITS
TLO T1,(TIC) ;FINALLY, T1="TIC .+1"
MOVEM T1,UNISTP(U) ;DON'T STOP PROGRAM AFTER SEEK!
MOVEI T2,UNICHP(U) ;RESET T2 TO POINT AT NORMAL CHANNEL PROGRAM
PJRST SETDVL ;SETUP TO RUN XFER PROGRAM
;FALL INTO SETDVL
;SUBROUTINE TO SET UP DEVICE LIST FOR A UNIT
;ARGS: T2=VIRTUAL ADDRESS OF CHANNEL PROGRAM
; STORE ADDRESS, THEN SET "START DEVICE" IN DEVICE LIST
SETDVL: MAP T2,(T2) ;CONVERT VIRTUAL ADDRESS TO PHYSICAL
TLZ T2,(MP.NAD) ;CLEAR NON-ADDRESS BITS
PMOVE T3,UNIDVP(U) ;GET DEVICE LIST ENTRY
AND T3,[776000,,0] ;PRESERVE ONLY DEVICE ADDRESS
TLO T3,(<DL.STA>B<SANDLO>) ;INSERT THE "GO" CODE
TDO T3,T2 ;INSERT THE PROGRAM ADRESS
PMOVEM T3,UNIDVP(U) ;INSERT NEW DEVICE LIST ENTRY IN LIST
MOVEM T3,UNIDVL(U) ;SAVE FOR DEBUGGING
POPJ P, ;RETURN
;SUBROUTINE TO COMPUTE AND STORE SEEK AND SEARCH DATA
;ARGS T1=BLOCK NUMBER
SETSIE: LDB T2,UNYBPY## ;BLOCKS PER CYLINDER
IDIV T1,T2 ;T1=CYLINDER NUMBER, T2=REM
MOVEM T1,UNICYL(U) ;REMEMBER OUR CYLINDER
LSH T1,SCYLSH ;SHIFT FOR CHANNEL PROGRAM DATA
MOVEM T1,UNISCY(U) ;STORE IN CHANNEL PROGRAM
LDB T3,UNYBPT## ;GET BLOCKS PER TRACK
IDIV T2,T3 ;T2=TRACK (HEAD) NUMBER, T3=REC NUMBER
DPB T2,UNYHNM ;STORE HEAD NUMBER IN CHANNEL PROG
AOJG T3,SETSI1 ;RECORD ID (FIRST REC IS REC 1)
STOPCD .+1,DEBUG,IR0, ;++ I/O TO RECORD R0
MOVEI T3,1 ;SET A BETTER RECORD
SETSI1: DPB T3,UNYRNM ;STORE RECORD ID
POPJ P, ;RETURN
;SUBROUTINE TO COMPUTE AND STORE SECTOR NUMBER
;ARGS: T3=RECORD ID
SIZGAP==^D135 ;TOTAL NUMBER OF BYTES IN GAPS FOR A NORMAL RECORD
SIZR0==^D237 ;TOTAL NUMBER OF BYTES IN R0 INCLUDING ITS GAPS, HOME, ETC
SECTRK==^D128 ;SECTORS PER TRACK
BYTTRK==^D13440 ;TOTAL NUMBER OF BYTES PER TRACK
SECERR: STOPCD .+1,DEBUG,ISN, ;++ ILLEGAL SECTOR NUMBER
MOVEI T3,1 ;SET A BETTER SECTOR NUMBER
SETSEC: SOJL T3,SECERR ;JUMP IF ILLEGAL SECTOR NUMBER
IMULI T3,SIZGAP+BLKBYT ;(REC NUM -1) * (TOTAL BYTES FOR A NORMAL RECORD)
ADDI T3,SIZR0 ;PLUS BYTES FOR R0 = BYTE NUM OF BEGINNING OF REC
IMULI T3,SECTRK ;TIMES SECTORS PER TRACK
IDIVI T3,BYTTRK ;THUS GET (BYTE NUM/TOTAL BYTES PER TRACK) * SECTORS
DPB T3,UNYSSC ;STORE SECTOR NUMBER
POPJ P, ;RETURN
;SUBROUTINE TO COMPUTE LATENCY - SHOULDN'T BE CALLLED
DSXLTM: SETZ T1, ;RETURN PERFECT EVERY TIME
JRST CPOPJ1## ;
;SUBROUTINE TO RETURN A PROTOTYPE DEVICE COMMAND WORD FOR SETTING UP CHANNEL PROGRAM
;REQUIRED BECAUSE IOWD IS MAPPED BEFORE CALLING DSX??? TO START READ OR WRITE
DSXDVC: MOVE T1,UNIRWC(U) ;GET PROTOTYPE READ DVW
TLNE S,IO ;SKIP IF READ IS DESIRED
ADD T1,[<O.WRIT>B15-<O.MTRD>B15] ;NO, CONVERT TO WRITE DVW
POPJ P,
;SUBROUTINE TO SET INTERRUPT ENABLE FOR A SUBCHANNEL
DSXENB: MOVEI T2,SO.ENB ;INTERRUPT ENABLE
PJRST CNOSET ;SET THE FLAG AND RETURN
SUBTTL AUTOCONFIGURE
;AUTCON ENTRY POINT
DSXCFG: JRST CPOPJ1## ;I'M NOT INTERESTED UNTIL SAXSER IS
;SAXSER ENTRY POINT
;M/ GLOBAL SA10 SUBCHANNEL NUMBER
;P1/ -N,,CONTROL UNIT ADDRESS (HIGH 'WIDCUA' BITS)
;P2/ SA10 SUBCHANNEL NUMBER
;P3/ AVAILABLE FOR USE
;P4/ ADDRESS OF SENSE CHANNEL PROGRAM FOR UNIT ZERO
DSXCFS: PUSHJ P,SAVW## ;FREE UP KDB ADDRESS AC
SETZ W, ;HAVEN'T SEEN A KDB YET
MOVSI P3,-DSXDMX ;INIT SEARCH FOR EXISTANT UNITS
DSXCF1: HRRZ T1,P1 ;GET DCU ADDRESS
LSH T1,WIDUNA ;POSITION IN HIGH 'WIDCUA' BITS
IORI T1,(P3) ;INCLUDE UNIT ADDRESS
PUSH P,T1 ;SAVE UNIT ADDRESS
PUSHJ P,DSXNOP ;DO A NO-OP ON THE UNIT
JRST DSXCF5 ;FAILED - GO SENSE AND STEP TO NEXT UNIT
POP P,T1 ;GET UNIT ADDRESS
PUSHJ P,DSXSNU ;DO A SENSE TO GET SOME USEFUL INFORMATION
JRST DSXCF4 ;SENSE TIMED OUT, MUST NOT BE A UNIT THERE
TLNE T1,(S.SE) ;SELECT ERROR?
JRST DSXCF4 ;YES
SKIPE SNSDAT+S16WRD(P4) ;ANY TCU REV LEVEL INFORMATION RETURNED?
JRST CPOPJ1## ;YES, MUST NOT BE A DISK CU
JUMPN W,DSXCF2 ;JUMP IF HAVE ALREADY SEEN A UNIT
PUSHJ P,DSXBKD ;BUILD AND LINK THE KDB
POPJ P, ;NO CORE, GIVE UP
DSXCF2: LDB T1,[POINT 8,SNSDAT+S04WRD(P4),7] ;GET SENSE BYTE 4
; (PHYSICAL MODULE ID)
ANDI T1,77 ;KEEP JUST GOOD STUFF
JUMPN T1,DSXCF3 ;JUMP IF ANYTHING THERE
SKIPN SNSDAT+S08WRD(P4) ;HOW ABOUT BYTES 8-11?
JRST DSXCF4 ;NOPE
DSXCF3: PUSHJ P,DSXUNI ;BUILD UDB
POPJ P, ;NO CORE
DSXCF4: AOBJN P3,DSXCF1 ;BUMP UNIT NUMBER AND KEEP LOOKING
POPJ P, ;RETURN
DSXCF5: POP P,T1 ;GET UNIT ADDRESS
PUSHJ P,DSXSNU ;DO A SENSE TO UNLOAD UNIT-CHECK INFO
JFCL ;OH WELL
JRST DSXCF4 ;THEN REJOIN CODE AND STEP TO NEXT UNIT
;BUILD AND LINK KDB
;M/ GLOBAL SA10 SUBCHANNEL NUMBER
;P1/ JUNK,,DCU ADDRESS (HIGH 'MAXCUA' BITS)
;P2/ SA10 SUBCHANNEL NUMBER
DSXBKD: HRRZ T1,P1 ;GET DCU ADDRESS AS MASSBUS NUMBER
TRO T1,400000 ;BUT MAKE IT LOOK NEGATIVE TO FAKE OUT AUTKDB
MOVEI T2,TYPDS ;UNIT TYPE CODE
PUSHJ P,DSKKON## ;BUILD A DISK KDB
POPJ P, ;GIVE UP IF NO CORE
ADDM J,DSXPTR(J) ;ADJUST DSXPTR
MOVSI T1,-<DSXIOE-DSXIOB> ;NUMBER OF WORDS TO CHECK
XMOVEI T2,DSXIOB(J) ;STARTING WORD
HRRZ T3,.CPDVC## ;<DEVICE CODE>/4
PUSHJ P,AUTDVC## ;SET DEVICE CODES
MOVS T1,P2 ;GET SUBCHANNEL NUMBER
IMULI T1,SO.CHN ;POSITION FOR CONO
HRR T1,P2 ;INCLUDE SUBCHANNEL NUMBER
MOVEM T1,DSXSCH(J) ;STORE IN KDB
MOVEM M,DSXGSN(J) ;SAVE GLOBAL SUBCHANNEL NUMBER
MOVE T1,SAXSBA##(M) ;GET BASE ADDRESS FOR THIS SUBCHANNEL
MOVEI T2,.CLICW(T1) ;GET ICW ADDRESS
MOVEM T2,DSXICW(J)
MOVEI T2,.CLCSW(T1) ;GET ECW ADDRESS
MOVEM T2,DSXCSW(J)
MOVSI T1,KOPECA ;GET THE "I KNOW HOW TO DO ECC" BIT
IORM T1,KONECA(J) ;...AND SET IT IN OUR KDB
MOVEI T1,DSXDMX ;NUMBER OF DEVICE LIST ENTRIES WE'LL REQUIRE
PUSHJ P,SAXDVL## ;ASSIGN THEM
POPJ P, ;THERE WEREN'T ENOUGH FREE?!
MOVEM T1,DSXDVP(J) ;SAVE ADDRESS OF START OF DEVICE LIST
JRST CPOPJ1## ;SKIP RETURN
;BUILD AND LINK UDB
;M/ GLOBAL SA10 SUBCHANNEL NUMBER
;J/ KDB ADDRESS
;P1/ JUNK,,DCU ADDRESS (HIGH 'MAXCUA' BITS)
;P2/ SA10 SUBCHANNEL NUMBER
;P3/ JUNK,,UNIT ADDRESS
;P4/ SENSE PROGRAM BUFFER ADDRESS
DSXUNI: HRLZ T1,P3 ;PHYSICAL DRIVE NUMBER
HRR T1,P3 ;UDB TABLE INDEX
MOVEI T2,.UT331 ;ASSUME 3331 UNIT
PUSHJ P,DSKDRV## ;BUILD AND LINK THE UDB
POPJ P, ;NO CORE
ADDM U,UNISEK+1(U)
ADDM U,UNISET+1(U)
ADDM U,UNISID(U)
ADDM U,UNISID+1(U)
ADDM U,UNISNP+1(U)
HRRZ T1,P1 ;GET DCU ADDRESS
LSH T1,WIDUNA ;POSITION IN HIGH 'WIDCUA' BITS
IORI T1,(P3) ;INCLUDE UNIT NUMBER
DPB T1,[POINT DVSDVA, UNIRCL(U), DVNDVA] ;INSERT DEVICE ADDRESS
DPB T1,[POINT DVSDVA, UNINOP(U), DVNDVA]
DPB T1,[POINT DVSDVA, UNISEK(U), DVNDVA]
DPB T1,[POINT DVSDVA, UNISET(U), DVNDVA]
DPB T1,[POINT DVSDVA, UNISIE(U), DVNDVA]
DPB T1,[POINT DVSDVA, UNISNP(U), DVNDVA]
DPB T1,[POINT DVSDVA, UNIRWC(U), DVNDVA]
MOVE T1,DSXDVP(J) ;GET START OF DEVICE LIST
ADDI T1,(P3) ;INCLUDE UNIT ADDRESS
MOVEM T1,UNIDVP(U) ;SAVE POINTER TO DEVICE LIST ENTRY
MOVEI T1,CPALEN ;GET LENGTH OF CHANNEL PROGRAM AREA
PUSHJ P,SAXCOR## ;GO GET A CHUNK OF SA10 MEMORY
POPJ P, ;DARN.
MOVEM T1,UNIPCP(U) ;SAVE ADDRESS OF CHANNEL PROGRAM BUFFER
HRRZ T1,P2 ;GET DCU ADDRESS
LSH T1,WIDUNA ;POSITION
HRRZ T2,P3 ;GET PHYSICAL DRIVE NUMBER
IOR T2,T1 ;BUILD FAKE DRIVE S/N SINCE IT CAN'T BE READ
SETZ T1, ;REALLY A ONE-WORD QUANTITY
DMOVEM T1,UDBDSN(U) ;SET SERIAL NUMBER IN UDB
JRST CPOPJ1## ;RETURN
;EXECUTE A SENSE OPERATION FOR A SPECIFIED ADDRESS.
;CALL:
; T1/ DEVICE ADDRESS
; P4/ CHANNEL PROGRAM BUFFER ADDRESS
; PUSHJ P,DSXSNU
; <ERROR RETURN>
; <NORMAL RETURN> ;T1/ CHANNEL STATUS BITS
DSXSNU: DPB T1,[POINT DVSDVA, SNSDVW(P4), DVNDVA] ;INSERT DEVICE ADDRESS
MOVE T1,P4 ;COPY CHANNEL PROGRAM ADDRESS
ADDI T1,SNSDVW ;POINT AT SENSE CMD
PJRST SAXRCP## ;RUN THE SENSE CHANNEL PROGRAM
;EXECUTE A NO-OP OPERATION FOR A SPECIFIED ADDRESS.
;CALL:
; T1/ DEVICE ADDRESS
; P4/ CHANNEL PROGRAM BUFFER ADDRESS
; PUSHJ P,DSXNOP
; <ERROR RETURN>
; <NORMAL RETURN> ;T1/ CHANNEL STATUS BITS
DSXNOP: DPB T1,[POINT DVSDVA, SNSDVW(P4), DVNDVA] ;INSERT DEVICE ADDRESS
DPB T1,[POINT DVSDVA, SNSNOP(P4), DVNDVA] ;INSERT DEVICE ADDRESS
MOVE T1,P4 ;COPY CHANNEL PROGRAM ADDRESS
PJRST SAXRCP## ;RUN THE NO-OP/SENSE CHANNEL PROGRAM
SUBTTL ONCE A SECOND CODE
DSXSEC: SKIPL @KDBCHN(J) ;CHANNEL BUSY?
POPJ P, ;LEAVE IT ALONE
SKIPE T1,DSXNUM(J) ;GET BIT MASK
JFFO T1,DSXSE1 ;FIND FIRST UNIT NUMBER
HRRZS KDBNUM(J) ;INDICATE NO DRIVES TO CONFIGURE
POPJ P, ;DONE
DSXSE1: PUSHJ P,AUTLOK## ;GET AUTCON INTERLOCK
POPJ P, ;TRY AGAIN NEXT TIME
PUSHJ P,SAVW## ;PRESERVE W
MOVE W,J ;COPY KDB ADDRESS TO W FOR AUTCON
REPEAT 0,<
MOVSS T2 ;MASSBUS UNIT = DRIVE NUMBER FOR DSX DISKS
PUSH P,T2 ;SAVE
MOVE T1,KDBDVC(J) ;DEVICE CODE
XMOVEI T2,DSXDSP ;DISPATCH
MOVE T3,KDBCHN(J) ;CHANNEL DATA BLOCK
PUSHJ P,AUTSET## ;SET UP CPU VARIABLES
EXCH P1,(P) ;SAVE P1, GET MASSBUS UNIT
PUSH P,KDBUNI(J) ;SAVE KDBUNI
MOVEM P1,KDBUNI(J) ;SET FOR THIS MASSBUS UNIT NUMBER (FOR RDMBR)
PUSHJ P,DSXUNI ;CONFIGURE A NEW UNIT
JFCL ;IGNORE ERRORS
PUSHJ P,AUTULK## ;RELEASE AUTCON INTERLOCK
POP P,KDBUNI(J) ;RESTORE KDBUNI
PJRST P1POPJ## ;RESTORE P1 AND RETURN
>; END REPEAT 0
POPJ P, ;*** FOR NOW
;TABLES OF BLOCKS PER UNIT INDEXED BY UNIT TYPE
BLKPRU: DEC 18*19*411 ;TYPE 0 (3330)
DEC 18*19*815 ;TYPE 1 (3331)
; ROUTINE TO TAKE A DF10C (IE: DEFAULT CHANNEL) CHANNEL IO LIST
; AND CONVERT IT INTO A 3330/3331 CHANNEL PROGRAM.
;
; PUSHJ P,MAPIO
; <ONLY RETURN, EVERYTHING DONE>
;
; P1=POINTER TO CURRENT DF10 LIST, USED ONLY BY GETIOW ET AL
; P2=POINTER TO CURRENT SA10B CHANNEL PROGRAM WORD, USED ONLY BY MAPIO
; P3=COUNT OF CONSECUTIVE WORDS IN A SINGLE DF10 IOWD, RETURNED BY GETIOW
; P4=ADDRESS OF CONSECUTIVE WORDS IN IOWD AS P3
; N.B.: GETIOW COMBINES CONSECUTIVE CONTIGUOUS DF10 IOWDS
MAPIO: PUSHJ P,SAVE4## ;SAVE SOME ACS
PUSHJ P,SAVR## ;SAVE SOME MORE
MOVE P1,UNIDRB(U) ;PICK UP POINTER TO DRB FOR THIS UNIT
MOVE T1,DRBBLK##(P1) ;GET 1ST BLOCK IN XFER
MOVEM T1,UNICBN(U) ;SAVE CURRENT BLOCK NUMBER
MOVE P1,DRBPRG##(P1) ;PICK UP POINTER TO DF10C LIST FOR THIS UNIT
MOVE P2,UNIPCP(U) ;PICK UP PHYSICAL POINTER TO SA10 PROGRAM
MOVE T2,P2 ;PICK UP COPY OF PHYSICAL ADDR OF PROGRAM
ADDI T2,CPALEN-2 ;COMPUTE FIRST AVAILABLE SID-DATA AREA
MOVEM T2,UNISDA(U) ;SAVE POINTER
PUSHJ P,SETSIE ;SETUP THE SEEK CMD IN THE UDB
PUSHJ P,SETSEC ;SETUP THE SET-SECTOR COMMAND IN THE UDB
PUSHJ P,DSXDVC ;COMPUTE CORRECT XFER COMMAND
MOVE W,T1 ;SAVE COPY OF COMMAND IN W
SETZ M, ;M=THIS BLOCKS WORD COUNT SO FAR
MAPIO1:
MAPIO2: PUSHJ P,STOXFR ;INSERT A COPY OF THE XFER COMMAND
MAPIO3: PUSHJ P,GETIOW## ;GO GET AN IOWD PAIR T1=COUNT,T2=ADR
JUMPE T1,MAPIO0 ;BRANCH IF "HALT"
DMOVE P3,T1 ;P3=COUNT, P4=ADR
MAPIO4: MOVEI T1,BLKSIZ ;GET SIZE OF A BLOCK
SUBI T1,(M) ;COMPUTE NUMBER OF WORDS NEEDED
CAILE T1,(P3) ;SKIP IF NEEDED IS LESS THAN AVAILABLE
JRST MAPIO5 ;BRANCH IF NEEDED IS MORE THAN AVAILABLE
;HERE WHEN #WORDS NEEDED TO FILL BLOCK IS LESS THAN WE GOT IN THIS IOWD
;IN THIS CASE, WE FINISH OUT THE BLOCK AND START ANOTHER.
MOVE T4,T1 ;SAVE A COPY OF THE WORDS TAKEN FROM P3/P4
PUSHJ P,STOIOW ;STORE FINAL IOWD FOR THIS BLOCK
PUSHJ P,STOXFR ;INSERT A NEW COMMAND
SUBI P3,(T4) ;ADJUST DF10 COUNT
ADDI P4,(T4) ;ADJUST DF10 ADDRESS
SETZ M, ;NEXT BLOCK HAS 0 WORDS IN IT, SO FAR
JUMPE P3,MAPIO3
JRST MAPIO4
;HERE WHEN THE #WORDS IN THIS IOWD PAIR CANNOT FINISH THIS BLOCK.
;IN THIS CASE, WE INSERT ANOTHER PARTIAL SIOWD AND GET ANOTHER DF10 IOWD
MAPIO5: MOVE T1,P3 ;COPY THE ACTUAL COUNT FOR THIS IOWD
ADD M,T1 ;COUNT THESE WORDS
TLO T1,(1B0) ;TURN ON PARTIAL FLAG
PUSHJ P,STOIOW ;STORE PARTIAL IOWD FOR THIS BLOCK
JRST MAPIO3 ;...GO GET ANOTHER DF10 IOWD
;HERE WHEN THE WORD COUNT WAS ZERO FOR A DF10 IOWD
MAPIO0:
;HERE IF BOTH COUNT AND ADDRESS FIELDS WERE 0 - MUST BE A HALT
MAPIOD: JUMPE M,MAPIOX ;EXIT NOW IF NO PENDING BLOCK
;$ IBM DOCUMENT SAYS THAT STORAGE-CONTROL WILL TAKE CARE OF
;$ PADDING WITH ZEROES IF WE FEED IT LESS THAN "COUNT AREA DL" WORDS.
;$ ALSO, UUOCON/MONIO WILL HAVE ALREADY MADE SURE WE'RE A MULTIPLE OF
;$ THE SIZE OF A SINGLE BLOCK ANYWAY.
;$ MOVEI T1,BLKSIZ ;GET SIZE OF A BLOCK
;$ SUBI T1,(M) ;COMPUTE REMAINING WORDS IN BLOCK
JUMPN M,MAPIOY ;BRANCH IF LAST BLOCK WASN'T FILLED
MAPIOX: MOVSI T1,(BMXEND) ;GET A HALT
MOVE P2,R ;GO BACK TO THE BEGINNING OF THE CURRENT GROUP
PUSHJ P,STODVC ;STORE THE END CMD
POPJ P, ;ALL DONE
;HERE IF LAST BLOCK WASN'T FILLED.
MAPIOY: SUBI P2,1 ;BACK UP "PC" TO POINT AT PARTIAL IOWD
PMOVE T1,P2 ;GET PARTIAL IOWD
TLO T1,(1B0) ;SET "LAST IOWD" AFTER ALL
PMOVEM T1,P2 ;STORE PARTIAL IOWD BACK AS A "LAST IOWD" INSTEAD
ADDI P2,1 ;RESTORE PC TO CURRENT PLACE
MOVE T1,BMXWRD ;GET A HALT
PJRST STODVC
; ROUTINES TO INSERT NON-IOWD CHANNEL COMMANDS INTO THE 3330/3331 PROGRAM
STOXFR: MOVE R,P2 ;THIS LOCATION GETS "HALT" IF NO MORE TO DO
TROE W,1 ;SKI IF FIRST BLOCK
TLNN S,IO ;SKIP IF READ COMMANDS NEEDED
SKIPA
PUSHJ P,STOSID ;INSERT A SEARCH-ID-EQUAL FOR WRITES
MOVE T1,W ;GET THE READ/WRITE COMMAND
PUSHJ P,STODVC ;STORE DEVICE COMMAND
AOS UNICBN(U) ;ADVANCE BLOCK #
POPJ P,
STOSID: MOVE T1,UNISIE(U) ;GET VIRGIN SEARCH ID
TLZ T1,(F.OFP) ;TURN OFF "START AT BYTE 3" BIT
PUSHJ P,STODVC ;STORE DEVICE COMMAND
MOVSI T1,777300 ;-5 BYTE COUNT (IE: C C H H R)
OR T1,UNISDA(U) ;ADD IN ADDRESS OF SEARCH DATA
PUSHJ P,STODVC ;STORE IOWD FOR SEARCH-ID-EQUAL
PUSHJ P,SETSID ;SETUP SEARCH DATA, UPDATE UNISDA
MOVE T1,P2 ;GET ADDRESS OF NEXT CMD
SUBI T1,2 ;BACK UP SO WE ARE POINTING AT SEARCH-EQUAL
TLO T1,(TIC) ;AND CREATE A TIC CMD THAT GOES TO SEARCH-EQUAL
PUSHJ P,STODVC ;INSERT TIC TO JUMP BACK TO SEARCH EQUAL
POPJ P, ;RETURN
STOIOW: IMUL T1,[-100,,0] ;POSITION THE COUNT FIELD
TDO T1,P4 ;INSERT THE ADDRESS FIELD
STODVC: PMOVEM T1,P2 ;STORE COMMAND IN THE CHANNEL PROGRAM
AOJA P2,CPOPJ## ;RETURN
;ROUTINE TO INSERT SEARCH ID DATA
SETSID: MOVE T1,UNICBN(U) ;GET CURRENT BLOCK NUMBER
LDB T2,UNYBPY## ;GET BLOCKS PER CYLINDER
IDIV T1,T2 ;COMPUTE T1=CYL#, T2=REMAINDER
ROT T1,-^D16 ;T1=LEFT JUSTIFIED CYL# IN 16 BIT FIELD
LDB T3,UNYBPT## ;GET BLOCKS PER TRACK
IDIV T2,T3 ;COMPUTE T2=TRACK/HEAD, T3=RECORD
ADDI T3,1 ;T3=RECORD NUMBER (START AT 1, NOT 0)
DPB T2,[POINT 16,T1,31];INSERT HEAD INFO INTO T1
MOVE T2,UNISDA(U) ;GET POINTER TO SEARCH DATA BUFFER
PMOVEM T1,T2 ;INSERT 1ST WORD OF IT
ADDI T2,1 ;POINT AT NEXT WORD
ROT T3,-^D8 ;LEFT JUSTIFY RECORD NUMBER IN 8 BIT FIELD
PMOVEM T3,T2 ;INSERT 2ND WORD OF IT
SUBI T2,3 ;UPDATE T2 TO NEW UNISDA
MOVEM T2,UNISDA(U) ;UPDATE UNISDA
POPJ P, ;RETURN
;ROUTINE TO TAKE THE SA10 UNDONE PC AND RESIDUAL COUNT
; AND USE IT TO CALCULATE AND UPDATE THE "CONTROL WORD" DATA FOR THE "DF10"
;SCAN THE SA10 PROGRAM FORWARDS UNTIL SIMULATED PC IS BEYOND THE DONE PC.
;KEEP TRACK OF EACH COMMAND AND COUNT BLKSIZ WORDS FOR EACH COMMAND.
FIXCWA: PUSHJ P,SAVT## ;SAVE ACS - INTERUPT LEVEL CARES
JUMPE S,FIXGUD ;BRANCH IF NO ERRORS
PUSHJ P,SAVR## ;SAVE
FIXCW0: LDB R,[POINT 22,UNITCA(U),35];GET THE UNDONE PC
MOVE T1,UNIPCP(U) ;GET THE PROGRAM POINTER
SETZ T4, ;ASSUME 0 WORDS IF HEADER ERROR
FIXCW1: PMOVE T2,T1 ;PICK UP THE "THING" THERE
CAME T2,BMXWRD ;SKIP IF A HALT (IE: A COMMAND)
CAMN T1,R ;SKIP IF NOT THE UNDONE PC
JRST FIXCC1 ;BRANCH IF UNDONE PC
TRNE T2,1 ;CHECK FOR AN XFER COMMAND
JRST FIXCW2 ;BRANCH IF AN XFER COMMAND
ADDI T1,3 ;MUST BE SEARCH-ID, IOWD, TIC, SO SKIP
JRST FIXCW1 ;...OVER THEM AND TRY AGAIN
FIXCW2: MOVEM T1,UNILPC(U) ;REMEMBER LAST PC OF XFER CMD
FIXCW3: ADDI T1,1 ;STEP TO NEXT IOWD
PMOVE T2,T1 ;GET IOWD
CAMN T1,R ;SKIP IF NOT UNDONE PC
JRST FIXCR1 ;BRANCH IF UNDONE PC
MOVE T3,T2 ;COPY THE IOWD
TLO T2,(1B0) ;TURN ON SIGN BIT
ASH T2,-^D24 ;T2=RIGHT JUSTIFIED -VE WORD COUNT
SUB T4,T2 ;T4=+VE WORD COUNT SO FAR
JUMPG T3,FIXCW3 ;BACK FOR MORE IF THIS IS PARTIAL IOWD
AOJA T1,FIXCW1 ;FOUND LAST IOWD, NOW STEP TO NEXT CMD
;HERE IF WE FIND THE UNDONE PC POINTING AT AN IOWD, MUST BE A RESIDUAL
;T1=PC OF IOWD
;T2=THE IOWD
;T3=JUNK
;T4=TOTAL WORDS SO FAR
FIXCR1: TLO T2,(1B0) ;MAKE IT APPEAR -VE EVEN IF NOT
ASH T2,-^D24 ;...SO THIS ASH WORKS
LDB T3,[POINT 12,UNITCA(U),11] ;GET RESIDUAL FROM SUBCHANNEL BLOCK
ASH T3,-^D24 ;RIGHT JUSTIFY IT TOO
SUB T2,T3 ;COMPUTE +VE XFER'ED ON THIS IOWD
ADD T4,T2 ;ADD INTO TOTAL
JRST FIXCC1 ;JOIN COMMAND CODE
;HERE IF WE FIND THE UNDONE PC POINTING AT A COMMAND
;NO RESIDUAL SINCE WE'RE POINTING AT A COMMAND, NOT IOWD
; NOW, SCAN DF10 PROGRAM UNTIL WE ENCOUNTER T4 WORDS
FIXCC1:
FIXCW5: MOVE T1,UNIDRB(U) ;POINT AT DRB
MOVE T2,T4 ;COPY WORD COUNT
IDIVI T2,^O200 ;COMPUTE # OF GOOD BLOCKS
MOVEM T2,DRBGOD##(T1) ;SAVE GOOD COUNT IN DRB
MOVE T1,DRBPRG##(T1) ;POINT AT DF10 PROGRAM
;SCAN DF10 PROGRAM UNTIL WE "XFER" (T4) WORDS
FIXCW6: LDB T2,[POINT 14,(T1),13] ;T2=WORD_COUNT
LDB T3,[POINT 22,(T1),35] ;T3=ADDRESS
JUMPE T2,FIXCW8 ;BRANCH IF HALT OR GOTO
IOR T2,[-1,,740000] ;EXTEND THE SIGN OF T2 TO 36 BITS
MOVNS T2 ;MAKE T2=+VE COUNT
MOVE R,T3 ;COPY BASE ADDRESS OF THIS XFER
CAMG T2,T4 ;SKIP IF THIS IOWD IS MORE THAN EENOUGH
AOJA T1,[ADD R,T2 ;...IF NOT ENUF, COMPUTE FINAL XFER ADR
SUB T4,T2 ;...IF NOT ENUF, ADJUST RUNNING REMAIN
JRST FIXCW6] ;...IF NOT ENUF, GO GET ANOTHER IOWD
ADD R,T4 ;COMPUTE FINAL XFER ADDRESS
FIXCW7: MOVE T2,KDBICP(J) ;T2=POINTER TO "DF10 ICW PAIR"
DPB T1,[POINT 14,1(T2),13] ;INSERT FINAL CWAD
DPB R, [POINT 22,1(T2),35] ;INSERT FINAL XFER ADDRESS
POPJ P,
FIXCW8: JUMPE T3,FIXCW7 ;BRANCH IF WE FOUND A DF10 HALT
MOVE T1,T3 ;PERFORM A "JMP" IF ONE IS FOUND
JRST FIXCW6 ;LOOP FOR MORE IOWD
;HERE IF THERE WASN'T AN ERROR, JUST USE COMPUTED DF10 WORD AND DRBGUD
FIXGUD: MOVE T1,UNIDRB(U) ;POINT AT DRB
MOVE T2,DRBBLK##(T1) ;GET EXPECTED WORDS
MOVEM T2,DRBGOD##(T1) ;MAKE IT ACTUAL BLOCKS
MOVE T2,KDBCHN(J) ;GET CHANNEL
MOVE T3,KDBICP(J) ;WHERE TO PUT IT
MOVE T2,CHNTCW(T2) ;GET WHAT FILIO WANTS
MOVEM T2,1(T3) ;PUT IT WHERE FILIO LOOKS
POPJ P,
$LOW ;LOW SEG STUFF
BMXWRD: BMXEND ;MUST BE LOW SEG SO SA10 GETS ACTUAL ADDR
$HIGH
SUBTTL THE END
$LIT
DSXEND: END