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

1 line
14 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 'Write' filter.
;
; Written by Matt Gulick. Started June 14,1988
;
; Copyright Apple Computer, Inc. 1988,89
;
;*******************************************************
;*******************************************************
;
; This file contains the 'Write' filter as defined in
; the ERS.
;
;*******************************************************
;*******************************************************
;
; Revision History:
;
;*******************************************************
; June 14, 1988 File started.
; June 21, 1988 Modified to mach the results of
; the Code Review and added
; register comments.
STRING PASCAL
BLANKS OFF
PAGESIZE 70
PRINT NOGEN
PRINT NOMDIR
MACHINE M65816
IMPORT unit_state
IMPORT test_unit_rdy
IMPORT auto_sense_data
IMPORT main_drvr
IMPORT call_type
IMPORT w_update_cache
IMPORT divend
IMPORT divsor
IMPORT result
IMPORT max_blk_cnt
IMPORT divide
IMPORT check_532_rw
PRINT OFF
INCLUDE 'scsihd.equates'
INCLUDE 'M16.MEMORY'
INCLUDE 'M16.UTIL'
PRINT ON
EJECT
;*******************************************************
;
; Main Entry point to the 'Write' filter. This
; "Filter" takes the information given by the caller
; on direct page and builds the equivilent to a Write
; Extended Control Call. In order of appearence:
;
; Verify that Device # ­ $0000
; Call Number = $0003
; 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 = GS/OS Direct Page
; Data Bank = Ours
;
; Errors: See Spec.
;
;*******************************************************
EXPORT Write
Write PROC
;-------------------------------------------------------------------------------
IF scsi_dtype = scanner THEN
;
; Device is not writable.
;
lda #drvr_bad_req
sec
rts
ENDIF
;-------------------------------------------------------------------------------
IF scsi_dtype = apple_cd\
OR scsi_dtype = changer THEN
;
; Device is not writable.
;
lda #drvr_wrt_prot
sec
rts
ENDIF
;-------------------------------------------------------------------------------
IF scsi_dtype <> apple_cd\
AND scsi_dtype <> changer\
AND scsi_dtype <> scanner THEN
stz @cache
;
; Is the device Removable?
;
ldy #dib.dvcchar
lda [dib_ptr],y
and #removable
beq @write ;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?
;
ldy #dib.dvcflag
lda [dib_ptr],y
and #dvc_hardofl
bne @off_line ;Yes.
lda [dib_ptr],y
and #dvc_online
bne @write ;Yes.
;
; Device is currently offline.
;
@off_line lda #drvr_off_line
sec
@rts_out rts
;
; Let's check the request count. If
; this is $00000000, then exit clean
; with no data transfered.
;
@write 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 @completed
;
; 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
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
bcs @rts_now
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
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
;
; Regardless of the Cache Priority,
; we need to see if it is in the cache.
;
; Set flag to cache the block only if
; it is already there.
;
dec @cache
lda <cache_prio ;Deferred Mode?
bmi @deferred ;Yes.
ENDIF
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
@no_cache
;
; Build the (Write Data) Status
; Command $802A, and just in case
; it is not accepted, we will also
; build $800A.
;
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_$802A
sta <scsi_mdrvr
lda #^cmd_$802A
sta <scsi_mdrvr+2
;
; Call Main Driver
;
lda #scsit_cont
sta |call_type
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
IF scsi_dtype = direct_acc THEN
;
; Issue the call.
;
jsr check_532_rw
bcc @deferred ;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.
@deferred 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 <rqst_cnt
sta @orig_rqst
sta @rem_rqst
sta |divend
lda <rqst_cnt+2
sta @orig_rqst+2
sta @rem_rqst+2
sta |divend+2
lda <blk_size
sta |divsor
jsr divide
bcc @do_it
rts
;
; Preserve Buffer pointer. We will need to
; bump it a few times.
;
@do_it lda <buff_ptr
sta @orig_buff
lda <buff_ptr+2
sta @orig_buff+2
;
; 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_$800A
sta <scsi_mdrvr
lda #^cmd_$800A
sta <scsi_mdrvr+2
;
; Call Main Driver
;
lda #scsit_cont
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 *
;* $80 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
ELSE
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
jsr |main_drvr
bcc @completed
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
IF scsi_dtype = mcd_40 THEN
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 #$0027 ;This cover $27 Write Protected
beq @write_protect
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!
@write_protect ldy #dib.dvcchar
lda [dib_ptr],y
and #write_allow--\
$ffff
sta [dib_ptr],y
lda #drvr_wrt_prot
sec
rts
@not_ready lda #drvr_off_line
sec
rts
ENDIF
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lda #drvr_io
rts ;There was an error!
@deferred
ENDIF
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
; Update Transfer Count.
;
@completed lda <rqst_cnt
;-------------------------------------------------------------------------------
IF block_dvc = true\
AND character_dvc = false THEN
and #%1111111111111110
ENDIF ;block_dvc = true
;-------------------------------------------------------------------------------
sta <trans_cnt
lda <rqst_cnt+2
sta <trans_cnt+2
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
IF cache_blks = true THEN
;
; Check if cache bypassed.
;
bit @cache
bpl @out_of_here ;Yes.
clc
lda <cache_prio ;Deferred Mode?
bmi @chk_cache ;Yes.
bne @chk_cache ;No.
sec ;Update only
@chk_cache jsr w_update_cache
bcc @out_of_here
lda <cache_prio ;Deferred Mode?
bpl @out_of_here ;No
stz @cache ;Yes. Force write skipping the cache
jmp @no_cache ;logic this time around.
ENDIF
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
; Exit No Error.
;
@out_of_here lda #$0000
clc
@rts rts
;
; Variables and storage for short call.
;
@cache dc.w null ;Cache flag
@do_532 dc.w null ;532 byte block flag
@orig_buff dc.l null ;Origonal Buffer Pointer
@orig_rqst dc.l null ;Origonal Request Count
@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_$800A dc.b $0A
dc.b $00
c_block_num_s dc.w $0000
c_block_cnt_s dc.b $00
dcb.b 7,$00
;
; Command Data for this call.
;
cmd_$802A dc.b $2A
dc.b $00
c_block_num_l dc.l $00000000
c_block_cnt_l dcb.b 3,$00
dcb.b 7,$00
ENDIF
;-------------------------------------------------------------------------------
ENDP
EJECT
END