home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-387-Vol-3of3.iso
/
g
/
gtak212.zip
/
OS2-ST01
/
st_tape.asm
< prev
next >
Wrap
Assembly Source File
|
1992-05-23
|
16KB
|
709 lines
SUBTTL Main Module
INCLUDE DEFS.INC ; which includes some other .incs
include debug.inc
StartData
;====================================================
;
; Device Header -
;
;====================================================
TAPE_DEV LABEL WORD
DD -1 ; SYSINIT handles the segment part
DW DEV_CHAR_DEV or DEV_PROTECT or DEV_OPEN or DEVLEV_2 or DEV_GIOCTL
; Use equates in DEVHDR.INC
; to define Attribute word
DW STRAT ; offset to strategy routine entry point
DW 0 ; IDC entry point
DB 'TAPE$4 ' ; Name of device
DPS DB 8 DUP (?) ; More reserved
; End of the device header.
;
;============================================================================
;
; data structure used by this device driver
;
EVEN
DISPTAB LABEL WORD
DW TAPE_INIT ;00: Init
DW TAPE_EXIT1 ;01: Media Check (Block Devices Only)
DW TAPE_EXIT1 ;02: Build BPB (Block Devices Only)
DW TAPE_EXIT1 ;03: Reserved (used to be Ioctl Input)
DW TAPE_INPUT ;04: Input (Read)
DW TAPE_INPNOWAIT ;05: Non-Destructive Input, no wait.
DW TAPE_INPSTATUS ;06: Input Status
DW TAPE_INPFLUSH ;07: Input Flush
DW TAPE_OUTPUT ;08: Output (Write)
DW TAPE_OUTVERIFY ;09: Output (Write) with verify
DW TAPE_OUTSTATUS ;0A: Output Status
DW TAPE_OUTFLUSH ;0B: Output Flush
DW TAPE_EXIT1 ;0C: Reserved (used to be Ioctl Output)
DW TAPE_OPEN ;0D: Device Open
DW TAPE_CLOSE ;0E: Device Close
DW TAPE_EXIT1 ;0F: Removable Media
DW TAPE_GIOCTL ;10: Generic Ioctl
DW TAPE_EXIT1 ;11: Reset Media
DW TAPE_EXIT1 ;12: Get Logical Drive Map
DW TAPE_EXIT1 ;13: Set Logical Drive Map
DW TAPE_EXIT1 ;14: DeInstall
DW TAPE_EXIT1 ;15: Port Access
DW TAPE_EXIT1 ;16: Partitionable HDs
DW TAPE_EXIT1 ;17: Logical Unit Mal
DW TAPE_EXIT1 ;18: -
DW TAPE_EXIT1 ;19: -
DW TAPE_EXIT1 ;1A: -
DW TAPE_EXIT1 ;1B: -
MAXCMD = (($ - DispTab)/2) - 1
public DevHlpPtr
even
DevHlpPtr dd 0
ReqPkt dd 0
waiting db 0 ;someone is waiting
lock_flag db 0 ;[0]: parm, [1]: data
even
para_handle dd 0 ;ioctl param handle
data_handle dd 0 ;ioctl data handle
data_ptr dd 0 ;data pointer
cmd_read db 08h, 01h, 0, 0, 0, 0
cmd_write db 0Ah, 01h, 0, 0, 0, 0
cmd_sense db 03h, 00h, 0, 0, 16, 0
sense_data db 16 dup(?)
cmd_block db 10 dup(?)
sense_data_ptr dd offset sense_data
if SCSI_LVL
errcode equ 12 ;SCSI standard
else
errcode equ 14 ;Tandberg
endif
EndData
StartIData
public end_data
end_data db 0
EndIData
StartICode
public end_code
end_code db 0
EndICode
StartCode
extrn command:near
extrn bus_reset:near
extrn device_reset:near
extrn delay:near
page
;============================================================================
;
; - TAPE_STRAT -
;
; Device Driver strategy entry point.
; Parameters - es:bx = Pointer to the request block
;
STRAT PROC FAR
push DevHlpPtr ;Make DevHlp callable w/o using DS/ES
mov bp, sp
mov ax, es
mov fs, ax
mov di, bx
cmp fs:[di].PktCmd, 0 ;INIT command? Debug is not yet
je short str_1 ;initialized.
outtext 2, 'Strategy '
outbyte 2, fs:[di].PktCmd
outchar 2, '$'
str_loop:
cmp ReqPkt._seg, 0 ;Driver busy?
jne str_busy
str_1: mov ReqPkt._off, di ;Save the bimodal address
mov ReqPkt._seg, fs ;of the request packet.
movzx eax, fs:[di].PktCmd ;Get command from packet and execute.
cmp al, MAXCMD
ja str_bad
call DISPTAB[eax*2]
str_x: xor ax, STDONE ;Mark operation complete.
mov fs:[di].PktStatus, ax
outtext 2, 'Strategy return '
outword 2, ax
outchar 2, '$'
cmp waiting, 0 ;Release waiting threads.
je short str_x1
outtext 3, 'Wakeup waiting driver$'
mov ax, ReqPkt._seg
mov bx, ReqPkt._off
mov ReqPkt._seg, 0
DevHlp DevHlp_Run
jmp short str_r
str_x1: mov ReqPkt._seg, 0
str_r: lea sp, [bp+4]
ret
str_busy: ;Driver is busy. Wait.
outtext 2, 'Driver busy$'
inc waiting
push fs
push di
mov ax, ReqPkt._seg ;Use bimodal pointer of running
mov bx, ReqPkt._off ;request packet as event ID.
mov di, 0 ;No timeout.
mov cx, 1000
mov dh, 0 ;Interruptible.
DevHlp DevHlp_Block
pop di
pop fs
pushf
dec waiting
popf
jnc str_loop ;Retry on event or timeout wakeup.
jz str_loop
mov ax, STDONE+STERR+11h ;Character I/O call interrupted.
mov fs:[di].PktStatus, ax
jmp short str_r
str_bad:
mov ax, STERR+03h ;Unknown command.
jmp str_x
STRAT ENDP
TAPE_EXIT1 proc near
mov ax, STERR+03h ;Unknown command.
ret
TAPE_EXIT1 endp
;====================================================
;
; Operations
; ----------
;
; In: FS:DI = ptr to request block
; Out: AX = exit code (incl. DONE)
;
;====================================================
TAPE_INPUT proc near ;04: Input (Read)
smsw ax ;Protected mode only.
test al, 1
jz short terr_1
mov dx, offset cmd_read
jmp rw_command
terr_1: mov ax, STERR+01h ;Unknown unit.
ret
TAPE_INPUT endp
TAPE_INPNOWAIT proc near ;05: Non-Destructive Input, no wait.
mov ax, STBUSY ;busy = none avail
ret
TAPE_INPNOWAIT endp
TAPE_INPSTATUS proc near ;06: Input Status
mov ax, STBUSY ;busy = none avail
ret
TAPE_INPSTATUS endp
TAPE_INPFLUSH proc near ;07: Input Flush
sub ax, ax
ret
TAPE_INPFLUSH endp
TAPE_OUTPUT proc near ;08: Output (Write)
smsw ax ;Protected mode only.
test al, 1
jz short terr_1
mov dx, offset cmd_write
jmp rw_command
TAPE_OUTPUT endp
TAPE_OUTVERIFY proc near ;09: Output (Write) with verify
smsw ax ;Protected mode only.
test al, 1
jz short terr_1
mov dx, offset cmd_write
jmp rw_command
TAPE_OUTVERIFY endp
TAPE_OUTSTATUS proc near ;0A: Output Status
sub ax, ax ;no wait
cmp waiting, 0
je short ost_r
mov ax, STBUSY ;busy + done = wait required
ost_r: ret
TAPE_OUTSTATUS endp
TAPE_OUTFLUSH proc near ;0B: Output Flush
sub ax, ax
ret
TAPE_OUTFLUSH endp
TAPE_OPEN proc near ;0D: Device Open
smsw ax ;Protected mode only.
test al, 1
jz short terr_1
sub ax, ax
ret
TAPE_OPEN endp
TAPE_CLOSE proc near ;0E: Device Close
sub ax, ax
ret
TAPE_CLOSE endp
;====================================================
;
; Generic IOCtl
;
;====================================================
TAPE_GIOCTL proc near ;10: Generic Ioctl
push si
outtext 2, 'IOCtl '
outbyte 2, fs:[di].GIOCategory
outchar 2, ' '
outbyte 2, fs:[di].GIOFunction
outchar 2, '$'
mov lock_flag, 0
movzx eax, fs:[di].GIOFunction
cmp fs:[di].GIOCategory, 80h ;Own IOCtl codes?
je short gio_cat_own
cmp fs:[di].GIOCategory, 11 ;general IOCtl codes?
je short gio_cat_11
gio_bad:
test fs:[di].GIOFunction, 80h ;Ignore invalid command?
jnz short gio_r0
mov ax, STERR+03h ;No, unknown command.
jmp short gio_r
gio_cat_11: ;Category 11: general device control.
cmp al, 01h ;Flush input.
je short gio_r0
cmp al, 02h ;Flush output.
je short gio_r0
cmp ax, 41h ;Session switch notification?
je short gio_r0
cmp ax, 60h ;Query monitor support?
mov ax, STERR+12h ;Monitor calls not supported.
je short gio_r
jmp gio_bad
even
giotab dw gio_scsi_slow ;0
dw gio_scsi_fast ;1
dw gio_bus_reset ;2
dw gio_dev_reset ;3
dw gio_set_trace ;4
gio_cat_own: ;Own IOCtl commands.
and al, 1Fh
cmp al, 04h
ja short gio_bad
jmp giotab[eax*2]
gio_scsi_slow: ;SCSI command - slow transfer.
mov al, 0
call gen_scsi_cmd
jmp short gio_r
gio_scsi_fast: ;SCSI command - fast transfer.
mov al, 1
call gen_scsi_cmd
jmp short gio_r
gio_bus_reset: ;SCSI bus reset.
call bus_reset
jc short gio_r
jmp short gio_r0
gio_dev_reset: ;SCSI device reset.
call device_reset
jc short gio_r
jmp short gio_r0
gio_set_trace:
if trace
push di
mov ax, fs:[di].GIOParaPack._seg
mov di, fs:[di].GIOParaPack._off
mov cx, 1
mov dl, 0 ;read-only
DevHlp DevHlp_VerifyAccess
pop di
jc gio_seg
les bx, fs:[di].GIOParaPack
mov al, es:[bx]
mov tracelvl, al
endif
jmp short gio_r0
gio_r0: sub ax, ax
gio_r: push ax
test lock_flag, 1 ;Unlock parameter and data segment.
jz short gio_r1
mov ax, para_handle._hi
mov bx, para_handle._lo
DevHlp DevHlp_Unlock
gio_r1:
test lock_flag, 2
jz short gio_r2
mov ax, data_handle._hi
mov bx, data_handle._lo
DevHlp DevHlp_Unlock
gio_r2:
mov lock_flag, 0
pop ax
pop si
ret
gio_seg:mov ax, STERR+13h ;iInvalid parameter.
jmp short gio_r
TAPE_GIOCTL endp
;====================================================
;
; Command Subroutines
;
;====================================================
;
; Request sense
;
; AX = device driver error status
; CX = number from information bytes
;
req_sense proc near
push si
mov al, 0 ;Execute "request sense"
mov ebx, sense_data_ptr
mov cx, 16
mov dx, offset cmd_sense
call command
jc reqs_no_stat
cmp cx, 4
jb reqs_no_stat
if trace ge 1
outtext 1, 'Sense data:'
mov si, offset sense_data
reqs_0: lodsb
outchar 1, ' '
outbyte 1, al
loop reqs_0
outchar 1, '$'
endif
mov al, sense_data+0 ;Check for unexpected
and al, 7Fh ;small sense block
cmp al, 70h
jne short reqs_short
cmp sense_data+errcode, 0Ah ;Insufficient Capacity?
jne short reqs_std
mov al, sense_data+2 ;EOM set but sense key
and al, 4Fh ;set to "NO SENSE"?
cmp al, 40h
je short reqs_ew
reqs_std:
mov al, sense_data+errcode ;Translate error class & code.
jmp short reqs_scan
reqs_short:
mov al, sense_data+0
reqs_scan:
and al, 7Fh
mov bx, offset reqs_t
mov cx, reqs_tlen
reqs_1: mov ah, cs:[bx+0]
mov dx, cs:[bx+1]
add bx, 3
cmp al, ah
loopnz reqs_1
jnz short reqs_unknown
mov ax, dx
reqs_r: mov cx, word ptr sense_data+5
xchg ch, cl
pop si
ret
reqs_unknown:
mov ax, STERR+07h ;Any other: unknown media.
jmp reqs_r
reqs_no_stat:
mov ax, STERR+07h ;No sense block
mov cx, 0FFFFh
pop si
ret
reqs_ew: ;Early EOT indication
outtext 1, 'Early Warning$'
mov ax, STERR+09h ;"Out of paper" :-)
jmp short reqs_r
sxlat macro sense, system
db sense
dw system
endm
reqs_t label byte
sxlat 00h, 0 ;no sense no error
sxlat 02h, STERR+02h ;hardware error drive not ready
sxlat 04h, STERR+02h ;drive not ready drive not ready
sxlat 09h, STERR+02h ;media not loaded drive not ready
sxlat 0Ah, STERR+0Ah ;insufficient capacity write fault
sxlat 11h, STERR+04h ;uncorrectable data error CRC error
sxlat 14h, STERR+08h ;no record found sector not found
sxlat 17h, STERR+00h ;write protected write protect violation
sxlat 19h, STERR+04h ;bad block found CRC error
sxlat 1Ch, 0 ;file mark detected EOF
sxlat 1Dh, STERR+04h ;compare error CRC error
sxlat 20h, STERR+03h ;invalid command unknown command
sxlat 30h, STERR+0Dh ;unit attention change disk
sxlat 33h, STERR+0Ah ;append error write fault
sxlat 34h, STERR+0Bh ;read EOM read fault
reqs_tlen equ ($ - offset reqs_t) / 3
req_sense endp
;
; Generic R/W command
; DX = command record
;
rw_command proc near
push si
outtext 3, 'R/W '
outword 3, fs:[di].IOpData._hi
outword 3, fs:[di].IOpData._lo
outchar 3, ' '
outword 3, fs:[di].IOcount
outchar 3, '$'
push dx ;Make virtual address
mov ax, fs:[di].IOpData._hi
mov bx, fs:[di].IOpData._lo
mov cx, fs:[di].IOcount
mov si, data_ptr._seg
DevHlp DevHlp_PhysToGDTSel
pop dx
mov ax, STERR+13h ;Invalid parameter.
jc rw_e
test cx, 01FFh ;Verify block alignment
mov ax, STERR+13h ;Invalid parameter.
stc
jnz short rw_e
mov al, ch ;Insert block count into command.
shr al, 1
mov bx, dx
mov [bx+4], al
mov al, 1 ;Run the command.
mov ebx, data_ptr
call command
jc short rw_ret
cmp dl, 00h
je short rw_ret
stc
cmp dl, 02h ;Check status?
mov ax, STERR+02h ;No -> not ready.
jne short rw_ret
call req_sense ;Do check status.
shl cx, 9 ;Convert number of blocks not handled
sub fs:[di].IOcount, cx ;to number of bytes actually xferred.
pop si
ret
rw_ret: mov fs:[di].IOcount, cx ;Number of bytes actually transferred.
pop si
ret
rw_e: mov fs:[di].IOcount, 0
pop si
ret
rw_command endp
;
; Verify and lock ioctl parameter block.
;
vfy_para proc near
cmp fs:[di].GIOParaLength, 0
je vfyp_1
and lock_flag, not 1
mov ax, fs:[di].GIOParaPack._seg
mov bh, 0 ;Lock, short-term, any memory.
mov bl, 0 ;Block until available.
DevHlp DevHlp_Lock
jc short vfyp_1
mov para_handle._hi, ax
mov para_handle._lo, bx
or lock_flag, 1
push di
mov cx, fs:[di].GIOParaLength ;Verify access.
mov ax, fs:[di].GIOParaPack._seg
mov di, fs:[di].GIOParaPack._off
mov dh, 0 ;Read-only.
DevHlp DevHlp_VerifyAccess
pop di
vfyp_1: ret
vfy_para endp
;
; Verify and lock ioctl data block.
; The data block can be NULL.
;
vfy_data proc near
cmp fs:[di].GIODataLength, 0
je vfyd_1
and lock_flag, not 2
movzx eax, fs:[di].GIODataLength ;NULL pointer & length?
or eax, fs:[di].GIODataPack
jz short vfyd_1
mov ax, fs:[di].GIODataPack._seg
mov bh, 0 ;Lock, short-term, any memory.
mov bl, 0 ;Block until available.
DevHlp DevHlp_Lock
jc short vfyd_1
mov data_handle._hi, ax
mov data_handle._lo, bx
or lock_flag, 2
push di
mov cx, fs:[di].GIODataLength ;Verify access.
mov ax, fs:[di].GIODataPack._seg
mov di, fs:[di].GIODataPack._off
mov dh, 1 ;Read+write.
DevHlp DevHlp_VerifyAccess
pop di
vfyd_1: ret
vfy_data endp
;
; Generic IOCTL, Subfunction "general SCSI command"
; AL = 0 for slow, 1 for fast xfer
;
gen_scsi_cmd proc near
push ax ;Slow/fast flag.
call vfy_para
jc short gen_e1
call vfy_data
jc short gen_e1
mov cx, fs:[di].GIOParaLength ;Copy command to data segment.
cmp cx, 10
ja short gen_e1
push di
push si
lgs si, fs:[di].GIOParaPack
mov ax, ds
mov es, ax
mov di, offset cmd_block
cld
rep movs byte ptr es:[di], byte ptr gs:[si]
pop si
pop di
pop ax ;Slow/fast flag
mov ebx, fs:[di].GIODataPack ;Data pointer
mov cx, fs:[di].GIODataLength
mov dx, offset cmd_block ;Execute command
call command
jc short gen_r
cmp dl, 0 ;Is ok, test SCSI status byte.
je short gen_r
mov al, 80h ;Not ok, return SCSI status byte.
or al, dl
jmp short gen_r
gen_e1: add sp, 2
gen_e: mov ax, STERR+13h ;Invalid parameters.
gen_r: ret
gen_scsi_cmd endp
;====================================================
;
; Initialization
;
;====================================================
extrn init_io:near
extrn init_debug:near
TAPE_INIT proc near ;00: Init
mov eax, fs:[di].InitDevHlp ;Set device helper vector.
mov DevHlpPtr, eax
mov ss:[bp], eax
mov sense_data_ptr._seg, ds ;Fixup.
push di ;Allocate selector for data pointer.
mov ax, ds
mov es, ax
mov di, offset data_ptr._seg
mov cx, 1
DevHlp DevHlp_AllocGDTSel
pop di
jc init_e
; les bx, fs:[di].InitParms
; FIXME: Interpret command line.
call init_debug
jc init_e
call init_io
jc init_e
outtext 2, 'ST_Tape Init done$'
init_r: mov fs:[di].InitcUnit, 0
mov fs:[di].InitEcode, offset end_code
mov fs:[di].InitEdata, offset end_data
mov fs:[di].InitpBPB, 0
sub ax, ax
ret
init_e: mov fs:[di].InitcUnit, 0
mov fs:[di].InitEcode, 0
mov fs:[di].InitEdata, 0
mov ax, STERR+0Ch
ret
TAPE_INIT endp
EndCode
end