mac-rom/OS/SCSIMgr4pt3/HALc96Routines.a

2300 lines
67 KiB
Plaintext
Raw Permalink Normal View History

;
; File: HALc96Routines.a
;
; Contains: 53c96 Hardware-Specific routines
;
; Written by: Paul Wolf
;
; Copyright: <09> 1990-1994 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <SM42> 2/3/94 DCB EnableSCSIIRQ was being called when DataDTask didn't run.
; <SM40> 2/1/94 DCB In my last checkin I introduced a re-entrancy problem in the
; deferred task. Now I block 68K ints instead of SCSI its before
; checking the semaphore.
; <SM39> 2/1/94 DCB Addressed a "minor" ordering problem with the DTPending
; semaphore which could cause sync wait hangs if somebody made a
; synchronous request from interrupt time.
; <SM38> 1/31/94 DCB Poured concrete over what I hope are the last remaining holes in
; the Q9x0 dual bus support.
; <SM37> 1/29/94 DCB Fixed several holes for dual bus psuedo DMA machines wherein we
; could clear the int at the VIA and not check the SCSI chip for
; the other bus.
; <SM36> 1/25/94 DCB Whoops, what's a little btst,bne between friends?
; <SM35> 1/25/94 DCB In order to allow our deferred task to run when user code is
; disabled I added a patch to the Deferred Task Manager which
; maintains our own private VM safe deferred task queue.
; <SM34> 1/19/94 DCB Slam interrupts to level 7 before leaving the deferred task.
; This prevents the stack overflow problem reported with the
; installer.
; <SM32> 12/19/93 DCB Major changes. The DeferAndWait function now installs a
; deferred task and then exits the SIM. We re-enter when the
; deferred task executes. This gets rid of the interrupt blocking
; and mouse freezing on pseudo-DMA machines.
; <SM31> 11/22/93 pdw Rolling in from <MCxx>.
; <MC6> 10/29/93 pdw Added the same sort of interrupt level lowering code around the
; call to ReselectISR that I added around the call to MyDT.
; <MC8> 11/8/93 pdw Added support for different inquiry data for different machines.
; <MC5> 10/28/93 pdw Fixed some Target mode stuff. Changed ISRs to drop interrupt
; level to previous level (determined by looking at the actual
; interrupt stack frame).
; <SM30> 11/19/93 chp Vectorize test of SCSI IE. Rework Install_ISR one more time.
; Implement <20>standard<72> VIA IRQ primitives as subroutines
; (basically copied from macros in HALc96equ.a).
; <SM29> 11/17/93 DCB Changing TestFor_GrandCentralExists so that it works on
; pre-SuperMario ROMs. This is necessary for the INIT version of
; the code.
; <SMG2> 9/22/93 chp Add Grand Central interrupt handler registration mechanism.
; <SM27> 11/8/93 DCB Disabling <SM26> until we get SCSIBusy fixed.
; <SM26> 10/29/93 DCB Using Deferred tasks to drop the interrupt level if we did
; indeed interrupt a level one task.
; <MC5> 10/28/93 pdw Fixed some Target mode stuff. Changed ISRs to drop interrupt
; level to previous level (determined by looking at the actual
; interrupt stack frame).
; <SM25> 10/15/93 DCB Getting rid of a debug trap in the bus error handler.
; <SM24> 10/14/93 pdw <MC> roll-in.
; <MC3> 10/12/93 pdw Added support for Synchronous data transfers, rewrote State
; Machine, message handling etc.
; <MC2> 9/26/93 pdw Changes to G_State usage from bit flags to enumeration.
; <SM23> 9/9/93 pdw Lots of little changes. Name changes, temporary cache_bug
; stuff.
; <SM22> 8/19/93 DCB Improving the bus error handler so that disconnects at
; non-polled bytes will work properly.
; <SM21> 8/13/93 pdw Removed PutXferPhase, instead stuffing phase after every
; interrupt.
; <SM20> 7/20/93 pdw Fixed a Cold Fusion IRQ registration problem by passing in the
; IRQ bit number so that InstallISR knows which slot in VIA2DT to
; use. Changed intDREQbitNum to a byte.
; <SM19> 7/17/93 pdw Lots of little things.
; <SM18> 7/8/93 pdw Changing record data to StkLowPt to help Kurt with debugging
; stack overflow bug.
; <SM17> 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. Resolving
; with my Ludwig sources.
; <SM16> 5/25/93 DCB Rollin from Ludwig. (The next item below)
; <LW11> 5/21/93 PW Added target mode stuff.
; <SM15> 5/6/93 PW Adding NOP to stop asm warnings.
; <SM14> 5/6/93 RC Killed some warnings in the build
; <SM13> 5/5/93 PW Converted names to meanies-friendly names. Updated with latest
; from Ludwig stuff.
; <SM12> 4/8/93 DCB Fixed up the BusErr Handler for Quadras.
; <LW9> 4/14/93 DCB Added parity checking in the interrupt handler.
; <LW8> 3/26/93 PW Changed dreqIn32bit to dreqNeedsSwapMMU and other minor name
; changes.
; <LW7> 3/8/93 PW Removed unnecessary use of D0 for restoring previous interrupt
; level.
; <SM11> 3/22/93 RC Fixed warning problem with useless bne.s
; <SM10> 3/20/93 PW Removed some of the PDMDebug stuff that's not needed.
; <LW6> 2/17/93 PW Added dual-bus/single-interrupt stuff for Quadra support.
; <SM9> 1/31/93 PW Update from the latest of Ludwig. Also changes required for PDM
; (will update Ludwig with these as needed myself).
; <LW5> 1/27/93 PW Disabled dropping of int level to 1 in HAL_ISR to help the old
; call from new call completion hang.
; <LW4> 1/27/93 PW Added HALIntPoll routine. Changed intEnable and intDisable
; calling around - now I disable going into MyDT and enable coming
; out and I disable going into HALAction and enable coming out.
; <LW3> 1/12/93 DCB Fixed the constant ISR! debugger breaks by moving bclr before
; returning int level to previous.
; <LW2> 1/8/93 PW Fixed interrupt reentrancy bug by slamming int level to 7 around
; critical sequence. Also added semaphore to check for reentrant
; ISR. This will not occur unless the level 7 fix is disabled.
; <SM8> 12/5/92 PW Add ability to handle reset interrupts - except for the Curio
; bus.
; <SM7> 10/30/92 DCB Lots of changes to reduce interrupt latency
; <SM6> 10/14/92 PW Removed some unused code and changed some comments.
; <SM5> 10/8/92 PW Lots of trivial name changes.
; <SM4> 8/31/92 PW Changed register and command definitions to reflect changes to
; SCSIEqu53c96.
; <SM3> 8/6/92 PW Added removal of BusErrHandler at the termination of the
; BusErrHandler. It used to be in the second half of Transfer.
; <SM2> 7/28/92 PW Resolved diffs between Clinton's and Paul's sources.
; <SM1> 7/25/92 PW Initial check-in.
;
;==========================================================================
MACHINE MC68020 ; '020-level
BLANKS ON ; assembler accepts spaces & tabs in operand field
PRINT OFF ; do not send subsequent lines to the listing file
; don't print includes
PostNOP EQU 1 ;
LOAD 'StandardEqu.d' ; from StandardEqu.a and for building ROMs
INCLUDE 'HardwarePrivateEqu.a' ;
INCLUDE 'UniversalEqu.a'
INCLUDE 'SysPrivateEqu.a' ;
INCLUDE 'MC680x0.a'
INCLUDE 'Debug.a' ; for NAME macro
INCLUDE 'ACAM.a'
INCLUDE 'SCSI.a'
INCLUDE 'XPTEqu.a'
INCLUDE 'SCSIEqu53c96.a'
INCLUDE 'SIMCoreEqu.a'
INCLUDE 'HALc96equ.a'
PRINT ON ; do send subsequent lines to the listing files
CASE OBJECT
HALc96Routines PROC EXPORT
EXPORT GetReconnectInfo, SizeOfGlobals
EXPORT GetSelectInfo
EXPORT WtForFIFOData
EXPORT Ck4SCSIInt
EXPORT Wt4SCSIInt
EXPORT HALIntPoll, Install_ISR
EXPORT ClearVIASCSIIRQ, EnableVIASCSIIRQ, DisableVIASCSIIRQ, TestVIASCSIIE
EXPORT HAL_SingleISR
EXPORT HAL_DualISR
EXPORT Ck4DREQ
EXPORT BusErrHandler96, InstallBEH96, RemoveBEH96
EXPORT GetInitiatorID, ReadInitiatorID
EXPORT HandleSelected, Disconnected, UnexpectedDisc
EXPORT DataDTask,DeferAndWait
EXPORT ResumeIntRegs, QuickIntCheck, FullIntRegs
EXPORT ci_jDisptch, ci_jDisptch_Vers
IMPORT ENQUEUEHEAD, VMEnableUserCode, VMDisableUserCode
IMPORT DEQUEUETRAP
IMPORT RecordEvent, RecordError, AsmInit53c9xHW
WITH HALc96GlobalRecord
WITH SCSI_IO, HALactions, SCSIPhase
;==========================================================================
SizeOfGlobals ; required for C to Asm connection because we have no complete C global structure
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
move.l #HALc96GlobalRecord.GlobalSize, D0 ; put global size into return value
rts ;
NAME 'SizeOfGlobals'
;==========================================================================
GetReconnectInfo
;_______________________________________________________________________
btst #bReselected, int_rINT(A5) ; reselected int?
beq.s @ck4selected
move.w #HALresult.kHALreselected, HALactionPB.result(A4)
bra.s @valid
@ck4selected
btst #bSelected, int_rINT(A5) ; selected maybe?
beq.s @noSuchThing ; nope, bogus dude!
move.w #HALresult.kHALselectedAsTarget, HALactionPB.result(A4)
@valid
clr.b gotInt(A5) ; we now took care of int
move.b r_selectingID(A5), d0 ; get ID bits (both ours and theirs)
move.b rCF1(a3), d1 ; get our ID number
and.b #$07, d1
bclr d1, d0 ; clear our ID bit (theirs left)
move.w #7, d1
@IDloop
lsl.b #1, d0
dbcs d1, @IDloop ; decrement d1 and loop if not CARRY
bcc.s @noIDonBus ; if no carry then no ID on bus
; bne.s @extraIDonBus ; if not zero, then an extra ID on bus
move.w d1, HALactionPB.selectorID(A4)
moveq.l #iPhaseMsk, d3 ; load mask bits for phase value
and.b rSTA(a3), d3 ; get phase value
move.b D3, currentPhase(A5)
cmpi.b #iMsgIn, d3 ; are we in MsgIn phase still?
bne.s @notMsgInPhase
move.b #SCSIphase.kMessageInPhaseNACK, currentPhase(A5)
btst #bSelected, int_rINT(A5) ; selected int?
bne.s @exit ; -> we're all done
;
; Get the information describing the Reconnect and put into HALactionPB
;
move.b r_selectingMsg1(A5), HALactionPB.msg(A4)
move.b r_selMsgLen(A5), HALactionPB.msgInLen(A4)
move.b r_selPhase(A5), currentPhase(A5) ; update currentPhase
@notMsgInPhase
@exit
rts
;
; Error cases
;
@noIDonBus ; no ID on bus (beside ours)
IfDebugStr 'Reselect with no ID on bus (beside ours)'
bra.s @errorExit
@extraIDonBus ; an extra ID on bus
IfDebugStr 'Reselect with extra ID on bus'
bra.s @errorExit
@noSuchThing
IfDebugStr 'GetReconnectInfo has no info'
@errorExit
cmp.w #HALresult.kHALselectedAsTarget, HALactionPB.result(A4)
beq.s @exit ; if select, leave it as is (ignore bogus ID stuff)
move.w #HALresult.kHALreselectBogus, HALactionPB.result(A4)
bra.s @exit
RTSNAME 'GetReconnectInfo'
;_______________________________________________________________________
GetSelectInfo
IfDebugStr 'GetSelectInfo called! Huh?'
moveq #dsIOCoreErr, D0
_SysError
rts
NAME 'GetSelectInfo'
;_______________________________________________________________________
STRING ASIS
InquiryDataPDM
dc.b $23 ; Processor type, no physical device currently attached
dc.b 0 ; no device-type modifier
dc.b 0 ; might/might not be ISO, ECMA, ANSI standard (not likely)
dc.b 2 ; inquiry data is SCSI-2 compliant
dc.b InquiryDataLen-5
dc.b 0, 0 ; reserved
dc.b 0 ; no RelAdr, WBus32,16, Sync, Linked, CmdQue, SftRe
dc.b 'APPLE ' ; vendor identification
dc.b 'PDM (PDM,CF,CS) '
dc.b '04.3' ; revision level
dc.b '{wolfware} & {gecko}'
InquiryDataLen equ *-InquiryDataPDM
RTSNAME 'InquiryDataPDM'
InquiryDataCyclone
dc.b $23 ; Processor type, no physical device currently attached
dc.b 0 ; no device-type modifier
dc.b 0 ; might/might not be ISO, ECMA, ANSI standard (not likely)
dc.b 2 ; inquiry data is SCSI-2 compliant
dc.b InquiryDataLen-5
dc.b 0, 0 ; reserved
dc.b 0 ; no RelAdr, WBus32,16, Sync, Linked, CmdQue, SftRe
dc.b 'APPLE ' ; vendor identification
dc.b 'Cyclone '
dc.b '04.3' ; revision level
dc.b '{wolfware} & {gecko}'
RTSNAME 'InquiryDataCyclone'
InquiryDataQuadra
dc.b $23 ; Processor type, no physical device currently attached
dc.b 0 ; no device-type modifier
dc.b 0 ; might/might not be ISO, ECMA, ANSI standard (not likely)
dc.b 2 ; inquiry data is SCSI-2 compliant
dc.b InquiryDataLen-5
dc.b 0, 0 ; reserved
dc.b 0 ; no RelAdr, WBus32,16, Sync, Linked, CmdQue, SftRe
dc.b 'APPLE ' ; vendor identification
dc.b 'Quadra '
dc.b '04.3' ; revision level
dc.b '{wolfware} & {gecko}'
RTSNAME 'InquiryDataQuadra'
InquiryDataTNT
dc.b $23 ; Processor type, no physical device currently attached
dc.b 0 ; no device-type modifier
dc.b 0 ; might/might not be ISO, ECMA, ANSI standard (not likely)
dc.b 2 ; inquiry data is SCSI-2 compliant
dc.b InquiryDataLen-5
dc.b 0, 0 ; reserved
dc.b 0 ; no RelAdr, WBus32,16, Sync, Linked, CmdQue, SftRe
dc.b 'APPLE ' ; vendor identification
dc.b 'TNT '
dc.b '04.3' ; revision level
dc.b 'wolfwaregeckocraiger'
RTSNAME 'InquiryDataTNT'
SenseData
dc.b $70 ; current error
dc.b 0 ; no segment number
dc.b $05 ; Sense Key = Illegal Request
dc.b 0,0,0,0 ; Information (none)
dc.b SenseDataLen-8
dc.b 0,0,0,0 ; Command-specific information
dc.b $25 ; ASC = Logical Unit Not Supported
dc.b 0 ; ASCQ = 0
dc.b 0 ; no FRU code
dc.b 0,0,0 ; sense-key specific (none)
SenseDataLen equ *-SenseData
RTSNAME 'SenseData'
STRING PASCAL
;_______________________________________________________________________
; HandleSelected( HALg)
;
; Inputs: A5 HALg
;
; Outputs: none
;
;
;_______________________________________________________________________
;
HandleSelected
IF RECORD_ON THEN
pea 'Targ' ;
pea '****' ;
bsr RecordEvent
addq.l #8, sp
ENDIF
;
; If cmd is 6 bytes long and we handle it, do so, otherwise, send Ck Cond status
;
move.b rcvdCommandLen(A5), D0
beq @returnCkCondition ; no command received -> return ckCond status
cmp.b #6, D0
bne @returnCkCondition ; not 6 byte cdb -> return ckCond status
move.b rcvdCommand(A5), D0 ; get Command byte
beq @DoTURCommand ; 00 = Test Unit Ready
cmp.b #$12, D0 ; 12 = Inquiry
beq.s @DoInquiryCommand
cmp.b #$03, D0 ; 03 = Request Sense
beq.s @DoRequestSenseCommand
bra @returnCkCondition ; unknown
;
; Inquiry command - send Inquiry data
;
@DoInquiryCommand
tst.b rcvdCommand+1(A5) ; test logical unit and EVPD
bne @returnCkCondition
tst.b rcvdCommand+2(A5) ; test page code
bne.s @returnCkCondition ; either nonzero -> return ck cond status
moveq.l #0, D1
move.b rcvdCommand+4(A5), D1 ; get requested count
cmp.b #InquiryDataLen, D1
bls.s @inqOK
move.b #InquiryDataLen, D1
@inqOK
; This should be changed to be decoder based
cmp.b #dmaTypeAMIC, dmaType(A5)
bne.s @cyclone
lea InquiryDataPDM, A0 ; point to our inquiry data
bra.s @sendData
@cyclone
cmp.b #dmaTypePSC, dmaType(A5)
bne.s @quadra
lea InquiryDataCyclone, A0 ; point to our inquiry data
bra.s @sendData
@quadra
cmp.b #dmaTypeNone, dmaType(A5)
bne.s @tnt
lea InquiryDataQuadra, A0 ; point to our inquiry data
bra.s @sendData
@tnt
; cmp.b #dmaTypeGC, dmaType(A5)
; bne.s @
lea InquiryDataTNT, A0 ; point to our inquiry data
bra.s @sendData
;
; Request Sense command - send Sense data
;
@DoRequestSenseCommand
moveq.l #0, D1
move.b rcvdCommand+4(A5), D1 ; get requested count
cmp.b #SenseDataLen, D1
bls.s @senseOK
move.b #SenseDataLen, D1
@senseOK
lea SenseData, A0 ; point to our request sense data
bra.s @sendData
;
; Send the D0 number of data bytes from address A0 by loading each into the FIFO
; then issuing the cSendData command and waiting for the interrupt. When complete,
; send good status and CmdComplete message.
;
@sendDataTop
nop
move.b (A0)+, rFIFO(A3)
nop
tst.b rSTA(A3)
nop
move.b #cSendData, rCMD(A3)
nop
@1
tst.b rSTA(A3) ; this is just to avoid <20> 'Ck4S' events in tape
bpl.s @1 ; wait for int
bsr Ck4SCSIInt
@sendData
dbra D1, @sendDataTop
bra.s @returnGoodStatus
;
; Test Unit Ready command - send Check condition status
;
@DoTURCommand
@returnCkCondition
move.b #$02, rFIFO(A3)
nop
move.b #$00, rFIFO(A3)
nop
bra.s @TerminateSeq
@returnGoodStatus
move.b #$00, rFIFO(A3) ; status
nop
move.b #$00, rFIFO(A3) ; message
nop
@TerminateSeq
move.b #cTerminateSeq, rCMD(A3)
nop
@2
bsr.s Ck4SCSIInt ; completes with FC and Disc interrupts
beq.s @2
; DoIntRegs takes care of phase
rts
NAME 'HandleSelected'
;_______________________________________________________________________
;
; PCto32Bit
; Inputs: none
; Destroys: A0, D0
; Calls: _Translate24To32
;
; Function: Converts the PC to a 32-bit address.
;
; Routine from EdiskDrvr.a
;_______________________________________________________________________
_Translate24To32 OPWORD $A091 ;
PCto32Bit
move.l (sp), d0 ; put return address in d0
_Translate24to32 ; convert the address to 32-bit mode
move.l d0, (sp) ; save the new return address
rts ;
NAME 'PCto32Bit'
;_______________________________________________________________________
;
; WtForFIFOData - wait for 256mS for the data to show up in the FIFO
;
; a3 -> SCSI chip read base address - SERIALIZED
; d0 <- number of bytes in FIFO (zero if timed out)
; Z <- .eq.=timed out .ne.=bytes available
;
WtForFIFOData
movem.l d1-d2, -(sp)
move.w TimeSCSIDB, d1 ; get # of DBRAs
lsl.l #8, d1 ; multiply by 256
move.l d1, d2 ; ...a 256mS wait
swap d2
@1
moveq.l #mFIFOCount, d0
and.b rFIFOflags(a3), d0 ; read FIFO flags regr
dbne d1, @1 ; loop until data or timeout
dbne d2, @1 ;
movem.l (sp)+,d1-d2
rts ;
NAME 'WtForFIFOData'
;_______________________________________________________________________
;
; Ck4SCSIInt - just check right now (once) for a SCSI intrp.
;
Ck4SCSIInt
IF RECORD_ON and 1 THEN
pea 'Ck4S'
move.l 4(sp), -(sp) ; and caller's addr
bsr RecordEvent
addq.l #8, sp
ENDIF
tst.b gotInt(A5) ; if there was already an interrupt waiting
bne.s @gotSCSIInt ;
bsr DoIntRegs ; check bINT bit rSTA for c96 interrupt
tst.b gotInt(A5) ; check for an int that we care about
beq.s @noSCSIInt ;
@gotSCSIInt
bsr GotSCSIInt
moveq.l #1, D0
rts
@noSCSIInt
moveq.l #0, D0
rts
NAME 'Ck4SCSIInt'
;_______________________________________________________________________
;
; Wt4SCSIInt - infinite loop to wait for a SCSI intrp. <SM7> PDW (the whole routine changed)
;
; Uses: D0, A0, A1, D5 (return)
;
; On exit: D5 = rFOS|rINT|rSQS|rSTA, byte values from the Seq.Step, Status & INT regrs.
;
; CCR.Z, (EQ) means NOT Disconnect interrupt (i.e. either FC or BS)
; CCR.z, (NE) Disconnect interrupt
allOurRegs REG D0-D7/A0-A6
numAllRegs equ 15
Wt4SCSIInt
IF RECORD_ON THEN
pea 'Wt4S'
move.l 4(sp), -(sp) ; and caller's addr
bsr RecordEvent
addq.l #8, sp
ENDIF
tst.b gotInt(A5) ; if reselect occurred during select prelims
bne.w GotSCSIInt ; we would have already had an interrupt
@noIntYet
; ---- save regs on stack
movem.l allOurRegs, -(sp)
bsr DoIntRegs ; check bINT bit rSTA for c96 interrupt
move.w sr, D0
ori.w #$0700, sr ; \/ \/ \/ Block Ints \/ \/ \/
tst.b gotInt(A5) ; if there was no int we should care about
beq.s GoAsyncDude ; bra - go asynchronous (rts to client)
move.w D0, sr ; if we got an int, Unblock ints /\ /\ /\
movem.l (sp)+, allOurRegs
bra.w GotSCSIInt
nop
RTSNAME 'Wt4SCSIInt'
;_______________________________________________________________________
;
GoAsyncDude
bset #waiting4int, intFlags(A5) ; defer if it comes in now
move.w D0, sr ; /\ /\ /\ Unblock ints /\ /\ /\
GoAsyncNeck
move.l sp, suspendedSP(A5) ; suspend SCSI thread
IF DEBUGGING THEN
move.b #2, privStackState(A5)
ENDIF
IF STACK_RECORD_ON THEN
pea 'Pub<'
move.l sp, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
move.l publicSP(A5), sp ; resume previous thread
move.l publicStkLowPt(A5), StkLowPt ; resume stack sniffing
IF STACK_RECORD_ON THEN
pea '<Pub'
move.l sp, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
moveq.l #0, D0
rts ; return to HALaction (or MyDT if already deferred)
NAME 'GoAsyncDude'
DeferAndWait
movem.l d0-d2/a0-a2,-(sp) ; save some regs
jsr DeferAndWaitInner
movem.l (sp)+,d0-d2/a0-a2 ; restore some regs
rts
; Defer further actions until interrupts are disabled. This is mainly used for data transfer
; which really screws up interrupt latency on pseudo DMA machines.
; IMPORTANT!
; We are using our own deferred task manager!! The real one doesn't operate with VMUserCode
; disabled. The jDisptch vector does get called however if there is something in the queue.
; Therefore we just stuff an entry in the DTQueue which points at an RTS and then when jDisptch
; gets called we take over and run our real deferred task regardless of whether user code is
; disabled.
DeferAndWaitInner
WITH SCSIGlobalsRec
move.w sr, D0 ; what interrupt level are we?
move.w D0, D1
and.w #$700, D1
beq.w ForgetIt ; if 0 -> getouttahere
btst #fromRealInt,dataDTFlags(a5) ; are we here as a result of a real interruptHandlers.a
; generated interrupt? ie is it safe to assume that our
; deferred task is going to be executed?
beq.w ForgetIt ; nope, don't defer
move.l SCSIGlobals, A0 ;
move.l privDTQHead(A0), D0 ; is Q empty?
bne.w ForgetIt ; no -> don't defer
btst #InDTQ, privDTQFlags(A0) ; already in dispatcher?
bne.w ForgetIt ; yes, can't defer
JustDoIt
IF RECORD_ON THEN
pea 'DtDf'
move.l a0, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
tst.l DTskQHdr ; Is there something in the queue?
bne.b @bogus_is_busy ; nope, no need to enqueue it then
lea DTQueue, A1 ; get ptr to real DT queue
lea dataDT_Null(A5), A0 ; get the DT task version that does nothing
; except mark dataDeferStuff clear
bsr.l ENQUEUEHEAD ; add the element
@bogus_is_busy
move.l SCSIGlobals, A0 ;
lea privDTQueue(A0), A1 ; get ptr to our private queue
lea dataDT(A5), A0 ; Get our deferred task record
bset.b #pendingDTask, dataDTFlags(a5) ; Remember that a deferred task is pending
bsr.l ENQUEUEHEAD ; go add element
movem.l allOurRegs, -(sp)
bra.w GoAsyncNeck
DataPollDTask
move.l a5, -(sp)
move.w sr, -(sp) ; for use down below
ori.w #$0700, sr ; \/ \/ \/ Block Ints \/ \/ \/
bclr.b #pendingDTask, dataDTFlags(a5) ; Should we be here?
beq.b @noGo ; nope, don't do anything
DisableSCSIIRQ ; disable scsi ints
move.w (sp)+, sr ; /\ /\ /\ Unblock ints /\ /\ /\
movem.l allOurRegs, -(sp) ; save all of our registers
;a5 is already setup by HalIntPoll
jsr DataDTaskInner ; Magic Stack Switch!
; Since we may have cleared an interrupt for the OTHER bus (9x0) at the VIA we need to
; poll for interrupts on the other bus until we don't have any more.
cmp.b #SHARED_VIA,intTypeSCSI(A5) ; is this a 900?
bne.b @noShare ; nope, good we don't have to do this
bclr #fromRealInt,dataDTFlags(A5) ; remember it is NOT safe to defer our data xfer routine
@0
move.l otherHALg(A5), A5
move.l baseRegAddr(A5), A3 ; A3 points to c96
bsr.w IntCommonFromDeferred
tst.b D0
bne.s @0
@1
move.l otherHALg(A5), A5
move.l baseRegAddr(A5), A3 ; A3 points to c96
bsr.w IntCommonFromDeferred
tst.b D0
bne.s @0 ; repeat until there are 2 no-ints in a row
@noShare
movem.l (sp)+, allOurRegs ; restore our registers
EnableSCSIIRQ ; re-enable ints
move.l (sp)+, a5
rts ; back to HalIntPoll
@noGo
move.w (sp)+, sr ; /\ /\ /\ Unblock ints /\ /\ /\
move.l (sp)+, a5
rts ; back to HalIntPoll
DataDTask
IF RECORD_ON THEN
pea 'Dts>'
move.l a5, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
move.l a5, -(sp)
move.l A1, A5 ; restore globals from dtParm
move.w sr, -(sp) ; for use down below
movem.l allOurRegs, -(sp) ; save all of our registers
; Note that if ints are enabled (ie we are at level 1 or 0 then
; DisableUserCode/Disable Ints needs to be atomic. Otherwise we
; could get an interrupt with user code disabled or if we reversed
; the order of the two we could get a page fault with ints blocked
; either way it could be bad...
ori.w #$0700, sr ; \/ \/ \/ Block Ints \/ \/ \/
bclr.b #pendingDTask, dataDTFlags(a5) ; Should we be here?
beq.w @noDT ; nope, don't do anything
jsr VMDisableUserCode ; disallow page faults
DisableSCSIIRQ ; disable ints
move.w numAllRegs * 4(sp), sr ; /\ /\ /\ Unblock ints /\ /\ /\
IF RECORD_ON THEN
pea 'Dts#'
move.l a5, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
jsr DataDTaskInner ; Magic Stack Switch!
; Since we may have cleared an interrupt for the OTHER bus (9x0) at the VIA we need to
; poll for interrupts on the other bus until we don't have any more.
cmp.b #SHARED_VIA,intTypeSCSI(A5) ; is this a 900?
bne.b @noShare ; nope, good we don't have to do this
bclr #fromRealInt,dataDTFlags(A5) ; remember it is NOT safe to defer our data xfer routine
@0
move.l otherHALg(A5), A5
move.l baseRegAddr(A5), A3 ; A3 points to c96
bsr.w IntCommonFromDeferred
tst.b D0
bne.s @0
@1
move.l otherHALg(A5), A5
move.l baseRegAddr(A5), A3 ; A3 points to c96
bsr.w IntCommonFromDeferred
tst.b D0
bne.s @0 ; repeat until there are 2 no-ints in a row
@noShare
ori.w #$0700, sr ; \/ \/ \/ Block 68K Ints (let DTManager lower it) \/ \/ \/
jsr VMEnableUserCode ; allow page faults
EnableSCSIIRQ ; re-enable SCSI ints at the VIA
@noDT
movem.l (sp)+, allOurRegs ; restore our registers
move.w (sp)+, d0 ; bit bucket old status register
; and let the DT Manager restore the int level
@noGo
IF RECORD_ON THEN
pea 'Dts<'
move.l a5, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
move.l (sp)+, a5
rts ; back to deferred task mgr
DataDTaskInner
move.w sr, D0
ori.w #$0700, sr ; \/ \/ \/ Block Ints \/ \/ \/
IF STACK_RECORD_ON THEN
pea '>Prv'
move.l sp, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
move.l StkLowPt, publicStkLowPt(A5) ; remember old StkLowPt
clr.l StkLowPt ; and disable stack sniffer
move.l sp, publicSP(A5) ; suspend interrupt thread
IF DEBUGGING THEN
move.b #3, privStackState(A5)
ENDIF
move.l suspendedSP(A5), sp ; resume SCSI thread
move.w D0, sr ; /\ /\ /\ Unblock ints /\ /\ /\
movem.l (sp)+, allOurRegs ; restore regs that we saved in DeferAndWait
ForgetIt
rts
NAME 'DataDTask'
;______________________________________________________________________
;
; DisptchTsk Patch, mostly stolen from DeferredTaskMgr.a
; Regs D0-D3 and A0-A3 are saved prior to call.
;
;______________________________________________________________________
; This is a patch to the jDisptch vector for the Deferred Task Manager. It works exactly like
; the real deferred task manager except that it doesn't check inVBL before executing the task.
; This allows it to work with VM user code disabled running which obviously we need if we are
; the backing store. If the version tag is in the SCSI globals it is installed. If you want
; to remove it first look at jDisptch. If it is there remove it and stuff your new one in. If
; not then somebody else has chained their own patch in. To get rid of it in this case you should
; change the version number in the globals and use a completely different set of variables in SCSI
; Globals for the private DT Queue etc. Thus if nothing gets enqueued in the old queue the old code
; will never run. This saves some "Am I running code" which is good since this gets executed a lot
; if FileShare or AppleShare is running. Also note that this assumes that nobody is going to do a
; replacement patch to this vector. If they do it will fail heinously.
;
; Note that since we drop the int level after leaving the real deferred task manager we have
; to check to see if any more got enqueued before leaving here.
;
ci_jDisptch_Vers dc.l 'gcko' ; !!! Change this if you modify the patch!
ci_jDisptch
move.l SCSIGlobals, A3 ; get our globals
bset.b #InDTQ,privDTQFlags(A3) ; already in dispatcher?
bne.s @Exit ; yup, run real deferred tasks and get out
bra.b @DspStart ; nope, run our deferred tasks
@DspLoop
movea.l D0,A0 ; else setup ptr for use
lea privDTQueue(A3) ,A1 ; get ptr to queue
jsr DEQUEUETRAP ; dequeue task to be executed
movea.l DTAddr(A0),A2 ; get ptr to first task
movea.l DTParm(A0),A1 ; get optional parameter
andi.w #$F8FF,SR ; enable all ints
jsr (A2) ; and go do task
move.l SCSIGlobals, A3 ; get our globals
@DspStart
ori.w #HiIntMask,SR ; disable all ints
move.l privDTQHead(A3) ,D0 ; get queue head
bne.s @DspLoop ; loop if tasks exist
bclr.b #InDTQ,privDTQFlags(A3) ; clear indicator
@Exit
move.l oldjDisptch(A3), A0 ; get the old jDisptch
jsr (A0) ; and run it.
move.l SCSIGlobals, A3 ; get our globals
btst.b #InDTQ,privDTQFlags(A3) ; are we busy?
bne.b @rts ; yes, get out!
tst.l privDTQHead(A3) ; anything more to do?
bne.b ci_jDisptch ; yep, go do it
@rts
rts ; else exit
NAME 'ci_jDisptch'
ENDWITH ;SCSIGlobalsRec
;_______________________________________________________________________
;
; GotSCSIInt - Come here when:
; 1: Ck4SCSIInt call found an int
; 2: Wt4SCSIInt call found an int already there
; 3: getRegsBack is 'bra'd to, from Wt4 or MyDT
;
GotSCSIInt
clr.b gotInt(A5) ; we now took care of int
IF RECORD_ON THEN
pea 'GotI'
move.l A2, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
IF GROSS_CHECK THEN
btst #bGrossError, int_rSTA(A5)
beq.s @skipGEdebugger
DebugStr 'Gross Error in GotSCSIInt'
@skipGEdebugger
ENDIF
IF PARITY_ENABLED THEN
btst #bParityError,D5 ; check for parity error
beq.s @goodParity
and.b #~mCF1_EnableParity,rCF1(a3) ; reset the parity bit so we don't get more errors
NOT!
move.l a0,-(sp) ; !!! Temp until I figure out if A0 needs to be saved
move.l HALactionPB.ioPtr(A4), A0 ; ptr to SCSI_IO pb
or.w #kBadParity,SIM_IO.ioEvent(a0) ; set the bad parity bit
move.l (sp)+,a0
_debugger
@goodParity
ENDIF
btst #bDisconnected, int_rINT(A5) ; check for disconnected
beq.s @exit ; returns .EQ as well
move.b #kBusFreePhase, currentPhase(A5) ; returns .NE as well
@exit
rts
NAME 'GetRegsBack_GotInt'
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
;
; UnexpectedDisc - return from an unexpected disconnect
;
UnexpectedDisc
move.w #SCResults.scsiUnexpectedBusFree, HALactionPB.result(A4)
rts
;_______________________________________________________________________
;
; Disconnected - does what needs to be done whenever we get a Disc int from c96
;
; Notes: This routine needs to flush the FIFO and then enable reselection.
; The flush may not be needed but should be safe here. It used to be
; performed just before the Select command was sent to the chip but that
; isn't safe because a reselect interrupt could come in while the move.b
; of the cFlushFIFO is executing. This would cause a flushing of the two
; reselection bytes - the (re)selection ID and the first message byte before
; the interrupt routine would have a chance to pull them out of the FIFO.
;
; We also set up the currentPhase here to kBusFree because a later
; reading of the rSTA register cannot determine if the bus is Free or Data<74>Out.
;
Disconnected
IF RECORD_ON THEN
pea 'Disc'
move.l sp, -(sp)
; move.w #$00, -(sp)
; move.w busID(A5), -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
RecCmd $01, 'R',$00
move.b #cFlushFIFO, rCMD(a3) ; Flush FIFO
nop
move.b #0, rSyncOffset(A3) ; no sync data anymore
and.b #~mCF3_FastSCSI, rCF3(A3) ; clr fast bit
IF PARITY_ENABLED THEN
and.b #~mCF1_EnableParity,rCF1(a3) ; reset the parity bit
ENDIF
RecCmd $44, 'R',$02
move.b #cEnableR_sel, rCMD(a3) ; enable selection/reselection
eieio
rts
NAME 'Disconnected'
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
;
; HAL_ISR, HALIntPoll
;
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
;
CregsToSave REG D3-D7/A2-A6
NumCRegsToSave EQU 10
; Return 1 if we handled a _real_ interrupt or zero if nothing or just a deferred task
HALIntPoll
movem.l CregsToSave, -(sp)
move.l 4+4*NumCRegsToSave(sp), A5 ; get HALg off of stack (passed by SIMCore)
move.l baseRegAddr(A5), A3 ; a3 points to c96
IF 0 AND RECORD_ON THEN
move.l #'ItP0', D0
add.b 1+busID(A5), D0
move.l D0, -(sp)
move.w sr, -(sp)
move.w $160, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
moveq.l #0, D0 ; default to "didn't handle an interrupt
moveq.l #0, D2 ; OR sr with 0 for NO EFFECT
moveq.l #-1, D3 ; AND sr with FFFF for NO EFFECT
; if SCSI IRQ is disabled that means that SIM/HAL doesn't want to be reentered
jsr ([HALc96GlobalRecord.jvTestSCSIIE,A5])
beq.s @skipDTask
bclr #fromRealInt,dataDTFlags(A5); remember it is NOT safe to defer our data xfer routine
bsr.w InterruptCommon
; Now check to see if we have a pending deferred task in the deferred task queue. If we do
; then we need to execute it since we got here from a sync wait loop and the interrupt level
; may not be reduced any time soon.
;
; Also note that UserCode is disabled here which is why there is a separate function for calling
; the DT from here as opposed to a real Deferred task.
btst.b #pendingDTask, dataDTFlags(a5) ; Are we expecting to execute the dTask?
beq.b @skipDTask
move.l D0, -(sp) ; save return from InterruptCommon
jsr DataPollDTask ; Execute it (and set semaphore so we don't do it again)
move.l (sp)+, D0 ; and restore it.
@skipDTask
IF 0 AND RECORD_ON THEN
move.l #'IP<0', -(sp)
move.l D0, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
movem.l (sp)+, CregsToSave
rts
RTSNAME 'HALIntPoll'
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
; Note:IntRegs reg D0-D3/A0-A3 ; registers saved by InterruptHandlers.a
regsToSave REG D4-D7/A4-A6
NumRegsToSave EQU 7
HAL_DualISR
movem.l regsToSave, -(sp)
move.l 4+4*NumRegsToSave(sp), A5 ; get HALg off of stack (passed by SIMCore)
IF 0 AND RECORD_ON THEN
move.l #'Duo>', -(sp)
move.w sr, -(sp)
move.w $160, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
@0
bsr.w HAL_ISRCommon
move.l otherHALg(A5), A5
tst.b D0
bne.s @0
@1
bsr.s HAL_ISRCommon
move.l otherHALg(A5), A5
tst.b D0
bne.s @0 ; repeat until there are 2 no-ints in a row
IF 0 AND RECORD_ON THEN
move.l #'Duo<',-(sp)
move.l D0, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
movem.l (sp)+, regsToSave
rts
NAME 'HAL_DualISR'
HAL_SingleISR
movem.l regsToSave, -(sp)
IF 0 AND RECORD_ON THEN
move.l #'Sgl>', -(sp)
move.w sr, -(sp)
move.w $160, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
move.l 4+4*NumRegsToSave(sp), A5 ; get HALg off of stack (passed by SIMCore)
bsr.s HAL_ISRCommon
IF 0 AND RECORD_ON THEN
move.l #'Sgl<', -(sp)
move.l D0, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
movem.l (sp)+, regsToSave
rts
NAME 'HAL_SingleISR'
HAL_ISRCommon
IF 0 AND RECORD_ON THEN
move.l #'ISR0', D0
add.b 1+busID(A5), D0
move.l D0, -(sp)
move.w sr, -(sp)
move.w $160, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
bset #fromRealInt,dataDTFlags(A5); remember that it IS safe to defer our data xfer routine
move.l baseRegAddr(A5), A3 ; A3 points to c96
; moveq.l #0, D2 ; OR sr with 0 for NO EFFECT
; moveq.l #-1, D3 ; AND sr with FFFF for NO EFFECT
move.w #$0700, D2 ; OR sr with 0700 for Block All Ints
move.w #$FFFF-$0600, D3 ; AND sr with FFFF for Drop to Level 1
; fall thru to InterruptCommon
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
InterruptCommon
bsr.w DoIntRegs
beq.s @notOurInt ; bra if the intrp isn't for this bus
;<3B><><EFBFBD> Check if some code is Waiting for this (i.e. Wt4SCSIInt)
tst.b gotInt(A5) ; if there was no int we should care about
beq.s @gotAnInt ; bra - exit ISR
@check4defer
bclr #waiting4int, intFlags(A5) ; is Wt4SCSIInt waiting for this?
beq.s @gotAnInt ; no -
DisableSCSIIRQ ; disable ints
move.w SR, D0
move.w D0, -(sp) ; save current interrupt level
or.w D2, D0 ; goto level 7 (or no change)
and.w D3, D0 ; then back to level 1 (or no change)
move.w D0, SR ;
bsr MyDT ; HANDLE THE INTERRUPT
move.w (sp)+, SR ; return to level 2 (or whatever)
EnableSCSIIRQ ; enable ints after we come back out
@gotAnInt
moveq.l #1, D0
rts
@notOurInt
moveq.l #0, D0
rts
NAME 'InterruptCommon'
IntCommonFromDeferred ; Same as above but for use from a deferred task
; but is simpler since it doesn't change the
; interrupt levell.
bsr.w DoIntRegs
beq.s @notOurInt ; bra if the intrp isn't for this bus
;<3B><><EFBFBD> Check if some code is Waiting for this (i.e. Wt4SCSIInt)
tst.b gotInt(A5) ; if there was no int we should care about
beq.s @gotAnInt ; bra - exit ISR
@check4defer
bclr #waiting4int, intFlags(A5) ; is Wt4SCSIInt waiting for this?
beq.s @gotAnInt ; no -
DisableSCSIIRQ ; disable ints
bsr MyDT ; HANDLE THE INTERRUPT
EnableSCSIIRQ ; enable ints after we come back out
@gotAnInt
moveq.l #1, D0
rts
@notOurInt
moveq.l #0, D0
rts
NAME 'IntCommonFromDeferred'
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
DoIntRegs
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
move.l D1, -(sp) ; save D1
move.w SR, -(sp) ; bump up interrupt level to 7 <LW2> pdw
or.w #$0700, sr
;<3B><><EFBFBD><EFBFBD> Determine if interrupt was for this HBA
move.b rSTA(A3), D1 ; test intrp bit of status regr
bpl itsNotOurInt ; bra if the intrp isn't for this bus
;<3B><><EFBFBD><EFBFBD> Got an interrupt
@isOurInt
cmp.b #EDGE, intSensSCSI(A5) ; if we are EDGE sensitive,
bne.s @1
ClearSCSIIRQ ; clear the VIA int source
@1
;<3B><><EFBFBD><EFBFBD> Get the status and sequence
move.b rCMD(A3), D1 ; D1 = x | x | x | rSQS
;; move.b rSQS(A3), D1 ; D1 = x | x | x | rSQS
move.b rSQS(A3), selectedRegSQS(A5) ; save rSQS for later (minimize changes)
lsl.w #8, D1 ; D1 = x | x | rSQS | x
move.b rSTA(A3), D1 ; D1 = x | x | rSQS | rSTA
swap D1 ; D1 = rSQS | rSTA | x | x
move.b rFIFOflags(A3), D1 ; D1 = rSQS | rSTA | x | rFOS
lsl.w #8, D1 ; D1 = rSQS | rSTA | rFOS | x
; next move.b clears rSQS, rSTA & rINT
move.b rINT(A3), D1 ; D1 = rSQS | rSTA | rFOS | rINT
bne.s @3
IfDebugStr 'no c9x interrupt cause bits set'
moveq #dsIOCoreErr, D0
_SysError
@3
cmp.b #STICKYBIT, intSensSCSI(A5) ; if we are STICKYBIT sensitive
bne.s @2
ClearSCSIIRQ ; clear the VIA int source
@2
move.w (sp)+, SR ; return to original level
ResumeIntRegs ; If we did a quick int check then we may
; need to come here if we got something we
; didn't expect
IF RECORD_ON THEN
move.l D0, -(sp)
move.w sr, D0
lsr.w #8, D0
and.l #$F, D0
add.l #'IRg0', D0
move.l D0, -(sp)
move.l D1, -(sp)
bsr RecordEvent
addq.l #8, sp
move.l (sp)+, D0
ENDIF
IF 0 AND STACK_RECORD_ON THEN
pea 'SP= '
move.l sp, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
IF DEBUGGING THEN
move.l olderRegsRead(A5), oldestRegsRead(A5)
move.l oldRegsRead(A5), olderRegsRead(A5)
move.l newRegsRead(A5), oldRegsRead(A5)
move.l D1, newRegsRead(A5)
ENDIF
;<3B><><EFBFBD><EFBFBD> Normal or NonNormal interrupt? <20><><EFBFBD><EFBFBD>
move.b D1, D0
and.b #mNonNormalInt, D0
bne.s @nonNormalInt
;<3B><><EFBFBD><EFBFBD> A normal interrupt - fastest path
@normalInt
st.b gotInt(A5)
move.l D1, intRegsRead(A5)
@doneWithRegularInt
moveq.l #iPhaseMsk, d0 ; load mask for phase bits
and.b rSTA(A3), d0 ; are we in data-in phase?
move.b D0, currentPhase(A5) ; update currentPhase
@doneWithInt
move.l (sp)+, D1 ; get D1 back
moveq.l #1, D0 ; set return value - "interrupt handled"
rts
;<3B><><EFBFBD><EFBFBD> Reselected?
@nonNormalInt
btst #bReselected, D1
beq.s @ck4Illegal
IF RECORD_ON THEN
pea 'Rsl-'
move.l sp, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
st.b gotInt(A5)
move.l D1, intRegsRead(A5)
move.b rFIFO(A3), r_selectingID(A5) ; reselecting ID
btst #bBusService, D1 ; was phase message in?
beq.s @gotMsg ; yes -> get message byte
@noMsg
clr.b r_selMsgLen(A5) ; no message
moveq.l #iPhaseMsk, D0 ; calc what phase we are in
and.b int_rSTA(A5), D0
move.b D0, r_selPhase(A5)
bra.s @callReselectISR
@gotMsg
move.b rFIFO(A3), r_selectingMsg1(A5) ; 1st msg byte from recon sequence
move.b #1, r_selMsgLen(A5)
move.b #kMessageInPhaseNACK, r_selPhase(A5)
@callReselectISR
move.l HALc96GlobalRecord.SIMstaticPtr(A5), -(sp) ; push parameter (ptr to SIMglobals)
move.l ReconnectISRptr(A5), A0
jsr (A0)
addq.l #4, sp
IF RECORD_ON THEN
pea '-Rsl'
move.l sp, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
bra.s @doneWithInt
;<3B><><EFBFBD><EFBFBD> Illegal Cmd, Selected or ResetDetected?
@ck4Illegal
btst #bIllegalCmd, D1
beq.s @ck4Select
move.l D1, illCmdRegsRead(A5)
bra.s @doneWithInt ; don't do anything with it
@ck4Select
move.l D1, intRegsRead(A5)
btst #bSelected, D1
bne.s selected
btst #bSelectedWAtn, D1
bne.s selected
;<3B><><EFBFBD><EFBFBD> Reset?
IF DEBUGGING THEN
btst #bResetDetected, D1
IfDebugStr 'SCSI Bus Reset detected'
ENDIF
st.b gotInt(A5)
bsr.w AsmInit53c9xHW
move.b #kBusFreePhase, currentPhase(A5) ; update currentPhase
bra.w @doneWithInt
itsNotOurInt
IF RECORD_ON and 0 THEN
pea 'NoIt'
move.l A3, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
move.w (sp)+, SR ; return to original level
move.l (sp)+, D1 ; get D1 back
moveq.l #0, D0
rts
NAME 'DoIntRegs'
;<3B><><EFBFBD><EFBFBD> Selected as a Target
selected
st.b gotInt(A5)
move.b rFIFO(A3), r_selectingID(A5) ; reselecting ID
btst #bSelected, D1
beq.s @SelectWAtn
;
; Select W/O Atn - decode sequence step to determine how many command bytes we got
;
@SelectWOAtn
clr.b rcvdMessageLen(A5) ; never get any msg w/o atn
move.b rFIFO(A3), r_selectingMsg1(A5) ; null msg byte (c96 filler)
move.b selectedRegSQS(A5), D1 ; get sequence step register
and.b #7, D1
@WOsqs0
bne.s @WOsqs1to7
clr.b rcvdCommandLen(A5) ; didn't get any cmd bytes
bra.w @sqsDn
@WOsqs1to7
bra.w @getCommandBytes ; get however many command bytes
;
; Select W/Atn - decode sequence to determine how many command and msg bytes we got
;
@SelectWAtn
move.b rFIFO(A3), r_selectingMsg1(A5) ; 1st msg byte
move.b r_selectingMsg1(A5), rcvdMessage(A5) ; store here also
move.b selectedRegSQS(A5), D1 ; get sequence step register
and.b #7, D1
@sqs0
bne.s @sqs1
move.b #1, rcvdMessageLen(A5) ; only 1 message byte
clr.b rcvdCommandLen(A5) ; and no command bytes
bra.s @sqsDn
@sqs1
sub.b #1, D1
bne.s @sqs2
move.b #1, rcvdMessageLen(A5) ; only 1 message byte
bra.s @getCommandBytes ; get however many command bytes
@sqs2
sub.b #1, D1
bne.s @sqs3
move.b #1, rcvdMessageLen(A5) ; only 1 message byte
bra.s @getCommandBytes ; get however many command bytes
@sqs3
sub.b #1, D1
bne.s @sqs4
bra.s @forceDisconnect ; no such sequence step
@sqs4
sub.b #1, D1
bne.s @sqs5to7
moveq.l #mFIFOCount, D0
and.b rFIFOflags(A3), D0 ; how many bytes in FIFO
bne.s @sqs4_1
bra.s @forceDisconnect ; at least 2 message bytes
@sqs4_1
sub.b #1, D0 ; 1 byte in FIFO?
bne.s @sqs4_2 ; no -> must be 2 left
move.b #2, rcvdMessageLen(A5) ; 2 message bytes total
move.b rFIFO(A3), rcvdMessage+1(A5) ; 2nd msg byte
bra.s @sqsDn
@sqs4_2
move.b #3, rcvdMessageLen(A5) ; 3 message bytes total
move.b rFIFO(A3), rcvdMessage+1(A5) ; 2nd msg byte
move.b rFIFO(A3), rcvdMessage+2(A5) ; 3rd msg byte
bra.s @sqsDn
@sqs5to7
move.b #3, rcvdMessageLen(A5) ; 3 message bytes total
move.b rFIFO(A3), rcvdMessage+1(A5) ; 2nd msg byte
move.b rFIFO(A3), rcvdMessage+2(A5) ; 3rd msg byte
;; bra.s @getCommandBytes
;
; All remaining bytes in FIFO are the command bytes - get them
;
@getCommandBytes
moveq.l #mFIFOCount, D0
and.b rFIFOflags(A3), D0 ; how many bytes in FIFO
move.b D0, rcvdCommandLen(A5)
lea rcvdCommand(A5), A0
bra.s @cmdLpBtm
@cmdLpTop
move.b rFIFO(A3), (A0)+ ; move cmd byte into rcvdCommand
@cmdLpBtm dbra D0, @cmdLpTop
;
; At this point, we should have gotten everything out of the FIFO from the Select process
;
@sqsDn
moveq.l #mFIFOCount, D0
and.b rFIFOflags(A3), D0 ; how many bytes in FIFO
beq.s @callSIMisr
@forceDisconnect
RecCmd cDisconnect, 'R',$04
move.b #cDisconnect, rCMD(A3)
bra.w @doneWithInt
@callSIMisr
IF RECORD_ON THEN
pea 'Tgt-'
move.l rcvdIDBits(A5), -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
move.l HALc96GlobalRecord.SIMstaticPtr(A5), -(sp) ; push parameter (ptr to SIMglobals)
move.l ReconnectISRptr(A5), a0
jsr (a0)
addq.l #4, sp
IF RECORD_ON THEN
pea '-Tgt'
move.l rcvdCommandLen(A5), -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
@doneWithInt
move.l (sp)+, D1 ; get D1 back
moveq.l #1, D0 ; set return value - "interrupt handled"
rts
RTSNAME 'R_Selected'
QuickIntCheck
;
; Fastest possible way to check for an interrupt from a data xfer routine
; Note we don't clear the int at the VIA in this routine or block ints because
; we are assuming ints are blocked at the VIA!
;
; On Entry
; d0 -> Expected Int
;
; On Exit
; d0 -> return value
; d1 -> the int regs
;
; returns 1 if we got an int
; returns 0 otherwise
moveq #0, D1
move.l #8, D0 ; setup for dbra
@checkInt
move.b rSTA(A3), D1 ; D1 = x | x | x | rSTA
bmi @gotInt ; bra if we got an int
dbra d0, @checkInt ; loop until int or we exceed our threshold
bra.b @noIntYet
@gotInt
lsl.w #8, D1 ; D1 = x | x | rSTA | x
move.b rFIFOflags(A3), D1 ; D1 = x | x | rSTA | rFOS
lsl.l #8, D1 ; D1 = x | rSTA | rFOS | x
; next move.b clears rSQS, rSTA & rINT
move.b rINT(A3), D1 ; D1 = x | rSTA | rFOS | rINT
bne.s @3
IfDebugStr 'no c9x interrupt cause bits set'
moveq #dsIOCoreErr, D0
_SysError
@3
move.l #1, D0
rts
@noIntYet
move.l #0, D0
rts
RTSNAME 'QuickIntCheck'
FullIntRegs
IF RECORD_ON THEN
pea 'FITR'
move.l a3, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
ClearSCSIIRQ ; clear the VIA int source since we haven't
; been doing it in QuickIntCheck
pea @retrn ; return address
move.l D1, -(sp) ; setup stack correctly for doIntRegs
jmp ResumeIntRegs
@retrn bra.w GotSCSIInt ; and handle the int normally
rts
RTSNAME 'FullIntRegs'
;==========================================================================
; At this point, the return address (to the Deferred Task Manager) is the
; only thing on the stack. We first get our globals pointer then restore
; the stack to where it was when we deferred this thing. Then we just
; jmp to GetRegsBack and it restores all of our regs. When the task
; REALLY completes (and does the callback to Machine), it will simply do
; an RTS which will return back to the Deferred Task Manager.
;--------------------------------------------------------------------------
MyDT
IF STACK_RECORD_ON THEN
pea '>Prv'
move.l sp, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
move.l StkLowPt, publicStkLowPt(A5) ; remember old StkLowPt
clr.l StkLowPt ; and disable stack sniffer
move.l sp, publicSP(A5) ; suspend interrupt thread
IF DEBUGGING THEN
move.b #3, privStackState(A5)
ENDIF
move.l suspendedSP(A5), sp ; resume SCSI thread
IF STACK_RECORD_ON THEN
pea 'Prv>'
move.l sp, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
movem.l (sp)+, allOurRegs ; restore regs that we saved in Wt4SCSIInt
bra.w GotSCSIInt
RTSNAME 'MyDT'
;=======================================================================
;_______________________________________________________________________
; Install ISR
Install_ISR
move.l XPT_ISRptr(A5), A0 ; we need to install XPT's ISR (it calls ours)
TestFor VIA2Exists
bnz.b @via2SCSI
@gcSCSI cmp.b #GRAND_CENTRAL,intTypeSCSI(A5)
bne.b @xInstISR
lea 0, A1 ; interrupt handler reference constant in A1
moveq #0, D0
move.w intOSNumberSCSI(A5), D0
_GCRegisterHandler
rts
@via2SCSI moveq #0, D0
move.b intIRQbitNum(A5), D0
lea VIA2DT, A1
move.l A0, (A1,D0.W*4) ; called by an intr on the CB2 pin of VIA2
@xInstISR rts
NAME 'Install_ISR'
;_______________________________________________________________________
ClearVIASCSIIRQ
move.b HALc96GlobalRecord.clearIRQvalue(A5), ([HALc96GlobalRecord.intFlagSCSIAddr,A5])
rts
NAME 'ClearVIASCSIIRQ'
;_______________________________________________________________________
EnableVIASCSIIRQ
move.b HALc96GlobalRecord.enableIRQvalue(A5), ([HALc96GlobalRecord.intEnableSCSIAddr,A5])
rts
NAME 'EnableVIASCSIIRQ'
;_______________________________________________________________________
DisableVIASCSIIRQ
move.b HALc96GlobalRecord.disableIRQvalue(A5), ([HALc96GlobalRecord.intEnableSCSIAddr,A5])
rts
NAME 'DisableVIASCSIIRQ'
;_______________________________________________________________________
TestVIASCSIIE
move.b ([HALc96GlobalRecord.intEnableSCSIAddr,A5]), D0
and.b HALc96GlobalRecord.testIRQenableValue(A5), D0
rts
NAME 'TestVIASCSIIE'
;--------------------------------------------------------------------------
;
; Wt4DREQorInt - infinite loop to wait for a DREQ signal or SCSI chip intrp.
; called by DoSelect to determine end of Selection phase (DREQ if success, Int if not)
;
; Uses: d3, d5
;
; Entry:
; --> d1 = phase to wait for (concurrent with DREQ)
;
; Exit:
; <-- d5 = rFOS|rINT|0|rSTA, byte values from the Seq.Step, Status & INT regrs.
; <-- d0 = 1 if DREQ, 0 if Int
;
;-----------------
Wt4DREQorInt
@1
; Check for interrupt first (to avoid unnecessary dog-slow DREQ check)
bsr Ck4SCSIInt
bne.s @gotAnInt ;
; If no Interrupt, check for DREQ
bsr.s Ck4DREQ
beq.s @1 ; no: try again
@gotDREQ
moveq.l #1, d0 ; return value = Got DREQ
bra.s @exit
; Get sequence and FIFO status registers into D5 (already got rSTA)
@gotAnInt
moveq.l #0, d0 ; return value = Got Interrup
@exit
rts ;
NAME 'Wt4DREQorInt'
;_______________________________________________________________________
;
; Ck4DREQ
; This is slow test. If the value of DREQ
; needs to be determined in a transfer loop, use something else.
;
; Trashes:
; D0
;_______________________________________________________________________
;
Ck4DREQ
movem.l D0/D5/A0, -(sp)
tst.b dreqNeedsSwapMMU(A5)
bne.s @32bit
@24bit
move.l dreqAddr(A5), a0 ; dreqAddr contains DREQ regr address
move.b (a0), d5 ; read DAFB regr
bra.s @both
@32bit
bsr PCto32Bit ; use pc relative
moveq #true32B, d0 ; switch to 32-bit mode to look at SCSI config regr
bsr.s SwapMMU ; (sets up d0 with previous mode)
move.l dreqAddr(A5), a0 ; dreqAddr contains DREQ regr address
move.b (a0), d5 ; read DAFB regr
bsr.s SwapMMU ; return to previous mode (in d0)
@both
move.b intDREQbitNum(A5), d0
btst.l d0, d5 ; check for active SCSI DREQ
movem.l (sp)+, D0/D5/A0
rts
NAME 'Ck4DREQ'
;_______________________________________________________________________
;
; SwapMMU
; Swaps MMU into mode specified in D0. Returns previous
; MMUMode in D0.
;
; Registers : D0 affected as above. No others affected.
;
;_______________________________________________________________________
;
SwapMMU movem.l d1/a0, -(sp)
jsr ([jSwapMMU]) ; do it, call _SwapMMUMode jump vector(smashes d1/a0)
movem.l (sp)+, d1/a0
rts
NAME 'SwapMMU'
;_______________________________________________________________________
;
; void ReadInitiatorID( HALg/hwDesc)
;
; Registers : D0,
; A0 are used but not trashed
;
;_______________________________________________________________________
;
ReadInitiatorID
clr.b -(sp) ; make room for data
move.l sp, A0 ; address of PRAM return buffer
move.l #$00010002, D0 ; read 1 byte of PRAM at offset 2
_ReadXPRam ; get the SCSI id of the Mac
moveq.l #0, D0 ; clear D0
move.b (sp)+, D0 ; get PRAM value in low byte
and.b #$07, D0 ; strip away all but ID bits
move.l 4(sp), A0 ; only parm is HALg/hwDescPtr
move.b D0, initiatorID(A0) ; put InitID value into HALglobals
rts
NAME 'ReadInitiatorID'
;_______________________________________________________________________
;
; uchar GetInitiatorID( HALg) C function
;
; Registers : D0 returns ID.
;
;_______________________________________________________________________
;
GetInitiatorID
move.l 4(sp), A1 ; only parm is HALg/hwDescPtr
moveq.l #0, D0 ; clear D0
move.b initiatorID(A1), D0 ; return InitID value in low byte
rts
NAME 'GetInitiatorID'
;___________________________________________________________________________
;
; BusErrHandler
; When the SCSI Mgr is performing a blind data transfer, it patches
; out the bus error vector. The old SCSI Mgr bus error handler
; assumed that if it got called, it must be handling a SCSI bus error.
; Unfortunately, NuBus cards could bus error while the SCSI Mgr is
; installed. To be a better bus error citizen, the SCSI bus error
; handler now checks that the fault address is the SCSI chip, and if
; not, it chains to the bus error handler that it replaced.
;
; This code returns control to Transfer and not to the routine
; caused the bus error. It does this by popping off the buserr stack
; frame and then doing an RTS, so...
; DON'T PUT ANYTHING ON THE STACK IN TRANSFER ROUTINES (FastRead,
; Fast<73>, etc.). At least don't leave it there during periods where a
; buserr may be possible.
;
; On the off chance that we get a bus error while in the emulator we need
; to handle 030 style bus error frames as well as 040 style. This implies
; not doing write backs among other things. Since the info might not always
; be accurate in an emulated BERR we might consider never trying to resume
; an instruction but rather always try to RTE out to somewhere else just like
; a phase change.
;
___________________________________________________________________________;
WITH AEXFrame,SCSIGlobalsRec
longBEXFrameType EQU $0A ; long bus cycle fault stack frame (020/030) !!! put in 680x0.a!
faultedAdrs EQU $10 ; offset of Faulted Address for 030
savedRegs REG D0-D2/D5/A0-A1/A5 ; save these registers because we need to use them
savedRSize EQU 7*4 ; # bytes on stack for saved registers
BusErrHandler96
; Is it our fault? -----
subq.l #4, sp ; make room for return addr (@notSCSIFault)
movem.l savedRegs, -(sp)
lea savedRSize+4(sp), A0 ; make A0 our AEXFrame pointer (regs+1 LW on stack)
; XPT should install its BusErrHandler and pass a ptr to the AEXFrame and the SIMg down into
; the SIM for every one of the SIMs that have registered a BEH. The SIM must then pass the
; HALg down here. (But we'll cheat for now since only our buses will need this BEH).
move.l SCSIGlobals, A1
cmp.l berr_halg0(A1),A5 ; are we talking to our bus 0?
bne.s @ckBus1
move.l pdmaNonSerlzdAddr(A5),d0 ; get the pseudo DMA Address
bfextu FrameType(a0){0:4},d1 ; get format code from stack
cmp.b #AEXFrameType,d1 ; 040 exception frame?
beq.b @do040 ;
cmp.l faultedAdrs(a0),d0 ; compare with faulted address
beq.s @SCSIFault ; if so, start processing the bus error
@do040
cmp.l FaultAddr(A0),d0 ; compare with faulted address
beq.s @SCSIFault ; if so, start processing the bus error
@ckBus1
cmp.l berr_halg1(A1),A5 ; are we talking to our bus 1?
bne.s @notSCSIFault
move.l pdmaNonSerlzdAddr(A5),d0 ; get the pseudo DMA Address
bfextu FrameType(a0){0:4},d1 ; get format code from stack
cmp.b #AEXFrameType,d1 ; 040 exception frame?
beq.b @do040_again ;
cmp.l faultedAdrs(a0),d0 ; compare with faulted address
beq.s @SCSIFault ; if so, start processing the bus error
@do040_again
cmp.l FaultAddr(A0),d0 ; compare with faulted address
beq.s @SCSIFault ; if so, start processing the bus error
; It's not our fault ------
@notSCSIFault
move.l yeOldeBusErrVct(A1), savedRSize(sp) ; stuff old Bus Error vector
movem.l (sp)+, savedRegs ; restore regs
rts ; jump to old handler, assuming it'll RTE
NAME 'BusErrHandlerTOP'
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
; It's all our fault (blame it on us) ------
@SCSIFault
move.w sr, savedSR(a5) ; save sr
ori.w #$0700, sr ; \/ \/ \/ Block Ints \/ \/ \/
; Wait for either DREQ or INT
IF RECORD_ON THEN
pea 'Berr' ;
move.l xPC(a0),-(sp) ;
bsr RecordEvent
addq.l #8, sp
ENDIF
move.l HALactionPB.ioPtr(A4),a1 ; get the IOPB
move.l scsiFlags(A1), D0
and.l #scsiDirectionMask, D0 ; are we data in or out?
cmp.l #scsiDirectionIn, D0 ; We may not want to do writebacks if we are
; writing.
bne.b @notDataIn
@DataIn ;****************************************
; clean up the writebacks on the stack frame
bfextu FrameType(a0){0:4},d1 ; get format code from stack
cmp.b #AEXFrameType,d1 ; 040 exception frame?
bne.b @wtloop ; nope, don't do writebacks...
move.w WB1S(A0), d0 ; check WB1 for validity
move.l WB1A(A0), A1 ; pass WB Address
move.l WB1D(A0), d1 ; pass WB Data
bsr.w DoWriteBack ; to routine that takes care of it
move.w WB2S(A0), d0 ; check WB2 for validity
move.l WB2A(A0), A1 ; pass WB Address
move.l WB2D(A0), d1 ; pass WB Data
bsr.w DoWriteBack ; to routine that takes care of it
move.w WB3S(A0), d0 ; check WB3 for validity
move.l WB3A(A0), A1 ; pass WB Address
move.l WB3D(A0), d1 ; pass WB Data
bsr.w DoWriteBack ; to routine that takes care of it
@wtloop
movem.l D1-D2/A0, -(sp)
bsr Ck4DREQ ;
movem.l (sp)+, D1-D2/A0
bne.w @doRTE
movem.l D1-D2/A0, -(sp)
bsr Ck4SCSIInt ; see if we have a phase change or something
movem.l (sp)+, D1-D2/A0
bne.w @phzChange ;
bra.b @wtloop
@notDataIn ;****************************************
cmp.l #scsiDirectionOut, D0
bne.s @noDataXfer
@1
movem.l D1-D2/A0, -(sp)
bsr Ck4DREQ ;
movem.l (sp)+, D1-D2/A0
bne.s @doWBacks
movem.l D1-D2/A0, -(sp)
bsr Ck4SCSIInt ; see if we have a phase change or something
movem.l (sp)+, D1-D2/A0
bne.w @phzChange ;
bra.b @1
@doWBacks
bfextu FrameType(a0){0:4},d1 ; get format code from stack
cmp.b #AEXFrameType,d1 ; 040 exception frame?
bne.b @doRTE ; nope, don't do writebacks...
; clean up the writebacks on the stack frame
move.w WB1S(A0), d0 ; check WB1 for validity
move.l WB1A(A0), A1 ; pass WB Address
move.l WB1D(A0), d1 ; pass WB Data
bsr.w DoWriteBack ; to routine that takes care of it
@2
movem.l D1-D2/A0, -(sp)
bsr Ck4DREQ ;
movem.l (sp)+, D1-D2/A0
beq.s @2
move.w WB2S(A0), d0 ; check WB2 for validity
move.l WB2A(A0), A1 ; pass WB Address
move.l WB2D(A0), d1 ; pass WB Data
bsr.w DoWriteBack ; to routine that takes care of it
@3
movem.l D1-D2/A0, -(sp)
bsr Ck4DREQ ;
movem.l (sp)+, D1-D2/A0
beq.s @3
move.w WB3S(A0), d0 ; check WB3 for validity
move.l WB3A(A0), A1 ; pass WB Address
move.l WB3D(A0), d1 ; pass WB Data
bsr.w DoWriteBack ; to routine that takes care of it
bra.b @doRTE ; rte and retry the instruction
@noDataXfer ;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
IfDebugStr 'In BEH but not Xfer Direction'
;
; if DREQ, retry the transfer -----
@doRTE
IF RECORD_ON THEN
pea 'Ber<' ;
move.l d4,-(sp) ;
bsr RecordEvent
addq.l #8, sp
ENDIF
move.w savedSR(a5),sr ; /\ /\ /\ Un Block Ints /\ /\ /\
movem.l (sp)+, savedRegs ; restore regs
addq.l #4, sp
rte ; restart
NAME 'BusErrHandlerMID'
; if phase change or timeout, cleanup and abort the transfer -----
; The could happen from a disconnect. We need to calculate the residual length and
; jump back to the Xfer routine and let it figure it out
@phzChange
movem.l (sp)+, savedRegs ; restore regs
addq.l #4, sp ; take scratch space off stack
; get any leftover bytes out of the FIFO if we were doing a FastRead
move.l HALactionPB.ioPtr(A4),a1 ; get the IOPB
move.l scsiFlags(A1), D0
and.l #scsiDirectionMask, D0 ; are we data in or out?
cmp.l #scsiDirectionIn, D0 ; we don't want to grab extra bytes from
; the fifo if we are writing.
bne.b @skipLeftovers
move.b rFIFOflags(A3), d0 ; get FIFO status - how many bytes in FIFO
and.w #mFIFOCount, d0 ;
ror.l #1, d0
bra.s @btm0
@top0
move.w rDMA(A3), (A2)+ ; get word from chip and put into user's buffer
@btm0
dbra d0, @top0
tst.l d0
bpl.s @4
move.b rFIFO(A3), (A2)+ ; get byte from chip and put into user's buffer
@4
; get rid of excp'n frame and create a throwaway frame for return to Transfer
@skipLeftovers
move.w xSR(sp), d0 ; save SR for new exception frame
bfextu FrameType(sp){0:4}, d1 ; get format code from stack
cmp.b #AEXFrameType, d1 ; check for 040 Access Error Exception Frame
beq.s @Drop040XFrame ; dispose of 040 AE exception frame
cmp.b #shortBEXFrameType, d1 ; short 020/030 exception frame?
bne.s @Drop46w ; no, so use larger frame
adda.w #shortBEXFrameSize, sp ; dispose of the 16-word frame
bra.s @DummyFrame ; and finish up
@Drop040XFrame ; 040 Bus Error frame-cleaning done here
add.w #aeXFrameSize, sp ; remove 040 Access Error Exception Frame
bra.s @DummyFrame ; and create dummy return frame
@Drop46w
add.w #46*2, sp ; size of exception frame
@DummyFrame
; Fake a format code 0 exception frame (4 words) to finish cleaning up
IF RECORD_ON THEN
pea 'Ber$' ;
move.l d4,-(sp) ;
bsr RecordEvent
addq.l #8, sp
ENDIF
move.w savedSR(a5),sr ; /\ /\ /\ Un Block Ints /\ /\ /\
clr.w -(sp) ; format code 0
pea FinishErr ; PC value
move.w d0, -(sp) ; sr value
rte ; 'return' from the fake exception
NAME 'BusErrHandlerBOTTOM'
;-----------------
FinishErr
;-----------------
swap d6 ; d6 contains the number of 64k xfers
move.w #0, D6 ; we only care about the high word
moveq #0,d0
move.b rXCM(A3),d0 ; TC regr (most-sig. byte)
lsl.l #8, d0 ; shift to get lower byte from the c96
move.b rXCL(A3),d0 ; TC regr (least-sig. byte) <- d4.b
add.l d0,d6 ; and get the total number of bytes left
move.l d6,d1 ; return the number of bytes xferred
move.l HALactionPB.ioPtr(A4),a1 ; get the IOPB
move.l scsiFlags(A1), D0
and.l #scsiDirectionMask, D0 ; are we data in or out?
cmp.l #scsiDirectionIn, D0 ; We don't need to check the FIFO if we
; are reading.
beq.b @ErrorDone
moveq.l #mFIFOCount, D0
and.b rFIFOflags(A3), D0 ; how many bytes in FIFO
move.b #cFlushFIFO, rCMD(A3) ; we should flush them out of there
add.l D0,D1 ; we didn't transfer these bytes
sub.l D0,A2 ; adjust the buffer ptr as well
@ErrorDone
moveq.l #scPhaseErr, d0 ; return premature phase change
bsr.w RemoveBEH96
IF RECORD_ON THEN
pea 'Ber!' ;
move.l d1,-(sp) ;
bsr RecordEvent
addq.l #8, sp
ENDIF
rts ; return status in d0 to the Transfer routine
NAME 'FinishBusErr'
;-----------------
DoWriteBack
;-----------------
btst #bValid, d0 ; if this writeback valid?
beq.s @wbDone ; no - done
and.w #SIZE_MSK, d0 ; yes, transfer proper size
cmp.w #WB_BYTE, d0
bne.s @1
move.B d1, (a1) ; move Byte
bra.s @wbDone
@1
cmp.w #WB_WORD, d0
bne.s @2
move.W d1, (a1) ; move Word
bra.s @wbDone
@2
cmp.w #WB_LONG, d0
bne.s @wbDone
move.L d1, (a1) ; move LongWord
@wbDone
rts
ENDWITH
NAME 'DoWriteBack'
InstallBEH96
WITH SCSIGlobalsRec
movem.l D0/A0-A1, -(sp)
move.l SCSIGlobals, A1
move.b numBEHs(A1), D0 ; how many installed?
bne.s @inc ; at least one? -> don't install any more
move.l BusErrVct, yeOldeBusErrVct(A1) ; save previous Bus Error vector
lea BusErrHandler96, A0 ; get address of our BEH
move.l A0, BusErrVct ; put ours in there
@inc add.b #1, D0
move.b D0, numBEHs(A1)
movem.l (sp)+, D0/A0-A1
rts
NAME 'InstallBEH96'
RemoveBEH96
movem.l D0/A0-A1, -(sp)
move.l SCSIGlobals, A1
sub.b #1, numBEHs(A1)
blt.s @aackBEH
bne.s @dontRemove
lea BusErrHandler96, A0 ; get address of our BEH
cmp.l BusErrVct, A0 ; is current one ours?
bne.s @dontRemove ; if not, -> don't remove it
move.l yeOldeBusErrVct(A1), BusErrVct ; restore previous Bus Error vector
@dontRemove
movem.l (sp)+, D0/A0-A1
rts
@aackBEH
_debugger ; AACK! we went negative
RTSNAME 'RemoveBEH96'
;==========================================================================
ENDWITH
ENDWITH
END