antoine-source/scsi2/SCSI.Drivers/SCSI Filter read

1 line
23 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;*******************************************************
;
; SCSI Driver 'Read' filter.
;
; Written by Matt Gulick. Started June 13,1988
;
; Copyright Apple Computer, Inc. 1988,89
;
;*******************************************************
;*******************************************************
;
; This file contains the 'Read' filter as defined in
; the ERS.
;
;*******************************************************
;*******************************************************
;
; Revision History:
;
;*******************************************************
; June 13, 1988 File started.
; June 20, 1988 Registers in and out are
STRING PASCAL
BLANKS OFF
PAGESIZE 70
PRINT NOGEN
PRINT NOMDIR
MACHINE M65816
IMPORT unit_state
IMPORT main_drvr
IMPORT call_type
IMPORT r_get_cache
IMPORT r_all_in_cache
IMPORT divend
IMPORT divsor
IMPORT result
IMPORT max_blk_cnt
IMPORT m_blk_size
IMPORT m_blk_cnt
IMPORT calc_bytes
IMPORT m_rslt
IMPORT gsos_dpage
IMPORT divide
IMPORT check_532_rw
IMPORT chk_play_mode
IMPORT auto_sense_data
IMPORT sense_data
IMPORT open_flag
IMPORT get_data_status
IMPORT internal_buff
IMPORT scratch0
IMPORT internal
PRINT OFF
INCLUDE 'scsihd.equates'
INCLUDE 'M16.MEMORY'
INCLUDE 'M16.UTIL'
PRINT ON
EJECT
IF block_dvc = true\
AND character_dvc = false THEN
;*******************************************************
;
; Main Entry point to the 'Read' filter. This
; "Filter" takes the information given by the caller
; on direct page and builds the equivilent to a Read
; Extended Status Call. In order of appearence:
;
; Verify that Device # ­ $0000
; Call Number = $0002
; Block Size = dib.blksize
;
; We now Build the SCSI Main Driver Command and send
; it.
;
; The following will be validated by the Main Driver
; when it builds the command.
;
; Request Count = Block Size * i
; Block Number = Blk Num + Offset
; This is for partitions.
;
; After calling the Main driver and if no errors were
; encountered, then the Transfer count will be
; updated.
;
; Inputs: None.
;
; Outputs: Acc = 0
; Carry = 0
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Errors: See Spec.
;
;*******************************************************
ENDIF
IF character_dvc = true\
AND block_dvc = false THEN
;*******************************************************
;
; Main Entry point to the 'Read' filter. This
; "Filter" takes the information given by the caller
; on direct page and builds the equivilent to a Read
; Extended Status Call. In order of appearence:
;
; Verify that Device # ­ $0000
; Call Number = $0002
; Block Size = $0000
; Device Opened = True
;
; We now Build the SCSI Main Driver Command and send
; it.
;
; After calling the Main driver and if no errors were
; encountered, then the Transfer count will be
; updated.
;
; Inputs: None.
;
; Outputs: Acc = 0
; Carry = 0
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Errors: See Spec.
;
;*******************************************************
ENDIF
EXPORT Read
Read PROC
;-------------------------------------------------------------------------------
IF block_dvc = true\
AND character_dvc = false THEN
stz @cache
;
; Is the device Removable?
;
ldy #dib.dvcchar
lda [dib_ptr],y
and #removable
beq @online ;No.
;
; This device is removable. Now we
; need to check to see if the unit
; has gone offline, (then we need to
; report that to the OS) or if the
; unit has come back online (Rebuild
; the DIBs).
;
jsr unit_state
bcs @rts_out
;
; Is the device online?
;
@online ldy #dib.dvcflag
lda [dib_ptr],y
and #dvc_hardofl
bne @off_line ;Yes.
lda [dib_ptr],y
and #dvc_online
bne @read ;Yes.
;
; Device is currently offline.
;
@off_line lda #drvr_off_line
sec
@rts_out rts
;
; Preserve entry values. This will
; help restore the environment when
; we exit. To much is going on for
; speeds sake to rely on these
; locations.
;
@read lda <rqst_cnt
sta @orig_rqst
lda <rqst_cnt+2
sta @orig_rqst+2
;
; Preserve Buffer pointer in case we
; need to bump it.
;
lda <buff_ptr
sta @orig_buff
lda <buff_ptr+2
sta @orig_buff+2
;
; Preserve starting Block Number in case
; we need to bump it.
;
lda <block_num
sta @orig_strt_blk
lda <block_num+2
sta @orig_strt_blk+2
;-------------------------------------------------------------------------------
IF scsi_dtype = apple_cd\
OR scsi_dtype = changer THEN
;
; If the device is a CD_ROM device
; then check to see if it is in audio
; play mode. If not clear the play
; flag, otherwise set the audio play
; flag. This is used to prevent reads
; while the audio tracks are playing.
;
; Is the device in Play Mode?
;
jsr chk_play_mode
ldy #dib.dvcflag
bcs @no_play_mode
lda #play_mode
ora [dib_ptr],y
bra @store_play
@no_play_mode lda #play_mode--\
$ffff
and [dib_ptr],y
@store_play sta [dib_ptr],y
bcs @read_2 ;No.
;
; Device is Busy in PLAY MODE..
;
lda #drvr_busy
sec
rts
@read_2
ENDIF
;-------------------------------------------------------------------------------
;
; Let's check the request count. If
; this is $00000000, then exit clean
; with no data transfered.
;
lda <rqst_cnt
and #$01ff ;Cheap Check for multiple of 512
bne @bad_rqst_cnt
lda <rqst_cnt
ora <rqst_cnt+2
bne @chk_max
jmp @out_of_here
;
; Block Number is beyond the range for this disk.
;
@out_of_range lda #drvr_bad_blk
sec
rts
;
; Requested Byte Count not a multiple of 512
;
@bad_rqst_cnt lda #drvr_bad_cnt
sec
rts
;
; Check to see if more is being
; requested then we can give him.
;
@chk_max lda <rqst_cnt
sta |divend
lda <rqst_cnt+2
sta |divend+2
lda #block_size
sta |divsor
sec
ldy #dib.blkcnt
lda [dib_ptr],y
sbc <block_num
sta |max_blk_cnt
tax
ldy #dib.blkcnt+2
lda [dib_ptr],y
sbc <block_num+2
sta |max_blk_cnt+2
bcc @out_of_range
ora |max_blk_cnt
beq @out_of_range
jsr divide
bcc @dont_fix_cnt
lda #block_size
sta |m_blk_size
lda |max_blk_cnt
sta |m_blk_cnt
lda |max_blk_cnt+2
sta |m_blk_cnt+2
jsr calc_bytes
lda |m_rslt
sta <rqst_cnt
sta @orig_rqst
lda |m_rslt+2
sta <rqst_cnt+2
sta @orig_rqst+2
@dont_fix_cnt
;-------------------------------------------------------------------------------
IF scsi_dtype = direct_acc THEN
;
; Verify Block Size.
;
@cnt_non_zero ldy #dib.blksize
lda [dib_ptr],y ;Block Size
cmp <blk_size
bne @chk_532
ldy #dib.blksize+2
lda [dib_ptr],y
beq @blk_size_ok
@bad_parm lda #drvr_bad_parm
sec
@rts_now rts
;
; Check for 532 byte block size
;
@chk_532 tax
lda <blk_size
cmp #block_size
bne @bad_parm
cpx #$0214
beq @no_cache
bra @bad_parm
ELSE
;-------------------------------------------------------------------------------
;
; Verify Block Size.
;
@cnt_non_zero ldy #dib.blksize
lda [dib_ptr],y ;Block Size
cmp <blk_size
bne @bad_parm
ldy #dib.blksize+2
lda [dib_ptr],y
beq @blk_size_ok
@bad_parm lda #drvr_bad_parm
sec
@rts_now rts
ENDIF
;-------------------------------------------------------------------------------
@blk_size_ok
;-------------------------------------------------------------------------------
IF cache_blks = true THEN
;
; Skip Cache if FST Number >$8000
; Otherwise check to see if they are
; all in the cache. If not we will
; need to issue a read call. If they
; are all there we will skip the read
; and go to the post processing
; section.
;
bit <fst_num ;Force Device Access?
bmi @no_cache ;Yes.
dec @cache
jsr r_all_in_cache ;Are they all there?
bcc @all_there ;Yes.
ENDIF
;-------------------------------------------------------------------------------
@no_cache
;
; Build the (Read Data) Status
; Command $8028, and just in case
; it is not accepted, we will also
; build $8008.
;
lda <block_num ; Sent to me Low >> High.
xba ; I Send it out High >> Low.
sta |c_block_num_l+2
sta |c_block_num_s
lda <block_num+2
xba
sta |c_block_num_l
;
; Set Main Driver Pointer to
; our data for the command.
;
lda #cmd_$8028
sta <scsi_mdrvr
lda #^cmd_$8028
sta <scsi_mdrvr+2
;
; Call Main Driver
;
lda #scsit_stat
sta |call_type
;-------------------------------------------------------------------------------
IF scsi_dtype = direct_acc THEN
;
; Issue the call.
;
jsr check_532_rw
bcc @all_there ;Everything went ok.
cmp #drvr_bad_code ;Was it a Bad Command?
beq @munge ;Yes. Do the Munging
brl @crapped_out2 ;No. Then get out of here.
@all_there jmp @completed
;
; At this point the extended call was not
; excepted. We must now issue the normal
; version of this command. First, we must
; check to see if the request is within the
; one byte block count range. If not, we
; will need to special process this request.
;
; Setup Divide routine while preserving the
; origonal count for later.
;
@munge lda @orig_rqst
sta @rem_rqst
sta |divend
lda @orig_rqst+2
sta @rem_rqst+2
sta |divend+2
lda <blk_size
sta |divsor
jsr divide
bcs @rts_0
;
; Get result in block count. If > $80,
; then we need to break it into multiple
; calls. If not, then send it as is.
;
lda |result+1
bne @gr8er_80
lda |result
dec a
cmp #$0080
blt @issue_call
;
; Set the max count for a single byte block
; count (Block size * $80).
;
@gr8er_80 lda <blk_size+1
and #$00ff
lsr a
sta <rqst_cnt+2
lda <blk_size-1
and #$ff00
ror a
sta <rqst_cnt
;
; Set Main Driver Pointer to
; our data for the command.
;
@issue_call lda #cmd_$8008
sta <scsi_mdrvr
lda #^cmd_$8008
sta <scsi_mdrvr+2
;
; Call Main Driver
;
lda #scsit_stat
sta |call_type
;
; Issue the call.
;
jsr check_532_rw
bcc @did_munge
sta @error_loc
lda auto_sense_data+\
rqst_sens.sense_key
and #$00ff ;Checking for $03
cmp #$0003 ;This covers $03
bne @craped_out
;
; Some kind of I/O Error.
;
@io_error lda #drvr_io
sec
rts
@craped_out lda @error_loc
@crapped_out2 and #$7FFF
cmp #$7E00
bge @io_error
sec
@rts_0 rts
@error_loc dc.w null
;
; Check for special processing.
;
@did_munge ;
; Get Transfer Result and bump values
; for the next call.
;
clc
ldy #dib.trx_rqst
lda [dib_ptr],y
sta @trans_cnt
adc <buff_ptr
sta <buff_ptr
ldy #dib.trx_rqst+2
lda [dib_ptr],y
sta @trans_cnt+2
adc <buff_ptr+2
sta <buff_ptr+2
;
; Get remaining bytes to be transfered.
;
sec
lda @rem_rqst
sbc @trans_cnt
sta @rem_rqst
lda @rem_rqst+2
sbc @trans_cnt+2
sta @rem_rqst+2
ora @rem_rqst
beq @done
clc ;Cause = values to result in Negative
lda @rem_rqst
sbc <rqst_cnt
lda @rem_rqst+2
sbc <rqst_cnt+2
bpl @over
lda @rem_rqst
sta <rqst_cnt
lda @rem_rqst+2
sta <rqst_cnt+2
;
;*****************************************
;* Bump Block number. Pay close *
;* attention to what this comment says. *
;* If you don't and you change the code *
;* then your on your own. This word is *
;* in MSB >> LSB order. We need to add *
;* $100 to it. This is done by a simple *
;* increment. *
;*****************************************
;
@over lda |c_block_num_s
clc
xba
adc #$0080
xba
sta |c_block_num_s
brl @issue_call
;
; Restore the environment.
;
@done lda @orig_rqst
sta <rqst_cnt
lda @orig_rqst+2
sta <rqst_cnt+2
lda @orig_buff
sta <buff_ptr
lda @orig_buff+2
sta <buff_ptr+2
ENDIF
;-------------------------------------------------------------------------------
IF scsi_dtype = apple_cd\
OR scsi_dtype = changer THEN
@redo_CDread jsr |main_drvr
bcc @all_there
cmp #$fe11
beq @redo_CDread
lda auto_sense_data+\ ;Is it an audio disk?
rqst_sens.addnl_sens_code
and #$00ff ;Checking for $84, $64, or $63
cmp #$0063 ;This cover $63
beq @audio_disk
cmp #$0064 ;This cover $64
beq @audio_disk
cmp #$0084 ;This cover $84
beq @audio_disk
lda #drvr_io
sec
rts ;There was an error!
@audio_disk lda #drvr_no_dev
sec
rts
@all_there
ENDIF
;-------------------------------------------------------------------------------
IF scsi_dtype = mcd_40 THEN
jsr |main_drvr
bcc @all_there
lda auto_sense_data+\
rqst_sens.addnl_sens_code
and #$00ff ;Checking for $04, $A7, $A8, or $B0
cmp #$0004 ;This cover $04
beq @not_ready
cmp #$00A7 ;This cover $A7
beq @not_ready
cmp #$00A8 ;This cover $A8
beq @not_ready
cmp #$00B0 ;This cover $B0
beq @not_ready
lda #drvr_io
sec
rts ;There was an error!
@not_ready lda #drvr_off_line
sec
rts
@all_there
ENDIF
;-------------------------------------------------------------------------------
@completed
;-------------------------------------------------------------------------------
IF cache_blks = true THEN
;
; Check force device access Flag. If
; set, then exit out.
;
bit @cache ;Forced Device Access?
bpl @out_of_here ;Yes.
;
; Check for CACHING.
;
clc ;Flag to force cache if needed.
lda <cache_prio ;Force Cache?
bne @do_cache ;Yes.
sec ;Update only.
@do_cache jsr r_get_cache
ENDIF
;-------------------------------------------------------------------------------
@out_of_here
;
; Restore the environment and
; update Transfer Count.
;
ldx |gsos_dpage
lda >rqst_cnt,x
sta <rqst_cnt
lda >rqst_cnt+2,x
sta <rqst_cnt+2
lda @orig_rqst
sta <trans_cnt
lda @orig_rqst+2
sta <trans_cnt+2
lda @orig_buff
sta <buff_ptr
lda @orig_buff+2
sta <buff_ptr+2
lda @orig_strt_blk
sta <block_num
lda @orig_strt_blk+2
sta <block_num+2
;
; Exit No Error.
;
lda #$0000
clc
@rts rts
;
; Variables and storage for short call.
;
@cache dc.w null ;Cache flag
@orig_buff dc.l null ;Origonal Buffer Pointer
@orig_rqst dc.l null ;Origonal Request Count
@orig_strt_blk dc.l null ;Origonal Starting Block Number
@rem_rqst dc.l null ;Number of bytes remaining
@trans_cnt dc.l null ;number of bytes transfered by device
;this time
;
; Command Data for this call.
;
cmd_$8028 dc.b $28
dc.b $00
c_block_num_l dc.l $00000000
c_block_cnt_l dcb.b 3,$00
dcb.b 7,$00
;
; Command Data for this call.
;
cmd_$8008 dc.b $08
dc.b $00
c_block_num_s dc.w $0000
c_block_cnt_s dc.b $00
dcb.b 7,$00
ENDIF
;-------------------------------------------------------------------------------
IF character_dvc = true\
AND block_dvc = false THEN
;
; Check to see if the Device is Opened.
;
lda |open_flag
beq @not_open
;
; Is the device online?
;
@open
ldy #dib.dvcflag
lda [dib_ptr],y
and #dvc_hardofl
bne @off_line ;Yes.
lda [dib_ptr],y
and #dvc_online
bne @read ;Yes.
;
; Device is currently offline.
;
@off_line lda #drvr_off_line
sec
@rts_out rts
;
; Device is not Opened.
;
@not_open lda #drvr_not_open
sec
rts
@read
;-------------------------------------------------------------------------------
IF scsi_dtype = scanner THEN
;
; Save Requested amount for later.
;
lda <rqst_cnt
sta @t_rqst_cnt ;Total Request Count (LOW)
sta @r_rqst_cnt ;Remaining Request Count (LOW)
lda <rqst_cnt+2
sta @t_rqst_cnt+2 ;Total Request Count (HIGH)
sta @r_rqst_cnt+2 ;Remaining Request Count (HIGH)
lda <buff_ptr
sta @orig_buffer
lda <buff_ptr+2
sta @orig_buffer+2
;
; Clear out Total Data Transfered Area.
;
stz @t_transfered
stz @t_transfered+2
;
; Check to see if there is data to be had.
;
@wait_loop jsr |get_data_status
bcs @io_error
lda |gds.data_avail\
+sense_data
ora |gds.data_avail\
+sense_data\
+1
beq @wait_loop
bra @have_data
;
; Return an I/O Error.
;
@io_error lda #drvr_io
sec
rts
;
; We have Data. We need to check to see
; if this is enough to give the user what
; he requested.
;
@have_data stz @enough_data
lda |gds.data_avail\ ;Data is in High -> Low format.
+sense_data\
+1
xba
sta |scratch0
lda |gds.data_avail\
+sense_data\
-1
xba
and #$00ff
sta |scratch0+2
sec
lda @r_rqst_cnt
sbc |scratch0
sta @stuff
lda @r_rqst_cnt+2
sbc |scratch0+2
;
; Was the request count < than what is
; available in the scanner? If so then
; we will return request count bytes only.
;
; Were They equal?
;
blt @do_rqst_cnt ;Yes.
ora @stuff
beq @do_rqst_cnt ;Yes.
;
; Well, it would apear that the request
; count is > then what is available. We
; will go ahead and get what is there
; and then we will check the wait flag.
; If we are in wait state, then we will
; loop around until we are able to get
; what the user has requested. If we are
; not in wait state, then we will exit
; after the read.
;
ldx |scratch0
ldy |scratch0+2
sec
lda @r_rqst_cnt
sbc |scratch0
sta @r_rqst_cnt
lda @r_rqst_cnt+2
sbc |scratch0+2
sta @r_rqst_cnt+2
dec @enough_data
bra @do_read
@do_rqst_cnt ldx @r_rqst_cnt
ldy @r_rqst_cnt+2
stz @r_rqst_cnt
stz @r_rqst_cnt+2
;
; Set our Request Count for this call.
;
@do_read stx <rqst_cnt
sty <rqst_cnt+2
;
; Set Main Driver Pointer to our data for the
; command.
;
lda #cmd_$8028
sta <scsi_mdrvr
lda #^cmd_$8028
sta <scsi_mdrvr+2
;
; It's a Status Call.
;
lda #scsit_stat
sta |call_type
;
; Set Internal Command Flag
;
dec |internal
;
; Issue the call.
;
jsr |main_drvr
;
; Save transfer count.
;
clc
ldy #dib.trx_len
lda [dib_ptr],y
adc @t_transfered
sta @t_transfered
ldy #dib.trx_len+2
lda [dib_ptr],y
adc @t_transfered+2
sta @t_transfered+2
;
; Was there enough data?
;
lda @enough_data
beq @no_wait ;Yes.
;
; Are we in WAIT Mode?
;
ldy #dib.dvcflag
lda [dib_ptr],y
and #wait_mode
beq @no_wait ;No.
;
; Bump Buffer Pointer
;
clc
ldy #dib.trx_len
lda [dib_ptr],y
adc <buff_ptr
sta <buff_ptr
ldy #dib.trx_len+2
lda [dib_ptr],y
adc <buff_ptr+2
sta <buff_ptr+2
jmp @wait_loop ;Yes.
;
; Update transfer count.
;
@no_wait lda @orig_buffer
sta <buff_ptr
lda @orig_buffer+2
sta <buff_ptr+2
lda @t_transfered
sta <trans_cnt
lda @t_transfered+2
sta <trans_cnt+2
;
; Clean Exit.
;
lda #$0000
clc
rts
;
; Data Area.
;
@orig_buffer dc.l null ;Origonal Buffer Pointer
@t_rqst_cnt dc.l null ;TOTAL REQUEST COUNT
@r_rqst_cnt dc.l null ;REMAINING REQUEST COUNT
@t_transfered dc.l null ;AMOUNT ACTUALLY TRANSFERED
@enough_data dc.w null ;Is there enough data flag.
@stuff dc.w null ;Temporary Storage
;
; Command Description.
;
cmd_$8028 dc.b $28
rel_adr dc.b null ;Relative Address Bit is bit 0
t_data_type dc.b null ;Transfer Data Type
dc.b null ;Reserved
t_id dc.w null ;Transfer ID
t_length dcb.b 3,null ;Transfer Length
control dc.b null ;Control Byte
ENDIF
;-------------------------------------------------------------------------------
ENDIF
;-------------------------------------------------------------------------------
ENDP
EJECT
END