	.IF	LISTG
	.LIST
	.PAGE
	.ELSE
	.NOLIST
	.ENDC
;****************************************************************************
;
;	Winchester Disk Driver - part 3
;
;	File:	SAGE.BIOSG.TEXT
;	Date:	27-Oct-83
;	Issue:	2C
;
;
;	COPYRIGHT (c) 1983 SAGE Computer Technology
;	All Rights Reserved
;
;****************************************************************************
;
;	History:
;
;	2     23-Mar-83 Initial SAGE IV release.
;	2A     6-Jun-83 Disable foreground around CSCHED.
;			Clear device map in WCFCH9.
;			Added CRC calculation & read back.
;			Fixed number of tracks returned by UNITSTATUS.
;			Added interrupt driven seek.
;	2B     1-Aug-83 Added track 0 seek error recovery.
;			Put in recovery for drive not ready.
;			Added recovery from read after write errors.
;	2C    27-Oct-83 UNITCLEAR modified to not recalibrate or reload
;			track map.
;			Allow seek only via control word bit 14.
;
;****************************************************************************


.PAGE
;****************************************************************************
;
;	Reading & Writing
;
;****************************************************************************

WTCHAN9
	MOVEM.L D1-D2/A4,-(SP)
	ST	D1		;Set write request flag
	BRA.S	CHAN9

RDCHAN9
	MOVEM.L D1-D2/A4,-(SP)
	CLR.B	D1		;Clear write request flag

CHAN9
	BSR	WDADDR		;Get drive table address
	BEQ.S	$60		;No drive defined
$5	MOVE	#2100H,SR	;Disable interrupts
	TST.B	WG_BUSY		;See if disk is busy
	BEQ.S	$10		;Disk is not busy
	STOP	#2000H		;Hang here
	BRA	$5		;Check again

;	Disk is not busy
$10	ST	WG_BUSY		;Mark disk busy
	MOVE	#2000H,SR	;Re-enable interrupts
	MOVE.L	A4,WG_VARS
	CLR.B	WG_DONE		;Indicate not done
	MOVE.B	D1,WT_DIR(A4)	;Set up direction
	SWAP	D0
	MOVE.B	D0,WT_CHAN(A4)	;Set up logical channel
	MOVE.L	4(A0),WT_LENG(A4) ;Set up length of transfer
	MOVE.L	8(A0),WT_MEMA(A4) ;Set up memory address for transfer
	MOVE.W	12.(A0),WT_LBN+2(A4);Set up low part of logical block number
	MOVE.W	14.(A0),WT_CTRL(A4) ;Set up control word
	MOVE.W	16.(A0),WT_LBN(A4) ;Set up high part of logical block number

;	Simulate an interrupt
	PEA	$20		;Return address
	MOVE	SR,-(SP)	; and status
	BRA	WTINIT		;Start the transfer process
	
;	Continue after initial activity
$20	BTST	#0,WT_CTRL+1(A4) ;Check for asynchronous request
	BNE.S	$50		;Found async request, just exit

;	Check for completion
$30	MOVE	#2100H,SR	;Disable interrupts
	TST.B	WG_DONE		;Check if done
	BNE.S	$40		;Done with transfer
	STOP	#2000H		;Hang here
	BRA	$30

;	Process transfer completion
$40	MOVE.B	WS_ERR(A4),D0	;Set up error reply
	EXT.W	D0
	MOVE.W	D0,2(A0)
$50	MOVEM.L (SP)+,D1-D2/A4
	RTS

;	No drive exists
$60	MOVE.W	#-14.,2(A0)	;Error code
	BRA	$50



.PAGE
;****************************************************************************
;
;	Transfer Initialization
;
;	Simulated interrupt which runs with interrupts & foreground
;	enabled.
;
;****************************************************************************

WTINIT
	MOVEM.L D0-D2/A0-A2/A4,-(SP)
	MOVEA.L WG_VARS,A4
	MOVE.W	#0D6H,D0	;Check for special tests
	AND.W	WI_TEST(A4),D0
	BNE	WTINITX		;Found special test
	TST.B	WG_INIT		;Check if controller is initialized
	BNE.S	$10		;Controller already initialized
	BSR	WCINIT		;Init the controller
$10	BTST	#4,WT_CTRL(A4)	;Check for CRC operation
	BNE	WTINIT8		;Found CRC operation
	BSR	WDSELECT
WTINIT1
	MOVE.B	WI_RTRY(A4),WT_RTRY(A4) ;Set up initial retry count
	MOVE.B	WI_WTRY(A4),WT_WTRY(A4) ;Set up write retry count
WTINIT2				;Direct entry point
	CLR.B	WS_ERR(A4)
	TST.B	WT_DIR(A4)	;Check for write
	BEQ.S	$5		;Not write
	BTST	#0,WI_STYPE+1(A4) ;Check for Syquest drive
	BEQ.S	$5		;Not Syquest
	BTST	#WB_WPROT,WP_1A ;Check for Write Protect
	BEQ	$70		;Write protect violation
$5	MOVEQ	#61.,D0
	SWAP	D0
$7	BTST	#WB_READY,WP_1A ;Check if drive ready
	BEQ.S	$8		;Drive is ready
	SUBQ.L	#1,D0
	BNE	$7		;Check again
	BRA	$80		;Drive never got ready
	
$8	TST.B	WG_INIT		;Check if controller is initialized
	BNE.S	$10		;Controller was initialized
	BSR	WCINIT		;Initialize the controller
$10	TST.B	WS_INIT(A4)	;Check if drive info is initialized
	BNE.S	$20		;Drive was initialized
	BSR	WDINIT		;Set up drive initialization
$20	CMPI.B	#2,WT_IMODE(A4) ;Check for drive initialize completion
	BNE.S	$30		;Not drive init completion
	BSR	WDINITC		;Set up drive initialize completion
$30	TST.L	WT_LENG(A4)	;See if any more bytes to transfer
	BEQ	WDEXIT		;No bytes left to transfer
	BSR	WDCALC		;Calculate transfer parameters
	BNE	WDIOERR		;Terminate on error
	MOVE.B	WT_DIR(A4),D0	;Check direction
	BEQ.S	$40		;Was read
	BTST	#5,WT_CTRL(A4)	;Check if formatting
	BEQ.S	$35		;Standard write
	MOVEQ	#2,D0		;Bypass read before write when formatting
	BRA	$40
	
$35	MOVEQ	#1,D0		;Set to Read before Write
$40	MOVE.B	D0,WT_TYPE(A4)
	MOVEQ	#0,D0
	MOVE.L	D0,WG_CONT	;Clear the continuation address
	CLR.B	WT_SKDN(A4)	;Clear the seek done flag
	BSR	WDSEEK		;Set up the seek
	MOVE	#2100H,SR	;Disable interrupts
	BCLR	#7,P8259+2	;Enable foreground interrupts
	TST.B	WT_SKDN(A4)	;Check for seek done
	BNE.S	$50		;Seek is done
	LEA	WDSKCOMP,A0	;Set up seek completion address
	MOVE.L	A0,WG_CONT
	BRA.S	$60		;Exit, RTE will enable interrupts

;	Directly enter WDDKIO
$50	MOVE	#2000H,SR
	BRA	WDDKIO1
	
$60	MOVEM.L (SP)+,D0-D2/A0-A2/A4
	RTE
	
;	Write protect violation
$70	MOVE.B	#-10.,WS_ERR(A4)
	BRA	WDIOERR

;	Drive is not ready
$80	MOVE.B	#-4.,WS_ERR(A4)
	BRA	WDIOERR
	
	
;	Test sequences
WTINITX
	MOVE.W	WI_TEST(A4),D0
	BTST	#1,D0		;Check for stepping test
	BNE.S	WTINIT5		;Found stepping test
	BTST	#2,D0		;Check for buffer test
	BNE.S	WTINIT3		;Found test selection
	BTST	#4,D0		;Check for D/A application
	BNE.S	WTINIT4		;Found D/A application
	BTST	#6,D0		;Check for VCO initialization.
	BNE.S	WTINIT6		;Found VCO initialization.
	BTST	#7,D0		;Check for drive status readback
	BNE.S	WTINIT7		;Found status readback
	BRA	WDEXIT

;	Set up buffer test
WTINIT3
	BSR	WDTEST1
	BRA	WDEXIT
	
;	Apply D/A value
WTINIT4
	MOVEA.L WT_MEMA(A4),A0
	MOVE.B	(A0),WP_DTOA	;Apply D/A value directly
	BRA	WDEXIT
	
;	Stepping test
WTINIT5
	MOVE.W	WT_LBN+2(A4),D1 ;Get step count
	BSR	WDSTEP
	BRA	WDEXIT
	
;	VCO read back & initialization
WTINIT6
	MOVEA.L WT_MEMA(A4),A1
	TST.B	WT_DIR(A4)
	BNE.S	$10		;Was write request
	MOVE.W	VCOCAL,(A1)+
	MOVE.W	VCOVAL,(A1)+
	MOVE.B	WG_VCODA,(A1)+
	MOVE.B	WG_VCOF,(A1)+
	BRA.S	WDEXIT
	
;	Write VCO data
$10	MOVE.W	(A1),VCOCAL
	BSR	WVCOINIT	;Recalibrate VCO
	BRA.S	WDEXIT
	
;	Drive Status readback
WTINIT7
	BSR	WDSELECT	;Select the drive
	MOVEA.L WT_MEMA(A4),A1
	MOVE.B	WP_1A,(A1)+	;Fetch port A
	BRA.S	WDEXIT
	
;	CRC operations
WTINIT8
	TST.B	WT_DIR(A4)	;Check direction
	BNE.S	$10		;Was write
	MOVEA.L WT_MEMA(A4),A1	;Pass CRC back
	MOVE.W	WI_CRC(A4),(A1)
	BRA.S	WDEXIT

$10	BSR	WDTEST1		;Calculate CRC

;	Fall into WDEXIT

;****************************************************************************
;
;	Done with Winchester Transfer
;
;****************************************************************************

WDEXIT
	BTST	#0,WI_TEST+1(A4) ;Check for special read test
	BNE.S	$10		;Don't deselect
	MOVE.B	WP_1B,D0	;Deselect the drive
	ANDI.B	#0F0H,D0
	MOVE.B	D0,WP_1B
$10	ST	WG_DONE		;Indicate done
	CLR.B	WG_BUSY		;Indicate not busy
	CLR.B	WT_IMODE(A4)	;Clear possible unfinished initialization
	BTST	#0,WT_CTRL+1(A4);Check for asynchronous transfer
	BEQ.S	$20		;Not asynchrounous
	MOVE.B	ATCHTBL+48.,D0	;Check if Attached
	BEQ.S	$20		;Not attached
	MOVEQ	#0,D0
	MOVE.B	WS_ERR(A4),D0	;Pass error code in high word
	SWAP	D0
	MOVE.W	#48.,D0
	JSR	SIGEVENT	;Signal the event
$20	MOVEM.L (SP)+,D0-D2/A0-A2/A4
	RTE
	
.PAGE
;****************************************************************************
;
;	Controller/Drive Transfer
;
;	Simulated interrupt which runs with interrupts & foreground
;	enabled.
;
;****************************************************************************

WDDKIO
	MOVEM.L D0-D2/A0-A2/A4,-(SP)
	MOVEA.L WG_VARS,A4
WDDKIO1				;Direct entry
	TST.B	WS_ERR(A4)	;Check for detected errors
	BNE	WDIOERR		;Found error
	BTST	#5,WI_TEST+1(A4);Check for seek only
	BNE	WDEXIT		;Direct seek is done
	BTST	#6,WT_CTRL(A4)	;Check for seek only (alternate spec)
	BNE	WDEXIT		;Direct seek is done
	MOVEQ	#0,D0
	MOVE.L	D0,WG_CONT	;Clear the continuation
	CLR.B	WG_IODN		;Clear the I/O done flag
	CMPI.B	#2,WT_TYPE(A4)	;Find which direction
	BEQ.S	$10		;Write direction
	BSR	WDREAD		;Set up the read
	BRA.S	$20

$10	BTST	#5,WT_CTRL(A4)	;Check if formatting
	BEQ.S	$15		;Not formatting
	BSR	WDMOVEO		;Move data to controller
$15	BSR	WDWRITE		;Set up the write

$20	MOVE	#2100H,SR	;Disable interrupts
	TST.B	WG_IODN		;Check for I/O done
	BNE.S	$30		;I/O is already done
	LEA	WDDKIOC,A0	;Set up I/O completion address
	MOVE.L	A0,WG_CONT
	LEA	WT_TIMO,A0	;Set up winchester timeout
	PEA	WDTIMO
	MOVE.L	(SP)+,4(A0)
	MOVEQ	#0,D0
	MOVE.W	#32000.,D0	;Allow .5 seconds
	MOVE.L	D0,8(A0)
	BSR	ESCHED		;Enter the schedule
	MOVEM.L (SP)+,D0-D2/A0-A2/A4
	RTE			;Re-enables interrupts
	
;	Direct transfer to I/O Completion
$30	MOVE	#2000H,SR	;Re-enable interrupts
	BRA.S	WDDKIOC1

.PAGE
;****************************************************************************
;
;	Controller/Drive Transfer Completion
;
;	Simulated interrupt which runs with interrupts & foreground
;	enabled.
;
;****************************************************************************

WDDKIOC
	MOVEM.L D0-D2/A0-A2/A4,-(SP)
	MOVEA.L WG_VARS,A4
WDDKIOC1			;Direct entry
	BCLR	#1,WP_2B	;Disable winchester interrupt
	MOVE.B	#8,WP_2CB	;Disable writing
	BSET	#6,WP_2B	;Disable write buffer
	MOVE.B	#5,WP_2CB	;Disable ram outputs
	BSET	#7,WP_2B	;Disable output buffers of read latch
	MOVE.B	#0FH,WP_2CB	;Set up CPU mode for controller buffer
	MOVE.B	#2,WP_2CB	;Set R/W mode mux to read
	LEA	WT_TIMO,A0	;Disable schedule
	BSET	#7,P8259+2	;Disable foreground
	BSR	CSCHED
	BCLR	#7,P8259+2	;Enable foreground
	BTST	#0,WI_TEST+1(A4)
	BNE.S	$10		;Bypass normal read/write activities
	TST.B	WS_ERR(A4)	;Check for detected errors
	BNE	WDIOERR		;Found error
	TST.B	WG_IODN		;Check if normal completion
	BEQ	$50		;Must have been timeout
	MOVEQ	#0,D0
	MOVE.L	D0,WG_CONT	;Clear the continuation
	MOVE.B	WT_TYPE(A4),D0	;Check which type
	BEQ.S	$20		;Was read
	SUBQ.B	#1,D0
	BEQ.S	$30		;Was read before write
	SUBQ.B	#1,D0
	BEQ.S	$40		;Was write

;	Process read after write
	BSR	WDVERIFY	;Verify the buffer data
	BNE	WDIOERR		;Found error
	
;	Update transfer arguments
$10	MOVEQ	#0,D0
	MOVE.W	WT_NUMB(A4),D0	;Set up byte count
	ADD.L	D0,WT_MEMA(A4)
	SUB.L	D0,WT_LENG(A4)
	DIVU	WI_BPS(A4),D0	;Calculate number of blocks
	EXT.L	D0		;Clear high part
	ADD.L	D0,WT_LBN(A4)
	ST	WS_INIT(A4)	;Mark drive maps initialized
	BRA	WTINIT1		;Set up next portion of transfer

;	Process read
$20	BSR	WDMOVEI		;Move data into memory from buffer
	BNE	WDIOERR		;Found error
	CMPI.B	#1,WT_IMODE(A4) ;Check if just read init data
	BNE	$10		;Update the arguments
	MOVE.B	#2,WT_IMODE(A4) ;Set up completion
	BRA	$10		;Update transfer arguments

;	Process read before write
$30	BSR	WDVERIFY	;Verify the buffer data
	BNE	WDIOERR		;Found error
	BSR	WDMOVEO		;Move data into buffer from memory
	MOVE.B	#2,WT_TYPE(A4)	;Set up write pass
	BRA	WDDKIO1		;Initiate transfer, via direct entry

;	Process write
$40	MOVE.B	#3,WT_TYPE(A4)	;Set up read after write pass
	MOVE.B	WI_RAWRT(A4),WT_RTRY(A4) ;Set up read after write retrys
	BRA	WDDKIO1		;Initiate transfer, via direct entry

;	Found timeout error
$50	MOVE.B	#-6,WS_ERR(A4)
	BRA	WDIOERR		;Enter error process

;****************************************************************************
;
;	Winchester Error Analysis
;
;****************************************************************************

WDIOERR
	CMPI.B	#1,WT_IMODE(A4) ;Check if initializing bad block table
	BNE.S	$5		;Not initiazation error
	BSR	WDCLTBL		;Clear bad track table
$5	MOVE.B	WS_ERR(A4),D0
	TST.B	WI_FERR(A4)	;Check if already had first error
	BNE.S	$10		;Not first error
	MOVE.B	D0,WI_FERR(A4)	;Save first error
$10	MOVE.B	D0,WI_LERR(A4)	;Save last error
	SUBQ.B	#1,WT_RTRY(A4)	;Check for retries
	BLE	$70		;No more retries
	
	CMPI.B	#-7,D0
	BEQ.S	$40		;Overrun, retry read/write
	CMPI.B	#-8,D0
	BEQ.S	$40		;CRC, retry read/write
	CMPI.B	#-9,D0
	BEQ.S	$40		;Read after write error, retry write
	
	CMPI.B	#-6,D0
	BEQ.S	$30		;Data timeout, retry seek
	CMPI.B	#-12.,D0
	BNE.S	$20		;Must be hard error
	
;	Wrong cylinder
	CMPI.B	#3,WT_RTRY(A4)
	BLT.S	$30		;Must recalibrate
	BRA.S	$36		;Try re-seek


;	Hard error
$20	MOVE.B	D0,WI_LHERR(A4) ;Save last hard error
	BRA	WDEXIT
	
;	Retry seek
$30	CLR.B	WS_RCAL(A4)	;Set up recalibrate request
	MOVE.W	#-1,D0
$35	DBF	D0,$35
$36	ADDQ.B	#1,WI_SOFT(A4)	;Count soft error
	CMPI.B	#1,WT_TYPE(A4)
	BGT	WDDKIO1		;Don't reseek if Write or Read after Write
	BRA	WTINIT2		;Retry the whole process
	
;	Retry read/write
$40	MOVE.W	#-1,D0
$45	DBF	D0,$45
	CLR.B	WS_ERR(A4)
	ADDQ.B	#1,WI_SOFT(A4)	;Count soft error
	MOVE.B	WI_SOFT(A4),D0	;Check for soft error threshold
	ANDI.B	#1FH,D0
	BEQ.S	$50		;Do VCO recalibrate every 32 soft errors
	MOVE.B	WI_RTRY(A4),D0
	LSR.B	#1,D0
	CMP.B	WT_RTRY(A4),D0
	BNE.S	$60		;Set up transfer
$50	BTST	#3,WI_TEST+1(A4);Check if VCO recalibrate is inhibited
	BNE.S	$55		;Don't recalibrate VCO
	BSR	WVCOINIT	;Recalibrate VCO

$55	TST.W	WT_CYL(A4)	;Check if trying for cylinder 0
	BNE.S	$60		;Not cylinder 0
	SUBQ.B	#1,WI_SOFT(A4)	;Adjust for double count
	BRA	$30		;Try recalibrate

$60	BRA	WDDKIO1		;Set up transfer again

;	Out of Retries
$70	CMPI.B	#3,WT_TYPE(A4)
	BNE	$20		;Not read after write, Hard Error
	SUBQ.B	#1,WT_WTRY(A4)
	BLE	$20		;No more retries
	CLR.B	WS_ERR(A4)
	BTST	#5,WT_CTRL(A4)	;Check if formatting
	BNE.S	$80		;Was formatting
	BSR	WDMOVEP		;Restore Pre-Read information
	BSR	WDMOVEO		;Set up user's output
$80	MOVE.B	WI_RTRY(A4),WT_RTRY(A4) ;Set up for another write
	MOVE.B	#2,WT_TYPE(A4)	;Indicate write type
	BRA	WDDKIO1		;Try write again



.PAGE
;****************************************************************************
;
;	Initialization & Status
;
;****************************************************************************

INCHAN9
	MOVE.L	A4,-(A7)
	BSR	WDADDR		;Address the drive table
	BNE.S	$10		;Drive equipped
	MOVE.W	#-14.,2(A0)	;Error reply code
$10	MOVEA.L (A7)+,A4
	RTS



STCHAN9
	MOVEM.L D1/A4,-(A7)
	BSR	WDADDR		;Address the drive table
	BEQ.S	$20		;No drive equipped
	
	CLR.W	(A1)		;Number of bytes buffered
	MOVE.W	WI_BPS(A4),2(A1) ;Number of bytes per sector
	CLR.W	D0
	MOVE.B	WI_SPT(A4),D0	;Number of sectors per track
	MOVE.W	D0,4(A1)
	SWAP	D0
	MOVE.W	D0,D1
	SWAP	D0
	ANDI.W	#0FH,D1		;Find sub device number
	LSL.W	#2,D1
	MOVE.W	WI_MAP+2(A4,D1.W),D0  ;Number of tracks per disk
	SUB.W	WI_MAP(A4,D1.W),D0
	ADDQ.W	#1,D0
	MOVE.W	D0,6(A1)
	
	MOVEQ	#0,D0
	MOVE.B	WG_BUSY,D0
	MOVE.W	D0,50.(A1)	;Save busy condition
	MOVE.B	WS_ERR(A4),D0
	MOVE.W	D0,52.(A1)	;Save current error code
	MOVE.B	WI_LHERR(A4),D0
	MOVE.W	D0,54.(A1)	;Save last hard error code
	MOVE.B	WI_FERR(A4),D0
	MOVE.W	D0,56.(A1)	;Save first error code
	MOVE.B	WI_LERR(A4),D0
	MOVE.W	D0,58.(A1)	;Save last error code
	
$10	MOVEM.L (A7)+,D1/A4
	RTS

;	No drive equipped
$20	MOVE.W	#-14.,2(A0)
	BRA	$10


;	Read Winchester configuration
RCFCH9
	MOVEM.L A2/A4,-(SP)
	TST.B	SAGE4		;Check if SAGE 4
	BEQ.S	$30		;Not SAGE 4
	BSR	WDADDR		;Address drive table
	MOVE.W	#WI_CONFS-1,D0
	MOVEA.L A4,A2
$10	MOVE.B	(A2)+,(A1)+	;Move configuration
	DBF	D0,$10
$20	MOVEM.L (SP)+,A2/A4
	RTS

;	Handle no drive error
$30	MOVE.W	#-14.,2(A0)	;Error reply code
	BRA	$20

;	Write Winchester configuration
WCFCH9
	MOVEM.L A2/A4,-(SP)
	TST.B	SAGE4		;Check if SAGE 4
	BEQ.S	$30		;Not SAGE 4
	BSR	WDADDR		;Address drive table
	MOVE.W	#WI_CONFS-1,D0
	MOVEA.L A4,A2
$10	MOVE.B	(A1)+,(A2)+	;Move configuration
	DBF	D0,$10
	CLR.B	WS_RCAL(A4)	;Force recalibrate
	CLR.B	WS_INIT(A4)	;Force drive re-init
	BSR	WDCLTBL		;Clear map tables
$20	MOVEM.L (SP)+,A2/A4
	RTS

;	Handle no drive error
$30	MOVE.W	#-14.,2(A0)	;Error reply code
	BRA	$20


;	Winchester driver startup
SSCHN9
	LEA	WG_VAR0,A0
	LEA	WG_VTBL,A1
	LEA	WI_CONF0,A2
	MOVEQ	#4-1,D0
$10	MOVE.L	A0,(A1)+	;Set up table address
	MOVE.W	#WI_CONFS-1,D1
$20	MOVE.B	(A2)+,(A0)+	;Move configuration
	DBF	D1,$20
	ADDA.W	#WI_SIZE-WI_CONFS,A0
	DBF	D0,$10
	RTS
	
	
;	Set up drive information table address in A4
;	EQ flag means no channel
WDADDR
	TST.B	SAGE4		;Check if SAGE IV board equipped
	BEQ.S	$10		;No SAGE IV board
	MOVEM.L D2,-(SP)
	SWAP	D0		;Access channel number
	MOVE.W	D0,D2
	SWAP	D0
	ANDI.W	#30H,D2		;Isolate drive number
	LSR.W	#2,D2
	LEA	WG_VTBL,A4	;Form table address
	MOVEA.L 0(A4,D2.W),A4
	TST.W	WI_NCYL(A4)	;Check if drive is equipped
	MOVEM.L (SP)+,D2
$10	RTS

                                                                                                                                                                                          