	.TITLE	DBDRIVER - RP04/05/06 DISK DRIVER
	.IDENT	/01/
 
;
; COPYRIGHT (C) 1977
; DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
;
; THIS SOFTWARE IS FURNISHED UNDER  A LICENSE FOR USE ONLY  ON  A
; SINGLE COMPUTER SYSTEM AND MAY BE  COPIED ONLY WITH  THE INCLU-
; SION OF  THE  ABOVE  COPYRIGHT NOTICE.  THIS SOFTWARE,  OR  ANY
; OTHER COPIES THEREOF, MAY NOT BE  PROVIDED  OR  OTHERWISE  MADE
; AVAILABLE TO ANY OTHER PERSON EXCEPT  FOR  USE  ON  SUCH SYSTEM
; AND TO  ONE WHO AGREES  TO  THESE LICENSE  TERMS.  TITLE TO AND
; OWNERSHIP OF THE SOFTWARE SHALL AT ALL TIMES REMAIN IN DEC.
;
; THE INFORMATION IN THIS SOFTWARE  IS  SUBJECT TO CHANGE WITHOUT
; NOTICE AND SHOULD NOT BE CONSTRUED  AS  A COMMITMENT BY DIGITAL
; EQUIPMENT CORPORATION.
;
; DEC ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
; SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DEC.
;
; D. N. CUTLER 30-JAN-77
;
; RP04/04/06 DISK DRIVER
;
; MACRO LIBRARY CALLS
;
 
	$CRBDEF				;DEFINE CRB OFFSETS
	$EMBDEF				;DEFINE EMB OFFSETS
	$IODEF				;DEFINE I/O FUNCTION CODES
	$IRPDEF				;DEFINE IRP OFFSETS
	$MBADEF				;DEFINE MBA REGISTER OFFSETS
	$PRDEF				;DEFINE PROCESSOR REGISTERS
	$UCBDEF				;DEFINE UCB OFFSETS
	$VECDEF				;DEFINE INTERRUPT DISPATCH VECTOR OFFSETS
 
;
; LOCAL MACROS
;
; EXECUTE FUNCTION AND BRANCH ON RETRIABLE ERROR CONDITION
;
 
	.MACRO	EXFUNC BDST,FCODE
		.IF NB	FCODE
		MOVZBL	#CD'FCODE,R0
		.ENDC
		BSBW	FEX
		.BYTE	BDST-.-1
	.ENDM
 
;
; GENERATE FUNCTION TABLE ENTRY AND CASE TABLE INDEX SYMBOL
;
 
	.MACRO	GENF FCODE
		CD'FCODE=.-FTAB
		.BYTE	FCODE!RP_CS1_M_GO
	.ENDM
 
;
; LOCAL SYMBOLS
;
; RP04/05/06 MASSBUS REGISTER OFFSETS
;
 
	$DEFINI	RP
 
$DEF	RP_CS1		.BLKL	1	;DRIVE CONTROL REGISTER
	_VIELD	RP_CS1,0,<-		; DRIVE CONTROL REGISTER BIT DEFINITIONS
		<GO,,M>,-		; GO BIT
		<FCODE,5>-		; FUNCTION CODE
	>				;
$DEF	RP_DS		.BLKL	1	;DRIVE STATUS REGISTER
	_VIELD	RP_DS,6,<-		; DRIVE STATUS REGISTER BIT DEFINITIONS
		<VV,,M>,-		; VOLUME VALID
		<DRY,,M>,-		; DRIVE READY
		<DPR,,M>,-		; DRIVE PRESENT
		<PGM,,M>,-		; PROGRAMMABLE
		<LST,,M>,-		; LAST SECTOR TRANSFERED
		<WRL,,M>,-		; DRIVE WRITE LOCKED
		<MOL,,M>,-		; MEDIUM ONLINE
		<PIP,,M>,-		; POSITIONING IN PROGRESS
		<ERR,,M>,-		; COMPOSITE ERROR
		<ATA,,M>-		; ATTENTION ACTIVE
	>				;
$DEF	RP_ER1		.BLKL	1	;ERROR REGISTER 1
	_VIELD	RP_ER1,0,<-		; ERROR REGISTER 1 BIT DEFINITIONS
		<ILF,,M>,-		; ILLEGAL FUNCTION
		<ILR,,M>,-		; ILLEGAL REGISTER
		<RMR,,M>,-		; REGISTER MODIFY REFUSED
		<PAR,,M>,-		; PARITY ERROR
		<FER,,M>,-		; FORMAT ERROR
		<WCF,,M>,-		; WRITE CLOCK FAIL
		<ECH,,M>,-		; ECC HARD ERROR
		<HCE,,M>,-		; HEADER COMPARE ERROR
		<HCRC,,M>,-		; HEADER CRC ERROR
		<AOE,,M>,-		; ADDRESS OVERFLOW ERROR
		<IAE,,M>,-		; ILLEGAL ADDRESS ERROR
		<WLE,,M>,-		; WRITE LOCK ERROR
		<DTE,,M>,-		; DRIVE TIMING ERROR
		<OPI,,M>,-		; OPERATION INCOMPLETE
		<UNS,,M>,-		; DRIVE UNSAFE
		<DCK,,M>-		; DATA CHECK ERROR
	>				;
$DEF	RP_MR		.BLKL	1	;MAINTENANCE REGISTER
$DEF	RP_AS		.BLKL	1	;ATTENTION SUMMARY REGISTER
$DEF	RP_DA		.BLKL	1	;DESIRED SECTOR/TRACK ADDRESS REGISTER
	_VIELD	RP_DA,0,<-		; DESIRED ADDRESS FIELD DEFINITIONS
		<SA,5>,-		; DESIRED SECTOR ADDRESS
		<,3>,-			; RESERVED BITS
		<TA,5>-			; DESIRED TRACK ADDRESS
	>				;
$DEF	RP_DT		.BLKL	1	;DRIVE TYPE REGISTER
	_VIELD	RP_DT,0,<-		; DRIVE TYPE REGISTER FIELD DEFINITIONS
		<DTN,9>,-		; DRIVE TYPE NUMBER
		<,2>,-			; RESERVED BITS
		<DRQ,,M>-		; DRIVE REQUEST REQUIRED
	>				;
$DEF	RP_LA		.BLKL	1	;LOOKAHEAD REGISTER
$DEF	RP_ER2		.BLKL	1	;ERROR REGISTER 2
$DEF	RP_OF		.BLKL	1	;OFFSET REGISTER
	_VIELD	RP_OF,0,<-		; OFFSET REGISTER BIT DEFINITIONS
		<OFF,8>,-		; OFFSET VALUE
		<DCK,,M>,-		; DATA CHECK IN PROGRESS (SOFTWARE)
		<,1>,-			; RESERVED BIT
		<HCI,,M>,-		; HEADER COMPARE INHIBIT
		<ECI,,M>,-		; ECC INHIBIT
		<FMT,,M>-		; 16-BIT FORMAT
	>				;
$DEF	RP_DC		.BLKL	1	;DESIRED CYLINDER ADDRESS
$DEF	RP_CC		.BLKL	1	;CURRENT CYLINDER ADDRESS
$DEF	RP_SN		.BLKL	1	;DRIVE SERIAL NUMBER
$DEF	RP_ER3		.BLKL	1	;ERROR REGISTER 3
	_VIELD	RP_ER3,14,<-		; ERROR REGISTER 3 BIT DEFINITIONS
		<SKI,,M>-		; SEEK INCOMPLETE
	>				;
$DEF	RP_EC1		.BLKL	1	;ECC POSITION REGISTER
	_VIELD	RP_EC1,0,<<POS,13>>	; ECC POSITION FIELD
$DEF	RP_EC2		.BLKL	1	;ECC PATTERN REGISTER
	_VIELD	RP_EC2,0,<<PAT,11>>	; ECC PATTERN FIELD
 
	$DEFEND	RP
 
;
; DEFINE DEVICE DEPENDENT UNIT CONTROL BLOCK OFFSETS
;
 
	$DEFINI	UCB
 
.=UCB$W_BCR+2				;
 
$DEF	UCB$L_DB_SR	.BLKL	1	;SAVE MBA STATUS REGISTER
 
	$DEFEND
 
;
; HARDWARE FUNCTION CODES
;
 
F_NOP=0*2				;NO OPERATION
F_UNLOAD=1*2				;UNLOAD DRIVE
F_SEEK=2*2				;SEEK CYLINDER
F_RECAL=3*2				;RECALIBRATE
F_DRVCLR=4*2				;DRIVE CLEAR
F_RELEASE=5*2				;RELEASE DRIVE
F_OFFSET=6*2				;OFFSET HEADS
F_RETCENTER=7*2				;RETURN TO CENTERLINE
F_READPRESET=8*2			;READ IN PRESET
F_PACKACK=9*2				;PACK ACKNOWLEDGE
F_SEARCH=12*2				;SEARCH FOR SECTOR
F_SEARCHA=12*2				;SEARCH AHEAD FOR SECTOR
F_WRITECHECK=20*2			;WRITE CHECK DATA
F_WRITECHECKH=21*2			;WRITE CHECK HEADER AND DATA
F_WRITEDATA=24*2			;WRITE DATA
F_WRITEHEAD=25*2			;WRITE HEADER AND DATA
F_READDATA=28*2				;READ DATA
F_READHEAD=29*2				;READ HEADER AND DATA
 
;
; LOCAL DATA
;
; DRIVER DISPATCH TABLE
;
 
	.PSECT	WIONONPAGED
DB$DDT::				;ADDRESS OF DRIVER DISPATCH TABLE
	.LONG	STARTIO			;START I/O OPERATION
	.LONG	UNSOLNT			;UNSOLICITED INTERRUPT
	.LONG	FUNCTABLE		;FUNCTION DECISION TABLE
	.LONG	0			;CANCEL I/O ENTRY POINT
	.LONG	REGDUMP			;REGISTER DUMP ROUTINE
	.WORD	<RP_EC2+4+MBA$L_BCR+4+8>+<<3+5+1>*4> ;SIZE OF DIAGNOSTIC BUFFER
	.WORD	<RP_EC2+4+MBA$L_BCR+4+8>+<1*4>+<EMB$L_DV_REGSAV> ;SIZE OF ERROR BUFFER
 
;
; DATA CHECK FUNCTION TRANSLATION TABLE
;
 
CHECKTAB:				;
	.BYTE	CDF_WRITECHECK		;WRITE DATA
	.BYTE	CDF_WRITECHECK		;READ DATA
	.BYTE	CDF_WRITECHECKH		;WRITE HEADER AND DATA
	.BYTE	CDF_WRITECHECKH		;READ HEADER AND DATA
 
;
; HARDWARE I/O FUNCTION CODE TABLE
;
 
FTAB:					;
	GENF	F_NOP			;NO OPERATION
	GENF	F_UNLOAD		;UNLOAD VOLUME
	GENF	F_SEEK			;SEEK CYLINDER
	GENF	F_RECAL			;RECALIBRATE
	GENF	F_DRVCLR		;DRIVE CLEAR
	GENF	F_RELEASE		;RELEASE PORT
	GENF	F_OFFSET		;OFFSET HEADS
	GENF	F_RETCENTER		;RETURN HEADS TO CENTERLINE
	GENF	F_PACKACK		;PACK ACKNOWLEDGE
	GENF	F_SEARCH		;SEARCH FOR SECTOR
	GENF	F_WRITECHECK		;WRITE CHECK
	GENF	F_WRITEDATA		;WRITE DATA
	GENF	F_READDATA		;READ DATA
	GENF	F_WRITEHEAD		;WRITE HEADER AND DATA
	GENF	F_READHEAD		;READ HEADER AND DATA
	GENF	F_WRITECHECKH		;WRITE CHECK HEADER AND DATA
	GENF	F_READPRESET		;READ IN PRESET
	GENF	F_SEARCHA		;SEARCH AHEAD FOR SECTOR
 
;
; OFFSET TABLE FOR RP06 - RP04 VALUES = RP06 VALUES * 2 & ^XFF
;
 
OFFTAB:					;
	.BYTE	0			;RETURN TO CENTERLINE
	.BYTE	^X8			;+200 (+400)
	.BYTE	^XC8			;-200 (-400)
	.BYTE	^X10			;+400 (+800)
	.BYTE	^XD0			;-400 (-800)
	.BYTE	^X18			;+600 (+1200)
	.BYTE	^XD8			;-600 (-1200)
	.BYTE	0			;RETURN TO CENTERLINE
OFFSIZ=.-OFFTAB				;SIZE OF OFFSET TABLE
	.PAGE
	.SBTTL	RP04/05/06 FUNCTION DECISION TABLE
;+
; RP04/05/06 FUNCTION DECISION TABLE
;-
 
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
		 SEARCH,-		;SEARCH FOR SECTOR
		 READPRESET,-		;READ IN PRESET
		 WRITECHECK,-		;WRITE CHECK
		 WRITEHEAD,-		;WRITE HEADER AND DATA
		 READHEAD,-		;READ HEADER AND DATA
		 WRITECHECKH,-		;WRITE CHECK HEADER AND DATA
		 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
	FUNCTAB	,-			;BUFFERED I/O FUNCTIONS
		<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
	FUNCTAB	ACP$READBLK,-		;READ FUNCTIONS
		<READHEAD,-		;READ HEADER
		 READLBLK,-		;READ LOGICAL BLOCK
		 READPBLK,-		;READ PHYSICAL BLOCK
		 READVBLK>		;READ VIRTUAL BLOCK
	FUNCTAB	ACP$WRITEBLK,-		;WRITE FUNCTIONS
		<WRITECHECK,-		;WRITE CHECK
		 WRITECHECKH,-		;WRITE CHECK HEADER AND DATA
		 WRITEHEAD,-		;WRITE HEADER
		 WRITELBLK,-		;WRITE LOGICAL BLOCK
		 WRITEPBLK,-		;WRITE PHYSICAL BLOCK
		 WRITEVBLK>		;WRITE VIRTUAL BLOCK
	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	EXE$ZEROPARM,-		;ZERO PARAMETER FUNCTIONS
		<NOP,-			;NO OPERATION
		 UNLOAD,-		;UNLOAD VOLUME
		 RECAL,-		;RECALIBRATE
		 DRVCLR,-		;DRIVE CLEAR
		 RELEASE,-		;RELEASE PORT
		 RETCENTER,-		;RETURN HEADS TO CENTERLINE
		 READPRESET,-		;READ IN PRESET
		 PACKACK>		;PACK ACKNOWLEDGE
	FUNCTAB	EXE$ONEPARM,-		;ONE PARAMETER FUNCTIONS
		<SEEK,-			;SEEK CYLINDER
		 OFFSET,-		;OFFSET HEADS
		 SEARCH>		;SEARCH FOR SECTOR
	.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:
;
;	******OUTPUTS*******
;-
 
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
	MOVL	IRP$L_MEDIA(R3),R0	;GET PARAMETER LONGWORD
 
;
; 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
	CMPB	#IO$_OFFSET,R1 		;OFFSET FUNCTION?
	BEQL	30$			;IF EQL YES
	CMPB	#IO$_SEARCH,R1		;SEARCH FUNCTION?
	BEQL	40$			;IF EQL YES
	MOVL	R0,UCB$W_DA(R5)		;STORE PARAMETER LONGWORD
	CMPB	#IO$_WRITECHECKH,R1	;DISJOINT FUNCTION CODE?
	BGTRU	50$			;IF GTRU NO
	SUBW	#IO$_WRITECHECKH-IO$_READHEAD-1,R1 ;CONVERT TO DENSE FUNCTION CODE
	BRB	50$			;
 
;
; SEEK FUNCTION - SET CYLINDER ADDRESS
;
 
20$:	MOVW	R0,UCB$W_DC(R5)		;SET CYLINDER ADDRESS
	BRB	50$			;
 
;
; OFFSET FUNCTION - SET CURRENT OFFSET VALUE
;
 
30$:	MOVB	R0,UCB$W_OFFSET(R5)	;SET OFFSET VALUE
	BRB	50$			;
 
;
; SEARCH FUNCTION - SET SECTOR ADDRESS
;
 
40$:	MOVB	R0,UCB$W_DA(R5)		;SET SECTOR ADDRESS
 
;
; FINISH PREPROCESSING
;
 
50$:	MOVB	R1,UCB$B_FEX(R5)	;SAVE FUNCTION DISPATCH INDEX
	MOVL	UCB$L_CRB(R5),R4	;GET ADDRESS OF CRB
	MOVL	@CRB$L_INTD+VEC$L_IDB(R4),R4 ;GET FIRST CONTROLLER CSR ADDRESS
	BBSC	#UCB$V_ECC,UCB$W_DEVSTS(R5),FDISPATCH ;CLEAR ECC CORRECTION MADE
 
;
; CENTRAL FUNCTION DISPATCH
;
 
FDISPATCH:				;FUNCTION DISPATCH
	MOVZBL	UCB$B_FEX(R5),R0	;GET DISPATCH FUNCTION CODE
	BICW	#UCB$M_CANCEL!-		;CLEAR CANCEL I/O,
		UCB$M_POWER!-		;POWERFAIL, AND
		UCB$M_TIMOUT,UCB$W_STS(R5) ;TIMEOUT STATUS BITS
	MOVB	#RP_OF_M_FMT/256,UCB$W_OFFSET+1(R5) ;CLEAR ECI, HCI, AND SET FORMAT
	MOVB	#1,UCB$B_OFFRTC(R5)	;SET INITIAL OFFSET RETRY COUNT
	CLRB	UCB$B_OFFNDX(R5)	;CLEAR INITIAL OFFSET TABLE INDEX
	CASE	R0,<-			;DISPATCH TO FUNCTION HANDLING ROUTINE
		WRITECHECK,-		;WRITE CHECK DATA
		WRITEDATA,-		;WRITE DATA
		READDATA,-		;READ DATA
		WRITEHEAD,-		;WRITE HEADER AND DATA
		READHEAD,-		;READ HEADER AND DATA
		WRITECHECKH,-		;WRITE CHECK HEADER AND DATA
		>,LIMIT=#CDF_WRITECHECK	;
 
;
; NO OPERATION, UNLOAD, SEEK, RECALIBRATE, DRIVE CLEAR, RELEASE, OFFSET,
; RETURN TO CENTER LINE, PACK ACKNOWLEDGE, SEARCH, AND READ IN PRESET
;
 
NOP:					;NO OPERATION
UNLOAD:					;UNLOAD DRIVE
SEEK:					;SEEK CYLINDER
RECAL:					;RECALIBRATE
DRVCLR:					;DRIVE CLEAR
RELEASE:				;RELEASE PORT
OFFSET:					;OFFSET READ HEADS
RETCENTER:				;RETURN TO CENTERLINE
PACKACK:				;PACK ACKNOWLEDGE
SEARCH:					;SEARCH FOR SECTOR
READPRESET:				;READIN PRESET
	EXFUNC	RETRY			;EXECUTE HOUSEKEEPING FUNCTION
	BRB	NORMAL			;
 
;
; WRITE CHECK DATA AND WRITE CHECK HEADER AND DATA
;
 
WRITECHECK:				;WRITE CHECK DATA
WRITECHECKH:				;WRITE CHECK HEADER AND DATA
	BBSC	#IO$V_DATACHECK,UCB$W_FUNC(R5),WRITEDATA ;CLEAR DATA CHECK REQUEST
 
;
; WRITE DATA, WRITE HEADER AND DATA, WRITE CHECK DATA, AND WRITE CHECK HEADER
; AND DATA
;
 
WRITEDATA:				;WRITE DATA
WRITEHEAD:				;WRITE HEADER AND DATA
	BISB	#RP_OF_M_ECI/256,UCB$W_OFFSET+1(R5) ;INHIBIT ECC CORRECTION 
 
;
; READ DATA, READ HEADER AND DATA, WRITE DATA, WRITE HEADER AND DATA, WRITE
; CHECK DATA, AND WRITE CHECK HEADER AND DATA
;
 
READDATA:				;READ DATA
READHEAD:				;READ HEADER AND DATA
	BBS	#IO$V_INHSEEK,UCB$W_FUNC(R5),TRANRQCH ;IF SET, NO EXPLICIT SEEK
	EXFUNC	RETRY,F_SEARCHA		;SEARCH AHEAD OF STARTING SECTOR
 
;
; DATA TRANSFER - REQUEST CHANNEL
;
 
TRANRQCH:				;DATA TRANSFER REQUEST CHANNEL
	REQPCHAN LOW			;REQUEST PRIMARY CHANNEL FOR TRANSFER
 
;
; DATA TRANSFER - CHANNEL ALREADY OWNED
;
 
TRANNOCH:				;DATA TRANSFER CHANNEL OWNED
	MOVZBL	UCB$B_FEX(R5),R0	;GET FUNCTION DISPATCH INDEX
	EXFUNC	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_DEVSTS(R5),CHECKXT ;IF SET, ECC CORRECTION MADE
	RELCHAN				;RELEASE CHANNEL
	MOVB	#<RP_OF_M_DCK!-		;SET DATA CHECK IN PROGRESS,
		RP_OF_M_ECI!-		;INHIBIT ECC CORRECTION, AND
		RP_OF_M_FMT>/256,UCB$W_OFFSET+1(R5) ;SET FORMAT
	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
	REQPCHAN LOW			;REQUEST PRIMARY CHANNEL FOR DATA CHECK
	MOVZBL	UCB$B_FEX(R5),R0	;GET FUNCTION DISPATCH INDEX
	MOVZBL	CHECKTAB-CDF_WRITEDATA[R0],R0 ;GET CASE TABLE INDEX
	EXFUNC	TRANXT			;EXECUTE DATA CHECK 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_WRITEDATA,UCB$B_CEX(R5) ;WRITE DATA FUNCTION?
	BEQL	RETRY			;IF EQL YES
	CMPB	#CDF_WRITEHEAD,UCB$B_CEX(R5) ;WRITE HEADER FUNCTION?
	BEQL	RETRY			;IF EQL YES
	BITL	#MBA$M_SR_DLT!-		;DATA LATE OR,
		MBA$M_SR_INVMAP!-	;INVALID MAP REGISTER OR,
		MBA$M_SR_MAPPE!-	;MAP REGISTER PARITY ERROR OR,
		MBA$M_SR_MCPE!-		;MASSBUS CONTROL PARITY ERROR OR,
		MBA$M_SR_MDPE!-		;MASSBUS DATA PARITY ERROR OR,
		MBA$M_SR_MXF!-		;MISSED TRANSFER OR,
		MBA$M_SR_NED!-		;NONEXISTENT DISK OR,
		MBA$M_SR_RDS!-		;READ DATA SUBSTITUTE OR,
		MBA$M_SR_WCKLWR!-	;WRITE CHECK LOWER BYTE OR,
		MBA$M_SR_WCKUPR,R1	;WRITE CHECK UPPER BYTE?
	BNEQ	RETRY			;IF NEQ YES - RETRY FUNCTION
	BITW	#RP_ER1_M_OPI!-		;OPERATION INCOMPLETE OR,
		RP_ER1_M_PAR!-		;PARITY ERROR OR,
		RP_ER1_M_WCF,R2		;WRITE CLOCK FAIL?
	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
	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
	BITW	#RP_ER1_M_HCE!-		;HEADER COMPARE ERROR OR,
		RP_ER1_M_HCRC,R2	;HEADER CRC ERROR?
	BNEQ	10$			;IF NEQ YES
	DECL	R0			;SET TO TRUNCATE LAST BLOCK TRANSFERED
10$:	BICW	#^X1FF,R0		;TRUNCATE RESIDUAL BYTES TRANSFERED
	BITW	#RP_ER1_M_DTE!-		;DRIVE TIMING ERROR OR,
		RP_ER1_M_ECH!-		;ECC HARD ERROR OR,
		RP_ER1_M_HCE!-		;HEADER COMPARE ERROR OR,
		RP_ER1_M_HCRC,R2	;HEADER CRC ERROR?
	BNEQ	OFF			;IF NEQ YES - PERFORM OFFSET RECOVERY
	BBS	#RP_OF_V_ECI,UCB$W_OFFSET(R5),OFF ;IF SET, ECC INHIBITED
	PUSHL	R1			;SAVE TOTAL NUMBER OF BYTES TRANSFERED
	BSBW	IOC$APPLYECC		;APPLY ECC CORRECTION
	POPL	R0			;RETRIEVE TRANSFERED BYTE COUNT
	BSBW	IOC$UPDATRANSP		;UPDATE TRANSFER PARAMETERS
	TSTW	UCB$W_BCNT(R5)		;ANY MORE TO TRANSFER?
	BEQL	20$			;IF EQL NO
	BRW	TRANNOCH		;TRANSFER NEXT SEGMENT
20$:	BRW	DATACHECK		;CHECK FOR WRITE CHECK
 
;
; OFF - OFFSET RECOVERY
;
; THIS CODE IS EXECUTED WHEN A DRIVE TIMING ERROR, HEADER COMPARE, OR ECC
; HARD ERROR IS DETECTED ON A READ FUNCTION.
;
 
OFF:					;OFFSET RECOVERY
	TSTL	R0			;ANY GOOD DATA TRANSFERED?
	BEQL	20$			;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.
;
 
	BSBW	IOC$UPDATRANSP		;UPDATE TRANSFER PARAMETERS
	CLRB	UCB$B_OFFNDX(R5)	;RESET OFFSET TABLE INDEX
10$:	MOVB	#16,UCB$B_OFFRTC(R5)	;SET OFFSET RETRY COUNT
	RELCHAN				;RELEASE CHANNEL
	EXFUNC	FATALERR,F_RETCENTER	;RETURN TO CENTERLINE
	CMPB	#OFFSIZ,UCB$B_OFFNDX(R5) ;ALL OFFSETS TRIED?
	BNEQ	50$			;IF NEQ NO
	BRB	FATALERR		;
 
;
; NO GOOD DATA TRANSFERED - CHECK IF CHANGE IN OFFSET NEEDED
;
 
20$:	BITW	#RP_ER1_M_DCK!-		;DATA CHECK OR,
		RP_ER1_M_DTE!-		;DRIVE TIMING OR,
		RP_ER1_M_ECH,R2		;ECC HARD ERROR?
	BNEQ	30$			;IF NEQ YES
	BISB	#RP_OF_M_HCI/256,UCB$W_OFFSET+1(R5) ;SET HEADER COMPARE INHIBIT
30$:	DECB	UCB$B_OFFRTC(R5)	;CHANGE CURRENT OFFSET?
	BNEQ	60$			;IF NEQ NO
	INCB	UCB$B_OFFNDX(R5)	;UPDATE OFFSET TABLE INDEX
	MOVZBL	UCB$B_OFFNDX(R5),R0	;GET NEXT OFFSET TABLE INDEX
	MOVZBL	OFFTAB-1[R0],R0		;GET NEXT OFFSET VALUE?
	BEQL	10$			;IF EQL RETURN TO CENTERLINE
	BITL	#2,RP_DT(R3)		;RP06 DRIVE?
	BNEQ	40$			;IF NEQ YES
	MULL	#2,R0			;CONVERT TO RP04 OFFSET VALUE
40$:	MOVB	R0,UCB$W_OFFSET(R5)	;SET NEW OFFSET VALUE
	MOVB	#2,UCB$B_OFFRTC(R5)	;SET OFFSET RETRY COUNT
	RELCHAN				;RELEASE CHANNEL
	EXFUNC	FATALERR,F_OFFSET	;OFFSET TO NEXT POSITION
50$:	BICB	#RP_OF_M_HCI/256,UCB$W_OFFSET+1(R5) ;CLEAR HEADER COMPARE INHIBIT
60$:	BBS	#RP_OF_V_DCK,UCB$W_OFFSET(R5),70$ ;IF SET, DATA CHECK FUNCTION
	BRW	TRANRQCH		;TRY FUNCTION AGAIN
70$:	BRW	CHECKRETRY		;TRY DATA CHECK AGAIN
 
;
; RETRIABLE ERROR
;
 
RETRYERR:				;RETRIABLE ERROR
	DECB	UCB$B_ERTCNT(R5)	;ANY RETRIES LEFT?
	BEQL	FATALERR		;IF EQL NO
	RELCHAN				;RELEASE CHANNEL IF OWNED
	BRW	FDISPATCH		;
 
;
; FATAL CONTROLLER/DRIVE ERROR, ERROR RETRY COUNT EXHAUSTED, ERROR RETRY
; INHIBITED, OR FINAL OFFSET TRIED
;
 
FATALERR:				;FATAL ERROR - SET STATUS
	BBC	#RP_DS_V_MOL,R0,10$	;IF CLR, MEDIUM OFFLINE
	BBC	#RP_DS_V_VV,R0,20$	;IF CLR, VOLUME INVALID
	MOVZWL	#SS$_UNSAFE,R0		;SET DRIVE UNSAFE STATUS
	BBS	#RP_ER1_V_UNS,R2,FUNCXT	;IF SET, DRIVE UNSAFE
	MOVZWL	#SS$_OPINCOMPL,R0	;SET OPERATION INCOMPLETE STATUS
	BBS	#RP_ER1_V_OPI,R2,FUNCXT	;IF SET, OPERATION INCOMPLETE
	MOVZWL	#SS$_FORMAT,R0		;SET FORMAT ERROR STATUS
	BBS	#RP_ER1_V_FER,R2,FUNCXT	;IF SET, FORMAT ERROR
	MOVZWL	#SS$_WRITLCK,R0		;SET WRITE LOCK ERROR STATUS
	BBS	#RP_ER1_V_WLE,R2,FUNCXT	;IF SET, WRITE LOCK ERROR
	MOVZWL	#SS$_IVADDR,R0		;SET INVALID DISK ADDRESS STATUS
	BITW	#RP_ER1_M_AOE!-		;DISK ADDRESS OVERFLOW OR,
		RP_ER1_M_IAE,R2		;INVALID DISK ADDRESS ERROR?
	BNEQ	FUNCXT			;IF NEQ YES
	MOVZWL	#SS$_DRVERR,R0		;SET DRIVE ERROR STATUS
	BITW	#RP_ER1_M_DTE!-		;DRIVE TIMING ERROR OR,
		RP_ER1_M_ILF!-		;ILLEGAL FUNCTION OR,
		RP_ER1_M_ILR!-		;ILLEGAL REGISTER OR,
		RP_ER1_M_RMR!-		;REGISTER MODIFY REFUSE OR,
		RP_ER1_M_WCF,R2		;WRITE CLOCK FAIL ERROR?
	BNEQ	FUNCXT			;IF NEQ YES
	MOVZWL	#SS$_PARITY,R0		;SET PARITY ERROR STATUS
	BITW	#RP_ER1_M_DCK!-		;DATA CHECK ERROR OR,
		RP_ER1_M_ECH!-		;ECC HARD ERROR OR,
		RP_ER1_M_HCE!-		;HEADER COMPARE ERROR OR,
		RP_ER1_M_HCRC!-		;HEADER CRC ERROR OR,
		RP_ER1_M_PAR,R2		;PARITY ERROR?
	BNEQ	FUNCXT			;IF NEQ YES
	BITL	#MBA$M_SR_MAPPE!-	;MAP PARITY ERROR OR,
		MBA$M_SR_MCPE!-		;MASSBUS CONTROL PARITY ERROR OR,
		MBA$M_SR_MDPE!-		;MASSBUS DATA PARITY ERROR OR,
		MBA$M_SR_RDS,R1		;READ DATA SUBSTITUTE?
	BNEQ	FUNCXT			;IF NEQ YES
	MOVZWL	#SS$_DATACHECK,R0	;SET DATA CHECK ERROR STATUS
	BITW	#MBA$M_SR_WCKLWR!-	;WRITE CHECK ERROR LOWER BYTE OR,
		MBA$M_SR_WCKUPR,R1	;WRITE CHECK ERROR UPPER BYTE?
	BNEQ	FUNCXT			;IF NEQ YES
	MOVZWL	#SS$_NONEXDRV,R0	;SET NONEXISTENT DRIVE STATUS
	BBS	#MBA$V_SR_NED,R1,FUNCXT	;IF SET, NONEXISTENT DRIVE
	MOVZWL	#SS$_CTRLERR,R0		;SET CONTROLLER ERROR STATUS
	BRB	FUNCXT			;
10$:	MOVZWL	#SS$_MEDOFL,R0		;SET MEDIUM OFFLINE STATUS
	BRB	FUNCXT			;
20$:	MOVZWL	#SS$_VOLINV,R0		;SET VOLUME INVALID STATUS
 
;
; FUNCTION COMPLETION COMMON EXIT
;
 
FUNCXT:					;FUNCTION EXIT
	PUSHR	#^M<R0,R1>		;SAVE REGISTERS
	BSBW	IOC$DIAGBUFILL		;FILL DIAGNOSTIC BUFFER IF PRESENT
	RELCHAN				;RELEASE CHANNEL IF OWNED
	CMPB	#CDF_WRITECHECK,UCB$B_FEX(R5) ;DRIVE RELATED FUNCTION?
	BGTRU	10$			;IF GTRU YES
	CMPB	#CDF_READPRESET,UCB$B_FEX(R5) ;READIN PRESET FUNCTION?
	BEQL	10$			;IF EQL YES
	MOVL	UCB$L_IRP(R5),R2	;RETRIEVE ADDRESS OF IRP
	ADDW3	UCB$W_BCR(R5),IRP$W_BCNT(R2),2(SP) ;CALCULATE BYTES TRANSFERED
10$:	POPR	#^M<R0,R1>		;RESTORE REGISTERS
	REQCOM				;COMPLETE REQUEST
	.PAGE
	.SBTTL	RP04/05/06 HARDWARE FUNCTION EXECUTION
;
; FEX - RP04/05/06 HARDWARE FUNCTION EXECUTION
;
; 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. IF THE FUNCTION IS AN
; IMMEDIATE FUNCTION CONTROL RETURNS IMMEDIATELY. ELSE 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:
;
;	R0 = FUNCTION TABLE DISPATCH INDEX.
;	R3 = ADDRESS OF DRIVE CONTROL STATUS REGISTER 1.
;	R4 = ADDRESS OF MBA CONFIGURATION STATUS REGISTER.
;	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 R0, R1, AND R2, AND THE UCB.
;
;	R0 = DRIVE STATUS REGISTER.
;	R1 = MBA STATUS REGISTER.
;	R2 = DRIVE ERROR REGISTER 1.
;
;	UCB$W_EC1(R5) = ECC POSITION REGISTER.
;	UCB$W_EC2(R5) = ECC PATTERN REGISTER.
;	UCB$W_BCR(R5) = BYTE COUNT REGISTER.
;
 
FEX:					;FUNCTION EXECUTOR
	POPL	UCB$L_DPC(R5)		;SAVE DRIVER PC VALUE
	MOVB	R0,UCB$B_CEX(R5)	;SAVE CASE INDEX
	MOVZBL	UCB$B_SLAVE+1(R5),R3	;GET DRIVE OFFSET CONSTANT
	MOVAL	MBA$L_ERB(R4)[R3],R3	;GET ADDRESS OF DRIVE REGISTERS
	CASE	R0,<-			;DISPATCH TO PROPER FUNCTION ROUTINE
		POSIT,-			;SEEK CYLINDER
		EXFNC,-			;RECALIBRATE
		IMMED,-			;DRIVE CLEAR
		IMMED,-			;RELEASE DRIVE
		EXFNC,-			;OFFSET HEADS
		EXFNC,-			;RETURN TO CENTERLINE
		IMMED,-			;PACK ACKNOWLEDGE
		POSIT,-			;SEARCH FOR SECTOR
		XFER,-			;WRITE CHECK
		XFER,-			;WRITE DATA
		XFER,-			;READ DATA
		XFER,-			;WRITE HEADER AND DATA
		XFER,-			;READ HEADER AND DATA
		XFER,-			;WRITE CHECK HEADER AND DATA
		IMMED,-			;READIN PRESET
		SEARCHA,-		;SEARCH AHEAD FOR SECTOR
		>,LIMIT=#CDF_SEEK	;
 
;
; IMMEDIATE FUNCTION EXECUTION
;
;	FUNCTIONS INCLUDE:
;
;		NO OPERATION,
;		UNLOAD VOLUME,
;		DRIVE CLEAR,
;		RELEASE PORT,
;		READ IN PRESET, AND
;		PACK ACKNOWLEDGE.
;
; THESE FUNCTIONS ARE EXECUTED IMMEDIATELY AND THE FINAL DEVICE REGISTERS
; ARE RETURNED TO THE CALLER.
;
 
IMMED:					;IMMEDIATE FUNCTION EXECUTION
	DSBINT				;DISABLE INTERRUPTS
	BBS	#UCB$V_POWER,UCB$W_STS(R5),ENBXIT ;IF SET, POWER HAS FAILED
	MOVZBL	#F_DRVCLR!1,RP_CS1(R3)	;CLEAR DRIVE ERRORS
	MOVZBL	FTAB[R0],RP_CS1(R3)	;EXECUTE FUNCTION
	BRB	ENBXIT			;
 
;
; SEARCH AHEAD FUNCTION EXECUTION
;
; THIS FUNCTION MINIMIZES ROTATIONAL LATENCY BY SEARCHING FOR THE SECTOR THAT IS
; FOUR SECTORS AHEAD OF THE STARTING SECTOR OF A TRANSFER.
;
; THE DESIRED CYLINDER, TRACK, AND SECTOR ADDRESS REGISTERS ARE LOADED, THE
; FUNCTION IS INITIATED, AND A WAITFOR INTERRUPT IS EXECUTED. WHEN THE INTER-
; RUPT OCCURS, THE FINAL DEVICE REGISTERS ARE RETURNED TO THE CALLER.
;
 
SEARCHA:				;
	MOVZWL	UCB$W_DA(R5),R1		;GET DESIRED TRACK AND SECTOR ADDRESS
	SUBB	#4,R1			;COMPUTE FOUR SECTORS BEFORE SPECIFIED SECTOR
	BGEQ	10$			;IF GEQ BEFORE SECTOR ZERO
	ADDB	UCB$B_SECTORS(R5),R1	;CONVERT TO AFTER SECTOR ZERO
10$:	MOVL	R1,RP_DA(R3)		;SET TRACK AND SECTOR ADDRESS
	BRB	LDCYL			;
 
;
; TRANSFER FUNCTION EXECUTION
;
;	FUNCTIONS INCLUDE:
;
;		WRITE CHECK,
;		WRITE CHECK HEADER AND DATA,
;		WRITE DATA,
;		WRITE HEADER AND DATA,
;		READ DATA, AND
;		READ HEADER AND DATA.
;
; THE MAP REGISTERS, BYTE COUNT REGISTER, AND VIRTUAL ADDRESS REGISTER ARE
; LOADED FOLLOWED BY THE DESIRED CYLINDER, TRACK, AND SECTOR ADDRESS REGISTERS.
; THE FUNCTION IS INITIATED AND A WAITFOR INTERRUPT IS EXECUTED. WHEN THE
; INTERRUPT OCCURS, THE FINAL DEVICE REGISTERS ARE RETURNED TO THE CALLER.
;
; IT ASSUMED THAT THE CALLER OWNS THE CHANNEL ON WHICH THE I/O IS TO OCCUR.
;
 
XFER:					;TRANSFER FUNCTION EXECUTION
	MCOML	#0,MBA$L_SR(R4)		;CLEAR MASSBUS ADAPTER ERRORS
	LOADMBA				;LOAD MAP, BYTE COUNT, AND VIRTUAL ADDRESS
	MOVZBL	UCB$B_CEX(R5),R0	;RETRIEVE FUNCTION TABLE INDEX
 
;
; POSITIONING FUNCTION EXECUTION
;
;	FUNCTIONS INCLUDE:
;
;		SEEK CYLINDER, AND
;		SEARCH FOR SECTOR.
;
; THE DESIRED CYLINDER, TRACK, AND SECTOR ADDRESS REGISTERS ARE LOADED, THE
; FUNCTION IS INITIATED, AND A WAITFOR INTERRUPT IS EXECUTED. WHEN THE INTER-
; RUPT OCCURS, THE FINAL DEVICE REGISTERS ARE RETURNED TO THE CALLER.
;
 
POSIT:					;POSITION FUNCTION EXECUTION
	MOVZWL	UCB$W_DA(R5),RP_DA(R3)	;SET DESIRED TRACK AND SECTOR ADDRESS
LDCYL:					;
	MOVZWL	UCB$W_DC(R5),RP_DC(R3)	;SET DESIRED CYLINDER ADDRESS
 
;
; INTERRUPT WAIT FUNCTION EXECUTION
;
;	FUNCTIONS INCLUDE:
;
;		OFFSET HEADS,
;		RECALIBRATE, AND
;		RETURN TO CENTERLINE.
;
; THE OFFSET REGISTER IS LOADED, THE FUNCTION IS INITIATED, AND A WAITFOR
; INTERRUPT IS EXECUTED. WHEN THE INTERRUPT OCCURS, THE FINAL DEVICE REGISTERS
; ARE RETURNED TO THE CALLER.
;
 
EXFNC:					;EXECUTE FUNCTION
	DSBINT				;DISABLE INTERRUPTS
	BBS	#UCB$V_POWER,UCB$W_STS(R5),ENBXIT ;IF SET, POWER FAILED
	MOVZBL	#F_DRVCLR!1,RP_CS1(R3)	;CLEAR DRIVE ERRORS
	MOVZWL	UCB$W_OFFSET(R5),RP_OF(R3) ;SET FORMAT, INHIBIT BITS, AND OFFSET
	MOVZBL	FTAB[R0],RP_CS1(R3)	;INITIATE FUNCTION
	WFIKPCH	RETREG,#6		;WAITFOR INTERRUPT AND KEEP CHANNEL
	MOVL	MBA$L_SR(R4),UCB$L_DB_SR(R5) ;SAVE FINAL CONTROLLER STATUS
	IOFORK				;CREATE FORK PROCESS
	BRB	RETREG			;
 
;
; ENABLE INTERRUPTS
;
 
ENBXIT:					;
	ENBINT				;ENABLE INTERRUPTS
 
;
; RETURN REGISTERS
;
 
RETREG:					;RETURN FINAL DEVICE REGISTERS
	CVTLW	RP_EC1(R3),UCB$W_EC1(R5) ;SAVE ECC POSITION REGISTER
	CVTLW	RP_EC2(R3),UCB$W_EC2(R5) ;SAVE ECC PATTERN REGISTER
	CVTLW	MBA$L_BCR(R4),UCB$W_BCR(R5) ;SAVE BYTE COUNT REGISTER
	MOVL	RP_DS(R3),R0		;GET CONTENTS OF DRIVE STATUS REGISTER
	MOVL	UCB$L_DB_SR(R5),R1	;RETRIEVE FINAL CONTROLLER STATUS
	MOVL	RP_ER1(R3),R2		;GET CONTENTS OF DRIVE ERROR REGISTER 1
	BITW	#UCB$M_POWER!-		;POWER FAIL OR DEVICE TIMEOUT?
		UCB$M_TIMOUT,UCB$W_STS(R5) ;
	BNEQ	40$			;IF NEQ YES - SPECIAL CONDITION
	CMPB	#CDF_WRITECHECK,UCB$B_CEX(R5) ;DRIVE RELATED FUNCTION?
	BGTRU	10$			;IF GTRU YES
	CMPB	#CDF_READPRESET,UCB$B_CEX(R5) ;READIN PRESET FUNCTION?
	BEQL	10$			;IF EQL YES
 
;
; CONTROLLER RELATED FUNCTION
;
 
	BITL	#MBA$M_ERROR,R1		;ANY CONTROLLER ERRORS?
	BEQL	30$			;IF EQL NO
	BSBW	ERL$DEVICERR		;ALLOCATE AND FILL ERROR MESSAGE BUFFER
	BBS	#IO$V_INHRETRY,UCB$W_FUNC(R5),50$ ;IF SET, RETRY INHIBITED
	BITL	#MBA$M_SR_ERCONF!-	;ERROR CONFIRMATION OR,
		MBA$M_SR_ISTO!-		;INTERFACE SEQUENCE TIMEOUT OR,
		MBA$M_SR_PGE!-		;PROGRAMMING ERROR OR,
		MBA$M_SR_RDTO,R1	;READ TIMEOUT?
	BNEQ	50$			;IF NEQ YES - FATAL CONTROLLER ERROR
	BITL	#MBA$M_SR_DLT!-		;DATA LATE OR,
		MBA$M_SR_INVMAP!-	;INVALID MAP REGISTER OR,
		MBA$M_SR_MAPPE!-	;MAP REGISTER PARITY ERROR OR,
		MBA$M_SR_MBEXC!-	;MASSBUS EXCEPTION OR,
		MBA$M_SR_MCPE!-		;MASSBUS CONTROL PARITY ERROR OR,
		MBA$M_SR_MDPE!-		;MASSBUS DATA PARITY ERROR OR,
		MBA$M_SR_MXF!-		;MISSED TRANSFER OR,
		MBA$M_SR_NED!-		;NONEXISTENT DRIVE OR,
		MBA$M_SR_RDS!-		;READ DATA SUBSTITUTE OR,
		MBA$M_SR_WCKLWR!-	;WRITE CHECK LOWER BYTE OR,
		MBA$M_SR_WCKUPR,R1	;WRITE CHECK UPPER BYTE?
	BNEQ	20$			;IF NEQ YES - RETRIABLE CONTROLLER ERROR
 
;
; DRIVE RELATED FUNCTION
;
 
10$:	BBC	#RP_DS_V_ERR,R0,30$	;IF CLR, NO DRIVE ERRORS
	BSBW	ERL$DEVICERR		;ALLOCATE AND FILL ERROR MESSAGE BUFFER
	BBS	#IO$V_INHRETRY,UCB$W_FUNC(R5),50$ ;IF SET, RETRY INHIBITED
20$:	BBC	#RP_DS_V_MOL,R0,50$	;IF CLR, MEDIUM OFFLINE
	BBC	#RP_DS_V_VV,R0,50$	;IF CLR, INVALID VOLUME
	BITW	#RP_ER1_M_AOE!-		;ADDRESS OVERFLOW OR,
		RP_ER1_M_FER!-		;FORMAT ERROR OR,
		RP_ER1_M_IAE!-		;INVALID ADDRESS OR,
		RP_ER1_M_ILF!-		;ILLEGAL FUNCTION OR,
		RP_ER1_M_ILR!-		;ILLEGAL REGISTER OR,
		RP_ER1_M_RMR!-		;REGISTER MODIFY REFUSE OR,
		RP_ER1_M_UNS!-		;DRIVE UNSAFE OR,
		RP_ER1_M_WLE,R2		;WRITE LOCK ERROR?
	BNEQ	50$			;IF NEQ YES - FATAL DRIVE ERROR
 
;
; RETRIABLE ERROR EXIT
;
 
	CVTBL	@UCB$L_DPC(R5),-(SP)	;GET BRANCH DISPLACEMENT
	ADDL	(SP)+,UCB$L_DPC(R5)	;CALCULATE RETURN ADDRESS - 1
30$:	INCL	UCB$L_DPC(R5)		;ADJUST TO CORRECT RETURN ADDRESS
	JMP	@UCB$L_DPC(R5)		;RETURN TO DRIVER
 
;
; SPECIAL CONDITION EXIT
;
 
40$:	CMPB	#CDF_WRITECHECK,UCB$B_CEX(R5) ;DRIVE RELATED FUNCTION?
	BGTRU	45$			;IF GTRU YES
	CMPB	#CDF_READPRESET,UCB$B_CEX(R5) ;DRIVE RELATED FUNCTION?
	BLEQU	45$			;IF LEQU YES
	MOVL	#MBA$M_CR_ABORT,MBA$L_CR(R4) ;ABORT CURRENT TRANSFER
45$:	SETIPL	UCB$B_FIPL(R5)		;LOWER IPL TO DEVICE FORK LEVEL
	MOVL	#MBA$M_CR_IE,MBA$L_CR(R4) ;ENABLE MBA INTERRUPTS
 
;
; FATAL CONTROLLER OR DRIVE ERROR EXIT
;
 
50$:	BRW	FATALERR		;
	.PAGE
	.SBTTL	RP04/05/06 REGISTER DUMP ROUTINE
;
; REGDUMP - RP04/05/06 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 ADAPTER CONFIGURATION REGISTER.
;	R5 = DEVICE UNIT UCB ADDRESS.
;
; OUTPUTS:
;
;	THE CONTROLLER AND DRIVE REGISTERS ARE SAVED IN THE SPECIFIED BUFFER.
;
 
REGDUMP:				;RP04/05/06 REGISTER DUMP ROUTINE
	MOVL	#<RP_EC2+4+MBA$L_BCR+4+8>/4,(R0)+ ;INSERT NUMBER OF DEVICE REGISTERS
	MOVL	MBA$L_CSR(R4),(R0)+	;SAVE CONFIGURATION REGISTER
	MOVL	MBA$L_CR(R4),(R0)+	;SAVE CONTROL REGISTER
	MOVL	UCB$L_DB_SR(R5),(R0)+	;SAVE STATUS REGISTER
	MOVL	MBA$L_VAR(R4),(R0)+	;SAVE VIRTUAL ADDRESS REGISTER
	MOVL	MBA$L_BCR(R4),(R0)+	;SAVE BYTE COUNT REGISTER
	EXTZV	#9,#8,-8(R0),R1		;GET FINAL MAP REGISTER NUMBER
	MOVL	MBA$L_MAP(R4)[R1],(R0)+	;SAVE FINAL MAP REGISTER CONTENTS
	CLRL	(R0)+			;ASSUME NO PREVIOUS MAP REGISTER
	DECL	R1			;CALCULATE PREVIOUS MAP REGISTER NUMBER
	BLSS	10$			;IF LSS NONE
	MOVL	MBA$L_MAP(R4)[R1],-4(R0) ;SAVE PREVIOUS MAP REGISTER CONTENTS
10$:	MOVZBL	#<RP_EC2+4>/4,R1	;SET NUMBER OF DRIVE REGISTERS TO SAVE
	MOVZBL	UCB$B_SLAVE+1(R5),R2	;GET DRIVE OFFSET CONSTANT
	MOVAL	MBA$L_ERB(R4)[R2],R2	;GET ADDRESS OF DRIVE REGISTERS
20$:	MOVL	(R2)+,(R0)+		;SAVE DRIVE REGISTER
	SOBGTR	R1,20$			;ANY MORE TO SAVE?
	RSB				;
 
UNSOLNT:	RSB			;******TEMP*******
 
	.END
