|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: ! 23: /* Sym8xxExecute.m created by russb2 on Sat 30-May-1998 */ ! 24: ! 25: #include "Sym8xxController.h" ! 26: ! 27: extern "C" ! 28: { ! 29: unsigned int ml_phys_read( vm_offset_t paddr ); ! 30: }; ! 31: ! 32: #if 0 ! 33: static UInt32 dropInt = 0; ! 34: #endif ! 35: ! 36: void Sym8xxSCSIController::Sym8xxStartSRB( SRB *srb ) ! 37: { ! 38: ! 39: srb->nexus.targetParms.scntl3Reg = adapter->targetClocks[srb->target].scntl3Reg; ! 40: srb->nexus.targetParms.sxferReg = adapter->targetClocks[srb->target].sxferReg; ! 41: ! 42: adapter->nexusPtrsVirt[srb->nexus.tag] = &srb->nexus; ! 43: adapter->nexusPtrsPhys[srb->nexus.tag] = (Nexus *)OSSwapHostToLittleInt32( (UInt32)&srb->srbPhys->nexus ); ! 44: adapter->schedMailBox[mailBoxIndex++] = (Nexus *)OSSwapHostToLittleInt32 ( (UInt32)&srb->srbPhys->nexus ); ! 45: ! 46: Sym8xxSignalScript( srb ); ! 47: } ! 48: ! 49: ! 50: /*-----------------------------------------------------------------------------* ! 51: * Interrupts from the Symbios chipset are dispatched here at task time under the ! 52: * IOThread's context. ! 53: *-----------------------------------------------------------------------------*/ ! 54: void Sym8xxSCSIController::interruptOccurred( IOInterruptEventSource *ies, int intCount ) ! 55: { ! 56: do ! 57: { ! 58: /* ! 59: * The chipset's ISTAT reg gives us the general interrupting condiditions, ! 60: * with DSTAT and SIST providing more detailed information. ! 61: */ ! 62: istatReg = Sym8xxReadRegs( chipBaseAddr, ISTAT, ISTAT_SIZE ); ! 63: ! 64: /* The INTF bit in ISTAT indicates that the script is signalling the driver ! 65: * that its IODone mailbox is full and that we should process a completed ! 66: * request. The script continues to run after posting this interrupt unlike ! 67: * other chipset interrupts which require the driver to restart the script ! 68: * engine. ! 69: */ ! 70: if ( istatReg & INTF ) ! 71: { ! 72: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, istatReg ); ! 73: #if 0 ! 74: if ( dropInt++ > 100 ) ! 75: { ! 76: dropInt = 0; ! 77: SCRIPT_VAR(R_ld_IOdone_mailbox) = 0; ! 78: continue; ! 79: } ! 80: #endif ! 81: Sym8xxProcessIODone(); ! 82: } ! 83: ! 84: /* ! 85: * Handle remaining interrupting conditions ! 86: */ ! 87: if ( istatReg & (SIP | DIP) ) ! 88: { ! 89: Sym8xxProcessInterrupt(); ! 90: } ! 91: } ! 92: while ( istatReg & (SIP | DIP | INTF) ); ! 93: ! 94: getWorkLoop()->enableAllInterrupts(); ! 95: ! 96: } ! 97: ! 98: /*-----------------------------------------------------------------------------* ! 99: * Process a request posted in the script's IODone mailbox. ! 100: * ! 101: *-----------------------------------------------------------------------------*/ ! 102: void Sym8xxSCSIController::Sym8xxProcessIODone() ! 103: { ! 104: SRB *srb; ! 105: Nexus *nexus; ! 106: IODoneMailBox *pMailBox; ! 107: ! 108: ! 109: /* ! 110: * The IODone mailbox contains an index into our Nexus pointer tables. ! 111: * ! 112: * The Nexus struct is part of the SRB so we can get our SRB address ! 113: * by subtracting the offset of the Nexus struct in the SRB. ! 114: */ ! 115: pMailBox = (IODoneMailBox *)&SCRIPT_VAR(R_ld_IOdone_mailbox); ! 116: nexus = adapter->nexusPtrsVirt[pMailBox->nexus]; ! 117: srb = (SRB *)((UInt32)nexus - offsetof(SRB, nexus)); ! 118: ! 119: srb->srbSCSIStatus = pMailBox->status; ! 120: ! 121: if ( srb->srbSCSIStatus == kSCSIStatusCheckCondition ) ! 122: { ! 123: Sym8xxCheckRequestSense( srb ); ! 124: } ! 125: ! 126: if ( srb->srbSCSIResult == kIOReturnSuccess ) ! 127: { ! 128: if ( srb->srbSCSIStatus != kSCSIStatusGood ) ! 129: { ! 130: srb->srbSCSIResult = kIOReturnIOError; ! 131: } ! 132: } ! 133: ! 134: Sym8xxUpdateXferOffset( srb ); ! 135: ! 136: /* ! 137: * Clear the completed Nexus pointer from our tables and clear the ! 138: * IODone mailbox. ! 139: */ ! 140: adapter->nexusPtrsVirt[pMailBox->nexus] = (Nexus *) -1; ! 141: adapter->nexusPtrsPhys[pMailBox->nexus] = (Nexus *) -1; ! 142: SCRIPT_VAR(R_ld_IOdone_mailbox) = 0; ! 143: ! 144: /* ! 145: * Wake up the client's thread to do post-processing ! 146: */ ! 147: Sym8xxCompleteSRB( srb ); ! 148: ! 149: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase]; ! 150: } ! 151: /*-----------------------------------------------------------------------------* ! 152: * ! 153: * ! 154: *-----------------------------------------------------------------------------*/ ! 155: void Sym8xxSCSIController::Sym8xxCompleteSRB( SRB *srb ) ! 156: { ! 157: IOSCSICommand *scsiCommand; ! 158: SCSIResults scsiResults; ! 159: ! 160: scsiCommand = srb->scsiCommand; ! 161: ! 162: bzero( &scsiResults, sizeof(scsiResults) ); ! 163: ! 164: scsiResults.returnCode = srb->srbSCSIResult; ! 165: ! 166: if ( srb == abortSRB ) ! 167: { ! 168: abortSRB = 0; ! 169: if ( abortReqPending == true ) ! 170: { ! 171: abortReqPending = false; ! 172: enableCommands(); ! 173: } ! 174: } ! 175: else ! 176: { ! 177: scsiResults.bytesTransferred = srb->xferDone; ! 178: scsiResults.scsiStatus = srb->srbSCSIStatus; ! 179: } ! 180: ! 181: scsiCommand->setResults( &scsiResults ); ! 182: scsiCommand->complete(); ! 183: } ! 184: ! 185: /*-----------------------------------------------------------------------------* ! 186: * General script interrupt processing ! 187: * ! 188: *-----------------------------------------------------------------------------*/ ! 189: void Sym8xxSCSIController::Sym8xxProcessInterrupt() ! 190: { ! 191: SRB *srb = NULL; ! 192: Nexus *nexus = NULL; ! 193: UInt32 nexusIndex; ! 194: UInt32 scriptPhase; ! 195: UInt32 fifoCnt = 0; ! 196: UInt32 dspsReg = 0; ! 197: UInt32 dspReg = 0; ! 198: ! 199: ! 200: /* ! 201: * Read DSTAT/SIST regs to determine why the script stopped. ! 202: */ ! 203: dstatReg = Sym8xxReadRegs( chipBaseAddr, DSTAT, DSTAT_SIZE ); ! 204: IODelay(5); ! 205: sistReg = Sym8xxReadRegs( chipBaseAddr, SIST, SIST_SIZE ); ! 206: ! 207: // printf( "SCSI(Symbios8xx): SIST = %04x DSTAT = %02x\n\r", sistReg, dstatReg ); ! 208: ! 209: /* ! 210: * This Script var tells us what the script thinks it was doing when the interrupt occurred. ! 211: */ ! 212: scriptPhase = OSSwapHostToLittleInt32( SCRIPT_VAR(R_ld_phase_flag) ); ! 213: ! 214: /* ! 215: * SCSI Bus reset detected ! 216: * ! 217: * Clean up the carnage. ! 218: * Note: This may be either an adapter or target initiated reset. ! 219: */ ! 220: if ( sistReg & RSTI ) ! 221: { ! 222: Sym8xxProcessSCSIBusReset(); ! 223: return; ! 224: } ! 225: ! 226: /* ! 227: * Calculate our current SRB/Nexus. ! 228: * ! 229: * Read a script var to determine the index of the nexus it was processing ! 230: * when the interrupt occurred. The script will invalidate the index if there ! 231: * is no target currently connected or the script cannot determine which target ! 232: * has reconnected. ! 233: */ ! 234: nexusIndex = OSSwapHostToLittleInt32(SCRIPT_VAR(R_ld_nexus_index)); ! 235: if ( nexusIndex >= MAX_SCSI_TAG ) ! 236: { ! 237: Sym8xxProcessNoNexus(); ! 238: return; ! 239: } ! 240: nexus = adapter->nexusPtrsVirt[nexusIndex]; ! 241: if ( nexus == (Nexus *) -1 ) ! 242: { ! 243: Sym8xxProcessNoNexus(); ! 244: return; ! 245: } ! 246: srb = (SRB *)((UInt32)nexus - offsetof(SRB, nexus)); ! 247: ! 248: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_phase_handler]; ! 249: ! 250: /* ! 251: * Parity and SCSI Gross Errors. ! 252: * ! 253: * Abort the current connection. The abort completion will trigger ! 254: * clean-up of the current SRB/Nexus. ! 255: */ ! 256: if ( sistReg & PAR ) ! 257: { ! 258: srb->srbSCSIResult = kIOReturnIOError; ! 259: Sym8xxAbortCurrent( srb ); ! 260: } ! 261: ! 262: else if ( sistReg & SGE ) ! 263: { ! 264: Sym8xxAbortCurrent( srb ); ! 265: } ! 266: ! 267: /* ! 268: * Unexpected disconnect. ! 269: * ! 270: * If we were currently trying to abort this connection then mark the abort ! 271: * as completed. For all cases clean-up and wake-up the client thread. ! 272: */ ! 273: else if ( sistReg & UDC ) ! 274: { ! 275: if ( srb->srbSCSIResult == kIOReturnSuccess ) ! 276: { ! 277: srb->srbSCSIResult = kIOReturnAborted; ! 278: } ! 279: adapter->nexusPtrsVirt[nexusIndex] = (Nexus *) -1; ! 280: adapter->nexusPtrsPhys[nexusIndex] = (Nexus *) -1; ! 281: ! 282: if ( scriptPhase == A_kphase_ABORT_CURRENT ) ! 283: { ! 284: abortCurrentSRB = NULL; ! 285: } ! 286: ! 287: Sym8xxCompleteSRB( srb ); ! 288: ! 289: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase]; ! 290: } ! 291: ! 292: /* ! 293: * Phase Mis-match ! 294: * ! 295: * If we are in MsgOut phase then calculate how much of the message we sent. For ! 296: * now, however, we dont handle the target rejecting messages, so the request is aborted. ! 297: * ! 298: * If we are in DataIn/DataOut phase. We update the SRB/Nexus with our current data ! 299: * pointers. ! 300: */ ! 301: else if ( sistReg & MA ) ! 302: { ! 303: if ( scriptPhase == A_kphase_MSG_OUT ) ! 304: { ! 305: srb->srbMsgResid = Sym8xxCheckFifo( srb, &fifoCnt ); ! 306: nexus->msg.ppData = OSSwapHostToLittleInt32( OSSwapHostToLittleInt32(nexus->msg.ppData) ! 307: + OSSwapHostToLittleInt32(nexus->msg.length) ! 308: - srb->srbMsgResid ); ! 309: nexus->msg.length = OSSwapHostToLittleInt32( srb->srbMsgResid ); ! 310: ! 311: Sym8xxAbortCurrent( srb ); ! 312: } ! 313: else if ( (scriptPhase == A_kphase_DATA_OUT) || (scriptPhase == A_kphase_DATA_IN) ) ! 314: { ! 315: Sym8xxAdjustDataPtrs( srb, nexus ); ! 316: } ! 317: else ! 318: { ! 319: IOLog("SCSI(Symbios8xx): Unexpected phase mismatch - scriptPhase = %08x\n\r", (int)scriptPhase); ! 320: Sym8xxAbortCurrent( srb ); ! 321: } ! 322: ! 323: Sym8xxClearFifo(); ! 324: } ! 325: ! 326: /* ! 327: * Selection Timeout. ! 328: * ! 329: * Clean-up the current request. ! 330: */ ! 331: else if ( sistReg & STO ) ! 332: { ! 333: srb->srbSCSIResult = kIOReturnOffline; ! 334: ! 335: adapter->nexusPtrsVirt[nexusIndex] = (Nexus *) -1; ! 336: adapter->nexusPtrsPhys[nexusIndex] = (Nexus *) -1; ! 337: SCRIPT_VAR(R_ld_IOdone_mailbox) = 0; ! 338: ! 339: Sym8xxCompleteSRB( srb ); ! 340: ! 341: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase]; ! 342: } ! 343: ! 344: /* ! 345: * Handle script initiated interrupts ! 346: */ ! 347: else if ( dstatReg & SIR ) ! 348: { ! 349: dspsReg = Sym8xxReadRegs( chipBaseAddr, DSPS, DSPS_SIZE ); ! 350: ! 351: // printf( "SCSI(Symbios8xx): DSPS = %08x\n\r", dspsReg ); ! 352: ! 353: switch ( dspsReg ) ! 354: { ! 355: /* ! 356: * Non-zero SCSI status ! 357: * ! 358: * Send request sense CDB or complete request depending on SCSI status value ! 359: */ ! 360: case A_status_error: ! 361: Sym8xxProcessIODone(); ! 362: break; ! 363: ! 364: /* ! 365: * Received SDTR/WDTR message from target. ! 366: * ! 367: * Prepare reply message if we requested negotiation. Otherwise reject ! 368: * target initiated negotiation. ! 369: */ ! 370: case A_negotiateSDTR: ! 371: Sym8xxNegotiateSDTR( srb, nexus ); ! 372: break; ! 373: ! 374: case A_negotiateWDTR: ! 375: Sym8xxNegotiateWDTR( srb, nexus ); ! 376: break; ! 377: ! 378: /* ! 379: * Partial SG List completed. ! 380: * ! 381: * Refresh the list from the remaining addresses to be transfered and set the ! 382: * script engine to branch into the list. ! 383: */ ! 384: case A_sglist_complete: ! 385: Sym8xxUpdateSGList( srb ); ! 386: scriptRestartAddr = (UInt32)&srb->srbPhys->nexus.sgListData[2]; ! 387: break; ! 388: ! 389: /* ! 390: * Completed abort request ! 391: * ! 392: * Clean-up the aborted request. ! 393: */ ! 394: case A_abort_current: ! 395: adapter->nexusPtrsVirt[nexusIndex] = (Nexus *) -1; ! 396: adapter->nexusPtrsPhys[nexusIndex] = (Nexus *) -1; ! 397: ! 398: abortCurrentSRB = NULL; ! 399: ! 400: Sym8xxCompleteSRB( srb ); ! 401: ! 402: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase]; ! 403: break; ! 404: ! 405: /* ! 406: * Script detected protocol errors ! 407: * ! 408: * Abort the current request. ! 409: */ ! 410: case A_unknown_msg_reject: ! 411: case A_unknown_phase: ! 412: case A_unexpected_msg: ! 413: case A_unexpected_ext_msg: ! 414: srb->srbSCSIResult = kIOReturnAborted; ! 415: Sym8xxAbortCurrent( srb ); ! 416: break; ! 417: ! 418: default: ! 419: IOLog( "SCSI(Symbios8xx): Unknown Script Int = %08x\n\r", (int)dspsReg ); ! 420: Sym8xxAbortCurrent( srb ); ! 421: } ! 422: } ! 423: ! 424: /* ! 425: * Illegal script instruction. ! 426: * ! 427: * We're toast! Abort the current request and hope for the best! ! 428: */ ! 429: else if ( dstatReg & IID ) ! 430: { ! 431: dspReg = Sym8xxReadRegs( chipBaseAddr, DSP, DSP_SIZE ); ! 432: ! 433: IOLog("SCSI(Symbios8xx): Illegal script instruction - dsp = %08x srb=%08x\n\r", (int)dspReg, (int)srb ); ! 434: ! 435: Sym8xxAbortCurrent( srb ); ! 436: } ! 437: ! 438: if ( scriptRestartAddr ) ! 439: { ! 440: Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr ); ! 441: } ! 442: } ! 443: ! 444: ! 445: /*-----------------------------------------------------------------------------* ! 446: * Current Data Pointer calculations ! 447: * ! 448: * To do data transfers the driver generates a list of script instructions ! 449: * in system storage to deliver data to the requested physical addresses. The ! 450: * script branches to the list when the target enters data transfer phase. ! 451: * ! 452: * When the target changes phase during a data transfer, data is left trapped ! 453: * inside the various script engine registers. This routine determines how much ! 454: * data was not actually transfered to/from the target and generates a new ! 455: * S/G List entry for the partial transfer and a branch back into the original ! 456: * S/G list. These script instructions are stored in two reserved slots at the ! 457: * top of the original S/G List. ! 458: * ! 459: *-----------------------------------------------------------------------------*/ ! 460: void Sym8xxSCSIController::Sym8xxAdjustDataPtrs( SRB *srb, Nexus *nexus ) ! 461: { ! 462: UInt32 i; ! 463: UInt32 sgResid; ! 464: UInt32 fifoCnt; ! 465: UInt32 dspReg; ! 466: UInt32 sgDone; ! 467: UInt8 scntl2Reg; ! 468: Nexus *nexusPhys; ! 469: ! 470: /* ! 471: * Determine SG element residual ! 472: * ! 473: * This routine returns how much of the current S/G List element the ! 474: * script was processing remains to be sent/received. All the information ! 475: * required to do this is stored in the script engine's registers. ! 476: */ ! 477: sgResid = Sym8xxCheckFifo( srb, &fifoCnt ); ! 478: ! 479: /* ! 480: * Determine which script instruction in our SGList we were executing when ! 481: * the target changed phase. ! 482: * ! 483: * The script engine's dspReg tells us where the script thinks it was. Based ! 484: * on the physical address of our current SRB/Nexus we can calculate ! 485: * an index into our S/G List. ! 486: */ ! 487: dspReg = Sym8xxReadRegs( chipBaseAddr, DSP, DSP_SIZE ); ! 488: ! 489: i = ((dspReg - (UInt32)srb->srbPhys->nexus.sgListData) / sizeof(SGEntry)) - 1; ! 490: ! 491: if ( i > MAX_SGLIST_ENTRIES-1 ) ! 492: { ! 493: IOLog("SCSI(Symbios8xx): Bad sgListIndex\n\r"); ! 494: Sym8xxAbortCurrent( srb ); ! 495: return; ! 496: } ! 497: ! 498: /* ! 499: * Wide/odd-byte transfers. ! 500: * ! 501: * When dealing with Wide data transfers, if a S/G List ends with an odd-transfer count, then a ! 502: * valid received data byte is left in the script engine's SWIDE register. The least painful way ! 503: * to recover this byte is to construct a small script thunk to transfer one additional byte. The ! 504: * script will automatically draw this byte from the SWIDE register rather than the SCSI bus. ! 505: * The script thunk then branches back to script's PhaseHandler entrypoint. ! 506: * ! 507: */ ! 508: nexusPhys = &srb->srbPhys->nexus; ! 509: ! 510: scntl2Reg = Sym8xxReadRegs( chipBaseAddr, SCNTL2, SCNTL2_SIZE ); ! 511: if ( scntl2Reg & WSR ) ! 512: { ! 513: adapter->xferSWideInst[0] = OSSwapHostToLittleInt32( srb->directionMask | 1 ); ! 514: adapter->xferSWideInst[1] = nexus->sgListData[i].physAddr; ! 515: adapter->xferSWideInst[2] = OSSwapHostToLittleInt32( 0x80080000 ); ! 516: adapter->xferSWideInst[3] = OSSwapHostToLittleInt32( (UInt32)&chipRamAddrPhys[Ent_phase_handler] ); ! 517: ! 518: scriptRestartAddr = (UInt32) adapterPhys->xferSWideInst; ! 519: ! 520: /* ! 521: * Note: There is an assumption here that the sgResid count will be > 1. It appears ! 522: * that the script engine does not generate a phase-mismatch interrupt until ! 523: * we attempt to move > 1 byte from the SCSI bus and the only byte available is ! 524: * in SWIDE. ! 525: */ ! 526: sgResid--; ! 527: } ! 528: ! 529: /* ! 530: * Calculate partial S/G List instruction and branch ! 531: * ! 532: * Fill in slots 0/1 of the SGList based on the SGList index (i) and SGList residual count ! 533: * (sgResid) calculated above. ! 534: * ! 535: */ ! 536: sgDone = (OSSwapHostToLittleInt32( nexus->sgListData[i].length ) & 0x00ffffff) - sgResid; ! 537: ! 538: nexus->sgListData[0].length = OSSwapHostToLittleInt32( sgResid | srb->directionMask ); ! 539: nexus->sgListData[0].physAddr = OSSwapHostToLittleInt32( OSSwapHostToLittleInt32(nexus->sgListData[i].physAddr) + sgDone ); ! 540: /* ! 541: * If a previously calculated SGList 0 entry was interrupted again, we dont need to calculate ! 542: * a new branch address since the previous one is still valid. ! 543: */ ! 544: if ( i != 0 ) ! 545: { ! 546: nexus->sgListData[1].length = OSSwapHostToLittleInt32( 0x80080000 ); ! 547: nexus->sgListData[1].physAddr = OSSwapHostToLittleInt32( (UInt32)&nexusPhys->sgListData[i+1] ); ! 548: nexus->sgNextIndex = i + 1; ! 549: } ! 550: nexus->ppSGList = (SGEntry *)OSSwapHostToLittleInt32( (UInt32) &nexusPhys->sgListData[0] ); ! 551: ! 552: /* ! 553: * The script sets this Nexus variable to non-zero each time it calls the driver generated ! 554: * S/G list. This allows the driver's completion routines to differentiate between a successful ! 555: * transfer vs no data transfer at all. ! 556: */ ! 557: nexus->dataXferCalled = 0; ! 558: ! 559: return; ! 560: } ! 561: ! 562: /*-----------------------------------------------------------------------------* ! 563: * Determine SG element residual ! 564: * ! 565: * This routine returns how much of the current S/G List element the ! 566: * script was processing remains to be sent/received. All the information ! 567: * required to do this is stored in the script engine's registers. ! 568: * ! 569: *-----------------------------------------------------------------------------*/ ! 570: UInt32 Sym8xxSCSIController::Sym8xxCheckFifo( SRB *srb, UInt32 *pfifoCnt ) ! 571: { ! 572: bool fSCSISend; ! 573: bool fXferSync; ! 574: UInt32 scriptPhase = 0; ! 575: UInt32 dbcReg = 0; ! 576: UInt32 dfifoReg = 0; ! 577: UInt32 ctest5Reg = 0; ! 578: UInt8 sstat0Reg = 0; ! 579: UInt8 sstat1Reg = 0; ! 580: UInt8 sstat2Reg = 0; ! 581: UInt32 fifoCnt = 0; ! 582: UInt32 sgResid = 0; ! 583: ! 584: scriptPhase = OSSwapHostToLittleInt32( SCRIPT_VAR(R_ld_phase_flag) ); ! 585: ! 586: fSCSISend = (scriptPhase == A_kphase_DATA_OUT) || (scriptPhase == A_kphase_MSG_OUT); ! 587: ! 588: fXferSync = ((scriptPhase == A_kphase_DATA_OUT) || (scriptPhase == A_kphase_DATA_IN)) ! 589: && (srb->nexus.targetParms.sxferReg & 0x1F); ! 590: ! 591: dbcReg = Sym8xxReadRegs( chipBaseAddr, DBC, DBC_SIZE ) & 0x00ffffff; ! 592: ! 593: if ( !(dstatReg & DFE) ) ! 594: { ! 595: ctest5Reg = Sym8xxReadRegs( chipBaseAddr, CTEST5, CTEST5_SIZE ); ! 596: dfifoReg = Sym8xxReadRegs( chipBaseAddr, DFIFO, DFIFO_SIZE ); ! 597: ! 598: if ( ctest5Reg & DFS ) ! 599: { ! 600: fifoCnt = ((((ctest5Reg & 0x03) << 8) | dfifoReg) - dbcReg) & 0x3ff; ! 601: } ! 602: else ! 603: { ! 604: fifoCnt = (dfifoReg - dbcReg) & 0x7f; ! 605: } ! 606: } ! 607: ! 608: sstat0Reg = Sym8xxReadRegs( chipBaseAddr, SSTAT0, SSTAT0_SIZE ); ! 609: sstat2Reg = Sym8xxReadRegs( chipBaseAddr, SSTAT2, SSTAT2_SIZE ); ! 610: ! 611: if ( fSCSISend ) ! 612: { ! 613: fifoCnt += (sstat0Reg & OLF ) ? 1 : 0; ! 614: fifoCnt += (sstat2Reg & OLF1) ? 1 : 0; ! 615: ! 616: if ( fXferSync ) ! 617: { ! 618: fifoCnt += (sstat0Reg & ORF ) ? 1 : 0; ! 619: fifoCnt += (sstat2Reg & ORF1) ? 1 : 0; ! 620: } ! 621: } ! 622: else ! 623: { ! 624: if ( fXferSync ) ! 625: { ! 626: sstat1Reg = Sym8xxReadRegs( chipBaseAddr, SSTAT0, SSTAT0_SIZE ); ! 627: fifoCnt += (sstat1Reg >> 4) | (sstat2Reg & FF4); ! 628: } ! 629: else ! 630: { ! 631: fifoCnt += (sstat0Reg & ILF ) ? 1 : 0; ! 632: fifoCnt += (sstat2Reg & ILF1) ? 1 : 0; ! 633: } ! 634: } ! 635: ! 636: sgResid = dbcReg + fifoCnt; ! 637: *pfifoCnt = fifoCnt; ! 638: ! 639: return sgResid; ! 640: } ! 641: ! 642: /*-----------------------------------------------------------------------------* ! 643: * Calculate transfer counts. ! 644: * ! 645: * This routine updates srb->xferDone with the amount of data transferred ! 646: * by the last S/G List executed. ! 647: * ! 648: *-----------------------------------------------------------------------------*/ ! 649: void Sym8xxSCSIController::Sym8xxUpdateXferOffset( SRB *srb ) ! 650: { ! 651: UInt32 i; ! 652: UInt32 xferOffset; ! 653: ! 654: /* ! 655: * srb->xferOffset contains the client buffer offset INCLUDING the range ! 656: * covered by the current SGList. ! 657: */ ! 658: xferOffset = srb->xferOffset; ! 659: ! 660: /* ! 661: * If script did not complete the current transfer list then we need to determine ! 662: * how much of the list was completed. ! 663: */ ! 664: if ( srb->nexus.dataXferCalled == 0 ) ! 665: { ! 666: /* ! 667: * srb->xferOffsetPrev contains the client buffer offset EXCLUDING the ! 668: * range covered by the current SGList. ! 669: */ ! 670: xferOffset = srb->xferOffsetPrev; ! 671: ! 672: /* ! 673: * Calculate bytes transferred for partially completed list. ! 674: * ! 675: * To calculate the amount of this list completed, we sum the residual amount ! 676: * in SGList Slot 0 and the completed list elements 2 to sgNextIndex-1. ! 677: */ ! 678: if ( srb->nexus.sgNextIndex != 0 ) ! 679: { ! 680: xferOffset += OSSwapHostToLittleInt32( srb->nexus.sgListData[srb->nexus.sgNextIndex-1].length ) ! 681: - OSSwapHostToLittleInt32( srb->nexus.sgListData[0].length ); ! 682: ! 683: for ( i=2; i < srb->nexus.sgNextIndex-1; i++ ) ! 684: { ! 685: xferOffset += OSSwapHostToLittleInt32( srb->nexus.sgListData[i].length ) & 0x00ffffff; ! 686: } ! 687: } ! 688: } ! 689: ! 690: /* ! 691: * The script leaves the result of any Ignore Wide Residual message received from the target ! 692: * during the transfer. ! 693: */ ! 694: xferOffset -= srb->nexus.wideResidCount; ! 695: ! 696: ! 697: #if 0 ! 698: { ! 699: UInt32 resid = srb->xferOffset - xferOffset; ! 700: if ( resid ) ! 701: { ! 702: IOLog( "SCSI(Symbios8xx): Incomplete transfer - Req Count = %08x Act Count = %08x - srb = %08x\n\r", ! 703: srb->xferCount, xferOffset, (UInt32)srb ); ! 704: } ! 705: } ! 706: #endif ! 707: ! 708: srb->xferDone = xferOffset; ! 709: } ! 710: ! 711: /*-----------------------------------------------------------------------------* ! 712: * No SRB/Nexus Processing. ! 713: * ! 714: * In some cases (mainly Aborts) not having a SRB/Nexus is normal. In other ! 715: * cases it indicates a problem such a reconnection from a target that we ! 716: * have no record of. ! 717: * ! 718: *-----------------------------------------------------------------------------*/ ! 719: void Sym8xxSCSIController::Sym8xxProcessNoNexus() ! 720: { ! 721: UInt32 dspsReg; ! 722: UInt32 dspReg = 0; ! 723: UInt32 scriptPhase = (UInt32)-1 ; ! 724: ! 725: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase]; ! 726: ! 727: dspsReg = Sym8xxReadRegs( chipBaseAddr, DSPS, DSPS_SIZE ); ! 728: ! 729: scriptPhase = OSSwapHostToLittleInt32( SCRIPT_VAR(R_ld_phase_flag) ); ! 730: ! 731: /* ! 732: * If we were trying to abort or disconnect a target and the bus ! 733: * is now free we consider the abort to have completed. ! 734: */ ! 735: if ( sistReg & UDC ) ! 736: { ! 737: if ( (scriptPhase == A_kphase_ABORT_MAILBOX) && abortSRB ) ! 738: { ! 739: Sym8xxCompleteSRB( abortSRB ); ! 740: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0; ! 741: } ! 742: else if ( scriptPhase == A_kphase_ABORT_CURRENT ) ! 743: { ! 744: abortCurrentSRB = NULL; ! 745: } ! 746: } ! 747: /* ! 748: * If we were trying to connect to a target to send it an abort message, and ! 749: * we timed out, we consider the abort as completed. ! 750: * ! 751: * Note: In this case the target may be hung, but at least its not on the bus. ! 752: */ ! 753: else if ( sistReg & STO ) ! 754: { ! 755: if ( (scriptPhase == A_kphase_ABORT_MAILBOX) && abortSRB ) ! 756: { ! 757: Sym8xxCompleteSRB( abortSRB ); ! 758: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0; ! 759: } ! 760: } ! 761: ! 762: /* ! 763: * If the script died, without a vaild nexusIndex, we abort anything that is currently ! 764: * connected and hope for the best! ! 765: */ ! 766: else if ( dstatReg & IID ) ! 767: { ! 768: dspReg = Sym8xxReadRegs( chipBaseAddr, DSP, DSP_SIZE ); ! 769: IOLog("SCSI(Symbios8xx): Illegal script instruction - dsp = %08x srb=0\n\r", (int)dspReg ); ! 770: Sym8xxAbortCurrent( (SRB *)-1 ); ! 771: } ! 772: ! 773: /* ! 774: * Script signaled conditions ! 775: */ ! 776: else if ( dstatReg & SIR ) ! 777: { ! 778: switch ( dspsReg ) ! 779: { ! 780: case A_abort_current: ! 781: abortCurrentSRB = NULL; ! 782: break; ! 783: ! 784: case A_abort_mailbox: ! 785: Sym8xxCompleteSRB( abortSRB ); ! 786: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0; ! 787: break; ! 788: ! 789: default: ! 790: Sym8xxAbortCurrent( (SRB *)-1 ); ! 791: } ! 792: } ! 793: else ! 794: { ! 795: Sym8xxAbortCurrent( (SRB *)-1 ); ! 796: } ! 797: ! 798: if ( scriptRestartAddr ) ! 799: { ! 800: Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr ); ! 801: } ! 802: } ! 803: ! 804: ! 805: /*-----------------------------------------------------------------------------* ! 806: * Abort currently connected target. ! 807: * ! 808: *-----------------------------------------------------------------------------*/ ! 809: void Sym8xxSCSIController::Sym8xxAbortCurrent( SRB *srb ) ! 810: { ! 811: if ( abortCurrentSRB ) ! 812: { ! 813: if ( abortCurrentSRB != srb ) ! 814: { ! 815: IOLog("SCSI(Symbios8xx): Multiple abort immediate SRBs - resetting\n\r"); ! 816: Sym8xxSCSIBusReset( (SRB *)0 ); ! 817: } ! 818: return; ! 819: } ! 820: ! 821: abortCurrentSRB = srb; ! 822: ! 823: if ( srb != (SRB *)-1 ) ! 824: { ! 825: if ( srb->srbSCSIResult == kIOReturnSuccess ) ! 826: { ! 827: srb->srbSCSIResult = kIOReturnAborted; ! 828: } ! 829: } ! 830: ! 831: /* ! 832: * Issue abort or abort tag depending on whether the is a tagged request ! 833: */ ! 834: SCRIPT_VAR(R_ld_AbortCode) = OSSwapHostToLittleInt32( ((srb != (SRB *)-1) && (srb->nexus.tag >= MIN_SCSI_TAG)) ? 0x0d : 0x06 ); ! 835: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_issueAbort_BDR]; ! 836: ! 837: Sym8xxClearFifo(); ! 838: } ! 839: ! 840: /*-----------------------------------------------------------------------------* ! 841: * This routine clears the script engine's SCSI and DMA fifos. ! 842: * ! 843: *-----------------------------------------------------------------------------*/ ! 844: void Sym8xxSCSIController::Sym8xxClearFifo() ! 845: { ! 846: UInt8 ctest3Reg; ! 847: UInt8 stest2Reg; ! 848: UInt8 stest3Reg; ! 849: ! 850: stest2Reg = Sym8xxReadRegs( chipBaseAddr, STEST2, STEST2_SIZE ); ! 851: if ( stest2Reg & ROF ) ! 852: { ! 853: Sym8xxWriteRegs( chipBaseAddr, STEST2, STEST2_SIZE, stest2Reg ); ! 854: } ! 855: ! 856: ctest3Reg = Sym8xxReadRegs( chipBaseAddr, CTEST3, CTEST3_SIZE ); ! 857: ctest3Reg |= CLF; ! 858: Sym8xxWriteRegs( chipBaseAddr, CTEST3, CTEST3_SIZE, ctest3Reg ); ! 859: ! 860: stest3Reg = Sym8xxReadRegs( chipBaseAddr, STEST3, STEST3_SIZE ); ! 861: stest3Reg |= CSF; ! 862: Sym8xxWriteRegs( chipBaseAddr,STEST3, STEST3_SIZE, stest3Reg ); ! 863: ! 864: do ! 865: { ! 866: ctest3Reg = Sym8xxReadRegs( chipBaseAddr, CTEST3, CTEST3_SIZE ); ! 867: stest2Reg = Sym8xxReadRegs( chipBaseAddr, STEST3, STEST3_SIZE ); ! 868: stest3Reg = Sym8xxReadRegs( chipBaseAddr, STEST3, STEST3_SIZE ); ! 869: } ! 870: while( (ctest3Reg & CLF) || (stest3Reg & CSF) || (stest2Reg & ROF) ); ! 871: } ! 872: ! 873: /*-----------------------------------------------------------------------------* ! 874: * This routine processes the target's response to our SDTR message. ! 875: * ! 876: * We calculate the values for the script engine's timing registers ! 877: * for synchronous registers, and update our tables indicating that ! 878: * requested data transfer mode is in-effect. ! 879: * ! 880: *-----------------------------------------------------------------------------*/ ! 881: void Sym8xxSCSIController::Sym8xxNegotiateSDTR( SRB *srb, Nexus *nexus ) ! 882: { ! 883: UInt32 x; ! 884: UInt8 *pMsg; ! 885: UInt32 syncPeriod; ! 886: ! 887: /* ! 888: * If we were not negotiating, the send MsgReject to targets negotiation ! 889: * attempt. ! 890: */ ! 891: if ( !(srb->srbCDBFlags & kCDBFlagsNegotiateSDTR) ) ! 892: { ! 893: Sym8xxSendMsgReject( srb ); ! 894: return; ! 895: } ! 896: ! 897: /* ! 898: * Get pointer to negotiation message received from target. ! 899: */ ! 900: pMsg = (UInt8 *) &SCRIPT_VAR(R_ld_message); ! 901: ! 902: /* ! 903: * The target's SDTR response contains the (transfer period / 4). ! 904: * ! 905: * We set our sync clock divisor to 1, 2, or 4 giving us a clock rates ! 906: * of: ! 907: * 80Mhz (Period = 12.5ns), ! 908: * 40Mhz (Period = 25.0ns) ! 909: * 20Mhz (Period = 50.0ns) ! 910: * ! 911: * This is further divided by the value in the sxfer reg to give us the final sync clock rate. ! 912: * ! 913: * The requested sync period is scaled up by 1000 and the clock periods are scaled up by 10 ! 914: * giving a result scaled up by 100. This is rounded-up and converted to sxfer reg values. ! 915: */ ! 916: if ( pMsg[4] == 0 ) ! 917: { ! 918: nexus->targetParms.scntl3Reg &= 0x0f; ! 919: nexus->targetParms.sxferReg = 0x00; ! 920: } ! 921: else ! 922: { ! 923: syncPeriod = (UInt32)pMsg[3] << 2; ! 924: if ( syncPeriod < 100 ) ! 925: { ! 926: nexus->targetParms.scntl3Reg |= SCNTL3_INIT_875_ULTRA; ! 927: x = (syncPeriod * 1000) / 125; ! 928: } ! 929: else if ( syncPeriod < 200 ) ! 930: { ! 931: nexus->targetParms.scntl3Reg |= SCNTL3_INIT_875_FAST; ! 932: x = (syncPeriod * 1000) / 250; ! 933: } ! 934: else ! 935: { ! 936: nexus->targetParms.scntl3Reg |= SCNTL3_INIT_875_SLOW; ! 937: x = (syncPeriod * 1000) / 500; ! 938: } ! 939: ! 940: if ( x % 100 ) x += 100; ! 941: ! 942: /* ! 943: * sxferReg Bits: 5-0 - Transfer offset ! 944: * 7-6 - Sync Clock Divisor (0 = sync clock / 4) ! 945: */ ! 946: nexus->targetParms.sxferReg = ((x/100 - 4) << 5) | pMsg[4]; ! 947: } ! 948: ! 949: /* ! 950: * Update our per-target tables and set-up the hardware regs for this request. ! 951: * ! 952: * On reconnection attempts, the script will use our per-target tables to set-up ! 953: * the scntl3 and sxfer registers in the script engine. ! 954: */ ! 955: adapter->targetClocks[srb->target].sxferReg = nexus->targetParms.sxferReg; ! 956: adapter->targetClocks[srb->target].scntl3Reg = nexus->targetParms.scntl3Reg; ! 957: ! 958: Sym8xxWriteRegs( chipBaseAddr, SCNTL3, SCNTL3_SIZE, nexus->targetParms.scntl3Reg ); ! 959: Sym8xxWriteRegs( chipBaseAddr, SXFER, SXFER_SIZE, nexus->targetParms.sxferReg ); ! 960: ! 961: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_clearACK]; ! 962: } ! 963: ! 964: /*-----------------------------------------------------------------------------* ! 965: * This routine processes the target's response to our WDTR message. ! 966: * ! 967: * In addition, if there is a pending SDTR message, this routine sends it ! 968: * to the target. ! 969: * ! 970: *-----------------------------------------------------------------------------*/ ! 971: void Sym8xxSCSIController::Sym8xxNegotiateWDTR( SRB *srb, Nexus *nexus ) ! 972: { ! 973: UInt8 *pMsg; ! 974: UInt32 msgBytesSent; ! 975: UInt32 msgBytesLeft; ! 976: ! 977: /* ! 978: * If we were not negotiating, the send MsgReject to targets negotiation ! 979: * attempt. ! 980: */ ! 981: if ( !(srb->srbCDBFlags & kCDBFlagsNegotiateWDTR) ) ! 982: { ! 983: Sym8xxSendMsgReject( srb ); ! 984: return; ! 985: } ! 986: ! 987: /* ! 988: * Set Wide (16-bit) vs Narrow (8-bit) data transfer mode based on target's response. ! 989: */ ! 990: pMsg = (UInt8 *) &SCRIPT_VAR(R_ld_message); ! 991: ! 992: if ( pMsg[3] == 1 ) ! 993: { ! 994: nexus->targetParms.scntl3Reg |= EWS; ! 995: } ! 996: else ! 997: { ! 998: nexus->targetParms.scntl3Reg &= ~EWS; ! 999: } ! 1000: ! 1001: /* ! 1002: * Update our per-target tables and set-up the hardware regs for this request. ! 1003: * ! 1004: * On reconnection attempts, the script will use our per-target tables to set-up ! 1005: * the scntl3 and sxfer registers in the script engine. ! 1006: */ ! 1007: ! 1008: adapter->targetClocks[srb->target].scntl3Reg = nexus->targetParms.scntl3Reg; ! 1009: Sym8xxWriteRegs( chipBaseAddr, SCNTL3, SCNTL3_SIZE, nexus->targetParms.scntl3Reg ); ! 1010: ! 1011: ! 1012: /* ! 1013: * If there any pending messages left for the target, send them now, ! 1014: */ ! 1015: msgBytesSent = OSSwapHostToLittleInt32( nexus->msg.length ); ! 1016: msgBytesLeft = srb->srbMsgLength - msgBytesSent; ! 1017: if ( msgBytesLeft ) ! 1018: { ! 1019: nexus->msg.length = OSSwapHostToLittleInt32( msgBytesLeft ); ! 1020: nexus->msg.ppData = OSSwapHostToLittleInt32( OSSwapHostToLittleInt32( nexus->msg.ppData ) + msgBytesSent ); ! 1021: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_issueMessageOut]; ! 1022: } ! 1023: ! 1024: /* ! 1025: * Otherwise, tell the script we're done with MsgOut phase. ! 1026: */ ! 1027: else ! 1028: { ! 1029: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_clearACK]; ! 1030: } ! 1031: } ! 1032: ! 1033: /*-----------------------------------------------------------------------------* ! 1034: * Reject message received from target. ! 1035: * ! 1036: *-----------------------------------------------------------------------------*/ ! 1037: void Sym8xxSCSIController::Sym8xxSendMsgReject( SRB *srb ) ! 1038: { ! 1039: srb->nexus.msg.ppData = OSSwapHostToLittleInt32((UInt32)&srb->srbPhys->nexus.msgData); ! 1040: srb->nexus.msg.length = OSSwapHostToLittleInt32(0x01); ! 1041: srb->nexus.msgData[0] = 0x07; ! 1042: ! 1043: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_issueMessageOut]; ! 1044: } ! 1045: ! 1046: ! 1047: /*-----------------------------------------------------------------------------* ! 1048: * This routine initiates a SCSI Bus Reset. ! 1049: * ! 1050: * This may be an internally generated request as part of error recovery or ! 1051: * a client's bus reset request. ! 1052: * ! 1053: *-----------------------------------------------------------------------------*/ ! 1054: void Sym8xxSCSIController::Sym8xxSCSIBusReset( SRB *srb ) ! 1055: { ! 1056: if ( srb ) ! 1057: { ! 1058: if ( resetSRB ) ! 1059: { ! 1060: srb->srbSCSIResult = kIOReturnBusy; ! 1061: Sym8xxCompleteSRB( srb ); ! 1062: return; ! 1063: } ! 1064: resetSRB = srb; ! 1065: } ! 1066: ! 1067: Sym8xxAbortScript(); ! 1068: ! 1069: Sym8xxWriteRegs( chipBaseAddr, SCNTL1, SCNTL1_SIZE, SCNTL1_SCSI_RST ); ! 1070: IODelay( 100 ); ! 1071: Sym8xxWriteRegs( chipBaseAddr, SCNTL1, SCNTL1_SIZE, SCNTL1_INIT ); ! 1072: } ! 1073: ! 1074: /*-----------------------------------------------------------------------------* ! 1075: * This routine handles a SCSI Bus Reset interrupt. ! 1076: * ! 1077: * The SCSI Bus reset may be generated by a target on the bus, internally from ! 1078: * the driver's error recovery or from a client request. ! 1079: * ! 1080: * Once the reset is detected we establish a settle period where new client requests ! 1081: * are blocked in the client thread. In addition we flush all currently executing ! 1082: * scsi requests back to the client. ! 1083: * ! 1084: *-----------------------------------------------------------------------------*/ ! 1085: void Sym8xxSCSIController::Sym8xxProcessSCSIBusReset() ! 1086: { ! 1087: UInt32 i; ! 1088: ! 1089: Sym8xxClearFifo(); ! 1090: ! 1091: /* ! 1092: * We clear the script's request mailboxes. Any work in the script mailboxes is ! 1093: * already in the NexusPtr tables so we have already have handled the SRB/Nexus ! 1094: * cleanup. ! 1095: */ ! 1096: for ( i=0; i < MAX_SCHED_MAILBOXES; i++ ) ! 1097: { ! 1098: adapter->schedMailBox[i] = 0; ! 1099: } ! 1100: ! 1101: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0; ! 1102: SCRIPT_VAR(R_ld_IOdone_mailbox) = 0; ! 1103: SCRIPT_VAR(R_ld_counter) = 0; ! 1104: mailBoxIndex = 0; ! 1105: ! 1106: ! 1107: /* ! 1108: * Reset the data transfer mode/clocks in our per-target tables back to Async/Narrow 8-bit ! 1109: */ ! 1110: for ( i=0; i < MAX_SCSI_TARGETS; i++ ) ! 1111: { ! 1112: adapter->targetClocks[i].scntl3Reg = SCNTL3_INIT_875; ! 1113: adapter->targetClocks[i].sxferReg = 0; ! 1114: } ! 1115: ! 1116: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase]; ! 1117: Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr ); ! 1118: ! 1119: if ( resetSRB ) ! 1120: { ! 1121: resetSRB->srbSCSIResult = kIOReturnSuccess; ! 1122: Sym8xxCompleteSRB( resetSRB ); ! 1123: resetSRB = 0; ! 1124: } ! 1125: else if ( initialReset == true ) ! 1126: { ! 1127: initialReset = false; ! 1128: } ! 1129: else ! 1130: { ! 1131: resetOccurred(); ! 1132: } ! 1133: } ! 1134: ! 1135: /*-----------------------------------------------------------------------------* ! 1136: * This routine sets the SIGP bit in the script engine's ISTAT ! 1137: * register. This signals the script to wake-up for a WAIT for ! 1138: * reselection instruction. The script will then check the mailboxes ! 1139: * for work to do. ! 1140: * ! 1141: *-----------------------------------------------------------------------------*/ ! 1142: void Sym8xxSCSIController::Sym8xxSignalScript( SRB *srb ) ! 1143: { ! 1144: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, SIGP ); ! 1145: } ! 1146: ! 1147: /*-----------------------------------------------------------------------------* ! 1148: * ! 1149: * ! 1150: * ! 1151: * ! 1152: * ! 1153: *-----------------------------------------------------------------------------*/ ! 1154: void Sym8xxSCSIController::Sym8xxCheckRequestSense( SRB *srb ) ! 1155: { ! 1156: IOSCSICommand *scsiCommand; ! 1157: IOMemoryDescriptor *reqSenseDesc; ! 1158: ! 1159: scsiCommand = srb->scsiCommand; ! 1160: ! 1161: scsiCommand->getPointers( &reqSenseDesc, 0, 0, true ); ! 1162: ! 1163: if ( reqSenseDesc != 0 ) ! 1164: { ! 1165: Sym8xxCancelMailBox( srb->target, srb->lun, true ); ! 1166: } ! 1167: } ! 1168: ! 1169: /*-----------------------------------------------------------------------------* ! 1170: * This routine does a mailbox abort. ! 1171: * ! 1172: * This type of abort is used for targets not currently connected to the SCSI Bus. ! 1173: * ! 1174: * The script will select the target and send a tag (if required) followed by the ! 1175: * appropriate abort message (abort/abort-tag) ! 1176: * ! 1177: *-----------------------------------------------------------------------------*/ ! 1178: void Sym8xxSCSIController::Sym8xxAbortBdr( SRB *srb ) ! 1179: { ! 1180: IOAbortBdrMailBox abortMailBox; ! 1181: ! 1182: abortSRB = srb; ! 1183: ! 1184: /* ! 1185: * Setup a script variable containing the abort information. ! 1186: */ ! 1187: abortMailBox.identify = srb->nexus.msgData[0]; ! 1188: abortMailBox.tag = srb->nexus.msgData[1]; ! 1189: abortMailBox.message = srb->nexus.msgData[2]; ! 1190: abortMailBox.scsi_id = srb->target; ! 1191: ! 1192: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = *(UInt32 *) &abortMailBox; ! 1193: ! 1194: Sym8xxSignalScript( srb ); ! 1195: } ! 1196: ! 1197: /*-----------------------------------------------------------------------------* ! 1198: * ! 1199: * ! 1200: * ! 1201: * ! 1202: *-----------------------------------------------------------------------------*/ ! 1203: bool Sym8xxSCSIController::Sym8xxCancelMailBox( Nexus *nexusCancel ) ! 1204: { ! 1205: Nexus *nexusPhys; ! 1206: UInt32 i; ! 1207: ! 1208: nexusPhys = (Nexus *)OSSwapHostToLittleInt32( (UInt32)nexusCancel ); ! 1209: for ( i=0; i < MAX_SCHED_MAILBOXES; i++ ) ! 1210: { ! 1211: if ( nexusPhys == adapter->schedMailBox[i] ) ! 1212: { ! 1213: adapter->schedMailBox[i] = (Nexus *)OSSwapHostToLittleInt32( kMailBoxCancel ); ! 1214: return true; ! 1215: } ! 1216: } ! 1217: return false; ! 1218: } ! 1219: ! 1220: ! 1221: /*-----------------------------------------------------------------------------* ! 1222: * ! 1223: * ! 1224: * ! 1225: * ! 1226: *-----------------------------------------------------------------------------*/ ! 1227: void Sym8xxSCSIController::Sym8xxCancelMailBox( UInt32 target, UInt32 lun, bool fReschedule ) ! 1228: { ! 1229: UInt32 tag; ! 1230: UInt32 tagPos; ! 1231: UInt32 tagShift; ! 1232: ! 1233: UInt32 i; ! 1234: ! 1235: SRB *srb; ! 1236: Nexus *nexus; ! 1237: Nexus *nexusPhys; ! 1238: ! 1239: tagPos = offsetof(Nexus, tag) & 0x03; ! 1240: tagShift = 24 - (tagPos << 3); ! 1241: ! 1242: for ( i=0; i < MAX_SCHED_MAILBOXES; i++ ) ! 1243: { ! 1244: nexusPhys = (Nexus *)OSSwapHostToLittleInt32( (UInt32)adapter->schedMailBox[i] ); ! 1245: if ( (nexusPhys != (Nexus *)kMailBoxEmpty) && (nexusPhys != (Nexus *)kMailBoxCancel) ) ! 1246: { ! 1247: /* ! 1248: * Read the 'tag' byte given Nexus physical address from the mailBox. ! 1249: * Look-up the virtual address of the corresponding Nexus struct. ! 1250: */ ! 1251: tag = ml_phys_read((UInt32)&nexusPhys->tag - tagPos); ! 1252: tag = (tag >> tagShift) & 0xff; ! 1253: ! 1254: nexus = adapter->nexusPtrsVirt[tag]; ! 1255: if ( nexus == (Nexus *)-1 ) ! 1256: { ! 1257: continue; ! 1258: } ! 1259: ! 1260: /* ! 1261: * If the SCSI target of the mailbox entry matches the abort SRB target, ! 1262: * then we may have a winner. ! 1263: */ ! 1264: srb = (SRB *)((UInt32)nexus - offsetof(SRB, nexus)); ! 1265: ! 1266: if ( srb->target == target ) ! 1267: { ! 1268: /* ! 1269: * For a device reset, we cancel all requests for that target regardless of lun. ! 1270: * For an abort all, we must match on both target and lun ! 1271: */ ! 1272: if ( (lun == (UInt32)-1) || (srb->lun == lun) ) ! 1273: { ! 1274: adapter->schedMailBox[i] = (Nexus *)OSSwapHostToLittleInt32( kMailBoxCancel ); ! 1275: ! 1276: if ( fReschedule == true ) ! 1277: { ! 1278: rescheduleCommand( srb->scsiCommand ); ! 1279: } ! 1280: } ! 1281: } ! 1282: } ! 1283: } ! 1284: } ! 1285: ! 1286: /*-----------------------------------------------------------------------------* ! 1287: * This routine is used to shutdown the script engine in an orderly fashion. ! 1288: * ! 1289: * Normally the script engine automatically stops when an interrupt is generated. However, ! 1290: * in the case of timeouts we need to change the script engine's dsp reg (instruction pointer). ! 1291: * to issue an abort. ! 1292: * ! 1293: *-----------------------------------------------------------------------------*/ ! 1294: void Sym8xxSCSIController::Sym8xxAbortScript() ! 1295: { ! 1296: mach_timespec_t currentTime; ! 1297: mach_timespec_t startTime; ! 1298: ! 1299: getWorkLoop()->disableAllInterrupts(); ! 1300: ! 1301: /* ! 1302: * We set the ABRT bit in ISTAT and spin until the script engine acknowledges the ! 1303: * abort or we timeout. ! 1304: */ ! 1305: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, ABRT ); ! 1306: ! 1307: IOGetTime( &startTime ); ! 1308: ! 1309: do ! 1310: { ! 1311: IOGetTime( ¤tTime ); ! 1312: SUB_MACH_TIMESPEC( ¤tTime, &startTime ); ! 1313: ! 1314: istatReg = Sym8xxReadRegs( chipBaseAddr, ISTAT, ISTAT_SIZE ); ! 1315: ! 1316: if ( istatReg & SIP ) ! 1317: { ! 1318: Sym8xxReadRegs( chipBaseAddr, SIST, SIST_SIZE ); ! 1319: continue; ! 1320: } ! 1321: ! 1322: if ( istatReg & DIP ) ! 1323: { ! 1324: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, 0x00 ); ! 1325: Sym8xxReadRegs( chipBaseAddr, DSTAT, DSTAT_SIZE ); ! 1326: break; ! 1327: } ! 1328: } ! 1329: while ( currentTime.tv_nsec < (kAbortScriptTimeoutMS * 1000 * 1000) ); ! 1330: ! 1331: istatReg = SIGP; ! 1332: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, istatReg ); ! 1333: ! 1334: getWorkLoop()->enableAllInterrupts(); ! 1335: ! 1336: if ( currentTime.tv_nsec >= (kAbortScriptTimeoutMS * 1000 * 1000) ) ! 1337: { ! 1338: IOLog( "SCSI(Symbios8xx): Abort script failed - resetting bus\n\r" ); ! 1339: } ! 1340: ! 1341: } ! 1342: ! 1343:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.