; ; File: SCSIMgrHW96.a ; ; Contains: SCSI Manager 53C96 Hardware-Specific routines ; ; Written by: Far Too Many People ; ; Copyright: © 1990-1993 by Apple Computer, Inc. All rights reserved. ; ; Change History (most recent first): ; ; 8/12/93 KW conditionalizing smurf branches ; 8/11/93 KW added some branches based on new smurf boxes ; 5/5/93 PW Enabling FastRead and FastWrite for EVT2 PDMs. ; 2/5/93 CSS Horror rollin. Export some entry points for the BIOS ROM SCSI ;
9/6/92 jab Exported some entry points for the BIOS ROM SCSI Mgr to use. ; mgr. ; 1/26/93 SAM Added various NOPs after the xferCount reg gets loaded before a ; xferInfo cmd is sent for NonSerializedIO machines. Added not ; forROM conditionals around all 24-bit/swapmmu code in here just ; for grins. Crippled all fast read/write routins for PDM only to ; not be fast (ie to use the slow FIFO xfer routines till Jimmy ; fixes his shit.) ; 12/23/92 RC Added Support for Smurf on Wombat ; 12/11/92 SAM Removed PDM bring-up hacks. ; 12/3/92 fau Changed the use of DAFBExists to check for the ; Spike/Eclipse/Zydeco/RiscQuadra box flag. Those registers on ; DAFB are only needed on those machines. ; 11/3/92 SWC Changed SCSIEqu.a->SCSI.a. ; 10/18/92 CCH Added nop's to support non-serial IO space, conditionals to use ; byte accesses to the DREQ register, and a hack to bypass ; pseudo-DMA on PDM for now. ; 8/9/92 CCH Modified boxflag check for Spike to include boxRiscQuadra. ; <5> 5/22/92 DTY #1029009 : Modified DREQ bit testing from global (setup in ; SCSIInit96) and rearranged writebacks to conform with Moto spec. ; <4> 5/1/92 JSM Don’t use isUniversal conditional, which was commented out ; anyway. Don’t use internal GEEZ conditional, which was always ; false. Use Max020030BusErrs instead of MaxBusErr, which is ; equated differently in SCSIPriv.a depending on how CPU was ; defined. For System builds, CPU is set to 00, which gave us the ; wrong value since this file is only used on 020's and above. ; <3> 3/17/92 pvh #1021847: ; Fix the removable device bug (CD ROMs etc.) on Quadras which ; caused the “This disk is unreadable. Do you want to format?” ; dialog to randomly appear. Apparently there is a bug in the ; 53C96 chip which causes the FIFO count to get stuck on occasion. ; We now flush the FIFO buffer to make sure the count is correct. ; <2> 12/2/91 SAM Using official boxflag equates now. ; <1> 10/24/91 SAM Rolled in Regatta file. ; ; Regatta Change History: ; ; <4> 9/4/91 SAM (PDW) Fixed polled write PhaseErr bug by using status register ; for phase test instead of bogus D5 register. ; <3> 8/21/91 SAM (PDW) Removed bunch of debugging stuff. Removed "fix" for VM_On ; BEH problem since "real" fix is now in dataCommon_96 ; (SCSIMgr96.a). ; <2> 8/19/91 SAM (PDW) Reverted to old in/out buserr handler support. Fixed ; incorrect loop counting in BusErrHandler (wasn't taking zero ; case into account). Increased quanta of DREQ timeout value ; in BEH (twice as long). Changed Transfer so that we don't modify ; yeOldeBusErrVct if vector at 8 is already our SCSI bus error ; handler. This fixes "symptom" of VM_On/BEHandler Vector bug. ; <1> 8/8/91 SAM (PDW) Checked into Regatta for the first time with lots of ; changes over the TERROR sources. ; <0> 8/8/91 SAM Split off from TERROR sources. ; ; Terror Change History: ; ; 7/8/91 djw (pdw) Fixed bug in FastRead_96 and FastComp_96 where any odd ; count over 256 bytes would fail (cmp.b should be a cmp.l). ; 6/27/91 BG (actually PDW/CCH/BG) changed the dynamic register setup stuff ; in InitSCSI96HW so that the ProductInfo record is where the ; information for the BoxFlag check comes from. ; 6/27/91 djw (actually PDW) Changes for better handling of select sequence ; across phases and across traps. Added NOPs at top and bottom of ; non-serialized accesses to squish pipeline (to avoid problems at ; higher CPU speeds. Fixed SlowRead hang (when phase changes ; before transfer is complete (scInc or scNoInc). Fixed FastRead ; residual byte problem (where we didn't detect the missing REQ) ; by checking the FIFO count before doing the rFFO. Also removed ; all traces of SCSIBusy and FreeHook stuff. Made BusErrHandler ; able to deal with no valid registers. (JMA) Added BusErrHandler ; routine. ; 6/14/91 djw (actually PDW) Created working Transfer_96 routine that sends ; ptr to non-serialized chip image to data routines. Also modified ; all data routines to use this for all rDMA register accesses. ; Put FCIntPend clear in WaitForSCSIIntrp (w & w/o timeout) so ; that every time the interrupt bit in the chip was cleared, this ; select_in_progress flag is cleared also. ; 6/9/91 BG (BG) InitHW_SCSI96: Reworked the routine to handle dynamic ; initialization of DAFB/Turbo SCSI register based on CPU clock ; speed. Modified check for SCSI clk speed initialization for ; Eclipse and Spike to (1) be based on D2 instead of BoxFlag, ; since BoxFlag has not been initialized yet when this routine is ; called, and (2) added dynamic initialization of 16/25MHz SCSI ; clk speed based on CPU clk speed. (PDW) Changed throwaway reg ; at end. Rearranged headers to work more consistently between ; test INIT and ROM builds. ; 3/30/91 BG (actually JMA) Rolled in faster SlowRead_96 and SlowComp_96 ; routines. ; 2/17/91 BG (actually JMA) Added SlowComp_96, FastComp_96 & Error calls. ; 1/11/91 BG Added fix to correctly reset SCSI 96 bus. ; 1/5/91 BG (actually JMA) Added functionalites. ; 12/7/90 JMA Checked into TERROR for the first time ; ;========================================================================== MACHINE MC68020 BLANKS ON STRING ASIS PRINT OFF LOAD 'StandardEqu.d' ; Load em if you got em... INCLUDE 'HardwarePrivateEqu.a' INCLUDE 'UniversalEqu.a' INCLUDE 'SCSI.a' INCLUDE 'SCSIPriv.a' INCLUDE 'SCSIEqu96.a' INCLUDE 'MC680x0.a' PRINT ON SCSIHW96 PROC EXPORT EXPORT SlowRead_96, Transfer_96, Xfer1Byte EXPORT Wt4DREQorInt, HandleSelInProg, WaitForIntNoTime EXPORT ResetBus_96, WaitForSCSIIntrp EXPORT BusErrHandler_96 ; EXPORT InitHW_SCSI96, IntHnd_SCSI96 EXPORT SlowWrite_96, SlowComp_96 ; EXPORT FastRead_96, FastWrite_96, FastComp_96 ; EXPORT OneByteWrite, OneByteRead, WtForFIFOData ;
CSS IMPORT ClearSCSIInt ; from InterruptHandlers.a IMPORT SCSIpcTo32bit, Error, SwapMMU ; from SCSIMgr96.a WITH scsiPB, scsiPrivPB WITH scsiGlobalRecord, dcInstr ;-------------------------------------------------------------------------- ; ; InitHW_SCSI96 - reset and initialize the 53C96 SCSI controller ; This routine resets all functions in the chip and returns ; it to a disconnected state. ; ; INPUTS ; a3 -> pointer to SCSI port base address ; a4 -> pointer to SCSI DAFB register ; (NOTE - this routine assumes that we are in 32-bit mode!) ; d2 -> 16/HWCfgFlags, 8/BoxFlag, 8/MemDecoder ; (the lowMem BoxFlag is not yet defined!) ; ; OUTPUTS ; d0 <- rINT(a3) ; ; trashes: d0, d1, a0 InitHW_SCSI96 move.b #cRstSChp, rCMD(a3) ; Reset the Chip (not the bus) if nonSerializedIO Then nop ; Force write to complete. endif move.b #cNOP, rCMD(a3) ; C96 NOP required after HW or SW reset move.b #cFlshFFO, rCMD(a3) ; Flush FIFO if nonSerializedIO Then nop ; Force write to complete. endif move.b #initCF1, rCF1(a3) ; load init config. value which affects: ; busID, SCSI reset reporting & parity checking move.b #initCF2, rCF2(a3) ; load init config. value move.b #initCF3, rCF3(a3) ; load init config. value if nonSerializedIO Then nop ; Force write to complete. endif ; Check whether or not we're 25 or 33MHz and set SCSI bus speed values appropriately thru next TestFor VIA2Exists ; see if we should check 25/33MHz VIA2 bit beq @dontChk ; if there's not a VIA2, don't do it. ; Change to check for BoxFlags for Spike/Eclipse/Zydeco, instead of DAFBExists, since this ; special stuff only applies to those 3 machines. move.l UnivInfoPtr,A0 ; get pointer to universal table cmp.b #BoxQuadra700,ProductInfo.ProductKind(A0) ; check for a Spike beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco cmp.b #BoxQuadra900,ProductInfo.ProductKind(A0) ; check for a Eclipse beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco cmp.b #BoxQuadra950,ProductInfo.ProductKind(A0) ; check for a Zydeco beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco IF forSmurf THEN cmp.b #boxRiscQuadra700,ProductInfo.ProductKind(A0) ; check for a RISC Spike beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco cmp.b #boxRiscQuadra900,ProductInfo.ProductKind(A0) ; check for a RISC Quadra900 beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco cmp.b #boxRiscQuadra950,ProductInfo.ProductKind(A0) ; check for a RISC Quadra950 beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco cmp.b #boxRiscCentris610,ProductInfo.ProductKind(A0) ; check for a RISC Centris610 beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco cmp.b #boxRiscCentris650,ProductInfo.ProductKind(A0) ; check for a RISC Centris650 beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco cmp.b #boxRiscQuadra800,ProductInfo.ProductKind(A0) ; check for a RISC Quadra800 beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco cmp.b #boxRiscQuadra610,ProductInfo.ProductKind(A0) ; check for a RISC Quadra610 beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco cmp.b #boxRiscQuadra650,ProductInfo.ProductKind(A0) ; check for a RISC Quadra650 beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco ENDIF ; for Smurf bra.s @dontChk ; only Spike/Eclipse have a VIA2 and DAFB @DoSpikeEclipseZydeco ; move.l VIA2,a0 ; and get VIA2 so that we can check the speed bit move.b vBufB(a0),d0 ; read PBx values for 25/33MHz checks btst #v2Speed,d0 ; are we 25 MHz or 33 Mhz? beq.s @25MHz ; IF Speed == 33MHz THEN move.l #tsc_cf_stg_33,(a4) ; setup DAFB SCSI config register. ; ... must move 32 bits to DAFB bra.s @0 ; ELSE // Speed == 25MHz @25MHz move.l #tsc_cf_stg_25,(a4) ; setup DAFB SCSI config register. ; ... must move 32 bits to DAFB @0 ; ENDIF ;******* TEMPORARY KLUDGE TO SUPPORT a 16/25Mhz Eclipse SCSI96 and ***** ;******* 25Mhz Spike SCSI96 ***** ; ; ASSUMPTION: If you are executing this code, you are either a Spike or Eclipse. ; ; ASSUMPTION: If you are a Spike, then you ALWAYS are a 25 MHz SCSI clock. ; If you are an Eclipse: ; If you have a 25 MHz CPUClk, you have a 15.6672 MHz SCSI clk ; If you have a 33 MHz CPUClk, you have a 24.28416 MHz SCSI clk move.l UnivInfoPtr,A0 ; get pointer to universal table cmp.b #boxQuadra700,ProductInfo.ProductKind(A0) ; check for a Spike <2> beq.s @ForSpike ; (note - BoxFlag is not defined yet!) IF forSmurf THEN cmp.b #boxRiscQuadra700,ProductInfo.ProductKind(A0) ; check for a RISC Quadra700 beq.s @ForSpike ; (note - BoxFlag is not defined yet!) cmp.b #boxRiscCentris610,ProductInfo.ProductKind(A0) ; check for a RISC Centris610 beq.s @ForSpike ; (note - BoxFlag is not defined yet!) cmp.b #boxRiscCentris650,ProductInfo.ProductKind(A0) ; check for a RISC Centris650 beq.s @ForSpike ; (note - BoxFlag is not defined yet!) cmp.b #boxRiscQuadra800,ProductInfo.ProductKind(A0) ; check for a RISC Quadra800 beq.s @ForSpike ; (note - BoxFlag is not defined yet!) cmp.b #boxRiscQuadra610,ProductInfo.ProductKind(A0) ; check for a RISC Quadra610 beq.s @ForSpike ; cmp.b #boxRiscQuadra650,ProductInfo.ProductKind(A0) ; check for a RISC Quadra650 beq.s @ForSpike ; ENDIF ; for Smurf ; Check for difference between 25 and 33MHz Eclipse machines: btst #v2Speed,d0 ; are we running at 25 or 33 MHZ? bne.s @33MHz ; IF Speed == 25MHz THEN move.b #ccf15to20MHz, rCKF(a3) ; load clock conversion factor (CCF) value move.b #SelTO16Mhz, rSTO(a3) ; load select/reselect timeout value bra.s @1 ; @33MHz ; ELSE // Speed == 33MHz * fall thru to @ForSpike * ; move.b #ccf20to25MHz, rCKF(a3) ; load clock conversion factor (CCF) value ; move.b #SelTO25Mhz, rSTO(a3) ; load select/reselect timeout value ; bra.s @1 ; ENDIF // Speed @ForSpike * fall thru to @dontChk. *clkCnvVal* == *ccf20to25MHz*; *SelTO25Mhz* == *slcTimeout* ; move.b #ccf20to25MHz, rCKF(a3) ; load clock conversion factor (CCF) value ; move.b #SelTO25Mhz, rSTO(a3) ; load select/reselect timeout value ; bra.s @1 ;********** TEMPORARY - DELETE WHEN SCSI CLOCK IS FINALIZED ;********** /// END of KLUDGE /// ;**** The 2 lines below are the correct code and UN-comment them. ; Delete the kludge section above when scsi clock is finalized @dontChk move.b #ccf20to25MHz, rCKF(a3) ; load clock conversion factor (CCF) value move.b #SelTO25Mhz, rSTO(a3) ; load select/reselect timeout value @1 IF forPDMDebug THEN ; SAM (someone shouyld fix that shit above!) move.b #ccf15to20MHz, rCKF(a3) ; load clock conversion factor (CCF) value move.b #SelTO16Mhz, rSTO(a3) ; load select/reselect timeout value nop ENDIF move.b #initOp, rSYO(a3) ; select syn or async operation; if sync then ; sync offset value must be nonzero ; Set synch xfer period and offset if using ; synch data xfer @4 if nonSerializedIO Then nop ; Force write to complete. endif move.b rINT(a3), d0 ; read & clear rFOS, rSTA & rINT into throwaway rts ;-------------------------------------------------------------------------- ; ; IntHnd_SCSI96 - This is the SCSI96 interrupt handler ; Called by: Macintosh Interrupt Dispatcher ; ; Regrs saved: a0-a5/d0-d7 ; IntHnd_SCSI96 movem.l intrRegs, -(sp) ; save registers movea.l SCSIGlobals, a4 ; get ptr to structure clr.l d5 ; addq.l #1, G_IntrpCount(a4) ; count intrps - FOR Debug move.l base539x0(a4), a3 ; load ptr for SBus0 btst.b #bINT, rSTA(a3) ; test intrp bit of status regr bne.s @gotSCSIInt ; bra. if we got SCSI intrp @chkNext move.l base539x1(a4), a3 ; load ptr for SBus1 btst.b #bINT, rSTA(a3) ; test intrp bit of status regr beq.s @ExitSCSIIntrp @gotSCSIInt ; ; addq.l #1, G_base5396(a4) ; incr. valid SCSI intrp counter, for debug move.b rSTA(a3), d5 ; read Status regr swap d5 ; move.b rFOS(a3), d5 ; read FIFO flag/Sequence Step regr lsl.w #8, d5 ; shift left by 1 byte move.b rINT(a3), d5 ; read & clear rFOS, rSTA & rINT swap d5 ; d5 = rFOS|rINT|0|rSTA move.l d5, G_IntrpStat(a4) ; save regr values, for debug @ExitSCSIIntrp movem.l (sp)+, intrRegs ; restore registers rts ; ;-------------------------------------------------------------------------- ; Transfer_96 - thru next ; ; Called by: dataCommon_96 ; (NewSCSIWBlind_96, NewSCSIWrite_96, NewSCSIRBlind_96, NewSCSIRead_96) ; ; Calls: The primitive data transfer routines ; ; Registers: d0 <-- error, if any ; d1 <-- bytes transferred ; d2 --> number of bytes to transfer ; d4 --> type of transfer to perform (offset into "dataTable") ; ; a2 --> ptr to data buffer ; a3 --> SCSI chip read base address - SERIALIZED ; a4 --> ptr to SCSI Mgr globals ; ; Function: Sets up and dispatches to the simple data-transfer routines ; ; All primitive data transfer routines called by this routine assume: ; ; d0 - <-- error (if any) ; d1 - <-- bytes transferred ; d2 - --> number of bytes to transfer ; d3 - scratch - saved ; d4 - --> type of transfer to perform ; d5 - scratch - saved ; d6 - scratch - saved ; ; a0 - scratch - saved ; a1 - SCSI chip read base address - NON-SERIALIZED ; a2 - ptr to data buffer - saved ; a3 - SCSI chip read base address - SERIALIZED ; a4 - ptr to SCSI Mgr globals ; a5 - scratch - saved ; ; ; Stack frame definitions (frame allocated in StdEntry) ; XferFrame RECORD {LINK},DECR returnAddr ds.l 1 ; return address ; no parameters LINK ds.l 1 ; location of old A6 (after LINK A6) ; local variables (set up and checked in BusErrHandler) BusErrTO ds.l 1 ; when to stop retrying bus errs BusErrAddr ds.l 1 ; user's data address when bus err happens linkSize EQU * ENDR WITH XferFrame Transfer_96: link a6, #linkSize ; allocate local storage move.l #0, BusErrAddr(a6) ; init so first bus err is seen as a new one moveq.l #noErr, d0 ; assume no error move.l d2, d1 ; make a copy of the count - is it zero ? beq.w @exit ; if so, get out movem.l a1-a5/d2-d6, -(sp) ; save registers movea.l a3,a1 ; point to serialized chip image IF NOT forPDMDebug THEN adda.l #nonSerlzdDisp,a1 ; point to non-serialized chip image ENDIF bsr HandleSelInProg ; handle unfinished select command bne.w @phaseErr ; if it is stuck, we are not in data phase move.b #cFlshFFO, rCMD(a3) ; Flush FIFO if nonSerializedIO Then nop ; Force write to complete. endif ; move.l BusErrVct, D0 ; compare old vector (at 8) <2> <3>removed ; cmp.l jvBusErr(a4), D0 ; with my vector <2> <3> ; beq.s @1 ; if same, skip the install process <2> <3> move.l BusErrVct,yeOldeBusErrVct(a4) ; keep old vector in low-mem move.l jvBusErr(a4), BusErrVct ; install our BE Handler @1 bset.b #HandleBusErrs, G_State96(a4) ; signal our bus err handler to be operative move.w d4, transferType(a4) ; store the type of transfer (only word is worth anything) lea.l dataTable(a4), a0 ; point to data transfer table in globals movea.l 0(a0,d4.l), a0 ; get the routine address jsr (a0) ; go to the appropriate routine @done bclr.b #HandleBusErrs, G_State96(a4) ; signal our bus err handler to be unoperative move.l yeOldeBusErrVct(a4),BusErrVct ; restore previous Bus Error vector <2> movem.l (sp)+, a1-a5/d2-d6 ; restore these guys tst.w d0 ; set the condition codes @exit unlk a6 ; release local storage rts ; from last @phaseErr moveq.l #scPhaseErr, d0 ; return a phase error moveq.l #0, d1 ; number of bytes transferred bra.s @done ; ENDWITH ;-------------------------------------------------------------------------- ; OneByteRead/OneByteWrite - proc to transfer 1 byte ; ; d0 - <-- error (if any) ; d1 - --> copy of d2 ; d1 - <-- bytes transferred ; d2 - --> number of bytes to transfer ; d3 - scratch - saved ; d4 - --> type of transfer to perform ; d5 - scratch - saved ; d6 - scratch - saved ; ; a0 - scratch - saved ; a1 - SCSI chip read base address - NON-SERIALIZED ; a2 - ptr to data buffer - saved ; a3 - SCSI chip read base address - SERIALIZED ; a4 - ptr to SCSI Mgr globals ; a5 - scratch - saved OneByteRead ; thru next move.b #cIOXfer, rCMD(a3) ; load IO transfer cmd & begin xfers if nonSerializedIO Then nop ; Force write to complete. endif jsr.w WaitForIntNoTime ; Wait for intrp w/o timeout ; on exit d5 = rFOS|rINT|0|rSTA bne.s xferErr ; bra. on xfer error move.b rFFO(a3), (a2)+ ; xfer byte from FIFO into input buffer thru next move.b rINT(a3), d3 ; read Intrp regr & clear rSTA, rSQS & rINT btst.l #bDSC, d3 ; check for disconnected intrp bne.s xferErr ; bra. on xfer error moveq.l #noErr, d0 ; successful read op rts OneByteWrite move.b (a2)+, rFFO(a3) ; preload the FIFO if nonSerializedIO Then nop ; Force write to complete. endif move.b #cIOXfer, rCMD(a3) ; load IO transfer cmd & begin xfers if nonSerializedIO Then nop ; Force write to complete. endif jsr.w WaitForIntNoTime ; Wait for intrp w/o timeout ; on exit d5 = rFOS|rINT|0|rSTA bne.s xferErr ; bra. on xfer error moveq.l #noErr, d0 ; successful write op rts xferErr move.l #$F0, d6 ; load proc ID, generic transfer thru next moveq.l #scCommErr, d0 ; transfer error bra.s errExit phaseErr1 move.l #$F0, d6 ; load proc ID, generic trnasfer moveq.l #scPhaseErr, d0 ; return a phase error errExit jsr Error ; call Error proc - for debug clr.l d1 ; no bytes transferred move.b #cFlshFFO, rCMD(a3) ; Flush FIFO if nonSerializedIO Then nop ; Force write to complete. endif rts ; ;-------------------------------------------------------------------------- ; Xfer1Byte - proc to transfer 1 byte of data ; ; Branched to by SlowRead/SlowWrite(Polled) & FastRead/SlowWrite(Blind). It returns directly ; Transfer proc which call either SlowRead or FastRead. ; ; d0 - <-- error (if any) ; d1 - --> copy of d2 ; d1 - <-- bytes transferred ; d2 - --> number of bytes to transfer ; d3 - scratch - saved ; d4 - --> type of transfer to perform ; d5 - scratch - saved ; d6 - scratch - saved ; ; a0 - scratch - saved ; a1 - SCSI chip read base address - NON-SERIALIZED ; a2 - ptr to data buffer - saved ; a3 - SCSI chip read base address - SERIALIZED ; a4 - ptr to SCSI Mgr globals ; a5 - scratch - saved Xfer1Byte move.b #cIOXfer, rCMD(a3) ; load IO transfer cmd & begin xfers if nonSerializedIO Then nop ; Force write to complete. endif jsr.w WaitForIntNoTime ; Wait for intrp w/o timeout ; on exit d5 = rFOS|rINT|0|rSTA rts ; IF z=1 then good xfer... ;-------------------------------------------------------------------------- ; SlowRead - implements Polled Read ; ; Called by: Transfer ; ; All primitive data transfer routines assume: ; ; d0 - <-- error (if any) ; d1 - --> copy of d2 ; d1 - <-- bytes transferred ; d2 - --> number of bytes to transfer ; d3 - scratch - saved ; d4 - --> type of transfer to perform ; d5 - scratch - saved ; d6 - scratch - saved ; ; a0 - scratch - saved ; a1 - SCSI chip read base address - NON-SERIALIZED ; a2 - ptr to data buffer - saved ; a3 - SCSI chip read base address - SERIALIZED ; a4 - ptr to SCSI Mgr globals ; a5 - scratch - saved ; ; Method of Data Transfer: (pDMA and programmed IO) to next ; 0) Make sure we got our intrp from the last cmd send ; 1) calculate # of 16-byte block transfers to perform using pDMA & remember the remainder ; 2) Enable c96 DMA and wait till the 16-byte FIFO is full and DREQ is asserted for the 17th byte ; 3) Transfer all data in the FIFO and wait for the intrp ; 4) Repeat until all block have been transferred ; 5) Transfer remaining data using non-DMA transfer command byte then ; Wait and poll for byte-in-fifo interrupt ; 6) Transfer data from fifo to input buffer ; 7) Repeat process until all remaining bytes have been transferred ; SlowRead_96 bsr HandleSelInProg ; handle unfinished select command bne.w @phaseErr ; if it is stuck, we are not in data phase @doRead moveq.l #iPhaseMsk, d0 ; load mask for phase bits and.b rSTA(a3), d0 ; are we in data-in phase? cmpi #iDataIn, d0 ; data-in phase bits = 001 bne.s phaseErr1 ; bra. on phase err clr.l d6 ; move.l d2, d4 ; d4 = copy of transfer count lsr.l #4, d4 ; divide xfer count by 16 beq.w @16orLess ; bra. if < 16 bytes subq.l #1, d4 ; adjust for DBRA move.l d4, d6 ; d4.w has lower 16-byte block count swap d6 ; d6.w has upper 16-byte word count @16orMore ; The next few lines are necessary in order to poll DREQ in nuBus ; address space. We don't need to do this if we're xferring <16 bytes. jsr SCSIpcTo32bit ; use pc relative move.b MMU32Bit, -(sp) ; save current mode on stack moveq #true32B, d0 ; switch to 32-bit mode to look at SCSI config regr jsr SwapMMU ; do it, call _SwapMMUMode jump vector move.l a2, d0 ; get destination addr in d0 _StripAddress ; clear upper byte if necessary move.l d0, a2 ; a2 = clean buffer ptr move.l G_SCSIDREQ(a4), a0 ; load SCSI DREQ regr move.b #cFlshFFO, rCMD(a3) ; Flush FIFO move.b #0, rXCM(a3) ; rXCM = 0, clear most-sig. byte count move.b #$10, rXCL(a3) ; rXCL = 16 bytes, least-sig. byte value if nonSerializedIO Then nop ; Force write to complete. endif and.l #$F, d2 ; d2 = remainder word count after 16-byte moves @read16 moveq.l #iPhaseMsk, d5 ; load mask bits for phase value and.b rSTA(a3), d5 ; are we still in data-in phase? cmpi.b #iDataIn, d5 ; data-in phase bits = 001 bne.w @premature2 ; no: probably in status phase - split move.b #cDMAXfer, rCMD(a3) ; load DMA transfer cmd & start loading FIFO nop ; currently loaded transfer count is used/reused @1 btst.b #bTRC, rSTA(a3) ; check if we've rcvd all the data thru next bne.s @4 ; if we have, go get the bytes btst.b #bINT, rSTA(a3) ; poll for unexpected intrp while waiting bne.w @prematureEnd ; ... maybe disconnected or something catastrophic. ; premature phase change won't generate intrp bit 'cuz of outstanding DREQ... ; ... we have to check this condition explicitly moveq.l #iPhaseMsk, d5 ; load mask bits for phase value and.b rSTA(a3), d5 ; are we still in data-in phase? cmpi.b #iDataIn, d5 ; data-in phase bits = 001 beq.s @1 ; yes, bra. & keep polling tst.b rXCL(a3) ; not data-in anymore, have we xferred all data (XCL = 0)? beq.s @1 ; if yes then there MUST be a transfer count zero bit set bra.w @prematureEnd ; transfer count not 0 so we have a premature end from prev ; We need 16 guaranteed DREQs to safely transfer 16 bytes without bus error. ; Ideally, DREQ should be active as long there are threshold number of bytes in the ; FIFO--as the c96 user's guide imply. But the c96 implementation also requires that ; REQ be active in order to get DREQ. This is why we must wait for the 17th REQ from ; the target--and it must remain active--before we proceed with the 16-byte transfer. @4 IF forPDMDebug THEN ; move.b (a0), d5 ; read DAFB regr (a0=DAFB register addr) ELSE move.l (a0), d5 ; read DAFB regr (a0=DAFB register addr) ENDIF move.b G_bitDREQ(a4),d0 ; load DREQ bit position <5> jab btst.l d0, d5 ; DREQ ? <5> jab beq.s @1 ; loop until asserted btst #4, rFOS(a3) ; see if FIFO is full beq.s @1 ; loop until asserted @10 nop ; squoosh pipeline move.w rDMA(a1), (a2)+ ; read 16 bytes thru next move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ ; from last IF nonSerializedIO THEN nop ; squoosh pipeline ENDIF ; Note that intrp is asserted only after transfer count is 0, FIFO is empty ; and the target asserts REQ for the next byte. @2 btst.b #bINT, rSTA(a3) ; check for c96 INTRP beq.s @2 ; loop until we get the intrp move.b rINT(a3), d5 ; read Intrp regr & clear rSTA, rSQS & rINT btst.l #bDSC, d5 ; check for disconnected intrp bne.s @premature2 ; Branch if transfer error dbra d4, @read16 ; loop until done, d4 is lower word count dbra d6, @read16 ; loop until done, d6 is upper word count move.b (sp)+, d0 ; switch to previous address mode jsr SwapMMU ; do it, call _SwapMMUMode jump vector bra.s @16OrLess ; take care of remaining data, if any @rdSingle ; use non-pDMA for remainder moveq.l #iPhaseMsk, d5 ; load mask bits for phase value and.b rSTA(a3), d5 ; are we still in data-in phase? cmpi.b #iDataIn, d5 ; data-in phase bits = 001 bne.s @phaseErr ; bra. on phase err move.b #cIOXfer, rCMD(a3) ; load IO transfer cmd & begin xfers if nonSerializedIO Then nop ; Force write to complete. endif @3 btst.b #bINT, rSTA(a3) ; check for c96 INTRP beq.s @3 ; loop until we get an intrp move.b rFFO(a3), (a2)+ ; xfer byte from FIFO into input buffer move.b rINT(a3), d5 ; read Intrp regr & clear rSTA, rSQS & rINT btst.l #bDSC, d5 ; check for disconnected intrp bne.s @xferErr ; Branch if transfer error @16OrLess dbra d2, @rdSingle ; read the rest of the remainders @goodSRead ; d1 = # of bytes transferred moveq.l #noErr, d0 ; successful read op rts ; ; Premature phase change - get leftover bytes out of FIFO, clear DREQ and INTRPT to next @prematureEnd moveq.l #iFOFMsk, d0 ; use mask to get FIFO flag field and.b rFOS(a3), d0 ; how many bytes left in FIFO? bra.s @btmLeftovers @topLeftovers move.b rFFO(a3), (a2)+ @btmLeftovers dbra d0,@topLeftovers @removeDREQ IF forPDMDebug THEN ; move.b (a0), d5 ; read DAFB regr (a0=DAFB register addr) ELSE move.l (a0), d5 ; read DAFB regr (a0=DAFB register addr) ENDIF move.b G_bitDREQ(a4),d0 ; load DREQ bit position <5> jab btst.l d0, d5 ; DREQ ? <5> jab beq.s @5 ; if no DREQ, skip dummy rDMA access move.w rDMA(a3), d5 ; remove that outstanding DREQ (magic), bra @removeDREQ ; and see if there's more (more magic) @5 ; and give us that intrp bsr.w WaitForIntNoTime ; Clear pending intrp & get err status ; on exit d5 = rFOS|rINT|0|rSTA ; Premature phase change with no leftover bytes @premature2 move.b (sp)+, d0 ; switch to previous address mode jsr SwapMMU ; do it, call _SwapMMUMode jump vector ; from prev ; calc how many bytes we've xferred... addq.w #1, d4 ; undo adjustment for dbra swap d6 ; calculate bytes left to transfer move.w d4, d6 ; form long word count lsl.l #4, d6 ; mult by 16 and.b #iPhaseMsk, d5 ; are we still in data-in phase? cmpi.b #iDataIn, d5 ; data-in phase bits = 001 beq.s @xferErr ; bra. to check for disconnect @phaseErr moveq.l #scPhaseErr, d0 ; return a phase error bra.s @badSRead ; @xferErr ; anything else is a comm. err moveq.l #scCommErr, d0 ; transfer error @badSRead add.l d2, d6 ; add un-xferred remainder sub.l d6, d1 ; number of bytes transferred move.l #scsiRead, d6 ; load proc ID jsr Error ; call Error proc - for debug move.b #cFlshFFO, rCMD(a3) ; Flush FIFO if nonSerializedIO Then nop ; Force write to complete. endif rts ; ;-------------------------------------------------------------------------- ; SlowWrite - implements Polled Write ; ; Called by: Transfer ; ; All primitive data transfer routines assume: ; ; d0 - <-- error (if any) ; d1 - --> copy of d2 ; d1 - <-- bytes transferred ; d2 - --> number of bytes to transfer ; d3 - scratch - saved ; d4 - --> type of transfer to perform ; d5 - scratch - saved ; d6 - scratch - saved ; ; a0 - scratch - saved ; a1 - SCSI chip read base address - NON-SERIALIZED ; a2 - ptr to data buffer - saved ; a3 - SCSI chip read base address - SERIALIZED ; a4 - ptr to SCSI Mgr globals ; a5 - scratch - saved ; ; Method of Data Transfer: (uses pseudo-DMA mode) ; 0) Make sure we got our intrp from the last cmd send ; 1) Parcel transfer into 64KB blocks since TC regr. handles 64KB max ; 2) Calc. the number of 16-byte block transfers to perform ; 3) Calc. the remaining number of transfers to perform ; 4) Write data 16-byte blocks at a time using word MOVEs ; 5) Wait without timeouts until FIFO is empty ie. 16-byte transfer completed ; 6) Transfer residual byte if there is one ; SlowWrite_96 bsr HandleSelInProg ; handle unfinished select command bne.w @phaseErr ; if it is stuck, we are not in data phase @doWrite moveq.l #iPhaseMsk, d0 ; and.b rSTA(a3), d0 ; are we in data-out phase? bne.w phaseErr1 ; data-out phase bits = 0, bra. on phase err thru next cmpi.l #1, d2 ; if 1 byte write then... beq.w OneByteWrite ; ...do 1 byte transfer move.l d2, d6 ; d6 = number 64KB block to perform swap d6 ; upper word of d6 = lower word of d2 andi.l #$0000FFFF, d2 ; mask out upper word beq @2 ; if 0 then we have $10000 (64K) bytes to xfer @next64KB moveq.l #iPhaseMsk, d3 ; load mask bits for phase value and.b rSTA(a3), d3 ; are we still in data-out phase? ; and.b d5, d3 ; are we still in data-out phase? ;; cmpi.b #iDataOut, d3 ; data-out phase bits = 000 bne.w @phaseErr ; bra. if phase err move.l d2, d4 ; d4 <- d2 move.b d4, rXCL(a3) ; TC regr (least-sig. byte) <- d4.b lsr.l #8, d4 ; get upper byte of low word move.b d4, rXCM(a3) ; TC regr (most-sig. byte) <- d4.b if nonSerializedIO Then nop ; Force write to complete. endif move.b #cDMAXfer, rCMD(a3) ; load DMA transfer cmd & begin xfers nop ; squoosh pipeline ; DREQ* should be active at this time move.l d2, d4 ; d4 <- d2 lsr.l #4, d4 ; divide xfer count by 16 ror.l #1, d2 ; xfer byte count to word & remember odd byte and.w #$7, d2 ; d2 = remainder word count after 16-byte moves neg.w d2 ; negate to form a backward jump offset jmp @emptyWait(d2.w*4) ; bra. into the loop @write16 ; nop ; squoosh pipeline move.w (a2)+, rDMA(a1) ; do 16 bytes thru next move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) ; from last @emptyWait IF nonSerializedIO THEN nop ; squoosh pipeline ENDIF btst.b #bINT, rSTA(a3) ; ...poll for unexpected intrp while waiting bne.s @prematureEnd ; ... maybe disconnected, phase changed, etc. moveq.l #iPhaseMsk, d3 ; load mask bits for phase value and.b rSTA(a3), d3 ; are we still in data-out phase? ;; ;cmpi.b #iDataOut, d3 ; data-out phase bits = 000 bne.s @prematureEnd ; bra. if phase err moveq.l #iFOFMsk, d0 ; use mask to get FIFO flag field and.b rFOS(a3), d0 ; get # of bytes in FIFO bne.s @emptyWait ; bra. if FIFO is empty else... thru next @1 dbra d4, @write16 ; d4 = # of 16-byte tranfers btst.l #31, d2 ; check if we have a residual byte beq.s @noResidual ; @residual move.b (a2)+, rDMA(a3) ; xfer residual byte if nonSerializedIO Then nop ; Force write to complete. endif @noResidual bsr.w WaitForIntNoTime ; Wait for intrp w/o timeout ; on exit d5 = rFOS|rINT|0|rSTA bne.s @xferErr ; bra. if xfer err @2 move.l #$10000, d2 ; init to transfer 64K bytes dbra d6, @next64KB ; @goodSWrite ; d1 = # of bytes transferred moveq.l #noErr, d0 ; successful write op rts ; @prematureEnd ; thru next ; 3 reasons to get an intrp 1) when TC=0 (bus service), xfer done 2) premature ; phase changes (bus service) 3) premature disconnect (disconnect) bsr.w WaitForIntNoTime ; Clear pending intrp & get err status ; on exit d5 = rFOS|rINT|0|rSTA btst.l #bTRC, d5 ; Maybe we're done xferring data ie. TC=1 bne.s @2 ; ...so proceed with next 64Kb block moveq.l #iPhaseMsk, d3 ; load mask bits for phase value and.b d5, d3 ; are we still in data-out phase? (d5 from WaitFor call) cmpi.b #iDataOut, d3 ; data-out phase bits = 000 beq.s @xferErr ; bra. if not phase err @phaseErr moveq.l #scPhaseErr, d0 ; return a phase error move.l #0, d1 ; no bytes transferred move.l #0, G_FakeStat(a4) ; Return a fake status bra.s @bytesXferd @xferErr moveq.l #scCommErr, d0 ; comm error @bytesXferd lsl.l #4, d4 ; multiply by 16 swap d6 ; calculate bytes left to transfer move.w d4, d6 ; get low order word moveq.l #iFOFMsk, d2 ; and.b rFOS(a3), d2 ; add # of un-xferred data in FIFO add.l d2, d6 ; sub.l d6, d1 ; d1 = bytes xferred @badSWrite move.l #0, G_FakeStat(a4) ; Return a fake status move.l #scsiWrite, d6 ; load proc ID jsr Error ; call Error proc - for debug move.b #cFlshFFO, rCMD(a3) ; Flush FIFO if nonSerializedIO Then nop ; Force write to complete. endif rts ; ;-------------------------------------------------------------------------- ; FastWrite - implements Blind Write ; ; Called by: Transfer ; ; All primitive data transfer routines assume: ; ; d0 - <-- error (if any) ; d1 - --> copy of d2 ; d1 - <-- bytes transferred ; d2 - --> number of bytes to transfer ; d3 - scratch - saved ; d4 - --> type of transfer to perform ; d5 - scratch - saved ; d6 - scratch - saved ; ; a0 - scratch - saved ; a1 - SCSI chip read base address - NON-SERIALIZED ; a2 - ptr to data buffer - saved ; a3 - SCSI chip read base address - SERIALIZED ; a4 - ptr to SCSI Mgr globals ; a5 - scratch - saved ; ; Method of Data Transfer: (uses pseudo-DMA mode) ; 0) Make sure we got our intrp from the last cmd send ; 1) Parcel transfer into 64KB blocks since TC regr. handles 64KB max ; 2) Preload FIFO with non-aligned byte; get us word aligned ; 3) Calc. the number of 32-byte block transfers to perform ; 4) Calc. the remaining number of transfers to perform ; 5) Write data 32-byte blocks at a time using word MOVEs ; 6) Write remaining data using word MOVEs ; 7) Transfer residual byte if there is one FastWrite_96 IF forPDMDebug THEN ; Jimmy, Jimmy, Jimmy.... cmp.b #$44,$CB3 ; PDM evt1? bne.s @fast ; -> Nope, its ok to do fast bra SlowWrite_96 @fast ENDIF bsr HandleSelInProg ; handle unfinished select command bne.w @phaseErr ; if it is stuck, we are not in data phase @doWrite move.b #cFlshFFO, rCMD(a3) ; Flush FIFO if nonSerializedIO Then nop ; Force write to complete. endif moveq.l #iPhaseMsk, d0 ; and.b rSTA(a3), d0 ; are we in data-out phase? bne.w phaseErr1 ; data-out phase bits = 0, bra. on phase err thru next cmpi.l #1, d2 ; if 1 byte write then... beq.w OneByteWrite ; ...do 1 byte transfer move.l d2, d6 ; d6 = number 64KB block to perform swap d6 ; upper word of d6 = lower word of d2 andi.l #$0000FFFF, d2 ; mask out upper word beq @2 ; if 0 then we have $10000 (64K) bytes to xfer move.l a2, d5 ; btst.l #0, d5 ; check if input buffer is on word boundary bne.w @misAligned @next64KB ; buffer is aligned from this point thru next move.l d2, d4 ; d4 <- d2 move.b d4, rXCL(a3) ; TC regr (least-sig. byte) <- d4.b lsr.l #8, d4 ; get upper byte of low word move.b d4, rXCM(a3) ; TC regr (most-sig. byte) <- d4.b if nonSerializedIO Then nop ; Force write to complete. endif move.b #cDMAXfer, rCMD(a3) ; load DMA transfer cmd & begin xfers ; DREQ* should be active at this time if nonSerializedIO Then nop ; Force write to complete. endif move.w d2, d4 ; d4 = copy of transfer count lsr.w #5, d4 ; divide xfer count by 32 ror.l #1, d2 ; xfer byte count to word & remember odd byte and.w #$F, d2 ; d2 = remainder word count after 32-byte moves neg.w d2 ; negate to form a backward jump offset nop ; squoosh pipeline jmp @WrLoop(d2.w*4) ; bra. into the loop @write32 ; move.w (a2)+, rDMA(a1) ; do 16 bytes thru next move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) ; do another 16 bytes move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) move.w (a2)+, rDMA(a1) ; from last @WrLoop dbra d4, @write32 ; d4 = # of 32-byte tranfers IF nonSerializedIO THEN nop ; squoosh pipeline ENDIF ; INT & TC maybe TRUE at this point btst.l #31, d2 ; check if we have a residual byte beq.s @noResidual ; @residual move.b (a2)+, rDMA(a3) ; xfer residual byte if nonSerializedIO Then nop ; Force write to complete. endif @noResidual bsr.w WaitForIntNoTime ; Wait for intrp w/o timeout ; on exit d5 = rFOS|rINT|0|rSTA bne.s @xferErr ; bra. if xfer err @2 move.l #$10000, d2 ; init to transfer 64K bytes dbra d6, @next64KB ; @goodFWrite ; d1 = # of bytes transferred moveq.l #noErr, d0 ; successful write op rts ; @misAligned ; subq.l #1, d2 ; adjust for transfer count calc move.b (a2)+, rFFO(a3) ; ...preload fifo with odd byte thru next if nonSerializedIO Then nop ; Force write to complete. endif bra.w @next64KB ; now we're word aligned @phaseErr moveq.l #scPhaseErr, d0 ; return a phase error bra.s @bytesXferd ; @xferErr moveq.l #scCommErr, d0 ; comm error @bytesXferd ; swap d6 ; calculate bytes left to transfer move.w d4, d6 ; get low order word lsl.l #5, d6 ; multiply by 32 ext.l d2 ; make d2 a long addq.l #1, d2 ; undo adjustment for dbra add.l d2, d6 ; add to total moveq.l #iFOFMsk, d2 ; and.b rFOS(a3), d2 ; add un-xferred byte in FIFO add.w d2, d6 ; sub.l d6, d1 ; result @badFWrite ; thru next move.l #0, G_FakeStat(a4) ; Return a fake status move.l #scsiWBlind, d6 ; load proc ID jsr Error ; call Error proc - for debug move.b #cFlshFFO, rCMD(a3) ; Flush FIFO if nonSerializedIO Then nop ; Force write to complete. endif rts ; ;-------------------------------------------------------------------------- ; FastRead - implements FastRead ; ; Called by: Transfer ; ; All primitive data transfer routines assume: ; ; d0 - <-- error (if any) ; d1 - --> copy of d2 ; d1 - <-- bytes transferred ; d2 - --> number of bytes to transfer ; d3 - scratch - saved ; d4 - --> type of transfer to perform ; d5 - <-- xxxx|xxxx|xxxx|rSTA ; d6 - scratch - saved ; ; a0 - scratch - saved ; a1 - SCSI chip read base address - NON-SERIALIZED ; a2 - ptr to data buffer - saved ; a3 - SCSI chip read base address - SERIALIZED ; a4 - ptr to SCSI Mgr globals ; a5 - scratch - saved ; ; Method of Data Transfer: (uses Pseudo-DMA) ; 0) Make sure we got our intrp from the last cmd send ; 1) Parcel transfer into 64KB blocks since TC regr. handles 64KB max ; 2) Read 1st byte if input buffer is NOT word aligned ; 3) Calc. the number of 32-byte block transfers to perform ; 4) Calc. the remaining number of byte transfers to perform ; 5) Read data 32-byte blocks at a time using word MOVEs ; 6) Read remaining data a word at a time ; 7) Transfer residual byte if there is one FastRead_96 IF forPDMDebug THEN ; Jimmy, Jimmy, Jimmy.... cmp.b #$44,$CB3 ; PDM evt1? bne.s @fast ; -> Nope, its ok to do fast bra SlowRead_96 @fast ENDIF bsr HandleSelInProg ; handle unfinished select command bne.w @phaseErr ; if it is stuck, we are not in data phase @doRead move.b #cFlshFFO, rCMD(a3) ; Flush FIFO if nonSerializedIO Then nop ; Force write to complete. endif moveq.l #iPhaseMsk, d0 ; load mask for phase bits thru next and.b rSTA(a3), d0 ; are we in data-in phase? cmpi.b #iDataIn, d0 ; data-in phase bits = 001 bne.w phaseErr1 ; bra. on phase err cmpi.l #1, d2 ; special case a 1 byte transfer beq.w OneByteRead ; move.l d2, d6 ; d6 = number 64KB block to perform swap d6 ; upper word of d6 = lower word of d2 andi.l #$0000FFFF, d2 ; mask out upper word beq @2 ; if 0 then we have $10000 (64K) bytes to xfer @next64KB move.l d2, d4 ; d4 <- d2 move.b d4, rXCL(a3) ; TC regr (least-sig. byte) <- d4.b lsr.l #8, d4 ; get upper byte of low word move.b d4, rXCM(a3) ; TC regr (most-sig. byte) <- d4.b move.b #cDMAXfer, rCMD(a3) ; load DMA transfer cmd & begin xfers ; DREQ* should be active at this time if nonSerializedIO Then nop ; Force write to complete. endif ; move.l a2, d5 ; ; btst.l #0, d5 ; check if input buffer is on word boundary ; bne.s @misAligned @aligned move.w d2, d4 ; d4 = copy of transfer count lsr.w #5, d4 ; divide xfer count by 32 thru next ror.l #1, d2 ; xfer byte count to word & remember odd byte and.w #$F, d2 ; d2 = remainder word count after 32-byte moves neg.w d2 ; negate to form a backward jump offset nop ; squoosh pipeline jmp @RdLoop(d2.w*4) ; bra. into the loop @read32 ; move.w rDMA(a1), (a2)+ ; do 16 bytes thru next move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ ; do another 16 bytes move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ move.w rDMA(a1), (a2)+ ; from last @RdLoop ; thru next dbra d4, @read32 ; d4 = # of 32-byte transfers IF nonSerializedIO THEN nop ; squoosh pipeline ENDIF ; INT & TC bits should be TRUE at this point bsr.w WaitForIntNoTime ; Wait for intrp w/o timeout ; on exit d5 = rFOS|rINT|0|rSTA bne.s @xferErr ; bra. if xfer err btst.l #31, d2 ; check if we have a residual byte beq.s @2 ; bra. if no residual @residual bsr WtForFIFOData ; returns number of bytes in FIFO beq.s @timedOut ; move.b rFFO(a3), (a2)+ ; xfer residual byte @2 move.l #$10000, d2 ; init to transfer 64K bytes dbra d6, @next64KB ; @goodFRead ; d1 = # of bytes transferred moveq.l #noErr, d0 ; successful read op rts ; @misAligned subq.l #1, d2 ; decr. for DBRA thru next move.b rFFO(a3), (a2)+ ; xfer byte from fifo into input buffer bra.s @aligned ; transfer the rest of data @timedOut ; moveq.l #scBusTOErr, d0 ; if we timed out, return error bra.s @bytesXferd ; @phaseErr moveq.l #scPhaseErr, d0 ; return a phase error bra.s @bytesXferd ; @xferErr moveq.l #scCommErr, d0 ; comm error @bytesXferd ; swap d6 ; calculate bytes left to transfer move.w d4, d6 ; get low order word lsl.l #5, d6 ; multiply by 32 ext.l d2 ; make d2 a long addq.l #1, d2 ; undo adjustment for dbra add.l d2, d6 ; add to total sub.l d6, d1 ; d1 = xfer count - bytes remaining to xfer thru next @badFRead move.l #0, G_FakeStat(a4) ; Return a fake status move.l #scsiRBlind, d6 ; load proc ID jsr Error ; call Error proc - for debug move.b #cFlshFFO, rCMD(a3) ; Flush FIFO if nonSerializedIO Then nop ; Force write to complete. endif rts ; ;-------------------------------------------------------------------------- to next ; ; 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 #iFOFMsk, d0 and.b rFOS(a3), d0 ; read FIFO flags regr dbne d1, @1 ; loop until data or timeout dbne d2, @1 ; movem.l (sp)+,d1-d2 rts ; from prev ;-------------------------------------------------------------------------- ; ; ResetBus - Reset the SCSI bus by asserting the SCSI Reset Output signal ; for some number of uS as determined by the clock conv. factor (CCF) ; ; a3 - SCSI chip read base address - SERIALIZED ; ResetBus_96 ; disable all intrps move.b #cRstSBus, rCMD(a3) ; load reset scsi bus cmd ; re-enable all intrps if nonSerializedIO Then nop ; Force write to complete. endif rts ;-------------------------------------------------------------------------- ; ; WaitForIntNoTime - infinite loop to wait for a SCSI intrp. ; ; Uses: d0, d5 ; ; On exit: d5 = rFOS|rINT|0|rSTA, byte values from the Seq.Step, Status & INT regrs. ; ; CCR.z = 1, means successful wait ; CCR.z = 0, means failed due to disconnect or lack of bus service req. WaitForIntNoTime @noTimeoutWait clr.l d5 ; move.b rSTA(a3), d5 ; read Status regr btst.l #bINT, d5 ; poll intrp on status regr. for pending intrp beq.s @noTimeoutWait ; ...loop until intrp req is detected swap d5 ; move.b rFOS(a3), d5 ; read FIFO flag/Sequence Step regr lsl.w #8, d5 ; shift left by 1 byte move.b rINT(a3), d5 ; read & clear rFOS, rSTA & rINT move.l d5, d0 ; we got here because of an intrp swap d5 ; d5 = rFOS|rINT|0|rSTA andi.b #iDcBsMsk, d0 ; get Disconnect & Bus Service bits cmpi.b #iDcBsOK, d0 ; expecting: not disconnected ; & target request info xfer phase rts ; d5 = rFOS|rINT|0|rSTA thru next ;-------------------------------------------------------------------------- ; ; HandleSelInProg ; ; 0 if no select in progress or if select is now complete ; 1 if a select is still in progress (i.e. in cmd or msg_out phase) ; HandleSelInProg btst.b #SelInProg, G_State96(a4) ; is Select cmd still in progress? beq.w @skipIt ; no - skip it btst.b #NeedMsgOut, G_State96(a4) ; are we expecting a Msg_Out phase? beq.s @chkCmd ; no - see about Command move.b #iMsgOut, d1 ; yes - wait for this phase or interrupt bra.s @doWait @chkCmd btst.b #NeedCmdSent, G_State96(a4) ; are we expecting a Command phase? beq.s @wtForFC ; no - wait for an interrupt then move.b #iCommand, d1 ; yes - wait for this phase or interrupt @doWait bsr.s Wt4DREQorInt bne.s @gotDREQ @gotInt bclr.b #FCIntPend, G_State96(a4) ; clear the FC Int pend flag bclr.b #SelInProg, G_State96(a4) ; and clear the SelectInProgress flag bclr.b #NeedMsgOut, G_State96(a4) ; and Message_Out bclr.b #NeedCmdSent, G_State96(a4) ; and Command expected flags tst.b d0 ; setup result again @gotDREQ @skipIt rts @wtForFC bsr.w WaitForIntNoTime move.b #cFlshFFO, rCMD(a3) ; Flush FIFO <3> if nonSerializedIO Then nop ; Force write to complete. endif moveq.l #0, d0 bra.s @gotInt ;-------------------------------------------------------------------------- ; ; Wt4DREQorInt - infinite loop to wait for a DREQ signal or SCSI chip intrp. ; ; Uses: d3, d5 ; ; Entry: ; --> d1 = phase to wait for (concurrent with DREQ) ; ; --> G_SCSIDREQ(a4) = addr of DAFB reg (for reading value of ; ; Exit: ; <-- d5 = rFOS|rINT|0|rSTA, byte values from the Seq.Step, Status & INT regrs. ; <-- d0 = 1 if DREQ, 0 if Int ; ;----------------- Wt4DREQorInt jsr SCSIpcTo32bit ; clean up PC first ; Check for interrupt first (to avoid unnecessary dog-slow DREQ check) @noTimeout clr.l d5 ; move.b rSTA(a3), d5 ; read Status regr btst.l #bINT, d5 ; poll intrp on status regr. for pending intrp bne.s @gotInt ; ; If no Interrupt, check for DREQ (go into and out of 32-bit mode to check) ; into 32-bit mode moveq #true32B, d0 ; switch to 32-bit mode to look at SCSI config regr jsr SwapMMU ; do it, puts previous mode in D0 move.l G_SCSIDREQ(a4), a0 ; G_SCSIDREQ contains DREQ regr address IF forPDMDebug THEN ; move.b (a0), d5 ; read DAFB regr (a0=DAFB register addr) ELSE move.l (a0), d5 ; read DAFB regr (a0=DAFB register addr) ENDIF ; out of 32-bit mode (return to previous mode - already in D0) jsr SwapMMU ; do it, call _SwapMMUMode jump vector ; DREQ? move.b G_bitDREQ(a4),d0 ; load DREQ bit position <5> jab btst.l d0, d5 ; DREQ ? <5> jab beq.s @noTimeout ; no: try again @gotDREQ move.b rSTA(a3), d3 ; get phase value to next and.b #iPhaseMsk, d3 ; load mask bits for phase value cmp.b d3, d1 ; are we in requested phase? bne.s @noTimeout ; moveq.l #1, d3 ; return value = Got DREQ bra.s @exit ; Get sequence and FIFO status registers into D5 (already got rSTA) @gotInt swap d5 ; move.b rFOS(a3), d5 ; read FIFO flag/Sequence Step regr lsl.w #8, d5 ; shift left by 1 byte move.b rINT(a3), d5 ; read & clear rFOS, rSTA & rINT move.l d5, d0 ; we got here because of an intrp swap d5 ; d5 = rFOS|rINT|0|rSTA moveq.l #0, d3 ; return value = Got Interrup @exit move.l d3, d0 rts ; ;-------------------------------------------------------------------------- ; ; WaitForSCSIIntrp ; ; Proc to wait for the SCSI interrupt with a 256mS watchdog timer. ; ; Uses: d0, d3, d5 ; ; On exit: d5 = rFOS|rINT|0|rSTA, byte values from the Seq.Step, ; Status & INT regrs. ; ccr.z = 1, means timedOut WaitForSCSIIntrp clr.l d5 moveq.l #0, d3 ; clear upper word move.w TimeSCSIDB, d3 ; get # of DBRAs lsl.l #8, d3 ; multiply by 256 move.l d3, d0 ; ...a 256mS wait swap d0 @1 move.b rSTA(a3), d5 ; read Status regr btst.l #bINT, d5 ; check for c96 INTRP dbne d3, @1 ; loop until INT is active or timeout dbne d0, @1 ; loop until INT is active or timeout beq.s @timedOut ; swap d5 move.b rFOS(a3), d5 ; read FIFO flag/Sequence Step regr lsl.w #8, d5 ; shift left by 1 byte move.b rINT(a3), d5 ; read & clear rFOS, rSTA & rINT @exit swap d5 ; btst.l #bINT, d5 ; set condition bits rts ; d5 = rFOS|rINT|0|rSTA @timedOut swap d5 move.b rFOS(a3), d5 ; read FIFO flag/Sequence Step regr lsl.w #8, d5 ; shift left by 1 byte move.b #0, d5 ; clear rINT value bra.s @exit ; ;-------------------------------------------------------------------------- ; FastCompare - implements FastRead ; ; Called by: Transfer ; ; All primitive data transfer routines assume: ; ; d0 - <-- error (if any) ; d1 - --> copy of d2 ; d1 - <-- bytes transferred ; d2 - --> number of bytes to transfer ; d3 - scratch - saved ; d4 - --> type of transfer to perform ; d5 - <-- xxxx|xxxx|xxxx|rSTA ; d6 - scratch - saved ; ; a0 - scratch - saved ; a1 - SCSI chip read base address - NON-SERIALIZED ; a2 - ptr to data buffer - saved ; a3 - SCSI chip read base address - SERIALIZED ; a4 - ptr to SCSI Mgr globals ; a5 - scratch - saved ; ; Method of Data Transfer: (uses Pseudo-DMA) ; 0) Make sure we got our intrp from the last cmd send ; 1) Parcel transfer into 64KB blocks since TC regr. handles 64KB max ; 2) Read 1st byte if input buffer is NOT word aligned ; 3) Calc. the number of 32-byte block transfers to perform ; 4) Calc. the remaining number of byte transfers to perform ; 5) Read data 32-byte blocks at a time using word MOVEs ; 6) Read remaining data a word at a time ; 7) Transfer residual byte if there is one FastComp_96 IF forPDMDebug THEN ; Jimmy, Jimmy, Jimmy.... bra SlowComp_96 ENDIF bsr HandleSelInProg ; handle unfinished select command bne.w @phaseErr ; if it is stuck, we are not in data phase @doRead moveq.l #iPhaseMsk, d0 ; load mask for phase bits thru next and.b rSTA(a3), d0 ; are we in data-in phase? cmpi.b #iDataIn, d0 ; data-in phase bits = 001 bne.w phaseErr1 ; bra. on phase err cmpi.l #1, d2 ; special case a 1 byte compare beq.w SlowComp_96 ; clr.l d3 ; init compare status move.l d2, d6 ; d6 = number 64KB block to perform swap d6 ; upper word of d6 = lower word of d2 andi.l #$0000FFFF, d2 ; mask out upper word beq.s @2 ; if 0 then we have $10000 (64K) bytes to xfer @next64KB move.l d2, d4 ; d4 <- d2 move.b d4, rXCL(a3) ; TC regr (least-sig. byte) <- d4.b lsr.l #8, d4 ; get upper byte of low word move.b d4, rXCM(a3) ; TC regr (most-sig. byte) <- d4.b move.b #cDMAXfer, rCMD(a3) ; load DMA transfer cmd & begin xfers ; DREQ* should be active at this time if nonSerializedIO Then nop ; Force write to complete. endif ror.l #1, d2 ; xfer byte count to word & remember odd byte subq.w #1, d2 ; adjust for DBRA @RdAndCmp move.w rDMA(a3), d0 ; cmp.w (a2)+, d0 ; compare a word at a time beq.s @Ok moveq.l #scCompareErr, d3 ; record a compare error @Ok dbra d2, @RdAndCmp ; loop until done ; INT & TC bits should be TRUE at this point bsr.w WaitForIntNoTime ; Wait for intrp w/o timeout ; on exit d5 = rFOS|rINT|0|rSTA bne.s @xferErr ; bra. if xfer err btst.l #31, d2 ; check if we have a residual byte beq.s @2 ; bra. if no residual @residual move.b rFFO(a3), d0 ; read byte data from FIFO cmp.b (a2)+, d0 ; xfer byte from FIFO into input buffer beq.s @2 moveq.l #scCompareErr, d3 ; record a compare error @2 move.l #$10000, d2 ; init to transfer 64K bytes dbra d6, @next64KB ; @ExitFCmp ; d1 = # of bytes transferred move.l d3, d0 ; return status rts ; @phaseErr moveq.l #scPhaseErr, d0 ; return a phase error bra.s @bytesXferd @xferErr moveq.l #scCommErr, d0 ; comm error @bytesXferd swap d6 ; calculate bytes left to transfer move.w d4, d6 ; get low order word lsl.l #5, d6 ; multiply by 32 ext.l d2 ; make d2 a long addq.l #1, d2 ; undo adjustment for dbra add.l d2, d6 ; add to total sub.l d6, d1 ; d1 = xfer count - bytes remaining to xfer @badFRead move.l #0, G_FakeStat(a4) ; Return a fake status move.l #scsiRBlind+$F0, d6 ; load proc ID, Fast compare jsr Error ; call Error proc - for debug move.b #cFlshFFO, rCMD(a3) ; Flush FIFO if nonSerializedIO Then nop ; Force write to complete. endif rts ; ;-------------------------------------------------------------------------- ; SlowComp - implements Polled Read ; ; Called by: Transfer ; ; All primitive data transfer routines assume: ; ; d0 - <-- error (if any) ; d1 - --> copy of d2 ; d1 - <-- bytes transferred ; d2 - --> number of bytes to transfer ; d3 - scratch - saved ; d4 - --> type of transfer to perform ; d5 - scratch - saved ; d6 - scratch - saved ; ; a0 - scratch - saved ; a1 - SCSI chip read base address - NON-SERIALIZED ; a2 - ptr to data buffer - saved ; a3 - SCSI chip read base address - SERIALIZED ; a4 - ptr to SCSI Mgr globals ; a5 - scratch - saved ; ; Method of Data Transfer: (pDMA and programmed IO) to next ; 0) Make sure we got our intrp from the last cmd send ; 1) calculate # of 16-byte block transfers to perform using pDMA & remember the remainder ; 2) Enable c96 DMA and wait till the 16-byte FIFO is full and DREQ is asserted for the 17th byte ; 3) Transfer all data in the FIFO and wait for the intrp ; 4) Repeat until all block have been transferred ; 5) Transfer remaining data using non-DMA transfer command byte then ; Wait and poll for byte-in-fifo interrupt ; 6) Transfer data from fifo to input buffer ; 7) Repeat process until all remaining bytes have been transferred SlowComp_96 bsr HandleSelInProg ; handle unfinished select command bne.w @phaseErr ; if it is stuck, we are not in data phase @doRead moveq.l #iPhaseMsk, d0 ; load mask for phase bits and.b rSTA(a3), d0 ; are we in data-in phase? cmpi #iDataIn, d0 ; data-in phase bits = 001 bne.w phaseErr1 ; bra. on phase err clr.l d3 ; init compare status move.l d2, d4 ; d4 = copy of transfer count lsr.l #4, d4 ; divide xfer count by 16 beq.w @16orLess ; bra. if < 16 bytes subq.l #1, d4 ; adjust for DBRA move.l d4, d6 ; d4.w has lower 16-byte block count swap d6 ; d6.w has upper 16-byte word count @16orMore ; The next few lines are necessary in order to poll a DREQ in nuBus ; address space. We don't need to do this if we're xferring <16 bytes. jsr SCSIpcTo32bit ; use pc relative move.b MMU32Bit, -(sp) ; save current mode on stack moveq #true32B, d0 ; switch to 32-bit mode to look at SCSI config regr jsr SwapMMU ; do it, call _SwapMMUMode jump vector move.l a2, d0 ; get destination addr in d0 _StripAddress ; clear upper byte if necessary move.l d0, a2 ; a2 = clean buffer ptr move.l G_SCSIDREQ(a4), a0 ; load SCSI DREQ regr move.b #0, rXCM(a3) ; rXCM = 0, clear most-sig. byte count move.b #$10, rXCL(a3) ; rXCL = 16 bytes, least-sig. byte value and.l #$F, d2 ; d2 = remainder word count after 16-byte moves @read16 move.b #cDMAXfer, rCMD(a3) ; load DMA transfer cmd & start loading FIFO if nonSerializedIO Then nop ; Force write to complete. endif @1 ; currently loaded transfer count is used/reused btst.b #bINT, rSTA(a3) ; poll for unexpected intrp while waiting bne.s @prematureEnd ; ... maybe disconnected, phase changed, etc. btst.b #bTRC, rSTA(a3) ; check if we've rcvd all the data beq.s @1 ; loop until FIFO is full ; We need 16 guaranteed DREQs to safely transfer 16 bytes without bus error. ; Ideally, DREQ should be active as long there are threshold number of bytes in the ; FIFO--as the c96 user's guide imply. But the c96 implementation also requires that ; REQ be active in order to get DREQ. This is why we must wait for the 17th REQ from ; the target--and it must remain active--before we proceed with the 16-byte transfer. IF forPDMDebug THEN ; move.b (a0), d5 ; read DAFB regr (a0=DAFB register addr) ELSE move.l (a0), d5 ; read DAFB regr (a0=DAFB register addr) ENDIF move.b G_bitDREQ(a4),d0 ; load DREQ bit position <5> jab btst.l d0, d5 ; DREQ ? <5> jab beq.s @1 ; loop until asserted move.w #$7, d5 ; load loop counter, 8 words @cmpFFO move.w rDMA(a3), d0 ; cmp.w (a2)+, d0 ; compare a word at a time beq.s @Ok1 moveq.l #scCompareErr, d3 ; record a compare error @Ok1 dbra d5, @cmpFFO ; continue with compare operation @2 ; Intrp should occur after ALL data have been ; read out of the FIFO btst.b #bINT, rSTA(a3) ; check for c96 INTRP beq.s @2 ; loop until we get the intrp move.b rINT(a3), d5 ; read Intrp regr & clear rSTA, rSQS & rINT btst.l #bDSC, d5 ; check for disconnected intrp bne.s @premature2 ; Branch if transfer error dbra d4, @read16 ; loop until done, d4 is lower word count dbra d6, @read16 ; loop until done, d6 is upper word count move.b (sp)+, d0 ; switch to previous address mode jsr SwapMMU ; do it, call _SwapMMUMode jump vector bra.s @16OrLess ; take care of remaining data, if any @rdSingle ; use non-pDMA for remainder moveq.l #iPhaseMsk, d5 ; load mask bits for phase value and.b rSTA(a3), d5 ; are we still in data-in phase? cmpi.b #iDataIn, d5 ; data-in phase bits = 001 bne.s @phaseErr ; bra. on phase err move.b #cIOXfer, rCMD(a3) ; load IO transfer cmd & begin xfers if nonSerializedIO Then nop ; Force write to complete. endif @3 btst.b #bINT, rSTA(a3) ; check for c96 INTRP beq.s @3 ; loop until we get an intrp move.b rFFO(a3), d0 ; read byte data from FIFO cmp.b (a2)+, d0 ; xfer byte from FIFO into input buffer beq.s @Ok2 moveq.l #scCompareErr, d3 ; record a compare error @Ok2 move.b rINT(a3), d5 ; read Intrp regr & clear rSTA, rSQS & rINT btst.l #bDSC, d5 ; check for disconnected intrp bne.s @xferErr ; Branch if transfer error @16OrLess dbra d2, @rdSingle ; read the rest of the remainders @ExitCmp ; d1 = # of bytes transferred move.l d3, d0 ; return status rts ; @prematureEnd bsr.w WaitForIntNoTime ; Clear pending intrp & get err status ; on exit d5 = rFOS|rINT|0|rSTA @premature2 move.b (sp)+, d0 ; switch to previous address mode jsr SwapMMU ; do it, call _SwapMMUMode jump vector ; calc how many bytes were xferred... addq.w #1, d4 ; undo adjustment for dbra swap d6 ; calculate bytes left to transfer move.w d4, d6 ; form long word count lsl.l #4, d6 ; mult by 16 and.b #iPhaseMsk, d5 ; are we still in data-in phase? cmpi.b #iDataIn, d5 ; data-in phase bits = 001 beq.s @xferErr ; bra. to check for disconnect @phaseErr moveq.l #scPhaseErr, d0 ; return a phase error bra.s @badSCmp ; @xferErr ; anything else is a comm. err moveq.l #scCommErr, d0 ; transfer error @badSCmp add.l d2, d6 ; add un-xferred remainder sub.l d6, d1 ; number of bytes transferred move.l #scsiRead+$F0, d6 ; load proc ID, Slow compare jsr Error ; call Error proc - for debug move.b #cFlshFFO, rCMD(a3) ; Flush FIFO if nonSerializedIO Then nop ; Force write to complete. endif rts ; ;___________________________________________________________________________ to next ; ; BusErrHandler_96 ; 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_96 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…, etc.). At least don't leave it there during periods where a ; buserr may be possible. ; ___________________________________________________________________________; WITH AEXFrame, XferFrame savedRegs REG D0-D3/A0-A1 ; save these registers because we need to use them added D3 savedRSize EQU 6*4 ; # bytes on stack for saved registers added D3 BusErrHandler_96 ; 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) cmp.l SCSIGlobals, A4 ; equal if this is from our transfer routine bne.s @notSCSIFault btst.b #HandleBusErrs, G_State96(A4) ; are we supposed to be active? beq.s @notSCSIFault ; no - not SCSI's fault move.l SCSIBase, D0 ; check if bus err on SCSI Bus0 address addi.l #rDMA, D0 ; add pseudo-DMA offset cmp.l FaultAddr(A0), D0 ; compare with faulted address beq.s @SCSIFault ; if so, start processing the bus error addi.l #nonSerlzdDisp, D0 ; add non-serialized offset cmp.l FaultAddr(A0), D0 ; compare with faulted address beq.s @SCSIFault ; if so, start processing the bus error move.l SCSI2Base, D0 ; check if bus err on SCSI Bus1 address addi.l #rDMA, D0 ; add pseudo-DMA offset cmp.l FaultAddr(A0), D0 ; compare with faulted address beq.s @SCSIFault ; if so, start processing the bus error addi.l #nonSerlzdDisp, D0 ; add non-serialized offset 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 SCSIGlobals, A0 ; put entry point to prev BEH on stack move.l yeOldeBusErrVct(A0), savedRSize(sp) ; (registers saved beneath return addr) movem.l (sp)+, savedRegs ; restore regs rts ; jump to old handler, assuming it'll RTE ; It's all our fault (blame it on us) ------ @SCSIFault ; old timed routine (using Ticks instead of TimeSCSIDB) ; cmp.l BusErrAddr(A6), A2 ; did we buserr at this point in the xfer b4? ; beq.s @oldBusErr ;@newBusErr ; move.l A2, BusErrAddr(A6) ; remember point in xfer that we got buserr ; move.l blindBusTO(A4), D0 ; init BusErrTO with… ; add.l Ticks, D0 ; BlindBusTO+Ticks ; move.l D0, BusErrTO(A6) ;@oldBusErr ; Wait for either DREQ, or INT or a timeout (from blindBusTO value) jsr SCSIpcTo32bit ; use pc relative moveq #true32B, D0 ; switch to 32-bit mode to look at SCSI config regr jsr SwapMMU ; (sets up d0 with previous mode) move.w D0, -(sp) ; save D0 (contains previous MMU mode) move.l G_SCSIDREQ(A4), A1 ; G_SCSIDREQ contains DREQ regr address move.l (A1), D0 ; read DAFB regr move.b G_bitDREQ(a4),d3 ; load DREQ bit position <5> jab btst.l d3, d0 ; DREQ ? <5> jab bne.s @retry move.l blindBusTO(A4), D1 bra.s @outerbtm ; bra to bottom of loop for zero case <2> @outerTop move.w TimeSCSIDB, D2 lsr.w #1, D2 ; divide by 2 (because of 5 instr'ns instead of 2) <2> @1 move.l (A1), D0 ; read DAFB regr btst.l d3, d0 ; DREQ ? <5> jab bne.s @retry btst #bINT, rSTA(A3) ; see if we have a phase change or something dbne D2, @1 bne.s @phzChange ; @outerbtm dbra D1, @outerTop ; loop dec. on low word of blindBusTO sub.l #$00010000, D1 ; sub 1 from high word of blindBusTO bcc.s @outerTop ; loop if result >=0 bra.s @cleanup ; if DREQ, retry the transfer ----- @retry move.w (sp)+, D0 ; get previous MMU mode into D0 jsr SwapMMU ; return to previous mode ; Clean up the writebacks on the stack frame <5> thru to next <5> jab 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 <5> jab movem.l (sp)+, savedRegs ; restore regs addq.l #4, sp rte ; haven't reached max retry count, so restart ; if phase change or timeout, cleanup and abort the transfer ----- @phzChange @cleanup ; return to previous MMU mode and return SP to the exception stack frame move.w (sp)+, D0 ; get previous MMU mode into D0 jsr SwapMMU ; return to previous mode 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 cmp.w #scsiReadFast, transferType(A4) bne.s @skipLeftovers move.b rFOS(a3), D0 ; get FIFO status - how many bytes in FIFO and.w #iFOFMsk, 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 @2 move.b rFFO(a3), (A2)+ ; get byte from chip and put into user's buffer @2 ; get rid of excp'n frame and create a throwaway frame for return to Transfer_96 @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 move.w zeroReg, -(sp) ; format code 0 pea FinishErr ; PC value move.w d0, -(sp) ; sr value rte ; 'return' from the fake exception ; If we busErr due to a slow peripheral then the c96 is still expecting to transfer ; data since it has no concept of bus error. Hopefully, the client upon seeing busTOErr ; will do the right thing and call SCSIComplete to clean up the bus. ;----------------- FinishErr ;----------------- ; What we really need to do here is to first empty the FIFO the call Wt4DREQorINT ; then do the right thing. %%% moveq.l #scBusTOErr, d0 ; assume bus timeout btst.b #bINT, rSTA(a3) ; poll for intrp due to premature phase change beq.s @ErrorDone ; bra. if no SCSI intrp 'cuz we busTO move.b rINT(a3), d5 ; got intrp so check cause also read & clear rFOS, rSTA & rINT btst.l #bBSS, d5 ; test for bus service intrp beq.s @ErrorDone ; bra. if not bus service moveq.l #scPhaseErr, d0 ; yup it's a premature phase change @ErrorDone rts ; return status in d0 to the Transfer routine from prev ;----------------- 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 ;========================================================================== ENDWITH END