mirror of
https://github.com/elliotnunn/sys7.1-doc-wip.git
synced 2024-10-31 19:05:04 +00:00
607 lines
25 KiB
Plaintext
607 lines
25 KiB
Plaintext
;—————————————————————————————————————————————————————————————————————————
|
|
;
|
|
; File: XPT.a
|
|
;
|
|
; Contains: SCSI Mgr for the 53c96/
|
|
;
|
|
; Written by: Paul Wolf
|
|
;
|
|
; Copyright: © 1990-1994 by Apple Computer, Inc., all rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM21> 1/31/94 DCB Added a semaphore to the SCSIBusy stuff so we don't call
|
|
; DeferUserFn from enable VM as much.
|
|
; <ML4> 1/9/94 pdw Took out aerror on build SCSIBusy patch with forROM.
|
|
; <ML3> 1/5/94 pdw Simplifying the SCSIBusy install stuff.
|
|
; <ML2> 1/5/94 pdw (DCB) Added SCSIBusy patch.
|
|
; <SM19> 12/19/93 DCB Added SetIntsAt2 and RestoreInts.
|
|
; <SM18> 11/22/93 pdw Rolling in from <MCxx>.
|
|
; <MC8> 11/10/93 pdw Added clearing of inDebugger flag.
|
|
; <MC7> 11/8/93 pdw Changed recording criteria around call to completion routine.
|
|
; <MC5> 10/14/93 pdw Fixing the occasional calling of completion routines at level 7
|
|
; bug. I was jumping to @call instead of @enableIntCall
|
|
; <SM17> 11/5/93 pdw Fixed build.
|
|
; <SM16> 11/5/93 pdw Series of attempts and re-attempts to fix various VM/FileShare
|
|
; problems. Finally ended up fixing it all at the very source of
|
|
; the problem - the File System!
|
|
; <SM15> 10/14/93 pdw <MC> roll-in.
|
|
; <MC4> 10/12/93 pdw Fixed bug where we would blow away our deferred task if we got
|
|
; another completion routine before we dispatch that task.
|
|
; <MC3> 10/12/93 pdw Added support for Synchronous data transfers, rewrote State
|
|
; Machine, message handling etc.
|
|
; <MC2> 10/6/93 pdw Removed call to DTInstallHead, instead doing it with ENQUEUEHEAD
|
|
; directly.
|
|
; <SM14> 9/12/93 pdw Changed the way I do the deferring of completion routines. I
|
|
; now check for inVBL rather than VM because that is how VM
|
|
; disables the DTQ. Also enqueue my task at the head of the DTQ.
|
|
; <SM13> 9/9/93 pdw Lots of little changes. Name changes, temporary cache_bug
|
|
; stuff.
|
|
; <SM12> 7/8/93 pdw Getting rid of useless InitXPTRecorder function.
|
|
; <SM11> 6/29/93 pdw Massive checkins: Change asynchronicity mechanism to CallMachine
|
|
; stack switching mechanism. Adding support for Cold Fusion.
|
|
; Rearranging HW/SW Init code. Some code optimizations.
|
|
; <SM10> 5/25/93 DCB Rollin from Ludwig. (The next two items below)
|
|
; <LW11> 5/21/93 PW Changing how we detect the presence of VM. Now using $B78 < 0
|
|
; instead of $CF0==-1.
|
|
; <LW10> 5/20/93 DCB Added ciDebuggerPatch. This is a patch to _DebugUtil which
|
|
; prevents deferred completion routines from occuring when we are
|
|
; in a debugger.
|
|
; <SM9> 5/5/93 PW Converted names to meanies-friendly names. Updated with latest
|
|
; from Ludwig stuff.
|
|
; <LW8> 4/14/93 DCB Added RemoveSyncWait and synced up with SuperMario
|
|
; <SM8> 3/29/93 PW Added an equate to better handle different movems.
|
|
; <SM7> 3/29/93 PW Added a return address RECORD_EVENT to catch the driver messing
|
|
; up the stack problem.
|
|
; <LW7> 3/26/93 mal (PW) Another try.
|
|
; <LW6> 3/26/93 mal (actually PW)Removed the bogus "fix" that I just put in.
|
|
; <LW5> 3/26/93 PW Removed RECORD_ON definition here since I put it in Debug.a.
|
|
; Fix last minute VM bug (this is what I get for checking in files
|
|
; after staying up all night).
|
|
; <LW4> 3/26/93 PW Fixing RECORD_ON problem.
|
|
; <LW3> 3/26/93 PW Adding code to defer completion routine if int level!=0 and
|
|
; DeferTask Q is empty and DeferredTask Manager is not busy (i.e.
|
|
; not working on the Q) and VM isn't running.
|
|
; <SM5> 1/31/93 PW Update from the latest of Ludwig. Also changes required for PDM
|
|
; (will update Ludwig with these as needed myself).
|
|
; <LW2> 1/30/93 PW Added glue code for calling completion routines (saving
|
|
; registers that were getting trashed by File Manager).
|
|
; <SM4> 11/20/92 PW Added some Includes that were removed from headers.
|
|
; <SM3> 11/3/92 PW Removed unneeded intrRegs definition.
|
|
; <SM2> 10/30/92 DCB Misc Interrupt handling changes to reduce interrupt latency.
|
|
;
|
|
;==========================================================================
|
|
|
|
|
|
MACHINE MC68020
|
|
BLANKS ON
|
|
PRINT OFF
|
|
|
|
|
|
|
|
LOAD 'StandardEqu.d'
|
|
INCLUDE 'Debug.a'
|
|
|
|
INCLUDE 'ACAM.a'
|
|
INCLUDE 'XPTEqu.a'
|
|
|
|
PRINT ON
|
|
CASE OBJECT
|
|
|
|
IMPORT RecordEvent ; Recorder.a
|
|
IMPORT VMDisableUserCode, VMEnableUserCode
|
|
IMPORT ENQUEUEHEAD
|
|
|
|
|
|
|
|
IF forROM THEN ;••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
|
|
;•
|
|
;•
|
|
;•
|
|
;———————————————————————————————————————————————————————————————————————
|
|
InitXPTAsm PROC EXPORT ; initialize SCSIGlobals based XPT globals
|
|
;———————————————————————————————————————————————————————————————————————
|
|
;
|
|
move.l SCSIGlobals, A1 ; use A1 as base
|
|
rts
|
|
|
|
NAME 'InitXPTAsm'
|
|
|
|
;———————————————————————————————————————————————————————————————————————
|
|
RemoveSyncWait PROC EXPORT ; RemoveSyncWait(XPTg)
|
|
;———————————————————————————————————————————————————————————————————————
|
|
;
|
|
; Possible problem - what if sombody else patched vSyncWait in
|
|
; the meantime? We are going to stuff the old one back in!!!
|
|
;
|
|
move.l 4(sp), a0 ; get ptr to XPTglobals
|
|
move.l XPTglobals.OldSyncWait(A0),jSyncWait ; put the old syncWait back
|
|
rts
|
|
|
|
NAME 'RemoveSyncWait'
|
|
|
|
;———————————————————————————————————————————————————————————————————————
|
|
InitSyncWait PROC EXPORT ; InitSyncWait(XPTg)
|
|
;———————————————————————————————————————————————————————————————————————
|
|
;
|
|
move.l 4(sp), a0 ; get ptr to XPTglobals
|
|
move.l jSyncWait, XPTglobals.OldSyncWait(A0)
|
|
lea CI_vSyncWait, A0
|
|
move.l A0, jSyncWait
|
|
rts
|
|
|
|
NAME 'InitSyncWait'
|
|
|
|
|
|
;———————————————————————————————————————————————————————————————————————
|
|
CI_vSyncWait
|
|
;———————————————————————————————————————————————————————————————————————
|
|
;
|
|
trashedRegs REG D0-D2/A0-A1/A5
|
|
sizeofTrashedRegs EQU 6*4
|
|
|
|
IMPORT InterruptLevel
|
|
|
|
move.w IOResult(A0), D0 ; test for completion
|
|
ble.s @fastWayOut ;
|
|
|
|
lea -4(sp), sp ; make room for return address (jmp to oldSyncWait)
|
|
movem.l trashedRegs, -(sp) ; save registers trashed by C routines and A5
|
|
GetXPTg ; into A5
|
|
|
|
IF 0 AND RECORD_ON THEN
|
|
pea 'Isyw'
|
|
move.l A0, -(sp)
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
ENDIF
|
|
|
|
@wait
|
|
CASE ON ;•
|
|
IMPORT CheckInterrupts
|
|
move.l A0, -(sp)
|
|
move.l A5, -(sp) ; push XPTg parameter
|
|
bsr CheckInterrupts
|
|
addq.l #4, sp
|
|
move.l (sp)+, A0
|
|
CASE OBJECT ;•
|
|
|
|
move.w IOResult(A0), D0 ; test for completion
|
|
bgt.s @wait
|
|
|
|
@endWait
|
|
move.l XPTglobals.OldSyncWait(A5), sizeofTrashedRegs(sp)
|
|
movem.l (sp)+, trashedRegs
|
|
rts ; rts's to old vSyncWait - not to caller
|
|
|
|
|
|
@fastWayOut
|
|
lea -4(sp), sp ; make room for return address (jmp to oldSyncWait)
|
|
move.l A5, -(sp)
|
|
GetXPTg ; into A5
|
|
move.l XPTglobals.OldSyncWait(A5), 4(sp)
|
|
move.l (sp)+, A5
|
|
rts ; rts's to old vSyncWait - not to caller
|
|
|
|
|
|
NAME 'CI_vSyncWait'
|
|
|
|
|
|
; Note:IntRegs reg a0-a3/d0-d3 ; registers saved by InterruptHandlers.a
|
|
|
|
;———————————————————————————————————————————————————————————————————————
|
|
XPT_ISR0 PROC EXPORT ; void XPT_ISR0 (void)
|
|
;———————————————————————————————————————————————————————————————————————
|
|
;
|
|
bsr VMDisableUserCode ; disable user code (so page faults won't happen)
|
|
|
|
IF INDEXED_IS_FASTER THEN
|
|
move.l ([SCSIGlobals],SCSIGlobalsRec.xptGlobals), A0
|
|
move.l XPTglobals.BusInfoPtrs+ 0 (A0), A0 ; ptr to initInfo
|
|
move.l BusInfo.initInfo.SIMstaticPtr(A0), -(sp) ; SIMg parameter
|
|
jsr ([BusInfo.initInfo.SIM_ISR, A0]) ; SIM_ISR call
|
|
ELSE
|
|
move.l SCSIGlobals, A0
|
|
move.l SCSIGlobalsRec.xptGlobals(A0), A0
|
|
move.l XPTglobals.BusInfoPtrs+ 0 (A0), A0 ; ptr to initInfo
|
|
move.l BusInfo.initInfo.SIMstaticPtr(A0), -(sp)
|
|
move.l BusInfo.initInfo.SIM_ISR(A0), A0
|
|
jsr (A0)
|
|
ENDIF
|
|
addq.l #4, sp
|
|
|
|
bra VMEnableUserCode ; enable user code (allow page faults)
|
|
;rts from VMEnableUserCode
|
|
|
|
RTSNAME 'XPT_ISR0'
|
|
|
|
|
|
;———————————————————————————————————————————————————————————————————————
|
|
XPT_ISR1 PROC EXPORT ; void XPT_ISR1 (void)
|
|
;———————————————————————————————————————————————————————————————————————
|
|
;
|
|
bsr VMDisableUserCode ; disable user code (so page faults won't happen)
|
|
|
|
IF INDEXED_IS_FASTER THEN
|
|
move.l ([SCSIGlobals],SCSIGlobalsRec.xptGlobals), A0
|
|
move.l XPTglobals.BusInfoPtrs+ 4 (A0), A0 ; ptr to initInfo
|
|
move.l BusInfo.initInfo.SIMstaticPtr(A0), -(sp) ; SIMg parameter
|
|
jsr ([BusInfo.initInfo.SIM_ISR, A0]) ; SIM_ISR call
|
|
ELSE
|
|
move.l SCSIGlobals, A0
|
|
move.l SCSIGlobalsRec.xptGlobals(A0), A0
|
|
move.l XPTglobals.BusInfoPtrs+ 4 (A0), A0 ; ptr to initInfo
|
|
move.l BusInfo.initInfo.SIMstaticPtr(A0), -(sp)
|
|
move.l BusInfo.initInfo.SIM_ISR(A0), A0
|
|
jsr (A0)
|
|
ENDIF
|
|
addq.l #4, sp
|
|
|
|
|
|
bra VMEnableUserCode ; enable user code (allow page faults)
|
|
;rts from VMEnableUserCode
|
|
|
|
RTSNAME 'XPT_ISR1'
|
|
|
|
|
|
|
|
;———————————————————————————————————————————————————————————————————————
|
|
InterruptLevel PROC EXPORT
|
|
;———————————————————————————————————————————————————————————————————————
|
|
;
|
|
move.w SR, D0
|
|
and.w #$0700, D0
|
|
lsr.w #8, D0
|
|
|
|
rts
|
|
|
|
NAME 'InterruptLevel'
|
|
|
|
;———————————————————————————————————————————————————————————————————————
|
|
SetIntsAt2 PROC EXPORT
|
|
;———————————————————————————————————————————————————————————————————————
|
|
;
|
|
move.w SR, D0
|
|
or.w #$0200, sr
|
|
and.w #$FEFF, sr
|
|
rts
|
|
|
|
NAME 'SetIntsAt2'
|
|
|
|
;———————————————————————————————————————————————————————————————————————
|
|
RestoreInts PROC EXPORT
|
|
;———————————————————————————————————————————————————————————————————————
|
|
;
|
|
move.w 6(sp), SR
|
|
rts
|
|
|
|
NAME 'RestoreInts'
|
|
|
|
ENDP
|
|
|
|
|
|
;———————————————————————————————————————————————————————————————————————
|
|
getCurrentA5 PROC EXPORT
|
|
;———————————————————————————————————————————————————————————————————————
|
|
;
|
|
move.l a5, D0
|
|
rts
|
|
|
|
NAME 'getCurrentA5'
|
|
|
|
;———————————————————————————————————————————————————————————————————————
|
|
restoreCurrentA5 PROC EXPORT
|
|
;———————————————————————————————————————————————————————————————————————
|
|
;
|
|
move.l 4(sp), a5
|
|
rts
|
|
|
|
NAME 'restoreCurrentA5'
|
|
|
|
|
|
;———————————————————————————————————————————————————————————————————————
|
|
ciDebuggerPatch PROC EXPORT
|
|
;———————————————————————————————————————————————————————————————————————
|
|
; Since debuggers have a tendency to turn off the deferred task manager
|
|
; we will deadlock if the debugger does file I/O (like a log in MacsBug).
|
|
; To prevent this problem we patch the entering and exiting debugger
|
|
; procedures in _DebugUtil
|
|
; WARNING, the KillXPT routine relies on @enabled being 4 bytes before @patch!!!
|
|
|
|
bra.s installDebuggerPatch
|
|
|
|
topPatch equ *
|
|
lea @enabled,a0 ; local storage
|
|
move.l #1,(a0) ; remember that we are enabled
|
|
lea @address,a0 ; address of old _DebugUtil
|
|
move.l 4(sp),(a0) ; save it in local storage
|
|
lea @patch,a0 ; the address of the patch
|
|
move.l a0,d0 ; return it to caller
|
|
rts
|
|
|
|
@address dc.l 0 ; address of old _DebugUtil
|
|
@enabled dc.l 0 ; enabled marker
|
|
@patch
|
|
move.l a5,-(sp) ; save a5
|
|
|
|
move.l SCSIGlobals, A5 ; aquire our globals
|
|
|
|
lea @enabled,a2 ; get enabled variable (a2 is saved but not a parameter)
|
|
tst.l (a2) ; Are we running?
|
|
beq.s @exit
|
|
cmp.b #2,d0 ; something we are interested in?
|
|
bhi.s @exit ; nope, outta here
|
|
beq.s @leaving ; leaving debugger?
|
|
tst.b d0 ; debuggerMax?
|
|
beq.s @exit ; yep, we don't do anything with this
|
|
@entering
|
|
addq.b #1, SCSIGlobalsRec.inDebugger(A5) ; inc counter
|
|
bra.s @exit
|
|
@leaving
|
|
subq.b #1, SCSIGlobalsRec.inDebugger(A5) ; dec counter
|
|
@exit
|
|
move.l (sp)+,a5 ; restore a5
|
|
move.l @address,a2 ; address of old _DebugUtil
|
|
jmp (a2)
|
|
|
|
RTSNAME 'debuggerPatch'
|
|
sizePatch equ *-topPatch
|
|
|
|
|
|
installDebuggerPatch
|
|
clr.b ([SCSIGlobals],SCSIGlobalsRec.inDebugger) ; clear counter
|
|
|
|
move.l #sizePatch,d0 ; size of patch
|
|
_NewPtrSys ; get storage for it
|
|
bne.s @failInst ; failed install get out
|
|
move.l a0,-(sp) ; save a0
|
|
|
|
move.l #sizePatch,a1 ; length of patch
|
|
_DebuggerLockMemory ; lock the memory
|
|
move.l (sp)+,a1 ; restore a0 into a1 since it is the destination for BlockMove
|
|
lea topPatch,a0 ; source for BlockMove
|
|
move.l #sizePatch,d0 ; length for BlockMove
|
|
_BlockMove ; BlockMove it into RAM (and flush cache)
|
|
jmp (a1) ; finish setting up (rts from there)
|
|
@failInst moveq #0,d0 ; nil ptr (we didn't install a patch)
|
|
rts
|
|
|
|
NAME 'installDebuggerPatch'
|
|
ENDP
|
|
|
|
;———————————————————————————————————————————————————————————————————————
|
|
CallCompRoutineGlue PROC EXPORT
|
|
;———————————————————————————————————————————————————————————————————————
|
|
; Note: This routine is needed for a couple of reasons.
|
|
; 1) because the file manager's BasicIO ioCompletion routine wipes out D2-D3
|
|
; and A0-A3. This filters up through the driver's scsiCompletion routine
|
|
; because it made the call to ioDone simply by jmping to it (and not worrying
|
|
; about any registers). We have changed our driver to save these registers
|
|
; as well but for paranoias sake, we do it here too (3rd-party drivers etc.)
|
|
; 2) because we want to run completion routines at level 0 if possible. This is
|
|
; done through the deferred task manager. To avoid deadlocks, we check for
|
|
; conditions that would prevent deferred tasks from running - if present, we
|
|
; will execute the completion routines immediately.
|
|
;
|
|
; 8(sp) ioPtr
|
|
; 4(sp) scsiCompletion
|
|
; 0(sp) return address
|
|
;
|
|
complTrashedRegs REG D3/A2-A3/A5
|
|
|
|
StackFrame RECORD {currentSP},DECR
|
|
completionDT ds.l 1
|
|
ioPtr ds.l 1
|
|
currentSP ds.l 1
|
|
ENDR
|
|
|
|
IF 0 THEN
|
|
move.w sr, D0 ; what interrupt level are we?
|
|
move.w D0, D1
|
|
and.w #$700, D1
|
|
beq.s @call ; if 0 -> call routine now
|
|
|
|
move.l SCSIGlobals, A1
|
|
tst.b SCSIGlobalsRec.inDebugger(A1) ; are we in a debugger?
|
|
bne.s @call ; yes -> call immediately
|
|
|
|
or.w #$700, sr ; else, block all ints temporarily
|
|
|
|
; Check to see if it's safe to install our deferred task. That is, can we be guaranteed
|
|
; that it will run before another synchronous request happens. This could occur from
|
|
; a VBL or from a Deferred Task so we need to see if either of these are busy.
|
|
; Note that VM will turn off the DTQ (and VBLs) by setting the inVBL bit.
|
|
|
|
btst #inVBL, VBLQueue+QFlags ; DTQ blocked because of VBL busy?
|
|
bne.s @enableIntCall ; yes -> call immediately
|
|
|
|
btst #InDTQ, DTQFlags ; already in dispatcher?
|
|
bne.s @enableIntCall ; yes -> call now then
|
|
|
|
; NOT We no longer care if there are any Deferred Tasks already enqueued because now we go
|
|
; and install ourselves at the beginning of the DTQ. Not very friendly but it will
|
|
; work as long as nobody else does the same thing.
|
|
|
|
move.l DTQueue+2, D1 ; is Q empty?
|
|
bne.s @enableIntCall ; no -> call now then
|
|
|
|
move.l StackFrame.completionDT(sp), A0 ; get addr of def.task
|
|
move.l StackFrame.ioPtr(sp), dtParm(A0) ; ioPtr is dtParm
|
|
IF RECORD_ON THEN
|
|
pea 'dfrC'
|
|
move.l dtParm(A0), -(sp)
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
ENDIF
|
|
move.w D0, -(sp) ; save SR
|
|
|
|
lea DTQueue, A1 ; get ptr to queue
|
|
bsr.l ENQUEUEHEAD ; go add element
|
|
|
|
move.w (sp)+, sr ; unblock ints
|
|
rts
|
|
|
|
@enableIntCall
|
|
move.w D0, sr ; unblock ints
|
|
ENDIF
|
|
|
|
@call
|
|
IF CALL_RECORD_ON THEN
|
|
pea 'imC-'
|
|
move.w sr, -(sp)
|
|
move.w DTQFlags, -(sp)
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
ENDIF
|
|
move.l StackFrame.ioPtr(sp), A1 ; get ioPtr from stack
|
|
movem.l complTrashedRegs, -(sp)
|
|
move.l A1, -(sp) ; A1 is ioPtr
|
|
move.l SCSI_IO.scsiXPTprivate(A1), A5 ; get client's A5
|
|
move.l SCSI_IO.scsiCompletion(A1), A1 ; get completion routine
|
|
jsr (A1) ; call completion routine
|
|
movem.l (sp)+, complTrashedRegs
|
|
IF CALL_RECORD_ON THEN
|
|
pea '-imC'
|
|
move.l sp, -(sp)
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
ENDIF
|
|
rts
|
|
|
|
NAME 'CallCompRoutineGlue'
|
|
|
|
ENDP
|
|
|
|
|
|
DEFERREDCALL PROC EXPORT
|
|
|
|
dtTrashedRegs REG D0-D7/A0-A6
|
|
dtTrashedRegsSize equ 15*4
|
|
|
|
movem.l dtTrashedRegs, -(sp)
|
|
|
|
move.l A1, -(sp) ; A1 is dtParm (ioPtr)
|
|
move.l SCSI_IO.scsiXPTprivate(A1), A5 ; get client's A5
|
|
|
|
IF RECORD_ON THEN
|
|
pea 'dtC-'
|
|
move.w SCSI_IO.scsiXPTprivate(A1), -(sp)
|
|
move.w 8(sp), -(sp) ; low word of ioPtr
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
ENDIF
|
|
|
|
jsr ([SCSI_IO.scsiCompletion,A1]) ; call completion routine
|
|
IF RECORD_ON THEN
|
|
pea '-dtC'
|
|
move.l A1, -(sp)
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
|
|
pea 'retA'
|
|
move.l dtTrashedRegsSize+8(sp), -(sp)
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
ENDIF
|
|
|
|
movem.l (sp)+, dtTrashedRegs
|
|
rts
|
|
|
|
NAME 'DEFERREDCALL'
|
|
|
|
ENDP
|
|
;•
|
|
;•
|
|
;•
|
|
ENDIF ;••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
|
|
|
|
|
|
;———————————————————————————————————————————————————————————————————————
|
|
ciBusyPatch PROC EXPORT
|
|
;———————————————————————————————————————————————————————————————————————
|
|
; Because we are deferring our data transfer routines in places where we are
|
|
; not re-entrant we will use the SCSIBusy mechanism to tell the File Manager
|
|
; whether we are re-entrant or not. The old SCSIBusy patch remains in the chain
|
|
; and fully functional. When our patch is executed it checks if SyncUnsafe is
|
|
; not zero and if so returns busy and remembers that the file system was attempting
|
|
; use the SCSI Manager when it wasn't safe. Then when EnableVM determines that
|
|
; we are safe again it checks the wasBusy flag and calls jvSCSIFreeHook to wake
|
|
; the file system up again.
|
|
;
|
|
; WARNING, the KillXPT routine relies on @enabled being 4 bytes before @patch!!!
|
|
|
|
bra.w installBusyPatch
|
|
|
|
topBusyPatch equ *
|
|
lea @enabled,a0 ; local storage
|
|
move.l #1,(a0) ; remember that we are enabled
|
|
lea @address,a0 ; address of old _SCSIDispatch
|
|
move.l 4(sp),(a0) ; save it in local storage
|
|
lea @patch,a0 ; the address of the patch
|
|
move.l a0,d0 ; return it to caller
|
|
rts
|
|
|
|
@address dc.l 0 ; address of old _SCSIDispatch
|
|
@enabled dc.l 0 ; enabled marker
|
|
@patch
|
|
move.l a5,-(sp) ; save a5
|
|
|
|
move.l SCSIGlobals, a5 ; aquire our globals
|
|
|
|
lea @enabled,a0 ; get enabled variable (a2 is saved but not a parameter)
|
|
tst.l (a0) ; Are we running?
|
|
beq.s @exit
|
|
|
|
cmpi.w #OldSCSICalls.kSCSIBusy, 8(sp) ; check selector after the return addr and saved A5
|
|
bne.s @exit ; not scsiBusy
|
|
|
|
move.l a4, -(sp) ; save a4
|
|
move.l SCSIGlobalsRec.xptGlobals(a5), a4 ; get XPTg for syncUnsafeCount
|
|
|
|
tst.w XPTglobals.syncUnsafeCount(a4) ; unsafe?
|
|
beq.b @a4Exit ; nope, pass through to regular SCSIBusy
|
|
|
|
bset.b #0,SCSIGlobalsRec.ciWasBusy(a5) ; remember that we returned busy
|
|
move.l (sp)+,a4 ; restore a4
|
|
move.l (sp)+,a5 ; restore a5
|
|
move.l (sp)+,a0 ; return address
|
|
adda.w #2,sp ; pop selector
|
|
move.w #1,(sp) ; return busy (pascal style return value on stack)
|
|
jmp (a0) ; return to client
|
|
|
|
@a4Exit
|
|
move.l (sp)+,a4 ; restore a4
|
|
@exit
|
|
move.l (sp)+,a5 ; restore a5
|
|
move.l @address,a0 ; address of old _SCSIDispatch
|
|
jmp (a0) ; call thru to old
|
|
|
|
RTSNAME 'busyPatch'
|
|
sizeBusyPatch equ *-topBusyPatch
|
|
|
|
|
|
installBusyPatch
|
|
move.l SCSIGlobals, a0 ; aquire our globals
|
|
clr.b SCSIGlobalsRec.ciWasBusy(a0) ; initialize
|
|
clr.b SCSIGlobalsRec.ciBusyPending(a0) ; initialize
|
|
|
|
|
|
move.l #sizeBusyPatch,d0 ; size of patch
|
|
_NewPtrSys ; get storage for it
|
|
bne.s @failInst ; failed install get out
|
|
move.l a0,-(sp) ; save a0
|
|
move.l #sizeBusyPatch,a1 ; length of patch
|
|
_DebuggerLockMemory ; lock the memory
|
|
move.l (sp)+,a1 ; restore a0 into a1 since it is the destination for BlockMove
|
|
lea topBusyPatch,a0 ; source for BlockMove
|
|
move.l #sizeBusyPatch,d0 ; length for BlockMove
|
|
_BlockMove ; BlockMove it into RAM (and flush cache)
|
|
jmp (a1) ; finish setting up (rts from there)
|
|
@failInst moveq #0,d0 ; nil ptr (we didn't install a patch)
|
|
rts
|
|
|
|
NAME 'installBusyPatch'
|
|
ENDP
|
|
END
|
|
|
|
|