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

1 line
23 KiB
Plaintext
Raw Permalink 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