;ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ ; ; 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): ; ; 11/22/93 pdw Rolling in from . ; 11/8/93 pdw Added some support for unexpected disconnect. Fixed a bug in ; the handling of the selected-as-target Curio bug. ; 11/5/93 pdw Series of attempts and re-attempts to fix various VM/FileShare ; problems. ; 10/28/93 pdw Trivial stuff. ; 11/16/93 SAM Include HardwarePrivateEqu.a ; 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. ; 10/29/93 pdw Fixing build - RecordCmd is being expanded in the ROM but not in ; the Init in SOME places. ; 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. ; 10/14/93 pdw roll-in. ; 10/12/93 pdw Fixed error reported on initiate w/too few message out bytes. ; 10/12/93 pdw Added support for Synchronous data transfers, rewrote State ; Machine, message handling etc. ; 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. ; 9/26/93 pdw Changes to G_State usage from bit flags to enumeration and other ; stuff. ; 9/12/93 pdw Comment changes. Changed post-ResetBus delay to 250mS instead ; of 500mS. ; 9/9/93 pdw Lots of little changes. Name changes, temporary cache_bug ; stuff. ; 8/13/93 pdw A lot of eieios, RecordRCMDs, reworked PutXferPhase/Disconnect ; stuff, rewrote SCSIComplete. ; 7/19/93 pdw Fixed build. ; 7/19/93 pdw Added an ENDIF to fix that build warning. ; 7/17/93 pdw Lots of little things. ; 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. ; 5/25/93 DCB Rollin from Ludwig. (The next item below) ; 5/21/93 PW Hopefully adding ability to handle being selected while we are ; trying to select. ; 5/5/93 PW Converted names to meanies-friendly names. Updated with latest ; from Ludwig stuff. ; 4/30/93 DCB Make DoHalInfo a separate function so it can be stuffed into a ; vector. ; 4/14/93 DCB Added SetParity HALAction but left it disabled for now. ; 3/26/93 PW Removed useless RejectMsg stuff. ; 3/29/93 PW Removed rCF3 manipulations for PDM. Now I just set it up once in ; HWInit for threshold 8 or not. ; 3/21/93 PW Removing useless RejectMsg stuff. ; 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. ; 2/17/93 PW Removed DoBitBucket and put it in HALc96Data.a instead. ; 3/20/93 PW Removed some bogus PDM stuff that causes problems on non-PDMs. ; 3/20/93 PW Removed DoBitBucket and put it in HALc96Data.a instead. ; 2/3/93 PW Removed initCF1 munging before and after DoReset to fix reset ; blowing up bug. ; 1/31/93 PW Update from the latest of Ludwig. Also changes required for PDM ; (will update Ludwig with these as needed myself). ; 1/29/93 PW Passing HALg into SetupIOPB function. ; 1/27/93 PW Playing around with some interrupt stuff. Changed HALaction ; events to include SR (for int level). ; 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. ; 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). ; 12/18/92 PW Really fix the hanging in vSyncWait after SCSICmd bug by ; clearing the G_State96 bits after Ck4SCSIInt sees the interrupt. ; 12/15/92 DCB Fixed SCSICmd bug with DSP running or with caches disabled by ; not calling Wt4S if ck4int reveals an interrupt. ; 12/9/92 PW Changed SCStats record name to SCResults. Rearranged DoCommand ; routine to fix some MORE bugs handling SCSISelAtn/SCSIMsgOut. ; 12/9/92 PW Fixed SCSIMsgOut bug by changing DMA xfer count from 3 bytes to ; 2. ; 12/5/92 PW Changed some names and fixed the DoReset routine so that it ; works when Reset interrupt reporting is on. ; 11/12/92 PW Changed beq.s and bra.s to beq.w and bra.w to work when ; RECORD_rCMD is turned on. ; 10/30/92 DCB Added Setup and Teardown routines to support Direct DMA into a ; user buffer ; 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. ; 9/11/92 DCB Rolled in Paul's fix for message out during initiate ; 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. ; 8/30/92 PW Added DoAssertATN and fixed SendMsg bugs (it couldn't handle ; multiple-byte msg non-SelWAtn case). ; 8/20/92 DCB Added Select w/o Atn and fixed SCSI Reset ; 7/28/92 PW Resolved differences in sources. ; 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. ; 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 ; 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 ; 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 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