Annotation of XNU/iokit/Drivers/scsi/drvSymbios8xx/Sym8xxExecute.cpp, revision 1.1.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.