;ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ ; ; 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): ; ; 1/31/94 DCB Added a semaphore to the SCSIBusy stuff so we don't call ; DeferUserFn from enable VM as much. ; 1/9/94 pdw Took out aerror on build SCSIBusy patch with forROM. ; 1/5/94 pdw Simplifying the SCSIBusy install stuff. ; 1/5/94 pdw (DCB) Added SCSIBusy patch. ; 12/19/93 DCB Added SetIntsAt2 and RestoreInts. ; 11/22/93 pdw Rolling in from . ; 11/10/93 pdw Added clearing of inDebugger flag. ; 11/8/93 pdw Changed recording criteria around call to completion routine. ; 10/14/93 pdw Fixing the occasional calling of completion routines at level 7 ; bug. I was jumping to @call instead of @enableIntCall ; 11/5/93 pdw Fixed build. ; 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! ; 10/14/93 pdw roll-in. ; 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. ; 10/12/93 pdw Added support for Synchronous data transfers, rewrote State ; Machine, message handling etc. ; 10/6/93 pdw Removed call to DTInstallHead, instead doing it with ENQUEUEHEAD ; directly. ; 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. ; 9/9/93 pdw Lots of little changes. Name changes, temporary cache_bug ; stuff. ; 7/8/93 pdw Getting rid of useless InitXPTRecorder function. ; 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. ; 5/25/93 DCB Rollin from Ludwig. (The next two items below) ; 5/21/93 PW Changing how we detect the presence of VM. Now using $B78 < 0 ; instead of $CF0==-1. ; 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. ; 5/5/93 PW Converted names to meanies-friendly names. Updated with latest ; from Ludwig stuff. ; 4/14/93 DCB Added RemoveSyncWait and synced up with SuperMario ; 3/29/93 PW Added an equate to better handle different movems. ; 3/29/93 PW Added a return address RECORD_EVENT to catch the driver messing ; up the stack problem. ; 3/26/93 mal (PW) Another try. ; 3/26/93 mal (actually PW)Removed the bogus "fix" that I just put in. ; 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). ; 3/26/93 PW Fixing RECORD_ON problem. ; 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. ; 1/31/93 PW Update from the latest of Ludwig. Also changes required for PDM ; (will update Ludwig with these as needed myself). ; 1/30/93 PW Added glue code for calling completion routines (saving ; registers that were getting trashed by File Manager). ; 11/20/92 PW Added some Includes that were removed from headers. ; 11/3/92 PW Removed unneeded intrRegs definition. ; 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