;<135-TENEX>DSKPAK.MAC;21     8-DEC-75 15:09:26    EDIT BY ROSENBERG
; SUPPORT UP TO 1024K FOR SA-10/CD230 TYPE DISKS
; NOTE 1024K NOT SUPPORTED FOR OTHER DISK CONTROLLERS/CHANNELS
;<134-TENEX>DSKPAK.MAC;20     6-NOV-75 09:54:36    EDIT BY ALLEN
; CHANGE SSA MEASURMENET BUGHLTS TO BUGNTES AND TAKE APPROPRIATE
;CORRECTIVE ACTION
;<134-TENEX>DSKPAK.MAC;13    15-OCT-75 19:14:34    EDIT BY ALLEN
; FIX TO QUEUING TIME MEASUREMENT
;<134-TENEX>DSKPAK.MAC;11    14-OCT-75 11:53:59    EDIT BY ALLEN
; ADDITIONAL CHECK ON MEASURMENT STUFF
;<134-TENEX>DCADSK.MAC;14     9-OCT-75 12:58:30    EDIT BY ALLEN
; ADD CHECKS TO BE SURE THAT WE SEE ALL MEASUREMENT INTERRUPTS
; WHEN WE EXPECT THEM
;<134-TENEX>DCADSK.MAC;12    12-SEP-75 14:53:37    EDIT BY CLEMENTS
; ADDED WDSK CODE FOR SSA VERSION.
;<134-TENEX>DCADSK.MAC;11     9-SEP-75 16:41:45    EDIT BY CLEMENTS
; ADDED RETRY CODE FOR SSA VERSION OF DSKCHK AND RLRMON
;<134-TENEX>DCADSK.MAC;10    30-JUL-75 19:13:50    EDIT BY ALLEN
; MINOR BUG FIXES
;<134-TENEX>DCADSK.MAC;8    22-JUL-75 15:58:41    EDIT BY ALLEN
; VARIOUS MINOR BUG FIXES
;<134-TENEX>DCADSK.MAC;7    22-JUL-75 12:21:55    EDIT BY ALLEN
;<134-TENEX>DSKPAK.MAC;7    14-MAR-75 14:34:10    EDIT BY CLEMENTS
; NAME CHANGE TO DSKPAK
;<134-TENEX>MDSKPA.MAC;6    14-MAR-75 14:24:26    EDIT BY CLEMENTS
; PUT NCRSTK DEFINITION BEFORE USE TO AVOID V ERR IN MACRO 50
;<134-TENEX>MDSKPA.MAC;5     3-FEB-75 22:53:21    EDIT BY ALLEN
; CORRECTION TO DSKIS
;<134-TENEX>MDSKPA.MAC;4    23-JAN-75 11:21:15    EDIT BY ALLEN
; FIX ERROR IN DSKIS
;<133-TENEX>MDSKPA.MAC;3    16-DEC-74 14:05:07    EDIT BY ALLEN
; VERIFY THAT DF10 REPORT OF NUMBER OF WORDS TRANSFERRED AGREES WITH
; DSKCAW
;<133-TENEX>MDSKPA.MAC;2     2-DEC-74 10:31:16    EDIT BY CLEMENTS
; RESET LOW CORE START ADDR FOR SSA IN DSKSVX
;<ALLEN>DSKPAK.MAC;19    19-OCT-74 17:19:39    EDIT BY ALLEN
; BUG FIX IN DSKIS
;<ALLEN>DSKPAK.MAC;18    18-OCT-74 13:55:46    EDIT BY ALLEN
;<ALLEN>DSKPAK.MAC;17    17-OCT-74 14:25:52    EDIT BY ALLEN
;<ALLEN>DSKPAK.MAC;15    12-OCT-74 21:01:54    EDIT BY ALLEN
; CORRECT ERROR IN DEFINITION OF SWPSEC
;<ALLEN>DSKPAK.MAC;14    12-OCT-74 12:39:43    EDIT BY ALLEN
;<ALLEN>DSKPAK.MAC;13    12-OCT-74 10:19:06    EDIT BY ALLEN
;<ALLEN>DSKPAK.MAC;12    11-OCT-74 16:54:24    EDIT BY ALLEN
;<ALLEN>DSKPAK.MAC;11    11-OCT-74 15:39:12    EDIT BY ALLEN
; HAVE DSKINI INDICATE MULTI-PAK SWAPPING IN MONDSC GETAB TABLE
;<ALLEN>DSKPAK.MAC;10    17-SEP-74 11:55:22    EDIT BY CLEMENTS
;<ALLEN>DSKPAK.MAC;9    16-SEP-74 12:11:31    EDIT BY CLEMENTS
; ADDITION OF RP03 CAPABILITY. PARAMS SHOULD DEFINE EITHER
; RP02F OR RP03F. CANNOT YET BE MIXED. CODE IS UNDER RP10F IN
; THIS MODULE, WHICH GETS SET HERE IF EITHER RP02F OR RP03F IS ON.
;<ALLEN>DSKPAK.MAC;8    13-SEP-74 10:48:08    EDIT BY ALLEN
;<ALLEN>DSKPAK.MAC;7     6-SEP-74 17:13:39    EDIT BY ALLEN
;<ALLEN>DSKPAK.MAC;6    26-AUG-74 12:23:19    EDIT BY ALLEN
;<ALLEN>DSKPAK.MAC;5    23-AUG-74 13:30:32    EDIT BY ALLEN
;<133-TENEX>DSKPAK.MAC;94    22-JUL-74 14:01:35    EDIT BY ALLEN
;<133-TENEX>DSKPAK.MAC;93    21-JUL-74 12:38:32    EDIT BY ALLEN
;<133-TENEX>DSKPAK.MAC;92    10-JUL-74 17:56:48    EDIT BY CLEMENTS
;<133-TENEX>DSKPAK.MAC;91    10-JUL-74 15:35:11    EDIT BY CLEMENTS
; EXPANDED ERROR STATUS SAVING AND PRINTING FOR 3330'S
;<133-TENEX>DSKPAK.MAC;90    10-JUL-74 13:28:20    EDIT BY CLEMENTS
;<TENEX-132>DSKPAK.MAC;88    24-JUN-74 10:28:08    EDIT BY CLEMENTS

;TENEX DRIVER FOR DISK PACKS.  D. MURPHY ET AL.

;GENERAL CODE FOR DISK PACK DEVICES; DEVICE DEPENDENT CODE FOR
;DEC RP10/RP02 AND TELEFILE DC10 INCLUDED UNDER ASSEMBLY SWITCH

	INTERN RLMX0,DSKRMA
	INTERN NDSKPR
	INTERN DSKIO,DSKCHK,UDSKIO,CVDSK,CDSKVA,DIDSCI
	EXTERN BLOCK1,DSKTIM,DISKP,FPTA,JFNOFN,NXTDMP
	EXTERN SETMPG,SETPT,DBUGSW,PSKED,DIDSCA,DEVMPE
	EXTERN DISGET,SCHEDP,EDISMS

;THE FOLLOWING ARE ALL OF THE DEVICE AND INSTALLATION DEPENDENT
;PARAMETERS

IFDEF RP02F,<	RP10F==1>	;COMMON FLAG FOR CONTROLLER OF RP02 OR
IFDEF RP03F,<	RP10F==1>	; RP03 DRIVES.

IFDEF RP10F,<		;RP02 AND RP03 DEVICE PARAMETERS

DSK=250			;DEVICE ADDRESS
DSKCP=62		;INITIAL CHANNEL ADDRESS
;NOTE - Support for a DF10C has not been coded. Therefore, the
;parameters below must define the word count and address fields
;as each being an 18 bit field.
WCSZ==^D18		;WORD COUNT IS AN 18 BIT FIELD
ADSZ==^D18		;PHYSICAL ADDRESS IS AN 18 BIT FIELD

IFDEF RP02F,<
NTKUN=^D203>		;NUMBER OF TRACKS PER DRIVE (UNIT)
IFDEF RP03F,<
NTKUN=^D400>		;NUMBER OF CYLS (TRACKS) ON RP03
NCYLBT==8		;BUT THE NINTH BIT IS IN TOP OF SECTOR FIELD
NSECBT==5		; ON THE RP03. NEITHER REALLY HAS 5 BITS OF SECS


NWSEC==200		;RPO2'S AND RP03'S HAVE 128 WORDS/SECTOR,
NSECS==^D10		; 10 SECTORS PER ROTATION,
NSURFS==^D20		; AND 20 SURFACES PER UNIT

	HOMCY1==1			; HOME CYLINDERS
	HOMCY2==1
	HOMSF1==5			; SURFACES
	HOMSF2==^D15
	HOMSC1==0			; AND SECTORS
	HOMSC2==0

>			;END OF RP10 PARAMETERS

IFDEF DC10F,<		;TELEFILE DC10 PARAMETERS

DSK=700
DSKCP=62
;NOTE - Support for a DF10C has not been coded. Therefore, the
;parameters below must define the word count and address fields
;as each being an 18 bit field.
WCSZ==^D18		;WORD COUNT IS AN 18 BIT FIELD
ADSZ==^D18		;PHYSICAL ADDRESS IS AN 18 BIT FIELD

IFNDEF CD215F,<
NTKUN==^D203
NWSEC==100
NSECS==^D18
NCYLBT==8
NSECBT==5
>

IFDEF	CD215F,<
NTKUN==^D406
NWSEC==200
NSECS==^D9
NCYLBT==9
NSECBT==4
>

NSURFS==^D20

	HOMCY1==1		; HOME CYLINDERS
	HOMCY2==1
	HOMSF1==5		; AND SURFACES
	HOMSF2==15
	HOMSC1==0		; AND SECTORS
	HOMSC2==0
	ADRPOS==^D14+NSECBT
>			;END OF DC10 PARAMETERS

IFDEF SSADF,<
;PARAMETERS FOR 3330 STYLE DISKS, ON IBM STYLE CONTROLLER, ON SSA.

;FOLLOWING FOR CD230'S (=3330'S)
NTKUN==^D406		; PLUS A FEW FOR ALTERNATES NOT COUNTED HERE.
NWSEC==1000		; WORDS ON DATA AREA OF A SECTOR
NSECS==5		; SECTORS AROUND THE PACK
NCYLBT==9		; BITS IN CYLINDER FIELD
NSECBT==4		; ONLY 3 NEEDED, BUT KEEP SAME AS CD215'S
NSURFS==^D19		; NUMBER OF HEADS (SURFACES) ON THE PACK

HOMCY1==1		; HOME CYLINDERS SAME AS CD215'S
HOMCY2==1
HOMSF1==5		; ALSO SECTORS AND SURFACES ARE SAME
HOMSF2==^D15
HOMSC1==0
HOMSC2==0

EXTERN SSABAS		; WHERE SSA GETS INITIAL COMMAND POINTER
IFNDEF SA10BF,<SA10BF==1>
IFE SA10BF,<
WCSZ==^D16
ADSZ==^D20
>
IFN SA10BF,<
WCSZ==^D12
ADSZ==^D24
>
>; END OF IFDEF SSADF

;COMMON PARAMETERS AND STORAGE

IFG ^D36-<^L<MAXCOR-1>>+^D9-ADSZ, <IF1,
<PRINTX DISK CONTROLLER CANNOT ACCESS ALL OF MEMORY
PRINTX DO NOT RUN THIS SYSTEM ON A MACHINE WITH MORE THAN 256K
>>

LS DSKBLK,1		;BIT TABLE LOCK
LS DBTJFN,1		;JFN OF BIT TABLE FILE

;DISC ADDRESS OF INDEX FILE

DIDSC0==<SWPTK-1>*NSECTK	;PUT NEXT TO SWAP AREA ON FIRST PACK

IF2,<IFL DIDSC0,<
	PRINTX DIDSC0 NEGATIVE, REDUCE SIZE OF PSEUDO-DRUM
>>

DIDSCI:	DIDSC0+DSKABT
GS DIDSCA,1

NDVMAX==10		;MAX NUMBER OF DRIVES

NDSKCM==10		;SIZE OF UDSKIO COMMAND BUFFER (20 OCTAL IS MAX)
NDSKPD==10		;SIZE OF INTERRUPT PDL
NPD1==20		;SIZE OF LOCAL (MAIN) PDL

;STATUS OF DRIVE IS RECORDED IN DSKSTS
;SIGN BIT IS DWRBIT, ON FOR WRITE, OFF FOR READ.
DSKSIP==(1B1)		;SEEK IN PROGRESS, LH OF DSKSTS
DSKCMR==(1B2)		;COMMAND READY, LH OF DSKSTS
DSKUIO==(1B3)		;UDSKIO TYPE OPERATION, LH OF DSKSTS
DSKRCB==(1B4)		;RECALIBRATE IN PROGRESS
DSKSNB==(1B5)		;ON SSA, SENSE BEING DONE.
DSKBSB==(1B6)		;ON SSA, DEVICE BUSY HAS BEEN REPORTED
DSKRTB==(1B7)		;ON SSA, OVERDUE XFER HAS BEEN RESTARTED
IFDEF SSAMEA,<
DSKSEK==(1B8)		;INDICATE SEEK IN PROGRESS. DEFINED AS A 
			;BIT FROM DSKSIP FOR MEASUREMENT PURPOSES TO 
			;CONFLICT WITH THE VARIOUS USES OF DSKSIP
DSKSCH==(1B9)		;SEARCHING IN PROGRESS
DSKTRN==(1B10)		;TRANSFER IN PROGRESS
> ;END SSA MEASUREMENT CONDITIONAL

; BITS 18 - 23 ARE ERROR COUNTER
; BITS 24 - 32 ARE CYLINDER AT WHICH DRIVE IS POSITIONED OR SEEKING
;LH BITS 13-17 ARE AN INDEX INTO THE UDSKIO COMMAND BUFFER
;DSKUIO BIT ON INDICATES UDSKIO TYPE OPERATION
; DSKRCB BIT ON INDICATES RECALIBRATE OPERATION IN PROGRESS
;STATE OF DRIVE IS INDICATED BY DSKSIP AND DSKCMR BITS IN LH
; 00 - NOTHING HAPPENING
; 10 - DRIVE SEEKING TRACK
; 01 - DRIVE POSITIONED, TRANSFER READY TO BE STARTED
; 11 - TRANSFER IN PROGRESS (ALSO USED WHEN REQUEST BEING UNQUEUED)


; DISK-RELATED PARAMETERS

NTRACK=NTKUN*NPACKS ;EACH DRIVE CONSIDERED A GROUP OF TRACKS
MNTRCK==:-NTRACK		;MINUS FOR MACRO/LOADER, USED IN DSK.MAC
NSECPG==1000/NWSEC		;SECTORS PER PAGE
NSECTK==NSURFS*NSECS		;NUMBER OF SECTORS PER TRACK
NPGTK==NSECTK*NWSEC/1000	;NUMBER OF PAGES PER TRACK
NBWTK==<NPGTK+^D35>/^D36	;NUMBER OF WORDS OF BITS PER TRACK
NMINFP==NPGTK/3			;MIN PAGES FOR FREE CHOICE ASSMT
DSKNST==<<<<NDST+NPGTK-1>/NPGTK>+NPACKS-1>/NPACKS>*NPACKS
					;NUMBER OF TRACKS FOR SWAPPING
					;ROUNDED UP TO NEAREST TRACK
					;AND THEN UP TO NEAREST INTEGRAL
					;MULTIPLE OF NPACKS SO THAT WE GET
					;EQUAL NUMBER OF TRACKS PER PACK
					;AND TOTAL WILL HOLD AT LEAST
					;NDST PAGES
IFGE <MAXCOR-^D512>,<
NCRTRK==<MAXCOR+NPGTK-1>/NPGTK		;RESERVE SPACE FOR CORE DUMP
>

IFL <MAXCOR-^D512>,<
NCRTRK==<^D512+NPGTK-1>/NPGTK
>
MONTKS==<PPRMPG+200+NPGTK-1>/NPGTK	;NO. TRACKS FOR MON IMAGES


SWPTK==NTKUN/2-<DSKNST/NPACKS>/2	;FIRST TRACK FOR SWAPPING PER PACK
SWPTKH==SWPTK+<DSKNST/NPACKS>	;LAST TRACK +1 FOR SWAPPING PER PACK

;TABLE OF ADDRESSES OF START OF SWAP AREA ON EACH PACK
SWPADR:

QQ==SWPTK*NSECTK
	REPEAT NPACKS,<
	QQ
QQ==QQ+<NSECTK*NTKUN>
>

SWPSEC==<DSKNST*NSECTK>/NPACKS		;NO. SECTORS PER PACK FOR SWAPPING

;THE FOLLOWING PARAMETERS RESERVE THE VARIOUS AREAS OF THE DISK(S)

HITRK=NTRACK-MONTKS-NCRTRK		;UPPER LIMIT OF FILES AREA
LOTRK==0				;LOWER LIMIT OF FILES AREA

DSKRMA==<NTRACK-MONTKS-NCRTRK>*NSECTK	;RESIDENT MON IMAGE FOR RELOADING
DSKSMA==DSKRMA+PPRMPG*NSECPG		;SWAP MON IMAGE
DSKCMA==<NTRACK-NCRTRK>*NSECTK		;LOC OF CORE DUMP AREA


NGSP DSKFCT,<<NTRACK+<NTRACK*NBWTK>+777>/1000>	;PAGE ALIGNED
			;SPACE FOR BIT TABLE. FIRST NTRACK WORDS
			;ARE COUNTS OF NUMBER OF FREE PAGES PER TRACK
DSKBTB=:DSKFCT+NTRACK	;BIT TABLE

;STORAGE

LS DSKFCL,1		;FREE LIST FOR UDSKIO REQUEST PAIRS
LS DSKCCT,1		;COUNT OF UDSKIO REQUESTS
LS DSKCL,2*NDSKCM	;COMMAND BUFFER FOR UDSKIO REQUESTS
LS DSKLUN,1		;LAST UNIT XFERRING, -1 IF NO UNIT XFERRING
LS DSKCCM,2		;BUFFER FOR DF10 CHANNEL COMMAND

LS DSKQ,NDVMAX		;QUEUE FOR ALL SWAP IO REQUESTS

LS DSKUI,NDVMAX		;UTILITY QUEUE IN
LS DSKUO,NDVMAX		;UTILITY QUEUE OUT

LS DSKDAW,NDVMAX	;DISK ADDRESS FOR CURRENT OPERATION
LS DSKCAW,NDVMAX	;CORE ADDRESS AND COUNT FOR CURRENT OPERATION
LS DSKSTS,NDVMAX	;STATUS OF DRIVE,,CURRENT TRACK
			; SEE BIT DEFINITIONS IN LH, ABOVE.
LS DSKLSV,NDVMAX	;TIME WHEN CURRENT OPERATION IS OVERDUE

LS DSKPD1,NPD1+1	;LOCAL MAIN PDL

LS DSKSVR,1		;INTERRUPT SERVICE RETURN
LS DSKACP,1		;SAVED AC-P
LS DSKPDL,NDSKPD	;INTERRUPT PDL

;DO NOT REORDER ERROR WORDS, USED BY GETAB

NDSKEW==^D10		;NUMBER OF ERROR WORDS FOR GETAB

LS DSKRCE,1		;COUNT OF RECOVERABLE ERRORS
LS DSKRER,4		;COMMAND WORDS AND ERROR BITS OF LAST ERROR
LS DSKNRE,1		;COUNT OF NON-RECOVERABLE ERRORS
LS DSKLER,4		;COMMAND WORDS AND ERROR BITS LAST NON-REC ERR
IFDEF SSADF,<
NDSKEW==NDSKEW+5
LS DSKESB,5>		;MORE ERROR WORDS FOR SENSE BYTES
;END OF GETTAB

DSKNTR==^D5		;NUMBER OF TRIES ON RECOVERABLE ERRORS

UCMIPT:	POINT 5,DSKSTS(A),17	; POINTER TO UDSKIO COMMAND INDEX
ERRCPT:	POINT 6,DSKSTS(A),23	;POINTER TO ERROR RETRY COUNT
CTRKPT:	POINT 9,DSKSTS(A),32	; CURRENT TRACK

IFDEF SSADF,<			; FOLLOWING ONLY FOR DISKS ON SSA
; STORAGE FOR CHANNEL PROGRAMS AND STATUS

DEFINE DSKSTM(N)<
LS DP'N'SEN,6		; SENSE BYTES FROM DRIVE N
LS DP'N'SEK,3		; SEEK ARGUMENT FOR DRIVE N
LS DP'N'ESB,6		; SENSE BYTES WHEN A REAL ERROR OCCURS,
			;  NOT STATISTICS FOR EXAMPLE
>
ZZ==0
REPEAT NDVMAX,<
DSKSTM(\ZZ)
ZZ==ZZ+1>		; ALLOCATE SENSE AND SEEK AREAS FOR ALL DRIVES

LS DPDEVL,NDVMAX+1	; BLOCK MULTIPLEXOR DEVICE LIST
LS DPCHS,NDVMAX		; CHANNEL STATUS (161) AT LAST INTERRUPT
LS DPCPC,NDVMAX		; WORD COUNT AND CHANNEL PC AT LAST INTERRUPT
LS DPADR,NDVMAX		; CCW RESTART,,CORE ADDRESS OF PAGE
LS DSKCDC,NDVMAX	; COUNT OF CORRECTABLE DATA CHECKS PER DRIVE

;POINTERS AND CHANNEL PROGRAMS, PRE-COMPILED.

DEFINE PNTM2(SIZ,ADR,POS,N)<
	POINT SIZ,DP'N'ADR,POS>
DEFINE POINTM(SIZ,ADR,POS)<
ZZ==0
REPEAT NDVMAX,<	PNTM2(SIZ,ADR,POS,\ZZ)
ZZ==ZZ+1>
>
DPCYL:	POINTM(16,SEK,31)	; WHERE CYLINDER GOES IN SEEK ARG
DPSRF:	POINTM(16,SEK+1,15)	; WHERE SURFACE GOES IN SEEK ARG
DPREC:	POINTM(8,SEK+1,23)	; WHERE RECORD NUMBER GOES IN SEARCH ARG
DPSEC:	POINTM(8,SEK+2,7)	; WHERE ROT SECTOR GOES IN SET SECTOR
NBYTES==<NWSEC*^D36>/^D8	; BYTES IN A RECORD
DPKSEC:				; TABLE OF ARGS FOR SET SECTOR COMMAND
REPEAT NSECS,<
	EXP <200*<^D237+<NBYTES*<.-DPKSEC>>>/^D13440>
>

;NOW THE CHANNEL PROGRAMS THEMSELVES

;FIRST THE READ/WRITE COMMAND CHAIN

DEFINE CHCMAC(N)<
PCIB=0
IFDEF SSAMEA,<PCIB=4>	;INTERRUPT FLAG BIT IN DEVICE COMMAND WORD
DP'N'RWC:	BYTE(8)70,IC.SEK,I.DDEV+N,0	;SEEK CYLINDER
	BYTE (WCSZ)-6(ADSZ)DP'N'SEK		; ARG TO SEEK
	BYTE (8)<70+PCIB>,IC.SSC,I.DDEV+N,0	; SET SECTOR
	BYTE (WCSZ)-1(ADSZ)DP'N'SEK+2	; SECTOR NUMBER
DPOSIE==.-DP'N'RWC
	BYTE (8)71,IC.SIE,I.DDEV+N,0	; SEARCH ID EQUAL
	BYTE (WCSZ)-5(ADSZ)DP'N'SEK		; ARG TO SEARCH RECORD
	TCH+.-2				; KEEP ON SEARCHIN'
DPOOPC==.-DP'N'RWC			; OFFSET TO RD OR WRT COMMAND
	BYTE (8)<40+PCIB>,IC.RDD,I.DDEV+N,0	; READ DATA, OR WRITE DATA
					; THIS CELL MODIFIED AT RUNTIME
DPOADR==.-DP'N'RWC			; OFFSET TO DATA ADDRESS
	BYTE (WCSZ)-1000(ADSZ).-.		; ADDRESS WORD MODIFIED
DPOHLT==.-DP'N'RWC
	0				; END OF COMMAND LIST

DPOSNP==.-DP'N'RWC			; OFFSET TO SENSE PROGRAM
DP'N'SNP:	BYTE (8)70,IC.SNS,I.DDEV+N,0	; SENSE COMMAND
	BYTE (WCSZ)-^D24(ADSZ)DP'N'SEN	; WHERE TO STORE SENSE BYTES
	0				; END OF SENSE PROGRAM
>

ZZ==0					; NOW BUILD ALL THOSE
REPEAT NDVMAX,<
	CHCMAC(\ZZ)
ZZ==ZZ+1>

DPBAS:					; POINTER TO THOSE PROGRAMS
DEFINE DPBASM(N)<
	XWD DP'N'SNP,DP'N'RWC>
ZZ==0
REPEAT NDVMAX,<
	DPBASM(\ZZ)
	ZZ==ZZ+1
>

DPESB:				; POINTER TO ERROR SENSE BYTES
DEFINE DPBASM(N)<
	XWD 0,DP'N'ESB>
ZZ==0
REPEAT NDVMAX,<
	DPBASM(\ZZ)
	ZZ==ZZ+1
>

IFDEF SSAMEA,<
	LS SSATIM,NDVMAX	;TEMPORARY FOR HOLDING START TIME OF
				;A MEASUREMENT INTERVAL
;TIME ACCUMULATORS FOR READ OPS
	LS SSRQTM,NDVMAX	;TIME SPENT QUEUED
	LS SSRSEK,NDVMAX	;TIME SPENT SEEKING
	LS SSRSCH,NDVMAX	;TIME SPENT IN SET SECTOR AND SEARCH
	LS SSRTRN,NDVMAX	;TIME SPENT TRANSFERRING
	LS SSROPS,NDVMAX	;COUNT OF READ OPS
;TIME ACCUMULATORS FOR WRITE OPS
	LS SSWQTM,NDVMAX	;TIME SPENT QUEUED
	LS SSWSEK,NDVMAX	;TIME SPENT SEEKING
	LS SSWSCH,NDVMAX	;TIME SPENT IN SET SECTOR AND SEARCH
	LS SSWTRN,NDVMAX	;TIME SPENT TRANSFERRING
	LS SSWOPS,NDVMAX	;COUNT OF WRITE OPS
;POINTERS TO ABOVE TABLES
SSAQTM:	Z SSRQTM(A)
	Z SSWQTM(A)
SSASEK:	Z SSRSEK(A)
	Z SSWSEK(A)
SSASCH:	Z SSRSCH(A)
	Z SSWSCH(A)
SSAOPS:	Z SSROPS(A)
	Z SSWOPS(A)
> ;END SSA MEASUREMENT CONDITIONAL

> ;END OF SSADF CONDITIONAL

;THE FOLLOWING IS A PROTOTYPE GETAB TABLE

DSKPRO:	LOTRK
	HITRK
	NSECTK
	NWSEC
	NTKUN
	NPACKS
	SWPTK
	SWPTKH
DSKRML:	DSKRMA
DSKSML:	DSKSMA
DSKCML:	DSKCMA
	NHOME
QQ==0
HOMPRO:	REPEAT NPACKS,<
	<QQ>B17+<HOMCY1>B<^D17+NCYLBT>+<HOMSF1>B<^D17+NCYLBT+5>+HOMSC1
	<QQ>B17+<HOMCY2>B<^D17+NCYLBT>+<HOMSF2>B<^D17+NCYLBT+5>+HOMSC2
QQ==QQ+1
>
NHOME==.-HOMPRO

NDSKPR==.-DSKPRO

; THE FOLLOWING IS A GETAB TABLE COMPILED BY DSKINI AT START-UP

LS(DSKPAR,NDSKPR-NHOME)
LS(HOME,NHOME)	; MUST BE CONTIGUOUS WITH DSKPAR

;DEVICE DEPENDENT CONSTANTS AND ROUTINES
;SOME ARE CALLED WITH PUSHJ, OTHERS ARE SINGLE INSTRUCTIONS EXECUTED
;WITH XCT

IFDEF RP10F,<		;DEC RP02 AND RP03 DRIVES

DSOIRQ:	CONSO DSK,1B32		;CONSO DSK INTERRUPT REQUEST

DSKPWF:	CONO DSK,175700+1B32	;CONO IN CASE OF POWER FAIL
	JRST DSKSV1

DSZERR:	CONSZ DSK,177760	;CONSZ ERROR CONDITIONS

DCLERR:	CONO DSK,175700+1B32+DSKCHN ;CONO CLEAR ALL ERROR CONDITIONS

DCLDNF:	CONO DSK,1B32+DSKCHN	;CONO CLEAR DONE FLOP

DRATT:	DATAI DSK,0		;READ ATTENTIONS TO AC0, B28-35

DSKPOS:	MOVE B,DSKDAW(A)	;ISSUE POSITION (SEEK) REQUEST
	TLO B,(4B2)		;UNIT NUMBER IN AC1, DSK ADR IN DSKDAW(A)
	DATAO DSK,B
	RET

DSKRCL:	MOVSI B,(7B2)		;ISSUE RECALIBRATE (RESTORE) COMMAND
	DPB A,[POINT 3,B,5]
	DATAO DSK,B
	RET

DCLATT:	CALL DCLAT1		;INST. TO CLEAR ATTENTIONS FOR DRIVE IN A

DCLAT1:	MOVSI B,(5B2)
	DPB A,[POINT 3,B,5]
	IOR B,BITS+^D27(A)
	DATAO DSK,B
	RET

DCKSEK:	DATAI DSK,B		;CALLED TO CHECK SEEK COMPLETE
	TLNN B,(1B11)		;SKIP RETURN IF NO SEEK INCOMPLETE
	TLNN B,(1B12)		;NOT SEEK INCOMP. HEADS POSN'D?
	RET			;NOT READY.
	AOS 0(P)		;OK. READY TO RUN.
	RET

DCKRDY:	DATAI DSK,B		;CHECK READY. MUST BE ON LINE AND
	TLNE B,(1B13)		; HEADS POSITIONED.
	TLNN B,(1B12)		; ..
	TDZA B,B		;ONE OR BOTH OFF. RETURN 0
	SETO B,0		;OK. RETURN -1
	RET

DSZPCI:	TLNE 0,(1B14+1B16)	;SKIP NO PCI (GIVEN CONI BITS IN 0)

DSZSCF:	TRNE 0,1B21		;SKIP NO SEARCH FAILURE

DSZATN:	TDNE 0,BITS+^D27(A)	;SKIP IF ZERO ATTENTION

DUEATT:	RET			;UNEXPECTED ATTENTION (NOP FOR RP02)

;TEST EXISTENCE OF UNIT AND INIT

DIUNIT:	CALL DSKTOL		;UNIT ON LINE?
	JUMPE B,[SETOM DSKSTS(A) ;NO. STATUS FLAGGED AS -1
		 SETZM DSKLSV(A) ;AND NO COMPLETION TIME PENDING.
		 RET]
	MOVEI C,0(A)		;ON LINE. INITIALIZE IT.
	ROT C,-6		;CONSTRUCT RECALIBRATE COMMAND
	TLO C,(7B2)
	DATAO DSK,C		;ISSUE IT
	JFCL
DSKII2:	DATAI DSK,C		;CHECK STATUS OF DRIVE
	LDB B,[POINT 8,C,10]	;TRACK
	JUMPN B,DSKII2		;WAIT FOR TRACK 0
	TLNN C,(1B12)		;AND 'ON CYLINDER'
	JRST DSKII2
	MOVEI C,0(A)
	ROT C,-6
	TLO C,(5B2)		;CONSTRUCT CLEAR ATTENTIONS COMMAND
	IOR C,BITS+^D27(A)
	DATAO DSK,C		;ISSUE IT
	SETZM DSKSTS(A)		;CLEAR STATUS AND SET TRACK TO 0
	RET

;TEST FOR ONLINE UNIT. RETURN 0 IN B IF OFFLINE, -1 IF ON.

DSKTOL:	MOVSI C,(6B2)		;CONSTRUCT A NO-OP COMMAND
	DPB A,[POINT 3,C,5]	;FOR THIS DRIVE
	DATAO DSK,C		;ISSUE IT, SELECTING UNIT
	JFCL
	DATAI DSK,C		;GET BITS FOR THAT UNIT
	LDB B,[POINT 3,C,2]	;GET UNIT NUMBER AS REPORTED
	CAIE B,0(A)		;AGREES?
	BUG(HLT,<DSK - FAILED TO SELECT UNIT>)
	TLNN C,(1B15)		;NO SUCH UNIT? OR
	TLNN C,(1B13)		;NOT ON LINE?
	TDZA B,B		;NOT READY. RETURN 0.
	SETO B,0		;OK, RETURN -1
	RET

DMKHWA:	LSH B,^D12		;CONVERT LOGICAL H'WARE ADR TO ACTUAL
	RET			;H'WARE FORMAT

DSKWDA:	1B2+DSKCP			;WRITE DATA COMMAND BITS
DSKRDA:	0B2+DSKCP			;READ DATA COMMAND BITS
>	;END OF RP10 SECTION

IFDEF DC10F,<			;TELEFILE DC10 CONSTANTS AND ROUTINES

DSOIRQ:	JSP A,.+1		;CONSO DSK REQUESTING
	CONSZ DSK,640777	;ERRORS, DONE, OR ATTENTIONS?
	CONSZ DSK,1B20		;AND NOT BUSY?
	JRST 0(A)		;NO
	JRST 1(A)		;YES

DSKPWF:	CONO DSK,0		;POWER FAIL - CLEAR PI
	JRST DSKSV1

DSZERR:	TDNE 0,[XWD 73700,440000] ;TEST ERRORS, IGNORE EOC

DCLERR:	CALL DCLER1		;DO NOP, CLEARS ALL ERROR FLOPS

DCLER1:	JSP B,DWTCTL		;WAIT FOR CONTROL NOT BUSY
	MOVEI B,1(A)		;DEVICE ADDRESS IS 1+LOGICAL UNIT
	LSH B,^D9		;SHIFT TO POSITION FOR DATAO
;	IORI B,0B22		;NOP COMMAND
	DATAO DSK,B
	RET

DCLDNF:	CALL [	JSP B,DWTCTL	;CLEAR DONE FLAG
		DATAO DSK,ZERO## ;ANY DATAO DOES IT
		RET]

DRATT:	CONI DSK,0		;READ ATTENTIONS INTO 0

DSKPOS:	JSP B,DWTCTL		;WAIT FOR CONTROLLER
	MOVE B,DSKDAW(A)	;DSK AND CYLINDER
	IORI B,3B22		;SEEK COMMAND
	DATAO DSK,B
	RET

DSKRCL:	JSP B,DWTCTL		;WAIT FOR CONTROL
	MOVEI B,1(A)		;DEVICE ADDRESS
	LSH B,^D9		;SHIFT FOR DATAO
	IORI B,2B22		;RECALIBRATE (RESET) COMMAND
	DATAO DSK,B
	RET

DCLATT:	CALL DCLER1		;CLEAR ATTENTIONS AND SELECT DRIVE

DCKSEK:	CONI DSK,0		;GET SELECTED DRIVE STATUS
	TLNN 0,(1B13)		;CHECK SEEK INCOMPLETE
	AOS 0(P)
	RET

DSZPCI:	TLNE 0,(1B0+1B1)	;CHECK PCI

DSZSCF:	TLNE 0,(1B7+1B8+1B9)	;CHECK SEARCH FAILURE

DSZATN:	CALL [	MOVEI B,1	;SKIP IF ZERO ATTENTION
		LSH B,0(A)	;COMPUTE BIT FOR DRIVE
		TDNN 0,B
		AOS 0(P)
		RET]

DUEATT:	RET			;UNEXPECTED ATTN (E.G. POWER ON)

DMKHWA:	MOVEI B,0(B)		;CYL, SURF, AND SEC
	LSH B,^D35-ADRPOS	;SHIFT FOR DATAO
	DPB A,[POINT 4,B,26]	;DRIVE NUMBER
	ADDI B,1B26		;PLUS 1 FOR DRIVE ADDRESS
	RET

;WAIT FOR CONTROL NOT BUSY

DWTCTL:	CONSO DSK,1B20		;CTL BUSY
	JRST 0(B)
	AOS NCTBSY		;COUNT CURRANCES
	JRST DWTCTL

LS NCTBSY,1

DSKCYL:	POINT NCYLBT,DSKDAW(A),9	;POINTER TO CYL IN HDWR ADDRESS

DSKWDA:	6B22+DSKCP		;WRITE DATA COMMAND
DSKRDA:	4B22+DSKCP		;READ DATA COMMAND

;TEST UNIT FOR READY AND INIT

DIUNIT:	MOVEI C,1(A)		;UNIT ADDRESS
	LSH C,^D9
	CONO DSK,DSKCHN(C)	;SELECT IT
	CONI DSK,C		;GET DEVICE STATUS
	TLNE C,(1B12+1B15)	;OFF LINE OR WRITE INHIBIT?
	JRST [	SETOM DSKSTS(A)	;YES, SET STATE TO OFFLINE
		RET]
	CALL DSKRCL		;ISSUE RECAL
	MOVEI B,1		;COMPUTE BIT FOR DRIVE
	LSH B,0(A)
	CONSO DSK,0(B)		;WAIT FOR ATTN
	JRST .-1
	CONI DSK,C
	TLNE C,(1B13)		;SEEK INCOMPLETE?
	BUG(HLT,<DSKINI - SEEK INCOMPLETE ON RECAL>)
	MOVEI C,1(A)
	LSH C,^D9
	IOR C,DSKRDA		;CONSTRUCT READ
	DATAO DSK,C		;DO 1-WORD READ TO CLEAR ATTN
	CONSZ DSK,1B20		;WAIT FOR DONE
	JRST .-1
	CONSZ DSK,0(B)		;ATTN NOW GONE?
	BUG(HLT,<DSKINI - XFER FAILED TO CLEAR ATTN>)
	SETZM DSKSTS(A)		;SET STATUS TO READY
	RET
>			;END DC10 SECTION

IFDEF SSADF,<			; SSA AND 3330 CONSTANTS AND ROUTINES

; MAKE HARDWARE ADDRESS FROM PACKED HARDWARE ADDRESS.
; CALLED WITH 1/ DRIVE NUMBER IN RH, 2/ CYL.SURF.SECT IN RH, PACKED.

DMKHWA:	LDB C,[POINT NCYLBT,B,^D17+NCYLBT]	; GET CYLINDER
	DPB C,DPCYL(A)		; STORE IN SEEK ARGUMENT AREA
	LDB C,[POINT 5,B,^D35-NSECBT]	; HEAD (SURFACE) NUMBER
	DPB C,DPSRF(A)		; TO SEEK AND SEARCH ARG AREA
	LDB C,[POINT NSECBT,B,35]	; RECORD NUMBER
	ADDI C,1		; RECORDS ARE 1,2,3 NOT 0,1,2
	DPB C,DPREC(A)		; TO SEARCH ARGUMENT
	MOVE C,DPKSEC-1(C)	; GET ARG FOR SET SECTOR COMMAND
	DPB C,DPSEC(A)		; STORE.
	RET			; RETURN. 2 STILL AS CALLED, FOR DSKDAW

DSKPWF::CONO SSA,SA.PIE+<SSADC>B32+SSACHN	; NO MORE DISK INT'S
	RET

DSKCYL:	POINT 9,DSKDAW(A),26	; POINTER TO CURRENT CYLINDER

DIUNIT:	RET			; NOT DONE YET

> ; END OF SSA/3330 ROUTINES

;DISK I/O DRIVER - CALLED FROM SWAPPER

DSKIO:	SKIPG DISKP
	JRST DRMIO		;NO DISK, USE DRUM
	MOVEM P,DSKPD1		;SETUP LOCAL STACK
	MOVE P,[XWD -NPD1,DSKPD1]
	PUSH P,1
	MOVE D,CST1(A)		;GET DISK ADDRESS
	TLNN D,10		;REGULAR DISK ADDRESS?
	JRST [	PUSH P,1	;NO, MUST BE SWAPPING ADDRESS
		MOVE A,4
		CALL DSKIS	;CONVERT TO REGULAR DISK ADDRESS
		MOVE D,1
		POP P,1
		JRST DSKI7]
DSKI7:	PUSH P,1
	MOVE A,4		;DISK ADDRESS
	CALL CVDSK		;CONVERT TO HARDWARE FORMAT
	POP P,4
	LDB C,[POINT NCYLBT,A,17+NCYLBT]	;GET TRACK NUMBER
	TLO D,0(C)		;PUT IN LH OF LIST WORD
	HLRZ A,1		;GET DRIVE NUMBER FOR INDEX

IFDEF SSADF,<IFDEF SSAMEA,<
;RECORD TIME TASK WAS QUEUED
	MOVN C,TODCLK
	SETZ B,
	TLNE D,DWRBIT		;WRITE?
	 AOJ B,			;YES
	ADDM C,@SSAQTM(B)
	AOS @SSAOPS(B)
>> ;END SSA MEASUREMENT CONDITIONAL

	PIOFF			;MUST NOT INTERRUPT QUEUEING
	MOVEI C,CST3(D)		;ADD TO SWAP QUEUE
	EXCH C,DSKQ(A)
	HRRI D,0(C)
	MOVEM D,@DSKQ(A)
	PION
	SETO C,
	CAMN C,DSKSTS(A)	;DRIVE INITIALIZED?
	BUG(CHK,<DSKIO REQUESTED ON UNAVAILABLE DRIVE>)
IFNDEF SSADF,<			; CONTROLLER MUST BE FREE UNLESS BLOCK
				; MULTIPLEXER CHANNEL IN USE
	SKIPGE DSKLUN>		;TRANSFER NOW IN PROGRESS?
	CALL DSKRC		;NO, GO START THIS OPERATION
DSKIR:	POP P,1
	MOVE P,DSKPD1		;RESTORE CALLERS STACK
	RET

;IF SWAPPING TO DISK, DISK ADDRESS DISGUISED AS DRUM ADDRESS

DSKIS:	SKIPE DRUMP		;REALLY SWAPPING ON DISK?
	BUG(HLT,<DSKIO - BAD SWAP ADDRESS>)
	HRRZS B,1		;LINEARIZE 'DRUM' ADDRESS
	ANDI B,77		;SECTOR
	LSH A,-6		;BAND
	IMULI A,DRMSEC
	ADD A,2		;LINEAR PAGE NUMBER

; MAP CONSECUTIVE PAGES TO CONSECUTIVE DRIVES
	IDIVI A,NPACKS	;A=PACK-RELATIVE PAGE, B=UNIT
	IMULI A,NSECPG	;CONVERT TO SECTORS
	ADD A,SWPADR(B)	;GET ABSOLUTE LINEAR SECTOR



;MAKE SURE THAT COMPUTED SWAP ADDRESS IS NOT WITHIN THE FILES AREA
	MOVE B,A
	IDIVI B,NSECTK		;CONVERT BACKTO LINEAR TRACK
	IDIVI B,NTKUN		;PACK-RELATIVE TRACK TO AC3
	CAIL C,SWPTK
	CAIL C,SWPTKH
	 BUG (HLT,<SWAP ADDRESS IN FILES AREA>)

	RET

;PERIODIC CHECK OF DISK

DSKCHK:	MOVEI A,^D1000		;DO IT ONCE PER SEC.
	MOVEM A,DSKTIM
	MOVSI A,-NDVMAX
DSKCH3:	SKIPE B,DSKLSV(A)	;TIME SETUP ON THIS DRIVE?
	CAMLE B,TODCLK		;AND PAST DUE?
	JRST DSKCH1		;NO
	SETO B,
	CAME B,DSKSTS(A)	;DRIVE UNINITIALIZED?
	JRST DSKCH4		;NO
;	CALL DIUNIT		;YES, TRY TO INIT IT
	MOVE B,TODCLK
	ADDI B,^D10000
	SKIPL DSKSTS(A)		;WAS INIT SUCCESSFUL?
	SETZ B,			;YES, NO FURTHER CHECK
	MOVEM B,DSKLSV(A)	;OTHERWISE CHECK AGAIN IN 10SEC.
DSKCH1:	AOBJN A,DSKCH3		;LOOP THRU ALL DRIVES
	RET			;AND BACK TO SCHED BACKGROUND.

IFDEF DC10F,<		;TELEFILE CONTROLLER CAN'T BE CLEARED REASONABLY

DSKCH4:	BUG(HLT,<DISK OPERATION OVERDUE>)
	JRST DSKCH1>

IFNDEF DC10F,<	;FOR OTHER SYSTEMS, GIVE ERROR AND GO ON.
DSKCH4:
IFNDEF SSADF,<
	SKIPGE B,DSKLUN
	JRST DSKCH1		;NO DRIVE GOING. JUST A SEEK. IGNORE.
	CAIE B,0(A)		;ACTIVE DRIVE THE ONE THAT TIMED OUT?
	JRST DSKCH1		;NO. IGNORE.
>
	BUG(CHK,<DISK OPERATION OVERDUE>)
IFDEF SSADF,<
	MOVSI B,DSKCMR		;TRANSFER STILL GOING?
	TDNN B,DSKSTS(A)	; ..
	JRST DSKCH1		;NO.
	MOVSI B,DSKRTB		;YES. SEE IF ALREADY RESTARTED IT ONCE
	TDNE B,DSKSTS(A)	; ..
	JRST DSKCH5		;YES. IT IS SICK.
	CHNOFF DSKCHN		;NO. START IT, FREEZE STATUS WORD
	CALL DSKSVX		;TRY TO MAKE IT GO AGAIN
	MOVSI B,DSKRTB		;AND SET BIT SAYING RETRIED ONCE
	IORM B,DSKSTS(A)	; ..
	CHNON DSKCHN
	JRST DSKCH1		;WAIT AND SEE IF IT FAILS AGAIN
DSKCH5:> ;END SSADF COND
	MOVSI B,DSKUIO		;GIVE ERROR COMPLETION FOR REQUEST
	TDNE B,DSKSTS(A)	;IN PROGRESS
	JRST [	LDB C,UCMIPT	; UTILITY OP
		MOVEI B,-1	;RETURN -1 FOR NONSPECIFIC FAILURE
		MOVEM B,DSKCL+1(C)
		JRST DSKCH1]
	CHNOFF DSKCHN
	CALL DSKEP1		;PROCESS 'UNREC' ERROR
	CHNON DSKCHN
	JRST DSKCH1
>

;UTILITY DISK I/O
; AC1/ HARDWARE DISK ADDRESS
; AC2/ BIT 13 - WRITE HEADER, BIT 14 - WRITE, BIT 15 - COMPARE CLASS
;      BITS 16-24 - CLASS, BITS 26-35 WORD COUNT
; AC3/ REAL CORE ADDRESS
;RETURNS +1 WITH ERROR BITS IN AC1 24-35 (0 IF NO ERRORS)

UDSKIO:
UDSK3:
	TRNE B,1B25		;WORD COUNT USED TO BE IN BITS 25-35
	BUG(HLT,<UDSKIO: WORD COUNT MORE THAN 10 BITS>)
	SOSGE DSKCCT		;COMMAND BUFFER FULL?
	JRST UDSK1		;YES, GO WAIT FOR ROOM
	NOSKED
	MOVE D,@DSKFCL		;GET A COMMAND PAIR
	EXCH D,DSKFCL
	HRLZM A,0(D)		;STORE DISK ADDRESS IN LH OF FIRST WORD
	MOVEM C,1(D)		;PHYSICAL ADDRESS IN B16 - B35
	MOVEI C,0(D)		;GET THE ADDRESS OF THIS ENTRY
	SUBI C,DSKCL		;MAKE THE ADDRESS INTO AN INDEX NUMBER
	TLNE B,(1B14)		;READ OR WRITE?
	TROA C,600000B46	;WRITE
	TRO C,400000B46		;READ, B0 SET = NOT COMPLETE
	DPB C,[POINT 7,1(D),6]	;CONTROL BITS IN B0-B1, INDEX # IN B2-B6
; NOTE THAT THE LEAST SIGNIFICANT BIT OF THE INDEX NUMBER MUST ALWAYS
; BE ZERO, BECAUSE WE ARE USING TWO-WORD ENTRIES. THEREFORE, WE WILL
; OVERWRITE IT WITH THE WORD COUNT STORED BY THE NEXT INSTRUCTION.
	DPB B,[POINT 10,1(D),15]	;WORD COUNT TO BITS B6 - B15
	HLRZ A,1		;DRIVE NUMBER
	ANDI A,-1_<-<^L<NDVMAX-1>>>	;ISOLATE THE DRIVE NUMBER
	SETO C,
	CAMN C,DSKSTS(A)	;UNIT INITIALIZED?
	JRST [	MOVEI A,-1	;NO, RETURN FAILURE
		JRST UDSK4]

IFDEF SSADF,<IFDEF SSAMEA,<
	MOVN 0,TODCLK		;RECORD TIME TASK WAS QUEUED
	SETZ C,
	TLNE B,(1B14)		;WRITE?
	 AOJ C,			;YES
	ADDM 0,@SSAQTM(C)
	AOS @SSAOPS(C)
>> ;END SSA MEASUREMENT CONDITIONAL

	PIOFF
	HRRM D,@DSKUI(A)	;APPEND TO UTILITY QUEUE
	HRRZM D,DSKUI(A)
	PION
	PUSH P,4
IFNDEF SSADF,<			; WAIT UNLESS ON BLK MPXR CHAN
	SKIPGE DSKLUN>		;STARTUP POSSIBLE?
	CALL DSKRC		;YES
	POP P,4
	OKSKED
	MOVEI A,DISGET		;SCHEDULER .GE. TEST
	HRLI A,1(D)		;WILL TEST SECOND WORD OF PAIR
	JSYS SCHEDP
	NOSKED
	MOVE A,1(D)		;ERROR BITS RETURNED HEREIN
UDSK4:	EXCH D,DSKFCL		;RETURN PAIR TO FREE LIST
	MOVEM D,@DSKFCL
	AOS DSKCCT
	OKSKED
	RET

UDSK1:	PUSH P,1
	AOS DSKCCT		;CORRECT COUNT
	MOVEI A,UDSK2
	JSYS EDISMS		;DISMISS TILL ROOM IN COMMAND LIST
	POP P,1
	JRST UDSK3

UDSK2:	SKIPG DSKCCT		;ROOM NOW?
	JRST 0(D)		;KEEP WAITING
	JRST 1(D)		;RUN

;ENTRY TO DSKRCK AT NON-INTERRUPT LEVEL
; CALLED WITH DRIVE NUMBER IN RH OF 1

DSKRC:	MOVSI C,DSKSIP+DSKCMR
	CHNOFF DSKCHN
IFNDEF SSADF,<
	SKIPGE DSKLUN>		;CONTROL BUSY, OR
	TDNE C,DSKSTS(A)	;THIS DRIVE NOW DOING SOMETHING?
	JRST [	CHNON DSKCHN	;YES, LEAVE IT
		RET]
	CALL DSKRCK		;NO, GO GET IT GOING
	CHNON DSKCHN
	RET

; HERE FROM DSKRCK IF UTILITY QUEUE HAS STUFF TO DO

DSKRC3:	HRRZ B,0(B)		;UNQUEUE
	JUMPN B,.+3
	MOVEI C,DSKUO(A)	;FIXUP ON END
	MOVEM C,DSKUI(A)
	EXCH B,DSKUO(A)
	MOVSI C,DWRBIT+DSKUIO
	ANDCAM C,DSKSTS(A)	;BITS
	LDB C,[POINT 5,1(B),6]	;DSKCL INDEX
	ANDI C,36		;FORCE LOW BIT OF INDEX TO BE ZERO
	DPB C,UCMIPT		 ;WHERE INTERRUPT ROUTINE CAN GET
	LDB C,[POINT 10,1(B),15]	;WORD COUNT
	LSH C,<^D36-WCSZ>	;WORD COUNT LEFT ALIGNED IN LH
	MOVNM C,DSKCAW(A)	;TO LH OF CHANNEL WORD
	MOVE D,1(B)		;PHYSICAL ADDRESS AND BITS
	MOVSI C,DSKUIO		;SET UTILITY BIT IN ANY CASE
	TLNE D,200000		;AND IF WRITE,
	MOVSI C,DSKUIO+DWRBIT	;SET WRITE BIT TOO
	IORM C,DSKSTS(A)	;YES
IFLE ADSZ-^D18,<
	HRRM D,DSKCAW(A)>	;STORE 18 BIT PHYSICAL ADDRESS
IFG ADSZ-^D18,<
	TLZ D,(-1B15)		;ISOLATE A 20 BIT PHYSICAL ADDRESS
	IORM D,DSKCAW(A)>	;AND ADD IT TO THE CHANNEL COMMAND
	HLRZ B,0(B)		;DISK ADDRESS
	HRLI B,0(A)		;INCLUDE UNIT
	JRST DSKRC4

;ROUTINE TO REMOVE REQUESTS FOR READ AND WRITE QUEUES AND
;INITIATE SEEK OPERATIONS
;CALLED AT MAIN AND INTERRUPT LEVEL WITH DRIVE NUMBER IN 1
; ONLY IF CONTROL FREE, EXCEPT ON SSA/3330 WHERE JUST DRIVE MUST BE FREE

DSKRCK:	IORM C,DSKSTS(A)	;SET BITS TO INDICATE UNQUEUEING IN PROG
	SKIPE B,DSKUO(A)	;UTILITY QUEUE WAITING?
	JRST DSKRC3		;YES, IS FIRST PRIORITY
	SKIPN DSKQ(A)		;SWAP REQUESTS WAITING?
	JRST DSKRCC		;NO
;SWAP REQUESTS WAITING. APPLY ONE-WAY ELEVATOR ALGORITHM.
	MOVEI B,DSKQ(A)		;PTR TO QUEUE
	LDB C,CTRKPT		 ;CURRENT TRACK
	CALL TRKSCH		;FIND NEAREST .GE. TRACK
	JRST [	SETZ C,		;NONE .GE., SO RESET TO 0
		MOVEI B,DSKQ(A)	;AND TRY AGAIN
		CALL TRKSCH
		JRST DSKRCC	;NONE, ALL MUST HAVE BEEN FLUSHED
		JRST .+1]
DSKRC2:	SUBI B,CST3		;CONVERT BACK TO CORE PAGE NUMBER
	HLL B,CST3(B)		;GET WRITE AND CLASS INFO
	MOVSI C,DWRBIT+DSKUIO
	ANDCAM C,DSKSTS(A)	;CLEAR BITS
	MOVSI C,DWRBIT
	TLNE B,DWRBIT		;WRITE BIT ON?
	IORM C,DSKSTS(A)	;YES, PUT IT ON IN STATUS WORD
	MOVEI C,0(B)
	LSH C,^D9		;MAKE PAGE NUMBER INTO CORE ADDRESS
	TLO C,(-1000B<WCSZ-1>)	;WITH ONE PAGE WORD COUNT
	MOVEM C,DSKCAW(A)	;LEAVE IT FOR TRANSFER STARTUP
	PUSH P,A
	MOVE A,CST1(B)		;DISK ADDRESS
	TLNN A,(DSKABT)		;REGULAR?
	CALL DSKIS		;NO, SWAPPING. CONVERT
	CALL CVDSK		;CONVERT TO HARDWARE FORMAT
	MOVE B,A
	POP P,A
;FALL THRU

;FALLS THRU FROM ABOVE, ALSO FROM DSKRC3 (UDSKIO)

; AT THIS POINT, DRIVE NUMBER IS IN RH OF A, PACKED HARDWARE
;  ADDRESS IS IN RH OF 2.

DSKRC4:
IFDEF RP10F,<
	LDB C,[POINT 8,B,25]	;LOW 8 BITS OF CYL
	TRNE B,1B31		;THE NINTH ONE
	TRO C,400>
	CALL DMKHWA		;MAKE INTO HARDWARE FORMAT
	MOVEM B,DSKDAW(A)	;LEAVE FOR OTHER ROUTINES
	SETZ B,
	DPB B,ERRCPT		;CLEAR ERROR COUNT BEFORE SEEK
IFNDEF RP10F,<
	LDB C,DSKCYL>		;GET DESIRED CYLINDER
	LDB B,CTRKPT		 ;CYL DISK IS NOW AT
	DPB C,CTRKPT		;SET NEW CURRENT TRACK
IFNDEF SSADF,<			; FOR DRIVES NEEDING SEPARATE SEEK
				;  COMMANDS TO ATTAIN OVERLAPPING...
	CAMN B,3		;NOW AT DESIRED TRACK?
	JRST [	CONSO PI,1B<DSKCHN+^D20> ;YES, ON PI LEVEL?
		JRST DSKSVX	;NO, GO START TRANSFER
		MOVSI B,DSKSIP	;YES, SET STATE TO READY
		ANDCAM B,DSKSTS(A) ;TRANSFER WILL BE STARTED BEFORE DBRK
		RET]
	MOVSI B,DSKCMR		;CLEAR READY BIT
	ANDCAM B,DSKSTS(A)
	MOVE B,TODCLK
	ADDI B,^D5000		;SET OVERDUE TIME FOR SEEK AS 5 SEC
	MOVEM B,DSKLSV(A)	;FROM NOW
	JRST DSKPOS		;ISSUE SEEK AND RETURN
>
IFDEF SSADF,<

IFDEF SSAMEA,<
	MOVE C,TODCLK		; TASK BEING UNQUEUED, NOTE TIME
	MOVSI B,DWRBIT
	TDNE B,DSKSTS(A)	; WRITE?
	 AOJ B,			; YES
	ADDM C,@SSAQTM(B)
> ;END SSA MEASUREMENT CONDITIONAL

	JRST DSKSVX>		; JUST START THE OPERATION IN BLK MPXR.

DSKRCC:	MOVSI C,DSKSIP+DSKCMR
	ANDCAM C,DSKSTS(A)	;SET DRIVE TO IDLE STATE
	RET

;SCAN FOR BEST OP TO DO NEXT
; 2/ QUEUE TO SEARCH
; 3/ CURRENT TRACK
; FIND ANY PAGE ON CURRENT TRACK, OR CLOSEST PAGE .G. CURRENT TRACK

TRKSCH:	PUSH P,1
	PUSH P,[400000]		;USED TO REMEMBER BEST DIFFERENCE FOUND
	PUSH P,[0]		;REMEMBERS PTR TO BEST PAGE FOUND
	PUSH P,3		;CURRENT TRACK
TRKS1:	HRRZ C,0(B)		;2 ALWAYS HAS PTR TO PTR TO ITEM
	JUMPE C,TRKSD		;END OF LIST
	MOVEI A,0(C)
	SUBI A,CST3		;GET PAGE NUMBER
	MOVE D,CST0(A)
	TLNE D,(700B8)		;PAGE NOW IN USE?
	JRST [	HRRZ D,0(C)	;YES, CANCEL IO. UNQUEUE PAGE
		HRRM D,0(B)
		MOVSI D,(CORMB)
		IORM D,CST0(A)	;SET MODIFIED BIT
		PUSH P,2

IFDEF SSADF,<IFDEF SSAMEA,<
		MOVE D,TODCLK	;NOTE TIME OF UNQUEUING
		MOVEI C,(A)	;PAGE NUMBER TO C
		MOVE A,-4(P)	;GET BACK UNIT NUMBER
		MOVSI 2,DWRBIT
		TDNE 2,CST3(C) ;WRITE?
		 AOJ 2,		 ;YES
		ADDM D,@SSAQTM(2)
		MOVEI A,(C)	;PG NUMBER BACK TO A FOR CALL TO SWPDON
>> ;END SSA MEASUREMENT CONDITIONAL

		JSP D,SWPDON
		POP P,2
		JRST TRKS1]
	HLRZ C,0(C)		;GET TRACK
	ANDI C,7777
	SUB C,0(P)		;DIFFERENCE OF THIS AND CURRENT TRACK
	JUMPE C,TRKSS		;SAME TRACK, CAN'T BE ANY BETTER
	JUMPL C,TRKSN		;LOWER TRACK, NOT INTERESTED
	CAML C,-2(P)		;BEST DIFFERENCE?
	JRST TRKSN		;NO
	MOVEM C,-2(P)		;YES, SAVE DIFFERENCE
	MOVEM B,-1(P)		;SAVE PTR
TRKSN:	HRRZ B,0(B)		;CDR
	JRST TRKS1

TRKSD:	MOVE D,-2(P)
	CAIL D,400000		;FOUND ANY PAGE?
	JRST TRKSX		;NO
	MOVE B,-1(P)		;YES, GET PTR
TRKSS:	HRRZ C,0(B)		;UNQUEUE PAGE
	HRRZ D,0(C)
	HRRM D,0(B)
	MOVEI B,0(C)
	AOS -4(P)		;RETURN SKIP
TRKSX:	SUB P,BHC+3		;FLUSH TEMPS
	POP P,1
	RET

;DISK INTERRUPT SERVICE

IFNDEF SSADF,<
	INTERN DSKSV

DSKSV:	XWD DSKSVR,.+1
	XCT DSOIRQ		;DISK REQUESTING?
	JRST @DSKSVR		;NO
	MOVEM P,DSKACP		;SAVE AC
	MOVE P,[IOWD NDSKPD,DSKPDL] ;SET UP LOCAL STACK POINTER
	CONI DSK,0		;GET ALL BITS
	SKIPE PWRDWN		;PWR FAIL?
	JRST DSKPWF		;YES, CLEAR DSK
	SKIPGE A,DSKLUN		;WAS A DRIVE TRANSFERRING?
	JRST DSKSV2		;NO
	XCT DSZERR		;ERROR?
	JRST DSKERR		;YES

;VERIFY THAT DF10 REPORTS THE CORRECT NUMBER OF WORDS TRANSFERRED
	HRRZ B,DSKCAW(A)	;START ADDRESS OF TRANSFER
	HLRE C,DSKCAW(A)	;-COUNT
	MOVNS C			;COUNT
	ADDI B,-1(C)		;B=COMPUTED ENDING ADDRESS
	HRRZ C,DSKCP+1		;ACTUAL ENDING ADDRESS REPORTED BY DF10
	CAME B,C		;SAME?
	BUG (HLT,<INCORRECT NUMBER OF WORDS TRANSFERRED BY DISK>)
DSKSV7:	MOVSI B,DSKSIP+DSKCMR	;XFER FINISHED
	ANDCAB B,DSKSTS(A)	;SO CLEAR ALL BITS FOR THAT DRIVE
	SETZM DSKLSV(A)		;RESET OVERDUE ALARM
	TLNE B,DSKUIO		;UTILITY OP?
	JRST DSKSVU		;YES
	HRRZ A,DSKCAW(A)	;GET CORE ADDRESS JUST FINISHED
	LSH A,-^D9		;PAGE NUMBER
	JSP D,SWPDON		;NOTE XFER COMPLETED
DSKSV2:	XCT DRATT		;READ ATTENTION BITS INTO AC0, B28-35
	MOVSI A,-NDVMAX
DSKSV6:	MOVSI C,DSKSIP+DSKCMR
	XCT DSZATN		;SEEK COMPLETE ON THIS DRIVE?
	JRST DSKSV4		;YES
	TDNN C,DSKSTS(A)	;THIS DRIVE FREE?
	CALL DSKRCK		;YES, SEE IF ANY WAITING REQUESTS
				; THIS WILL SET STATE TO "READY", AND
				; WILL START SEEKS, BUT WILL NOT START
				; DATA TRANSFER SINCE CALLED ON PI LEVEL
DSKSV5:	AOBJN A,DSKSV6		;CHECK ALL DRIVES
	AOS A,DSKLUN		;START WITH NEXT UNIT, OR 0 IF NONE
	HRLI A,-NDVMAX		; FIND A DRIVE TO START DATA XFR ON
DSKSV3:	MOVEI B,0(A)
	CAIL B,NDVMAX
	HRRI A,0		;WRAPAROUND DRIVE NUMBER
	MOVE C,DSKSTS(A)
	TLNE C,DSKCMR		;COMMAND READY AND NO SEEK IN PROGRESS?
	TLNE C,DSKSIP
	JRST [	AOBJN A,DSKSV3	;NO, CHECK NEXT DRIVE
		SETOM DSKLUN	;ALL DRIVES CHECKED, NONE XFERRING
		XCT DCLDNF	;CLEAR DONE FLAG
		 IFDEF DC10F,<
		 XCT DSOIRQ	;NEW ATTENTIONS APPEARED?
		 JRST DSKSV1	;NO
		 JRST DSKSV2>	;YES, MUST SERVICE NOW CAUSE PI CLRD
		JRST DSKSV1]	;GO DEBREAK
	SETZ B,			; THIS DRIVE READY TO START DATA XFR
	DPB B,ERRCPT		;CLEAR ERROR COUNT
	CALL DSKSVX		;START TRANSFER
DSKSV1:	MOVE P,DSKACP		;RESTORE AC-P
	UNBRK DSK		;DEBREAK
>		; END OF NON-SSA INT ROUTINE (FIRST LEVEL)

;ROUTINE TO START XFER ON READY DRIVE
;CALLED HERE ON BOTH PROCESS AND INTERRUPT LEVELS

IFNDEF SSADF,<
DSKSVX:	MOVSI C,DSKSIP+DSKCMR
	IORB C,DSKSTS(A)	;SET STATE TO XFER IN PROGRESS
	MOVE B,TODCLK
	ADDI B,^D1000		;SET OVERDUE ALARM FOR 1 SEC.
	MOVEM B,DSKLSV(A)
	MOVE B,DSKCAW(A)	;CORE ADDRESS AND COUNT
	HRRI B,-1(B)		;LIKE IOWD, ADDRESS IN 1 LESS
	MOVEM B,DSKCCM		;FIXED LOCATION FOR CHANNEL COMMAND
	MOVE B,DSKDAW(A)	;DISK ADDRESS
	TLNE C,DWRBIT		;READ OR WRITE?
	TDOA B,DSKWDA		;WRITE, CONSTRUCT COMMAND
	TDO B,DSKRDA		;CONSTRUCT READ COMMAND
	PIOFF
	DATAO DSK,2		;START XFER
	HRRZM A,DSKLUN		;REMEMBER NUMBER OF DRIVE XFERRING
	PION
	RET
>

IFDEF SSADF,<

; CALLED HERE FROM SSASRV WHEN SSA INTERRUPTS ON SUBCHANNEL SSADC .
; A/ DEVICE NUMBER
; B/ SSADC
; C/ SSABAS+4*SSADC
; D/ CHANNEL STATUS WORD A, FROM 1(C)

DSKSV::	SUBI A,I.DDEV		;CONVERT TO LOCAL INDEX
	CAIL A,0		; SEE IF IN RANGE
	CAIL A,NPACKS		; ..
	JRST DSVXT1		; NO. DISMISS (MIGHT BUGCHK HERE)

IFDEF SSAMEA,<
	TLNN D,(SS.PIF)		; PROGRAM REQUESTED INTERRUPT?
	 JRST DSKSV9		; NO
	PUSH P,E
	HRRZ 0,2(C)		; GET ADDRESS OF COMMAND FOLLOWING THE
				; ONE WHICH REQUESTED THE INTERRUPT
	HRRZ E,DPBAS(A)		; GET ADDRESS OF CHANNEL PROG FOR THIS 
				; DEVICE
	SUBI 0,0(E)		; 0=OFFSET TO COMMAND FOLLOWING 
				; REQUESTING COMMAND
	CAIN 0,DPOSIE		; PC POINT TO SEARCH? IF SO, INTERRUPT
				; REQUESTED BY SET SECTOR
	 JRST DSKSKE		; YES
	CAIE 0,DPOHLT		; PC POINT TO HALT? IF SO, INTERRUPT
				; REQUESTED BY READ OR WRITE.
	  JRST DSKME1		;REPORT UNIDENTIFIABLE PCI

	MOVE E,DSKSTS(A)	;MAKE SURE WE WERE EXPECTING THIS 
	TLC E,DSKSCH		;INTERRUPT
	TLNE E,DSKSEK+DSKSCH+DSKTRN
	 JRST DSKME2		;REPORT ERROR
	TLO E,DSKTRN		;INDICATE NOW TRANSFERRING
	MOVEM E,DSKSTS(A)
	MOVE 0,TODCLK
	SUBM 0,SSATIM(A)	
	EXCH 0,SSATIM(A)	; 0= TIME SPENT SEARCHING
	MOVSI E,DWRBIT
	TDNE E,DSKSTS(A)	; WRITE?
	 AOJ E,			; YES
	ADDM 0,@SSASCH(E)	; ACCUMULATE SEARCH TIME
DSKME4:	POP P,E
	JRST DSVXT1		; DEBRK

;HERE ON DETECTING INVALID CONDITION WHILE SERVICING A PCI INTERRUPT
DSKME1:	BUG (NTE,<UNIDENTIFIABLE PROGRAM REQUESTED INTERRUPT>)
	JRST DSKME
DSKME2:	BUG (NTE,<INVALID SEARCH TIME MEASUREMENT INTERRUPT>)
	JRST DSKME
DSKME3:	BUG (NTE,<INVALID SEEK TIME MEASUREMENT INTERRUPT>)
DSKME:	MOVSI E,DSKSEK+DSKSCH+DSKTRN
	ANDCAM E,DSKSTS(A)
	JRST DSKME4		;DEBRK WITH ALL BITS CLEAR


; HERE ON INTERRUPT FOLLOWING COMPLETION OF SEEK
DSKSKE:	MOVE E,DSKSTS(A)	;MAKE SURE WE WERE EXPECTING THIS
	TLC E,DSKSEK		;INTERRUPT
	TLNE E,DSKSEK+DSKSCH+DSKTRN
	 JRST DSKME3		;REPORT ERROR
	TLO E,DSKSCH		;INDICATE NOW SEARCHING
	MOVEM E,DSKSTS(A)
	MOVE 0,TODCLK
	SUBM 0,SSATIM(A)
	EXCH 0,SSATIM(A)
	MOVSI E,DWRBIT
	TDNE E,DSKSTS(A)	; WRITE?
	 AOJ E,		; YES
	ADDM 0,@SSASEK(E)
	POP P,E
	JRST DSVXT1		; DEBRK
> ;END SSA MEASUREMENT CONDITIONAL

DSKSV9:	LSH D,-^D20		; OK. GET THE CHANNEL AND DEVICE STATUS
	CAIN D,0B27+ID.CHE+ID.DVE ; CHECK FOR THE NORMAL CASE FIRST
	JRST DSKSV7		; OK. GO DO COMPLETION ACTION
	TRNE D,ID.UCK		; NOT NORMAL. SEE WHAT IT IS. UNIT CHK?
	JRST DSVUCK		; YES. GO DO SENSE OP.
	TRNE D,ID.BSY		; REJECTED DUE TO BUSY?
	JRST DSVBSY		; YES.
	TRNE D,ID.CUE		; CONTROL UNIT END?
	JRST DSVCUE		; YES. CU END, NO BUSY.
	TRNE D,<<SS.SER!SS.BIP!SS.CSE!SS.PIF!SS.LNE>_<-^D20>>!ID.ATN!ID.UEX
	JRST DSVXT2		; NO GOOD. TRY TO RESTART IT.
	TRNE D,ID.DVE		; DEVICE END ALONE?
	JRST DSVDVE		; YES. ASYNCHRONOUS, PROBABLY.
				; CHANNEL END OR NOTHING AT ALL. IGNORE.
DSVXT1:	CONO SSA,SA.STS!<SSADC>B32!SSACHN	; CLEAR INT REQ FLAG
	POPJ P,0		; RETURN TO SSASRV

DSVXT2:	BUG(CHK,<DSK - BAD STATUS BITS>)
DSVXT3:	MOVE B,DSKSTS(A)	; SEE IF IT WAS GOING BEFORE
	TLNN B,DSKSIP!DSKCMR
	 JRST DSVXT1		;NO, JUST DISMISS
DSVXT4:
IFDEF SSAMEA,<	MOVSI 4,DSKSEK+DSKSCH+DSKTRN
	ANDCAM 4,DSKSTS(A)	;RESET MEASUREMENT STATE BITS
> ;END SSA MEASUREMENT CONDITIONAL
	PUSHJ P,DSKSVX		;YES. RESTART IT.
	JRST DSVXT1		; AND GO DISMISS THIS INT.

;HERE ON DEVICE END ALONE

DSVDVE:	MOVE B,DSKSTS(A)	; SEE WHAT THIS DRIVE HAD BEEN UP TO
	CAMN B,MINUS1##
	JRST DSVDV1		; WAS OFF LINE. JUST CAME ON.
	TLNN B,DSKBSB		; WAS IT BUSY BEFORE?
	JRST DSKSV2		; NO. RESTART IF NEEDED, ELSE IGNORE.
	MOVSI B,DSKBSB		; YES. CLEAR BUSY BIT,
	ANDCAM B,DSKSTS(A)	; ..
	JRST DSVXT3		; RESTART IF NEEDED, DISMISS.

DSVDV1:	SETZM DSKSTS(A)		; MARK DRIVE UP AND IDLE
	JRST DSKSV2		; AND DISMISS THIS INTERRUPT

;NORMAL COMPLETION OR SENSE DONE

DSKSV7:	MOVSI B,DSKBSB		; CLEAR "BUSY BEEN SEEN" BIT
	ANDCAB B,DSKSTS(A)	; AND PICK UP STATUS
	TLNE B,DSKSNB		; SENSE COMPLETED AFTER UNIT CHECK?
	JRST DSVSND		; YES. GO LOOK AT SENSE DATA
DSKSV8:				; BACK HERE AFTER CORRECTING DATA CKS
	MOVSI B,DSKSIP!DSKCMR!DSKSNB ; CLEAR BUSY AND SENSE BITS
	ANDCAB B,DSKSTS(A)	; ..

IFDEF SSAMEA,<
;MAKE SURE WE WERE EXPECTING THIS INTERRUPT
	TLC B,DSKTRN		
	TLNE B,DSKSEK+DSKSCH+DSKTRN
	 BUG (HLT,<INVALID TRANSFER TIME MEASUREMENT INTERRUPT>)
	MOVEM B,DSKSTS(A)
	MOVE D,TODCLK		; NOTE TIME TRANSFER COMPLETED
	SUB D,SSATIM(A)
	TLNE B,DWRBIT		; WRITE?
	 JRST [ADDM D,SSWTRN(A)	; YES
		JRST .+2]
	ADDM D,SSRTRN(A)
> ;END SSA MEASUREMENT CONDITIONAL

	SETZM DSKLSV(A)		; NO LONGER WAITING FOR COMPLETION
	TLNE B,DSKUIO		; DSKUIO TYPE OP?
	JRST DSKSVU		; YES. GO COMPLETE IT.
	PUSH P,A		; SAVE UNIT NUMBER
	MOVE A,DSKCAW(A)	; PAGE BEING TRANSFERRED
	TLZ A,(-1B<^D35-ADSZ>)	; ISOLATE THE ADDRESS FIELD
	LSH A,-11		; JUST PAGE, NOT ADDRESS
	JSP D,SWPDON		; CALL SWAPPER FOR COMPLETION
	POP P,A			; GET BACK DRIVE NUMBER
DSKSV2:	MOVSI C,DSKSIP!DSKCMR	; SEE WHAT ELSE TO DO ON THIS DRIVE
	PUSHJ P,DSKRCK		; ..
	JRST DSVXT1		; AND DISMISS THE INTERRUPT

DSKSVU:	TDZA 0,0		; NO ERRORS
DSKUER:	MOVEI 0,4000		; ERRORS NOT ENCODED YET ON 3330'S
	LDB C,UCMIPT		; FIND PLACE IN DSKUIO COMMAND LIST
	MOVEM 0,DSKCL+1(C)	; STORE FINAL STATUS
	AOS PSKED		; SIGNAL SCHEDULER ON PAGE COMPLETION
	JRST DSKSV2		; NEXT ACTION ON DRIVE, DISMISS INT.

;HERE WHEN SENSE DONE ON A DRIVE

DSVSND:	MOVSI D,(3B1)		; BACK TO BMX MODE
	HRRI D,DPDEVL
	MOVEM D,SSABAS+4*SSADC
	CONO SSA,SA.GOF+SA.SET+<SSADC>B32+SSACHN
	HLRZ D,DPBAS(A)		; SENSE PROGRAM START
	HRRZ B,1(D)		; SENSE DATA STORAGE
	MOVE D,0(B)		; FIRST WORD OF SENSE INFO
	LSH D,-20		; KEEP TOP 2 AND A HALF BYTES
	CAIN D,100004		; CORRECTABLE DATA CHECK?
	JRST DSVCDC		; YES.
	CAIN D,1		; STATISTICS?
	JRST DSVXT4		; YES. IGNORE FOR NOW
	TLNN D,3		; INTERV REQUIRED?
	JRST DSVSD1		; NO
	BUG (CHK,<DISK OFF LINE OR WRITE PROTECTED>)
	JRST DSVXT3		; RESTART IF NEEDED
DSVSD1:
REPEAT 0,<
	TRNE D,4332		; PERM ERR, BAD PACK, ETC.
	JRST DSKERP		; YES. PERMANENT ERROR HANDLER
>
	JRST DSKERR		; RETRY THIS ERROR

DSVUCK:	MOVSI B,DSKSNB		; SENSE REQUEST.
	TDNE B,DSKSTS(A)	; ALREADY ONE?
	BUG (CHK,<UNIT CHECK ON DISK SENSE>)
	IORM B,DSKSTS(A)	; REQUEST SENSE, FLAG IT.
	HLRZ D,DPBAS(A)		; SENSE PROGRAM STARTS HERE
	HRRZ B,1(D)		; CLOBBER OLD SENSE BYTES
	SETOM 0(B)		; ..
	HRLI D,(TCH)		; NON BMX MODE FOR SENSE
	MOVEM D,SSABAS+<4*SSADC>
	CONO SSA,SA.GOF!SA.SET!<SSADC>B32!SSACHN
	JRST DSVXT1		; START SENSE AND DISMISS.

DSVBSY:	TRNE D,ID.CUE!ID.DVE	; BUSY. ANY ENDS COME WITH IT?
	JRST DSVXT4		; YES. RETRY, CLEAR BUSY, DISMISS.
	MOVSI B,DSKBSB		; NO. FLAG BUSY SEEN,
	IORM B,DSKSTS(A)	; ..
	JRST DSVXT1		; AND WAIT FOR AN END

DSVCUE:	MOVSI A,-NPACKS		;CONTROL UNIT END. RESTART PACKS WITH
DSVCU1:	MOVSI B,DSKBSB		; BUSY ON IN STATUS WORD.
	TDNN B,DSKSTS(A)	; THIS ONE BEEN STOPPED WITH BUSY?
	JRST DSVCU2		; NO.
	ANDCAM B,DSKSTS(A)	; YES. CLEAR THE BIT,
	PUSHJ P,DSKSVX		; AND RESTART THE TRANSFER
DSVCU2:	AOBJN A,DSVCU1		; LOOP THRU ALL DRIVES.
	JRST DSVXT1		; ALL RESTARTED. SO DISMISS INT.

;ERROR ROUTINES

;DSKERS IS ERROR SUBROUTINE CALLED TO COUNT ERRORS, MOVE ERROR WORDS.
; CALL WITH DRIVE IN A, POINTER TO SENSE DATA IN B

DSKERS:	MOVE C,DSKCAW(A)	; THE CORE ADDRESS
	MOVEM C,DSKRER
	MOVE C,DSKDAW(A)	; PACKED HARDWARE ADDRESS
	MOVEM C,DSKRER+1
	MOVE C,DSKSTS(A)	; STATUS WORD
	MOVEM C,DSKRER+2
	MOVE C,0(B)		; FIRST WORD OF SENSE DATA
	DPB A,[POINT 4,C,35]	; WITH DRIVE NUMBER IN LOW 4 BITS
	MOVEM C,DSKRER+3	; SAVE IT
	PUSH P,B
	MOVSI C,0(B)		; COPY TO ERROR AREA
	HRR C,DPESB(A)
	MOVEI B,5(C)
	BLT C,0(B)
	POP P,B
	AOS DSKRCE		; COUNT RECOVERABLE ERRORS
	POPJ P,0		; RETURN FROM DSKERS

DSKERR:	PUSHJ P,DSKERS		; STORE ERROR WORDS
	LDB C,ERRCPT		; GET THE ERROR COUNT
	ADDI C,1		; COUNT IT UP
	DPB C,ERRCPT		; ..
	CAIG C,DSKNTR		; TOO MANY RETRIES?
	JRST DSVXT4		; NO, TRY IT AGAIN, SAM.
DSKERP:	SETZM DSKLSV(A)		; PERMANENT ERROR. CLEAR WAIT TIME.
	PUSHJ P,DSKERS		; COPY ERR WORDS (IN CASE CALLED DSKERP)
	AOS DSKNRE		; COUNT NON-RECOVERABLE ERRORS
	MOVE C,[DSKRER,,DSKLER]
	BLT C,DSKLER+3		; COPY TO PERM ERROR MEMORY AREA
	MOVSI C,1(B)
	HRRI C,DSKESB		; COPY THE REST OF THE SENSE BYTES
	BLT C,DSKESB+4		; ..
	MOVNI C,DSKNTR
	ADDM C,DSKRCE		; COUNT DOWN RECOV ERRS
	MOVSI C,DSKUIO		; UTILITY OP?
	TDNE C,DSKSTS(A)	; ..
	JRST DSKUER		; YES. DIFFERENT COMPLETION ACTION
	PUSHJ P,DSKEP1		; FILESYSTEM COMPLETION ON ERROR
	JRST DSKSV2		; TRY SOMETHING ELSE.

DSVCDC:	AOS DSKCDC(A)		; COUNT CORRECTABLE DATA CHECKS PER DRV
	LDB C,[POINT 8,3(B),31]	; FIRST MAKE SURE A PAGE WAS READ
	MOVE D,4(B)		; ..
	LSHC C,^D16		; LENGTH IN BYTES OF TRANSFER
	HRRZ D,DSKCAW(A)	; AND MAKE SURE PAGE-ALIGNED
	TRNN D,777		; (MAY FAIL IN RLRMON)
	CAIE C,4400		; ONE PAGE?
	JRST DSKERR		; NOT NORMAL CASE. RETRY.
	PUSHJ P,DSKERS		; COUNT ERROR, MOVE SENSE BYTES
	MOVE D,5(B)		; GET THE ERROR PATTERN
	TRZ D,7777		; THREE BYTES TO XOR IN
	LDB B,[POINT 16,4(B),31] ; POSITION FROM END
	CAIGE B,3		; THE CHECK FOR ERRS IN CORRECTION BYTES
	TDZ D,[377B23]		; WHICH HAVE TO BE MASKED OUT
	CAIGE B,2		; ..
	TLZ D,(377B15)
	CAIGE B,1
	TLZ D,(377B7)		; (ERROR ENTIRLY IN CORRECTION BYTES!)
	MOVNS B			; NOW COUNT FROM START TO ERR
	ADDI B,4400		; ..
	IDIVI B,11		; B GETS WORD PAIRS, C GETS BYTES TO ERR
	IMUL C,[-10]		; FOR SHIFT TO ERR POSITION
	ADDI B,(B)		; WORDS, NOT WORD PAIRS
	CAMLE C,[-^D36]		; ERROR ALL BEYOND FIRST WD OF PAIR?
	JRST .+3		; NO.
	  ADDI B,1		; YES. COUNT UP A WORD
	  ADDI C,^D36		; AND SHIFT 36 LESS BITS
	PUSH P,5		; MAKE WORD PAIR OF ERROR IN 4 AND 5
	MOVEI 5,0		; ..
	LSHC D,(C)		; MOVE THE ERROR BITS AROUND
	MOVE C,DSKCAW(A)	; GET CORE ADDRESS OF PAGE
	TLZ C,(-1B<^D35-ADSZ>)	; ISOLATE THE ADDRESS FIELD
	LSH C,-11		; CORE PAGE NUMBER (REAL CORE)
	TRNE B,1		; ODD NUMBER WORD OF TRANSFER?
	ROT D,4			; YES. BYTE PACKING DIDDLE
	SKIPE D			; DON'T CLEAR AR'S IF NOT NEEDED
	PUSHJ P,XRMRCA##	; XOR IN THE ERROR PATTERN
	ADDI B,1		; NOW THE SECOND WORD OF ERRORS
	MOVE D,5		; SECOND GROUP OF ERROR BITS
	TRNE B,1		; IF ODD WORD,
	ROT D,4			; MOVE AROUND FOR PACKING MODE
	SKIPE D			; IF ANY ERRORS IN THIS WORD,
	PUSHJ P,XRMRCA		; CORRECT THEM
	POP P,5			; RESTORE STACK
DSCDCX:	JRST DSKSV8		; CORRECTED. GO FINISH UP

>	; END OF SSA INTERRUPT LEVEL CODE

;ROUTINE TO START XFER ON READY DRIVE
;CALLED HERE ON BOTH PROCESS AND INTERRUPT LEVELS

IFDEF SSADF,<
DSKSVX:	MOVSI C,DSKSIP!DSKCMR	; SET STATE TO TRANSFER IN PROG
	IORM C,DSKSTS(A)	; AND PICK UP STATE WORD
	MOVSI C,DSKSNB!DSKBSB!DSKRTB	; CLEAR THESE
	ANDCAB C,DSKSTS(A)	; AND PICK UP STATUS IN 3
	MOVE B,TODCLK		; SET OVERDUE ALARM TO COVER SEEK AND 
	ADDI B,^D10000		;  DATA TRANSFER TIME
	MOVEM B,DSKLSV(A)	; ..
	HRRZ D,DPBAS(A)		; CHANNEL PROGRAM FOR THIS DRIVE
	MOVE B,DSKCAW(A)	; GET THE CHANNEL COMMAND
	TLZ B,(-1B<WCSZ-1>)	; ZERO THE WORD COUNT FIELD
	TLO B,(-1000B<WCSZ-1>)	; SET THE WORD COUNT TO ONE PAGE
	MOVEM B,DPOADR(D)	; MODIFY THE DATA CHAIN WORD
	MOVEI B,IC.RDD		; READ DISK OPCODE
	TLNE C,DWRBIT		; UNLESS WRITE REQUESTED,
	MOVEI B,IC.WRD		; WRITE DISK OPCODE
	DPB B,[POINT 8,DPOOPC(D),15]	; TO CHANNEL READ/WRITE PROGRAM
	MOVEI B,I.DDEV(A)	; PUT IN DEVICE NUMBER
IFE SA10BF,<
	HRLI D,(<BMX.S>B7)	; MAKE BMX START WORD
	DPB B,[POINT 8,D,15]>	; PUT IN DEVICE NUMBER
IFN SA10BF,<
	HRLI D,(<BMX.S>B15)
	DPB B,[POINT 8,D,7]>	; PUT IN DEVICE NUMBER
	MOVEM D,DPDEVL(A)	; STORE IN DEVICE LIST
	MOVSI D,(3B1)		; RESET START WORD TO BMX TYPE,
	HRRI D,DPDEVL		; IN CASE SENSE NOT FINISHED PROPERLY
	MOVEM D,SSABAS+4*SSADC	; TO LOW CORE START ADDRESS
	CONO SSA,SA.GOF+SA.SET+<SSADC>B32+SSACHN	; START I/O
	HRRZM A,DSKLUN		; THIS UNIT GOING

IFDEF SSAMEA,<
	MOVE D,TODCLK		; NOTE TIME SEEK BEGAN
	MOVEM D,SSATIM(A)
	MOVSI D,DSKSEK+DSKSCH+DSKTRN ;BE SURE ALL BITS OFF
	TDNE D,DSKSTS(A)
	 CALL DSKSVE
	MOVSI D,DSKSEK		;INDICATE SEEKING
	IORM D,DSKSTS(A)
> ;END SSA MEASUREMENT CONDITIONAL

	RET

IFDEF SSAMEA,<

DSKSVE:	BUG (NTE,<INVALID MEASUREMENT STATE WHEN STARTING DSK OP>)
	ANDCAM D,DSKSTS(A)	;TURN ALL OFF
	RET
> ;END SSA MEASUREMENT CONDITIONAL

> ; END OF SSA VERSION OF DSKSVX

IFNDEF SSADF,<
;FOUND ATTN BIT FOR DRIVE

DSKSV4:	XCT DCLATT		;CLEAR ATTENTIONS
	MOVSI C,DSKSIP
	XOR C,DSKSTS(A)
	TLCE C,DSKSIP+DSKCMR	;WAS SEEK IN PROGRESS?
	JRST DSKSC1		;NO
	TLNE C,DSKRCB		;WAS RECALIBRATE COMMAND?
	JRST [	MOVSI C,DSKRCB	;YES, CLEAR BIT
		ANDCAM C,DSKSTS(A)
		CALL DSKPOS	;ISSUE NEW SEEK COMMAND
		JRST DSKSV5]
	CALL DCKSEK		;SKIP NO SEEK INCOMPLETE
	JRST DSKSKE
DSKSK1:	MOVSI C,DSKSIP+DSKCMR
	XORM C,DSKSTS(A)	;CHANGE STATE TO COMMAND READY
	JRST DSKSV5

DSKSC1:	TLNE C,DSKSIP+DSKCMR	;WAS IN COMMAND READY STATE?
	CALL DUEATT		;NO, UNEXPECTED
	JRST DSKSV5		;IGNORE IT

DSKSKE:	LDB C,ERRCPT		;GET RETRY COUNT
	ADDI C,1
	CAILE C,DSKNTR		;UNRECOVERABLE?
	JRST DSKSK1		;YES, TRY XFER ANYHOW
	DPB C,ERRCPT
	MOVSI C,DSKRCB		;SEEK INCOMPLETE, TRY RECAL
	IORM C,DSKSTS(A)
	CALL DSKRCL
	JRST DSKSV5

DSKUER:	MOVSI C,DSKSIP+DSKCMR
	ANDCAM C,DSKSTS(A)
	TLZA 0,400000		;RETURN ERROR BITS (B0 SHOULD BE OFF)
DSKSVU:	SETZ 0,			;0 MEANS NO ERRORS
	LDB C,UCMIPT		; GET COMMAND INDEX
	MOVEM 0,DSKCL+1(C)	;WORD GOING POSITIVE INDICATES DONE
	AOS PSKED		;SIG SCHED
	JRST DSKSV2
;STILL IN COND ON NOT SSADF

;STILL ON NON-SSA COND
;DISK ERROR

	INTERN DSKERR

DSKERR:	XCT DCLERR		;CLEAR ALL ERROR CONDITIONS
	MOVE C,DSKDAW(A)	;SAVE ERROR WORDS
	MOVEM C,DSKRER
	MOVE C,DSKCAW(A)
	MOVEM C,DSKRER+1
	MOVE C,DSKSTS(A)
	MOVEM C,DSKRER+2
	MOVEM 0,DSKRER+3	;AND ERROR BITS
	AOS DSKRCE		;COUNT REC ERRORS
	LDB C,ERRCPT		;RETRY COUNT
	ADDI C,1
	DPB C,ERRCPT
	CAILE C,DSKNTR		;UNRECOVERABLE?
	JRST DSKERP		;YES
DSKER2:	XCT DSZSCF		;SKIP NO SEARCH FAILURE
	JRST DSKER3		;SEARCH FAILED, TRY RECALIBRATE
	CALL DSKSVX		;START XFER OVER AGAIN
	JRST DSKSV1		;DEBREAK

DSKER3:	MOVSI C,DSKCMR+DSKRCB	;SET STATE TO RECAL IN PROGRESS
	XORM C,DSKSTS(A)
	MOVE B,TODCLK
	ADDI B,^D5000
	MOVEM B,DSKLSV(A)	; RESTART TIMER FOR RECAL
	CALL DSKRCL		;INITIATE RECAL
	JRST DSKSV2		;CONTINUE PROCESSING INTERRUPTS
;STILL IN NON-SSA COND

;STILL IN NON-SSA COND
;UNRECOVERABLE ERROR

DSKERP:	XCT DSZPCI		;SKIP NO PCI ERROR
	JRST [	MOVE C,[SIXBIT /DSKPAK/]
		MOVEM C,DEVMPE	;YES, REQUEST CORE SCAN
		ISB APRCHN
		JRST DSKER2]	;TRY AGAIN
	SETZM DSKLSV(A)		;RESET OVERDUE ALARM
	MOVNI C,DSKNTR
	ADDM C,DSKRCE		;REMOVE FROM RECOVERABLE COUNT
	AOS DSKNRE		;COUNT IRRECOVERABLE
	MOVE C,[XWD DSKRER,DSKLER]
	BLT C,DSKLER+3		;SAVE COMMAND WORDS
	MOVSI C,DSKUIO
	TDNE C,DSKSTS(A)	;UTILITY OP?
	JRST DSKUER		;YES
	CALL DSKEP1		;CLEAN UP
	JRST DSKSV2
>
;USE THIS CODE FOR BOTH DF10 AND SSA DISKS

DSKEP1:	MOVE B,DSKCAW(A)	;'NORMAL' IRREC TYPE ERROR
	TLZ B,(-1B<^D35-ADSZ>)	; ISOLATE THE ADDRESS FIELD
	LSH B,-^D9		;GET PAGE NUMBER
	MOVSI C,SWPERR
	IORM C,CST3(B)		;NOTIFY SWAPPER OF ERROR
	MOVE C,CST2(B)		;FIND OUT WHAT PAGE IS
	TLNN C,-1		;FROM SPT?
	JRST [	CAIL C,NOFN	;YES, OFN?
		HLRZ C,SPTH(C)	;NO, GET OFN
		JRST DSKXX3]
	HLRZ C,3
DSKXX3:	CAIL C,1		;SENSITIVE FILE? I.E. DI OR DIRECTORY?
	CAILE C,NFDIB+3
	JRST .+2
	BUG(CHK,<DISK ERROR IN SENSITIVE PAGE>)
	MOVSI C,DSKSIP+DSKCMR
	ANDCAM C,DSKSTS(A)
	PUSH P,1
	MOVE A,2		;CORE PAGE NUMBER
	JSP D,SWPDON		;NOTIFY SWAPPER OF COMPLETION
	POP P,1
	RET

INTERN CHKDSK,CHKDE1		; MOVED FROM SWPMON SO THEY CAN BE
				; DEVICE DEPENDENT

	SWAPCD

CHKDSK:	MOVEM 1,CHKDNE##	;SAVE NEW COUNT
	HRROI 1,[ASCIZ /
***NON-REC DISK ERROR: /]
	MOVEI 6,DSKLER		;4 WORD BLOCK OF COMMANDS AND ERR BITS
CHKDE2:	PSOUT
	MOVEI 1,101
IFNDEF SSADF,<
	HRLI 6,-4>		;REPORT 4 WORDS
IFDEF SSADF,<
	HRLI 6,-3>		; OR 3 ON 3330'S.
	MOVE 3,[1B0+^D8]	;IN MAGNITUDE OCTAL
CHKD1:	MOVE 2,0(6)
	NOUT
	  JFCL
	MOVEI 2," "
	BOUT
	AOBJN 6,CHKD1
IFDEF SSADF,<			; MORE CODE FOR TYPING SENSE BYTES
	MOVE 6,0(6)		; GET DRIVE NUMBER IN ERROR
	ANDI 6,7		;  ..
	MOVE 6,DPESB(6)		; WHERE SENSE BYTES ARE STASHED ON ERROR
	HRLI 6,441000		; READ AS 8-BIT BYTES
	PUSH P,6
	LDB 6,[POINT 6,1(6),7]	; GET PHYSICAL DRIVE
	HRROI 2,[ASCIZ / PHYSICAL DRIVE /]
	MOVEI 3,0
	SOUT
	MOVSI 5,-10
	CAMN 6,PHADRT(5)
	JRST PHADR1
	AOBJN 5,.-2
	MOVEI 2,"?"
	SKIPA
PHADR1:	MOVEI 2,"A"(5)
	BOUT
	HRROI 2,[ASCIZ /
ERROR BITS:
/]
	MOVEI 3,0
	SOUT
	MOVE 6,0(P)
	MOVE 6,0(6)		; FIRST WORD OF SENSE INFO
	LSH 6,-20		; PRINT OUT TOP TWENTY BITS
	MOVEI 5,SNSMTB		; SENSE MESSAGES TABLE
PBITS:	JUMPE 6,CHKD8		;DONE IF NO MORE ONE-BITS
	TRNN 6,1		; THIS BIT ON?
	JRST PBIT1		; NO
	TLON 5,(1B0)		; FIRST BIT MENTIONED?
	JRST PBIT2		; YES
	MOVEI 2,"+"		; NO, SAY ADDITIONAL
	BOUT
PBIT2:	HRRO 2,0(5)		; TEXT FOR THIS BIT
	SOUT
PBIT1:	LSH 6,-1
	AOJA 5,PBITS
CHKD8:	POP P,6
	MOVEI 5,^D24		; NUMBER OF SENSE BYTES
	HRROI 2,[ASCIZ /
SENSE BYTES: /]
	MOVEI 3,0
	SOUT
CHKD3:	HRROI 2,[ASCIZ /
/]
	MOVEI 3,0
	TRNN 5,7		; NEW LINE AFTER 8 BYTES
	SOUT
	ILDB 2,6
	MOVE 3,[140002,,20]	; OUTPUT A BYTE IN HEX WITH LDG 0
	NOUT
	  JFCL
	MOVEI 2," "		; SPACE
	BOUT
	SOJG 5,CHKD3
>
	JRST CHKR1##		; ADD DATE/TIME STAMP

CHKDE1:	MOVEM 1,CHKDRE##	;SAVE NEW COUNT
	HRROI 1,[ASCIZ /
*DISK ERROR: /]
	MOVEI 6,DSKRER		;4 WORD BLOCK OF COMMANDS, ETC.
	JRST CHKDE2

IFDEF SSADF,<
PHADRT:	EXP 70,61,52,43,34,25,16,07	; HARDWARE NAMES OF DRVS 0-7

SNSMTB:	EXP MMM1,MMM2,MMM3,MMM4,MMM5,MMM6,MMM7,MMM8,MMM9,MMM10,MMM11
	EXP MMM12,MMM13,MMM14,MMM15,MMM16,MMM17,MMM18,MMM19,MMM20
MMM1:!	ASCIZ /STATISTICS/
MMM2:!	ASCIZ /2-2/
MMM3:!	ASCIZ /CORRECTABLE/
MMM4:!	ASCIZ /2-0/
MMM5:!	ASCIZ /INCOMPLETE/
MMM6:!	ASCIZ /WRITE INHIBIT/
MMM7:!	ASCIZ /FILE PROTECT/
MMM8:!	ASCIZ /NO RECORD FOUND/
MMM9:!	ASCIZ /1-3/
MMM10:!	ASCIZ /CYLINDER END/
MMM11:!	ASCIZ /TRACK OVERRUN/
MMM12:!	ASCIZ /PERMANENT ERROR/
MMM13:!	ASCIZ /0-7/
MMM14:!	ASCIZ /0-6/
MMM15:!	ASCIZ /OVERRUN/
MMM16:!	ASCIZ /DATA CHECK/
MMM17:!	ASCIZ /EQUIP CHECK/
MMM18:!	ASCIZ /BUS OUT PARITY ERR/
MMM19:!	ASCIZ /INTERVENTION REQD/
MMM20:!	ASCIZ /COMMAND REJECT/
> ;END SSA CONDITIONAL

	RESCD

;DISK DRIVER INITIALIZATION

	INTERN DSKINI,DSKRST

DSKINI:	IFNDEF DRMCHN,<CALL DRMINI> ;INIT SWAP BIT TABLE
DSKRST:	SETOM DSKLUN
	SKIPN DISKP
	RET
	SETOM DSKBLK
	MOVEI A,DSKCL+2*NDSKCM-2
	SETZM 0(A)		;END OF LIST
	MOVEM A,-2(A)		;INIT UTILITY FREE LIST
	SUBI A,2
	CAILE A,DSKCL
	JRST .-3
	MOVEM A,DSKFCL
	MOVEI A,NDSKCM
	MOVEM A,DSKCCT		;INIT UTILITY COMMAND FREE COUNT
IFNDEF SSADF,<
	MOVEI A,DSKCCM
	MOVEM A,DSKCP>		;INITIAL COMMAND WORD FOR CHANNEL
	MOVSI A,-NDVMAX		;FOR EACH UNIT, DO:
DSKII1:	SETZM DSKQ(A)
	MOVEI B,DSKUO(A)	;INIT UTILITY QUEUE
	MOVEM B,DSKUI(A)
	CALL DIUNIT		;INIT UNIT
DSKII3:	AOBJN A,DSKII1
	MOVSI C,-NDSKPR+NHOME
DSKII4:	MOVE A,DSKPRO(C)	; LOOP THRU PROTOTYPE TABLE
	MOVEM A,DSKPAR(C)	; AND COPY DSK PARAMETERS
	AOBJN C,DSKII4
	MOVSI C,-NHOME		; FOR ALL HOME BLOCK ADDRESSES
DSKII5:	MOVE A,HOMPRO(C)	; GET LOGICAL HARDWARE ADDRESS
	HLRZ B,1		; LOGICAL UNIT
	HRL A,DRIVTB(B)		; CONVERT TO HDWR ADDRESS (NOT PHYSICAL)
	MOVEM A,HOME(C)
	AOBJN C,DSKII5

	MOVSI A,(1B1)		;INDICATE MULTI-PACK SWAPPING
	IORM A,MONDSC##

	MOVE A,[JRST CRASH1]
	MOVEM A,CRASH+1		;INIT DUMP ROUTINE FOR JSR
IFNDEF SSADF,<
	CONO DSK,DSKCHN>	;GIVE IT ITS PI ASSMT
	RET

;RELOAD RES MON, CALLED FROM SYSGO

RLRMA==3000		;RUN LOCATION OF RELOAD ROUTINE
RLRCA==36		;FIRST CORE LOCATION RESTORED

RLRMON:	MOVE A,[XWD RLMX0,RLRMA]
	BLT A,RLRMA+777		;MOVE RELOAD ROUTINE TO RUN LOCATION
	JRST RLMGO		;IT RELOADS AND STARTS MON

IFDEF RP10F,<		;BOOT ROUTINE FOR RP02,RP03

;RELOAD ROUTINE, RUN IN LOWER CORE. CAN BE EXTRACTED FOR PAPER TAPE, ETC.

RLMX0:	PHASE RLRMA

RLMC5:	REPEAT PPRMPG,<0>	;TABLE OF DISK ADDRESSES, SETUP AT POSTLD

MNBOOT:	SETZM 20		;CLEAR CORE NOT CLEARED BY TENDMP
	MOVSI A,20
	HRRI A,21
	BLT A,777
	MOVEI 7,100		;SETUP RETURN TO DDT WHEN LOADED
RLMGO:	MOVSI 10,-PPRMPG+1
	MOVEI 11,RLRCA		;FIRST CORE LOC TO LOAD INTO
RLMG2:	CAIGE 11,RLRMA+1000
	CAIGE 11,RLRMA
	CAIA
	ADDI 11,1000		;SKIP OVER THIS CODE WHEN READING
	MOVE A,RLMC5(10)	;DISK ADDRESS
	LSH A,^D12
	TLO A,(4B2)
	DATAO DSK,1		;POSITION HEADS
	ROTC B,^D72		;DELAY SEEMS NECESSARY HERE
RLMG1:	DATAI DSK,2
	TLNN B,(1B11)		;ERROR?
	TLNN B,(1B13)		;OR NOT ON LINE?
	JRST 4,RLMGO		;YES
	TLNN B,(1B12)		;ON CYL?
	JRST RLMG1		;NO, WAIT
	CONO DSK,1B32		;CLEAR DONE
	MOVEI B,-1(11)		;CONSTRUCT CHANNEL COMMAND
	HRLI B,-1000		;TRANSFER ONE PAGE
	MOVEM B,RLMNB
	SETZM RLMNB+1		;ONE WORD CHAN PGM
	MOVEI B,RLMNB
	MOVEM B,DSKCP		;INITIAL CHANNEL LOC
	TLZ A,(7B2)		;READ COMMAND = 0
	IORI A,DSKCP		;CONSTRUCT READ COMMAND
	DATAO DSK,1		;ISSUE READ
	CONSO DSK,1B31		;WAIT TILL BUSY OFF AND DONE ON
	CONSO DSK,1B32
	JRST .-2
	ANDCMI 11,777		;BUMP TO NEXT PAGE
	ADDI 11,1000
	AOBJN 10,RLMG2
	AOS GETSMF
	JRST 0(7)		;RETURN

RLMNB:	REPEAT 2,<0>

	DEPHASE
RLRMX1:
>			;END RP10F

IFDEF DC10F,<		;BOOT ROUTINE FOR TELEFILE DC10

;RELOAD ROUTINE, RUN IN LOWER CORE. CAN BE EXTRACTED FOR PAPER TAPE, ETC.

DCBSY==1B20		;DC10 BUSY FLAG

RLMX0:	PHASE RLRMA

RLMC5:	REPEAT PPRMPG,<0>	;TABLE OF DISK ADDRESSES, SETUP AT POSTLD

MNBOOT:	SETZM 20	;CLEAR CORE NOT CLEARED BY TENDMP
	MOVSI A,20
	HRRI A,21
	BLT A,777
	MOVEI 7,100	;SET UP RETURN TO DDT

RLMGO:	MOVSI 10,-PPRMPG+1
	MOVEI 11,RLRCA		;FIRST CORE LOC TO LOAD INTO
RLMG2:	CAIGE 11,RLRMA+1000
	CAIGE 11,RLRMA
	CAIA
	ADDI 11,1000		;SKIP OVER THIS CODE WHEN READING
	MOVE A,RLMC5(10)	;DISK ADDRESS
	HLRZ B,1	;FORM REAL HARWARE DISK ADR
	ADDI B,1	;UNIT IN 2 +1 (CONTROLLER IS 0)
	HRRZS 1
	LSH A,^D35-ADRPOS
	LSH B,^D9
	IORI A,100000+DSKCP	; MAKE READ COMMAND
	IORI A,(B)	;COMPLETE HARDWARE ADR
	JSR RWDSK	;CORE ADR IN 11, DISK DATAO IN 1
	ANDCMI 11,777		;BUMP TO NEXT PAGE
	ADDI 11,1000
	AOBJN 10,RLMG2
	AOS GETSMF
	JRST 0(7)	;RETURN

;STAND ALONE DISK DRIVER FOR RELOADING MONITOR OFF DISK, AND FOR 
;WRITING CRASH COPY OF MONITOR TO CRASH AREA OF DISK.  AC2,3 SCRATCH
;	1=DATAO WORD FOR DISK
;	11=CORE ADDRESS
;	JSR RWDSK

RWDSK:	0
	MOVEI B,0(11)
	ANDI B,777
	SUBI B,1000	;-WDCNT FOR PARTIAL OR COMPLETE PAGE
	HRLI B,-1(11)	;XWD ADR-1, -WDCNT	(BACKWARDS IOWD)
	MOVSM B,RLMNB	;IOWD TO CHANNEL CMD LOCATION
	MOVEI B,RLMNB	;SET UP DF10 CMD POINTER
	MOVEM B,DSKCP
RWDSK3:	MOVEI C,DSKNTR	;NO. OF RETRIES IF ERROR
RWDSK1:	MOVE B,1	;DISK CMD WORD
	ANDI B,17000	;JUST GET UNIT
	CONO DSK,DSKCHN(B)	;SELECT THE UNIT
	CONI DSK,2	;AND READ ITS STATUS
	TLNE B,(1B12+1B14+1B15)	;OFF LINE, UNSAFE, OR WRITE PROTECTED?
	HALT RWDSK1	;YES, HALT. CLEAR HALT TO TRY AGAIN
	DATAO DSK,1	;START XFER
	CONSZ DSK,DCBSY	;WAIT FOR CONTROLLER BUSY STATE TO RESET
	JRST .-1
	CONSO DSK,640000	;ERRORS?
	JRST @RWDSK	;NO, JUST RETURN
	SOJG C,RWDSK1	;YES, TRY AGAIN
	HALT RWDSK3	;HARD ERROR, CLEAR HALT TO RETRY

RLMNB:	REPEAT 2,<0>

	DEPHASE
RLRMX1:
>			;END DC10F


IFDEF SSADF,<		;RLRMON FOR 3330'S

RLMX0:	PHASE RLRMA

RLMC5:	REPEAT PPRMPG,<0>	; TABLE OF PACKED HWARE DSK ADDRESSES

MNBOOT:	SETZM 20		; CLEAR LOW CORE
	MOVSI A,20
	HRRI A,21
	BLT A,777		; ..
	MOVEI 7,100		; SET RETURN PC TO DDT
RLMGO:	MOVSI 10,-PPRMPG+1	; LOAD ALL OF RES CORE EXCEPT THIS PAGE
	MOVEI 11,RLRCA		; WHERE TO START LOADING
RLMG2:	CAIGE 11,RLRMA+1000	; SKIP SELF
	CAIGE 11,RLRMA
	CAIA
	ADDI 11,1000		; POINTING AT SELF. SKIP.
	HLRZ A,RLMC5(10)	; DISK DRIVE, THIS PAGE
	ADDI A,I.DDEV		; REAL ADDRESS
	LSH A,^D12		; SHIFT OVER
	HRRM A,RLMNB		; PUT IN CHANNEL COMMAND
	HRRM A,RLMNB+2		; IN THREE COMMANDS. SEEK, SRCH, RD.
	HRRM A,RLMNB+5		; ..
	HRRZ A,RLMC5(10)	; NOW SET THE CYLINDER
	LSH A,-5
	MOVEM A,RLMNB1
	HRRZ A,RLMC5(10)	; THEN THE SURFACE AND RECORD
	ANDI A,777		; JUST THOSE, FLUSH CYLINDER.
	ADDI A,1		; AND ACCT FOR FIRST REC BEING 1 NOT 0.
	ROTC A,-NSECBT
	LSH A,^D8-NSECBT
	ROTC A,NSECBT
	LSH A,^D12		; TO RIGHT POSITION FOR SEARCH SECTOR ID
	MOVEM A,RLMNB1+1
	HRRM 11,RLMNB2		; THE CORE ADDRESS BEING READ INTO
	MOVSI A,(TCH)		; SET LOW CORE TO GO
	HRRI A,RLMNB		; TO THIS CHANNEL PROGRAM
	MOVEM A,SSABAS+<4*SSADC>
	CONO SSA,SA.STS+<SSADC>B32	; CLEAR ANY PREV DONE FLAG
	CONO SSA,SA.GOF+SA.SET+<SSADC>B32	; MAKE IT READ
	CONSZ SSA,SA.MPE!SA.NXM	; DISASTER?
	JRST RLMRTY		; YES. RETRY.
	CONSO SSA,1B<^D29+SSADC>	; DONE?
	JRST .-3		; NOT YET.
	MOVE A,SSABAS+<4*SSADC>+1	; GET COMPLETION STATUS
	TLC A,(<ID.DVE+ID.CHE>B15)	; THESE SHOULD BE ON, REST OFF.
	TLNE A,177774		; ALL CORRECT?
	JRST RLMRTY		; NO. RETRY.
	TRZ 11,777		; GOOD. ON TO NEXT PAGE
	ADDI 11,1000		; ..
	AOBJN 10,RLMG2		; READ ALL PAGES NEEDED
	AOS GETSMF
	JRST 0(7)		; RETURN TO DDT OR CALLER.
RLMRTY:	CONO SSA,600000		;CLEAR CHANNEL AND MEM ERRS
	MOVSI 1,1		; DELAY FOR CHANNEL TO DO RESET
	SOJG 1,.-1		; AND IBM CONTROLLERS TO FINISH.
	JRST RLMGO		; TRY IT AGAIN

RLMNB:	;SIMPLE CHANNEL PROGRAM TO READ ONE PAGE FROM DISK.
	; THIS PROGRAM IS IMPURE -- MODIFIED ABOVE.

	BYTE (8)70,IC.SEK,I.DDEV	; ISSUE SEEK TO CYLINDER
	BYTE (WCSZ)-6(ADSZ)RLMNB1	; SIX BYTES FROM BUFFER 1
	BYTE (8)71,IC.SIE,I.DDEV	; SEARCH FOR RECORD
	BYTE (WCSZ)-5(ADSZ)RLMNB1	; ARG TO SEARCH FOR
	TCH+.-2				; IF SEARCH FAILS, LOOP.
	BYTE (8)60,IC.RDD,I.DDEV	; READ FROM DISK
RLMNB2:	BYTE (WCSZ)-1000(ADSZ).-.	; ONE PAGE, ADDRESS PLUGGED IN.
	0				; END OF CHANNEL PROGRAM

RLMNB1:	0				; 00CC
	0				; HHRX

	DEPHASE
RLRMX1:
> ; END OF RLRMON FOR 3330'S

RLRMSZ==400	;MINIMUM SIZE BECAUSE TENDMP CAN'T LOAD 1 BLOCK FILES
	IFG <RLRMX1-RLMX0-RLRMSZ>,<RLRMSZ==RLRMX1-RLMX0>
	IFG <RLRMSZ-1000>,<PRINTX <RELOAD MONITOR ROUTINE EXCEEDS 1 PAGE - CODE WON'T WORK>>

;STAND-ALONE ROUTINE TO DUMP CORE TO DISK NON-DESTRUCTIVELY
;CALLED BY JSR CRASH
;RETURNS +1 IF DISK CONTROLLER NOT AVAILABLE AFTER SOME TIME
;	+2 IF UNRECOVERABLE HARDWARE ERROR IS ENCOUNTERED
;	+3 IF DUMP SUCCESSFULLY WRITTEN

LS CRASH,2
LS CRACS,20			;ACS AT CRASH
LS DF10CW,2			;CONTROL WORDS FOR DF10
NCRSTK==10
LS CRSTK,NCRSTK			;LOCAL PDL
LS CRERR,1			;STATUS BITS IF ERROR DETECTED

DUMP==:JSR+CRASH		;USED TO INVOKE DUMP ROUTINE

CRASH1:	MOVEM 17,CRACS+17	;STASH ACS
	MOVEI 17,CRACS
	BLT 17,CRACS+16

;CONTROLLER AVAILABLE?
	MOVSI A,2
	SKIPGE DSKLUN
	 JRST .+3		;ITS AVAILABLE, PROCEED.
	SOJG A,.-2		;NOT AVAILABLE, TRY AGAIN.
	 JRST CRRACS		;TRIED HARD ENOUGH, RETURN.

;SAVE CURRENT STATE OF PI AND THEN TURN IT OFF
	CONI PI,16
	PIOFF

	AOS CRASH		;WE WILL AT LEAST RETURN +2

	MOVE 17,[IOWD NCRSTK,CRSTK]	;SET UP LOCAL STACK

IFNDEF SSADF,<			; IF THERE IS A DF10 INVOLVED,
	PUSH 17,DSKCP		;SAVE OLD DSK ICWD ADDRESS

	MOVEI 15,DF10CW		;SET UP NEW ONE
	MOVEM 15,DSKCP

	MOVNI 15,1000		;SET UP DF10 IOWD COUNT
	HRLM 15,DF10CW
>
	MOVSI B,-MAXCOR		;AOBJN POINTER FOR CORE SWEEP
	MOVE C,[DSKCMA]		;ADDRESS OF CRASH AREA (IN SECTORS)

CRLOOP:	MOVE A,3
	PUSH P,2
	CALL CVDSK		;GET UNIT,,HARDWARE ADDRESS
	POP P,2
	CALL WDSK		;WRITE THE PAGE
	ADDI C,NSECPG		;STEP TO NEXT DISK PAGE
	AOBJN B,CRLOOP		;AND NEXT CORE PAGE, IF ANY

	AOS CRASH		;INDICATE SUCCESSFUL

CRRPI:
IFNDEF SSADF,<
	POP 17,DSKCP>		;RESTORE DSKCP
	ANDI 16,1B28		;AND RESTORE PI
	CONO PI,0(16)

;RESTORE ACS
CRRACS:	MOVSI 17,CRACS
	BLT 17,16
	MOVE 17,CRACS+17
	JRST @CRASH		;AND RETURN


IFDEF DC10F,<
;WDSK ROUTINE FOR DC10
WDSK:	HLRZ 5,1		;GET UNIT
	ADDI 5,1		;+1 (CONTROLLER IS 0)
	HRRZS 1			;CLEAR LEFT HALF

	LSH A,^D35-ADRPOS	;GET DISK ADDRESS INTO CORRECT POSITION
	LSH 5,^D9		;DO SAME TO UNIT
	IOR A,DSKWDA		;WRITE COMMAND
	IORI A,(5)		;STUFF IN UNIT

;SET UP CONTROL WORD FOR DF10
	PUSH P,2
	LSH B,^D9		;TURN PAGE NO. INTO ADDRESS
	SUBI B,1		;LESS 1
	HRRM B,DF10CW		;ADDR-1 TO IOWD
	POP P,2
	SETZM DF10CW+1	;MAKE SURE DF10 STOPS

;SEE IF DESIRED UNIT IS ALIVE AND WELL
	CONO DSK,DSKCHN(5)	;SELECT UNIT
	CONI DSK,15		;READ STATUS
	TLNE 15,(1B12!1B14!1B15)	;OFFLINE,UNSAFE, OR WRITE PROTECTED?
	 JRST WDSKQ		;YES, QUIT

;DEVICE SEEMS OKAY, ATTEMPT DATA TRANSFER
	MOVEI D,DSKNTR		;RETRY COUNT IF ERROR

WDSK2:	DATAO DSK,1		;ISSUE WRITE COMMAND
	CONSZ DSK,DCBSY		;WAIT TIL CONTROLLER NOT BUSY
	 JRST .-1

	CONSO DSK,640000	;ANY ERRORS?
	 RET			;NO, RETURN

;ERROR OCCURRED. SEE IF IT IS A NXM
	CONI DSK,15
	TLNE 15,(1B2)		;NXM?
	 RET			;YES, THAT'S OK, JUST RETURN

	SOJG D,WDSK2		;TRY AGAIN

;UNRECOVERABLE ERROR
WDSKQ:	MOVEM 15,CRERR		;SAVE STATUS BITS
	SUB 17,BHC+1		;BACK UP STACK POINTER
	JRST CRRPI		;AND EXIT

;END OF WDSK FOR DC10
>

IFDEF RP10F,<
;WDSK ROUTINE FOR RP02 OR RP03
WDSK:	LSH A,^D12		;GET ADDRESS TO PROPER POSITION
	TLO A,(4B2)		;POSITION HEADS COMMAND
	DATAO DSK,1		;ISSUE COMMAND
	ROTC 5,^D72		;DELAY
WDSK2:	DATAI DSK,15		;GET STATUS
	TLNN 15,(1B11!1B16)	;POSITION FAILURE OR READONLY?
	TLNN 15,(1B13)		;OR NOT ONLINE?
	 JRST WDSKQ		;QUIT

	TLNN 15,(1B12)		;IN POSITION?
	 JRST WDSK2		;NOT YET, KEEP TRYING

	CONO DSK,1B32		;CLEAR DONE

	PUSH P,2		;SET UP IOWD FOR DF10
	LSH B,^D9
	SUBI B,1
	HRRM B,DF10CW		;CORE ADDRESS -1
	SETZM DF10CW+1
	POP P,2

;ATTEMPT DATA TRANSFER
	TLC A,(5B2)		;TURN SEEK INTO WRITE
	IORI A,DSKCP		;INIT CW ADDRESS

	MOVEI D,DSKNTR		;RETRY COUNT
WDSK3:	DATAO DSK,1		;ISSUE COMMAND
	CONSO DSK,1B31		;WAIT TILL BUSY OFF
	CONSO DSK,1B32		;AND DONE ON
	 JRST .-2

	CONI DSK,15		;GET STATUS
	CONO DSK,0(15)		;AND CLEAR FLAGS

	TDNN 15,[17,,347700]	;TEST FOR ERRORS EXCEPT NXM AND DATA LATE
	 RET			;NO ERRORS, RETURN

	SOJG D,WDSK3		;TRY AGAIN

WDSKQ:	MOVEM 15,CRERR		;SAVE STATUS
	SUB 17,BHC+1
	JRST CRRPI		;EXIT

;END OF WDSK FOR RP10
>

IFDEF SSADF,< ;SSA/3330 VERSION
; HARDWARE ADDRESS IN A, CORE PAGE IN B. MUST PRESERVE B,C

WDSK:	PUSH P,SSABAS+4*SSADC	;SAVE THE START POINTER
	PUSH P,B		;AND CORE ADDRESS
	LSH B,^D9		;ADDR FROM PAGE NUMBER
	DPB B,[POINT ADSZ,WDSKB2,35] ;ADDRESS FOR CHANNEL
	MOVSI 5,(TCH)		;CONSTRUCT POINTER TO CHANNEL PROGRAM
	HRRI 5,WDSKCB		; ..
	MOVEM 5,SSABAS+4*SSADC	;STORE IN LOW CORE.
	HLRZ 5,A		;DRIVE NUMBER
	ADDI 5,I.DDEV		;DEVICE ADDRESS ON CHANNEL BUS
	LSH 5,^D12		;PUT IN RIGHT PLACE IN COMMAND WORD
	HRRM 5,WDSKCB		;PUT IN EACH COMMAND OF CHANNEL PRGM
	HRRM 5,WDSKCB+2		; ..
	HRRM 5,WDSKCB+5		; ..
	HRRZ 5,A		;NOW GET THE CYLINDER
	LSH 5,-^D9+4		;TO 3RD AND 4TH BYTES
	MOVEM 5,WDSKB1		; ..
	HRRZ 5,A		;NOW HEAD AND RECORD
	ANDI 5,777		; ..
	ADDI 5,1		;R0 IS NOT A DATA RECORD
	ROTC 5,-NSECBT		;SECTOR TO HIGH END OF B
	LSH 5,^D8-NSECBT	;ZEROES TO PAD RECORD BYTE
	ROTC 5,NSECBT		;BRING RECORD BACK IN
	LSH 5,^D12		;AND POSITION FOR CHANNEL
	MOVEM 5,WDSKB1+1	;HHRX
	CONI SSA,5		;SAVE STATE OF PI ASSIGNMENT
	CONO SSA,SA.GOF!SA.SET!<SSADC>B32	;MAKE IT GO
	CONSZ SSA,SA.MPE!SA.NXM
	JRST WDSKME		;MEMORY ERROR
	CONSO SSA,1B<^D29+SSADC>
	JRST .-3		;NOT DONE YET.
	MOVE A,SSABAS+<4*SSADC>+1	;SEE IF ANY ERRORS
	TLC A,(<ID.DVE!ID.CHE>B15)	;SHOULD HAVE THESE TWO BITS
	TLNE A,177774		;AND NONE OF THESE OTHERS
	JRST WDSKDE		;ERROR
WDSKOK:	CONO SSA,SA.STS!<SSADC>B32!SA.CME
	TRNE 5,7		;WAS THERE A PI CHANNEL?
	CONO SSA,SSACHN		;YES. RESTORE IT.
	POP P,B			;RESTORE STACK AND AC
	POP P,SSABAS+<4*SSADC>	;AND LOW CORE WORD
	POPJ P,0		;RETURN
WDSKME:	CONSO SSA,SA.MPE	;PARITY ERROR?
	JRST WDSKOK		;NO, NXM. THAT'S NOT FATAL.
WDSKDE:	MOVEI A,CRRPI		;ERROR. MAKE POPJ RETURN TO HERE.
	MOVEM A,-2(P)		; ..
	JRST WDSKOK		;AND CLEAN UP BEFORE GOING TO FAIL EXIT

WDSKCB:	BYTE(8)70,IC.SEK,I.DDEV		;IMPURE PROG. MODIFIED ABOVE.
	BYTE(WCSZ)-6(ADSZ)WDSKB1	;POINT TO 00CCHH
	BYTE(8)71,IC.SIE,I.DDEV		;SEARCH ID EQUAL
	BYTE(WCSZ)-5(ADSZ)WDSKB1	;CCHHR
	TCH+.-2				;WAIT FOR IT
	BYTE(8)60,IC.WRD,I.DDEV		;WRITE DATA
WDSKB2:	BYTE(WCSZ)-1000(ADSZ).-.	;A PAGE OF DATA
	0				;END OF CHANNEL PROGRAM
WDSKB1:	0				;00CC
	0				;HHRX
>;END OF SSA VERSION OF WDSK

;CONVERT LINEAR ADDRESS TO HARDWARE DISK ADDRESS

CVDSK:	TLZ A,DSKMSK		;FLUSH EXTRA BITS
	IDIVI A,NSECTK		;GET TRACK, SECTORS
	PUSH P,B		; SAVE SECTOR AND SURFACE
	IDIVI A,NTKUN		;GIVES DRIVE NO IN A, TRACK IN 2
	LSH B,^D18-NCYLBT	;TRACK TO BITS 18-XX
IFDEF RP10F,<
	TLZE B,(1B17)		;TRACK OVER 400?
	TRO B,1B31>		;YES, MOVE BIT TO HIGH SECTOR FIELD
	HRL B,DRIVTB(A)		;PHYS. DRIV NO FOR TRK GROUP TO B15-17
	POP P,A			; GET BACK SECTOR AND SURFACE
	PUSH P,B		; SAVE DRIVE,,<CYL_N>
	IDIVI A,NSECS		;GET SURFACE, SECTOR
	LSH A,NSECBT		;SURFACE TO B26-30
	IORI A,0(B)		;WITH SECTOR IN B31-35
	POP P,B			;RECOVER DRIVE AND TRACK
	IOR A,B			;MERGE ALL FIELDS
	RET			; DRIVE,,(9)CYL(5)SURF(4)SEC IF 215, 230

;CONVERT HARDWARE FORMAT TO LINEAR ADDRESS

CDSKVA:	HLRZ B,A		;15-17 IS DRIVE
	ANDI B,7
	HLRZ C,DRIVTB(B)	;GET CORRESPONDING TRACK GROUP NO
	IMULI C,NTKUN		;FIRST OF THIS GROUP OF TRACKS
	LDB B,[POINT NCYLBT,A,17+NCYLBT]	;18-25 IS TRACK ON SPECIFIED DRIVE
IFDEF RP10F,<
	TRZE A,1B31		;CYL BIT HIDING IN SECTOR FIELD?
	TRO B,400>		;YES. MOVE IT OVER.
	ADDI C,0(B)		;NOW HAVE ACTUAL TRACK NUMBER
	IMULI C,NSECTK		;COMPUTE SECTOR NUMBER
	LDB B,[POINT 5,A,35-NSECBT]	;26-30 IS SURFACE
	IMULI B,NSECS		;FIRST SECTOR THIS SURFACE
	ANDI A,<1_NSECBT>-1	;31-35 IS SECTOR
	ADDI A,0(B)		;TOTAL SECTORS
	ADD A,C
	RET

;TABLE FOR CONVERSION BETWEEN PHYSICAL DRIVE NUMBERS AND INTERNAL
;TRACK GROUPS NUMBERS.  INDEXED BY INTERNAL, RH GIVES PHYSICAL.
;INDEXED BY PHYSICAL, LH GIVES INTERNAL

DRIVTB:	XWD 0,0
	XWD 1,1
	XWD 2,2
	XWD 3,3
	XWD 4,4
	XWD 5,5
	XWD 6,6
	XWD 7,7

	END
