;shard segment
; assume cs: shard
; assume ds: shard, es:nothing, ss:nothing
;================================================================
; modul hdisk.asm
; hard - disk - treiber
;
; Status:
; 0.0 13.11.84 erste Testversion
;================================================================
TIMEOUT1 equ 20h ; warten auf Disk-Interrupt
; (20.0000h Tests)
;-------------------------------------------------------;
; Fehlercodes
; Bem: 11h ist eigentlich k e i n Fehler !
;-------------------------------------------------------;
;sense_fail equ 0ffh ; sense operation
;undef_err equ 0bbf ; undefined error occurred
;time_out equ 80h ; attachment failed to respond
;bad_seek equ 40h ; seek operation failed
;bad_cntlr equ 20h ; controller has failed
;data_corrected equ 11h ; ecc corrected data error
;bad_ecc equ 10h ; bad ecc on disk read
;bad_track equ 0bh ; bad track flag detected
;dma_boundary equ 9 ; attempt to dma across 64k
;init_fail equ 7 ; drive parameter activity failed
;bad_reset equ 5 ; reset failed
;record_not_fnd equ 4 ; requested sector not found
;bad_addr_mark equ 2 ; address mark not found
;bad_cmd equ 1 ; bad command passed to disk i/o
;-------------------------------------------------------;
; interrrupt and status area ;
;-------------------------------------------------------;
dummy segment at 0
org 0dh *4
hdisk_int label dword
org 13h * 4
org_vector label dword
org 19h *4
hf_tbl_vec label dword
dummy ends
;-----------------------------------------------------------------------;
; cmd_block
;
; +0 Kommando
; +1 Kopfnummer Aufrufparameter 1
; +2 2-Bit Zylinder & Rest Sektor Aufrufparameter 2
; +3 Zylinder Aufrufparameter 3
; +4 Block - Count (ist immer 1 )
; +5 Control-Byte (Step - Option)
;-----------------------------------------------------------------------;
cmd_block label byte
hd_error db 7 dup(?)
disk_status db ?
;-------------------------------------------------------;
; hardware specific values ;
; ;
; - Controller i/o port ;
; > when ready from: ;
; hf_port+0 - read data (from controller to cpu ;
; hf_port+1 - read controller hardware status ;
; (controller to cpu) ;
; hf_port+2 - read configuration switches ;
; hf_port+3 - not used ;
; < when written to: ;
; hf_port+0 - write data (from cpu to controller) ;
; hf_port+1 - controller reset ;
; hf_port+2 - generate controller select pulse ;
; hf_port+3 - write pattern to dma and interrupt ;
; mask register ;
;-------------------------------------------------------;
hf_port equ 320h ; disk port
r1_busy equ 00001000b ; disk port 1 busy bit
r1_bus equ 00000100b ; command/data bit
r1_iomode equ 00000010b ; mode bit
r1_req equ 00000001b ; request bit
dma_read equ 01000111b ; channel 3 (47h)
dma_write equ 01001011b ; channel 3 (4bh)
dma equ 0 ; dma address
dma_high equ 82h ; port for high 4 bits of dma
tst_rdy_cmd equ 0 ; cntrl ready (00h)
recal_cmd equ 00000001b ; recal (01h)
sense_cmd equ 00000011b ; sense (03h)
fmtdrv_cmd equ 00000100b ; drive (04h)
chk_trk_cmd equ 00000101b ; t chk (05h)
fmttrk_cmd equ 00000110b ; track (06h)
fmtbad_cmd equ 00000111b ; bad (07h)
read_cmd equ 00001000b ; read (08h)
write_cmd equ 00001010b ; write (0ah)
seek_cmd equ 00001011b ; seek (0bh)
init_drv_cmd equ 00001100b ; init (0ch)
rd_ecc_cmd equ 00001101b ; burst (00h)
rd_buff_cmd equ 00001110b ; buffr (0eh)
wr_buff_cmd equ 00001111b ; buffr (0fh)
ram_diag_cmd equ 11100000b ; ram (e0h)
chk_drv_cmd equ 11100011b ; drv (e3h)
cntrl_diag_cmd equ 11100100b ; cntlr (e4h)
rd_long_cmd equ 11100101b ; rlong (e5h)
wr_long_cmd equ 11100110b ; wlong (e6h)
int_ctl_port equ 20h ; 8259 control port
eoi equ 20h ; end of interrupt command
page
;===============================================================;
; MAIN - Routine
; Input:
; ah - 0 write disk
; - 1 read disk
; (es:bx) - Datenadresse
; cmd_block
; Output:
; disk_status 0 - alles OK
;===============================================================;
hard_dsk proc
; mov ax,0 ; interrupt initiieren
; mov es,ax
; mov word ptr es:[hdisk_int+2],cs
; mov word ptr es:[hdisk_int],offset hd_int
sti ; enable interrupts
mov disk_status,0 ; noch alles ok !
mov cmd_block+5,5 ; 70 ysec steprate
cmp ah,0 ; ah = 0 --> write disk
jz a4 ; ah <> 0 --> read disk
call disk_read
jmp short dsbl
a4: call disk_write
;-------------------------------------------------------;
; dsbl
; make shure that all housekeeping is done
; before exit
;-------------------------------------------------------;
dsbl:
mov dx,hf_port+3
sub al,al
out dx,al ; reset int/dma mask
mov al,7
out dma+10,al ; set dma - mode to disable
cli ; disable interrupts
in al,21h
or al,20h
out 21h,al ; disable interrupt 5
sti ; enable interrupts
ret
hard_dsk endp
;========================================================
; disk read routine
; Input:
; (es:bx) - Datenadresse
; cmd_block
;========================================================
disk_read proc near
mov al,dma_read ; mode byte for dma read
mov cmd_block+0,read_cmd
jmp do_io
disk_read endp
;========================================================
; disk write routine
; Input:
; (es:bx) - Datenadresse
; cmd_block
;========================================================
disk_write proc near
mov al,dma_write ; mode byte for dma write
mov cmd_block+0, write_cmd
jmp do_io
disk_write endp
page
;========================================================
; do_io
; gemeinsame Routine fuer alle Kommandos
; Input:
; (es:bx) - Datenadresse
; al - mode (dma_read/dma_write)
; cmd_block
;========================================================
do_io proc near
mov cmd_block+4,1 ; Blockzahl immer 1
;-------------------------------------------------------;
; DMA_SETUP
; diese Routine dressiert den DMA
;-------------------------------------------------------;
cli ; keine Interrupts mehr
out dma+12,al ; first/last ff setzen
push ax ; warten ?
pop ax
out dma+11,al ; mode setzen
;-----phys. Adresse zum DMA ausgeben:
mov ax,es
mov cl,4
rol ax,cl ; h - nibble von es nach al
mov ch,al
and al,0f0h
add ax,bx
jnc j33
inc ch ; Uebertrag notieren
j33: out dma+6,al ; a0 - a7 ausgeben
push ax ; fuer Ueberlauftest merken
mov al,ah
out dma+6,al ; a8 - a15 ausgeben
mov al,ch
and al,0fh
out dma_high,al ; a16 - a19 ausgeben
;-----Blocklaenge zum DMA ausgeben:
mov ax,511 ; Blocklaenge
out dma+7,al ; Blocklaenge ausgeben
mov al,ah
out dma+7,al
sti ; Interrupts scharfmachen
pop ax
add ax,511 ; 64k Overflow testen
jnc gx ; wenn kein Overflow
mov disk_status, dma_boundary
ret
gx: call command
jc error_chk ; wenn was schiefgelaufen ist
mov al,3 ; controller dma/interrupt register mask
out dma+10,al ; initialize the disk channel
g3:
in al,21h
and al,0dfh
out 21h,al
;-------------------------------------------------------;
; wait_int
; this routine waits for the fixed disk
; controller to signal, that an interrupt
; has occured
;-------------------------------------------------------;
sti ; muss das nochmal sein ???
push es
push si
;----- set timeout values
sub bh,bh
mov bl,TIMEOUT1 ; timout Zaehler setzen (high word)
sub cx,cx
;----- wait for interrupt
w1:
push ds
push bx
push cx
call cs:warte ; nicht dumm rumloopen, sondern
pop cx ; arbeiten !!
pop bx
pop ds
mov dx,hf_port+1
in al,dx
and al,20h
cmp al,20h
jz w2
loop w1
dec bx
jnz w1
mov disk_status,time_out
w2: mov dx, hf_port
in al,dx
and al,2
or disk_status,al ; Fehler merken
mov dx,hf_port+3
xor al,al
out dx,al
pop si
pop es
;-----------------------------------------------;
; error_chk ;
;-----------------------------------------------;
error_chk:
ret ; zunaechst keine Fehler- Auswertung
mov al,disk_status
or al,al
jnz g21
ret
;-----perform sense status
g21: mov ax, shard
mov es,ax
sub ax,ax
mov di,ax
mov cmd_block+0, sense_cmd
sub al,al
call command
jc sense_abort
mov cx,4
g22:
call hd_wait_req
jc g24
mov dx,hf_port
in al,dx
mov hd_error[di],al
inc di
mov dx,hf_port+1
loop g22
call hd_wait_req
jc g24
mov dx,hf_port
in al,dx
test al,2
jz stat_err
sense_abort:
mov disk_status, sense_fail
g24:
stc
ret
do_io endp
;========================================================
; command
; erklaert dem controller, was zu tun ist
; input
; cmd_block
;========================================================
command proc near
mov dx,hf_port+2
out dx,al ; controller select pulse ausgeben
mov dx,hf_port+3
mov al,3 ; controller dma/interrupt register mask
out dx,al ; DMA und Interrupt-Maske setzen
; eigentlich ist es nicht normal, wenn der Controller an dieser
; Stelle beschaeftigt ist, aber wer weiss ...
sub cx,cx ; timeout - Zaehler setzen
mov dx,hf_port+1
wait_busy:
in al,dx ; status lesen
and al,0fh
cmp al,r1_busy or r1_bus or r1_req
je weiter_gehts ; weiter, wenn controller frei
loop wait_busy ; warten...
mov disk_status, time_out ; is nix
stc
ret
weiter_gehts:
cld ; clear direction flag
mov cx,6 ; Blocklaenge fuer move
mov si, offset cmd_block
cm3: mov dx,hf_port ; Command-Block ausgeben
lodsb ;
out dx,al
loop cm3
inc dx ; weiter nach hf_port+1
in al,dx ; status lesen
test al,r1_req
jz cm7 ; wenn alles ok
mov disk_status, bad_cntlr ; war nix
stc
cm7:
ret
command endp
;================================================================
; hd_int
;================================================================
hd_int proc near
push ax
mov al,eoi ; end of interrupt
out int_ctl_port,al
mov al,7 ; set dma mode to disable
out dma+10,al
in al,21h
or al,20h
out 21h,al
pop ax
iret
hd_int endp
t_0 dw type_0
t_1 dw type_1
t_2 dw type_2
t_3 dw type_3
stat_err:
mov bl,es:hd_error ; get error byte
mov al,bl
and al,0fh
and bl,00110000b
sub bh,bh
mov cl,3
shr bx,cl
jmp word ptr cs:[bx + offset t_0]
type0_table label byte
db 0, bad_cntlr, bad_seek, bad_cntlr, time_out, 0, bad_cntlr
db 0, bad_seek
type0_len equ $-type0_table
type1_table label byte
db bad_ecc, bad_ecc, bad_addr_mark, 0, record_not_fnd
db bad_seek, 0, 0, data_corrected, bad_track
type1_len equ $-type1_table
type2_table label byte
db bad_cmd, bad_addr_mark
type2_len equ $-type2_table
type3_table label byte
db bad_cntlr, bad_cntlr, bad_ecc
type3_len equ $-type3_table
type_0:
ret
type_1:
ret
type_2:
ret
type_3:
ret
;================================================================
; hd_wait_req
;================================================================
hd_wait_req proc near
push cx
sub cx,cx ; timeout - Zaehler setzen
mov dx,hf_port + 1
l1:
in al,dx
test al,r1_req
jnz l2 ; wenn ok
loop l1
mov disk_status, time_out
stc
l2:
pop cx
ret
hd_wait_req endp
; end