
		eject
;**************************************************
;		HARDDISK Formatter
;**************************************************

;Autor	Wilfried Schmitten, Heidebloeck 16, 2 Hamburg 74

;letzte Aenderung :	29.10.1988

;Include File fuer Harddisk Utility

	subttl	Low Level Routines
;	LOW LEVEL ROUTINES
;	------------------

		dseg

cyl:		dw	0
sector:		db	0
head:		db	0
lun:		db	0	;0=Lun 0, 20=Lun 1


;alternate Track
;acyl		dw	0
;ahead		db	0

disretry	equ	80h
disecc		equ	40h
enbuffer	equ	40h
s10us		equ	1	
ilval		equ	3
fillpattern	equ	0e5h

		cseg
		
delay:
	push	bc
	ld	b,0
	ld	c,a
dly1:	djnz	dly1
	dec	c
	jr	nz,dly1
	pop	bc
	ret	



;	Kommando an Controller
;	<HL>	Pointer 6 byte Kommando

command:
	out	(hd$select),a	;Controller mit dummy ansprechen
	ld	b,6		;6 byte
	ld	c,hd$data	;nach Adresse
coml:	call	waitreq		;teste Data request
	outi			;ausgeben
	jr	nz,coml	
	ret			


;	Kommando 	SET DRIVE CHARACTERISTICS

ksetp:
	db	12,0,0,0,0,0

drive$data:

if parkcyl > cylinder

	db	high	parkcyl
	db	low	parkcyl
else

	db	high	cylinder
	db	low	cylinder
	
endif	
	db	hd$head
	db	high	red$wrcur
	db	low	red$wrcur
	db	high	wr$pre$comp
	db	low	wr$pre$comp
	db	0
setp:	
	ld	a,(lun)
	ld	(ksetp+1),a
	ld	hl,ksetp
	call	command
	ld	hl,drive$data
	ld	b,8
	ld	c,hd$data
setl:	call	waitreq
	outi
	jr	nz,setl
	jp	errorcheck	

;	wie oben, aber exakte Einstellung der Cylinder-Zahl
;	fuer formatieren und Drive Diagnostic

fksetp:		db	12,0,0,0,0,0
fdrive$data:
		db	high	cylinder
		db	low	cylinder
		db	hd$head
		db	high	red$wrcur
		db	low	red$wrcur
		db	high	wr$pre$comp
		db	low	wr$pre$comp
		db	0

fsetp:
	
	ld	a,(lun)
	ld	(fksetp+1),a
	ld	hl,fksetp
	call	command
	ld	hl,fdrive$data
	ld	b,8
	ld	c,hd$data
fsetl:	call	waitreq
	outi
	jr	nz,fsetl
	jp	errorcheck	



;	Kommando 	REQUEST SENSE

kreqs:
	db	3,0,0,0,0,0

errorcheck:
	call	waitreq
	in	a,(hd$data)
	and	2
	ret	z		;fehlerfrei

reqsense:
	ld	a,1
	call	delay
	ld	a,(lun)
	ld	(kreqs+1),a
	ld	hl,kreqs
	call	command
	call	waitreq
	and	2
	jr	nz,req1
	ld	hl,dsense	;Ergebnispuffer
	ld	c,hd$data
reql:				;4 byte data
	ini			;abholen
req2:	in	a,(hd$status)
	rrca
	jr	nc,req2
	and	3
	xor	1		;0 fuer write, 1 fuer read
	jr	z,reql
	ini			;Statusbyte abholen
req1:	scf
	ret


	dseg

dsense	ds	5

;	Command descriptor block	

cdbcom		ds	1	;Operation code
cdbhead		ds	1	;bit 7 =cyl 2~10, head
cdbsector	ds	1	;bit 7,6 = cyl 2~9,2~8, sector
cdbcyl		ds	1	;cyl 2~7 - 2~0
cdbcount	ds	1	;block count
cdbcontrol	ds	1	;bit 7=1=disable retrey
				;bit 6=1=disable error correction
				;bit 2,1,0 step option	


	cseg


waitreq:
	in	a,(hd$status)
	rrca
	ret	c
	jr	waitreq	



;	Kommando	CHECK DRIVE READY
;	Ausgang		nc	= ready

krcheck:	db	0,0,0,0,0,0

readycheck:
	ld	a,(lun)
	ld	(krcheck+1),a
	ld	hl,krcheck
	call	command
rc2:	in	a,(hd$status)
	rrca
	jr	c,rc1		;ready
	ld	c,6
	ld	e,0feh		;conin Status
	call	bdos
	or	a
	scf
	jr	nz,rc1		;Abbruch
	jr	rc2		;weiter warten
rc1:	jp	errorcheck



;	Kommando	RECALIBRATE

kcalibr:	db	1,0,0,0,0,s10us

calibr:
	ld	a,(lun)
	ld	(kcalibr+1),a
	ld	hl,kcalibr
	call	command
	jp	errorcheck


;	Kommando 	CONTROLLER RAM DIAGNOSTIC

kramdiag:	db	0e0h,0,0,0,0,0

ramdiag:
	ld	hl,kramdiag
	jr	diag

;	Kommando 	CONTROLLER INTERNAL DIAGNOSTIC

kcontrdiag:	db	0e4h,0,0,0,0,0

contrdiag:
	ld	hl,kcontrdiag
	jr	diag

;	Kommando 	DRIVE DIAGNOSTIC

kdrivediag:	db	0e3h,0,0,0,0,disretry or s10us

drivediag:
	ld	a,(lun)
	ld	(kdrivediag+1),a
	ld	hl,kdrivediag
diag:	call	command
	jp	errorcheck
		
;	Kommando	READ ECC BURST ERROR LENGTH

keccburst:	db	0dh,0,0,0,0,0

	dseg

burstlength:	ds	1

	cseg

eccburst:
	ld	hl,keccburst
	call	command
ecc1:	call	waitreq
	and	1
	jr	z,ecc1
	in	a,(hd$data)
	ld	(burstlength),a
	jp	errorcheck

;	Kommando 	WRITE DATA TO SECTOR BUFFER

kfsector:	db	15,0,0,0,1,0

fsector:
	ld	hl,kfsector
	call	command
fs2:	
	call	waitreq
	and	2		;wegen shift in waitreq
	jr	nz,fs3	
	ld	b,fillpattern
	ld	c,hd$data
fs5:	out	(c),b
fs4:	in	a,(hd$status)
	rrca
	jr	nc,fs4
	and	3
	xor	0
	jr	z,fs5

fs3:	jp	errorcheck

;	Kommando 	FORMAT TRACK

ftrack:
	ld	a,6
	jr	form1

;	Kommando 	FORMAT BAD TRACK

fbtrack:
	ld	a,7
	jr	form1

;	Kommando 	ASSIGN ALTERNATE TRACK

aatrack:
	ld	a,11h
form1:	ld	(cdbcom),a
	call	cylcalc
	ld	a,(interleave)
	ld	(cdbcount),a
	ld	a,enbuffer or s10us
	ld	(cdbcontrol),a
	ld	hl,cdbcom
	call	 command
	ld	a,(cdbcom)
	cp	11h		;assign alternate track?
	jp	nz,errorcheck

	call	waitreq
	and	2
	jp	nz,errorcheck
	ld	hl,alttrack	;alternate
				;track Daten uebergeben
	ld	c,hd$data
form3:	
	outi
form2:	in	a,(hd$status)
	rrca
	jr	nc,form2	
	and	3
	xor	0
	jr	z,form3
	jp	errorcheck

	dseg

alttrack:	db	0,0,0,0

	cseg


;	Kommando	READ ID

readid:
	ld	a,0e2h
	ld	(cdbcom),a
	call	cylcalc
	xor	a
	ld	(cdbcount),a
	ld	a,disretry or s10us
	ld	(cdbcontrol),a
	ld	hl,cdbcom
	call	command
	call	waitreq
	and	2
	jp	nz,errorcheck
	ld	hl,riddescrip	;ID Descriptor
				;Daten lesen
	ld	c,hd$data
rid3:	
	ini
rid2:	in	a,(hd$status)
	rrca
	jr	nc,rid2	
	and	3
	xor	1
	jr	z,rid3
	jp	errorcheck

	dseg

riddescrip:	ds	4

	cseg	

;	Kommando 	READ
;	Eingang jeweils mit <A> = controlbyte

iniop	equ	0a2h
outiop	equ	0a3h

read:	
	ld	(cdbcontrol),a
	ld	a,8
	ld	b,iniop
	ld	c,1
	jr	rwcom

;	Kommando 	WRITE

write:
	ld	(cdbcontrol),a
	ld	a,10
	ld	b,outiop
	ld	c,0
rwcom:	ld	(cdbcom),a
	ld	a,b
	ld	(rwpatch1+1),a
	ld	a,c
	ld	(rwpatch2+1),a
	call	cylcalc
	ld	a,1
	ld	(cdbcount),a
	ld	hl,cdbcom
	call	command
	call	waitreq
	and	2
	jr	nz,rw2
	ld	hl,hddma
	ld	c,hd$data
rwpatch1:
	outi
rw1:	in	a,(hd$status)
	rrca
	jr	nc,rw1
	and	3
rwpatch2:
	xor	0		;0 fuer write, 1 fuer read
	jr	z,rwpatch1
rw2:	jp	errorcheck

	dseg

hddma:		ds	sector$size

	cseg


;	Kommando	FORMAT DRIVE
;			Vorher Plattengroesse exakt einstellen!!
;			Formatieren des Bereichs cylinder bis parkcyl
;			fuehrt zu fehlerhaftem Verhalten

kfdrive:	db	4,0,0,0,0,enbuffer or s10us


fdrive:

	ld	a,(lun)
	ld	(kfdrive+1),a
	ld	a,(interleave)
	ld	(kfdrive+4),a
	ld	hl,kfdrive
	call	command
fdr1:	in	a,(hd$status)
	rrca
	jr	c,fdr2		;ready
	ld	c,6
	ld	e,0feh		;conin Status
	call	bdos
	or	a
	scf
	jr	z,fdr1		
				; carry + <A> = FF, dann
				;Abbruch durch Reset
	ret

fdr2:	jp	errorcheck	
				; !! Drive Parameter neu setzen

;	Kommando       SEEK

seek:
	ld	a,11
	ld	(cdbcom),a
	call	cylcalc
	xor	a
	ld	(cdbcount),a
	ld	a,disretry or s10us
	ld	(cdbcontrol),a
	ld	hl,cdbcom
	call	command
	jp	errorcheck



;	Kommando       	READ VERIFY

rdverify:
	ld	a,5
	ld	(cdbcom),a
	call	cylcalc
	ld	a,sector$nmb
	ld	(cdbcount),a
	ld	a,disretry or disecc or s10us
	ld	(cdbcontrol),a
	ld	hl,cdbcom
	call	command
	jp	errorcheck

cylcalc:
	ld	a,(cyl)
	ld	(cdbcyl),a	;low byte cylinder
	xor	a
	ld	a,(cyl+1)
	ld	hl,sector
	rra
	rra
	rra
	push	af		;2~10 in carry !!
	or	(hl)		;2~9,2~8 lksbuendig + sector
	ld	(cdbsector),a
	pop	af
	rra
	and	80h		;2~10
	inc	hl
	or	(hl)		;+ head
	ld	hl,lun
	or	(hl)		;+ lun
	ld	(cdbhead),a

	ret
