#define USE_ELG 0 // for debugging
#define kEvLogSize (4096*16) // 16 pages = 64K = 4096 events
#if USE_ELG
#define ELG(A,B,ASCI,STRING) EvLog( (UInt32)(A), (UInt32)(B), (UInt32)(ASCI), STRING )
#define PAUSE(A,B,ASCI,STRING) Pause( (UInt32)(A), (UInt32)(B), (UInt32)(ASCI), STRING )
#else
#define ELG(A,B,ASCI,S)
#define PAUSE(A,B,ASCI,STRING) IOLog( "MESH: %8x %8x " STRING "\n", (unsigned int)(A), (unsigned int)(B) )
#endif
#ifndef SynchronizeIO
#define SynchronizeIO() eieio()
#endif
enum { kMaxAutosenseByteCount = 255 };
enum
{
kMESHRegisterBase = 0,
kDBDMARegisterBase = 1,
kNumberRegisters = 2
};
typedef enum BusPhase
{
kBusPhaseDATO = 0,
kBusPhaseDATI,
kBusPhaseCMD,
kBusPhaseSTS,
kBusPhaseReserved1,
kBusPhaseReserved2,
kBusPhaseMSGO,
kBusPhaseMSGI
} BusPhase;
typedef enum
{ kCommandExecute,
kCommandResetBus,
kCommandAbortRequest
} CommandOperation;
typedef enum MsgInState
{
kMsgInInit = 0,
kMsgInReading,
kMsgInCounting,
kMsgInReady
} MsgInState;
enum
{ kInvalidTarget = 0xFF,
kInvalidLUN = 0xFF,
kInvalidTag = 0xFFFFFFFF
};
enum
{
kInitiatorIDDefault = 7,
kMaxTargetID = 8,
kMaxDMATransfer = 0xF000ul,
kMaxMemCursorSegs = 15
};
#define APPLE_SCSI_RESET_DELAY 250
typedef struct MeshRegister
{
volatile UInt8 transferCount0; UInt8 pad00[ 0x0F ];
volatile UInt8 transferCount1; UInt8 pad01[ 0x0F ];
volatile UInt8 xFIFO; UInt8 pad02[ 0x0F ];
volatile UInt8 sequence; UInt8 pad03[ 0x0F ];
volatile UInt8 busStatus0; UInt8 pad04[ 0x0F ];
volatile UInt8 busStatus1; UInt8 pad05[ 0x0F ];
volatile UInt8 FIFOCount; UInt8 pad06[ 0x0F ];
volatile UInt8 exception; UInt8 pad07[ 0x0F ];
volatile UInt8 error; UInt8 pad08[ 0x0F ];
volatile UInt8 interruptMask; UInt8 pad09[ 0x0F ];
volatile UInt8 interrupt; UInt8 pad10[ 0x0F ];
volatile UInt8 sourceID; UInt8 pad11[ 0x0F ];
volatile UInt8 destinationID; UInt8 pad12[ 0x0F ];
volatile UInt8 syncParms; UInt8 pad13[ 0x0F ];
volatile UInt8 MESHID; UInt8 pad14[ 0x0F ];
volatile UInt8 selectionTimeOut;
} MeshRegister;
typedef union MESHShadow
{ UInt32 longWord[ 3 ];
struct
{ UInt8 interrupt;
UInt8 error;
UInt8 exception;
UInt8 FIFOCount;
UInt8 busStatus0;
UInt8 busStatus1;
UInt8 interruptMask;
UInt8 transferCount0;
UInt8 transferCount1;
UInt8 sequence;
UInt8 syncParms;
UInt8 destinationID;
} mesh;
} MESHShadow;
enum
{
kMeshTransferCount0 = 0x00,
kMeshTransferCount1 = 0x10,
kMeshFIFO = 0x20,
kMeshSequence = 0x30,
kMeshBusStatus0 = 0x40,
kMeshBusStatus1 = 0x50,
kMeshFIFOCount = 0x60,
kMeshException = 0x70,
kMeshError = 0x80,
kMeshInterruptMask = 0x90,
kMeshInterrupt = 0xA0,
kMeshSourceID = 0xB0,
kMeshDestinationID = 0xC0,
kMeshSyncParms = 0xD0,
kMeshMESHID = 0xE0,
kMeshSelTimeOut = 0xF0
};
enum { kMeshMESHID_Value = 0x02 };
typedef enum
{
kMeshNoOpCmd = 0x00,
kMeshArbitrateCmd = 0x01,
kMeshSelectCmd = 0x02,
kMeshCommandCmd = 0x03,
kMeshStatusCmd = 0x04,
kMeshDataOutCmd = 0x05,
kMeshDataInCmd = 0x06,
kMeshMessageOutCmd = 0x07,
kMeshMessageInCmd = 0x08,
kMeshBusFreeCmd = 0x09,
kMeshEnableParity = 0x0A,
kMeshDisableParity = 0x0B,
kMeshEnableReselect = 0x0C,
kMeshDisableReselect = 0x0D,
kMeshResetMESH = 0x0E,
kMeshFlushFIFO = 0x0F,
kMeshSeqDMA = 0x80,
kMeshSeqTMode = 0x40,
kMeshSeqAtn = 0x20
} MeshCommand;
enum
{
kMeshIO = 0x01,
kMeshCD = 0x02,
kMeshMsg = 0x04,
kMeshAtn = 0x08,
kMeshAck = 0x10,
kMeshReq = 0x20,
kMeshAck32 = 0x40,
kMeshReq32 = 0x80
};
enum { kMeshPhaseMask = (kMeshMsg + kMeshCD + kMeshIO) };
enum
{
kMeshSel = 0x20,
kMeshBsy = 0x40,
kMeshRst = 0x80
};
enum
{
kMeshExcSelTO = 0x01,
kMeshExcPhaseMM = 0x02,
kMeshExcArbLost = 0x04,
kMeshExcResel = 0x08,
kMeshExcSelected = 0x10,
kMeshExcSelectedWAtn = 0x20
};
enum
{
kMeshErrParity0 = 0x01,
kMeshErrParity1 = 0x02,
kMeshErrParity2 = 0x04,
kMeshErrParity3 = 0x08,
kMeshErrSequence = 0x10,
kMeshErrSCSIRst = 0x20,
kMeshErrDisconnected = 0x40
};
enum
{
kMeshIntrCmdDone = 0x01,
kMeshIntrException = 0x02,
kMeshIntrError = 0x04,
kMeshIntrMask = (kMeshIntrCmdDone | kMeshIntrException | kMeshIntrError)
};
enum
{
kSyncParmsAsync = 0x02,
kSyncParmsFast = 0xF0
};
enum
{
kcclStageIdle = 0,
kcclStageInit,
kcclStageCCLx,
kcclStageArb,
kcclStageSelA,
kcclStageMsgO,
kcclStageCmdO,
kcclStageXfer,
kcclStageBucket,
kcclStageSyncHack,
kcclStageStat,
kcclStageMsgI,
kcclStageFree,
kcclStageGood,
kcclStageStop,
kcclTerminatorWithoutComma
};
#define kcclProblem 0x00 // Interrupt & Stop channel commands for anomalies
#define kcclCMDOdata 0x20 // reserve for 6, 10, 12 byte commands
#define kcclMSGOdata 0x30 // reserve for Identify, Tag stuff
#define kcclMSGOLast 0x3F // reserve for last or only msg0ut byte
#define kcclMSGIdata 0x40 // reserve for Message In data
#define kcclBucket 0x48 // Bit Bucket
#define kcclStatusData 0x4F // reserve for Status byte
#define kcclBatchSize 0x60 // Current MESH batch size
#define kcclStageLabel 0x6C // storage for label of last stage entered.
#define kcclSense 0x70 // Channel Commands for (Auto)Sense
#define kcclPrototype 0xC0 // Prototype MESH 4-command Transfer sequence
#define kcclReadBuf8 0x100 // Buffer for non-8-byte-aligned reads
#define kcclStart 0x120 // Channel Program starts here with Arbitrate
#define kcclBrProblem 0x140 // channel command to wait for cmdDone & Br if problem
#define kcclMsgoStage 0x190 // Branch to single byte Message-Out
#define kcclMsgoBranch 0x1B0 // Branch to single byte Message-Out
#define kcclMsgoMTC 0x1D8 // MESH Transfer Count for MSGO (low order only)
#define kcclMsgoDTC 0x1F0 // DMA Transfer Count for MSGO (low order only)
#define kcclLastMsgo 0x210 // Channel commands to put last/only byte of Message-Out
#define kcclCmdoStage 0x290 // Start of Command phase
#define kcclCmdoMTC 0x2C8 // MESH Transfer Count for CMDO (low order only)
#define kcclCmdoDTC 0x2E0 // DMA Transfer Count for CMDO (low order only)
#define kcclReselect 0x2F0 // Reselect enters CCL here - Branch to xfer data
#define kcclOverrun 0x320 // data overrun - dump the excess in the bit bucket
#define kcclOverrunMESH 0x370 // data overrun - patch the MESH Seq Reg I/O
#define kcclOverrunDBDMA 0x380 // data overrun - patch the DBDMA I/O
#define kcclSyncCleanUp 0x3B0 // clean up at end of Sync xfer
#define kcclGetStatus 0x3D0 // Finish up with Status, Message In, and Bus Free
#define kcclMsgiStage 0x420 // Get Message-In hopefully Command Complete
#define kcclBusFreeStage 0x480 // enable Reselect and go Bus Free
#define kcclMESHintr 0x4D0 // transaction done or going well
#define kcclDataXfer 0x500 // INPUT or OUTPUT channel commands for data
#define kRelNone 0x00
#define kRelMESH 0x01
#define kRelCP 0x02
#define kRelCPdata 0x03
#define kRelPhys 0x04
#define kRelNoSwap 0x05
#define kRelAddress 0xFF <<8
#define kRelAddressMESH kRelMESH <<8
#define kRelAddressCP kRelCP <<8
#define kRelAddressPhys kRelPhys <<8
#define kRelCmdDep 0xFF
#define kRelCmdDepCP kRelCP
#define kRelCmdDepLabel kRelNoSwap
#define STAGE(v) STORE_QUAD | KEY_SYSTEM | 4, kcclStageLabel, v, kRelAddressCP | kRelCmdDepLabel
#define CLEAR_CMD_DONE STORE_QUAD | KEY_SYSTEM | 1, kMeshInterrupt, kMeshIntrCmdDone, kRelAddressMESH
#define CLEAR_INT_REG STORE_QUAD | KEY_SYSTEM | 1, kMeshInterrupt, kMeshIntrMask, kRelAddressMESH
#define CLR_PHASEMM STORE_QUAD | KEY_SYSTEM | 1, kMeshInterrupt, kMeshIntrCmdDone | kMeshIntrException, kRelAddressMESH
#define MOVE_1(a,v,r) STORE_QUAD | KEY_SYSTEM | 1, a, v, r
#define MOVE_4(a,v,r) STORE_QUAD | KEY_SYSTEM | 4, a, v, r
#define MESH_REG(a,v) STORE_QUAD | KEY_SYSTEM | 1, a, v, kRelAddressMESH
#define MESH_REG_WAIT(a,v) STORE_QUAD | KEY_SYSTEM | kWaitIfTrue | 1, a, v, kRelAddressMESH
#define MSGO(a,c) OUTPUT_LAST | kBranchIfFalse | kWaitIfTrue | c, a, kcclProblem, kRelAddressCP | kRelCmdDepCP
#define CMDO(c) OUTPUT_LAST | kBranchIfFalse | kWaitIfTrue | c, kcclCMDOdata, kcclProblem, kRelAddressCP | kRelCmdDepCP
#define MSGI(c) INPUT_LAST | kBranchIfFalse | kWaitIfTrue | c, kcclMSGIdata, kcclProblem, kRelAddressCP | kRelCmdDepCP
#define STATUS_IN INPUT_LAST | kBranchIfFalse | kWaitIfTrue | 1, kcclStatusData, kcclProblem, kRelAddressCP | kRelCmdDepCP
#define BUCKET INPUT_LAST | kBranchIfFalse | 8, kcclBucket, kcclProblem, kRelAddressCP | kRelCmdDepCP
#define BRANCH(a) NOP_CMD | kBranchAlways, 0, a, kRelCmdDepCP
#define BR_IF_PROBLEM NOP_CMD | kBranchIfFalse | kWaitIfTrue, 0, kcclProblem, kRelCmdDepCP
#define BR_NO_PROBLEM(a) NOP_CMD | kBranchIfTrue , 0, a, kRelCmdDepCP
#define STOP(L) STOP_CMD, 0, L, kRelCmdDepLabel
#define INTERRUPT(a) NOP_CMD | kIntAlways, 0, a, 0
#define RESERVE 0xCEFECEFE, 0xCEFECEFE, 0xCEFECEFE, 0xCEFECEFE
#define WAIT_4_CMDDONE NOP_CMD | kWaitIfTrue, 0, 0, 0
#define SWAP(x) (UInt32)OSSwapInt32( (UInt32)(x) )
enum
{ kHardwareStartOK,
kHardwareStartBusy
};
struct DBDMAChannelRegisters
{
volatile UInt32 channelControl;
volatile UInt32 channelStatus;
volatile UInt32 commandPtrHi;
volatile UInt32 commandPtrLo;
volatile UInt32 interruptSelect;
volatile UInt32 branchSelect;
volatile UInt32 waitSelect;
volatile UInt32 transferModes;
volatile UInt32 data2PtrHi;
volatile UInt32 data2PtrLo;
volatile UInt32 reserved1;
volatile UInt32 addressHi;
volatile UInt32 reserved2[4];
};
typedef struct DBDMAChannelRegisters DBDMAChannelRegisters;
struct DBDMADescriptor
{
UInt32 operation;
UInt32 address;
UInt32 cmdDep;
UInt32 result;
};
typedef struct DBDMADescriptor DBDMADescriptor;
enum
{
OUTPUT_MORE = 0x00000000,
OUTPUT_LAST = 0x10000000,
INPUT_MORE = 0x20000000,
INPUT_LAST = 0x30000000,
STORE_QUAD = 0x40000000,
LOAD_QUAD = 0x50000000,
NOP_CMD = 0x60000000,
STOP_CMD = 0x70000000,
kdbdmaCmdMask = 0xF0000000
};
enum
{
KEY_STREAM0 = 0x00000000,
KEY_STREAM1 = 0x01000000,
KEY_STREAM2 = 0x02000000,
KEY_STREAM3 = 0x03000000,
KEY_REGS = 0x05000000,
KEY_SYSTEM = 0x06000000,
KEY_DEVICE = 0x07000000,
kdbdmaKeyMask = 0x07000000,
kIntNever = 0x00000000,
kIntIfTrue = 0x00100000,
kIntIfFalse = 0x00200000,
kIntAlways = 0x00300000,
kdbdmaIMask = 0x00300000,
kBranchNever = 0x00000000,
kBranchIfTrue = 0x00040000,
kBranchIfFalse = 0x00080000,
kBranchAlways = 0x000C0000,
kdbdmaBMask = 0x000C0000,
kWaitNever = 0x00000000,
kWaitIfTrue = 0x00010000,
kWaitIfFalse = 0x00020000,
kWaitAlways = 0x00030000,
kdbdmaWMask = 0x00030000,
};
class meshSCSIController;
typedef struct globals
{
UInt32 evLogFlag; UInt8 *evLogBuf;
UInt8 *evLogBufe;
UInt8 *evLogBufp;
UInt8 intLevel;
MESHShadow shadow;
UInt32 cclLogAddr, cclPhysAddr; UInt32 meshAddr; class meshSCSIController *meshInstance;
} globals;
typedef struct PrivCmdData
{
IOMemoryDescriptor *mdp;
UInt32 xferCount;
UInt32 savedDataPosition;
SCSIResults results;
bool isWrite;
bool negotiatingSDTR;
bool negotiatingSDTRComplete;
} PrivCmdData;
class meshSCSIController : public IOSCSIParallelController
{
OSDeclareDefaultStructors( meshSCSIController )
protected:
bool configure( IOService *provider, SCSIControllerInfo *controllerDataSize );
void executeCommand( IOSCSIParallelCommand* );
void cancelCommand( IOSCSIParallelCommand* );
void resetCommand( IOSCSIParallelCommand* );
void free();
private:
IOReturn initializeHardware();
IOReturn getHardwareMemoryMaps();
IOReturn allocHdwAndChanMem();
IOReturn doHBASelfTest();
void initCP();
void interruptOccurred( IOInterruptEventSource *ies, int intCount );
void doHardwareInterrupt();
void processInterrupt();
UInt8 startCommand();
void setupMsgO();
void clearCPResults();
void updateCP( bool reselecting );
void runDBDMA ( UInt32 offset, UInt32 stageLabel );
void completeCommand();
void disconnect();
void updateCurrentIndex();
void handleReselectionInterrupt();
bool getReselectionTargetID();
IOReturn reselectNexus();
void startBucket();
void setSeqReg( MeshCommand meshCommand );
void getHBARegsAndClear( bool clearInts );
void setIntMask( UInt8 interruptMask );
IOReturn resetBus();
IOReturn waitForMesh( bool clearInterrupts );
void abortActiveCommand();
void abortDisconnectedCommand();
void doInterruptStageArb();
void doInterruptStageSelA();
void doInterruptStageMsgO();
void doInterruptStageCmdO();
void doInterruptStageXfer();
void doInterruptStageGood();
IOReturn DoMessageInPhase();
void ProcessMSGI();
void issueReject();
private:
IOService *fProvider;
IOSCSIParallelCommand *fCmd;
PrivCmdData *fCmdData;
IOMemoryMap *fIOMap;
IOInterruptEventSource *fInterruptEvent;
IOMemoryMap *fSCSIMemoryMap;
MeshRegister *fMESHAddr;
UInt32 fMESHPhysAddr;
IOMemoryMap *fDBDMAMemoryMap;
UInt8 *dbdmaAddr;
IOPhysicalAddress dbdmaAddrPhys;
IOPhysicalAddress fCCLPhysAddr;
UInt8 *fCCL;
UInt32 fCCLSize;
UInt32 fDBDMADescriptorMax;
IOBigMemoryCursor *fMemoryCursor;
UInt32 fReadAlignmentCount; UInt32 fReadAlignmentIndex;
SCSITargetLun fCurrentTargetLun;
UInt32 fTag;
UInt8 fTagType;
UInt8 fSyncParms[ 8 ];
UInt8 *fMsgOutPtr;
UInt8 fMsgInBuffer[ 16 ];
SInt8 fMsgInCount;
MsgInState fMsgInState;
#define kFlagMsgIn_Reject 0x01
#define kFlagMsgIn_Disconnect 0x02
UInt8 fMsgInFlag;
#define kFlagMsgOut_SDTR 0x01
#define kFlagMsgOut_Queuing 0x02
UInt8 fMsgOutFlag;
UInt8 fInitiatorID;
UInt8 fInitiatorIDMask;
UInt8 fSelectionTimeout;
UInt8 fFlagIncompleteDBDMA;
UInt8 fFlagReselecting;
};