; Copyright (c) 1997-1999 Apple Computer, Inc. All rights reserved.
;
; @APPLE_LICENSE_HEADER_START@
;
; The contents of this file constitute Original Code as defined in and
; are subject to the Apple Public Source License Version 1.1 (the
; "License"). You may not use this file except in compliance with the
; License. Please obtain a copy of the License at
; http://www.apple.com/publicsource and read it before using this file.
;
; This Original Code and all software distributed under the License are
; distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
; License for the specific language governing rights and limitations
; under the License.
;
; @APPLE_LICENSE_HEADER_END@
;
; File Ownership:
;
; DRI: Mike Johnson
;
; Other Contact: Russ Berkoff
;
; Technology: SCSI
;
; Writers:
;
; (MLJ) Mike Johnson
; (RRA) Rick Auricchio
; NCR Errata Listing 125 Item 1 : Clear the SCNTL0 start bit
; when jump to reselect during select (try_reselect)
;
; NCR Errata Listing 117 Item 4 : Bad parity if odd bytes during
; wide transfer. Only for DATA OUT in Initiator mode.
; (Confirm by Manfred Eierle 3rd June 93 not during DATA IN)
ARCH 825A ;specifically for 825a and 875 (new instructions)
;*****************************************************************
;
; Phase codes - These values represent which action is being handled
;
;*****************************************************************
ABSOLUTE kphase_DATA_OUT = 0x00
ABSOLUTE kphase_DATA_IN = 0x01
ABSOLUTE kphase_COMMAND = 0x02
ABSOLUTE kphase_STATUS = 0x03
ABSOLUTE kphase_MSG_OUT = 0x06
ABSOLUTE kphase_MSG_IN = 0x07
ABSOLUTE kphase_SELECT = 0x08
ABSOLUTE kphase_RESELECT = 0x09
ABSOLUTE kphase_ABORT_CURRENT = 0x0A
ABSOLUTE kphase_ABORT_MAILBOX = 0x0B
ABSOLUTE kphase_CMD_COMPLETE = 0x0C
ABSOLUTE kphase_DISCONNECT = 0x0D
ABSOLUTE kphase_saveDataPointer = 0x0E ; ??? driver work to be done
ABSOLUTE kphase_restoreDataPointer = 0x0F ; ??? driver work to be done
;*****************************************************************
; interrupt codes
;*****************************************************************
ABSOLUTE unknown_phase = 0x00 ; A spurious phase on SCSI Bus
ABSOLUTE status_error = 0x01 ; IO completes, but with status error
ABSOLUTE unexpected_msg = 0x02 ; An 'unknown' message is in ld_message var
ABSOLUTE unexpected_ext_msg = 0x03 ; An 'unknown' extended message in ld_message
ABSOLUTE wide_32_not_supported = 0x04 ; The device wants 32 bits data phase
ABSOLUTE no_msgin_after_reselect = 0x05 ; No message-in after reselection
ABSOLUTE reqack_too_large = 0x06 ; The device answer ReqAck offset is greater than 8
ABSOLUTE unknown_reselect = 0x07 ; The valid bit in SFBR reg not set
ABSOLUTE unallocated_nexus = 0x08 ; nexus index -> 0xFFFFFFFF
ABSOLUTE abort_mailbox = 0x09 ; Abort/BDR mailbox completed
ABSOLUTE abort_current = 0x0A ; Abort/BDR current op completed
ABSOLUTE unknown_message_out = 0x0B ; Unknown phase before message out
ABSOLUTE unknown_msg_reject = 0x0C ; Unknown message reject
ABSOLUTE negotiateSDTR = 0x0D ; Sync negotiation rx'd
ABSOLUTE negotiateWDTR = 0x0E ; Wide negotiation rx'd
ABSOLUTE sglist_complete = 0x0F ; SGList complete
;*****************************************************************
;
; Data structure for T/L/Q Nexus:
;
;*****************************************************************
ABSOLUTE TLQ_SCSI_ID = 0 ; 4 SCSI ID et al for SELECT instruction
ABSOLUTE TLQ_xferAdr = 4 ; 4 Physical address of CHMOV instructions
ABSOLUTE TLQ_MSGOp = 8 ; 8 Byte count, data adr -> TLQ_MSGO
ABSOLUTE TLQ_CDBp = 16 ; 8 Byte count, data adr -> TLQ_CDB
ABSOLUTE TLQ_CDP = 24 ; 4 Current Data Pointer
ABSOLUTE TLQ_SDP = 28 ; 4 Saved Data Pointer
ABSOLUTE TLQ_index = 32 ; 1 index into nexus array
ABSOLUTE TLQ_xferStarted= 33 ; 1 transfer started flag
ABSOLUTE TLQ_IWR = 34 ; 1 flag to Ignore Wide Residue
ABSOLUTE TLQ_pad = 35 ; 1 pad byte
;*****************************************************************
;
; ENTRY declarations - Declare entry points for driver
;
;*****************************************************************
ENTRY select_phase
ENTRY phase_handler
ENTRY issueMessageOut ; for negotiation and Reject messages
ENTRY issueAbort_BDR ; to immediately Abort or Bus-Device-Reset
ENTRY clearACK ; MsgIn done - clr ACK, jump to phase handler
;*****************************************************************
;
; Define local data structure at start of SCRIPTS.
; This structure is allocated by the following nops.
;
;*****************************************************************
;
RELATIVE local_data \
ld_AbortCode = 4{??}\ ; 1 byte code to Abort or BDR
ld_zeroes = 4{??}\ ; 4 bytes of 0 to clear registers
ld_status = 4{??}\ ; Status byte from target
ld_counter = 4{??}\ ; index into mailbox array
ld_AbortBdr_mailbox = 4{??}\ ; Abort/BusDeviceReset mailbox
ld_IOdone_mailbox = 4{??}\ ; [ nexus 0 0 semaphore ]
ld_sched_mlbx_base_adr = 4{??}\ ; base addr of mailbox array
ld_mailboxp = 4{??}\ ; address of current mailbox
ld_scsi_id = 4{??}\ ; ptr to current mailbox
ld_nexus_array_base = 4{??}\ ; base address of Nexus pointers
ld_nexus_index = 4{??}\ ; index to Nexus pointer
ld_nexus = 4{??}\ ; address of Nexus
ld_phase_flag = 4{??}\ ; for debugging
ld_device_table_base_adr = 4{??}\ ; device configuration table
ld_scratch = 4{??}\ ; scratch memory
ld_unused = 4{??}\ ; unused
ld_message = 4{??}\ ; buffer for MsgIn bytes
ld_message4 = 4{??}\ ; buffer continuation
ld_pad = 4{??}\ ; padding
ld_size = 4{??} ; size of this structure
PROC BSC_SCRIPT:
; *** These NOPs must be at address 0. ***
; *** This is reserved space for the structure "local_data". ***
; *** The driver inits this area to zero. ***
nop 0 ; ld_AbortCode, ld_zeroes
nop 0 ; ld_status, ld_counter
nop 0 ; ld_AbortBdr_mailbox, ld_IOdone_mailbox
nop 0 ; ld_sched_mlbx_base_adr, ld_mailboxp
nop 0 ; ld_scsi_id, ld_nexus_array_base
nop 0 ; ld_nexus_index, ld_nexus
nop 0 ; ld_phase_flag, ld_device_table_base_adr
nop 0 ; ld_scratch, ld_unused
nop 0 ; ld_message, ld_message4
nop ld_size ; ld_pad, ld_size (Use ld_size or lose it)
nop sglist_complete ; use sglist_complete or lose it from gen'd output file
;****************************************************************************
;
; findNexusFromIndex - load DSA with pointer to Nexus given a Nexus index:
;
;****************************************************************************
findNexusFromIndex:
load SCRATCHA0, 4, ld_nexus_index ; load index and leading zeroes
clear CARRY
move SCRATCHA0 SHL 0 to SCRATCHA0 ; double the index
move SCRATCHA1 SHL 0 to SCRATCHA1
move SCRATCHA0 SHL 0 to SCRATCHA0 ; double again
move SCRATCHA1 SHL 0 to SCRATCHA1 ; A0 now has index to 4-byte address
store SCRATCHA0, 4, patchArrayOffset+4 ; *** patch the code
load DSA0, 4, ld_nexus_array_base ; load base address of array of Nexus pointers
patchArrayOffset:
load DSA0, 4, DSAREL( 0 ) ; *** patched offset. Load pointer.
move DSA0 to SFBR ; Ensure pointer is not 0xFFFFFFFF
int unallocated_nexus, if 0xFF ; Interrupt if NFG
store DSA0, 4, ld_nexus ; Store the Nexus pointer
return ; end findNexusFromIndex
;****************************************************************************
;
; initContext - Initialize the registers for Sync and Wide using
; values stored in the device configuration table.
; Return with values in SCRATCHB for Select code.
;
;****************************************************************************
initContext:
load SCRATCHB0, 4, ld_scsi_id ; load 4-bit SCSI ID and zeroes
clear CARRY
move SCRATCHB0 SHL SCRATCHB0 ; * 2
move SCRATCHB0 SHL SCRATCHB0 ; * 2 -> UInt32 index
store SCRATCHB0, 4, patchGetDevConfigOffset+4 ; *** Patch load code
load DSA0, 4, ld_device_table_base_adr ; load base physical addr of tables
patchGetDevConfigOffset:
load SCRATCHB0, 4, DSAREL( 0 ) ; *** Patched table offset ***
; SCRATCHB0 = 0
; SCRATCHB1 = TP,MO (SXFER bits7-5 bits3-0)
; SCRATCHB2 = 0 (position for SCSI ID)
; SCRATCHB3 = SCCF,EWS (SCNTL3 bits6-4 bit 3)
move SCRATCHB1 to SFBR ; init SXFER from B1
move SFBR to SXFER
; Init SCNTL3 from B3
move SCRATCHB3 to SFBR
move SFBR to SCNTL3
return ; return with SCRATCHB intact.
;*****************************************************************
;
; Select_phase:
; Clear the SIGP bit.
; Check if any Abort/BusDeviceReset request waiting.
; Nexus is found in the list of 256 mailboxes.
; If current mailbox is empty, jump to reselect_phase.
; SCRIPTS tries to select device.
; If select fails due to reselect, jump to reselect_phase
; Select Timeout handled by driver.
; If select succeeds, clear the mailbox entry
; and increment the mailbox counter.
; Jump to the phase_handler (hopefully for MSG_OUT)
;
;*****************************************************************
select_phase:
move CTEST2 | 0x00 to CTEST2 ; Clear SIGP bit from ISTAT reg
; Check abort mailbox:
load SCRATCHA0, 4, ld_AbortBdr_mailbox ; Get AbortBdr mailbox
; The Identify byte in byte 0 is also the semaphore
; A0 = Identify byte (0xC0 + LUN N.B. Disconnect allowed)
; A1 = Tag, if any
; A2 = SCSI ID
; A3 = Abort code Abort=0x06; Abort Tag=0D; Bus Device Reset=0x0C
move SCRATCHA0 to SFBR ; test the semaphore/Identify
jump rel( AbortMailbox ), if not 0 ; jump if aborting
; Get the next IO nexus in the mailboxes circular list.
; Calculate current mailbox address as so:
; counter byte index * 4 to get mailbox index
; add base physical address of mailboxes giving current mailbox address
load SCRATCHA0, 4, ld_counter ; get 1-byte mailbox counter & 0s
clear CARRY
move SCRATCHA0 SHL 0 to SCRATCHA0 ; double it
move SCRATCHA1 SHL 0 to SCRATCHA1
move SCRATCHA0 SHL 0 to SCRATCHA0 ; double it again
move SCRATCHA1 SHL 0 to SCRATCHA1 ; now have a UInt32 index
store SCRATCHA0, 4, fetchMailbox+4 ; *** patch the load DSA instruction
store SCRATCHA0, 4, clear_mailbox+4 ; *** patch the store DSA instruction
load DSA0, 4, ld_sched_mlbx_base_adr ; load base physical address of mailboxes
fetchMailbox:
load DSA0, 4, DSAREL( 0 ) ; *** Patched offset. Load Nexus address
store DSA0, 4, ld_nexus ; save pointer to current Nexus
load SCRATCHA0, 4, ld_nexus ; copy to A0
move SCRATCHA0 to SFBR ;
jump rel( next_mailbox ), if 1 ; if low-byte == 0x01 then cancelled mailbox
move SCRATCHA1 | SFBR to SFBR ; if non-zero, have implicit semaphore
move SCRATCHA2 | SFBR to SFBR
move SCRATCHA3 | SFBR to SFBR
jump rel( reselect_phase ), if 0 ; go to reselect_phase if empty
;*****************************************************************
;
; Something in mailbox: we have work to do
;
;*****************************************************************
move kphase_SELECT to SCRATCHB0 ; set phase indicator
store SCRATCHB0, 1, ld_phase_flag
load SCRATCHB0, 4, ld_zeroes ; clr the invalid-nexus-index flag
load SCRATCHB0, 1, DSAREL( TLQ_index ) ; get index byte from nexus
store SCRATCHB0, 4, ld_nexus_index ; save it in local data
load DSA0, 4, ld_nexus ; restore DSA register
load SCRATCHB2, 1, DSAREL( TLQ_SCSI_ID+2 ) ; get Target's SCSI ID
move SCRATCHB2 to SFBR
move SFBR to SCRATCHB0 ; position it
store SCRATCHB0, 1, ld_scsi_id ; save it
call rel( initContext ) ; setup Sync/Wide regs in SCRATCHB
load DSA0, 4, ld_nexus ; restore DSA register
store SCRATCHB1, 1, DSAREL( TLQ_SCSI_ID+1 ) ; SXFER
store SCRATCHB3, 1, DSAREL( TLQ_SCSI_ID+3 ) ; SCNTL3
;********************** select the device ********************************
SELECT ATN from TLQ_SCSI_ID, rel( try_reselect ) ; ************************
;*************************************************************************
; looking good - clear the mailbox:
next_mailbox:
load SCRATCHA0, 4, ld_zeroes ; zero out scratch register A
load DSA0, 4, ld_sched_mlbx_base_adr ; load base physical address of mailboxes
clear_mailbox:
store SCRATCHA0, 4, DSAREL( 0 ) ; *** Patched offset. Zero the mailbox
; Update the index to the mailbox circular list:
load SCRATCHB0, 1, ld_counter ; get counter (mailbox index)
move SCRATCHB0 + 1 to SCRATCHB0 ; add 1
store SCRATCHB0, 1, ld_counter ; put it back
load SCRATCHB0, 1, ld_nexus ; if low-byte == 0x01 then cancelled mailbox
move SCRATCHB0 to SFBR
jump rel( select_phase ), if 1
; *** FALL THROUGH TO phase_handler ***
;*****************************************************************
;
; Phase_handler
; The phase handler script is a dispatcher function of SCSI phase
;
;*****************************************************************
phase_handler:
load DSA0, 4, ld_nexus ; reload DSA
jump rel( command_phase ), when CMD ; wait for REQ
jump rel( data_out_phase ), if DATA_OUT ; already latched REQ signal
jump rel( message_out_phase ), if MSG_OUT
jump rel( data_in_phase ), if DATA_IN
jump rel( status_phase ), if STATUS
jump rel( message_in_phase ), if MSG_IN
int unknown_phase
;*****************************************************************
;
; Message-Out phase
;
;*****************************************************************
message_out_phase:
move kphase_MSG_OUT to SCRATCHB0 ; Set phase indicator
store SCRATCHB0, 1, ld_phase_flag
move from TLQ_MSGOp, when MSG_OUT ; put out the message(s)
jump rel( phase_handler )
; issueMessageOut - Driver entry point for Sync/Wide negotiation and
; to issue message Reject:
issueMessageOut:
set ATN ; tell Target we have something to say
clear ACK
jump rel( message_out_phase ), when MSG_OUT ; wait for REQ. Jump if msg-out phase.
jump rel( phase_handler ), if not MSG_IN ; jump if weird phase
move 1, ld_scratch+1, when MSG_IN ; dump the msg byte
clear ACK ; accept Target's last msg-in byte
jump rel( issueMessageOut )
;*****************************************************************
;
; Command phase
;
;*****************************************************************
command_phase:
move kphase_COMMAND to SCRATCHB0 ; Set phase indicator
store SCRATCHB0, 1, ld_phase_flag
clear ATN ; In case we missed the sending nego
move FROM TLQ_CDBp, when CMD ; issue the CDB
jump rel( phase_handler )
;*****************************************************************
;
; Data_out_phase
;
;*****************************************************************
data_out_phase:
move kphase_DATA_OUT to SCRATCHB0 ; Set phase indicator
store SCRATCHB0, 1, ld_phase_flag
call rel( driverXfer ) ; call driver-built CHMOV instructions
jump rel( phase_handler ) ; if all data xfer'd, get next phase
driverXfer: ; get here from data-in code also
load SCRATCHA0, 4, DSAREL( TLQ_xferAdr )
store SCRATCHA0, 4, doItPatch+4 ; *** patch the JUMP address
move 0xFF to SCRATCHA1
store SCRATCHA1, 1, DSAREL( TLQ_xferStarted )
doItPatch:
jump 0x0333 ; *** patched address
;*****************************************************************
;
; Data_in_phase
; 875 sets ATN if bad parity detected.
; Use of CHMOV instructions assures that we properly handle
; a leftover wide byte in the SWIDE or SODL register, depending
; on the data direction. This can happen in either of two conditions:
; 1. The Target disconnects at an odd boundary. This is
; extremely unlikely with disk devices.
; 2. The client passes either an odd buffer address or
; an odd transfer count. When the Target disconnects (at
; an even boundary, we end up with the extra wide
; byte in SWIDE or SODL. MacOS does this with VM on.
;
;*****************************************************************
data_in_phase:
move kphase_DATA_IN to SCRATCHB0 ; Set phase indicator
store SCRATCHB0, 1, ld_phase_flag
call rel( driverXfer ) ; call driver-built CHMOV instructions
; The driver gets interrupted if a phase mismatch occurs as when
; the Target goes MSG-IN with a Disconnect.
; The driver codes either a RETURN if the Scatter/Gather list is complete or
; an INT if more Scatter/Gather elements need to be generated.
; On the Macintosh, client programs expect extra incoming data to be dumped.
; For example, during boot the ROM reads 512 bytes from a 2K-byte-sector CD.
bucket_loop:
jump rel( phase_handler ), when not DATA_IN ; wait for phase, exit if changed
CHMOV 1, ld_status, when DATA_IN ; eat a byte
jump rel( bucket_loop ); ; keep dumping bytes
;*****************************************************************
;
; Status phase
;
;*****************************************************************
status_phase:
move kphase_STATUS to SCRATCHB0 ; Set phase indicator
store SCRATCHB0, 1, ld_phase_flag
move 1, ld_status, when STATUS ; Read Status byte from bus
jump rel( phase_handler )
;*****************************************************************
;
; Message-In phase
;
;*****************************************************************
message_in_phase:
move kphase_MSG_IN to SCRATCHB0 ; Set phase indicator
store SCRATCHB0, 1, ld_phase_flag
move 1, ld_message, when MSG_IN ; Read byte from bus
jump rel( cmdComplete ), if 0x00 ; Command Complete
jump rel( saveDataPointer ), if 0x02 ; Save Data Pointer
jump rel( disconnect_msg ), if 0x04 ; Disconnect
jump rel( ignoreWideResidue ), if 0x23 ; Ignore Wide Residue
jump rel( restoreDataPointer ), if 0x03 ; Restore Data Pointer
jump rel( extended_msg ), if 0x01 ; Extended message
jump rel( msg_reject ), if 0x07 ; Message Reject
; Identify, if 0x80-FF ; Identify + LUN
; simple_queue_tag, if 0x20 ; Simple Queue Tag
; initiate_recovery, if 0x0F ; Initiate Recovery
; linked_cde_complete, if 0x0A/0x0B
int unexpected_msg ; unknown
msg_reject:
int unknown_msg_reject
clearACK: ; ENTRY point to end negotiation
clear ACK
jump rel( phase_handler )
;*****************************************************************
;
; Ignore Wide Residue
;
;*****************************************************************
ignoreWideResidue: ; this is a two byte message so snag the 2nd byte here
clear ACK
move 1, ld_message+1, when MSG_IN ; save residue count
move SFBR to SCRATCHB2 ; byte is still in SFBR. Position it.
store SCRATCHB2, 1, DSAREL( TLQ_IWR ) ; Store residue count in Nexus for driver.
clear ACK
jump rel( phase_handler )
;*****************************************************************
;
; Extended message
; Accept Wide and Synchronous Data Transfer messages
;
;*****************************************************************
extended_msg:
clear ACK
move 1, ld_message+1, when MSG_IN ; read msg length byte from bus
clear ACK
move 1, ld_message+2, when MSG_IN ; read ext msg code from bus
clear ACK
; extended_identify, IF 0x02
; modify_data_pointer, if 0x00
jump rel( sdtr ), if 0x01 ; jump if SDTR, sync negotiation msg
jump rel( wdtr ), if 0x03 ; jump if WDTR, wide negotiation msg
int unexpected_ext_msg ; let driver deal with unknown
;*****************************************************************
;
; Command complete
; The Command-Complete message is sent to indicate that the
; IO operation has completed and valid status has been sent.
; The Target should then disconnect.
; SCRIPTS must spin until the IOdone mailbox is empty.
; Then it sets the IOdone mailbox with the current Nexus.
; The status message is analyzed.
; If status is good, INTF the driver and jump to select_phase.
; If status is NG, save it in the NEXUS and INT the driver.
;
;*****************************************************************
cmdComplete:
move kphase_CMD_COMPLETE to SCRATCHB0 ; Set phase indicator
store SCRATCHB0, 1, ld_phase_flag
move SCNTL2 & 0X7F to SCNTL2 ; Clr SDU: SCSI Disconnect Unexpected
clear ACK
WAIT DISCONNECT
testMbxLp: ; loop until IOdone mailbox empty
load SCRATCHA0, 4, ld_IOdone_mailbox
move SCRATCHA3 to SFBR ; A3 = semaphore
jump rel( testMbxLp ), if not 0
; Fill in the IOdone mailbox with the following:
; A0 = index to Nexus
; A1 = Status
; A2 = 0
; A3 = semaphore (FF = set)
load SCRATCHA0, 1, ld_nexus_index ; A0 = index to Nexus
load SCRATCHB0, 1, ld_status
move SCRATCHB0 to SFBR
move SFBR to SCRATCHA1 ; A1 = Status
move 0x00 to SCRATCHA2 ; A2 = 0
move 0xFF to SCRATCHA3 ; A3 = semaphore IOdone mailbox
store SCRATCHA0, 4, ld_IOdone_mailbox
move SCRATCHA1 to SFBR ; Test the Status of this IO
; SFBR = status msg
; Test status - If good, Interrupt on the fly and jump to select phase
intfly 0xFF, if 0 and mask 0xC1 ; mask off reserved bits
jump rel( select_phase ), if 0 and mask 0xC1
int status_error ; Status err. Interrupt driver & stop
;*****************************************************************
;
; Disconnect
; The 8xx Accepts the disconnection and jumps to the select_phase
; to check for another IO
;
;*****************************************************************
disconnect_msg:
load SCRATCHB0, 1, ld_phase_flag
move SCRATCHB0 to SFBR
; If we got here from reselect just bailout since ld_nexus is
; not setup and the code using it is not needed anyway (no data xfer)
jump rel( bailout ), if kphase_RESELECT
move kphase_DISCONNECT to SCRATCHB0
store SCRATCHB0, 1, ld_phase_flag
bailout:
move 0xFF to SCRATCHB3 ; invalidate nexus index for driver
store SCRATCHB3, 1, ld_nexus_index+3
move SCNTL2 & 0x7F to SCNTL2 ; Clr SDU: SCSI Disconnect Unexpected
clear ACK
WAIT DISCONNECT ; wait for bus-free
jump rel( select_phase ) ; go see if more to do
;******************************************************************
;
; ??? mlj - saveDataPointer and restoreDataPointer are incorrect.
; ??? They basically do nothing.
; Save Data Pointer
;
;*****************************************************************
saveDataPointer:
move kphase_saveDataPointer to SCRATCHB0
store SCRATCHB0, 1, ld_phase_flag
clear ACK
jump rel( phase_handler )
;******************************************************************
;
; ??? mlj - saveDataPointer and restoreDataPointer are incorrect.
; ??? They basically do nothing.
; Restore Data Pointer
; The local values still blocks, still bytes and data address
; must be loaded from the corresponding NEXUS data set.
; This message should followed an IDE (parity error)
;
;*****************************************************************
restoreDataPointer:
move kphase_restoreDataPointer to SCRATCHB0
store SCRATCHB0, 1, ld_phase_flag
clear ACK
jump rel( phase_handler )
;*****************************************************************
;
; Synchronous data transfer request or response
;
;*****************************************************************
sdtr:
move 2, ld_message+3, when MSG_IN ; Read period & offset from bus
int negotiateSDTR
;***************************************************************************
;
; Wide Data Transfer request or response
;
;***************************************************************************
wdtr:
move 1, ld_message+3, when MSG_IN ; get Transfer Width Exponent fm bus
int negotiateWDTR
;*****************************************************************
;
; Reselect phase
; The chip waits here either for a Reselection from a Target or
; a SIGP from the driver indicating something in the mailbox.
; If reselected, the script uses the Nexus value which is either
; a Tag or a SCSI ID/LUN combo to lookup the Nexus.
; Then init the SXFER and SCNTL3 registers from the device config table.
;
;*****************************************************************
try_reselect: ; Select failed - probably reselecting
; Cf NCR Errata Listing 117 Item 1:
move SCNTL0 & 0xDF to SCNTL0 ; clr Start bit
move CTEST2 | 0x00 to CTEST2 ; Clear SIGP bit from ISTAT reg
reselect_phase:
move kphase_RESELECT to SCRATCHB0 ; Set phase indicator
store SCRATCHB0, 1, ld_phase_flag
move 0xFF to SCRATCHB3 ; invalidate nexus index for driver
store SCRATCHB3, 1, ld_nexus_index+3
; wait here for reselect from a Target
; or SIGP from the driver
WAIT RESELECT REL( select_phase ) ; jump if SIGP
; Reselected:
move SSID to SFBR ; SSID = [ Valxxx Scsi_id ]
int unknown_reselect, if 0 and mask 0x7F; Interrupt if VAL bit not set
move SFBR & 0x0F to SCRATCHB0 ; B0 = Target ID
store SCRATCHB0, 1, ld_scsi_id ; save it
call rel( initContext ) ; setup sync regs here
int no_msgin_after_reselect, when not MSG_IN
move 1, ld_message, when MSG_IN ; Read Identify byte from bus
; if another REQ is asserted, a SimpleQueueTag message should be next
clear ACK ; notify Target: msg byte rx'd
jump rel( getNextMsg ), when MSG_IN ; jump if SimpleQueueTag coming
; untagged operation:
move SFBR & 0x07 to SCRATCHA0 ; isolate LUN from Identify byte
load SCRATCHB0, 1, ld_scsi_id ; B0 = Target ID
clear CARRY
move SCRATCHB0 SHL SFBR ; shift left #1
move SFBR SHL SCRATCHB0 ; shift left #2
move SCRATCHB0 SHL SFBR ; shift left #3
move SCRATCHA0 | SFBR to SCRATCHA0 ; form Nexus index = 0b0TTTTLLL
store SCRATCHA0, 1, ld_nexus_index ; store as index to Nexus
jump rel( haveNexusIndex )
; should be tagged operation:
getNextMsg:
move 1, ld_message, when MSG_IN ; read message byte from bus
jump rel( disconnect_msg ), if 0x04 ; if Disconnect, oh well.
clear ACK
jump rel( phase_handler ), if not 0x20; Branch if not Queue tag code
; get the Queue Tag and save as the nexus index
move 1, ld_nexus_index, when MSG_IN ; Nexus index <- Tag from bus
clear ACK ; acknowledge it
haveNexusIndex:
move 0x00 to SCRATCHB3 ; clear invalid-nexus-index flag
store SCRATCHB3, 1, ld_nexus_index+3
call rel( findNexusFromIndex ) ; set DSA <- Nexus pointer
jump rel( phase_handler ) ; start handling phases.
;*****************************************************************
;
; AbortMailbox - Abort (or BusDeviceReset) the mailbox entry.
; This is a queued operation - not an immediate
; operation as is issueAbort_BDR.
; The Abort message clears all IO processes for the
; selecting Initiator on the specified LUN.
;
; The Bus Device Reset message clears all IO processes for
; all Initiators on all LUNs of selected Target.
; It forces a hard reset condition to the selected SCSI device.
;
; A0 = Identify byte (0xC0 + LUN N.B. Disconnect allowed)
; A1 = Tag, if any
; A2 = SCSI ID
; A3 = Abort code Abort=0x06; Abort Tag=0D; Bus Device Reset=0x0C
;
; Mailbox not cleared by SCRIPTS so that driver can find SCSI ID when done
; N.B.: Device is Async and Narrow after BDR!!!
; Driver must set the device config table values accordingly.
;*****************************************************************
AbortMailbox:
move kphase_ABORT_MAILBOX to SCRATCHB0 ; Set phase code
store SCRATCHB0, 1, ld_phase_flag
move 0xFF to SCRATCHB3 ; invalidate nexus index for driver
store SCRATCHB3, 1, ld_nexus_index+3
load SCRATCHB2, 1, ld_AbortBdr_mailbox+2 ; get SCSI ID
store SCRATCHB2, 1, AbortSelect+2 ; *** Patch the Select/ATN instruction
AbortSelect:
SELECT ATN 0, REL( try_reselect ) ; *** Patched SCSI ID
move SCRATCHA1 to SFBR ; check for Tag
jump rel( taggedAbort ) if not 0x00 ; jump if tagged abort
; untagged Abort or BusDeviceReset:
move SCRATCHA3 to SFBR ; position the abort code
move SFBR to SCRATCHA1
store SCRATCHA0, 2, ld_scratch ; Store Identify and Abort msgs
move 0x00 to SCNTL2 ; Clr SDU SCSI Disconnect Unexpected
move 2, ld_scratch , when MSG_OUT ; emit Identify and Abort messages
WAIT DISCONNECT
int abort_mailbox
; AbortTag:
taggedAbort:
move SCRATCHA1 to SFBR ; position the Tag
move SFBR to SCRATCHA2
move 0x20 to SCRATCHA1 ; gen SimpleQueueTag code
store SCRATCHA0, 4, ld_scratch ; store Identify, SQT, Tag, AbortTag
move 0x00 to SCNTL2 ; Clr SDU SCSI Disconnect Unexpected
move 4, ld_scratch, when MSG_OUT ; emit all 4 bytes
WAIT DISCONNECT
int abort_mailbox
;*****************************************************************
;
; issueAbort_BDR - Abort (or BusDeviceReset) the current operation.
; This is an immediate operation - not a queued operation
; as is AbortMailbox.
; The Abort message clears all IO processes for the
; selecting Initiator on the specified LUN.
;
; The Bus Device Reset message clears all IO processes for
; all Initiators on all LUNs of selected Target.
; It forces a hard reset condition to the selected SCSI device.
;
;*****************************************************************
issueAbort_BDR:
move kphase_ABORT_CURRENT to SCRATCHB0 ; Set phase code
store SCRATCHB0, 1, ld_phase_flag
move ISTAT & 0x08 to SFBR ; see if Target connected to bus
int abort_current, if 0 ; interrupt driver if not connected
SET ATN ; get Target's attention
load DSA0, 4, ld_nexus ; load pointer to Nexus
bucketLoop:
clear ACK
jump rel( sendAbortBDR ), when MSG_OUT ; wait for REQ. Jump if OK.
jump rel( BucketInStatus ), if STATUS ; bit bucket in
jump rel( BucketInMsg ), if MSG_IN ; bit bucket in
jump rel( BucketInData ), if DATA_IN ; bit bucket in
move 0xAD to SCRATCHA0
jump rel( BucketOutData ), if DATA_OUT ; bit bucket out
jump rel( BucketOutCmd ), if CMD ; bit bucket out
int unknown_phase ; back to driver for harsher measures
BucketInStatus:
move 1, ld_scratch, when STATUS ; eat the Status byte
jump rel( bucketLoop ); ; keep bit-bucketing bytes
BucketInMsg:
move 1, ld_scratch, when MSG_IN ; eat a message byte
jump rel( bucketLoop ); ; keep bit-bucketing bytes
BucketInData:
move 1, ld_scratch, when DATA_IN ; eat a data byte
jump rel( bucketLoop ); ; keep bit-bucketing bytes
BucketOutData:
move SCRATCHA0 xor 0x73 to SCRATCHA0 ; gen 0xDEAD ...
store SCRATCHA0, 1, ld_scratch
move 1, ld_scratch, when DATA_OUT ; pad a byte out
jump rel( bucketLoop ); ; keep bit-bucketing bytes
BucketOutCmd:
move 0x00 to SCRATCHA0 ; load Null, TestUnitReady, whatever
store SCRATCHA0, 1, ld_scratch
move 1, ld_scratch, when CMD ; pad a byte out
jump rel( bucketLoop ); ; keep bit-bucketing bytes
sendAbortBDR:
move 0x00 to SCNTL2 ; Clr SDU SCSI Disconnect Unexpected
move 1, ld_AbortCode, when MSG_OUT ; Send Abort(06) or BDR(0C) message
load SCRATCHA0, 4, ld_zeroes ; load 0's
store SCRATCHA0, 4, ld_AbortCode ; clear the Abort code
WAIT DISCONNECT
int abort_current ; went BusFree - tell Driver