mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
9200 lines
245 KiB
9200 lines
245 KiB
/*
|
|
***********************************************************************
|
|
* *
|
|
* 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
|