Annotation of kernel/bsd/dev/ppc/drvSymbios8xx/Sym8xxExecute.m, 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:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /* Sym8xxExecute.m created by russb2 on Sat 30-May-1998 */
        !            26: 
        !            27: #import "Sym8xxController.h"
        !            28: 
        !            29: /*-----------------------------------------------------------------------------*
        !            30:  * IOThread Routines
        !            31:  *
        !            32:  * This module contains routines that run on the driver's IOThread.
        !            33:  *
        !            34:  *-----------------------------------------------------------------------------*/
        !            35: 
        !            36: @implementation Sym8xxController(Execute)
        !            37: 
        !            38: /*-----------------------------------------------------------------------------*
        !            39:  *  This is the main command processing loop for the driver's I/O thread.
        !            40:  *  It removes SRBs from the driver's command queue and processes them according
        !            41:  *  to the command code in srb->srbCmd.
        !            42:  *
        !            43:  *-----------------------------------------------------------------------------*/
        !            44: - (void) commandRequestOccurred
        !            45: {
        !            46:     SRB                                *srb = NULL;
        !            47: 
        !            48:     while ( 1 )
        !            49:     {
        !            50:        [srbPendingQLock lock];
        !            51: 
        !            52:        if ( queue_empty(&srbPendingQ) )
        !            53:        {
        !            54:           [srbPendingQLock unlock];
        !            55:            break;
        !            56:        }
        !            57:        queue_remove_first( &srbPendingQ, srb, SRB *, srbQ );
        !            58: 
        !            59:        [srbPendingQLock unlock];
        !            60: 
        !            61:     
        !            62:         /*
        !            63:          * If we are in the quiet period after a SCSI Bus reset, then reject new SRBs. In
        !            64:          * general the client thread processing will block new SRBs, however, some may have
        !            65:          * been on the IOThread's SRB queue when the reset occurred.
        !            66:          */
        !            67:         if ( resetQuiesceTimer )
        !            68:         {
        !            69:             srb->srbSCSIResult = SR_IOST_RESET;
        !            70:             [srb->srbCmdLock unlockWith: ksrbCmdComplete];  
        !            71:             continue;
        !            72:         }
        !            73: 
        !            74:         switch ( srb->srbCmd )
        !            75:         {
        !            76:             /*
        !            77:              * For a SCSI CDB request, stuff the physical address of the SRB's  Nexus struct into a
        !            78:              * mailbox and signal the Symbios script engine.
        !            79:              */
        !            80:             case ksrbCmdExecuteReq:
        !            81:                 srb->nexus.targetParms.scntl3Reg = adapter->targetClocks[srb->target].scntl3Reg;
        !            82:                 srb->nexus.targetParms.sxferReg  = adapter->targetClocks[srb->target].sxferReg;
        !            83: 
        !            84:                 adapter->nexusPtrsVirt[srb->nexus.tag] = &srb->nexus;
        !            85:                 adapter->nexusPtrsPhys[srb->nexus.tag] = (Nexus *)EndianSwap32( (u_int32_t)&srb->srbPhys->nexus );
        !            86:                 adapter->schedMailBox[mailBoxIndex++]  = (Nexus *)EndianSwap32 ( (u_int32_t)&srb->srbPhys->nexus );
        !            87: 
        !            88:                 [self Sym8xxSignalScript: srb];
        !            89:                 break;
        !            90: 
        !            91:             case ksrbCmdResetSCSIBus:
        !            92:                 [self Sym8xxSCSIBusReset: srb];
        !            93:                 break;
        !            94:            
        !            95:             case ksrbCmdAbortReq:
        !            96:            case ksrbCmdBusDevReset:
        !            97:                 [self Sym8xxAbortBdr: srb];
        !            98:                 break;
        !            99: 
        !           100:             default:
        !           101:                 ; 
        !           102:         }         
        !           103:     }
        !           104: }
        !           105: 
        !           106: 
        !           107: /*-----------------------------------------------------------------------------*
        !           108:  * Interrupts from the Symbios chipset are dispatched here at task time under the
        !           109:  * IOThread's context.
        !           110:  *-----------------------------------------------------------------------------*/
        !           111: - (void) interruptOccurred
        !           112: {
        !           113:     do
        !           114:     {
        !           115:         /* 
        !           116:          * The chipset's ISTAT reg gives us the general interrupting condiditions,
        !           117:          * with DSTAT and SIST providing more detailed information.
        !           118:          */
        !           119:         istatReg = Sym8xxReadRegs( chipBaseAddr, ISTAT, ISTAT_SIZE );
        !           120: 
        !           121:         /* The INTF bit in ISTAT indicates that the script is signalling the driver
        !           122:          * that its IODone mailbox is full and that we should process a completed
        !           123:          * request. The script continues to run after posting this interrupt unlike 
        !           124:          * other chipset interrupts which require the driver to restart the script
        !           125:          * engine.
        !           126:          */
        !           127:         if ( istatReg & INTF )
        !           128:         {
        !           129:             Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, istatReg );
        !           130:             [self Sym8xxProcessIODone];
        !           131:         }
        !           132: 
        !           133:         /*
        !           134:          * Handle remaining interrupting conditions
        !           135:          */  
        !           136:         if ( istatReg & (SIP | DIP) )
        !           137:         {
        !           138:             [self Sym8xxProcessInterrupt];    
        !           139:         }
        !           140:     }
        !           141:     while ( istatReg & (SIP | DIP | INTF) );
        !           142: 
        !           143:     [self enableAllInterrupts];
        !           144: 
        !           145: }
        !           146: 
        !           147: /*-----------------------------------------------------------------------------*
        !           148:  * Process a request posted in the script's IODone mailbox.
        !           149:  *
        !           150:  *-----------------------------------------------------------------------------*/
        !           151: - (void) Sym8xxProcessIODone
        !           152: {
        !           153:     SRB                                *srb;
        !           154:     Nexus                      *nexus;
        !           155:     IODoneMailBox              *pMailBox;
        !           156:     
        !           157:  
        !           158:     /*
        !           159:      * The IODone mailbox contains an index into our Nexus pointer tables.
        !           160:      *
        !           161:      * The Nexus struct is part of the SRB so we can get our SRB address
        !           162:      * by subtracting the offset of the Nexus struct in the SRB.
        !           163:      */
        !           164:     pMailBox = (IODoneMailBox *)&SCRIPT_VAR(R_ld_IOdone_mailbox);
        !           165:     nexus = adapter->nexusPtrsVirt[pMailBox->nexus];        
        !           166:     srb   = (SRB *)((u_int32_t)nexus - offsetof(SRB, nexus));    
        !           167: 
        !           168:     /*
        !           169:      * If there was no request sense performed, then update the transfer
        !           170:      * counts in the SRB.
        !           171:      */
        !           172:     if ( srb->srbState == ksrbStateCDBDone  )
        !           173:     {
        !           174:         [self Sym8xxUpdateXferOffset: srb];
        !           175:     }
        !           176: 
        !           177:     /* 
        !           178:      * Clear the completed Nexus pointer from our tables and clear the
        !           179:      * IODone mailbox.
        !           180:      */
        !           181:     adapter->nexusPtrsVirt[pMailBox->nexus] = (Nexus *) -1;
        !           182:     adapter->nexusPtrsPhys[pMailBox->nexus] = (Nexus *) -1;
        !           183:     SCRIPT_VAR(R_ld_IOdone_mailbox)       = 0;
        !           184: 
        !           185:     /*
        !           186:      * Don't ask why we need to do this -- we shouldn't if the Indirect SCSI
        !           187:      * drivers worked properly!
        !           188:      * 
        !           189:      */
        !           190:     if ( nexus->cdbData.cdb_opcode == C6OP_INQUIRY )
        !           191:     {
        !           192:         [self Sym8xxCheckInquiryData: srb];
        !           193:     }
        !           194: 
        !           195:     /*
        !           196:      * Wake up the client's thread to do post-processing
        !           197:      */
        !           198:     [srb->srbCmdLock unlockWith: ksrbCmdComplete];  
        !           199: }
        !           200: 
        !           201: /*-----------------------------------------------------------------------------*
        !           202:  * General script interrupt processing
        !           203:  *
        !           204:  *-----------------------------------------------------------------------------*/
        !           205: - (void) Sym8xxProcessInterrupt
        !           206: {
        !           207:     SRB                        *srb            = NULL;
        !           208:     Nexus              *nexus          = NULL;
        !           209:     u_int32_t          nexusIndex;
        !           210:     u_int32_t          scriptPhase;
        !           211:     u_int32_t          fifoCnt         = 0;
        !           212:     u_int32_t          dspsReg         = 0;
        !           213:     u_int32_t          dspReg          = 0;
        !           214: 
        !           215: 
        !           216:     /*
        !           217:      * Read DSTAT/SIST regs to determine why the script stopped.
        !           218:      */
        !           219:     dstatReg = Sym8xxReadRegs( chipBaseAddr,  DSTAT, DSTAT_SIZE );
        !           220:     IODelay(5);
        !           221:     sistReg =  Sym8xxReadRegs( chipBaseAddr,  SIST,  SIST_SIZE );
        !           222: 
        !           223: //  kprintf( "SCSI(Symbios8xx): SIST = %04x DSTAT = %02x\n\r", sistReg, dstatReg  );
        !           224: 
        !           225:     /*
        !           226:      * This Script var tells us what the script thinks it was doing when the interrupt occurred.
        !           227:      */
        !           228:     scriptPhase = EndianSwap32( SCRIPT_VAR(R_ld_phase_flag) );
        !           229: 
        !           230:     /*
        !           231:      * SCSI Bus reset detected 
        !           232:      *
        !           233:      * Clean up the carnage.     
        !           234:      * Note: This may be either an adapter or target initiated reset.
        !           235:      */
        !           236:     if ( sistReg & RSTI )
        !           237:     {
        !           238:         [self Sym8xxProcessSCSIBusReset];
        !           239:         return;
        !           240:     }
        !           241: 
        !           242:     /*
        !           243:      * Calculate our current SRB/Nexus.
        !           244:      *
        !           245:      * Read a script var to determine the index of the nexus it was processing
        !           246:      * when the interrupt occurred. The script will invalidate the index if there
        !           247:      * is no target currently connected or the script cannot determine which target
        !           248:      * has reconnected.
        !           249:      */
        !           250:     nexusIndex = EndianSwap32(SCRIPT_VAR(R_ld_nexus_index));
        !           251:     if ( nexusIndex >= MAX_SCSI_TAG )
        !           252:     {
        !           253:         [self Sym8xxProcessNoNexus];
        !           254:         return;
        !           255:     }
        !           256:     nexus  = adapter->nexusPtrsVirt[nexusIndex];        
        !           257:     if ( nexus == (Nexus *) -1 )
        !           258:     {
        !           259:         [self Sym8xxProcessNoNexus];
        !           260:         return;
        !           261:     }
        !           262:     srb = (SRB *)((u_int32_t)nexus - offsetof(SRB, nexus));  
        !           263: 
        !           264:     scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_phase_handler];
        !           265:    
        !           266:     /*   
        !           267:      * Parity and SCSI Gross Errors.
        !           268:      *
        !           269:      * Abort the current connection. The abort completion will trigger
        !           270:      * clean-up of the current SRB/Nexus.
        !           271:      */
        !           272:     if ( sistReg & PAR )
        !           273:     {  
        !           274:          srb->srbSCSIResult = SR_IOST_PARITY;
        !           275:          [self Sym8xxAbortCurrent: srb];
        !           276:     }
        !           277: 
        !           278:     else if ( sistReg & SGE )
        !           279:     {
        !           280:          srb->srbSCSIResult = SR_IOST_BV;
        !           281:          [self Sym8xxAbortCurrent: srb];
        !           282:     }
        !           283:        
        !           284:     /*
        !           285:      * Unexpected disconnect. 
        !           286:      *
        !           287:      * If we were currently trying to abort this connection then mark the abort
        !           288:      * as completed. For all cases clean-up and wake-up the client thread.
        !           289:      */ 
        !           290:     else if ( sistReg & UDC )
        !           291:     {
        !           292:         if ( srb->srbSCSIResult == SR_IOST_GOOD )
        !           293:         {
        !           294:             srb->srbSCSIResult = SR_IOST_BV;
        !           295:         }
        !           296:         adapter->nexusPtrsVirt[nexusIndex] = (Nexus *) -1;
        !           297:         adapter->nexusPtrsPhys[nexusIndex] = (Nexus *) -1;
        !           298: 
        !           299:         if ( scriptPhase == A_kphase_ABORT_CURRENT )
        !           300:         {
        !           301:             abortCurrentSRB = NULL;
        !           302:         }
        !           303: 
        !           304:         [srb->srbCmdLock unlockWith: ksrbCmdComplete];  
        !           305: 
        !           306:         scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_select_phase];
        !           307:     }
        !           308: 
        !           309:     /*
        !           310:      * Phase Mis-match
        !           311:      *
        !           312:      * If we are in MsgOut phase then calculate how much of the message we sent. For
        !           313:      * now, however, we dont handle the target rejecting messages, so the request is aborted.
        !           314:      *
        !           315:      * If we are in DataIn/DataOut phase. We update the SRB/Nexus with our current data 
        !           316:      * pointers.
        !           317:      */
        !           318:     else if ( sistReg & MA )
        !           319:     {
        !           320:         if ( scriptPhase == A_kphase_MSG_OUT )
        !           321:         {
        !           322:             srb->srbMsgResid = [self Sym8xxCheckFifo:srb FifoCnt:&fifoCnt];
        !           323:             nexus->msg.ppData   = EndianSwap32( EndianSwap32(nexus->msg.ppData) + EndianSwap32(nexus->msg.length) 
        !           324:                                          - srb->srbMsgResid );
        !           325:             nexus->msg.length   = EndianSwap32( srb->srbMsgResid );
        !           326: 
        !           327:             [self Sym8xxAbortCurrent: srb];
        !           328:         }
        !           329:         else if ( (scriptPhase == A_kphase_DATA_OUT) || (scriptPhase == A_kphase_DATA_IN) )
        !           330:         {
        !           331:             [self Sym8xxAdjustDataPtrs:srb Nexus:nexus];
        !           332:         }
        !           333:         else
        !           334:         {
        !           335: //          kprintf("SCSI(Symbios8xx): Unexpected phase mismatch - scriptPhase = %08x\n\r", scriptPhase);
        !           336:             srb->srbSCSIResult = SR_IOST_BV;
        !           337:             [self Sym8xxAbortCurrent: srb];
        !           338:         }
        !           339: 
        !           340:         [self Sym8xxClearFifo];
        !           341:     }
        !           342:     
        !           343:     /*
        !           344:      * Selection Timeout.
        !           345:      *
        !           346:      * Clean-up the current request.
        !           347:      */
        !           348:     else if ( sistReg & STO )
        !           349:     {
        !           350:         srb->srbSCSIResult = SR_IOST_SELTO;
        !           351: 
        !           352:         adapter->nexusPtrsVirt[nexusIndex] = (Nexus *) -1;
        !           353:         adapter->nexusPtrsPhys[nexusIndex] = (Nexus *) -1;
        !           354:         SCRIPT_VAR(R_ld_IOdone_mailbox)    = 0;
        !           355: 
        !           356:         [srb->srbCmdLock unlockWith: ksrbCmdComplete];  
        !           357: 
        !           358:         scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_select_phase];
        !           359:     }
        !           360:         
        !           361:     /*
        !           362:      * Handle script initiated interrupts
        !           363:      */
        !           364:     else if ( dstatReg & SIR )
        !           365:     {
        !           366:         dspsReg = Sym8xxReadRegs( chipBaseAddr, DSPS, DSPS_SIZE );
        !           367: 
        !           368:         switch ( dspsReg )
        !           369:         {
        !           370:             /* 
        !           371:              * Non-zero SCSI status
        !           372:              *
        !           373:              * Send request sense CDB or complete request depending on SCSI status value
        !           374:              */
        !           375:             case A_status_error:
        !           376:                 if ( [self Sym8xxProcessStatus:srb] == NO )
        !           377:                 {
        !           378:                     [self Sym8xxProcessIODone];
        !           379:                 }
        !           380:                 break;
        !           381:              
        !           382:             /*
        !           383:              * Received SDTR/WDTR message from target.
        !           384:              *
        !           385:              * Prepare reply message if we requested negotiation. Otherwise reject
        !           386:              * target initiated negotiation.
        !           387:              */
        !           388:            case A_negotiateSDTR:
        !           389:                 [self Sym8xxNegotiateSDTR:srb Nexus: nexus];
        !           390:                 break;
        !           391: 
        !           392:            case A_negotiateWDTR:
        !           393:                 [self Sym8xxNegotiateWDTR:srb Nexus: nexus];
        !           394:                 break;
        !           395: 
        !           396:             /*
        !           397:              * Partial SG List completed.
        !           398:              *
        !           399:              * Refresh the list from the remaining addresses to be transfered and set the
        !           400:              * script engine to branch into the list.
        !           401:              */
        !           402:             case A_sglist_complete:
        !           403:                 [self Sym8xxUpdateSGList:srb];
        !           404:                 scriptRestartAddr = (u_int32_t)&srb->srbPhys->nexus.sgListData[2];
        !           405:                 break;
        !           406: 
        !           407:             /*
        !           408:              * Completed abort request
        !           409:              *
        !           410:              * Clean-up the aborted request.
        !           411:              */
        !           412:            case A_abort_current:       
        !           413:                 if ( srb->srbSCSIResult == SR_IOST_GOOD )
        !           414:                 {
        !           415:                     srb->srbSCSIResult = SR_IOST_BV;
        !           416:                 }
        !           417: 
        !           418:                 adapter->nexusPtrsVirt[nexusIndex] = (Nexus *) -1;
        !           419:                 adapter->nexusPtrsPhys[nexusIndex] = (Nexus *) -1; 
        !           420: 
        !           421:                 abortCurrentSRB = NULL;
        !           422: 
        !           423:                 [srb->srbCmdLock unlockWith: ksrbCmdComplete];  
        !           424: 
        !           425:                 scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_select_phase];
        !           426:                 break;
        !           427:     
        !           428:             /*
        !           429:              * Script detected protocol errors
        !           430:              *
        !           431:              * Abort the current request.
        !           432:              */
        !           433:             case A_unknown_msg_reject:
        !           434:             case A_unknown_phase:
        !           435:             case A_unexpected_msg:
        !           436:             case A_unexpected_ext_msg:
        !           437:                 srb->srbSCSIResult = SR_IOST_TABT;
        !           438:                 [self Sym8xxAbortCurrent: srb];
        !           439:                 break;
        !           440: 
        !           441:             default:
        !           442:                 kprintf( "SCSI(Symbios8xx): Unknown Script Int = %08x\n\r", dspsReg );
        !           443:                 srb->srbSCSIResult = SR_IOST_INT;
        !           444:                 [self Sym8xxAbortCurrent: srb];
        !           445:         }
        !           446:     }
        !           447: 
        !           448:     /*
        !           449:      * Illegal script instruction.
        !           450:      *
        !           451:      * We're toast! Abort the current request and hope for the best!
        !           452:      */
        !           453:     else if ( dstatReg & IID )
        !           454:     {
        !           455:         dspReg  = Sym8xxReadRegs( chipBaseAddr, DSP, DSP_SIZE );
        !           456: 
        !           457:         kprintf("SCSI(Symbios8xx): Illegal script instruction - dsp = %08x srb=%08x\n\r", dspReg, (u_int32_t)srb );
        !           458: 
        !           459:         srb->srbSCSIResult = SR_IOST_INT;
        !           460:         [self Sym8xxAbortCurrent: srb];
        !           461:     }
        !           462: 
        !           463:     if ( scriptRestartAddr )
        !           464:     {
        !           465:         Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr );
        !           466:     }
        !           467: }    
        !           468: 
        !           469: /*-----------------------------------------------------------------------------*
        !           470:  * Handle non-zero SCSI status
        !           471:  *
        !           472:  * Returns: 
        !           473:  *    NO  - Clean-up request now.
        !           474:  *    YES - Wait for request sense to complete.
        !           475:  *
        !           476:  * This routine filter's out BUSY and more arcane SCSI status conditions,
        !           477:  * leaving CHECK_CONDITION, for which it set's up a request sense operation.
        !           478:  *
        !           479:  *-----------------------------------------------------------------------------*/
        !           480: - (BOOL) Sym8xxProcessStatus: (SRB *) srb;
        !           481: {
        !           482:     IODoneMailBox              *pMailBox;
        !           483: 
        !           484:     scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_select_phase];
        !           485:  
        !           486:     pMailBox = (IODoneMailBox *)&SCRIPT_VAR(R_ld_IOdone_mailbox);
        !           487: 
        !           488:     /*
        !           489:      * If a previous request sense failed, then clean-up the request now.
        !           490:      */
        !           491:     if ( srb->srbState != ksrbStateCDBDone )
        !           492:     {
        !           493:         if ( srb->srbSCSIResult == SR_IOST_GOOD )
        !           494:         {
        !           495:             srb->srbSCSIResult = SR_IOST_CHKSNV;
        !           496:         }
        !           497:         return NO;
        !           498:     }
        !           499: 
        !           500:     /*
        !           501:      * Update the SRB with our byte transferred count and SCSI status.
        !           502:      * This information needs to be captured before we issue the request
        !           503:      * sense.
        !           504:      */
        !           505:     srb->srbSCSIStatus = pMailBox->status;
        !           506: 
        !           507:     [self Sym8xxUpdateXferOffset: srb];
        !           508: 
        !           509:     if ( pMailBox->status != STAT_CHECK )
        !           510:     {
        !           511:         srb->srbSCSIResult = ST_IOST_BADST;
        !           512:         return NO;
        !           513:     }
        !           514:     if ( srb->senseData == NULL )
        !           515:     {
        !           516:         srb->srbSCSIResult = SR_IOST_CHKSNV;
        !           517:         return NO;
        !           518:     }
        !           519: 
        !           520:     [self Sym8xxIssueRequestSense: srb];
        !           521: 
        !           522:     return YES;
        !           523: }
        !           524: 
        !           525: /*-----------------------------------------------------------------------------*
        !           526:  * Prepare request sense request.
        !           527:  *
        !           528:  *-----------------------------------------------------------------------------*/
        !           529: - (void) Sym8xxIssueRequestSense:(SRB *) srb
        !           530: {
        !           531:     IODoneMailBox              *pMailBox;
        !           532:     u_int32_t                  reqSenseMailBox;
        !           533: 
        !           534:     pMailBox = (IODoneMailBox *)&SCRIPT_VAR(R_ld_IOdone_mailbox);
        !           535: 
        !           536:     /*
        !           537:      * We put the request sense Nexus in the last completed script mailbox and
        !           538:      * back-up the script's mailbox pointer.
        !           539:      */
        !           540:     reqSenseMailBox = (u_int8_t)(EndianSwap32(SCRIPT_VAR(R_ld_counter)) - 1);
        !           541:     SCRIPT_VAR(R_ld_counter) = EndianSwap32( reqSenseMailBox );
        !           542: 
        !           543:     srb->srbTimeout = kReqSenseTimeoutMS / kSCSITimerIntervalMS + 1; 
        !           544: 
        !           545:     srb->srbState      = ksrbStateReqSenseDone;
        !           546:     srb->srbSCSIResult = SR_IOST_CHKSV;
        !           547: 
        !           548:     /*
        !           549:      * Reuse the original Nexus struct. The original CDB is not preserved. The
        !           550:      * original status and transfer counts and tag are kept in the SRB.
        !           551:      */
        !           552:     bzero( &srb->nexus.cdbData, 6 );
        !           553:     srb->nexus.cdbData.cdb_c6.c6_opcode = C6OP_REQSENSE;
        !           554:     srb->nexus.cdbData.cdb_c6.c6_lun    = srb->lun;
        !           555:     srb->nexus.cdbData.cdb_c6.c6_len    = srb->senseDataLength;
        !           556:     srb->nexus.cdb.length               = EndianSwap32( 6 );
        !           557: 
        !           558:     /* 
        !           559:      * Force renegotiation on request sense.
        !           560:      */
        !           561:     targets[srb->target].flags &= ~(kTFXferSync | kTFXferWide16);
        !           562:     srb->srbRequestFlags       &= ~(ksrbRFCmdQueueAllowed | ksrbRFDisconnectAllowed);
        !           563:     [self Sym8xxCalcMsgs:srb];
        !           564: 
        !           565:     /*
        !           566:      * Create a new SG List for the request sense data
        !           567:      *
        !           568:      */
        !           569:     srb->xferOffset        = 0;
        !           570:     srb->xferOffsetPrev    = 0;
        !           571:     srb->xferClient        = IOVmTaskSelf();
        !           572:     srb->xferBuffer        = srb->senseData;
        !           573:     srb->xferCount         = srb->senseDataLength;
        !           574:     srb->directionMask     = 0x01000000;
        !           575:     srb->nexus.ppSGList    = (SGEntry *)EndianSwap32((u_int32_t)&srb->srbPhys->nexus.sgListData[2]);
        !           576:     [self Sym8xxUpdateSGList: srb];
        !           577: 
        !           578:     /*
        !           579:      * If the original request was using cmd-queuing, we clean-up the original tagged request
        !           580:      * and convert it to a non-tagged request sense.
        !           581:      */
        !           582:     if ( srb->nexus.tag >= MIN_SCSI_TAG )
        !           583:     {
        !           584:         adapter->nexusPtrsVirt[pMailBox->nexus] = (Nexus *) -1;
        !           585:         adapter->nexusPtrsPhys[pMailBox->nexus] = (Nexus *) -1;
        !           586: 
        !           587:         srb->nexus.tag  = (srb->target << 3) | srb->lun;
        !           588:         adapter->nexusPtrsVirt[srb->nexus.tag] = &srb->nexus;
        !           589:         adapter->nexusPtrsPhys[srb->nexus.tag] = (Nexus *)EndianSwap32( (u_int32_t)&srb->srbPhys->nexus );
        !           590:     }
        !           591: 
        !           592:     adapter->schedMailBox[reqSenseMailBox]  = (Nexus *)EndianSwap32 ( (u_int32_t)&srb->srbPhys->nexus );
        !           593: 
        !           594:     [self Sym8xxSignalScript: srb];
        !           595: 
        !           596:     SCRIPT_VAR(R_ld_IOdone_mailbox) = 0;
        !           597: }
        !           598: 
        !           599: /*-----------------------------------------------------------------------------*
        !           600:  * Current Data Pointer calculations
        !           601:  * 
        !           602:  * To do data transfers the driver generates a list of script instructions 
        !           603:  * in system storage to deliver data to the requested physical addresses. The
        !           604:  * script branches to the list when the target enters data transfer phase.
        !           605:  *
        !           606:  * When the target changes phase during a data transfer, data is left trapped
        !           607:  * inside the various script engine registers. This routine determines how much
        !           608:  * data was not actually transfered to/from the target and generates a new
        !           609:  * S/G List entry for the partial transfer and a branch back into the original
        !           610:  * S/G list. These script instructions are stored in two reserved slots at the
        !           611:  * top of the original S/G List.
        !           612:  *
        !           613:  *-----------------------------------------------------------------------------*/
        !           614: - (void) Sym8xxAdjustDataPtrs:(SRB *) srb Nexus:(Nexus *) nexus
        !           615: {
        !           616:     u_int32_t          i;
        !           617:     u_int32_t          sgResid;
        !           618:     u_int32_t          fifoCnt;
        !           619:     u_int32_t          dspReg;
        !           620:     u_int32_t          sgDone;
        !           621:     u_int8_t           scntl2Reg;
        !           622:     Nexus              *nexusPhys;
        !           623: 
        !           624:     /*
        !           625:      * Determine SG element residual
        !           626:      *
        !           627:      * This routine returns how much of the current S/G List element the 
        !           628:      * script was processing remains to be sent/received. All the information
        !           629:      * required to do this is stored in the script engine's registers.
        !           630:      */
        !           631:     sgResid = [self Sym8xxCheckFifo:srb FifoCnt:&fifoCnt];
        !           632: 
        !           633:     /*
        !           634:      * Determine which script instruction in our SGList we were executing when
        !           635:      * the target changed phase.
        !           636:      *
        !           637:      * The script engine's dspReg tells us where the script thinks it was. Based
        !           638:      * on the physical address of our current SRB/Nexus we can calculate
        !           639:      * an index into our S/G List.  
        !           640:      */
        !           641:     dspReg  = Sym8xxReadRegs( chipBaseAddr, DSP, DSP_SIZE );
        !           642: 
        !           643:     i = ((dspReg - (u_int32_t)srb->srbPhys->nexus.sgListData) / sizeof(SGEntry)) - 1;
        !           644:        
        !           645:     if ( i > MAX_SGLIST_ENTRIES-1 )
        !           646:     {
        !           647:        kprintf("SCSI(Symbios8xx): Bad sgListIndex\n\r");
        !           648:        [self Sym8xxAbortCurrent: srb];
        !           649:        return;
        !           650:     }
        !           651: 
        !           652:     /* 
        !           653:      * Wide/odd-byte transfers.
        !           654:      *     
        !           655:      * When dealing with Wide data transfers, if a S/G List ends with an odd-transfer count, then a
        !           656:      * valid received data byte is left in the script engine's SWIDE register. The least painful way
        !           657:      * to recover this byte is to construct a small script thunk to transfer one additional byte. The
        !           658:      * script will automatically draw this byte from the SWIDE register rather than the SCSI bus.
        !           659:      * The script thunk then branches back to script's PhaseHandler entrypoint.
        !           660:      * 
        !           661:      */
        !           662:     nexusPhys = &srb->srbPhys->nexus;
        !           663: 
        !           664:     scntl2Reg = Sym8xxReadRegs( chipBaseAddr, SCNTL2, SCNTL2_SIZE );
        !           665:     if ( scntl2Reg & WSR )
        !           666:     {
        !           667:         adapter->xferSWideInst[0] = EndianSwap32( srb->directionMask | 1 );
        !           668:         adapter->xferSWideInst[1] = nexus->sgListData[i].physAddr;
        !           669:         adapter->xferSWideInst[2] = EndianSwap32( 0x80080000 );
        !           670:         adapter->xferSWideInst[3] = EndianSwap32( (u_int32_t)&chipRamAddrPhys[Ent_phase_handler] );
        !           671: 
        !           672:         scriptRestartAddr = (u_int32_t) adapterPhys->xferSWideInst;
        !           673:         
        !           674:         /*
        !           675:          * Note: There is an assumption here that the sgResid count will be > 1. It appears 
        !           676:          *       that the script engine does not generate a phase-mismatch interrupt until 
        !           677:          *       we attempt to move > 1 byte from the SCSI bus and the only byte available is
        !           678:          *       in SWIDE. 
        !           679:          */        
        !           680:         sgResid--;
        !           681:     }
        !           682: 
        !           683:     /*
        !           684:      * Calculate partial S/G List instruction and branch
        !           685:      *
        !           686:      * Fill in slots 0/1 of the SGList based on the SGList index (i) and SGList residual count
        !           687:      * (sgResid) calculated above.
        !           688:      *
        !           689:      */
        !           690:     sgDone  = (EndianSwap32( nexus->sgListData[i].length ) & 0x00ffffff) - sgResid;
        !           691: 
        !           692:     nexus->sgListData[0].length   = EndianSwap32( sgResid | srb->directionMask );
        !           693:     nexus->sgListData[0].physAddr = EndianSwap32( EndianSwap32(nexus->sgListData[i].physAddr) + sgDone );
        !           694:     /*
        !           695:      * If a previously calculated SGList 0 entry was interrupted again, we dont need to calculate
        !           696:      * a new branch address since the previous one is still valid.
        !           697:      */
        !           698:     if ( i != 0 )
        !           699:     {
        !           700:         nexus->sgListData[1].length   = EndianSwap32( 0x80080000 );
        !           701:         nexus->sgListData[1].physAddr = EndianSwap32( (u_int32_t)&nexusPhys->sgListData[i+1] );
        !           702:         nexus->sgNextIndex            = i + 1;
        !           703:     }
        !           704:     nexus->ppSGList = (SGEntry *)EndianSwap32( (u_int32_t) &nexusPhys->sgListData[0] );
        !           705:  
        !           706:     /*
        !           707:      * The script sets this Nexus variable to non-zero each time it calls the driver generated
        !           708:      * S/G list. This allows the driver's completion routines to differentiate between a successful
        !           709:      * transfer vs no data transfer at all.
        !           710:      */
        !           711:     nexus->dataXferCalled = 0;
        !           712: 
        !           713:     return;
        !           714: }
        !           715: 
        !           716: /*-----------------------------------------------------------------------------*
        !           717:  * Determine SG element residual
        !           718:  *
        !           719:  * This routine returns how much of the current S/G List element the 
        !           720:  * script was processing remains to be sent/received. All the information
        !           721:  * required to do this is stored in the script engine's registers.
        !           722:  *
        !           723:  *-----------------------------------------------------------------------------*/
        !           724: - (u_int32_t) Sym8xxCheckFifo: (SRB *) srb FifoCnt:(u_int32_t *)pfifoCnt
        !           725: {
        !           726:     BOOL               fSCSISend;
        !           727:     BOOL               fXferSync;
        !           728:     u_int32_t          scriptPhase     = 0;
        !           729:     u_int32_t          dbcReg          = 0;
        !           730:     u_int32_t          dfifoReg        = 0;
        !           731:     u_int32_t          ctest5Reg       = 0;
        !           732:     u_int8_t           sstat0Reg       = 0;
        !           733:     u_int8_t           sstat1Reg       = 0;
        !           734:     u_int8_t           sstat2Reg       = 0;
        !           735:     u_int32_t          fifoCnt         = 0;
        !           736:     u_int32_t          sgResid         = 0;
        !           737: 
        !           738:     scriptPhase = EndianSwap32( SCRIPT_VAR(R_ld_phase_flag) );
        !           739: 
        !           740:     fSCSISend =  (scriptPhase == A_kphase_DATA_OUT) || (scriptPhase == A_kphase_MSG_OUT);
        !           741:  
        !           742:     fXferSync =  ((scriptPhase == A_kphase_DATA_OUT) || (scriptPhase == A_kphase_DATA_IN)) 
        !           743:                          && (srb->nexus.targetParms.sxferReg & 0x1F);  
        !           744: 
        !           745:     dbcReg = Sym8xxReadRegs( chipBaseAddr, DBC, DBC_SIZE ) & 0x00ffffff;
        !           746: 
        !           747:     if ( !(dstatReg & DFE) )
        !           748:     {
        !           749:         ctest5Reg = Sym8xxReadRegs( chipBaseAddr, CTEST5, CTEST5_SIZE );
        !           750:         dfifoReg  = Sym8xxReadRegs( chipBaseAddr, DFIFO,  DFIFO_SIZE );
        !           751: 
        !           752:         if ( ctest5Reg & DFS )
        !           753:         {
        !           754:             fifoCnt = ((((ctest5Reg & 0x03) << 8) | dfifoReg) - dbcReg) & 0x3ff;
        !           755:         }
        !           756:         else
        !           757:         {
        !           758:             fifoCnt = (dfifoReg - dbcReg) & 0x7f;
        !           759:         }
        !           760:     }
        !           761: 
        !           762:     sstat0Reg = Sym8xxReadRegs( chipBaseAddr, SSTAT0, SSTAT0_SIZE );
        !           763:     sstat2Reg = Sym8xxReadRegs( chipBaseAddr, SSTAT2, SSTAT2_SIZE );
        !           764:  
        !           765:     if ( fSCSISend )
        !           766:     {    
        !           767:         fifoCnt += (sstat0Reg & OLF )  ? 1 : 0;
        !           768:         fifoCnt += (sstat2Reg & OLF1)  ? 1 : 0;
        !           769: 
        !           770:         if ( fXferSync )
        !           771:         {
        !           772:             fifoCnt += (sstat0Reg & ORF )  ? 1 : 0;
        !           773:             fifoCnt += (sstat2Reg & ORF1)  ? 1 : 0;
        !           774:         }
        !           775:     }
        !           776:     else
        !           777:     {
        !           778:         if ( fXferSync )
        !           779:         {
        !           780:             sstat1Reg = Sym8xxReadRegs( chipBaseAddr, SSTAT0, SSTAT0_SIZE );
        !           781:             fifoCnt +=  (sstat1Reg >> 4) | (sstat2Reg & FF4);  
        !           782:         }
        !           783:         else
        !           784:         {
        !           785:             fifoCnt += (sstat0Reg & ILF )  ? 1 : 0;
        !           786:             fifoCnt += (sstat2Reg & ILF1)  ? 1 : 0;
        !           787:         }
        !           788:     }   
        !           789:     
        !           790:     sgResid   = dbcReg + fifoCnt;
        !           791:     *pfifoCnt = fifoCnt;
        !           792: 
        !           793:     return sgResid;
        !           794: }
        !           795: 
        !           796: /*-----------------------------------------------------------------------------*
        !           797:  * Calculate transfer counts.
        !           798:  *
        !           799:  * This routine updates srb->xferDone with the amount of data transferred
        !           800:  * by the last S/G List executed.
        !           801:  *
        !           802:  *-----------------------------------------------------------------------------*/
        !           803: - (void) Sym8xxUpdateXferOffset:(SRB *) srb
        !           804: {
        !           805:     u_int32_t          i;
        !           806:     u_int32_t          xferOffset;
        !           807: 
        !           808:     /*
        !           809:      * srb->xferOffset contains the client buffer offset INCLUDING the range
        !           810:      * covered by the current SGList.
        !           811:      */
        !           812:     xferOffset = srb->xferOffset;
        !           813: 
        !           814:     /*
        !           815:      * If script did not complete the current transfer list then we need to determine
        !           816:      * how much of the list was completed.
        !           817:      */
        !           818:     if ( srb->nexus.dataXferCalled == 0 )
        !           819:     {
        !           820:         /* 
        !           821:          * srb->xferOffsetPrev contains the client buffer offset EXCLUDING the
        !           822:          * range covered by the current SGList.
        !           823:          */
        !           824:         xferOffset = srb->xferOffsetPrev;
        !           825: 
        !           826:         /*
        !           827:          * Calculate bytes transferred for partially completed list.
        !           828:          *
        !           829:          * To calculate the amount of this list completed, we sum the residual amount
        !           830:          * in SGList Slot 0 and the completed list elements 2 to sgNextIndex-1.
        !           831:          */
        !           832:         if ( srb->nexus.sgNextIndex != 0 )
        !           833:         {
        !           834:             xferOffset += EndianSwap32( srb->nexus.sgListData[srb->nexus.sgNextIndex-1].length )
        !           835:                              - EndianSwap32( srb->nexus.sgListData[0].length );
        !           836: 
        !           837:             for ( i=2; i < srb->nexus.sgNextIndex-1; i++ )
        !           838:             {
        !           839:                 xferOffset += EndianSwap32( srb->nexus.sgListData[i].length ) & 0x00ffffff;
        !           840:             }
        !           841:         }
        !           842:     }
        !           843:     
        !           844:     /*
        !           845:      * The script leaves the result of any Ignore Wide Residual message received from the target
        !           846:      * during the transfer.
        !           847:      */
        !           848:     xferOffset -= srb->nexus.wideResidCount;
        !           849: 
        !           850: 
        !           851: #if 0
        !           852:     {
        !           853:         u_int32_t      resid = srb->xferOffset - xferOffset;
        !           854:         if ( resid )
        !           855:         {
        !           856:             kprintf( "SCSI(Symbios8xx): Incomplete transfer - Req Count = %08x Act Count = %08x - srb = %08x\n\r", 
        !           857:                     srb->xferCount, xferOffset, (u_int32_t)srb );
        !           858:         }   
        !           859:     }
        !           860: #endif
        !           861: 
        !           862:     srb->xferDone = xferOffset;
        !           863: }
        !           864: 
        !           865: /*-----------------------------------------------------------------------------*
        !           866:  * No SRB/Nexus Processing.
        !           867:  *
        !           868:  * In some cases (mainly Aborts) not having a SRB/Nexus is normal. In other
        !           869:  * cases it indicates a problem such a reconnection from a target that we
        !           870:  * have no record of.
        !           871:  *
        !           872:  *-----------------------------------------------------------------------------*/
        !           873: - (void) Sym8xxProcessNoNexus
        !           874: {
        !           875:     u_int32_t                  dspsReg;
        !           876:     u_int32_t                  dspReg      = 0;
        !           877:     u_int32_t                  scriptPhase = -1 ;
        !           878: 
        !           879:     scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_select_phase];
        !           880: 
        !           881:     dspsReg = Sym8xxReadRegs( chipBaseAddr, DSPS, DSPS_SIZE );
        !           882: 
        !           883:     scriptPhase = EndianSwap32( SCRIPT_VAR(R_ld_phase_flag) );
        !           884: 
        !           885:     /* 
        !           886:      * If we were trying to abort or disconnect a target and the bus
        !           887:      * is now free we consider the abort to have completed.
        !           888:      */
        !           889:     if ( sistReg & UDC ) 
        !           890:     {
        !           891:         if ( (scriptPhase == A_kphase_ABORT_MAILBOX) && abortSRB )
        !           892:         {
        !           893:             [abortSRB->srbCmdLock unlockWith: ksrbCmdComplete];
        !           894:             abortSRB = (SRB *) NULL;  
        !           895:             SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
        !           896:         }         
        !           897:         else if ( scriptPhase == A_kphase_ABORT_CURRENT )
        !           898:         {
        !           899:             abortCurrentSRB = NULL;
        !           900:         }
        !           901:     }
        !           902:     /*
        !           903:      * If we were trying to connect to a target to send it an abort message, and
        !           904:      * we timed out, we consider the abort as completed.
        !           905:      *
        !           906:      * Note: In this case the target may be hung, but at least its not on the bus.
        !           907:      */
        !           908:     else if ( sistReg & STO )
        !           909:     {
        !           910:         if ( (scriptPhase == A_kphase_ABORT_MAILBOX) && abortSRB )
        !           911:         {
        !           912:             [abortSRB->srbCmdLock unlockWith: ksrbCmdComplete];
        !           913:             abortSRB = (SRB *) NULL;  
        !           914:             SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
        !           915:         }         
        !           916:     }     
        !           917:     
        !           918:     /*
        !           919:      * If the script died, without a vaild nexusIndex, we abort anything that is currently
        !           920:      * connected and hope for the best!
        !           921:      */
        !           922:     else if ( dstatReg & IID )
        !           923:     {
        !           924:         dspReg  = Sym8xxReadRegs( chipBaseAddr, DSP, DSP_SIZE );
        !           925:         kprintf("SCSI(Symbios8xx): Illegal script instruction - dsp = %08x srb=0\n\r", dspReg );
        !           926:         [self Sym8xxAbortCurrent: (SRB *) -1];
        !           927:     }
        !           928: 
        !           929:     /*
        !           930:      * Script signaled conditions
        !           931:      */
        !           932:     else if ( dstatReg & SIR )
        !           933:     {
        !           934:         switch ( dspsReg )
        !           935:         {
        !           936:             case A_abort_current:
        !           937:                 abortCurrentSRB = NULL;
        !           938:                 break;
        !           939:               
        !           940:             case A_abort_mailbox:
        !           941:                 [abortSRB->srbCmdLock unlockWith: ksrbCmdComplete];
        !           942:                 abortSRB = (SRB *) NULL;  
        !           943:                 SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
        !           944:                 break;
        !           945:            
        !           946:             default:
        !           947:                [self Sym8xxAbortCurrent: (SRB *)-1];
        !           948:         }
        !           949:     }             
        !           950:     else
        !           951:     {
        !           952:         [self Sym8xxAbortCurrent: (SRB *)-1];
        !           953:     }
        !           954: 
        !           955:     if ( scriptRestartAddr )
        !           956:     {
        !           957:         Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr );
        !           958:     }
        !           959: }
        !           960:  
        !           961: 
        !           962: /*-----------------------------------------------------------------------------*
        !           963:  * Abort currently connected target.
        !           964:  *
        !           965:  *-----------------------------------------------------------------------------*/
        !           966: - (void) Sym8xxAbortCurrent:(SRB *)srb
        !           967: {
        !           968:     if ( abortCurrentSRB )
        !           969:     {
        !           970:         if ( abortCurrentSRB != srb )
        !           971:         {
        !           972: //          kprintf("SCSI(Symbios8xx): Multiple abort immediate SRBs - resetting\n\r");
        !           973:             [self Sym8xxSCSIBusReset: (SRB *)NULL];
        !           974:         }
        !           975:         return;
        !           976:     }
        !           977:    
        !           978:     abortCurrentSRB        = srb;
        !           979:     abortCurrentSRBTimeout = kAbortTimeoutMS / kSCSITimerIntervalMS + 1; 
        !           980: 
        !           981:     /*
        !           982:      * Issue abort or abort tag depending on whether the is a tagged request
        !           983:      */
        !           984:     SCRIPT_VAR(R_ld_AbortCode) = EndianSwap32( ((srb != (SRB *)-1) && (srb->nexus.tag >= MIN_SCSI_TAG)) ? 0x0d : 0x06 );
        !           985:     scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_issueAbort_BDR];
        !           986: 
        !           987:     [self Sym8xxClearFifo];
        !           988: }
        !           989: 
        !           990: /*-----------------------------------------------------------------------------*
        !           991:  * This routine clears the script engine's SCSI and DMA fifos.
        !           992:  *
        !           993:  *-----------------------------------------------------------------------------*/
        !           994: - (void) Sym8xxClearFifo
        !           995: {
        !           996:     u_int8_t           ctest3Reg;
        !           997:     u_int8_t           stest2Reg;
        !           998:     u_int8_t           stest3Reg;
        !           999: 
        !          1000:     stest2Reg  = Sym8xxReadRegs( chipBaseAddr, STEST2, STEST2_SIZE );
        !          1001:     if ( stest2Reg & ROF )
        !          1002:     {
        !          1003:         Sym8xxWriteRegs( chipBaseAddr, STEST2, STEST2_SIZE, stest2Reg );
        !          1004:     }
        !          1005: 
        !          1006:     ctest3Reg = Sym8xxReadRegs( chipBaseAddr, CTEST3, CTEST3_SIZE );
        !          1007:     ctest3Reg |= CLF;
        !          1008:     Sym8xxWriteRegs( chipBaseAddr, CTEST3, CTEST3_SIZE, ctest3Reg );
        !          1009: 
        !          1010:     stest3Reg = Sym8xxReadRegs( chipBaseAddr, STEST3, STEST3_SIZE );
        !          1011:     stest3Reg |= CSF;
        !          1012:     Sym8xxWriteRegs( chipBaseAddr,STEST3, STEST3_SIZE, stest3Reg );
        !          1013: 
        !          1014:     do
        !          1015:     {
        !          1016:         ctest3Reg = Sym8xxReadRegs( chipBaseAddr, CTEST3, CTEST3_SIZE );
        !          1017:         stest2Reg = Sym8xxReadRegs( chipBaseAddr, STEST3, STEST3_SIZE );
        !          1018:         stest3Reg = Sym8xxReadRegs( chipBaseAddr, STEST3, STEST3_SIZE );
        !          1019:     } 
        !          1020:     while( (ctest3Reg & CLF) || (stest3Reg & CSF) || (stest2Reg & ROF) );            
        !          1021: }
        !          1022: 
        !          1023: /*-----------------------------------------------------------------------------*
        !          1024:  * This routine processes the target's response to our SDTR message.
        !          1025:  * 
        !          1026:  * We calculate the values for the script engine's timing registers
        !          1027:  * for synchronous registers, and update our tables indicating that
        !          1028:  * requested data transfer mode is in-effect.
        !          1029:  *
        !          1030:  *-----------------------------------------------------------------------------*/
        !          1031: - (void) Sym8xxNegotiateSDTR:(SRB *) srb Nexus:(Nexus *)nexus
        !          1032: {
        !          1033:     u_int32_t          x;
        !          1034:     u_int8_t           *pMsg;
        !          1035:     u_int32_t          syncPeriod;
        !          1036:     
        !          1037:     /*
        !          1038:      * If we were not negotiating, the send MsgReject to targets negotiation
        !          1039:      * attempt.
        !          1040:      */
        !          1041:     if ( !(srb->srbRequestFlags & ksrbRFNegotiateSync) )
        !          1042:     {
        !          1043:         [self Sym8xxSendMsgReject: srb];
        !          1044:         return;
        !          1045:     }
        !          1046: 
        !          1047:     /* 
        !          1048:      * Get pointer to negotiation message received from target.
        !          1049:      */
        !          1050:     pMsg = (u_int8_t *) &SCRIPT_VAR(R_ld_message);
        !          1051: 
        !          1052:     /*
        !          1053:      * The target's SDTR response contains the (transfer period / 4).
        !          1054:      *
        !          1055:      * We set our sync clock divisor to 1, 2, or 4 giving us a clock rates
        !          1056:      * of:
        !          1057:      *     80Mhz (Period = 12.5ns), 
        !          1058:      *     40Mhz (Period = 25.0ns)
        !          1059:      *     20Mhz (Period = 50.0ns) 
        !          1060:      *
        !          1061:      * This is further divided by the value in the sxfer reg to give us the final sync clock rate.
        !          1062:      *
        !          1063:      * The requested sync period is scaled up by 1000 and the clock periods are scaled up by 10
        !          1064:      * giving a result scaled up by 100. This is rounded-up and converted to sxfer reg values.
        !          1065:      */
        !          1066:     syncPeriod = (u_int32_t)pMsg[3] << 2;
        !          1067:     if ( syncPeriod < 100 )
        !          1068:     {
        !          1069:         nexus->targetParms.scntl3Reg |= SCNTL3_INIT_875_ULTRA;
        !          1070:         x = (syncPeriod * 1000) / 125;
        !          1071:     }
        !          1072:     else if ( syncPeriod < 200 )
        !          1073:     {
        !          1074:         nexus->targetParms.scntl3Reg  |= SCNTL3_INIT_875_FAST;
        !          1075:         x = (syncPeriod * 1000) / 250;
        !          1076:     }
        !          1077:     else 
        !          1078:     {
        !          1079:         nexus->targetParms.scntl3Reg  |= SCNTL3_INIT_875_SLOW;
        !          1080:         x = (syncPeriod * 1000) / 500;
        !          1081:     }
        !          1082:            
        !          1083:     if ( x % 100 ) x += 100;
        !          1084:     
        !          1085:     /*
        !          1086:      * sxferReg  Bits: 5-0 - Transfer offset
        !          1087:      *                 7-6 - Sync Clock Divisor (0 = sync clock / 4)
        !          1088:      */
        !          1089:     nexus->targetParms.sxferReg = ((x/100 - 4) << 5) | pMsg[4];
        !          1090: 
        !          1091:     /*
        !          1092:      * Update our per-target tables and set-up the hardware regs for this request.
        !          1093:      *
        !          1094:      * On reconnection attempts, the script will use our per-target tables to set-up
        !          1095:      * the scntl3 and sxfer registers in the script engine.
        !          1096:      */
        !          1097:     adapter->targetClocks[srb->target].sxferReg  = nexus->targetParms.sxferReg;
        !          1098:     adapter->targetClocks[srb->target].scntl3Reg = nexus->targetParms.scntl3Reg;
        !          1099: 
        !          1100:     Sym8xxWriteRegs( chipBaseAddr, SCNTL3, SCNTL3_SIZE, nexus->targetParms.scntl3Reg );
        !          1101:     Sym8xxWriteRegs( chipBaseAddr, SXFER,  SXFER_SIZE,  nexus->targetParms.sxferReg );
        !          1102: 
        !          1103:     targets[srb->target].flags |= kTFXferSync;
        !          1104: 
        !          1105:     scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_clearACK];
        !          1106: }
        !          1107:    
        !          1108: /*-----------------------------------------------------------------------------*
        !          1109:  * This routine processes the target's response to our WDTR message.
        !          1110:  *
        !          1111:  * In addition, if there is a pending SDTR message, this routine sends it
        !          1112:  * to the target.
        !          1113:  *
        !          1114:  *-----------------------------------------------------------------------------*/
        !          1115: - (void) Sym8xxNegotiateWDTR:(SRB *) srb Nexus:(Nexus *)nexus
        !          1116: {
        !          1117:     u_int8_t           *pMsg;
        !          1118:     u_int32_t          msgBytesSent;
        !          1119:     u_int32_t           msgBytesLeft;
        !          1120: 
        !          1121:     /*
        !          1122:      * If we were not negotiating, the send MsgReject to targets negotiation
        !          1123:      * attempt.
        !          1124:      */
        !          1125:    if ( !(srb->srbRequestFlags & ksrbRFNegotiateWide) )
        !          1126:     {
        !          1127:         [self Sym8xxSendMsgReject: srb];
        !          1128:         return;
        !          1129:     }
        !          1130: 
        !          1131:     /* 
        !          1132:      * Set Wide (16-bit) vs Narrow (8-bit) data transfer mode based on target's response.
        !          1133:      */
        !          1134:     pMsg = (u_int8_t *) &SCRIPT_VAR(R_ld_message);
        !          1135: 
        !          1136:     if ( pMsg[3] == 1 )
        !          1137:     {
        !          1138:         nexus->targetParms.scntl3Reg |= EWS;
        !          1139:     }
        !          1140:     else
        !          1141:     {
        !          1142:         nexus->targetParms.scntl3Reg &= ~EWS;
        !          1143:     }
        !          1144: 
        !          1145:     /*
        !          1146:      * Update our per-target tables and set-up the hardware regs for this request.
        !          1147:      *
        !          1148:      * On reconnection attempts, the script will use our per-target tables to set-up
        !          1149:      * the scntl3 and sxfer registers in the script engine.
        !          1150:      */
        !          1151: 
        !          1152:     adapter->targetClocks[srb->target].scntl3Reg = nexus->targetParms.scntl3Reg;
        !          1153:     Sym8xxWriteRegs( chipBaseAddr, SCNTL3, SCNTL3_SIZE, nexus->targetParms.scntl3Reg );
        !          1154: 
        !          1155:     targets[srb->target].flags |= kTFXferWide16;
        !          1156: 
        !          1157:     /*
        !          1158:      * If there any pending messages left for the target, send them now, 
        !          1159:      */
        !          1160:     msgBytesSent = EndianSwap32( nexus->msg.length );
        !          1161:     msgBytesLeft = srb->srbMsgLength - msgBytesSent;
        !          1162:     if ( msgBytesLeft )
        !          1163:     {
        !          1164:         nexus->msg.length = EndianSwap32( msgBytesLeft );
        !          1165:         nexus->msg.ppData = EndianSwap32( EndianSwap32( nexus->msg.ppData ) + msgBytesSent );                
        !          1166:         scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_issueMessageOut];
        !          1167:     }
        !          1168: 
        !          1169:     /*
        !          1170:      * Otherwise, tell the script we're done with MsgOut phase.
        !          1171:      */
        !          1172:     else
        !          1173:     {
        !          1174:         scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_clearACK];
        !          1175:     }
        !          1176: }  
        !          1177: 
        !          1178: /*-----------------------------------------------------------------------------*
        !          1179:  * Reject message received from target.
        !          1180:  *
        !          1181:  *-----------------------------------------------------------------------------*/
        !          1182: - (void) Sym8xxSendMsgReject:(SRB *) srb
        !          1183: {
        !          1184:     srb->nexus.msg.ppData = EndianSwap32((u_int32_t)&srb->srbPhys->nexus.msgData);
        !          1185:     srb->nexus.msg.length = EndianSwap32(0x01);
        !          1186:     srb->nexus.msgData[0] = 0x07;
        !          1187: 
        !          1188:     scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_issueMessageOut];
        !          1189: }
        !          1190:   
        !          1191: /*-----------------------------------------------------------------------------*
        !          1192:  * This routine snoops inquiry data.
        !          1193:  *
        !          1194:  * The indirect SCSI Disk driver in driverKit, does not bother to check the target's 
        !          1195:  * capabilities before enabling Synchronous Negotiation or Cmd Queueing. If things 
        !          1196:  * were left to themselves, targets that did not support tags would be broken since 
        !          1197:  * the request comming from driverKit always indicate that tags are allowed.
        !          1198:  *
        !          1199:  *-----------------------------------------------------------------------------*/
        !          1200: - (void) Sym8xxCheckInquiryData: (SRB *)srb
        !          1201: {
        !          1202:     IOMemoryDescriptor                 *mem;
        !          1203:     inquiry_reply_t                    inqData;
        !          1204:     u_int32_t                          inqSize;
        !          1205: 
        !          1206:     bzero( &inqData, sizeof(inqData) );
        !          1207: 
        !          1208:     inqSize = (srb->xferDone < sizeof(inqData)) ? srb->xferDone : sizeof(inqData);
        !          1209: 
        !          1210:     mem = [[ IOSimpleMemoryDescriptor alloc ] initWithAddress: (void *)srb->xferBuffer length: inqSize ];
        !          1211:     [mem setClient: srb->xferClient];
        !          1212: 
        !          1213:     do
        !          1214:     {
        !          1215:         if ( srb->srbSCSIResult != SR_IOST_GOOD )
        !          1216:         {
        !          1217:             continue;
        !          1218:         }
        !          1219:         if ( srb->xferDone < offsetof(inquiry_reply_t, ir_vendorid) )
        !          1220:         {
        !          1221:             continue;
        !          1222:         }
        !          1223:           
        !          1224:         if ( [mem readFromClient: (void *) &inqData count: inqSize] != inqSize )
        !          1225:         {
        !          1226:             continue;
        !          1227:         }
        !          1228:         if ( inqData.ir_qual != DEVQUAL_OK )
        !          1229:         {
        !          1230:             continue;
        !          1231:         }
        !          1232: 
        !          1233:         if ( inqData.ir_wbus16 )
        !          1234:         {
        !          1235:             targets[srb->target].flags |= kTFXferWide16Supported;
        !          1236:         }
        !          1237:         if ( inqData.ir_sync )
        !          1238:         {
        !          1239:            targets[srb->target].flags |= kTFXferSyncSupported;
        !          1240:         }
        !          1241:         if ( inqData.ir_cmdque )
        !          1242:         {
        !          1243:            targets[srb->target].flags |= kTFCmdQueueSupported;
        !          1244:         }
        !          1245:     }
        !          1246:     while ( 0 );
        !          1247:     [mem release];
        !          1248: }
        !          1249: 
        !          1250: 
        !          1251: /*-----------------------------------------------------------------------------*
        !          1252:  * This routine initiates a SCSI Bus Reset.
        !          1253:  *
        !          1254:  * This may be an internally generated request as part of error recovery or
        !          1255:  * a client's bus reset request.
        !          1256:  *
        !          1257:  *-----------------------------------------------------------------------------*/
        !          1258: - (void) Sym8xxSCSIBusReset: (SRB *)srb
        !          1259: {
        !          1260:     if ( srb )
        !          1261:     {
        !          1262:         if ( resetSRB )
        !          1263:         {
        !          1264:             srb->srbSCSIResult = SR_IOST_CMDREJ;
        !          1265:             [srb->srbCmdLock unlockWith: ksrbCmdComplete];  
        !          1266:             return;
        !          1267:         }    
        !          1268:         resetSRB = srb;
        !          1269:     }
        !          1270: 
        !          1271:     Sym8xxWriteRegs( chipBaseAddr, SCNTL1, SCNTL1_SIZE, SCNTL1_SCSI_RST );
        !          1272:     IODelay( 25 );
        !          1273:     Sym8xxWriteRegs( chipBaseAddr, SCNTL1, SCNTL1_SIZE, SCNTL1_INIT );
        !          1274: }
        !          1275:     
        !          1276: /*-----------------------------------------------------------------------------*
        !          1277:  * This routine handles a SCSI Bus Reset interrupt.
        !          1278:  *
        !          1279:  * The SCSI Bus reset may be generated by a target on the bus, internally from
        !          1280:  * the driver's error recovery or from a client request.
        !          1281:  *
        !          1282:  * Once the reset is detected we establish a settle period where new client requests
        !          1283:  * are blocked in the client thread. In addition we flush all currently executing
        !          1284:  * scsi requests back to the client.
        !          1285:  *
        !          1286:  *-----------------------------------------------------------------------------*/
        !          1287: - (void) Sym8xxProcessSCSIBusReset
        !          1288: {
        !          1289:     SRB                        *srb   = 0;
        !          1290:     Nexus              *nexus = 0;
        !          1291:     u_int32_t          i;
        !          1292: 
        !          1293:     /*
        !          1294:      * If we got another bus reset event during the settle period we extend the settle
        !          1295:      * period accordingly.
        !          1296:      */
        !          1297:     if ( resetQuiesceTimer )
        !          1298:     {
        !          1299:         resetQuiesceTimer = kResetQuiesceDelayMS / kSCSITimerIntervalMS + 1;
        !          1300:         return;
        !          1301:     }
        !          1302: 
        !          1303:     resetSeqNum = srbSeqNum;
        !          1304: //  kprintf("SCSI(Symbios8xx): Reset Started - SRB Seq = %d\n\r", resetSeqNum);
        !          1305: 
        !          1306:     /*
        !          1307:      * We take the resetQuiesceSem lock which will block new client thread requests.
        !          1308:      * 
        !          1309:      * Note: The client thread checks resetQuiesceTimer for <> 0 before taking this lock.
        !          1310:      */
        !          1311:     [resetQuiesceSem lock];
        !          1312:     resetQuiesceTimer = kResetQuiesceDelayMS / kSCSITimerIntervalMS + 1;
        !          1313: 
        !          1314:     /*
        !          1315:      * We end any aborts currently in progress
        !          1316:      */
        !          1317:     abortCurrentSRB = (SRB *)NULL;
        !          1318: 
        !          1319:     if ( abortSRB )
        !          1320:     {
        !          1321:         [abortSRB->srbCmdLock unlockWith: ksrbCmdComplete];
        !          1322:         abortSRB = (SRB *) NULL;  
        !          1323:     }
        !          1324: 
        !          1325:    [self Sym8xxClearFifo];
        !          1326: 
        !          1327:    /* 
        !          1328:     * We return anything in our Nexus table back to the client
        !          1329:     */
        !          1330:    for ( i=0; i < MAX_SCSI_TAG; i++ )
        !          1331:     {
        !          1332:         nexus = adapter->nexusPtrsVirt[i];
        !          1333:         if ( nexus == (Nexus *) -1 )
        !          1334:         {
        !          1335:             continue;
        !          1336:         }
        !          1337: 
        !          1338:         srb = (SRB *)((u_int32_t)nexus - offsetof(SRB, nexus));
        !          1339:   
        !          1340:         srb->srbSCSIResult = SR_IOST_RESET;
        !          1341: 
        !          1342:         adapter->nexusPtrsVirt[i] = (Nexus *) -1;
        !          1343:         adapter->nexusPtrsPhys[i] = (Nexus *) -1;
        !          1344: 
        !          1345:         [srb->srbCmdLock unlockWith: ksrbCmdComplete];  
        !          1346:     }
        !          1347: 
        !          1348:     /*
        !          1349:      * We clear the script's request mailboxes. Any work in the script mailboxes is
        !          1350:      * already in the NexusPtr tables so we have already have handled the SRB/Nexus
        !          1351:      * cleanup.
        !          1352:      */
        !          1353:     for ( i=0; i < MAX_SCHED_MAILBOXES; i++ )
        !          1354:     {
        !          1355:         adapter->schedMailBox[i] = 0;
        !          1356:     }
        !          1357: 
        !          1358:     SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
        !          1359:     SCRIPT_VAR(R_ld_IOdone_mailbox)   = 0;
        !          1360:     SCRIPT_VAR(R_ld_counter)          = 0;
        !          1361:     mailBoxIndex                      = 0;
        !          1362: 
        !          1363:     /*
        !          1364:      * Reset the data transfer mode/clocks in our per-target tables back to Async/Narrow 8-bit
        !          1365:      */
        !          1366:     for ( i=0; i < MAX_SCSI_TARGETS; i++ )
        !          1367:     {
        !          1368:         targets[i].flags &= ~(kTFXferSync | kTFXferWide16);
        !          1369: 
        !          1370:         adapter->targetClocks[i].scntl3Reg = SCNTL3_INIT_875;
        !          1371:         adapter->targetClocks[i].sxferReg  = 0;
        !          1372:     }
        !          1373: 
        !          1374:     scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_select_phase];
        !          1375:     Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr );
        !          1376: 
        !          1377: }
        !          1378: 
        !          1379: /*-----------------------------------------------------------------------------*
        !          1380:  * This routine sets the SIGP bit in the script engine's ISTAT
        !          1381:  * register. This signals the script to wake-up for a WAIT for
        !          1382:  * reselection instruction. The script will then check the mailboxes
        !          1383:  * for work to do.
        !          1384:  *
        !          1385:  *-----------------------------------------------------------------------------*/
        !          1386: - (void) Sym8xxSignalScript:(SRB *)srb
        !          1387: {
        !          1388:     Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, SIGP );
        !          1389: }
        !          1390: 
        !          1391: /*-----------------------------------------------------------------------------*
        !          1392:  * Timeout handler.
        !          1393:  *
        !          1394:  * This routine is scheduled and implements timeouts for the driver.
        !          1395:  *
        !          1396:  * The following items are timed:
        !          1397:  *
        !          1398:  * - Reset settle period.
        !          1399:  * - Aborts
        !          1400:  * - SRBs
        !          1401:  *
        !          1402:  *-----------------------------------------------------------------------------*/
        !          1403: - (void) timeoutOccurred
        !          1404: {
        !          1405:     SRB                                *srb;
        !          1406:     Nexus                      *nexus;
        !          1407:     u_int32_t                  i;
        !          1408:     u_int32_t                  nexusIndex;
        !          1409:     u_int32_t                  mailboxNexusIndex = -1;
        !          1410: 
        !          1411:     if ( SCRIPT_VAR( R_ld_IOdone_mailbox ) )
        !          1412:     {
        !          1413:         mailboxNexusIndex = ((IODoneMailBox *)&SCRIPT_VAR(R_ld_IOdone_mailbox))->nexus;
        !          1414:     }
        !          1415: 
        !          1416:     nexusIndex = EndianSwap32( SCRIPT_VAR(R_ld_nexus_index) );
        !          1417: 
        !          1418:     /*
        !          1419:      * If we are in a reset settle period, suspend all other timing. 
        !          1420:      *
        !          1421:      * When the reset settle period completes, return the SRB if the
        !          1422:      * client requested the bus reset. Also unlock the reset semaphore.
        !          1423:      */
        !          1424:     if ( resetQuiesceTimer )
        !          1425:     {
        !          1426:         if ( --resetQuiesceTimer )
        !          1427:         {
        !          1428:             goto timeoutOccurred_Exit;
        !          1429:         }
        !          1430: 
        !          1431:         if ( resetSRB )
        !          1432:         {
        !          1433:             [resetSRB->srbCmdLock unlockWith: ksrbCmdComplete];  
        !          1434:             resetSRB = (SRB *) NULL;
        !          1435:         }
        !          1436: //      kprintf("SCSI(Symbios8xx): Reset Ended - SRB Seq = %d\n\r", srbSeqNum);
        !          1437:         [resetQuiesceSem unlock];
        !          1438:     }
        !          1439: 
        !          1440:     /*
        !          1441:      * Check whether an abort timed out. If it does, then its likely that a target is
        !          1442:      * hung on the bus. In this case the only recourse is to issue a SCSI Bus reset.
        !          1443:      */
        !          1444:     if ( abortCurrentSRB && abortCurrentSRBTimeout )
        !          1445:     {
        !          1446:         if ( !(--abortCurrentSRBTimeout) )
        !          1447:         {
        !          1448: //          kprintf("SCSI(Symbios8xx): Abort Current SRB failed - resetting\n\r");
        !          1449:             [self Sym8xxSCSIBusReset: (SRB *)NULL];
        !          1450:             goto timeoutOccurred_Exit;
        !          1451:         }
        !          1452:     }
        !          1453: 
        !          1454:     if ( abortSRB && abortSRBTimeout )
        !          1455:     {
        !          1456:         if ( !(--abortSRBTimeout) )
        !          1457:         {
        !          1458: //          kprintf("SCSI(Symbios8xx): MailBox abort failed - resetting\n\r");
        !          1459:             [self Sym8xxSCSIBusReset: (SRB *)NULL];
        !          1460:             goto timeoutOccurred_Exit;
        !          1461:         }
        !          1462:     }
        !          1463: 
        !          1464:     /*
        !          1465:      * Scan the Nexus pointer table looking for SRBs to timeout
        !          1466:      */
        !          1467:     for ( i=0; i < MAX_SCSI_TAG; i++ )
        !          1468:     {
        !          1469:          nexus = adapter->nexusPtrsVirt[i];
        !          1470:          if ( nexus == (Nexus *) -1 )
        !          1471:          {
        !          1472:              continue;
        !          1473:          }
        !          1474: 
        !          1475:          srb = (SRB *)((u_int32_t)nexus - offsetof(SRB, nexus));
        !          1476:          if ( srb->srbTimeout )
        !          1477:          {
        !          1478:              if ( !(--srb->srbTimeout) )
        !          1479:              {  
        !          1480: //               kprintf("SCSI(Symbios8xx): Timeout - Target = %d SRB = %08x SRB Seq = %d\n\r", 
        !          1481: //                            srb->target, (u_int32_t)srb, srb->srbSeqNum );
        !          1482: 
        !          1483:                  /* If the SRB we're timing out is in the script's IODone mailbox, then
        !          1484:                   * clear the mailbox in addition to timing out the request.
        !          1485:                   */
        !          1486:                  if ( i == mailboxNexusIndex )
        !          1487:                  {
        !          1488:                      SCRIPT_VAR(R_ld_IOdone_mailbox) = 0;
        !          1489:                  }
        !          1490:                  
        !          1491:                  /* 
        !          1492:                   * If the target for the SRB we're timing out is currently connected on 
        !          1493:                   * the SCSI Bus, then issue an abort. Since it is likely that the script
        !          1494:                   * is running in this scenario, we call a Sym8xxAbortScript to shutdown the
        !          1495:                   * script engine in an orderly fashion.
        !          1496:                   */
        !          1497:                  if ( i == nexusIndex )
        !          1498:                  {
        !          1499:                      [self Sym8xxAbortScript];
        !          1500:                      srb->srbSCSIResult = SR_IOST_IOTO;
        !          1501:                      [self Sym8xxAbortCurrent: srb];
        !          1502:                      Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr );
        !          1503:                  }  
        !          1504:                 
        !          1505:                  /* 
        !          1506:                   * If target for the SRB we're timing out is not on the SCSI bus, then
        !          1507:                   * we mark the request as requiring an Abort and return it to the client
        !          1508:                   * thread. The client thread will then schedule the abort.
        !          1509:                   */ 
        !          1510:                  else
        !          1511:                  {
        !          1512:                      adapter->nexusPtrsVirt[i] = (Nexus *) -1;
        !          1513:                      adapter->nexusPtrsPhys[i] = (Nexus *) -1;
        !          1514:                      
        !          1515:                      srb->srbSCSIResult = SR_IOST_IOTO;
        !          1516:                      srb->srbCmd        = ksrbCmdProcessTimeout;
        !          1517:                      [srb->srbCmdLock unlockWith: ksrbCmdComplete];  
        !          1518:                  }
        !          1519:              }
        !          1520:          }
        !          1521:     }
        !          1522: 
        !          1523:    
        !          1524: timeoutOccurred_Exit: ;
        !          1525:     /*
        !          1526:      * Reschedule the next timer interval.
        !          1527:      */
        !          1528:     ns_timeout((func) Sym8xxTimerReq, (void *) self, (ns_time_t) kSCSITimerIntervalMS * 1000 * 1000, (int)CALLOUT_PRI_THREAD);
        !          1529: }  
        !          1530:   
        !          1531: /*-----------------------------------------------------------------------------*
        !          1532:  * This routine does a mailbox abort.
        !          1533:  *
        !          1534:  * This type of abort is used for targets not currently connected to the SCSI Bus.
        !          1535:  *
        !          1536:  * The script will select the target and send a tag (if required) followed by the
        !          1537:  * appropriate abort message (abort/abort-tag)
        !          1538:  *
        !          1539:  *-----------------------------------------------------------------------------*/
        !          1540: - (void) Sym8xxAbortBdr:(SRB *) srb
        !          1541: {
        !          1542:     IOAbortBdrMailBox                  abortMailBox;
        !          1543: 
        !          1544:     abortSRB        = srb;
        !          1545:     abortSRBTimeout = kAbortTimeoutMS / kSCSITimerIntervalMS + 1; 
        !          1546: 
        !          1547:     /*
        !          1548:      * Setup a script variable containing the abort information.
        !          1549:      */
        !          1550:     abortMailBox.message   = ( srb->nexus.tag < MIN_SCSI_TAG) ? 0x06 : 0x0d;
        !          1551:     abortMailBox.identify  = srb->lun | 0xC0 ;
        !          1552:     abortMailBox.scsi_id   = srb->target;
        !          1553:     abortMailBox.tag       = ( srb->nexus.tag < MIN_SCSI_TAG) ? 0 : srb->nexus.tag;
        !          1554: 
        !          1555:     SCRIPT_VAR(R_ld_AbortBdr_mailbox) = *(u_int32_t *) &abortMailBox;
        !          1556: 
        !          1557:     [self Sym8xxSignalScript: srb];
        !          1558: }
        !          1559: 
        !          1560: /*-----------------------------------------------------------------------------*
        !          1561:  * This routine is used to shutdown the script engine in an orderly fashion.
        !          1562:  *
        !          1563:  * Normally the script engine automatically stops when an interrupt is generated. However,
        !          1564:  * in the case of timeouts we need to change the script engine's dsp reg (instruction pointer).
        !          1565:  * to issue an abort.
        !          1566:  *
        !          1567:  *-----------------------------------------------------------------------------*/
        !          1568: - (void) Sym8xxAbortScript
        !          1569: {
        !          1570:     ns_time_t          currentTime;
        !          1571:     ns_time_t          endTime;
        !          1572: 
        !          1573:     [self disableAllInterrupts];
        !          1574:     
        !          1575:     /*
        !          1576:      * We set the ABRT bit in ISTAT and spin until the script engine acknowledges the
        !          1577:      * abort or we timeout.
        !          1578:      */
        !          1579:     Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, ABRT );
        !          1580:     
        !          1581:     IOGetTimestamp( &endTime );
        !          1582: 
        !          1583:     endTime += (kAbortScriptTimeoutMS * 1000 * 1000);
        !          1584: 
        !          1585:     do
        !          1586:     {
        !          1587:         IOGetTimestamp( &currentTime );
        !          1588: 
        !          1589:         istatReg = Sym8xxReadRegs( chipBaseAddr, ISTAT, ISTAT_SIZE );
        !          1590: 
        !          1591:         if ( istatReg & SIP )
        !          1592:         {
        !          1593:             Sym8xxReadRegs( chipBaseAddr, SIST, SIST_SIZE );
        !          1594:             continue;
        !          1595:         }
        !          1596:     
        !          1597:         if ( istatReg & DIP )
        !          1598:         {
        !          1599:             Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, 0x00 );
        !          1600:             Sym8xxReadRegs( chipBaseAddr, DSTAT, DSTAT_SIZE );
        !          1601:             break;
        !          1602:         }
        !          1603:     }
        !          1604:     while ( currentTime < endTime );
        !          1605:     
        !          1606:     istatReg = SIGP;
        !          1607:     Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, istatReg );
        !          1608: 
        !          1609:     [self enableAllInterrupts];
        !          1610: 
        !          1611:     if ( currentTime >= endTime )
        !          1612:     {
        !          1613: //      kprintf( "SCSI(Symbios8xx): Abort script failed - resetting bus\n\r" );
        !          1614:         [self Sym8xxSCSIBusReset: NULL];
        !          1615:     }  
        !          1616: 
        !          1617:   }
        !          1618:     
        !          1619: @end

unix.superglobalmegacorp.com

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