sys7.1-doc-wip/OS/SCSIMgr4pt3/HALc96.a
2019-07-27 22:37:48 +08:00

2141 lines
64 KiB
Plaintext

;————————————————————————————————————————————————————————————————————————————————————
;
; File: HALc96.a
;
; Contains: Hardware Abstraction Layer for the 53c96 machines (Quadra + Cyclone)
;
; Written by: Paul Wolf
;
; Copyright: © 1992-1993 by Apple Computer, Inc., all rights reserved.
;
;
; NOTES on HALc96
;
; This HAL is written assuming at least a 68020! If we ever have a 68000 machine with
; a 53c96 then we have to change a few things.
;
;
; Change History (most recent first):
;
; <SM33> 11/22/93 pdw Rolling in from <MCxx>.
; <MC7> 11/8/93 pdw Added some support for unexpected disconnect. Fixed a bug in
; the handling of the selected-as-target Curio bug.
; <MC6> 11/5/93 pdw Series of attempts and re-attempts to fix various VM/FileShare
; problems.
; <MC5> 10/28/93 pdw Trivial stuff.
; <SM32> 11/16/93 SAM Include HardwarePrivateEqu.a
; <SMG2> 9/29/93 chp Substitute a 68020 addressing mode when referencing G_JmpTbl.
; The HAL variables have expanded enough that the old 8-bit base
; displacement indexed addressing mode is not sufficient.
; <SM30> 10/29/93 pdw Fixing build - RecordCmd is being expanded in the ROM but not in
; the Init in SOME places.
; <SM29> 10/29/93 DCB Removing a bogus clear of the gotInt flag at the start of
; doInitiate and SCSISelect which caused a sync wait hang.
; <SM28> 10/14/93 pdw <MC> roll-in.
; <MC4> 10/12/93 pdw Fixed error reported on initiate w/too few message out bytes.
; <MC3> 10/12/93 pdw Added support for Synchronous data transfers, rewrote State
; Machine, message handling etc.
; <SM27> 9/26/93 DCB SCSI Reset was not clearing the FIFO. This led to some weird
; crashes if the reset interrupted something that had left data
; there. In particular SCSI CDBs were being send instead of
; identify messages. Yikes.
; <MC2> 9/26/93 pdw Changes to G_State usage from bit flags to enumeration and other
; stuff.
; <SM26> 9/12/93 pdw Comment changes. Changed post-ResetBus delay to 250mS instead
; of 500mS.
; <SM25> 9/9/93 pdw Lots of little changes. Name changes, temporary cache_bug
; stuff.
; <SM24> 8/13/93 pdw A lot of eieios, RecordRCMDs, reworked PutXferPhase/Disconnect
; stuff, rewrote SCSIComplete.
; <SM23> 7/19/93 pdw Fixed build.
; <SM22> 7/19/93 pdw Added an ENDIF to fix that build warning.
; <SM21> 7/17/93 pdw Lots of little things.
; <SM20> 6/29/93 pdw Massive checkins: Change asynchronicity mechanism to CallMachine
; stack switching mechanism. Adding support for Cold Fusion.
; Rearranging HW/SW Init code. Some code optimizations. Resolving
; with my Ludwig sources.
; <SM19> 5/25/93 DCB Rollin from Ludwig. (The next item below)
; <LW15> 5/21/93 PW Hopefully adding ability to handle being selected while we are
; trying to select.
; <SM18> 5/5/93 PW Converted names to meanies-friendly names. Updated with latest
; from Ludwig stuff.
; <LW14> 4/30/93 DCB Make DoHalInfo a separate function so it can be stuffed into a
; vector.
; <LW12> 4/14/93 DCB Added SetParity HALAction but left it disabled for now.
; <LW11> 3/26/93 PW Removed useless RejectMsg stuff.
; <SM17> 3/29/93 PW Removed rCF3 manipulations for PDM. Now I just set it up once in
; HWInit for threshold 8 or not.
; <SM16> 3/21/93 PW Removing useless RejectMsg stuff.
; <LW10> 3/8/93 PW Fixed another instance of c96-FIFO-stuck bug in DoCommand by
; checking not only for zero bytes but for 1 byte in FIFO after
; interrupt.
; <LW9> 2/17/93 PW Removed DoBitBucket and put it in HALc96Data.a instead.
; <SM15> 3/20/93 PW Removed some bogus PDM stuff that causes problems on non-PDMs.
; <SM14> 3/20/93 PW Removed DoBitBucket and put it in HALc96Data.a instead.
; <LW8> 2/3/93 PW Removed initCF1 munging before and after DoReset to fix reset
; blowing up bug.
; <SM13> 1/31/93 PW Update from the latest of Ludwig. Also changes required for PDM
; (will update Ludwig with these as needed myself).
; <LW7> 1/29/93 PW Passing HALg into SetupIOPB function.
; <LW6> 1/27/93 PW Playing around with some interrupt stuff. Changed HALaction
; events to include SR (for int level).
; <LW5> 1/27/93 PW Changed the name of InitDataPointer to InitDataStuff (since it's
; more general now). Changed intEnable and intDisable calling
; around - now I disable going into MyDT and enable coming out and
; I disable going into HALAction and enable coming out.
; <LW4> 1/8/93 PW Removed bogusing the phase and selectorID values in HALActionPB
; in ReadHALAction. This fixes the problem where RestorePointers
; action trashes phase so following SwitchPhase breaks. Also added
; fixes to Initiate to handle Reselect better - moved call to
; InitDataPointer to after select complete and flushed FIFO after
; checking for a second interrupt on a r_select. Also flushed FIFO
; after a select is complete (for targets which dont get all of
; the command bytes (i.e. IBM 160 with a $90 command).
; <LW3> 12/18/92 PW Really fix the hanging in vSyncWait after SCSICmd bug by
; clearing the G_State96 bits after Ck4SCSIInt sees the interrupt.
; <LW2> 12/15/92 DCB Fixed SCSICmd bug with DSP running or with caches disabled by
; not calling Wt4S if ck4int reveals an interrupt.
; <SM12> 12/9/92 PW Changed SCStats record name to SCResults. Rearranged DoCommand
; routine to fix some MORE bugs handling SCSISelAtn/SCSIMsgOut.
; <SM11> 12/9/92 PW Fixed SCSIMsgOut bug by changing DMA xfer count from 3 bytes to
; 2.
; <SM10> 12/5/92 PW Changed some names and fixed the DoReset routine so that it
; works when Reset interrupt reporting is on.
; <SM9> 11/12/92 PW Changed beq.s and bra.s to beq.w and bra.w to work when
; RECORD_rCMD is turned on.
; <SM8> 10/30/92 DCB Added Setup and Teardown routines to support Direct DMA into a
; user buffer
; <SM7> 10/8/92 PW Added GrossError checks. Some trivial name changes. Added test
; for out of bounds xferType. (cb) Fixed .w vs .l direction
; parameter bug in calling of StartDMA.
; <SM6> 9/11/92 DCB Rolled in Paul's fix for message out during initiate
; <SM5> 8/31/92 PW Changed register and command definitions to reflect changes to
; SCSIEqu53c96. Also added SelWAtnStop stuff to send 2 and 4 or
; more byte messages out in DoInitiate.
; <SM4> 8/30/92 PW Added DoAssertATN and fixed SendMsg bugs (it couldn't handle
; multiple-byte msg non-SelWAtn case).
; <SM3> 8/20/92 DCB Added Select w/o Atn and fixed SCSI Reset
; <SM2> 7/28/92 PW Resolved differences in sources.
; <SM1> 7/27/92 PW Initial check-in.
;
;____________________________________________________________________________________
MACHINE MC68020 ; '020-level
BLANKS ON ; assembler accepts spaces & tabs in operand field
PRINT OFF ; do not send subsequent lines to the listing file
; don't print includes
INCLUDE 'SysEqu.a'
wholeErrors equ 1
INCLUDE 'SysErr.a'
INCLUDE 'HardwarePrivateEqu.a'
INCLUDE 'Debug.a' ; for NAME macro
INCLUDE 'SCSI.a'
INCLUDE 'SCSIStandard.a'
INCLUDE 'SCSIEqu53c96.a'
INCLUDE 'ACAM.a'
INCLUDE 'SIMCoreEqu.a'
INCLUDE 'HALc96equ.a'
PRINT ON ; do send subsequent lines to the listing files
CASE OBJECT
IMPORT Xfer1Byte96, Wt4SCSIInt
IMPORT Ck4SCSIInt
IMPORT GetSelectInfo, GetReconnectInfo
IMPORT InitDataStuff
IMPORT GetHalInfo
IMPORT RecordEvent, Ck4DREQ
IMPORT AsmInit53c9xHW
IMPORT Disconnected, UnexpectedDisc
;====================================================================================
;************************************************************************************
;
; HALaction - main entry point for HAL (called by SIMCore)
;
; This routine gets handed 1 parameter on the stack - a pointer to a HALactionPB.
; It establishes the following register convention and then calls the requested action.
;
; A0 - current SCSI_IO parameter block ptr
; A3 - ptr to 53c96 base address
; A4 - ptr to the HALactionPB (passed in as parameter on stack)
; A5 - HALg (ptr to the HALglobals)
;
; These register conventions are used throughout the HAL. Any routine that uses
; any of these registers must save/restore them.There are no conventions for
; Dx registers.
;
; The action is specified in the HALactionPB.action parameter. We use the handy
; jump table to find and call the appropriate routine.
;
; When we return from the requested HALaction, the phase is checked to see if some
; additional work is needed before returning to the SIM. If Bus Free, then we need
; to do some housework associated with Disconnecting. If MsgIn phase, the we will go
; ahead and get the message for the SIM but we won't accept it unless we know what to
; do with it.
;
;====================================================================================
HALaction PROC EXPORT
;————————————————————————————————————————————————————————————————————————————————————
regsToSave REG D3-D7/A2-A5
numRegsToSave EQU 9
WITH HALactions
WITH HALc96GlobalRecord
WITH SCSIPhase
movem.l regsToSave, -(sp)
move.l numRegsToSave*4+4(sp), A4 ; get the one parameter from stack (HALactionPB)
move.l HALactionPB.HALstaticPtr(A4), A5 ; and get the staticPtr
; Initialize the values in the HALactionPB
clr.w HALactionPB.result(A4) ; assume noErr, Action will change if needed
; Get stuff out of PB into our world
move.l baseRegAddr(A5), A3 ; load A3 with base addr of 53c96
move.w HALactionPB.action(A4), D0 ; get Action from HALactionPB
cmp.w #kNumHALaction, D0 ; is scsiSelector higher than last one?
bhs.s @Unknown ; yes - unknown
move.l (G_JmpTbl, A5, D0.w*4), A1 ; get action routine from jump table
IF RECORD_ON THEN
pea 'HAL-'
move.b HALactionPB.action+1(A4), D3
lsl.l #8, D3
move.b HALactionPB.msgOutLen(A4), D3
lsl.l #8, D3
move.b HALactionPB.msg(A4), D3
lsl.l #8, D3
move.b currentPhase(A5), D3
move.l D3, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
;…………………………… Call the selected routine ……………………………………
move.l HALactionPB.ioPtr(A4), A0 ; load A0 with ptr to SCSI_IO pb
jsr (A1) ; and go to requested action routine
;…………………………………………………………………………………………………………………………………………
move.b currentPhase(A5), D0
@ck4msgIn
cmp.b #kMessageInPhase, D0
bne.s @ck4busFree
jsr ([jvAutoMsgIn, A5])
move.b currentPhase(A5), D0
@ck4busFree
cmp.b #kBusFreePhase, D0
bne.s @normalPhase
bsr Disconnected
@normalPhase
move.b D0, HALactionPB.phase(A4)
IF RECORD_ON THEN
pea '-HAL'
move.b HALactionPB.action+1(A4), D3
lsl.l #8, D3
move.b HALactionPB.result+1(A4), D3
lsl.l #8, D3
move.b HALactionPB.msg(A4), D3
lsl.l #8, D3
move.b HALactionPB.phase(A4), D3
move.l D3, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
movem.l (sp)+, regsToSave
rts
@Unknown
IfDebugStr 'HAL action selector too high'
moveq #dsIOCoreErr, D0
_SysError
bra.s *
RTSNAME 'HALaction'
;==========================================================================
HALc96 PROC EXPORT
;——————————————————————————————————————————————————————————————————————————
EXPORT DoInitiate, Wt4SelectComplete, HandleBusInt
EXPORT DoAcceptMsg
EXPORT DoMsgOut
EXPORT DoStatus
EXPORT DoComplete
EXPORT DoSelect
EXPORT DoCommand
EXPORT SetParity
EXPORT CyclePhase
EXPORT AutoMsgIn
EXPORT HALResetBus, HALAssertATN, HALTeardownIO
EXPORT HALSyncConfig
EXPORT DoAssertATN
EXPORT SetupIONoDMA, TeardownIONoDMA
EXPORT DoReset
WITH HALc96GlobalRecord
WITH SCSI_IO, HALactions, SCSIPhase
;==========================================================================
;
Unimplemented
IfDebugStr 'Unknown HAL action selector'
moveq #dsIOCoreErr, D0
_SysError
;——————————————————————————————————————————————————————————————————————————
rts
NAME 'Unimplemented'
;################################################################################
;********** HALActions *********
;################################################################################
IF 0 THEN
;========================================================================
Initiate a connection
Arbitrate, Select and send [Identify message and] CDB to target
Description:
Once DMA is setup to do CDB and c96 is setup to do Arb+Select+Identify+CDB,
it can end up several ways:
• Arbitration failed
SCSI Int - ??
no DMA int
• Select failed
SCSI Int - ??
no DMA int
• Select w/Atn but didn't go into MessageOut phase
SCSI Int - ??
no DMA int
• didn't go into Command phase
SCSI Int - ??
no DMA int
• only sent part of CDB before target went out of Command phase
SCSI Int - ??
no DMA int
• sent CDB but didn't get out of Command phase
SCSI Int - Function Complete + ??
DMA int - xfer complete
c96 will bitblast 00 out until !Command phase. Can/can't?? tell it happened.
• all OK - send MsgOut and Command out and went into a different phase
SCSI Int - Function Complete + Bus Service, rSEQ=??
DMA int - xfer complete
Flow:
Setup c96 to do a Select w/Atn with Identify msg in FIFO and CDB in DMA
Setup DMA for CDB
Return to caller and wait for interrupt from c96 and DMA
Int c96:
get status, fifo seq and interrupt regs
all cool?
yes: DMA already int?
no: rts - wait for DMA_complete int
yes: call InitiateComplete(success)
no: find out what went wrong
terminate DMA
call InitiateComplete(failed)
Int DMA:
SCSI already int?
no: rts - wait for SCSI int
yes: check
;
ENDIF
;==========================================================================
; Initiate
; - Arbitrate, Select, Send Message(s) (optional), Send CDB (command bytes, optional)
;
; 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.
;
; A4 - ptr to HALaction pb
; A3 - SCSI read base address
; A5 - ptr to SCSI Mgr globals
;
;--------------------------------------------------------------------------
DoInitiate
IF RECORD_ON THEN
move.l D0, -(sp)
pea 'Init'
moveq #'0', D0
add.b scsiDevice.targetID(A0), D0 ; ID
move.l D0, -(sp)
bsr RecordEvent
addq.l #8, sp
move.l (sp)+, D0
ENDIF
move.b rSTA(A3), D1 ; interrupt?
bmi.w @getBusInt ; if we got an int from the bus, go check it out
;
; Set up chip for select process (init dest ID)
;
move.b scsiDevice.targetID(A0), rDID(A3) ; tell chip which target ID to select
;—————————————————————————————————————————————————————————
;
; Check scsiDisableSelectWAtn flag and number of msg_out bytes needed to determine what kind
; of Select operation we need to do.
;
move.w SCSI_IO.scsiIOFlags(A0), D0 ; Get the flags field
and.w #scsiDisableSelectWAtn,D0 ; Are we doing select with attention?
bne @useNoAtnSel ; nope, don't send an identify message
;
; How many message bytes are there? This will determine what Select command
; we will issue to the c96.
;
moveq.l #0, D0
move.b HALactionPB.msgOutLen(A4), D0
IF DEBUGGING THEN
bne.s @99 ; if no msg bytes to send, we're toast!!!
DebugStr 'DoInitiate:SelectWAtn but no msg'
ENDIF
@99 cmp.b #1, D0 ; 1 message byte?
bne.s @ck3byteSel ; no->ck for 3 bytes
;—————————————————————————————————————————————————————————
;
; If there is 1 message out byte, we can stuff it and the CDB into the
; FIFO then send a SelWAtn command.
;
@use1byteSel
move.b HALactionPB.msg(A4), rFIFO(A3) ; move message into FIFO
tst.b HALactionPB.sendCDB(A4) ; are we sposed to send CDB too?
beq.s @skipCDB1 ; no->skip it
bsr MoveCDBintoFIFO ; yes: stuff it and check for bus int
bmi.w @getBusInt ; if we got an int, go check it out
@skipCDB1
RecCmd $42, 'A',$08
eieio
move.b #cSelWAtn, rCMD(A3) ; issue Select w/ Atn cmd (non-DMA)
eieio
bra.w @SelStarted
;—————————————————————————————————————————————————————————
;
; If there are 3 message bytes to send, use a SelWAtn3 command.
;
@ck3byteSel
cmp.b #3, D0 ; 3 message bytes?
bne.s @doSelAndStop
@use3byteSel
lea.l HALactionPB.msg(A4), A1
move.b (A1)+, rFIFO(A3) ; move message into FIFO
move.b (A1)+, rFIFO(A3) ; move message into FIFO
move.b (A1)+, rFIFO(A3) ; move message into FIFO
move.b rSTA(A3), D1 ; interrupt?
bmi.w @getBusInt ; if we got an int, go find out what it is
tst.b HALactionPB.sendCDB(A4) ; are we sposed to send CDB too?
beq.s @skipCDB3 ; no->skip it
bsr MoveCDBintoFIFO ; yes: stuff it and check for bus int
bmi.w @getBusInt ; if we got an int, go check it out
@skipCDB3
RecCmd $46, 'A',$0a
eieio ; flush all writes out before issuing cmd
move.b #cSelWAtn3, rCMD(a3) ; issue Select w/ Atn3 cmd (non-DMA)
eieio
bra.w @SelStarted
;—————————————————————————————————————————————————————————
;
; If there are other than 1 or 3 message out bytes, we have to do a SelAndStop command
; followed by cIOXfer of the remainder of the message then cIOXfer of the command bytes.
;
@doSelAndStop
lea.l HALactionPB.msg(A4), A1
move.b (A1)+, rFIFO(A3) ; move 1st message byte into FIFO
eieio
RecCmd $41, 'A',$00
move.b #cSelWATNStop, rCMD(a3) ; do Select w/Atn and stop (after 1 msg-out)
eieio
jsrv jvWt4SelectComplete, A2
bne.w @exit ; if we didn't select, exit
;
; Check phase and/or check FIFO: if we didn't send the 1 message byte out, set a flag
; indicating that. If we did but we aren't still in msg_out phz, set a different flag.
; If we did and we are still in msg_out phase - jolly good - stuff the rest of the msg
; into the FIFO.
;
moveq.l #mFIFOCount, D1 ; use mask to get FIFO flag field
and.b int_rFIFOflags(A5), D1 ; is the byte still in the FIFO?
beq.s @sendRestOfMsg ; no -> send rest of message
bra.w @selIncompleteMsg ;
@sendRestOfMsg
cmpi.b #kMessageOutPhase, currentPhase(A5) ; are we in MsgOut phase?
beq.s @inMsgOutPhase ; yes->send rest of bytes
move.b #1, HALactionPB.msgOutLen(A4) ; no: we only sent 1 msg byte
bra.w @selIncMsgNoCalc
@inMsgOutPhase
moveq.l #0, D0
move.b HALactionPB.msgOutLen(A4), D0
subq.w #2, D0 ; 1 for missing dbra, 1 for 1st msg byte
@lp
move.b (A1)+, rFIFO(A3) ; move message into FIFO
dbra D0, @lp
eieio
;
; Do the IOxfer and check the results (FIFO count and phase). Note if we didn't get all
; of our message bytes out (and clear them out with FlushFIFO).
;
RecCmd $10, 'A',$04
move.b #cIOXfer, rCMD(a3) ; load Transfer cmd byte in CMD regr
eieio
bsr Wt4SCSIInt ; Wait for intrp w/o timeout
moveq.l #mFIFOCount, D1 ; use mask to get FIFO flag field
and.b int_rFIFOflags(A5), D1 ; are there bytes still in the FIFO?
beq.s @ck4CmdPhase ; no -> see if we're in cmd Phase
; we didn't send all of our message out
bra @selIncompleteMsg
@ck4CmdPhase
tst.b HALactionPB.sendCDB(A4) ; are we sposed to send CDB too?
beq.w @selComplete ; no->we're done
cmpi.b #kCommandPhase, currentPhase(A5) ; are we in Command phase?
bne.w @selNoCommand ; no->we missed Command phase
@inCommandPhase
bsr MoveCDBintoFIFO ; yes: stuff it and check for bus int
RecCmd $10, 'A',$06
move.b #cIOXfer, rCMD(a3) ; load Transfer cmd byte in CMD regr
eieio
bsr Wt4SCSIInt ; Wait for intrp w/o timeout
bne UnexpectedDisc ; bus free? -> exit
moveq.l #mFIFOCount, D1 ; use mask to get FIFO flag field
and.b int_rFIFOflags(A5), D1 ; are there bytes still in the FIFO?
beq.w @selComplete ; no -> select is complete
bra.s @selIncompleteCommand ; yes-> sent too few Command bytes
;—————————————————————————————————————————————————————————
;
; If we aren't supposed to Select w/Atn, then we don't have any message bytes
; to send
;
@useNoAtnSel
bsr MoveCDBintoFIFO
bmi @getBusInt ; if we got an int, go check it out
RecCmd $41, 'A',$0c
move.b #cSelWOATN, rCMD(a3) ; issue Select w/o Atn cmd (non-DMA)
eieio
;—————————————————————————————————————————————————————————
@SelStarted
jsrv jvWt4SelectComplete, A2 ; wt 4 something to happen
bne.w @selectDidnt ; reselect/bus free -> didn't select
moveq.l #mFIFOCount, D1 ; use mask to get FIFO flag field
and.b int_rFIFOflags(A5), D1 ; are there bytes still in the FIFO?
beq.w @selComplete
tst.b HALactionPB.sendCDB(A4)
beq.s @selIncompleteMsg
sub.b scsiCDBLength(A0), D1 ; how does fifo count compare to cdb len?
beq.s @selNoCommand ; same? -> no command
bcs.s @selIncompleteCommand ; cdb>fifo count? -> incomplete cmd
@selIncompleteMsg
sub.w D1, HALactionPB.msgOutLen(A4) ; calc xferred bytes
@selIncMsgNoCalc
IF ERR_RECORD_ON THEN
move.l D0, -(sp)
pea 'Err!'
move.l #'msg0', D0
add.b HALactionPB.msgOutLen(A4), D0
move.l D0, -(sp)
bsr RecordEvent
addq.l #8, sp
move.l (sp)+, D0
ENDIF
move.w #HALresult.kHALpartialMsgOut, HALactionPB.result(A4)
bra.s @exitWFlush
@selIncompleteCommand
IF ERR_RECORD_ON THEN
pea 'Err!'
pea 'cmdx'
bsr RecordEvent
addq.l #8, sp
ENDIF
move.w #HALresult.kHALpartialCommand, HALactionPB.result(A4)
bra.s @exitWFlush
@selNoCommand
IF ERR_RECORD_ON THEN
pea 'Err!'
pea 'cmd0'
bsr RecordEvent
addq.l #8, sp
ENDIF
move.w #HALresult.kHALnoCommand, HALactionPB.result(A4)
@exitWFlush
RecCmd $01, 'A',$0e
move.b #cFlushFIFO, rCMD(A3) ; yes - get rid of them
eieio
@selectDidnt
@selComplete
@exit
rts
@getBusInt
jsrv jvHandleBusInt, A2
rts
;———————————————————
NAME 'DoInitiate'
;——————————————————————————————————————————————————————————————————————————————————————
;———————————————————————————————————————————
Wt4SelectComplete
bsr InitDataStuff ; set up saved and current data pointers
;
; OK - first we need to setup any buffers for DMA
;
; The reason we are setting up the buffers here instead of somewhere else is that a select will typically
; take a fair amount of time. Instead of giving that time back to the client we will use it to do a lock
; memory. This optimizes for transaction performance rather than asynchronicity. <SM8>
;
move.l A0, -(sp) ; pb that gets setup
jsrv jvSetupIO, A2
move.l (sp)+, A0 ; get rid of parm and restore A0
;————————————————————————
HandleBusInt
; Check for an int - either Disconnected (fld select) or Bus Service/Func. Cmplt (good select)
bsr Wt4SCSIInt
;
; 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 and either finished the message out
; and command phases then saw a REQ or it went to an unexpected phase. (OR A RESELECT !)
;
cmp.b #mFuncComplete+mBusService, int_rINT(A5) ; was interrupt a FuncComplete/BusService ?
bne.s @ck4reselect ; no -> check disconnect, reselect etc.
@exitDidSelect
moveq.l #0, D0 ; yes: successful select
rts
;——— Was it a Reconnect (during select)?
@ck4reselect
btst #bReselected, int_rINT(A5) ; was it a Reselect?
beq.s @1
bsr Ck4SCSIInt ; check for another int (in case of illegal cmd)
move.b #cFlushFIFO, rCMD(A3) ; wipe misc. msg and CDB that we stuffed
eieio
jsrv jvGetReconnectInfo, A2
@exitDidntSelect
moveq.l #1, D0 ; didn't select result code
rts
;——— Was it a bus-initiated Select (during our select)?
@1 btst #bSelected, int_rINT(A5) ; selected int?
beq.s @2
jsrv jvGetReconnectInfo, A2
bra.s @exitDidntSelect
;——— Was it a failed select? (i.e. a disconnect interrupt)
@2 btst #bDisconnected, int_rINT(A5) ; (i.e. timed-out then bus free)
beq.s @unknownInt
move.w #HALresult.kHALselectFld, HALactionPB.result(A4) ; select timeout
bra.s @exitDidntSelect
;——— It was an unknown interrupt
@unknownInt
DebugStr 'Unknown interrupt on Initiate'
bra.s @exitDidSelect
RTSNAME 'Wt4SelectComplete'
;———————————————————————————————————————————
MoveCDBintoFIFO
move.l SCSI_IO.scsiFlags(A0), D0
and.l #scsiCDBIsPointer, D0
beq.s @CDBisReal
move.l scsiCDB(A0), A1 ; get CDB from io pb
bra.s @moveBytes
@CDBisReal
lea.l scsiCDB(A0), A1 ; get CDB from io pb
@moveBytes
moveq.l #0, D0 ; clear upper part of D0 for dbra
move.b scsiCDBLength(A0), D0 ; get len of CDB from io pb
IF RECORD_ON THEN
move.l 0(A1),-(sp) ; CDB bytes 0-3
move.l 4(A1),-(sp) ; CDB bytes 4-7
bsr RecordEvent
addq.l #8, sp
ENDIF
bra.s @cdbLpBtm
@cdbLoop
move.b (A1)+, rFIFO(a3)
@cdbLpBtm
move.b rSTA(A3), D1 ; interrupt?
dbmi D0, @cdbLoop ; if so, fall thru, else, dec and bra
eieio
rts ; <SM5> pdw from prev
NAME 'MoveCDBintoFIFO'
;——————————————————————————————————————————————————————————————————————————————————————
;
; FUNCTION SCSISelect(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.
;
DoSelect
; Set up chip for select process (init dest ID)
move.b scsiDevice.targetID(A0), rDID(A3) ; tell chip which target ID to select
; delayed eieio
IF DEBUGGING THEN
tst.b HBAhasPseudoDMA(A5) ; if we have pseudoDMA ...
bne.s @DREQable ;
tst.b HBAhasDMA(A5) ; or real DMA ...
bne.s @DREQable ; ... use this routine
IfDebugStr 'bad hwDesc - no DMA or pDMA'
moveq #dsIOCoreErr, D0
_SysError
@DREQable
ENDIF
cmp.w #scsiSelAtn, scsiSelector(A0) ; Select w/Atn?
beq.s @withAtn ; yes->set up for msg byte expected
; If Select w/o Atn then set up for 2 DMA bytes (last bytes of command block) and start process
@withoutATN
eieio
move.b #NeedCmdSent, G_State96(A5) ; flag=expect to see a COMMAND phase next
clr.b rXCM(a3) ; tell chip that we will be sending 2
move.b #2, rXCL(a3) ; DMA bytes (in command phase)
move.b #kCommandPhase, currentPhase(A5) ; fake out command phase
RecCmd $c1, 'A',$10
move.b #cDMASelWOAtn, rCMD(a3) ; issue Select w/o Atn cmd
eieio
bra.s @0
; If Select w/Atn then set up for 2 DMA bytes (msg_out byte + last byte of command block)
@withATN
eieio
move.b #NeedMsgOut, G_State96(A5) ; flag=expect to see a MESSAGE_OUT phase next
clr.b rXCM(a3) ; tell chip that we will be sending 1
move.b #2, rXCL(a3) ; DMA bytes (1 in msg_out, 2 in command)
move.b #kMessageOutPhase, currentPhase(A5) ; fake out MessageOut phas
RecCmd $c2, 'A',$12
move.b #cDMASelWAtn, rCMD(a3) ; issue Select w/ Atn cmd
eieio
@0
; Set up >512mS timeout for select operation to get somewhere (probably more like 4 seconds)
moveq.l #0, d1 ; clear upper word
move.w TimeSCSIDB, d1 ; get # of DBRAs
lsl.l #8, d1 ; multiply by 256
move.l d1, d2 ; 4-16 sec wait for overall watchdog
swap d2
; 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 Phase (if Sel w/o Atn)
; or Message_Out Phase (if Sel w/Atn). Here we will see a Function Complete/Bus Service
; interrupt.
; - the target may select OK and go into the expected Phase - 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)
bsr Ck4DREQ ; DREQ?
bne.s @gotDREQ ; yes-> we have a REQ for MsgOut or Cmd byte
; Check for an int - Disconnected, good select, reselected or selected
tst.b gotInt(A5) ; check for an int
bne.s @doneWithSel ;
tst.b rSTA(A3) ; interrupt?
dbmi D1, @waitLoop ;
dbmi D2, @waitLoop ; loop until count exhausted or intrp detected
; count is up or intrp detected so we're outta' here
bpl.s @timedOut ; if not interrupt
;———————————————————
; 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.
@doneWithSel ; got an interrupt
clr.b G_State96(A5) ; not waiting for anything
jsrv jvHandleBusInt, A2
rts
;———
@gotDREQ
bsr InitDataStuff ; set up saved and current data pointers
rts
NAME 'Select'
;———————————————————
@timedOut
IF ERR_RECORD_ON THEN
pea 'STmO'
move.w busID(A5), -(sp)
move.w int_rINT(A5), -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
move.w #scArbNBErr, HALactionPB.result(A4) ; arbitration timeout (1/2 second or so)
;
; Check for CURIO Target mode bug (where it goes into DMA mode halfway through
; receiving the command bytes.
;
cmp.b #$0a, rSTA(A3) ; cmd_xfer_cmplt + cmd phz
bne.s @exit ; not same value -> not the bug
cmp.b #$30, rFIFOflags(A3) ; no bytes in FIFO
bne.s @exit
cmp.b #$c1, rSQS(A3) ; sequence step == C1
bne.s @exit
cmp.b #$c1, rCMD(A3) ; last command was our DMA select
bne.s @exit
IfDebugStr 'AMD shines again!'
IF ERR_RECORD_ON THEN
pea 'Err!'
pea 'AMD!'
bsr RecordEvent
addq.l #8, sp
ENDIF
bsr AsmInit53c9xHW ; reset this chip and start over!
move.b #kBusFreePhase, currentPhase(A5)
move.w #HALresult.kHALselectedAsTargetFld, HALactionPB.result(A4) ; select timeout
@exit
rts
NAME 'DoSelect_excptns'
;==========================================================================
;
; Send Command.
;
; A0, A3, A5 - usual HAL conventions
;
; Sends the CDB bytes that are specified in the IOpb (A0). There are two ways of
; doing this, depending on whether we are working on an old API or new API transaction.
; In both cases, we stuff all of the CDB except 2 bytes and then, depending on whether
; it's old or new, we do different things for the last two bytes - see details below.
;
;
DoCommand
;---- Load the FIFO with ALMOST all of the bytes
@sendBytes
move.l SCSI_IO.scsiFlags(A0), D0
and.l #scsiCDBIsPointer, D0
beq.s @CDBisReal
move.l scsiCDB(A0), A1 ; get CDB from io pb
bra.s @1
@CDBisReal
lea.l scsiCDB(A0), A1 ; get CDB from io pb
@1
moveq.l #0, D2 ; clear upper part of D2 for dbra
move.b scsiCDBLength(A0), D2 ; get len of CDB from io pb
subq.l #2, D2 ; adjust for DMA of last bytes
bge.s @btmLoadFIFO ; bra to dbra for zero case (2 byte CDB)
bra @oneByteCDB
@loadFIFO ; loading the FIFO w/o pseudo-DMA will simulate
move.b (A1)+, rFIFO(A3) ; preloading of the FIFO...we then pDMA the
@btmLoadFIFO ;
dbra D2, @loadFIFO
eieio
;---- send the last 2 bytes
@oldAPIorNewAPI
tst.b G_State96(A5) ; are we doing a Select operation?
beq @newAPIcmd ; no -> new API: rFIFO last 2, IOXfer
; yes: old API: rDMA(), no cmd
;————— Old API Last 2 bytes ————————————————
;
;---- Handle the Select operation that's in progress
; If the NeedCmdSent condition is true, that means that we are in the middle of an old-API
; transaction which means that we are sitting right in the middle of a c96 SelW(O)Atn
; process which means that all we have to do is stuff the last two bytes into the FIFO
; with pseudo-DMA or real DMA. No command needs to be issued to the c96 since it is
; working on the Select command.
;
@lastCmdBytes
tst.b HBAhasPseudoDMA(A5)
beq.s @ck4hasDMA
move.w (A1)+, rDMA(A3) ; Use Pseudo DMA to load last bytes
bra.s @sentAll
eieio
@ck4hasDMA
tst.b HBAhasDMA(A5)
bne.s @hasDMA
IfDebugStr 'Bad hwDesc - no DMA or pDMA'
moveq #dsIOCoreErr, D0
_SysError
@hasDMA
move.w (a1)+, ([logicalCopyBuffer,A5]) ; put last bytes into our DMA buffer
move.w #false, -(sp) ; false = out
move.l #2, -(sp)
move.l physicalCopyBuffer(A5), -(sp)
jsr ([jvStartDMA,A5])
lea 10(sp), sp
jsr ([jvWt4DMAComplete,A5])
@sentAll
move.b #FCIntPend,G_State96(A5) ; now we can expect a FunctionCmplt interrupt
;---- Wait for either FIFO empty (c96 sent the bytes) or an interrupt (target bailed early)
@wt4EmptyOrInt
moveq.l #mFIFOCount, D1 ; use mask to get FIFO flag field
and.b rFIFOflags(A3), D1 ; how many bytes left in FIFO?
beq.s @wt4int ; if none, return out to caller, we'll wait
; for int at start of next call (in XPT)
bsr Ck4SCSIInt ; if not empty, did we get an interrupt?
beq.s @wt4EmptyOrInt
; Did we send all the bytes?
moveq.l #mFIFOCount, D1 ; use mask to get FIFO flag field
and.b rFIFOflags(A3), D1 ; how many bytes left in FIFO?
beq.s @gotSelInt ; ->if none then we're cool
RecCmd $01, 'A',$83
move.b #cFlushFIFO, rCMD(a3) ; if bytes in FIFO, wipe them out
cmp.b #1, D1 ; check for c96 FIFO-gets-stuck bug
beq.s @gotSelInt ; ->if 1 then we're cool too (probably)
bra.s @phaseErr ; if >1 byte left, then target bailed early
@wt4int ; <L2> pdw
;---- Wait till we get an interrupt (indicating a REQ beyond Command Phz)
bsr.w Wt4SCSIInt
@gotSelInt
;
; We have to flush the FIFO because of another bug in the c96 where it leaves a byte
; in the FIFO (or at least the count is nonzero) after a cSelWOAtn operation (that
; was sent during a SCSISelect call). This caused a later SCSIComplete
; to read in a bogus Status byte before reading in the real Status byte (which was
; thought to be the Message byte). The null Status byte is usually OK on hard disks and
; such but when polling for a CD-ROM, we are supposed to be getting 02 (check condition)
; and when the CD-ROM driver sees a null, it posts a bogus DiskInsert event.
;
@flushAndExit
RecCmd $01, 'A',$86
move.b #cFlushFIFO, rCMD(A3) ; Flush FIFO - REMEMBER THE CD-ROM BUG!!!
eieio
@noErrRet
clr.b G_State96(A5) ; not waiting for anything
cmp.b #kBusFreePhase, currentPhase(A5)
beq UnexpectedDisc ; bus free? -> exit
rts
;————— New API Last 2 bytes ————————————————
;
; If we didn't have the NeedCmdSent condition, that means that we aren't doing an old-API
; transaction which means that we aren't sitting in the middle of a c96 cSelectWOAtn
; process. This means that we need to stuff the last two bytes into the FIFO using the
; regular byte-wide rFIFO register (not DMA) and issue a cIOXfer command to the c96 to
; actually send the whole FIFO full of CDB bytes.
;
@newAPIcmd
move.b (a1)+, rFIFO(A3) ; load last 2 bytes
move.b (a1)+, rFIFO(A3)
eieio
RecCmd $10, 'A',$13
move.b #cIOXfer, rCMD(A3) ; issue IOXfer command
eieio
bra.s @wt4int
RTSNAME 'DoCommand'
;————— Exceptions ————————————————
@oneByteCDB
move.b (a1), d0
lsl.w #8, D0
move.b (a1), d0 ;_debugger CAN't DO THIS ON A CYCLONE!!!!%%%
move.w D0, rDMA(a3) ; Use Pseudo DMA to load only byte
; do a word to satisfy c96's DMA counter
eieio
bra.s @sentAll
@phaseErr
IF ERR_RECORD_ON THEN
pea 'Err!'
pea 'CPz2'
bsr RecordEvent
addq.l #8, sp
ENDIF
@2
moveq.l #scPhaseErr, d0 ; no error
move.w D0, HALactionPB.result(A4) ; with whatever err
bra.s @flushAndExit
RTSNAME 'DoCommand_excptns'
;==========================================================================
;
; 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
DoStatus
DoComplete
@chkPhase
cmpi.b #kStatusPhase, currentPhase(A5) ; are we in status phase?
beq.s @inStatusPhase ;
cmp.b #kBusFreePhase, currentPhase(A5)
beq @scsiComplPhaseErr ;
@notInStatusPhase ; only called for Complete phase errors
bsr CyclePhase
bra.s @chkPhase
@inStatusPhase
RecCmd $11, 'A',$14
move.b #cCmdComplete, rCMD(a3) ; load cmd complete code
eieio
bsr Ck4SCSIInt ; Check for intrp
bne.s @gotStatus ; got it -> good
bsr Ck4SCSIInt ; Check for intrp
bne.s @gotStatus ; got it -> good
bsr Wt4SCSIInt ; no, try again and wait for it
@gotStatus
move.b rFIFO(a3), D2 ; read status byte from FIFO
move.b D2, scsiSCSIstatus(A0) ; return status byte
moveq.l #mFIFOCount, d1 ; use mask to get FIFO flag field
and.b rFIFOflags(a3), d1 ; bytes left in FIFO?
bne.s @gotMsg ; ->if so, it's the message byte
cmp.b #kBusFreePhase, currentPhase(A5) ;
beq.s @scsiComplPhaseErr
@gotMsg
move.b rFIFO(A3), D2 ; read msg byte from FIFO
move.b D2, scsiSCSImessage(A0) ; and return message byte in PB also
move.b #1, HALactionPB.msgInLen(A4) ; say we returned 1 byte
RecCmd $12, 'A',$16
move.b #cMsgAccept, rCMD(a3) ; load msg accepted code which de-asserts *ACK
eieio
bsr Wt4SCSIInt ; Wait for intrp w/o timeout
@check4BusFree
cmp.b #kBusFreePhase, currentPhase(A5)
beq.s @disconnected ; if disconnected -> we're done
@badAcpt
bsr Ck4SCSIInt ; Check for intrp (bouncy REQ)
bne.s @check4BusFree ; got it -> go back to check for busfree
@scsiComplPhaseErr
move.w #SCResults.scsiSequenceFailed, D0 ; bad
@exitComplete
move.w D0, HALactionPB.result(A4) ; with whatever err
@disconnected ;
rts
NAME 'DoSCSIComplete'
;==========================================================================
;
; CyclePhase -- 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 Pseudo-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 Pseudo-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 ; (accessed thru jvCyclePhase)
@checkNextPhase ;
move.b currentPhase(A5), d0 ; get phase value
cmp.b #kDataInPhase, d0 ;
beq.s @dumpDataIn ;
cmp.b #kDataOutPhase, d0 ;
beq.s @shoveDataOut ;
cmp.b #kCommandPhase, d0 ;
beq.w @shoveCommand ;
cmp.b #kMessageOutPhase, d0 ;
beq.w @shoveMsgOut ;
cmp.b #kMessageInPhase, d0 ;
beq.w @bitbucketMsgIn ;
cmp.b #kStatusPhase, 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
NAME 'CyclePhaseTOP'
;
; Data Phases - note that we no longer support the (pseudo) DMA bitbucketing here because
; the buserr handler should completely clean itself up before exiting out of the data
; routine/call.
;
; Data_In ------
;
@dumpDataIn
bsr Xfer1Byte96 ; xfer 1 byte and wait for intrp w/o timeout
move.b rFIFO(A3), D0 ; just empty the FIFO
bra.s @checkNextPhase
;
; Data_Out ------
;
@shoveDataOut
; DebugStr 'Old API bitbucketing'
move.b #$EE, rFIFO(a3) ; load filler byte into FIFO
eieio
bsr Xfer1Byte96 ; xfer 1 byte and wait for intrp w/o timeout
bra.s @checkNextPhase
;
; Command ------
;
@shoveCommand
tst.b G_State96(A5) ; did we expect this?
beq.s @cmdNonDMA ; no - bra, do xfer using FIFO
tst.b HBAhasPseudoDMA(A5)
beq.s @ck4hasDMA
move.w #$EEEE, rDMA(a3) ; use pseudo DMA (since chip is waiting for it)
eieio
bra.s @sentCmd
@ck4hasDMA
tst.b HBAhasDMA(A5)
bne.s @hasDMA
IfDebugStr 'Bad hwDesc - no DMA or pDMA'
moveq #dsIOCoreErr, D0
_SysError
@hasDMA
move.w #$EEEE, ([logicalCopyBuffer,A5]) ; put last bytes into our DMA buffer
move.w #false, -(sp) ; false = out
move.l #2, -(sp) ; send 2 bytes
move.l physicalCopyBuffer(A5), -(sp) ; starting at this physical address
jsr ([jvStartDMA,A5])
lea 10(sp), sp
jsr ([jvWt4DMAComplete,A5])
@sentCmd
bsr.w Wt4SCSIInt
;
; We have to flush the FIFO because of a bug in the c96. See the DoCommand routine for
; further information
;
@flushAndExit
RecCmd $01, 'A',$17
move.b #cFlushFIFO, rCMD(A3) ; Flush FIFO - REMEMBER THE CD-ROM BUG!!!
eieio
clr.b G_State96(A5)
bra.w @checkNextPhase
@cmdNonDMA
move.b #$EE, rFIFO(A3) ; load filler byte into FIFO
move.b #$EE, rFIFO(A3) ; load filler byte into FIFO
move.b #$EE, rFIFO(A3) ; load filler byte into FIFO
move.b #$EE, rFIFO(A3) ; load filler byte into FIFO
eieio
bsr Xfer1Byte96 ; send cmd and wait for intrp w/o timeout
bra.s @flushAndExit
;
; Message_Out ------
;
@shoveMsgOut
tst.b G_State96(A5) ; are we in cSelW(O)Atn process?
bne.s @ck4hasDMA ; yes-> go to cmd phase routine
move.b #$08, rFIFO(A3) ; load filler byte into FIFO (NOP message)
eieio
@needXferCmd
bsr Xfer1Byte96 ; xfer 1 byte and wait for intrp w/o timeout
bra.w @checkNextPhase
;
; Message-In ------
;
@bitbucketMsgIn
bsr Xfer1Byte96 ; xfer 1 byte and wait for intrp w/o timeout
move.b rFIFO(A3), D0 ; just empty the FIFO
RecCmd $12, 'A',$18
move.b #cMsgAccept, rCMD(a3) ; load msg accepted code which de-asserts ACK
eieio
bsr Wt4SCSIInt ; Wait for intrp w/o timeout
bra.w @checkNextPhase
RTSNAME 'CyclePhaseBOTTOM'
;==========================================================================
;
; AutoMsgIn
;
; Get message in bytes. If a HAL-recognized message, do what we need to do then
; return to caller (HALaction). If not, put entire message into buffer - either
; 2 bytes if msg=$2x, or extended message if 1st msg=01 (2+length bytes), or 1
; byte.
;
; Note: This routine, not being a HALaction proper, is not allowed to return an
; error in HALaction.result!
;
AutoMsgIn
@0
RecCmd $10, 'A',$24
move.b #cIOXfer, rCMD(A3)
eieio
bsr Wt4SCSIInt
bne UnexpectedDisc ; bus free? -> exit
moveq.l #0, D0
move.b rFIFO(A3), D0 ; retrieve first message from FIFO
IF RECORD_ON THEN
pea 'AMsg'
move.l D0, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
;
; Check for a one byte message that we recognize.
;
@ck4SaveDP
cmp.b #kSaveDataPointerMsg, D0
bne.s @ck4RestoreDP
RecCmd $12, 'A',$28
move.b #cMsgAccept, rCMD(A3) ; de-assert ACK
eieio
jsrv jvSaveDataPointer, A1 ;
bra.s @wt4acceptComp
@ck4RestoreDP
cmp.b #kRestorePointersMsg, D0
bne.s @ck4ExtendedMsg
RecCmd $12, 'A',$2c
move.b #cMsgAccept, rCMD(A3) ; de-assert ACK
eieio
jsrv jvRestorePointers, A1 ;
@wt4acceptComp
bsr Wt4SCSIInt
cmp.b #kMessageInPhase, currentPhase(A5) ; still in msg phase?
beq.w @0 ; yes-> go back and get next msg
bra @outOfPhase ; no: return to SIM w/new phase
;
; Check for extended message
;
@ck4ExtendedMsg
lea HALactionPB.msg(A4), A0
move.b D0, (A0)+ ; put the message in bfr
move.b #1, HALactionPB.msgInLen(A4) ;
cmp.b #kExtendedMsg, D0 ; extended msg?
bne @ck2byteMsg ; no->check 4 2-byte message
;
; Extended Msg: Accept 1st message, get 2nd message byte (length) then, for each
; byte in length, accept previous byte then get the next. This leaves ACK for
; last byte.
;
@get2ndMsg
bsr DoAcceptMsg
cmp.b #kMessageInPhase, currentPhase(A5)
bne @outOfPhase
RecCmd $10, 'A',$30
move.b #cIOXfer, rCMD(A3)
eieio
bsr Wt4SCSIInt
bne UnexpectedDisc ; bus free? -> exit
moveq.l #0, D0
move.b rFIFO(A3), D0 ; retrieve 2nd message from FIFO
move.b D0, (A0)+
bne.s @lpEnd ; non-zero-> byte is # of bytes left
move.w #$100, D0 ; zero-> 256 bytes left
bra.s @lpEnd ; loop: ack prev byte, get next
@lpTop
bsr DoAcceptMsg ; drop ACK, where does phase go?
cmp.b #kMessageInPhase, currentPhase(A5) ; still messageIn?
bne.s @outOfPhase ; no->out of here
RecCmd $10, 'A',$38
move.b #cIOXfer, rCMD(A3) ; get the byte (assert ACK)
eieio
bsr Wt4SCSIInt
bne UnexpectedDisc ; bus free? -> exit
move.b rFIFO(A3), (A0)+ ; retrieve next message from FIFO
addq.b #1, HALactionPB.msgInLen(A4) ;
@lpEnd
dbra D0, @lpTop
IF RECORD_ON THEN
pea 'XMsg'
move.l HALactionPB.msg(A4), -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
@inPhase
move.b #kMessageInPhaseNACK, currentPhase(A5)
@outOfPhase
rts
;
; Check for a 2-byte message - this includes all messages of the form $2x. We don't
; interpret any 2-byte messages in the HAL so just get them and return.
;
@ck2byteMsg
and.b #$F0, D0
cmp.b #$20, D0 ; msg = $2x?
bne.s @inPhase ; no-> we're done
;
; If 2-byte msg, accept 1st byte then get second byte and return to caller
;
bsr.s DoAcceptMsg
cmp.b #kMessageInPhase, currentPhase(A5)
bne.s @outOfPhase
RecCmd $10, 'A',$40
move.b #cIOXfer, rCMD(A3)
eieio
bsr Wt4SCSIInt
bne UnexpectedDisc ; bus free? -> exit
moveq.l #0, D0
move.b rFIFO(A3), (A0)+ ; retrieve next message from FIFO
move.b #2, HALactionPB.msgInLen(A4) ; inc count
bra.s @inPhase
RTSNAME 'AutoMsgIn'
;==========================================================================
;
; AcceptMsg - accept a message
;
DoAcceptMsg
RecCmd $12, 'A',$44
move.b #cMsgAccept, rCMD(A3) ; de-assert ACK
eieio
bsr Wt4SCSIInt
rts ; don't touch result
NAME 'DoAcceptMsg'
;==========================================================================
;
; DoMsgOut - Send a message byte to the target
;
; Send the HALactionPB.msgLen message bytes in HALactionPB.msg[]. Don't change
; result (noErr) if all bytes sent, else, return err and indicate how many bytes
; WEREN'T sent in HALactionPB.msgOutLen. We will only be called if we are IN msg
; out phase already.
;
DoMsgOut
lea HALactionPB.msg(A4), A1 ; where the message is
tst.b G_State96(A5) ; Is this part of an old API Select w/ATN?
bne.s @oldAPI ; yes->
;
; If we didn't send a SelWAtn, then we need to stuff the FIFO full of the message bytes
; that we need to send then issue a xferInfo command which will drop ATN during the
; last byte. Hole: what about more than 16 message out bytes? HA!
;
@needXfer
moveq.l #0, D0
move.b HALactionPB.msgOutLen(A4), D0
bne.s @loopBtm
bra.s @goodExit
@loopTop
move.b (A1)+, rFIFO(A3) ; move msg byte into FIFO
@loopBtm
dbra D0, @loopTop ;
eieio
; now we sent all of the message bytes
RecCmd $10, 'A',$48
move.b #cIOXfer, rCMD(A3) ; load IO transfer cmd & begin xfers
eieio
bsr.w Wt4SCSIInt ; Wait for intrp w/o timeout
moveq.l #mFIFOCount, D0
and.b int_rFIFOflags(A5), D0 ; how many bytes left?
bne.s @phaseChange
@goodExit
rts
;
; If we sent a SelWAtn, we only need to stick the message byte (only 1) into the FIFO.
; The c96 and the target continue from there.
;
@oldAPI
move.b #NeedCmdSent, G_State96(A5) ; we will expect to see command phz
move.b #kCommandPhase, currentPhase(A5) ; pretend like we're there already
move.b (A1), rFIFO(A3) ; xfer msg byte
eieio
bra.s @goodExit ; don't wait for int - CDB needed first
@phaseChange
sub.b D0, HALactionPB.msgOutLen(A4) ; calc how many bytes were xferred
move.w #HALresult.kHALpartialMsgOut, HALactionPB.result(A4)
rts
NAME 'DoMsgOut'
;==========================================================================
;
; SetParity - Set the parity bit in the c96 configuration register2
; so that parity errors will be reported. Note that we
; turn this off at each disconnect to prevent problems on
; reconnects from devices that don't support parity.
;
;
SetParity
IF PARITY_ENABLED THEN
move.l HALactionPB.ioPtr(A4), A0 ; ptr to SCSI_IO pb
move.w SCSI_IO.scsiIOFlags(A0), D0 ; Get the flags field
and.w #scsiNoParityCheck,D0 ; Are we doing parity?
bne.s @noParity ; nope-> don't send an identify message
or.b #mCF1_EnableParity,rCF1(a3) ; set the parity bit
@noParity
ENDIF
rts
NAME 'SetParity'
;################################################################################
;********** Non-HALActions *********
;################################################################################
;==========================================================================
;
; HALSyncConfig - Configure registers for Synchronous Data Transfer
; 4 8 12
; void HALSyncConfig( offset, periodFactor, HALc96Globals * HALg );
;
HALSyncConfig
move.l A3, -(sp)
move.l A5, -(sp)
move.l 20(sp), A5 ; get HALg
move.l baseRegAddr(A5), A3 ; load A3 with base addr of 53c96
IF RECORD_ON THEN
pea 'SCfg'
move.w 22(sp), -(sp)
move.w 22(sp), -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
move.l 16(sp), D0 ; get periodFactor
move.b (periodTable, D0.w), D1
bmi.s @illegalValue
and.b #$1f, D1
move.b D1, rSyncPeriod(A3)
cmp.b #50, D0 ; are we in Fast range?
bcc.s @notFast
or.b #mCF3_FastSCSI, rCF3(A3) ; set fast bit
bra.s @1
@notFast
and.b #~mCF3_FastSCSI, rCF3(A3) ; clr fast bit
@1
move.l 12(sp), D1 ; get offset
move.b D1, rSyncOffset(A3)
@illegalValue
move.l (sp)+, A5
move.l (sp)+, A3
rts
NAME 'HALSyncConfig'
;……………………………………………………………………………………………………………………………………………………………………………………………………
; set period 25
; loop
; if {period}<100
; echo -n "@0{period} "
; else
; echo -n "@{period} "
; end
; echo -n "dc.b "
; evaluate -h {period}*1000 div 625 div 10
; evaluate period+=1
; break if {period}==256
; end
;
;……………………………………………………………………………………………………………………………………………………………………………………………………
periodTable
@0 dc.b $80, $80, $80, $80, $80, $80, $80, $80
@8 dc.b $80, $80, $80, $80, $80, $80, $80, $80
@16 dc.b $80, $80, $80, $80, $80, $80, $80, $80
@24 dc.b $80
@025 dc.b $04
@026 dc.b $04
@027 dc.b $04
@028 dc.b $04
@029 dc.b $04
@030 dc.b $04
@031 dc.b $04
@032 dc.b $05
@033 dc.b $05
@034 dc.b $05
@035 dc.b $05
@036 dc.b $05
@037 dc.b $05
@038 dc.b $06
@039 dc.b $06
@040 dc.b $06
@041 dc.b $06
@042 dc.b $06
@043 dc.b $06
@044 dc.b $07
@045 dc.b $07
@046 dc.b $07 ; -
@047 dc.b $07 ; -
@048 dc.b $07 ; -
@049 dc.b $07 ; Fast SCSI bit set
@050 dc.b $08 ; Fast SCSI bit clr
@051 dc.b $08 ; -
@052 dc.b $08 ; -
@053 dc.b $08 ; -
@054 dc.b $08
@055 dc.b $08
@056 dc.b $08
@057 dc.b $09
@058 dc.b $09
@059 dc.b $09
@060 dc.b $09
@061 dc.b $09
@062 dc.b $09
@063 dc.b $0a
@064 dc.b $0a
@065 dc.b $0a
@066 dc.b $0a
@067 dc.b $0a
@068 dc.b $0a
@069 dc.b $0b
@070 dc.b $0b
@071 dc.b $0b
@072 dc.b $0b
@073 dc.b $0b
@074 dc.b $0b
@075 dc.b $0c
@076 dc.b $0c
@077 dc.b $0c
@078 dc.b $0c
@079 dc.b $0c
@080 dc.b $0c
@081 dc.b $0c
@082 dc.b $0d
@083 dc.b $0d
@084 dc.b $0d
@085 dc.b $0d
@086 dc.b $0d
@087 dc.b $0d
@088 dc.b $0e
@089 dc.b $0e
@090 dc.b $0e
@091 dc.b $0e
@092 dc.b $0e
@093 dc.b $0e
@094 dc.b $0f
@095 dc.b $0f
@096 dc.b $0f
@097 dc.b $0f
@098 dc.b $0f
@099 dc.b $0f
@100 dc.b $10
@101 dc.b $10
@102 dc.b $10
@103 dc.b $10
@104 dc.b $10
@105 dc.b $10
@106 dc.b $10
@107 dc.b $11
@108 dc.b $11
@109 dc.b $11
@110 dc.b $11
@111 dc.b $11
@112 dc.b $11
@113 dc.b $12
@114 dc.b $12
@115 dc.b $12
@116 dc.b $12
@117 dc.b $12
@118 dc.b $12
@119 dc.b $13
@120 dc.b $13
@121 dc.b $13
@122 dc.b $13
@123 dc.b $13
@124 dc.b $13
@125 dc.b $14
@126 dc.b $14
@127 dc.b $14
@128 dc.b $14
@129 dc.b $14
@130 dc.b $14
@131 dc.b $14
@132 dc.b $15
@133 dc.b $15
@134 dc.b $15
@135 dc.b $15
@136 dc.b $15
@137 dc.b $15
@138 dc.b $16
@139 dc.b $16
@140 dc.b $16
@141 dc.b $16
@142 dc.b $16
@143 dc.b $16
@144 dc.b $17
@145 dc.b $17
@146 dc.b $17
@147 dc.b $17
@148 dc.b $17
@149 dc.b $17
@150 dc.b $18
@151 dc.b $18
@152 dc.b $18
@153 dc.b $18
@154 dc.b $18
@155 dc.b $18
@156 dc.b $18
@157 dc.b $19
@158 dc.b $19
@159 dc.b $19
@160 dc.b $19
@161 dc.b $19
@162 dc.b $19
@163 dc.b $1a
@164 dc.b $1a
@165 dc.b $1a
@166 dc.b $1a
@167 dc.b $1a
@168 dc.b $1a
@169 dc.b $1b
@170 dc.b $1b
@171 dc.b $1b
@172 dc.b $1b
@173 dc.b $1b
@174 dc.b $1b
@175 dc.b $1c
@176 dc.b $1c
@177 dc.b $1c
@178 dc.b $1c
@179 dc.b $1c
@180 dc.b $1c
@181 dc.b $1c
@182 dc.b $1d
@183 dc.b $1d
@184 dc.b $1d
@185 dc.b $1d
@186 dc.b $1d
@187 dc.b $1d
@188 dc.b $1e
@189 dc.b $1e
@190 dc.b $1e
@191 dc.b $1e
@192 dc.b $1e
@193 dc.b $1e
@194 dc.b $1f
@195 dc.b $1f
@196 dc.b $1f
@197 dc.b $1f
@198 dc.b $1f
@199 dc.b $1f
@200 dc.b $00
@201 dc.b $00
@202 dc.b $00
@203 dc.b $00
@204 dc.b $00
@205 dc.b $00
@206 dc.b $00
@207 dc.b $01
@208 dc.b $01
@209 dc.b $01
@210 dc.b $01
@211 dc.b $01
@212 dc.b $01
@213 dc.b $02
@214 dc.b $02
@215 dc.b $02
@216 dc.b $02
@217 dc.b $02
@218 dc.b $02
@219 dc.b $03
@220 dc.b $03
@221 dc.b $03
@222 dc.b $03
@223 dc.b $03
@224 dc.b $03
@225 dc.b $84
@226 dc.b $84
@227 dc.b $84
@228 dc.b $84
@229 dc.b $84
@230 dc.b $84
@231 dc.b $84
@232 dc.b $85
@233 dc.b $85
@234 dc.b $85
@235 dc.b $85
@236 dc.b $85
@237 dc.b $85
@238 dc.b $86
@239 dc.b $86
@240 dc.b $86
@241 dc.b $86
@242 dc.b $86
@243 dc.b $86
@244 dc.b $87
@245 dc.b $87
@246 dc.b $87
@247 dc.b $87
@248 dc.b $87
@249 dc.b $87
@250 dc.b $88
@251 dc.b $88
@252 dc.b $88
@253 dc.b $88
@254 dc.b $88
@255 dc.b $88
;==========================================================================
;
; HALResetBus - Reset the scsi bus
;
; void HALResetBus( HALc96Globals * HALg );
;
HALResetBus
move.l A3, -(sp)
move.l A5, -(sp)
move.l 12(sp), A5 ; get HALg
move.l baseRegAddr(A5), A3 ; load A3 with base addr of 53c96
; move.w sr, -(sp) ; Block interrupts
; or.w #$0700, sr
IF RECORD_ON THEN
pea 'RstB'
move.l A1, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
jsrv jvResetBus, A1
; move.w (sp)+, sr ; restore interrupt level
move.l (sp)+, A5
move.l (sp)+, A3
rts
NAME 'HALResetBus'
;……………………………………………………………………………………………………………………………………………………………………………………………………
;
; DoReset - Reset the scsi bus
;
DoReset
; move.b #initCF1+mResetIntrpDisable, rCF1(A3) ; load init config value which affects:
; busID, SCSI reset reporting & parity checking
eieio
RecCmd $03, 'A',$4c
move.b #cResetSCSIBus, rCMD(A3) ; load reset scsi bus cmd - no int generated
; except that ResetO goes to ResetI which
; DOES generate an interrupt
eieio
;
; Just for the fun of it, we're going to wait 128mS, then reset that CF1 register
; then wait another 128mS and see if we got an interrupt - Just for the heck of it.
;
moveq.l #0, D0 ; clear upper word
move.w TimeDBRA, D0 ; get # of DBRAs per mS
lsl.l #7, D0 ; multiply by 128
move.l D0, D1 ; ...a 128mS wait
swap D1
@1 dbra D0, @1 ; D0 low word of counter
dbra D1, @1 ; D1 high word
; move.b #initCF1, rCF1(A3) ; reload init config value
eieio
moveq.l #0, D0 ; clear upper word
move.w TimeDBRA, D0 ; get # of DBRAs per mS
lsl.l #7, D0 ; multiply by 128
move.l D0, D1 ; ...a 128mS wait
swap D1
@2 dbra D0, @2 ; D0 low word of counter
dbra D1, @2 ; D1 high word
bsr Ck4SCSIInt ; did we get an interrupt?
; Did we? Who cares? I don't.
RecCmd $01, 'A',$50
move.b #cFlushFIFO, rCMD(a3) ; reset doesn't flush the @#$%^&! fifo!
eieio
move.b #kBusFreePhase, currentPhase(A5) ; in Bus Free Phase now
rts
NAME 'DoReset'
;==========================================================================
;
; HALAssertATN - Assert the ATN signal on the scsi bus <SM4> pdw
; 4
; void HALAssertATN( HALc96Globals * HALg );
;
HALAssertATN
move.l A3, -(sp)
move.l A5, -(sp)
move.l 12(sp), A5 ; get HALg
move.l baseRegAddr(A5), A3 ; load A3 with base addr of 53c96
move.l jvAssertATN(A5), A1
IF RECORD_ON THEN
pea 'AAtn'
move.l A1, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
jsr (A1)
move.l (sp)+, A5
move.l (sp)+, A3
rts
NAME 'HALAssertATN'
;……………………………………………………………………………………………………………………………………………………………………………………………………
;
DoAssertATN
RecCmd $1a, 'A',$54
move.b #cSetAtn, rCMD(A3)
eieio
rts
NAME 'DoAssertATN'
;==========================================================================
;
; HALTeardownIO -
; 8 4
; void HALTeardownIO( SCSI_IO * ioPtr, HALc96Globals * HALg );
;
HALTeardownIO
move.l 8(sp), A0 ; get HALg
move.l jvTeardownIO(A0), A0
IF RECORD_ON THEN
pea 'tdIO'
move.l A0, -(sp)
bsr RecordEvent
addq.l #8, sp
ENDIF
jmp (A0) ; calling through to a C routine so
; we leave parms as is on the stack
RTSNAME 'HALAssertATN'
;……………………………………………………………………………………………………………………………………………………………………………………………………
;
SetupIONoDMA
TeardownIONoDMA
rts
NAME 'Set/TearIONoDMA'
;################################################################################
;********** Utilities *********
;################################################################################
;==========================================================================
;
MoveSmallBlock
; D0 = number of bytes
; A1 = source
; A2 = dest
move.l @table(D0.w*4), D0
jmp @table(D0.w)
@table
dc.l @0-@table
dc.l @1-@table
dc.l @2-@table
dc.l @3-@table
dc.l @4-@table
dc.l @5-@table
dc.l @6-@table
dc.l @7-@table
dc.l @8-@table
dc.l @9-@table
dc.l @10-@table
dc.l @11-@table
dc.l @12-@table
dc.l @13-@table
dc.l @14-@table
dc.l @15-@table
dc.l @16-@table
@13
move.l (A1)+, (A2)+
@9
move.l (A1)+, (A2)+
@5
move.l (A1)+, (A2)+
@1
move.b (A1)+, (A2)+
@0
rts
@14
move.l (A1)+, (A2)+
@10
move.l (A1)+, (A2)+
@6
move.l (A1)+, (A2)+
@2
move.w (A1)+, (A2)+
rts
@15
move.l (A1)+, (A2)+
@11
move.l (A1)+, (A2)+
@7
move.l (A1)+, (A2)+
@3
move.w (A1)+, (A2)+
move.b (A1)+, (A2)+
rts
@16
move.l (A1)+, (A2)+
@12
move.l (A1)+, (A2)+
@8
move.l (A1)+, (A2)+
@4
move.l (A1)+, (A2)+
rts
NAME 'MoveSmallBlock'
ENDWITH
ENDPROC
END