|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: ! 26: /** ! 27: * Copyright (c) 1994-1996 NeXT Software, Inc. All rights reserved. ! 28: * Copyright � 1997 Apple Computer Inc. All Rights Reserved. ! 29: * @author Martin Minow mailto:[email protected] ! 30: * @revision 1997.02.13 Initial conversion from AMDPCSCSIDriver sources. ! 31: * ! 32: * Set tabs every 4 characters. ! 33: * ! 34: * Edit History ! 35: * 1997.02.13 MM Initial conversion from AMDPCSCSIDriver sources. ! 36: */ ! 37: ! 38: ! 39: #define AUTO_SENSE_ENABLE 1 ! 40: ! 41: /* These are accessible by SCSIInspector: */ ! 42: ! 43: #define SYNC_ENABLE "Synchronous" ! 44: #define FAST_ENABLE "Fast SCSI" ! 45: #define CMD_QUEUE_ENABLE "Cmd Queueing" ! 46: ! 47: /* These are only accessible by Configure's Expert mode: */ ! 48: ! 49: #define EXTENDED_TIMING "Extended Timing" ! 50: #define SCSI_CLOCK_RATE "SCSI Clock Rate" /* in MHz */ ! 51: ! 52: ! 53: #define USE_ELG FALSE ! 54: #define CustomMiniMon FALSE ! 55: //#define CustomMiniMon TRUE ! 56: //#define USE_ELG TRUE ! 57: #define kEvLogSize (4096*16) // 16 pages = 64K = 4096 events ! 58: ! 59: #if USE_ELG /* (( */ ! 60: #define ELG(A,B,ASCI,STRING) EvLog( (UInt32)(A), (UInt32)(B), (UInt32)(ASCI), STRING ) ! 61: #define PAUSE(A,B,ASCI,STRING) Pause( (UInt32)(A), (UInt32)(B), (UInt32)(ASCI), STRING ) ! 62: #else /* ) not USE_ELG: ( */ ! 63: #define ELG(A,B,ASCI,S) ! 64: #define PAUSE(A,B,ASCI,S) ! 65: #define CKSTOP(A,E,ASCI,S) ! 66: #endif /* USE_ELG )) */ ! 67: ! 68: #define TIMESTAMP_AT_IOCOMPLETE 0 ! 69: ! 70: #ifndef TIMESTAMP_AT_IOCOMPLETE ! 71: #define TIMESTAMP_AT_IOCOMPLETE 0 ! 72: #endif ! 73: ! 74: ! 75: #ifndef TIMESTAMP ! 76: #define TIMESTAMP 0 // mlj - linking problems with Curio ! 77: #endif ! 78: ! 79: /* These types will ultimately be moved to an implementation-wide header file*/ ! 80: #ifndef __APPLE_TYPES_DEFINED__ ! 81: #define __APPLE_TYPES_DEFINED__ 1 ! 82: typedef unsigned char UInt8; /* An unsigned 8-bit value */ ! 83: typedef unsigned int UInt32; /* An unsigned integer */ ! 84: typedef signed int SInt32; /* An explicitly signed int */ ! 85: typedef void *LogicalAddress; /* A virtual address */ ! 86: typedef UInt32 PhysicalAddress; /* A hardware address */ ! 87: typedef UInt32 ByteCount; /* A transfer length count */ ! 88: typedef UInt32 ItemCount; /* An index or counter */ ! 89: typedef UInt32 Boolean; /* A true/false value */ ! 90: #ifndef TRUE ! 91: #define TRUE 1 ! 92: #define FALSE 0 ! 93: #endif ! 94: #endif /* __APPLE_TYPES_DEFINED__ */ ! 95: typedef signed char SInt8; ! 96: typedef UInt32 OSType; ! 97: ! 98: #ifndef SynchronizeIO ! 99: #define SynchronizeIO() eieio() /* TEMP */ ! 100: #endif /* SynchronizeIO */ ! 101: ! 102: ! 103: enum ! 104: { DBDMA_ReadStartAlignment = 8, // mlj ??? ! 105: DBDMA_WriteStartAlignment = 8 ! 106: }; ! 107: ! 108: /* Operation flags and options: */ ! 109: ! 110: typedef enum BusPhase /* These are the real SCSI bus phases (from busStatus0): */ ! 111: { ! 112: kBusPhaseDATO = 0, ! 113: kBusPhaseDATI, ! 114: kBusPhaseCMD, ! 115: kBusPhaseSTS, ! 116: kBusPhaseReserved1, ! 117: kBusPhaseReserved2, ! 118: kBusPhaseMSGO, ! 119: kBusPhaseMSGI, ! 120: kBusPhaseBusFree ! 121: } BusPhase; ! 122: ! 123: /* Command to be executed by IO thread. */ ! 124: /* These are ultimately derived from ioctl control values. */ ! 125: ! 126: typedef enum ! 127: { kCommandExecute, /* Execute IOSCSIRequest */ ! 128: kCommandResetBus, /* Reset bus */ ! 129: kCommandAbortRequest /* Abort IO thread */ ! 130: } CommandOperation; ! 131: ! 132: /* We read target messages using a simple state machine. */ ! 133: /* On entrance to MSGI phase, gMsgInState = kMsgInInit. */ ! 134: /* Continue reading messages until either */ ! 135: /* gMsgInState == kMsgInReady or the target changes phase */ ! 136: /* (which is an error). */ ! 137: typedef enum MsgInState ! 138: { ! 139: kMsgInInit = 0, /* 0 Not reading a message (must be zero) */ ! 140: kMsgInReading, /* 1 MSG input state: reading counted data */ ! 141: kMsgInCounting, /* 2 MSG input state: reading count byte */ ! 142: kMsgInReady /* 3 MSG input state: a msg is now available */ ! 143: } MsgInState; ! 144: ! 145: ! 146: /* This is the maximum number of bytes to be transferred */ ! 147: /* in an autosense request. It is, by inspection, less than 256. */ ! 148: enum { kMaxAutosenseByteCount = sizeof( esense_reply_t ) }; ! 149: ! 150: /* These values are stored in gCurrentTarget and gCurrentLUN */ ! 151: /* when there is no active request. */ ! 152: enum ! 153: { kInvalidTarget = 0xFFFF, ! 154: kInvalidLUN = 0xFFFF ! 155: }; ! 156: ! 157: /* The default initiator bus ID (needs to be fetched from NVRAM). */ ! 158: enum { kInitiatorIDDefault = 7 }; ! 159: #define APPLE_SCSI_RESET_DELAY 250 /* Msec */ ! 160: ! 161: /* Command struct passed to IO thread. */ ! 162: /* One of these are created for each active IO request. */ ! 163: ! 164: typedef struct CommandBuffer ! 165: { ! 166: /* Fields valid when commandBuf is passed to IO thread. */ ! 167: CommandOperation op; /* kCommandExecute, etc. */ ! 168: ! 169: /* The following 3 fields are only valid if op == kCommandExecute. */ ! 170: /* They are passed into the SCSI driver by executeRequest. */ ! 171: ! 172: IOSCSIRequest *scsiReq; /* -> The SCSI command parameter block */ ! 173: IOMemoryDescriptor *mem; /* -> Memory to transfer, if any */ ! 174: vm_task_t client; /* == The client task (for vm mapping) */ ! 175: ! 176: /* These fields are used by the IO thread to manage the IO request: */ ! 177: /* cmdLock Wait for the command to complete */ ! 178: /* link Queue link for the command, disconnect, and */ ! 179: /* pending queues. */ ! 180: /* timeoutPort Port for timeout messages */ ! 181: /* queueTag SCSI tagged request if not QUEUE_TAG_NONTAGGED */ ! 182: ! 183: NXConditionLock *cmdLock; /* client waits on this */ ! 184: queue_chain_t link; /* for enqueueing on commandQ */ ! 185: // port_t timeoutPort; /* for timeout messages */ ! 186: UInt8 queueTag; /* QUEUE_TAG_NONTAGGED or queue tag */ ! 187: UInt8 cdbLength; /* Actual length of this command */ ! 188: ! 189: /* SCSI bus state variables. Note that currentDataIndex can exceed */ ! 190: /* scsiReq->maxTransfer if the device sends (receives) more data than */ ! 191: /* we can receive (send). These values are NOT used for autosense. */ ! 192: /* The first byte to transfer is at logical address */ ! 193: /* gActiveCommand->buffer + currentDataIndex. */ ! 194: ! 195: UInt32 currentDataIndex; /* Where we are in the DATA transfer */ ! 196: UInt32 savedDataIndex; /* For SaveDataPointers */ ! 197: ! 198: IOMemoryDescriptorState savedDataState;/* saved index for IOMemoryDescriptor*/ ! 199: ! 200: /* Request management flags */ ! 201: /* flagActive */ ! 202: /* Set if we're in the active array and active count */ ! 203: /* reflects our existance. Managed by [ self activateCmd ] */ ! 204: /* and [ self deactivateCmd : cmdBuf ]. */ ! 205: /* and that IOScheduleFunc() has been called. */ ! 206: /* flagRequestSelectOK */ ! 207: /* Arbitration/selection succeeded for this request. */ ! 208: /* flagIsAutosense */ ! 209: /* Set if we are executing an internally-generated */ ! 210: /* Request Sense command. If this is an autosense, */ ! 211: /* the operation is modified as follows: */ ! 212: /* Arb/Select: Disable disconnects. Re-establish */ ! 213: /* synchronous and fast for this target, */ ! 214: /* use the current tag, if any. */ ! 215: /* Command: Use an internally-generated Request Sense. */ ! 216: /* Data: Read into our wired-down sense buffer. */ ! 217: /* Do not touch the data index and transfer */ ! 218: /* count variables. On completion, copy */ ! 219: /* from our wired-down buffer to the caller's */ ! 220: /* sense array. */ ! 221: /* Completion: Good status, return SR_IOST_CHKSV to client.*/ ! 222: /* Bad status: never set isAutosense. Driver */ ! 223: /* return SR_IOST_CHKSNV. */ ! 224: ! 225: UInt32 flagActive:1, /* We're in activeArray and activeCount */ ! 226: flagRequestSelectOK:1, /* Did arbitration/selection succeed? */ ! 227: flagIsAutosense:1, /* Set if THIS is an autosense command */ ! 228: pad:29; ! 229: /* This is set by autosense Status phase. */ ! 230: UInt8 autosenseStatus; /* Did autosense complete ok? */ ! 231: /* Statistics support. */ ! 232: ns_time_t startTime; /* time cmd started */ ! 233: ns_time_t disconnectTime; /* time of last disconnect */ ! 234: ! 235: } CommandBuffer; ! 236: ! 237: /* Condition variable states for commandBuf.cmdLock. */ ! 238: ! 239: enum { CMD_PENDING = 0, CMD_COMPLETE }; ! 240: ! 241: /* Value of queueTag for nontagged commands. */ ! 242: /* This value is never used for the tag for tagged commands. */ ! 243: ! 244: enum { QUEUE_TAG_NONTAGGED = 0 }; ! 245: ! 246: /* Per-target info. */ ! 247: /* */ ! 248: /* maxQueue is set to a non-zero value when we reach a target's queue size */ ! 249: /* limit, detected by a STAT_QUEUE_FULL status. A value of zero means we */ ! 250: /* have not reached the target's limit and we are free to queue additional */ ! 251: /* commands (if allowed by the overall cmdQueueEnable flag). */ ! 252: /* */ ! 253: /* syncXferPeriod and syncXferOffset are set to non-zero during sync */ ! 254: /* transfer negotiation. Units of syncXferPeriod is NANOSECONDS, which */ ! 255: /* differs from both the chip's register format (dependent on clock */ ! 256: /* frequency and fast SCSI/fast clock enables) and the SCSI bus's format */ ! 257: /* (which is 4 ns per unit). */ ! 258: /* */ ! 259: /* cmdQueueDisable and syncDisable have a default (initial) value of */ ! 260: /* zero regardless of the driver's overall cmdQueueEnable and syncModeEnable */ ! 261: /* flags. They are set to one when a target explicitly tells us that the */ ! 262: /* indicated feature is unsupported. */ ! 263: /* */ ! 264: /* negotiateSDTR has one of the following values (defined in */ ! 265: /* AppleMeshDefinitions.h): */ ! 266: /* kSyncParmsAsync Async with min period */ ! 267: /* kSyncParmsFast Offset = 15, period = Fast (10 MB/s) */ ! 268: /* syncParms Shadow of MESH syncParms register. */ ! 269: ! 270: typedef struct ! 271: { ! 272: UInt8 maxQueue; /* Max queue depth for this target */ ! 273: UInt8 negotiateSDTR; /* Synchronous negotiation control */ ! 274: UInt8 syncParms; /* Synchronous period and offset */ ! 275: UInt8 inquiry_7; /* 7th byte peeked fm Inquiry data */ ! 276: UInt8 syncDisable; /* No synchronous for this target */ ! 277: } PerTargetData; ! 278: ! 279: typedef struct MeshRegister /* Mesh registers: */ ! 280: { ! 281: volatile UInt8 transferCount0; UInt8 pad00[ 0x0F ]; ! 282: volatile UInt8 transferCount1; UInt8 pad01[ 0x0F ]; ! 283: volatile UInt8 xFIFO; UInt8 pad02[ 0x0F ]; ! 284: volatile UInt8 sequence; UInt8 pad03[ 0x0F ]; ! 285: volatile UInt8 busStatus0; UInt8 pad04[ 0x0F ]; ! 286: volatile UInt8 busStatus1; UInt8 pad05[ 0x0F ]; ! 287: volatile UInt8 FIFOCount; UInt8 pad06[ 0x0F ]; ! 288: volatile UInt8 exception; UInt8 pad07[ 0x0F ]; ! 289: volatile UInt8 error; UInt8 pad08[ 0x0F ]; ! 290: volatile UInt8 interruptMask; UInt8 pad09[ 0x0F ]; ! 291: volatile UInt8 interrupt; UInt8 pad10[ 0x0F ]; ! 292: volatile UInt8 sourceID; UInt8 pad11[ 0x0F ]; ! 293: volatile UInt8 destinationID; UInt8 pad12[ 0x0F ]; ! 294: volatile UInt8 syncParms; UInt8 pad13[ 0x0F ]; ! 295: volatile UInt8 MESHID; UInt8 pad14[ 0x0F ]; ! 296: volatile UInt8 selectionTimeOut; ! 297: } MeshRegister; ! 298: ! 299: /* The following structure shadows the MESH chip registers: */ ! 300: ! 301: typedef union MESHShadow ! 302: { UInt32 longWord[ 3 ]; /* for debugging ease. */ ! 303: struct ! 304: { UInt8 interrupt; /* Interrupt */ ! 305: UInt8 error; /* Error register */ ! 306: UInt8 exception; /* Exception register */ ! 307: UInt8 FIFOCount; /* FIFO count */ ! 308: ! 309: UInt8 busStatus0; /* Bus phase + REQ, ACK, & ATN signals */ ! 310: UInt8 busStatus1; /* RST, BSY, SEL */ ! 311: UInt8 interruptMask; /* Interrupt mask for debugging */ ! 312: UInt8 transferCount0; /* low order byte of transfer count */ ! 313: ! 314: UInt8 transferCount1; /* high order byte of transfer count */ ! 315: UInt8 sequence; /* Sequence register */ ! 316: UInt8 syncParms; /* syncParms for debugging */ ! 317: UInt8 destinationID; /* Target ID */ ! 318: } mesh; ! 319: } MESHShadow; ! 320: ! 321: /* Mesh Register set offsets */ ! 322: ! 323: enum ! 324: { ! 325: kMeshTransferCount0 = 0x00, ! 326: kMeshTransferCount1 = 0x10, ! 327: kMeshFIFO = 0x20, ! 328: kMeshSequence = 0x30, ! 329: kMeshBusStatus0 = 0x40, ! 330: kMeshBusStatus1 = 0x50, ! 331: kMeshFIFOCount = 0x60, ! 332: kMeshException = 0x70, ! 333: kMeshError = 0x80, ! 334: kMeshInterruptMask = 0x90, ! 335: kMeshInterrupt = 0xA0, ! 336: kMeshSourceID = 0xB0, ! 337: kMeshDestinationID = 0xC0, ! 338: kMeshSyncParms = 0xD0, ! 339: kMeshMESHID = 0xE0, ! 340: kMeshSelTimeOut = 0xF0 ! 341: }; ! 342: ! 343: enum { kMeshMESHID_Value = 0x02 }; /* Read value of kMESHID lowest 5 bits only */ ! 344: ! 345: ! 346: /* MESH commands & modifiers for sequence register: */ ! 347: ! 348: typedef enum ! 349: { ! 350: kMeshNoOpCmd = 0x00, ! 351: ! 352: kMeshArbitrateCmd = 0x01, ! 353: kMeshSelectCmd = 0x02, ! 354: kMeshCommandCmd = 0x03, ! 355: kMeshStatusCmd = 0x04, ! 356: kMeshDataOutCmd = 0x05, ! 357: kMeshDataInCmd = 0x06, ! 358: kMeshMessageOutCmd = 0x07, ! 359: kMeshMessageInCmd = 0x08, ! 360: kMeshBusFreeCmd = 0x09, ! 361: /* non interrupting: */ ! 362: kMeshEnableParity = 0x0A, ! 363: kMeshDisableParity = 0x0B, ! 364: kMeshEnableReselect = 0x0C, ! 365: kMeshDisableReselect = 0x0D, ! 366: kMeshResetMESH = 0x0E, ! 367: kMeshFlushFIFO = 0x0F, ! 368: /* Sequence command modifier bits: */ ! 369: kMeshSeqDMA = 0x80, /* Data Xfer for this command will use DMA */ ! 370: kMeshSeqTMode = 0x40, /* Target mode - unused */ ! 371: kMeshSeqAtn = 0x20 /* ATN is to be asserted after command */ ! 372: } MeshCommand; ! 373: ! 374: /* The bus Status Registers 0 & 1 have the actual */ ! 375: /* bus signals WHEN READ. */ ! 376: ! 377: enum /* bus Status Register 0 bits: */ ! 378: { ! 379: kMeshIO = 0x01, /* phase bit */ ! 380: kMeshCD = 0x02, /* phase bit */ ! 381: kMeshMsg = 0x04, /* phase bit */ ! 382: kMeshAtn = 0x08, /* Attention signal */ ! 383: kMeshAck = 0x10, /* Ack signal */ ! 384: kMeshReq = 0x20, /* Request signal */ ! 385: kMeshAck32 = 0x40, /* unused - 32 bit bus */ ! 386: kMeshReq32 = 0x80 /* unused - 32 bit bus */ ! 387: }; ! 388: ! 389: enum { kMeshPhaseMask = (kMeshMsg + kMeshCD + kMeshIO) }; ! 390: ! 391: enum /* bus Status Register 1 bits: */ ! 392: { ! 393: kMeshSel = 0x20, /* Select signal */ ! 394: kMeshBsy = 0x40, /* Busy signal */ ! 395: kMeshRst = 0x80 /* Reset signal */ ! 396: }; ! 397: ! 398: enum /* Exception Register bits: */ ! 399: { ! 400: kMeshExcSelTO = 0x01, /* Selection timeout */ ! 401: kMeshExcPhaseMM = 0x02, /* Phase mismatch */ ! 402: kMeshExcArbLost = 0x04, /* lost arbitration */ ! 403: kMeshExcResel = 0x08, /* reselection occurred */ ! 404: kMeshExcSelected = 0x10, ! 405: kMeshExcSelectedWAtn = 0x20 ! 406: }; ! 407: ! 408: enum /* Error Register bits: */ ! 409: { ! 410: kMeshErrParity0 = 0x01, /* parity error */ ! 411: kMeshErrParity1 = 0x02, /* unused - 32 bit bus */ ! 412: kMeshErrParity2 = 0x04, /* unused - 32 bit bus */ ! 413: kMeshErrParity3 = 0x08, /* unused - 32 bit bus */ ! 414: kMeshErrSequence = 0x10, /* Sequence error */ ! 415: kMeshErrSCSIRst = 0x20, /* Reset signal asserted */ ! 416: kMeshErrDisconnected = 0x40 /* unexpected disconnect */ ! 417: }; ! 418: ! 419: enum /* Interrupt Register bits: */ ! 420: { ! 421: kMeshIntrCmdDone = 0x01, /* command done */ ! 422: kMeshIntrException = 0x02, /* exception occurred */ ! 423: kMeshIntrError = 0x04, /* error occurred */ ! 424: kMeshIntrMask = (kMeshIntrCmdDone | kMeshIntrException | kMeshIntrError) ! 425: }; ! 426: ! 427: ! 428: enum /* Values for SyncParms MESH register: */ ! 429: { /* 1st nibble is offset, 2nd is period. */ ! 430: /* Zero offset means async. */ ! 431: kSyncParmsAsync = 0x02, /* Async with min period = 2 */ ! 432: kSyncParmsFast = 0xF0 /* offset = 15, period = Fast (10 MB/s) */ ! 433: }; ! 434: ! 435: /* The following are specific to the MESH CCL */ ! 436: /* Stage Names. (These were originally 'xxxx' identifiers, */ ! 437: /* which is convenient for debugging, but results in many */ ! 438: /* warning messages from the NeXT compiler. */ ! 439: enum ! 440: { ! 441: kcclStageIdle = 0, /* 0 - Idle */ ! 442: kcclStageInit, /* 1 - 'Init' */ ! 443: kcclStageCCLx, /* 2 - 'CCL~' */ ! 444: kcclStageArb, /* 3 - ' Arb' */ ! 445: kcclStageSelA, /* 4 - 'SelA' */ ! 446: kcclStageMsgO, /* 5 - 'MsgO' */ ! 447: kcclStageCmdO, /* 6 - 'CmdO' */ ! 448: kcclStageXfer, /* 7 - 'Xfer' */ ! 449: kcclStageBucket, /* 8 - 'Buck' */ ! 450: kcclStageSyncHack, /* 9 - 'Hack' */ ! 451: kcclStageStat, /* A - ' Sta' */ ! 452: kcclStageMsgI, /* B - 'MsgI' */ ! 453: kcclStageFree, /* C - 'Free' */ ! 454: kcclStageGood, /* D - 'Good' */ ! 455: kcclStageStop, /* E - '++++' */ ! 456: kcclTerminatorWithoutComma ! 457: }; ! 458: ! 459: /* offsets into the Channel Command List page: */ ! 460: ! 461: #define kcclProblem 0x00 // Interrupt & Stop channel commands for anomalies ! 462: #define kcclCMDOdata 0x20 // reserve for 6, 10, 12 byte commands ! 463: #define kcclMSGOdata 0x30 // reserve for Identify, Tag stuff ! 464: #define kcclMSGOLast 0x3F // reserve for last or only msg0ut byte ! 465: #define kcclMSGIdata 0x40 // reserve for Message In data ! 466: #define kcclBucket 0x48 // Bit Bucket ! 467: #define kcclStatusData 0x4F // reserve for Status byte ! 468: #define kcclSenseCDB 0x50 // CDB for (auto) Sense ! 469: #define kcclBatchSize 0x60 // Current MESH batch size ! 470: #define kcclStageLabel 0x6C // storage for label of last stage entered. ! 471: #define kcclSense 0x70 // Channel Commands for (Auto)Sense ! 472: #define kcclPrototype 0xC0 // Prototype MESH 4-command Transfer sequence ! 473: #define kcclStart 0x120 // Channel Program starts here with Arbitrate ! 474: #define kcclBrProblem 0x140 // channel command to wait for cmdDone & Br if problem ! 475: #define kcclMsgoStage 0x190 // Branch to single byte Message-Out ! 476: #define kcclMsgoBranch 0x1B0 // Branch to single byte Message-Out ! 477: #define kcclMsgoMTC 0x1D8 // MESH Transfer Count for MSGO (low order only) ! 478: #define kcclMsgoDTC 0x1F0 // DMA Transfer Count for MSGO (low order only) ! 479: #define kcclLastMsgo 0x210 // Channel commands to put last/only byte of Message-Out ! 480: #define kcclCmdoStage 0x290 // Start of Command phase ! 481: #define kcclCmdoMTC 0x2C8 // MESH Transfer Count for CMDO (low order only) ! 482: #define kcclCmdoDTC 0x2E0 // DMA Transfer Count for CMDO (low order only) ! 483: #define kcclReselect 0x2F0 // Reselect enters CCL here - Branch to xfer data ! 484: #define kcclOverrun 0x320 // data overrun - dump the excess in the bit bucket ! 485: #define kcclOverrunMESH 0x370 // data overrun - patch the MESH Seq Reg I/O ! 486: #define kcclOverrunDBDMA 0x380 // data overrun - patch the DBDMA I/O ! 487: #define kcclSyncCleanUp 0x3B0 // clean up at end of Sync xfer ! 488: #define kcclGetStatus 0x3D0 // Finish up with Status, Message In, and Bus Free ! 489: #define kcclMESHintr 0x4D0 // transaction done or going well ! 490: #define kcclSenseBuffer 0x500 // Buffer for Autosense data ! 491: #define kcclDataXfer 0x600 // INPUT or OUTPUT channel commands for data ! 492: #define kcclSenseResult 0x63C // Result field in Sense INPUT channel command ! 493: ! 494: ! 495: /* generic relocation types: */ ! 496: ! 497: #define kRelNone 0x00 /* default - no relocation */ ! 498: #define kRelMESH 0x01 /* Relocate to MESH register area */ ! 499: #define kRelCP 0x02 /* Relocate to Channel Program area */ ! 500: #define kRelCPdata 0x03 /* Relocate to Channel Program data structure */ ! 501: #define kRelPhys 0x04 /* Relocate to user Physical address space */ ! 502: #define kRelNoSwap 0x05 /* don't relocate or swap (Label) */ ! 503: ! 504: /* Relocatable ADDRESS types: */ ! 505: ! 506: #define kRelAddress 0xFF <<8 /* relocatable address mask */ ! 507: #define kRelAddressMESH kRelMESH <<8 /* MESH physical address */ ! 508: #define kRelAddressCP kRelCP <<8 /* Channel Program Physical address */ ! 509: #define kRelAddressPhys kRelPhys <<8 /* User data Physical address */ ! 510: ! 511: /* Relocatable COMMAND-DEPENDENT types: */ ! 512: ! 513: #define kRelCmdDep 0xFF /* relocatable command-dependent mask */ ! 514: #define kRelCmdDepCP kRelCP /* Channel Program command-dependent (branch) */ ! 515: #define kRelCmdDepLabel kRelNoSwap /* Channel Program label - don't swap */ ! 516: ! 517: ! 518: /* Channel Program macros: */ ! 519: ! 520: #define STAGE(v) STORE_QUAD | KEY_SYSTEM | 4, kcclStageLabel, v, kRelAddressCP | kRelCmdDepLabel ! 521: #define CLEAR_CMD_DONE STORE_QUAD | KEY_SYSTEM | 1, kMeshInterrupt, kMeshIntrCmdDone, kRelAddressMESH ! 522: #define CLEAR_INT_REG STORE_QUAD | KEY_SYSTEM | 1, kMeshInterrupt, kMeshIntrMask, kRelAddressMESH ! 523: #define CLR_PHASEMM STORE_QUAD | KEY_SYSTEM | 1, kMeshInterrupt, kMeshIntrCmdDone | kMeshIntrException, kRelAddressMESH ! 524: #define MOVE_1(a,v,r) STORE_QUAD | KEY_SYSTEM | 1, a, v, r ! 525: #define MOVE_4(a,v,r) STORE_QUAD | KEY_SYSTEM | 4, a, v, r ! 526: #define MESH_REG(a,v) STORE_QUAD | KEY_SYSTEM | 1, a, v, kRelAddressMESH ! 527: #define MESH_REG_WAIT(a,v) STORE_QUAD | KEY_SYSTEM | kWaitIfTrue | 1, a, v, kRelAddressMESH ! 528: ! 529: #define SENSE(c) INPUT_LAST | kBranchIfFalse | kWaitIfTrue | c, kcclSenseBuffer, kcclProblem, kRelAddressCP | kRelCmdDepCP ! 530: #define MSGO(a,c) OUTPUT_LAST | kBranchIfFalse | kWaitIfTrue | c, a, kcclProblem, kRelAddressCP | kRelCmdDepCP ! 531: #define CMDO(c) OUTPUT_LAST | kBranchIfFalse | kWaitIfTrue | c, kcclCMDOdata, kcclProblem, kRelAddressCP | kRelCmdDepCP ! 532: #define MSGI(c) INPUT_LAST | kBranchIfFalse | kWaitIfTrue | c, kcclMSGIdata, kcclProblem, kRelAddressCP | kRelCmdDepCP ! 533: #define STATUS_IN INPUT_LAST | kBranchIfFalse | kWaitIfTrue | 1, kcclStatusData, kcclProblem, kRelAddressCP | kRelCmdDepCP ! 534: #define BUCKET INPUT_LAST | kBranchIfFalse | 8, kcclBucket, kcclProblem, kRelAddressCP | kRelCmdDepCP ! 535: ! 536: #define BRANCH(a) NOP_CMD | kBranchAlways, 0, a, kRelCmdDepCP ! 537: #define BR_IF_PROBLEM NOP_CMD | kBranchIfFalse | kWaitIfTrue, 0, kcclProblem, kRelCmdDepCP ! 538: #define BR_NO_PROBLEM(a) NOP_CMD | kBranchIfTrue , 0, a, kRelCmdDepCP ! 539: #define STOP(L) STOP_CMD, 0, L, kRelCmdDepLabel ! 540: #define INTERRUPT(a) NOP_CMD | kIntAlways, 0, a, 0 ! 541: #define RESERVE 0xCEFECEFE, 0xCEFECEFE, 0xCEFECEFE, 0xCEFECEFE ! 542: #define WAIT_4_CMDDONE NOP_CMD | kWaitIfTrue, 0, 0, 0 ! 543: ! 544: //#define SWAP(x) (UInt32)EndianSwap32Bit( (UInt32)( x ) ) ! 545: #define SWAP(x) (UInt32)EndianSwap32( (UInt32)( x ) ) ! 546: ! 547: ! 548: /* Return values from hardwareStart. */ ! 549: ! 550: typedef enum ! 551: { kHardwareStartOK, /* command started successfully */ ! 552: kHardwareStartRejected, /* command rejected, try another */ ! 553: kHardwareStartBusy /* hardware not ready for command */ ! 554: } HardwareStartResult; ! 555: ! 556: /* This structure defines the DBDMA Channel Command descriptor. */ ! 557: /***** WARNING: Endian-ness issues must be considered when *****/ ! 558: /***** performing load/store! *****/ ! 559: /***** DBDMA specifies memory organization as quadlets so it *****/ ! 560: /***** is not correct to think of either the operation or *****/ ! 561: /***** result field as two 16-bit fields. This would have *****/ ! 562: /***** undesirable effects on the byte ordering within their *****/ ! 563: /***** respective quadlets. Use the accessor macros provided *****/ ! 564: /***** below. *****/ ! 565: ! 566: struct DBDMADescriptor ! 567: { ! 568: UInt32 operation; /* cmd || key || i || b || w || reqCount */ ! 569: UInt32 address; ! 570: UInt32 cmdDep; ! 571: UInt32 result; /* xferStatus || resCount */ ! 572: }; ! 573: typedef struct DBDMADescriptor DBDMADescriptor; ! 574: ! 575: typedef DBDMADescriptor *DBDMADescriptorPtr; ! 576: ! 577: /* These constants define the DBDMA channel command operations and modifiers.*/ ! 578: ! 579: enum /* Command.cmd operations */ ! 580: { ! 581: OUTPUT_MORE = 0x00000000, ! 582: OUTPUT_LAST = 0x10000000, ! 583: INPUT_MORE = 0x20000000, ! 584: INPUT_LAST = 0x30000000, ! 585: STORE_QUAD = 0x40000000, ! 586: LOAD_QUAD = 0x50000000, ! 587: NOP_CMD = 0x60000000, ! 588: STOP_CMD = 0x70000000, ! 589: kdbdmaCmdMask = 0xF0000000 ! 590: }; ! 591: ! 592: ! 593: enum ! 594: { /* Command.key modifiers */ ! 595: /* (choose one for INPUT, OUTPUT, LOAD, and STORE) */ ! 596: KEY_STREAM0 = 0x00000000, /* default modifier*/ ! 597: KEY_STREAM1 = 0x01000000, ! 598: KEY_STREAM2 = 0x02000000, ! 599: KEY_STREAM3 = 0x03000000, ! 600: KEY_REGS = 0x05000000, ! 601: KEY_SYSTEM = 0x06000000, ! 602: KEY_DEVICE = 0x07000000, ! 603: kdbdmaKeyMask = 0x07000000, /* Command.i modifiers (choose one for INPUT, OUTPUT, LOAD, STORE, and NOP)*/ ! 604: kIntNever = 0x00000000, /* default modifier */ ! 605: kIntIfTrue = 0x00100000, ! 606: kIntIfFalse = 0x00200000, ! 607: kIntAlways = 0x00300000, ! 608: kdbdmaIMask = 0x00300000, /* Command.b modifiers (choose one for INPUT, OUTPUT, and NOP)*/ ! 609: kBranchNever = 0x00000000, /* default modifier */ ! 610: kBranchIfTrue = 0x00040000, ! 611: kBranchIfFalse = 0x00080000, ! 612: kBranchAlways = 0x000C0000, ! 613: kdbdmaBMask = 0x000C0000, /* Command.w modifiers (choose one for INPUT, OUTPUT, LOAD, STORE, and NOP)*/ ! 614: kWaitNever = 0x00000000, /* default modifier */ ! 615: kWaitIfTrue = 0x00010000, ! 616: kWaitIfFalse = 0x00020000, ! 617: kWaitAlways = 0x00030000, ! 618: kdbdmaWMask = 0x00030000, /* operation masks */ ! 619: }; ! 620: ! 621: ! 622: /* This is a temporary implementation of EndianSwap32Bit */ ! 623: /* until the correct library/method is made available. */ ! 624: /* @param value The value to change */ ! 625: /* @result The value endian-swapped. */ ! 626: ! 627: #ifdef CRAP ! 628: static inline unsigned EndianSwap32Bit( unsigned value ) ! 629: { ! 630: register unsigned temp; ! 631: ! 632: temp = ((value & 0xFF000000) >> 24); ! 633: temp |= ((value & 0x00FF0000) >> 8); ! 634: temp |= ((value & 0x0000FF00) << 8); ! 635: temp |= ((value & 0x000000FF) << 24); ! 636: return temp; ! 637: } ! 638: #else ! 639: static __inline__ UInt32 EndianSwap32( UInt32 y ) ! 640: { ! 641: UInt32 result; ! 642: volatile UInt32 x; ! 643: ! 644: x = y; ! 645: __asm__ volatile("lwbrx %0, 0, %1" : "=r" (result) : "r" (&x) : "r0"); ! 646: return result; ! 647: } ! 648: #endif /* CRAP */ ! 649: ! 650: ! 651: typedef struct globals /* Globals for this module (not per instance) */ ! 652: { ! 653: UInt32 evLogFlag; // debugging only ! 654: UInt8 *evLogBuf; ! 655: UInt8 *evLogBufe; ! 656: UInt8 *evLogBufp; ! 657: UInt8 intLevel; ! 658: ! 659: MESHShadow shadow; // move to per instance??? /* Last MESH register state */ ! 660: ! 661: UInt32 cclLogAddr, cclPhysAddr; // for debugging/miniMon ease ! 662: UInt32 meshAddr; // for debugging/miniMon ease ! 663: } globals; ! 664: ! 665: ! 666: /* "Global" data for each instance of the MESH Host Bus Adapter: */ ! 667: ! 668: @interface AppleMesh_SCSI : IOSCSIController < IOPower > ! 669: { ! 670: /* These globals locate the hardware interfaces in */ ! 671: /* logical and physical address spaces. */ ! 672: ! 673: MeshRegister *meshAddr; /* -> Mesh registers (logical) */ ! 674: PhysicalAddress gMESHPhysAddr; /* -> Mesh registers (physical) */ ! 675: ! 676: dbdma_regmap_t *dbdmaAddr; /* -> DBDMA registers (logical) */ ! 677: PhysicalAddress dbdmaAddrPhys; /* -> DBDMA registers (physical) */ ! 678: ! 679: PhysicalAddress cclPhysAddr; /* -> DBDMA channel area (physical) */ ! 680: DBDMADescriptor *cclLogAddr; /* -> DBDMA channel area (logical) */ ! 681: UInt32 cclLogAddrSize; /* == DBDMA channel allocated size */ ! 682: UInt32 gDBDMADescriptorMax; /* Number of DATA descriptors */ ! 683: ! 684: ! 685: /* There are 3 queues: incomingCmdQ, pendingCmdQ, disconnectedCmdQ. */ ! 686: /* Commands are passed from exported methods to the IO thread via */ ! 687: /* incomingCmdQ, which is protected by incomingCmdLock. */ ! 688: /* Commands which are disconnected but not complete are kept in */ ! 689: /* disconnectedCmdQ. */ ! 690: /* Commands which have been dequeued from incomingCmdQ by the IO thread */ ! 691: /* but which have not been started because a command is currently active*/ ! 692: /* on the bus are kept in pendingCmdQ. This queue also holds commands */ ! 693: /* pushed back when we lose arbitration. */ ! 694: ! 695: /* The currently active command, if any, is kept in gActiveCommand. */ ! 696: /* Only commandBufs with op == kCommandExecute are ever placed in */ ! 697: /* gActiveCommand. */ ! 698: id incomingCmdLock; /* NXLock for incomingCmdQ */ ! 699: queue_head_t incomingCmdQ; ! 700: queue_head_t pendingCmdQ; ! 701: queue_head_t disconnectedCmdQ; ! 702: queue_head_t abortCmdQ; ! 703: ! 704: /* This is the command we're currently execution. If NULL, the Mac */ ! 705: /* is idle (or all commands are disconnected). Normally, gCurrentTarget */ ! 706: /* and gCurrentLUN track the values in the active command's associated */ ! 707: /* SCSI request. They are set to kInvalidTarget and kInvalidLUN at */ ! 708: /* initialization, command deactivation, command complete, and command */ ! 709: /* disconnect. They are set to valid values (with no active command) */ ! 710: /* during reselection. This is tricky, so look carefully at the code. */ ! 711: CommandBuffer *gActiveCommand; /* -> The currently executing command */ ! 712: UInt32 gCurrentTarget; /* == The current target bus ID */ ! 713: UInt32 gCurrentLUN; /* == The current target LUN */ ! 714: ! 715: /* Global option flags, accessible via instance table or setIntValues. Note: some of ! 716: * these are intended for debugging. However, users may need to disable command ! 717: * queuing, synchronous, or fast to handle device or bus limitations. The ! 718: * architecture-specific initialization "looks" at the device to determine whether ! 719: * specific features (such as synchronous) are supported. ! 720: * gOptionAutoSenseEnable Debug only, normally set ! 721: * gOptionCmdQueueEnable Enable tagged queuing. ! 722: * gOptionSyncModeEnable Enable synchronous transfers (clear if problems) ! 723: * gOptionFastModeEnable Enable fast transfers (clear if problems) ! 724: * gOptionExtendTiming Extended selection timing (debug, unused) ! 725: * gFlagIOThreadRunning Set when IO thread is initialized. Needed ! 726: * for shutdown. ! 727: * gFlagIncompleteDBDMA Set in the data transfer setup if there was ! 728: * so much data that the entire transfer could not ! 729: * be stored in the CCL area. If so, the interrupt ! 730: * service routine ("good completion") will restart ! 731: * the data transfer operation. ! 732: */ ! 733: UInt32 gOptionAutoSenseEnable : 1, ! 734: gOptionCmdQueueEnable : 1, ! 735: gOptionSyncModeEnable : 1, ! 736: gOptionFastModeEnable : 1, ! 737: gOptionExtendTiming : 1, ! 738: gFlagIOThreadRunning : 1, /* Set at init */ ! 739: gFlagIncompleteDBDMA : 1, /* Need more DMA */ ! 740: gFlagReselecting : 1, /* Reselection in progress */ ! 741: pad : 24; ! 742: ! 743: /* Array of active IO counters, one counter per LUN per target. */ ! 744: /* If command queueing is disabled, the max value of each counter is 1. */ ! 745: /* gActiveCount is the sum of all elements in activeArray. */ ! 746: ! 747: UInt8 gActiveArray[ SCSI_NTARGETS ][ SCSI_NLUNS ]; ! 748: UInt32 gActiveCount; ! 749: ! 750: /* These variables change during SCSI IO operation. */ ! 751: /* msgOutPtr Points to the next free byte in the MSGO buffer */ ! 752: /* in the shared CCL area. */ ! 753: ! 754: UInt8 *msgOutPtr; /* ptr to message-out data */ ! 755: ! 756: /* These variables manage Message-In bus phase. Because the */ ! 757: /* Message-In handler uses programmed IO, gMsgInCount and */ ! 758: /* gMsgInState are actually local variables to the message */ ! 759: /* reader, and are here for debugging convenience. */ ! 760: ! 761: UInt8 gMsgInBuffer[ 16 ]; ! 762: SInt8 gMsgInCount; /* Message bytes still to read */ ! 763: MsgInState gMsgInState; /* How are we handling messages */ ! 764: ! 765: #define kFlagMsgIn_Reject 0x01 ! 766: #define kFlagMsgIn_Disconnect 0x02 ! 767: UInt8 gMsgInFlag; ! 768: ! 769: #define kFlagMsgOut_SDTR 0x01 ! 770: #define kFlagMsgOut_Queuing 0x02 ! 771: UInt8 gMsgOutFlag; ! 772: ! 773: /* These variables are used during reselection to select the correct */ ! 774: /* (tagged) command. msgInTagType is the last Tagged Queue message */ ! 775: /* received from a target during reselection. msgInTag is the */ ! 776: /* tag value. Currently, we should only see a Simple Queue Tag. */ ! 777: UInt8 msgInTagType; /* Last tag type */ ! 778: UInt8 msgInTag; /* Last tag value */ ! 779: ! 780: /* Hardware related variables: */ ! 781: ! 782: UInt8 gInitiatorID; /* Our SCSI ID */ ! 783: UInt8 gInitiatorIDMask; /* BusID bitmask for selection */ ! 784: UInt8 gSelectionTimeout; /* In MESH 10 msec units */ ! 785: ! 786: /* commandBuf->queueTag for next IO. This is never zero; */ ! 787: /* for all requests involving a T/L/Q nexus, a queue tag */ ! 788: /* of zero indicates a nontagged command. */ ! 789: UInt8 gNextQueueTag; ! 790: ! 791: PerTargetData gPerTargetData[ SCSI_NTARGETS ]; ! 792: ! 793: /* Statistics support: */ ! 794: ! 795: UInt32 gMaxQueueLen; ! 796: UInt32 gQueueLenTotal; ! 797: UInt32 gTotalCommands; ! 798: } ! 799: ! 800: /* Public methods (called by higher-level driver functions) */ ! 801: ! 802: + (Boolean) probe : deviceDescription; /* Initialize the SCSI driver. */ ! 803: - free; /* Shutdown the driver. */ ! 804: ! 805: ! 806: - (sc_status_t) executeRequest /* Execute a SCSI IO request */ ! 807: : (IOSCSIRequest*) scsiReq ! 808: buffer : (void*) buffer ! 809: client : (vm_task_t) client; ! 810: ! 811: /* Execute a SCSI request using an IOMemoryDescriptor. */ ! 812: /* This allows callers to provide (kernel-resident) logical scatter-gather */ ! 813: /* lists. For compatibility with existing implementations, the low-level */ ! 814: /* SCSI device driver must first ensure that */ ! 815: /* executeRequest:ioMemoryDescriptor is supported by executing: */ ! 816: /* [controller respondsToSelector : executeRequest:ioMemoryDescriptor] */ ! 817: /* @param scsiReq The SCSI request command record, including the */ ! 818: /* target device and LUN, the command to execute, and various control flags.*/ ! 819: /* @param ioMemoryDescriptor The data buffer(s), if any. This may be NULL */ ! 820: /* if no data phase is expected. */ ! 821: /* @param client The client task that "owns" the memory buffer. */ ! 822: /* @return Return a bus adaptor specific error status. */ ! 823: - (sc_status_t) executeRequest : (IOSCSIRequest*)scsiReq ! 824: ioMemoryDescriptor : (IOMemoryDescriptor*)ioMemoryDescriptor; ! 825: ! 826: - (sc_status_t) resetSCSIBus; /* Reset the SCSI bus */ ! 827: - (void) resetStatistics; /* Reset statistics buffers */ ! 828: - (unsigned) numQueueSamples; ! 829: - (unsigned) sumQueueLengths; ! 830: - (unsigned) maxQueueLength; ! 831: ! 832: /* interruptOccurred is a public method called by the */ ! 833: /* IO thread in IODirectDevice when an interrupt occurs. */ ! 834: - (void) interruptOccurred; ! 835: ! 836: /* timeoutOccurred is a public method called by the */ ! 837: /* IO thread in IODirectDevice when it receives a */ ! 838: /* timeout message. */ ! 839: ! 840: - (void) timeoutOccurred; ! 841: ! 842: #if APPLE_MESH_ENABLE_GET_SET ! 843: ! 844: - (IOReturn) setIntValues : (unsigned*) parameterArray ! 845: forParameter : (IOParameterName) parameterName ! 846: count : (unsigned) count; ! 847: ! 848: - (IOReturn) getIntValues : (unsigned*) parameterArray ! 849: forParameter : (IOParameterName) parameterName ! 850: count : (unsigned*) count; /* in/out */ ! 851: ! 852: /* get/setIntValues parameters: */ ! 853: ! 854: #define APPLE_MESH_AUTOSENSE "AutoSense" ! 855: #define APPLE_MESH_CMD_QUEUE "CmdQueue" ! 856: #define APPLE_MESH_SYNC "Synchronous" ! 857: #define APPLE_MESH_FAST_SCSI "FastSCSI" ! 858: #define APPLE_MESH_RESET_TARGETS "ResetTargets" ! 859: #define APPLE_MESH_RESET_TIMESTAMP "ResetTimestamp" ! 860: #define APPLE_MESH_ENABLE_TIMESTAMP "EnableTimestamp" ! 861: #define APPLE_MESH_DISABLE_TIMESTAMP "DisableTimestamp" ! 862: #define APPLE_MESH_PRESERVE_FIRST_TIMESTAMP "PreserveFirstTimestamp" ! 863: #define APPLE_MESH_PRESERVE_LAST_TIMESTAMP "PreserveLastTimestamp" ! 864: #define APPLE_MESH_READ_TIMESTAMP "ReadTimestamp" ! 865: #define APPLE_MESH_STORE_TIMESTAMP "StoreTimestamp" ! 866: ! 867: /* ! 868: * Recording and setting timestamps may be done using getIntValues (this permits ! 869: * access from non-privileged tasks. ! 870: * ResetTimestamp Clear the timestamp vector - do this before starting ! 871: * a sequence (no parameters) ! 872: * EnableTimestamp Start recording (no parameters) (default) ! 873: * DisableTimestamp Stop recording (no parameters) ! 874: * PreserveFirstTimestamp Stop recording when the buffer fills (until it is emptied) ! 875: * PreserveLastTimestamp Discard old values when new arrive (default) ! 876: * ReadTimestamp Read a vector of timestamps (see sample below) ! 877: * StoreTimestamp Store a timestamp (from user mode) (see sample below) ! 878: * ReadTimestamp copies timestamps from the internal database to user-specified vector. ! 879: * Because getIntValues parameters are defined in int units, the code is slighthly ! 880: * non-obvious: ! 881: * TimestampDataRecord myTimestamps[ 123 ]; ! 882: * unsigned count; ! 883: * count = sizeof (myTimestamps) / sizeof (unsigned); ! 884: * [scsiDevice getIntValues ! 885: * : (unsigned int *) myTimestamps ! 886: * forParameter : APPLE_MESH_READ_TIMESTAMP ! 887: * count : &count ! 888: * ]; ! 889: * count = (count * sizeof (unsigned)) / sizeof (TimestampDataRecord); ! 890: * for (i = 0; i < count; i++) { ! 891: * Process(myTimestamps[i]); ! 892: * } ! 893: * Applications can store timestamps using one of three parameter formats: ! 894: * unsigned paramVector[4]; ! 895: * Tag only -- the library will supply the event time ! 896: * paramVector[0] = kMyTagValue; ! 897: * [scsiDevice getIntValues ! 898: * : paramVector ! 899: * forParameter : "StoreTimestamp" ! 900: * count : 1 ! 901: * ]; ! 902: * Tag plus value: ! 903: * paramVector[0] = kMyTagValue; ! 904: * paramVector[1] = 123456; ! 905: * [scsiDevice getIntValues ! 906: * : paramVector ! 907: * forParameter : "StoreTimestamp" ! 908: * count : 2 ! 909: * ]; ! 910: * Tag plus value + time: ! 911: * paramVector[0] = kMyTagValue; ! 912: * paramVector[1] = 123456; ! 913: * IOGetTimestamp( (ns_time_t*)¶mVector[2] ); ! 914: * [scsiDevice getIntValues ! 915: * : paramVector ! 916: * forParameter : "StoreTimestamp" ! 917: * count : 4 ! 918: * ]; ! 919: * Note that you can combine tag only with tag plus value plus time to measure ! 920: * user->device latency. ! 921: */ ! 922: ! 923: #endif APPLE_MESH_ENABLE_GET_SET ! 924: ! 925: @end ! 926: ! 927: ! 928: ! 929: @interface AppleMesh_SCSI( Hardware ) ! 930: ! 931: - InitializeHardware : deviceDescription; ! 932: - (IOReturn) ResetHardware : (Boolean)resetSCSIBus; ! 933: - (HardwareStartResult) hardwareStart : (CommandBuffer*)cmdBuf; ! 934: ! 935: @end ! 936: ! 937: ! 938: /* These macros are used to access words (32 bit) and bytes (8 bit) in */ ! 939: /* the channel command area. They may be used as source or destination. */ ! 940: /* CCLDescriptor is aligned to a descriptor start, CCLAddress is just */ ! 941: /* an address pointer. */ ! 942: #define CCLAddress(offset) (((UInt8*)cclLogAddr) + (offset)) ! 943: #define CCLDescriptor(offset) ((DBDMADescriptor*)CCLAddress(offset)) ! 944: #define CCLWord(offset) (*((UInt32*)CCLAddress(offset))) ! 945: #define CCLByte(offset) (*((UInt8*)CCLAddress(offset))) ! 946: ! 947: @interface AppleMesh_SCSI ( HardwarePrivate ) ! 948: ! 949: - (IOReturn) AllocHdwAndChanMem : deviceDescription; ! 950: - (void) InitAutosenseCCL; ! 951: - (void) UpdateCP : (Boolean) reselecting; ! 952: - (void) StartBucket; ! 953: - (void) SetupMsgO; ! 954: - (void) ClearCPResults; ! 955: - (void) InitCP; ! 956: ! 957: @end ! 958: ! 959: @interface AppleMesh_SCSI( MeshInterrupt ) ! 960: ! 961: - (void) DoHardwareInterrupt; /* Respond to an Interrupt Service message. */ ! 962: - (void) ProcessInterrupt; ! 963: - (void) DoInterruptStageArb; ! 964: - (void) DoInterruptStageSelA; ! 965: - (void) DoInterruptStageMsgO; ! 966: - (void) DoInterruptStageCmdO; ! 967: - (void) DoInterruptStageXfer; ! 968: - (void) DoInterruptStageXferAutosense; ! 969: - (void) DoInterruptStageGood; ! 970: - (IOReturn) DoMessageInPhase; /* Handle MSGI phase. */ ! 971: - (void) ProcessMSGI; ! 972: - (void) HandleReselectionInterrupt; /* Process a reselection interrupt. */ ! 973: - (Boolean) getReselectionTargetID; ! 974: ! 975: @end ! 976: ! 977: ! 978: /* SCSI command status (from status phase) */ ! 979: ! 980: #define kScsiStatusGood 0x00 /* Normal completion */ ! 981: #define kScsiStatusCheckCondition 0x02 /* Need GetExtendedStatus */ ! 982: #define kScsiStatusConditionMet 0x04 ! 983: #define kScsiStatusBusy 0x08 /* Device busy (self-test?) */ ! 984: #define kScsiStatusIntermediate 0x10 /* Intermediate status */ ! 985: #define kScsiStatusIntermediateMet 0x14 /* Intermediate cond. met */ ! 986: #define kScsiStatusResConflict 0x18 /* Reservation conflict */ ! 987: #define kScsiStatusTerminated 0x22 /* Command Terminated */ ! 988: #define kScsiStatusQueueFull 0x28 /* Target can't do command */ ! 989: #define kScsiStatusReservedMask 0x3E /* Vendor specific? */ ! 990: ! 991: /* SCSI command codes. Commands defined as ...6, ...10, ...12, are */ ! 992: /* six-byte, ten-byte, and twelve-byte variants of the indicated command. */ ! 993: ! 994: /* These commands are supported for all devices. */ ! 995: ! 996: #define kScsiCmdChangeDefinition 0x40 ! 997: #define kScsiCmdCompare 0x39 ! 998: #define kScsiCmdCopy 0x18 ! 999: #define kScsiCmdCopyAndVerify 0x3A ! 1000: #define kScsiCmdInquiry 0x12 ! 1001: #define kScsiCmdLogSelect 0x4C ! 1002: #define kScsiCmdLogSense 0x4D ! 1003: #define kScsiCmdModeSelect12 0x55 ! 1004: #define kScsiCmdModeSelect6 0x15 ! 1005: #define kScsiCmdModeSense12 0x5A ! 1006: #define kScsiCmdModeSense6 0x1A ! 1007: #define kScsiCmdReadBuffer 0x3C ! 1008: #define kScsiCmdRecvDiagResult 0x1C ! 1009: #define kScsiCmdRequestSense 0x03 ! 1010: #define kScsiCmdSendDiagnostic 0x1D ! 1011: #define kScsiCmdTestUnitReady 0x00 ! 1012: #define kScsiCmdWriteBuffer 0x3B ! 1013: ! 1014: /* These commands are supported by direct-access devices only: */ ! 1015: ! 1016: #define kScsiCmdFormatUnit 0x04 ! 1017: #define kSCSICmdCopy 0x18 ! 1018: #define kSCSICmdCopyAndVerify 0x3A ! 1019: #define kScsiCmdLockUnlockCache 0x36 ! 1020: #define kScsiCmdPrefetch 0x34 ! 1021: #define kScsiCmdPreventAllowRemoval 0x1E ! 1022: #define kScsiCmdRead6 0x08 ! 1023: #define kScsiCmdRead10 0x28 ! 1024: #define kScsiCmdReadCapacity 0x25 ! 1025: #define kScsiCmdReadDefectData 0x37 ! 1026: #define kScsiCmdReadLong 0x3E ! 1027: #define kScsiCmdReassignBlocks 0x07 ! 1028: #define kScsiCmdRelease 0x17 ! 1029: #define kScsiCmdReserve 0x16 ! 1030: #define kScsiCmdRezeroUnit 0x01 ! 1031: #define kScsiCmdSearchDataEql 0x31 ! 1032: #define kScsiCmdSearchDataHigh 0x30 ! 1033: #define kScsiCmdSearchDataLow 0x32 ! 1034: #define kScsiCmdSeek6 0x0B ! 1035: #define kScsiCmdSeek10 0x2B ! 1036: #define kScsiCmdSetLimits 0x33 ! 1037: #define kScsiCmdStartStopUnit 0x1B ! 1038: #define kScsiCmdSynchronizeCache 0x35 ! 1039: #define kScsiCmdVerify 0x2F ! 1040: #define kScsiCmdWrite6 0x0A ! 1041: #define kScsiCmdWrite10 0x2A ! 1042: #define kScsiCmdWriteAndVerify 0x2E ! 1043: #define kScsiCmdWriteLong 0x3F ! 1044: #define kScsiCmdWriteSame 0x41 ! 1045: ! 1046: /* These commands are supported by sequential devices: */ ! 1047: ! 1048: #define kScsiCmdRewind 0x01 ! 1049: #define kScsiCmdWriteFilemarks 0x10 ! 1050: #define kScsiCmdSpace 0x11 ! 1051: #define kScsiCmdLoadUnload 0x1B ! 1052: ! 1053: /* ANSI SCSI-II for CD-ROM devices. */ ! 1054: #define kScsiCmdReadCDTableOfContents 0x43 ! 1055: ! 1056: /* Message codes (for Msg In and Msg Out phases). */ ! 1057: ! 1058: #define kScsiMsgAbort 0x06 ! 1059: #define kScsiMsgAbortTag 0x0D ! 1060: #define kScsiMsgBusDeviceReset 0x0C ! 1061: #define kScsiMsgClearQueue 0x0E ! 1062: #define kScsiMsgCmdComplete 0x00 ! 1063: #define kScsiMsgDisconnect 0x04 ! 1064: #define kScsiMsgIdentify 0x80 ! 1065: #define kScsiMsgIdentifyLUNMask 0x07 /* LUN bits in Identify message */ ! 1066: #define kScsiMsgIgnoreWideResdue 0x23 ! 1067: #define kScsiMsgInitiateRecovery 0x0F ! 1068: #define kScsiMsgInitiatorDetectedErr 0x05 ! 1069: #define kScsiMsgLinkedCmdComplete 0x0A ! 1070: #define kScsiMsgLinkedCmdCompleteFlag 0x0B ! 1071: #define kScsiMsgParityErr 0x09 ! 1072: #define kScsiMsgRejectMsg 0x07 ! 1073: #define kScsiMsgModifyDataPtr 0x00 /* Extended msg */ ! 1074: #define kScsiMsgNop 0x08 ! 1075: #define kScsiMsgHeadOfQueueTag 0x21 /* Two byte msg */ ! 1076: #define kScsiMsgOrderedQueueTag 0x22 /* Two byte msg */ ! 1077: #define kScsiMsgSimpleQueueTag 0x20 /* Two byte msg */ ! 1078: #define kScsiMsgReleaseRecovery 0x10 ! 1079: #define kScsiMsgRestorePointers 0x03 ! 1080: #define kScsiMsgSaveDataPointers 0x02 ! 1081: #define kScsiMsgSyncXferReq 0x01 /* Extended msg */ ! 1082: #define kScsiMsgWideDataXferReq 0x03 /* Extended msg */ ! 1083: #define kScsiMsgTerminateIOP 0x11 ! 1084: #define kScsiMsgExtended 0x01 ! 1085: #define kScsiMsgEnableDisconnectMask 0x40 ! 1086: ! 1087: #define kScsiMsgOneByteMin 0x02 ! 1088: #define kScsiMsgOneByteMax 0x1F ! 1089: #define kScsiMsgTwoByteMin 0x20 ! 1090: #define kScsiMsgTwoByteMax 0x2F ! 1091: ! 1092: ! 1093: ! 1094: /* These methods bang on the MESH chip. */ ! 1095: /* Many should be redone as inline functions. */ ! 1096: ! 1097: @interface AppleMesh_SCSI( Mesh ) ! 1098: ! 1099: - (IOReturn) ResetMESH : (Boolean) resetSCSIBus; ! 1100: - (IOReturn) DoHBASelfTest; ! 1101: - (IOReturn) WaitForMesh : (Boolean) clearInterrupts; ! 1102: - (IOReturn) WaitForReq; ! 1103: - (void) SetSeqReg : (MeshCommand) meshCommand; ! 1104: - (void) RunDBDMA : (UInt32) offset stageLabel : (UInt32) stageLabel; ! 1105: - (void) GetHBARegsAndClear : (Boolean) clearInts; ! 1106: - (void) SetIntMask : (UInt8) interruptMask; ! 1107: - (void) AbortActiveCommand; ! 1108: - (void) AbortDisconnectedCommand; ! 1109: ! 1110: - (void) logTimestamp : (const char*) reason; ! 1111: ! 1112: @end ! 1113: ! 1114: ! 1115: @interface AppleMesh_SCSI( Private ) ! 1116: ! 1117: /* Send a command to the controller thread, and wait for its completion. */ ! 1118: /* Only invoked by publicly exported methods in SCSIController.m. */ ! 1119: ! 1120: - (IOReturn) executeCmdBuf : (CommandBuffer*) cmdBuf; ! 1121: ! 1122: /* Abort all active and disconnected commands with specified status. */ ! 1123: /* No hardware action. Used by threadResetBus and during processing */ ! 1124: /* of a kCommandAbortRequest command. */ ! 1125: - (void) abortAllCommands : (sc_status_t) status; ! 1126: ! 1127: /* IO thread version of resetSCSIBus and executeRequest. */ ! 1128: - (void) threadResetBus : (const char*) reason; ! 1129: ! 1130: ! 1131: - (void) threadExecuteRequest : (CommandBuffer*) cmdBuf; ! 1132: ! 1133: /* Methods called by other modules in this driver: */ ! 1134: ! 1135: /* Called when a transaction associated with cmdBuf is complete. Notify ! 1136: * waiting thread. If cmdBuf->scsiReq exists (i.e., this is not a reset ! 1137: * or an abort), scsiReq->driverStatus must be valid. If cmdBuf is activeCmd, ! 1138: * caller must remove from activeCmd. ! 1139: */ ! 1140: - (void) ioComplete : (CommandBuffer*) cmdBuf; ! 1141: ! 1142: /* A target reported a full queue. Push this command back on the pending ! 1143: * queue and try it again, later. (Return SR_IOST_GOOD if successful, ! 1144: * SR_IOST_BADST on failure. ! 1145: */ ! 1146: - (sc_status_t) pushbackFullTargetQueue : (CommandBuffer*) cmdBuf; ! 1147: ! 1148: /* A command couldn't be issued (because a target is trying to reselect ! 1149: * us or we lost arbitration for some other reason). Push this request ! 1150: * onto the front of the pending request queue. ! 1151: */ ! 1152: - (void) pushbackCurrentRequest : (CommandBuffer*) cmdBuf; ! 1153: ! 1154: /* A command can't be continued. Perhaps there is no target. */ ! 1155: - (void) killCurrentRequest; ! 1156: ! 1157: /* IO associated with activeCmd has disconnected. Place it */ ! 1158: /* on disconnectQ and enable another transaction. */ ! 1159: - (void) disconnect; ! 1160: ! 1161: /* Specified target, lun, and queueTag is trying to reselect. If we have ! 1162: * a CommandBuffer for this TLQ nexus on disconnectQ, remove it, make it the ! 1163: * current activeCmd, and return YES. Else return NO. ! 1164: * A value of zero for queueTag indicates a nontagged command (zero is never ! 1165: * used as the queue tag value for a tagged command). ! 1166: */ ! 1167: - (IOReturn) reselectNexus : (UInt8) target ! 1168: lun : (UInt8) lun ! 1169: queueTag : (UInt8) queueTag; ! 1170: - (Boolean) commandCanBeStarted : (CommandBuffer*) cmdBuf; ! 1171: - (void) selectNextRequest; /* Choose the next request that can be started. */ ! 1172: - (void) killActiveCommand : (sc_status_t) status; // mlj added ! 1173: - (void) activateCommand : (CommandBuffer*) cmdBuf; ! 1174: - (void) deactivateCmd : (CommandBuffer*) cmdBuf; ! 1175: ! 1176: /* Kill everything in the indicated queue. Called after bus reset. */ ! 1177: - (void) killQueue : (queue_head_t*)queuePtr finalStatus : (sc_status_t)scsiStatus; ! 1178: - (void) UpdateCurrentIndex; ! 1179: ! 1180: @end ! 1181: ! 1182: #if USE_ELG && CustomMiniMon ! 1183: /* for debugging: */ ! 1184: extern void EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str ); ! 1185: extern void Pause( UInt32 a, UInt32 b, UInt32 ascii, char* str ); ! 1186: extern void AllocateEventLog( UInt32 ); // defined in miniMon ! 1187: #endif /* NotMiniMon */ ! 1188: extern void call_kdp(); // for debugging ! 1189: ! 1190: ! 1191: /* Usage: ! 1192: * 1. In the makefile (or elsewhere), define TIMESTAMP non-zero. If zero, this ! 1193: * code will be stubbed out. ! 1194: * 2. In your initialization routine, call MakeTimestampRecord() to create a ! 1195: * timestamp record. This will be stored in a static, private, variable. ! 1196: * 3. When you want to time something, call StoreTimestamp() as follows: ! 1197: * { ! 1198: * ns_time_t eventTime; ! 1199: * IOGetTimestamp(&eventTime); ! 1200: * StoreTimestamp(timestampTag, timestampValue, eventTime); ! 1201: * } ! 1202: * Where timestampTag and timestampValue are 32-bit unsigned integers ! 1203: * that are not otherwise interpreted by the Timestamp library. By ! 1204: * convention, timestampTag contains a 4-byte character (Macintosh OSType) ! 1205: * that distinguishes timing events. The OSType and OSTag macros ! 1206: * can be used to construct tag values. OSTag is useful for recording ! 1207: * elapsed time: ! 1208: * StoreTimestamp(OSTag('+', "foo"), 0, startTime); ! 1209: * ... ! 1210: * StoreTimestamp(OSTag('-', "foo"), 0, endTime); ! 1211: */ ! 1212: ! 1213: ! 1214: //#ifndef TIMESTAMP ! 1215: #define TIMESTAMP 0 // mlj - resolve dup symbols with Curio /* TEMP TEMP TEMP */ ! 1216: //#endif ! 1217: ! 1218: /* Construct an OSType from four characters. */ ! 1219: #define OSType(c0, c1, c2, c3) ( \ ! 1220: ( ((c0) << 24) \ ! 1221: | ((c1) << 16) \ ! 1222: | ((c2) << 8) \ ! 1223: | ((c3) << 0) )) ! 1224: /* Construct an OSType from a single character and the */ ! 1225: /* first three characters from a given string. */ ! 1226: #define OSTag(where, what) (OSType((where), (what)[0], (what)[1], (what)[2])) ! 1227: ! 1228: /* ._______________________________________________________________________________. ! 1229: | Each timestamp entry contains the following information: | ! 1230: | timestampTag A user-specified OSType that identifies this timestamp | ! 1231: | timestampValue A user-specified additional value | ! 1232: | eventTime The system UpTime value at the time the data was collected. | ! 1233: ._______________________________________________________________________________. ! 1234: */ ! 1235: struct TimestampDataRecord ! 1236: { ! 1237: OSType timestampTag; /* Caller's tag parameter */ ! 1238: UInt32 timestampValue; /* Caller's value parameter */ ! 1239: ns_time_t eventTime; /* UpTime() at Timestamp call */ ! 1240: }; ! 1241: typedef struct TimestampDataRecord TimestampDataRecord, *TimestampDataPtr; ! 1242: ! 1243: #if TIMESTAMP /* (( */ ! 1244: void MakeTimestampRecord( UInt32 nEntries ); ! 1245: void StoreTimestamp( OSType timestampTag, ! 1246: UInt32 timestampValue, ! 1247: ns_time_t timestampEvent ); ! 1248: /** ! 1249: * Returns the next timestamp, if any, in resultData. ! 1250: * @param resultData Where to store the data ! 1251: * @return TRUE Valid data returned ! 1252: * FALSE No data is available. ! 1253: */ ! 1254: Boolean ReadTimestamp( TimestampDataPtr resultData ); ! 1255: /** ! 1256: * Return a vector of timestamps. ! 1257: * @param resultVector Where to store the data ! 1258: * @param count On entrance, this has the maximum number of elements ! 1259: * to return. On exit, this will have the actual number ! 1260: * of elements that were returned. ! 1261: * Note that, if the semaphore is blocked, ReadTimestampVector will not return any ! 1262: * data. Data cannot be collected while ReadTimestampVector is copying data ! 1263: * to the user's buffer. Note that, since the user's buffer will typically be ! 1264: * in pageable memory, pageing I/O that might otherwise be timestamped will ! 1265: * be lost. ! 1266: */ ! 1267: void ReadTimestampVector( TimestampDataPtr resultVector, UInt32 *count ); /* -> Max count, <-actual */ ! 1268: Boolean EnableTimestamp( Boolean enableTimestamp ); ! 1269: Boolean PreserveTimestamp( Boolean preserveFirst ); ! 1270: void ResetTimestampIndex(void); ! 1271: UInt32 GetTimestampSemaphoreLostCounter( void ); ! 1272: #else /* )( not TIMESTAMP: */ ! 1273: #define MakeTimestampRecord( nEntries ) /* Nothing */ ! 1274: #define StoreTimestamp( timestampTag, timestampValue, timestampEvent ) /* Nothing */ ! 1275: #define ReadTimestamp(resultData) (0) /* Fails */ ! 1276: #define ReadTimestampVector(resultVector, count) \ ! 1277: do { if ( count ) { *(count) = 0; } } while (0) ! 1278: #define EnableTimestamp( enableTimestamp ) (enableTimestamp) ! 1279: #define PreserveTimestamp( preserveFirst ) (preserveFirst) ! 1280: #define ResetTimestampIndex() /* Nothing */ ! 1281: #define GetTimestampSemaphoreLostCount() (0) ! 1282: #endif /* )) */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.