|
|
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: * Copyright (c) 1994-1996 NeXT Software, Inc. All rights reserved. ! 27: * Copyright 1997 Apple Computer Inc. All Rights Reserved. ! 28: * @author Martin Minow mailto:[email protected] ! 29: * @revision 1997.02.13 Initial conversion from AMDPCSCSIDriver sources. ! 30: * ! 31: * Apple96SCSI.h - top-level API for Apple 53C96 (Curio/DBDMA) SCSI adaptor. ! 32: * Apple96SCSI is closely based on Doug Mitchell's AMD 53C974/79C974 driver. ! 33: * ! 34: * Edit History ! 35: * 1997.02.13 MM Initial conversion from AMDPCSCSIDriver sources. ! 36: * 1997.03.24 MM Normalized against AppleMeshSCSI.h ! 37: * 1997.11.12 MM Added support for scatter-gather lists. ! 38: */ ! 39: #define APPLE96_ALWAYS_ASSERT 0 ! 40: #define APPLE96_ENABLE_GET_SET 1 ! 41: #define VERY_SERIOUS_DEBUGGING 0 /* Log each method entry and exit */ ! 42: #define SERIOUS_DEBUGGING 0 /* Log command, buffer, etc operation */ ! 43: #define LOG_COMMAND_AND_RESULT 0 /* Log command and results */ ! 44: #define LOG_ERROR_RECOVERY 0 /* Log during error recovery */ ! 45: #define LOG_RESULT_ON_ERROR 0 /* Log all errors, even expected ones */ ! 46: #define DUMP_USER_BUFFER 0 /* Set to buffer length to dump */ ! 47: #define TIMESTAMP_AT_IOCOMPLETE 0 ! 48: /* ! 49: * Radar 2005639. Tell SCSIDisk how many threads to create. ! 50: */ ! 51: #define MAX_CLIENT_THREADS 1 /* Ask SCSIDisk to create threads */ ! 52: #define ENABLE_DISCONNECT FALSE /* TEMP TEMP TEMP */ ! 53: #define ENABLE_TAGGED_QUEUEING FALSE /* TEMP TEMP TEMP */ ! 54: // #define USE_CURIO_METHODS 1 /* TEMP TEMP TEMP */ ! 55: #define USE_CURIO_METHODS 0 /* Default to inline */ ! 56: #define WRITE_CHIP_OPERATION_INTO_TIMESTAMP_LOG 1 ! 57: #define APPLE96_ENABLE_GET_SET 1 /* Enable management ioctl's */ ! 58: #ifndef VERY_SERIOUS_DEBUGGING ! 59: #define VERY_SERIOUS_DEBUGGING 0 ! 60: #endif ! 61: #ifndef USE_CURIO_METHODS ! 62: #define USE_CURIO_METHODS 0 ! 63: #endif ! 64: #ifndef WRITE_CHIP_OPERATION_INTO_TIMESTAMP_LOG ! 65: #define WRITE_CHIP_OPERATION_INTO_TIMESTAMP_LOG 0 ! 66: #endif ! 67: #ifndef APPLE96_ALWAYS_ASSERT ! 68: #define APPLE96_ALWAYS_ASSERT 0 ! 69: #endif ! 70: #if VERY_SERIOUS_DEBUGGING ! 71: #undef SERIOUS_DEBUGGING ! 72: #define SERIOUS_DEBUGGING 1 ! 73: #endif ! 74: #ifndef SERIOUS_DEBUGGING ! 75: #define SERIOUS_DEBUGGING 0 ! 76: #endif ! 77: #ifndef LOG_COMMAND_AND_RESULT ! 78: #define LOG_COMMAND_AND_RESULT 0 ! 79: #endif ! 80: #ifndef LOG_ERROR_RECOVERY ! 81: #define LOG_ERROR_RECOVERY 0 ! 82: #endif ! 83: #ifndef TIMESTAMP_AT_IOCOMPLETE ! 84: #define TIMESTAMP_AT_IOCOMPLETE 0 ! 85: #endif ! 86: #ifndef MAX_CLIENT_THREADS ! 87: #define MAX_CLIENT_THREADS 6 /* Radar 2005639 */ ! 88: #endif ! 89: ! 90: #undef NDEBUG /* Enable ASSERT macro */ ! 91: ! 92: #import <driverkit/IODirectDevice.h> ! 93: #import <driverkit/IOSCSIController.h> ! 94: #import <driverkit/scsiTypes.h> ! 95: #import <driverkit/IOPower.h> ! 96: #import "Apple96Types.h" ! 97: #import "Apple96Curio.h" ! 98: #import "Apple96DBDMADefs.h" ! 99: #import "Timestamp.h" ! 100: #import "Apple96DDM.h" ! 101: ! 102: @interface Apple96_SCSI : IOSCSIController <IOPower> ! 103: { ! 104: /* ! 105: * These globals locate the hardware interface registers in logical and physical ! 106: * address spaces. ! 107: */ ! 108: PhysicalAddress gSCSIPhysicalAddress; /* -> NCR registers (physical) */ ! 109: volatile UInt8 *gSCSILogicalAddress; /* -> NCR registers (logical) */ ! 110: UInt32 gSCSIRegisterLength; /* == Size of NCR registers */ ! 111: ! 112: PhysicalAddress gDBDMAPhysicalAddress; /* -> DBDMA registers (physical) */ ! 113: DBDMAChannelRegisters *gDBDMALogicalAddress; /* -> DBDMA registers (logical) */ ! 114: UInt32 gDBDMARegisterLength; /* == Size of DBDMA registers */ ! 115: ! 116: PhysicalAddress gDBDMAChannelAddress; /* -> DBDMA channel area (physical) */ ! 117: DBDMADescriptor *gChannelCommandArea; /* -> DBDMA channel area (logical) */ ! 118: UInt32 gChannelCommandAreaSize; /* == DBDMA channel allocated size */ ! 119: UInt32 gDBDMADescriptorMax; /* Number of DATA descriptors */ ! 120: ! 121: UInt32 gPageSize; /* Logical page size */ ! 122: UInt32 gPageMask; /* Logical page size - 1 */ ! 123: ! 124: /* ! 125: * Autosense I/O requests write into this permanently-allocated area. Then, we copy ! 126: * the sense data to the caller's SCSI command parameter block. The autosense area ! 127: * is at the end of the descriptor area. ! 128: */ ! 129: esense_reply_t *gAutosenseArea; /* -> Autosense area (logical) */ ! 130: PhysicalAddress gAutosenseAddress; /* Used to autosense DMA */ ! 131: ! 132: /* ! 133: * This is the message port that the kernel uses to signal hardware interrupts. ! 134: */ ! 135: port_t gKernelInterruptPort; ! 136: ! 137: /* ! 138: * Commands are passed from exported methods to the I/O thread ! 139: * via gIncomingCommandQueue, which is protected by gIncomingCommandLock. ! 140: * ! 141: * Commands which are disconnected but not complete are kept ! 142: * in gDisconnectedCommandQueue. ! 143: * ! 144: * Commands which have been dequeued from gIncomingCommandQueue by the ! 145: * I/O thread but which have not been started because a command is currently ! 146: * active on the bus are kept in gPendingCommandQueue. This queue also ! 147: * holds commands pushed back when we lose arbitration. ! 148: * ! 149: * The currently active command, if any, is kept in gActiveCommand. ! 150: * Only commandBufs with op == kCommandExecute are ever placed in ! 151: * gActiveCommand. ! 152: */ ! 153: queue_head_t gIncomingCommandQueue; ! 154: id gIncomingCommandLock; /* NXLock for gIncomingCommandQueue */ ! 155: queue_head_t gPendingCommandQueue; ! 156: queue_head_t gDisconnectedCommandQueue; ! 157: /* ! 158: * This is the command we're currently execution. If NULL, the Macintosh is idle ! 159: * (or all commands are disconnected). Normally, gCurrentTarget and gCurrentLUN ! 160: * track the values in the active command's associated SCSI request. They are set ! 161: * to kInvalidTarget and kInvalidLUN at initialization, command deactivation, ! 162: * command complete, and command disconnect. They are set to valid values (with no ! 163: * active command) during reselection. This is tricky, so look carefully at the code. ! 164: */ ! 165: CommandBuffer *gActiveCommand; /* -> The currently executing command */ ! 166: UInt32 gCurrentTarget; /* == The current target bus ID */ ! 167: UInt32 gCurrentLUN; /* == The current target LUN */ ! 168: ! 169: /* ! 170: * Global option flags, accessible via instance table or setIntValues. Note: some of ! 171: * these are intended for debugging. However, users may need to disable command ! 172: * queuing, synchronous, or fast to handle device or bus limitations. The ! 173: * architecture-specific initialization "looks" at the device to determine whether ! 174: * specific features (such as synchronous) are supported. ! 175: * gOptionAutoSenseEnable Debug only, normally set ! 176: * gOptionCmdQueueEnable Enable tagged queuing. ! 177: * gOptionSyncModeEnable Enable synchronous transfers (clear if problems) ! 178: * gOptionFastModeEnable Enable fast transfers (clear if problems) ! 179: * gOptionDisconnectEnable Debug only, normally set. ! 180: * gOptionExtendTiming Extended selection timing (debug, unused) ! 181: * gOptionSyncModeSupportedByHardware Set if this NCR chip supports synchronous. ! 182: * gOptionFastModeSupportedByHardware Set if this NCR chip supports fast mode. ! 183: * gFlagIOThreadRunning Set when I/O thread is initialized. Needed ! 184: * for shutdown. ! 185: * gFlagBusBusy Set in the state machine when we are apparently ! 186: * connected to a target (even for target selection). ! 187: * Cleared in the interrupt service routine on ! 188: * a disconnected or bus reset interrupt state. ! 189: * gFlagCheckForAnotherInterrupt Set in the interrupt service routine on ! 190: * entrance to the bus finite-state automaton. ! 191: * Automaton functions clear this to force an ! 192: * exit from the ISR when it expects a long bus ! 193: * operation. ! 194: */ ! 195: unsigned gOptionAutoSenseEnable : 1, ! 196: gOptionCmdQueueEnable : 1, ! 197: gOptionSyncModeEnable : 1, ! 198: gOptionFastModeEnable : 1, ! 199: gOptionExtendTiming : 1, ! 200: gOptionDisconnectEnable : 1, ! 201: gOptionSyncModeSupportedByHardware : 1, ! 202: gOptionFastModeSupportedByHardware : 1, ! 203: gFlagIOThreadRunning : 1, /* Set at init */ ! 204: gFlagBusBusy : 1, ! 205: gFlagCheckForAnotherInterrupt : 1, /* Loop through ISR */ ! 206: gFlagNeedAnotherInterrupt : 1, /* mikej */ ! 207: pad : 20; ! 208: UInt32 scsiClockRate; /* in MHz */ ! 209: ! 210: /* ! 211: * Array of active I/O counters, one counter per lun per target. If command ! 212: * queueing is disabled, the max value of each counter is 1. gActiveCount is ! 213: * the sum of all elements in activeArray. ! 214: */ ! 215: UInt8 gActiveArray[SCSI_NTARGETS][SCSI_NLUNS]; ! 216: UInt32 gActiveCount; ! 217: ! 218: /* ! 219: * These variables change during SCSI I/O operation. ! 220: */ ! 221: BusState gBusState; /* The overall state automaton */ ! 222: /* ! 223: * These variables manage Message In bus phase. Because the message in handler ! 224: * uses programmed I/O, gMsgInCount, gMsgInIndex, and gMsgInState are actually ! 225: * local variables to the message reader, and are here for debugging convenience. ! 226: */ ! 227: signed int gMsgInCount; /* Message bytes still to read */ ! 228: MsgInState gMsgInState; /* How are we handling messages */ ! 229: UInt32 gMsgInIndex; /* -> free spot in gMsgInBuffer */ ! 230: UInt8 gMsgInBuffer[kMessageInBufferLength]; ! 231: /* ! 232: * These variables manage Message Out bus phase. To send a message, ! 233: * write it into the buffer, starting at gMsgOutSendIndex and set ATN. ! 234: * When the target enters Message Out phase, write the bytes into the ! 235: * NCR fifo starting at gMsgOutStoreIndex. When the transfer completes ! 236: * with MSG parity error, use the residual count to "back up" gMsgOutSendIndex ! 237: * to resend the message. ! 238: */ ! 239: UInt8 *gMsgOutPtr; /* -> free spot in gMsgOutBuffer */ ! 240: UInt8 *gMsgPutPtr; /* -> next byte to send */ ! 241: UInt8 gMsgOutBuffer[kMessageOutBufferLength]; ! 242: UInt8 gLastMsgOut[2]; /* Has last message out specifier */ ! 243: /* ! 244: * Hardware related variables ! 245: */ ! 246: UInt8 gInitiatorID; /* Our SCSI ID */ ! 247: UInt8 gInitiatorIDMask; /* BusID bitmask for selection */ ! 248: // UInt8 gSelectionTimeout; /* In MESH 10 msec units */ ! 249: UInt32 gClockFrequency; /* For selection timeout */ ! 250: ! 251: /* ! 252: * commandBuf->queueTag for next I/O. This is never zero; for all requests ! 253: * involving a T/L/Q nexus, a queue tag of zero indicates a nontagged command. ! 254: */ ! 255: UInt8 gNextQueueTag; ! 256: ! 257: /* ! 258: * Shadow current chip values. ! 259: * gSaveStatus rSTA register at last interrupt. ! 260: * gSaveSeqStep rSQS register at last interrupt ! 261: * gSaveInterrupt rINT register at last interrupt. ! 262: * gCurrentBusPhase The last bus phase (for error recovery) ! 263: * gLastSelectionTimeout Last selection timeout we stored in Curio ! 264: * gLastSynchronousOffset Last synchronous offset we stored in Curio. ! 265: * gLastSynchronousPeriod Last synchronous perioud we stored in Curio. ! 266: */ ! 267: UInt8 gSaveStatus; ! 268: UInt8 gSaveSeqStep; ! 269: UInt8 gSaveInterrupt; ! 270: UInt8 gCurrentBusPhase; /* Last known SCSI phase */ ! 271: UInt8 gLastSelectionTimeout; /* Chip selection timeout */ ! 272: UInt8 gLastSynchronousOffset; /* Synchronous transfer offset */ ! 273: UInt8 gLastSynchronousPeriod; /* Synchronous period shadow */ ! 274: /* ! 275: * Per-target information. ! 276: */ ! 277: PerTargetData gPerTargetData[SCSI_NTARGETS]; ! 278: ! 279: /* ! 280: * Statistics support. ! 281: */ ! 282: UInt32 gMaxQueueLen; ! 283: UInt32 gQueueLenTotal; ! 284: UInt32 gTotalCommands; ! 285: } ! 286: ! 287: /** ! 288: * Public methods ! 289: */ ! 290: /** ! 291: * Initialize the SCSI driver. ! 292: */ ! 293: + (Boolean) probe : deviceDescription; ! 294: /** ! 295: * Shutdown the driver. ! 296: */ ! 297: - free; ! 298: ! 299: /* ! 300: * Execute a SCSI request using a single logical address range. ! 301: * This is compatible with earlier DriverKit implementations. ! 302: * @param scsiReq The SCSI request command record, including the ! 303: * target device and LUN, the command to execute, ! 304: * and various control flags. ! 305: * @param buffer The data buffer, if any. This may be NULL if ! 306: * no data phase is expected. ! 307: * @param client The client task that "owns" the memory buffer. ! 308: * @return Return a bus adaptor specific error status. ! 309: */ ! 310: - (sc_status_t) executeRequest : (IOSCSIRequest *) scsiReq ! 311: buffer : (void *) buffer ! 312: client : (vm_task_t) client; ! 313: ! 314: /* ! 315: * Execute a SCSI request using an IOMemoryDescriptor. This allows callers to ! 316: * provide (kernel-resident) logical scatter-gather lists. For compatibility ! 317: * with existing implementations, the low-level SCSI device driver must first ! 318: * ensure that executeRequest:ioMemoryDescriptor is supported by executing: ! 319: * [controller respondsToSelector : executeRequest:ioMemoryDescriptor] ! 320: * @param scsiReq The SCSI request command record, including the ! 321: * target device and LUN, the command to execute, ! 322: * and various control flags. ! 323: * @param ioMemoryDescriptor The data buffer(s), if any. This may be NULL if ! 324: * no data phase is expected. ! 325: * @param client The client task that "owns" the memory buffer. ! 326: * @return Return a bus adaptor specific error status. ! 327: */ ! 328: - (sc_status_t) executeRequest ! 329: : (IOSCSIRequest *) scsiReq ! 330: ioMemoryDescriptor : (IOMemoryDescriptor *) ioMemoryDescriptor; ! 331: ! 332: - (sc_status_t) resetSCSIBus; ! 333: ! 334: /** ! 335: * Reset the SCSI bus. ! 336: */ ! 337: - (sc_status_t) resetSCSIBus; ! 338: /** ! 339: * Reset statistics buffers. ! 340: */ ! 341: - (void) resetStats; ! 342: ! 343: - (unsigned) numQueueSamples; ! 344: ! 345: - (unsigned) sumQueueLengths; ! 346: ! 347: - (unsigned) maxQueueLength; ! 348: ! 349: /** ! 350: * interruptOccurred is a public method called by the I/O ! 351: * thread in IODirectDevice when an interrupt occurs. ! 352: */ ! 353: - (void) interruptOccurred; ! 354: ! 355: /** ! 356: * timeoutOccurred is a public method called by the I/O ! 357: * thread in IODirectDevice when it receives a timeout ! 358: * message. ! 359: */ ! 360: - (void) timeoutOccurred; ! 361: ! 362: #if APPLE96_ENABLE_GET_SET ! 363: ! 364: - (IOReturn) setIntValues : (unsigned *)parameterArray ! 365: forParameter : (IOParameterName)parameterName ! 366: count : (unsigned)count; ! 367: - (IOReturn) getIntValues : (unsigned *)parameterArray ! 368: forParameter : (IOParameterName)parameterName ! 369: count : (unsigned *)count; // in/out ! 370: /* ! 371: * get/setIntValues parameters. ! 372: */ ! 373: #define APPLE96_AUTOSENSE "AutoSense" ! 374: #define APPLE96_CMD_QUEUE "CmdQueue" ! 375: #define APPLE96_SYNC "Synchronous" ! 376: #define APPLE96_FAST_SCSI "FastSCSI" ! 377: #define APPLE96_RESET_TARGETS "ResetTargets" ! 378: #define APPLE96_RESET_TIMESTAMP "ResetTimestamp" ! 379: #define APPLE96_ENABLE_TIMESTAMP "EnableTimestamp" ! 380: #define APPLE96_DISABLE_TIMESTAMP "DisableTimestamp" ! 381: #define APPLE96_PRESERVE_FIRST_TIMESTAMP "PreserveFirstTimestamp" ! 382: #define APPLE96_PRESERVE_LAST_TIMESTAMP "PreserveLastTimestamp" ! 383: #define APPLE96_READ_TIMESTAMP "ReadTimestamp" ! 384: #define APPLE96_STORE_TIMESTAMP "StoreTimestamp" ! 385: /* ! 386: * Radar 2005639. Tell SCSIDisk how many threads to create. ! 387: * Allow access to the enable disconnect option. ! 388: */ ! 389: #define APPLE96_ENABLE_DISCONNECT "EnableDisconnect" ! 390: #define APPLE_MAX_THREADS "ClientThreads" ! 391: ! 392: /* ! 393: * Recording and setting timestamps may be done using getIntValues (this permits ! 394: * access from non-privileged tasks. ! 395: * ResetTimestamp Clear the timestamp vector - do this before starting ! 396: * a sequence (no parameters) ! 397: * EnableTimestamp Start recording (no parameters) (default) ! 398: * DisableTimestamp Stop recording (no parameters) ! 399: * PreserveFirstTimestamp Stop recording when the buffer fills (until it is emptied) ! 400: * PreserveLastTimestamp Discard old values when new arrive (default) ! 401: * ReadTimestamp Read a vector of timestamps (see sample below) ! 402: * StoreTimestamp Store a timestamp (from user mode) (see sample below) ! 403: * ReadTimestamp copies timestamps from the internal database to user-specified vector. ! 404: * Because getIntValues parameters are defined in int units, the code is slighthly ! 405: * non-obvious: ! 406: * TimestampDataRecord myTimestamps[123]; ! 407: * unsigned count; ! 408: * count = sizeof (myTimestamps) / sizeof (unsigned); ! 409: * [scsiDevice getIntValues ! 410: * : (unsigned int *) myTimestamps ! 411: * forParameter : APPLE96_READ_TIMESTAMP ! 412: * count : &count ! 413: * ]; ! 414: * count = (count * sizeof (unsigned)) / sizeof (TimestampDataRecord); ! 415: * for (i = 0; i < count; i++) { ! 416: * Process(myTimestamps[i]); ! 417: * } ! 418: * Applications can store timestamps using one of three parameter formats: ! 419: * unsigned paramVector[4]; ! 420: * Tag only -- the library will supply the event time ! 421: * paramVector[0] = kMyTagValue; ! 422: * [scsiDevice getIntValues ! 423: * : paramVector ! 424: * forParameter : "StoreTimestamp" ! 425: * count : 1 ! 426: * ]; ! 427: * Tag plus value: ! 428: * paramVector[0] = kMyTagValue; ! 429: * paramVector[1] = 123456; ! 430: * [scsiDevice getIntValues ! 431: * : paramVector ! 432: * forParameter : "StoreTimestamp" ! 433: * count : 2 ! 434: * ]; ! 435: * Tag plus value + time: ! 436: * paramVector[0] = kMyTagValue; ! 437: * paramVector[1] = 123456; ! 438: * IOGetTimestamp((ns_time_t *) ¶mVector[2]); ! 439: * [scsiDevice getIntValues ! 440: * : paramVector ! 441: * forParameter : "StoreTimestamp" ! 442: * count : 4 ! 443: * ]; ! 444: * Note that you can combine tag only with tag plus value plus time to measure ! 445: * user->device latency. ! 446: */ ! 447: ! 448: #endif /* APPLE96_ENABLE_GET_SET */ ! 449: ! 450: @end ! 451: ! 452:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.