	.TITLE	HDDRV
	.IDENT	/01.00/

	.MCALL	SCBDF$,UCBDF$

	SCBDF$	,,SYSDEF
	UCBDF$

.IIF	DF	M$$MGE	.ERROR		;MEMORY MANAGEMENT NOT SUPPORTED

;
;LOCAL DEFINITIONS
;
CS.UNI	=	1			;SET UNIT COMMAND
CS.BLK	=	2			;SET STARTING BLOCK NUMBER COMMAND
CS.BUF	=	3			;SET BUFFER ADDRESS COMMAND
CS.WCT	=	4			;SET WORD COUNT COMMAND
CS.RLB	=	5			;READ LOGICAL BLOCK COMMAND
CS.WLB	=	6			;WRITE LOGICAL BLOCK COMMAND
CS.SIZ	=	7			;GET DISK SIZE COMMAND

;
;DRIVER DISPATCH TABLE
;
$HDTBL::
	.WORD	HDINI			;DEVICE INITIATOR ENTRY POINT
	.WORD	HDCAN			;CANCEL I/O OPERATION ENTRY POINT
	.WORD	HDOUT			;DEVICE TIMEOUT ENTRY POINT
	.WORD	HDPWF			;POWERFAIL ENTRY POINT

;+
;**-HDINI- HD DISK COTROLLER INITIATOR
;
;THIS ROUTINE IS ENTERED FROM THE QUEUE I/O DIRECTIVE WHEN AN I/O REQUEST
;IS QUEUED AND THE END OF A PREVIOUS I/O OPERATION TO PROPAGATE THE
;EXECUTION OF THE DRIVER. IF THE SPECIFIED CONTROLLER IS NOT BUSY, THEN AN
;ATTEMPT IS MADE TO DEQUEUE THE NEXT I/O REQUEST. ELSE A RETURN TO THE
;CALLER IS EXECUTED. IF THE DEQUEUE ATTEMPT IS SUCCESSFUL, THEN THE NEXT I/O
;OPERATION IS INITIATED. A RETURN TO THE CALLER IS THEN EXECUTED.
;
;INPUTS:
;	R5	- ADDRESS OF THE UCB OF THE CONTROLER TO BE INITIATED
;-
HDINI:	CALL	$GTPKT			;GET AN I/O PACKET TO PROCESS
	BCS	HDOUT			;IS CS CONTROLLER BUSY OR NO REQUEST
;
;THE FOLLOWING ARGUMENTS ARE RETURNED BY $GTPKT:
;
;	R1	- ADDRESS OF THE I/O REQUEST PACKET
;	R2	- PHYSICAL UNIT NUMBER OF THE REQUEST UCB
;	R3	- CONTROLLER INDEX
;	R4	- ADDRESS OF THE SCB
;	R5	- ADDRESS OF THE UCB
;
	MOV	#IE.IFC&377,R0		;ASSUME ILLEGAL FUNCTION
	MOV	#CS.WLB,I.PRM+14(R1)	;ASSUME WRITE LOGICAL BLOCK FUNCTION
	CMPB	#IO.WLB/400,I.FCN+1(R1)	;WRITE LOGICAL BLOCK FUNCTION?
	BEQ	10$			;IF EQ YES
	MOV	#CS.RLB,I.PRM+14(R1)	;ASSUME WRITE LOGICAL BLOCK FUNCTION
	CMPB	#IO.RLB/400,I.FCN+1(R1)	;READ LOGICAL BLOCK FUNCTION?
	BEQ	10$			;IF EQ YES
.IF	DF	E$$DVC
	CLR	R2			;SET STARTING/FINAL RETRY COUNT
.ENDC
	BR	50$			;FINISH I/O OPERATION
10$:	CALL	$BLKCK			;CHECK LOGICAL BLOCK NUMBER
	MOV	S.CSR(R4),R2		;GET ADDRESS OF CSR
	MOVB	U.UNIT(R5),R1		;GET UNIT NUMBER
	MOV	R1,2(R2)		;SELECT THE DRIVE
	MOV	#CS.UNI,@R2		;SET UNIT COMMAND
	TST	@R2			;SELECT ERROR?
	BMI	40$			;IF MI YES
	MOV	R0,2(R2)		;SET BLOCK NUMBER
	MOV	#CS.BLK,@R2		;
	TST	@R2			;SELECT ERROR?
	BMI	40$			;IF MI YES
	MOV	I.PRM+2(R3),2(R2)	;SET BUFFER ADDRESS
	MOV	#CS.BUF,@R2		;
	MOV	I.PRM+4(R3),R1		;GET BYTE COUNT
	MOV	R1,R0			;
	ROR	R0			;CONVERT TO WORD COUNT
	MOV	R0,2(R2)		;SET WORD COUNT
	MOV	#CS.WCT,@R2		;
	MOV	#IS.SUC,R0		;ASSUME SUCCESFUL COMPLETION
	TST	@R2			;PAST END OF DISK?
	BMI	40$			;IF MI YES
	MOV	I.PRM+14(R3),@R2	;START I/O OPERATION
	TST	@R2			;I/O ERROR?
	BPL	50$			;IF PL NO
40$:	MOV	#IE.VER&377,R0		;UNRECOVERABLE I/O ERROR
	CLR	R1			;
50$:	CLR	R2			;XXX
	CALL	$IODON			;FINISH I/O OPERATION
	BR	HDINI			;PROCESS THE NEXT REQUEST

;+
;**-HDPWF- POWERFAIL ENTRY POINT
;
;HANDLE POWER FAILURES AND BRING CONTROLLER(S) AND UNIT(S) ONLINE
;FOR RSX-11M
;
;INPUTS:
;	R4	- SCB
;	R5	- UCB
;-
HDPWF:	MOV	S.CSR(R4),R0		;GET ADDRESS OF CSR
	MOVB	U.UNIT(R5),R1		;GET PHYSICAL UNIT NUMBER
	BISB	#US.OFL,U.ST2(R5)	;ASSUME UNIT OFFLINE
	MOV	R1,2(R0)		;SELECT UNIT NUMBER
	MOV	#CS.UNI,@R0		;SET UNIT COMMAND
	TST	@R0			;UNIT OFFLINE?
	BMI	HDOUT			;IF MI YES
	BICB	#US.OFL,U.ST2(R5)	;BRING UNIT ONLINE
	MOV	#CS.SIZ,@R0		;GET DEVICE SIZE COMMAND
	MOV	2(R0),U.CW3(R5)		;UPDATE UCB

HDOUT:
HDCAN:	RETURN				;RETURN

	.END
                                                              