Source to bsd/dev/ppc/drvAppleMesh_SCSI/MESH_DBDMA.h
/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
* Source License Version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License."
*
* @APPLE_LICENSE_HEADER_END@
*/
/**
* Copyright (c) 1994-1996 NeXT Software, Inc. All rights reserved.
* Copyright � 1997 Apple Computer Inc. All Rights Reserved.
* @author Martin Minow mailto:[email protected]
* @revision 1997.02.13 Initial conversion from AMDPCSCSIDriver sources.
*
* Set tabs every 4 characters.
*
* Edit History
* 1997.02.13 MM Initial conversion from AMDPCSCSIDriver sources.
*/
#define AUTO_SENSE_ENABLE 1
/* These are accessible by SCSIInspector: */
#define SYNC_ENABLE "Synchronous"
#define FAST_ENABLE "Fast SCSI"
#define CMD_QUEUE_ENABLE "Cmd Queueing"
/* These are only accessible by Configure's Expert mode: */
#define EXTENDED_TIMING "Extended Timing"
#define SCSI_CLOCK_RATE "SCSI Clock Rate" /* in MHz */
#define USE_ELG FALSE
#define CustomMiniMon FALSE
//#define CustomMiniMon TRUE
//#define USE_ELG TRUE
#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 /* ) not USE_ELG: ( */
#define ELG(A,B,ASCI,S)
#define PAUSE(A,B,ASCI,S)
#define CKSTOP(A,E,ASCI,S)
#endif /* USE_ELG )) */
#define TIMESTAMP_AT_IOCOMPLETE 0
#ifndef TIMESTAMP_AT_IOCOMPLETE
#define TIMESTAMP_AT_IOCOMPLETE 0
#endif
#ifndef TIMESTAMP
#define TIMESTAMP 0 // mlj - linking problems with Curio
#endif
/* These types will ultimately be moved to an implementation-wide header file*/
#ifndef __APPLE_TYPES_DEFINED__
#define __APPLE_TYPES_DEFINED__ 1
typedef unsigned char UInt8; /* An unsigned 8-bit value */
typedef unsigned int UInt32; /* An unsigned integer */
typedef signed int SInt32; /* An explicitly signed int */
typedef void *LogicalAddress; /* A virtual address */
typedef UInt32 PhysicalAddress; /* A hardware address */
typedef UInt32 ByteCount; /* A transfer length count */
typedef UInt32 ItemCount; /* An index or counter */
typedef UInt32 Boolean; /* A true/false value */
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#endif /* __APPLE_TYPES_DEFINED__ */
typedef signed char SInt8;
typedef UInt32 OSType;
#ifndef SynchronizeIO
#define SynchronizeIO() eieio() /* TEMP */
#endif /* SynchronizeIO */
enum
{ DBDMA_ReadStartAlignment = 8, // mlj ???
DBDMA_WriteStartAlignment = 8
};
/* Operation flags and options: */
typedef enum BusPhase /* These are the real SCSI bus phases (from busStatus0): */
{
kBusPhaseDATO = 0,
kBusPhaseDATI,
kBusPhaseCMD,
kBusPhaseSTS,
kBusPhaseReserved1,
kBusPhaseReserved2,
kBusPhaseMSGO,
kBusPhaseMSGI,
kBusPhaseBusFree
} BusPhase;
/* Command to be executed by IO thread. */
/* These are ultimately derived from ioctl control values. */
typedef enum
{ kCommandExecute, /* Execute IOSCSIRequest */
kCommandResetBus, /* Reset bus */
kCommandAbortRequest /* Abort IO thread */
} CommandOperation;
/* We read target messages using a simple state machine. */
/* On entrance to MSGI phase, gMsgInState = kMsgInInit. */
/* Continue reading messages until either */
/* gMsgInState == kMsgInReady or the target changes phase */
/* (which is an error). */
typedef enum MsgInState
{
kMsgInInit = 0, /* 0 Not reading a message (must be zero) */
kMsgInReading, /* 1 MSG input state: reading counted data */
kMsgInCounting, /* 2 MSG input state: reading count byte */
kMsgInReady /* 3 MSG input state: a msg is now available */
} MsgInState;
/* This is the maximum number of bytes to be transferred */
/* in an autosense request. It is, by inspection, less than 256. */
enum { kMaxAutosenseByteCount = sizeof( esense_reply_t ) };
/* These values are stored in gCurrentTarget and gCurrentLUN */
/* when there is no active request. */
enum
{ kInvalidTarget = 0xFFFF,
kInvalidLUN = 0xFFFF
};
/* The default initiator bus ID (needs to be fetched from NVRAM). */
enum { kInitiatorIDDefault = 7 };
#define APPLE_SCSI_RESET_DELAY 250 /* Msec */
/* Command struct passed to IO thread. */
/* One of these are created for each active IO request. */
typedef struct CommandBuffer
{
/* Fields valid when commandBuf is passed to IO thread. */
CommandOperation op; /* kCommandExecute, etc. */
/* The following 3 fields are only valid if op == kCommandExecute. */
/* They are passed into the SCSI driver by executeRequest. */
IOSCSIRequest *scsiReq; /* -> The SCSI command parameter block */
IOMemoryDescriptor *mem; /* -> Memory to transfer, if any */
vm_task_t client; /* == The client task (for vm mapping) */
/* These fields are used by the IO thread to manage the IO request: */
/* cmdLock Wait for the command to complete */
/* link Queue link for the command, disconnect, and */
/* pending queues. */
/* timeoutPort Port for timeout messages */
/* queueTag SCSI tagged request if not QUEUE_TAG_NONTAGGED */
NXConditionLock *cmdLock; /* client waits on this */
queue_chain_t link; /* for enqueueing on commandQ */
// port_t timeoutPort; /* for timeout messages */
UInt8 queueTag; /* QUEUE_TAG_NONTAGGED or queue tag */
UInt8 cdbLength; /* Actual length of this command */
/* SCSI bus state variables. Note that currentDataIndex can exceed */
/* scsiReq->maxTransfer if the device sends (receives) more data than */
/* we can receive (send). These values are NOT used for autosense. */
/* The first byte to transfer is at logical address */
/* gActiveCommand->buffer + currentDataIndex. */
UInt32 currentDataIndex; /* Where we are in the DATA transfer */
UInt32 savedDataIndex; /* For SaveDataPointers */
IOMemoryDescriptorState savedDataState;/* saved index for IOMemoryDescriptor*/
/* Request management flags */
/* flagActive */
/* Set if we're in the active array and active count */
/* reflects our existance. Managed by [ self activateCmd ] */
/* and [ self deactivateCmd : cmdBuf ]. */
/* and that IOScheduleFunc() has been called. */
/* flagRequestSelectOK */
/* Arbitration/selection succeeded for this request. */
/* flagIsAutosense */
/* Set if we are executing an internally-generated */
/* Request Sense command. If this is an autosense, */
/* the operation is modified as follows: */
/* Arb/Select: Disable disconnects. Re-establish */
/* synchronous and fast for this target, */
/* use the current tag, if any. */
/* Command: Use an internally-generated Request Sense. */
/* Data: Read into our wired-down sense buffer. */
/* Do not touch the data index and transfer */
/* count variables. On completion, copy */
/* from our wired-down buffer to the caller's */
/* sense array. */
/* Completion: Good status, return SR_IOST_CHKSV to client.*/
/* Bad status: never set isAutosense. Driver */
/* return SR_IOST_CHKSNV. */
UInt32 flagActive:1, /* We're in activeArray and activeCount */
flagRequestSelectOK:1, /* Did arbitration/selection succeed? */
flagIsAutosense:1, /* Set if THIS is an autosense command */
pad:29;
/* This is set by autosense Status phase. */
UInt8 autosenseStatus; /* Did autosense complete ok? */
/* Statistics support. */
ns_time_t startTime; /* time cmd started */
ns_time_t disconnectTime; /* time of last disconnect */
} CommandBuffer;
/* Condition variable states for commandBuf.cmdLock. */
enum { CMD_PENDING = 0, CMD_COMPLETE };
/* Value of queueTag for nontagged commands. */
/* This value is never used for the tag for tagged commands. */
enum { QUEUE_TAG_NONTAGGED = 0 };
/* Per-target info. */
/* */
/* maxQueue is set to a non-zero value when we reach a target's queue size */
/* limit, detected by a STAT_QUEUE_FULL status. A value of zero means we */
/* have not reached the target's limit and we are free to queue additional */
/* commands (if allowed by the overall cmdQueueEnable flag). */
/* */
/* syncXferPeriod and syncXferOffset are set to non-zero during sync */
/* transfer negotiation. Units of syncXferPeriod is NANOSECONDS, which */
/* differs from both the chip's register format (dependent on clock */
/* frequency and fast SCSI/fast clock enables) and the SCSI bus's format */
/* (which is 4 ns per unit). */
/* */
/* cmdQueueDisable and syncDisable have a default (initial) value of */
/* zero regardless of the driver's overall cmdQueueEnable and syncModeEnable */
/* flags. They are set to one when a target explicitly tells us that the */
/* indicated feature is unsupported. */
/* */
/* negotiateSDTR has one of the following values (defined in */
/* AppleMeshDefinitions.h): */
/* kSyncParmsAsync Async with min period */
/* kSyncParmsFast Offset = 15, period = Fast (10 MB/s) */
/* syncParms Shadow of MESH syncParms register. */
typedef struct
{
UInt8 maxQueue; /* Max queue depth for this target */
UInt8 negotiateSDTR; /* Synchronous negotiation control */
UInt8 syncParms; /* Synchronous period and offset */
UInt8 inquiry_7; /* 7th byte peeked fm Inquiry data */
UInt8 syncDisable; /* No synchronous for this target */
} PerTargetData;
typedef struct MeshRegister /* Mesh registers: */
{
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;
/* The following structure shadows the MESH chip registers: */
typedef union MESHShadow
{ UInt32 longWord[ 3 ]; /* for debugging ease. */
struct
{ UInt8 interrupt; /* Interrupt */
UInt8 error; /* Error register */
UInt8 exception; /* Exception register */
UInt8 FIFOCount; /* FIFO count */
UInt8 busStatus0; /* Bus phase + REQ, ACK, & ATN signals */
UInt8 busStatus1; /* RST, BSY, SEL */
UInt8 interruptMask; /* Interrupt mask for debugging */
UInt8 transferCount0; /* low order byte of transfer count */
UInt8 transferCount1; /* high order byte of transfer count */
UInt8 sequence; /* Sequence register */
UInt8 syncParms; /* syncParms for debugging */
UInt8 destinationID; /* Target ID */
} mesh;
} MESHShadow;
/* Mesh Register set offsets */
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 }; /* Read value of kMESHID lowest 5 bits only */
/* MESH commands & modifiers for sequence register: */
typedef enum
{
kMeshNoOpCmd = 0x00,
kMeshArbitrateCmd = 0x01,
kMeshSelectCmd = 0x02,
kMeshCommandCmd = 0x03,
kMeshStatusCmd = 0x04,
kMeshDataOutCmd = 0x05,
kMeshDataInCmd = 0x06,
kMeshMessageOutCmd = 0x07,
kMeshMessageInCmd = 0x08,
kMeshBusFreeCmd = 0x09,
/* non interrupting: */
kMeshEnableParity = 0x0A,
kMeshDisableParity = 0x0B,
kMeshEnableReselect = 0x0C,
kMeshDisableReselect = 0x0D,
kMeshResetMESH = 0x0E,
kMeshFlushFIFO = 0x0F,
/* Sequence command modifier bits: */
kMeshSeqDMA = 0x80, /* Data Xfer for this command will use DMA */
kMeshSeqTMode = 0x40, /* Target mode - unused */
kMeshSeqAtn = 0x20 /* ATN is to be asserted after command */
} MeshCommand;
/* The bus Status Registers 0 & 1 have the actual */
/* bus signals WHEN READ. */
enum /* bus Status Register 0 bits: */
{
kMeshIO = 0x01, /* phase bit */
kMeshCD = 0x02, /* phase bit */
kMeshMsg = 0x04, /* phase bit */
kMeshAtn = 0x08, /* Attention signal */
kMeshAck = 0x10, /* Ack signal */
kMeshReq = 0x20, /* Request signal */
kMeshAck32 = 0x40, /* unused - 32 bit bus */
kMeshReq32 = 0x80 /* unused - 32 bit bus */
};
enum { kMeshPhaseMask = (kMeshMsg + kMeshCD + kMeshIO) };
enum /* bus Status Register 1 bits: */
{
kMeshSel = 0x20, /* Select signal */
kMeshBsy = 0x40, /* Busy signal */
kMeshRst = 0x80 /* Reset signal */
};
enum /* Exception Register bits: */
{
kMeshExcSelTO = 0x01, /* Selection timeout */
kMeshExcPhaseMM = 0x02, /* Phase mismatch */
kMeshExcArbLost = 0x04, /* lost arbitration */
kMeshExcResel = 0x08, /* reselection occurred */
kMeshExcSelected = 0x10,
kMeshExcSelectedWAtn = 0x20
};
enum /* Error Register bits: */
{
kMeshErrParity0 = 0x01, /* parity error */
kMeshErrParity1 = 0x02, /* unused - 32 bit bus */
kMeshErrParity2 = 0x04, /* unused - 32 bit bus */
kMeshErrParity3 = 0x08, /* unused - 32 bit bus */
kMeshErrSequence = 0x10, /* Sequence error */
kMeshErrSCSIRst = 0x20, /* Reset signal asserted */
kMeshErrDisconnected = 0x40 /* unexpected disconnect */
};
enum /* Interrupt Register bits: */
{
kMeshIntrCmdDone = 0x01, /* command done */
kMeshIntrException = 0x02, /* exception occurred */
kMeshIntrError = 0x04, /* error occurred */
kMeshIntrMask = (kMeshIntrCmdDone | kMeshIntrException | kMeshIntrError)
};
enum /* Values for SyncParms MESH register: */
{ /* 1st nibble is offset, 2nd is period. */
/* Zero offset means async. */
kSyncParmsAsync = 0x02, /* Async with min period = 2 */
kSyncParmsFast = 0xF0 /* offset = 15, period = Fast (10 MB/s) */
};
/* The following are specific to the MESH CCL */
/* Stage Names. (These were originally 'xxxx' identifiers, */
/* which is convenient for debugging, but results in many */
/* warning messages from the NeXT compiler. */
enum
{
kcclStageIdle = 0, /* 0 - Idle */
kcclStageInit, /* 1 - 'Init' */
kcclStageCCLx, /* 2 - 'CCL~' */
kcclStageArb, /* 3 - ' Arb' */
kcclStageSelA, /* 4 - 'SelA' */
kcclStageMsgO, /* 5 - 'MsgO' */
kcclStageCmdO, /* 6 - 'CmdO' */
kcclStageXfer, /* 7 - 'Xfer' */
kcclStageBucket, /* 8 - 'Buck' */
kcclStageSyncHack, /* 9 - 'Hack' */
kcclStageStat, /* A - ' Sta' */
kcclStageMsgI, /* B - 'MsgI' */
kcclStageFree, /* C - 'Free' */
kcclStageGood, /* D - 'Good' */
kcclStageStop, /* E - '++++' */
kcclTerminatorWithoutComma
};
/* offsets into the Channel Command List page: */
#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 kcclSenseCDB 0x50 // CDB for (auto) Sense
#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 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 kcclMESHintr 0x4D0 // transaction done or going well
#define kcclSenseBuffer 0x500 // Buffer for Autosense data
#define kcclDataXfer 0x600 // INPUT or OUTPUT channel commands for data
#define kcclSenseResult 0x63C // Result field in Sense INPUT channel command
/* generic relocation types: */
#define kRelNone 0x00 /* default - no relocation */
#define kRelMESH 0x01 /* Relocate to MESH register area */
#define kRelCP 0x02 /* Relocate to Channel Program area */
#define kRelCPdata 0x03 /* Relocate to Channel Program data structure */
#define kRelPhys 0x04 /* Relocate to user Physical address space */
#define kRelNoSwap 0x05 /* don't relocate or swap (Label) */
/* Relocatable ADDRESS types: */
#define kRelAddress 0xFF <<8 /* relocatable address mask */
#define kRelAddressMESH kRelMESH <<8 /* MESH physical address */
#define kRelAddressCP kRelCP <<8 /* Channel Program Physical address */
#define kRelAddressPhys kRelPhys <<8 /* User data Physical address */
/* Relocatable COMMAND-DEPENDENT types: */
#define kRelCmdDep 0xFF /* relocatable command-dependent mask */
#define kRelCmdDepCP kRelCP /* Channel Program command-dependent (branch) */
#define kRelCmdDepLabel kRelNoSwap /* Channel Program label - don't swap */
/* Channel Program macros: */
#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 SENSE(c) INPUT_LAST | kBranchIfFalse | kWaitIfTrue | c, kcclSenseBuffer, kcclProblem, kRelAddressCP | kRelCmdDepCP
#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)EndianSwap32Bit( (UInt32)( x ) )
#define SWAP(x) (UInt32)EndianSwap32( (UInt32)( x ) )
/* Return values from hardwareStart. */
typedef enum
{ kHardwareStartOK, /* command started successfully */
kHardwareStartRejected, /* command rejected, try another */
kHardwareStartBusy /* hardware not ready for command */
} HardwareStartResult;
/* This structure defines the DBDMA Channel Command descriptor. */
/***** WARNING: Endian-ness issues must be considered when *****/
/***** performing load/store! *****/
/***** DBDMA specifies memory organization as quadlets so it *****/
/***** is not correct to think of either the operation or *****/
/***** result field as two 16-bit fields. This would have *****/
/***** undesirable effects on the byte ordering within their *****/
/***** respective quadlets. Use the accessor macros provided *****/
/***** below. *****/
struct DBDMADescriptor
{
UInt32 operation; /* cmd || key || i || b || w || reqCount */
UInt32 address;
UInt32 cmdDep;
UInt32 result; /* xferStatus || resCount */
};
typedef struct DBDMADescriptor DBDMADescriptor;
typedef DBDMADescriptor *DBDMADescriptorPtr;
/* These constants define the DBDMA channel command operations and modifiers.*/
enum /* Command.cmd operations */
{
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
{ /* Command.key modifiers */
/* (choose one for INPUT, OUTPUT, LOAD, and STORE) */
KEY_STREAM0 = 0x00000000, /* default modifier*/
KEY_STREAM1 = 0x01000000,
KEY_STREAM2 = 0x02000000,
KEY_STREAM3 = 0x03000000,
KEY_REGS = 0x05000000,
KEY_SYSTEM = 0x06000000,
KEY_DEVICE = 0x07000000,
kdbdmaKeyMask = 0x07000000, /* Command.i modifiers (choose one for INPUT, OUTPUT, LOAD, STORE, and NOP)*/
kIntNever = 0x00000000, /* default modifier */
kIntIfTrue = 0x00100000,
kIntIfFalse = 0x00200000,
kIntAlways = 0x00300000,
kdbdmaIMask = 0x00300000, /* Command.b modifiers (choose one for INPUT, OUTPUT, and NOP)*/
kBranchNever = 0x00000000, /* default modifier */
kBranchIfTrue = 0x00040000,
kBranchIfFalse = 0x00080000,
kBranchAlways = 0x000C0000,
kdbdmaBMask = 0x000C0000, /* Command.w modifiers (choose one for INPUT, OUTPUT, LOAD, STORE, and NOP)*/
kWaitNever = 0x00000000, /* default modifier */
kWaitIfTrue = 0x00010000,
kWaitIfFalse = 0x00020000,
kWaitAlways = 0x00030000,
kdbdmaWMask = 0x00030000, /* operation masks */
};
/* This is a temporary implementation of EndianSwap32Bit */
/* until the correct library/method is made available. */
/* @param value The value to change */
/* @result The value endian-swapped. */
#ifdef CRAP
static inline unsigned EndianSwap32Bit( unsigned value )
{
register unsigned temp;
temp = ((value & 0xFF000000) >> 24);
temp |= ((value & 0x00FF0000) >> 8);
temp |= ((value & 0x0000FF00) << 8);
temp |= ((value & 0x000000FF) << 24);
return temp;
}
#else
static __inline__ UInt32 EndianSwap32( UInt32 y )
{
UInt32 result;
volatile UInt32 x;
x = y;
__asm__ volatile("lwbrx %0, 0, %1" : "=r" (result) : "r" (&x) : "r0");
return result;
}
#endif /* CRAP */
typedef struct globals /* Globals for this module (not per instance) */
{
UInt32 evLogFlag; // debugging only
UInt8 *evLogBuf;
UInt8 *evLogBufe;
UInt8 *evLogBufp;
UInt8 intLevel;
MESHShadow shadow; // move to per instance??? /* Last MESH register state */
UInt32 cclLogAddr, cclPhysAddr; // for debugging/miniMon ease
UInt32 meshAddr; // for debugging/miniMon ease
} globals;
/* "Global" data for each instance of the MESH Host Bus Adapter: */
@interface AppleMesh_SCSI : IOSCSIController < IOPower >
{
/* These globals locate the hardware interfaces in */
/* logical and physical address spaces. */
MeshRegister *meshAddr; /* -> Mesh registers (logical) */
PhysicalAddress gMESHPhysAddr; /* -> Mesh registers (physical) */
dbdma_regmap_t *dbdmaAddr; /* -> DBDMA registers (logical) */
PhysicalAddress dbdmaAddrPhys; /* -> DBDMA registers (physical) */
PhysicalAddress cclPhysAddr; /* -> DBDMA channel area (physical) */
DBDMADescriptor *cclLogAddr; /* -> DBDMA channel area (logical) */
UInt32 cclLogAddrSize; /* == DBDMA channel allocated size */
UInt32 gDBDMADescriptorMax; /* Number of DATA descriptors */
/* There are 3 queues: incomingCmdQ, pendingCmdQ, disconnectedCmdQ. */
/* Commands are passed from exported methods to the IO thread via */
/* incomingCmdQ, which is protected by incomingCmdLock. */
/* Commands which are disconnected but not complete are kept in */
/* disconnectedCmdQ. */
/* Commands which have been dequeued from incomingCmdQ by the IO thread */
/* but which have not been started because a command is currently active*/
/* on the bus are kept in pendingCmdQ. This queue also holds commands */
/* pushed back when we lose arbitration. */
/* The currently active command, if any, is kept in gActiveCommand. */
/* Only commandBufs with op == kCommandExecute are ever placed in */
/* gActiveCommand. */
id incomingCmdLock; /* NXLock for incomingCmdQ */
queue_head_t incomingCmdQ;
queue_head_t pendingCmdQ;
queue_head_t disconnectedCmdQ;
queue_head_t abortCmdQ;
/* This is the command we're currently execution. If NULL, the Mac */
/* is idle (or all commands are disconnected). Normally, gCurrentTarget */
/* and gCurrentLUN track the values in the active command's associated */
/* SCSI request. They are set to kInvalidTarget and kInvalidLUN at */
/* initialization, command deactivation, command complete, and command */
/* disconnect. They are set to valid values (with no active command) */
/* during reselection. This is tricky, so look carefully at the code. */
CommandBuffer *gActiveCommand; /* -> The currently executing command */
UInt32 gCurrentTarget; /* == The current target bus ID */
UInt32 gCurrentLUN; /* == The current target LUN */
/* Global option flags, accessible via instance table or setIntValues. Note: some of
* these are intended for debugging. However, users may need to disable command
* queuing, synchronous, or fast to handle device or bus limitations. The
* architecture-specific initialization "looks" at the device to determine whether
* specific features (such as synchronous) are supported.
* gOptionAutoSenseEnable Debug only, normally set
* gOptionCmdQueueEnable Enable tagged queuing.
* gOptionSyncModeEnable Enable synchronous transfers (clear if problems)
* gOptionFastModeEnable Enable fast transfers (clear if problems)
* gOptionExtendTiming Extended selection timing (debug, unused)
* gFlagIOThreadRunning Set when IO thread is initialized. Needed
* for shutdown.
* gFlagIncompleteDBDMA Set in the data transfer setup if there was
* so much data that the entire transfer could not
* be stored in the CCL area. If so, the interrupt
* service routine ("good completion") will restart
* the data transfer operation.
*/
UInt32 gOptionAutoSenseEnable : 1,
gOptionCmdQueueEnable : 1,
gOptionSyncModeEnable : 1,
gOptionFastModeEnable : 1,
gOptionExtendTiming : 1,
gFlagIOThreadRunning : 1, /* Set at init */
gFlagIncompleteDBDMA : 1, /* Need more DMA */
gFlagReselecting : 1, /* Reselection in progress */
pad : 24;
/* Array of active IO counters, one counter per LUN per target. */
/* If command queueing is disabled, the max value of each counter is 1. */
/* gActiveCount is the sum of all elements in activeArray. */
UInt8 gActiveArray[ SCSI_NTARGETS ][ SCSI_NLUNS ];
UInt32 gActiveCount;
/* These variables change during SCSI IO operation. */
/* msgOutPtr Points to the next free byte in the MSGO buffer */
/* in the shared CCL area. */
UInt8 *msgOutPtr; /* ptr to message-out data */
/* These variables manage Message-In bus phase. Because the */
/* Message-In handler uses programmed IO, gMsgInCount and */
/* gMsgInState are actually local variables to the message */
/* reader, and are here for debugging convenience. */
UInt8 gMsgInBuffer[ 16 ];
SInt8 gMsgInCount; /* Message bytes still to read */
MsgInState gMsgInState; /* How are we handling messages */
#define kFlagMsgIn_Reject 0x01
#define kFlagMsgIn_Disconnect 0x02
UInt8 gMsgInFlag;
#define kFlagMsgOut_SDTR 0x01
#define kFlagMsgOut_Queuing 0x02
UInt8 gMsgOutFlag;
/* These variables are used during reselection to select the correct */
/* (tagged) command. msgInTagType is the last Tagged Queue message */
/* received from a target during reselection. msgInTag is the */
/* tag value. Currently, we should only see a Simple Queue Tag. */
UInt8 msgInTagType; /* Last tag type */
UInt8 msgInTag; /* Last tag value */
/* Hardware related variables: */
UInt8 gInitiatorID; /* Our SCSI ID */
UInt8 gInitiatorIDMask; /* BusID bitmask for selection */
UInt8 gSelectionTimeout; /* In MESH 10 msec units */
/* commandBuf->queueTag for next IO. This is never zero; */
/* for all requests involving a T/L/Q nexus, a queue tag */
/* of zero indicates a nontagged command. */
UInt8 gNextQueueTag;
PerTargetData gPerTargetData[ SCSI_NTARGETS ];
/* Statistics support: */
UInt32 gMaxQueueLen;
UInt32 gQueueLenTotal;
UInt32 gTotalCommands;
}
/* Public methods (called by higher-level driver functions) */
+ (Boolean) probe : deviceDescription; /* Initialize the SCSI driver. */
- free; /* Shutdown the driver. */
- (sc_status_t) executeRequest /* Execute a SCSI IO request */
: (IOSCSIRequest*) scsiReq
buffer : (void*) buffer
client : (vm_task_t) client;
/* Execute a SCSI request using an IOMemoryDescriptor. */
/* This allows callers to provide (kernel-resident) logical scatter-gather */
/* lists. For compatibility with existing implementations, the low-level */
/* SCSI device driver must first ensure that */
/* executeRequest:ioMemoryDescriptor is supported by executing: */
/* [controller respondsToSelector : executeRequest:ioMemoryDescriptor] */
/* @param scsiReq The SCSI request command record, including the */
/* target device and LUN, the command to execute, and various control flags.*/
/* @param ioMemoryDescriptor The data buffer(s), if any. This may be NULL */
/* if no data phase is expected. */
/* @param client The client task that "owns" the memory buffer. */
/* @return Return a bus adaptor specific error status. */
- (sc_status_t) executeRequest : (IOSCSIRequest*)scsiReq
ioMemoryDescriptor : (IOMemoryDescriptor*)ioMemoryDescriptor;
- (sc_status_t) resetSCSIBus; /* Reset the SCSI bus */
- (void) resetStatistics; /* Reset statistics buffers */
- (unsigned) numQueueSamples;
- (unsigned) sumQueueLengths;
- (unsigned) maxQueueLength;
/* interruptOccurred is a public method called by the */
/* IO thread in IODirectDevice when an interrupt occurs. */
- (void) interruptOccurred;
/* timeoutOccurred is a public method called by the */
/* IO thread in IODirectDevice when it receives a */
/* timeout message. */
- (void) timeoutOccurred;
#if APPLE_MESH_ENABLE_GET_SET
- (IOReturn) setIntValues : (unsigned*) parameterArray
forParameter : (IOParameterName) parameterName
count : (unsigned) count;
- (IOReturn) getIntValues : (unsigned*) parameterArray
forParameter : (IOParameterName) parameterName
count : (unsigned*) count; /* in/out */
/* get/setIntValues parameters: */
#define APPLE_MESH_AUTOSENSE "AutoSense"
#define APPLE_MESH_CMD_QUEUE "CmdQueue"
#define APPLE_MESH_SYNC "Synchronous"
#define APPLE_MESH_FAST_SCSI "FastSCSI"
#define APPLE_MESH_RESET_TARGETS "ResetTargets"
#define APPLE_MESH_RESET_TIMESTAMP "ResetTimestamp"
#define APPLE_MESH_ENABLE_TIMESTAMP "EnableTimestamp"
#define APPLE_MESH_DISABLE_TIMESTAMP "DisableTimestamp"
#define APPLE_MESH_PRESERVE_FIRST_TIMESTAMP "PreserveFirstTimestamp"
#define APPLE_MESH_PRESERVE_LAST_TIMESTAMP "PreserveLastTimestamp"
#define APPLE_MESH_READ_TIMESTAMP "ReadTimestamp"
#define APPLE_MESH_STORE_TIMESTAMP "StoreTimestamp"
/*
* Recording and setting timestamps may be done using getIntValues (this permits
* access from non-privileged tasks.
* ResetTimestamp Clear the timestamp vector - do this before starting
* a sequence (no parameters)
* EnableTimestamp Start recording (no parameters) (default)
* DisableTimestamp Stop recording (no parameters)
* PreserveFirstTimestamp Stop recording when the buffer fills (until it is emptied)
* PreserveLastTimestamp Discard old values when new arrive (default)
* ReadTimestamp Read a vector of timestamps (see sample below)
* StoreTimestamp Store a timestamp (from user mode) (see sample below)
* ReadTimestamp copies timestamps from the internal database to user-specified vector.
* Because getIntValues parameters are defined in int units, the code is slighthly
* non-obvious:
* TimestampDataRecord myTimestamps[ 123 ];
* unsigned count;
* count = sizeof (myTimestamps) / sizeof (unsigned);
* [scsiDevice getIntValues
* : (unsigned int *) myTimestamps
* forParameter : APPLE_MESH_READ_TIMESTAMP
* count : &count
* ];
* count = (count * sizeof (unsigned)) / sizeof (TimestampDataRecord);
* for (i = 0; i < count; i++) {
* Process(myTimestamps[i]);
* }
* Applications can store timestamps using one of three parameter formats:
* unsigned paramVector[4];
* Tag only -- the library will supply the event time
* paramVector[0] = kMyTagValue;
* [scsiDevice getIntValues
* : paramVector
* forParameter : "StoreTimestamp"
* count : 1
* ];
* Tag plus value:
* paramVector[0] = kMyTagValue;
* paramVector[1] = 123456;
* [scsiDevice getIntValues
* : paramVector
* forParameter : "StoreTimestamp"
* count : 2
* ];
* Tag plus value + time:
* paramVector[0] = kMyTagValue;
* paramVector[1] = 123456;
* IOGetTimestamp( (ns_time_t*)¶mVector[2] );
* [scsiDevice getIntValues
* : paramVector
* forParameter : "StoreTimestamp"
* count : 4
* ];
* Note that you can combine tag only with tag plus value plus time to measure
* user->device latency.
*/
#endif APPLE_MESH_ENABLE_GET_SET
@end
@interface AppleMesh_SCSI( Hardware )
- InitializeHardware : deviceDescription;
- (IOReturn) ResetHardware : (Boolean)resetSCSIBus;
- (HardwareStartResult) hardwareStart : (CommandBuffer*)cmdBuf;
@end
/* These macros are used to access words (32 bit) and bytes (8 bit) in */
/* the channel command area. They may be used as source or destination. */
/* CCLDescriptor is aligned to a descriptor start, CCLAddress is just */
/* an address pointer. */
#define CCLAddress(offset) (((UInt8*)cclLogAddr) + (offset))
#define CCLDescriptor(offset) ((DBDMADescriptor*)CCLAddress(offset))
#define CCLWord(offset) (*((UInt32*)CCLAddress(offset)))
#define CCLByte(offset) (*((UInt8*)CCLAddress(offset)))
@interface AppleMesh_SCSI ( HardwarePrivate )
- (IOReturn) AllocHdwAndChanMem : deviceDescription;
- (void) InitAutosenseCCL;
- (void) UpdateCP : (Boolean) reselecting;
- (void) StartBucket;
- (void) SetupMsgO;
- (void) ClearCPResults;
- (void) InitCP;
@end
@interface AppleMesh_SCSI( MeshInterrupt )
- (void) DoHardwareInterrupt; /* Respond to an Interrupt Service message. */
- (void) ProcessInterrupt;
- (void) DoInterruptStageArb;
- (void) DoInterruptStageSelA;
- (void) DoInterruptStageMsgO;
- (void) DoInterruptStageCmdO;
- (void) DoInterruptStageXfer;
- (void) DoInterruptStageXferAutosense;
- (void) DoInterruptStageGood;
- (IOReturn) DoMessageInPhase; /* Handle MSGI phase. */
- (void) ProcessMSGI;
- (void) HandleReselectionInterrupt; /* Process a reselection interrupt. */
- (Boolean) getReselectionTargetID;
@end
/* SCSI command status (from status phase) */
#define kScsiStatusGood 0x00 /* Normal completion */
#define kScsiStatusCheckCondition 0x02 /* Need GetExtendedStatus */
#define kScsiStatusConditionMet 0x04
#define kScsiStatusBusy 0x08 /* Device busy (self-test?) */
#define kScsiStatusIntermediate 0x10 /* Intermediate status */
#define kScsiStatusIntermediateMet 0x14 /* Intermediate cond. met */
#define kScsiStatusResConflict 0x18 /* Reservation conflict */
#define kScsiStatusTerminated 0x22 /* Command Terminated */
#define kScsiStatusQueueFull 0x28 /* Target can't do command */
#define kScsiStatusReservedMask 0x3E /* Vendor specific? */
/* SCSI command codes. Commands defined as ...6, ...10, ...12, are */
/* six-byte, ten-byte, and twelve-byte variants of the indicated command. */
/* These commands are supported for all devices. */
#define kScsiCmdChangeDefinition 0x40
#define kScsiCmdCompare 0x39
#define kScsiCmdCopy 0x18
#define kScsiCmdCopyAndVerify 0x3A
#define kScsiCmdInquiry 0x12
#define kScsiCmdLogSelect 0x4C
#define kScsiCmdLogSense 0x4D
#define kScsiCmdModeSelect12 0x55
#define kScsiCmdModeSelect6 0x15
#define kScsiCmdModeSense12 0x5A
#define kScsiCmdModeSense6 0x1A
#define kScsiCmdReadBuffer 0x3C
#define kScsiCmdRecvDiagResult 0x1C
#define kScsiCmdRequestSense 0x03
#define kScsiCmdSendDiagnostic 0x1D
#define kScsiCmdTestUnitReady 0x00
#define kScsiCmdWriteBuffer 0x3B
/* These commands are supported by direct-access devices only: */
#define kScsiCmdFormatUnit 0x04
#define kSCSICmdCopy 0x18
#define kSCSICmdCopyAndVerify 0x3A
#define kScsiCmdLockUnlockCache 0x36
#define kScsiCmdPrefetch 0x34
#define kScsiCmdPreventAllowRemoval 0x1E
#define kScsiCmdRead6 0x08
#define kScsiCmdRead10 0x28
#define kScsiCmdReadCapacity 0x25
#define kScsiCmdReadDefectData 0x37
#define kScsiCmdReadLong 0x3E
#define kScsiCmdReassignBlocks 0x07
#define kScsiCmdRelease 0x17
#define kScsiCmdReserve 0x16
#define kScsiCmdRezeroUnit 0x01
#define kScsiCmdSearchDataEql 0x31
#define kScsiCmdSearchDataHigh 0x30
#define kScsiCmdSearchDataLow 0x32
#define kScsiCmdSeek6 0x0B
#define kScsiCmdSeek10 0x2B
#define kScsiCmdSetLimits 0x33
#define kScsiCmdStartStopUnit 0x1B
#define kScsiCmdSynchronizeCache 0x35
#define kScsiCmdVerify 0x2F
#define kScsiCmdWrite6 0x0A
#define kScsiCmdWrite10 0x2A
#define kScsiCmdWriteAndVerify 0x2E
#define kScsiCmdWriteLong 0x3F
#define kScsiCmdWriteSame 0x41
/* These commands are supported by sequential devices: */
#define kScsiCmdRewind 0x01
#define kScsiCmdWriteFilemarks 0x10
#define kScsiCmdSpace 0x11
#define kScsiCmdLoadUnload 0x1B
/* ANSI SCSI-II for CD-ROM devices. */
#define kScsiCmdReadCDTableOfContents 0x43
/* Message codes (for Msg In and Msg Out phases). */
#define kScsiMsgAbort 0x06
#define kScsiMsgAbortTag 0x0D
#define kScsiMsgBusDeviceReset 0x0C
#define kScsiMsgClearQueue 0x0E
#define kScsiMsgCmdComplete 0x00
#define kScsiMsgDisconnect 0x04
#define kScsiMsgIdentify 0x80
#define kScsiMsgIdentifyLUNMask 0x07 /* LUN bits in Identify message */
#define kScsiMsgIgnoreWideResdue 0x23
#define kScsiMsgInitiateRecovery 0x0F
#define kScsiMsgInitiatorDetectedErr 0x05
#define kScsiMsgLinkedCmdComplete 0x0A
#define kScsiMsgLinkedCmdCompleteFlag 0x0B
#define kScsiMsgParityErr 0x09
#define kScsiMsgRejectMsg 0x07
#define kScsiMsgModifyDataPtr 0x00 /* Extended msg */
#define kScsiMsgNop 0x08
#define kScsiMsgHeadOfQueueTag 0x21 /* Two byte msg */
#define kScsiMsgOrderedQueueTag 0x22 /* Two byte msg */
#define kScsiMsgSimpleQueueTag 0x20 /* Two byte msg */
#define kScsiMsgReleaseRecovery 0x10
#define kScsiMsgRestorePointers 0x03
#define kScsiMsgSaveDataPointers 0x02
#define kScsiMsgSyncXferReq 0x01 /* Extended msg */
#define kScsiMsgWideDataXferReq 0x03 /* Extended msg */
#define kScsiMsgTerminateIOP 0x11
#define kScsiMsgExtended 0x01
#define kScsiMsgEnableDisconnectMask 0x40
#define kScsiMsgOneByteMin 0x02
#define kScsiMsgOneByteMax 0x1F
#define kScsiMsgTwoByteMin 0x20
#define kScsiMsgTwoByteMax 0x2F
/* These methods bang on the MESH chip. */
/* Many should be redone as inline functions. */
@interface AppleMesh_SCSI( Mesh )
- (IOReturn) ResetMESH : (Boolean) resetSCSIBus;
- (IOReturn) DoHBASelfTest;
- (IOReturn) WaitForMesh : (Boolean) clearInterrupts;
- (IOReturn) WaitForReq;
- (void) SetSeqReg : (MeshCommand) meshCommand;
- (void) RunDBDMA : (UInt32) offset stageLabel : (UInt32) stageLabel;
- (void) GetHBARegsAndClear : (Boolean) clearInts;
- (void) SetIntMask : (UInt8) interruptMask;
- (void) AbortActiveCommand;
- (void) AbortDisconnectedCommand;
- (void) logTimestamp : (const char*) reason;
@end
@interface AppleMesh_SCSI( Private )
/* Send a command to the controller thread, and wait for its completion. */
/* Only invoked by publicly exported methods in SCSIController.m. */
- (IOReturn) executeCmdBuf : (CommandBuffer*) cmdBuf;
/* Abort all active and disconnected commands with specified status. */
/* No hardware action. Used by threadResetBus and during processing */
/* of a kCommandAbortRequest command. */
- (void) abortAllCommands : (sc_status_t) status;
/* IO thread version of resetSCSIBus and executeRequest. */
- (void) threadResetBus : (const char*) reason;
- (void) threadExecuteRequest : (CommandBuffer*) cmdBuf;
/* Methods called by other modules in this driver: */
/* Called when a transaction associated with cmdBuf is complete. Notify
* waiting thread. If cmdBuf->scsiReq exists (i.e., this is not a reset
* or an abort), scsiReq->driverStatus must be valid. If cmdBuf is activeCmd,
* caller must remove from activeCmd.
*/
- (void) ioComplete : (CommandBuffer*) cmdBuf;
/* A target reported a full queue. Push this command back on the pending
* queue and try it again, later. (Return SR_IOST_GOOD if successful,
* SR_IOST_BADST on failure.
*/
- (sc_status_t) pushbackFullTargetQueue : (CommandBuffer*) cmdBuf;
/* A command couldn't be issued (because a target is trying to reselect
* us or we lost arbitration for some other reason). Push this request
* onto the front of the pending request queue.
*/
- (void) pushbackCurrentRequest : (CommandBuffer*) cmdBuf;
/* A command can't be continued. Perhaps there is no target. */
- (void) killCurrentRequest;
/* IO associated with activeCmd has disconnected. Place it */
/* on disconnectQ and enable another transaction. */
- (void) disconnect;
/* Specified target, lun, and queueTag is trying to reselect. If we have
* a CommandBuffer for this TLQ nexus on disconnectQ, remove it, make it the
* current activeCmd, and return YES. Else return NO.
* A value of zero for queueTag indicates a nontagged command (zero is never
* used as the queue tag value for a tagged command).
*/
- (IOReturn) reselectNexus : (UInt8) target
lun : (UInt8) lun
queueTag : (UInt8) queueTag;
- (Boolean) commandCanBeStarted : (CommandBuffer*) cmdBuf;
- (void) selectNextRequest; /* Choose the next request that can be started. */
- (void) killActiveCommand : (sc_status_t) status; // mlj added
- (void) activateCommand : (CommandBuffer*) cmdBuf;
- (void) deactivateCmd : (CommandBuffer*) cmdBuf;
/* Kill everything in the indicated queue. Called after bus reset. */
- (void) killQueue : (queue_head_t*)queuePtr finalStatus : (sc_status_t)scsiStatus;
- (void) UpdateCurrentIndex;
@end
#if USE_ELG && CustomMiniMon
/* for debugging: */
extern void EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str );
extern void Pause( UInt32 a, UInt32 b, UInt32 ascii, char* str );
extern void AllocateEventLog( UInt32 ); // defined in miniMon
#endif /* NotMiniMon */
extern void call_kdp(); // for debugging
/* Usage:
* 1. In the makefile (or elsewhere), define TIMESTAMP non-zero. If zero, this
* code will be stubbed out.
* 2. In your initialization routine, call MakeTimestampRecord() to create a
* timestamp record. This will be stored in a static, private, variable.
* 3. When you want to time something, call StoreTimestamp() as follows:
* {
* ns_time_t eventTime;
* IOGetTimestamp(&eventTime);
* StoreTimestamp(timestampTag, timestampValue, eventTime);
* }
* Where timestampTag and timestampValue are 32-bit unsigned integers
* that are not otherwise interpreted by the Timestamp library. By
* convention, timestampTag contains a 4-byte character (Macintosh OSType)
* that distinguishes timing events. The OSType and OSTag macros
* can be used to construct tag values. OSTag is useful for recording
* elapsed time:
* StoreTimestamp(OSTag('+', "foo"), 0, startTime);
* ...
* StoreTimestamp(OSTag('-', "foo"), 0, endTime);
*/
//#ifndef TIMESTAMP
#define TIMESTAMP 0 // mlj - resolve dup symbols with Curio /* TEMP TEMP TEMP */
//#endif
/* Construct an OSType from four characters. */
#define OSType(c0, c1, c2, c3) ( \
( ((c0) << 24) \
| ((c1) << 16) \
| ((c2) << 8) \
| ((c3) << 0) ))
/* Construct an OSType from a single character and the */
/* first three characters from a given string. */
#define OSTag(where, what) (OSType((where), (what)[0], (what)[1], (what)[2]))
/* ._______________________________________________________________________________.
| Each timestamp entry contains the following information: |
| timestampTag A user-specified OSType that identifies this timestamp |
| timestampValue A user-specified additional value |
| eventTime The system UpTime value at the time the data was collected. |
._______________________________________________________________________________.
*/
struct TimestampDataRecord
{
OSType timestampTag; /* Caller's tag parameter */
UInt32 timestampValue; /* Caller's value parameter */
ns_time_t eventTime; /* UpTime() at Timestamp call */
};
typedef struct TimestampDataRecord TimestampDataRecord, *TimestampDataPtr;
#if TIMESTAMP /* (( */
void MakeTimestampRecord( UInt32 nEntries );
void StoreTimestamp( OSType timestampTag,
UInt32 timestampValue,
ns_time_t timestampEvent );
/**
* Returns the next timestamp, if any, in resultData.
* @param resultData Where to store the data
* @return TRUE Valid data returned
* FALSE No data is available.
*/
Boolean ReadTimestamp( TimestampDataPtr resultData );
/**
* Return a vector of timestamps.
* @param resultVector Where to store the data
* @param count On entrance, this has the maximum number of elements
* to return. On exit, this will have the actual number
* of elements that were returned.
* Note that, if the semaphore is blocked, ReadTimestampVector will not return any
* data. Data cannot be collected while ReadTimestampVector is copying data
* to the user's buffer. Note that, since the user's buffer will typically be
* in pageable memory, pageing I/O that might otherwise be timestamped will
* be lost.
*/
void ReadTimestampVector( TimestampDataPtr resultVector, UInt32 *count ); /* -> Max count, <-actual */
Boolean EnableTimestamp( Boolean enableTimestamp );
Boolean PreserveTimestamp( Boolean preserveFirst );
void ResetTimestampIndex(void);
UInt32 GetTimestampSemaphoreLostCounter( void );
#else /* )( not TIMESTAMP: */
#define MakeTimestampRecord( nEntries ) /* Nothing */
#define StoreTimestamp( timestampTag, timestampValue, timestampEvent ) /* Nothing */
#define ReadTimestamp(resultData) (0) /* Fails */
#define ReadTimestampVector(resultVector, count) \
do { if ( count ) { *(count) = 0; } } while (0)
#define EnableTimestamp( enableTimestamp ) (enableTimestamp)
#define PreserveTimestamp( preserveFirst ) (preserveFirst)
#define ResetTimestampIndex() /* Nothing */
#define GetTimestampSemaphoreLostCount() (0)
#endif /* )) */