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

1 line
46 KiB
Plaintext

;*******************************************************
;
; SCSI Driver 'Control' filter.
;
; Written by Matt Gulick. Started August 13,1988
;
; Copyright Apple Computer, Inc. 1988,89
;
;*******************************************************
;*******************************************************
;
; This file contains the 'Control' filter as defined
; in the ERS.
;
;*******************************************************
;*******************************************************
;
; Revision History:
;
;*******************************************************
; Aug 13, 1988 File started.
STRING PASCAL
BLANKS OFF
PAGESIZE 70
PRINT NOGEN
PRINT NOMDIR
MACHINE M65816
IMPORT rpm_blk_num
IMPORT wpm_blk_num
IMPORT stat_cont
IMPORT rebuild
IMPORT read_pm_blk
IMPORT write_pm_blk
IMPORT call_type
IMPORT internal
IMPORT main_drvr
IMPORT f_partition
IMPORT direct_page
IMPORT gsos_dpage
IMPORT internal_buff
IMPORT set_our_dp
IMPORT chk_lnk_offline
IMPORT set_disk_sw
IMPORT leave_switched ; *** MSG 12/12/91 ***
IMPORT disk_switch
IMPORT rebld_dibs
IMPORT unit_state
IMPORT test_unit_rdy
IMPORT trash_volume
IMPORT trash_it
IMPORT ko_cache
IMPORT trans_flag
IMPORT uses_dc
IMPORT dib_data_struct
IMPORT display_cnt
IMPORT current_fmt
IMPORT opt1_blk_cnt
IMPORT opt1_blk_siz
IMPORT opt1_interleave
IMPORT opt1_med_siz
IMPORT opt2_blk_cnt
IMPORT opt2_blk_siz
IMPORT opt2_interleave
IMPORT opt2_med_siz
IMPORT opt3_blk_cnt
IMPORT opt3_blk_siz
IMPORT opt3_interleave
IMPORT opt3_med_siz
IMPORT format_data
IMPORT check_532_rw
IMPORT sense_data
IMPORT t_dvc_blocks
IMPORT un_formatted
ENTRY reset_dvc
ENTRY eject
ENTRY s_config_parms
ENTRY s_wait_mode
ENTRY format_opt
ENTRY assign_part
ENTRY arm_signal
ENTRY disarm_sig
ENTRY set_p_map
ENTRY format_dvc
PRINT OFF
INCLUDE 'scsihd.equates'
INCLUDE 'M16.MEMORY'
INCLUDE 'M16.UTIL'
PRINT ON
;-------------------------------------------------------------------------------
IF scsi_dtype = direct_acc THEN
ENTRY sdp
ENTRY svp
ENDIF
;-------------------------------------------------------------------------------
EJECT
;*******************************************************
;
; Main Entry point to the 'Control' filter. This
; "Filter" is called when a Control Command comes in.
; See the headers of the seperate sections for the
; details of the commands.
;
; Called via 'JSR'
;
; Inputs: [dib_ptr] = Target DIB l (LONG)
; Acc = Unspecified
; Carry = Unspecified
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Returns via 'RTS'
;
; Outputs: Acc = 0
; Carry = 0
; or
; Acc = Error
; Carry = 1
;
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Errors: See Spec.
;
;*******************************************************
EXPORT control
control PROC
;
; Check to see if this is a set Config call.
; If so, then don't worry yet about ONLINE
; or REMOVABLE.
;
lda <cont_code
cmp #$0003
beq @control
;
; 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
beq @online ;**** test Code ****
bit |un_formatted ;**** test Code ****
bpl @sec_out ;**** test Code ****
; bmi @rts_out
;
; Check to see if this is a Device Specific
; Status call. If so, then don't worry
; about it being Offline
;
@online lda <cont_code
bmi @control
;
; Is the device online?
;
ldy #dib.dvcflag
lda [dib_ptr],y
and #dvc_online
bne @control ;Yes.
;
; Device is currently offline.
;
lda #drvr_off_line
@sec_out sec
@rts_out rts
;
; Zero out the Data Chaining Flag
;
@control stz |uses_dc
;
; Clear transfer count.
;
lda #null
ldy #dib.trx_len
sta [dib_ptr],y
ldy #dib.trx_len+2
sta [dib_ptr],y
;
; Entry to the Control Call Filter.
; This filter acts as a mini driver.
; It examines the Control Code sent
; and calls the appropriate routines.
; If the Command is $8000 or greater,
; then it will be routed to the device
; specific section.
;
lda <cont_code
bmi @do_dvc_spec ;Device Specific Code.
;
; Check the range of the command.
;
cmp #max_c_cmd+1
bge @error
;
; Convert to an index
;
asl a
tax
jsr (@ncmd_tbl,x)
rts
;
; Normal Command Table.
;
@ncmd_tbl dc.w reset_dvc ;Coded
dc.w format_dvc ;Coded
dc.w eject ;Coded
dc.w s_config_parms ;Coded Temp
dc.w s_wait_mode ;Coded
dc.w format_opt ;Coded
dc.w assign_part
dc.w arm_signal ;Coded & Tested
dc.w disarm_sig ;Coded & Tested
dc.w set_p_map ;Coded & Tested
;
; Bad Command Error.
;
@error lda #drvr_bad_req
sec
rts
;
; Device Specific Code handling
; starts here.
;
@do_dvc_spec
;-------------------------------------------------------------------------------
IF scsi_dtype = direct_acc THEN
cmp #$F000
blt @do_scsi_cmd
and #$00ff
cmp #max_config_cmd+1
bge @error
;
; Convert to an index
;
asl a
tax
jsr (@c_cmd_tbl,x)
rts
;
; Config Command Table.
;
@c_cmd_tbl dc.w sdp ;Coded (Set Disk Parms)
dc.w svp ;Coded (Set Volume Parms)
@do_scsi_cmd
ENDIF
;-------------------------------------------------------------------------------
;
; Check version of data structure
;
stz @chk_zero ;Precondition the flag to no check
lda [buff_ptr]
beq @version_0
cmp #$0001
bne @error
;
; Version 1. Preserve the data pointer
; currently used in the DIB and replace
; it with a pointer to the USER supplied
; Data Chaining instructions.
;
clc
ldy #dib.trx_ptr
lda [dib_ptr],y
sta |dib_data_struct
lda <buff_ptr
adc #ds.DCcode ;Offset to first D.C. Data
sta [dib_ptr],y
ldy #dib.trx_ptr+2
lda [dib_ptr],y
sta |dib_data_struct+2
lda <buff_ptr+2
adc #^ds.DCcode
sta [dib_ptr],y
;
; Set flag to indicate that D.C. Commands
; were used and that we need to restore
; the pointer in the DIB to the normal
; data descriptor. Also set the flag to
; indicate that we need to check the first
; buffer pointer for Zero.
;
dec |uses_dc
dec @chk_zero
;
; Do the rest normally and check the above
; flag later.
;
@version_0 clc
lda <buff_ptr
adc #$0002
sta <scsi_mdrvr
lda <buff_ptr+2
adc #null
sta <scsi_mdrvr+2
ldy #$000C
lda [scsi_mdrvr],y
sta <buff_ptr
ldy #$000C+2
lda [scsi_mdrvr],y
sta <buff_ptr+2
;
; Check First Buffer for $00000000
;
ora <buff_ptr
bne @DH_Branch
lda @chk_zero
bne @error
;
; Call Main Driver
;
@DH_Branch lda #scsit_cont
sta |call_type
jsr |main_drvr
bcs @exit
;
; Save transfer count.
;
ldy #dib.trx_len
lda [dib_ptr],y
sta @call_trns_cnt
ldy #dib.trx_len+2
lda [dib_ptr],y
sta @call_trns_cnt+2
;
; Check to see if we need to handle
; a Disk Switched Event. If not,
; then exit.
;
lda disk_switch ;= $ffff
bpl @exit
;
; Don't Trash the Volumes.
;
jsr set_disk_sw ;DISK_SW for each Linked DIB.
jsr rebld_dibs ;Rebuild DIBs.
lda #null
clc
;
; Restore Direct Page Values.
;
@exit pha
php
;
; Check the D.C. Flag
;
lda |uses_dc
beq @set_our_zp
ldy #dib.trx_ptr
lda |dib_data_struct
sta [dib_ptr],y
ldy #dib.trx_ptr+2
lda |dib_data_struct+2
sta [dib_ptr],y
stz |uses_dc ;Reset Flag
@set_our_zp jsr set_our_dp
;
; Set transfer count.
;
lda @call_trns_cnt
sta <trans_cnt
lda @call_trns_cnt+2
sta <trans_cnt+2
;-------------------------------------------------------------------------------
IF cache_blks = true THEN
;
; If it is a Data Call and has a timer
; that is adjusted by the block count,
; then this call could cause the cache
; to be in-validated.
;
lda |trans_flag
and #scsit_data++\ ;Is it a data call
scsic_tout++\ ;with a block count
scsit_cont ;Writing data?
cmp #scsit_data++\
scsic_tout++\
scsit_cont
bne @no_write ;No.
jsr ko_cache ;Yes. Kill the blocks.
ENDIF
;-------------------------------------------------------------------------------
;
; Exit.
;
@no_write plp
pla
rts
;
; Data Area.
;
@call_trns_cnt dc.l null ;Transfer count befor we steped on it.
@chk_zero dc.w null ;Check first DCMove Flag.
ENDP
EJECT
;*******************************************************
;
; This Control Call is used to reset a particular
; device to it's default settings. A Device Driver
; should configure itself based on the contents of the
; drivers configuration parameter list. This call
; should reset any media variables that were modified
; through a Set_Format_Options call.
;
; Called via 'JSR'
;
; Inputs: [dib_ptr] = Target DIB l (LONG)
; Acc = Unspecified
; Carry = Unspecified
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Returns via 'RTS'
;
; Outputs: Acc = 0
; Carry = 0
; or
; Acc = Error
; Carry = 1
;
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Errors: See Spec.
;
;*******************************************************
EXPORT reset_dvc
reset_dvc PROC
;
; Issue a REeZero Unit Call to the device.
;
; Set Main Driver Pointer to
; our data for the command.
;
lda #cmd_$8001
sta <scsi_mdrvr
lda #^cmd_$8001
sta <scsi_mdrvr+2
;
; Call Main Driver
;
lda #scsit_cont
sta |call_type
jsr |main_drvr
;
; Update Transfer Count.
;
stz <trans_cnt
stz <trans_cnt+2
;
; Exit No Error.
;
lda #$0000
clc
rts
;
; Command Data for this call.
;
cmd_$8001 dc.b $01
dcb.b 11,$00
ENDP
EJECT
;*******************************************************
;
; The Format call will ensure that the media is
; formatted and ready to receive data. If the DIB
; points to a partition then the Format call will
; return no error while taking no action (If it is
; partitioned, then it must have been formatted or the
; partition map could not have been written. Right?).
;
; Called via 'JSR'
;
; Inputs: [dib_ptr] = Target DIB l (LONG)
; Acc = Unspecified
; Carry = Unspecified
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Returns via 'RTS'
;
; Outputs: Acc = 0
; Carry = 0
; or
; Acc = Error
; Carry = 1
;
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Errors: See Spec.
;
;*******************************************************
EXPORT format_dvc
format_dvc PROC
;-------------------------------------------------------------------------------
IF character_dvc = true THEN
;
; It's a character device and
; the Acc is zero by virtue of
; the missed branch.
;
stz <trans_cnt
stz <trans_cnt+2
lda #null
clc
rts
ENDIF
;-------------------------------------------------------------------------------
IF scsi_dtype = apple_cd\
OR scsi_dtype = changer THEN
;
; If the device is a CD_ROM, then
; it is write protected.
;
stz <trans_cnt
stz <trans_cnt+2
lda #drvr_wrt_prot
sec
rts
ENDIF
;-------------------------------------------------------------------------------
IF scsi_dtype = mcd_40 THEN
;
; Is the device Write Enabled?
;
ldy #dib.dvcchar
lda [dib_ptr],y
and #write_allow
beq @write_protect
;
; Set Format Parm Pointer.
;
lda #@format_p
sta <scsi_mdrvr
lda #^@format_p
sta <scsi_mdrvr+2
;
; Set our own buffer pointer
; for this call.
;
lda #format_data
sta <buff_ptr
lda #^format_data
sta <buff_ptr+2
;
; Set our own request count
; for this call.
;
stz <rqst_cnt
stz <rqst_cnt+2
;
; It's a Control Call.
;
lda #scsit_cont
sta |call_type
;
; Set Internal Command Flag
;
dec |internal
;
; Issue the Call
;
jsr |main_drvr
pha
php
@test_loop jsr |test_unit_rdy
bcc @fmt_done
cmp #$FE08
beq @test_loop
cmp #$FE02
bne @test_loop
bra @tape_io_error
@fmt_done plp
pla
rts
;
; Return an I/O Error
;
@tape_io_error plp
pla
lda #drvr_io
sec
rts
;
; Return a Write Protected Error
;
@write_protect lda #drvr_wrt_prot
sec
rts
;
; FORMAT Command Packet
;
@format_p dc.b $04 ;Command Number
dc.b $00 ;Vendor Unique
dc.b $00 ;Reserved
dc.b $00 ;SCSI Interleave (MSB)
@interleave dc.b interleave ;SCSI Interleave (LSB)
dcb.b 6,$00 ;Reserved
ENDIF
;-------------------------------------------------------------------------------
IF scsi_dtype = direct_acc THEN
;
; It's a block device. But is
; it partitioned? If it has a
; zero start block then there is
; no partition.
;
stz @error ;Set to No Error.
ldy #dib.start_blk
lda [dib_ptr],y
ldy #dib.start_blk+2
ora [dib_ptr],y
beq @over
;
; Well, it is a partition. But is it
; the only partition. By this, I mean,
; is it a disk with a partition map
; containing only two entries, one for
; the partition map and the other for
; a single volume?
;
; First check if this is the first or
; second entry in the Partition Map.
;
ldy #dib.part_blk
lda [dib_ptr],y
xba
cmp #$0003
bge @do_part_fmt ;Past the second entry. Do as if multi
;partition.
;
; Is it linked? Let's see.
;
ldy #dib.dvcchar
lda [dib_ptr],y
and #linked_dvc
beq @over ;Not linked. Must be only one.
@do_part_fmt jsr trash_volume ;Trash this volume only.
jmp @clean_exit ;Sorry. Not the only volume
;
; Well there is no getting around
; it. We need to issue a format
; call to this device.
;
; Setup from last format options call
;
@over lda |current_fmt
dec a
asl a
asl a
asl a
asl a
tax
ldy #dib.blksize
lda |opt1_blk_siz,x
sta [dib_ptr],y
xba
sta @blk_size+2
lda |opt1_blk_cnt,x
sta |t_dvc_blocks
lda |opt1_blk_cnt+2,x
sta |t_dvc_blocks+2
stz @blk_size
shortm
lda opt1_interleave,x
sta @interleave
longm
;
; Preserve the Current Direct
; Page values stored in the
; buff_ptr and rqst_cnt fields.
;
pei <buff_ptr
pei <buff_ptr+2
pei <rqst_cnt
pei <rqst_cnt+2
;
; Set Format Parm Pointer.
;
lda #@format_p
sta <scsi_mdrvr
lda #^@format_p
sta <scsi_mdrvr+2
;
; Set our own buffer pointer
; for this call.
;
lda #format_data
sta <buff_ptr
lda #^format_data
sta <buff_ptr+2
;
; Set our own request count
; for this call.
;
stz <rqst_cnt
stz <rqst_cnt+2
;
; It's a Control Call.
;
lda #scsit_cont
sta |call_type
;
; Set Internal Command Flag
;
dec |internal
;
; Issue the Call
;
jsr |main_drvr
bcc @rebuild_dib
;
; Save error code
;
sta @error
;
; Rebuild the DIB.
;
@rebuild_dib jsr rebld_dibs
;
; Restore the Direct Page Values.
;
@return_dp pla
sta <rqst_cnt+2
pla
sta <rqst_cnt
pla
sta <buff_ptr+2
pla
sta <buff_ptr
;
; Restore the Acc result.
;
@clean_exit jsr set_disk_sw
lda @error
and #$7FFF
cmp #$7E00
bge @io_error
cmp #$0001
rts
;
; Some kind of I/O Error.
;
@io_error lda #drvr_io
rts
;
; Data for this call
;
@error dc.w null
;
; MODE SELECT Command Packet
;
@mode_select dc.b $15 ;Command Number
dc.b $00 ;Vendor Unique
dc.b $00 ;Reserved
dc.b $00 ;Reserved
dc.b $00 ;Resolved by Main Driver
dcb.b 6,$00 ;Reserved
;
; MODE SELECT Data
;
@mode_data dc.b $00 ;Command Number
dc.b $00 ;Reserved
dc.b $00 ;Reserved
dc.b $08 ;Length of extension
dc.b $00 ;Block Count (MSB)
dc.b $00 ;Block Count
dc.b $00 ;Block Count
dc.b $00 ;Block Count (LSB)
@blk_size dc.b $00 ;Block Size (MSB)
dc.b $00 ;Block Size
dc.b $02 ;Block Size
dc.b $00 ;Block Size (LSB)
;
; FORMAT Command Packet
;
@format_p dc.b $04 ;Command Number
dc.b $00 ;Vendor Unique
dc.b $00 ;Reserved
dc.b $00 ;SCSI Interleave (MSB)
@interleave dc.b interleave ;SCSI Interleave (LSB)
dcb.b 6,$00 ;Reserved
ENDIF
;-------------------------------------------------------------------------------
;
; Bad Parm Error
;
@bad_parm lda #drvr_bad_parm
sec
rts
ENDP
EJECT
;*******************************************************
;
; The EJECT command is used to cause the target to
; eject the currently mounted device. This could be a
; CD Device, Tape Drive or Removable hard disk. The
; first thing that we will check is to see if the
; removable bit is set. It not then a DRVR_BAD_CODE
; error will be returned. Otherwise the call will be
; sent to the device. Any error, if any at all, will
; be returned to the caller of this routine.
;
; Called via 'JSR'
;
; Inputs: [dib_ptr] = Target DIB l (LONG)
; Acc = Unspecified
; Carry = Unspecified
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Returns via 'RTS'
;
; Outputs: Acc = 0
; Carry = 0
; or
; Acc = Error
; Carry = 1
;
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Errors: See Spec.
;
;*******************************************************
EXPORT eject
eject PROC
;-------------------------------------------------------------------------------
IF block_dvc = true\
AND character_dvc = false THEN
;
; Verify request count. Should be
; zero
;
clc
lda <rqst_cnt
bne @bad_parm
;
; Check to see if it's removable. If it
; is then we will only mark it as offline,
; no EJECT will be attempted.
;
ldy #dib.dvcchar
lda [dib_ptr],y
and #removable
clc
beq @mark_offline ;Carry Clear says do Switch
;
; Is this device linked to other
; active devices?
;
jsr chk_lnk_offline
bcs @mark_offline ;Yes. Skip Eject and DISK SWITCH Calls
;
; Issue the eject call to the device.
;
; Set internal command flag
;
dec |internal
;
; Tell the Main Driver where
; our command structure resides.
;
;* BD 201811
;* Eject with the standard #$1B
;* If it fails, eject with the non-standard $C0
lda #@eject
sta <scsi_mdrvr
lda #^@eject
sta <scsi_mdrvr+2
;
; Set the Call Type and Issue the
; EJECT Command.
;
lda #scsit_cont
sta |call_type
jsr |main_drvr
; bcs @rts
IF scsi_dtype = apple_cd\
OR scsi_dtype = changer THEN
bcc @ejectOK
clc
lda #@ejectC0 ; If we're here, the eject $1B
sta <scsi_mdrvr ; returned in error
lda #^@ejectC0 ; so, we try the non-standa
sta <scsi_mdrvr+2 ; $C0 command
lda #scsit_cont
sta |call_type
jsr |main_drvr ; and we call the driver again
;
ENDIF
; Issue DISK_SW Call. This is only done
; when the media is actually EJECTed
; in response to this call.
;
@ejectOK jsr set_disk_sw
;
; Mark this DIB as Switched and Hard
; Offline.
;
lda #dvc_hardofl++\
dvc_switch
clc ;Do the Switch Call
bra @mark_offline2
;
; Mark this DIB as Switched only.
;
@mark_offline lda #dvc_switch
dec leave_switched
@mark_offline2 ldy #dib.dvcflag
ora [dib_ptr],y
and #dvc_online--\
$ffff
sta [dib_ptr],y
;
; Issue DISK_SW Call. This is only done when
; carry is clear which can only happen when
; ejecting non-removable media or when the
; media is actually EJECTed in response to
; this call.
;
bcs @no_switch
jsr set_disk_sw
;
; Clean Exit.
;
@no_switch lda #no_error
clc
rts
;
; Bad request length.
;
@bad_parm lda #drvr_bad_parm
sec
;
; Exit.
;
@rts rts
;-------------------------------------------------------------------------------
IF scsi_dtype = direct_acc THEN
;
; Command Packet
;
@eject dc.b $1B
dc.b $01 ;IMMED Bit Set
dcb.b 2,$00 ;Reserved
dc.b $02 ;Normal Unload. See document.
dcb.b 7,$00
ENDIF ;scsi_dtype = direct_acc
;-------------------------------------------------------------------------------
IF scsi_dtype = apple_cd\
OR scsi_dtype = changer THEN
;
; Command Packet
;
@eject dc.b $1B
dc.b $00 ;IMMED Bit Set
dcb.b 2,$00 ;Reserved
dc.b $02 ;Normal Unload. See document.
dcb.b 7,$00
@ejectC0 dc.b $C0 ; BD 201811 - renamed
dcb.b 11,$00
ENDIF ;scsi_dtype = apple_cd or changer
;-------------------------------------------------------------------------------
IF scsi_dtype = mcd_40 THEN
;
; Command Packet
;
@eject dc.b $1B
dc.b $01 ;IMMED Bit Set
dcb.b 2,$00 ;Reserved
dc.b $00 ;Normal Unload. See document.
dcb.b 7,$00
ENDIF ;scsi_dtype = mcd_40
;-------------------------------------------------------------------------------
ENDIF ;block_dvc = true
;-------------------------------------------------------------------------------
IF block_dvc = false\
AND character_dvc = true THEN
;
; If the device is a Character Device,
; then there is nothing to eject.
;
stz <trans_cnt
stz <trans_cnt+2
lda #null
clc
rts
ENDIF ;character_dvc = true
;-------------------------------------------------------------------------------
ENDP
EJECT
;*******************************************************
;
; This call set the configuration parms for the
; specified device. The parameters are device
; specific. The list is preceded by a word length
; which must be equal to the transmit count. If not
; then a DRVR_BAD_PARM error is returned.
;
; Called via 'JSR'
;
; Inputs: [dib_ptr] = Target DIB l (LONG)
; Acc = Unspecified
; Carry = Unspecified
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Returns via 'RTS'
;
; Outputs: Acc = 0
; Carry = 0
; or
; Acc = Error
; Carry = 1
;
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Errors: See Spec.
;
;*******************************************************
EXPORT s_config_parms
s_config_parms PROC
;-------------------------------------------------------------------------------
IF block_dvc = true\
AND character_dvc = false THEN
;-------------------------------------------------------------------------------
IF scsi_dtype = apple_cd\
OR scsi_dtype = changer THEN
;
; Exit Write Protect Error.
;
lda #drvr_wrt_prot
sec
rts
ENDIF ;scsi_dtype = apple_cd or changer
;-------------------------------------------------------------------------------
IF scsi_dtype = mcd_40 THEN
;
; Exit Bad Call Error.
;
lda #drvr_bad_code
sec
rts
ENDIF ;scsi_dtype = mcd_40
;-------------------------------------------------------------------------------
IF scsi_dtype = direct_acc THEN
; INCLUDE 'SCSI Set Config'
lda #null
sta <trans_cnt
sta <trans_cnt+2
clc
rts
ENDIF ;scsi_dtype = direct_acc
;-------------------------------------------------------------------------------
ELSE ;block_dvc = False
;-------------------------------------------------------------------------------
;
; Lie for now. Say that we did even
; though we didn't.
;
clc
lda <rqst_cnt ;*************************
beq @rts ;*************************
;
; Bad request length.
;
lda #drvr_bad_parm
sec
;
; Exit.
;
@rts rts
;-------------------------------------------------------------------------------
ENDIF ;block_dvc = true
;-------------------------------------------------------------------------------
IF scsi_dtype = direct_acc THEN
INCLUDE 'SCSI Set Vol/Disk'
ENDIF ;scsi_dtype = direct_acc
;-------------------------------------------------------------------------------
ENDP
EJECT
;*******************************************************
;
; This call is used to set the Wait or No Wait state
; for a character device. If in wait mode the device
; will wait until request count bytes have been read
; before returning to the caller. Block devices will
; return no error for this call.
;
; Called via 'JSR'
;
; Inputs: [dib_ptr] = Target DIB l (LONG)
; [buff_ptr] = Wait flag
; $0000 = Wait Mode
; $8000 = No Wait Mode
; Acc = Unspecified
; Carry = Unspecified
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Returns via 'RTS'
;
; Outputs: Acc = 0
; Carry = 0
; or
; Acc = Error
; Carry = 1
;
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Errors: See Spec.
;
;*******************************************************
EXPORT s_wait_mode
s_wait_mode PROC
;
; Check the parameters list.
; Should contain a WORD
;
lda <rqst_cnt
cmp #$0002
bne @bad_parm
;
; Is it a block device?
;
ldy #dib.dvcchar
lda [dib_ptr],y
and #blk_device
bne @clean_exit
;
; It's a character device. Do we
; set or clear the wait bit?
;
@char_dvc lda [buff_ptr]
beq @set_wait ;Set the Wait Mode
cmp #$8000
bne @bad_parm
;
; Clear the Wait mode to No Wait.
;
ldy #dib.dvcflag
lda [dib_ptr],y
and #wait_mode--\ ;Generate a mask for this bit
$ffff
;
; Save it and exit.
;
bra @set_state
;
; Set Wait Mode
;
@set_wait ldy #dib.dvcflag
lda [dib_ptr],y
ora #wait_mode
;
; Save New Mode
;
@set_state sta [dib_ptr],y
lda #$0002
sta <trans_cnt
stz <trans_cnt+2
;
; Clean Exit
;
@clean_exit lda #null ;Clear the Acc.
clc
rts
;
; Bad Parm Error
;
@bad_parm lda #drvr_bad_parm
sec
rts
ENDP
EJECT
;*******************************************************
;
; The set format options call is not supported by this
; driver. No error is returned unless they send a
; transfer length > 0000.
;
; Called via 'JSR'
;
; Inputs: [dib_ptr] = Target DIB l (LONG)
; Acc = Unspecified
; Carry = Unspecified
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Returns via 'RTS'
;
; Outputs: Acc = 0
; Carry = 0
; or
; Acc = Error
; Carry = 1
;
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Errors: See Spec.
;
;*******************************************************
EXPORT format_opt
format_opt PROC
;-------------------------------------------------------------------------------
IF block_dvc = true\
AND character_dvc = false THEN
;-------------------------------------------------------------------------------
IF scsi_dtype = apple_cd\
OR scsi_dtype = changer THEN
;
; If the device is a CD_ROM, then there
; are no format options.
stz <trans_cnt
stz <trans_cnt+2
lda #bad_dev_number
sec
rts
ENDIF ;scsi_dtype = apple_cd or changer
;-------------------------------------------------------------------------------
IF scsi_dtype = mcd_40 THEN
;
; If the device is a Tape, then there
; are no format options.
stz <trans_cnt
stz <trans_cnt+2
lda #bad_dev_number
sec
rts
ENDIF ;scsi_dtype = mcd_40
;-------------------------------------------------------------------------------
IF scsi_dtype = direct_acc THEN
;
; If we are partitioned, then no data.
;
ldy #dib.dvcchar
lda [dib_ptr],y
and #linked_dvc
beq @no_link ;No.
stz <trans_cnt
stz <trans_cnt+2
lda #null
clc
rts
;
;
; Check the count
;
@no_link lda <rqst_cnt
beq @bad_parm
cmp #$0002
bne @bad_parm
sta <trans_cnt
stz <trans_cnt+2
;
; Set default Option.
;
lda [buff_ptr]
sta current_fmt
;
; Exit.
;
lda #null
clc
rts
;
; Bad request length.
;
@bad_parm lda #drvr_bad_parm
sec
rts
ENDIF ;scsi_dtype = direct_acc
;-------------------------------------------------------------------------------
ENDIF ;block_dvc = true
;-------------------------------------------------------------------------------
IF block_dvc = false\
AND character_dvc = true THEN
;
; If the device is a Character Device,
; then there are no format options.
;
lda #drvr_bad_code
sec
rts
ENDIF ;character_dvc = true
;-------------------------------------------------------------------------------
ENDP
EJECT
;*******************************************************
;
; Main Entry point to the 'Control' filter. This
; "Filter" is called when a Control Command comes in.
; See the headers of the seperate sections for the
; details of the commands.
;
; Called via 'JSR'
;
; Inputs: [dib_ptr] = Target DIB l (LONG)
; Acc = Unspecified
; Carry = Unspecified
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Returns via 'RTS'
;
; Outputs: Acc = 0
; Carry = 0
; or
; Acc = Error
; Carry = 1
;
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Errors: See Spec.
;
;*******************************************************
EXPORT assign_part
assign_part PROC
;-------------------------------------------------------------------------------
IF block_dvc = true\
AND character_dvc = false THEN
;-------------------------------------------------------------------------------
IF scsi_dtype = apple_cd\
OR scsi_dtype = changer THEN
;
; Exit Write Protect Error.
;
lda #drvr_wrt_prot
sec
rts
ENDIF ;scsi_dtype = apple_cd or changer
;-------------------------------------------------------------------------------
IF scsi_dtype = mcd_40 THEN
;
; Exit Bad Call Error.
;
lda #drvr_bad_code
sec
rts
ENDIF ;scsi_dtype = mcd_40
;-------------------------------------------------------------------------------
IF scsi_dtype = direct_acc THEN
;
; Validate that this DIB is from
; a Partition Map Entry.
;
ldy #dib.start_blk
lda [dib_ptr],y
ldy #dib.start_blk+2
ora [dib_ptr],y
bne @over
;
; Not from a partition.
;
lda #bad_dev_number
sec
rts
;
; Get block that contains this
; DIB's Partition Map Entry.
;
@over ldy #dib.part_blk
lda [dib_ptr],y
sta |rpm_blk_num
sta |wpm_blk_num
;
; Tell the code that we have already
; set the Block Number and that this
; is not a startup call.
;
dec |stat_cont ;This is from a Status or Control Call
dec |rebuild ;And not from a startup Call
;
; Issue the Read PM Block Call.
;
jsr |read_pm_blk
;
; Restore Direct Page Values.
;
pha
php
jsr set_our_dp
plp
pla
bcs @bad_exit ;There was an error.
;
; Is what we read a Partition Map?
;
lda |pm.Sig\
+internal_buff
cmp #Part_sig
bne @bad_exit ;Bad Data Read.
;
; Set a pointer to actual text.
;
clc
lda <buff_ptr
adc #$0002
sta <scsi_zp4
lda <buff_ptr+2
adc #null
sta <scsi_zp4+2
;
; Get length of data
;
lda [buff_ptr]
cmp #$0020+1
bge @bad_exit
tay
tax
dey ;16 bit mode
dex
;
; Are they the same? If so we can
; save a block write.
;
@cmp_loop lda |pm.PartType\
+internal_buff,y
cmp [scsi_zp4],y
bne @move_new
dey
bpl @cmp_loop
bra @all_done
;
; Not the same. Replace old with
; the new.
;
@move_new txa
tay
@move_loop lda [scsi_zp4],y
sta |pm.PartType\
+internal_buff,y
dey
bpl @move_loop
;
; Issue the Write PM Block Call.
;
jsr |write_pm_blk
;
; Restore Direct Page Values.
;
pha
php
jsr set_our_dp
plp
pla
bcc @all_done ;There was no error.
;
; Error exit point.
;
@bad_exit lda #drvr_io
sec
rts
;
; Clean Exit
;
@all_done lda #no_error
clc
rts
ENDIF ;scsi_dtype = direct_acc
;-------------------------------------------------------------------------------
ENDIF ;block_dvc = true
;-------------------------------------------------------------------------------
IF block_dvc = false\
AND character_dvc = true THEN
;
; If the device is a Character Device,
; then there are no Partitions to
; assign.
;
stz <trans_cnt
stz <trans_cnt+2
lda #null
clc
rts
ENDIF ;character_dvc = true
;-------------------------------------------------------------------------------
ENDP
EJECT
;*******************************************************
;
; Entry point for the Arm Signal Drivcer Call. This
; call is not supported by this driver. An error is
; returned in all cases.
;
; Called via 'JSR'
;
; Inputs: [dib_ptr] = Target DIB l (LONG)
; Acc = Unspecified
; Carry = Unspecified
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Returns via 'RTS'
;
; Outputs: Acc = 0
; Carry = 0
; or
; Acc = Error
; Carry = 1
;
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Errors: See Spec.
;
;*******************************************************
EXPORT arm_signal
arm_signal PROC
lda #drvr_bad_code
sec
rts
ENDP
EJECT
;*******************************************************
;
; Entry point for the Disarm Signal Drivcer Call.
; This call is not supported by this driver. An error
; is returned in all cases.
;
; Called via 'JSR'
;
; Inputs: [dib_ptr] = Target DIB l (LONG)
; Acc = Unspecified
; Carry = Unspecified
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Returns via 'RTS'
;
; Outputs: Acc = 0
; Carry = 0
; or
; Acc = Error
; Carry = 1
;
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Errors: See Spec.
;
;*******************************************************
EXPORT disarm_sig
disarm_sig PROC
lda #drvr_bad_code
sec
rts
ENDP
EJECT
;*******************************************************
;
; Most be the first device in a link!!!!
;
; Entry point to the 'Set PMap' call. This call
; takes the information given by the caller on direct
; page and builds the equivilent to a Write Status
; Call to write request count bytes starting at
; physical block number 1. This is done by setting
; the high bit of the partition call flag
; 'f_partition'.
;
; 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 (No Offset)
; This is for partitions.
;
; After calling the Main driver and if no errors were
; encountered, then the Transfer count will be
; updated.
;
; Called via 'JSR'
;
; Inputs: [dib_ptr] = Target DIB l (LONG)
; Acc = Unspecified
; Carry = Unspecified
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Returns via 'RTS'
;
; Outputs: Acc = 0
; Carry = 0
; or
; Acc = Error
; Carry = 1
;
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Errors: See Spec.
;
;*******************************************************
EXPORT set_p_map
set_p_map PROC
;-------------------------------------------------------------------------------
IF block_dvc = true\
AND character_dvc = false THEN
;-------------------------------------------------------------------------------
IF scsi_dtype = apple_cd\
OR scsi_dtype = changer THEN
;
; Exit Write Protect Error.
;
lda #drvr_wrt_prot
sec
rts
ENDIF ;scsi_dtype = apple_cd or changer
;-------------------------------------------------------------------------------
IF scsi_dtype = mcd_40 THEN
;
; Exit No Error.
;
lda #drvr_bad_code
sec
rts
ENDIF ;scsi_dtype = mcd_40
;-------------------------------------------------------------------------------
IF scsi_dtype = direct_acc THEN
stz @do_532
;
; Set the Block size on Direct Page.
; It is not placed there for this call,
; and we should not rely on it being
; left behind by the last call.
;
lda #block_size
sta <blk_size
;
; Check if first DIB in link if any.
; If it is zero, then we are already
; there. If not then error out.
;
ldy #dib.headptr+2
lda [dib_ptr],y
ldy #dib.headptr
ora [dib_ptr],y
bne @bad_dev_num
;
; Let's check the request count. If
; this is $00000000, then exit clean
; with no data transfered.
;
lda <rqst_cnt
ora <rqst_cnt+2
bne @cnt_non_zero
jmp @out_of_here
;
; 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
@bad_dev_num lda #bad_dev_number
sec
rts
;
; Check for 532 byte block size
;
@chk_532 tax
lda <blk_size
cmp #block_size
bne @bad_parm
cpx #$0214
bne @bad_parm
dec @do_532
@blk_size_ok
;
; Build the (Write Data)
; Control Command $800A
lda #$0001 ; Sent to me Low >> High.
xba ; Send it out High >> Low.
sta |c_block_num
;
; Set Main Driver Pointer to
; our data for the command.
;
lda #cmd_$800A
sta <scsi_mdrvr
lda #^cmd_$800A
sta <scsi_mdrvr+2
;
; Set the Partition call flag
;
dec |f_partition
;
; Call Main Driver
;
lda #scsit_cont
sta |call_type
;
; Issue the call.
;
jsr check_532_rw
bcs @rts
;
; Build the (Write Data) command
; to write the Driver Descriptor
; Map.
;
@do_ddm lda #$5245 ;Defined by MAC as $4552
sta |sense_data
lda #block_size
sta <rqst_cnt
stz <rqst_cnt+2
xba
sta |sense_data+2 ;Defined by MAC as $0200
ldx #$0040
@loop stz |sense_data+4,x
dex
dex
bpl @loop
stz |c_block_num
;
; Set our buffer pointer
;
lda #sense_data
sta <buff_ptr
lda #^sense_data
sta <buff_ptr+2
;
; Set Main Driver Pointer to
; our data for the command.
;
lda #cmd_$800A
sta <scsi_mdrvr
lda #^cmd_$800A
sta <scsi_mdrvr+2
;
; Set the Partition call flag
;
dec |f_partition
;
; Call Main Driver
;
lda #scsit_cont
sta |call_type
;
; Issue the call.
;
jsr check_532_rw
bcs @rts
;
; Rebuild the DIBs.
; Trashing the Volumes.
;
dec |trash_it
;
jsr rebld_dibs ;Issues a DISK_SW for each rebuilt DIB.
;
; Reset The 'TRASH IT' Flag..
;
stz |trash_it
;
; Restore the origonal Direct Page values.
;
jsr set_our_dp
;
; Update Transfer Count.
;
@out_of_here lda <rqst_cnt
sta <trans_cnt
lda <rqst_cnt+2
sta <trans_cnt+2
;
; Exit No Error.
;
lda #$0000
clc
@rts rts
;
; Variables and storage for short call.
;
@do_532 dc.w null ;532 byte block flag
;
; Command Data for this call.
;
cmd_$800A dc.b $0A
dc.b $00
c_block_num dc.w $0000
c_block_cnt dc.b $00
dcb.b 7,$00
ENDIF ;scsi_dtype = direct_acc
;-------------------------------------------------------------------------------
ENDIF ;block_dvc = true
;-------------------------------------------------------------------------------
IF block_dvc = false\
AND character_dvc = true THEN
;
; If the device is a Character Device,
; then there are no Partitions to
; write.
;
stz <trans_cnt
stz <trans_cnt+2
lda #null
clc
rts
ENDIF ;character_dvc = true
;-------------------------------------------------------------------------------
ENDP
EJECT
END