Annotation of XNU/iokit/Drivers/scsi/drvSymbios8xx/Sym8xxExecute.cpp, revision 1.1

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( &currentTime );
        !          1312:         SUB_MACH_TIMESPEC( &currentTime, &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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.