mirror of
https://github.com/elliotnunn/boot3.git
synced 2024-11-18 15:07:14 +00:00
5b0f0cc134
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
1607 lines
56 KiB
Plaintext
1607 lines
56 KiB
Plaintext
;
|
|
; File: SCSIMgr96.a
|
|
;
|
|
; Contains: SCSI Mgr for the 53C96
|
|
;
|
|
; Written by: Far Too Many People
|
|
;
|
|
; Copyright: © 1990-1993 by Apple Computer, Inc. All rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM11> 9/13/93 SAM Removed a redundant definition of Translate24to32.
|
|
; <SM10> 1/26/93 SAM Put in a PDMDebug only mod to CyclePhases to drop into macsbug
|
|
; when it gets called. Only call HwPriv's FlushRangeCodeCache at
|
|
; the end of data xfer calls only on 040s running VM.
|
|
; <SM9> 11/3/92 SWC Changed SCSIEqu.a->SCSI.a.
|
|
; <SM8> 10/18/92 CCH Added nop's to support non-serial IO space, and conditionals to
|
|
; use byte accesses to the DREQ register.
|
|
; <4> 5/22/92 DTY #1029009 <jab>: Modified DREQ bit testing from global (setup in
|
|
; SCSIInit96).
|
|
; <3> 5/1/92 JSM DonÕt use isUniversal conditional, which was always commented
|
|
; out anyway.
|
|
; <2> 10/24/91 SAM Changed an include of HardwareEqu to HardwarePrivEqu.
|
|
; <1> 10/24/91 SAM Rolled in Regatta file.
|
|
;
|
|
; Regatta Change History
|
|
;
|
|
; <3> 8/21/91 SAM (PDW) Added a FlushCacheRange call of the BusErrVct (long word
|
|
; at 8) after replacing my BEH with the previous BEH. This is to
|
|
; fix VM_On/BEHandler bug which is apparently a bug with MOVE16
|
|
; instructions that cause Access Errors (page faults).
|
|
; <2> 8/19/91 SAM (PDW) SendCmd_96 did not correctly detect a premature end of
|
|
; command phase. Added a wait for FIFO empty or phase change to
|
|
; detect this. Turned slow_cable mode off after sending command
|
|
; (like we did before B2).
|
|
; <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 7.0 GM sources.
|
|
;
|
|
; Terror Change History:
|
|
;
|
|
; <T9> 6/27/91 djw (actually PDW) Removed all traces of SCSIBusy and FreeHook
|
|
; stuff. Made minimum CDB 1 byte instead of 2. Added slow cable
|
|
; mode to command phase to improve reliability. Added multi-stage
|
|
; select modeling to handle many more odd phase transitions.
|
|
; Rewrote CyclePhase to handle all phases instead of just data
|
|
; phases and also to handle new Select sequence flags.
|
|
; Jump-vectorized CyclePhase_96.
|
|
; <T8> 6/14/91 djw (actually PDW) Made mods to Interrupt handling of Select to work
|
|
; with devices that go from Select to Status phz (like the
|
|
; LaserWriter SC). Also eliminated wait for Select complete
|
|
; interrupt at end of Command - we can do it in data phz or
|
|
; Complete. Changed Select watchdog to be longer than the timeout
|
|
; value used by the '96 (512mS vs 256mS).
|
|
; <T7> 6/9/91 BG Rolled in Paul Wolf's SCSI changes: Rearranged headers to work
|
|
; more consistently between test INIT and ROM builds. (Should not
|
|
; affect ROM build).
|
|
; <T6> 5/24/91 CCH Rolled in Paul Wolf's SCSI fixes: Reworked DoSCSISelect_D96
|
|
; procs: Disabled automatic redirection of select if a device
|
|
; disappears. Added 512mS delay after SCSIReset to fix Quantum
|
|
; Q250 bug and to be consistent with all old CPUs.
|
|
; <T5> 4/22/91 BG (actually JMA) Reworked DoSCSIComplete proc and fix SendCmd.
|
|
; <T4> 3/30/91 BG (actually JMA) Reworked SendCmd and DoSCSISelect procs; fixed
|
|
; SCSIStat bug; incorporated new FS hook fix but still is UNUSED.
|
|
; <T3> 2/17/91 BG (actually JMA) Added Error calls, removed _Debugger calls, fixed
|
|
; CyclePhase bug, added DoSCSIBusy_96 support & move stuff around.
|
|
; <T2> 1/5/91 BG (actually JMA) Added functionalities.
|
|
; <T1> 12/7/90 JMA Checked into TERROR for the first time.
|
|
;
|
|
;========================================================================== <T3>
|
|
|
|
|
|
MACHINE MC68020
|
|
BLANKS ON
|
|
STRING ASIS
|
|
PRINT OFF
|
|
|
|
LOAD 'StandardEqu.d'
|
|
INCLUDE 'HardwarePrivateEqu.a'
|
|
INCLUDE 'SCSI.a'
|
|
INCLUDE 'SCSIPriv.a'
|
|
INCLUDE 'UniversalEqu.a'
|
|
INCLUDE 'SCSIEqu96.a'
|
|
|
|
PRINT ON
|
|
|
|
SCSI96 PROC EXPORT
|
|
|
|
EXPORT SCSIMgr_96
|
|
EXPORT DoSCSICmd_96, DoSCSIComplete_96
|
|
EXPORT DoSCSISelect_S96, DoSCSISelect_D96 ; <T2>
|
|
EXPORT DoSCSISelAtn_S96, DoSCSISelAtn_D96, CyclePhase_96 ; <T9>
|
|
EXPORT DoSCSIStat_96, DoSCSIMsgOut_96
|
|
EXPORT SwapMMU, SCSIpcTo32bit, Error
|
|
|
|
|
|
EXPORT Unimplemented_96
|
|
EXPORT DoSCSIReset_96, DoSCSIGet_96 ; <T2>
|
|
EXPORT DoSCSIMsgIn_96 ; <T2>
|
|
EXPORT NewSCSIRead_96, NewSCSIWrite_96
|
|
EXPORT NewSCSIWBlind_96, NewSCSIRBlind_96
|
|
EXPORT SCSIpcTo32Bit ; <T9>
|
|
EXPORT Error, SCSIErr_96 ; <T9>
|
|
|
|
|
|
IMPORT Xfer1Byte, WaitForSCSIIntrp, WaitForIntNoTime
|
|
IMPORT Wt4DREQorInt, HandleSelInProg
|
|
|
|
WITH scsiPB, scsiPrivPB
|
|
WITH scsiGlobalRecord, dcInstr
|
|
VMGlobals EQU $0B78 ; Pointer to VM's globals (yeah, yeah, had to do it) <SM10> SAM
|
|
|
|
;==========================================================================
|
|
|
|
|
|
|
|
;-------------------------------------------------------------
|
|
;
|
|
; A SCSI Function request handler. SCSI's are invoked by params on
|
|
; stack followed by a routine selector Int, and return address.
|
|
; NOTE: SCSIMgr is a Toolbox trap & follows Pascal calling conventions.
|
|
;
|
|
; A4 is set up by StdEntry and contains a pointer to the SCSI Manager global
|
|
; area in the system heap.
|
|
;
|
|
|
|
SCSIMgr_96: ; "Normal" 680x0 CPU's with "SCSIGlobals" lomem
|
|
move.l (sp)+,a0 ; get the return address
|
|
move.w (sp)+,d0 ; function selector (word)
|
|
move.l a0,-(sp) ; push the return address
|
|
|
|
cmp.w #numSelectors,d0 ; valid selector?
|
|
bhs.s Unimplemented_96 ; Sorry, Charlie
|
|
|
|
link a6,#LocalSize ; locals for bus error stuff
|
|
movem.l a2-a5/d2-d7,-(sp) ; save registers
|
|
movea.l SCSIGlobals,a4 ; get pointer to SCSI Manager globals
|
|
|
|
scsiMgrCommon
|
|
move.l base5380(a4),a3 ;
|
|
moveq.l #0,zeroReg
|
|
moveq.l #0,d4 ; needed by read/write
|
|
|
|
move.w d0,d1 ; save a copy of selector
|
|
|
|
move.l 0(a4,d0.w*4),a0 ; indexed addressing
|
|
|
|
jmp (a0) ; and go there
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
StdExit
|
|
movem.l (sp)+, a2-a5/d2-d7 ; restore these guys
|
|
unlk a6
|
|
move.l (sp)+, a0 ; get return address
|
|
add.w d0, sp ; fixup the stack <T4>
|
|
jmp (a0)
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; Common code when exiting old SCSI Mgr after an error
|
|
;
|
|
; Uses : d0, a0
|
|
|
|
ExitCleanup:
|
|
move.b zeroReg, G_State(a4) ; clear out SCSI Mgr semaphore
|
|
; (from ClearState proc, SCSIMgrNew.a)
|
|
rts ; <T3>
|
|
|
|
|
|
|
|
|
|
;----------------------------------------------------------------
|
|
;
|
|
; Unimplemented selector (or out of range)
|
|
;
|
|
|
|
Unimplemented_96
|
|
moveq.l #dsCoreErr, d0 ; unimplemented core routine <T3>
|
|
_SysError ; sorry, Charlie <T3>
|
|
@1 bra.s @1 ; not safe to continue
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; FUNCTION SCSIStat: INTEGER;
|
|
; (8)
|
|
;
|
|
; Get SCSI bus status.
|
|
;
|
|
; A bit-to-bit bus and status register mapping is not possible from the 53C80 to 53C96.
|
|
; Consequently, we fake the status and return what we think the status should be.
|
|
; Also note that we OR the two SCSI bus stati(?) because only 2 situations are possbile:
|
|
; 1) One bus is active and the other idle 2) both buses are idle.
|
|
;
|
|
; The following list is the status bit map:
|
|
; signal names in parenthesis are the closest c96 status bit equivalents
|
|
;
|
|
; 53c80 Status Bit 53c96 Status Bits
|
|
; DBP n/a
|
|
; SEL n/a
|
|
; I/O I/O
|
|
; C/D C/D
|
|
; MSG MSG
|
|
; REQ n/a (1 if scBusy)
|
|
; BSY n/a (1 if scBusy)
|
|
; RST n/a <T4>
|
|
; ACK n/a
|
|
; ATN n/a
|
|
; BSY ERR n/a <T4>
|
|
; PHS MAT n/a
|
|
; INT REQ n/a (INT PEND)
|
|
; PRT ERR n/a <T4>
|
|
; DMA REQ DREQ (DMA REQ) <T4>
|
|
; END DMA n/a
|
|
;
|
|
; G_FakeStat contains fake bit values that different procs of the SCSI manager
|
|
; have set or cleared. The values in it reflect the best-guessed status of the
|
|
; bus as determined by the SCSI manager.
|
|
;
|
|
; Uses: d0, d1, d2
|
|
;
|
|
; Return Codes:
|
|
; noErr
|
|
|
|
DoSCSIStat_96
|
|
and.w #$FFF2, G_FakeStat(a4) ; clear phase bits first, except SEL <T4>
|
|
move.l a3, -(sp) ; save a3
|
|
clr.l d1 ;
|
|
move.l base539x0(a4), a3 ; load ptr for SBus0 <T2>
|
|
move.b rSTA(a3), d1 ; read this bus' status <T2>
|
|
|
|
TestFor SCSI96_2Exists ; do we have a 2nd SCSI96 chip? <T2>
|
|
beq.s @noSCSI96 ; bra. if no 2nd SCSI96 <T2>
|
|
move.l base539x1(a4), a3 ; load ptr for SBus1 <T2>
|
|
or.b rSTA(a3), d1 ; OR this bus' status <T2>
|
|
@noSCSI96 ; <T2>
|
|
|
|
move.l (sp)+, a3 ; restore a3
|
|
andi.b #iPhaseMsk, d1 ; mask off the rest to get phase bits
|
|
lsl.b #2, d1 ; position the MSG-CD-IO bits
|
|
or.w d1, G_FakeStat(a4) ;
|
|
|
|
moveq.l #aBSY+aSEL, D0 ; what are Busy and Sel signals set to?
|
|
and.w G_FakeStat(a4), D0
|
|
cmp.w #aBSY, D0 ; if Busy but no Sel,
|
|
bne.s @1 ;
|
|
or.w #aREQ, G_FakeStat(a4) ; set REQ also
|
|
bra.s @2
|
|
@1
|
|
and.w #$FFFF-aREQ, G_FakeStat(a4) ; else, clear REQ
|
|
@2
|
|
move.w G_FakeStat(a4), 8(a6) ; 8(a6) <- Bus and Status
|
|
bra.s NoByteExit ; 9(a6) <- Current SCSI Bus Status
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; FUNCTION SCSIReset: INTEGER;
|
|
; (8)
|
|
;
|
|
; If we have two scsi buses, hard reset both since the interface does not provide a <T2>
|
|
; way for the client to specify a target bus in a dual-SCSI bus system. <T2>
|
|
;
|
|
; Uses: a0, a3, d0, d2, d3
|
|
;
|
|
; Return Codes:
|
|
; noErr
|
|
|
|
DoSCSIReset_96
|
|
move.l a3, -(sp) ; save a3 <T2>
|
|
movea.l jvResetBus(a4), a0 ; get address of SCSI reset routine <T2>
|
|
move.l base539x0(a4), a3 ; load ptr for SBus0 <T2>
|
|
jsr (a0) ; reset SCSI bus and kill all requests <T2>
|
|
|
|
TestFor SCSI96_2Exists ; do we have a second SCSI96 chip? <T2>
|
|
beq.s @noSCSI96 ; bra. if no 2nd SCSI96 <T2>
|
|
movea.l jvResetBus(a4), a0 ; get address of SCSI reset routine <T2>
|
|
move.l base539x1(a4), a3 ; load ptr for SBus1 <T2>
|
|
jsr (a0) ; reset SCSI bus and kill all requests <T2>
|
|
@noSCSI96 ; <T2>
|
|
|
|
move.l (sp)+, a3 ; restore a3
|
|
move.l #0, G_FakeStat(a4) ; clear fake status
|
|
move.w zeroReg, 8(a6) ; always returns 0 status
|
|
bsr.s ExitCleanup ; clean up to leave
|
|
|
|
moveq.l #0, d2 ; clear upper word <T6> thru next <T6>
|
|
move.w TimeDBRA, d2 ; get # of DBRAs per mS
|
|
lsl.l #8, d2 ; multiply by É
|
|
lsl.l #1, d2 ; É512
|
|
move.l d2, d3 ; ...a 512mS wait
|
|
swap d3
|
|
@1
|
|
dbra d2, @1 ; d2 low word of counter
|
|
dbra d3, @1 ; d3 high word <T6>
|
|
|
|
|
|
|
|
|
|
NoByteExit
|
|
moveq.l #0, d0 ; no arguments to clean up
|
|
bra.w StdExit
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; FUNCTION SCSIGet: INTEGER;
|
|
; (8)
|
|
;
|
|
; SCSI arbitration is now an integrated operation with SELECT
|
|
; in the 5394/5396. It is here only for backward compatibility. We will fake
|
|
; an asserted BSY & SEL signals just in case the user above decides to perform
|
|
; a SCSIStat.
|
|
;
|
|
; IMPORTANT: SCSIMgr clients MUST still call SCSIGet before SCSISelect. This will be enforced in <T4>
|
|
; SCSISelect. G_State will be used as a flag to indicate that SCSIGet was called.
|
|
;
|
|
; Uses: d0, d1, d2, d3
|
|
;
|
|
; Return Codes:
|
|
; noErr
|
|
|
|
DoSCSIGet_96
|
|
bset.b #scBusy, G_State(a4) ; set to SCSI busy state <T2>
|
|
bne.s @isBusy ; if nonzero, SCSI Mgr is in use <T2>
|
|
|
|
; move.l zeroReg, d0 ; disable SCSI interrupts with old SCSI Mgr
|
|
; movea.l jvDisEnable(a4), a0 ; addr of interrupt enable/disable routine
|
|
; jsr (a0) ; disable interrupts
|
|
|
|
move.w #aBSY+aSEL, G_FakeStat(a4) ; Set to a fake successful arb status
|
|
moveq.l #noErr, d0 ; no error
|
|
@exit ; <T2>
|
|
move.w d0, 8(a6) ; return code
|
|
bra.s NoByteExit
|
|
|
|
@isBusy ; <T2>
|
|
moveq.l #scMgrBusyErr ,d0 ; SCSI Mgr is busy <T2>
|
|
bra.s @exit ; bail out in order to avoid deadlock <T2>
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; FUNCTION SCSISelect(TargID:INTEGER): INTEGER;
|
|
; FUNCTION SCSISelAtn(TargID:INTEGER): INTEGER;
|
|
; (8) (10)
|
|
;
|
|
; Select the target at TargID on the "virtual" SCSI bus. Returns 0 for success, or error.
|
|
; Selection can be done with or without the ATN line.
|
|
;
|
|
; This proc sets up the proper SCSI chip addresses for Select_96 for dual-bus machines.
|
|
; It uses the G_SCSIDevMapX bitmap for each bus with 1 bit for each ID on that bus to
|
|
; decide which bus to send a selection attempt to. During initialization of the SCSI
|
|
; manager, these bitmaps are cleared, indicating that no device has been detected at
|
|
; any of the SCSI IDs for either bus. The proper bit is set the first time a successful
|
|
; select of that ID on that bus is performed.
|
|
;
|
|
; Functionally, if no device has been seen on either the internal or external buses,
|
|
; the internal bus will be checked first and if that fails, the external bus is checked.
|
|
; If both fail (if no device is at that ID on either bus) then neither bit will have
|
|
; been set. Also, if a device has been seen once at a certain ID, then that ID will
|
|
; only be accessible from that bus until the next reboot.
|
|
;
|
|
; This routine will first check the state of the requested ID's external bit. If it
|
|
; is set, the first and only selection attempt is performed on bus 1 otherwise it is
|
|
; attempted on bus 0. If the bus 0 select fails, then the bus 0 bitmap is checked to
|
|
; see if there was previously a device at that ID. If there wasn't then a selection
|
|
; is sent to bus 1 as well.
|
|
|
|
DoSCSISelect_D96
|
|
DoSCSISelAtn_D96
|
|
bset.b #scBusy, G_State(a4) ; set SCSI busy state here too for those who bypass SCSIGet <T4>
|
|
move.w G_FakeStat(a4), -(sp) ; save fake status <T4>
|
|
move.w #aBSY, (sp) ; assume successful selection, set fake status <T4>
|
|
|
|
moveq.l #0, d6 ; clear upper bits <T6> thru next <T6>
|
|
move.w 8(a6), d6 ; get the target's ID
|
|
cmp.w #scsiSelAtn, d1 ; select with ATN?
|
|
bne.s @noATN ; no ATN
|
|
;@wATN
|
|
bset.l #16, d6 ; use ATN
|
|
ori.w #aATN, (sp) ; assume successful select w/ATN, set fake status <T4>
|
|
@noATN
|
|
move.l d6, G_TargetID(a4) ; remember destination ID & ATN bit
|
|
btst.b d6, G_SCSIDevMap1(a4) ; if this device is marked as on bus 1...
|
|
bne.s @SBus1 ; then try select on bus 1
|
|
|
|
@SBus0 ; else try select on bus 0
|
|
move.l base539x0(a4), a3 ; load SCSI base 0
|
|
move.l a3, base5380(a4) ; expected SCSI base adrs for this ID for SCSIRead/Write/Complete etc.
|
|
move.l pdma5380(a4), a0 ; pdma5380 contains DREQ regr address
|
|
move.l d6, d0 ; copy target ID
|
|
bsr.w Select_96 ; try it
|
|
bne.s @fldSel0 ; branch if select failed
|
|
bset.b d6, G_SCSIDevMap0(a4) ; else record this device's existence
|
|
bra.s @exit
|
|
@fldSel0
|
|
btst.b d6, G_SCSIDevMap0(a4) ; if this device was marked as on bus 0
|
|
bne.s CommonSelErrXit ; then we return an error
|
|
; else we try bus 1
|
|
@SBus1
|
|
move.l base539x1(a4), a3 ; load SCSI base 1
|
|
move.l a3, base5380(a4) ; expected SCSI base adrs for this ID for SCSIRead/Write/Complete etc.
|
|
move.l hhsk5380(a4), a0 ; hhsk5380 contains DREQ regr address
|
|
move.l d6, d0 ; copy target ID
|
|
bsr.w Select_96 ; try it
|
|
bne.s CommonSelErrXit ; branch if select failed
|
|
bset.b d6, G_SCSIDevMap1(a4) ; else record this device's existence
|
|
;; bra.s @exit
|
|
|
|
|
|
@exit
|
|
move.w (sp)+, G_FakeStat(a4) ; save new fake status <T4>
|
|
move.l a0, G_SCSIDREQ(a4) ; save SCSI DREQ regr for SCSIRead/Write/Complete etc.
|
|
move.w d0, 10(a6) ; return the result
|
|
moveq.l #2, d0 ; stack cleanup
|
|
bra.w StdExit ; <T6> from prev <T6>
|
|
|
|
|
|
;-----------------
|
|
|
|
CommonSelErrXit ; common Select error exit
|
|
clr.w (sp) ; set failed fake status
|
|
move.l d0, -(sp) ; save d0
|
|
bsr.w ExitCleanup ; clean up to leave
|
|
move.l (sp)+, d0 ; restore d0
|
|
move.l #scsiSelect, d6 ; load proc ID
|
|
bsr.w Error ; call Error proc - for debug
|
|
move.w (sp)+, G_FakeStat(a4) ; save new fake status
|
|
move.w d0, 10(a6) ; return the result
|
|
moveq.l #2, d0 ; stack cleanup
|
|
bra.w StdExit ; special exit <T9>
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; FUNCTION SCSISelect(TargID:INTEGER): INTEGER;
|
|
; FUNCTION SCSISelAtn(TargID:INTEGER): INTEGER;
|
|
; (8) (10)
|
|
;
|
|
; Select the target on the bus. Returns 0 for success, or error.
|
|
; Selection can be done with or without the ATN line.
|
|
; Single SCSI BUS Select Proc
|
|
|
|
DoSCSISelect_S96
|
|
DoSCSISelAtn_S96
|
|
bset.b #scBusy, G_State(a4) ; set SCSI busy state here too for those who bypass SCSIGet <T4>
|
|
move.w G_FakeStat(a4), -(sp) ; save fake status <T4>
|
|
move.w #aBSY, (sp) ; assume successful selection, set fake status <T4>
|
|
|
|
moveq.l #0, d0 ; clear upper bits
|
|
move.w 8(a6), d0 ; get the target's ID
|
|
cmp.w #scsiSelAtn, d1 ; select with ATN?
|
|
bne.s @noATN ; no ATN
|
|
bset.l #16, d0 ; use ATN
|
|
ori.w #aATN, (sp) ; assume successful select w/ATN, set fake status <T4>
|
|
@noATN
|
|
move.l d6, G_TargetID(a4) ; remember destination ID & ATN bit <T9>
|
|
move.l pdma5380(a4), a0 ; pdma5380 contains DREQ regr address
|
|
bsr.w Select_96 ; try it
|
|
bne.s CommonSelErrXit ; branch if error <T4>
|
|
@exit
|
|
move.w (sp)+, G_FakeStat(a4) ; save new fake status <T4>
|
|
move.l a0, G_SCSIDREQ(a4) ; save SCSI DREQ regr
|
|
move.w d0, 10(a6) ; return the result
|
|
moveq.l #2, d0 ; stack cleanup
|
|
bra.w StdExit
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; FUNCTION SCSICmd(Buffer:Ptr, Count:INTEGER): INTEGER;
|
|
; (10) (8) (14)
|
|
;
|
|
; Send the target the given command.
|
|
;
|
|
; Return Codes:
|
|
; noErr, scPhaseErr, scCommErr
|
|
|
|
DoSCSICmd_96
|
|
move.l 10(a6), a2 ; get command buffer address
|
|
move.w 8(a6), d2 ; get the length
|
|
bsr.w SendCMD_96 ; send it
|
|
bne.s @err ; bra. if error
|
|
@exit ; <T3> thru next T3>
|
|
move.w d0, 14(a6) ; return the result
|
|
moveq.l #6, d0
|
|
bra.w StdExit
|
|
@err
|
|
move.l d0, -(sp) ; save d0
|
|
move.l (sp)+, d0 ; restore d0
|
|
|
|
move.l #scsiCmd, d6 ; load proc ID
|
|
bsr.w Error ; call Error proc - for debug
|
|
bra.s @exit ; <T3>
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; SCSIRead, SCSIRBlind, SCSIWrite, SCSIWBlind
|
|
;
|
|
; Called by: Toolbox Trap Dispatcher
|
|
;
|
|
; Calls: Transfer, primitive data transfer routines
|
|
;
|
|
; On entry: a3 - SCSI read base address
|
|
; a4 - pointer to SCSI Manager globals
|
|
;
|
|
; Internal: a1 - TIB scan pointer
|
|
;
|
|
; Function: Performs TIB interpretation, and data transfers.
|
|
|
|
NewSCSIWBlind_96
|
|
moveq.l #scsiWriteFast, d4 ; select the fast write routine
|
|
bra.s dataCommon_96 ; continue
|
|
NewSCSIWrite_96
|
|
moveq.l #scsiWriteSlow, d4 ; select the slow write routine
|
|
bra.s dataCommon_96 ; continue
|
|
NewSCSIRBlind_96
|
|
moveq.l #scsiReadFast, d4 ; select the fast read routine
|
|
bra.s startRead_96 ; continue
|
|
NewSCSIRead_96
|
|
moveq.l #scsiReadSlow, d4 ; select the slow read routine
|
|
startRead_96
|
|
|
|
dataCommon_96
|
|
|
|
move.l 8(a6), a1 ; get the TIB pointer
|
|
bra.s @exec ; tighten loop by branching first
|
|
|
|
@c_compare
|
|
bset.l #scsiCompBit, d4 ; add offset to use the compare routines
|
|
; FALL THROUGH to @c_inc ; continue
|
|
|
|
@c_inc
|
|
movea.l jvTransfer(a4), a0 ; get the address of the transfer routine
|
|
jsr (a0) ; go to the transfer routine
|
|
bne.s @data_end ; if error, bail out
|
|
add.l d1, scParam1(a1) ; increment the pointer
|
|
bclr.l #scsiCompBit, d4 ; remove offset for the compare routines
|
|
; FALL THROUGH to @next_cmd ; continue
|
|
|
|
@next_cmd
|
|
@c_nop ; also NOP, just skip the command
|
|
add.w #scSize, a1 ; point to the next TIB instruction
|
|
; FALL THROUGH to @exec
|
|
|
|
@exec
|
|
move.w scOpcode(a1), d1 ; get the function opcode
|
|
move.l scParam1(a1), a2 ; get the generic address
|
|
move.l scParam2(a1), d2 ; get the generic count
|
|
|
|
cmp.w #maxOpcode, d1 ; valid opcode ?
|
|
bhi.s @c_badop ; return err if not
|
|
|
|
add.w d1,d1 ; index times two
|
|
jmp @JmpTable(d1.w) ; jump into table
|
|
|
|
@JmpTable ;
|
|
bra.s @c_badop ; 0 is not a valid opcode
|
|
bra.s @c_inc ; 1
|
|
bra.s @c_noinc ; 2
|
|
bra.s @c_add ; 3
|
|
bra.s @c_move ; 4
|
|
bra.s @c_loop ; 5
|
|
bra.s @c_nop ; 6
|
|
bra.s @c_stop ; 7
|
|
bra.s @c_compare ; 8
|
|
|
|
@c_badop
|
|
moveq.l #scBadparmsErr, d0 ; bad opcode
|
|
bra.s @data_end
|
|
|
|
@c_noinc ; NOINC addr,count
|
|
movea.l jvTransfer(a4), a0 ; get the address of the transfer routine
|
|
jsr (a0) ; go to the transfer routine
|
|
|
|
bne.s @data_end ; if error, exit
|
|
bra.s @next_cmd ; else process next command
|
|
|
|
@c_add ; ADD addr,data
|
|
add.l d2, (a2) ; the count added to the where
|
|
bra.s @next_cmd ; process the next command
|
|
|
|
@c_move ; MOVE addr1,addr2
|
|
move.l d2, a0 ; get the destination address
|
|
move.l (a2), (a0) ; simple enough
|
|
bra.s @next_cmd ; process the next command
|
|
|
|
@c_loop ; LOOP relative addr,count
|
|
tst.l d2 ; check for zero loop count
|
|
beq.s @next_cmd ; if count is already zero, quit loop
|
|
subq.l #1, d2 ; drop the count
|
|
move.l d2, scParam2(a1) ; put the count back for next time
|
|
beq.s @next_cmd ; if count exhausted, don't loop
|
|
add.l a2, a1 ; modify the command pointer
|
|
bra.s @exec ; and process the next command
|
|
|
|
@c_stop
|
|
moveq.l #noErr, d0 ; indicate no error
|
|
; FALL THROUGH to @data_end ; <C846>
|
|
|
|
|
|
@data_end
|
|
cmpi.b #cpu68040,CPUFlag ; Do we have an 040? <SM10>
|
|
bne.s @TheRealExit ; -> No. No MOVE16. No Problem.
|
|
cmpi.l #-1,VMGlobals ; VM running?
|
|
beq.s @TheRealExit ; -> No, no VM, no problem
|
|
|
|
|
|
;--- Flush the cache line that contains location 8 (because of MOVE16 bug) <3> thru next <3>
|
|
|
|
movem.l D0-D2, -(sp)
|
|
moveq.l #9, D0 ; FlushCacheRange HWPriv selector
|
|
move.l #8, A0 ; starting address of flush range
|
|
move.l #4, A1 ; length of range
|
|
_HWPriv
|
|
movem.l (sp)+, D0-D2 ; restore regs <3> from last <3>
|
|
|
|
;--- exit and return result
|
|
|
|
@TheRealExit
|
|
move.w d0, 12(a6) ; return the result
|
|
moveq.l #4, d0 ; stack cleanup
|
|
bra.w StdExit
|
|
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; FUNCTION SCSIComplete(VAR Stat, Message: INTEGER; wait:LongInt): INTEGER;
|
|
; (16) (12) (8) (20)
|
|
;
|
|
; Complete the SCSI command by:
|
|
; 1) Sending command complete sequence byte to get status & msg bytes from target
|
|
; 2) Sending message accepted command to complete the cycle
|
|
;
|
|
; Return Codes:
|
|
; noErr, scCommErr, scPhaseErr, scComplPhaseErr
|
|
|
|
DoSCSIComplete_96
|
|
move.w zeroReg, -(sp) ; assume no_error return value
|
|
move.l Ticks, d4 ; get current time
|
|
add.l 8(a6), d4 ; add count to start ticks
|
|
jsr HandleSelInProg
|
|
bne.w @phaseErr
|
|
@chkStatus
|
|
moveq.l #iPhaseMsk, d3 ; load mask bits for phase value
|
|
and.b rSTA(a3), d3 ; get phase bits
|
|
cmpi.b #iStatus, d3 ; are we in status phase?
|
|
bne.w @phaseErr ;
|
|
@inPhase ; we should be in status phase.
|
|
move.b #cCmdComp, rCMD(a3) ; load cmd complete code
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
jsr WaitForSCSIIntrp ; Wait for intrp w/ timeout
|
|
; on exit d5 = rF0S|rINT|0|rSTA
|
|
beq.w @noStatus ; Branch if timedout
|
|
@gotStatus
|
|
clr.l d2
|
|
move.b rFFO(a3), d2 ; read status byte from FIFO
|
|
move.l 16(a6), a1 ; get the Status ptr
|
|
move.w d2, (a1) ; return status byte
|
|
@gotMsg
|
|
move.b rFFO(a3), d2 ; read msg byte from FIFO
|
|
move.l 12(a6), a1 ; get the Message ptr
|
|
move.w d2,(a1) ; return the msg byte
|
|
|
|
; ;move.l d5, d0 ; <T8> thru next <T8>
|
|
; ;andi.b #iPhaseMsk, d0 ; we should be in msg-in phase.
|
|
; ;cmpi.b #iMsgIn, d0 ; & *ACK still asserted
|
|
; ;bne.s @cmdErr <T8> from last <T8>
|
|
|
|
move.b #cMsgAcep, rCMD(a3) ; load msg accepted code which de-asserts *ACK
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
jsr WaitForSCSIIntrp ; Wait for intrp w/ timeout
|
|
; on exit d5 = rFOS|rINT|0|rSTA
|
|
beq.w @badAcpt ; Branch if timedout
|
|
|
|
@completeDone
|
|
move.l #0, G_FakeStat(a4) ; clear fake status
|
|
move.w (sp)+, 20(a6) ; return error
|
|
bsr.w ExitCleanup ; clean up to leave
|
|
|
|
moveq.l #12, d0 ; stack cleanup
|
|
bra.w StdExit ; <T3>
|
|
|
|
@phaseErr ; only called for Complete phase errors
|
|
move.w #scPhaseErr, (sp) ; phase Err but try getting us to status phase <T9>
|
|
jsr ([jvCyclePhase,a4]) ; get us to status phase if possible
|
|
beq.s @1 ; if cyclephz has no error, keep old one
|
|
move.w d0, (sp) ; else save this new error in (sp)
|
|
@1
|
|
moveq.l #iPhaseMsk, d3 ; load mask bits for phase value
|
|
and.b rSTA(a3), d3 ; get phase bits
|
|
cmpi.b #iStatus, d3 ; are we in status phase?
|
|
beq.w @inPhase ; yes - go get the data
|
|
@checkTime
|
|
cmp.l Ticks, d4 ; got the time, pal?
|
|
bhi.w @chkStatus ; bra. & check phase if we still have time...
|
|
; btst.b #FCIntPend, G_State96(a4) ; timed out; were we waiting for a slow peripheral? <T9>
|
|
; beq.s @completeDone ; no - exit with whatever status we've got
|
|
@timedOut
|
|
@noStatus ;
|
|
@badAcpt
|
|
@notDSCErr
|
|
@cmdErr
|
|
move.w #scCommErr, (sp) ; return status
|
|
@badComp
|
|
move.l (sp), d0 ; load error
|
|
move.l #scsiComplete, d6 ; load proc ID
|
|
bsr.w Error ; call Error proc - for debug
|
|
bra.s @completeDone ; <T5>
|
|
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; FUNCTION SCSIMsgIn(VAR Message: INTEGER): INTEGER;
|
|
; (8) (12)
|
|
;
|
|
; Receive a message from the target.
|
|
;
|
|
; Return Codes:
|
|
; noErr, scCommErr, scPhaseErr
|
|
|
|
DoSCSIMsgIn_96 ; SCSIMsgIn added
|
|
bsr.w GetMsg_96
|
|
bne.s @err ; bra. if error <T3>
|
|
move.l 8(a6), a1 ; get the Message ptr
|
|
move.w d2, (a1) ; return the Message byte
|
|
@exit
|
|
move.w d0, 12(a6) ; return error
|
|
moveq.l #4, d0 ; stack cleanup <T3> thru next <T3>
|
|
bra.w StdExit
|
|
@err
|
|
move.l #scsiMsgIn, d6 ; load proc ID
|
|
bsr.w Error ; call Error proc - for debug
|
|
bra.s @exit ; <T3>
|
|
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; FUNCTION SCSIMsgOut(Message: INTEGER): INTEGER;
|
|
; (8) (10)
|
|
;
|
|
; Send a message to the target.
|
|
;
|
|
; Return Codes:
|
|
; noErr, scCommErr, scPhaseErr
|
|
|
|
DoSCSIMsgOut_96 ; SCSIMsgOut added
|
|
move.w 8(a6), d2 ; get the Message in d2
|
|
bsr SendMsg_96
|
|
bne.s @err ; <T3> thru next <T3>
|
|
@exit
|
|
move.w d0, 10(a6) ; return error
|
|
moveq.l #2, d0 ; stack cleanup
|
|
bra.w StdExit
|
|
@err
|
|
move.l #scsiMsgIn, d6 ; load proc ID
|
|
bsr.w Error ; call Error proc - for debug
|
|
bra.s @exit
|
|
|
|
|
|
|
|
|
|
|
|
;----------------------------------------------------------------
|
|
; Select Device.
|
|
; In the 5396, arbitration, selection and command-send operations are integrated operations.
|
|
; We need the target id and the actual command descriptor block in order to exploit the
|
|
; capabilities of the chip. Unfortunately, the old SCSI manager was structured for separate
|
|
; such operations. This proc is an attempt to remain compatible to that type of operation.
|
|
; Our goal is to select a target and report the success or failure of that operation.
|
|
; This is accomplished by:
|
|
; 1) Loading transfer count, TC, with one in order to activate the select process
|
|
; 2) Using DMA mode in order to allow us to send the actual CDB during DoSCSICmd proc.
|
|
;
|
|
; Upon exit, we should be in transfer phase waiting for the client to perform either a
|
|
; command send or msg-out--if select w/ ATN. The c96 would be ready and waiting for the
|
|
; CDB or message byte because we told it to expect at least 1 byte of data.
|
|
;
|
|
; Select w/ ATN asserts the ATTENTION line during selection process. This allows the
|
|
; client to perform a 1 byte msg-out via SCSIMsgOut. The ATN line is deasserted
|
|
; prior to sending the msg byte.
|
|
;
|
|
; --> A0 = DAFB register address for this c96 (for reading DREQ state)
|
|
; d0.w --> Target ID
|
|
; d0.b16 --> If bit 16 of d0 is set, then ATN is asserted during selection.
|
|
; This is useful for telling the target that we
|
|
; want to send it a message before the command phase.
|
|
;
|
|
; Uses: d0, d1, d2, d3
|
|
|
|
Select_96
|
|
; set MMU Mode to 32-bit for DREQ test later on
|
|
move.b MMU32Bit, -(sp) ; save current mode on stack
|
|
move.l d0, -(sp) ; save D0
|
|
jsr SCSIpcTo32bit ; use pc relative
|
|
moveq #true32B, d0 ; switch to 32-bit mode to look at SCSI config regr
|
|
jsr SwapMMU ; do it, call _SwapMMUMode jump vector
|
|
move.l (sp)+, d0 ; restore D0
|
|
|
|
; Set up chip for select process (flush FIFO, init dest ID)
|
|
move.b d0, rDID(a3) ; load select bus ID w/ target ID
|
|
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO, make sure it's empty
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
|
|
btst.l #16, d0 ; is this a Sel w/Atn?
|
|
bne.s @withAtn
|
|
|
|
; If Select w/o Atn then set up for 1 DMA byte (last byte of command block) and start process
|
|
@withoutATN
|
|
move.b zeroReg, rXCM(a3) ; tell chip that we will be sending 1
|
|
move.b #1, rXCL(a3) ; DMA byte (in command phase)
|
|
move.b #cDMASelWOAtn, rCMD(a3) ; issue Select w/o Atn cmd
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
bset.b #NeedCmdSent, G_State96(a4) ; flag=expect to see a COMMAND phase next <T9>
|
|
bra.s @2
|
|
|
|
; If Select w/Atn then set up for 2 DMA bytes (msg_out byte + last byte of command block)
|
|
@withATN
|
|
move.b zeroReg, rXCM(a3) ; tell chip that we will be sending 2
|
|
move.b #1, rXCL(a3) ; DMA bytes (1 in msg_out, 1 in command)
|
|
move.b #cDMASelWAtn, rCMD(a3) ; issue Select w/ Atn cmd
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
bset.b #NeedMsgOut, G_State96(a4) ; flag=expect to see a MESSAGE_OUT phase next <T9>
|
|
@2
|
|
bset.b #SelInProg, G_State96(a4) ; set flag->select is in prog, expect intrpt <T8><T9>
|
|
|
|
|
|
; Set up >512mS timeout for select operation to get somewhere (probably more like 2 seconds)
|
|
moveq.l #0, d1 ; clear upper word
|
|
move.w TimeSCSIDB, d1 ; get # of DBRAs
|
|
lsl.l #8, d1 ; multiply by 256
|
|
lsl.l #1, d1 ; multiply by 2 <T8> thru next <T8>
|
|
move.l d1, d2 ; ...a 512mS wait for overall watchdog
|
|
swap d2
|
|
|
|
moveq.l #-1,d3 ; for debug - last four rSTA reads
|
|
moveq.l #-1,d4 ; for debug - last four rSQS reads
|
|
|
|
|
|
; We have told the chip to start it, now we wait for an indication that it has completed a
|
|
; selection. Several things can happen:
|
|
; - the target at the requested ID may not exist or may not respond to the select. In
|
|
; this case we will receive a Disconnect interrupt from the chip.
|
|
; - the target may select OK but go into something other than Command phz (if Sel w/o Atn)
|
|
; or Message_Out phz (if Sel w/Atn). Here we will see a Function Complete/Bus Service
|
|
; interrupt.
|
|
; - the target may select OK and go into the expected phz - the SUCCESS case. When this
|
|
; happens, the chip will assert DREQ because it wants the Command (or Msg_Out) byte.
|
|
; - the bus may be hung and the chip is unable to arbitrate. We detect this by timing
|
|
; out on the whole process.
|
|
;
|
|
; So basically, this is a 3-way wait for:
|
|
; 1) DREQ asserted
|
|
; 2) interrupt
|
|
; 3) loop timed out
|
|
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
@waitLoop
|
|
; Check for a REQ from the target (within valid phase)
|
|
IF forPDMDebug THEN ; <SM8>
|
|
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 <4> jab
|
|
btst.l d0, d5 ; DREQ ? <4> jab
|
|
bne.s @gotDREQ ; yes: then we have a REQ for Msg_Out or Cmd byte
|
|
|
|
; Check for an int - either Disconnected (fld select) or Bus Service/Func. Cmplt (good select)
|
|
lsl.l #8,d3 ; shift old rSTA reads up a byte
|
|
move.b rSTA(a3),d3
|
|
move.b d3,d0
|
|
btst.l #bINT,d0 ; check for intrp bit ie. timeout or weird phase
|
|
dbne d1, @waitLoop ; if intrp then non-normal select op so exit.
|
|
dbne d2, @waitLoop ; loop until count exhausted or intrp detected
|
|
; count is up or intrp detected so we're outta' here
|
|
beq @timedOut
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
|
|
; If we got an interrupt, it means that the select command is complete. Either the target did
|
|
; not respond (i.e. didn't exist) or it was selected but went to an unexpected phase.
|
|
@gotINT ; else we got an interrupt
|
|
move.b rSTA(a3), d3 ; read status for debug
|
|
move.b rINT(a3), d1 ; clear intrp bit
|
|
move.b d3, lastSTAread(a4) ; store in case anybody wants to knowÉ
|
|
move.b d1, lastINTread(a4) ; Éwhat kind of INT we got
|
|
bclr.b #FCIntPend, G_State96(a4) ; clear the FC Int pend flag <T9>
|
|
bclr.b #SelInProg, G_State96(a4) ; and clear the SelectInProgress flag <T9>
|
|
bclr.b #NeedMsgOut, G_State96(a4) ; and Message_Out <T9>
|
|
bclr.b #NeedCmdSent, G_State96(a4) ; and Command expected flags <T9>
|
|
|
|
; Was it a disconnect interrupt? (i.e. a failed select?)
|
|
btst.l #bDSC,d1 ; (i.e. timed-out then bus free)
|
|
beq @goodSEL ; no - assume it is a good select then
|
|
@badSEL ; <T8> from last <T8>
|
|
moveq.l #scCommErr, d2 ; select timeout
|
|
bra.s @exit
|
|
|
|
@timedOut
|
|
moveq.l #scArbNBErr, d2 ; select timeout <T9>
|
|
bra @exit ; branch if our watchdog timed out
|
|
|
|
@gotDREQ
|
|
@goodSEL
|
|
moveq.l #noErr, d2 ; successful selection
|
|
@exit
|
|
move.b (sp)+, d0 ; switch to previous mode
|
|
jsr SwapMMU ; do it, call _SwapMMUMode jump vector
|
|
move.l d2, d0
|
|
rts
|
|
|
|
|
|
|
|
; Check for non-zero sequence value - means select has completed and
|
|
;@1 lsl.l #8,d4 ; shift old rSQS reads up a byte
|
|
; move.b rSQS(a3), d4 ; determine where we are in select sequence
|
|
; move.b d4,d0 ; make copy for checking
|
|
; and.b #iSQSMsk, d0 ; did we get somewhere in the sequence?
|
|
; beq.s @zeroSSV ; i.e. a non-zero seq.step value
|
|
|
|
; If we have a non-zero phase value and non-zero sequence, then we had a good select
|
|
; lsl.l #8,d3 ; shift old rSTA reads up a byte
|
|
; move.b rSTA(a3), d3 ; get phase value
|
|
; move.b d3,d0
|
|
; and.b #iPhaseMsk, d0 ; look for info xfer phz (i.e. non zero)
|
|
; bne.s @goodSEL ; bra if not in bus-free (we have a data_out hole here)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; Send Command. # bytes in d2. Command block pointer is in a2.
|
|
;
|
|
; d0 - <-- error (if any)
|
|
; d2 - --> number of command bytes
|
|
; d5 - <-- xxxx|xxxx|xxxx|rSTA
|
|
;
|
|
; a2 - ptr to command block
|
|
; a3 - SCSI read base address
|
|
; a4 - ptr to SCSI Mgr globals
|
|
;
|
|
; The command descriptor block is sent using both pseudo-DMA and non-pDMA. The non-pDMA
|
|
; send appears as preloaded data in the FIFO. The last byte is send via pDMA to satisfy
|
|
; the transfer count and DMA-mode of the c96. See SELECT proc.
|
|
;
|
|
;
|
|
; Reminder: Check this routine to make sure it still works with
|
|
; Tape Backup 40SC drive. See note in SCSIMgrOld.a, SendCMD routine.
|
|
;
|
|
; Uses: d0, d1, d3, d5
|
|
;
|
|
; Error Codes:
|
|
; scPhaseErr, scCommErr
|
|
;
|
|
; STILL NEEDS: If somehow we end up here but did not have NeedCmdSent but we are actually in Cmd Phase,
|
|
; we should probably go ahead and do it anyway - just do the transfer with all rFFO (no rDMA).
|
|
|
|
SendCMD_96
|
|
btst.b #NeedCmdSent, G_State96(a4) ; are we expecting a command phase here?
|
|
beq @notExpected ; no - handle it without DMA
|
|
move.b #iCommand, d1 ; set up wait for command phase
|
|
jsr Wt4DREQorInt ; yes - wait till target REQs or screws up
|
|
beq @gotInt ; if Int then we're not in Command phase
|
|
; else, we are, so send the bytes
|
|
@sendBytes
|
|
ori.b #SlowCableMode,rCF1(a3) ; set Slow cable mode for the command bytes <T9>
|
|
subq.l #1, d2 ; adjust for DMA of last byte <T9>
|
|
bra.s @btmLoadFIFO ; bra to dbra for zero case (1 byte CDB) <T9>
|
|
@loadFIFO ; loading the FIFO w/o pseudo-DMA will simulate
|
|
move.b (a2)+, rFFO(a3) ; preloading of the FIFO...we then pDMA the
|
|
@btmLoadFIFO ; <T9>
|
|
dbra d2, @loadFIFO ; last byte in order to satisfy the c96's DMA <T2>
|
|
; circuitry & get us that intrp. <T2>
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
|
|
btst.b #NeedCmdSent, G_State96(a4) ; were we expecting a command phase here? <2> thru next <2>
|
|
beq.s @skipDMA
|
|
|
|
; Wait for either FIFO empty or a phase change
|
|
|
|
@wt4EmptyOrPhz
|
|
moveq.l #iFOFMsk, d1 ; use mask to get FIFO flag field
|
|
and.b rFOS(a3), d1 ; how many bytes left in FIFO?
|
|
beq.s @lastCmdByte ; if none, send the last command byte
|
|
|
|
moveq.l #iPhaseMsk, d1 ;
|
|
and.b rSTA(a3), d1 ; are we in command phase?
|
|
cmp.b #iCommand, d1 ;
|
|
beq.s @wt4EmptyOrPhz ; yes - loop again
|
|
@lastCmdByte
|
|
moveq.l #iPhaseMsk, d1 ;
|
|
and.b rSTA(a3), d1 ; get phase bits before sending last byte <2> from prev <2>
|
|
|
|
move.b (a2)+, rDMA(a3) ; Use psuedo DMA to load last byte <T2>
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
|
|
bclr.b #NeedCmdSent,G_State96(a4) ; no longer need command sent and, <T9>
|
|
bset.b #FCIntPend,G_State96(a4) ; now we can expect a FunctionCmplt interrupt <T9>
|
|
cmp.b #iCommand, d1 ; were we in command phz b4 last byte? <2>
|
|
bne.s @phaseErr ; no - then we had a phase error <2>
|
|
@skipDMA
|
|
moveq.l #iPhaseMsk, d3 ; load mask bits for phase value
|
|
and.b rSTA(a3), d3 ; get phase value
|
|
cmpi.b #iCommand, d3 ; are we in command phase?
|
|
beq.s @cmdHack ; bra. if we're still in cmd phase
|
|
@cmdOK
|
|
; we no longer waste a wait here for the FC interrupt but instead do it in a data <T8>
|
|
; phase or in SCSIComplete with a call to HandleSelInProg.
|
|
|
|
moveq.l #noErr, d0 ; no error <T9>
|
|
@cmdExit ; At this point, we're out of cmd phase
|
|
and.b #$FF-SlowCableMode,rCF1(a3) ; turn-off Slow cable mode <T9>
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
tst.w d0 ;
|
|
rts
|
|
|
|
; This is a hack for the Tape Backup 40SC drive. 40SC asserts an extra REQ on
|
|
; 10-byte commands, which appears as a request for an 11th byte (that's what
|
|
; the SCSI standard says!) On very fast CPU's, this extra REQ hangs over to
|
|
; the next phase of the transaction, causing a phase error, and causes the
|
|
; transaction to fail. This delay code will wait at most 256ms
|
|
; for a phase change before continuing.
|
|
; NOTE: On the c96, this code is probably worthless since the chip will fill
|
|
; any additional bytes (for any additional REQs) after the DREQ is fulfilled
|
|
; whether we wait for it or not. (See state diagram in Emulex lit.)
|
|
@cmdHack
|
|
move.l zeroReg, d0 ; clear upper word
|
|
move.w TimeSCSIDB, d0 ; get SCSI DBRA's ms timing constant
|
|
lsl.l #8, d0 ; wait at least 256ms for the tape drive
|
|
move.l d0, d2 ; set up d2 as high word
|
|
swap d2 ;
|
|
@hack
|
|
moveq.l #iPhaseMsk, d3 ; load mask bits for phase value
|
|
and.b rSTA(a3), d3 ; get phase value
|
|
cmpi.b #iCommand, d3 ; are we in command phase?
|
|
dbne.w d0, @hack ; loop until not cmd phase or timeout
|
|
dbne.w d2, @hack ; high word of timeout
|
|
bra.s @cmdOk
|
|
|
|
; We got our select_process complete interrupt - set our state reflecting that
|
|
@gotInt
|
|
bclr.b #FCIntPend, G_State96(a4) ; clear the FC Int pend flag <Taa>
|
|
bclr.b #SelInProg, G_State96(a4) ; and clear the SelectInProgress flag <Taa>
|
|
bclr.b #NeedMsgOut, G_State96(a4) ; and Message_Out <Taa>
|
|
bclr.b #NeedCmdSent, G_State96(a4) ; and Command expected flags <Taa>
|
|
move.b #cFlshFFO, rCMD(a3) ; flush the FIFO of unused Command bytes
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
@phaseErr
|
|
moveq.l #scPhaseErr, d0 ; phase error <T5>
|
|
move.l #scsiCmd, d6 ; load proc ID <T5>
|
|
bsr.w Error ; call Error proc - for debug <T5>
|
|
bra.s @cmdExit ; <T5>
|
|
|
|
|
|
@notExpected
|
|
moveq.l #iPhaseMsk, d3 ; load mask bits for phase value
|
|
and.b rSTA(a3), d3 ; get phase value
|
|
cmpi.b #iCommand, d3 ; are we in command phase?
|
|
bne.w @phaseErr ; bra. on phase err
|
|
addq.l #1, d2 ; adjust for DMA of last byte <T9>
|
|
bra.w @sendBytes
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; GetMsg - get a message byte from target and return in d2
|
|
;
|
|
; Uses: d0, d2, d3
|
|
;
|
|
; Return Codes:
|
|
; noErr, scCommErr, scPhaseErr
|
|
|
|
GetMsg_96
|
|
moveq.l #iPhaseMsk, d3 ; load mask bits for phase value
|
|
and.b rSTA(a3), d3 ; get phase value
|
|
cmpi.b #iMsgIn, d3 ; are we in MsgIn phase already?
|
|
bne.s @phaseErr ;
|
|
|
|
move.b #cIOXfer, rCMD(a3) ; load Transfer cmd byte in CMD regr
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
jsr WaitForSCSIIntrp ; Wait for intrp w/ timeout <T3>
|
|
; on exit d5 = xxxx|rSQS|rSTA|rINT
|
|
beq.s @timedOut ; Branch if timedout
|
|
|
|
move.b rFFO(a3), d2 ; xfer fifo msg byte into d2 w/ *ACK still asserted
|
|
; now, unconditionally accept the message byte
|
|
move.b #cMsgAcep, rCMD(a3) ; load msg accepted code which de-asserts *ACK
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
jsr WaitForSCSIIntrp ; Wait for intrp w/ timeout <T3>
|
|
; on exit d5 = rFOS|rINT|0|rSTA
|
|
beq.s @timedOut ; Branch if timedout
|
|
|
|
; check for disconnect or bus service intrp
|
|
; <--- here!
|
|
moveq.l #noErr, d0
|
|
rts
|
|
|
|
|
|
@dscErr
|
|
@timedOut
|
|
moveq.l #scCommErr, d0 ; comm error
|
|
bra.s @badGetMsg
|
|
@phaseErr
|
|
moveq.l #scPhaseErr, d0
|
|
@badGetMsg
|
|
move.l #0, G_FakeStat(a4) ; Set to a fake stat
|
|
tst.l d0 ; set the condition code <T3>
|
|
rts
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; SendMsg - Send a message byte to the target (in d2 on entry)
|
|
;
|
|
; This proc assumes that the ATTENTION line has been asserted via SEL w/ ATN.
|
|
; Note that only 1 msg byte can be sent via this method.
|
|
;
|
|
; Entry:
|
|
; --> d2 message byte to send
|
|
; --> a3 base address of 53c96
|
|
;
|
|
; Exit:
|
|
; <-- d0 result code
|
|
;
|
|
; Uses: d0, d1, d3
|
|
;
|
|
; Error Codes:
|
|
; noErr, scCommErr, scPhaseErr
|
|
|
|
SendMsg_96
|
|
btst.b #NeedMsgOut,G_State96(a4) ; did we send a Select w/ATN?
|
|
beq.s @unexpected ; no - just phase err out of here then
|
|
|
|
move.b #iMsgOut, d1 ; set up wait for command phase
|
|
jsr Wt4DREQorInt
|
|
beq.s @gotInt ; if we got an interrupt, something's wrong
|
|
|
|
move.b rSTA(a3), d3 ; get phase value <T9> to next <T9>
|
|
and.b #iPhaseMsk, d3 ; load mask bits for phase value
|
|
cmpi.b #iMsgOut, d3 ; are we in MsgOut phase already?
|
|
bne.s @phaseErr ;
|
|
|
|
@inPhase ; We probably got here from Select w/ATN which means
|
|
; ATN is deasserted prior to transfer of msg byte
|
|
move.b d2, rFFO(a3) ; xfer msg byte
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
bclr.b #NeedMsgOut,G_State96(a4) ; did we send a Select w/ATN?
|
|
beq.s @needXfer ; no - just split
|
|
bset.b #NeedCmdSent,G_State96(a4) ; yes - we took care of MsgOut, now we need to send command
|
|
bra.s @noErr
|
|
@needXfer
|
|
jsr Xfer1Byte
|
|
bra.s @noErr
|
|
|
|
|
|
@unexpected ; wait for 256mS for correct phase
|
|
jsr HandleSelInProg
|
|
bne.s @phaseErr
|
|
|
|
moveq.l #0, d1 ; clear upper word
|
|
move.w TimeSCSIDB, d1 ; get # of DBRAs
|
|
lsl.l #8, d1 ; multiply by 256
|
|
move.l d1, d3 ; ...a 256mS wait
|
|
swap d3
|
|
|
|
@1
|
|
move.b rSTA(a3), d3 ; get phase value <T9> to next <T9>
|
|
and.b #iPhaseMsk, d3 ; load mask bits for phase value
|
|
cmpi.b #iMsgOut, d3 ; are we in MsgOut phase already?
|
|
beq.s @inPhase ; yes - send byte
|
|
dbra d1, @1 ;
|
|
dbra d3, @1 ; loop until done
|
|
|
|
|
|
@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 <T9>
|
|
bclr.b #NeedCmdSent, G_State96(a4) ; and Command expected flags <T9>
|
|
@phaseErr
|
|
moveq.l #scPhaseErr, d0 ; phase error
|
|
bra.s @clrATN ;
|
|
|
|
@commErr
|
|
moveq.l #scCommErr, d0 ; comm error
|
|
bra.s @clrATN ;
|
|
|
|
@noErr
|
|
moveq.l #noErr, d0 ; no error
|
|
@clrATN
|
|
and.w #$FFFF-aATN,G_FakeStat(a4) ; clear fake ATN bit! <T9> from prev <T9>
|
|
tst.w d0 ; return results in status register
|
|
rts
|
|
|
|
|
|
|
|
|
|
;-------------------------------------------------------------------------- <T3>
|
|
;
|
|
; CyclePhase_96 -- we may have to discard data or write filler bytes to get to
|
|
; the desired phase, status phase.
|
|
;
|
|
; This routine is broken into two main sections; standard I/O and psuedo-DMA. The DMA
|
|
; sequence is used in case we are in the middle of a failed DMA transfer which left the
|
|
; transfer count nonzero. We only have to handle psuedo-DMA in data phase. All other
|
|
; phases (and normal I/O mode data phase) are handled 1 byte at a time by individual
|
|
; phase handling code with, after each byte, returns to check the next phase to see
|
|
; where to go next.
|
|
;
|
|
; Phase Action
|
|
; ÑÑÑÑÑ ÑÑÑÑÑÑ
|
|
; Command: We send as many EE bytes as needed to get out of phase. If the select sequence
|
|
; flag 'NeedCmdSent' is set, it turns out that the chip will do the fill by itself
|
|
; once we send 1 rDMA byte (thereby completing the transfer) using
|
|
; rDMA. We also set the flag 'FCIntPend' bit if 'NeedCmdSent' was set.
|
|
;
|
|
; Msg_Out: We send as many 08(NOP) bytes as needed to get out of phase. If the select
|
|
; sequence flag 'NeedMsgOut' flag is set we set the flag 'NeedCmdSent' and continue.
|
|
;
|
|
; Data_In: We bitbucket as many bytes as needed to clear phase.
|
|
;
|
|
; Data_Out: We send as many EE bytes as needed to get out of phase.
|
|
;
|
|
;
|
|
; Note: We need to check if the SCSIMgr is busy in order to differentiate between <T2>
|
|
; IDLE bus phase and DATA OUT phase. They both have phase value = 0. <T2>
|
|
;
|
|
; Uses: d0
|
|
|
|
CyclePhase_96 ; (accessed thru jvCyclePhase)
|
|
btst.b #scBusy, G_State(a4) ; check if SCSIMgr is active <T2>
|
|
beq.s @xferErr ; bra. if not
|
|
|
|
IF forPDMDebug THEN ; Till Jimmy stops ignoring DREQ... <SM10>
|
|
PEA @FuckedUpStr
|
|
_DebugStr
|
|
ENDIF
|
|
|
|
@checkNextPhase ; <T9> to next <T9>
|
|
moveq.l #iPhaseMsk, d0 ; load mask bits for phase value
|
|
and.b rSTA(a3), d0 ; get phase bits
|
|
|
|
; cmp #iDataOut, d0 ;
|
|
beq.s @inDataPhase ;
|
|
|
|
cmp #iDataIn, d0 ;
|
|
beq.s @inDataPhase ;
|
|
|
|
cmp #iCommand, d0 ;
|
|
beq @shoveCommand ;
|
|
|
|
cmp #iMsgOut, d0 ;
|
|
beq.w @shoveMsgOut ;
|
|
|
|
cmp #iMsgIn, d0 ;
|
|
beq.w @bitbucketMsgIn ;
|
|
|
|
cmp #iStatus, d0 ;
|
|
bne.s @xferErr
|
|
@okExit
|
|
move.w #scComplPhaseErr, d0 ; tell SCSIComplete we had to read/write junk <T2>
|
|
rts ; err code is saved
|
|
|
|
@xferErr ; <T3>
|
|
clr.l d0 ; no recovery
|
|
rts
|
|
|
|
IF forPDMDebug THEN
|
|
STRING PASCAL
|
|
@FuckedUpStr DC.W 'SCSIMgr is in CyclePhases. Bitbucketting Data...'
|
|
STRING ASIS
|
|
ENDIF
|
|
|
|
; If data phase, check if we have been transferring with psuedo-DMA, if so, continue.
|
|
@inDataPhase
|
|
move.b rCMD(a3), d1 ; what was our most recent command?
|
|
cmp.b #cDMAXfer, d1 ; IF command was DMAXfer AND É
|
|
bne.s @notDMA ;
|
|
tst.b rXCL(a3) ; Éthere are outstanding pDMA transfers É
|
|
bne.w @pDMA ; THEN go finish them up with psuedo-DMA
|
|
tst.b rXCM(a3)
|
|
bne.w @pDMA
|
|
@notDMA
|
|
cmp.b #iDataOut, d0 ; ELSE É what phase?
|
|
beq.s @shoveDataOut ; data_out - shove data using IO xfers
|
|
;; bra.s @bitbucketData ; data_in - bit bucket using normal IO xfers
|
|
|
|
; Grab and bit bucket a data_in bytes until we've gone into another phase
|
|
@bitbucketData
|
|
jsr Xfer1Byte ; xfer 1 byte and wait for intrp w/o timeout
|
|
; on exit d5 = rFOS|rINT|0|rSTA
|
|
bne.s @xferErr ; bra. on xfer error
|
|
move.b rFFO(a3), d0 ; just empty the FIFO
|
|
bra.s @checkNextPhase
|
|
|
|
|
|
; Dump out data_out bytes until we've gone into another phase
|
|
@shoveDataOut
|
|
move.b #$EE, rFFO(a3) ; load filler byte into FIFO
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
jsr Xfer1Byte ; xfer 1 byte and wait for intrp w/o timeout
|
|
; on exit d5 = rFOS|rINT|0|rSTA
|
|
bne.s @xferErr ; bra. on xfer error
|
|
bra.s @checkNextPhase
|
|
|
|
|
|
; Dump out Command bytes until we've gone into another phase
|
|
@shoveCommand
|
|
bclr.b #NeedCmdSent, G_State96(a4) ; did we expect this?
|
|
beq.s @nonDMA ; no - bra, do xfer using FIFO
|
|
move.b #$EE, rDMA(a3) ; yes - use DMA (since chip is waiting for it)
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
bset.b #FCIntPend,G_State96(a4) ; we took care of cmd, now expect FC interrupt
|
|
jsr WaitForSCSIIntrp
|
|
beq.s @timedOut ; bra if timedout
|
|
bclr.b #FCIntPend, G_State96(a4) ; clear the FC Int pend flag
|
|
bclr.b #SelInProg, G_State96(a4) ; clear the select in progress flag
|
|
@timedOut ; if we timed out, something's haywire
|
|
bra.s @2 ; trying again is as good as anything else
|
|
@nonDMA
|
|
move.b #$EE, rFFO(a3) ; load filler byte into FIFO
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
jsr Xfer1Byte ; xfer 1 byte and wait for intrp w/o timeout
|
|
bne.s @xferErr ; bra. on xfer error
|
|
@2
|
|
bra.s @checkNextPhase
|
|
|
|
|
|
; Dump out message_out bytes until we've gone into another phase
|
|
@shoveMsgOut
|
|
move.b #$08, rFFO(a3) ; load filler byte into FIFO (NOP message)
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
bclr.b #NeedMsgOut, G_State96(a4) ; did we expect this?
|
|
beq.s @needXferCmd ; no - branch
|
|
bset.b #NeedCmdSent,G_State96(a4) ; yes - taking care of MsgOut, now we need cmd
|
|
bra.s @skipXferCmd
|
|
@needXferCmd
|
|
jsr Xfer1Byte ; xfer 1 byte and wait for intrp w/o timeout
|
|
bne.s @xferErr ; bra. on xfer error
|
|
@skipXferCmd
|
|
bra.s @checkNextPhase
|
|
|
|
|
|
; Grab and bit bucket message bytes until we've gone into another phase
|
|
@bitbucketMsgIn
|
|
jsr Xfer1Byte ; xfer 1 byte and wait for intrp w/o timeout
|
|
bne.s @xferErr ; bra. on xfer error
|
|
move.b rFFO(a3), d0 ; just empty the FIFO
|
|
move.b #cMsgAcep, rCMD(a3) ; load msg accepted code which de-asserts ACK
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
jsr WaitForSCSIIntrp ; Wait for intrp w/ timeout
|
|
; on exit d5 = rFOS|rINT|0|rSTA
|
|
bra.s @checkNextPhase
|
|
|
|
|
|
;
|
|
; Use pseudo-DMA to clean up pending pDMA transfers ie. recovery from bus timeout <JMA> to next <JMA>
|
|
; It is entirely possible that we might have to use non-pDMA to complete the cleanup
|
|
; which is what the upper half of cyclePhase does.
|
|
|
|
@pDMA
|
|
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 G_SCSIDREQ(a4), a0 ; G_SCSIDREQ contains DREQ regr address
|
|
|
|
moveq.l #iPhaseMsk, d0 ;
|
|
and.b rSTA(a3), d0 ;
|
|
cmp #iDataOut, d0 ; what phase?
|
|
beq.s @pDMAwrite ; data_out - pDMAwrite
|
|
;; bra.s @pDMAread ; data_in - pDMAread
|
|
|
|
; Read data bytes using DMA until DREQ goes away
|
|
|
|
@pDMAread
|
|
btst.b #bINT, rSTA(a3) ; poll for intrp hopefully from TC zero
|
|
bne.s @readAll ; bra. if we got one
|
|
IF forPDMDebug THEN ; <SM8>
|
|
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 <4> jab
|
|
btst.l d0, d5 ; DREQ ? <4> jab
|
|
beq.s @pDMAread ; bra. if inactive
|
|
move.w rDMA(a3), d5 ; bit-bucket data
|
|
bra.s @pDMAread
|
|
@readAll ; Intrp will occur when REQ is asserted for the next phase
|
|
jsr WaitForIntNoTime ; Expecting an intrp, clear it when occurs
|
|
; on exit d5 = rFOS|rINT|0|rSTA
|
|
bra.s @pDMADone ; check if we reached status phase
|
|
|
|
|
|
; Write data bytes using DMA until DREQ goes away
|
|
|
|
@pDMAwrite
|
|
btst.b #bINT, rSTA(a3) ; poll for intrp hopefully from TC zero
|
|
bne.s @writeAll ; bra. if we filled all data
|
|
IF forPDMDebug THEN ; <SM8>
|
|
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 <4> jab
|
|
btst.l d0, d5 ; DREQ ? <4> jab
|
|
beq.s @pDMAwrite ; bra. if inactive
|
|
move.w #$EEEE, rDMA(a3) ; load filler data into FIFO
|
|
if nonSerializedIO Then
|
|
nop ; Force write to complete. <SM8>
|
|
endif
|
|
bra.s @pDMAwrite
|
|
@writeAll ; Intrp will occur when REQ is asserted for the next phase
|
|
jsr WaitForIntNoTime ; Expecting an intrp, clear it when occurs
|
|
; on exit d5 = rFOS|rINT|0|rSTA
|
|
|
|
; Return to previous MMUMode and check for next phase to cycle out of
|
|
|
|
@pDMADone
|
|
move.b (sp)+, d0 ; switch to previous mode
|
|
jsr SwapMMU ; do it, call _SwapMMUMode jump vector
|
|
bra.w @checkNextPhase ; go check for next phase to cycle out of
|
|
; <T9> from prev <T9>
|
|
|
|
|
|
|
|
|
|
;_______________________________________________________________________ <T2> thru next <T2>
|
|
;
|
|
; SCSIpcTo32Bit
|
|
; Inputs: none
|
|
; Destroys: A0, D0
|
|
; Calls: _Translate24To32
|
|
;
|
|
; Function: Converts the PC to a 32-bit address.
|
|
;
|
|
; Routine from EdiskDrvr.a
|
|
;_______________________________________________________________________
|
|
|
|
SCSIpcTo32Bit
|
|
IF not forROM THEN ; SM is always in 32-bit mode
|
|
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
|
|
ENDIF
|
|
rts ; <T2>
|
|
|
|
|
|
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; TestForDREQ
|
|
; This is good for a one time only test. If the value of DREQ
|
|
; needs to be determined in a loop, use something else.
|
|
;_______________________________________________________________________
|
|
;
|
|
TestForDREQ
|
|
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.l G_SCSIDREQ(a4), a0 ; G_SCSIDREQ contains DREQ regr address
|
|
IF forPDMDebug THEN ; <SM8>
|
|
move.b (a0), d5 ; read DAFB regr (a0=DAFB register addr)
|
|
ELSE
|
|
move.l (a0), d5 ; read DAFB regr (a0=DAFB register addr)
|
|
ENDIF
|
|
|
|
jsr SwapMMU ; return to previous mode (in d0)
|
|
|
|
move.b G_bitDREQ(a4),d0 ; load DREQ bit position <4> jab
|
|
btst.l d0, d5 ; DREQ ? <4> jab
|
|
rts
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; Error -- proc call by most top level SCSI proc when an error occurs
|
|
; Primarily for debugging.
|
|
;
|
|
; Called by: SCSISelect(S/D,ATN), SCSICmd, SCSIRead(Slow/Fast), SCSIWrite(Slow/Fast),
|
|
; SCSIComp(Slow/Fast), SCSIMsgIn, SCSIMsgOut, SCSIComplete
|
|
;
|
|
; d0 -> SCSI error code
|
|
; d6 -> SCSI proc ID
|
|
;
|
|
; Uses: a0
|
|
|
|
Error
|
|
movea.l jvErr(a4), a0 ; get address of error routine
|
|
jsr (a0) ;
|
|
rts
|
|
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; SCSIErr -- Primarily for debugging.
|
|
;
|
|
SCSIErr_96
|
|
rts ;
|
|
|
|
|
|
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; SwapMMU
|
|
; Swaps MMU into mode specified in D0. Returns previous
|
|
; MMUMode in D0.
|
|
;
|
|
; Registers : D0 affected as above. No others affected.
|
|
;
|
|
SwapMMU
|
|
IF not forROM THEN
|
|
movem.l d1/a0, -(sp)
|
|
jsr ([jSwapMMU]) ; do it, call _SwapMMUMode jump vector(smashes d1/a0)
|
|
movem.l (sp)+, d1/a0
|
|
ENDIF
|
|
rts
|
|
|
|
|
|
;==========================================================================
|
|
|
|
ENDWITH
|
|
|
|
END
|