	.TITLE	XYDRIVER - XYLOGICS-CDC DISK DRIVER
	.IDENT	/V0001/
	.LIST	MEB

; COPYRIGHT (C) 1978
; MIT BATES LINEAR ACCELERATOR, MIDDLETON, MA
;
; T. J. PROVOST	10-10-78
; T. J. PROVOST 12-21-78
;
; XYLOGICS-CDC DISK DRIVER
;
; MACRO LIBRARY CALLS
;;
 
	$DCDEF		;DEFINE DEVICE CLASSES AND TYPES
	$ADPDEF		;DEFINE ADAPTER CONTROL BLOCK OFFSETS
	$CRBDEF		;DEFINE CHANNEL REQUEST BLOCK OFFSETS
	$DDBDEF		;DEFINE DEVICE DATA BLOCK OFFSETS
	$DPTDEF		;DEFINE DEVICE PROLOGUE TABLE OFFSETS
	$EMBDEF		;DEFINE EMB OFFSETS
	$IDBDEF		;DEFINE INTERRUPT DISPATCH BLOCK OFFSETS
	$IODEF		;DEFINE I/O FUNCTION CODES
	$IRPDEF		;DEFINE I/O REQUEST PACKET OFFSETS
	$UBADEF		;DEFINE UNIBUS ADAPTER REGISTER OFFSETS
	$UCBDEF		;DEFINE UNIT CONTROL BLOCK OFFSETS
	$VECDEF		;DEFINE INTERRUPT DISPATCH VECTOR OFFSETS
 
	.PAGE


	.SBTTL	LOCAL MACROS
;
; LOCAL MACROS
;
; EXECUTE FUNCTION AND BRANCH ON RETRIABLE ERROR CONDITION
;
 
	.MACRO	EXFUNCH BDST,FCODE
		.IF NB	FCODE
		MOVZBL	#CD'FCODE,R3
		.ENDC
		BSBW	FEXH
		.BYTE	BDST-.-1
	.ENDM
 
	.MACRO	EXFUNCL BDST,FCODE
		.IF NB	FCODE
 		MOVZBL	#CD'FCODE,R3
		.ENDC
		BSBW	FEXL
		.BYTE	BDST-.-1
	.ENDM
 
;
; GENERATE FUNCTION TABLE ENTRY AND CASE TABLE INDEX SYMBOL
;
 
	.MACRO	GENF FCODE
		CD'FCODE=.-FTAB/2
		.WORD	FCODE!XY_CSR_M_GO!XY_CSR_M_IE
	.ENDM
 
	.PAGE


	.SBTTL	LOCAL SYMBOLS

;
; LOCAL SYMBOLS
;
; XYLOGICS-CDC CONTROLLER REGISTER OFFSETS
;
 
	$DEFINI	XY
 
$DEF	XY_CSR		.BLKW	1	; CONTROL & STATUS REGISTER
	_VIELD	XY_CSR,0,<-		;	FIELD DEFINITIONS
		<GO,,M>,-		; GO BIT
		<FCODE,4>,-		; FUNCTION CODE
		<,1>,-			; RESERVED BIT
		<IE,,M>,-		; INTERRUPT ENABLE
		<RDY,,M>,-		; CONTROLLER READY
		<OFF,4>,-		; OFFSET
		<MEX,2>,-		; MEMORY EXTENSION BITS
		<SKI,,M>,-		; SEEK INHIBIT
		<CERR,,M>,-		; CONTROLLER ERROR
	>				;

$DEF	XY_DA		.BLKW	1	; DISK ADDRESS REGISTER (USH)
	_VIELD	XY_DA,0,<-		;	FIELD DEFINITIONS
		<SA,7>,-		; DESIRED SECTOR ADDRESS
		<TA,5>,-		; DESIRED TRACK (HEAD) ADDRESS
		<DS,2>,-		; DRIVE SELECT (UNIT)
		<,2>,-			; RESERVED BITS
	>

$DEF	XY_BA		.BLKW	1	; BUFFER ADDRESS REGISTER

$DEF	XY_WC		.BLKW	1	; WORD COUNT REGISTER

$DEF	XY_DC		.BLKW	1	; DESIRED CYLINDER REGISTER

$DEF	XY_DS		.BLKW	1	; DRIVE STATUS REGISTER
	_VIELD	XY_DS,0,<-		;	FIELD DEFINITIONS
		<SID,2>,-		; SEEK DONE INT. DISK DR ID
		<SDD,4>,-		; SEEK DONE PER DRIVE STATUS
		<,1>,-			; BIT RESERVED FOR MULTIPORT
		<SDF,,M>,-		; SEEK DONE FLAG
		<DSS,4>,-		; DRIVE SEEKING STATUS
		<DSC,,M>,-		; DRIVE STATUS (PACK?) CHANGE
		<WRL,,M>,-		; DRIVE WRITE LOCKED
		<,1>,-			; BIT RESERVED FOR MULTIPORT
		<DRDY,,M>,-		; DISK DRIVE READY
	>

$DEF	XY_ER	.BLKW	1		; ERROR REGISTER
	_VIELD	XY_ER,0,<-		;	BIT DEFINITIONS
		<CCE,,M>,-		; CYLINDER ADDRESS COMPARE ERROR
		<SHCE,,M>,-		; SECTOR/HEAD ADDRESS COMP ERR
		<WLE,,M>,-		; WRITE LOCK ERROR
		<COE,,M>,-		; CYLINDER OVERFLOW ERROR
		<IHAE,,M>,-		; INVALID HEAD ADDR ERR (NXH)
		<ICAE,,M>,-		; INVALID CYLINDER ADDR ERR (NXC)
		<ISAE,,M>,-		; INVALID SECTOR ADDR ERR (NXS)
		<DLT,,M>,-		; DATA LATE ERROR
		<HVRC,,M>,-		; HEADER (OR DATA) VRC (CRC) ERR
		<CTO,,M>,-		; CONTROLLER TIMEOUT ERROR
		<SKI,,M>,-		; SEEK INCOMPLETE (HARD SEEK) ERR
		<UNS,,M>,-		; DRIVE UNSAVE (FAULT) ERROR
		<DTE,,M>,-		; DRIVE TIMING (NONRDY) ERR
		<BSE,,M>,-		; BAD SECTOR ERROR
		<WCE,,M>,-		; WRITE CHECK ERROR
		<BTE,,M>,-		; BUS TIMEOUT ERROR
	>				;

	$DEFEND	XY
 
;
; SOFTWARE STATUS IN UPPER BYTE OF OFFSET WORD
;
 
	_VIELD	XY,0,<-			;SOFTWARE STATUS BIT DEFINTIONS
		<ECI,,M>,-		; ECC INHIBIT
		<DCK,,M>-		; DATACHECK IN PROGRESS
	>				;
 
;
; DEFINE DEVICE DEPENDENT UNIT CONTROL BLOCK  OFFSETS
;
 
	$DEFINI	UCB
 
.=UCB$W_BCR+2				;
 
$DEF	UCB$W_XY_CSR	.BLKW	1	;CONTROL STATUS REGISTER
$DEF	UCB$W_XY_DA	.BLKW	1	;DISK ADDRESS REGISTER
$DEF	UCB$W_XY_BA	.BLKW	1	;BUFFER ADDRESS REGISTER
$DEF	UCB$W_XY_WC	.BLKW	1	;WORD COUNT REGISTER
$DEF	UCB$W_XY_DC	.BLKW	1	;DESIRED CYLINDER REGISTER
$DEF	UCB$W_XY_DS	.BLKW	1	;DRIVE STATUS REGISTER
$DEF	UCB$W_XY_ER	.BLKW	1	;ERROR REGISTER
$DEF	UCB$W_XY_DPN	.BLKW	1	;DATAPATH NUMBER
$DEF	UCB$L_XY_DPR	.BLKL	1	;DATAPATH REGISTER
$DEF	UCB$L_XY_FMPR	.BLKL	1	;FINAL MAP REGISTER
$DEF	UCB$L_XY_PMPR	.BLKL	1	;PREVIOUS MAP REGISTER
			.BLKW	1	;SPARE USED WORD
$DEF	UCB$W_CYL0	.BLKW	1	;STARTING CYLINDER # FOR VIRTUAL DRIVE
$DEF	UCB$W_REALUNIT	.BLKW	1	;REAL UNIT # FOR THIS VIRTUAL UNIT
 
	$DEFEND	UCB
 
;
; HARDWARE FUNCTION CODES
;

; THE FOLLOWING FUNCTION CODES EXIST FOR RK611
; BUT HAVE NO EQUIVALENT ON THE XYLOGICS-CDC

;	F_UNLOAD		;SELECTS DRIVE
;	F_OFFSET		;DOES SEEK TO CYL
;	F_RETCENTER		;DOES SEEK TO CYL
;	F_PACKACK
;	F_STARTSPNDL

; THE FOLLOWING FUNCTION CODES EXIST FOR XYLOGICS-CDC
; BUT HAVE NO EQUIVALENT ON THE RK611

;	F_SCLR		>>>	REWIND
;	F_RIHC		>>>	READTRACKD
;	F_WBWD		>>>	WRITECHECKH
;	F_WRITEHDC	>>>	WRITETRACKD
;	F_RNS		UNUSED OPTION
;	F_PRC		CALCOMP DISKS ONLY

; THE FOLLOWING I/O FUNCTION CODES EXECUTE DIFFERENTLY
; ON THE RK611 AND ON THE XYLOGICS-CDC

;	IO$_NOP		;RK611 SELECTS DRIVE, XYLOC TRUE NOP
;	IO$_OFFSET	;RK611 SEEKS, XYLOG ONLY SETS UCB

F_NOP		=^XF*2		; NO OPERATION (SELECT DRIVE)
F_SEEK		=^X1*2		; SEEK CYLINDER (ONLY)
F_RECAL		=^XA*2		; RECALIBRATE (RTZ)
F_DRVCLR	=^X9*2		; DRIVE (FAULT) CLEAR
F_RELEASE	=^XC*2		; (PORT) RELEASE DRIVE
F_SCLR		=^X0*2		; SYSTEM CLEAR
F_RIHC		=^X7*2		; READ DATA IGNORING HEADER CHECK
F_WBWD		=^X8*2		; WRITE OVER WRITE PROTECTED SECTOR
F_RNS		=^XD*2		; READ NO STRIP (OPTION)
F_PRC		=^XE*2		; PORT RELEASE (CALCOMP ONLY)
F_WRITECHECK	=^XB*2		; WRITE CHECK (DISK) DATA
F_WRITEDATA	=^X3*2		; WRITE DATA (NORMAL)
F_WRITEHEAD	=^X4*2		; (FORMAT)
F_WRITEHDC	=^X6*2		; WRITE HEADER AND DATA (& CRC)
F_READDATA	=^X2*2		; READ DATA (NORMAL)
F_READHEAD	=^X5*2		; READ HEADER AND DATA (& CRC)
 
	.PAGE


	.SBTTL	DRIVER PROLOGUE TABLE

;
; LOCAL DATA
;
; DRIVER PROLOGUE TABLE
;

	DT$_CDC=DT$_RM03		;MIGHT AS WELL!
	DT$_CDCN=DT$_RM03		;MIGHT AS WELL

;	MUST CONSIDER POSSIBLE NEED FOR UNLOAD IN DPTAB
;	ALSO, POSSIBLE IDB INITIALIZATION
;	ALSO UCBSIZE DECREASE

	DPTAB	-			;DEFINE DRIVER PROLOGUE TABLE
		END=XY_END,-		;END OF DRIVER
		ADAPTER=UBA,-		;ADAPTER TYPE
		FLAGS=DPT$M_SVP,-	;SYSTEM PAGE TABLE ENTRY REQUIRED
		UCBSIZE=200,-		;UCB SIZE
		NAME=DPDRIVER		;DRIVER NAME
	DPT_STORE INIT			;CONTROL BLOCK INIT VALUES
	DPT_STORE DDB,DDB$L_ACPD,L,<^A\F11\> ;DEFAULT ACP NAME
	DPT_STORE DDB,DDB$L_ACPD+3,B,3	;ACP CLASS
	DPT_STORE UCB,UCB$B_FIPL,B,8	;FORK IPL
	DPT_STORE UCB,UCB$L_DEVCHAR,L,-	;DEVICE CHARACTERISTICS
		<DEV$M_FOD-		; FILES ORIENTED
		!DEV$M_DIR-		; DIRECTORY STRUCTURED
		!DEV$M_AVL-		; AVAILABLE
		!DEV$M_ELG-		; ERROR LOGGING ENABLED
		!DEV$M_SHR-		; SHAREABLE
		!DEV$M_IDV-		; INPUT DEVICE
		!DEV$M_ODV-		; OUTPUT DEVICE
		!DEV$M_RND>		; RANDOM ACCESS
	DPT_STORE UCB,UCB$B_DEVCLASS,B,DC$_DISK ;DEVICE CLASS
	DPT_STORE UCB,UCB$W_DEVBUFSIZ,W,512 ;DEFAULT BUFFER SIZE
	DPT_STORE UCB,UCB$B_SECTORS,B,32 ;NUMBER OF SECTORS PER TRACK
	DPT_STORE UCB,UCB$B_TRACKS,B,19	;NUMBER OF TRACKS PER CYLINDER
	DPT_STORE UCB,UCB$W_CYLINDERS,W,109 ;NUMBER OF CYLINDERS
	DPT_STORE UCB,UCB$L_MAXBLOCK,L,<109*19*32> ;MAXIMUM BLOCK NO.
	DPT_STORE UCB,UCB$B_DEVTYPE,B,DT$_CDC
	DPT_STORE UCB,UCB$B_DIPL,B,22	;DEVICE IPL
	DPT_STORE UCB,UCB$B_ERTCNT,B,8	;ERROR RETRY COUNT
	DPT_STORE UCB,UCB$B_ERTMAX,B,8	;MAX ERROR RETRY COUNT
	DPT_STORE REINIT		;CONTROL BLOCK RE-INIT VALUES
	DPT_STORE CRB,CRB$L_INTD+4,D,XY$INT ;INTERRUPT SERVICE ROUTINE ADDRESS
	DPT_STORE CRB,CRB$L_INTD+VEC$L_INITIAL,D,XY_XYLOG_INIT ;CONTROLLER INIT
	DPT_STORE CRB,CRB$L_INTD+VEC$L_UNITINIT,D,XY_CDC_INIT ;UNIT INIT
	DPT_STORE DDB,DDB$L_DDT,D,DP$DDT ;DDT ADDRESS
	DPT_STORE END			;
 
	.PAGE


	.SBTTL	DRIVER DISPATCH TABLE

;
; DRIVER DISPATCH TABLE
;
 
	DDTAB	DP,-			;DRIVER DISPATCH TABLE
		XY_STARTIO,-		;START I/O OPERATION
		XY_UNSOLNT,-		;UNSOLICITED INTERRUPT
		XY_FUNCTABLE,-		;FUNCTION DECISION TABLE
		0,-			;CANCEL I/O ENTRY POINT
		XY_REGDUMP,-		;REGISTER DUMP ROUTINE
 		<12*4>,- ;SIZE OF DIAGNOSTIC BUFFER
		<12*4+<EMB$L_DV_REGSAV>> ;SIZE OF ERROR BUFFER
 
;
; HARDWARE I/O FUNCTION CODE TABLE
;
 
FTAB:					;
	GENF	F_NOP		; NO OPERATION (SELECT DRIVE)
	GENF	F_SCLR		; SYSTEM CLEAR
	GENF	F_SEEK		; SEEK CYLINDER (ONLY)
	GENF	F_RECAL		; RECALIBRATE (RTZ)
	GENF	F_DRVCLR	; DRIVE (FAULT) CLEAR
	GENF	F_RELEASE	; (PORT) RELEASE DRIVE
	GENF	F_RNS		; READ NO STRIP (OPTION)
	GENF	F_PRC		; PORT RELEASE (CALCOMP ONLY)
	GENF	F_WBWD		; WRITE OVER WRITE PROTECTED SECTOR
	GENF	F_WRITECHECK	; WRITE CHECK (DISK) DATA
	GENF	F_WRITEDATA	; WRITE DATA (NORMAL)
	GENF	F_WRITEHEAD	; (FORMAT)
	GENF	F_READDATA	; READ DATA (NORMAL)
	GENF	F_READHEAD	; READ HEADER AND DATA (& CRC)
	GENF	F_WRITEHDC	; WRITE HEADER AND DATA (& CRC)
	GENF	F_RIHC		; READ DATA IGNORING HEADER CHECK
 
;
; OFFSET TABLE FOR XYLOGICS-CDC
;
 
OFFTAB:					;
	.BYTE	0			;RETURN TO CENTERLINE
	.BYTE	^X01			;NORMAL	MINUS
	.BYTE	^X02			;NORMAL	PLUS
	.BYTE	^X04			;LATE	NORMAL
	.BYTE	^X08			;EARLY	NORMAL
	.BYTE	^X05			;LATE	MINUS
	.BYTE	^X06			;LATE	PLUS
	.BYTE	^X09			;EARLY	MINUS
	.BYTE	^X0A			;EARLY	PLUS
	.BYTE	0			;RETURN TO CENTERLINE
OFFSIZ=.-OFFTAB				;SIZE OF OFFSET TABLE
	.PAGE


 	.SBTTL	XYLOGICS-CDC FUNCTION DECISION TABLE
;+
; XYLOGICS-CDC FUNCTION DECISION TABLE
;-
;	DEFINE CDC SPECIFIC FUNCTION CODES


IO$_WRITEHDC	=IO$_WRITETRACKD
IO$_WBWD	=IO$_WRITECHECKH
IO$_RIHC	=IO$_READTRACKD
IO$_SCLR	=IO$_REWIND

;THE FOLLOWING FUNCTION CODES ARE NEVER QUEUED TO STARTIO
;	THEY ARE HANDLED BY FDT ROUTINES
;	ALTHOUGH THEY MAY RESULT IN FUTURE QIO'S

;	SENSECHAR, SENSEMODE, SETCHAR, SETMODE
;	READLBLK, READVBLK, WRITEVBLK, WRITELBLK
;	ACCESS, DEACCESS, ACPCONTROL
;	CREATE, DELETE, MODIFY, MOUNT

;	NOP		NOTIMP		FDT	NORMAL
;	UNLOAD		NOTIMP		FDT	NORMAL
;	SEEK		EXE$ONEPARM	SIO	IO$_SEEK
;	RECAL		EXE$ZEROPARM	SIO	IO$_RECAL
;	DRVCLR		EXE$ZEROPARM	SIO	IO$_DRVCLR
;	RELEASE		NOTIMP		FDT	NORMAL
;	OFFSET		XY_SETOFF	FDT	NORMAL
;	RETCENTER	XY_SETOFF	FDT	NORMAL
;	PACKACK		NOTIMP		FDT	NORMAL
;	STARTSPNDL	NOTIMP		FDT	NORMAL
;	SENSECHAR	EXE$SENSEMODE	FDT
;	SETCHAR		EXE$SETCHAR	FDT
;	SENSEMODE	EXE$SENSEMODE	FDT
;	SETMODE		EXE$SETCHAR	FDT
;	WRITECHECK	ACP$WRITEBLK	SIO	IO$_WRITECHECK
;	WRITEHEAD	ACP$WRITEBLK	SIO	IO$_WRITEHEAD
;	READHEAD	ACP$READBLK	SIO	IO$_READHEAD
;	READLBLK	ACP$READBLK	ACP
;	WRITELBLK	ACP$WRITEBLK	ACP
;	READPBLK	ACP$READBLK	SIO	IO$_READPBLK
;	WRITEPBLK	ACP$WRITEBLK	SIO	IO$_WRITEPBLK
;	READVBLK	ACP$READBLK	ACP
;	WRITEVBLK	ACP$WRITEBLK	ACP
;	ACCESS		ACP$ACCESS	ACP
;	ACPCONTROL	ACP$MODIFY	ACP
;	CREATE		ACP$ACCESS	ACP
;	DEACCESS	ACP$DEACCESS	ACP
;	DELETE		ACP$MODIFY	ACP
;	MODIFY		ACP$MODIFY	ACP
;	MOUNT		ACP$MOUNT	ACP
;	WRITEHDC	ACP$WRITEBLK	SIO	IO$_WRITEHDC
;	WBWD		ACP$WRITEBLK	SIO	IO$_WBWD?
;	RIHC		ACP$READBLK	SIO	IO$_RIHC
;	SCLR		EXE$ZEROPARM	SIO	IO$_SCLR

XY_FUNCTABLE:				;FUNCTION DECISION TABLE
	FUNCTAB	,-			;LEGAL FUNCTIONS
		<NOP,-			;NO OPERATION
		 UNLOAD,-		;UNLOAD VOLUME
		 SEEK,-			;SEEK CYLINDER
		 RECAL,-		;RECALIBRATE
		 DRVCLR,-		;DRIVE CLEAR
		 RELEASE,-		;RELEASE PORT
		 OFFSET,-		;OFFSET HEADS
		 RETCENTER,-		;RETURN HEADS TO CENTERLINE
		 PACKACK,-		;PACK ACKNOWLEDGE
		 STARTSPNDL,-		;START SPINDLE
		 SENSECHAR,-		;SENSE CHARACTERISTICS
		 SETCHAR,-		;SET CHARACTERISITCS
		 SENSEMODE,-		;SENSE MODE
		 SETMODE,-		;SET MODE
		 WRITECHECK,-		;WRITE CHECK
		 WRITEHEAD,-		;WRITE HEADERS
		 READHEAD,-		;READ HEADER
		 READLBLK,-		;READ LOGICAL BLOCK
		 WRITELBLK,-		;WRITE LOGICAL BLOCK
		 READPBLK,-		;READ PHYSICAL BLOCK
		 WRITEPBLK,-		;WRITE PHYSICAL BLOCK
		 READVBLK,-		;READ VIRTUAL BLOCK
		 WRITEVBLK,-		;WRITE VIRTUAL BLOCK
		 ACCESS,-		;ACCESS FILE AND/OR FIND DIRECTORY ENTRY
		 ACPCONTROL,-		;ACP CONTROL FUNCTION
		 CREATE,-		;CREATE FILE AND/OR CREATE DIRECTORY ENTRY
		 DEACCESS,-		;DEACCESS FILE
		 DELETE,-		;DELETE FILE AND/OR DIRECTORY ENTRY
		 MODIFY,-		;MODIFY FILE ATTRIBUTES
		 MOUNT,-		;MOUNT VOLUME
		 WRITEHDC,-		;WRITE HEAD, DATA, CRC
		 WBWD,-			;WRITE OVER PROTECTED SEC
		 RIHC,-			;READ DATA IGNORING HEADERS
		 SCLR>			;SYSTEM CLEAR
	FUNCTAB	,-			;BUFFERED I/O FUNCTIONS
		<NOP,-			;NO OPERATION
		 UNLOAD,-		;UNLOAD VOLUME
		 SEEK,-			;SEEK CYLINDER
		 RECAL,-		;RECALIBRATE
		 DRVCLR,-		;DRIVE CLEAR
		 RELEASE,-		;RELEASE PORT
		 OFFSET,-		;OFFSET HEADS
		 RETCENTER,-		;RETURN HEADS TO CENTERLINE
		 PACKACK,-		;PACK ACKNOWLEDGE
		 STARTSPNDL,-		;START SPINDLE
		 SENSECHAR,-		;SENSE CHARACTERISTICS
		 SETCHAR,-		;SET CHARACTERISITCS
		 SENSEMODE,-		;SENSE MODE
		 SETMODE,-		;SET MODE
		 ACCESS,-		;ACCESS FILE AND/OR FIND DIRECTORY ENTRY
		 ACPCONTROL,-		;ACP CONTROL FUNCTION
		 CREATE,-		;CREATE FILE AND/OR CREATE DIRECTORY ENTRY
		 DEACCESS,-		;DEACCESS FILE
		 DELETE,-		;DELETE FILE AND/OR DIRECTORY ENTRY
 		 MODIFY,-		;MODIFY FILE ATTRIBUTES
		 MOUNT>			;MOUNT VOLUME
	FUNCTAB	XY_SETOFF,-		;OFFSET, RETCENTER
		<OFFSET,-		;OFFSET
		 RETCENTER>		;RETCENTER
	FUNCTAB	XY_NOTIMP,-		;NOT IMPLEMENTED FUNCTIONS
		<NOP,-			;NOP (SELECT DRIVE)
		 UNLOAD,-		;UNLOAD VOLUME
		 RELEASE,-		;RELEASE PORT
		 PACKACK,-		;PACK ACKNOWLEDGE
		 STARTSPNDL>		;LOAD VOLUME
	FUNCTAB	XY_ALIGN,-		;TEST ALIGNMENT FUNCTIONS
		<READHEAD,-		;READ HEADER
		 READLBLK,-		;READ LOGICAL BLOCK
		 READPBLK,-		;READ PHYSICAL BLOCK
		 READVBLK,-		;READ VIRTUAL BLOCK
		 RIHC,-			;READ IGNORING HEADER CHK
		 WRITECHECK,-		;WRITE CHECK
		 WRITEHEAD,-		;WRITE HEADERS
		 WRITELBLK,-		;WRITE LOGICAL BLOCK
		 WRITEPBLK,-		;WRITE PHYSICAL BLOCK
		 WRITEVBLK,-		;WRITE VIRTUAL BLOCK
		 WRITEHDC,-		;WRITE HEADER, DATA, CRC
		 WBWD>			;WRITE OVER PROTECTED SEC
	FUNCTAB	+ACP$READBLK,-		;READ FUNCTIONS
		<READHEAD,-		;READ HEADER
		 READLBLK,-		;READ LOGICAL BLOCK
		 READPBLK,-		;READ PHYSICAL BLOCK
		 READVBLK,-		;READ VIRTUAL BLOCK
		 RIHC>			;READ IGNORING HEADER CHK
	FUNCTAB	+ACP$WRITEBLK,-		;WRITE FUNCTIONS
		<WRITECHECK,-		;WRITE CHECK
		 WRITEHEAD,-		;WRITE HEADERS
		 WRITELBLK,-		;WRITE LOGICAL BLOCK
		 WRITEPBLK,-		;WRITE PHYSICAL BLOCK
		 WRITEVBLK,-		;WRITE VIRTUAL BLOCK
		 WRITEHDC,-		;WRITE HEADER, DATA, CRC
		 WBWD>			;WRITE OVER PROTECTED SEC
	FUNCTAB	+ACP$ACCESS,<ACCESS,CREATE> ;ACCESS AND CREATE FILE OR DIRECTORY
	FUNCTAB	+ACP$DEACCESS,<DEACCESS> ;DEACCESS FILE
	FUNCTAB	+ACP$MODIFY,-		;
		<ACPCONTROL,-		;ACP CONTROL FUNCTION
		 DELETE,-		;DELETE FILE OR DIRECTORY ENTRY
		 MODIFY>		;MODIFY FILE ATTRIBUTES
	FUNCTAB	+ACP$MOUNT,<MOUNT>	;MOUNT VOLUME
	FUNCTAB	+EXE$ZEROPARM,-		;ZERO PARAMETER FUNCTIONS
		<RECAL,-		;RECALIBRATE
		 DRVCLR,-		;DRIVE CLEAR
		 SCLR>			;SYSTEM CLEAR
	FUNCTAB	+EXE$ONEPARM,-		;ONE PARAMETER FUNCTIONS
		<SEEK>			;SEEK CYLINDER
	FUNCTAB	+EXE$SENSEMODE,-		;
		<SENSECHAR,-		;SENSE CHARACTERISTICS
		 SENSEMODE>		;SENSE MODE
	FUNCTAB	+EXE$SETCHAR,-		;
		<SETCHAR,-		;SET CHARACTERISTICS
		 SETMODE>		;SET MODE
	.PAGE


 	.SBTTL	TEST ALIGNMENT OF BUFFER
;+
; XY_ALIGN - TEST ALIGNMENT OF BUFFER
;
; THIS ROUTINE IS CALLED FROM THE FUNCTION DECISION TABLE DISPATCHER TO CHECK THE
; ALIGNMENT OF THE BUFFER.
;
; INPUTS:
;
;	R0 = SCRATCH.
;	R1 = SCRATCH.
;	R2 = SCRATCH.
;	R3 = ADDRESS OF I/O REQUEST PACKET.
;	R4 = CURRENT PROCESS PCB ADDRESS.
;	R5 = ASSIGNED DEVICE UCB ADDRESS.
;	R6 = ADDRESS OF CCB.
;	R7 = I/O FUNCTION CODE.
;	R8 = FUNCTION DECISION TABLE DISPATCH ADDRESS.
;	R9 = SCRATCH.
;	R10 = SCRATCH.
;	R11 = SCRATCH.
;	AP = ADDRESS OF FIRST FUNCTION DEPENDENT PARAMETER.
;
; OUTPUTS:
;
;	THE BUFFER BYTE COUNT IS CHECKED FOR BEING EQUAL TO 0 MOD 2. IF THE CHECK
;	FAILS, THEN THE I/O OPERATION IS TERMINATED WITH AN ERROR. ELSE A RETURN
;	TO THE FUNCTION DECISION TABLE DISPATCHER IS EXECUTED.
;-
 
XY_ALIGN:				;
	BBS	#0,4(AP),10$		;IF SET, ODD BYTE COUNT

	TSTL	4(AP)			;ZERO LENGTH TRANSFER?
	BEQL	20$			; EQL => YES

	RSB				;
10$:	MOVZWL	#SS$_BUFBYTALI,R0	;SET BUFFER ALIGNMENT STATUS
	JMP	G^EXE$ABORTIO		;

20$:	MOVW	#SS$_NORMAL,R0		;NO BYTES => SUCCESSFUL XFER
	JMP	G^EXE$FINISHIOC		; SO GO HOME HAPPY

	.PAGE


	.SBTTL	NOT IMPLEMENTED FUNCTIONS
;+
; XY_NOTIMP - DISPOSE OF FUNCTIONS WHICH DO NOT EXECUTE ANYWAY
;
; THIS ROUTINE IS CALLED FROM THE FUNCTION DECISION TABLE DISPATCHER
; TO DISPOSE OF FUNCTIONS NOT IMPLEMENTED ON THE XYLOGICS CONTROLLER
;
; INPUTS:
;
;	R0 = SCRATCH.
;	R1 = SCRATCH.
;	R2 = SCRATCH.
;	R3 = ADDRESS OF I/O REQUEST PACKET.
;	R4 = CURRENT PROCESS PCB ADDRESS.
;	R5 = ASSIGNED DEVICE UCB ADDRESS.
;	R6 = ADDRESS OF CCB.
;	R7 = I/O FUNCTION CODE.
;	R8 = FUNCTION DECISION TABLE DISPATCH ADDRESS.
;	R9 = SCRATCH.
;	R10 = SCRATCH.
;	R11 = SCRATCH.
;	AP = ADDRESS OF FIRST FUNCTION DEPENDENT PARAMETER.
;
; OUTPUTS:
;
;	SETS SS$_NORMAL IN R0 AND JMPS TO EXE$FINISHIOC
XY_NOTIMP:				;DISPOSE OF NON-IMP CMDS
	MOVW	#SS$_NORMAL,R0		;SET CONDITION NORMAL (SUCCESS)
	JMP	G^EXE$FINISHIOC		; AND GO HOME

	.PAGE



	.SBTTL	OFFSET-RETCENTER HANDLED AT FDT LEVEL
;+
; XY_SETOFF - OFFSET, RETCENTER WILL MERELY SET UCB VALUE
;
; THIS ROUTINE IS CALLED FROM THE FUNCTION DECISION TABLE DISPATCHER
; TO INSERT NEW OFFSET INTO UCB
;
; INPUTS:
;
;	R0 = SCRATCH.
;	R1 = SCRATCH.
;	R2 = SCRATCH.
;	R3 = ADDRESS OF I/O REQUEST PACKET.
;	R4 = CURRENT PROCESS PCB ADDRESS.
;	R5 = ASSIGNED DEVICE UCB ADDRESS.
;	R6 = ADDRESS OF CCB.
;	R7 = I/O FUNCTION CODE.
;	R8 = FUNCTION DECISION TABLE DISPATCH ADDRESS.
;	R9 = SCRATCH.
;	R10 = SCRATCH.
;	R11 = SCRATCH.
;	AP = ADDRESS OF FIRST FUNCTION DEPENDENT PARAMETER.
;
; OUTPUTS:
;
;	INSERTS OFFSET IN UCB
;	SETS SS$_NORMAL IN R0 AND JMPS TO EXE$FINISHIOC
XY_SETOFF:				;SET OFFSETS
	CLRW	UCB$W_OFFSET(R5)	;ASSUME RETCENTER
	CMPB	#IO$_RETCENTER,R7	; IS IT?
	BEQL	10$			; EQL > YES
	MOVW	IRP$L_MEDIA(R3),UCB$W_OFFSET(R5) ;INSERT OFFSET
10$:	MOVW	#SS$_NORMAL,R0		;SET CONDITION NORMAL (SUCCESS)
	JMP	G^EXE$FINISHIOC		; AND GO HOME

	.PAGE


 	.SBTTL	START I/O OPERATION
;+
; STARTIO - START I/O OPERATION ON DEVICE UNIT
;
; THIS ENTRY POINT IS ENTERED TO START AN I/O OPERATION ON A DEVICE UNIT.
;
; INPUTS:
;
;	R3 = ADDRESS OF I/O PACKET.
;	R5 = UCB ADDRESS OF DEVICE UNIT.
;
; OUTPUTS:
;
;	FUNCTION DEPENDENT PARAMETERS ARE STORED IN THE DEVICE UCB, THE ERROR
;	RETRY COUNT IS RESET, AND THE FUNCTION IS EXECUTED. AT FUNCTION COMPLETION
;	THE OPERATION IS TERMINATED THROUGH REQUEST COMPLETE.
;-
 
XY_STARTIO:				;START I/O OPERATION
	MOVB	UCB$B_ERTMAX(R5),UCB$B_ERTCNT(R5) ;INITIALIZE ERROR RETRY COUNT
	MOVW	IRP$W_FUNC(R3),UCB$W_FUNC(R5) ;SAVE FUNCTION CODE AND MODIFIERS
 
;
; MOVE FUNCTION DEPENDENT PARAMETERS TO UCB
;
 
10$:	EXTZV	#IRP$V_FCODE,#IRP$S_FCODE,- ;EXTRACT I/O FUNCTION CODE
		IRP$W_FUNC(R3),R1	;

	CMPB	#IO$_SEEK,R1 		;SEEK FUNCTION?
	BEQL	20$			;IF EQL YES
	MOVL	IRP$L_MEDIA(R3),-
		UCB$W_DA(R5)		;STORE PARAMETER LONGWORD
	BRB	50$			;
 
;
; SEEK FUNCTION - SET CYLINDER ADDRESS
;
 
20$:	MOVW	IRP$L_MEDIA(R3),-
		UCB$W_DC(R5)		;SET CYLINDER ADDRESS
;
; FINISH PREPROCESSING
;
 
50$:	MOVB	R1,UCB$B_FEX(R5)	;SAVE FUNCTION CODE
	BICW	#UCB$M_ECC!-		;CLEAR ECC CORRECTION MADE AND,
		UCB$M_DIAGBUF,UCB$W_DEVSTS(R5) ;DIAGNOSTIC BUFFER PRESENT
	BBC	#IRP$V_DIAGBUF,IRP$W_STS(R3),FDISPATCH ;IF CLR, NO BUFFER

	BISW	#UCB$M_DIAGBUF,UCB$W_DEVSTS(R5) ;SET DIAGNOSTIC BUFFER PRESENT
 
	.PAGE


	.SBTTL	CENTRAL FUNCTION DISPATCH

;
; CENTRAL FUNCTION DISPATCH
;

;******BEWARE**** YOU CAN GET HERE FROM ELSEWHERE*******
 
FDISPATCH:				;FUNCTION DISPATCH
	MOVL	UCB$L_IRP(R5),R3	;RETRIEVE ADDRESS OF I/O PACKET
	BBS	#IRP$V_PHYSIO,IRP$W_STS(R3),10$ ;IF SET, PHYSICAL I/O FUNCTION

	BBS	#UCB$V_VALID,UCB$W_STS(R5),10$ ;IF SET, VOLUME SOFTWARE VALID

	MOVZWL	#SS$_VOLINV,R0		;SET VOLUME INVALID STATUS
	BRW	RESETXFR		;
 
;
; UNIT IS SOFTWARE VALID OR FUNCTION IS PHYSICAL I/O
;
 
10$:	CLRB	UCB$W_OFFSET+1(R5)	;CLEAR ECC INHIBIT AND DATACHECK IN PROGRESS
	CLRL	UCB$W_XY_CSR(R5)	;CLEAR SEEK INHIBIT, ETC.
	MOVB	#1,UCB$B_OFFRTC(R5)	;SET INITIAL OFFSET RETRY COUNT
	CLRB	UCB$B_OFFNDX(R5)	;CLEAR INITIAL OFFSET TABLE INDEX

;**** DM DISPATCHES VIA CASE
;**** THIS COUNTS ON IO$_XXXX RETAINING RELATIVE VALUE
;**** ACCROSS VMS RELEASES. I DON'T BELIEVE IT, SO I
;**** DISPATCH ELSEWISE

	MOVZBL	UCB$B_FEX(R5),R3	;RETRIEVE FUNCTION CODE

	CMPB	#IO$_SEEK,R3		;IF SEEK
	BNEQ	20$			;NEQ => NOT SEEK
	EXFUNCH	RETRY,F_SEEK		;GO SEEK
	BRW	NORMAL			;SUCCESS

20$:	CMPB	#IO$_RECAL,R3		;OR RECAL
	BNEQ	30$			;NEQ => NOT RECAL
	EXFUNCH	RETRY,F_RECAL		;GO RECAL
	BRW	NORMAL			;SUCCESS

30$:	CMPB	#IO$_DRVCLR,R3		;OR DRVCLR
	BNEQ	40$			;NEQ => NOT DRIVE CLEAR
	EXFUNCH	RETRY,F_DRVCLR		;GO CLEAR DRIVE
	BRW	NORMAL			;SUCCESS

40$:	CMPB	#IO$_SCLR,R3		;OR SCLR
	BNEQ	50$			;NEQ => NOT SYSTEM CLEAR
	EXFUNCH	RETRY,F_SCLR		;GO CLEAR SYSTEM
	BRW	NORMAL			;SUCCESS

50$:	MOVB	#CDF_WRITEDATA,R3		;STUFF CASE INDEX
	CMPB	#IO$_WRITEPBLK,UCB$B_FEX(R5)	;WRITEPBLK
	BEQL	WRITEDATA			;	=WRITEDATA

	MOVB	#CDF_READDATA,R3		;STUFF CASE INDEX
	CMPB	#IO$_READPBLK,UCB$B_FEX(R5)	;READPBLK
	BEQL	READDATA		;	=READDATA

	MOVB	#CDF_WRITECHECK	,R3		;STUFF CASE INDEX
	CMPB	#IO$_WRITECHECK,UCB$B_FEX(R5)	;WRITECHECK
	BEQL	CLRDATCHK			;	=> CLEAR DATA CHECK

	MOVB	#CDF_WRITEHEAD,R3		;STUFF CASE INDEX
	CMPB	#IO$_WRITEHEAD,UCB$B_FEX(R5)	;WRITEHEAD
	BEQL	CLRDATCHK			;	=> CLEAR DATA CHECK

	MOVB	#CDF_READHEAD,R3		;STUFF CASE INDEX
	CMPB	#IO$_READHEAD,UCB$B_FEX(R5)	;READHEAD
	BEQL	CLRDATCHK			;	=> CLEAR DATA CHECK

	MOVB	#CDF_WRITEHDC,R3		;STUFF CASE INDEX
	CMPB	#IO$_WRITEHDC,UCB$B_FEX(R5)	;WRITEHDC
	BEQL	CLRDATCHK			;	=> CLEAR DATA CHECK

	MOVB	#CDF_RIHC,R3			;STUFF CASE INDEX
	CMPB	#IO$_RIHC,UCB$B_FEX(R5)		;RIHC
	BEQL	CLRDATCHK			;	=> CLEAR DATA CHECK

	MOVB	#CDF_WBWD,R3			;STUFF CASE INDEX
	CMPB	#IO$_WBWD,UCB$B_FEX(R5)		;WBWD
	BEQL	CLRDATCHK			;	=> CLEAR DATA CHECK


; ELSE IGNORE DATA CHK
 
;
; WRITE CHECK DATA, WRITE HEADERS, AND READ HEAD
; READ IGNORING HEADER AND CRC
; WRITE HEADER, DATA, CRC
; WRITE OVER PROTECTED SECTOR
;
 
CLRDATCHK:
	BICW	#IO$M_DATACHECK,UCB$W_FUNC(R5) ;CLEAR DATA CHECK REQUEST
 
;
; WRITE DATA, WRITE CHECK DATA, WRITE HEADERS, AND READ HEADER
;
 
WRITEDATA:				;WRITE DATA
 
;
; READ DATA, WRITE DATA, WRITE CHECK DATA, WRITE HEADERS, AND READ HEADER
;
 
READDATA:				;READ DATA
	BBC	#IO$V_INHSEEK,-
		UCB$W_FUNC(R5),-
		TRANSFR		 ;IF CLEAR, EXPLICIT SEEK

	BISW	#XY_CSR_M_SKI,-
		UCB$W_XY_CSR(R5)	;SET SEEK INHIBIT
 
;
; DATA TRANSFER
;
 
TRANSFR:				;DATA TRANSFER REQUEST CHANNEL
	EXFUNCL	TRANXT			;EXECUTE TRANSFER FUNCTION
 
;
; DATA CHECK
;
 
DATACHECK:				;DATA CHECK
	BBC	#IO$V_DATACHECK,UCB$W_FUNC(R5),NORMAL ;IF CLR, NO DATA CHECK

	MOVZWL	#SS$_WASECC,R0		;ASSUME ECC CORRECTION WAS MADE
	BBS	#UCB$V_ECC,UCB$W_FUNC(R5),CHECKXT ;IF SET, ECC CORRECTION MADE

	MOVB	#XY_M_DCK!-		;SET DATA CHECK IN PROGRESS
		XY_M_ECI,UCB$W_OFFSET+1(R5) ;AND INHIBIT ECC CORRECTION
	MOVB	#1,UCB$B_OFFRTC(R5)	;SET INITIAL OFFSET RETRY COUNT
	CLRB	UCB$B_OFFNDX(R5)	;CLEAR INITIAL OFFSET TABLE INDEX
	MOVL	UCB$L_IRP(R5),R2	;GET ADDRESS OF IRP
	MOVQ	IRP$L_SVAPTE(R2),UCB$L_SVAPTE(R5) ;RESET TRANSFER PARAMETERS
	MOVL	IRP$L_MEDIA(R2),UCB$W_DA(R5) ;
 
;
 ; DATA CHECK RETRY
;
 
CHECKRETRY:				;DATA CHECK RETRY
	EXFUNCL	TRANXT,F_WRITECHECK	;EXECUTE WRITECHECK FUNCTION
 
;
; SUCCESSFUL OPERATION COMPLETION
;
 
NORMAL:					;
	MOVZWL	S^#SS$_NORMAL,R0	;SET NORMAL COMPLETION STATUS
CHECKXT:				;
	BRW	FUNCXT			;
 
;
; TRANSFER ENDED WITH A RETRIABLE ERROR
;
 
TRANXT:					;TRANSFER EXIT
	CMPB	#CDF_WRITEHEAD,UCB$B_CEX(R5) ;WRITE HEADER FUNCTION?
	BEQL	RETRY			;IF EQL YES
	CMPB	#CDF_WRITEHDC,UCB$B_CEX(R5) ;WRITE HEADER, DATA, CRC FUNCTION?
	BEQL	RETRY			;IF EQL YES
	CMPB	#CDF_WBWD,UCB$B_CEX(R5) ;WRITE BLOCK IGNORING PROTECTION
	BEQL	RETRY			;IF EQL YES
	BITW	#XY_ER_M_DTE!-		;DISK TIMING ERROR,
		 XY_ER_M_WCE!-		;WRITE CHECK ERROR?
		 XY_ER_M_BTE!-		;BUS TIMEOUT?
		 XY_ER_M_UNS!-		;DRIVE UNSAFE?
		 XY_ER_M_SKI,R3		;SEEK INCOMPLETE?
	BEQL	ECC			;IF EQL NO
RETRY:					;
	BRW	RETRYERR		;RETRIABLE ERROR
 
;
; ECC, DRIVE TIMING, OR HEADER ERROR - APPLY ECC OR PERFORM OFFSET RECOVERY
;
 
ECC:					;ECC CORRECTION
	TSTL	R2			;HAS ER,DS BEEN CLEARED?
	BEQL	RETRY			;YES, BETTER RETRY FROM SCRATCH

	MOVZWL	UCB$W_BCR(R5),R0	;GET NEGATIVE NUMBER OF BYTES REMAINING
	ADDW	UCB$W_BCNT(R5),R0	;CALCULATE NUMBER OF BYTES TRANSFERED
	MOVL	R0,R1			;COPY NUMBER OF BYTES TRANSFERED
	BEQL	OFF			;IF EQL NONE - PERFORM OFFSET RECOVERY
	BBS	#XY_ER_V_HVRC,R3,10$	;IF SET, HEADER VRC ERROR

	DECL	R0			;SET TO TRUNCATE LAST BLOCK TRANSFERED
10$:	BICW	#^X1FF,R0		;TRUNCATE RESIDUAL BYTES XFERRED
	SUBL2	#^X200,R0		;CORRECT FOR SECTOR BUFFER

;	FALL THROUGH TO OFFSET RECOVERY, SINCE NO ECC EXISTS
 
;
; OFF - OFFSET RECOVERY
;
; THIS CODE IS EXECUTED WHEN A DRIVE TIMING ERROR, HEADER VRC, OR ECC HARD
; ERROR IS DETECTED ON A READ FUNCTION.
;
 
OFF:					;OFFSET RECOVERY
	TSTL	R0			;ANY GOOD DATA TRANSFERED?
	BLEQ	10$			;IF EQL NO
 
;
; THE TRANSFER ENDED IN AN ERROR BUT THERE WERE SECTORS TRANSFERED THAT
; CONTAINED GOOD DATA. SINCE THE ERROR COULD HAVE BEEN CAUSED BY A CYLIN-
; DER CROSSING, THE GOOD DATA IS SAVED AND THE TRANSFER IS RETRIED FROM THE
; POINT OF ERROR.
;
 
	JSB	G^IOC$UPDATRANSP	;UPDATE TRANSFER PARAMETERS
	CLRB	UCB$B_OFFNDX(R5)	;RESET OFFSET TABLE INDEX
;	BRB	20$			;
	BRB	40$			;********CUT OFFSET DEBUG*******
 
;
; NO GOOD DATA TRANSFERED - CHECK IF CHANGE IN OFFSET NEEDED
;
 
10$:
	BRB	40$			;********CUT OFFSET DEBUG*******
	CMPB	#CDF_WRITEDATA,UCB$B_CEX(R5) ;WRITE DATA FUNCTION?
	BEQL	40$			;IF EQL YES
	DECB	UCB$B_OFFRTC(R5)	;CHANGE CURRENT OFFSET?
	BNEQ	40$			;IF NEQ NO
	MOVB	#2,UCB$B_OFFRTC(R5)	;SET OFFSET RETRY COUNT
20$:	INCB	UCB$B_OFFNDX(R5)	;UPDATE OFFSET TABLE INDEX
	MOVZBL	UCB$B_OFFNDX(R5),R0	;GET NEXT OFFSET TABLE INDEX
	CMPB	#OFFSIZ,R0		;ALL OFFSETS TRIED?
	BEQL	OFFSETERR		;IF EQL YES
	MOVB	OFFTAB-1[R0],UCB$W_OFFSET(R5) ;SET NEXT OFFSET VALUE
	BNEQ	30$			;IF NEQ NOT OFFSET ZERO
	MOVB	#16,UCB$B_OFFRTC(R5)	;SET OFFSET RETRY COUNT
30$:
40$:
	DECB	UCB$B_ERTCNT(R5)	;ANY RETRIES LEFT?
	BEQL	FATALERR		;IF EQL NO
	BBS	#XY_V_DCK,UCB$W_OFFSET+1(R5),50$ ;IF SET, DATA CHECK FUNCTION

	MOVZBL	UCB$B_CEX(R5),R3	;RETRIEVE CASE DISPATCH INDEX
	BRW	TRANSFR			;TRY FUNCTION AGAIN
50$:	BRW	CHECKRETRY		;TRY DATA CHECK AGAIN
 
;
; RETRIABLE ERROR
;
 
 RETRYERR:				;RETRIABLE ERROR
	DECB	UCB$B_ERTCNT(R5)	;ANY RETRIES LEFT?
	BEQL	FATALERR		;IF EQL NO
10$:	BRW	FDISPATCH		;
 
;
; ALL OFFSETS TRIED - RETRIEVE FINAL TRANSFER STATUS
;
 
OFFSETERR:				;OFFSET RECOVERY ERROR
	MOVZWL	UCB$W_XY_CSR(R5),R1	;RETRIEVE CONTROL STATUS REGISTER
 
;
; FATAL CONTROLLER/DRIVE ERROR, ERROR RETRY COUNT EXHAUSTED, ERROR RETRY
; INHIBITED, OR FINAL OFFSET TRIED
;
 
FATALERR:				;FATAL ERROR - SET STATUS
	MOVZWL	#SS$_UNSAFE,R0		;SET DRIVE UNSAFE STATUS
	BBS	#XY_ER_V_UNS,R3,FUNCXT	;IF SET, DRIVE UNSAFE

	MOVZWL	#SS$_WRITLCK,R0		;SET WRITE LOCK ERROR
	BBS	#XY_ER_V_WLE,R3,FUNCXT	;IF SET, WRITE LOCK ERROR

	MOVZWL	#SS$_IVADDR,R0		;SET INVALID DISK ADDRESS STATUS
	BITW	#XY_ER_M_COE!-		;CYLINDER ADDRESS OVERFLOW OR,
		XY_ER_M_IHAE!-		;INVALID HEADER ADDR ERROR?
		XY_ER_M_ICAE!-		;INVALID CYLINDER ADDR ERROR?
		XY_ER_M_ISAE,R3		;INVALID SECTOR ADDR ERROR?
	BNEQ	FUNCXT			;IF NEQ YES
	MOVZWL	#SS$_DRVERR,R0		;SET DRIVE ERROR STATUS
	BITW	#XY_ER_M_DTE!-		;DRIVE TIMING ERROR OR,
		XY_ER_M_SKI,R3		;SEEK INCOMPLETE?
	BNEQ	FUNCXT			;IF NEQ YES

	MOVZWL	#SS$_PARITY,R0		;SET PARITY ERROR STATUS
	BITW	#XY_ER_M_BSE!-		;BAD SECTOR ERROR OR,
		XY_ER_M_HVRC,R3		;HEADER VRC ERROR?
	BNEQ	FUNCXT			;IF NEQ YES
 
	MOVZWL	#SS$_DATACHECK,R0	;SET DATA CHECK ERROR STATUS
	BITW	#XY_ER_V_WCE,R3		;IF SET, WRITE CHECK ERROR
	BNEQ	FUNCXT			;IF NEQ, YES

	MOVZWL	#SS$_CTRLERR,R0		;SET CONTROLLER ERROR STATUS
 
;
; FUNCTION COMPLETION COMMON EXIT
;
 
FUNCXT:					;FUNCTION EXIT
	PUSHL	R0			;SAVE FINAL REQUEST STATUS
	JSB	G^IOC$DIAGBUFILL	;FILL DIAGNOSTIC BUFFER IF PRESENT
	CMPB	#CDF_WBWD,UCB$B_CEX(R5) ;DRIVE RELATED FUNCTION?
	BGTRU	10$			;IF GTRU YES
	MOVL	UCB$L_IRP(R5),R3	;RETRIEVE ADDRESS OF IRP
	ADDW3	UCB$W_BCR(R5),IRP$W_BCNT(R3),2(SP) ;CALCULATE BYTES TRANSFERED

10$:	MOVL	UCB$W_XY_DS(R5),R1	;DS,ER INTO SECOND IOSB LONGWORD
	POPL	R0			;RETRIEVE FINAL REQUEST STATUS
	REQCOM				;COMPLETE REQUEST

	.PAGE


 	.SBTTL	XYLOGICS-CDC HARDWARE FUNCTION EXECUTION
;
; FEXH - XYLOGICS-CDC HARDWARE FUNCTION EXECUTION (HIGH PRIORITY)
; FEXL - XYLOGICS-CDC HARDWARE FUNCTION EXECUTION (LOW PRIORITY)
;
; THIS ROUTINE IS CALLED VIA A BSB WITH A BYTE IMMEDIATELY FOLLOWING THAT
; SPECIFIES THE ADDRESS OF AN ERROR ROUTINE. ALL DATA IS ASSUMED TO HAVE BEEN
; SET UP IN THE UCB BEFORE THE CALL. THE APPROPRIATE PARAMETERS ARE LOADED
; INTO DEVICE REGISTERS AND THE FUNCTION IS INITIATED. THE RETURN ADDRESS
; IS STORED IN THE UCB AND A WAITFOR INTERRUPT IS EXECUTED. WHEN THE INTER-
; RUPT OCCURS, CONTROL IS RETURNED TO THE CALLER.
;
; INPUTS:
;
;	R3 = FUNCTION TABLE DISPATCH INDEX.
;	R4 = ADDRESS OF CONTROL STATUS REGISTER 1.
;	R5 = DEVICE UNIT UCB ADDRESS.
;
;	00(SP) = RETURN ADDRESS OF CALLER.
;	04(SP) = RETURN ADDRESS OF CALLER'S CALLER.
;
;	IMMEDIATELY FOLLOWING INLINE AT THE CALL SITE IS A BYTE WHICH CONTAINS
;	A BRANCH DESTINATION TO AN ERROR RETRY ROUTINE.
;
; OUTPUTS:
;
;	THERE ARE FOUR EXITS FROM THIS ROUTINE:
;
;	1. SPECIAL CONDITION - THIS EXIT IS TAKEN IF A POWER FAILURE OCCURS
;		OR THE OPERATION TIMES OUT. IT IS A JUMP TO THE APPROPRIATE
;		ERROR ROUTINE.
;
;	2. FATAL ERROR - THIS EXIT IS TAKEN IF A FATAL CONTROLLER OR DRIVE
;		ERROR OCCURS OR IF ANY ERROR OCCURS AND ERROR RETRY IS
;		INHIBITED. IT IS A JUMP TO THE FATAL ERROR EXIT ROUTINE.
;
;	3. RETRIABLE ERROR - THIS EXIT IS TAKEN IF A RETRIABLE CONTROLLER
;		OR DRIVE ERROR OCCURS AND ERROR RETRY IS NOT INHIBITED.
;		IT CONSISTS OF TAKING THE ERROR BRANCH EXIT.
;
;	4. SUCCESSFUL OPERATION - THIS EXIT IS TAKEN IF NO ERROR OCCURS
;		DURING THE OPERATION. IT CONSISTS OF A RETURN INLINE.
;
;	IN ALL CASES IF AN ERROR OCCURS, AN ATTEMPT IS MADE TO LOG THE ERROR.
;
;	IN ALL CASES FINAL DRIVE AND CONTROLLER REGISTERS ARE RETURNED VIA
;	THE GENERAL REGISTERS R1, R2, AND R3, AND THE UCB.
;
;	R1 = CONTROL STATUS REGISTER.
;	R2 = DISK STATUS REGISTER.
;	R3 = ERROR REGISTER.
;
;	UCB$W_BCR(R5) = BYTE COUNT REGISTER.
;
 
 	.ENABL	LSB
FEXH:					;FUNCTION EXECUTOR (HIGH PRIORITY)
	MOVAB	G^IOC$REQPCHANH,R2	;SET ADDRESS OF REQUEST CHANNEL ROUTINE
	BRB	10$			;
FEXL:					;FUNCTION EXECUTOR (LOW PRIORITY)
	MOVAB	G^IOC$REQPCHANL,R2	;SET ADDRESS OF REQUEST CHANNEL ROUTINE
10$:	POPL	UCB$L_DPC(R5)		;SAVE DRIVER PC VALUE
	MOVB	R3,UCB$B_CEX(R5)	;STORE CASE INDEX
	JSB	(R2)			;REQUEST CHANNEL
	CLRL	R2
	INSV	UCB$W_REALUNIT(R5),-	;INSERT UNIT NUMBER
		#XY_DA_V_DS,-
		#XY_DA_S_DS,-
		R2

;**** DM DISPATCHES VIA CASE
;**** THIS COUNTS ON IO$_XXXX RETAINING RELATIVE VALUE
;**** ACCROSS VMS RELEASES. I DON'T BELIEVE IT, SO I
;**** DISPATCH ELSEWISE

	CMPB	#CDF_SEEK,R3		;IF SEEK
	BEQL	POSIT		;	POSITION
	CMPB	#CDF_RECAL,R3		;IF RECAL
	BEQL	POSIT		;	POSITION
	CMPB	#CDF_DRVCLR,R3		;IF DRVCLR
	BEQL	IMMED		;	IMMEDIATE
	CMPB	#CDF_SCLR,R3		;IF SCLR
	BEQL	IMMED			;	IMMEDIATE

	BRW	XFER			;TRANSFER FUNCTION
	.DSABL	LSB
 
;
; IMMEDIATE FUNCTION EXECUTION
;
;	FUNCTIONS INCLUDE:
;
;		SYSTEM CLEAR
;		DRIVE CLEAR
;
; INTERRUPTS ARE LOCKED OUT, THE APPROPRIATE FUNCTION IS INITIATED WITH
; INTERRUPT ENABLE, AND A WAITFOR INTERRUPT AND KEEP CHANNEL IS EXECUTED.
;
; THESE FUNCTIONS ALL EXECUTE WITHIN A VERY SHORT TIME (15 US), BUT ARE
; VERY INFREQUENT AND THEREFORE ARE DONE WITH INTERRUPTS TO AVOID AN EXTRA
; SET OF REGISTER SAVE LOGIC.
;
 
IMMED:					;IMMEDIATE FUNCTION EXECUTION
	DSBINT				;DISABLE INTERRUPTS
	BBS	#UCB$V_POWER,UCB$W_STS(R5),ENBXIT ;IF SET, POWER HAS FAILED

	MOVW	R2,XY_DA(R4)
	MOVW	FTAB[R3],XY_CSR(R4) ;EXECUTE FUNCTION

	BRW	ENBXIT			;
  
;
; POSITIONING FUNCTION EXECUTION
;
;	FUNCTIONS INCLUDE:
;
;		SEEK CYLINDER,
;		RECALIBRATE
;
; THE OFFSET REGISTER AND CYLINDER ADDRESS REGISTERS ARE LOADED, INTERRUPTS
; ARE LOCKED OUT, AND THE APPROPRIATE POSITIONING FUNCTION IS INITIATED
; WITHOUT INTERRUPT ENABLE. THE CONTROLLER IS THEN POLLED FOR READY, DEVICE
; INTERRUPTS ARE ENABLED, AND A WAITFOR INTERRUPT AND RELEASE CHANNEL IS
; EXECUTED.
;
 
POSIT:					;POSITIONING FUNCTION
	DSBINT				;DISABLE INTERRUPTS
	BBC	#UCB$V_POWER,UCB$W_STS(R5),ENBXIT ;IF SET, POWER HAS FAILED

	ADDW3	UCB$W_CYL0(R5),UCB$W_DC(R5),XY_DC(R4)	;SET PHY CYL
	MOVW	R2,XY_DA(R4)		;SET UNIT NUMBER
	MOVW	FTAB[R3],XY_CSR(R4)	;EXECUTE FUNCTION

	WFIKPCH	RLSCHN,#60		;WAITFOR INTERRUPT
	IOFORK				;CREATE FORK PROCESS
	BRW	RLSCHN			;
ENBXIT:					;
	ENBINT				;
	BRW	RLSCHN			;
	.PAGE


	.SBTTL	TRANSFER FUNCTION EXECUTION
 
;
; TRANSFER FUNCTION EXECUTION
;
;	FUNCTIONS INCLUDE:
;
;		WRITE CHECK,
;		WRITE DATA,
;		WRITE HEADERS,
;		WRITE HEADER, DATA, CRC
;		WRITE OVER PROTECTED SECTOR
;		READ DATA, AND
;		READ HEADER.
;		READ IGNORING HEADER AND CRC CHECKS
;
;	REGISTER USAGE:
;		R2 = UNIT # IN POSITION FOR XY_DA (USH)
;		R3 = CEX
;		R4 = CSR
;		R5 = UCB
;
; A UNIBUS DATAPATH IS REQUESTED FOLLOWED BY THE APPROPRIATE NUMBER OF MAP
; REGISTERS REQUIRED FOR THE TRANSFER. THE TRANSFER PARAMETERS ARE LOADED  
; INTO THE DEVICE REGISTERS, INTERRUPTS ARE LOCKED OUT, THE FUNCTION IS
 ; INITIATED, AND A WAITFOR INTERRUPT AND KEEP CHANNEL IS EXECUTED.
;
 
XFER:					;TRANSFER FUNCTION EXECUTION

; SET SBI <=> UNIBUS

	REQDPR				;REQUEST DATAPATH
	REQMPR				;REQUEST MAP REGISTERS
	TSTL	@UCB$L_SVAPTE(R5)	;BAD SVAPTE?
	BNEQ	1$			; NEQ => NO
	BUG_CHECK	BADPAGTYPE	; ELSE BUGCHECK
1$:	LOADUBA				;LOAD UNIBUS MAP REGISTERS

; SET XY_DA

	CLRL	R2
	INSV	UCB$W_REALUNIT(R5),-	;INSERT UNIT NUMBER
		#XY_DA_V_DS,-
		#XY_DA_S_DS,-
		R2
	BISB	UCB$W_DA(R5),R2		;INSERT SECTOR
	MOVZBL	UCB$W_DA+1(R5),R1	;GET DESIRED HEAD NUMBER
	ASHL	#7,R1,R1		;POSITION HEAD NUMBER
	BISW	R1,R2			; AND INSERT IT
	MOVW	R2,XY_DA(R4)		;GIVE IT TO THE CONTROLLER

; SET XY_WC

	MOVZWL	UCB$W_BCNT(R5),R0	;GET TRANSFER BYTE COUNT
	DIVL	#2,R0			;CALCULATE TRANSFER WORD COUNT
	DSBINT	UCB$B_DIPL(R5)		;DISABLE DEVICE INTERRUPTS
	MNEGW	R0,XY_WC(R4)		;SET TRANSFER WORD COUNT

; SET XY_BA

	MOVZWL	UCB$W_BOFF(R5),R0	;GET BYTE OFFSET IN PAGE
	MOVL	UCB$L_CRB(R5),R1	;GET ADDRESS OF CRB
	INSV	CRB$L_INTD+VEC$W_MAPREG(R1),#9,#7,R0 ;INSERT HIGH 7 BITS OF ADDRESS
	MOVW	R0,XY_BA(R4)		;SET BUFFER ADDRESS
	EXTZV	#7,#2,CRB$L_INTD+VEC$W_MAPREG(R1),R0 ;GET MEMORY EXTENSION BITS

; SET XY_DC

	ADDW3	UCB$W_CYL0(R5),UCB$W_DC(R5),XY_DC(R4)	;SET PHY CYL

; SET UP FOR XY_CSR

	BICW	#^CXY_CSR_M_SKI,UCB$W_XY_CSR(R5)
	ASHL	#12,R0,R0		;SHIFT LEFT 12 BITS
	INSV	UCB$W_OFFSET(R5),-
		#XY_CSR_V_OFF,-
		#XY_CSR_S_OFF,-
		R0			;SET OFFSET VALUE
	BISW	FTAB[R3],R0		;MERGE FUNCTION CODE
	BISW	R0,UCB$W_XY_CSR(R5)	;MERGE WITH SEEK INH.

;*******************INTERRUPTS DISABLED********************************

	SETIPL	#31			;DISABLE INTERRUPTS
	BBC	#UCB$V_POWER,UCB$W_STS(R5),10$ ;IF CLR, NO POWER FAILURE

	ENBINT				;ENABLE INTERRUPTS
	BRW	60$			;
10$:	MOVW	UCB$W_XY_CSR(R5),XY_CSR(R4) ;EXECUTE FUNCTION

;**********************INTERRUPTS ENABLED AGAIN************************

	WFIKPCH	61$,#60			;WAITFOR INTERRUPT AND KEEP CHANNEL
	BRW	62$

61$:	BISW3	#XY_CSR_M_CERR,XY_CSR(R4),UCB$W_XY_CSR(R5) ;SAVE CSR
	MOVAB	XY_DA(R4),R2		;GET ADR OF D.A. REG
	MOVAB	UCB$W_XY_DA(R5),R3	;GET ADR OF D.A. SAVE AREA
	MOVW	(R2)+,(R3)+		;SAVE XY_DA
	MOVW	(R2)+,(R3)+		;SAVE XY_BA
	MOVW	(R2)+,(R3)+		;SAVE XY_WC
	MOVW	(R2)+,(R3)+		;SAVE XY_DC
	MOVW	(R2)+,(R3)+		;SAVE XY_DS
	MOVW	(R2)+,(R3)+		;SAVE XY_ER
	MOVW	#F_SCLR!1,XY_CSR(R4)	;CLEAR CONTROLLER TO STOP INT.
	MOVZBW	#XY_CSR_M_IE,XY_CSR(R4) ;RESET INTERRUPT ENABLE

62$:	IOFORK				;CREATE FORK PROCESS

	MOVL	UCB$L_CRB(R5),R3	;GET ADDRESS OF CRB
	MOVL	@CRB$L_INTD+VEC$L_ADP(R3),R2 ;GET ADDRESS OF CONFIGURATION REGISTER
	EXTZV	#VEC$V_DATAPATH,#VEC$S_DATAPATH,- ;EXTRACT DATAPATH NUMBER
		CRB$L_INTD+VEC$B_DATAPATH(R3),R1 ;

	ASHL	#UBA$V_DPR_BNE,#1,UBA$L_DPR(R2)[R1] ;PURGE DATAPATH

	ASHL	#31-UBA$V_DPR_XMTER,UBA$L_DPR(R2)[R1],R0 ;ANY TRANSMISSION ERROR?

	BGEQ	20$			;IF GEQ NO
	MOVL	UBA$L_DPR(R2)[R1],UBA$L_DPR(R2)[R1]	;CLEAR DPPE
	BISW	#XY_CSR_M_CERR,-	;SET CONTROLLER ERROR
		UCB$W_XY_CSR(R5)
	CLRW	UCB$W_XY_ER(R5)		;CLEAR ERROR REGISTER
	CLRW	UCB$W_XY_DS(R5)		;CLEAR DISK STATUS REGISTER
20$:	BBS	#XY_CSR_V_CERR,UCB$W_XY_CSR(R5),30$ ;IF SET , DEVICE ERRORS

	BBC	#UCB$V_DIAGBUF,UCB$W_DEVSTS(R5),40$ ;IF CLR, NO DIAGNOSTIC BUFFER

; HERE ON DEVICE ERROR OR DIAGNOSTIC BUFFER PRESENT

30$:	MOVW	R1,UCB$W_XY_DPN(R5)	;SAVE DATAPATH NUMBER
	MOVL	UBA$L_DPR(R2)[R1],UCB$L_XY_DPR(R5) ;SAVE DATAPATH REGISTER
	EXTZV	#9,#7,UCB$W_XY_BA(R5),R0 ;GET LOW BITS OF FINAL MAP REGISTER NUMBER
	EXTZV	#XY_CSR_V_MEX,-
		#XY_CSR_S_MEX,-
		UCB$W_XY_CSR(R5),R1	;GET HIGH BITS OF FINAL MAP REG.

	INSV	R1,#7,#2,R0 ;INSERT HIGH BITS OF FINAL MAP REGISTER
 
	CMPW	#495,R0			;LEGAL MAP REGISTER NUMBER?
	BGEQ	35$			;IF GEQ YES
	MOVZWL	#495,R0			;RESTRICT MAP REGISTER NUMBER
35$:	MOVL	UBA$L_MAP(R2)[R0],UCB$L_XY_FMPR(R5) ;SAVE FINAL MAP REGISTER
	CLRL	UCB$L_XY_PMPR(R5)	;CLEAR PREVIOUS MAP REGISTER CONTENTS
	DECL	R0			;CALCULATE PREVIOUS MAP REGISTER NUMBER
	CMPV	#VEC$V_MAPREG,#VEC$S_MAPREG,- ;ANY PREVIOUS MAP REGISTER?
		CRB$L_INTD+VEC$W_MAPREG(R3),R0 ;

	BGTR	40$			;IF GTR NO
	MOVL	UBA$L_MAP(R2)[R0],UCB$L_XY_PMPR(R5) ;SAVE PREVIOUS MAP REGISTER

; HERE IN ANY CASE

40$:	MULW3	#2,UCB$W_XY_WC(R5),UCB$W_BCR(R5) ;CONVERT WORD COUNT TO BYTE COUNT
					;AND FALL THROUGH TO RELEASE DPR

; HERE IN ANY CASE

60$:	RELDPR				;RELEASE DATA PATH
	RELMPR				;RELEASE MAP REGISTERS
RLSCHN:					;
	RELCHAN				;RELEASE CHANNEL
 
;
; RETURN REGISTERS
;
 
	.ENABL	LSB
RETREG:					;RETURN FINAL DEVICE REGISTERS
	MOVZWL	UCB$W_XY_CSR(R5),R1	;RETRIEVE CONTROL STATUS REGISTER
	MOVZWL	UCB$W_XY_DS(R5),R2	;RETRIEVE DISK STATUS REGISTER
	MOVZWL	UCB$W_XY_ER(R5),R3	;RETRIEVE ERROR REGISTER
	BITW	#UCB$M_POWER!-		;POWER FAIL OR DEVICE TIMEOUT?
		UCB$M_TIMOUT,UCB$W_STS(R5) ;
	BNEQ	30$			;IF NEQ YES - SPECIAL CONDITION
	BBC	#XY_CSR_V_CERR,R1,10$	;IF CLR, NO ERRORS
	BBS	#XY_ER_V_DLT,R3,7$	;IF SET, JUST DATA LATE, DON'T FILL E.L.

	JSB	G^ERL$DEVICERR		;ALLOCATE AND FILL ERROR MESSAGE BUFFER
	BBS	#IO$V_INHRETRY,UCB$W_FUNC(R5),20$ ;IF SET, RETRY INHIBITED

	BITW	#XY_ER_M_BSE!-		;BAD SECTOR ERROR OR,
		XY_ER_M_COE!-		;CYLINDER ADDRESS OVERFLOW OR,
		XY_ER_M_IHAE!-		;INVALID HEADER ADDR ERROR OR,
		XY_ER_M_ISAE!-		;INVALID SECTOR ADDR ERROR OR,
		XY_ER_M_ICAE!-		;INVALID CYLINDER ADDR ERROR OR,
		XY_ER_M_WLE,R3		;WRITE LOCK ERROR?
	BNEQ	20$			;IF NEQ YES

 
;
; RETRIABLE ERROR EXIT
;
; RETURN TO FEX CALL OR DISPLACEMENT THEREFROM STORED IN NEXT BYTE
;
 
7$:	MOVZBL	@UCB$L_DPC(R5),-(SP)	;GET BRANCH DISPLACEMENT
	ADDL	(SP)+,UCB$L_DPC(R5)	;CALCULATE RETURN ADDRESS - 1
10$:	INCL	UCB$L_DPC(R5)		;ADJUST TO CORRECT RETURN ADDRESS
	JMP	@UCB$L_DPC(R5)		;RETURN TO DRIVER
 
;
; FATAL CONTROLLER OR DRIVE ERROR EXIT
;
 
20$:	BRW	FATALERR		;
 
;
; SPECIAL CONDITION (POWER FAILURE OR DEVICE TIME OUT)
;
 
30$:	BBSC	#UCB$V_POWER,UCB$W_STS(R5),50$ ;IF SET, POWER FAILURE

 
;
; DEVICE TIME OUT
;
 
	JSB	G^ERL$DEVICTMO		;LOG DEVICE TIME OUT
	MOVL	UCB$L_CRB(R5),R3	;GET ADDRESS OF CRB
	MOVL	CRB$L_INTD+VEC$L_IDB(R3),R3 ;GET ADDRESS OF IDB
	CMPL	R5,IDB$L_OWNER(R3)	;DEVICE OWN CONTROLLER?
	BNEQ	40$			;IF NEQ NO
	MOVW	#F_SCLR!1,XY_CSR(R4) ;CLEAR ENTIRE XYLOGICS SUBSYSTEM
	MOVZBW	#XY_CSR_M_IE,XY_CSR(R4)	;ENABLE DEVICE INTERRUPTS


40$:	SETIPL	UCB$B_FIPL(R5)		;LOWER TO FORK LEVEL


	MOVZWL	#SS$_TIMEOUT,R0		;SET DEVICE TIMEOUT STATUS
	DECB	UCB$B_ERTCNT(R5)	;ANY ERROR RETRIES REMAINING?
	BEQL	RESETXFR		;IF EQL NO
	RELCHAN				;RELEASE CHANNEL IF OWNED
	BICW	#UCB$M_TIMOUT,UCB$W_STS(R5) ;CLEAR TIME OUT STATUS
	BRW	FDISPATCH		;
 
;
; RESET TRANSFER BYTE COUNT TO ZERO
;
 
RESETXFR:				;
 	MOVL	UCB$L_IRP(R5),R3	;RETRIEVE ADDRESS OF I/O PACKET
	MNEGW	IRP$W_BCNT(R3),UCB$W_BCR(R5) ;RESET TRANSFER BYTE COUNT
	BRW	FUNCXT			;
 
;
; POWER FAILURE
;
 
50$:	RELCHAN				;RELEASE CHANNEL IF OWNED
	MOVL	UCB$L_IRP(R5),R3	;RETRIEVE ADDRESS OF I/O PACKET
	MOVQ	IRP$L_SVAPTE(R3),UCB$L_SVAPTE(R5) ;RESTORE TRANSFER PARAMETERS
	BRW	XY_STARTIO		;
	.DSABL	LSB

	.PAGE


 	.SBTTL	XYLOGICS-CDC REGISTER DUMP ROUTINE
;
; XY_REGDUMP - XYLOGICS-CDC REGISTER DUMP ROUTINE
;
; THIS ROUTINE IS CALLED TO SAVE THE CONTROLLER AND DRIVE REGISTERS IN A
; SPECIFIED BUFFER. IT IS CALLED FROM THE DEVICE ERROR LOGGING ROUTINE AND
; FROM THE DIAGNOSTIC BUFFER FILL ROUTINE.
;
; INPUTS:
;
;	R0 = ADDRESS OF REGISTER SAVE BUFFER.
;	R4 = ADDRESS OF CONTROL STATUS REGISTER 1.
;	R5 = DEVICE UNIT UCB ADDRESS.
;
; OUTPUTS:
;
;	THE CONTROLLER AND DRIVE REGISTERS ARE SAVED IN THE SPECIFIED BUFFER.
;
 
XY_REGDUMP:				;XYLOGICS-CDC REGISTER DUMP ROUTINE
	MOVL	#11,(R0)+		;INSERT NUMBER OF DEVICE REGISTERS
	MOVAL	UCB$W_XY_CSR(R5),R1	;GET ADDRESS OF SAVED DEVICE REGISTERS
	MOVL	#8,R2			;SET NUMBER OF REGISTERS TO MOVE
10$:	MOVZWL	(R1)+,(R0)+		;MOVE REGISTER TO BUFFER
	SOBGTR	R2,10$			;ANY MORE TO MOVE?
	MOVL	(R1)+,(R0)+		;INSERT DATAPATH REGISTER
	MOVL	(R1)+,(R0)+		;INSERT FINAL MAP REGISTER
	MOVL	(R1),(R0)+		;INSERT PREVIOUS MAP REGISTER
	RSB				;

	.PAGE


	.SBTTL	CDC DISK DRIVE INITIALIZATION
;
; XY_CDC_INIT - CDC DISK DRIVE INITIALIZATION
;
; THIS ROUTINE IS CALLED AT SYSTEM INITIALIZATION AND AT POWER RECOVERY TO SET
; DRIVE PARAMETERS AND TO WAIT FOR ONLINE DRIVES TO SPIN UP.
;
; INPUTS:
;
;	R4 = ADDRESS OF CONTROL STATUS REGISTER 1.
;	R5 = DEVICE UNIT UCB ADDRESS.
;
; OUTPUTS:
;
;	UNIT PARAMETERS ARE ESTABLISHED AND THE DRIVE IS SPUN UP IF IT WAS ONLINE.
;
 
XY_CDC_INIT:						;CDC UNIT INITIALIZATION
	MOVB	S^#DT$_CDC,UCB$B_DEVTYPE(R5)		;SET CDC DEVTYP
	REQDPR						;GET A DATAPATH
	MOVL	UCB$L_CRB(R5),R0			;GET CRB
	BISL	#VEC$M_PATHLOCK,CRB$L_INTD+VEC$B_DATAPATH(R0)	;AND KEEP
	MOVZWL	UCB$W_UNIT(R5),R0			;GET VIRT UNIT #
	MOVW	TABLE_CYL0[R0],UCB$W_CYL0(R5)		;SET STARTING CYL
	MOVW	TABLE_CYLCNT[R0],UCB$W_CYLINDERS(R5)	;SET CYLINDER COUNT
	MOVW	TABLE_REALUNIT[R0],UCB$W_REALUNIT(R5)	;SET PHY UNIT #
	MOVL	TABLE_MAXBLOCK[R0],UCB$L_MAXBLOCK(R5)	;SET MAX BLOCK #
	BISW	#UCB$M_ONLINE!UCB$M_VALID,UCB$W_STS(R5)	;SET UNIT ONLINE
	RSB				;

TABLE_CYL0:	.WORD	7,211,415,619,7,211,415,619
TABLE_CYLCNT:	.WORD	204,204,204,204,204,204,204,204
TABLE_REALUNIT:	.WORD	0,0,0,0,1,1,1,1
TABLE_MAXBLOCK:	.LONG	204*19*32,204*19*32,204*19*32,204*19*32,-
			204*19*32,204*19*32,204*19*32,204*19*32


	.PAGE

 	.SBTTL	XYLOGICS-CDC UNSOLICITED INTERRUPT ROUTINE
;
; XY_UNSOLNT - XYLOGICS-CDC UNSOLICITED INTERRUPT ROUTINE
;
; THIS ROUTINE IS CALLED WHEN AN UNSOLICITED ATTENTION CONDITION IS DETECTED FOR
; AN CDC OR CDC DRIVE.
;
; INPUTS:
;
;	R4 = ADDRESS OF CONTROL STATUS REGISTER 1.
;	R5 = DEVICE UNIT UCB ADDRESS.
;
; OUTPUTS:
;
;	IF VOLUME VALID IS CLEAR, THEN SOFTWARE VOLUME VALID IS CLEARED. THE
;	UNIT STATUS IS CHANGED TO ONLINE AND THE DRIVE TYPE AND PARAMETERS ARE
;	CLASSIFIED.
;
 
XY_UNSOLNT:				;XYLOGICS-CDC UNSOLICITED INTERRUPT
	MOVB	S^#DT$_CDC,UCB$B_DEVTYPE(R5)	;SET CDC DEVTYP
	MOVW	#109,UCB$W_CYLINDERS(R5)		;SET NUMBER OF CYLS
	MOVL	#109*19*32,UCB$L_MAXBLOCK(R5)	;SET MAX BLK NO.
	TSTW	UCB$W_UNIT(R5)			;UNIT = 0?
	BEQL	10$				;EQ => YES

	MOVB	S^#DT$_CDCN,UCB$B_DEVTYPE(R5)	;SET CDCN DEVTYP
	MOVW	#102,UCB$W_CYLINDERS(R5)		;SET NUMBER OF CYLS
	MOVL	#102*19*32,UCB$L_MAXBLOCK(R5)	;SET MAX BLK NO.
10$:

	BISW	#UCB$M_ONLINE,UCB$W_STS(R5) ;SET UNIT ONLINE
	RSB				;

	.PAGE


 	.SBTTL	XYLOGICS DISK CONTROLLER INTERRUPT DISPATCHER
;+
; XY$INT - XYLOGICS DISK CONTROLLER INTERRUPT DISPATCHER
;
; THIS ROUTINE IS ENTERED VIA A JSB INSTRUCTION WHEN AN INTERRUPT OCCURS
; ON AN XYLOGICS DISK CONTROLLER. THE STATE OF THE STACK ON ENTRY IS:
;
;	00(SP) = ADDRESS OF IDB ADDRESS.
;	04(SP) = SAVED R0
;	08(SP) = SAVED R1
;	12(SP) = SAVED R2.
;	16(SP) = SAVED R3.
;	20(SP) = SAVED R4.
;	24(SP) = SAVED R5.
;	28(SP) = INTERRUPT PC.
;	32(SP) = INTERRUPT PSL.
;
; INTERRUPT DISPATCHING OCCURS AS FOLLOWS:
;
;	IF THE INTERRUPTING CONTROLLER IS CURRENTLY OWNED AND THE OWNER
;	UNIT IS EXPECTING AN INTERRUPT, THEN THAT UNIT IS DISPATCHED FIRST.
;	ALL OTHER UNITS ARE DISPATCHED BY READING THE ATTENTION SUMMARY
;	REGISTER AND SCANNING FOR UNITS THAT HAVE ATTENTION SET. AS EACH
;	UNIT IS FOUND,  A TEST IS MADE TO DETERMINE IF AN INTERRUPT IS
;	EXPECTED ON THE UNIT. IF YES, THEN THE DRIVER IS CALLED AT ITS
;	INTERRUPT RETURN ADDRESS. ELSE THE DRIVER IS CALLED AT ITS UNSOL-
;	ICITED INTERRUPT ADDRESS. AS EACH CALL TO THE DRIVER RETURNS, THE
;	ATTENTION SUMMARY REGISTER IS REREAD AND AN ATTEMPT IS MADE TO FIND
;	ANOTHER UNIT TO DISPATCH. WHEN NO UNITS REQUESTING ATTENTION REMAIN,
;	THE INTERRUPT IS DISMISSED.
;-
 
XY$INT::				;XYLOGICS DISK CONTROLLER INTERRUPT DISPATCHER
	MOVL	@(SP),R3		;GET ADDRESS OF IDB
	MOVL	IDB$L_CSR(R3),R4	;GET ADDRESS OF CONTROL STATUS REGISTER
	MOVL	IDB$L_OWNER(R3),R5	;GET OWNER UNIT UCB ADDRESS
	BEQL	10$			;IF EQL NO OWNER
	BBSC	#UCB$V_INT,UCB$W_STS(R5),30$ ;IF SET, INTERRUPT EXPECTED

; HERE IF NO OWNER, OR OWNER NOT EXPECTING INTERRUPT

10$:
; EVENTUALLY MUST GO THROUGH THIS CODE TO EXIT INTERRUPT

; HERE IF NO MORE SEEK DONE DISKS

	MOVZBW	#XY_CSR_M_IE,XY_CSR(R4)	;ENABLE DEVICE INTERRUPTS
	ADDL	#4,SP			;CLEAN STACK
	MOVQ	(SP)+,R0		;RESTORE REGISTERS
	MOVQ	(SP)+,R2		;
	MOVQ	(SP)+,R4		;
	REI				;
; HERE IF OWNER EXISTS AND EXPECTS INTERRUPT
; FALL THROUGH TO HERE IF INTERRUPT EXPECTED BY SEEK DONE DISK

 30$:
	MOVAB	XY_CSR(R4),R2		;GET ADDRESS OF CONTROL STATUS REGISTER
	MOVAB	UCB$W_XY_CSR(R5),R3	;GET ADDRESS OF REGISTER SAVE AREA
	MOVW	(R2)+,(R3)+		;SAVE CONTROL STATUS REGISTER
	BLSS	100$			;IF LSS ERROR ENCOUNTERED

	BBS	#UCB$V_DIAGBUF,UCB$W_DEVSTS(R5),100$ ;IF SET, DIAGNOSTIC BUFFER

	MOVW	(R2)+,(R3)+		;SAVE DISK ADDRESS REGISTER
	MOVW	(R2)+,(R3)+		;SAVE BUFFER ADDRESS REGISTER
	MOVW	(R2),(R3)		;SAVE WORD COUNT REGISTER

; REACH HERE WITH NEED TO CALL DRIVER IN STARTIO AT WFIK CALL

50$:	MOVQ	UCB$L_FR3(R5),R3	;RESTORE DRIVER CONTEXT
	JSB	@UCB$L_FPC(R5)		;CALL DRIVER AT INTERRUPT RETURN ADDRESS
	MOVL	@(SP),R3		;GET ADDRESS OF IDB
	MOVL	IDB$L_CSR(R3),R4	;GET ADDRESS OF CSR
	CLRL	R2

	BRW	10$			;

; REACH HERE IF UNIT DETERMINED AND ERROR EXISTS

100$:	MOVW	(R2)+,(R3)+		;SAVE DESIRED SECTOR/TRACK ADDRESS REGISTER
	MOVW	(R2)+,(R3)+		;SAVE BUFFER ADDRESS REGISTER
	MOVW	(R2)+,(R3)+		;SAVE WORD COUNT REGISTER
	MOVW	(R2)+,(R3)+		;SAVE DESIRED CYLINDER ADDRESS REGISTER
	MOVW	(R2)+,(R3)+		;SAVE DRIVE STATUS REGISTER
	MOVW	(R2)+,(R3)+		;SAVE ERROR REGISTER
	JSB	XY_CLEAR		;CLEAR THE SYSTEM
	BRW	50$			;

; THIS SUBROUTINE CLEARS ALL ERRORS IN SELECTED DRIVE

; CORRECT UCB ADR MUST BE IN R5
; AND CORRECT UNIT MUST BE IN XY_DA

XY_CLEAR:
	BBC	#XY_ER_V_UNS,XY_ER(R4),10$	;CLEAR => NO DRIVE UNSAFE
	MOVW	#F_DRVCLR!1,XY_CSR(R4)		;CLEAR POSSIBLE DRIVE FAULT
10$:	BITW	#XY_ER_M_SKI!XY_ER_M_CCE,XY_ER(R4)   ;HARD SEEK ERROR?
	BEQL	20$				;EQ => NO HARD SEEK ERROR
	MOVW	#F_RECAL!1,XY_CSR(R4)		;CLEAR HARD SEEK ERROR
20$:	RSB

	.PAGE


 	.SBTTL	XYLOGICS DISK CONTROLLER INITIALIZATION
;+
; XY_XYLOG_INIT - XYLOGICS DISK CONTROLLER INITIALIZATION
;
; THIS ROUTINE IS CALLED VIA A JSB INSTRUCTION AT SYSTEM STARTUP AND AFTER
; A POWER RECOVERY RESTART TO ALLOW INITIALIZATION OF XYLOGICS DISK CONTROLLERS.
; 
; INPUTS:
;
;	R0 = SCRATCH.
;	R1 = SCRATCH.
;	R2 = SCRATCH.
;	R3 = SCRATCH.
;	R4 = ADDRESS OF CONTROL STATUS REGISTER 1.
;	R5 = ADDRESS OF CONTROLLER IDB.
;
;	ALL INTERRUPTS ARE LOCKED OUT.
;
; OUTPUTS:
;
;	THE XYLOGICS CONTROLLER IS INITIALIZED AND INTERRUPTS ARE ENABLED.
;-
 
XY_XYLOG_INIT:				;XYLOGICS DISK CONTROLLER INITIALIZATION
	CLRW	XY_DA(R4)		;SELECT UNIT NUMBER
	MOVW	CDF_SCLR,XY_CSR(R4)	;CLEAR CONTROLLER AND DRIVES
	RSB				;
XY_END:					;ADDRESS OF LAST LOCATION IN DRIVER
 
	.END
