home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1993 #2
/
Image.iso
/
os2
/
gtak212b.zip
/
SOURCE.ZIP
/
OS2-ST01
/
st_io.asm
< prev
next >
Wrap
Assembly Source File
|
1992-07-02
|
19KB
|
918 lines
SUBTTL ST01 Module
INCLUDE DEFS.INC
include sysinfo.inc
include debug.inc
EnableFast equ 1 ;Fast transfer mode
EnableBlock equ 0 ;Block transfer mode (not for 486)
BlockSize equ 512 ;Max block transfer size
WrtWait equ 12 ;Wait loop at fast write
;
; Register conventions:
;
; DS: data segment
; ES: available, not preserved
; FS: port segment, preserved
; GS: available, not preserved
;
; Caution: The device helper functions Block and Yield
; clear FS and GS - im Gegensatz zur Doku!
;
if JR
PhysIO equ 0C9A00h ;Physical address of ST01 I/O ports
else
PhysIO equ 0CFA00h ;Physical address of ST01 I/O ports
endif
IRQnum equ 5 ;IRQ number
HostID equ 6 ;Host adapter SCSI ID
if JR
TargetID equ 4 ;Target SCSI ID
else
TargetID equ 4 ;Target SCSI ID
endif
TimeSlice equ 2000 ;Time to sleep in execution phase
_cmd equ 0000h ;Control/status port
_dat equ 0200h ;Data port (1KB)
cmd equ byte ptr fs:[_cmd] ;usually
dat equ byte ptr fs:[_dat]
CEN equ 80h ;enable
CIE equ 40h ;interrupt enable
CPE equ 20h ;parity enable
CARB equ 10h ;start arbitration
CATN equ 08h
CBSY equ 04h
CSEL equ 02h
CRST equ 01h
SARB equ 80h ;arbitration complete
SPE equ 40h ;parity error
SSEL equ 20h
SREQ equ 10h
SCD equ 08h
SIO equ 04h
SMSG equ 02h
SBSY equ 01h
; Message-In/Out Codes
MsgComplete equ 00h
MsgSavePointer equ 02h
MsgRestPointer equ 03h
MsgDisconnect equ 04h
MsgError equ 05h
MsgAbort equ 06h
MsgReject equ 07h
MsgNop equ 08h
MsgParity equ 09h
MsgLinkedCompl equ 0Ah
MsgLinkedComplF equ 0Bh
MsgReset equ 0Ch
MsgIdentify equ 80h
;; MsgCanDisconn equ 0h
MsgCanDisconn equ 40h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
StartData
public host_id
public target_id
public irq_num
public phys_addr
public sysinfo_seg
extrn DevHlpPtr:dword
;
; Set by command line switches
;
even
phys_addr dd PhysIO ;Physical address of I/O ports
irq_num dw IRQnum ;IRQ number
host_id db 1 shl HostID ;Host adapter SCSI ID mask
target_id db 1 shl TargetID ;Target SCSI ID mask
;
; Other data
;
even
port_seg dw 0 ;Protected mode I/O port selector
sysinfo_seg dw 0 ;Bimodal sysinfo segment address
yield_ptr dd 0 ;Bimodal ptr to yield flag
timeout dd 0 ;Start time
event_id dd 0 ;Dummy phys addr used as event ID
data_ptr dd 0 ;Virtual data transfer address
data_len dw 0 ;Requested transfer length
actual_len dw 0 ;Actual transfer length
cmdptr dw 0 ;Near pointer to next command byte
xstatus dw 0 ;Execute returns this on completion
status db 0 ;Status byte
wait_for_int db 0 ;Waiting for reselection interrupt
reconnect_flag db 0 ;Reconnection interrupt occurred
msg_byte db 0 ;Send this in message out phase
fast_xfer db 0 ;Fast block transfer mode
EndData
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
StartCode
public dev_interrupt
public command
public bus_reset
public device_reset
public init_io
public delay
public ST_INIT_null
ST_INIT_null:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Set time to now + CX
;
set_time proc near
mov es, sysinfo_seg
movzx ecx, cx
add ecx, es:[0].msec_timer
mov timeout, ecx
ret
set_time endp
;
; Compare time to saved time
;
cmp_time proc near
mov es, sysinfo_seg
mov eax, es:[0].msec_timer
cmp eax, timeout
ret
cmp_time endp
;
; Wait CX msec
;
delay proc near
outtext 10, 'Delay '
outword 10, cx
outchar 10, '$'
push fs
pusha
mov ax, cs
mov bx, offset delay
sub di, di
mov dh, 1 ;not interruptible
DevHlp DevHlp_Block
popa
pop fs
ret
delay endp
;
; Wait for event (interruptible), max CX msec
; Return: C=0: event wakeup
; C=1: Z=1: timeout
; Z=0: interrupted
;
sleep proc near
outtext 5, 'Sleep '
outword 5, cx
push fs
push di
mov ax, event_id._hi
mov bx, event_id._lo
sub di, di
mov dh, 0
DevHlp DevHlp_Block
pop di
pop fs
if trace
pushf
jc short sl_1
outtext 5, ': event$'
jmp short sl_2
sl_1: outtext 5, ': timeout$'
sl_2: popf
endif
ret
sleep endp
yield proc near
push dx
push bx
les bx, yield_ptr
cmp byte ptr es:[bx], 0
je short yield1
outtext 5, 'Yield$'
push fs
DevHlp DevHlp_Yield
pop fs
yield1: pop bx
pop dx
yield2: ret
yield endp
;
; Wait for (status & DH) == DL, max CX msec
; C=1: timeout
wait_for proc near
outtext 10, 'Wait '
outword 10, cx
outtext 10, ' for (status & '
outbyte 10, dh
outtext 10, ') == '
outbyte 10, dl
outchar 10, '$'
pusha
popa
mov al, cmd
and al, dh
cmp al, dl
jne short wf_wait
wf_ok: clc
ret
wf_wait:call set_time
wf_loop: ;;!! call yield
mov al, cmd
and al, dh
cmp al, dl
je short wf_ok
call cmp_time
jb short wf_loop
wf_to: stc
ret
wait_for endp
waitfor macro mask, comp, time
mov dx, (mask) * 256 + (comp)
mov cx, time
call wait_for
endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Device interrupt
; - Check for proper reselection and wakeup driver if
; waiting for reconnection.
; - Take care of race conditions in a system with
; multiple host adapters on the same bus.
; - The CIE bit does not to seem to be what its name
; suggests, so accept but ignore interrupts at other
; times.
; - Cannot use waitfor, since Yield is unusable at
; interrupt time.
;
dev_interrupt proc far
push fs
push DevHlpPtr ;Setup for DevHlp calls.
mov bp, sp
outtext 3, '-IRQ-'
cmp wait_for_int, 0 ;Perhaps unexpected?
mov wait_for_int, 0
je int_ign
smsw ax ;Set I/O segment for each mode.
test al, 1
jnz short int_pm
int_rm: mov eax, phys_addr ;The interrupt can occur in real mode.
shr eax, 4
mov fs, ax
jmp short int_cont
int_pm: mov fs, port_seg
int_cont:
mov cmd, CPE ;Disable ST01 interrupts
mov ax, irq_num ;Allow all other interrupts
DevHlp DevHlp_EOI ;to reduce interrupt latency.
test cmd, SSEL ;The SEL line should be active since
jz int_bad ;it triggered the interrupt.
mov cx, 1000 ;Wait for release of BSY for IO
int_1: test cmd, SBSY ;line and ID bits to become active.
loopnz int_1
jnz short int_bad
mov al, cmd ;Check for a valid reselection.
test al, SIO ;Is it a reselection?
jz short int_bad
test al, SPE ;Ignore reselections with bad parity.
jnz short int_bad
mov al, dat ;Check initiator & target IDs.
xor al, host_id
xor al, target_id
jnz short int_bad
test cmd, SSEL ;The SEL line should still be active
jz short int_bad ;but maybe another host adapter
;got selected and the ID bits on the
;data bus were garbage. In this case,
;the SEL line should now be inactive.
mov cmd, CEN+CPE+CBSY ;Acknowledge reselection.
mov cx, 10000 ;Wait for end of SEL.
int_2: test cmd, SSEL
loopnz int_2
jcxz int_bad
mov cmd, CEN+CPE+CIE ;Now the targed controls BSY.
mov ax, event_id._hi ;Wakeup waiting driver.
mov bx, event_id._lo
DevHlp DevHlp_Run
mov reconnect_flag, 1 ;Show the world.
outtext 10, 'OK-'
int_r: lea sp, [bp+4]
pop fs
clc ;The interrupt is ok.
ret
int_ign:
outtext 3, 'IGN-'
mov ax, irq_num
DevHlp DevHlp_EOI
jmp short int_r
int_bad:
outtext 3, 'BAD-'
mov cmd, CPE+CIE ;Rearm for next (re-)selection.
jmp short int_r
dev_interrupt endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Initiate SCSI bus operations
; C=1, AX=error-code
arbitrate proc near
outtext 3, 'Arbitration$'
arb_loop:
mov cmd, CPE ;Clear pending parity errors.
mov al, host_id ;Send host adapter SCSI ID.
mov dat, al
mov cmd, CEN+CPE+CARB ;Start bus arbitration.
waitfor SARB, SARB, 100 ;Wait for success.
jnc short arb_select
mov cx, TimeSlice ;Takes long, go to sleep.
call sleep
jnc short arb_loop
jz short arb_loop
mov ax, STERR+11h ;Character I/O call interrupted.
stc
ret
arb_select:
outtext 4, 'Select target$'
mov al, target_id ;Send both host & target SCSI IDs.
or dat, al
mov cmd, CEN+CPE+CATN+CSEL ;Signal target selection. Request
waitfor SBSY, SBSY, 250 ;a message out phase via ATN.
jc short dev_not_ready
mov cmd, CEN+CPE+CATN ;Now target controls SEL.
outtext 4, 'Arbitration done$'
clc
ret
dev_not_ready:
outtext 1, 'Initiation error$'
mov ax, STERR+02h
stc
ret
arbitrate endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Disconnected. Wait for reselection
; Interrupts are disabled on entry.
; C=1, AX=error-code
reconnect proc near
outtext 3, 'Waiting for reselection$'
res_loop:
cli
cmp reconnect_flag, 0 ;Check the flag to be sure
jne res_ok ;the interrupt didn't get lost.
mov cx, 1000 ;Wait for reselection.
call sleep
sti
jnc short res_ok ;Event?
jnz short res_int ;Interrupt?
jmp short res_loop ;Timeout.
res_ok:
sti
outtext 3, 'Reconnected$'
mov wait_for_int, 0
clc
ret
res_int:
outtext 1, 'Reconnection interrupted$'
mov ax, STERR+11h ;Character I/O call interrupted.
mov wait_for_int, 0
stc
ret
reconnect endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; On SCSI bus. Execute transfer as controlled by target.
; C=1, AX=error-code on error
;
execute proc near
outtext 3, 'Execute$'
push di
push si
mov xstatus, 0
jmp x_loop
even ;CD IO MSG phase
x_table dw x_data_out ;0 0 0 data out
dw x_inv_bus ;0 0 1 -invalid-
dw x_data_in ;0 1 0 data in
dw x_inv_bus ;0 1 1 -invalid-
dw x_cmd_out ;1 0 0 command
dw x_msg_out ;1 0 1 message out
dw x_stat_in ;1 1 0 status
dw x_msg_in ;1 1 1 message in
x_inv_bus:
outtext 1, 'X: Invalid bus state$'
call bus_reset ;Bus reset required.
mov ax, STERR+0Ch ;General failure.
jmp x_error
x_parity:
outtext 1, 'X: Parity error$'
mov cmd, CEN+CPE+CATN ;Request message phase
mov msg_byte, MsgError ;to inform the target of the problem.
jmp x_loop ;Target should terminate the command.
x_loop: mov bl, cmd ;First check for next byte.
outtext 20, 'X_Loop '
outbyte 20, bl
outchar 20, '$'
test bl, SBSY
jz x_not_bsy
test bl, SREQ
jz short x_wait
test bl, SPE
jnz short x_parity
x_jump: and bx, SCD+SIO+SMSG ;Execute next byte or block.
jmp x_table[bx]
x_wait: mov cx, 100 ;Not yet avail., setup for timeout.
call set_time
x_test: mov bl, cmd ;Wait for next byte or timeout.
outtext 20, 'X_Loop '
outbyte 20, bl
outchar 20, '$'
test bl, SBSY
jz x_not_bsy
test bl, SREQ
jnz short x_jump
test bl, SPE
jnz x_parity
call yield
call cmp_time
jb short x_test
mov cx, TimeSlice ;Takes a long time
call sleep ;so give up timeslices.
jnc short x_test
jnz short x_interrupted
mov al, msg_byte ;Timeout.
test al, MsgIdentify ;Message out phase pending?
jnz short x_test
cmp al, MsgReject
je short x_test
x_no_response:
outtext 1, 'X: No response$' ;Target did not respond to message out.
call bus_reset ;phase request. Reset the bus.
mov ax, STERR+02h ;Device not ready
jmp x_error
x_interrupted:
outtext 1, 'X: Interrupted$'
cmp msg_byte, MsgAbort ;Repeated?
je short x_no_response
mov cmd, CEN+CPE+CIE+CATN ;Request message phase
mov msg_byte, MsgAbort ;to abort the running command.
mov xstatus, STERR+11h ;Character I/O call interrupted.
jmp x_loop
x_not_bsy:
cmp msg_byte, MsgReset ;Bus free due to reset message?
je short x_retx
cmp msg_byte, MsgAbort ;Bus free due to abort message?
je short x_retx
outtext 1, 'X: Not BSY$' ;No, a real failure.
mov ax, STERR+0Ch ;General failure.
jmp x_error
x_ovf:
mov cmd, CEN+CPE+CIE+CATN ;Request message phase
outtext 1, 'X: Overflow$'
mov msg_byte, MsgAbort ;to abort the running command.
mov xstatus, STERR+0Ch ;General failure.
mov data_len, 0
jmp x_loop
x_error:
pop si
pop di
stc
ret
x_retx: mov ax, xstatus
test ax, ax
jnz short x_error
x_ret: pop si
pop di
clc
ret
x_data_in:
cld
if EnableFast
cmp fast_xfer, 0
jne x_fast_in
endif
mov al, dat
sub data_len, 1
jc x_ovf
outtext 5, 'Slow data in: '
outbyte 5, al
outtext 5, ' at '
outword 5, actual_len
outchar 5, '$'
les di, data_ptr
stos byte ptr es:[di]
mov data_ptr._off, di
inc actual_len
jmp x_loop
if EnableFast
x_fi_0: mov fast_xfer, 0
jmp x_ovf
x_fast_in:
mov cx, data_len
cmp cx, BlockSize
jb short x_fi_1
mov cx, BlockSize
x_fi_1: jcxz x_fi_0
outtext 4, 'Fast data in: '
outword 4, cx
outtext 4, ' at '
outword 4, actual_len
outchar 4, '$'
add actual_len, cx
sub data_len, cx
mov si, _dat
les di, data_ptr
rep movs byte ptr es:[di], byte ptr fs:[si]
mov data_ptr._off, di
jmp x_loop
endif
x_data_out:
cld
if EnableFast
cmp fast_xfer, 0
jne x_fast_out
endif
sub data_len, 1
jc x_do_0
les si, data_ptr
lods byte ptr es:[si]
mov data_ptr._off, si
mov dat, al
outtext 5, 'Slow data out: '
outbyte 5, al
outtext 5, ' at '
outword 5, actual_len
outchar 5, '$'
inc actual_len
jmp x_loop
x_do_0: mov dat, 0
jmp x_ovf
if EnableFast
x_fo_0: mov fast_xfer, 0
jmp x_ovf
x_fast_out:
mov cx, data_len
cmp cx, BlockSize
jb short x_fo_1
mov cx, BlockSize
x_fo_1: jcxz x_fo_0
outtext 4, 'Fast data out: '
outword 4, cx
outtext 4, ' at '
outword 4, actual_len
outchar 4, '$'
add actual_len, cx
sub data_len, cx
lgs si, data_ptr
mov ax, fs
mov es, ax
mov di, _dat
if EnableBlock
rep movs byte ptr es:[di], byte ptr gs:[si]
else
x_fo_2: movs byte ptr es:[di], byte ptr gs:[si]
push cx
mov cx, WrtWait
loop $
pop cx
loop x_fo_2
endif
mov data_ptr._off, si
jmp x_loop
endif
x_msg_in:
outtext 4, 'Message in: '
cli
mov wait_for_int, 1 ;Enable full interrupt management,
mov reconnect_flag, 0
mov cmd, CEN+CPE+CIE ;don't miss reselection interrupt.
mov al, dat
cmp al, MsgDisconnect
je short x_disconnect
mov wait_for_int, 0 ;Not a disconnect, forget about
sti ;interrupts.
cmp al, MsgComplete
je short x_complete
test al, MsgIdentify ;Check for other known messages.
jnz short x_msg_ok
cmp al, MsgSavePointer
je short x_msg_ok
cmp al, MsgRestPointer
je short x_msg_ok
mov cmd, CEN+CPE+CIE+CATN ;Unknown message, request message out
mov msg_byte, MsgReject ;phase and signal message reject.
outtext 4, 'Rejected '
outbyte 4, al
x_msg_ok:
outchar 4, '$'
jmp x_loop
x_disconnect:
outtext 4, 'Disconnect$'
waitfor SBSY, 0, 100 ;Wait until bus free
mov cmd, CPE+CIE ; and release bus.
call reconnect
jnc x_loop
push ax ;Reconnection failed, abort command.
call abort
pop ax
jmp x_error
x_complete:
outtext 4, 'Complete$'
waitfor SBSY, 0, 100 ;Wait until bus free
mov cmd, CPE+CIE ; and release bus.
jmp x_retx
x_msg_out:
outtext 4, 'Message out: '
outbyte 4, msg_byte
outchar 4, '$'
mov cmd, CEN+CPE+CIE ;Release message phase request.
mov al, msg_byte
mov dat, al
jmp x_loop
x_cmd_out:
mov si, cmdptr
lodsb
mov dat, al
mov cmdptr, si
outtext 5, 'Command out: '
outbyte 5, al
outchar 5, '$'
jmp x_loop
x_stat_in:
mov al, dat
mov status, al
outtext 4, 'Status in: '
outbyte 4, al
outchar 4, '$'
jmp x_loop
execute endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Reset SCSI bus.
;
bus_reset proc near
push fs
mov fs, port_seg
outtext 2, 'Bus reset$'
mov cmd, CEN+CPE+CRST
mov cx, 100
call delay
mov cmd, 0
mov cx, 100
call delay
pop fs
clc
ret
bus_reset endp
;
; Reset device.
;
device_reset proc near
push fs
mov fs, port_seg
outtext 2, 'Device reset$'
mov msg_byte, MsgReset
call arbitrate
jc short drst_r
call execute
drst_r: pop fs
ret
device_reset endp
;
; Abort command.
abort proc near
push fs
mov fs, port_seg
outtext 2, 'Abort command$'
mov msg_byte, MsgAbort
call arbitrate
jc short abrt_r
call execute
abrt_r: pop fs
ret
abort endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Execute SCSI command
; In:
; AL = 0 for slow, 1 for fast transfer
; EBX = virtual data transfer address
; CX = expected data length
; DX = pointer to command record
; Out:
; C = set on error
; AX = error code, 0 if no error
; CX = number of data bytes actually transferred
; DL = status byte, 0FFh if no status available
;
command proc near
push fs
push es
if trace
pusha
outtext 2, 'Command, len='
outword 2, cx
outtext 2, ', cmd:'
mov si, dx
mov cx, 6
cmd1: lodsb
outchar 2, ' '
outbyte 2, al
loop cmd1
outchar 2, '$'
popa
endif
mov fast_xfer, al
mov data_ptr, ebx
mov data_len, cx
mov cmdptr, dx
mov actual_len, 0
mov status, 0FFh
mov fs, port_seg
mov msg_byte, MsgIdentify+MsgCanDisconn+0
call arbitrate
jc short cmd_e
call execute
jc short cmd_e
mov dl, status
mov cx, actual_len
outtext 2, 'Command status='
outbyte 2, dl
outtext 2, ', length='
outword 2, cx
outchar 2, '$'
pop es
pop fs
clc
ret
cmd_e: mov dl, status
mov cx, actual_len
outtext 2, 'Command error='
outword 2, ax
outtext 2, ', status='
outbyte 2, dl
outtext 2, ', length='
outword 2, cx
outchar 2, '$'
pop es
pop fs
stc
ret
command endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
init_io proc near
push di
push si
outtext 2, 'ST_Tape IO init$'
mov ax, phys_addr._hi ;Clear cmd register.
mov bx, phys_addr._lo
mov cx, 1000h
mov dh, 1
DevHlp DevHlp_PhysToVirt
jc init_r
mov byte ptr es:[di+_cmd], 0
DevHlp DevHlp_UnPhysToVirt
mov al, 1 ;Get sysinfo segment (for msec timer).
DevHlp DevHlp_GetDOSVar
jc init_r
mov es, ax
mov ax, es:[bx]
mov sysinfo_seg, ax
mov al, 8 ;Get pointer to yield flag.
DevHlp DevHlp_GetDOSVar
jc init_r
mov yield_ptr._seg, ax
mov yield_ptr._off, bx
sub si, si ;The physical address of the driver's
DevHlp DevHlp_VirtToPhys ;data segment is used as event ID.
mov event_id._hi, ax
mov event_id._lo, bx
mov ax, ds ;Allocate port I/O segment selector.
mov es, ax
mov di, offset port_seg
mov cx, 1
DevHlp DevHlp_AllocGDTSel
jc short init_r
mov ax, phys_addr._hi ;Set port I/O segment address.
mov bx, phys_addr._lo
mov cx, 1000h
mov si, port_seg
DevHlp DevHlp_PhysToGDTSel
jc short init_r
mov ax, offset dev_interrupt
mov bx, irq_num ;Set interrupt handler.
mov dh, 0
DevHlp DevHlp_SetIRQ
jc short init_r
init_r: pop si
pop di
ret
init_io endp
EndCode
end