boot3/OS/SCSIMgr/SCSIMgr96BIOS.a
Elliot Nunn 5b0f0cc134 Bring in CubeE sources
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.
2017-12-26 10:02:57 +08:00

1375 lines
47 KiB
Plaintext

;__________________________________________________________________________________________________
;
; File: SCSIMgr96BIOS.a
;
; Contains: SCSI Mgr for the BIOS based 53c96
;
; Written by: James Blair
;
; Copyright: © 1992 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <SM1> 2/5/93 CSS Checkin from Horror.
; <H3> 10/17/92 jab Added changes to allow messaging to work successfully.
; <H2> 10/5/92 jab Fixed bug that was allowing MSG signal to remain in fake status
; byte.
; <1> 9/6/92 jab first checked in
;__________________________________________________________________________________________________
MACHINE MC68020 ; '020-level
BLANKS ON ; assembler accepts spaces & tabs in operand field
STRING ASIS ; generate string as specified
PRINT OFF ; do not send subsequent lines to the listing file
; don't print includes
LOAD 'StandardEqu.d' ; from StandardEqu.a and for building ROMs
INCLUDE 'HardwarePrivateEqu.a'
INCLUDE 'SCSI.a' ; <SM1> CSS
INCLUDE 'SCSIPriv.a'
INCLUDE 'UniversalEqu.a' ; for TestFor
INCLUDE 'SCSIEqu96.a'
PRINT ON ; do send subsequent lines to the listing files
SCSI96BIOS PROC EXPORT
EXPORT SCSIMgr_96_BIOS, DoSCSIReset_96_BIOS
EXPORT DoSCSICmd_96_BIOS, DoSCSIComplete_96_BIOS
EXPORT DoSCSISelect_S96_BIOS ;
EXPORT DoSCSISelAtn_S96_BIOS, CyclePhase_96_BIOS ;
EXPORT DoSCSIStat_96_BIOS, DoSCSIMsgOut_96_BIOS
EXPORT Unimplemented_96_BIOS
EXPORT DoSCSIGet_96_BIOS ;
EXPORT DoSCSIMsgIn_96_BIOS ;
EXPORT NewSCSIRead_96_BIOS, NewSCSIWrite_96_BIOS
EXPORT NewSCSIWBlind_96_BIOS, NewSCSIRBlind_96_BIOS
EXPORT Error_BIOS, SCSIErr_96_BIOS
IMPORT Xfer1Byte, WaitForSCSIIntrp, WaitForIntNoTime
IMPORT Wt4DREQorInt_BIOS, HandleSelInProg_BIOS
WITH scsiPB, scsiPrivPB ; access record without explicit qualification
WITH scsiGlobalRecord, dcInstr
;==========================================================================
;-------------------------------------------------------------
;
; 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_BIOS: ; "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_BIOS ; 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
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 ;
;----------------------------------------------------------------
;
; Unimplemented selector (or out of range)
;
Unimplemented_96_BIOS
moveq.l #dsCoreErr, d0 ; unimplemented core routine
_SysError ; sorry, Charlie
@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
; ACK n/a
; ATN n/a
; BSY ERR n/a
; PHS MAT n/a
; INT REQ n/a (INT PEND)
; PRT ERR n/a
; DMA REQ DREQ (DMA REQ)
; 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_BIOS
and.w #$FFE2, G_FakeStat(a4) ; clear phase bits first, except SEL <H2>
move.l a3, -(sp) ; save a3
clr.l d1 ;
move.l base539x0(a4), a3 ; load ptr for SBus0
move.b rSTA(a3), d1 ; read this bus' status
TestFor SCSI96_2Exists ; do we have a 2nd SCSI96 chip?
beq.s @noSCSI96 ; bra. if no 2nd SCSI96
move.l base539x1(a4), a3 ; load ptr for SBus1
or.b rSTA(a3), d1 ; OR this bus' status
@noSCSI96 ;
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
; way for the client to specify a target bus in a dual-SCSI bus system.
;
; Uses: a0, a3, d0, d2, d3
;
; Return Codes:
; noErr
DoSCSIReset_96_BIOS
move.l a3, -(sp) ; save a3
movea.l jvResetBus(a4), a0 ; get address of SCSI reset routine
move.l base539x0(a4), a3 ; load ptr for SBus0
jsr (a0) ; reset SCSI bus and kill all requests
TestFor SCSI96_2Exists ; do we have a second SCSI96 chip?
beq.s @noSCSI96 ; bra. if no 2nd SCSI96
movea.l jvResetBus(a4), a0 ; get address of SCSI reset routine
move.l base539x1(a4), a3 ; load ptr for SBus1
jsr (a0) ; reset SCSI bus and kill all requests
@noSCSI96 ;
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
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
NoByteExit
moveq.l #0, d0 ; no arguments to clean up
bra.w StdExit
;-----------------
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_BIOS ; 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
;--------------------------------------------------------------------------
;
; 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
; 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_BIOS
bset.b #scBusy, G_State(a4) ; set to SCSI busy state
bne.s @isBusy ; if nonzero, SCSI Mgr is in use
move.w #aBSY+aSEL, G_FakeStat(a4) ; Set to a fake successful arb status
moveq.l #noErr, d0 ; no error
@exit ;
move.w d0, 8(a6) ; return code
bra.s NoByteExit
@isBusy ;
moveq.l #scMgrBusyErr ,d0 ; SCSI Mgr is busy
bra.s @exit ; bail out in order to avoid deadlock
;--------------------------------------------------------------------------
;
; 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_BIOS
DoSCSISelAtn_S96_BIOS
bset.b #scBusy, G_State(a4) ; set SCSI busy state here too for those who bypass SCSIGet
move.w G_FakeStat(a4), -(sp) ; save fake status
move.w #aBSY, (sp) ; assume successful selection, set fake status
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
@noATN
move.l d6, G_TargetID(a4) ; remember destination ID & ATN bit
move.l pdma5380(a4), a0 ; pdma5380 contains DREQ regr address
bsr.w Select_96_BIOS ; try it
bne.s CommonSelErrXit ; branch if error
@exit
move.w (sp)+, G_FakeStat(a4) ; save new fake status
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_BIOS
move.l 10(a6), a2 ; get command buffer address
move.w 8(a6), d2 ; get the length
bsr.w SendCMD_96_BIOS ; send it
bne.s @err ; bra. if error
@exit ;
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_BIOS ; call Error proc - for debug
bra.s @exit ;
;--------------------------------------------------------------------------
;
; 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_BIOS
moveq.l #scsiWriteFast, d4 ; select the fast write routine
bra.s dataCommon_96 ; continue
NewSCSIWrite_96_BIOS
moveq.l #scsiWriteSlow, d4 ; select the slow write routine
bra.s dataCommon_96 ; continue
NewSCSIRBlind_96_BIOS
moveq.l #scsiReadFast, d4 ; select the fast read routine
bra.s startRead_96 ; continue
NewSCSIRead_96_BIOS
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
;--- Flush the cache line that contains location 8 (because of MOVE16 bug)
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
;--- exit and return result
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_BIOS
move.w zeroReg, -(sp) ; assume no_error return value
bclr.b #PendBusFree,G_State96(a4) ; <H3>
bne.s @completeDone ; <H3>
move.l Ticks, d4 ; get current time
add.l 8(a6), d4 ; add count to start ticks
jsr HandleSelInProg_BIOS
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
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO, make sure it's empty <H3>
move.b #cCmdComp, rCMD(a3) ; load cmd complete code
bsr.l 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.b #cMsgAcep, rCMD(a3) ; load msg accepted code which de-asserts *ACK
bsr.l 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 ;
@phaseErr ; only called for Complete phase errors
move.w #scPhaseErr, (sp) ; phase Err but try getting us to status phase
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?
; 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_BIOS ; call Error proc - for debug
bra.s @completeDone ;
;--------------------------------------------------------------------------
;
; FUNCTION SCSIMsgIn(VAR Message: INTEGER): INTEGER;
; (8) (12)
;
; Receive a message from the target.
;
; Return Codes:
; noErr, scCommErr, scPhaseErr
DoSCSIMsgIn_96_BIOS ; SCSIMsgIn added
bsr.w GetMsg_96_BIOS
bne.s @err ; bra. if error
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
bra.w StdExit
@err
move.l #scsiMsgIn, d6 ; load proc ID
bsr.w Error_BIOS ; call Error proc - for debug
bra.s @exit ;
;--------------------------------------------------------------------------
;
; FUNCTION SCSIMsgOut(Message: INTEGER): INTEGER;
; (8) (10)
;
; Send a message to the target.
;
; Return Codes:
; noErr, scCommErr, scPhaseErr
DoSCSIMsgOut_96_BIOS ; SCSIMsgOut added
move.w 8(a6), d2 ; get the Message in d2
bsr SendMsg_96_BIOS
bne.s @err ;
@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_BIOS ; 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_BIOS
; 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
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
bset.b #NeedCmdSent, G_State96(a4) ; flag=expect to see a COMMAND phase next
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 <H3>
bset.b #NeedMsgOut, G_State96(a4) ; flag=expect to see a MESSAGE_OUT phase next
@2
bset.b #SelInProg, G_State96(a4) ; set flag->select is in prog, expect intrpt
; 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
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)
move.l (a0), d5 ; read DAFB regr (a0=DAFB register addr)
move.b G_bitDREQ(a4),d0 ; load DREQ bit position
btst.l d0, d5 ; DREQ ?
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
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
; 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 ;
moveq.l #scCommErr, d2 ; select timeout
bra.s @exit
@timedOut
moveq.l #scArbNBErr, d2 ; select timeout
bra @exit ; branch if our watchdog timed out
@gotDREQ
@goodSEL
moveq.l #noErr, d2 ; successful selection
@exit
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_BIOS
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_BIOS ; 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
; <H3> thru next <H3>
bclr.b #SelMsgOut,G_State96(a4) ; should we wait for interrupt if we came from MsgOut ?
beq.s @sendBytes
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO, make sure it's empty
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 #cDMAXfer, rCMD(a3) ; issue Select w/o Atn cmd
; <H3> from prev <H3>
@sendBytes
ori.b #SlowCableMode,rCF1(a3) ; set Slow cable mode for the command bytes
subq.l #1, d2 ; adjust for DMA of last byte
bra.s @btmLoadFIFO ; bra to dbra for zero case (1 byte CDB)
@loadFIFO ; loading the FIFO w/o pseudo-DMA will simulate
move.b (a2)+, rFFO(a3) ; preloading of the FIFO...we then pDMA the
@btmLoadFIFO ;
dbra d2, @loadFIFO ; last byte in order to satisfy the c96's DMA
; circuitry & get us that intrp.
btst.b #NeedCmdSent, G_State96(a4) ; were we expecting a command phase here?
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
move.b (a2)+, rDMA(a3) ; Use psuedo DMA to load last byte
bclr.b #NeedCmdSent,G_State96(a4) ; no longer need command sent and,
bset.b #FCIntPend,G_State96(a4) ; now we can expect a FunctionCmplt interrupt
cmp.b #iCommand, d1 ; were we in command phz b4 last byte?
bne.s @phaseErr ; no - then we had a phase error
@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
; phase or in SCSIComplete with a call to HandleSelInProg.
moveq.l #noErr, d0 ; no error
@cmdExit ; At this point, we're out of cmd phase
and.b #$FF-SlowCableMode,rCF1(a3) ; turn-off Slow cable mode
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 #SelMsgOut,G_State96(a4) ; should we wait for interrupt if we came from MsgOut ? <H3>
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
move.b #cFlshFFO, rCMD(a3) ; flush the FIFO of unused Command bytes
@phaseErr
moveq.l #scPhaseErr, d0 ; phase error
move.l #scsiCmd, d6 ; load proc ID
bsr.w Error_BIOS ; call Error proc - for debug
bra.s @cmdExit ;
@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
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_BIOS
; <H3> thru next <H3>
bclr.b #NeedCmdSent,G_State96(a4) ; yes - we took care of MsgOut, now we need to send command
beq.s @getMsg
bclr.b #SelMsgOut,G_State96(a4) ; should we wait for interrupt if we came from MsgOut ?
bne.s @contMsgIn ; 1 - no
@doWait
bsr.l WaitForIntNoTime ; Wait for intrp w/o timeout
@contMsgIn
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO, make sure it's empty
@getMsg ; <H3> from last <H3>
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
bsr.l WaitForIntNoTime ; Wait for intrp w/ timeout <H3>
; on exit d5 = xxxx|rSQS|rSTA|rINT
;; beq.s @timedOut ; Branch if timedout <H3>
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
bsr.l WaitForIntNoTime ; Wait for intrp w/ timeout <H3> thru next <H3>
; on exit d5 = rFOS|rINT|0|rSTA
;; beq.s @timedOut ; Branch if timedout
btst.l #bDSC+16,d5 ; was there a disconnected interrupt?
beq.s @notFree ;
bclr.b #FCIntPend, G_State96(a4) ; clear the FC Int pend flag
bclr.b #NeedMsgOut, G_State96(a4) ; and Message_Out
bset.b #PendBusFree,G_State96(a4)
bclr.b #NeedCmdSent, G_State96(a4) ; and Command expected flags
move.b zeroReg, G_State(a4) ; clear fake
move.l zeroReg, G_FakeStat(a4) ; clear fake
@notFree
bclr.b #SelMsgOut,G_State96(a4) ; <H3> from last <H3>
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
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_BIOS
btst.b #NeedMsgOut,G_State96(a4) ; did we send a Select w/ATN?
beq.w @unexpected ; no - just phase err out of here then
move.b #iMsgOut, d1 ; set up wait for message phase
jsr Wt4DREQorInt_BIOS
beq.w @gotInt ; if we got an interrupt, something's wrong
move.b rSTA(a3), d3 ; get phase value
and.b #iPhaseMsk, d3 ; load mask bits for phase value
cmpi.b #iMsgOut, d3 ; are we in MsgOut phase already?
bne.w @phaseErr ;
@inPhase ; We probably got here from Select w/ATN which means
; ATN is deasserted prior to transfer of msg byte
btst.l #bIDENT,d2 ; <H3> thru next <H3>
bne.s @useFIFO ; if we are sending x80 then we don't want
; to flush the fifo with the dma write
move.b d2, rDMA(a3) ; xfer msg byte
bsr.l WaitForIntNoTime ; Wait for intrp w/o timeout
; on exit d5 = rFOS|rINT|0|rSTA
btst.l #bDSC+16,d5 ; was there a disconnected interrupt?
beq.s @moreMsg ;
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
bset.b #PendBusFree,G_State96(a4)
move.b zeroReg, G_State(a4) ; clear fake
move.l zeroReg, G_FakeStat(a4) ; clear fake
moveq.l #noErr, d0 ; no error
tst.w d0 ; return results in status register
rts
@useFIFO
andi.b #$BF,d2 ; get rid of disconnect priviledge
move.b d2, rFFO(a3) ; xfer msg byte
bset.b #NeedCmdSent, G_State96(a4) ; and Command expected flags
bclr.b #PendBusFree,G_State96(a4)
bra.s @noErr
@moreMsg
; if we have reached here then we have successfully sent our msg byte out and the
; drive is either going into Cmd phase or MsgIn phase (rejecting the message)
;
bset.b #SelMsgOut,G_State96(a4) ;
bclr.b #NeedMsgOut,G_State96(a4) ;
move.b d5,d3
and.b #iPhaseMsk, d3 ; load mask bits for phase value
cmpi.b #iCommand,d3
bne.s @setMsgIn
bset.b #NeedCmdSent, G_State96(a4) ; and Command expected flags
bclr.b #PendBusFree,G_State96(a4)
bra.s @noErr
@setMsgIn ;
bclr.b #NeedCmdSent, G_State96(a4) ; and Command expected flags
bset.b #PendBusFree,G_State96(a4)
bra.s @noErr ; <H3> from last <H3>
@unexpected ; wait for 256mS for correct phase
jsr HandleSelInProg_BIOS
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
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
bclr.b #NeedCmdSent, G_State96(a4) ; and Command expected flags
@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!
tst.w d0 ; return results in status register
rts
;--------------------------------------------------------------------------
;
; 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
; IDLE bus phase and DATA OUT phase. They both have phase value = 0.
;
; Uses: d0
CyclePhase_96_BIOS ; (accessed thru jvCyclePhase)
btst.b #scBusy, G_State(a4) ; check if SCSIMgr is active
beq.s @xferErr ; bra. if not
@checkNextPhase ;
moveq.l #iPhaseMsk, d0 ; load mask bits for phase value
and.b rSTA(a3), d0 ; get phase bits
cmp #iDataIn, d0 ;
beq.s @inDataPhase ;
cmp #iDataOut, d0 ;
beq.s @inDataPhase ;
cmp #iCommand, d0 ;
beq.s @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
rts ; err code is saved
@xferErr ;
clr.l d0 ; no recovery
rts
; 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
bsr.l 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
bsr.l 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)
bset.b #FCIntPend,G_State96(a4) ; we took care of cmd, now expect FC interrupt
bsr.l WaitForSCSIIntrp ; Wait for intrp w/ timeout
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
bsr.l 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)
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
bsr.l 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
bsr.l 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
bsr.l 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
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
move.l (a0), d5 ; read DAFB SCSI DREQ
move.b G_bitDREQ(a4),d0 ; load DREQ bit position
btst.l d0, d5 ; DREQ ?
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
bsr.l WaitForIntNoTime ; Wait for intrp w/o timeout
; 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
move.l (a0), d5 ; read DAFB SCSI DREQ
move.b G_bitDREQ(a4),d0 ; load DREQ bit position
btst.l d0, d5 ; DREQ ?
beq.s @pDMAwrite ; bra. if inactive
move.w #$EEEE, rDMA(a3) ; load filler data into FIFO
bra.s @pDMAwrite
@writeAll ; Intrp will occur when REQ is asserted for the next phase
bsr.l WaitForIntNoTime ; Wait for intrp w/o timeout
; on exit d5 = rFOS|rINT|0|rSTA
; Check for next phase to cycle out of
@pDMADone
bra.w @checkNextPhase ; go check for next phase to cycle out of
;
;--------------------------------------------------------------------------
;
; Error_BIOS -- 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_BIOS
movea.l jvErr(a4), a0 ; get address of error routine
jsr (a0) ;
rts
;--------------------------------------------------------------------------
;
; SCSIErr -- Primarily for debugging.
;
SCSIErr_96_BIOS
rts ;
;_______________________________________________________________________
;
; 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_BIOS
move.l G_SCSIDREQ(a4), a0 ; G_SCSIDREQ contains DREQ regr address
move.l (a0), d5 ; read DAFB regr
move.b G_bitDREQ(a4),d0 ; load DREQ bit position
btst.l d0, d5 ; DREQ ?
rts
;==========================================================================
ENDWITH
END