|
|
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 1993-1995 by Apple Computer, 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: * Accessor functions for the 53C96 registers and commands. ! 32: * As noted above, the class provides an instance variable defined as: ! 33: * volatile UInt8 *gSCSILogicalAddress The chip's LogicalAddress ! 34: * ! 35: * Set tabs every 4 characters. ! 36: * Edit History ! 37: * 1997.02.13 MM Initial conversion from AMDPCSCSIDriver sources. ! 38: * 1997.07.18 MM Added USE_CURIO_METHODS and wrote macros for the ! 39: * one-liner methods. ! 40: */ ! 41: ! 42: #import "Apple96CurioPrivate.h" ! 43: #import "Apple96CurioPublic.h" ! 44: #import "Apple96CurioDBDMA.h" ! 45: #import "MacSCSICommand.h" ! 46: #import <driverkit/generalFuncs.h> ! 47: #import <kernserv/prototypes.h> ! 48: ! 49: extern IONamedValue gAutomatonStateValues[]; ! 50: ! 51: @implementation Apple96_SCSI(Curio) ! 52: ! 53: /* ! 54: * This spin-loop looks for another chip operation - it prevents ! 55: * exiting the interrupt service routine if the chip presents ! 56: * another operation within ten microseconds. Note that this ! 57: * must be called from an IOThread, not from a "real" primary ! 58: * interrupt service routine. ! 59: */ ! 60: - (Boolean) curioQuickCheckForChipInterrupt ! 61: { ! 62: ns_time_t startTime; ! 63: ns_time_t endTime; ! 64: unsigned elapsedNSec; ! 65: Boolean result; ! 66: ! 67: ENTRY("Cin curioQuickCheckForChipInterrupt"); ! 68: IOGetTimestamp(&startTime); ! 69: result = FALSE; ! 70: do { ! 71: if (CURIOinterruptPending()) { ! 72: result = TRUE; ! 73: break; ! 74: } ! 75: IOGetTimestamp(&endTime); ! 76: elapsedNSec = (unsigned) (endTime - startTime); ! 77: } while (elapsedNSec < 10000U); ! 78: RESULT(result); ! 79: return (result); ! 80: } ! 81: ! 82: /* ! 83: * Determine if SCSI interrupt is pending. If so, store the current ! 84: * chip state. Note that reading the interrupt register clears the ! 85: * interrupt source, so this should be done once for each interrupt. ! 86: */ ! 87: - (Boolean) curioInterruptPending ! 88: { ! 89: UInt8 chipStatus; ! 90: Boolean result = FALSE; ! 91: ! 92: ! 93: ENTRY( "Cip curioInterruptPending" ); ! 94: ! 95: /* mlj - use WHILE to check for double interrupts */ ! 96: /* and get get most recent conditions. */ ! 97: while (((chipStatus = CURIOreadStatusRegister()) & sIntPend) != 0) ! 98: { ! 99: result = TRUE; ! 100: gSaveStatus = chipStatus; ! 101: gSaveSeqStep = CURIOreadSequenceStateRegister(); ! 102: gSaveInterrupt = CURIOreadInterruptRegister(); ! 103: } ! 104: RESULT( result ); ! 105: return result; ! 106: }/* end curioInterruptPending */ ! 107: ! 108: ! 109: /* ! 110: * Store the current command into the fifo. If this is an autosense, ! 111: * store a REQUEST SENSE command. ! 112: */ ! 113: - (void) curioPutCommandIntoFifo ! 114: { ! 115: IOSCSIRequest *scsiReq; ! 116: UInt32 i; ! 117: ! 118: ENTRY("Cpc curioPutCommandIntoFifo"); ! 119: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL); ! 120: scsiReq = gActiveCommand->scsiReq; ! 121: if (gActiveCommand->flagIsAutosense) { ! 122: UInt32 actualAutosenseTransferLength; ! 123: /* ! 124: * This should be provided by the client (and checked that it is ! 125: * less than or equal to kMaxAutosenseByteCount). Note that this ! 126: * sequence is duplicated in Apple96HWPrivate.m. ! 127: */ ! 128: actualAutosenseTransferLength = (sizeof (esense_reply_t) < kMaxAutosenseByteCount) ! 129: ? (sizeof (esense_reply_t)) : kMaxAutosenseByteCount; ! 130: ASSERT(actualAutosenseTransferLength <= 255); ! 131: /* ! 132: * Put the autosense command into the fifo. ! 133: */ ! 134: CURIOputByteIntoFifo(kScsiCmdRequestSense); ! 135: CURIOputByteIntoFifo(scsiReq->lun << 5); ! 136: CURIOputByteIntoFifo(0); ! 137: CURIOputByteIntoFifo(0); ! 138: CURIOputByteIntoFifo(actualAutosenseTransferLength); ! 139: CURIOputByteIntoFifo(0); ! 140: } ! 141: else { ! 142: /* ! 143: * Put the original command into the fifo. ! 144: */ ! 145: for (i = 0; i < gActiveCommand->cdbLength; i++) { ! 146: CURIOputByteIntoFifo(((UInt8 *) &scsiReq->cdb)[i]); ! 147: } ! 148: } ! 149: EXIT(); ! 150: } ! 151: ! 152: /* ! 153: * Reset the chip to hardware power on state. ! 154: */ ! 155: - (void) curioResetChip ! 156: { ! 157: ENTRY("Crc curioResetChip"); ! 158: CURIOsetCommandRegister(cRstSChp); /* Reset chip */ ! 159: IODelay(50); /* Chip settle */ ! 160: CURIOnop(); /* Re-enable chip */ ! 161: CURIOflushFifo(); /* In a clean state */ ! 162: EXIT(); ! 163: } ! 164: ! 165: /** ! 166: * The caller (hardwareReset and the bus reset interrupt handler) must delay for 250 msec ! 167: * after resetting the bus or detecting a bus reset. This serves two purposes: "The 53C96 ! 168: * needs a vacation of about 100 msec after a reset otherwise it gets cranky" -- according ! 169: * to notes in HALc96.c. Also, some devices don't respond if we issue another command too ! 170: * quickly after bus reset. ! 171: */ ! 172: - (void) curioResetSCSIBus ! 173: { ! 174: ENTRY("Crb curioResetSCSIBus"); ! 175: SynchronizeIO(); ! 176: CURIOsetCommandRegister(cRstSBus); ! 177: EXIT(); ! 178: } ! 179: ! 180: #if USE_CURIO_METHODS ! 181: /* ! 182: * These are stub methods that implement the exact same code as ! 183: * the inline macros. ! 184: */ ! 185: ! 186: /** ! 187: * Retrieve the status register. This can be done without disturbing ! 188: * the chip operation state. ! 189: */ ! 190: - (UInt8) curioReadStatusRegister ! 191: { ! 192: return (__CURIOreadStatusRegister()); ! 193: } ! 194: ! 195: /** ! 196: * Retrieve the internal state register. This is done after an interrupt. ! 197: */ ! 198: - (UInt8) curioReadSequenceStateRegister ! 199: { ! 200: return (__CURIOreadSequenceStateRegister()); ! 201: } ! 202: ! 203: /** ! 204: * Retrieve the interrupt register. This is done after an interrupt. ! 205: * Note: reading this register "releases" the chip. Registers must ! 206: * be read in the following order: ! 207: * 1. Status (skip the rest if the interrupt bit is clear) ! 208: * 2. SequenceStep ! 209: * 3. Interrupt ! 210: */ ! 211: - (UInt8) curioReadInterruptRegister ! 212: { ! 213: return (__CURIOreadInterruptRegister()); ! 214: } ! 215: ! 216: /** ! 217: * The target is in MSGI phase. Start the transfer. ! 218: */ ! 219: - (void) curioStartMSGIAction ! 220: { ! 221: __CURIOstartMSGIAction(); ! 222: } ! 223: ! 224: /** ! 225: * CurioNop is a temporizing command to give the chip time to stabalize ! 226: * its internal registers. ! 227: */ ! 228: - (void) curioNop ! 229: { ! 230: __CURIOnop(); /* Restart the chip */ ! 231: } ! 232: ! 233: /** ! 234: * Start a byte-by-byte transfer that does not involve the DMA subsystem. ! 235: */ ! 236: - (void) curioStartNonDMATransfer ! 237: { ! 238: __CURIOstartNonDMATransfer(); /* Start a non-DMA transfer */ ! 239: } ! 240: ! 241: /** ! 242: * Start a DMA transfer. ! 243: */ ! 244: - (void) curioStartDMATransfer ! 245: : (UInt32) transferCount ! 246: { ! 247: ENTRY("Cds curioStartDMATransfer"); ! 248: __CURIOstartDMATransfer(transferCount); ! 249: EXIT(); ! 250: } ! 251: ! 252: - (void) curioTransferPad ! 253: : (Boolean) forOutput ! 254: { ! 255: __CURIOtransferPad(forOutput); ! 256: } ! 257: ! 258: /** ! 259: * CurioClearTransferCountZeroBit ! 260: * This is called after DMA transfers to stabalize the DMA and clear its fifo. ! 261: * It is needed to keep the process alive in the following sequence: ! 262: * DATO Start DMA transfer to the target ! 263: * MSGI Target changes to message in in order to disconnect. ! 264: */ ! 265: - (void) curioClearTransferCountZeroBit ! 266: { ! 267: __CURIOclearTransferCountZeroBit(); /* Clear TC zero bit */ ! 268: } ! 269: ! 270: /** ! 271: * Return the current transfer count. This is generally zero after DMA, but will be ! 272: * non-zero if some data was not transferred. ! 273: */ ! 274: - (UInt32) curioGetTransferCount ! 275: { ! 276: UInt32 result; ! 277: ! 278: ENTRY("Cgt curioGetTransferCount"); ! 279: result = __CURIOgetTransferCount(); ! 280: RESULT(result); ! 281: return (result); ! 282: } ! 283: ! 284: /** ! 285: * Load the target destination id register. ! 286: */ ! 287: - (void) curioSetDestinationID ! 288: : (UInt8) targetID ! 289: { ! 290: __CURIOsetDestinationID(targetID); ! 291: } ! 292: ! 293: /** ! 294: * Start an initiator-initiated command-complete sequence. ! 295: */ ! 296: - (void) curioInitiatorCommandComplete ! 297: { ! 298: __CURIOinitiatorCommandComplete(); ! 299: } ! 300: ! 301: /** ! 302: * The bus is (presumably) free: allow us to be reselected. ! 303: */ ! 304: - (void) curioEnableSelectionOrReselection ! 305: { ! 306: __CURIOenableSelectionOrReselection(); ! 307: } ! 308: ! 309: /** ! 310: * Disconnect from the SCSI bus. ! 311: */ ! 312: - (void) curioDisconnect ! 313: { ! 314: __CURIOdisconnect(); ! 315: } ! 316: ! 317: ! 318: /** ! 319: * Manipulate the FIFO ! 320: * CurioGetFifoByte Return the current fifo byte. ! 321: * CurioPutByteIntoFifo Store a byte into the fifo ! 322: * CurioFlushFifo Clear the fifo ! 323: * CurioGetFifoCount Get the number of bytes in the fifo. ! 324: * Note: the fifo only holds 16 bytes. For some reason, ! 325: * we ignore the 0x10 bit (follows Copland DR1 debugging). ! 326: */ ! 327: - (UInt8) curioGetFifoByte ! 328: { ! 329: return (__CURIOgetFifoByte()); ! 330: } ! 331: ! 332: - (void) curioPutByteIntoFifo ! 333: : (UInt8) theByte ! 334: { ! 335: __CURIOputByteIntoFifo(theByte); ! 336: } ! 337: ! 338: - (void) curioFlushFifo ! 339: { ! 340: __CURIOflushFifo(); ! 341: } ! 342: ! 343: - (UInt32) curioGetFifoCount ! 344: { ! 345: return (__CURIOgetFifoCount()); ! 346: } ! 347: ! 348: /** ! 349: * Configure the 53C96 chip. ! 350: */ ! 351: - (void) curioSetSelectionTimeout ! 352: : (UInt8) selectionTimeout ! 353: { ! 354: __CURIOsetSelectionTimeout(selectionTimeout); ! 355: } ! 356: ! 357: - (void) curioConfigForNonDMA ! 358: { ! 359: __CURIOconfigForNonDMA(); ! 360: } ! 361: ! 362: - (void) curioConfigForDMA ! 363: { ! 364: __CURIOconfigForDMA(); ! 365: } ! 366: ! 367: /** ! 368: * Manage Message Phase ! 369: */ ! 370: - (void) curioMessageAccept ! 371: { ! 372: __CURIOmessageAccept(); ! 373: } ! 374: ! 375: - (void) curioMessageReject ! 376: { ! 377: __CURIOmessageReject(); ! 378: } ! 379: ! 380: - (void) curioSetATN ! 381: { ! 382: __CURIOsetATN(); ! 383: } ! 384: ! 385: - (void) curioClearATN ! 386: { ! 387: __CURIOclearATN(); ! 388: } ! 389: ! 390: ! 391: /* ! 392: * Sync negotiation methods ! 393: * To do: don't load a register if its shadow has the same value.. ! 394: */ ! 395: - (void) curioSetSynchronousOffset ! 396: : (UInt8) synchronousOffset ! 397: { ! 398: __CURIOsetSynchronousOffset(synchronousOffset); ! 399: } ! 400: ! 401: - (void) curioSetSynchronousPeriod ! 402: : (UInt8) synchronousPeriod ! 403: { ! 404: __CURIOsetSynchronousPeriod(synchronousPeriod); ! 405: } ! 406: ! 407: /** ! 408: * Write a random register (used for configuration registers) ! 409: */ ! 410: - (void) curioWriteRegister ! 411: : (UInt8) curioRegister ! 412: value : (UInt8) value ! 413: { ! 414: __CURIOwriteRegister(curioRegister, value); ! 415: } ! 416: ! 417: /** ! 418: * Read a random register (used for configuration registers) ! 419: */ ! 420: - (UInt8) curioReadRegister ! 421: : (UInt8) curioRegister ! 422: { ! 423: return (__CURIOreadRegister(curioRegister)); ! 424: } ! 425: ! 426: /** ! 427: * This is the only place that the command register is written. ! 428: */ ! 429: - (void) curioSetCommandRegister ! 430: : (UInt8) commandByte ! 431: { ! 432: __CURIOsetCommandRegister(commandByte); ! 433: } ! 434: ! 435: /** ! 436: * Error recovery needs to peek at the last command ! 437: */ ! 438: - (UInt8) curioReadCommandRegister ! 439: { ! 440: return (__CURIOreadCommandRegister()); ! 441: } ! 442: ! 443: /* ! 444: * Convert the selection timeout to the value that must be stored in the ! 445: * chip registers. ! 446: */ ! 447: - (UInt32) curioSelectTimeout ! 448: : (UInt32) selectTimeoutMSec ! 449: curioClockMHz : (UInt32) chipClockRateMHz ! 450: curioClockFactor : (UInt32) chipClockFactor ! 451: { ! 452: return ( ! 453: __CURIOsetSelectTimeout( ! 454: selectTimeoutMSec, ! 455: chipClockRateMHz, ! 456: chipClockFactor) ! 457: ); ! 458: } ! 459: #endif /* USE_CURIO_METHODS */ ! 460: ! 461: @end /* Apple96_SCSI(Curio) */ ! 462: ! 463: #if USE_CURIO_METHODS || WRITE_CHIP_OPERATION_INTO_TIMESTAMP_LOG ! 464: volatile UInt8 ! 465: __CurioReadRegister__( ! 466: volatile UInt8 *scsiLogicalAddress, ! 467: UInt32 index ! 468: ) ! 469: { ! 470: volatile UInt8 result = scsiLogicalAddress[index]; ! 471: const char *why; ! 472: const char *what; ! 473: switch (index) { ! 474: case rXCL: what = "XCL"; break; ! 475: case rXCM: what = "XCM"; break; ! 476: case rFFO: what = "FFO"; break; ! 477: case rCMD: what = "CMD"; break; ! 478: case rSTA: what = "STA"; break; ! 479: case rINT: what = "INT"; break; ! 480: case rSQS: what = "SQS"; break; ! 481: case rFOS: what = "FOS"; break; ! 482: case rCF1: what = "CF1"; break; ! 483: case rCKF: what = "CKF"; break; ! 484: case rTST: what = "TST"; break; ! 485: case rCF2: what = "CF2"; break; ! 486: case rCF3: what = "CF3"; break; ! 487: case rCF4: what = "CF4"; break; ! 488: case rTCH: what = "TCH"; break; ! 489: case rDMA: what = "DMA"; break; ! 490: default: what = "?\?\?"; break; ! 491: } ! 492: RAW_TAG(OSTag('<', what), (index << 8) | result); ! 493: return (result); ! 494: } ! 495: ! 496: void ! 497: __CurioWriteRegister__( ! 498: volatile UInt8 *scsiLogicalAddress, ! 499: UInt32 index, ! 500: UInt8 value ! 501: ) ! 502: { ! 503: const char *what; ! 504: switch (index) { ! 505: case rXCL: what = "XCL"; break; ! 506: case rXCM: what = "XCM"; break; ! 507: case rFFO: what = "FFO"; break; ! 508: case rCMD: what = "CMD"; break; ! 509: case rSTA: what = "DST"; break; ! 510: case rINT: what = "TMO"; break; ! 511: case rSQS: what = "SQS"; break; ! 512: case rFOS: what = "FOS"; break; ! 513: case rCF1: what = "CF1"; break; ! 514: case rCKF: what = "CKF"; break; ! 515: case rTST: what = "TST"; break; ! 516: case rCF2: what = "CF2"; break; ! 517: case rCF3: what = "CF3"; break; ! 518: case rCF4: what = "CF4"; break; ! 519: case rTCH: what = "TCH"; break; ! 520: case rDMA: what = "DMA"; break; ! 521: default: what = "?\?\?"; break; ! 522: } ! 523: RAW_TAG(OSTag('>', what), (index << 8) | value); ! 524: scsiLogicalAddress[index] = value; ! 525: } ! 526: #endif /* USE_CURIO_METHODS */ ! 527:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.