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

1 line
9.5 KiB
Plaintext

;*******************************************************
;
; SCSI Driver 'Shutdown' filter.
;
; Written by Matt Gulick. Started August 9,1988
;
; Copyright Apple Computer, Inc. 1988,89
;
;*******************************************************
;*******************************************************
;
; This file contains the 'Shutdown' filter as defined
; in the ERS.
;
;*******************************************************
;*******************************************************
;
; Revision History:
;
;*******************************************************
;
; Aug 9, 1988 File started.
; Mar 8, 1989 Modified to support Warm/Cold
; Shutdown.
STRING PASCAL
BLANKS OFF
PAGESIZE 70
PRINT NOGEN
PRINT NOMDIR
MACHINE M65816
IMPORT direct_page
IMPORT default_dib
IMPORT tot_dib_cnt
IMPORT active_starts
IMPORT stop_unit
PRINT OFF
INCLUDE 'scsihd.equates'
INCLUDE 'M16.MEMORY'
INCLUDE 'M16.UTIL'
PRINT ON
EJECT
;*******************************************************
;
; Main Entry point to the 'Shutdown' filter. This
; "Filter" is called when a Device is no longer
; desired in the tables. The following code segment
; first checks to see if the DIB being shut down is
; the default dib (it will only be shutdown durring
; startup). If it is the default dib we will do
; nothing and exit with no error. If on the other
; hand it is a valid DIB, we will clear some key
; fields within the dib and then we will alter the
; links to skip this DIB, then we update a field in the
; first DIB of this memory segment. This count tells
; how many active dibs there are in that segment. If
; this reaches zero we will then dispose this handle
; because it is unused. If we later need space to
; bring new devices online and we don't have the space,
; we'll get it at that time. If on exit there are
; still any active dibs that use this code segment then
; a DRVR_BUSY error will be returned. If no DIBs are
; active then no error will be returned.
;
; Inputs: [dib_ptr] = Last DIB built (LONG)
; Acc = Unspecified
; Carry = Unspecified
; Y register = Unspecified
; X register = Unspecified
; P register = 0=M=X=e
; Direct Page = Ours
; Data Bank = Ours
;
; Outputs: Acc = DRVR_BUSY
; Carry = 1
; unless we have no more dibs then
; 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 shutdown
shutdown PROC
;
; Check to see if this is for the
; 'default_dib'. If it is, then we
; need to exit with a DRVR_BUSY Error.
;
lda <dib_ptr
cmp #default_dib
bne @real_dib
lda <dib_ptr+2
cmp #^default_dib
bne @real_dib
;
; Return a DRVR BUSY error and take
; no action.
;
lda #drvr_busy
sec
rts
@real_dib
;-------------------------------------------------------------------------------
IF warm_ss_suprt = true THEN
;
; It's a real DIB. Is it a COLD
; SHUTDOWN?
;
lda >warm_cold_flag
and #$0001
beq @do_cold ;It's Cold
;
; Yeah, so it's a warm shutdown. But
; does this device know what that
; means? We'll see!
;
ldy #dib.dvcchar
lda [dib_ptr],y
and #restartable
beq @do_cold ;Not restartable.
;
; Mark as OFFLINE and Relaxing
;
ldy #dib.dvcflag
lda [dib_ptr],y
and #dvc_online--\
$ffff
ora #relaxing
sta [dib_ptr],y
;
; Is the device removable?
;
; ldy #dib.dvcchar
; lda [dib_ptr],y
; and #removable
; beq @continue ;Not removable.
;
; Reinitialise DIB Device Number to
; zero.
;
lda #null
ldy #dib.devnum
sta [dib_ptr],y
;
; Do the Head and Forward links also.
;
ldy #dib.headlnk
sta [dib_ptr],y
ldy #dib.fdvclnk
sta [dib_ptr],y
;
; Get out of here updating only
; the active DIB count not the
; total DIB Count.
;
@continue jmp @update_acnt
ENDIF
;-------------------------------------------------------------------------------
;
; It's a real DIB. Issue a $1B
; START/STOP Command. Ignor all
; errors, not all devices support
; this optional command.
;
@do_cold jsr stop_unit
;
; Set Device to Default.
;
ldy #dib.dvcflag
lda #wait_mode++\
cold_dib
sta [dib_ptr],y
;
; Shut it down. To do this we clear
; the DIB Device Number.
;
ldy #dib.devnum
lda [dib_ptr],y
sta @this_device ;Save for a while
lda #null
sta [dib_ptr],y
;
; Dec Device count for this memory
; segment.
;
ldy #dib.handle ;Set up to deref the handle to find
lda [dib_ptr],y ;where this memory segment starts.
sta <scsi_zp0
sta |@deref_handle ;Save in case we dispose of it.
ldy #dib.handle+2
lda [dib_ptr],y
sta <scsi_zp0+2
sta |@deref_handle+2
;
; Deref the Handle.
;
ldy #$0002
lda [scsi_zp0]
tax
lda [scsi_zp0],y
sta scsi_zp0+2
stx scsi_zp0
;
; Dec the count. If now = zero then
; dispose of this handle.
;
ldy #dib.mem_dib_cnt
lda [scsi_zp0],y
dec a
sta [scsi_zp0],y
bne @chk_links ;Not zero. Update link if it exists.
;
; We have emptied this memory segment.
; We now need to deallocate this
; memory segment.
;
ldy #$0002
pushword |@deref_handle+2
pushword |@deref_handle
_disposehandle
;
; Find location of previous DIB in
; linked list.
;
; Start at the default DIB.
;
lda #default_dib
sta <prev_dib
lda #^default_dib
sta <prev_dib+2
;
; Does this DIB point to the
; requseted DIB?
;
ldy #dib.linkptr+2
@prev_loop lda [prev_dib],y
tax ;Save value for later
lda [prev_dib] ;Do they match?
cmp <dib_ptr
bne @advnc_loop ;No.
cpx <dib_ptr+2
beq @set_prev ;Yes. Set new links.
@advnc_loop stx <prev_dib+2 ;No. Advance to the next DIB.
sta <prev_dib
ora <prev_dib+2
bne @prev_loop
bra @chk_links
;
; Set previous DIBs link pointer
; to the DIB that follws the one
; being shutdown.
;
@set_prev lda [dib_ptr]
sta [prev_dib]
lda [dib_ptr],y
sta [prev_dib],y
;
; We must now check to see if this DIB
; that was shutdown is linked to any
; other DIBs.
;
@chk_links ldy #dib.dvcchar
lda [dib_ptr],y
and #linked_dvc
beq @update_tcnt ;No it is not linked.
;
; It is linked. First we need to go to
; the head device if this is not it. If
; it is the head, then we need to do
; something completly different.
;
clc
ldy #dib.headptr
lda [dib_ptr],y
ldy #dib.headptr+2
ora [dib_ptr],y
beq @at_head
lda [dib_ptr],y
sta <scsi_zp0+2
ldy #dib.headptr
lda [dib_ptr],y
sta <scsi_zp0
bra @chk_lnk_loop
@at_head lda <dib_ptr
sta <scsi_zp0
lda <dib_ptr+2
sta <scsi_zp0+2
@chk_lnk_loop ldy #dib.fdvclnk
lda [scsi_zp0],y
beq @update_tcnt
cmp @this_device
beq @update_link
ldy #dib.fdvcptr
lda [scsi_zp0],y
tax
ldy #dib.fdvcptr+2
lda [scsi_zp0],y
sta <scsi_zp0+2
stx <scsi_zp0
bra @chk_lnk_loop
@update_link ldy #dib.headptr
lda [dib_ptr],y
sta [scsi_zp0],y
ldy #dib.headptr+2
lda [dib_ptr],y
sta [scsi_zp0],y
ldy #dib.fdvcptr
lda [dib_ptr],y
sta [scsi_zp0],y
ldy #dib.fdvcptr+2
lda [dib_ptr],y
sta [scsi_zp0],y
ldy #dib.fdvclnk
lda [dib_ptr],y
sta [scsi_zp0],y
;
; Clear the FDVCLNK and HEADLNKs
; incase this segment is used later.
;
lda #null
sta [dib_ptr],y
ldy #dib.headlnk
sta [dib_ptr],y
;
; Update the total DIB Count. If
; there are still some dibs left,
; then we will return a DRVR_BUSY
; error. If all done we will return
; no error. This will cause us to
; be purged.
;
@update_tcnt dec |tot_dib_cnt
@update_acnt dec |active_starts
beq @thats_all_folks
;
; More left. Return an error.
;
lda #DRVR_BUSY
sec
rts
;
; ThThThThThaaaaattt'ss all folks.
; I give, go ahead purge me. I
; LOVE IT when you do that to
; me!!!!!!
;
@thats_all_folks
;
; Exit no Error.
;
lda #null
clc
rts
;
; Internal Data Areas.
;
@deref_handle dc.l null
@this_device dc.w null
ENDP
END
EJECT