diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/miniport/symbios/dirs | 26 | ||||
-rw-r--r-- | private/ntos/miniport/symbios/symc810/makefile | 6 | ||||
-rw-r--r-- | private/ntos/miniport/symbios/symc810/scrpt810.asm | 667 | ||||
-rw-r--r-- | private/ntos/miniport/symbios/symc810/scrpt810.h | 273 | ||||
-rw-r--r-- | private/ntos/miniport/symbios/symc810/sources | 39 | ||||
-rw-r--r-- | private/ntos/miniport/symbios/symc810/symc810.c | 9200 | ||||
-rw-r--r-- | private/ntos/miniport/symbios/symc810/symc810.h | 101 | ||||
-rw-r--r-- | private/ntos/miniport/symbios/symc810/symc810.rc | 41 | ||||
-rw-r--r-- | private/ntos/miniport/symbios/symc810/symnvm.h | 325 | ||||
-rw-r--r-- | private/ntos/miniport/symbios/symc810/symscam.h | 107 | ||||
-rw-r--r-- | private/ntos/miniport/symbios/symc810/symsiop.h | 452 |
11 files changed, 11237 insertions, 0 deletions
diff --git a/private/ntos/miniport/symbios/dirs b/private/ntos/miniport/symbios/dirs new file mode 100644 index 000000000..803baf6a6 --- /dev/null +++ b/private/ntos/miniport/symbios/dirs @@ -0,0 +1,26 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dirs. + +Abstract: + + This file specifies the subdirectories of the current directory that + contain component makefiles. + + +Author: + + Steve Wood (stevewo) 17-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl + +!ENDIF + +DIRS= \ + \ + symc810 + diff --git a/private/ntos/miniport/symbios/symc810/makefile b/private/ntos/miniport/symbios/symc810/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/miniport/symbios/symc810/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/miniport/symbios/symc810/scrpt810.asm b/private/ntos/miniport/symbios/symc810/scrpt810.asm new file mode 100644 index 000000000..2e6fe2eb5 --- /dev/null +++ b/private/ntos/miniport/symbios/symc810/scrpt810.asm @@ -0,0 +1,667 @@ +;/************************************************************************ +;* * +;* Copyright 1994 Symbios Logic Inc. All rights reserved. * +;* * +;* This file is confidential and a trade secret of Symbios Logic * +;* The receipt of or possession of this file does not convey any * +;* rights to reproduce or disclose its contents or to manufacture, * +;* use, or sell anything is may describe, in whole, or in part, * +;* without the specific written consent of Symbios Logic * +;* * +;************************************************************************/ +; +;/*+++HDR +; * +; * Version History +; * --------------- +; * +; * Date Who? Description +; * -------- ---- ------------------------------------------------------- +; * +; * 1/12/96 SPD Add new script entry point to restart negotiations for +; * synch transfer mode on same IO as wide negotiation. +; * Fix for parity error on wide data transfers. +; * +;---*/ +; + +; +; Successful operation codes +; + +Absolute CommandOk = 0x0aa00 ; command completed successfully +Absolute Save_Pointers = 0x0aa01 ; SDP message received +Absolute Save_with_Disc = 0x0aa02 ; SDP + Disconnect messages received +Absolute Device_Discon = 0x0aa03 ; Disconnect message received +Absolute Restore_Pointers = 0x0aa04 ; RDP message received. +Absolute ScriptsAborted = 0x0aa05 ; scripts aborted by device driver +Absolute Tag_Received = 0x0aa06 ; RDP message received. +Absolute SynchNegotComp = 0x0aa0c ; synchronous negotiation completed +Absolute WideNegotComp = 0x0aa1c ; wide negotiation completed + +; +; Error codes +; + +Absolute DeviceReset = 0x0ff07 ; had to bail out +Absolute ResetFailed = 0x0ff08 ; ...but couldn't. +Absolute RestSenseComplete = 0x0ff09 ; request sense has completed +Absolute ParityMessageSent = 0x0ff0a ; parity message has been sent +Absolute SynchNotSupported = 0x0ff0b ; synchronous xfer is not supported +Absolute WideNotSupported = 0x0ff1b ; wide xfer is not supported +Absolute InvalidReselector = 0x0ff0d ; reselecting drive id invalid +Absolute MessageRejected = 0x0ff0e ; target rejected our message +Absolute InvalidTaggedMessage = 0x0ff0f ; target did not send a tagged message. + +Absolute DeviceAborted = 0x0ff10 ; device accepted abort message +Absolute AbortFailed = 0x0ff11 ; abort message failed + +Absolute ReselByTarget = 0x0080 + + +; +; offsets in DSA structure follow +; THESE OFFSETS MUST BE CHANGED IF SCRIPT DATA STRUCTURE IN DEVICE EXTENSION +; CHANGES. +; + +Absolute SelectDataOff = 0 +Absolute CDBDataOff = SelectDataOff + 4 +Absolute MsgOutOff = CDBDataOff + 8 +Absolute StatusDataOff = MsgOutOff + 8 +Absolute OneByteMsgOff = StatusDataOff + 8 +Absolute RejectMsgOff = OneByteMsgOff + 8 +Absolute ParityMsgOff = RejectMsgOff + 8 +Absolute AbortMsgOff = ParityMsgOff + 8 +Absolute BDRMsgOff = AbortMsgOff + 8 +Absolute TwoByteMsgOff = BDRMsgOff + 8 +Absolute SGEntry18Off = TwoByteMsgOff + 8 +Absolute SGEntry17Off = SGEntry18Off + 8 +Absolute SGEntry16Off = SGEntry17Off + 8 +Absolute SGEntry15Off = SGEntry16Off + 8 +Absolute SGEntry14Off = SGEntry15Off + 8 +Absolute SGEntry13Off = SGEntry14Off + 8 +Absolute SGEntry12Off = SGEntry13Off + 8 +Absolute SGEntry11Off = SGEntry12Off + 8 +Absolute SGEntry10Off = SGEntry11Off + 8 +Absolute SGEntry09Off = SGEntry10Off + 8 +Absolute SGEntry08Off = SGEntry09Off + 8 +Absolute SGEntry07Off = SGEntry08Off + 8 +Absolute SGEntry06Off = SGEntry07Off + 8 +Absolute SGEntry05Off = SGEntry06Off + 8 +Absolute SGEntry04Off = SGEntry05Off + 8 +Absolute SGEntry03Off = SGEntry04Off + 8 +Absolute SGEntry02Off = SGEntry03Off + 8 +Absolute SGEntry01Off = SGEntry02Off + 8 + +; +; 53C8xx register bits used by scripts +; +; +;Absolute CTEST2_sigp = 0x40 +;Absolute CTEST7_notime = 0x10 +; +; +; SCSI definitions used by scripts +; + +Absolute SCSIMESS_ABORT = 0x06 +Absolute SCSIMESS_ABORT_WITH_TAG = 0x0D +Absolute SCSIMESS_BUS_DEVICE_RESET = 0X0C +Absolute SCSIMESS_CLEAR_QUEUE = 0X0E +Absolute SCSIMESS_DISCONNECT = 0X04 +Absolute SCSIMESS_EXTENDED_MESSAGE = 0X01 +Absolute SCSIMESS_IDENTIFY = 0X80 +Absolute SCSIMESS_IDENTIFY_WITH_DISCON = 0XC0 +Absolute SCSIMESS_IGNORE_WIDE_RESIDUE = 0X23 +Absolute SCSIMESS_INITIATE_RECOVERY = 0X0F +Absolute SCSIMESS_INIT_DETECTED_ERROR = 0X05 +Absolute SCSIMESS_LINK_CMD_COMP = 0X0A +Absolute SCSIMESS_LINK_CMD_COMP_W_FLAG = 0X0B +Absolute SCSIMESS_MESS_PARITY_ERROR = 0X09 +Absolute SCSIMESS_MESSAGE_REJECT = 0X07 +Absolute SCSIMESS_NO_OPERATION = 0X08 +Absolute SCSIMESS_HEAD_OF_QUEUE_TAG = 0X21 +Absolute SCSIMESS_ORDERED_QUEUE_TAG = 0X22 +Absolute SCSIMESS_SIMPLE_QUEUE_TAG = 0X20 +Absolute SCSIMESS_RELEASE_RECOVERY = 0X10 +Absolute SCSIMESS_RESTORE_POINTERS = 0X03 +Absolute SCSIMESS_SAVE_DATA_POINTER = 0X02 +Absolute SCSIMESS_TERMINATE_IO_PROCESS = 0X11 +Absolute SCSIMESS_COMMAND_COMPLETE = 0X00 +Absolute SCSIMESS_SYNCHRONOUS_DATA_REQ = 0X01 +Absolute SCSIMESS_WIDE_DATA_REQUEST = 0X03 +Absolute SCSISTAT_CHECK_CONDITION = 0x02 + +; +; Script entry point declarations follow +; + +Entry EndOfScript +Entry ResetDevice +Entry AbortDevice +Entry AbortExecution +Entry ProcessSelectReselect +Entry ReselectScript +Entry SendErrorMessage +Entry RejectReceived +Entry RejectIN +Entry SendReject +Entry RejectMessage +Entry ExtMsgRcvd +Entry ProcessDisconnect +Entry RestPtrsRcvd +Entry SaveDataPointers +Entry MessageIn +Entry RestartScript +Entry SyncMsgNegot + +Entry DataOutJump +Entry DataInJump +Entry DataOut18 +Entry DataOut01 +Entry DataIn18 +Entry DataIn01 + +Entry GetStatus +Entry SendCommand +Entry SendID +Entry CommandScriptStart +Entry QueueTagMessage +Entry ContNegScript + +CommandScriptStart: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; This is the entry point for initiating SCSI I/O +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + select ATN from SelectDataOff, rel( ReselectScript ) ; Select device + move GPREG & 0xFE to GPREG ; turn LED on + jump rel ( GetStatus ), when STATUS ; If status exit + jump rel ( ResetSelectedDev ), if not MSG_OUT ; Bad phase check + +SendID: + move from MsgOutOff, when MSG_OUT ; Send ID message + jump rel ( SendCommand ) when CMD ; Expected next phase + jump rel ( GetStatus ) if STATUS ; Handle status phase + jump rel ( MessageIn ) if MSG_IN ; Handle message phase + jump rel ( ResetSelectedDev ) ; Error - reset device + +SendCommand: + move from CDBDataOff, when CMD ; Move the CDB +;; new entry to take care of a posible SCSI parity error + move SOCL & 0xFD to SOCL + + jump rel ( ResetSelectedDev ) when CMD ; Error - reset device + + jump rel ( GetStatus ) if STATUS ; Handle status phase + jump rel ( MessageIn ) if MSG_IN ; Handle message phase + + +ProcessDataPhase: + +; Jump to the data in handling when in data-in phase. This jump +; may be patched by the miniport. + +DataInJump: + + jump rel ( DataIn18 ) if DATA_IN ; Handle data in + +; Jump to the data in handling when in data-in phase. This jump +; may be patched by the miniport. + +DataOutJump: + jump rel ( DataOut18 ) if DATA_OUT ; Handle data out + + jump rel ( ResetSelectedDev ) ; Bad phase encountered + +GetStatus: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; This script routine handles status phase +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + move from StatusDataOff, when STATUS ; Get status + +; +; MESSAGE IN phase should follow STATUS phase. +; + + jump rel ( MessageIn ) when MSG_IN ; Handle message in phase + jump rel ( ResetSelectedDev ) ; Error - reset device + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; This the data out section of scripts. +; Up to 18 gather moves can be processed at once. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +DataOut18: + chmov from SGEntry18Off, when DATA_OUT + chmov from SGEntry17Off, when DATA_OUT + chmov from SGEntry16Off, when DATA_OUT + chmov from SGEntry15Off, when DATA_OUT + chmov from SGEntry14Off, when DATA_OUT + chmov from SGEntry13Off, when DATA_OUT + chmov from SGEntry12Off, when DATA_OUT + chmov from SGEntry11Off, when DATA_OUT + chmov from SGEntry10Off, when DATA_OUT + chmov from SGEntry09Off, when DATA_OUT + chmov from SGEntry08Off, when DATA_OUT + chmov from SGEntry07Off, when DATA_OUT + chmov from SGEntry06Off, when DATA_OUT + chmov from SGEntry05Off, when DATA_OUT + chmov from SGEntry04Off, when DATA_OUT + chmov from SGEntry03Off, when DATA_OUT + chmov from SGEntry02Off, when DATA_OUT + +DataOut01: + chmov from SGEntry01Off, when DATA_OUT + + jump rel ( GetStatus) when STATUS ; Handle status + jump rel ( MessageIn) if MSG_IN ; Handle messages + jump rel ( ResetSelectedDev) ; Error - reset device + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; This the data in section of scripts. +; Up to 18 scatter moves can be processed at once. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +DataIn18: + chmov from SGEntry18Off, when DATA_IN + chmov from SGEntry17Off, when DATA_IN + chmov from SGEntry16Off, when DATA_IN + chmov from SGEntry15Off, when DATA_IN + chmov from SGEntry14Off, when DATA_IN + chmov from SGEntry13Off, when DATA_IN + chmov from SGEntry12Off, when DATA_IN + chmov from SGEntry11Off, when DATA_IN + chmov from SGEntry10Off, when DATA_IN + chmov from SGEntry09Off, when DATA_IN + chmov from SGEntry08Off, when DATA_IN + chmov from SGEntry07Off, when DATA_IN + chmov from SGEntry06Off, when DATA_IN + chmov from SGEntry05Off, when DATA_IN + chmov from SGEntry04Off, when DATA_IN + chmov from SGEntry03Off, when DATA_IN + chmov from SGEntry02Off, when DATA_IN + +DataIn01: + chmov from SGEntry01Off, when DATA_IN + + jump rel ( GetStatus) when STATUS ; Handle status + jump rel ( MessageIn) if MSG_IN ; Handle messages + jump rel ( ResetSelectedDev) ; Error - reset device + + +ContNegScript: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; ContNegScript +; +; Entry point for continuing negotiations for sync after wide negotiations +; have occurred. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + set ATN ; bring target back to + ; msg in phase + clear ACK ; still need to ack + ; last wide neg. byte + jump rel ( ResetSelectedDev ), when not MSG_OUT ; Bad phase check + move from MsgOutOff, when MSG_OUT ; Send synch messages + jump rel ( RestartPlus ), when MSG_IN + jump rel ( ResetSelectedDev ) + + +RestartScript: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; RestartScript +; +; Entry point for restarting script after reselect, etc. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; new command to take care of possibel parity error + move SOCL & 0xFD to SOCL + clear ACK and ATN ; Clear pending conditions + +RestartPlus: +; +; note that the call to message in will return only if the message is IDENTIFY +; + + jump rel ( SendCommand ) when CMD ; Process phase + call rel ( MessageIn ) if MSG_IN ; Handle messages + jump rel ( GetStatus ) if STATUS ; Handle status + jump rel ( ProcessDataPhase ) if DATA_IN ; + jump rel ( ProcessDataPhase ) if DATA_OUT ; + jump rel ( SendErrorMessage ) if MSG_OUT ; + jump rel ( ResetSelectedDev ) ; Error - reset device + + +MessageIn: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; This script routine processes message from target +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + move from OneByteMsgOff, when MSG_IN + +; steved - +; do we need to move identify further up? + +; +; Handle command complete message +; + + jump rel ( ProcessCommandComplete ) if SCSIMESS_COMMAND_COMPLETE + +; +; Handle disconnect +; + + jump rel ( ProcessDisconnect ) if SCSIMESS_DISCONNECT + +; +; Handle Save Data Pointers +; + + jump rel ( SaveDataPointers ) if SCSIMESS_SAVE_DATA_POINTER + +; +; Handle Restore Pointers +; + + jump rel ( RestPtrsRcvd ) if SCSIMESS_RESTORE_POINTERS + +; +; Handle extended message +; + + jump rel ( ExtMsgRcvd ) if SCSIMESS_EXTENDED_MESSAGE + +; +; Handle Message Reject +; + + jump rel ( RejectReceived ) if SCSIMESS_MESSAGE_REJECT + +; +; If not Identify, reject the message +; + + jump rel ( RejectMessage ) if not SCSIMESS_IDENTIFY and mask 0x0F + +; +; Process Identify message. Note that we throw away the Identify message +; at this point because it has already been processed by the driver. +; + + clear ACK ; Throw message away + jump rel ( MessageIn ) when MSG_IN ; Handle more messages + +; +; Note that this routine is CALLed only by the reselection script routine. +; We should only receive an identify message immediately after a +; reselection. Therefore, the RETURN below will be executed only when this +; routine is called by the reselection code. +; + return ; Return to caller + +SaveDataPointers: + clear ACK ; Acknowledge SDP + +; +; Normally, disconnect message will follow SDP. We save ourselves an interrupt +; by assuming this is the case. +; + + int Save_Pointers when not MSG_IN ; Another message? + move from OneByteMsgOff, when MSG_IN ; If so move it + +; +; bugbug- +; although it is very improbable that a device would send a message other +; than DISCONNECT after an SDP, we need to handle this case more gracefully. +; + jump rel ( ResetSelectedDev ) if not SCSIMESS_DISCONNECT + ; If not disconnect, + ; error - reset device + + move SCNTL2 & 0x7F to SCNTL2 ; Disable unexpected disconnect + move GPREG | 0x01 to GPREG ; LED off ; Clear disconnect message + clear ACK + wait DISCONNECT ; + int Save_with_Disc ; Indicate SDP and + ; disconnect + +RestPtrsRcvd: + clear ACK ; Accept message + int Restore_Pointers ; Indicate restore pointers + + +ProcessDisconnect: + + move SCNTL2 & 0x7F to SCNTL2 ; Disable unexpected disconnect + move GPREG | 0x01 to GPREG ; LED off ; Clear disconnect message + clear ACK ; Clear disconnect message + wait DISCONNECT ; Wait for disconnect to happen + int Device_Discon ; Indicate device disconnected + + +ProcessCommandComplete: + + move SCNTL2 & 0x7F to SCNTL2 ; Disable unexpected disconnect + move GPREG | 0x01 to GPREG ; LED off ; Clear disconnect message + clear ACK ; Acknowledge message + wait DISCONNECT ; Wait for disconnect to happen + int CommandOk ; Indicate command complete + +ExtMsgRcvd: + clear ACK ; Accept first byte of message + jump rel ( ResetSelectedDev ) when not MSG_IN ; If not MSG-IN, error - reset device + move from OneByteMsgOff, when MSG_IN ; Get next message byte + + jump rel ( SyncMsgNegot ) if 3 ; If not two byte message, + jump rel ( RejectMessage ) if not 2 + + clear ACK ; Accept first byte of wide message + move from OneByteMsgOff, when MSG_IN ; Get next byte of message + + jump rel ( RejectMessage ) if not SCSIMESS_WIDE_DATA_REQUEST + + + clear ACK ; Accept SDTR byte +; +; the following code processes the SDTR extended message +; + move from OneByteMsgOff, when MSG_IN ; Get wide parameters + + int WideNegotComp ; Indicate wide supported + + +SyncMsgNegot: +; +; NOTE: the following extended message lengths are currently supported: +; +; 3 byte messages +; + clear ACK ; Accept first byte of sync message + move from OneByteMsgOff, when MSG_IN ; Get next byte of message + jump rel ( RejectMessage ) if not SCSIMESS_SYNCHRONOUS_DATA_REQ + + clear ACK ; Accept SDTR byte +; +; the following code processes the SDTR extended message +; + + move from TwoByteMsgOff, when MSG_IN ; Get sync parameters + int SynchNegotComp ; Indicate synchronous supported + + +RejectMessage: + set ATN + clear ACK ; Clear the message + jump rel ( RejectIN ) when MSG_IN ; If still MSG IN, jump to + ; clear extended message +SendReject: + jump ResetSelectedDev, if not MSG_OUT ; If not MSG OUT, error - reset device + move from RejectMsgOff, when MSG_OUT ; Send REJECT message + jump rel ( ResetSelectedDev) when MSG_OUT ; If not accepted, error - reset device + jump rel ( RestartScript ) ; Reject successful - restart + ; the state machine + +RejectIN: + move from OneByteMsgOff, when MSG_IN ; Get message + clear ACK ; Acknowledge it + jump rel ( RejectIN ) when MSG_IN ; If more message bytes, process them + jump rel ( SendReject ) ; Send REJECT message + +RejectReceived: + ;clear ACK ; Clear the message + int MessageRejected ; Indicate message rejected + +SendErrorMessage: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; Send either INITIATOR DETECTED ERROR or MESSAGE PARITY ERROR message +; (set by driver before calling) to target. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + set ATN ; Ask for message out + clear ACK ; Clear any pending msgs + +; +; If the device does not go immediately to message out, we don't try to +; coax it. +; + jump rel ( ResetSelectedDev ) when not MSG_OUT ; Error - reset device + +DoParityMove: + move from ParityMsgOff, when MSG_OUT ; Move the error message + int ParityMessageSent ; Indicate message sent + +ReselectScript: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; Wait for a Reselection/selection +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + wait reselect rel ( AbortExecution ) + move GPREG & 0xFE to GPREG ;LED on + +ProcessSelectReselect: + + jump rel( ProcessSelectReselect ) if not MSG_IN + + move from OneByteMsgOff, when MSG_IN + +ReselectInterrupt: + + int ReselByTarget + +AbortExecution: + + move CTEST2 to SFBR ; Signal that we are stalled + int ScriptsAborted + + +ResetDevice: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; ResetDevice: +; +; Select device, reset device and exit. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; First have to select the device. + + select ATN from SelectDataOff, rel( ReselectScript ) ; Select device + move GPREG & 0xFE to GPREG ; LED on + jump rel ( ResetSendMsg ) + +ResetSelectedDev: + + set ATN ; Set ATN before releasing any messages + clear ACK ; Release messages + +; +; if the wayward device does not immediately go into message phase, we +; will bail out. No attempt is made to coax the drive by transferring +; any additional data or message bytes. +; + +ResetSendMsg: + int ResetFailed when not MSG_OUT ; Interrupt the reset failed + +DoBDRMove: + move SCNTL2 & 0x7F to SCNTL2 ; Disable unexpected disconnect + move from BDRMsgOff, when MSG_OUT ; Send BDR message + + move GPREG | 0x01 to GPREG ; LED off + wait DISCONNECT ; Wait for device to disconnect + int DeviceReset ; Indicate device reset + +AbortDevice: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; AbortDevice: +; +; Abort all I/Os for the device and exit. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; First have to select the device. + + select ATN from SelectDataOff, rel( ReselectScript ) ; Select device + move GPREG & 0xFE to GPREG ; LED on + +; +; if the wayward device does not immediately go into message phase, we +; will bail out. No attempt is made to coax the drive by transferring +; any additional data or message bytes. +; + + int AbortFailed when not MSG_OUT ; Interrupt the abort failed + + +DoAbortMove: + move SCNTL2 & 0x7F to SCNTL2 ; Disable unexpected disconnect + move from AbortMsgOff, when MSG_OUT ; Send abort message + + move GPREG | 0x01 to GPREG ; LED off + wait DISCONNECT ; Wait for device to disconnect + int DeviceAborted ; Indicate device aborted + + +QueueTagMessage: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; QueueTagMessage - +; +; This routine processes a queue tagged message. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + clear ACK ; Acknowledge identify message + move from OneByteMsgOff, when MSG_IN ; Get the first message byte + + int InvalidTaggedMessage, if not SCSIMESS_SIMPLE_QUEUE_TAG + ; If not simple queue tag message, + ; indicate this to driver + + clear ACK ; Acknowledge queue tag message + move from OneByteMsgOff, when MSG_IN ; Get the queue tag message + int Tag_Received ; Indicate queue tag received + + +EndOfScript: diff --git a/private/ntos/miniport/symbios/symc810/scrpt810.h b/private/ntos/miniport/symbios/symc810/scrpt810.h new file mode 100644 index 000000000..1199b5262 --- /dev/null +++ b/private/ntos/miniport/symbios/symc810/scrpt810.h @@ -0,0 +1,273 @@ +typedef unsigned long ULONG; + +ULONG SCRIPT[] = { + 0x47000000L, 0x00000470L, + 0x7C07FE00L, 0x00000000L, + 0x838B0000L, 0x00000070L, + 0x86820000L, 0x000004A8L, + 0x1E000000L, 0x0000000CL, + 0x828B0000L, 0x00000018L, + 0x838A0000L, 0x00000050L, + 0x878A0000L, 0x00000228L, + 0x80880000L, 0x00000480L, + 0x1A000000L, 0x00000004L, + 0x7C09FD00L, 0x00000000L, + 0x828B0000L, 0x00000468L, + 0x838A0000L, 0x00000020L, + 0x878A0000L, 0x000001F8L, + 0x818A0000L, 0x000000D0L, + 0x808A0000L, 0x00000020L, + 0x80880000L, 0x00000440L, + 0x1B000000L, 0x00000014L, + 0x878B0000L, 0x000001D0L, + 0x80880000L, 0x00000428L, + 0x10000000L, 0x0000004CL, + 0x10000000L, 0x00000054L, + 0x10000000L, 0x0000005CL, + 0x10000000L, 0x00000064L, + 0x10000000L, 0x0000006CL, + 0x10000000L, 0x00000074L, + 0x10000000L, 0x0000007CL, + 0x10000000L, 0x00000084L, + 0x10000000L, 0x0000008CL, + 0x10000000L, 0x00000094L, + 0x10000000L, 0x0000009CL, + 0x10000000L, 0x000000A4L, + 0x10000000L, 0x000000ACL, + 0x10000000L, 0x000000B4L, + 0x10000000L, 0x000000BCL, + 0x10000000L, 0x000000C4L, + 0x10000000L, 0x000000CCL, + 0x10000000L, 0x000000D4L, + 0x838B0000L, 0xFFFFFF50L, + 0x878A0000L, 0x00000128L, + 0x80880000L, 0x00000380L, + 0x11000000L, 0x0000004CL, + 0x11000000L, 0x00000054L, + 0x11000000L, 0x0000005CL, + 0x11000000L, 0x00000064L, + 0x11000000L, 0x0000006CL, + 0x11000000L, 0x00000074L, + 0x11000000L, 0x0000007CL, + 0x11000000L, 0x00000084L, + 0x11000000L, 0x0000008CL, + 0x11000000L, 0x00000094L, + 0x11000000L, 0x0000009CL, + 0x11000000L, 0x000000A4L, + 0x11000000L, 0x000000ACL, + 0x11000000L, 0x000000B4L, + 0x11000000L, 0x000000BCL, + 0x11000000L, 0x000000C4L, + 0x11000000L, 0x000000CCL, + 0x11000000L, 0x000000D4L, + 0x838B0000L, 0xFFFFFEA8L, + 0x878A0000L, 0x00000080L, + 0x80880000L, 0x000002D8L, + 0x58000008L, 0x00000000L, + 0x60000040L, 0x00000000L, + 0x86830000L, 0x000002C0L, + 0x1E000000L, 0x0000000CL, + 0x878B0000L, 0x00000018L, + 0x80880000L, 0x000002A8L, + 0x7C09FD00L, 0x00000000L, + 0x60000048L, 0x00000000L, + 0x828B0000L, 0xFFFFFE10L, + 0x8F8A0000L, 0x00000028L, + 0x838A0000L, 0xFFFFFE40L, + 0x818A0000L, 0xFFFFFE20L, + 0x808A0000L, 0xFFFFFE18L, + 0x868A0000L, 0x000001F0L, + 0x80880000L, 0x00000260L, + 0x1F000000L, 0x0000001CL, + 0x808C0000L, 0x000000C8L, + 0x808C0004L, 0x00000098L, + 0x808C0002L, 0x00000038L, + 0x808C0003L, 0x00000078L, + 0x808C0001L, 0x000000D0L, + 0x808C0007L, 0x000001A8L, + 0x80840F80L, 0x00000148L, + 0x60000040L, 0x00000000L, + 0x878B0000L, 0xFFFFFFB0L, + 0x90080000L, 0x00000000L, + 0x60000040L, 0x00000000L, + 0x9F030000L, 0x0000AA01L, + 0x1F000000L, 0x0000001CL, + 0x80840004L, 0x000001E8L, + 0x7C027F00L, 0x00000000L, + 0x7A070100L, 0x00000000L, + 0x60000040L, 0x00000000L, + 0x48000000L, 0x00000000L, + 0x98080000L, 0x0000AA02L, + 0x60000040L, 0x00000000L, + 0x98080000L, 0x0000AA04L, + 0x7C027F00L, 0x00000000L, + 0x7A070100L, 0x00000000L, + 0x60000040L, 0x00000000L, + 0x48000000L, 0x00000000L, + 0x98080000L, 0x0000AA03L, + 0x7C027F00L, 0x00000000L, + 0x7A070100L, 0x00000000L, + 0x60000040L, 0x00000000L, + 0x48000000L, 0x00000000L, + 0x98080000L, 0x0000AA00L, + 0x60000040L, 0x00000000L, + 0x87830000L, 0x00000150L, + 0x1F000000L, 0x0000001CL, + 0x808C0003L, 0x00000038L, + 0x80840002L, 0x00000060L, + 0x60000040L, 0x00000000L, + 0x1F000000L, 0x0000001CL, + 0x80840003L, 0x00000048L, + 0x60000040L, 0x00000000L, + 0x1F000000L, 0x0000001CL, + 0x98080000L, 0x0000AA1CL, + 0x60000040L, 0x00000000L, + 0x1F000000L, 0x0000001CL, + 0x80840001L, 0x00000018L, + 0x60000040L, 0x00000000L, + 0x1F000000L, 0x00000044L, + 0x98080000L, 0x0000AA0CL, + 0x58000008L, 0x00000000L, + 0x60000040L, 0x00000000L, + 0x878B0000L, 0x00000020L, + 0x86020000L, 0x000004C8L, + 0x1E000000L, 0x00000024L, + 0x868B0000L, 0x000000A8L, + 0x80880000L, 0xFFFFFDF8L, + 0x1F000000L, 0x0000001CL, + 0x60000040L, 0x00000000L, + 0x878B0000L, 0xFFFFFFE8L, + 0x80880000L, 0xFFFFFFC0L, + 0x98080000L, 0x0000FF0EL, + 0x58000008L, 0x00000000L, + 0x60000040L, 0x00000000L, + 0x86830000L, 0x00000060L, + 0x1E000000L, 0x0000002CL, + 0x98080000L, 0x0000FF0AL, + 0x54000000L, 0x00000020L, + 0x7C07FE00L, 0x00000000L, + 0x87820000L, 0xFFFFFFF8L, + 0x1F000000L, 0x0000001CL, + 0x98080000L, 0x00000080L, + 0x721A0000L, 0x00000000L, + 0x98080000L, 0x0000AA05L, + 0x47000000L, 0xFFFFFFC0L, + 0x7C07FE00L, 0x00000000L, + 0x80880000L, 0x00000010L, + 0x58000008L, 0x00000000L, + 0x60000040L, 0x00000000L, + 0x9E030000L, 0x0000FF08L, + 0x7C027F00L, 0x00000000L, + 0x1E000000L, 0x0000003CL, + 0x7A070100L, 0x00000000L, + 0x48000000L, 0x00000000L, + 0x98080000L, 0x0000FF07L, + 0x47000000L, 0xFFFFFF68L, + 0x7C07FE00L, 0x00000000L, + 0x9E030000L, 0x0000FF11L, + 0x7C027F00L, 0x00000000L, + 0x1E000000L, 0x00000034L, + 0x7A070100L, 0x00000000L, + 0x48000000L, 0x00000000L, + 0x98080000L, 0x0000FF10L, + 0x60000040L, 0x00000000L, + 0x1F000000L, 0x0000001CL, + 0x98040020L, 0x0000FF0FL, + 0x60000040L, 0x00000000L, + 0x1F000000L, 0x0000001CL, + 0x98080000L, 0x0000AA06L + +}; + +#define A_SCSIMESS_COMMAND_COMPLETE 0x00000000L +#define A_SelectDataOff 0x00000000L +#define A_SCSIMESS_EXTENDED_MESSAGE 0x00000001L +#define A_SCSIMESS_SYNCHRONOUS_DATA_REQ 0x00000001L +#define A_SCSIMESS_SAVE_DATA_POINTER 0x00000002L +#define A_SCSIMESS_WIDE_DATA_REQUEST 0x00000003L +#define A_SCSIMESS_RESTORE_POINTERS 0x00000003L +#define A_SCSIMESS_DISCONNECT 0x00000004L +#define A_CDBDataOff 0x00000004L +#define A_SCSIMESS_MESSAGE_REJECT 0x00000007L +#define A_MsgOutOff 0x0000000CL +#define A_StatusDataOff 0x00000014L +#define A_OneByteMsgOff 0x0000001CL +#define A_SCSIMESS_SIMPLE_QUEUE_TAG 0x00000020L +#define A_RejectMsgOff 0x00000024L +#define A_ParityMsgOff 0x0000002CL +#define A_AbortMsgOff 0x00000034L +#define A_BDRMsgOff 0x0000003CL +#define A_TwoByteMsgOff 0x00000044L +#define A_SGEntry18Off 0x0000004CL +#define A_SGEntry17Off 0x00000054L +#define A_SGEntry16Off 0x0000005CL +#define A_SGEntry15Off 0x00000064L +#define A_SGEntry14Off 0x0000006CL +#define A_SGEntry13Off 0x00000074L +#define A_SGEntry12Off 0x0000007CL +#define A_ReselByTarget 0x00000080L +#define A_SCSIMESS_IDENTIFY 0x00000080L +#define A_SGEntry11Off 0x00000084L +#define A_SGEntry10Off 0x0000008CL +#define A_SGEntry09Off 0x00000094L +#define A_SGEntry08Off 0x0000009CL +#define A_SGEntry07Off 0x000000A4L +#define A_SGEntry06Off 0x000000ACL +#define A_SGEntry05Off 0x000000B4L +#define A_SGEntry04Off 0x000000BCL +#define A_SGEntry03Off 0x000000C4L +#define A_SGEntry02Off 0x000000CCL +#define A_SGEntry01Off 0x000000D4L +#define A_CommandOk 0x0000AA00L +#define A_Save_Pointers 0x0000AA01L +#define A_Save_with_Disc 0x0000AA02L +#define A_Device_Discon 0x0000AA03L +#define A_Restore_Pointers 0x0000AA04L +#define A_ScriptsAborted 0x0000AA05L +#define A_Tag_Received 0x0000AA06L +#define A_SynchNegotComp 0x0000AA0CL +#define A_WideNegotComp 0x0000AA1CL +#define A_DeviceReset 0x0000FF07L +#define A_ResetFailed 0x0000FF08L +#define A_ParityMessageSent 0x0000FF0AL +#define A_MessageRejected 0x0000FF0EL +#define A_InvalidTaggedMessage 0x0000FF0FL +#define A_DeviceAborted 0x0000FF10L +#define A_AbortFailed 0x0000FF11L +#define Ent_AbortExecution 0x000004A0L +#define Ent_AbortDevice 0x00000508L +#define Ent_CommandScriptStart 0x00000000L +#define Ent_ContNegScript 0x000001F0L +#define Ent_DataIn01 0x000001D0L +#define Ent_DataIn18 0x00000148L +#define Ent_DataOut01 0x00000128L +#define Ent_DataOut18 0x000000A0L +#define Ent_DataInJump 0x00000070L +#define Ent_DataOutJump 0x00000078L +#define Ent_ExtMsgRcvd 0x00000368L +#define Ent_EndOfScript 0x00000578L +#define Ent_GetStatus 0x00000088L +#define Ent_MessageIn 0x00000268L +#define Ent_ProcessDisconnect 0x00000318L +#define Ent_ProcessSelectReselect 0x00000488L +#define Ent_QueueTagMessage 0x00000548L +#define Ent_RejectMessage 0x000003F0L +#define Ent_RejectIN 0x00000428L +#define Ent_RejectReceived 0x00000448L +#define Ent_ReselectScript 0x00000478L +#define Ent_ResetDevice 0x000004B0L +#define Ent_RestPtrsRcvd 0x00000308L +#define Ent_RestartScript 0x00000220L +#define Ent_SaveDataPointers 0x000002C0L +#define Ent_SendCommand 0x00000048L +#define Ent_SendErrorMessage 0x00000450L +#define Ent_SendID 0x00000020L +#define Ent_SendReject 0x00000408L +#define Ent_SyncMsgNegot 0x000003C0L + + +ULONG LABELPATCHES[] = { + 0x00000103L +}; + +#define INSTRUCTIONS 0x000000AFL diff --git a/private/ntos/miniport/symbios/symc810/sources b/private/ntos/miniport/symbios/symc810/sources new file mode 100644 index 000000000..df6c3b7ae --- /dev/null +++ b/private/ntos/miniport/symbios/symc810/sources @@ -0,0 +1,39 @@ +!IF 0 +/************************************************************************ +* * +* Copyright 1994 Symbios Logic inc. All rights reserved. * +* * +* This file is confidential and a trade secret of Sybios Corp. * +* The receipt of or possession of this file does not convey any * +* rights to reproduce or disclose its contents or to manufacture, * +* use, or sell anything is may describe, in whole, or in part, * +* without the specific written consent of Symbios Logic Inc. * +* * +************************************************************************/ + +/*+++HDR + * + * Version History + * --------------- + * + * Date Who? Description + * -------- ---- ------------------------------------------------------- + * + * +---*/ +!ENDIF + +MAJORCOMP=ntos +MINORCOMP=miniport + +TARGETNAME=symc810 +TARGETPATH=\nt\public\sdk\lib +TARGETTYPE=DRIVER + +INCLUDES=..\..\..\inc + +TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib + +SOURCES= symc810.c \ + symc810.rc + diff --git a/private/ntos/miniport/symbios/symc810/symc810.c b/private/ntos/miniport/symbios/symc810/symc810.c new file mode 100644 index 000000000..89abf9b23 --- /dev/null +++ b/private/ntos/miniport/symbios/symc810/symc810.c @@ -0,0 +1,9200 @@ +/* +*********************************************************************** +* * +* Copyright 1994 Symbios Logic Inc. All rights reserved. * +* * +* This file is confidential and a trade secret of Sybios Logic Inc. * +* The receipt of or possession of this file does not convey any * +* rights to reproduce or disclose its contents or to manufacture, * +* use, or sell anything is may describe, in whole, or in part, * +* without the specific written consent of Symbios Logic Inc. * +* * +************************************************************************/ + +/*+++HDR + * + * Version History + * --------------- + * + * Date Who? Description + * -------- ---- ------------------------------------------------------- + * 2-23-95 SAM no longer negotiate wide/sync only on LUN 0 + * on reselections we now set the chip to the wide and sync + * parms of the reselecting Target values. + * above changes for 1.02.03 + * + * 3-14-95 SAM incorporated SCAM code to the 1.02.05 base + * + * 3-14-95 SAM incorporated FAST20 Logic into code + * + * 7-7-95 SAM put in support for the 825A and 875 Script Ram buffer. + * Increased burst sizes of all chips to 16 from 8 and for + * the 825A and 875 it is 128. + * Converted to memory mapped IO instead of port IO. + * + * 7-14-95 SAM Incorporated the nvram utilities. Changed the burst length + * to 8 on all chips except the 875 and 825A parts which are + * set to 64. This should allow for better system utilization + * since we will get onto the PCI bus when the fifo is half + * full and not full leaving more room for bus latency. + * For 875/825A parts- do not use the prefetch unit because it + * gives problems when using burst lengths of 64 ( since we're + * using scripts ram on these parts anyway the prefetch unit + * doesn't really buy us a thing) + * + * 4XX BIOS config utility leaves the SCAM Portion of the + * nvram all zeroes. Therefore no work was done on incorp- + * orating the users SCAM ID values onto SCAM devices was done. + * (the structure is still read at this time, nothing done in + * SCAM code though) + * Base for DULUTH 1.92.01 code - initial GCA source base + * + * 7-20-95 SAM made a change so 95 will run with Port IO and NT memory + * mapped. If 95 changed to memory mapped too remember to + * change the scsiportreadPORTuchar call in the de_glitch rtn + * to do REGISTER IO. DULUTH-1.92.02 + * + * 7-21-95 SAM added a parameter fro scam code - initial_run - so the scam + * function will be done all at once on the driver initializa- + * tion pass, and use the system timer calls to split up the + * function during reset processing. change needed because + * with timer calls the driver was holding off the OS during + * its initial bus scan ( waiting for scam to finish ) that it + * would stop looking for device ID 0 and first see devices + * with ID of 1. DULUTH-1.92.03 + * + * 7-25-95 SAM took out the script ram feature for Windows 95, the access- + * ing of the physical memory during Script loading (?) causes + * 95 to bomb. Also changed the device ID to F from f for the + * 875 chip. 95 wants the ID in upper case. + * + * 7-26-95 SAM Well NT wants the ID of the 875 part in lower case, so now + * there is an ifdef around this declaration. + * + * 9-26-95 SAM Added autorequest sense capabilities to the driver. + * + * 1-2-96 SPD 1) PreFetch has been disabled due to chip problems. + * 2) If an unexpected disconnect occurrs during wide/sync + * negotiations, mark the dev. as not supporting wide/sync + * 3) Added a check in ISR_Service_Next to verify the function + * being requested before calling 'StartSCSIRequest'. + * + * 1-23-96 SPD 1) Deleted the bus reset done in SymHWInitialize. In order + * to acheive the same results without doing the reset, we + * will negotiate async/narrow on first I/O to every device + * until the O/S tells us to go Sync and/or Wide. + * 2) Changes to do wide/sync negotiations on same IO. + * 3) Added new conditional compile define 'PORT_IO', replaced + * 'FOR_95' in FinadAdapter routine to determine port or + * memory mapped IO. + * 4) Set/reset DFLAGS QUE_Bit on Reselection for Queueing. + * DULUTH-2.00.04 + * + * 3-15-96 SCH Modified save_reg, restore_reg, & AdapterState to save + * SIOP registers at driver init and restore them at driver + * shutdown. (Used only by Win 95 at shutdown and for + * reboot to MS-DOS mode.) Eliminated setting of HAB SCSI ID + * in FindAdapter (it's done in InitializeSIOP). Also moved + * setting of large FIFO from FindAdapter to InitializeSIOP. + * + * 4-1-96 SPD For Win95, added back in the bus reset at init time. + * In general, added verify for memory mapped addrs, change to + * add device exclusion option, put an entry in the error log + * with ASC/ASCQ values for check conditions. + * + * 4-26-96 SCH Fixed multiple problems with auto request sense routines. + * - Clear SCSI/DMA interrupts (DSTAT,SIST0,SIST1) + * - Added code to handle phase mismatch during reselection + * - Scatter/Gather changed to use proper (current) SRB + * - Changed ReqSnsCmdDoneRtn to use ISR_Service_Next routine + * (scripts were not always being restarted after Req Sns + * Changed ResetSCSIBus to check for valid Srb before using + * LuFlags + * Changed SetupLuFlags to keep WIDE_NEGOT_DONE set after a + * bus reset if wide negotiation had failed + * Fixed problem with hang if bus reset called during auto + * request sense processing + * Added read of SIST1 in AbortScript routine to clear SIP + * bit in ISTAT + * + * 6-10-96 SCH Removed auto request sense routines at Microsoft's + * request. Use ScsiPortWriteRegister routines when using + * Scripts RAM to copy scripts and patch instructions. + * (Alpha Scripts RAM fix.) Added target ID parameter to + * ProcessWideNotSupported (fix blue screen on some bus + * resets). Read SIST1 in AbortCurrentScript. + * +---*/ + +// +// include files used by the Miniport +// +//#define FOR_95 // this define opens up the SCAM protocall code. +//#define PORT_IO // this define specifies port IO for Win95 or Winnt driver. + +#include "miniport.h" +#include "scsi.h" +#include "symc810.h" +#include "scrpt810.h" +#include "symsiop.h" +#include "symnvm.h" + +#ifdef FOR_95 +#include "symscam.h" +#endif + +// +// Define the 53C8xx Logical Unit Extension structure +// + +typedef struct _SPECIFIC_LOGICAL_UNIT_EXTENSION { + PSCSI_REQUEST_BLOCK UntaggedRequest; +} SPECIFIC_LOGICAL_UNIT_EXTENSION, *PSPECIFIC_LOGICAL_UNIT_EXTENSION; + +// +// Define the SRB Extension. +// + +typedef struct _SRB_EXTENSION { + CDB Cdb; + ULONG SavedDataPointer; // saved data pointer and + ULONG SavedDataLength; // length + ULONG DataTransferred; // data transferred so far + UCHAR SGMovesComplete; // # of scatter/gather moves + UCHAR PhysBreakCount; // physical break count +}SRB_EXTENSION, *PSRB_EXTENSION; + + +#define SRB_EXT(x) ((PSRB_EXTENSION)(x->SrbExtension)) + +// +// Symbios 53C8xx script data structure +// + +typedef struct _SCRIPT_DATA_STRUCT { + +// +// Define the Scripts firmware interface structure. +// +// NOTE THAT THIS STRUCTURE MUST BE IN SYNC WITH THE STRUCTURE IN SCRIPTS. +// IF ANYTHING IN THIS STRUCTURE CHANGES, THE EQUIVALENT STRUCTURE +// IN SCRIPTS.ASM MUST ALSO BE CHANGED, SINCE THERE IS NO WAY TO LINK UP THE +// TWO STRUCTURES AUTOMATICALLY. +// + +// +// set up the data table for selection +// + + UCHAR SelectDataRes1; // reserved - MBZ + UCHAR SelectDataSXFER; // Synchronous parameters + UCHAR SelectDataID; // ID to be selected + UCHAR SelectDataSCNTL3; // SCSI Control 3 + +// +// set up the structure for the CDB +// + + ULONG CDBDataCount; // size of CDB + ULONG CDBDataBuff; // pointer to CDB + +// +// set up the structure for the MESSAGE OUT buffer +// + + ULONG MsgOutCount; // number of bytes of MESSAGE OUT data + ULONG MsgOutBuf; // pointer to MESSAGE OUT buffer + +// +// set up the structure for status +// + + ULONG StatusDataCount; // size of STATUS buffer + ULONG StatusDataBuff; // pointer to STATUS buffer + +// +// set up the structure for one-byte messages +// + + ULONG OneByteMsgCount; // size of one-byte message !! + ULONG OneByteMsgBuff; // pointer to message-in buff + +// +// set up the structure for MESSAGE REJECT message +// + + ULONG RejectMsgCount; // size of reject message + ULONG RejectMsgBuff; // pointer to reject message + +// +// set up the structure for parity error message +// + + ULONG ParityMsgCount; // size of parity message + ULONG ParityMsgBuff; // pointer to parity message + +// +// set up the structure for ABORT message +// + + ULONG AbortMsgCount; // size of abort message + ULONG AbortMsgBuff; // pointer to abort message + +// +// set up the structure for the BUS DEVICE RESET message +// + ULONG BDRMsgCount; // size of BDR message + ULONG BDRMsgBuff; // pointer to BDR message + +// +// set up the structure for two-byte messages +// + + ULONG TwoByteMsgCount; // # of bytes in two byte message + ULONG TwoByteMsgBuff; // pointer to two byte message buff + +// +// what follows are the data blocks for each scatter/gather move instruction +// + SCRIPTSG SGBufferArray[ MAX_PHYS_BREAK_COUNT]; + +} SCRIPTDATASTRUCT, *PSCRIPTDATASTRUCT; + +// +// Define the noncached extension. Data items are placed in the noncached +// extension because they are accessed via DMA. +// + +typedef struct _HW_NONCACHED_EXTENSION { + +// +// define the array for the SCSI scripts +// + + SCRIPTINS ScsiScripts[ sizeof(SCRIPT) / sizeof(SCRIPTINS) ]; + +// +// define area for script data structure. +// + + SCRIPTDATASTRUCT ScriptData; // 53C8xx script data structure + +// +// define storage locations for the messages sent by SCSI scripts. +// an element in the script data structure is set up for each of these +// storage locations. +// + + UCHAR MsgOutBuf[MESSAGE_BUFFER_SIZE]; // buffer for message out data + UCHAR MsgInBuf[MESSAGE_BUFFER_SIZE]; // buffer for message in data + UCHAR StatusData; // buffer for status + UCHAR RejectMsgData; // buffer for reject message + UCHAR ParityMsgData; // buffer for parity message + UCHAR AbortMsgData; // buffer for abort message + UCHAR BDRMsgData; // buffer for BDR message + +} HW_NONCACHED_EXTENSION, *PHW_NONCACHED_EXTENSION; + +// +// Define the 53C8xx Device Extension structure +// + +typedef struct _HW_DEVICE_EXTENSION { + + PHW_NONCACHED_EXTENSION NonCachedExtension; // pointer to noncached + // device extension + PSIOP_REGISTER_BASE SIOPRegisterBase; // 53C8xx SIOP register base. + + USHORT DeviceFlags; // bus specific flags + UCHAR SIOPBusID; // SCSI bus ID in integer form. + UCHAR ScsiBusNumber; // This value increments up for each SCSI + // bus on the system, starting with zero. + UCHAR BusNumber; // This value is the bus number for this + // particular SCSI controller. Since all + // current Symbios controllers support only one + // bus, this value is always zero. + +// +// script physical address entry points follow... +// + + ULONG DataOutStartPhys; // phys ptr to data out script + ULONG DataInStartPhys; // phys ptr to data in script + ULONG WaitReselectScriptPhys; // phys ptr to wait resel script + ULONG RestartScriptPhys; // phys ptr to restart script + ULONG ContNegScriptPhys; // phys ptr to continue negotiations script + ULONG CommandScriptPhys; // phys ptr to cmd start script + ULONG SendIDEScriptPhys; // phys ptr to IDE message script + ULONG AbortScriptPhys; // phys ptr to abort message script + ULONG ResetDevScriptPhys; // phys ptr to bus device reset msg script + ULONG RejectScriptPhys; // phys ptr to reject message script + ULONG QueueTagPhys; // phys ptr to queue tag script + ULONG DSAAddress; // phys ptr to script buffer + +// +// Used for script patching +// + PVOID DataInJumpVirt; + PVOID DataOutJumpVirt; + +// +// define depth counter for disconnected requests. we only start the WAIT +// RESELECT script instruction if there are disconnected requests pending. +// + + ULONG DisconnectedCount[SYM_MAX_TARGETS]; + +// +// define pointers to the active logical unit object and request +// + + PSCSI_REQUEST_BLOCK ActiveRequest; // pointer to active LU + PSCSI_REQUEST_BLOCK NextSrbToProcess; // pointer to the next SRB. +// +// logical unit specific flags and logical unit index +// + + USHORT LuFlags[SYM_MAX_TARGETS]; // logical unit spec. flags + UCHAR SyncParms[SYM_MAX_TARGETS]; // synch parameter composite + UCHAR WideParms[SYM_MAX_TARGETS]; // wide parameter composite + UCHAR ClockSpeed; // SIOP clock speed + UCHAR TargetId; + UCHAR LUN; + UCHAR scam_completed; + USHORT hbaCapability; + UCHAR nextstate; + UCHAR current_state; + ULONG timer_value; + +// +// Set up patch array for both data in and data out. Note that +// the array size is larger than the number of scatter/gather +// elements to aid ease of patching. +// + + ULONG dataInPatches[MAX_SG_ELEMENTS + 1]; + ULONG dataOutPatches[MAX_SG_ELEMENTS + 1]; + +// used to hold off system queued cmds to a target that has a contingient +// allegience condition + UCHAR CA_Condition[SYM_MAX_TARGETS][SCSI_MAXIMUM_LOGICAL_UNITS]; + + UCHAR preserved_reg; + +#ifdef FOR_95 +// +// SCAM variables +// + SIOP_REG_STORE AdapStateStore; // SIOP reg storage for AdapterState + SIOP_REG_STORE ScamStore; // SIOP reg storage for SCAM + UCHAR initial_run; + UCHAR checkseen; + UCHAR sna_delay; + UCHAR eatint_flag; + ULONG ID_map; + UINT8 NumValidScamDevices; + SCAM_TABLE ScamTables[HW_MAX_SCAM_DEVICES]; +#endif + + ULONG ScriptRamPhys; + PULONG ScriptRamVirt; + +// extra resources for the nvram values + UINT8 UsersHBAId; + +} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION; + +typedef struct +{ + UCHAR hbaCount; + USHORT hbaCapability; + ULONG hbaDeviceID; +} HWInfo, *PHWInfo; + +// variable used for a loop within the SCAM protocall code + UCHAR i; + +/* The following macros are used to simplify reading of the nvram code. + * + * DATA_MASK - This is the GPREG bit used as a data line. + * CLOCK_MASK - This is the GPREG bit used as a clock line. + */ + +#define DATA_OUTPUT() WRITE_SIOP_UCHAR(GPCNTL,(UCHAR)(READ_SIOP_UCHAR(GPCNTL) \ + & (~DATA_MASK)) ) + +#define DATA_INPUT() WRITE_SIOP_UCHAR(GPCNTL,(UCHAR)(READ_SIOP_UCHAR(GPCNTL) \ + | DATA_MASK) ) + +#define SET_DATA() WRITE_SIOP_UCHAR( GPREG,(UCHAR)(READ_SIOP_UCHAR(GPREG) \ + | DATA_MASK) ) + +#define RESET_DATA() WRITE_SIOP_UCHAR(GPREG,(UCHAR)(READ_SIOP_UCHAR(GPREG) \ + & (~DATA_MASK)) ) + +#define SET_CLOCK() WRITE_SIOP_UCHAR(GPREG,(UCHAR)(READ_SIOP_UCHAR(GPREG) \ + | CLOCK_MASK) ) + +#define RESET_CLOCK() WRITE_SIOP_UCHAR(GPREG,(UCHAR)(READ_SIOP_UCHAR(GPREG) \ + & (~CLOCK_MASK)) ) + +// +// Symbios 53C8xx miniport driver function declarations. +// + +BOOLEAN NvmDetect( PHW_DEVICE_EXTENSION DeviceExtension ); +void NvmSendStop( PHW_DEVICE_EXTENSION DeviceExtension ); +void NvmSendStart( PHW_DEVICE_EXTENSION DeviceExtension ); +UINT NvmSendData( PHW_DEVICE_EXTENSION DeviceExtension, UINT Value ); +UINT8 NvmReadData( PHW_DEVICE_EXTENSION DeviceExtension ); +void NvmSendAck( PHW_DEVICE_EXTENSION DeviceExtension ); +UINT NvmReceiveAck( PHW_DEVICE_EXTENSION DeviceExtension ); +void NvmSendNoAck( PHW_DEVICE_EXTENSION DeviceExtension); + +MEMORY_STATUS HwReadNonVolatileMemory( PHW_DEVICE_EXTENSION DeviceExtension, + UINT8 *Buffer, + UINT Offset, UINT Length ); + +UINT16 CalculateCheckSum(UINT8 * PNvmData, UINT16 Length); +BOOLEAN RetrieveNvmData( PHW_DEVICE_EXTENSION DeviceExtension); +void InvalidateNvmData( PHW_DEVICE_EXTENSION DeviceExtension ); +UCHAR set_8xx_clock(PHW_DEVICE_EXTENSION DeviceExtension); +UCHAR set_875_multipler( PHW_DEVICE_EXTENSION DeviceExtension ); + + +#ifdef FOR_95 +VOID scam_scan(PHW_DEVICE_EXTENSION DeviceExtension); +UCHAR EatInts(PHW_DEVICE_EXTENSION DeviceExtension); +VOID EnterLLM(PHW_DEVICE_EXTENSION DeviceExtension); +VOID ExitLLM(PHW_DEVICE_EXTENSION DeviceExtension); +VOID init_send_byte(LONG dbyte,PHW_DEVICE_EXTENSION DeviceExtension); +UCHAR init_recv_byte(PHW_DEVICE_EXTENSION DeviceExtension); +VOID SCAM_Arbitrate(PHW_DEVICE_EXTENSION DeviceExtension); +VOID SCAM_release(PHW_DEVICE_EXTENSION DeviceExtension); +VOID SCAM_master_select(PHW_DEVICE_EXTENSION DeviceExtension); +UCHAR SCAM_xfer(UCHAR quintet,PHW_DEVICE_EXTENSION DeviceExtension); +LONG SCAM_isolate(UCHAR *outstr, UCHAR *instr, UCHAR *greatest_ID, + UCHAR *desired_ID, UCHAR function, + PHW_DEVICE_EXTENSION DeviceExtension); +VOID SCAM_assign_IDs(PHW_DEVICE_EXTENSION DeviceExtension); +VOID Find_nonSCAM_IDs(PHW_DEVICE_EXTENSION DeviceExtension); +VOID restore_reg (PHW_DEVICE_EXTENSION DeviceExtension, + PSIOP_REG_STORE RegStore); +VOID save_reg (PHW_DEVICE_EXTENSION DeviceExtension, + PSIOP_REG_STORE RegStore); +VOID ISR_Service_Next(PHW_DEVICE_EXTENSION DeviceExtension, + UCHAR ISRDisposition); +VOID de_glitch(ULONG offset,UCHAR value,PHW_DEVICE_EXTENSION DeviceExtension); +void delay_mils( USHORT counter); +#endif + +BOOLEAN +AbortCurrentScript( + IN PHW_DEVICE_EXTENSION DeviceExtension + ); + +VOID +BusResetPostProcess( + IN PHW_DEVICE_EXTENSION DeviceExtension + ); + +VOID +clear_CA_Condition( + IN PHW_DEVICE_EXTENSION DeviceExtension + ); + +VOID +ComputeSCSIScriptVectors( + IN PHW_DEVICE_EXTENSION DeviceExtension + ); + +ULONG +DriverEntry( + IN PVOID DriverObject, + IN PVOID Argument2 + ); + +VOID +InitializeSIOP( + IN PHW_DEVICE_EXTENSION DeviceExtension + ); + +BOOLEAN +IsCompaqSystem( + IN PVOID DeviceExtension, + IN PPORT_CONFIGURATION_INFORMATION ConfigInfo + ); + +BOOLEAN +Sym8xxAdapterState( + IN PVOID Context, + IN PVOID ConfigContext, + IN BOOLEAN SaveState + ); + +ULONG +Sym8xxFindAdapter( + PVOID Context, + PVOID ConfigContext, + IN PVOID BusInformation, + IN PCHAR ArgumentString, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + OUT PBOOLEAN Again + ); + +BOOLEAN +Sym8xxHWInitialize( + IN PVOID Context + ); + +BOOLEAN +Sym8xxISR( + IN PVOID Context + ); + +BOOLEAN +Sym8xxReset( + IN PVOID DeviceExtension, + IN ULONG PathId + ); + +BOOLEAN +Sym8xxStartIo( + IN PVOID Context, + IN PSCSI_REQUEST_BLOCK Srb + ); + +UCHAR +ProcessAbortOccurred( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessBusResetReceived( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessCommandComplete( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessDeviceResetFailed( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessDeviceResetOccurred( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessDisconnect( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessDMAInterrupt( + PHW_DEVICE_EXTENSION DeviceExtension, + UCHAR DmaStatus + ); + +UCHAR +ProcessErrorMsgSent( + VOID + ); + +UCHAR +ProcessGrossError( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessIllegalInstruction( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessInvalidReselect( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessParityError( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessPhaseMismatch( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +BOOLEAN +ProcessParseArgumentString( + PCHAR String, + PCHAR WantedString, + PULONG ValueWanted + ); + +UCHAR +ProcessQueueTagReceived( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessRejectReceived( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessReselection( + PHW_DEVICE_EXTENSION DeviceExtension, + UCHAR TargetID + ); + +UCHAR +ProcessRestorePointers( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessSaveDataPointers( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessSCSIInterrupt( + PHW_DEVICE_EXTENSION DeviceExtension, + UCHAR ScsiStatus + ); + +UCHAR +ProcessSelectionTimeout( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessSynchNegotComplete( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessSynchNotSupported( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +UCHAR +ProcessUnexpectedDisconnect( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +VOID +ResetPeripheral( + IN PHW_DEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ); + +VOID +ResetSCSIBus( + IN PHW_DEVICE_EXTENSION DeviceExtension + ); + +VOID +ScatterGatherScriptSetup( + IN PHW_DEVICE_EXTENSION DeviceExtension, + IN PSRB_EXTENSION SrbExtension + ); + +VOID +SetupLuFlags( + IN PHW_DEVICE_EXTENSION DeviceExtension, + IN UCHAR ResetFlag + ); + +UCHAR +ProcessWideNotSupported( + PHW_DEVICE_EXTENSION DeviceExtension, + UCHAR DestId + ); + +UCHAR +ProcessWideNegotComplete( + PHW_DEVICE_EXTENSION DeviceExtension + ); + +VOID +StartSCSIRequest( + PSCSI_REQUEST_BLOCK Srb, + PHW_DEVICE_EXTENSION DeviceExtension + ); + +VOID +StartSIOP( + IN PHW_DEVICE_EXTENSION DeviceExtension, + IN ULONG ScriptPhysAddr + ); + + +BOOLEAN +AbortCurrentScript( + IN PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + + This routine aborts the script instruction currently processing, + and clears the SCRIPT_RUNNING flag after scripts have stopped. + +Arguments: + + DeviceExtension - Supplies the device Extension for the SCSI bus adapter. + +Return Value: + + True - abort sucessful + False - abort unsucessful + +--*/ + +{ + UCHAR IntStat; + UCHAR AbortIteration = 0; + +AbortScript: + + // + // set script abort bit high + // + + WRITE_SIOP_UCHAR( ISTAT, ISTAT_ABORT); + + // + // spin for an interrupt (either DMA or SCSI) + // + + do + { + IntStat = READ_SIOP_UCHAR( ISTAT); + + // + // if we are in the second or greater iteration of this loop.. + // + + if (AbortIteration++) + { + + // + // wait a moment + // + + ScsiPortStallExecution( ABORT_STALL_TIME); + + // + // if we have exceeded our maximum loop count, we reset the + // SIOP and SCSI bus in hopes that whatever has freaked the + // SIOP out will be corrected. + // + + if (AbortIteration > MAX_ABORT_TRIES) + { + + DebugPrint((1, + "Sym8xx(%2x): AbortCurrentScript timeout - ISTAT = %x\n", + DeviceExtension->SIOPRegisterBase, + IntStat)); + + // If can't get DMA_INT bit to set, assume that abort of script + // worked and break to check DSTAT for abort bit below. If not + // set, will loop to restart abort sequence again + break; + + } // if + } // if + } while ( !( IntStat & ( ISTAT_SCSI_INT | ISTAT_DMA_INT))); + + if ( IntStat & ISTAT_SCSI_INT) + { + + // + // Note that we ignore any SCSI interrupts at this time, + // since no SCSI error should occur in this section of + // code. We make this assumption since nothing was + // connected to the bus when this path was entered, and + // interrupts are synchronized, so the only thing a device + // could have done at this point is reselected. + // + + // + // read SCSI interrupts to clear ISTAT. + // + + READ_SIOP_UCHAR(SIST0); + READ_SIOP_UCHAR(SIST1); + + // + // go back to abort + // + + goto AbortScript; + } // if + + // + // A DMA interrupt has occured. + // + // Note that we ignore any DMA interrupts other than ABORTED + // at this time, since no DMA error should occur in this section + // of code. We make this assumption since nothing was connected + // to the bus when this path was entered, and interrupts are + // synchronized, so the only thing a device could have done + // at this point is reselected. + // + + // + // clear the ABORT bit in ISTAT. + // + + WRITE_SIOP_UCHAR( ISTAT, 0); + + // + // if interrupt was not ABORT, just go back to try to abort again. + // + + if ( !( READ_SIOP_UCHAR( DSTAT) & DSTAT_ABORTED)) + { + goto AbortScript; + } + + // + // We have now successfully aborted script execution, so indicate + // that scripts have stopped. + // + + DeviceExtension->DeviceFlags &= ~DFLAGS_SCRIPT_RUNNING; + + // + // write script buffer start address to DSA register. + // + + WRITE_SIOP_ULONG( DSA, DeviceExtension->DSAAddress); + + return TRUE; + +} // AbortCurrentScript + + +VOID +BusResetPostProcess( + IN PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine aborts any pending requests after a bus reset is received. + +Arguments: + + DeviceExtension - Supplies a pointer to device extension for the bus that + was reset. + +Return Value: + + None. + +--*/ + +{ + USHORT i; + UCHAR max_targets; + + + // + // Prepare the LU Flags for work. + // + + SetupLuFlags( DeviceExtension, 1 ); + + // + // indicate no pending requests (these guys will be aborted below). + // + + DeviceExtension->NextSrbToProcess = NULL; + + DeviceExtension->ActiveRequest = NULL; + + // clear the Contigent Allegience blocker + clear_CA_Condition(DeviceExtension); + + // + // Complete all requests outstanding on this SCSI bus with + // SRB_STATUS_BUS_RESET completion code. + // + + ScsiPortCompleteRequest( DeviceExtension, + DeviceExtension->BusNumber, + SP_UNTAGGED, + SP_UNTAGGED, + SRB_STATUS_BUS_RESET + ); + + // + // zero depth counter for disconnected requests + // + + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE) + { + max_targets = SYM_MAX_TARGETS; + } + else + { + max_targets = SYM_NARROW_MAX_TARGETS; + } + + for ( i = 0; i < max_targets; i++ ) + DeviceExtension->DisconnectedCount[i] = 0; + + DeviceExtension->DeviceFlags &= ~DFLAGS_CONNECTED; + +#ifdef FOR_95 + // set up flags for the SCAM code to work from + // only do SCAM if Single Ended + // if this is the scam run from our init code, do it straight away + // without the delay call of the OS + // + if ( !(READ_SIOP_UCHAR(STEST2) & STEST2_DIFF_MODE) ) + { + if (DeviceExtension->initial_run) + { + scam_scan(DeviceExtension); + } + else + { + DeviceExtension->current_state=TRUE; + DeviceExtension->scam_completed=FALSE; + DebugPrint((0, "Sym8xx: Begin TimerCall... \n")); + + ScsiPortNotification(RequestTimerCall, + DeviceExtension, + scam_scan, + 1000); + + DebugPrint((0, "Sym8xx: Exiting BusResetPostProcess... \n")); + } + } + else + { + if ( !(DeviceExtension->DeviceFlags & DFLAGS_WORK_REQUESTED)) + { + DeviceExtension->DeviceFlags |= DFLAGS_WORK_REQUESTED; + + ScsiPortNotification(NextRequest, + DeviceExtension, + NULL + ); + } + + ScsiPortStallExecution( POST_RESET_STALL_TIME ); + DeviceExtension->scam_completed=TRUE; + } + +#else + if ( !(DeviceExtension->DeviceFlags & DFLAGS_WORK_REQUESTED)) + { + DeviceExtension->DeviceFlags |= DFLAGS_WORK_REQUESTED; + + ScsiPortNotification( NextRequest, + DeviceExtension, + NULL + ); + } + + ScsiPortStallExecution( POST_RESET_STALL_TIME ); + DeviceExtension->scam_completed=TRUE; +#endif + + return; + +} // BusResetPostProcess + + +VOID +clear_CA_Condition( + IN PHW_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This routine clears the Contingent Allegience blocking array. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + UCHAR target, lun; + + for (target = 0; target < SYM_MAX_TARGETS; target++) + { + for (lun = 0; lun < SCSI_MAXIMUM_LOGICAL_UNITS; lun++) + DeviceExtension->CA_Condition[target][lun] = 0; + } +} + +VOID +ComputeSCSIScriptVectors( + IN PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine computes 53C8xx script physical addresses, and fills in + device extension fields used by scripts. + +Arguments: + + PHW_DEVICE_EXTENSION DeviceExtension + +Return Value: + + None. + +--*/ + +{ + ULONG SegmentLength; // receives length of physical memory segment + + PHW_NONCACHED_EXTENSION NonCachedExtPtr = + DeviceExtension->NonCachedExtension; + PSCRIPTDATASTRUCT ScriptDataPtr = + &DeviceExtension->NonCachedExtension->ScriptData; + PULONG ScriptArrayPtr; + + // Added for SCRIPT patching. + + PULONG dataInPatches = &DeviceExtension->dataInPatches[0]; + PULONG dataOutPatches = &DeviceExtension->dataOutPatches[0]; + ULONG patchInOffset; + ULONG patchOutOffset; + USHORT i; + + // + // make local copy of scripts in device extension. Total copy size + // is # of instructions * (8 bytes / instruction). + // + + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_SCRIPT_RAM) + { + ScriptArrayPtr = DeviceExtension->ScriptRamVirt; + } + else + { + ScriptArrayPtr=(PULONG) DeviceExtension->NonCachedExtension->ScsiScripts; + } + + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_SCRIPT_RAM) + { + ScsiPortWriteRegisterBufferUchar((PUCHAR)ScriptArrayPtr, + (PUCHAR)SCRIPT, + INSTRUCTIONS * sizeof (SCRIPTINS)); + } + else + { + ScsiPortMoveMemory( ScriptArrayPtr, + SCRIPT, + INSTRUCTIONS * sizeof(SCRIPTINS) + ); + } + + // + // the following code computes physical addresses of script entry points. + // note that the "Ent_..." constants are generated by the scripts + // compiler, and are byte indices into the script instruction array. + // we divide these constants by 4 to correctly index into the array, + // since each array element consists of a longword. + // + + // + // compute command script start physical address + // + if ( !(DeviceExtension->hbaCapability & HBA_CAPABILITY_SCRIPT_RAM) ) + { + DeviceExtension->CommandScriptPhys = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &ScriptArrayPtr[ Ent_CommandScriptStart / 4], + &SegmentLength + )); + + + // + // compute data in script physical address + // + + DeviceExtension->DataInStartPhys = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &ScriptArrayPtr[ Ent_DataIn01 / 4], + &SegmentLength + )); + + // + // compute data out script physical address + // + + DeviceExtension->DataOutStartPhys = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &ScriptArrayPtr[ Ent_DataOut01 / 4], + &SegmentLength + )); + + // + // compute restart after reselection script phys address + // + + DeviceExtension->RestartScriptPhys = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &ScriptArrayPtr[ Ent_RestartScript / 4], + &SegmentLength + )); + + // + // compute continue negotiation script phys address + // + + DeviceExtension->ContNegScriptPhys = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &ScriptArrayPtr[ Ent_ContNegScript / 4], + &SegmentLength + )); + + // + // compute script send abort script phys address + // + + DeviceExtension->AbortScriptPhys = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &ScriptArrayPtr[ Ent_AbortDevice / 4], + &SegmentLength + )); + + // + // compute script send bus device reset script phys address + // + + DeviceExtension->ResetDevScriptPhys = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &ScriptArrayPtr[ Ent_ResetDevice / 4], + &SegmentLength + )); + + // + // compute reject message script phys address + // + + DeviceExtension->RejectScriptPhys = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &ScriptArrayPtr[ Ent_RejectMessage / 4], + &SegmentLength + )); + + // + // compute wait for reselect script phys address + // + + DeviceExtension->WaitReselectScriptPhys = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &ScriptArrayPtr[ Ent_ReselectScript / 4], + &SegmentLength + )); + + // + // compute wait for queue tag phys address + // + + DeviceExtension->QueueTagPhys = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &ScriptArrayPtr[ Ent_QueueTagMessage / 4], + &SegmentLength + )); + + // + // Compute the IDE (Initiatior Detected Error)/MPE (Message Parity Error) + // message script routine phys address + // + + DeviceExtension->SendIDEScriptPhys = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &ScriptArrayPtr[ Ent_SendErrorMessage / 4], + &SegmentLength + )); + + } + + else + { + + DeviceExtension->CommandScriptPhys = + DeviceExtension->ScriptRamPhys + + ( &ScriptArrayPtr[Ent_CommandScriptStart] - ScriptArrayPtr ); + + DeviceExtension->DataInStartPhys = + DeviceExtension->ScriptRamPhys + + ( &ScriptArrayPtr[Ent_DataIn01] - ScriptArrayPtr ); + + DeviceExtension->DataOutStartPhys = + DeviceExtension->ScriptRamPhys + + ( &ScriptArrayPtr[Ent_DataOut01] - ScriptArrayPtr ); + + DeviceExtension->RestartScriptPhys = + DeviceExtension->ScriptRamPhys + + ( &ScriptArrayPtr[Ent_RestartScript] - ScriptArrayPtr ); + + DeviceExtension->ContNegScriptPhys = + DeviceExtension->ScriptRamPhys + + ( &ScriptArrayPtr[Ent_ContNegScript] - ScriptArrayPtr ); + + DeviceExtension->AbortScriptPhys = + DeviceExtension->ScriptRamPhys + + ( &ScriptArrayPtr[Ent_AbortDevice] - ScriptArrayPtr ); + + DeviceExtension->ResetDevScriptPhys = + DeviceExtension->ScriptRamPhys + + ( &ScriptArrayPtr[Ent_ResetDevice] - ScriptArrayPtr ); + + DeviceExtension->RejectScriptPhys = + DeviceExtension->ScriptRamPhys + + ( &ScriptArrayPtr[Ent_RejectMessage] - ScriptArrayPtr ); + + DeviceExtension->WaitReselectScriptPhys = + DeviceExtension->ScriptRamPhys + + ( &ScriptArrayPtr[Ent_ReselectScript] - ScriptArrayPtr ); + + DeviceExtension->QueueTagPhys = + DeviceExtension->ScriptRamPhys + + ( &ScriptArrayPtr[Ent_QueueTagMessage] - ScriptArrayPtr ); + + DeviceExtension->SendIDEScriptPhys = + DeviceExtension->ScriptRamPhys + + ( &ScriptArrayPtr[Ent_SendErrorMessage] - ScriptArrayPtr ); + } + + + // + // Compute the patch address for the Data-In routine. Note that this + // is a virtual address. + // + + DeviceExtension->DataInJumpVirt = + (PVOID) &ScriptArrayPtr[ Ent_DataInJump / 4]; + + // + // Compute the patch address for the Data-Out routine. Note that this + // is a virtual address. + // + + DeviceExtension->DataOutJumpVirt = + (PVOID) &ScriptArrayPtr[ Ent_DataOutJump / 4]; + + // + // Set up first Data-In offset patch value. + // + + patchInOffset = Ent_DataIn18 - Ent_DataInJump - SCRIPT_INS_SIZE; + + // + // Set up first Data-Out offset patch value. + // + + patchOutOffset = Ent_DataOut18 - Ent_DataOutJump - SCRIPT_INS_SIZE; + + // + // Fill in offset table for Data In and Data Out patches. Note that + // the offset for a list of 7 segments will be in table entry 7. Entry + // zero will be unused. + // + + for ( i = MAX_SG_ELEMENTS; i > 0; i-- ) + { + dataInPatches[i] = patchInOffset; + dataOutPatches[i] = patchOutOffset; + patchInOffset += 8; + patchOutOffset += 8; + } + + // + // Flag the zero element to aid in debugging. + // + + dataInPatches[0] = 0xFACEBEAD; + dataOutPatches[0] = 0xFACEBEAD; + + // + // fill in script structures required for table indirect script mode + // (see 53C8xx data manual fo details) + // + + ScriptDataPtr->MsgOutCount = 0; // no message out bytes + ScriptDataPtr->StatusDataCount = 1; // STATUS buf is 1 byte + ScriptDataPtr->OneByteMsgCount = 1; // 1 byte messages + ScriptDataPtr->TwoByteMsgCount = 2; // 2 byte messages + ScriptDataPtr->RejectMsgCount = 1; // Reject msg is 1 byte + ScriptDataPtr->ParityMsgCount = 1; // Parity msg is 1 byte + ScriptDataPtr->AbortMsgCount = 1; // Abort msg is 1 byte + ScriptDataPtr->BDRMsgCount = 1; // BDR msg is 1 byte + + // + // Initialize reject message buffer + // + + NonCachedExtPtr->RejectMsgData = SCSIMESS_MESSAGE_REJECT; + + // + // Initialize parity message buffer + // + + NonCachedExtPtr->ParityMsgData = SCSIMESS_INIT_DETECTED_ERROR; + + // + // Initialize abort message buffer + // + + NonCachedExtPtr->AbortMsgData = SCSIMESS_ABORT; + + // + // Initialize bus device reset message buffer + // + + NonCachedExtPtr->BDRMsgData = SCSIMESS_BUS_DEVICE_RESET; + + // + // the following code initializes physical pointers to the data bytes + // and buffers filled in above + // + + // + // set up MESSAGE OUT buffer pointer + // + + ScriptDataPtr->MsgOutBuf = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) NonCachedExtPtr->MsgOutBuf, + &SegmentLength + )); + + // + // set up one byte message ptr + // + + ScriptDataPtr->OneByteMsgBuff = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) NonCachedExtPtr->MsgInBuf, + &SegmentLength + )); + + // + // set up two byte message ptr + // + + ScriptDataPtr->TwoByteMsgBuff = ScriptDataPtr->OneByteMsgBuff; + + // + // set up status buffer ptr + // + + ScriptDataPtr->StatusDataBuff = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &NonCachedExtPtr->StatusData, + &SegmentLength + )); + + // + // set up reject message ptr + // + + ScriptDataPtr->RejectMsgBuff = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &NonCachedExtPtr->RejectMsgData, + &SegmentLength + )); + + // + // set up Initiator Detected Error (IDE) message ptr + // + + ScriptDataPtr->ParityMsgBuff = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &NonCachedExtPtr->ParityMsgData, + &SegmentLength + )); + + // + // set up ABORT message ptr + // + + ScriptDataPtr->AbortMsgBuff = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &NonCachedExtPtr->AbortMsgData, + &SegmentLength + )); + + // + // set up BUS DEVICE RESET message ptr + // + + ScriptDataPtr->BDRMsgBuff = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &NonCachedExtPtr->BDRMsgData, + &SegmentLength + )); + + // + // compute physical address of script data buffer start point + // + + DeviceExtension->DSAAddress = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) &NonCachedExtPtr->ScriptData, + &SegmentLength + )); + +} // ComputeSCSIScriptVectors + + +ULONG +DriverEntry( + IN PVOID DriverObject, + IN PVOID Argument2 + ) +/****************************************************************************** + +Routine Description: + + Initial entry point for Symbios 53C8xx miniport driver. + +Arguments: + + Driver Object + +Return Value: + + Status indicating whether adapter(s) were found and initialized. + +--*/ + +{ + HW_INITIALIZATION_DATA hwInitializationData; + ULONG pciStatus810; + ULONG pciStatus810A; + ULONG pciStatus815; + ULONG pciStatus820; + ULONG pciStatus825; + ULONG pciStatus825A; + ULONG pciStatus860; + ULONG pciStatus875; + ULONG retValue1; + ULONG retValue2; + ULONG retValue3; + ULONG retValue4; + ULONG i; + UCHAR vendorId[4] = {'1', '0', '0', '0'}; + UCHAR deviceId[4] = {'0', '0', '0', '0'}; + + HWInfo hwInfo; + + DebugPrint((1, "\nSymbios 53c8XX SCSI Miniport Driver.\n\n")); + + // + // Initialize the hardware initialization data structure. + // + + for ( i = 0; i < sizeof( HW_INITIALIZATION_DATA); i++) + { + ((PUCHAR)&hwInitializationData)[i] = 0; + } + + // + // Set size of hardware initialization structure. + // + + hwInitializationData.HwInitializationDataSize = + sizeof(HW_INITIALIZATION_DATA); + + // + // Identify required miniport entry point routines. + // + + hwInitializationData.HwInitialize = Sym8xxHWInitialize; + hwInitializationData.HwStartIo = Sym8xxStartIo; + hwInitializationData.HwInterrupt = Sym8xxISR; + hwInitializationData.HwFindAdapter = Sym8xxFindAdapter; + hwInitializationData.HwResetBus = Sym8xxReset; + hwInitializationData.HwAdapterState = Sym8xxAdapterState; + + // + // Specifiy adapter specific information. + // + + hwInitializationData.NeedPhysicalAddresses = TRUE; + hwInitializationData.NumberOfAccessRanges = 3; + hwInitializationData.AdapterInterfaceType = PCIBus; + hwInitializationData.VendorId = &vendorId; + hwInitializationData.VendorIdLength = 4; + hwInitializationData.DeviceId = &deviceId; + hwInitializationData.DeviceIdLength = 4; + + // + // Set required extension sizes. + // + + hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION); + hwInitializationData.SrbExtensionSize = sizeof(SRB_EXTENSION); + hwInitializationData.SpecificLuExtensionSize = + sizeof(SPECIFIC_LOGICAL_UNIT_EXTENSION); + + // + // Initialize the driver configuration information. + // + + hwInfo.hbaCount = 0; + hwInfo.hbaCapability = 0; + + // + // Check for the SymC810. + // + + deviceId[3] = '1'; + hwInfo.hbaDeviceID = 0x01; + hwInfo.hbaCapability |= HBA_CAPABILITY_810_FAMILY; + + pciStatus810 = ScsiPortInitialize( DriverObject, + Argument2, + &hwInitializationData, + &hwInfo); + + // + // Check for the SymC820. + // + + deviceId[3] = '2'; + hwInfo.hbaDeviceID = 0x02; + hwInfo.hbaCapability = 0; + hwInfo.hbaCapability |= HBA_CAPABILITY_WIDE; + hwInfo.hbaCapability |= HBA_CAPABILITY_DIFFERENTIAL; + + pciStatus820 = ScsiPortInitialize( DriverObject, + Argument2, + &hwInitializationData, + &hwInfo); + + // + // Check for the SymC825. + // + + deviceId[3] = '3'; + hwInfo.hbaDeviceID = 0x03; + hwInfo.hbaCapability = 0; + hwInfo.hbaCapability |= HBA_CAPABILITY_WIDE; + hwInfo.hbaCapability |= HBA_CAPABILITY_DIFFERENTIAL; + hwInfo.hbaCapability |= HBA_CAPABILITY_825_FAMILY; + // testing purposes only -> + // hwInfo.hbaCapability |= HBA_CAPABILITY_FAST20; + + pciStatus825 = ScsiPortInitialize( DriverObject, + Argument2, + &hwInitializationData, + &hwInfo); + + // + // Check for the SYMC815. + // + + deviceId[3] = '4'; + hwInfo.hbaDeviceID = 0x04; + hwInfo.hbaCapability = 0; + + pciStatus815 = ScsiPortInitialize( DriverObject, + Argument2, + &hwInitializationData, + &hwInfo); + + // + // Check for the SYMC810A. + // + + deviceId[3] = '5'; + hwInfo.hbaDeviceID = 0x05; + hwInfo.hbaCapability = 0; + + pciStatus810A = ScsiPortInitialize( DriverObject, + Argument2, + &hwInitializationData, + &hwInfo); + + // + // Check for the SYMC860. + // + + deviceId[3] = '6'; + hwInfo.hbaDeviceID = 0x06; + hwInfo.hbaCapability = 0; + hwInfo.hbaCapability |= HBA_CAPABILITY_FAST20; + + pciStatus860 = ScsiPortInitialize( DriverObject, + Argument2, + &hwInitializationData, + &hwInfo); + + // + // Check for the SYMC825A. + // + + deviceId[3] = 'E'; + hwInfo.hbaDeviceID = 0x0E; + hwInfo.hbaCapability = 0; + hwInfo.hbaCapability |= HBA_CAPABILITY_WIDE; + hwInfo.hbaCapability |= HBA_CAPABILITY_DIFFERENTIAL; + hwInfo.hbaCapability |= HBA_CAPABILITY_875_LARGE_FIFO; + hwInfo.hbaCapability |= HBA_CAPABILITY_SYNC_16; + +#ifndef FOR_95 + hwInfo.hbaCapability |= HBA_CAPABILITY_SCRIPT_RAM; +#endif + + + pciStatus825A = ScsiPortInitialize( DriverObject, + Argument2, + &hwInitializationData, + &hwInfo); + // + // Check for the SYMC875, + // + +#ifdef FOR_95 + deviceId[3] = 'F'; +#else + deviceId[3] = 'f'; +#endif + + hwInfo.hbaDeviceID = 0x0F; + hwInfo.hbaCapability = 0; + hwInfo.hbaCapability |= HBA_CAPABILITY_WIDE; + hwInfo.hbaCapability |= HBA_CAPABILITY_DIFFERENTIAL; + hwInfo.hbaCapability |= HBA_CAPABILITY_SYNC_16; + hwInfo.hbaCapability |= HBA_CAPABILITY_FAST20; + hwInfo.hbaCapability |= HBA_CAPABILITY_875_LARGE_FIFO; + hwInfo.hbaCapability |= HBA_CAPABILITY_875_FAMILY; + +#ifndef FOR_95 + hwInfo.hbaCapability |= HBA_CAPABILITY_SCRIPT_RAM; +#endif + + pciStatus875 = ScsiPortInitialize( DriverObject, + Argument2, + &hwInitializationData, + &hwInfo); + + + // + // Return the smaller status. + // + retValue1 = (pciStatus810 < pciStatus820 ? pciStatus810 : pciStatus820); + retValue2 = (pciStatus825 < pciStatus815 ? pciStatus825 : pciStatus815); + retValue3 = (pciStatus810A < pciStatus860 ? pciStatus810A : pciStatus860); + retValue4 = (pciStatus825A < pciStatus875 ? pciStatus825A : pciStatus875); + + retValue1 = (retValue1 < retValue2 ? retValue1 : retValue2); + retValue2 = (retValue3 < retValue4 ? retValue3 : retValue4); + + return(retValue1 < retValue2 ? retValue1 : retValue2); + +} // end DriverEntry() + + +VOID +InitializeSIOP( + IN PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This function initializes the Symbios SCSI adapter chip. Presently, we do + not reset the SIOP, although this may be necessary in the future. Resetting + the SIOP will clear all of the chip registers, making it impossible to + execute BIOS calls for disk access (SETUP makes BIOS calls after loading + the driver). + +Arguments: + + DeviceExtension - Pointer to the specific device extension for this SCSI + bus. + +Return Value: + + NONE + +--*/ + +{ + UCHAR HbaId = 0; + UCHAR max_targets; + UCHAR scntl3Value = 0; + USHORT i; + BOOLEAN needChipReset = FALSE; + + // + // Clear (not flush) the DMA FIFO in case something left over. + // + + WRITE_SIOP_UCHAR( CTEST3, 0x04 ); + + // + // Wait for the DMA FIFO to clear. + // + + for ( i = 0; i < MAX_CLEAR_FIFO_LOOP; i++ ) + { + ScsiPortStallExecution( CLEAR_FIFO_STALL_TIME ); + + // + // Check if the clear bit reset itself. + // + + if (!(READ_SIOP_UCHAR( CTEST3 ) & 0x04)) + break; + } + + // + // If the DMA FIFO did not clear, we will have to reset the chip. + // + + if ( !(READ_SIOP_UCHAR( DSTAT ) & 0x80) ) + { + needChipReset = TRUE; + + DebugPrint((3, "Sym8xx(%2x): DMA FIFO not cleared... Need chip reset \n", + DeviceExtension->SIOPRegisterBase + )); + } + + // + // Clear (not flush) the SCSI FIFO in case something left over. + // + + WRITE_SIOP_UCHAR( STEST3, 0x02 ); + + // + // Wait for the SCSI FIFO to clear. + // + + for ( i = 0; i < MAX_CLEAR_FIFO_LOOP; i++ ) + { + ScsiPortStallExecution( CLEAR_FIFO_STALL_TIME ); + + // + // Check if the clear bit reset itself. + // + + if ( !(READ_SIOP_UCHAR( STEST3 ) & 0x02) ) + break; + } + + // + // If the SCSI FIFO did not clear, we will have to reset the chip. + // + + if ( READ_SIOP_UCHAR( STEST3 ) & 0x02 ) + { + needChipReset = TRUE; + + DebugPrint((3, + "Sym8xx(%2x): SCSI FIFO not cleared... Need chip reset \n", + DeviceExtension->SIOPRegisterBase + )); + } + + if ( needChipReset ) + { + DebugPrint((3, "Sym8xx(%2x): Resetting chip now... \n", + DeviceExtension->SIOPRegisterBase )); + +#ifdef _MIPS_ + + // + // Preserve GPCNTL contents for SNI PCI boxes + // which set bit 7 to 1 to get internal bus + // master signal on GPIO1 to drive a LED + // + + DeviceExtension->preserved_reg = READ_SIOP_UCHAR(GPCNTL); +#endif + WRITE_SIOP_UCHAR( ISTAT, 0x40 ); + + for ( i = 0; i < MAX_CLEAR_FIFO_LOOP; i++ ) + { + ScsiPortStallExecution( POST_RESET_STALL_TIME ); + + // + // Clear the chip reset. + // + + WRITE_SIOP_UCHAR( ISTAT, 0 ); + + if ( !(READ_SIOP_UCHAR( ISTAT ) & 0x40) ) + break; + } + +#ifdef _MIPS_ + + // + // Restore GPCNTL contents for SNI PCI boxes + // which set bit 7 to 1 to get internal bus + // master signal on GPIO1 to drive a LED + // + + WRITE_SIOP_UCHAR(GPCNTL,DeviceExtension->preserved_reg); +#endif + + } + + else // Abort any running script in order to change clock settings. + { + AbortCurrentScript (DeviceExtension); + } + + // + // Insure that Flush DMA FIFO, Clear DMA FIFO, and Fetch Pin Mode + // bits are all cleared. + // + + WRITE_SIOP_UCHAR( CTEST3, 0 ); + + // + // set DMA burst length: + // 8 - transfer burst for all chips except 825A and 875 + // Set to 64 if we're using the large fifo and scripts ram on the + // 825A and 875 part. Do not set up the prefetch unit since it buys + // us nothing in speed and can create a problem using 64 as the burst + // length. + // Set DMA control values: + // do not enable the Totem Pole driver - violates PCI spec + // Flush and enable the script prefetch for devices (except as noted above) + // (units that do not have pre-fetch will ignore this.) + // + + if (!(DeviceExtension->hbaCapability & HBA_CAPABILITY_875_LARGE_FIFO) ) + { + WRITE_SIOP_UCHAR( DMODE, DMODE_BURST_1 ); +// +// Do not enable pre-fetch until chips are fixed... +// +// WRITE_SIOP_UCHAR( DCNTL, 0x60 ); + WRITE_SIOP_UCHAR( DCNTL, 0x00 ); + } + else + { + WRITE_SIOP_UCHAR( DMODE, DMODE_BURST_0 ); + WRITE_SIOP_UCHAR(CTEST5, (UCHAR)(READ_SIOP_UCHAR(CTEST5) | + (CTEST5_USE_LARGE_FIFO + CTEST5_BURST))); + WRITE_SIOP_UCHAR( DCNTL, 0x00 ); + } + + // + // set SCSI Control Register 0 bits + // Full arbitration, selection, or reselection + // Enable SCSI parity checking and raising ATN on bad parity + // + + WRITE_SIOP_UCHAR( SCNTL0, SCNTL0_ARB_MODE_1 + SCNTL0_ARB_MODE_0 + + SCNTL0_ENA_PARITY_CHK + SCNTL0_ASSERT_ATN_PAR ); + + if ( (DeviceExtension->hbaCapability & HBA_CAPABILITY_875_FAMILY) && + (READ_SIOP_UCHAR(CTEST3) & 0xF0) > 0x10 ) + { + // 875 rev. E or greater part with clock doubler + scntl3Value = set_875_multipler (DeviceExtension); + } + + // + // Still need to set up the clock stuff if we did not already do it in the + // clock multipler code above. + // + if (!scntl3Value) + { + scntl3Value = set_8xx_clock (DeviceExtension); + } + + DeviceExtension->NonCachedExtension->ScriptData.SelectDataSCNTL3 = + scntl3Value; + + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE) + max_targets = SYM_MAX_TARGETS; + else + max_targets = SYM_NARROW_MAX_TARGETS; + + for ( i = 0; i < max_targets; i++ ) + { + DeviceExtension->WideParms[i] = scntl3Value; + DeviceExtension->SyncParms[i] = ASYNCHRONOUS_MODE_PARAMS; + } + + // + // set SCSI bus SCSI ID + // Enable response to reselections + // + + WRITE_SIOP_UCHAR( SCID, (UCHAR)(DeviceExtension->SIOPBusID + 0x40 )); + + // + // set reselection ID + // + + if ( DeviceExtension->SIOPBusID < 0x08 ) + { + WRITE_SIOP_UCHAR( RESPID0, (UCHAR) (1 << DeviceExtension->SIOPBusID )); + } + + else + { + HbaId = DeviceExtension->SIOPBusID - 8; + WRITE_SIOP_UCHAR( RESPID1, (UCHAR) (1 << HbaId )); + } + + // + // Enable appropriate SCSI interrupts + // + + WRITE_SIOP_UCHAR( SIEN0, SIEN0_PHASE_MISMATCH + + SIEN0_SCSI_GROSS_ERROR + + SIEN0_UNEXPECTED_DISCON + + SIEN0_RST_RECEIVED + + SIEN0_PARITY_ERROR + ); + + // + // enable appropriate DMA interrupts + // + + WRITE_SIOP_UCHAR( DIEN, DIEN_ENA_ABRT_INT + + DIEN_BUS_FAULT + + DIEN_ENABLE_INT_RCVD + + DIEN_ENABLE_ILL_INST + ); + + // + // Enable additional SCSI interrupts + // Selection or relection time-out interrupt + // + + WRITE_SIOP_UCHAR( SIEN1, 0x04 ); + + // + // Set the SCSI timer values + // Handshake-to-handshake timer disabled + // Selection time out set to 204.8 ms + // + + WRITE_SIOP_UCHAR( STIME0, 0x0c ); + + // + // Enable TolerANT + // + + WRITE_SIOP_UCHAR( STEST3, 0x80 ); + + // + // Enable differential mode + // + +#ifdef _MIPS_ + // Preserve GPCNTL contents for SNI PCI boxes + // which set bit 7 to 1 to get internal bus + // master signal on GPIO1 to drive a LED + WRITE_SIOP_UCHAR(GPCNTL,(UCHAR)(READ_SIOP_UCHAR(GPCNTL) | GPCNTL_GPIO3)); +#else + WRITE_SIOP_UCHAR(GPCNTL,GPCNTL_GPIO3); +#endif + + if ( !(READ_SIOP_UCHAR(GPREG) & GPCNTL_GPIO3) && + (DeviceExtension->hbaCapability & HBA_CAPABILITY_DIFFERENTIAL) ) + { + WRITE_SIOP_UCHAR(STEST2,STEST2_DIFF_MODE); + } + + + // + // turn GPIO 0 into an output by clearing its bit in the control reg + // to enable LED use + // + + WRITE_SIOP_UCHAR(GPCNTL,(UCHAR)(READ_SIOP_UCHAR(GPCNTL) & 0xFE) ); + + // + // initially have the LED off + // + + WRITE_SIOP_UCHAR(GPREG, (UCHAR)(READ_SIOP_UCHAR(GPREG) | 0x01) ); + + +} // InitializeSIOP + + +#if defined (_X86_) + +BOOLEAN +IsCompaqSystem( + IN PVOID DeviceExtension, + IN PPORT_CONFIGURATION_INFORMATION ConfigInfo + ) +/* + +Routine Description: + + This routine locates a Compaq system so the differential support + may be disabled. + +Arguments: + + DeviceExtension - Supplies the device Extension for the SCSI bus adapter. + ConfigInfo - port configuration structure. + +Return Value: + + TRUE if 'compaq' string is found in system BIOS space + +--*/ + +{ + BOOLEAN isCompaq = FALSE; + CHAR signatureBuffer[6]; + CHAR compaqString[6] = { 'c', 'o', 'm', 'p', 'a', 'q' }; + PVOID signatureAddress; + ULONG index; + CHAR tmp; + + // + // Get a mapped system address to the physical address of the ROM signature + // for Compaq systems. + // + + signatureAddress = ScsiPortGetDeviceBase( DeviceExtension, + ConfigInfo->AdapterInterfaceType, + 0, + ScsiPortConvertUlongToPhysicalAddress( 0x000FFFEAL ), + 6, // strlen("COMPAQ") + FALSE ); // not in I/O space + + if (signatureAddress) + { + + // + // Read 6 bytes from the mapped address. + // + + ScsiPortReadRegisterBufferUchar( (PUCHAR)signatureAddress, + (PUCHAR)(&signatureBuffer[0]), + 6 ); + // + // lower case string from memory + // + + for (index = 0; index < 6; index++) + { + + tmp = signatureBuffer[index]; + if (tmp >= 'A' && tmp <= 'Z') + { + tmp = tmp + ('a' - 'A'); + signatureBuffer[index] = tmp; + } + } + + // + // Compare the bytes to "compaq". + // + + for (index = 0; index < 6; index++) + { + if (signatureBuffer[index] != compaqString[index]) + { + break; + } + } + + if (index == 6) + { + isCompaq = TRUE; + + } + } + + // + // Free the device base address. + // + + ScsiPortFreeDeviceBase( DeviceExtension, signatureAddress ); + + return isCompaq; +} // end IsCompaqSystem() + +#endif + +VOID +ISR_Service_Next( + PHW_DEVICE_EXTENSION DeviceExtension, + UCHAR ISRDisposition + ) +/****************************************************************************** + +Routine Description: + +Arguments: + + DeviceExtension - Supplies the device Extension for the SCSI bus adapter. + +Return Value: + + +--*/ + +{ + BOOLEAN discIo; + USHORT i; + UCHAR max_targets; + PSCSI_REQUEST_BLOCK Srb; + PSCRIPTDATASTRUCT ScriptDataPtr = + &DeviceExtension->NonCachedExtension->ScriptData; + + + DebugPrint((3, "Sym8xx: Entering ISR_Service_Next... \n")); + + switch (ISRDisposition) + { + case ISR_START_NEXT_REQUEST: + + // + // try to start next request. + // + + if ( DeviceExtension->NextSrbToProcess != NULL) + { + + // + // Now check to see if this request is for a SCSI I/O request... + // + + if (DeviceExtension->NextSrbToProcess->Function == + SRB_FUNCTION_EXECUTE_SCSI) + { + + + DebugPrint((3, "StartSCSIRequest [1]... \n")); + + StartSCSIRequest(DeviceExtension->NextSrbToProcess, DeviceExtension); + } + + else if (DeviceExtension->NextSrbToProcess->Function == + SRB_FUNCTION_RESET_DEVICE ) + { + ResetPeripheral( DeviceExtension, DeviceExtension->NextSrbToProcess); + } + + //else + //{ + // What else should be checked for???? + //} + + + } + + else + { + + // + // no pending request, so start WAIT RESELECT script to wait + // for a reselection, and ask for a new request if we have not + // already asked. + // + + discIo = FALSE; + + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE) + max_targets = SYM_MAX_TARGETS; + else + max_targets = SYM_NARROW_MAX_TARGETS; + + for ( i = 0; i < max_targets; i++ ) + { + if ( DeviceExtension->DisconnectedCount[i] > 0 ) + { + discIo = TRUE; + break; + } + } + + if ( ( !( DeviceExtension->DeviceFlags & DFLAGS_SCRIPT_RUNNING)) + && ( discIo ) ) + { + StartSIOP( DeviceExtension, + DeviceExtension->WaitReselectScriptPhys); + } // if + + if ( !( DeviceExtension->DeviceFlags & DFLAGS_WORK_REQUESTED)) + { + DeviceExtension->DeviceFlags |= DFLAGS_WORK_REQUESTED; + + if (DeviceExtension->DeviceFlags & DFLAGS_TAGGED_SELECT) + { + DebugPrint((3, "PortNotification [2]... \n")); + ScsiPortNotification( NextLuRequest, + DeviceExtension, + DeviceExtension->BusNumber, + DeviceExtension->TargetId, + DeviceExtension->LUN + ); + + } + else + { + DebugPrint((3, "PortNotification [3]... \n")); + ScsiPortNotification( NextRequest, + DeviceExtension, + NULL + ); + } + + } // if + + } // else + + break; + + + case ISR_RESTART_SCRIPT: + + // + // set up synchronous parameters and restart the script. + // + + Srb=DeviceExtension->ActiveRequest; + + ScriptDataPtr->SelectDataSCNTL3 = + DeviceExtension->WideParms[Srb->TargetId]; + ScriptDataPtr->SelectDataSXFER = + DeviceExtension->SyncParms[Srb->TargetId]; + + WRITE_SIOP_UCHAR (SCNTL3, DeviceExtension->WideParms[Srb->TargetId] ); + WRITE_SIOP_UCHAR (SXFER, DeviceExtension->SyncParms[Srb->TargetId] ); + + StartSIOP( DeviceExtension, DeviceExtension->RestartScriptPhys); + break; + + + case ISR_CONT_NEG_SCRIPT: + + // + // set up synchronous parameters and restart the script. + // + + Srb=DeviceExtension->ActiveRequest; + + ScriptDataPtr->SelectDataSCNTL3 = + DeviceExtension->WideParms[Srb->TargetId]; + ScriptDataPtr->SelectDataSXFER = + DeviceExtension->SyncParms[Srb->TargetId]; + + WRITE_SIOP_UCHAR (SCNTL3, DeviceExtension->WideParms[Srb->TargetId] ); + WRITE_SIOP_UCHAR (SXFER, DeviceExtension->SyncParms[Srb->TargetId] ); + + StartSIOP( DeviceExtension, DeviceExtension->ContNegScriptPhys); + break; + + + case ISR_EXIT: + default: + break; + + } // switch ISR_DISPOSITION + + DebugPrint((3, "Sym8xx: Exiting ISR_Service_Next... \n")); + + return; +} //isr_service_next + + +BOOLEAN +Sym8xxAdapterState( + IN PVOID Context, + IN PVOID ConfigContext, + IN BOOLEAN SaveState + ) +/****************************************************************************** + +Routine Description: + + This function saves the SIOP registers on driver init and restores + them when Windows 95 shuts down. Nothing is done for Windows NT. + +Arguments: + + Context - Supplies a pointer to the device extension. + + ConfigContext - miniport configuration data structure + + SaveState - save/restore indicator flag (TRUE = Save, FALSE = Restore) + +Return Value: + + Returns status of save/restore operation. + +--*/ + +{ + PHW_DEVICE_EXTENSION DeviceExtension = Context; + +#ifdef FOR_95 + if ( SaveState ) + { + // + // Save SIOP registers as they were in DOS mode + // + + save_reg( DeviceExtension, &(DeviceExtension->AdapStateStore) ); + } + else + { + // + // Return all devices to asynchronous transfer mode + // by resetting the SCSI bus. + // + + WRITE_SIOP_UCHAR( SCNTL1, SCNTL1_RESET_SCSI_BUS ); + + // + // Delay the minimum assertion time for a SCSI bus reset to make sure + // a valid reset signal is sent. + // + + ScsiPortStallExecution( RESET_STALL_TIME); + + // + // set the bus reset line low to end the bus reset event + // + + WRITE_SIOP_UCHAR(SCNTL1, 0); + + DebugPrint((1, "Sym8xx(%2x): Restore State\n", + DeviceExtension->SIOPRegisterBase + )); + + // + // Wait 250 milliseconds before returning (Reset to Selection Time) + // + + for (i=0; i<250; i++) + { + ScsiPortStallExecution(999); + } + + // + // Restore SIOP registers to state they were in DOS mode + // + + restore_reg( DeviceExtension, &(DeviceExtension->AdapStateStore) ); + } +#endif + + return TRUE; +} + + +ULONG +Sym8xxFindAdapter( + IN PVOID Context, + IN PVOID InitContext, + IN PVOID BusInformation, + IN PCHAR ArgumentString, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + OUT PBOOLEAN Again + ) +/****************************************************************************** + +Routine Description: + + This function fills in the configuration information structure + +Arguments: + + Context - Supplies a pointer to the device extension. + + InitContext - Supplies adapter initialization structure. + + BusInformation - Unused. + + ArgumentString - Unused. + + ConfigInfo - Pointer to the configuration information structure to be + filled in. + + Again - Returns back a request to call this function again. + +Return Value: + + Returns status based upon results of adapter parameter acquisition. + +--*/ + +{ + PHW_DEVICE_EXTENSION DeviceExtension = Context; + ULONG Status; + PACCESS_RANGE AccessRange, SAccessRange; + ULONG do_fast20 = 0; + ULONG whatslot, whatid; + UCHAR excludechip = 0; + + // + // Get information from previous calls. + // + + PHWInfo hwInfo = (PHWInfo)InitContext; + + // + // Get access range. + // + +#ifdef FOR_95 + DeviceExtension->initial_run = 1; // so scam code runs without delays +#endif + +#ifdef PORT_IO + // + // Look through addresses taken from our PCI config space til + // we find on that is for port I/O. Else set range length to + // 0 to reject this device. + // + AccessRange = &((*(ConfigInfo->AccessRanges))[0]); + if (AccessRange->RangeInMemory == TRUE) + AccessRange = &((*(ConfigInfo->AccessRanges))[1]); + if (AccessRange->RangeInMemory == TRUE) + AccessRange->RangeLength = 0; +#else + // + // Look through addresses taken from our PCI config space til + // we find on that is for memory mapped I/O. Else set range + // length to 0 to reject this device. + // + AccessRange = &((*(ConfigInfo->AccessRanges))[1]); + if (AccessRange->RangeInMemory != TRUE) + AccessRange = &((*(ConfigInfo->AccessRanges))[0]); + if (AccessRange->RangeInMemory != TRUE) + AccessRange->RangeLength = 0; +#endif + + if (AccessRange->RangeLength != 0) + { + + DeviceExtension->SIOPRegisterBase = + (PSIOP_REGISTER_BASE)ScsiPortGetDeviceBase(DeviceExtension, + ConfigInfo->AdapterInterfaceType, + ConfigInfo->SystemIoBusNumber, + AccessRange->RangeStart, + AccessRange->RangeLength, + (BOOLEAN)!AccessRange->RangeInMemory); + + // always default to not doing FAST20. + + DeviceExtension->hbaCapability = 0; + + if (ArgumentString != NULL) + { + if (ProcessParseArgumentString(ArgumentString,"Ex_Slot",&whatslot)) + { + if ( ((whatslot & 0x0F) == (ULONG)ConfigInfo->SlotNumber) && + (((whatslot & 0xF0) >> 4) == ConfigInfo->SystemIoBusNumber) ) + excludechip = 1; + } + + if (ProcessParseArgumentString(ArgumentString,"Ex_ChipID",&whatid)) + { + if (whatid == hwInfo->hbaDeviceID) + excludechip = 1; + } + + if (excludechip) + { + // + // We'll need to free up the address base for this chip/slot + // + ScsiPortFreeDeviceBase (DeviceExtension, + DeviceExtension->SIOPRegisterBase); + *Again = TRUE; + return (SP_RETURN_NOT_FOUND); + } + + if (ProcessParseArgumentString(ArgumentString,"Fast20_Support", + &do_fast20)) + { + if (do_fast20) + DeviceExtension->hbaCapability = HBA_CAPABILITY_REGISTRY_FAST20; + } + } + + // detect if this board has the NVRAM on board and + // if it is programmed with user supplied data. + + if (NvmDetect(DeviceExtension) == SUCCESS) + { + if (RetrieveNvmData(DeviceExtension) != SUCCESS) + InvalidateNvmData(DeviceExtension); + } + + else + { + InvalidateNvmData(DeviceExtension); + } + + // + // Set SCSI ID obtained from NVRAM (or defaulted to 7) + // + + DeviceExtension->SIOPBusID = (UCHAR)DeviceExtension->UsersHBAId; + + // + // Set remainder of configuration + // + + // + // Set the bus number for this controller. Since Symbios controllers + // currently only support one SCSI bus each, this value is zero. + // + + DeviceExtension->BusNumber = 0; + + // + // Set the SCSI bus number. This value is incremented for each + // SCSI bus found in the system. + // + + DeviceExtension->ScsiBusNumber = hwInfo->hbaCount++; + + DeviceExtension->hbaCapability |= hwInfo->hbaCapability; + + + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_825_FAMILY) + { + if ( (READ_SIOP_UCHAR(MACNTL) & 0xF0) >= 0x60 ) + // 825A part + { + DeviceExtension->hbaCapability |= HBA_CAPABILITY_SYNC_16; + DeviceExtension->hbaCapability |= HBA_CAPABILITY_875_LARGE_FIFO; + +#ifndef FOR_95 + DeviceExtension->hbaCapability |= HBA_CAPABILITY_SCRIPT_RAM; +#endif + } + } + + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_FAST20) + { + DeviceExtension->ClockSpeed = 80; + } + + else + { + DeviceExtension->ClockSpeed = 40; + } + + ConfigInfo->MaximumTransferLength = MAX_XFER_LENGTH; + ConfigInfo->NumberOfPhysicalBreaks = MAX_SG_ELEMENTS - 1; + + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE) + { + ConfigInfo->MaximumNumberOfTargets = SYM_MAX_TARGETS; + } + + else + { + ConfigInfo->MaximumNumberOfTargets = SYM_NARROW_MAX_TARGETS; + } + + ConfigInfo->NumberOfBuses = 1; + ConfigInfo->ScatterGather = TRUE; + ConfigInfo->Master = TRUE; + + ConfigInfo->AdapterScansDown = FALSE; + ConfigInfo->TaggedQueuing = TRUE; + ConfigInfo->Dma32BitAddresses = TRUE; + + ConfigInfo->InitiatorBusId[0] = DeviceExtension->SIOPBusID; + + DeviceExtension->ScriptRamPhys = (ULONG)NULL; + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_SCRIPT_RAM) + { + SAccessRange = &((*(ConfigInfo->AccessRanges))[2]); + if (ScsiPortConvertPhysicalAddressToUlong(SAccessRange->RangeStart)) + { + // just map the Script Ram area here so NT knows about the space, + // save the needed address into ScriptRamPhys. + + DeviceExtension->ScriptRamVirt = + (PULONG)ScsiPortGetDeviceBase(DeviceExtension, + ConfigInfo->AdapterInterfaceType, + ConfigInfo->SystemIoBusNumber, + SAccessRange->RangeStart, + SAccessRange->RangeLength, + (BOOLEAN)!SAccessRange->RangeInMemory); + DeviceExtension->ScriptRamPhys = SAccessRange->RangeStart.LowPart; + } + + if (!DeviceExtension->ScriptRamPhys) + { + DeviceExtension->hbaCapability &= ~HBA_CAPABILITY_SCRIPT_RAM; + } + } + + DeviceExtension->NonCachedExtension = + ScsiPortGetUncachedExtension( + DeviceExtension, + ConfigInfo, + sizeof(HW_NONCACHED_EXTENSION) + ); + + if (DeviceExtension->NonCachedExtension == NULL) + { + Status = SP_RETURN_ERROR; + } + + else + { + Status = SP_RETURN_FOUND; + + DebugPrint((1, "Symbios 53c8xx(%1x) IO Base=%x Irq=%x HBA Id=%x \n", + DeviceExtension->ScsiBusNumber, + DeviceExtension->SIOPRegisterBase, + ConfigInfo->BusInterruptLevel, + ConfigInfo->InitiatorBusId[0] + )); + + DebugPrint((3, + "Sym8xx(%2x) Sym8xxFindAdapter: DeviceExtension at 0x%x \n", + DeviceExtension->SIOPRegisterBase, + DeviceExtension + )); + + DebugPrint((3, "Sym8xx(%2x) Sym8xxFindAdapter: SCSI SCRIPTS at 0x%x \n", + DeviceExtension->SIOPRegisterBase, + DeviceExtension->NonCachedExtension->ScsiScripts + )); + } + + // + // Disable differential support if this is a compaq. + // + +#if defined(_X86_) + if (IsCompaqSystem( DeviceExtension, ConfigInfo )) + { + DeviceExtension->hbaCapability &= ~HBA_CAPABILITY_DIFFERENTIAL; + } + +#endif + + // + // Prepare the LU Flags for work. + // + + SetupLuFlags( DeviceExtension, 0 ); + + // + // Tell system to look for more adapters. + // + + *Again = TRUE; + + } + + else + { + // + // Access Range == 0 ... + // + + // + // Tell system to stop search for adapters. + // + + Status = SP_RETURN_NOT_FOUND; + *Again = FALSE; + } + + return(Status); + +} // Sym8xxFindAdapter + + +BOOLEAN +Sym8xxHWInitialize( + IN PVOID Context + ) +/****************************************************************************** + +Routine Description: + + This function initializes the Symbios 53C8xx SCSI Scripts, and then + initializes the SIOP. + +Arguments: + + Context - Pointer to the device extension for this SCSI bus. + +Return Value: + + TRUE + +--*/ + +{ + PHW_DEVICE_EXTENSION DeviceExtension = Context; + + // + // Initialize SCSI script buffers and pointers and the Symbios 53C8xx + // SCSI I/O processor for the current hardware implementation. + // + + ComputeSCSIScriptVectors(DeviceExtension); + InitializeSIOP(DeviceExtension); + + // + // For WinNT: Deleting this reset, going to do asynch neg. on all I/O's + // till OS says to do Synch. + // +#ifdef FOR_95 + ResetSCSIBus( DeviceExtension); +#else + // + // scam_completed flag needs to be set to true for NT to allow I/O's thru + DeviceExtension->scam_completed=TRUE; +#endif + + clear_CA_Condition(DeviceExtension); + + return(TRUE); + +} // Sym8xxHWInitialize + + +BOOLEAN +Sym8xxISR( + PVOID Context + ) +/****************************************************************************** + +Routine Description: + + This is the interrupt service routine for the Symbios 53C8xx SCSI chip. + This routine calls one of two interrupt routines, depending upon whether + the DMA or SCSI core of the SIOP interrupted. Both routines return a + disposition code indicating what action to take next. + +Arguments: + + Context - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + TRUE - Indicates that an interrupt was pending on adapter. + + FALSE - Indicates the interrupt was not ours. + +--*/ + +{ + PHW_DEVICE_EXTENSION DeviceExtension = Context; + UCHAR IntStatus; + UCHAR ScsiStatus = 0; + UCHAR DmaStatus = 0; + UCHAR ScsiStatus1 = 0; + UCHAR ISRDisposition; + PSCRIPTDATASTRUCT ScriptDataPtr = + &DeviceExtension->NonCachedExtension->ScriptData; + + + if (!((IntStatus = READ_SIOP_UCHAR(ISTAT)) & + (ISTAT_SCSI_INT | ISTAT_DMA_INT))) + { + + // + // Reject this interrupt. This could be the loader polling or a + // shared interrupt. + // + + DebugPrint((2, + "Sym8xx(%2x) Sym8xxISR: Unexpected interrupt. Dev. Ext. = %x \n", + DeviceExtension->SIOPRegisterBase, + DeviceExtension + )); + + return(FALSE); + } + + // CHC - 53c810 pass 1 chip bug workaround. + // + // We need to make sure the ISTAT_SIGP bit is cleared since + // this bit could be still set when we attempted to abort + // a scsi script and got a reselection instead. Reading + // CTEST2 clears this bit. + // + + if (IntStatus & ISTAT_SIGP) + { + READ_SIOP_UCHAR(CTEST2); + } + + // + // Indicate that the scripts have stopped and determine + // the type of interrupt received. + // + + DeviceExtension->DeviceFlags &= ~DFLAGS_SCRIPT_RUNNING; + + // + // Check if a DMA interrupt occurred. + // + + if ( IntStatus & ISTAT_DMA_INT) + { + // + // DMA Interrupt occurred, get the DMA status. + // + + DmaStatus = READ_SIOP_UCHAR(DSTAT); + + // + // Call routine to process the appropriate DMA interrupt. + // + + ISRDisposition = ProcessDMAInterrupt( DeviceExtension, DmaStatus); + + // + // Check if a SCSI interrupt occurred. + // + } + + else if ( IntStatus & ISTAT_SCSI_INT ) + { + // + // SCSI interrupt occurred, get the SCSI interrupt status. + // + + ScsiStatus = READ_SIOP_UCHAR(SIST0); + + // + // Call routine to process the appropriate SCSI interrupt. + // + + // + // Check for Selection/Reselection timeout. + // + + if ( (ScsiStatus1 = READ_SIOP_UCHAR(SIST1)) & SIST1_SEL_RESEL_TIMEOUT ) + { + ISRDisposition = ProcessSelectionTimeout( DeviceExtension); + } + + else + { + ISRDisposition = ProcessSCSIInterrupt( DeviceExtension, ScsiStatus); + } + + } + + // + // Neither DMA interrupt or SCSI interrupt. Must be an error. + // + + else + { + DebugPrint((2, + "Sym8xx(%2x) Sym8xxISR: Unexpected int. - neither DIP or SIP set\n", + DeviceExtension->SIOPRegisterBase + )); + + return FALSE; + } + + DebugPrint((2, + "Sym8xx(%2x) Sym8xxISR: ISTAT=%x, DSTAT=%x, SIST0=%x, SIST1=%x \n", + DeviceExtension->SIOPRegisterBase, + IntStatus, DmaStatus, ScsiStatus, ScsiStatus1 + )); + + ISR_Service_Next(DeviceExtension,ISRDisposition); + + return(TRUE); + +} // Sym8xxISR + + +BOOLEAN +Sym8xxReset( + IN PVOID Context, + IN ULONG PathId + ) +/****************************************************************************** + +Routine Description: + + This externally called routine resets the SIOP and the SCSI bus. + +Arguments: + + DeviceExtension - Supplies a pointer to the specific device extension. + + PathId - Indicates adapter to reset. + +Return Value: + + None + +--*/ + +{ + PHW_DEVICE_EXTENSION DeviceExtension = Context; + ULONG Limit = 0; + PSCSI_REQUEST_BLOCK srb; + UCHAR IntStatus; + + // + // Check to see if an interrupt is pending on the card. + // + + if (((IntStatus = READ_SIOP_UCHAR(ISTAT)) & + (ISTAT_SCSI_INT | ISTAT_DMA_INT))) + { + DebugPrint((1, + "Sym8xxReset: Interrupt pending on chip. ISTAT %x.\n", + IntStatus)); + // + // Interrupt is there. Assume that the chip is disabled, but still + // assigned resources (Omniplex). + // + + srb = DeviceExtension->ActiveRequest; + + // + // Set flag to ensure that the rest are caught in startIo + // + + DeviceExtension->DeviceFlags |= DFLAGS_IRQ_NOT_CONNECTED; + + // + // Log this. + // + + ScsiPortLogError(Context, + srb, + 0, + 0, + 0, + SP_IRQ_NOT_RESPONDING, + (1 << 8) | IntStatus); + + // + // Fall through and execute rest of reset code, to ensure that + // the scripts and chip are coherent. + // + } + + + DebugPrint((1, "Sym8xx(%2x): O/S requested SCSI bus reset\n", + DeviceExtension->SIOPRegisterBase + )); + + if (DeviceExtension->DeviceFlags & DFLAGS_SCRIPT_RUNNING) + { + WRITE_SIOP_UCHAR(ISTAT, ISTAT_SIGP); + + IntStatus = READ_SIOP_UCHAR(ISTAT); + + while (!(IntStatus & ISTAT_DMA_INT)) + { + IntStatus = READ_SIOP_UCHAR(ISTAT); + + if (IntStatus & ISTAT_SCSI_INT) + { + READ_SIOP_UCHAR(SIST0); + } + + ScsiPortStallExecution(10); + + if (Limit++ > 1000 * 10) + { + break; + } + } + + DeviceExtension->DeviceFlags &= ~DFLAGS_SCRIPT_RUNNING; + + // + // Check to see if a reselection occurred or the abort was successful. + // + + if (IntStatus & ISTAT_SIGP) + { + READ_SIOP_UCHAR(CTEST2); + } + + else + { + READ_SIOP_UCHAR(DSTAT); + } + + } // if scripts running + + // + // reset the SIOP. + // + + InitializeSIOP( DeviceExtension); + + // + // reset the SCSI bus. + // + + ResetSCSIBus( DeviceExtension); + + return (TRUE); + +} // Sym8xxReset + + +BOOLEAN +Sym8xxStartIo( + IN PVOID Context, + IN PSCSI_REQUEST_BLOCK Srb + ) +/****************************************************************************** + +Routine Description: + + This routine receives requests from the port driver. + +Arguments: + + Context - pointer to the device extension for the adapter. + + Srb - pointer to the request to be started. + +Return Value: + + TRUE - the request was accepted. + + FALSE - the request must be submitted later. + +--*/ + +{ + PHW_DEVICE_EXTENSION DeviceExtension = Context; + UCHAR pathId = Srb->PathId; + + if (!(DeviceExtension->scam_completed)) + { + DebugPrint((3,"Entered Sym8xxStartIO before SCAM finished... \n")); + Srb->SrbStatus = SRB_STATUS_BUSY; + DeviceExtension->DeviceFlags &= ~DFLAGS_WORK_REQUESTED; + + ScsiPortNotification( RequestComplete, + DeviceExtension, + Srb + ); + + return(FALSE); + } + + + switch (Srb->Function) + { + case SRB_FUNCTION_EXECUTE_SCSI: + + if (Srb->Cdb[0] == SCSIOP_INQUIRY) + { + if (DeviceExtension->DeviceFlags & DFLAGS_IRQ_NOT_CONNECTED) + { + Srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT; + + ScsiPortNotification( RequestComplete, + DeviceExtension, + Srb + ); + + ScsiPortNotification( NextRequest, + DeviceExtension, + NULL + ); + + return(TRUE); + } + } + + // + // Indicate a request for work is not pending. + // + + DeviceExtension->DeviceFlags &= ~DFLAGS_WORK_REQUESTED; + + StartSCSIRequest( Srb, DeviceExtension ); + + return(TRUE); + + case SRB_FUNCTION_ABORT_COMMAND: + case SRB_FUNCTION_TERMINATE_IO: + + if ( DeviceExtension->ActiveRequest == Srb->NextSrb) + { + // + // Indicate a request for work is not pending. + // + + DeviceExtension->DeviceFlags &= ~DFLAGS_WORK_REQUESTED; + + // + // abort the script that is processing the request + // + + AbortCurrentScript( DeviceExtension); + + // + // temporarily disable unexpected disconnect interrupt, as + // an unexpected disconnect interrupt could occur after we + // send the abort command, but before we receive the script + // interrupt indicating the request was aborted. + // + + WRITE_SIOP_UCHAR( SIEN0, (UCHAR) ( READ_SIOP_UCHAR(SIEN0) & + (UCHAR) ~SIEN0_UNEXPECTED_DISCON)); + + // + // abort the request - we will be interrupted later regardless + // of whether abort succeeds or fails. + // + + StartSIOP( DeviceExtension, DeviceExtension->AbortScriptPhys); + + return( TRUE); + } // if + + // + // the request we were asked to abort is not currently in process, + // so fail the abort request and ask for a new one. + // + + Srb->SrbStatus = SRB_STATUS_ABORT_FAILED; + + ScsiPortNotification( RequestComplete, + DeviceExtension, + Srb + ); + + ScsiPortNotification( NextRequest, + DeviceExtension, + NULL + ); + + return(TRUE); + + case SRB_FUNCTION_RESET_DEVICE: + + DebugPrint((2, "Sym8xx(%2x) Sym8xxStartIO: ResetDevice received.\n", + DeviceExtension->SIOPRegisterBase + )); + + // + // Indicate a request for work is not pending. + // + + DeviceExtension->DeviceFlags &= ~DFLAGS_WORK_REQUESTED; + + // + // reset the SCSI device. + // + + ResetPeripheral( DeviceExtension,Srb ); + + return(TRUE); + + case SRB_FUNCTION_RESET_BUS: + + DebugPrint((2, "Sym8xx(%2x) Sym8xxStartIO: ResetBus received.\n", + DeviceExtension->SIOPRegisterBase + )); + + // + // reset the SCSI bus. + // + + ResetSCSIBus( DeviceExtension ); + + return(TRUE); + + + default: + + DebugPrint((1, + "Sym8xx(%2x) Sym8xxStartIO: Unknown function code received.\n", + DeviceExtension->SIOPRegisterBase + )); + + // + // Unknown function code in the request. Complete the request with + // an error and ask for the next request. + // + + Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION; + ScsiPortNotification( RequestComplete, + DeviceExtension, + Srb + ); + + ScsiPortNotification( NextRequest, + DeviceExtension, + NULL + ); + + return(TRUE); + + } // switch + +} // Sym8xxStartIO + + +UCHAR +ProcessAbortOccurred( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine is called when scripts sucessfully sent an Abort message + to a device. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + + PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest; + PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension; + + DebugPrint((1, "Sym8xx(%2x) Abort message occurred \n", + DeviceExtension->SIOPRegisterBase)); + + // + // indicate that the abort was successful + // + + Srb->SrbStatus = SRB_STATUS_SUCCESS; + + DeviceExtension->ActiveRequest = NULL; + + if ( !(Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) ) + { + + LuExtension = ScsiPortGetLogicalUnit( DeviceExtension, + Srb->PathId, + Srb->TargetId, + Srb->Lun + ); + + LuExtension->UntaggedRequest = NULL; + + } + + // + // call back the request. + // + + ScsiPortNotification( RequestComplete, + DeviceExtension, + Srb + ); + + // + // enable UNEXPECTED DISCONNECT interrupt in case we disabled it. + // + + WRITE_SIOP_UCHAR( SIEN0, (UCHAR) ( READ_SIOP_UCHAR(SIEN0) + | (UCHAR) SIEN0_UNEXPECTED_DISCON) ); + + // + // tell ISR to start next request + // + + return( ISR_START_NEXT_REQUEST ); + +} // ProcessAbortOccurred + + +UCHAR +ProcessBusResetReceived( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine processes SCSI bus resets detected by the SIOP. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + // + // tell port driver that a bus reset has occurred + // + + ScsiPortNotification( ResetDetected, + DeviceExtension, + NULL + ); + + // + // if the bus reset was internal, we will not try to start a new + // request, since the routine that issued the reset would have already + // done this. + // + + if ( DeviceExtension->DeviceFlags & DFLAGS_BUS_RESET) + { + // + // clear the flag indicating internal bus reset. + // + + DeviceExtension->DeviceFlags &= ~DFLAGS_BUS_RESET; + + // + // tell ISR to continue without doing anything. + // + + return( ISR_EXIT); + } + + else + { + // + // the bus reset was externally generated, so abort any started or + // pending requests and try to start a new one. + // + + BusResetPostProcess( DeviceExtension); + + return( ISR_START_NEXT_REQUEST); + } + +} // ProcessBusResetReceived + + +UCHAR +ProcessCommandComplete( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine handles normal SCSI request completion. Routine first checks + SCSI status returned from device, and if some permutation of GOOD sets + error flag in SRB. Routine then does port notification of request + completion. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest; + PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension; + + DebugPrint((3, "Sym8xx(%2x) Sym8xxCommand: Completing request for Path=%2x Id=%2x Lun=%2x\n", + DeviceExtension->SIOPRegisterBase, + DeviceExtension->ScsiBusNumber, + Srb->TargetId, + Srb->Lun )); + + // + // if a synchronous negotiation is pending, the target was nice enough + // to not acknowledge our SDTR message. go to asynchronous. + // + + if ( DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_SYNC_NEGOT_PEND) + { + ProcessSynchNotSupported( DeviceExtension); + } + + if ((DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_WIDE_NEGOT_PEND) || + (DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_NARROW_NEGOT_PEND)) + { + ProcessWideNotSupported( DeviceExtension, Srb->TargetId); + } + + // + // set status data from script buffer. + // + + Srb->ScsiStatus = DeviceExtension->NonCachedExtension->StatusData; + + // + // check for bad status. + // + + if ( Srb->ScsiStatus != SCSISTAT_GOOD && + Srb->ScsiStatus != SCSISTAT_CONDITION_MET && + Srb->ScsiStatus != SCSISTAT_INTERMEDIATE && + Srb->ScsiStatus != SCSISTAT_INTERMEDIATE_COND_MET ) + { + // check to see if Contingient Condition now exists + if (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION) + { + DeviceExtension->CA_Condition[Srb->TargetId][Srb->Lun] = 1; + } + + if ( (Srb->ScsiStatus == SCSISTAT_BUSY) || + (Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) ) + { + Srb->SrbStatus = SRB_STATUS_BUSY; + } + + else + { + Srb->SrbStatus = SRB_STATUS_ERROR; + } + + DebugPrint((1, + "Sym8xx(%2x): Request failed for Path=%2x Id=%2x Lun=%2x \n", + DeviceExtension->SIOPRegisterBase, + DeviceExtension->ScsiBusNumber, + Srb->TargetId, + Srb->Lun + )); + DebugPrint((1, " ScsiStatus: 0x%x SrbStatus: 0x%x\n SrbFlags: 0x%x", + Srb->ScsiStatus, + Srb->SrbStatus, + Srb->SrbFlags + )); + + // + // Make sure the next command is not for the current LUN. + // + + if ( DeviceExtension->NextSrbToProcess != NULL && + DeviceExtension->NextSrbToProcess->PathId == Srb->PathId && + DeviceExtension->NextSrbToProcess->TargetId == Srb->TargetId && + DeviceExtension->NextSrbToProcess->Lun == Srb->Lun) + { + DebugPrint((1, "Sym8xx(%2x): Failing request with busy status due to check condition\n", + DeviceExtension->SIOPRegisterBase)); + + DeviceExtension->NextSrbToProcess->SrbStatus = SRB_STATUS_ABORTED; + + DeviceExtension->NextSrbToProcess->ScsiStatus = SCSISTAT_BUSY; + + ScsiPortNotification( RequestComplete, + DeviceExtension, + DeviceExtension->NextSrbToProcess + ); + + DeviceExtension->NextSrbToProcess = NULL; + + if ( !( DeviceExtension->DeviceFlags & DFLAGS_WORK_REQUESTED)) + { + DeviceExtension->DeviceFlags |= DFLAGS_WORK_REQUESTED; + + ScsiPortNotification(NextRequest, + DeviceExtension, + NULL + ); + + } + } + } + + else + { + // Status is good... + Srb->SrbStatus = SRB_STATUS_SUCCESS; + } + + // Check for data underrun. + + if ( SRB_EXT(Srb)->DataTransferred != 0) + { + Srb->DataTransferLength = Srb->DataTransferLength - + SRB_EXT(Srb)->SavedDataLength + SRB_EXT(Srb)->DataTransferred; + + if (Srb->DataTransferLength == 0) + { + Srb->SrbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE; + } + + else + { + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + } + } + + // indicate no request is active. + DeviceExtension->ActiveRequest = NULL; + + if (!(Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) ) + { + LuExtension = ScsiPortGetLogicalUnit( DeviceExtension, + Srb->PathId, + Srb->TargetId, + Srb->Lun + ); + + LuExtension->UntaggedRequest = NULL; + } + + // indicate request completed to port driver. + ScsiPortNotification( RequestComplete, + DeviceExtension, + Srb + ); + + // tell ISR to try to start a new request + return( ISR_START_NEXT_REQUEST); + +} // ProcessCommandComplete + + +UCHAR +ProcessDeviceResetFailed( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine is called when scripts try to reset a wayward device, but + cannot. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest; + + DebugPrint((1, "Sym8xx(%2x) Bus Device Reset or Abort failed \n", + DeviceExtension->SIOPRegisterBase)); + + // + // since the device would not get off the bus, we must blow him (and every- + // body else) away. + // + + // + // reset SIOP + // + + InitializeSIOP( DeviceExtension ); + + // + // reset SCSI bus + // + + ResetSCSIBus( DeviceExtension ); + + return( ISR_START_NEXT_REQUEST ); + +} // ProcessDeviceResetFailed + + +UCHAR +ProcessDeviceResetOccurred( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine is called when scripts sucessfully sent a Bus Device + Reset message to a device. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + UCHAR lun; + + PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest; + PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension; + + DebugPrint((1, "Sym8xx(%2x) Bus Device Reset occurred \n", + DeviceExtension->SIOPRegisterBase)); + + if ( Srb->Function == SRB_FUNCTION_RESET_DEVICE ) + { + // + // indicate that the reset was successful + // + + Srb->SrbStatus = SRB_STATUS_SUCCESS; + } + + else + { + // + // indicate the device was wayward. + // + Srb->SrbStatus = SRB_STATUS_ERROR; + Srb->ScsiStatus = SCSISTAT_COMMAND_TERMINATED; + } + + // reset the Contingent Allegience blocker for this Target + for ( lun = 0; lun < SCSI_MAXIMUM_LOGICAL_UNITS; lun++ ) + DeviceExtension->CA_Condition[Srb->TargetId][lun] = 0; + + DeviceExtension->ActiveRequest = NULL; + + if ( !(Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) ) + { + LuExtension = ScsiPortGetLogicalUnit( DeviceExtension, + Srb->PathId, + Srb->TargetId, + Srb->Lun + ); + + LuExtension->UntaggedRequest = NULL; + } + + // + // call back the request. + // + + ScsiPortNotification( RequestComplete, + DeviceExtension, + Srb + ); + + // + // enable UNEXPECTED DISCONNECT interrupt in case we disabled it. + // + + WRITE_SIOP_UCHAR( SIEN0, (UCHAR) ( READ_SIOP_UCHAR(SIEN0) | + (UCHAR) SIEN0_UNEXPECTED_DISCON) ); + + // + // Remove all the disconnected I/Os for this target. + // + + DeviceExtension->DisconnectedCount[Srb->TargetId] = 0; + + if ( DeviceExtension->DeviceFlags & DFLAGS_TAGGED_SELECT ) + { + ScsiPortNotification( NextLuRequest, + DeviceExtension, + DeviceExtension->BusNumber, + DeviceExtension->TargetId, + DeviceExtension->LUN + ); + } + + else + { + ScsiPortNotification( NextRequest, + DeviceExtension, + NULL + ); + } + + return( ISR_EXIT ); + +} // ProcessDeviceResetOccurred + + +UCHAR +ProcessDisconnect( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine handles a normal device disconnect. Note that this routine + is not called in the case of a command completion, so we expect a + reselection after the completion of this call. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest; + + // + // indicate that no request is active. + // + + DebugPrint((3, "Sym8xx(%2x) Sym8xxDMAInterrupt: Disconnect \n", + DeviceExtension->SIOPRegisterBase)); + + // + // increment depth counter for disconnected requests + // + + DeviceExtension->DisconnectedCount[Srb->TargetId]++; + + // + // indicate no work is pending, and tell ISR to start next request. + // + + DeviceExtension->ActiveRequest = NULL; + + return( ISR_START_NEXT_REQUEST); + +} // ProcessDisconnect + + +UCHAR +ProcessDMAInterrupt( + PHW_DEVICE_EXTENSION DeviceExtension, + UCHAR DmaStatus + ) +/****************************************************************************** + +Routine Description: + + The routine processes interrupts from the DMA core of the 53C8xx SIOP. + +Arguments: + + Context - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + TRUE + +--*/ + +{ + ULONG i; + UCHAR ScriptIntOpcode; + PSCSI_REQUEST_BLOCK Srb; + + Srb = DeviceExtension->ActiveRequest; + + if ( DmaStatus & DSTAT_SCRPTINT) + { + // + // Check for residual data in the C8xx DMA FIFO and + // flush it as neccessary. + // + + if (!(DmaStatus & 0x80)) + { + WRITE_SIOP_UCHAR( CTEST3, CTEST3_FLUSH_FIFO); + + for (i=0; i < 1000; i++) + { + if (READ_SIOP_UCHAR(DSTAT) & 0x80) + { + break; + } + + ScsiPortStallExecution(5); + } + + if (i >= 1000) + { + // + // Give up and reset the chip. + // + + InitializeSIOP( DeviceExtension); + ResetSCSIBus( DeviceExtension); + return( ISR_START_NEXT_REQUEST); + } + + WRITE_SIOP_UCHAR( CTEST3, 0); + } + + // + // read the register that contains the script interrupt opcode. + // if the RESELECT bit is set in the opcode, process the reselect. + // + + if (( ScriptIntOpcode = READ_SIOP_UCHAR( DSPS[0])) & DSPS_RESELOP) + { + // + // CHC - 53c810 pass 1 chip bug workaround. + // + // We need to make sure the ISTAT_SIGP bit is cleared since + // this bit could be still set when we attempted to abort + // a scsi script and got a reselection instead. Reading + // CTEST2 clears this bit. + // + + READ_SIOP_UCHAR( CTEST2); + + // + // A reselection occurred. + // The reselection id is in the low byte of the SSID register. + // + + ScriptIntOpcode = READ_SIOP_UCHAR( SSID ) & 0x0F; + + // + // call routine to process reselection. return disposition code + // to the ISR. + // + + return ( ProcessReselection( DeviceExtension, ScriptIntOpcode) ); + } + + // + // the script interrupt opcode was not a reselection, so process it. + // + // + // CHC - 53c810 pass 1 chip bug workaround. + // + // To get around the parity error on the PCI bus, we will handle + // the aborting of scsi scripts here. + // + + if ( ScriptIntOpcode == SCRIPT_INT_SCRIPT_ABORTED) + { + // + // Just make sure we've cleared the DSTAT register + // + + READ_SIOP_UCHAR( DSTAT); + + return( ISR_START_NEXT_REQUEST); + } + + // + // The following DMA interrupts should only occur when we have an + // active SRB. To be safe, we check for one. If there is not an + // active SRB, the hardware has interrupted inappropriately, + // so reset everything. + // + + if ( DeviceExtension->ActiveRequest == NULL && + ScriptIntOpcode != SCRIPT_INT_TAG_RECEIVED) + { + DebugPrint((1, "Sym8xx(%2x) ProcessDMAInterrupt unknown request\n", + DeviceExtension->SIOPRegisterBase)); + DebugPrint((1, " ActiveRequest: %lx DmaStatus: %x\n", + DeviceExtension->ActiveRequest, DmaStatus)); + DebugPrint((1, " DSPS[0]: %x\n", + ScriptIntOpcode)); + + InitializeSIOP( DeviceExtension); + ResetSCSIBus( DeviceExtension); + return( ISR_START_NEXT_REQUEST); + } + + DebugPrint((3, "Sym8xx(%2x) ProcessDMAInterrupt ...ScriptIntOpcode=%x\n", + DeviceExtension->SIOPRegisterBase, ScriptIntOpcode + )); + + switch (ScriptIntOpcode) + { + // + // call appropriate routine to process script interrupt. + // todo - decide whether to move critical path routines up + // from subroutines to reduce overhead. + // + + case SCRIPT_INT_COMMAND_COMPLETE: + + // + // process COMMAND COMPLETE script interrupt. return + // disposition code to ISR. + // + + return( ProcessCommandComplete( DeviceExtension)); + + case SCRIPT_INT_SAVE_DATA_PTRS: + case SCRIPT_INT_SAVE_WITH_DISCONNECT: + + // + // most of the time, a SAVE DATA POINTERS is followed + // by a DISCONNECT message. We make the determination + // in scripts, and if this is the case we save ourselves + // an interrupt by processing both at once. + // + + ProcessSaveDataPointers( DeviceExtension); + + // + // if not SAVE WITH DISCONNECT just return. + // + + if (ScriptIntOpcode == SCRIPT_INT_SAVE_DATA_PTRS) + { + return ( ISR_RESTART_SCRIPT); + } + + // + // fall through to process disconnect. + // + + case SCRIPT_INT_DISCONNECT: + + // + // process SCRIPT_INT_DISCONNECT script interrupt. return + // disposition code to ISR. + // + + return( ProcessDisconnect( DeviceExtension)); + + case SCRIPT_INT_RESTORE_POINTERS: + + // + // process SCRIPT_INT_RESTORE_POINTERS script interrupt. + // return disposition code to ISR. + // + + return( ProcessRestorePointers( DeviceExtension)); + + case SCRIPT_INT_DEV_RESET_OCCURRED: + + // + // process SCRIPT_INT_DEV_RESET_OCCURRED script interrupt. return + // disposition code to ISR. + // + + return( ProcessDeviceResetOccurred( DeviceExtension)); + + case SCRIPT_INT_DEV_RESET_FAILED: + case SCRIPT_INT_ABORT_FAILED: + + // + // process SCRIPT_INT_DEV_RESET_FAILED script interrupt. return + // disposition code to ISR. + // + + return( ProcessDeviceResetFailed( DeviceExtension)); + + case SCRIPT_INT_IDE_MSG_SENT: + + // + // process SCRIPT_INT_IDE_MSG_SENT script interrupt. return + // disposition code to ISR. + // + + return( ProcessErrorMsgSent( )); + + case SCRIPT_INT_SYNC_NOT_SUPP: + + // + // process SCRIPT_INT_SYNC_NOT_SUPP script interrupt. return + // disposition code to ISR. + // + + return ( ProcessSynchNotSupported( DeviceExtension)); + + case SCRIPT_INT_SYNC_NEGOT_COMP: + + // + // process SCRIPT_INT_SYNC_NEGOT_COMP script interrupt. + // return disposition code to ISR. + // + + return( ProcessSynchNegotComplete( DeviceExtension)); + + case SCRIPT_INT_WIDE_NOT_SUPP: + + // + // process SCRIPT_INT_WIDE_NOT_SUPP script interrupt. return + // disposition code to ISR. + // + + return ( ProcessWideNotSupported( DeviceExtension, Srb->TargetId)); + + case SCRIPT_INT_WIDE_NEGOT_COMP: + + // + // process SCRIPT_INT_WIDE_NEGOT_COMP script interrupt. + // return disposition code to ISR. + // + + return( ProcessWideNegotComplete( DeviceExtension)); + + case SCRIPT_INT_INVALID_RESELECT: + case SCRIPT_INT_INVALID_TAG_MESSAGE: + + // + // process SCRIPT_INT_INVALID_RESELECT script interrupt. + // return disposition code to ISR. + // + + return( ProcessInvalidReselect( DeviceExtension) ); + + case SCRIPT_INT_REJECT_MSG_RECEIVED: + + // + // process SCRIPT_INT_REJECT_MSG_RECEIVED script interrupt. + // return disposition code to ISR. + // + + return( ProcessRejectReceived( DeviceExtension)); + + case SCRIPT_INT_TAG_RECEIVED: + + // + // Process the queue tag message. + // + + return( ProcessQueueTagReceived( DeviceExtension)); + + case SCRIPT_INT_ABORT_OCCURRED: + + // + // The device was successfully aborted. + // + + return( ProcessAbortOccurred( DeviceExtension ) ); + + default: + + // + // something went really wrong. + // perform drastic error recovery. + // + + InitializeSIOP( DeviceExtension); + ResetSCSIBus( DeviceExtension); + return( ISR_START_NEXT_REQUEST); + + } // switch ( SCRIPT_INT_OPCODE) + + } // if + + // + // if we arrive here a DMA error of some type has occurred. + // + + if ( DmaStatus & DSTAT_ILLEGAL_INSTRUCTION) + { + return( ProcessIllegalInstruction( DeviceExtension)); + } + + // + // all other cases indicate that things are really screwed up, since + // we mask off all other types of DMA interrupts. perform drastic error + // recovery. + // + + InitializeSIOP( DeviceExtension); + ResetSCSIBus( DeviceExtension); + return( ISR_START_NEXT_REQUEST); + +} // ProcessDMAInterrupt + + +UCHAR +ProcessErrorMsgSent( + VOID + ) +/****************************************************************************** + +Routine Description: + + This routine is called when scripts sucessfully sent an IDE or MPE + message to a device. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + // + // Target devices should either: + // + // a) return CHECK CONDITION status after receiving an IDE message, or + // + // b) resend the entire message in the case of an MPE message. + // + // Therefore, we simply restart the script state machine. + // + + // + // tell ISR to restart the script + // + + return( ISR_RESTART_SCRIPT); + +} // ProcessErrorMsgSent + + + +UCHAR +ProcessGrossError( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine processes gross scsi errors. See 53C8xx data manual for + a description of gross errors. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + DebugPrint((3, "Sym8xx(%2x) SCSI Gross Error occurred \n", + DeviceExtension->SIOPRegisterBase)); + + // + // A gross error implies the hardware or SCSI device is in an unknown + // state. We reset the chip and SCSI bus in hopes that the problem will + // not recur. + // + + // + // reset SIOP + // + + InitializeSIOP( DeviceExtension); + + // + // reset SCSI bus + // + + ResetSCSIBus( DeviceExtension); + + return( ISR_START_NEXT_REQUEST); + +} // ProcessGrossError + + +UCHAR +ProcessIllegalInstruction( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine is called when illegal script instruction is fetched by + the 53C8xx. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + ULONG ScriptPhysAddr; + + DebugPrint((1, + "Sym8xx(%2x) Sym8xxDMAInterrupt: Illegal script instruction \n", + DeviceExtension->SIOPRegisterBase + )); + + // + // if a WAIT DISCONNECT has generated an ILLEGAL INSTRUCTION interrupt, + // meaning that we have been reselected before the WAIT DISCONNECT could + // be fetched and processed, we must determine why the device + // disconnected. We do this by fetching the next script instruction, + // which should be an INT instruction, and processing it. + // + + if ( READ_SIOP_UCHAR( DCMD) == DCMD_WAIT_DISCONNECT) + { + DebugPrint((1, + "Sym8xx(%2x) Sym8xxDMAInterrupt: Illegal WAIT DISCONNECT \n", + DeviceExtension->SIOPRegisterBase + )); + + // + // get the physical address of the next script instruction. + // + + ScriptPhysAddr = READ_SIOP_ULONG(DSP); + + // + // start the script instruction. + // + + StartSIOP( DeviceExtension, ScriptPhysAddr); + + return( ISR_EXIT); + } + + // + // if we reach here, either scripts have been corrupted in memory or the + // hardware is hosed. since we can't do anything about the former case, + // we will assume the latter and reset everything. + // + + // + // reset SIOP + // + + InitializeSIOP( DeviceExtension); + + // + // reset SCSI bus + // + + ResetSCSIBus( DeviceExtension); + + return( ISR_START_NEXT_REQUEST); + +} // ProcessIllegalInstruction + + +UCHAR +ProcessInvalidReselect( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine is called when a device reselects that did not disconnect. + Since something is really broken at this point, we just reset everything + we can, and hope for the best. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + DebugPrint((1, "Sym8xx(%2x) Sym8xxDMAInterrupt: Invalid Reselect \n", + DeviceExtension->SIOPRegisterBase + )); + + // + // reset SIOP + // + + InitializeSIOP( DeviceExtension); + + // + // reset SCSI bus + // + + ResetSCSIBus( DeviceExtension); + + return( ISR_START_NEXT_REQUEST); + +} // ProcessInvalidReselect + + +UCHAR +ProcessParityError( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine processes parity errors detected on the SCSI bus by the + host adapter. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + // + // we must determine if we are in message in phase, or some other phase, + // since we must send a different message for each case. + // + + DebugPrint((1, "Sym8xx(%2x) ProcessParityError: Parity error detected \n", + DeviceExtension->SIOPRegisterBase)); + + // + // check if SCSI bus message line is high. if so, send MESSAGE PARITY + // message, and if not, send INITIATOR DETECTED ERROR message. + // + + if ( READ_SIOP_UCHAR(SBCL) & SBCL_MSG) + { + DeviceExtension->NonCachedExtension->ParityMsgData = + SCSIMESS_MESS_PARITY_ERROR; + } + + else + { + DeviceExtension->NonCachedExtension->ParityMsgData = + SCSIMESS_INIT_DETECTED_ERROR; + } + + // + // Start script to send the appropriate message to device. + // + + StartSIOP( DeviceExtension, DeviceExtension->SendIDEScriptPhys); + + return( ISR_EXIT); + +} // ProcessParityError + + +UCHAR +ProcessPhaseMismatch( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine is called when a phase mismatch occurs during a data + transfer. This normally occurs when a device wishes to disconnect + mid-transfer to move to a new cylinder, etc. + + The routine determines how much data the 53C8xx has transferred + and how much remains in the chip, and updates pointers accordingly. + + The # of scatter/gather move instructions successfully completed before + the phase mismatch occurred is returned in the SCRATCH0 register. A + value of FF in this register indicates the mismatch did not occur in + DATA phase. This happens with some drives that get confused during + synchronous negotiation. + + If the mismatch occurred in a DATA phase, we set a flag to indicate that + a mismatch has occurred. When the device issues a SAVE DATA POINTER + message, we use the value calculated by this routine to determine the + new pointer value. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + ISR_RESTART_SCRIPT to continue normally + ISR_START_NEXT_REQUEST if error +--*/ + +{ + PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest; + ULONG BytesRemaining = 0; + ULONG DataTransferred = 0; + UCHAR ScsiStatus; + UCHAR ScsiStatus2; + UCHAR ScriptMoveIndex; + USHORT FIFOCount; + USHORT DMAFifoByteCount = 0; + UCHAR ArrayIndexStart; + UCHAR ArrayIndexEnd; + ULONG ScriptPhysAddr; + PSCRIPTDATASTRUCT ScriptDataPtr = + &DeviceExtension->NonCachedExtension->ScriptData; + UCHAR i; + SCRIPTSG SampleBuffer; + PVOID VirtualBufferPointer; + ULONG RemainingDataCount; + ULONG ElementLength; + UCHAR MovedData = 0; + UCHAR SCNTL2Reg; + UCHAR DataValue; + ULONG BufferUlongAddress; + + // + // if this phase mismatch occurred during a data phase, the value + // returned in the scratch0 register will not be FF. + // + + DebugPrint((3, "Sym8xx(%2x) ProcessPhaseMismatch: Mismatch Occurred \n", + DeviceExtension->SIOPRegisterBase)); + + // + // get physical address of script instruction upon which we changed + // phases. Note that the DSP register points to the instruction following + // the one we want, so we must back up one instruction. + // + + ScriptPhysAddr = READ_SIOP_ULONG(DSP); + + ScriptPhysAddr -= SCRIPT_INS_SIZE; + + // + // Calculate the index into the script move array upon which we changed + // phases: subtract the physical address of the first script move + // from the address calculated above, and divide by 8 to convert into + // an index (8 bytes per move instruction). + // + + if (ScriptPhysAddr <= (DeviceExtension->DataOutStartPhys + + sizeof(SCRIPTINS))) + { + ScriptMoveIndex = (UCHAR) (( DeviceExtension->DataOutStartPhys - + ScriptPhysAddr) >> 3); + + Srb->SrbFlags &= ~SRB_FLAGS_DATA_IN; + } + + else + { + ScriptMoveIndex = (UCHAR) (( DeviceExtension->DataInStartPhys - + ScriptPhysAddr) >> 3); + + Srb->SrbFlags &= ~SRB_FLAGS_DATA_OUT; + } + + if ( ScriptMoveIndex < MAX_PHYS_BREAK_COUNT) + { + DebugPrint((3, + "Sym8xx(%2x) ProcessPhaseMismatch: Moves processed = %x\n", + DeviceExtension->SIOPRegisterBase, + ScriptMoveIndex + )); + + // + // get 24 bit BYTES REMAINING counter for this S/G entry from SIOP. + // + + for ( i = 0; i < 3; i++) + { + ((PUCHAR) (&BytesRemaining))[i] = READ_SIOP_UCHAR( DBC[i]); + } + + // + // if the request was a write, we must determine how much data + // remains in the SIOP FIFO's. + // + + if ( Srb->SrbFlags & SRB_FLAGS_DATA_OUT) + { + // 875s' large FIFO / normal 64 byte FIFO + // get the low 10 / 7 bits of the DMA FIFO, and subtract the low + // 10 / 7 bytes of the # of bytes remaining, and clear the hi bit of + // the resultant byte. + // + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_875_LARGE_FIFO) + { + DMAFifoByteCount = (USHORT)READ_SIOP_UCHAR(DFIFO); + DMAFifoByteCount |= (USHORT)((READ_SIOP_UCHAR(CTEST5)&0x03)<<8); + FIFOCount = DMAFifoByteCount - (USHORT)(BytesRemaining & 0x3FF); + FIFOCount &= 0x3FF; + } + + else + { + FIFOCount = (( READ_SIOP_UCHAR( DFIFO) + & (UCHAR) DFIFO_LOW_SEVEN) + - (UCHAR) ( BytesRemaining & 0x07f)) + & (UCHAR) DFIFO_LOW_SEVEN; + } + + // + // if the SCSI output data register contains a byte, increment + // the FIFO count. + // + // Possible chip bug reported by CHC (DEC) Under heavy scsi traffic, + // the SSTAT1_ORF bit will get lit for some reason when the transfer + // is asynchronous. This bit should *only* be checked + // during synchronous transfers. + // + + if (((ScsiStatus = READ_SIOP_UCHAR(SSTAT0)) & (UCHAR) SSTAT1_ORF) && + !(DeviceExtension->LuFlags[Srb->TargetId] & + LUFLAGS_SYNC_NEGOT_FAILED)) + { + FIFOCount += 1; + } + + if (((ScsiStatus2 = READ_SIOP_UCHAR(SSTAT2)) & (UCHAR) SSTAT2_ORF) && + !(DeviceExtension->LuFlags[Srb->TargetId] & + LUFLAGS_SYNC_NEGOT_FAILED)) + { + FIFOCount += 1; + } + + // + // if the SCSI output data latch contains a byte, increment + // the FIFO count. + // + + if ( ScsiStatus & SSTAT1_OLF) + { + FIFOCount += 1; + } + + if ( ScsiStatus2 & (UCHAR) SSTAT2_OLF) + { + FIFOCount += 1; + } + + // + // add the FIFO count to the bytes remaining. + // + + BytesRemaining += (ULONG) FIFOCount; + + // + // clear the DMA and SCSI FIFO's + // + + WRITE_SIOP_UCHAR( CTEST3, CTEST3_CLEAR_FIFO); + + // insure the WSS bit is off so the low order byte stored in the chip + // will be forgotten about. (chmov script instruction) stored in + // SODL register so the fifo count has already been taken care of + + if ( (SCNTL2Reg = READ_SIOP_UCHAR(SCNTL2)) & SCNTL2_WSS) + { + WRITE_SIOP_UCHAR(SCNTL2, (UCHAR)(SCNTL2Reg & ~SCNTL2_WSS)); + } + + } // if for data out checks + + else // data in section + { + // if the WSR bit is on, the chip is retaining a byte in the swide + // register which we need to manually put into its RAM space. This + // byte will always be at the start of a scatter\gather section so + // we only need to scan the virtual buffers break points for the + // location to stick the byte. (wide transfer - odd byte scatter/ + // gather lists possibility. + + if ( (SCNTL2Reg = READ_SIOP_UCHAR(SCNTL2)) & SCNTL2_WSR) + { + DataValue = READ_SIOP_UCHAR(SWIDE); + WRITE_SIOP_UCHAR(SCNTL2, (UCHAR)(SCNTL2Reg & ~SCNTL2_WSR)); + BytesRemaining--; + BufferUlongAddress = + ScriptDataPtr->SGBufferArray[ScriptMoveIndex + 1].SGBufferPtr; + VirtualBufferPointer = Srb->DataBuffer; + RemainingDataCount = Srb->DataTransferLength; + do + { + SampleBuffer.SGBufferPtr = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( + DeviceExtension, + Srb, + VirtualBufferPointer, + &ElementLength)); + if ( BufferUlongAddress == SampleBuffer.SGBufferPtr ) + { + *(PUCHAR)VirtualBufferPointer = DataValue; + MovedData = 1; + RemainingDataCount = 0; + } + + else + { + if ( ElementLength > RemainingDataCount ) + { + ElementLength = RemainingDataCount; + } + + (ULONG)VirtualBufferPointer += ElementLength; + RemainingDataCount -= ElementLength; + } + } while ( RemainingDataCount ); + + if ( !MovedData ) + { + // if we're here, pointers have gotten messed up, just reset + InitializeSIOP(DeviceExtension); + ResetSCSIBus(DeviceExtension); + return(ISR_START_NEXT_REQUEST); + } + } + } + + // + // loop through all the moves that were processed to get the total + // byte count moved before the SAVE DATA PTRS. + // + + ArrayIndexStart = MAX_SG_ELEMENTS - SRB_EXT(Srb)->PhysBreakCount; + ArrayIndexEnd = ArrayIndexStart + SRB_EXT(Srb)->PhysBreakCount - + ScriptMoveIndex - 1; + + for ( i = ArrayIndexStart; i <= ArrayIndexEnd; i++) + { + DataTransferred += ScriptDataPtr->SGBufferArray[i].SGByteCount; + } + + // + // subtract the bytes remaining on the last move processed from the + // total bytes transferred, and store this value. + // + + SRB_EXT(Srb)->DataTransferred = DataTransferred - BytesRemaining; + } + + + else + { + // + // the phase mismatch did not occur during a data phase. + // this will happen in cases such as a phase change during an + // extended message. flush the FIFO's and exit. + // + + WRITE_SIOP_UCHAR( CTEST3, CTEST3_CLEAR_FIFO); + } + + // + // tell ISR to restart script state machine + // + + return(ISR_RESTART_SCRIPT); + +} // ProcessPhaseMismatch + + +BOOLEAN +ProcessParseArgumentString( + IN PCHAR String, + IN PCHAR WantedString, + OUT PULONG ValueFound + ) + +/****************************************************************************** + +Routine Description: + + This routine will parse the string for a match on the wanted string, then + calculate the value for the wnated string and return it to the caller. + +Arguments: + + String - The ASCII string to parse. + WantedString - The keyword for the value desired. + ValueFound - address where the value found is placed + +Return Values: + + TRUE if WantedString found, FALSE if not + ValueFound converted from ASCII to binary. + +--*/ + +{ + PCHAR cptr; + PCHAR kptr; + ULONG stringLength = 0; + ULONG WantedStringLength = 0; + ULONG index; + + // + // Calculate the string length and lower case all characters. + // + cptr = String; + while (*cptr) + { + if (*cptr >= 'A' && *cptr <= 'Z') + { + *cptr = *cptr + ('a' - 'A'); + } + + cptr++; + stringLength++; + } + + // + // Calculate the wanted strings length and lower case all characters. + // + cptr = WantedString; + while (*cptr) + { + if (*cptr >= 'A' && *cptr <= 'Z') + { + *cptr = *cptr + ('a' - 'A'); + } + + cptr++; + WantedStringLength++; + } + + if (WantedStringLength > stringLength) + { + // Can't possibly have a match. + return FALSE; + } + + // + // Now setup and start the compare. + // + cptr = String; + +ContinueSearch: + // + // The input string may start with white space. Skip it. + // + while (*cptr == ' ' || *cptr == '\t') + { + cptr++; + } + + if (*cptr == '\0') + { + // end of string. + return FALSE; + } + + kptr = WantedString; + while (*cptr++ == *kptr++) + { + if (*(cptr - 1) == '\0') + // end of string + return FALSE; + } + + if (*(kptr - 1) == '\0') + { + // May have a match backup and check for blank or equals. + cptr--; + while (*cptr == ' ' || *cptr == '\t') + { + cptr++; + } + + // Found a match. Make sure there is an equals. + if (*cptr != '=') + { + // Not a match so move to the next semicolon. + while (*cptr) + { + if (*cptr++ == ';') + goto ContinueSearch; + } + return FALSE; + } + + // Skip the equals sign. + cptr++; + + // Skip white space. + while ((*cptr == ' ') || (*cptr == '\t')) + cptr++; + + if (*cptr == '\0') + // Early end of string, return not found + return FALSE; + + if (*cptr == ';') + { + // This isn't it either. + cptr++; + goto ContinueSearch; + } + + *ValueFound = 0; + if ((*cptr == '0') && (*(cptr + 1) == 'x')) + { + // Value is in Hex. Skip the "0x" + cptr += 2; + for (index = 0; *(cptr + index); index++) + { + if (*(cptr + index) == ' ' || *(cptr + index) == '\t' || + *(cptr + index) == ';') + { + break; + } + + if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) + { + *ValueFound = (16 * (*ValueFound)) + (*(cptr + index) - '0'); + } + + else + { + if ((*(cptr + index) >= 'a') && (*(cptr + index) <= 'f')) + { + *ValueFound = (16 * (*ValueFound)) + (*(cptr + index) - 'a' + 10); + } + else + { + // Syntax error, return not found. + return FALSE; + } + } + } + } + + else + { + // Value is in Decimal. + for (index = 0; *(cptr + index); index++) + { + if (*(cptr + index) == ' ' || *(cptr + index) == '\t' || + *(cptr + index) == ';') + { + break; + } + + if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) + { + *ValueFound = (10 * (*ValueFound)) + (*(cptr + index) - '0'); + } + + else + { + // Syntax error return not found. + return FALSE; + } + } + } + + return TRUE; + } + + else + { + // Not a match check for ';' to continue search. + while (*cptr) + { + if (*cptr++ == ';') + goto ContinueSearch; + } + } + + return FALSE; + +} // ProcessParseArgumentString + + +UCHAR +ProcessQueueTagReceived( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine is called when the target sends a queue tag messaged as + part of reselected. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + Returns the action to be taken after the interrupt. + +--*/ + +{ + UCHAR Tag; + DebugPrint((2, "Sym8xx(%2x) Queue tag messaged received \n", + DeviceExtension->SIOPRegisterBase)); + + // + // Clear the connection flag. + // + + DeviceExtension->DeviceFlags &= ~DFLAGS_CONNECTED; + + // + // Get the tag from the message buffer; + // + + Tag = DeviceExtension->NonCachedExtension->MsgInBuf[0]; + + // + // Get the active SRB. + // + + DeviceExtension->ActiveRequest = ScsiPortGetSrb( DeviceExtension, + 0, + DeviceExtension->TargetId, + DeviceExtension->LUN, + Tag + ); + + // + // See if this is a tagged request. + // + + if (DeviceExtension->ActiveRequest == NULL) + { + DebugPrint((1, + "Sym8xx(%2x): Invalid Tag, Path=%2x Id= %2x, Tag = %2x\n", + DeviceExtension->SIOPRegisterBase, + DeviceExtension->ScsiBusNumber, + DeviceExtension->TargetId, + Tag)); + + // + // either we were SELECTED, or something is really hosed. + // perform drastic error recovery. + // + + InitializeSIOP( DeviceExtension); + ResetSCSIBus( DeviceExtension); + return( ISR_START_NEXT_REQUEST); + } + + // + // if there is data to transfer set up scatter/gather. + // + + if (DeviceExtension->ActiveRequest->SrbFlags & + SRB_FLAGS_UNSPECIFIED_DIRECTION ) + { + ScatterGatherScriptSetup( DeviceExtension, + DeviceExtension->ActiveRequest->SrbExtension + ); + } + + return( ISR_RESTART_SCRIPT); + +} // ProcessQueueTagReceived + + +UCHAR +ProcessRejectReceived( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine is called when a device rejects a message sent in scripts. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + PSCSI_REQUEST_BLOCK Srb; + + DebugPrint((1, + "Sym8xx(%2x) ProcessDMAInterrupt: Message reject received \n", + DeviceExtension->SIOPRegisterBase + )); + + Srb = DeviceExtension->ActiveRequest; + + if ((DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_WIDE_NEGOT_PEND) || + (DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_NARROW_NEGOT_PEND)) + { + return( ProcessWideNotSupported( DeviceExtension, Srb->TargetId)); + } + + if ((DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_SYNC_NEGOT_PEND) || + (DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_ASYNC_NEGOT_PEND)) + { + return( ProcessSynchNotSupported( DeviceExtension)); + } + + // + // the rejected message + // + + return( ISR_RESTART_SCRIPT); + +} // ProcessRejectReceived + + +UCHAR +ProcessReselection( + PHW_DEVICE_EXTENSION DeviceExtension, + UCHAR TargetID + ) +/****************************************************************************** + +Routine Description: + + This routine handles a normal device reselection. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension; + UCHAR LUN; + + // + // check if there is an active request. if so, we preempted someone + // who was trying to start a new request. + // + + if ( DeviceExtension->ActiveRequest != NULL) + { + // + // put this guy back on holding queue. + // + + DeviceExtension->NextSrbToProcess = DeviceExtension->ActiveRequest; + + // + // indicate no active request + // + + DeviceExtension->ActiveRequest = NULL; + + DebugPrint((3, "Sym8xx(%2x) Preemptive reselection, Path=%2x Id=%2x\n", + DeviceExtension->SIOPRegisterBase, + DeviceExtension->ScsiBusNumber, + TargetID + )); + } + + DebugPrint((3, "Sym8xx(%2x) Reselection by Path=%2x Id=%2x \n ", + DeviceExtension->SIOPRegisterBase, + DeviceExtension->ScsiBusNumber, + TargetID + )); + + // + // retrieve LUN from MESSAGE IN buffer + // + + LUN = (UCHAR) ( DeviceExtension->NonCachedExtension->MsgInBuf[0] & + SCSIMESS_IDENTIFY_LUN_MASK); + + DeviceExtension->TargetId = TargetID; + DeviceExtension->LUN = LUN; + + // + // get logical unit extension for this ID/LUN. + // + + LuExtension = ScsiPortGetLogicalUnit( DeviceExtension, + DeviceExtension->BusNumber, + TargetID, + LUN + ); + // + // Confirm that this is a valid logical unit. + // + + if (LuExtension == NULL) + { + DebugPrint((1, "Sym8xx(%2x): Invalid reselection, Path=%2x Id=%2x \n", + DeviceExtension->SIOPRegisterBase, + DeviceExtension->ScsiBusNumber, + TargetID + )); + TargetID = READ_SIOP_UCHAR(SSID); + + // + // Temporary workaround for chip anomoly + // + // TODO: Find out why this occurs, if it still occurs. + // + + if (TargetID & 0x80) + { + TargetID &= 0x07; + LuExtension = ScsiPortGetLogicalUnit( DeviceExtension, + DeviceExtension->BusNumber, + TargetID, + LUN + ); + } + + else + { + DebugPrint((1, "Sym8xx(%2x): Still invalid, Path=%2x Id=%2x \n", + DeviceExtension->SIOPRegisterBase, + DeviceExtension->ScsiBusNumber, + TargetID + )); + } + + // + // either we were SELECTED, or something is really hosed. + // perform drastic error recovery. + // + + DebugPrint((0,"Reselection Error[1] \n")); + InitializeSIOP( DeviceExtension); + ResetSCSIBus( DeviceExtension); + return( ISR_START_NEXT_REQUEST); + + } // if + + // + // decrement depth counter for disconnected requests + // + + if ( DeviceExtension->DisconnectedCount[TargetID] != 0 ) + { + DeviceExtension->DisconnectedCount[TargetID]-- ; + } + + // + // See if this is a tagged request. + // + + DeviceExtension->ActiveRequest = LuExtension->UntaggedRequest; + + if (DeviceExtension->ActiveRequest == NULL) + { + // + // Set the connection flag, etc.. + // + + DeviceExtension->DeviceFlags |= DFLAGS_CONNECTED; + DeviceExtension->DeviceFlags |= DFLAGS_TAGGED_SELECT; + + // + // This request must be tagged, process the tagged message. + // + + StartSIOP( DeviceExtension, DeviceExtension->QueueTagPhys); + return( ISR_EXIT); + } + + DeviceExtension->DeviceFlags &= ~DFLAGS_TAGGED_SELECT; + + // + // If there is data to transfer set up scatter/gather. + // + + if (DeviceExtension->ActiveRequest->SrbFlags & + SRB_FLAGS_UNSPECIFIED_DIRECTION) + { + ScatterGatherScriptSetup( DeviceExtension, + DeviceExtension->ActiveRequest->SrbExtension + ); + } + + // + // tell ISR to restart script state machine + // + + return( ISR_RESTART_SCRIPT); + +} // ProcessReselection + + +UCHAR +ProcessRestorePointers( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine restores the data pointers if they exist. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + // + // If there is data to transfer set up scatter/gather. + // + + if ( DeviceExtension->ActiveRequest->SrbFlags & + SRB_FLAGS_UNSPECIFIED_DIRECTION) + { + ScatterGatherScriptSetup( DeviceExtension, + DeviceExtension->ActiveRequest->SrbExtension + ); + } + + // + // tell ISR to restart script state machine + // + + return( ISR_RESTART_SCRIPT); + +} // ProcessRestorePointers + + +UCHAR +ProcessSaveDataPointers( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine determines how much data was transferred before the SAVE + DATA PTRS message was received, and updates pointers accordingly. + + The # of scatter/gather move instructions successfully completed before + the SAVE DATA PTRS occurred is returned in the SCRATCH0 register. A + value of FF in this register indicates that no data was transferred. + If a phase mismatch occurred before we arrived here, a flag was set to + a mismatch has occurred. When the device issues a SAVE DATA POINTER + indicate the mismatch, and the value of scratch0 was saved at that time. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + PSRB_EXTENSION SrbExtension = DeviceExtension->ActiveRequest->SrbExtension; + + // + // compute the new pointers. + // + + SrbExtension->SavedDataPointer += SrbExtension->DataTransferred; + SrbExtension->SavedDataLength -= SrbExtension->DataTransferred; + + // + // tell the ISR to restart the script and complete the request. + // + + return( ISR_RESTART_SCRIPT); + +} // ProcessSaveDataPointers + + +UCHAR +ProcessSCSIInterrupt( + PHW_DEVICE_EXTENSION DeviceExtension, + UCHAR ScsiStatus + ) +/****************************************************************************** + +Routine Description: + + This routine processes interrupts from the SCSI core of the 53C8xx SIOP. + +Arguments: + + Context - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + TRUE + +--*/ + +{ + // + // todo - decide whether to move critical path SCSI interrupt processing + // up from subroutines to reduce overhead. + // + + // + // if a SCSI bus reset is detected, call routine to process, and return + // disposition code to ISR. + // + + if ( ScsiStatus & SSTAT0_RESET) + { + return( ProcessBusResetReceived( DeviceExtension)); + } + + // + // The following SCSI interrupts should only occur when we have an + // active SRB. To be safe, we check for one. If there is not an + // active SRB, the hardware has interrupted inappropriately, + // so reset everything. + // + + if (DeviceExtension->ActiveRequest == NULL) + { + DebugPrint((1, "Sym8xx(%2x) ProcessSCSIInterrupt unknown request\n", + DeviceExtension->SIOPRegisterBase)); + DebugPrint((1, " ActiveRequest: %lx ScsiStatus: %x\n", + DeviceExtension->ActiveRequest, ScsiStatus)); + + InitializeSIOP( DeviceExtension); + ResetSCSIBus( DeviceExtension); + return( ISR_START_NEXT_REQUEST); + } + + // + // if a SCSI phase mismatch occurred call routine to process, and return + // disposition code to ISR. + // + + if ( ScsiStatus & SSTAT0_PHASE_MISMATCH) + { + return( ProcessPhaseMismatch( DeviceExtension)); + } + + // + // if a SCSI gross error occurred call routine to process, and return + // disposition code to ISR. + // + + if ( ScsiStatus & SSTAT0_GROSS_ERROR) + { + return( ProcessGrossError( DeviceExtension)); + } + + // + // if an unexpected disconnect occurred call routine to process, and + // return disposition code to ISR. + // + + if ( ScsiStatus & SSTAT0_UNEXPECTED_DISCONNECT) + { + return( ProcessUnexpectedDisconnect( DeviceExtension)); + } + + // + // if a parity error was detected call routine to process, and return + // disposition code to ISR. + // + + if ( ScsiStatus & SSTAT0_PARITY_ERROR) + { + return( ProcessParityError( DeviceExtension)); + } + + // + // if none of the above, the hardware is in an unknown state. Perform + // drastic error recovery. + // + + InitializeSIOP( DeviceExtension); + ResetSCSIBus( DeviceExtension); + return( ISR_START_NEXT_REQUEST); + +} // ProcessSCSIInterrupt + + +UCHAR +ProcessSelectionTimeout( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine processes selection timeouts. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + PSCSI_REQUEST_BLOCK Srb; + PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension; + + // + // the 53C8xx SIOP generates an UNEXPECTED DISCONNECT interrupt along + // with SELECTION TIMEOUT. We read the SCSI STATUS register to throw + // it away. This is safe since no additional SCSI interrupt should have + // been generated at this time. + // + + READ_SIOP_UCHAR( SIST0); + + // + // get the logical unit extension and SRB for the request that timed out. + // + + Srb = DeviceExtension->ActiveRequest; + + if (!Srb) + { + return ISR_EXIT; + } + + DebugPrint((1, + "Sym8xx(%2x) SelectionTimeout: Timeout for Path=%2x Id=%2x \n", + DeviceExtension->SIOPRegisterBase, + DeviceExtension->ScsiBusNumber, + Srb->TargetId + )); + + // + // indicate this request is no longer active. + // + + DeviceExtension->ActiveRequest = NULL; + + if (!(Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) ) + { + LuExtension = ScsiPortGetLogicalUnit( DeviceExtension, + Srb->PathId, + Srb->TargetId, + Srb->Lun + ); + + LuExtension->UntaggedRequest = NULL; + } + + // + // indicate selection timeout occurred and notify superiors. + // + + Srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT; + + ScsiPortNotification( RequestComplete, + DeviceExtension, + Srb + ); + + // + // tell ISR to start new request. + // + + return( ISR_START_NEXT_REQUEST); + +} // ProcessSelectionTimeout + + +UCHAR +ProcessSynchNegotComplete( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine handles successful synchronous negotiation. The routine + first retrieves the synchronous period and offset from the message in + buffer, then massages the parameters into a form the SIOP can use. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + UCHAR RecvdSynchPeriod; + UCHAR RecvdSynchOffset; + UCHAR SynchIndex = 0; + UCHAR Scntl3Value; + UCHAR EffectiveClockSpeed; + UCHAR MaxOffset, MinPeriod; + UCHAR SynchPeriod; + PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest; + PSCRIPTDATASTRUCT ScriptDataPtr = + &DeviceExtension->NonCachedExtension->ScriptData; + + if (!(DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_SYNC_NEGOT_PEND) && + !(DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_ASYNC_NEGOT_PEND)) + { + DebugPrint((1, + "Sym8xx(%2x) ProcessSynchNegotComplete: Rejecting SDTR message.\n", + DeviceExtension->SIOPRegisterBase + )); + + // + // If we are not doing negotation then reject this request. + // + + DeviceExtension->SyncParms[Srb->TargetId] = ASYNCHRONOUS_MODE_PARAMS; + ScriptDataPtr->SelectDataSXFER=DeviceExtension->SyncParms[Srb->TargetId]; + WRITE_SIOP_UCHAR (SXFER, DeviceExtension->SyncParms[Srb->TargetId] ); + + StartSIOP( DeviceExtension, DeviceExtension->RejectScriptPhys); + + // + // We're here if the target device has tried to negotiate sync with + // us when we don't support the target initiating the negotiation. + // Now, make sure we do not think that this device is still in SYNCH. + // transfer mode from some earlier successful negotiation. We'll i + // redo it all on the next command with US as the initiator. + // + + DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_SYNC_NEGOT_DONE; + + return( ISR_EXIT); + } + + // + // If we were trying Asynch negotiations, cleanup is a lot less + // + + if ( DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_ASYNC_NEGOT_PEND ) + { + + // + // indicate we are no longer expecting a negotiation reply + // + + DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_ASYNC_NEGOT_PEND + + LUFLAGS_SYNC_NEGOT_PEND); + + // + // pick up offset from Script message buffer + // + + RecvdSynchOffset = DeviceExtension->NonCachedExtension->MsgInBuf[1]; + + if (RecvdSynchOffset != 0) + { + DebugPrint((0, "Sym8xx(%2x) Rejecting SDTR message. Asynch failed\n", + DeviceExtension->SIOPRegisterBase + )); + + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_SYNC_NEGOT_FAILED; + + DeviceExtension->SyncParms[Srb->TargetId] = ASYNCHRONOUS_MODE_PARAMS; + WRITE_SIOP_UCHAR (SXFER, DeviceExtension->SyncParms[Srb->TargetId] ); + + // + // value out of range, reject this request. + // + + StartSIOP( DeviceExtension, DeviceExtension->RejectScriptPhys); + + return( ISR_EXIT); + } + + // + // indicate asynch params are valid, and restart the script. + // + + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_ASYNC_NEGOT_DONE; + DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_SYNC_NEGOT_DONE; + } + + else // Finish up synchronous negotiations. + { + // + // indicate we are no longer expecting a negotiation reply + // + + DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_ASYNC_NEGOT_PEND + + LUFLAGS_SYNC_NEGOT_PEND); + + // + // Clear the failed negot. flag. If needed, it will be set on failure. + // if we have done sync. values, now need to check sstat1_orf + + DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_SYNC_NEGOT_FAILED; + + // + // pick up synch period and offset from Script message buffer + // + + RecvdSynchPeriod = DeviceExtension->NonCachedExtension->MsgInBuf[0]; + RecvdSynchOffset = DeviceExtension->NonCachedExtension->MsgInBuf[1]; + + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_SYNC_16) + { + MaxOffset = MAX_875_SYNCH_OFFSET; + } + + else + { + MaxOffset = MAX_SYNCH_OFFSET; + } + + if (RecvdSynchOffset == 0) + { + MinPeriod = 0; + } + + else + { + if ((DeviceExtension->hbaCapability & HBA_CAPABILITY_FAST20) && + (DeviceExtension->hbaCapability & HBA_CAPABILITY_REGISTRY_FAST20)) + { + MinPeriod = 0x0C; + } + + else + { + MinPeriod = 0x19; + } + } + + DebugPrint((1, + "Sym8xx(%2x) SynchronousNegotiation Received - Path=%2x Id=%2x \n", + DeviceExtension->SIOPRegisterBase, + DeviceExtension->ScsiBusNumber, + Srb->TargetId + )); + + DebugPrint((1, " Period: %x Offset: %x\n", + RecvdSynchPeriod, + RecvdSynchOffset + )); + + if ( RecvdSynchOffset == 0 ) + { + DeviceExtension->SyncParms[Srb->TargetId] = ASYNCHRONOUS_MODE_PARAMS; + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_SYNC_NEGOT_FAILED; + + DebugPrint((1, "Sym8xx(%1x) Synchronous Disabled - Target: %x\n", + DeviceExtension->ScsiBusNumber, + Srb->TargetId + )); + } + + else + { + // + // Check for a FAST SCSI request. If the request is faster than 200ns + // then it is fast. + // + + EffectiveClockSpeed = DeviceExtension->ClockSpeed; + Scntl3Value = (DeviceExtension->WideParms[Srb->TargetId] & 0x0F); + + if (EffectiveClockSpeed == 80) + { + // check to see if device wants to do FAST 20 + // + + if (RecvdSynchPeriod == 0x0C) + { + Scntl3Value = (UCHAR)(Scntl3Value | 0x90); + WRITE_SIOP_UCHAR(SCNTL3, Scntl3Value); + DeviceExtension->NonCachedExtension->ScriptData.SelectDataSCNTL3 = + Scntl3Value; + DeviceExtension->WideParms[Srb->TargetId] = Scntl3Value; + DeviceExtension->SyncParms[Srb->TargetId] = RecvdSynchOffset; + } + + else // set up to check regular SCSI Sync + { + // divide 80Mhz clock by 2 so we can still use old conversion rtn + Scntl3Value = (UCHAR)(Scntl3Value | 0x30); + WRITE_SIOP_UCHAR(SCNTL3, Scntl3Value); + DeviceExtension->NonCachedExtension->ScriptData.SelectDataSCNTL3 = + Scntl3Value; + DeviceExtension->WideParms[Srb->TargetId] = Scntl3Value; + EffectiveClockSpeed = 40; + } + } + + if (EffectiveClockSpeed == 40) + { + if (DeviceExtension->ClockSpeed == 40) + { + Scntl3Value = (UCHAR)(Scntl3Value | 0x10); + WRITE_SIOP_UCHAR(SCNTL3, Scntl3Value); + DeviceExtension->NonCachedExtension->ScriptData.SelectDataSCNTL3 = + Scntl3Value; + DeviceExtension->WideParms[Srb->TargetId] = Scntl3Value; + } // if + + for (SynchIndex = 0;SynchIndex < MAX_SYNCH_TABLE_ENTRY; SynchIndex++) + { + SynchPeriod = ((1000 / EffectiveClockSpeed) * (4 + SynchIndex)) / 4; + if (RecvdSynchPeriod <= SynchPeriod) + { + DeviceExtension->SyncParms[Srb->TargetId] = + (UCHAR) (SynchIndex << 0x05) | RecvdSynchOffset; + break; + } + } // for + } // if + } // else + + // check for valid values, reject target if not OK + if ( (SynchIndex >= MAX_SYNCH_TABLE_ENTRY) || + (RecvdSynchOffset > MaxOffset) || + (RecvdSynchPeriod < MinPeriod) || + ( (RecvdSynchPeriod > 0x0C) && + (RecvdSynchPeriod < 0x19) && + (RecvdSynchOffset != 0) ) ) + { + DebugPrint((0, "Sym8xx(%2x) Rejecting SDTR message. Rate too slow\n", + DeviceExtension->SIOPRegisterBase + )); + + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_SYNC_NEGOT_FAILED; + DeviceExtension->SyncParms[Srb->TargetId] = ASYNCHRONOUS_MODE_PARAMS; + WRITE_SIOP_UCHAR (SXFER, DeviceExtension->SyncParms[Srb->TargetId] ); + + // + // values were out of our range, reject this request. + // + + StartSIOP( DeviceExtension, DeviceExtension->RejectScriptPhys); + + return( ISR_EXIT); + + } // if + + // + // indicate synch params are valid, and restart the script. + // + + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_SYNC_NEGOT_DONE; + DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_ASYNC_NEGOT_DONE; + + } // else + + // + // tell ISR to restart script state machine + // + // + + return( ISR_RESTART_SCRIPT); + +} // ProcessSynchNegotComplete + + +UCHAR +ProcessSynchNotSupported( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine handles unsuccessful synchronous negotiation. The routine + sets the synchronous parameters to asynchronous, and sets the appropriate + flag. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest; + PSCRIPTDATASTRUCT ScriptDataPtr = + &DeviceExtension->NonCachedExtension->ScriptData; + + DebugPrint((1, + "Sym8xx(%2x) Synchronous negotiation failed, Path=%2x Id=%2x \n", + DeviceExtension->SIOPRegisterBase, + DeviceExtension->ScsiBusNumber, + *((PUCHAR) &(DeviceExtension->ActiveRequest)->TargetId) + )); + + // + // indicate drive is low technology. + // + if (DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_SYNC_NEGOT_PEND) + { + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_SYNC_NEGOT_DONE + + LUFLAGS_SYNC_NEGOT_FAILED; + } + else + { + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_ASYNC_NEGOT_DONE + + LUFLAGS_SYNC_NEGOT_FAILED; + } + + // + // indicate we are no longer expecting a negotiation reply + // + DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_SYNC_NEGOT_PEND + + LUFLAGS_ASYNC_NEGOT_PEND); + + // + // set up for asynchronous xfer. + // + DeviceExtension->SyncParms[Srb->TargetId] = ASYNCHRONOUS_MODE_PARAMS; + + // + // tell ISR to restart script state machine + // + + return( ISR_RESTART_SCRIPT); + +} // ProcessSynchNotSupported + + +UCHAR +ProcessWideNegotComplete( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine handles successful wide negotiation. The routine + first retrieves the wide width from the message in + buffer, then massages the parameters into a form the SIOP can use. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + UCHAR RecvdWideWidth; + PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest; + PSCRIPTDATASTRUCT ScriptDataPtr = + &DeviceExtension->NonCachedExtension->ScriptData; + PHW_NONCACHED_EXTENSION NonCachedExt = DeviceExtension->NonCachedExtension; + ULONG MessageCount=0; + + if (!(DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_WIDE_NEGOT_PEND)&& + !(DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_NARROW_NEGOT_PEND)) + { + DebugPrint((1, + "Sym8xx(%1x) ProcessWideNegotComplete: Rejecting SDTR message.\n", + DeviceExtension->ScsiBusNumber + )); + + // + // If we are not doing negotation then reject this request. + // + + StartSIOP( DeviceExtension, DeviceExtension->RejectScriptPhys); + + // + // We're here if the target device has tried to negotiate wide with + // us when we don't support the target initiating the negotiation. + // Now, make sure we do not think that this device is still in WIDE + // transfer mode from some earlier successful negotiation. We'll i + // redo it all on the next command with US as the initiator. + // + + DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_WIDE_NEGOT_DONE + + LUFLAGS_NARROW_NEGOT_DONE); + + return( ISR_EXIT); + } // if + + if (DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_WIDE_NEGOT_PEND) + { + // + // indicate we are no longer expecting a negotiation reply + // + DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_WIDE_NEGOT_PEND + + LUFLAGS_NARROW_NEGOT_PEND); + + // + // Assume that wide neg. reset any synch/asynch settings + // + DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_SYNC_NEGOT_DONE + + LUFLAGS_ASYNC_NEGOT_DONE); + + // + // pick up wide width from Script message buffer + // + RecvdWideWidth = DeviceExtension->NonCachedExtension->MsgInBuf[0]; + + DebugPrint((1, "Sym8xx(%1x) WideNegotiation Received - Target: %x\n", + DeviceExtension->ScsiBusNumber, + Srb->TargetId + )); + + if (RecvdWideWidth == 0) + { + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_WIDE_NEGOT_FAILED; + DeviceExtension->WideParms[Srb->TargetId] &= ~ENABLE_WIDE; + DebugPrint((1, "Sym8xx(%1x) Wide Disabled - Target: %x\n", + DeviceExtension->ScsiBusNumber, + Srb->TargetId + )); + } + + else + { + DeviceExtension->WideParms[Srb->TargetId] |= ENABLE_WIDE; + DebugPrint((1, "Sym8xx(%1x) WideNegotiation Agreed - Target: %x\n", + DeviceExtension->ScsiBusNumber, + Srb->TargetId + )); + } + + // + // indicate wide params are valid, and restart the script. + // + DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_NARROW_NEGOT_DONE; + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_WIDE_NEGOT_DONE; + } + + else + { + // + // indicate we are no longer expecting a negotiation reply + // + DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_NARROW_NEGOT_PEND + + LUFLAGS_WIDE_NEGOT_PEND); + + // + // Assume that narrow neg. reset any synch/asynch settings + // + DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_SYNC_NEGOT_DONE + + LUFLAGS_ASYNC_NEGOT_DONE); + + // + // pick up wide width from Script message buffer + // + RecvdWideWidth = DeviceExtension->NonCachedExtension->MsgInBuf[0]; + + DebugPrint((1, "Sym8xx(%1x) NarrowNegotiation Received - Target: %x\n", + DeviceExtension->ScsiBusNumber, + Srb->TargetId + )); + + if (RecvdWideWidth != 0) + { + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_WIDE_NEGOT_FAILED; + DeviceExtension->WideParms[Srb->TargetId] &= ~ENABLE_WIDE; + DebugPrint((1, "Sym8xx(%1x) Wide Disabled - Target: %x\n", + DeviceExtension->ScsiBusNumber, + Srb->TargetId + )); + } + + else + { + DeviceExtension->WideParms[Srb->TargetId] &= ~ENABLE_WIDE; + DebugPrint((1, "Sym8xx(%1x) NarrowNegotiation Agreed - Target: %x\n", + DeviceExtension->ScsiBusNumber, + Srb->TargetId + )); + } + + // + // indicate wide params are valid, and restart the script. + // + DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_WIDE_NEGOT_DONE; + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_NARROW_NEGOT_DONE; + } + + // + // check on synch/asynch negotiations + // + if ((!(DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_SYNC_NEGOT_DONE) + && !( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER )) + || (!(DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_ASYNC_NEGOT_DONE) + && ( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER )) ) + { + // + // fill in the parameters for SDTR extended message + // + NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_EXTENDED_MESSAGE; + NonCachedExt->MsgOutBuf[MessageCount++] = 3; // 3 message bytes + NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_SYNCHRONOUS_DATA_REQ; + + if (!( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER)) + { + // + // Clear any synchronous negotiations + // + DeviceExtension->SyncParms[Srb->TargetId]=ASYNCHRONOUS_MODE_PARAMS; + + // + // indicate sync negotiation is not done + // + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_SYNC_NEGOT_PEND; + DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_ASYNC_NEGOT_PEND; + + // + // Initialize sync period to maximum supported + // + // Period = ((1000 / (ClockSpeed / 1)) * (4 + xferp)) / 4 + // where xferp = 0 + // modified for FAST20 devices, set msg byte to 0x0C since divide + // of 1000 by 80 equals 12.5 + // + if ((DeviceExtension->hbaCapability & HBA_CAPABILITY_FAST20) && + (DeviceExtension->hbaCapability & HBA_CAPABILITY_REGISTRY_FAST20)) + { + NonCachedExt->MsgOutBuf[MessageCount++] = 12; + } + + else + { + NonCachedExt->MsgOutBuf[MessageCount++] = 25; + } + + // + // Initialize sync offset to maximum + // + + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_SYNC_16) + { + NonCachedExt->MsgOutBuf[MessageCount++] = MAX_875_SYNCH_OFFSET; + } + + else + { + NonCachedExt->MsgOutBuf[MessageCount++] = MAX_SYNCH_OFFSET; + } + + DebugPrint((1, + "Sym8xx(%2x): SynchronousNegotiation Requested - Target: %x\n", + DeviceExtension->SIOPRegisterBase, + (DeviceExtension->ActiveRequest)->TargetId + )); + + DebugPrint((1, " Period: %x Offset: %x\n", + NonCachedExt->MsgOutBuf[MessageCount-2], + MAX_SYNCH_OFFSET + )); + } + + else + { + // + // Clear any synchronous negotiations + // + DeviceExtension->SyncParms[Srb->TargetId]=ASYNCHRONOUS_MODE_PARAMS; + + // + // indicate async negotiation is not done + // + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_ASYNC_NEGOT_PEND; + DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_SYNC_NEGOT_PEND; + + // + // Initialize sync period to 0 + // + NonCachedExt->MsgOutBuf[MessageCount++] = 0; + + // + // Initialize sync offset to 0 + // + NonCachedExt->MsgOutBuf[MessageCount++] = 0; + + DebugPrint((1, + "Sym8xx(%2x): AsynchronousNegotiation Requested - Target: %x\n", + DeviceExtension->SIOPRegisterBase, + (DeviceExtension->ActiveRequest)->TargetId + )); + + DebugPrint((1, " Period: %x Offset: %x\n", + NonCachedExt->MsgOutBuf[MessageCount-2], + MAX_SYNCH_OFFSET + )); + } + + ScriptDataPtr->SelectDataSCNTL3 = + DeviceExtension->WideParms[Srb->TargetId]; + ScriptDataPtr->SelectDataSXFER = + DeviceExtension->SyncParms[Srb->TargetId]; + WRITE_SIOP_UCHAR (SCNTL3, DeviceExtension->WideParms[Srb->TargetId] ); + WRITE_SIOP_UCHAR (SXFER, DeviceExtension->SyncParms[Srb->TargetId] ); + + ScriptDataPtr->MsgOutCount = 5; + + return (ISR_CONT_NEG_SCRIPT); + + } // if + + return (ISR_RESTART_SCRIPT); + +} // ProcessWideNegotComplete + + +UCHAR +ProcessWideNotSupported( + PHW_DEVICE_EXTENSION DeviceExtension, + UCHAR DestId + ) +/****************************************************************************** + +Routine Description: + + This routine handles unsuccessful wide negotiation. The routine + sets the wide parameters to narrow, and sets the appropriate + flag. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + PSCRIPTDATASTRUCT ScriptDataPtr = + &DeviceExtension->NonCachedExtension->ScriptData; + PHW_NONCACHED_EXTENSION NonCachedExt = DeviceExtension->NonCachedExtension; + + DebugPrint((1, + "Sym8xx(%1x) WideNotSupp: Wide negotiation failed, ID = %2x\n", + DeviceExtension->ScsiBusNumber, DestId)); + + // + // indicate drive is low technology. + // + if (DeviceExtension->LuFlags[DestId] & LUFLAGS_WIDE_NEGOT_PEND) + { + DeviceExtension->LuFlags[DestId] |= LUFLAGS_WIDE_NEGOT_DONE + + LUFLAGS_WIDE_NEGOT_FAILED; + } + else + { + DeviceExtension->LuFlags[DestId] |= LUFLAGS_NARROW_NEGOT_DONE + + LUFLAGS_WIDE_NEGOT_FAILED; + } + + // + // indicate we are no longer expecting a negotiation reply + // + DeviceExtension->LuFlags[DestId] &= ~(LUFLAGS_WIDE_NEGOT_PEND + + LUFLAGS_NARROW_NEGOT_PEND); + + // + // set up for narrow xfer. + // + DeviceExtension->WideParms[DestId] &= ~ENABLE_WIDE; + + // + // check on asynch negotiations + // + if (!(DeviceExtension->LuFlags[DestId] & LUFLAGS_ASYNC_NEGOT_DONE)) + { + // + // fill in the parameters for SDTR extended message + // + NonCachedExt->MsgOutBuf[0] = SCSIMESS_EXTENDED_MESSAGE; + NonCachedExt->MsgOutBuf[1] = 3; // 3 message bytes + NonCachedExt->MsgOutBuf[2] = SCSIMESS_SYNCHRONOUS_DATA_REQ; + + // + // Clear any synchronous negotiations + // + DeviceExtension->SyncParms[DestId]=ASYNCHRONOUS_MODE_PARAMS; + + // + // indicate async negotiation is not done + // + DeviceExtension->LuFlags[DestId] |= LUFLAGS_ASYNC_NEGOT_PEND; + DeviceExtension->LuFlags[DestId] &= ~LUFLAGS_SYNC_NEGOT_PEND; + + // + // Initialize sync period to 0 + // + NonCachedExt->MsgOutBuf[3] = 0; + + // + // Initialize sync offset to 0 + // + NonCachedExt->MsgOutBuf[4] = 0; + + DebugPrint((1, + "Sym8xx(%2x): AsynchronousNegotiation Requested - Target: %x\n", + DeviceExtension->SIOPRegisterBase, DestId)); + + DebugPrint((1, " Period: %x Offset: %x\n", + NonCachedExt->MsgOutBuf[3], + MAX_SYNCH_OFFSET + )); + + ScriptDataPtr->MsgOutCount = 5; + + return (ISR_CONT_NEG_SCRIPT); + + } // if + + return (ISR_RESTART_SCRIPT); + +} // ProcessWideNotSupported + + +UCHAR +ProcessUnexpectedDisconnect( + PHW_DEVICE_EXTENSION DeviceExtension + ) +/****************************************************************************** + +Routine Description: + + This routine processes unexpected disconnects. An unexpected disconnect + is defined as a disconnect occurring before a disconnect message is + received. + +Arguments: + + DeviceContext - Supplies a pointer to the device extension for the + interrupting adapter. + +Return Value: + + None + +--*/ + +{ + PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension; + PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest; + + /* + * if wide negotiation is pending on this device, mark the + * device as NOT wide capable. + */ + + if ((DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_WIDE_NEGOT_PEND) || + (DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_NARROW_NEGOT_PEND)) + { + (void) ProcessWideNotSupported(DeviceExtension, Srb->TargetId); + } + + /* + * Ditto for sync... + */ + + if ( DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_SYNC_NEGOT_PEND ) + { + (void) ProcessSynchNotSupported(DeviceExtension); + } + + // + // indicate unexpected disconnect occurred. + // + + Srb->SrbStatus = SRB_STATUS_UNEXPECTED_BUS_FREE; + + // + // indicate this request is no longer active. + // + + DeviceExtension->ActiveRequest = NULL; + + // + // This delay added due to issues found with older Quantum drives which + // went BUS FREE after a MSG Reject. Seems on faster machines (>100Mhz) + // we would hit them again too quickly and they would mess up. This delay + // seems to have corrected the problem. + // + + ScsiPortStallExecution( 999 ); + + if (!(Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) ) + { + LuExtension = ScsiPortGetLogicalUnit( DeviceExtension, + Srb->PathId, + Srb->TargetId, + Srb->Lun + ); + + LuExtension->UntaggedRequest = NULL; + } + + // + // call back the request. + // + + ScsiPortNotification( RequestComplete, + DeviceExtension, + Srb + ); + + // + // tell ISR to start next request + // + + return( ISR_START_NEXT_REQUEST); + +} // ProcessUnexpectedDisconnected + + +VOID +ResetPeripheral( + IN PHW_DEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ) + +/****************************************************************************** + +Routine Description: + + This routine resets a specified SCSI peripheral. + + Note that since the 53C8xx generates a bus reset interrupt when we reset + the bus, we set a flag indicating we have reset the bus so the reset + postprocess routine will not be called twice. + +Arguments: + + DeviceExtension - Supplies a pointer to the specific device extension. + +Return Value: + + None + +--*/ +{ + PSCRIPTDATASTRUCT ScriptDataPtr = + &DeviceExtension->NonCachedExtension->ScriptData; + // + // store away SRB. + // + + DeviceExtension->NextSrbToProcess = Srb; + + // + // If we have an active request, just return. Since we saved away the + // SRB we just received, it will be started later. + // + + if ( DeviceExtension->ActiveRequest != NULL ) + { + return; + } + + // + // CHC - 53c810 pass 1 chip bug workaround. + // + // To get around the parity error on the PCI bus, we will set + // the bit to abort the script here but let the ISR routine do + // the actual processing. As long as we don't poll the ISTAT + // register while script is running, we should be ok. + // + + if ( DeviceExtension->DeviceFlags & DFLAGS_SCRIPT_RUNNING ) + { + WRITE_SIOP_UCHAR( ISTAT, ISTAT_SIGP ); + return; + } + + // + // Make this request active. + // + + DeviceExtension->ActiveRequest = Srb; + DeviceExtension->TargetId = Srb->TargetId; + + // + // indicate no pending request. + // + + DeviceExtension->NextSrbToProcess = NULL; + + // + // set up target ID in select script buffer. + // + + ScriptDataPtr->SelectDataID = Srb->TargetId; + + // + // clear the tagged command queueing flag + // + + DeviceExtension->DeviceFlags &= ~DFLAGS_TAGGED_SELECT; + + // + // indicate message length + // + + ScriptDataPtr->MsgOutCount = 1; + + // + // Attempt to start the request. + // + + StartSIOP( DeviceExtension, DeviceExtension->ResetDevScriptPhys ); + +} // ResetPeripheral + + +VOID +ResetSCSIBus( + IN PHW_DEVICE_EXTENSION DeviceExtension + ) + +/****************************************************************************** + +Routine Description: + + This routine resets the SCSI bus and calls the bus reset postprocess + routine. + + Note that since the 53C8xx generates a bus reset interrupt when we reset + the bus, we set a flag indicating we have reset the bus so the reset + postprocess routine will not be called twice. + +Arguments: + + DeviceExtension - Supplies a pointer to the specific device extension. + +Return Value: + + None + +--*/ + +{ + PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest; + ULONG tmpflg = 0x00; + + DebugPrint((1, "Sym8xx(%2x) ResetSCSIBus\n", + DeviceExtension->SIOPRegisterBase)); + + // + // set the bus reset line high + // + + WRITE_SIOP_UCHAR (SCNTL1, (UCHAR) ( READ_SIOP_UCHAR(SCNTL1) | + (UCHAR) SCNTL1_RESET_SCSI_BUS)); + + // + // Delay the minimum assertion time for a SCSI bus reset to make sure a + // valid reset signal is sent. + // + + ScsiPortStallExecution( RESET_STALL_TIME); + + // + // set the bus reset line low to end the bus reset event + // + + WRITE_SIOP_UCHAR(SCNTL1, (UCHAR) ( READ_SIOP_UCHAR(SCNTL1) & + (UCHAR) ~SCNTL1_RESET_SCSI_BUS)); + + // + // if wide negotiation is pending on this device, mark the + // device as NOT wide capable. + // + + // + // make sure we have an active request and were not just called + // directly by the OS to reset the bus + // + + if (Srb) + { + if (DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_WIDE_NEGOT_PEND) + { + tmpflg = LUFLAGS_WIDE_NEGOT_PEND; + } + } + + // + // abort any pending or started requests. + // + + BusResetPostProcess(DeviceExtension); + + // + // indicate that we reset the bus locally. + // + + DeviceExtension->DeviceFlags |= DFLAGS_BUS_RESET; + + if (tmpflg) + { + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_WIDE_NEGOT_PEND; + ProcessWideNotSupported (DeviceExtension, Srb->TargetId); + } + +} // ResetSCSIBus + +VOID +ScatterGatherScriptSetup( + IN PHW_DEVICE_EXTENSION DeviceExtension, + IN PSRB_EXTENSION SrbExtension + ) +/****************************************************************************** + +Routine Description: + + This routine copies physical break pointers and transfer lengths to the + appropriate locations in the SCSI script data buffer and sets the SCRATCH0 + register to the # of S/G elements to process. + +Arguments: + + DeviceExtension - Supplies the device Extension for the SCSI bus adapter. + + SrbExtension - Supplies the SRB Extension for the request to be setup + +Return Value: + + TRUE + +--*/ + +{ + ULONG ElementLength; + PVOID VirtualBufferPointer; + UCHAR PhysBreakCount = 0; + ULONG RemainingDataCount; + SCRIPTSG MoveBuffer[ MAX_SG_ELEMENTS]; + + // + // Added for script patching. + // + + PULONG dataInPatches = &DeviceExtension->dataInPatches[0]; + PULONG dataOutPatches = &DeviceExtension->dataOutPatches[0]; + + PULONG patchInArea; + PULONG patchOutArea; + + // + // set pointer to offset into xfer buffer + // + + VirtualBufferPointer = (PVOID) SrbExtension->SavedDataPointer; + + // + // get length of data remaining to xfer + // + + RemainingDataCount = SrbExtension->SavedDataLength; + + do + { + MoveBuffer[ PhysBreakCount].SGBufferPtr = + ScsiPortConvertPhysicalAddressToUlong ( + ScsiPortGetPhysicalAddress ( DeviceExtension, + DeviceExtension->ActiveRequest, + VirtualBufferPointer, + &ElementLength + )); + + if ( ElementLength > RemainingDataCount) + { + ElementLength = RemainingDataCount; + } + + MoveBuffer[ PhysBreakCount++].SGByteCount = ElementLength; + + (ULONG) VirtualBufferPointer += ElementLength; + RemainingDataCount -= ElementLength; + + } while ( RemainingDataCount != 0); + + // + // Indicate that we have not yet transfered any data. + // + + SrbExtension->DataTransferred = 0L; + + ScsiPortMoveMemory( + DeviceExtension->NonCachedExtension->ScriptData.SGBufferArray + + (MAX_SG_ELEMENTS - PhysBreakCount), + MoveBuffer, + PhysBreakCount * SCRIPT_INS_SIZE + ); + + WRITE_SIOP_UCHAR( SCRATCH[0], PhysBreakCount); + + SrbExtension->PhysBreakCount = PhysBreakCount; + + DebugPrint((3, + "Sym8xx(%2x) Sym8xxScatterGather: Phys breaks = %2x, total size = %8x \n", + DeviceExtension->SIOPRegisterBase, + PhysBreakCount, + *((PULONG) &SrbExtension->SavedDataLength) + )); + + // + // Set up pointers to the patch area, which is 4 bytes (1 long word) + // past the jump instructions for data in and data out. + // + + patchInArea = (PULONG)DeviceExtension->DataInJumpVirt; + patchInArea += 1; + + patchOutArea = (PULONG)DeviceExtension->DataOutJumpVirt; + patchOutArea += 1; + + // + // Move the pre-determined jump amount into these patch areas. + // + + if (!(DeviceExtension->hbaCapability & HBA_CAPABILITY_SCRIPT_RAM)) + { + // + // Script in system memory, patch it. + // + + (ULONG)*patchInArea = dataInPatches[ PhysBreakCount ]; + (ULONG)*patchOutArea = dataOutPatches[ PhysBreakCount ]; + } + else + { + // + // Script in onboard RAM, patch it. + // + + ScsiPortWriteRegisterUlong(patchInArea, dataInPatches[PhysBreakCount]); + ScsiPortWriteRegisterUlong(patchOutArea, dataOutPatches[PhysBreakCount]); + } + +} // ScatterGatherScriptSetup + + +VOID +SetupLuFlags( + IN PHW_DEVICE_EXTENSION DeviceExtension, + IN UCHAR ResetFlag + ) +/****************************************************************************** + +Routine Description: + + This routine clears the LU flags which hold information such as whether + a peripheral device supports synchronous. + +Arguments: + + PHW_DEVICE_EXTENSION DeviceExtension + ResetFlag Specifies a bus reset has just been done + +Return Value: + + None. + +--*/ + +{ + PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension; + + UCHAR TargetId; + UCHAR Lun; + UCHAR max_targets; + + // + // Indicate that no negotiations have been done, and there are no + // outstanding tagged requests. + // + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE) + { + max_targets = SYM_MAX_TARGETS; + } + else + { + max_targets = SYM_NARROW_MAX_TARGETS; + } + + for (TargetId = 0; TargetId < max_targets; TargetId++) + { + DeviceExtension->LuFlags[TargetId] &= ~LUFLAGS_SYNC_NEGOT_DONE; + DeviceExtension->LuFlags[TargetId] &= ~LUFLAGS_WIDE_NEGOT_DONE; + + if (!(ResetFlag)) + { + DeviceExtension->LuFlags[TargetId] &= ~LUFLAGS_ASYNC_NEGOT_DONE; + DeviceExtension->LuFlags[TargetId] &= ~LUFLAGS_NARROW_NEGOT_DONE; + } + else + { + DeviceExtension->LuFlags[TargetId] |= LUFLAGS_ASYNC_NEGOT_DONE; + DeviceExtension->LuFlags[TargetId] |= LUFLAGS_NARROW_NEGOT_DONE; + if (DeviceExtension->LuFlags[TargetId] & LUFLAGS_WIDE_NEGOT_FAILED) + { + DeviceExtension->LuFlags[TargetId] |= LUFLAGS_WIDE_NEGOT_DONE; + } + } + + // set failed bit as a check to see when we actually get to go sync. + // needed as a check so we only look at sstat1_orf when we are sync + DeviceExtension->LuFlags[TargetId] |= LUFLAGS_SYNC_NEGOT_FAILED; + + for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++) + { + LuExtension = ScsiPortGetLogicalUnit( + DeviceExtension, + DeviceExtension->BusNumber, + TargetId, + Lun + ); + + if (LuExtension != NULL) + { + LuExtension->UntaggedRequest = NULL; + } + } // for + } // for + +} // SetupLuFlags + + +VOID +StartSCSIRequest( + PSCSI_REQUEST_BLOCK Srb, + PHW_DEVICE_EXTENSION DeviceExtension + ) + +/****************************************************************************** + +Routine Description: + + This procedure starts a request if possible, and also + determines if synchronous negotiation is necessary. + +Arguments: + + Srb - Pointer to the request to be started. + + DeviceExtension - Pointer to the device extension for this adapter. + +Return Value: + + None + +--*/ + +{ + ULONG VirtualBufferLength; + PHW_NONCACHED_EXTENSION NonCachedExt = DeviceExtension->NonCachedExtension; + PSRB_EXTENSION SrbExtension = Srb->SrbExtension; + PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension; + PSCRIPTDATASTRUCT ScriptDataPtr = + &DeviceExtension->NonCachedExtension->ScriptData; + ULONG MessageCount; + + // + // store away SRB. + // + + DeviceExtension->NextSrbToProcess = Srb; + + // + // If we have an active request, just return. Since we saved away the + // SRB we just received, it will be started later. + // + + if (DeviceExtension->ActiveRequest != NULL) + { + return; + } + + // + // CHC - 53c810 pass 1 chip bug workaround. + // + // To get around the parity error on the PCI bus, we will set + // the bit to abort the script here but let the ISR routine do + // the actual processing. As long as we don't poll the ISTAT + // register while script is running, we should be ok. + // + + if (DeviceExtension->DeviceFlags & DFLAGS_SCRIPT_RUNNING) + { + WRITE_SIOP_UCHAR(ISTAT, ISTAT_SIGP); + return; + } + + // + // Make this request active. + // + + DeviceExtension->ActiveRequest = Srb; + DeviceExtension->TargetId = Srb->TargetId; + DeviceExtension->LUN = Srb->Lun; + + // + // Initialize the data pointer and transfer length for this request. + // + + SrbExtension->SavedDataPointer = (ULONG) Srb->DataBuffer; + SrbExtension->SavedDataLength = Srb->DataTransferLength; + SrbExtension->DataTransferred = 0L; + + // + // indicate no pending request. + // + + DeviceExtension->NextSrbToProcess = NULL; + + // + // If there is data to transfer set up scatter/gather. + // + + if ( Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) + { + ScatterGatherScriptSetup( DeviceExtension, + DeviceExtension->ActiveRequest->SrbExtension + ); + } + + // + // set CDB length and physical address in buffer. + // + + ScriptDataPtr->CDBDataCount = (ULONG) Srb->CdbLength; + ScsiPortMoveMemory(Srb->SrbExtension, Srb->Cdb, Srb->CdbLength); + ScriptDataPtr->CDBDataBuff = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress( DeviceExtension, + NULL, + (PVOID) Srb->SrbExtension, + &VirtualBufferLength + )); + + // + // Set up the identify message. If disconnect is disabled reset DSCPRV. + // + + DeviceExtension->NonCachedExtension->MsgOutBuf[0] = + (UCHAR) SCSIMESS_IDENTIFY_WITH_DISCON + Srb->Lun; + + if ( Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) + { + DeviceExtension->NonCachedExtension->MsgOutBuf[0] &= + ~SCSIMESS_IDENTIFY_DISC_PRIV_MASK; + } + + // + // indicate length of identify message. + // + + MessageCount = 1; + + // + // set up target ID in select script buffer. + // + + ScriptDataPtr->SelectDataID = Srb->TargetId; + + DebugPrint((3, "Sym8xx(%2x) StartSCSIRequest: Starting request for Path=%2x Id=%2x Lun=%2x \n", + DeviceExtension->SIOPRegisterBase, + DeviceExtension->ScsiBusNumber, + Srb->TargetId, + Srb->Lun )); + + + if (Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) + { + // before passing on this tagged cmd, make sure there is no + // Contingent Allegence Condition pending for this ITL nexus, + // if there is abort this SRB and have the class driver retry it + // after the CA condition is cleared. + + if (DeviceExtension->CA_Condition[Srb->TargetId][Srb->Lun]) + { + DeviceExtension->ActiveRequest = NULL; + Srb->SrbStatus = SCSISTAT_CHECK_CONDITION; + + Srb->ScsiStatus = SCSISTAT_BUSY; + + ScsiPortNotification( RequestComplete, + DeviceExtension, + Srb); + + if ( !(DeviceExtension->DeviceFlags & DFLAGS_WORK_REQUESTED)) + { + DeviceExtension->DeviceFlags |= DFLAGS_WORK_REQUESTED; + + ScsiPortNotification( NextRequest, + DeviceExtension, + NULL + ); + } + + return; + } + + // + // The queue tag message is two bytes the first is the queue action + // and the second is the queue tag. + // + NonCachedExt->MsgOutBuf[1] = Srb->QueueAction; + NonCachedExt->MsgOutBuf[2] = Srb->QueueTag; + MessageCount = 3; + + // + // Set Tagged select command. + // + DeviceExtension->DeviceFlags |= DFLAGS_TAGGED_SELECT; + + DebugPrint((3, "Sym8xx(%2x) Tagged I/O request \n", + DeviceExtension->SIOPRegisterBase + )); + } // if + + else + { + // blindly clear the Contingent Allegience blocker on non-tagged cmds + DeviceExtension->CA_Condition[Srb->TargetId][Srb->Lun] = 0; + + // Clear Tagged select command. + // + DeviceExtension->DeviceFlags &= ~DFLAGS_TAGGED_SELECT; + LuExtension = ScsiPortGetLogicalUnit( DeviceExtension, + Srb->PathId, + Srb->TargetId, + Srb->Lun + ); + + LuExtension->UntaggedRequest = Srb; + + DebugPrint((3, "Sym8xx(%2x) Untagged I/O request \n", + DeviceExtension->SIOPRegisterBase + )); + } // else + + DebugPrint((3, " CDB = %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x \n", + Srb->Cdb[0], Srb->Cdb[1], Srb->Cdb[2], Srb->Cdb[3], + Srb->Cdb[4], Srb->Cdb[5], Srb->Cdb[6], Srb->Cdb[7], + Srb->Cdb[8], Srb->Cdb[9], Srb->Cdb[10], Srb->Cdb[11] + )); + + //************************************************************************* + // + // Decide if wide negotiations are needed (either 8 or 16 bit) + // + //************************************************************************* + + // + // OK, the following mess does this: + // 1st half of if - checks to see if wide neg. NOT already done AND the OS + // is NOT restricting SYNCH transfers AND the chip is + // capable of wide transfers.(will do wide negotiations) + // + // 2nd half of if (after the ||) - checks to see if narrow neg. NOT + // already done AND the OS IS restricting SYNCH transfers + // and the chip is capable of wide transfers. (will do + // narrow negotiations) + + if ((!(DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_WIDE_NEGOT_DONE)&& + !( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER) && + (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE)) || // OR... + + (!(DeviceExtension->LuFlags[Srb->TargetId]&LUFLAGS_NARROW_NEGOT_DONE)&& + (Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER) && + (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE))) + { + + // + // fill in the parameters for SDTR extended message + // + NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_EXTENDED_MESSAGE; + NonCachedExt->MsgOutBuf[MessageCount++] = 2; // 2 message bytes + NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_WIDE_DATA_REQUEST; + + if (!( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER)) + { + // Will be doing WIDE negotiations... + // + // + // Clear any synchronous negotiations + // + DeviceExtension->SyncParms[Srb->TargetId]=ASYNCHRONOUS_MODE_PARAMS; + ScriptDataPtr->SelectDataSXFER = + DeviceExtension->SyncParms[Srb->TargetId]; + + WRITE_SIOP_UCHAR (SXFER,DeviceExtension->SyncParms[Srb->TargetId]); + DeviceExtension->WideParms[Srb->TargetId] |= ENABLE_WIDE; + + // + // indicate wide negotiation is not done + // + DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_WIDE_NEGOT_DONE; + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_WIDE_NEGOT_PEND; + + // + // Initialize transfer wide width to maximum supported + // Width = 16 bits + // + NonCachedExt->MsgOutBuf[MessageCount++] = 1; + + DebugPrint((1, "Sym8xx(%2x): WideNegotiation Requested - Target: %x\n", + DeviceExtension->SIOPRegisterBase, + Srb->TargetId + )); + } + + else + { + // Will be doing NARROW negotiations... + // + DeviceExtension->SyncParms[Srb->TargetId]=ASYNCHRONOUS_MODE_PARAMS; + ScriptDataPtr->SelectDataSXFER = + DeviceExtension->SyncParms[Srb->TargetId]; + + WRITE_SIOP_UCHAR (SXFER,DeviceExtension->SyncParms[Srb->TargetId]); + DeviceExtension->WideParms[Srb->TargetId] &= ~ENABLE_WIDE; + + // + // indicate narrow negotiation is not done + // + DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_NARROW_NEGOT_DONE; + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_NARROW_NEGOT_PEND; + + // + // Set for asynchronous negotiations + // + DeviceExtension->SyncParms[Srb->TargetId]=ASYNCHRONOUS_MODE_PARAMS; + ScriptDataPtr->SelectDataSXFER = + DeviceExtension->SyncParms[Srb->TargetId]; + WRITE_SIOP_UCHAR (SXFER,DeviceExtension->SyncParms[Srb->TargetId]); + + // + // Initialize transfer width to minimum supported + // Width = 8 bits + // + NonCachedExt->MsgOutBuf[MessageCount++] = 0; + + DebugPrint((1, "Sym8xx(%2x): Narrow Neg. Requested - Target: %x\n", + DeviceExtension->SIOPRegisterBase, + Srb->TargetId + )); + } + + } // if + + // check on sync negotiations + + else if (!(DeviceExtension->LuFlags[Srb->TargetId] & + LUFLAGS_SYNC_NEGOT_DONE) && + (!( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER ))) + { + // + // Clear any synchronous negotiations + // + DeviceExtension->SyncParms[Srb->TargetId]=ASYNCHRONOUS_MODE_PARAMS; + + // + // indicate sync negotiation is not done + // + DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_SYNC_NEGOT_DONE; + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_SYNC_NEGOT_PEND; + + // + // fill in the parameters for SDTR extended message + // + NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_EXTENDED_MESSAGE; + NonCachedExt->MsgOutBuf[MessageCount++] = 3; // 3 message bytes + NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_SYNCHRONOUS_DATA_REQ; + + // + // Initialize sync period to maximum supported + // + // Period = ((1000 / (ClockSpeed / 1)) * (4 + xferp)) / 4 + // where xferp = 0 + // modified for FAST20 devices, set msg byte to 0x0C since divide + // of 1000 by 80 equals 12.5 + // + if ((DeviceExtension->hbaCapability & HBA_CAPABILITY_FAST20) && + (DeviceExtension->hbaCapability & HBA_CAPABILITY_REGISTRY_FAST20)) + { + NonCachedExt->MsgOutBuf[MessageCount++] = 12; + } + else + { + NonCachedExt->MsgOutBuf[MessageCount++] = 25; + } + + // + // Initialize sync offset to maximum + // + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_SYNC_16) + { + NonCachedExt->MsgOutBuf[MessageCount++] = MAX_875_SYNCH_OFFSET; + } + else + { + NonCachedExt->MsgOutBuf[MessageCount++] = MAX_SYNCH_OFFSET; + } + + DebugPrint((1, + "Sym8xx(%2x): SynchronousNegotiation Requested - Target: %x\n", + DeviceExtension->SIOPRegisterBase, + (DeviceExtension->ActiveRequest)->TargetId + )); + + DebugPrint((1, " Period: %x Offset: %x\n", + NonCachedExt->MsgOutBuf[MessageCount-2], + MAX_SYNCH_OFFSET + )); + + } // else if + + // + // Let's just force async negotiation if need be to make sure device is + // in a known state. + // + + else if (!(DeviceExtension->LuFlags[Srb->TargetId] & + LUFLAGS_ASYNC_NEGOT_DONE) && + (( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER ))) + { + // + // Set the knowns... + // + DeviceExtension->SyncParms[Srb->TargetId]=ASYNCHRONOUS_MODE_PARAMS; + DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_ASYNC_NEGOT_DONE; + DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_ASYNC_NEGOT_PEND; + + // + // fill in the parameters for SDTR extended message + // + NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_EXTENDED_MESSAGE; + NonCachedExt->MsgOutBuf[MessageCount++] = 3; // 3 message bytes + NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_SYNCHRONOUS_DATA_REQ; + + // + // sync period to 0 + // + NonCachedExt->MsgOutBuf[MessageCount++] = 0; + + // + // Initialize sync offset to 0 + // + NonCachedExt->MsgOutBuf[MessageCount++] = 0; + + DebugPrint((1, + "Sym8xx(%2x): AsynchronousNegotiation Requested - Target: %x\n", + DeviceExtension->SIOPRegisterBase, + (DeviceExtension->ActiveRequest)->TargetId + )); + + } // else if + + ScriptDataPtr->SelectDataSCNTL3 = DeviceExtension->WideParms[Srb->TargetId]; + ScriptDataPtr->SelectDataSXFER = DeviceExtension->SyncParms[Srb->TargetId]; + WRITE_SIOP_UCHAR (SCNTL3, DeviceExtension->WideParms[Srb->TargetId] ); + WRITE_SIOP_UCHAR (SXFER, DeviceExtension->SyncParms[Srb->TargetId] ); + + // + // indicate message length + // + ScriptDataPtr->MsgOutCount = MessageCount; + + // + // Attempt to start the request. + // + StartSIOP( DeviceExtension, DeviceExtension->CommandScriptPhys); + +} // StartSCSIRequest + + +VOID +StartSIOP( + IN PHW_DEVICE_EXTENSION DeviceExtension, + IN ULONG ScriptPhysAddr + ) +/****************************************************************************** + +Routine Description: + + This routine indicates that scripts are running and starts the script + instruction whose physical address is passed to it. + +Arguments: + + DeviceExtension - Supplies the device Extension for the SCSI bus adapter. + ScriptPhysAddr - Supplies the address of the script routine to start. + +Return Value: + + None + +--*/ + +{ + // + // indicate scripts are running + // + DeviceExtension->DeviceFlags |= DFLAGS_SCRIPT_RUNNING; + + // + // write script buffer start address to DSA register. + // + WRITE_SIOP_ULONG( DSA, DeviceExtension->DSAAddress); + + // + // write script instruction start address to DSP register. + // + WRITE_SIOP_ULONG( DSP, ScriptPhysAddr); + +} // StartSIOP + + +// start of NVRAM useage code +// NVRAM_CODE +/* BOOLEAN NvmDetect( PHW_DEVICE_EXTENSION DeviceExtension ) + * + * Input: + * + * PHW_DEVICE_EXTENSION DeviceExtension - This contains the I/O port + * address of the adapter to test. + * + * Output: + * + * NONE + * + * Returns: + * + * BOOLEAN - SUCCESS if NVM was detected + * FAILURE if NVM was not detected + * + * Purpose: + * + * This routine is used to test the adapter to see if NVM is installed on + * the GPIO pins of the 8xx chip. + */ + + +BOOLEAN NvmDetect( PHW_DEVICE_EXTENSION DeviceExtension ) +{ + UINT flag; + UINT retries; + + /* Turn the data line into an output and the clock line into an output, + * then send a stop signal to the I2C chip to reset it to a known state. + */ + + WRITE_SIOP_UCHAR( GPCNTL, + (UCHAR)(READ_SIOP_UCHAR(GPCNTL) & (~(DATA_MASK | CLOCK_MASK ))) ); + NvmSendStop(DeviceExtension); /* Reset the I2C chip */ + + /* Attempt to issue a read for retries number of times. If the ACK is not + * received, then return that the I2C chip is not present or not + * functional. + */ + + flag = 1; + retries = 100; + + do + { + NvmSendStart(DeviceExtension); + /* Send a dummy write 1010 | A2 A1 A0 | Write */ + } while (--retries && + (NvmSendData(DeviceExtension, 0xA0 | 0x00 | 0x00) != 0x00) ); + + if (retries != 0) + { + flag = NvmSendData( DeviceExtension, 0x00 ); /* Address zero */ + NvmSendStart(DeviceExtension); + /* 1010 | A2 A1 A0 | Read */ + flag += NvmSendData( DeviceExtension, 0xA0 | 0x00 | 0x01 ); /* read */ + (void)NvmReadData(DeviceExtension); + NvmSendNoAck(DeviceExtension); /* Also sends stop */ + } + + /* Turn the clock back into an input signal so that the I2C won't + * recognize our LED line (same as the data line) toggling. Then turn the + * data line to an output signal for the drive activity LED. + */ + + WRITE_SIOP_UCHAR( GPCNTL, + (UCHAR)((READ_SIOP_UCHAR( GPCNTL ) & (~DATA_MASK)) | CLOCK_MASK )); + + return( (flag == 0) ? SUCCESS : FAILURE ); +} + + +/****************************************************************************** + * + * void NvmSendStop( PHW_DEVICE_EXTENSION ) + * + * Input: + * + * DATA line is an output + * CLOCK line is an output + * + * Output: + * + * An I2C 'stop' signal is sent. + * DATA line is asserted + * CLOCK line is deasserted + * + * Returns + * + * NONE + * + * Purpose: + * + * This routine is used to send an I2C stop signal. + */ + +void NvmSendStop( PHW_DEVICE_EXTENSION DeviceExtension ) +{ + RESET_DATA(); + ScsiPortStallExecution(10L); + SET_CLOCK(); + ScsiPortStallExecution(10L); + SET_DATA(); + ScsiPortStallExecution(10L); + RESET_CLOCK(); +} + + +/****************************************************************************** + * + * void NvmSendStart( PHW_DEVICE_EXTENSION ) + * + * Input: + * + * DATA line is an output + * CLOCK line is an output + * + * Output: + * + * An I2C 'start' signal is sent. + * DATA line is deasserted + * CLOCK line is deasserted + * + * Returns + * + * NONE + * + * Purpose: + * + * This routine is used to send an I2C start signal. + */ + +void NvmSendStart( PHW_DEVICE_EXTENSION DeviceExtension ) +{ + SET_DATA(); + ScsiPortStallExecution(10L); + SET_CLOCK(); + ScsiPortStallExecution(10L); + RESET_DATA(); + ScsiPortStallExecution(10L); + RESET_CLOCK(); +} + + +/****************************************************************************** + * + * UINT NvmSendData( PHW_DEVICE_EXTENSION, UINT Value ) + * + * Input: + * + * UINT Value - This is the data value to send (lower 8 bits only) + * + * ??? + * + * Output: + * + * ??? + * + * Returns + * + * UINT - == 0 if no acknowledge signal is present. + * != 0 if an acknowledge signal is present. + * + * Purpose: + * + * This routine is used to send a single data byte to the I2C interface. + */ + +UINT NvmSendData( PHW_DEVICE_EXTENSION DeviceExtension, UINT Value ) +{ + UINT i; + UINT8 bit; + + for (i = 0, bit = 0x80; i < 8; i++, bit >>= 1) + { + if (Value & bit) + { + SET_DATA(); + } + else + { + RESET_DATA(); + } + + ScsiPortStallExecution(10L); + SET_CLOCK(); + ScsiPortStallExecution(10L); + RESET_CLOCK(); + } + return( NvmReceiveAck(DeviceExtension) ); +} + + +/****************************************************************************** + * + * UINT8 NvmReadData( PHW_DEVICE_EXTENSION ) + * + * Input: + * + * ??? + * + * Output: + * + * ??? + * + * Returns + * + * UINT8 - The data byte read from the I2C interface. + * + * Purpose: + * + * This routine is used to read a single data byte from the I2C interface. + */ + +UINT8 NvmReadData( PHW_DEVICE_EXTENSION DeviceExtension ) +{ + UINT i; + UINT8 value; + + value = 0; + DATA_INPUT(); + for (i = 0; i < 8; i++) + { + ScsiPortStallExecution(10L); + SET_CLOCK(); + ScsiPortStallExecution(10L); + + /* Read in the next bit and shift it into place. + * + * NOTE: The following code only works properly because we know that + * DATA_MASK is bit 0. If that ever changes, then this code + * must also change. + */ + + value = (UINT8)(value << 1) | (READ_SIOP_UCHAR( GPREG ) & DATA_MASK); + RESET_CLOCK(); + } + DATA_OUTPUT(); + return( value ); +} + + +/****************************************************************************** + * + * void NvmSendAck( PHW_DEVICE_EXTENSION ) + * + * Input: + * + * ??? + * + * Output: + * + * ??? + * + * Returns + * + * NONE + * + * Purpose: + * + * This routine is used to send an acknowledge signal to the I2C part. + */ + +void NvmSendAck( PHW_DEVICE_EXTENSION DeviceExtension ) +{ + ScsiPortStallExecution(10L); + RESET_DATA(); + SET_CLOCK(); + ScsiPortStallExecution(10L); + RESET_CLOCK(); + RESET_DATA(); +} + + +/****************************************************************************** + * + * UINT NvmReceiveAck( PHW_DEVICE_EXTENSION ) + * + * Input: + * + * ??? + * + * Output: + * + * ??? + * + * Returns + * + * UINT - == 0 if no acknowledge signal is present. + * != 0 if an acknowledge signal is present. + * + * Purpose: + * + * This routine is used to check for an acknowledge signal from the I2C + * part. + */ + +UINT NvmReceiveAck( PHW_DEVICE_EXTENSION DeviceExtension ) +{ + UINT status; + + DATA_INPUT(); + ScsiPortStallExecution(10L); + SET_CLOCK(); + status = READ_SIOP_UCHAR( GPREG ) & DATA_MASK; + ScsiPortStallExecution(10L); + RESET_CLOCK(); + DATA_OUTPUT(); + return( status ); +} + + +/****************************************************************************** + * + * void NvmSendNoAck( PHW_DEVICE_EXTENSION ) + * + * Input: + * + * ??? + * + * Output: + * + * ??? + * + * Returns + * + * NONE + * + * Purpose: + * + * This routine is used to send a 'no acknowledge' signal to the I2C part. + */ + +void NvmSendNoAck( PHW_DEVICE_EXTENSION DeviceExtension) +{ + ScsiPortStallExecution(10L); + SET_DATA(); + SET_CLOCK(); + ScsiPortStallExecution(10L); + RESET_CLOCK(); + RESET_DATA(); + NvmSendStop(DeviceExtension); +} + + +/****************************************************************************** + * + * MEMORY_STATUS HwReadNonVolatileMemory(PHW_DEVICE_EXTENSION DeviceExtension, + * UINT8 *Buffer, UINT Offset, + * UINT Length ) + * + * Input: + * + * PHW_DEVICE_EXTENSION DevcieExtesnion - The adapter whose NVM is being + * read. If the ACF_NO_NON_VOLATILE_MEMORY bit in the Public.ControlFlags + * field is set, then it is illegal to call this routine. + * + * UINT8 far *Buffer - The data buffer in which to store the data being + * accessed. This buffer must be Length UINT8 elements in size. + * + * UINT Offset - The non-volatile memory offset to start reading at. + * + * UINT Length - The number of UINT8 elements to read from the NVM. + * + * Output: + * + * UINT8 far *Buffer - If this routine returns MS_GOOD, then this buffer + * is filled with Length UINT8 elements from the NVM. + * + * Returns: + * + * MS_GOOD - If the operation completed successfully. + * + * Another MEMORY_STATUS - If the operation failed for some reason. + * + * Purpose: + * + * This routine is used to read the non-volatile memory of a particular + * adapter. + */ + +MEMORY_STATUS HwReadNonVolatileMemory( PHW_DEVICE_EXTENSION DeviceExtension, + UINT8 *Buffer, + UINT Offset, UINT Length ) +{ + UINT i; + UINT nvmAddress; + + /* Make sure that the requested addresses are in range */ + + if (Offset + Length > 2048) + { + return( MS_ILLEGAL_ADDRESS ); + } + + /* Turn the data line into an output and the clock line into an output, + * then send a stop signal to the I2C chip to reset it to a known state. + */ + + WRITE_SIOP_UCHAR( GPCNTL, + (UCHAR)(READ_SIOP_UCHAR( GPCNTL ) & (~(DATA_MASK | CLOCK_MASK ))) ); + NvmSendStop(DeviceExtension); // Reset the I2C chip + + /* Now read in all of the requested data */ + + nvmAddress = 0xA0 | ((Offset & 0x700) >> 7); + do + { + NvmSendStart(DeviceExtension); + } while ( NvmSendData( DeviceExtension, nvmAddress | 0x00 ) != 0x00 ); + // dummy write + + (void)NvmSendData( DeviceExtension, Offset & 0x00FF ); // address + NvmSendStart(DeviceExtension); + (void)NvmSendData( DeviceExtension, nvmAddress | 0x01 ); // read + + *Buffer = NvmReadData(DeviceExtension); + for (i = 1; i < Length; i++) + { + NvmSendAck(DeviceExtension); + Buffer++; + *Buffer = NvmReadData(DeviceExtension); + } + + NvmSendNoAck(DeviceExtension); // Also sends Stop + + /* Turn the clock back into an input signal so that the I2C won't + * recognize our LED line (same as the data line) toggling. Then turn the + * data line to an output signal for the drive activity LED. + */ + + WRITE_SIOP_UCHAR( GPCNTL, + (UCHAR)((READ_SIOP_UCHAR( GPCNTL ) & (~DATA_MASK)) | CLOCK_MASK )); + + return( MS_GOOD ); +} + + +/****************************************************************************** + * + * void InvalidateNvmData(PHW_DEVICE_EXTENSION DeviceExtension) + * + * Input: + * + * PHW_DEVICE_EXTENSION DevcieExtesnion - The adapter whose NVM + * is being used. + * + * Returns: + * None + * + * Purpose: + * + * This routine is used to corrupt the nv ram fields so the rest of the + * driver will not try to use them. + * + */ + +void InvalidateNvmData( PHW_DEVICE_EXTENSION DeviceExtension ) +{ + DeviceExtension->UsersHBAId = 0x07; +#ifdef FOR_95 + DeviceExtension->NumValidScamDevices = 0x00; +#endif +} + + +/****************************************************************************** + * + * BOOLEAN RetrieveNvmData( PHW_DEVICE_EXTENSION) + * + * Input: + * + * PHW_DEVICE_EXTENSION DevcieExtesnion - The adapter whose NVM + * is being read. + * + * + * Returns: + * + * BOOLEAN + * SUCCESS if nvram data is of correct type, correct sumcheck and + * correct major\minor numbers, FAILURE if any flaws are found. + * + * + * Purpose: + * + * This routine is used to read the non-volatile memory of a particular + * adapter, verify it as valid and to fill the DeviceExtension fields + * housed within the nvram structure. + */ + + BOOLEAN RetrieveNvmData( PHW_DEVICE_EXTENSION DeviceExtension) + { + NVM_HEADER NvmHeader; + NON_VOLATILE_SETTINGS NvmData; + BOOLEAN Status = FAILURE; + USHORT maxid = (SYM_NARROW_MAX_TARGETS - 1); +#ifdef FOR_95 + ULONG i; + UINT8 *ScamBuffer, *NvmBuffer; +#endif + + if (HwReadNonVolatileMemory(DeviceExtension, (UINT8 *)&NvmHeader, + (0 + NVMDATAOFFSET), sizeof(NvmHeader)) == MS_GOOD) + { + if (NvmHeader.Type == HT_BOOT_ROM) + { + if (HwReadNonVolatileMemory(DeviceExtension, (UINT8 *)&NvmData, + (sizeof(NvmHeader) + NVMDATAOFFSET), sizeof(NvmData)) == MS_GOOD) + { + if (CalculateCheckSum((UINT8 *)&NvmData, NvmHeader.Length) == + NvmHeader.CheckSum) + { + if ( (NvmData.VersionMajor == NVS_VERSION_MAJOR) && + (NvmData.VersionMinor == NVS_VERSION_MINOR) ) + { + DeviceExtension->UsersHBAId = NvmData.HostScsiId; + if ( DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE ) + { + maxid = (SYM_MAX_TARGETS - 1); + } + + if ((DeviceExtension->UsersHBAId > maxid)) + { + DeviceExtension->UsersHBAId = 0x07; + } + +#ifdef FOR_95 + DeviceExtension->NumValidScamDevices=NvmData.NumValidScamDevices; + ScamBuffer = (UINT8 *)&DeviceExtension->ScamTables[0]; + NvmBuffer = (UINT8 *)&(NvmData.ScamTable[0]); + if (DeviceExtension->NumValidScamDevices > HW_MAX_SCAM_DEVICES) + { + DeviceExtension->NumValidScamDevices = HW_MAX_SCAM_DEVICES; + } + for( i=0; + i<(DeviceExtension->NumValidScamDevices * sizeof(SCAM_TABLE)); + i++, ScamBuffer++, NvmBuffer++) + { + *ScamBuffer = *NvmBuffer; + } +#endif + Status = SUCCESS; + } + } + } + } + } + return (Status); +} + + +/****************************************************************************** + * + * UINT16 CalculateCheckSum( UINT8 * PNvmData, UINT16 Length) + * + * Input: + * + * UINT8 * PNvmData Pointer to the NVRAM data just read + * UINT16 Length length of the data to calculate sum check against + * + * + * Returns: + * + * UINT16 returns the 16 bit sum of NVRAM data ( read as all 8 bit members) + * + * + * Purpose: + * + * This routine is used calculate the sum check of the nvram data + * area to insure it is valid before its use. + */ + +UINT16 CalculateCheckSum(UINT8 * PNvmData, UINT16 Length) +{ + UINT16 i; + UINT16 CheckSum = 0; + + for ( i = 0; i < Length; i++, PNvmData++) + { + CheckSum += *PNvmData; + } + + return ( CheckSum); +} + + +/******************************************************* +** ** +** set_8xx_clock ** +** ** +*******************************************************/ + +UCHAR set_8xx_clock(PHW_DEVICE_EXTENSION DeviceExtension) +{ + UCHAR scntl3Value = 0; + + // + // set SCSI clock frequency + // fast20 assumes 80Mhz clock else 40Mhz + // + + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_FAST20) + scntl3Value = 0xD5; + else + scntl3Value = 0x33; + + WRITE_SIOP_UCHAR( SCNTL3, scntl3Value ); + + return (scntl3Value); +} + + +/******************************************************* +** ** +** set_875_multipler ** +** ** +*******************************************************/ + +UCHAR set_875_multipler(PHW_DEVICE_EXTENSION DeviceExtension) +{ + UCHAR scntl3Value = 0; + + WRITE_SIOP_UCHAR( STEST1, + (UCHAR)(READ_SIOP_UCHAR(STEST1) | STEST1_DOUBLER_ENABLE)); + + // wait at least 20 usec. + ScsiPortStallExecution( RESET_STALL_TIME ); + + WRITE_SIOP_UCHAR( STEST3, + (UCHAR)(READ_SIOP_UCHAR(STEST3) | STEST3_HALT_CLOCK)); + + scntl3Value = 0xD5; // 80Mhz clock speed after doubling + + WRITE_SIOP_UCHAR( SCNTL3, scntl3Value ); + + WRITE_SIOP_UCHAR( STEST1, + (UCHAR)(READ_SIOP_UCHAR(STEST1) | STEST1_DOUBLER_SELECT)); + + WRITE_SIOP_UCHAR( STEST3, + (UCHAR)(READ_SIOP_UCHAR(STEST3) & ~STEST3_HALT_CLOCK)); + + return (scntl3Value); +} + +#ifdef FOR_95 +/******************************************************* + + + +** SCAM Code procedures ** + + + +*******************************************************/ + +/******************************************************* +** ** +** Scam_Scan ** +** ** +*******************************************************/ + +VOID scam_scan(PHW_DEVICE_EXTENSION DeviceExtension) +{ + UCHAR overall_timer = 0; + UCHAR scntl3Value = 0; + + if (DeviceExtension->initial_run) + { + DeviceExtension->initial_run = 0; + DeviceExtension->eatint_flag=FALSE; + DeviceExtension->current_state=FALSE; + save_reg(DeviceExtension, &(DeviceExtension->ScamStore)); + // RESET the chip + WRITE_SIOP_UCHAR(ISTAT,0x40); + delay_mils(1); + // Clear reset + WRITE_SIOP_UCHAR(ISTAT,0x00); + delay_mils(750); + + /* Enable function complete int */ + WRITE_SIOP_UCHAR(SIEN0,(UCHAR)(READ_SIOP_UCHAR(SIEN0) | 0x40)); + + /* Enable sel\resel timeout int */ + WRITE_SIOP_UCHAR(SIEN1,(UCHAR)(READ_SIOP_UCHAR(SIEN1) | 0x04)); + + if ( (DeviceExtension->hbaCapability & HBA_CAPABILITY_875_FAMILY) && + (READ_SIOP_UCHAR(CTEST3) & 0xF0) > 0x10 ) + { + // 875 rev. E or greater part with clock doubler + scntl3Value = set_875_multipler (DeviceExtension); + } + + // + // Still need to set up the clock stuff if we did not already do it + // in the clock doubler code above. + // + if (!scntl3Value) + { + scntl3Value = set_8xx_clock (DeviceExtension); + } + + EnterLLM(DeviceExtension); + delay_mils(1); + + /* Mark all IDs except own as available */ + DeviceExtension->ID_map = 1 << DeviceExtension->SIOPBusID; + Find_nonSCAM_IDs(DeviceExtension); + + do + { + DeviceExtension->sna_delay=0; + SCAM_Arbitrate(DeviceExtension); + delay_mils(270); + + SCAM_master_select(DeviceExtension); + SCAM_assign_IDs(DeviceExtension); + SCAM_release(DeviceExtension); + + if (DeviceExtension->sna_delay) + delay_mils(750); + else + delay_mils(1); + + overall_timer++; + } while ( (DeviceExtension->sna_delay != 0) && + (overall_timer < 10) && + (DeviceExtension->eatint_flag != TRUE) ); + + if (DeviceExtension->eatint_flag) + SCAM_release(DeviceExtension); + + ExitLLM(DeviceExtension); + + // Reset chip + WRITE_SIOP_UCHAR(ISTAT,0x40); + delay_mils(1); + // Clear reset + WRITE_SIOP_UCHAR(ISTAT,0x00); + delay_mils(750); + + if (DeviceExtension->eatint_flag) + { + InitializeSIOP(DeviceExtension); + ResetSCSIBus(DeviceExtension); + } + else + { + restore_reg(DeviceExtension, &(DeviceExtension->ScamStore)); + scntl3Value = 0x00; + if ( (DeviceExtension->hbaCapability & HBA_CAPABILITY_875_FAMILY) && + (READ_SIOP_UCHAR(CTEST3) & 0xF0) > 0x10 ) + { + // 875 rev. E or greater part with clock doubler + scntl3Value = set_875_multipler (DeviceExtension); + } + + // + // Still need to set up the clock stuff if we did not already do it + // in the clock doubler code above. + // + if (!scntl3Value) + { + scntl3Value = set_8xx_clock (DeviceExtension); + } + + DeviceExtension->scam_completed=TRUE; + } + + return; + } + else + { + if (DeviceExtension->current_state) + { + DebugPrint((0, "Sym8xx: Entering SCAM code... \n")); + DeviceExtension->eatint_flag=FALSE; + save_reg(DeviceExtension, &(DeviceExtension->ScamStore)); + DeviceExtension->nextstate=10; + DeviceExtension->timer_value=1000; + DeviceExtension->current_state=FALSE; + } + else + { + switch (DeviceExtension->nextstate) + { + case 10: + + DebugPrint((2, "SCAM phase 1... \n")); + + // Reset Chip + WRITE_SIOP_UCHAR(ISTAT,0x40); + DeviceExtension->timer_value=1000; + DeviceExtension->nextstate=20; + break; + + case 20: + DebugPrint((2, "SCAM phase 2... \n")); + + // Clear reset + WRITE_SIOP_UCHAR(ISTAT,0x00); + DeviceExtension->timer_value=750000; + DeviceExtension->nextstate=30; + break; + + + case 30: + DebugPrint((2, "SCAM phase 3... \n")); + + /* Enable function complete int */ + WRITE_SIOP_UCHAR(SIEN0,(UCHAR)(READ_SIOP_UCHAR(SIEN0) | 0x40)); + + /* Enable sel\resel timeout int */ + WRITE_SIOP_UCHAR(SIEN1,(UCHAR)(READ_SIOP_UCHAR(SIEN1) | 0x04)); + + /* Set divide by 2 for 40MHz clock */ + /* divide by 4 if 80 MHz */ + if (DeviceExtension->ClockSpeed == 0x80) + { + WRITE_SIOP_UCHAR(SCNTL3, 0x55); + } + else + { + WRITE_SIOP_UCHAR(SCNTL3,0x33); + } + + EnterLLM(DeviceExtension); + DeviceExtension->timer_value=1000; + DeviceExtension->nextstate=40; + break; + + case 40: + DeviceExtension->timer_value=1000; + DeviceExtension->nextstate=50; + DebugPrint((2, "SCAM phase 4... \n")); + + // loop up to 5 times to clear the C.A. conditions + // of the found legacy devices. O.S. could be in + // Queueing environment which means leaving the C.A. + // condition present could present a BUSY Status problem + + for (i = 0; i < 5; i++) + { + /* Mark all IDs except own as available */ + DeviceExtension->ID_map = 1 << DeviceExtension->SIOPBusID; + Find_nonSCAM_IDs(DeviceExtension); + if (!DeviceExtension->checkseen) + break; + } + break; + + case 50: + DeviceExtension->timer_value=270000; + DeviceExtension->nextstate=60; + DeviceExtension->sna_delay=0; + DebugPrint((2, "SCAM phase 5... \n")); + SCAM_Arbitrate(DeviceExtension); + break; + + case 60: + DebugPrint((2, "SCAM phase 6... \n")); + SCAM_master_select(DeviceExtension); + SCAM_assign_IDs(DeviceExtension); + SCAM_release(DeviceExtension); + + if (DeviceExtension->sna_delay) + { + DeviceExtension->timer_value=750000; + DeviceExtension->nextstate=50; + } + else + { + DeviceExtension->timer_value=1000; + DeviceExtension->nextstate=70; + } + break; + + case 70: + DebugPrint((2, "SCAM phase 7... \n")); + if (DeviceExtension->eatint_flag) + SCAM_release(DeviceExtension); + + ExitLLM(DeviceExtension); + + // Reset chip + WRITE_SIOP_UCHAR(ISTAT,0x40); + DeviceExtension->timer_value=1000; + DeviceExtension->nextstate=80; + break; + + case 80: + DebugPrint((2, "SCAM phase 8... \n")); + + // Clear reset + WRITE_SIOP_UCHAR(ISTAT,0x00); + DeviceExtension->timer_value=750000; + DeviceExtension->nextstate=90; + break; + + case 90: + if (DeviceExtension->eatint_flag) + DeviceExtension->nextstate=150; + else + DeviceExtension->nextstate=100; + DeviceExtension->timer_value=5000; + break; + + case 100: + DebugPrint((2, "SCAM phase 100... \n")); + restore_reg(DeviceExtension, &(DeviceExtension->ScamStore)); + + if ((DeviceExtension->hbaCapability & HBA_CAPABILITY_875_FAMILY) + && (READ_SIOP_UCHAR(CTEST3) & 0xF0) > 0x10 ) + { + // 875 rev. E or greater part with clock doubler + scntl3Value = set_875_multipler (DeviceExtension); + } + + // + // Still need to set up the clock stuff if we did not + // already do it in the clock doubler code above. + // + if (!scntl3Value) + { + scntl3Value = set_8xx_clock (DeviceExtension); + } + + DeviceExtension->scam_completed=TRUE; + DebugPrint((0, "Sym8xx: Exiting SCAM code!! \n")); + ISR_Service_Next(DeviceExtension,ISR_START_NEXT_REQUEST); + DeviceExtension->nextstate=0; + DeviceExtension->timer_value=1000; + break; + + case 150: + DebugPrint((2, "SCAM phase 150... \n")); + InitializeSIOP(DeviceExtension); + ResetSCSIBus(DeviceExtension); + DeviceExtension->timer_value=270000; + DeviceExtension->nextstate=0; + break; + + default: + DeviceExtension->nextstate=0; + break; + } + } + } + + if (DeviceExtension->nextstate) + { + ScsiPortNotification(RequestTimerCall, + DeviceExtension, + scam_scan, + DeviceExtension->timer_value); + } + else + { + return; + } +} + + + +/******************************************************* +** ** +** save_reg ** +** ** +*******************************************************/ + +VOID save_reg(PHW_DEVICE_EXTENSION DeviceExtension, + PSIOP_REG_STORE RegStore) +{ + RegStore->reg_st[0] = READ_SIOP_UCHAR(SCNTL0); + RegStore->reg_st[1] = READ_SIOP_UCHAR(SCNTL3); + RegStore->reg_st[2] = READ_SIOP_UCHAR(SCID); + RegStore->reg_st[3] = READ_SIOP_UCHAR(SXFER); + RegStore->reg_st[4] = READ_SIOP_UCHAR(SDID); + RegStore->reg_st[5] = READ_SIOP_UCHAR(GPREG); + RegStore->reg_st[6] = READ_SIOP_UCHAR(CTEST3); + RegStore->reg_st[7] = READ_SIOP_UCHAR(CTEST4); + RegStore->reg_st[8] = READ_SIOP_UCHAR(CTEST5); + RegStore->reg_st[9] = READ_SIOP_UCHAR(DMODE); + RegStore->reg_st[10] = READ_SIOP_UCHAR(DIEN); + RegStore->reg_st[11] = READ_SIOP_UCHAR(DCNTL); + RegStore->reg_st[12] = READ_SIOP_UCHAR(SIEN0); + RegStore->reg_st[13] = READ_SIOP_UCHAR(SIEN1); + RegStore->reg_st[14] = READ_SIOP_UCHAR(GPCNTL); + RegStore->reg_st[15] = READ_SIOP_UCHAR(STIME0); + RegStore->reg_st[16] = READ_SIOP_UCHAR(STIME1); + RegStore->reg_st[17] = READ_SIOP_UCHAR(RESPID0); + RegStore->reg_st[18] = READ_SIOP_UCHAR(RESPID1); + RegStore->reg_st[19] = READ_SIOP_UCHAR(STEST2); + RegStore->reg_st[20] = READ_SIOP_UCHAR(STEST3); + RegStore->long_st = READ_SIOP_ULONG(DSA); +} + + +/************************************************************************/ +/* This routine puts the 720 into Low Level Mode, enables SCE and ADB */ +/* to allow direct drive of ALL SCSI signals, plus the data bus. ADB */ +/* is required to have the 720 generate parity on direct driven data. */ +/************************************************************************/ + +VOID EnterLLM(PHW_DEVICE_EXTENSION DeviceExtension) +{ + UCHAR id = DeviceExtension->SIOPBusID; + + WRITE_SIOP_UCHAR(SCID,id); + + /* Make sure no control signals are asserted */ + WRITE_SIOP_UCHAR(SOCL,0x00); + WRITE_SIOP_UCHAR(SODL,0x00); + WRITE_SIOP_UCHAR(SODL+1,0x00); + + /* Enable Lower Level Mode */ + + WRITE_SIOP_UCHAR(STEST2,(UCHAR)(READ_SIOP_UCHAR(STEST2) | 0x81)); + + /* Sometimes have interrupt on entry to LLM */ + EatInts(DeviceExtension); +} + + +/************************************************************************/ +/* This routine finds hard IDs not already in the passed-in idmap, and */ +/* returns the new filled-in idmap. */ +/************************************************************************/ + +VOID Find_nonSCAM_IDs(PHW_DEVICE_EXTENSION DeviceExtension) +{ + UCHAR current_id=0; + UCHAR istat=0; + UCHAR dispose; + UCHAR count; + UCHAR maxim_ID; + ULONG idmap = DeviceExtension->ID_map; + + DebugPrint((2, "Sym8xx: Entering Find_nonSCAM_IDs...\n")); + + /* Wide Support */ + if (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE) + maxim_ID = 15; + else + maxim_ID=7; + + // clear out the C.A. check condition + DeviceExtension->checkseen = 0; + while (current_id <= maxim_ID) + { + if (idmap & (ULONG)(1 << current_id)) + { + ; + } + + else + { /* Check for unoccupied ID */ + + /* Eat the interrupt (possible UDC after bus free) + /* from previous loop put here to give longer delay + + DebugPrint((2, "EatInts [1] \n")); + if (!EatInts(DeviceExtension)) + { + DeviceExtension->nextstate=70; + DeviceExtension->eatint_flag=TRUE; + DeviceExtension->ID_map = 0; + return; + } + + WRITE_SIOP_UCHAR(STIME1,0x00); /* Disable GEN timer */ + WRITE_SIOP_UCHAR(STIME0,(UCHAR)SHORT_720_STO); + /* Enable short SEL TO */ + WRITE_SIOP_UCHAR(SDID,current_id); /* Choose current ID target */ + WRITE_SIOP_UCHAR(SCNTL0,0xe0); /* Full arb & select wo/ATN */ + istat=READ_SIOP_UCHAR(ISTAT); + + count=0; + /* Wait for completion */ + while ( !(istat & 0x02) ) + { + DebugPrint((2, "Stuck... [10], istat=%2x \n",istat)); + count++; + + if (count > 30) + { + DeviceExtension->nextstate=70; + DeviceExtension->eatint_flag=TRUE; + DeviceExtension->ID_map = 0; + return; + } + ScsiPortStallExecution(5000); + istat=READ_SIOP_UCHAR(ISTAT); + } + + if (istat & CONNECTED) + { + /* Someone responded! */ + if (!EatInts(DeviceExtension)) + { + DeviceExtension->nextstate=70; + DeviceExtension->eatint_flag=TRUE; + DeviceExtension->ID_map = 0; + return; + } + idmap |= (1 << current_id); + + /* Send Test Unit Ready cmd */ + init_send_byte(0x00,DeviceExtension); + init_send_byte(0x00,DeviceExtension); + init_send_byte(0x00,DeviceExtension); + init_send_byte(0x00,DeviceExtension); + init_send_byte(0x00,DeviceExtension); + init_send_byte(0x00,DeviceExtension); + + /* Accept STATUS */ + dispose=(UCHAR)init_recv_byte(DeviceExtension); + if (dispose == 0x02) + DeviceExtension->checkseen = 1; + + /* Accept MSG_IN */ + dispose=(UCHAR)init_recv_byte(DeviceExtension); + + /* Wait for BUS FREE */ + while(READ_SIOP_UCHAR(ISTAT) & CONNECTED) + DebugPrint((2, "Stuck... [11] \n")); + + DebugPrint((2, "EatInts [2] \n")); + if (!EatInts(DeviceExtension)) + { + DeviceExtension->nextstate=70; + DeviceExtension->eatint_flag=TRUE; + DeviceExtension->ID_map = 0; + return; + } + + } + else + { + DebugPrint((2, "EatInts [3] \n")); + if (!EatInts(DeviceExtension)) + { + DeviceExtension->nextstate=70; + DeviceExtension->eatint_flag=TRUE; + DeviceExtension->ID_map = 0; + return; + } + } + } + current_id++; + } + + DebugPrint((2, "Sym8xx: Exiting Find_nonSCAM_IDs, Idmap=%2x \n",idmap)); + DeviceExtension->ID_map = idmap; + return; +} + + +/************************************************************************/ +/* This routine performs a SCAM Level I arbitration with the already */ +/* set chip SCID value. It asserts SEL and MSG to indicate a SCAM */ +/* selection will follow. */ +/************************************************************************/ + +VOID SCAM_Arbitrate(PHW_DEVICE_EXTENSION DeviceExtension) +{ + UCHAR count; + volatile UCHAR won_arb=FALSE; + long ID_seen; + UCHAR sstat0; + + DebugPrint((2, "Sym8xx: Entering SCAM_Arbitrate... \n")); + + while (!won_arb) + { + /* Start simple arb */ + WRITE_SIOP_UCHAR(SCNTL0,0x20); + + count=0; + sstat0=READ_SIOP_UCHAR(SSTAT0); + + /* Wait for arb to begin */ + while ( !(sstat0 & ARB_IN_PROGRESS)) + { + DebugPrint((2, "Stuck... [20] \n")); + count++; + + if (count > 30) + { + EatInts(DeviceExtension); + DeviceExtension->nextstate=70; + DeviceExtension->eatint_flag=TRUE; + return; + } + ScsiPortStallExecution(5000); + sstat0=READ_SIOP_UCHAR(SSTAT0); + } + + ID_seen = READ_SIOP_UCHAR(SBDL); + + /* Need code in here to take care of the case where we have been selected + or reselected while waiting to win BUS arbitration */ + + if ( ID_seen > (1 << (READ_SIOP_UCHAR(SCID) & 0x0F) ) ) + { + DebugPrint((2, "SCAM Arbitrate, ID_seen=%2l \n",ID_seen)); + + } /* Higher ID asserted, wait 'til next time */ + else + { /* We win, so assert SEL & MSG */ + WRITE_SIOP_UCHAR(SOCL,(UCHAR)(READ_SIOP_UCHAR(SOCL) | MSG | SEL)); + + /* End simple arb */ + WRITE_SIOP_UCHAR(SCNTL0,0x00); + won_arb=TRUE; + } + } + DebugPrint((2, "Sym8xx: Exiting SCAM_Arbitrate... \n")); +} + + +/************************************************************************/ +/* This routine performs a SCAM Level I selection. It assumes SEL and */ +/* MSG are already asserted, and that a SCAM arbitration has been done. */ +/************************************************************************/ + +VOID SCAM_master_select(PHW_DEVICE_EXTENSION DeviceExtension) +{ + DebugPrint((3, "Sym8xx: Entering SCAM_master_select... \n")); + + /* De-assert message */ + WRITE_SIOP_UCHAR(SOCL,(UCHAR)(READ_SIOP_UCHAR(SOCL) & ~MSG)); + + /* Wait for message release */ + de_glitch(0x0B,MSG,DeviceExtension); +// while ((READ_SIOP_UCHAR(SBCL) & MSG) || (READ_SIOP_UCHAR(SBCL) & MSG)); + + /* Re-assert busy */ + WRITE_SIOP_UCHAR(SOCL,(UCHAR)(READ_SIOP_UCHAR(SOCL) | BSY)); + + /* Assert CD & IO */ + WRITE_SIOP_UCHAR(SOCL,(UCHAR)(READ_SIOP_UCHAR(SOCL) | IO | CD)); + + /* Assert DB7 & DB6 */ + WRITE_SIOP_UCHAR(SODL,0xC0); + + /* Assert SCSI data bus */ + WRITE_SIOP_UCHAR(SCNTL1,(UCHAR)(READ_SIOP_UCHAR(SCNTL1) | 0x40)); + + /* De-assert select */ + WRITE_SIOP_UCHAR(SOCL,(UCHAR)(READ_SIOP_UCHAR(SOCL) & ~SEL)); + + /* Wait for select release */ + de_glitch(0x0B,SEL,DeviceExtension); +// while ((READ_SIOP_UCHAR(SBCL) & SEL) || (READ_SIOP_UCHAR(SBCL) & SEL)); + + /* De-assert DB6 */ + WRITE_SIOP_UCHAR(SODL,0x80); + + /* Wait for DB6 release */ + de_glitch(0x58,0x40,DeviceExtension); +// while ((READ_SIOP_UCHAR(SBDL) & 0x40) || (READ_SIOP_UCHAR(SBDL) & 0x40)); + + /* Re-assert select */ + WRITE_SIOP_UCHAR(SOCL,(UCHAR)(READ_SIOP_UCHAR(SOCL) | SEL)); + + DebugPrint((3, "Sym8xx: Exiting SCAM_master_select \n")); +} + + +/************************************************************************/ +/* 1 routine assigns IDs from the passed-in idmap, and returns the */ +/* new filled-in idmap. */ +/************************************************************************/ + +VOID SCAM_assign_IDs(PHW_DEVICE_EXTENSION DeviceExtension) +{ + LONG isolation; /* SCAM_isolation() status return */ + UCHAR i; + UCHAR scam_str[SCAM_ID_STRLEN]; + UCHAR encoded_id[8]; + UCHAR greatest_ID; + UCHAR desired_ID; + UCHAR *greatest_IDptr; + UCHAR *desired_IDptr; + UCHAR *scam_strptr; + CHAR wide, set_greater, try_greater; + UCHAR wanted_id, min_id; + UCHAR new_id; + ULONG idmap = DeviceExtension->ID_map; + + isolation=ISOLATED; + + encoded_id[0] = 0x18; + encoded_id[1] = 0x11; + encoded_id[2] = 0x12; + encoded_id[3] = 0x0b; + encoded_id[4] = 0x14; + encoded_id[5] = 0x0d; + encoded_id[6] = 0x0e; + encoded_id[7] = 0x07; + + desired_IDptr = &desired_ID; + greatest_IDptr = &greatest_ID; + scam_strptr = scam_str; + + DebugPrint((3, "Sym8xx: Entering SCAM_assign_IDs... \n")); + + while ( isolation==ISOLATED ) + { + SCAM_xfer(SCAM_SYNC,DeviceExtension); + SCAM_xfer(SCAM_ASSIGN_ID,DeviceExtension); + + isolation=SCAM_isolate(NULL, scam_strptr, greatest_IDptr, desired_IDptr, + DEFER,DeviceExtension); + if (DeviceExtension->sna_delay) + { + DeviceExtension->ID_map = idmap; + return; + } + + if (isolation == ISOLATED) + { + /* Assign desired Id if possible, if not, scan to the next lowest + value possible, if none lower found then search for higer ID to + assign */ + + /* Check for wide support */ + if ( (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE) && + (greatest_ID == 0x01) ) + { + wide = 1; + } + + else + { + wide = 0; + } + + new_id = 0xFF; + + if (desired_ID & ASSIGNABLE_ID) + { + /* Leave only wanted ID */ + desired_ID &= ~ASSIGNABLE_ID; + min_id = 0; + + /* Set to correct max ID for bus type */ + if ( !wide && (desired_ID > 7) ) + { + desired_ID = 0; + } + else if (wide) + { + if (desired_ID > 7) + min_id = 8; + if (desired_ID > 15) + desired_ID = 8; + } + + try_greater = 0; + set_greater = 0; + wanted_id = desired_ID; + + /* This do loop is for the 2nd try at finding an open ID. + * If the next do loop fails to find an ID that is the desired + * ID or one that is lower, this loop will be enabled to try + * scanning from highest ID to lowest ID. + */ + + do + { + if (set_greater) + { + try_greater = 1; + set_greater = 0; + } + + do + { + /* Search desired ID then all lower IDs till an + available one is found or set flag to indicate + higher priority IDs need to be searched */ + + for ( i=0; (idmap & (ULONG)(1<<(wanted_id - i))) && + ((wanted_id-i) >= min_id); i++); + if ( (wanted_id - i) >= min_id ) + { + new_id = wanted_id - i; + idmap |= (ULONG)(1 << new_id); + } + else if (min_id == 0) + { + if (wide) + { + min_id = 8; + wanted_id = 15; + } + else + set_greater = 1; + } + else + set_greater = 1; + + } while ( (new_id == 0xff) && (set_greater == 0) ); + + /* heres the check to see if we need to continue */ + if (set_greater) + { + wanted_id = 7; + min_id = 0; + } + + } while ( !try_greater && set_greater ); + } + + if ( new_id != 0xff ) + { + if ( new_id <= 7 ) + SCAM_xfer(SCAM_SET_ID_00,DeviceExtension); + else + SCAM_xfer(SCAM_SET_ID_01,DeviceExtension); + + /* Send encoded ID */ + SCAM_xfer(encoded_id[new_id],DeviceExtension); + } + else + isolation = NOBODY_HOME; + } + } + + /* This SCAM iteration is to stop all SCAM protocol on the bus. Possibly + get a broken drive off the bus or one that can not be assigned an ID. */ + + SCAM_xfer(SCAM_SYNC,DeviceExtension); + SCAM_xfer(SCAM_ASSIGN_ID,DeviceExtension); + isolation=SCAM_isolate(NULL, scam_strptr, greatest_IDptr, desired_IDptr, + STOP,DeviceExtension); + + DebugPrint((3, "Sym8xx: Exiting SCAM_assign_IDs, Idmap=%2x \n",idmap)); + + DeviceExtension->ID_map = idmap; + return; +} + + +/************************************************************************/ +/* Returns: */ +/* ISOLATED valid isolation cycle */ +/* NOBODY_HOME no data was transferred */ +/************************************************************************/ + +LONG SCAM_isolate(UCHAR *outstr, UCHAR *instr, + UCHAR *greatest_ID, UCHAR *desired_ID, + UCHAR function,PHW_DEVICE_EXTENSION DeviceExtension) +{ + UCHAR first_quintet=1; + UCHAR byteloop=0; + UCHAR strloop=0; + UCHAR valid_id; + UCHAR *sendstr; + UCHAR *recvstr; + CHAR sendchar='\0',recvchar='\0'; + UCHAR terminate=0,quintet=0; + + sendstr=outstr; /* Make copies of the string pointers */ + recvstr=instr; /* for local manipulation. */ + + strloop=1; /* Init loop count */ + while ((strloop <= SCAM_ID_STRLEN) && (!terminate)) + { + if (sendstr==NULL) + sendchar='\0'; + else + sendchar=*sendstr++; + + byteloop=1; /* Init loop count through the byte */ + recvchar='\0'; /* Clear received character */ + + while ((byteloop <= 8) && (!terminate)) + { + if (function == DEFER) + { + quintet=SCAM_xfer(0,DeviceExtension); + terminate=(quintet==0); /* Abort if no players */ + } + else if (function == STOP) + { + quintet = SCAM_xfer(0x10,DeviceExtension); + terminate=1; + } + else + { + quintet = (sendchar & 0x80) ? 2 : 1; + quintet = SCAM_xfer(quintet, DeviceExtension); + + /* Defer if sent a 0 bit and saw a 1 bit */ + function=(!(sendchar & 0x80) && (quintet==0x3)); + } + + /* Always terminate if DB4 asserted */ + if (quintet & 0x10) + terminate=1; + + recvchar=(recvchar | ((quintet == 0x01) ? 0 : 1)); + + /* Don't shift on last read */ + if (byteloop != 8) + { + sendchar=(sendchar << 1); /* Shift to next bit */ + recvchar=(recvchar << 1); /* Shift to next bit */ + } + byteloop++; + + if (first_quintet && terminate) + return(NOBODY_HOME); + first_quintet=0; /* Clear first flag */ + } + + if (recvstr != NULL) + *recvstr++ = recvchar; + + if (strloop == 1) + { + *greatest_ID = ( (recvchar & 0x30) >> 4); + valid_id = ( (recvchar & 0x06) >> 1 ); + + if (!(recvchar & 0x01)) + { + DeviceExtension->sna_delay=0x01; + return(NOBODY_HOME); + } + } + else if (strloop == 2) + { + switch ( valid_id ) + { + case 1: + { + *desired_ID = ( (recvchar & 0x1F) | ASSIGNABLE_ID ); + break; + } + case 2: + { + *desired_ID = ( recvchar & 0x1F ); + break; + } + default: + { + *desired_ID = 0x7F; + break; + } + } + } + strloop++; + } + + return(ISOLATED); +} + + +/************************************************************************/ +/* This routine performs all SCAM handshaking necessary to transfer a */ +/* single quintet. It leaves the bus ready for another transfer. */ +/* It returns the actual quintet which was transferred on the bus. */ +/************************************************************************/ + +UCHAR SCAM_xfer(UCHAR quintet,PHW_DEVICE_EXTENSION DeviceExtension) +{ + UCHAR actual; + UCHAR myquint; + +#define CURRENT READ_SIOP_UCHAR(SBDL) + + myquint=quintet & QUINTET_MASK; + + /* While waiting for bits to drop read reg twice to take care of glitches */ + + /* Assert data and DB5 */ + WRITE_SIOP_UCHAR(SODL,(UCHAR)(myquint |DB5 |DB7)); + + /* Assert SCSI data bus */ + WRITE_SIOP_UCHAR(SCNTL1,(UCHAR)(READ_SIOP_UCHAR(SCNTL1) | 0x40)); + + /* Release DB7 */ + WRITE_SIOP_UCHAR(SODL,(UCHAR)((CURRENT & ~DB7) | DB5)); + + /* Wait for DB7 release */ + de_glitch(0x58,DB7,DeviceExtension); +// while((READ_SIOP_UCHAR(SBDL) & DB7) || (READ_SIOP_UCHAR(SBDL) & DB7)); + + /* Latch quintet */ + actual = READ_SIOP_UCHAR(SBDL) & QUINTET_MASK; + + /* Assert DB6 (begin handshake) */ + WRITE_SIOP_UCHAR(SODL,(UCHAR)(CURRENT | DB5 | DB6)); + + /* Release DB5 (end Handshake) */ + WRITE_SIOP_UCHAR(SODL,(UCHAR)((CURRENT & ~DB5) | DB6)); + + /* Wait for DB5 release */ + de_glitch(0x58,DB5,DeviceExtension); +// while ((READ_SIOP_UCHAR(SBDL) & DB5) || (READ_SIOP_UCHAR(SBDL) & DB5)); + + /* Assert DB7 (begin handshake) */ + WRITE_SIOP_UCHAR(SODL,(UCHAR)(DB6 | DB7)); + + /* Release DB6 (end handshake) */ + WRITE_SIOP_UCHAR(SODL,(UCHAR)(DB7)); + + /* Wait for DB6 release */ + de_glitch(0x58,DB6,DeviceExtension); +// while ((READ_SIOP_UCHAR(SBDL) & DB6) || (READ_SIOP_UCHAR(SBDL) & DB6)); + + return(actual); +} + + +/************************************************************************/ +/* This routine ends the current SCAM protocol by dropping all signals */ +/************************************************************************/ + +VOID SCAM_release(PHW_DEVICE_EXTENSION DeviceExtension) +{ + /* Make sure no control signals are asserted */ + WRITE_SIOP_UCHAR(SOCL,0x00); + WRITE_SIOP_UCHAR(SODL,0x00); + WRITE_SIOP_UCHAR(SODL+1,0x00); +} + + +/************************************************************************/ +/* This routine restores the 720 to a normal operating mode. */ +/************************************************************************/ + +VOID ExitLLM(PHW_DEVICE_EXTENSION DeviceExtension) +{ + /* Disable low level mode */ + WRITE_SIOP_UCHAR(STEST2,(UCHAR)(READ_SIOP_UCHAR(STEST2) & 0x7E)); + + EatInts(DeviceExtension); +} + + +/******************************************************* +** ** +** restore_reg ** +** ** +*******************************************************/ + +VOID restore_reg( PHW_DEVICE_EXTENSION DeviceExtension, + PSIOP_REG_STORE RegStore) +{ + WRITE_SIOP_UCHAR(SCNTL0,RegStore->reg_st[0]); + WRITE_SIOP_UCHAR(SCNTL3,RegStore->reg_st[1]); + WRITE_SIOP_UCHAR(SCID,RegStore->reg_st[2]); + WRITE_SIOP_UCHAR(SXFER,RegStore->reg_st[3]); + WRITE_SIOP_UCHAR(SDID,RegStore->reg_st[4]); + WRITE_SIOP_UCHAR(GPREG,RegStore->reg_st[5]); + WRITE_SIOP_UCHAR(CTEST3,RegStore->reg_st[6]); + WRITE_SIOP_UCHAR(CTEST4,RegStore->reg_st[7]); + WRITE_SIOP_UCHAR(CTEST5,RegStore->reg_st[8]); + WRITE_SIOP_UCHAR(DMODE,RegStore->reg_st[9]); + WRITE_SIOP_UCHAR(DIEN,RegStore->reg_st[10]); + WRITE_SIOP_UCHAR(DCNTL,RegStore->reg_st[11]); + WRITE_SIOP_UCHAR(SIEN0,RegStore->reg_st[12]); + WRITE_SIOP_UCHAR(SIEN1,RegStore->reg_st[13]); + WRITE_SIOP_UCHAR(GPCNTL,RegStore->reg_st[14]); + WRITE_SIOP_UCHAR(STIME0,RegStore->reg_st[15]); + WRITE_SIOP_UCHAR(STIME1,RegStore->reg_st[16]); + WRITE_SIOP_UCHAR(RESPID0,RegStore->reg_st[17]); + WRITE_SIOP_UCHAR(RESPID1,RegStore->reg_st[18]); + WRITE_SIOP_UCHAR(STEST2,RegStore->reg_st[19]); + WRITE_SIOP_UCHAR(STEST3,RegStore->reg_st[20]); + WRITE_SIOP_ULONG(DSA,RegStore->long_st); +} + + + +/******************************************************/ +/* This routine eats any interrupts pending. */ +/******************************************************/ + +UCHAR EatInts(PHW_DEVICE_EXTENSION DeviceExtension) +{ + UCHAR dispose; + UCHAR istat=0; + UCHAR sist0=0; + UCHAR reset_flag; + +#define DIP 0x01 +#define SIP 0x02 + + reset_flag=TRUE; + istat=READ_SIOP_UCHAR(ISTAT); + sist0=READ_SIOP_UCHAR(SIST0); + + /* Spin until no DMA or SCSI interrupts left */ + while ( (istat & (DIP + SIP)) || (sist0 & 0x02) ) + { + if (sist0 & 0x02) + { + reset_flag=FALSE; + dispose=READ_SIOP_UCHAR(SIST0); + dispose=READ_SIOP_UCHAR(SIST1); + } + + if (istat & SIP) + { + dispose=READ_SIOP_UCHAR(SIST0); + dispose=READ_SIOP_UCHAR(SIST1); + } + + if (istat & DIP) + { + dispose=READ_SIOP_UCHAR(DSTAT); + } + + ScsiPortStallExecution(5000); + istat=READ_SIOP_UCHAR(ISTAT); + sist0=READ_SIOP_UCHAR(SIST0); + } + return(reset_flag); +} + + +/************************************************************************/ +/* This routine handshakes ACK based on REQ to send a byte to a target */ +/************************************************************************/ + +VOID init_send_byte(LONG dbyte,PHW_DEVICE_EXTENSION DeviceExtension) +{ + /* Wait for REQ asserted */ + while (!(READ_SIOP_UCHAR(SBCL) & REQ)) + { + if (READ_SIOP_UCHAR(ISTAT) & 0x02) + return; + } + + WRITE_SIOP_UCHAR(SODL,(UCHAR)dbyte); /* Assert data */ + + WRITE_SIOP_UCHAR(SCNTL1,(UCHAR)(READ_SIOP_UCHAR(SCNTL1) | 0x40)); + /* Assert SCSI data bus */ + WRITE_SIOP_UCHAR(SOCL,0x00); /* Clear ATN */ + WRITE_SIOP_UCHAR(SOCL,ACK); /* Set ACK */ + + /* Wait for REQ released */ + while (READ_SIOP_UCHAR(SBCL) & REQ); + + WRITE_SIOP_UCHAR(SODL,0x00); /* Clear data */ + WRITE_SIOP_UCHAR(SOCL,0x00); /* Clear ACK */ + + /* De-assert SCSI data bus */ + WRITE_SIOP_UCHAR(SCNTL1,(UCHAR)(READ_SIOP_UCHAR(SCNTL1) & ~0x40)); +} + + +/************************************************************************/ +/* This routine handshakes ACK based on REQ to receive a byte from a */ +/* target. */ +/************************************************************************/ + +UCHAR init_recv_byte(PHW_DEVICE_EXTENSION DeviceExtension) +{ + UCHAR dbyte; + + /* De-assert SCSI data bus */ + WRITE_SIOP_UCHAR(SCNTL1,(UCHAR)(READ_SIOP_UCHAR(SCNTL1) & ~0x40)); + + /* Wait for REQ asrt */ + while (!(READ_SIOP_UCHAR(SBCL) & REQ)) + { + if (READ_SIOP_UCHAR(ISTAT) & 0x02) + return(0); + } + + dbyte=READ_SIOP_UCHAR(SBDL); /* Latch data */ + WRITE_SIOP_UCHAR(SOCL,0x00); /* Clear ATN */ + WRITE_SIOP_UCHAR(SOCL,ACK); /* Set ACK */ + + /* Wait for REQ released */ + while (READ_SIOP_UCHAR(SBCL) & REQ); + + WRITE_SIOP_UCHAR(SOCL,0x00); /* Clear ACK */ + return(dbyte); +} + + +/************************************************************************/ +/* de-glitch is used to take the bounce off the async control lines */ +/* used for SCAM data passing. The glitch value is set to 32 to */ +/* take care of the possible 32 wired or glitches if a wide 32 bit bus */ +/* is used and all ID's are taken. */ +/************************************************************************/ + +VOID de_glitch(ULONG offset,UCHAR value,PHW_DEVICE_EXTENSION DeviceExtension) +{ + UCHAR glitch,i; + ULONG chip_base=(ULONG)DeviceExtension->SIOPRegisterBase; + PUCHAR chip_reg; + + chip_reg = (PUCHAR)(chip_base+offset); + + do + { + glitch=0; + for (i=0;i<32;i++) + { + if (ScsiPortReadPortUchar(chip_reg) & value) + { + glitch=1; + i=32; + } + } + } while (glitch); +} + + +/*****************************************************************************/ +/* delay_mils is used to delay the scam code X amount of milliseconds by +** using the system call of scsiportstallexecution +** +******************************************************************************/ +void delay_mils( USHORT counter) +{ + USHORT i; + + for ( i = counter; i > 0; i--) + ScsiPortStallExecution(999); +} + +#endif diff --git a/private/ntos/miniport/symbios/symc810/symc810.h b/private/ntos/miniport/symbios/symc810/symc810.h new file mode 100644 index 000000000..06b917fd6 --- /dev/null +++ b/private/ntos/miniport/symbios/symc810/symc810.h @@ -0,0 +1,101 @@ +/************************************************************************ +* * +* Copyright 1994 Symbios Logic Inc. All rights reserved. * +* * +* This file is confidential and a trade secret of Symbios Logic * +* The receipt of or possession of this file does not convey any * +* rights to reproduce or disclose its contents or to manufacture, * +* use, or sell anything is may describe, in whole, or in part, * +* without the specific written consent of Symbios Logic Inc * +* * +************************************************************************/ + +/*+++HDR + * + * Version History + * --------------- + * + * Date Who? Description + * -------- ---- ------------------------------------------------------- + * + * +---*/ + + +#ifndef _SYM53C810_ +#define _SYM53C810_ + + +// +// 53C8XX SIOP I/O registers. +// + +typedef struct _SIOP_REGISTER_BASE { + UCHAR SCNTL0; // 00 SCSI control 0 + UCHAR SCNTL1; // 01 SCSI control 1 + UCHAR SCNTL2; // 02 SCSI control 2 + UCHAR SCNTL3; // 03 SCSI control 3 + UCHAR SCID; // 04 SCSI chip ID + UCHAR SXFER; // 05 SCSI transfer + UCHAR SDID; // 06 SCSI destination ID + UCHAR GPREG; // 07 general purpose bits + UCHAR SFBR; // 08 SCSI first byte received + UCHAR SOCL; // 09 SCSI output control latch + UCHAR SSID; // 0a SCSI selector id + UCHAR SBCL; // 0b SCSI bus control lines + UCHAR DSTAT; // 0c DMA status + UCHAR SSTAT0; // 0d SCSI status 0 + UCHAR SSTAT1; // 0e SCSI status 1 + UCHAR SSTAT2; // 0f SCSI status 2 + ULONG DSA; // 10-13 data structure address + UCHAR ISTAT; // 14 interrupt status + UCHAR RESERVED0[3]; // 15-17 reserved + UCHAR CTEST0; // 18 chip test 0 + UCHAR CTEST1; // 19 chip test 1 + UCHAR CTEST2; // 1a chip test 2 + UCHAR CTEST3; // 1b chip test 3 + ULONG TEMP; // 1c-1f temporary stack + UCHAR DFIFO; // 20 DMA fifo + UCHAR CTEST4; // 21 chip test 4 + UCHAR CTEST5; // 22 chip test 5 + UCHAR CTEST6; // 23 chip test 6 + UCHAR DBC[3]; // 24-26 DMA byte counter + UCHAR DCMD; // 27 DMA command + ULONG DNAD; // 28-2b DMA next address for data + ULONG DSP; // 2c-2f DMA scripts pointer + UCHAR DSPS[4]; // 30-33 DMA scripts pointer save + UCHAR SCRATCH[4]; // 34-37 general purpose scratch pad A + UCHAR DMODE; // 38 DMA mode + UCHAR DIEN; // 39 DMA interrupt enable + UCHAR DWT; // 3a DMA watchdog timer + UCHAR DCNTL; // 3b DMA control + ULONG ADDER; // 3c-3f sum output of internal adder + UCHAR SIEN0; // 40 SCSI interrupt enable 0 + UCHAR SIEN1; // 41 SCSI interrupt enable 1 + UCHAR SIST0; // 42 SCSI interrupt status 0 + UCHAR SIST1; // 43 SCSI interrupt status 1 + UCHAR SLPAR; // 44 SCSI longitudinal parity + UCHAR SWIDE; // 45 SCSI wide residue + UCHAR MACNTL; // 46 memory access control + UCHAR GPCNTL; // 47 general purpose control + UCHAR STIME0; // 48 SCSI timer 0 + UCHAR STIME1; // 49 SCSI timer 1 + UCHAR RESPID0; // 4a response ID low-byte + UCHAR RESPID1; // 4b response ID high-byte + UCHAR STEST0; // 4c SCSI test 0 + UCHAR STEST1; // 4d SCSI test 1 + UCHAR STEST2; // 4e SCSI test 2 + UCHAR STEST3; // 4f SCSI test 3 + UCHAR SIDL; // 50-51 SCSI input data latch + UCHAR SIDL_LOWER; + UCHAR RESERVED3[2]; // 52-53 reserved + UCHAR SODL; // 54-55 SCSI output data latch + UCHAR SODL_LOWER; + UCHAR RESERVED4[2]; // 56-57 reserved + UCHAR SBDL; // 58-59 SCSI bus data lines + UCHAR SBDL_LOWER; + UCHAR RESERVED5[2]; // 5a-5b reserved + ULONG SCRATCHB; // 5c-5f general purpose scratch pad B +} SIOP_REGISTER_BASE, *PSIOP_REGISTER_BASE; + +#endif diff --git a/private/ntos/miniport/symbios/symc810/symc810.rc b/private/ntos/miniport/symbios/symc810/symc810.rc new file mode 100644 index 000000000..38d852f94 --- /dev/null +++ b/private/ntos/miniport/symbios/symc810/symc810.rc @@ -0,0 +1,41 @@ +/************************************************************************ +* * +* Copyright 1994 Symbios Logic Inc. All rights reserved. * +* * +* This file is confidential and a trade secret of Symbios Logic Inc. * +* The receipt of or possession of this file does not convey any * +* rights to reproduce or disclose its contents or to manufacture, * +* use, or sell anything is may describe, in whole, or in part, * +* without the specific written consent of Symbios Logic inc. * +* * +************************************************************************/ + +/*+++HDR + * + * Version History + * --------------- + * + * Date Who? Description + * -------- ---- ------------------------------------------------------- + * + * +---*/ + +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Symbios Logic Inc. SCSI Miniport Driver" +#define VER_INTERNALNAME_STR "SYMC8XX.SYS" + + +#define VER_COMPANYNAME_STR "Symbios Logic Inc." +#define VER_LEGALCOPYRIGHT_YEARS "1992-1994" +#define VER_LEGALCOPYRIGHT_STR "Copyright \251 Symbios Logic Inc. " VER_LEGALCOPYRIGHT_YEARS +#define VER_PRODUCTNAME_STR "Symbios Logic Inc. SCSI Miniport Driver" +#define VER_PRODUCTVERSION_STR "DULUTH-1.92.05" + +#include "common.ver" + diff --git a/private/ntos/miniport/symbios/symc810/symnvm.h b/private/ntos/miniport/symbios/symc810/symnvm.h new file mode 100644 index 000000000..5d09df2a1 --- /dev/null +++ b/private/ntos/miniport/symbios/symc810/symnvm.h @@ -0,0 +1,325 @@ +/*************************************************************************** + * * + * Copyright 1995 Symbios Logic Incorporated. All rights reserved. * + * * + * This file is confidential and a trade secret of Symbios Logic. The * + * receipt of or possession of this file does not convey any rights to * + * reproduce or disclose its contents or to manufacture, use, or sell * + * anything it may describe, in whole, or in part, without the specific * + * written consent of Symbios Logic Incorporated. * + * * + ***************************************************************************/ + +/* Name: SYMNVM.H + * Title: NT's header file for NVRAM support + * $Workfile: symnvm.h $ + * $Revision: 1.1 $ + * $Modtime: 22 Sep 1995 13:03:58 $ + * Programmer: Scott Masterson + * Creation Date: July 14, 1995 + * + * Version History + * --------------- + * + * Date Who? Description + * -------- ---- ------------------------------------------------------- +#BeginRevision + * 7/14/95 SAM Initial check in. For definitions of fields see the SDMS4.0 + * bootrom files. + * 7/18/95 SAM updated structures to match major 0 minor 0x30 rev levels + * added IoPort field to HBA_INIT structure +#EndRevision + * + * +#BeginDescription + * + * This include file contains the definitions for the NT driver to read user + * set values in the nvram chip. The driver looks at the HBA ID and scam ID values. + * The structure version number for this code is major -0x00 minor -0x21. + * To get the definitions of the fields look at the SDMS4.0 bootrom include files + * ROMTYPES.H + * ROMPUBLC.H + * ROMSTRUC.H + * ROMSCAM.H + * ROMHW.H + * ROMBIOS.H + + * +#EndDescription + * + *------------------------------------------------------------------------- + * + * $Header: P:/VCS/WINNT/DULUTH/SYMNVM.H_v 1.1 29 Feb 1996 13:50:46 SDENNY $ + * + */ + +/* If this header file has not been included yet */ +#if ! defined SYMNVM_H +#define SYMNVM_H + +/* Since all data structures must be byte aligned throughout this file, we + * issue the commands to perform that alignment once, and then restore the + * compilers default alignment at the end of this file. + */ + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * Non Volatile Memory types + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + +/* NVS_VERSION_MAJOR and NVS_VERSION_MINOR are #defined to the revision of the + * main data structure (NON_VOLATILE_SETTINGS) in this document. + */ + +#define NVS_VERSION_MAJOR (0x00) +#define NVS_VERSION_MINOR (0x30) + +#define BI_MAX_HBA 4 +#define HW_MAX_DEVICES 16 +#define HW_MAX_SCAM_DEVICES 4 +#define NVMDATAOFFSET 0x100 + +#define DATA_MASK 0x01 +#define CLOCK_MASK 0x02 + +#define FAILURE (0) +#define SUCCESS (1) + +typedef enum _HEADER_TYPE +{ + HT_BOOT_ROM = 0, + HT_DOS_ASPI = 1, + HT_WINDOWS_ASPI = 2, + HT_NETWARE = 3, + HT_UNIXWARE = 4, + HT_SCO_UNIX = 5, + HT_WINDOWS_NT = 6, + HT_WINDOWS95 = 7, + HT_OS_2 = 8, + HT_SOLARIS = 9, + HT_INTERACTIVE = 10, + HT_NEXTSTEP = 11, + HT_END_MEMORY_BLOCK = 0xFEFE +} HEADER_TYPE; + +typedef unsigned int UINT; +typedef unsigned char UINT8; +typedef unsigned int UINT16; +typedef unsigned long UINT32; + +#define WIDE_NONE (8) +#define WIDE_16 (16) +#define WIDE_32 (32) +#define WIDE_NO_CHANGE (0xFF) + +typedef UINT8 WIDE_PARAMETERS; +typedef USHORT IO_ADDRESS; +typedef UINT32 PHYS_ADDRESS; + +typedef USHORT HBA_FLAGS; +#define HF_SCAM_ENABLED (0x0001) +#define HF_PARITY_ENABLED (0x0002) +#define HF_DISPLAY_VERBOSE_ENABLED (0x0004) +#define HF_NO_NON_VOLATILE_MEMORY (0x0008) + +typedef UINT8 DEVICE_FLAGS; +#define DF_DISCONNECT_ENABLED (0x01) +#define DF_SCAN_ENABLED (0x02) +#define DF_LUNS_ENABLED (0x04) +#define DF_QT_ENABLED (0x08) +#define DF_ALL_FEATURES_ENABLED (DF_DISCONNECT_ENABLED | DF_SCAN_ENABLED | \ + DF_LUNS_ENABLED | DF_QT_ENABLED) + +typedef enum MEMORY_STATUS +{ + MS_GOOD = 0, + MS_ILLEGAL_ADDRESS, + MS_GENERAL_ERROR +} MEMORY_STATUS; + +typedef enum _TERMINATION_STATE +{ + TS_CANT_PROGRAM = 0, + TS_ENABLED = 1, + TS_DISABLED = 2 +} TERMINATION_STATE; + +typedef enum _ADAPTER_TYPE +{ + AT_UNKNOWN = 0, + AT_400A = 1, + AT_406A = 2, + AT_416 = 3, + AT_8XX = 4 +} ADAPTER_TYPE; + +typedef struct _ADAPTER_IO_INFO +{ + USHORT RangeSize; + IO_ADDRESS IoBasePort; +} ADAPTER_IO_INFO, * PTR_ADAPTER_IO_INFO; + +typedef struct _ADAPTER_MEMORY_INFO +{ + PHYS_ADDRESS PhyMemoryBase; + UINT8 *VirtMemoryBase; +} ADAPTER_MEMORY_INFO, * PTR_ADAPTER_MEMORY_INFO; + +typedef struct _ADAPTER_416_INFO +{ + UINT32 DeviceId; + UINT32 SerialNumber; +} ADAPTER_416_INFO, * PTR_ADAPTER_416_INFO; + +typedef struct _ADAPTER_8XX_INFO +{ + USHORT DeviceId; + USHORT VendorId; + UINT8 BusNumber; + UINT8 BusIndex; +} ADAPTER_8XX_INFO, * PTR_ADAPTER_8XX_INFO; + +typedef union _ADAPTER_INFO +{ + ADAPTER_416_INFO Hba416; + ADAPTER_8XX_INFO Hba8xx; + ADAPTER_IO_INFO HbaIo; + ADAPTER_MEMORY_INFO HbaMemory; +} ADAPTER_INFO, * PTR_ADAPTER_INFO; + +typedef enum _SCAN_ORDER +{ + SO_LOW_TO_HIGH = 0, + SO_HIGH_TO_LOW = 1 +} SCAN_ORDER; + +typedef enum _REMOVABLE_MEDIA +{ + RM_NO_SUPPORT = 0, + RM_BOOT_DEVICE_ONLY = 1, + RM_MEDIA_INSTALLED_ONLY = 2 +} REMOVABLE_MEDIA; + +typedef struct _HBA_INIT +{ + USHORT Type; + ADAPTER_INFO HbaInfo; + BOOLEAN InitStatus; + IO_ADDRESS IoPort; +} HBA_INIT, * PTR_HBA_INIT; + +typedef struct _DEVICE_TABLE +{ + USHORT Flags; // 8 bits + UINT8 Reserved; + USHORT WideDataBits; // 8 bits + UINT8 SyncOffset; + USHORT SyncPeriodNs; + USHORT Timeout; +} DEVICE_TABLE, * PTR_DEVICE_TABLE; + +typedef struct _SCAM_IDENTIFIER +{ + UINT8 DeviceType[ 2 ]; + char VendorId[ 8 ]; + char VendorSpecific[ 21 ]; + UINT8 Reserved; +} SCAM_IDENTIFIER, * PTR_SCAM_IDENTIFIER; + +typedef enum _SCAM_ID_METHOD +{ + SIM_DEFAULT_METHOD = 0, + SIM_DONT_ASSIGN = 1, + SIM_SET_SPECIFIC_ID = 2, + SIM_USE_ORDER_GIVEN = 3 +} SCAM_ID_METHOD; + +typedef enum _SCAM_STATUS +{ + SS_UNKNOWN = 0, + SS_DEVICE_NOT_FOUND = 1, + SS_ID_NOT_SET = 2, + SS_ID_VALID = 3 +} SCAM_STATUS; + +typedef struct _SCAM_TABLE +{ + USHORT ScamId; + USHORT HowToSetId; + USHORT ScamStatus; + UINT8 ScamTargetId; + UINT8 Reserved; +} SCAM_TABLE, * PTR_SCAM_TABLE; + +typedef struct _NVM_HEADER +{ + USHORT Type; + USHORT Length; + USHORT CheckSum; +} NVM_HEADER, * PTR_NVM_HEADER; + +typedef SCAM_TABLE NVM_SCAM_DATA; +typedef PTR_SCAM_TABLE PTR_NVM_SCAM_DATA; + + +typedef struct _NON_VOLATILE_SETTINGS +{ + UINT8 VersionMajor; + UINT8 VersionMinor; + UINT8 BootCrc[4]; // changed def. to match our compiler + USHORT HbaFlags; + USHORT ScanOrder; + USHORT TerminatorState; + USHORT RemovableMediaSetting; + UINT8 HostScsiId; + UINT8 NumHba; + UINT8 NumDevices; + UINT8 MaxScamDevices; + UINT8 NumValidScamDevices; + UINT8 Reserved; + HBA_INIT HbaInit[ BI_MAX_HBA ]; + DEVICE_TABLE DeviceTable[ HW_MAX_DEVICES ]; + NVM_SCAM_DATA ScamTable[ HW_MAX_SCAM_DEVICES ]; + UINT8 freespace[1024]; // this added by NT so we can read past end + // of the NVRAM structure to get all data + // used for checksum + +} NON_VOLATILE_SETTINGS, * PTR_NON_VOLATILE_SETTINGS; + + +/* Define some macros to access the offsets of particular portions of this + * data structure. These macros are then used to allow the code to more + * easily program only those parts of non-volatile memory which might have + * changed when the user issues a set NVM call. + */ + +#define NVS_ADAPTER_BEGIN (offsetof(struct _NON_VOLATILE_SETTINGS, HbaFlags)) +#define NVS_ADAPTER_END (offsetof(struct _NON_VOLATILE_SETTINGS, \ + DeviceTable[ 0 ])) +#define NVS_ADAPTER_LENGTH (NVS_ADAPTER_END - NVS_ADAPTER_BEGIN) + +#define NVS_DEVICE_BEGIN(x) (offsetof(struct _NON_VOLATILE_SETTINGS, \ + DeviceTable[(x)])) +#define NVS_DEVICE_END(x) (offsetof(struct _NON_VOLATILE_SETTINGS, \ + DeviceTable[(x)+1])) +#define NVS_DEVICE_LENGTH (sizeof( DEVICE_TABLE )) + +#if HW_MAX_SCAM_DEVICES != 0 + #define NVS_SCAM_BEGIN (offsetof(struct _NON_VOLATILE_SETTINGS, \ + ScamTable[0])) + #define NVS_SCAM_END (sizeof(NON_VOLATILE_SETTINGS)) + #define NVS_SCAM_LENGTH (NVS_SCAM_END - NVS_SCAM_BEGIN) +#endif + +/* NVM_DATA_SIZE defines the number of bytes of data we need to access the + * NVM header structure and the NVM data structure for our ROM. + */ + +#define NVM_DATA_SIZE (sizeof(NVM_HEADER) + sizeof(NON_VOLATILE_SETTINGS)) + +/* We are now done with the requirement of forcing byte alignment on all + * elements so restore the compilers default structure alignment. + */ + +#endif /* End of if SYMNVM_H */ + diff --git a/private/ntos/miniport/symbios/symc810/symscam.h b/private/ntos/miniport/symbios/symc810/symscam.h new file mode 100644 index 000000000..2b65c33d3 --- /dev/null +++ b/private/ntos/miniport/symbios/symc810/symscam.h @@ -0,0 +1,107 @@ +/************************************************************************ +* * +* Copyright 1994 Symbios Logic Inc. All rights reserved. * +* * +* This file is confidential and a trade secret of Symbios Logic Inc. * +* The receipt of or possession of this file does not convey any * +* rights to reproduce or disclose its contents or to manufacture, * +* use, or sell anything is may describe, in whole, or in part, * +* without the specific written consent of Symbios Logic Inc. * +* * +************************************************************************/ + +/*+++HDR + * + * Version History + * --------------- + * + * Date Who? Description + * -------- ---- ------------------------------------------------------- + * + * +---*/ + + +#ifndef _SYMSCAM_ +#define _SYMSCAM_ + + + + + +/************************/ +/* SCAM data structures */ +/************************/ + +/* TC1_TC2_VENDOR__VENDOR_UNIQUE________ */ +static CHAR our_scam_id_str[]= {"\045\007SYM SDMS SCAMCore - Alpha"}; + +typedef struct _SIOP_REG_STORE { // storage to save/restore SIOP state + UCHAR reg_st[21]; // used by AdapterState and SCAM + ULONG long_st; +} SIOP_REG_STORE, *PSIOP_REG_STORE; + +/************************/ +/* SCAM definitions */ +/************************/ + +#define Ent_fragmovefirstin 0 +#define Ent_fragmovelastin 8 +#define INSTRUCT 1 +#define ISOLATED 0 +#define NOBODY_HOME -1 + +#define QUINTET_MASK 0x1F +#define SCAM_SYNC 0x1F +#define SCAM_ASSIGN_ID 0x00 +#define SCAM_SET_PRIO 0x01 +#define SCAM_SET_ID_00 0x18 +#define SCAM_SET_ID_01 0x11 +#define SCAM_SET_ID_10 0x12 +#define SCAM_SET_ID_11 0x0B + +#define ASSIGNABLE_ID 0x80 +#define DEFER 0x01 +#define STOP 0x02 + +#define SCAM_ID_STRLEN 0x20 +#define SCAM_DEFERRED -1 +#define SCAM_TERMINATED -2 + +#define MSG_NOOP 0x08 +#define MSG_RESET 0x0C + +#define ARB_IN_PROGRESS 0x10 +#define CONNECTED 0x08 + +/* Timer value for HTH/SEL/GEN timers for short timeout */ +/* 0x05 is 1.6mS which is comfortably between the 1 & 4 */ +/* mS times for SCAM tolerant vs SCAM compliant. */ +#define SHORT_720_STO 0x05 +#define DISABLE_720_STO 0x00 + +#define IO 0x01 +#define CD 0x02 +#define MSG 0x04 +#define ATN 0x08 +#define SEL 0x10 +#define BSY 0x20 +#define ACK 0x40 +#define REQ 0x80 + +/* SBCL phases */ +#define PHASE_MASK (MSG & CD & IO) +#define DATA__OUT (~MSG & ~CD & ~IO) +#define DATA__IN (~MSG & ~CD & IO) +#define COMMAND (~MSG & CD & ~IO) +#define STATUS (~MSG & CD & IO) +#define MESSAGE_OUT (MSG & CD & ~IO) +#define MESSAGE_IN (MSG & CD & IO) +#define PHASE (READ_SIOP_UCHAR(SBCL) & PHASE_MASK) + +#define DB5 0x20 +#define DB6 0x40 +#define DB7 0x80 + +#endif + diff --git a/private/ntos/miniport/symbios/symc810/symsiop.h b/private/ntos/miniport/symbios/symc810/symsiop.h new file mode 100644 index 000000000..15b67c09a --- /dev/null +++ b/private/ntos/miniport/symbios/symc810/symsiop.h @@ -0,0 +1,452 @@ +/************************************************************************ +* * +* Copyright 1994 Symbios Logic Inc. All rights reserved. * +* * +* This file is confidential and a trade secret of Symbios Logic Inc. * +* The receipt of or possession of this file does not convey any * +* rights to reproduce or disclose its contents or to manufacture, * +* use, or sell anything is may describe, in whole, or in part, * +* without the specific written consent of Symbios Logic Inc. * +* * +************************************************************************/ + +/*+++HDR + * + * Version History + * --------------- + * + * Date Who? Description + * -------- ---- ------------------------------------------------------- + * 1-16-96 SPD Added define for new ISR disposition + * +---*/ + + +#ifndef _SYMSIOP_ +#define _SYMSIOP_ + +// +// Define miniport constants. +// + +#define MAX_SYNCH_TABLE_ENTRY 8 // # of entries in synch period array +#define ASYNCHRONOUS_MODE_PARAMS 0x00 // asychronous xfer mode +#define MAX_SG_ELEMENTS 18 // max # of page breaks + 1 +#define MAX_ABORT_TRIES 100 // max times we will try to abort script +#define ABORT_STALL_TIME 3 // stall time between script abort tries +#define MAX_SYNCH_OFFSET 0x08 // max synchronous offset supported +#define MAX_875_SYNCH_OFFSET 0x10 // 875 larger sync offset +#define ENABLE_WIDE 0x08 // enable wide scsi +#define MAX_PHYS_BREAK_COUNT 18 // Max # of S/G elements +#define MESSAGE_BUFFER_SIZE 8 // maximum message size +#define RESET_STALL_TIME 30 // length of time bus reset line high +#define POST_RESET_STALL_TIME 1000 // drive recovery time after reset +#define CLEAR_FIFO_STALL_TIME 500 // Time to clear SCSI and DMA fifos +#define MAX_CLEAR_FIFO_LOOP 10 // Number of times in clear loop +#define SYM_MAX_TARGETS 16 +#define SYM_NARROW_MAX_TARGETS 8 + +//#define ADAPTER_CRYSTAL_SPEED 40 // adapter crystal speed +//#define DCNTL_DIVIDE_FACTOR 2 // crystal divide factor set in DCNTL + // register (see 53c8xx data manual) +#define MAX_XFER_LENGTH 0x00FFFFFF // maximum transfer length per request +// speed at which SIOP is clocked... +//#define SIOP_CLOCK_SPEED (ADAPTER_CRYSTAL_SPEED / DCNTL_DIVIDE_FACTOR) + +// +// SCSI equates and flags not included in SCSI.H +// TODO: Rework code to omit these +// + +#define SCSIMESS_IDENTIFY_DISC_PRIV_MASK 0x40 +#define SCSIMESS_IDENTIFY_LUN_MASK 0x07 +#define DSPS_RESELOP 0x80 + +#define CTEST3_CLEAR_FIFO 0x04 +#define CTEST3_FLUSH_FIFO 0x08 +#define CTEST5_USE_LARGE_FIFO 0x20 +#define CTEST5_BURST 0x04 + +#define DCMD_WAIT_DISCONNECT 0x48 +#define SSTAT1_ORF 0x40 +#define SSTAT1_OLF 0x20 +#define SSTAT2_ORF 0x40 +#define SSTAT2_OLF 0x20 +#define SBCL_MSG 0x04 +#define DFIFO_LOW_SEVEN 0x7F + +// +// Retry limits. +// + +#define MAX_SELECTION_RETRIES 1 + +// +// Symbios Logic 53C8xx script interrupt definitions. These values are returned in the +// DSPS register when a script routine completes. +// + +#define SCRIPT_INT_COMMAND_COMPLETE 0x00 // SCSI command complete +#define SCRIPT_INT_SAVE_DATA_PTRS 0x01 // save data ptrs +#define SCRIPT_INT_SAVE_WITH_DISCONNECT 0x02 // combination SDP & disconnect +#define SCRIPT_INT_DISCONNECT 0x03 // disconnect from SCSI bus +#define SCRIPT_INT_RESTORE_POINTERS 0x04 // restore data pointers +#define SCRIPT_INT_SCRIPT_ABORTED 0x05 // SCSI script aborted +#define SCRIPT_INT_TAG_RECEIVED 0x06 // Queue tag message recieved +#define SCRIPT_INT_DEV_RESET_OCCURRED 0x07 // indicates device was reset + // due to wierd phase +#define SCRIPT_INT_DEV_RESET_FAILED 0x08 // indicates above effort + // failed +#define SCRIPT_INT_IDE_MSG_SENT 0x0A // initiator detected error +#define SCRIPT_INT_SYNC_NOT_SUPP 0x0B // synchronous not supported +#define SCRIPT_INT_SYNC_NEGOT_COMP 0x0C // synchronous neg complete +#define SCRIPT_INT_WIDE_NOT_SUPP 0x1B // synchronous not supported +#define SCRIPT_INT_WIDE_NEGOT_COMP 0x1C // synchronous neg complete +#define SCRIPT_INT_INVALID_RESELECT 0x0D // reselecting device returned + // invalid SCSI id. +#define SCRIPT_INT_REJECT_MSG_RECEIVED 0x0E // message reject msg received +#define SCRIPT_INT_INVALID_TAG_MESSAGE 0x0F // target did not send tag +#define SCRIPT_INT_ABORT_OCCURRED 0x10 +#define SCRIPT_INT_ABORT_FAILED 0x11 + + +// +// define 53C810 SCSI Script instruction size +// + +#define SCRIPT_INS_SIZE 8 // size of a script instruction + +// +// ISR disposition codes. these codes are returned by ISR subroutines to +// indicate what should be done next. +// + +#define ISR_START_NEXT_REQUEST 0x00 // indicates bus is free for new req. +#define ISR_RESTART_SCRIPT 0x01 // indicates script restart necessary +#define ISR_EXIT 0x02 // indicates no action needed +#define ISR_CONT_NEG_SCRIPT 0x03 // indicates to continue with Synch + // negotiations after wide + // negotiations have completed + +// +// Device Extension driver flags. +// + +#define DFLAGS_WORK_REQUESTED 0x01 // indicates new work has been requested. + // this flag was necessary because + // NextRequest port notification is not + // reentrant + +#define DFLAGS_BUS_RESET 0x02 // indicates SCSI bus was reset internally + +#define DFLAGS_SCRIPT_RUNNING 0x04 // indicates SCSI scripts processor running + // this flag does NOT indicate bus busy. + // (used in conjunction with WAIT + // RESELECT script instruction which runs + // when bus is not busy) + +#define DFLAGS_CONNECTED 0x08 // indicate that a lun is currently + // connected, but is not active. + +#define DFLAGS_TAGGED_SELECT 0x10 // The last select was for a tagged command. + +#define DFLAGS_DIFF_SCSI 0x40 // indicates that this SIOP should be + // configured to support differential + // SCSI devices + +#define DFLAGS_IRQ_NOT_CONNECTED 0x80 // Indicates that the chip is 'disabled' but resources + // were still assigned. (Omniplex problem) + +// +// Logical Unit Extension flags. +// + +#define LUFLAGS_SYNC_NEGOT_PEND 0x0001 // synch negot in prog. +#define LUFLAGS_SYNC_NEGOT_DONE 0x0002 // synch negot done +#define LUFLAGS_SYNC_NEGOT_FAILED 0x0004 // synch not supp. + +// +// Future wide... +// + +#define LUFLAGS_WIDE_NEGOT_PEND 0x0010 // wide negot in prog. +#define LUFLAGS_WIDE_NEGOT_DONE 0x0020 // wide negot done +#define LUFLAGS_WIDE_NEGOT_FAILED 0x0040 // wide not supp. +#define LUFLAGS_WIDE_NEGOT_CHECK 0x0080 // need to check inquiry data + +#define LUFLAGS_WIDE_NEGOT_MASK 0xFF0F // mask for wide flags + +#define LUFLAGS_ASYNC_NEGOT_PEND 0x0100 // asynch negot in prog. +#define LUFLAGS_ASYNC_NEGOT_DONE 0x0200 // asynch negot done. +#define LUFLAGS_NARROW_NEGOT_PEND 0x0400 // narrow negot in prog. +#define LUFLAGS_NARROW_NEGOT_DONE 0x0800 // narrow negot done. + + +#define HBA_CAPABILITY_WIDE 0x01 +#define HBA_CAPABILITY_DIFFERENTIAL 0x02 +#define HBA_CAPABILITY_FAST20 0x04 +#define HBA_CAPABILITY_REGISTRY_FAST20 0x08 +#define HBA_CAPABILITY_SYNC_16 0x10 +#define HBA_CAPABILITY_810_FAMILY 0x20 +#define HBA_CAPABILITY_825_FAMILY 0x40 +#define HBA_CAPABILITY_875_LARGE_FIFO 0x80 +#define HBA_CAPABILITY_SCRIPT_RAM 0x100 +#define HBA_CAPABILITY_875_FAMILY 0x200 + +// +// Inquiry data representing the capabilities of the SCSI peripheral. +// + +#define INQUIRY_DATA_SYNC_SUPPORTED 0x10 +#define INQUIRY_DATA_WIDE_SUPPORTED 0x20 +#define INQUIRY_DATA_TAGS_SUPPORTED 0x02 + +// +// SCSI Protocol Chip Definitions. +// + +// +// Define the SCSI Control Register 0 bit equates +// + +#define SCNTL0_ARB_MODE_1 0x80 +#define SCNTL0_ARB_MODE_0 0x40 +#define SCNTL0_ENA_PARITY_CHK 0x08 + +#define SCNTL0_ASSERT_ATN_PAR 0x02 +#define SCNTL0_TAR 0x01 + +// +// Define the SCSI Control Register 1 bit equates +// + +#define SCNTL1_EXT_CLK_CYC 0x80 +#define SCNTL1_SODLTOSCSI 0x40 + +#define SCNTL1_CONNECTED 0x10 +#define SCNTL1_RESET_SCSI_BUS 0x08 + +// +// Define the SCSI Control Register 2 bit equates +// + +#define SCNTL2_WSS 0x08 +#define SCNTL2_WSR 0x01 + +// +// Define the SCSI Interrupt Enable register bit equates +// + +#define SIEN0_PHASE_MISMATCH 0x80 +#define SIEN0_FUNCTION_COMP 0x40 + +#define SIEN0_RESELECT 0x10 +#define SIEN0_SCSI_GROSS_ERROR 0x08 +#define SIEN0_UNEXPECTED_DISCON 0x04 +#define SIEN0_RST_RECEIVED 0x02 +#define SIEN0_PARITY_ERROR 0x01 + +// +// Define the DMA Status Register bit equates +// + +#define DSTAT_ILLEGAL_INSTRUCTION 0x01 +#define DSTAT_ABORTED 0x10 +#define DSTAT_SCRPTINT 0x04 + +// +// Define the SCSI Status Register 0 bit equates +// + +#define SSTAT0_PHASE_MISMATCH 0x80 +#define SSTAT0_RESELECTED 0x10 +#define SSTAT0_GROSS_ERROR 0x08 +#define SSTAT0_UNEXPECTED_DISCONNECT 0x04 +#define SSTAT0_RESET 0x02 +#define SSTAT0_PARITY_ERROR 0x01 + +// +// Define the Interrupt Status Register bit equates +// + +#define ISTAT_ABORT 0x80 +#define ISTAT_RESET 0x40 +#define ISTAT_SIGP 0x20 +#define ISTAT_SEM 0x10 +#define ISTAT_CON 0x08 +#define ISTAT_INTF 0x04 +#define ISTAT_SCSI_INT 0x02 +#define ISTAT_DMA_INT 0x01 + +// +// Define the DMA Mode Register bit equates +// + +#define DMODE_BURST_1 0x80 +#define DMODE_BURST_0 0x40 + +// +// Define the DMA Interrupt Enable Register bit equates +// +#define DIEN_BUS_FAULT 0x20 +#define DIEN_ENA_ABRT_INT 0x10 +#define DIEN_ENA_SNGL_STP_INT 0x08 +#define DIEN_ENABLE_INT_RCVD 0x04 +#define DIEN_ENABLE_ILL_INST 0x01 + +// +// Define the SIST1 equates. SCSI Interrupt Status 1. +// + +#define SIST1_SEL_RESEL_TIMEOUT 0x04 + +// +// Define STEST1 equates +// + +#define STEST1_DOUBLER_SELECT 0x04 +#define STEST1_DOUBLER_ENABLE 0x08 + +// +// Define STEST2 equates +// + +#define STEST2_DIFF_MODE 0x20 + +// +// Define STEST3 equates +// + +#define STEST3_HALT_CLOCK 0x20 + +// +// Define GPCNTL equates +// + +#define GPCNTL_GPIO3 0x08 + + +// +// Define specific script instruction structures +// + +// +// Define the scatter/gather move script instruction +// + +typedef struct _SCRIPTSG { + ULONG SGByteCount; + ULONG SGBufferPtr; +} SCRIPTSG, *PSCRIPTSG; + +// +// Define the structure for the CDB move script instruction +// + +typedef struct _SCRIPTCDB { + UCHAR CDBLength; + UCHAR Reserved1; + UCHAR Reserved2; + UCHAR CDBMoveOpcode; + ULONG CDBBufferPtr; +} SCRIPTCDB, *PSCRIPTCDB; + +// +// Define the structure for the SELECT script instruction +// + +typedef struct _SCRIPTSELECT { + UCHAR Reserved1; + UCHAR Reserved2; + UCHAR SelectID; + UCHAR SelectOpcode; + ULONG AltAddress; +} SCRIPTSELECT, *PSCRIPTSELECT; + +// +// Define the structure for the JUMP script instruction +// + +typedef struct _SCRIPTJUMP { + ULONG JumpOpcode; + ULONG JumpAddress; +} SCRIPTJUMP, *PSCRIPTJUMP; + +// +// Build a composite script instruction structure +// + +typedef union _SCRIPTINS { + SCRIPTCDB ScriptCDB; + SCRIPTSELECT ScriptSelect; + SCRIPTJUMP ScriptJump; + SCRIPTSG ScriptSG; +} SCRIPTINS, *PSCRIPTINS; + +// +// SDTR extended message structure used by scsi scripts +// + +typedef struct SYNCH_MESSAGE_STRUCT { + UCHAR ExtMsg; + UCHAR ExtMsgCount; + UCHAR SynchMsgOpcode; + UCHAR OurSynchPeriod; + UCHAR OurSynchOffset; +} SYNCHMESSAGESTRUCT, *PSYNCHMESSAGESTRUCT; + +// +// Symbios SIOP I/O macros. +// + +#ifdef PORT_IO // either driver can use Port IO +#define READ_SIOP_UCHAR(RegisterOffset) \ + (ScsiPortReadPortUchar( &(DeviceExtension-> \ + SIOPRegisterBase)->RegisterOffset)) \ + + +#define WRITE_SIOP_UCHAR(RegisterOffset, BitMask) \ +{ \ + ScsiPortWritePortUchar( &(DeviceExtension-> \ + SIOPRegisterBase)->RegisterOffset, \ + BitMask); \ +} + +#define READ_SIOP_ULONG(RegisterOffset) \ + (ScsiPortReadPortUlong( &(DeviceExtension-> \ + SIOPRegisterBase)->RegisterOffset)) \ + + +#define WRITE_SIOP_ULONG(RegisterOffset, BitMask) \ +{ \ + ScsiPortWritePortUlong( &(DeviceExtension-> \ + SIOPRegisterBase)->RegisterOffset, \ + BitMask); \ +} +#else // NT will use Memory Mapped IO +#define READ_SIOP_UCHAR(RegisterOffset) \ + (ScsiPortReadRegisterUchar( &(DeviceExtension-> \ + SIOPRegisterBase)->RegisterOffset)) \ + + +#define WRITE_SIOP_UCHAR(RegisterOffset, BitMask) \ +{ \ + ScsiPortWriteRegisterUchar( &(DeviceExtension-> \ + SIOPRegisterBase)->RegisterOffset, \ + BitMask); \ +} + +#define READ_SIOP_ULONG(RegisterOffset) \ + (ScsiPortReadRegisterUlong( &(DeviceExtension-> \ + SIOPRegisterBase)->RegisterOffset)) \ + + +#define WRITE_SIOP_ULONG(RegisterOffset, BitMask) \ +{ \ + ScsiPortWriteRegisterUlong( &(DeviceExtension-> \ + SIOPRegisterBase)->RegisterOffset, \ + BitMask); \ +} +#endif + +#endif |