Annotation of kernel/bsd/dev/ppc/drvApple96_SCSI/Apple96SCSIPrivate.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: /**
        !            26:  * Copyright (c) 1994-1996 NeXT Software, Inc. All rights reserved. 
        !            27:  * Copyright 1997 Apple Computer Inc. All Rights Reserved.
        !            28:  * @author  Martin Minow    mailto:[email protected]
        !            29:  * @revision   1997.02.18  Initial conversion from AMDPCSCSIDriver sources.
        !            30:  *
        !            31:  * Apple96SCSIPrivate.m - "Main" private methods for the 53C96 PCI SCSI interface.
        !            32:  * Apple96SCSI is closely based on Doug Mitchell's AMD 53C974/79C974 driver.
        !            33:  *
        !            34:  * Hmm, these methods are probably common to all Apple SCSI implementations.
        !            35:  *
        !            36:  * Edit History
        !            37:  * 1997.02.13  MM      Initial conversion from AMDPCSCSIDriver sources. 
        !            38:  */
        !            39: 
        !            40: #import "Apple96SCSI.h"
        !            41: #import "Apple96SCSIPrivate.h"
        !            42: #import "Apple96CurioPublic.h"
        !            43: #import "Apple96Hardware.h"
        !            44: #import "bringup.h"
        !            45: #import "MacSCSICommand.h"
        !            46: #import <mach/message.h>
        !            47: #import <driverkit/generalFuncs.h>
        !            48: #import <driverkit/interruptMsg.h>
        !            49: #import <driverkit/align.h>
        !            50: #import <driverkit/kernelDriver.h>
        !            51: #import <kernserv/prototypes.h>
        !            52: 
        !            53: /* 
        !            54:  * Template for command message sent to the I/O thread.
        !            55:  */
        !            56: static const msg_header_t cmdMessageTemplate = {
        !            57:     0,                         /* msg_unused           */
        !            58:     1,                         /* msg_simple           */
        !            59:     sizeof(msg_header_t),      /* msg_size             */ 
        !            60:     MSG_TYPE_NORMAL,           /* msg_type             */
        !            61:     PORT_NULL,                 /* msg_local_port       */
        !            62:     PORT_NULL,                 /* msg_remote_port - filled in  */
        !            63:     IO_COMMAND_MSG             /* msg_id               */
        !            64: };
        !            65: 
        !            66: /*
        !            67:  * Template for timeout message.
        !            68:  */
        !            69: static const msg_header_t timeoutMsgTemplate = {
        !            70:     0,                          /* msg_unused          */
        !            71:     1,                         /* msg_simple           */
        !            72:     sizeof(msg_header_t),      /* msg_size             */ 
        !            73:     MSG_TYPE_NORMAL,           /* msg_type             */
        !            74:     PORT_NULL,                 /* msg_local_port       */
        !            75:     PORT_NULL,                 /* msg_remote_port - filled in  */
        !            76:     IO_TIMEOUT_MSG             /* msg_id               */
        !            77: };
        !            78: 
        !            79: static void                serviceTimeoutInterrupt(
        !            80:        void                    *arg
        !            81:     );
        !            82: 
        !            83: @implementation Apple96_SCSI(Private)
        !            84: 
        !            85: /*
        !            86:  * Private chip- and architecture-independent methods.
        !            87:  */
        !            88: /*
        !            89:  * Pass one CommandBuffer to the I/O thread; wait for completion.
        !            90:  * (We are called on the client's execution thread.)
        !            91:  * Normal completion status is in cmdBuf->scsiReq->driverStatus; 
        !            92:  * a non-zero return from this function indicates a Mach IPC error.
        !            93:  *
        !            94:  * This method allocates and frees cmdBuf->cmdLock.
        !            95:  */
        !            96: - (IOReturn)   executeCmdBuf
        !            97:                        : (CommandBuffer *) cmdBuf
        !            98: {
        !            99:        msg_header_t        msg             = cmdMessageTemplate;
        !           100:        kern_return_t       kernelReturn;
        !           101:        IOReturn            ioReturn        = IO_R_SUCCESS;
        !           102: 
        !           103:        ENTRY("Sex executeCmdBuf");
        !           104:        cmdBuf->flagActive = 0;
        !           105:        cmdBuf->cmdLock = [[NXConditionLock alloc] initWith:CMD_PENDING];
        !           106:        [gIncomingCommandLock lock];
        !           107:        queue_enter(&gIncomingCommandQueue, cmdBuf, CommandBuffer *, link);
        !           108:        [gIncomingCommandLock unlock];
        !           109: 
        !           110:        /*
        !           111:         * Create a Mach message and send it in order to wake up the 
        !           112:         * I/O thread.
        !           113:         */
        !           114:        msg.msg_remote_port = gKernelInterruptPort;
        !           115:        kernelReturn = msg_send_from_kernel(&msg, MSG_OPTION_NONE, 0);
        !           116:        if (kernelReturn != KERN_SUCCESS) {
        !           117:            IOLog("%s: msg_send_from_kernel() error status %d\n", 
        !           118:                [self name],
        !           119:                kernelReturn
        !           120:            );
        !           121:            ioReturn = IO_R_IPC_FAILURE;
        !           122:            goto exit;
        !           123:        }
        !           124: 
        !           125:        /*
        !           126:         * Wait for I/O complete.
        !           127:         */
        !           128:        ddmExported("executeCmdBuf: waiting for completion on cmdBuf 0x%x\n",
        !           129:            cmdBuf, 2,3,4,5);
        !           130:        [cmdBuf->cmdLock lockWhen:CMD_COMPLETE];
        !           131: exit:  RESULT(ioReturn);       /* Log the completion before clearing the lock */
        !           132:        [cmdBuf->cmdLock free];
        !           133:        return (ioReturn);
        !           134: }
        !           135: 
        !           136: /*
        !           137:  * Abort all active and disconnected commands with specified status. No 
        !           138:  * hardware action. Currently used by threadResetBus and during processing
        !           139:  * of a kCommandAbortRequest command. 
        !           140:  */
        !           141: - (void) abortAllCommands : (sc_status_t) status
        !           142: {
        !           143:        ENTRY("Sab abortAllCommands");
        !           144:        ddmThread("abortAllCommands\n", 1,2,3,4,5);
        !           145:        [gIncomingCommandLock lock];
        !           146:        [self killActiveCommand : status];
        !           147:        [self killQueue  : &gDisconnectedCommandQueue   finalStatus : status];
        !           148:        [self killQueue  : &gPendingCommandQueue        finalStatus : status];
        !           149:        [self killQueue  : &gIncomingCommandQueue       finalStatus : status];
        !           150: #ifdef DEBUG
        !           151:        /*
        !           152:         * activeArray "should be" empty...if not, make sure it is for debug.
        !           153:         */
        !           154:        do {
        !           155:            int         target;
        !           156:            int         lun;
        !           157:            int         active;
        !           158:            
        !           159:            for (target = 0; target < SCSI_NTARGETS; target++) {
        !           160:                for (lun = 0; lun < SCSI_NLUNS; lun++) {
        !           161:                    active = gActiveArray[target][lun];
        !           162:                    if (active > 0) {
        !           163:                        IOLog("%s: (abortAllCommands) gActiveArray[%d][%d] = %d, should be zero\n",
        !           164:                            [self name],
        !           165:                            target, lun, active
        !           166:                        );
        !           167:                        gActiveCount -= active;
        !           168:                        gActiveArray[target][lun] = 0;
        !           169:                    }
        !           170:                }
        !           171:            }
        !           172:            if (gActiveCount != 0) {
        !           173:                IOLog("%s: (abortAllCommands) activeCount = %d, should be zero\n",
        !           174:                    [self name],
        !           175:                    gActiveCount
        !           176:                );
        !           177:                gActiveCount = 0;
        !           178:            }
        !           179:        } while (0);
        !           180: #endif DEBUG
        !           181:        [gIncomingCommandLock unlock];
        !           182:        EXIT();
        !           183: }
        !           184: 
        !           185: /*
        !           186:  * Abort all active and disconnected commands with status SR_IOST_RESET.
        !           187:  * Reset hardware and SCSI bus. If there is a command in gPendingCommandQueue,
        !           188:  * start it up.
        !           189:  */
        !           190: - (void)    threadResetBus
        !           191:                        : (const char *) reason
        !           192: {
        !           193:        ENTRY("Str threadResetBus");
        !           194:        [self abortAllCommands : SR_IOST_RESET];
        !           195:        [self hardwareReset : TRUE      reason : reason];   /* Reset SCSI and chip  */
        !           196:        [self busFree];                                 /* Restart commands     */
        !           197:        EXIT();
        !           198: }
        !           199: 
        !           200: /*
        !           201:  * Commence processing of the specified command. This is called by
        !           202:  * commandRequestOccurred when it receives a kCommandExecute message
        !           203:  * from IODirectDevice. There is a new SCSI request. Either start
        !           204:  * it now, or add it to the end of our pending request queue.
        !           205:  */
        !           206: - (void)    threadExecuteRequest
        !           207:                        : (CommandBuffer *) cmdBuf
        !           208: {
        !           209:        ENTRY("Stx threadExecuteRequest");
        !           210:        if (gActiveCommand != NULL) {
        !           211:            /*
        !           212:             * We are currently executing a request.
        !           213:             */
        !           214:            ddmThread("threadExecuteRequest: ACTIVE; deferring 0x%x\n",
        !           215:                cmdBuf,
        !           216:                2,3,4,5
        !           217:            );
        !           218:            queue_enter(&gPendingCommandQueue, cmdBuf, CommandBuffer *, link);
        !           219:        }       
        !           220:        else if ([self commandCanBeStarted:cmdBuf] == NO) {
        !           221:            /*
        !           222:             * This request can't be started right now (perhaps the
        !           223:             * target's tagged command limit has been reached).
        !           224:             */
        !           225:            ddmThread("threadExecuteRequest: !commandCanBeStarted; deferring 0x%x\n",
        !           226:                cmdBuf,
        !           227:                2,3,4,5
        !           228:            );
        !           229:            queue_enter(&gPendingCommandQueue, cmdBuf, CommandBuffer *, link);
        !           230:        }
        !           231:        else {
        !           232:            /*
        !           233:             * Apparently, we can start this request. Call the hardware layer.
        !           234:             */
        !           235:            ddmThread("calling hardwareStart: cmdBuf 0x%x activeArray[%d][%d] = %d\n",
        !           236:                cmdBuf,
        !           237:                cmdBuf->scsiReq->target,
        !           238:                cmdBuf->scsiReq->lun,
        !           239:                gActiveArray[cmdBuf->scsiReq->target][cmdBuf->scsiReq->lun],
        !           240:                5
        !           241:            );  
        !           242:            switch ([self hardwareStart : cmdBuf]) {
        !           243:            case kHardwareStartBusy:            /* Hardware can't start now     */
        !           244:                ddmThread("threadExecuteRequest: hardware busy\n", 1, 2, 3, 4, 5);
        !           245:                break;
        !           246:            case kHardwareStartOK:              /* Command started correctly    */
        !           247:                break;
        !           248:            case kHardwareStartRejected:        /* Command rejected, try another */
        !           249:                ddmThread("threadExecuteRequest: calling busFree\n", 1,2,3,4,5);
        !           250:                [self busFree];                 /* Try another command          */
        !           251:            }
        !           252:            ddmThread("threadExecuteRequest(0x%x): DONE\n", cmdBuf, 2,3,4,5);
        !           253:        }
        !           254:        EXIT();
        !           255: }
        !           256: 
        !           257: /*
        !           258:  * Methods called by hardware-dependent modules.
        !           259:  */
        !           260: 
        !           261: #if TEST_QUEUE_FULL
        !           262: int testQueueFull; /* Set in the debugger to return queue full status */
        !           263: #endif TEST_QUEUE_FULL
        !           264: 
        !           265: /*
        !           266:  * Called when a transaction associated with cmdBuf is complete. Notify 
        !           267:  * waiting thread. If cmdBuf->scsiReq exists (i.e., this is not a reset
        !           268:  * or an abort), scsiReq->driverStatus must be valid. If cmdBuf is active,
        !           269:  * caller must remove from gActiveCommand. We decrement activeArray[][] counter
        !           270:  * if appropriate.
        !           271:  */
        !           272: - (void) ioComplete
        !           273:            : (CommandBuffer *) cmdBuf
        !           274:        finalStatus : (sc_status_t) finalStatus
        !           275: {
        !           276:        ns_time_t               currentTime;
        !           277:        IOSCSIRequest           *scsiReq;
        !           278:        
        !           279:        ENTRY("Sic ioComplete");
        !           280:        ASSERT(cmdBuf != NULL);
        !           281:        if (cmdBuf == gActiveCommand) {
        !           282:            [self deactivateCmd];
        !           283:        }
        !           284:        scsiReq = cmdBuf->scsiReq;
        !           285:        if (scsiReq != NULL) {
        !           286:            if (scsiReq->driverStatus == SR_IOST_INVALID) {
        !           287:                scsiReq->driverStatus = finalStatus;
        !           288:            }
        !           289:            IOGetTimestamp(&currentTime);
        !           290:            scsiReq->totalTime = currentTime - cmdBuf->startTime;
        !           291:            scsiReq->bytesTransferred = cmdBuf->currentDataIndex;
        !           292: #if SERIOUS_DEBUGGING || LOG_COMMAND_AND_RESULT
        !           293:            IOLog("%s: ioComplete %d.%d: Transferred %d bytes, status %d: %s\n",
        !           294:                    [self name],
        !           295:                    scsiReq->target,
        !           296:                    scsiReq->lun,
        !           297:                    scsiReq->bytesTransferred,
        !           298:                    scsiReq->driverStatus,
        !           299:                    IOFindNameForValue(scsiReq->driverStatus, IOScStatusStrings)
        !           300:                );
        !           301: #endif /* SERIOUS_DEBUGGING || LOG_COMMAND_AND_RESULT */
        !           302: #if (SERIOUS_DEBUGGING || DUMP_USER_BUFFER) && __IO_MEMORY_DESCRIPTOR_DEBUG__
        !           303:            if (cmdBuf->mem != NULL) {
        !           304:                IOMemoryDescriptorState         state;
        !           305:                LogicalRange                    range;
        !           306:                unsigned int                    newPosition = 0;
        !           307:     
        !           308:                [cmdbuf->mem state : &state];
        !           309:                [cmdbuf->mem setPosition : 0];
        !           310:                while (newPosition < scsiReq->bytesTransferred
        !           311:                    && [cmdbuf->mem getLogicalRange : 1
        !           312:                            maxByteCount            : scsiReq->bytesTransferred - newPosition
        !           313:                            newPosition             : &newPosition
        !           314:                            actualRanges            : NULL
        !           315:                            logicalRanges           : &range] != 0) {
        !           316:                    [self logMemory         : range.address
        !           317:                            length          : range.length
        !           318:                            reason          : "User buffer at I/O Complete"
        !           319:                    ];
        !           320:                }
        !           321:                [cmdbuf->mem setState : &state];
        !           322:            }
        !           323: #endif /* (SERIOUS_DEBUGGING || DUMP_USER_BUFFER) && __IO_MEMORY_DESCRIPTOR_DEBUG__ */
        !           324:            /*
        !           325:             * Catch bad SCSI status now.
        !           326:             */
        !           327:            if (scsiReq->driverStatus == SR_IOST_GOOD) {
        !           328: #if TEST_QUEUE_FULL
        !           329:                if (testQueueFull
        !           330:                 && (activeArray[scsiReq->target][scsiReq->lun] > 1)) {
        !           331:                    scsiReq->scsiStatus = STAT_QUEUE_FULL;
        !           332:                    testQueueFull = 0;
        !           333:                }
        !           334: #endif  TEST_QUEUE_FULL
        !           335:                if (cmdBuf->flagIsAutosense) {
        !           336:                    /*
        !           337:                     * We are completing an autosense command. Don't touch
        !           338:                     * the request status (it should still be Check Condition).
        !           339:                     * Queue full is a real problem.
        !           340:                     */
        !           341:                    ASSERT(scsiReq->scsiStatus == kScsiStatusCheckCondition);
        !           342:                    switch (cmdBuf->autosenseStatus) {
        !           343:                    case kScsiStatusGood:
        !           344:                        bcopy(gAutosenseArea, &scsiReq->senseData, sizeof (esense_reply_t));
        !           345: #if SERIOUS_DEBUGGING || DUMP_USER_BUFFER
        !           346:                        [self logMemory         : &scsiReq->senseData
        !           347:                                length          : sizeof (esense_reply_t)
        !           348:                                reason          : "Autosense at I/O completion"
        !           349:                        ];
        !           350: #endif /* SERIOUS_DEBUGGING || DUMP_USER_BUFFER */
        !           351:                        scsiReq->driverStatus = SR_IOST_CHKSV;
        !           352:                        break;
        !           353:                    case kScsiStatusQueueFull:
        !           354:                        if ([self pushbackFullTargetQueue : cmdBuf] == SR_IOST_GOOD) {
        !           355:                            ddmThread("ioComplete: queue full after autosense\n", 1, 2, 3, 4, 5);
        !           356:                            goto exit;
        !           357:                        }
        !           358:                        /* Fall through to failure */
        !           359:                    default:
        !           360:                        scsiReq->driverStatus = SR_IOST_CHKSNV;
        !           361:                        break;
        !           362:                    }
        !           363:                }
        !           364:                else { /* Normal command: not autosense */
        !           365:                    switch (scsiReq->scsiStatus) {
        !           366:                    case kScsiStatusGood:
        !           367:        
        !           368:                        /* If this was an Inquiry, peek at the data     */
        !           369:                        /* for Synchronous and Tagged Queuing support:  */
        !           370:        
        !           371:                        if ( (*(UInt8*)&scsiReq->cdb == kScsiCmdInquiry)
        !           372:                         &&  (cmdBuf->currentDataIndex > 7)
        !           373:                         &&  (cmdBuf->mem != NULL) ) {
        !           374:                            IOMemoryDescriptorState             state;
        !           375:                            UInt8                               byte;
        !           376:                            unsigned int                        count;
        !           377:                            
        !           378:                            [cmdBuf->mem state : &state];
        !           379:                            [cmdBuf->mem setPosition : 7];
        !           380:                            count = [cmdBuf->mem readFromClient : &byte count : 1];
        !           381:                            [cmdBuf->mem setState : &state];
        !           382:                            if (count == 1) {
        !           383:                                gPerTargetData[ scsiReq->target ].inquiry_7 = byte;
        !           384:                                if ( (byte & 0x02) == 0) {
        !           385:                                    gPerTargetData[ scsiReq->target ].cmdQueueDisable = TRUE;
        !           386:                                }
        !           387:                            }
        !           388:                        } /* end if successful inquiry completion */
        !           389:                        break;
        !           390:                    case kScsiStatusCheckCondition:
        !           391:                        /*
        !           392:                         * ** ** ** The 386 SIM supresses autosense for Test
        !           393:                         * ** ** ** Unit Ready to avoid request sense when polling
        !           394:                         * ** ** ** for removable devices. This should be the caller's
        !           395:                         * ** ** ** decision.
        !           396:                         */
        !           397:                        if ( gOptionAutoSenseEnable                     /* Supress for debugging        */
        !           398:                         && (scsiReq->ignoreChkcond == FALSE) ) {
        !           399:                            cmdBuf->flagIsAutosense = 1;    /* We're doing autosense    */
        !           400:                            queue_enter_first(&gPendingCommandQueue, cmdBuf, CommandBuffer *, link);
        !           401:                            ddmThread("ioComplete: queuing for autosense\n", 1, 2, 3, 4, 5);
        !           402:                            goto exit;
        !           403:                        }
        !           404:                        else {
        !           405:                            /*
        !           406:                             * This command failed and we aren't doing autosense.
        !           407:                             */                 
        !           408:                            scsiReq->driverStatus = SR_IOST_CHKSNV;
        !           409:                        }
        !           410:                        break;
        !           411:                    case kScsiStatusQueueFull:
        !           412:                        if ([self pushbackFullTargetQueue : cmdBuf] == SR_IOST_GOOD) {
        !           413:                            /*
        !           414:                             * ioComplete target tagged, queue full
        !           415:                             */
        !           416:                            ddmThread("ioComplete: target tagged, queue full\n", 1, 2, 3, 4, 5);
        !           417:                            goto exit;
        !           418:                        }
        !           419:                        /* Huh? we weren't doing tagged queuing, fall through */
        !           420:                    default:
        !           421:                        scsiReq->driverStatus = SR_IOST_BADST;
        !           422:                        break;
        !           423:                    } /* switch */
        !           424:                } /* If not autosense */
        !           425:            } /* if scsiReq->driverStatus == SR_IOST_GOOD on entrance */
        !           426:        } /* if (scsiReq != NULL) */
        !           427: #if DDM_DEBUG
        !           428:        do {
        !           429:            const char          *status;
        !           430:            unsigned            moved;
        !           431:            
        !           432:            if (scsiReq != NULL) {
        !           433:                status = IOFindNameForValue(scsiReq->driverStatus, 
        !           434:                    IOScStatusStrings);
        !           435:                moved = scsiReq->bytesTransferred;
        !           436:            }
        !           437:            else {
        !           438:                status = "Complete";
        !           439:                moved = 0;
        !           440:            }
        !           441:            ddmThread("ioComplete: cmdBuf 0x%x status %s bytesXfr 0x%x\n", 
        !           442:                cmdBuf, status, moved,4,5);
        !           443:        } while (0);
        !           444: #if LOG_RESULT_ON_ERROR
        !           445:        if (scsiReq != NULL && scsiReq->driverStatus != SR_IOST_GOOD) {
        !           446:            [self logCommand
        !           447:                                : cmdBuf
        !           448:                logMemory       : TRUE
        !           449:                reason          : "Unsuccessful result"
        !           450:            ];
        !           451:        }
        !           452: #endif /* LOG_RESULT_ON_ERROR */
        !           453: #endif DDM_DEBUG
        !           454:        [cmdBuf->cmdLock lock];
        !           455:        [cmdBuf->cmdLock unlockWith:YES];
        !           456: exit:  ; /* This semicolon is needed to prevent errors in the EXIT macro */
        !           457:        EXIT();
        !           458: }
        !           459: 
        !           460: /**
        !           461:  * A target reported a full queue. Push this command back on the pending
        !           462:  * queue and try it again, later. (Return SR_IOST_GOOD if successful,
        !           463:  * SR_IOST_BADST on failure.
        !           464:  */
        !           465: - (sc_status_t) pushbackFullTargetQueue
        !           466:                            : (CommandBuffer *) cmdBuf
        !           467: {
        !           468:        IOSCSIRequest           *scsiReq;
        !           469:        int                     target;
        !           470:        int                     lun;
        !           471:        IOReturn                ioReturn;
        !           472: 
        !           473:        ENTRY("Spf pushbackFullTargetQueue");
        !           474:        ASSERT(cmdBuf != NULL && cmdBuf->scsiReq != NULL);
        !           475:        ASSERT(cmdBuf != gActiveCommand);
        !           476:        /*
        !           477:         * Avoid notifying client of this condition; update
        !           478:         * perTarget.maxQueue and place this request on gPendingCommandQueue.
        !           479:         * We'll try this again when we ioComplete at least one
        !           480:         * command in this target's queue.
        !           481:         ** ** ** Note that this can execute commands out of order.
        !           482:         ** ** ** This can be disasterous for directory commands.
        !           483:         ** ** ** In the long run, the client (disk/tape/whatever)
        !           484:         ** ** ** needs to tell us how to execute the command
        !           485:         ** ** ** (in-order, out-of-order, etc.) For example,
        !           486:         ** ** ** virtual-memory page faults can be executed
        !           487:         ** ** ** out of order, but directory and volume bitmap
        !           488:         ** ** ** updates must be executed in-order to preserve
        !           489:         ** ** ** volume integrity.
        !           490:         */
        !           491:        if (cmdBuf->queueTag == QUEUE_TAG_NONTAGGED) {
        !           492:            /*
        !           493:             * Huh? We're not doing command queueing...
        !           494:             */
        !           495:            ioReturn = SR_IOST_BADST;
        !           496:        }
        !           497:        else {
        !           498:            scsiReq     = cmdBuf->scsiReq;
        !           499:            target      = scsiReq->target;
        !           500:            lun         = scsiReq->lun;
        !           501:            gPerTargetData[target].maxQueue = gActiveArray[target][lun];
        !           502:            ddmThread("Target %d queue full, maxQueue set to %d\n",
        !           503:                target,
        !           504:                gPerTargetData[target].maxQueue,
        !           505:                3,4,5
        !           506:            );
        !           507:            [self pushbackCurrentRequest : cmdBuf];
        !           508:            ioReturn = SR_IOST_GOOD;
        !           509:        }
        !           510:        RESULT(ioReturn);
        !           511:        return (ioReturn);
        !           512: }
        !           513: 
        !           514: /**
        !           515:  * Push this request back on the pending queue.
        !           516:  */
        !           517: - (void) pushbackCurrentRequest
        !           518:                : (CommandBuffer *) cmdBuf
        !           519: {
        !           520:        ENTRY("Spc pushbackCurrentRequest");
        !           521:        if (gActiveCommand != NULL) {
        !           522:            [self deactivateCmd];
        !           523:        }
        !           524:        queue_enter_first(&gPendingCommandQueue, cmdBuf, CommandBuffer *, link);
        !           525:        EXIT();
        !           526: }
        !           527: 
        !           528: #if 0
        !           529: /**
        !           530:  * Kill a request that can't be continued.
        !           531:  */
        !           532: - (void) killCurrentRequest
        !           533: {
        !           534:        ENTRY("Skc killCurrentRequest");
        !           535:        if (gActiveCommand != NULL) {
        !           536:            if (gActiveCommand->scsiReq != NULL
        !           537:             && gActiveCommand->scsiReq->driverStatus == SR_IOST_INVALID) {
        !           538:                if (gCurrentBusPhase == kBusPhaseBusFree) {
        !           539:            gActiveCommand->scsiReq->driverStatus = SR_IOST_SELTO;  /* No such device   */
        !           540:                }
        !           541:                else {
        !           542:            gActiveCommand->scsiReq->driverStatus = SR_IOST_HW;     /* Target went away */
        !           543:                }
        !           544:            }
        !           545:            [self ioComplete
        !           546:                                : gActiveCommand
        !           547:                finalStatus     : SR_IOST_INVALID
        !           548:            ];
        !           549:        }
        !           550:        EXIT();
        !           551: }
        !           552: #endif
        !           553: 
        !           554: /*
        !           555:  * I/O associated with gActiveCommand has disconnected. Place it on the
        !           556:  * disconnected command queue and enable another transaction.
        !           557:  */ 
        !           558: - (void) disconnect
        !           559: {
        !           560:        ENTRY("Sdi disconnect");
        !           561:        ASSERT(gActiveCommand != NULL);
        !           562:        ddmThread("DISCONNECT: cmdBuf 0x%x target %d lun %d tag %d\n",
        !           563:            gActiveCommand, gActiveCommand->scsiReq->target,
        !           564:            gActiveCommand->scsiReq->lun, gActiveCommand->queueTag, 5);
        !           565:        queue_enter(
        !           566:            &gDisconnectedCommandQueue,
        !           567:            gActiveCommand,
        !           568:            CommandBuffer *,
        !           569:            link
        !           570:        );
        !           571: #if DDM_DEBUG
        !           572:        if ((gActiveCommand->currentDataIndex != gActiveCommand->scsiReq->maxTransfer)
        !           573:         && (gActiveCommand->currentDataIndex != 0)) {
        !           574:            ddmThread("disconnect after partial DMA (max 0x%d curr 0x%x)\n",
        !           575:                gActiveCommand->scsiReq->maxTransfer, 
        !           576:                gActiveCommand->currentDataIndex, 3,4,5);
        !           577:        }
        !           578: #endif DDM_DEBUG
        !           579:        /*
        !           580:         * Record this time so that gActiveCommand can be billed for
        !           581:         * disconnect latency at reselect time.
        !           582:         */
        !           583:        IOGetTimestamp(&gActiveCommand->disconnectTime);
        !           584:        gActiveCommand      = NULL;
        !           585:        gCurrentTarget      = kInvalidTarget;
        !           586:        gCurrentLUN         = kInvalidLUN;
        !           587:        /*
        !           588:         * Since there is no active command, the caller must configure the
        !           589:         * bus interface to wait for bus free, then allow reselection.
        !           590:         */
        !           591:        EXIT();
        !           592: }
        !           593: 
        !           594: /*
        !           595:  * Specified target, lun is trying to reselect. If we have a CommandBuffer
        !           596:  * for this TL nexus and it is not tagged, remove it, make it the current
        !           597:  * gActiveCommand, and return IO_R_SUCCESS. If the first disconnected
        !           598:  * command is tagged, we need to read the queue tag message, return
        !           599:  * IO_R_INTERNAL to signal this (it is not an error).
        !           600:  */
        !           601: - (IOReturn)   reselectNexusWithoutTag
        !           602: {
        !           603:        CommandBuffer       *cmdBuf;
        !           604:        IOSCSIRequest       *scsiReq;
        !           605:        ns_time_t           currentTime;
        !           606:        IOReturn            ioReturn        = SR_IOST_HW;   /* Presume failure  */
        !           607: 
        !           608:        ENTRY("Srn reselectNexusWithoutTag");
        !           609:        ASSERT(gActiveCommand == NULL);
        !           610:        cmdBuf = (CommandBuffer *) queue_first(&gDisconnectedCommandQueue);
        !           611:        while (queue_end(&gDisconnectedCommandQueue, (queue_t) cmdBuf) == FALSE) {
        !           612:            scsiReq = cmdBuf->scsiReq;
        !           613:            if (scsiReq->target == gCurrentTarget
        !           614:             && scsiReq->lun == gCurrentLUN
        !           615:             && cmdBuf->queueTag == QUEUE_TAG_NONTAGGED) {
        !           616:                /*
        !           617:                 * We found the correct command.
        !           618:                 */
        !           619:                ddmThread("RESELECT: target %d.%d no tag %FOUND; cmdBuf 0x%x\n",
        !           620:                    gCurrentTarget,
        !           621:                    gCurrentLUN,
        !           622:                    cmdBuf,
        !           623:                    4, 5
        !           624:                );
        !           625:                queue_remove(
        !           626:                    &gDisconnectedCommandQueue,
        !           627:                    cmdBuf,
        !           628:                    CommandBuffer *,
        !           629:                    link
        !           630:                );
        !           631:                gActiveCommand = cmdBuf;
        !           632:                /*
        !           633:                 * Bill this operation for latency time.
        !           634:                 */
        !           635:                IOGetTimestamp(&currentTime);
        !           636:                scsiReq->latentTime += 
        !           637:                            (currentTime - gActiveCommand->disconnectTime);
        !           638:                ioReturn = IO_R_SUCCESS;
        !           639:                break;
        !           640:            }
        !           641:            /*
        !           642:             * Try next element in queue.
        !           643:             */
        !           644:            cmdBuf = (CommandBuffer *) cmdBuf->link.next;
        !           645:        }
        !           646:        RESULT(ioReturn);
        !           647:        return (ioReturn);
        !           648: }
        !           649: /*
        !           650:  * Specified target, lun, and queueTag is trying to reselect. If we have 
        !           651:  * a CommandBuffer for this TLQ nexus on disconnectQ, remove it, make it the
        !           652:  * current activeCmd, and return IO_R_SUCCESS. Else return IO_R_HW.
        !           653:  */
        !           654: - (IOReturn) reselectNexusWithTag
        !           655:                    : (UInt8) queueTag
        !           656: {
        !           657:        CommandBuffer       *cmdBuf;
        !           658:        IOSCSIRequest       *scsiReq;
        !           659:        ns_time_t           currentTime;
        !           660:        IOReturn            ioReturn        = SR_IOST_HW;   /* Presume failure  */
        !           661: 
        !           662:        ENTRY("Srt reselectNexusWithTag");
        !           663:        ASSERT(gActiveCommand == NULL);
        !           664:        ASSERT(queueTag != QUEUE_TAG_NONTAGGED);
        !           665:        /*
        !           666:         * Scan the disconnected queue looking for a command for this
        !           667:         * T/L/Q nexus.
        !           668:         */
        !           669:        cmdBuf = (CommandBuffer *) queue_first(&gDisconnectedCommandQueue);
        !           670:        while (queue_end(&gDisconnectedCommandQueue, (queue_t) cmdBuf) == FALSE) {
        !           671:            scsiReq = cmdBuf->scsiReq;
        !           672:            if (scsiReq->target == gCurrentTarget
        !           673:             && scsiReq->lun == gCurrentLUN
        !           674:             && cmdBuf->queueTag == queueTag) {
        !           675:                /*
        !           676:                 * We found the correct command.
        !           677:                 */
        !           678:                ddmThread("RESELECT: target %d.%d tag %d FOUND; cmdBuf 0x%x\n",
        !           679:                    gCurrentTarget,
        !           680:                    gCurrentLUN,
        !           681:                    queueTag,
        !           682:                    cmdBuf,
        !           683:                    5
        !           684:                );
        !           685:                queue_remove(
        !           686:                    &gDisconnectedCommandQueue,
        !           687:                    cmdBuf,
        !           688:                    CommandBuffer *,
        !           689:                    link
        !           690:                );
        !           691:                gActiveCommand = cmdBuf;
        !           692:                ASSERT(scsiReq->target == gCurrentTarget && scsiReq->lun == gCurrentLUN);
        !           693:                /*
        !           694:                 * Bill this operation for latency time.
        !           695:                 */
        !           696:                IOGetTimestamp(&currentTime);
        !           697:                scsiReq->latentTime += 
        !           698:                            (currentTime - gActiveCommand->disconnectTime);
        !           699:                ioReturn = IO_R_SUCCESS;
        !           700:                break;
        !           701:            }
        !           702:            /*
        !           703:             * Try next element in queue.
        !           704:             */
        !           705:            cmdBuf = (CommandBuffer *) cmdBuf->link.next;
        !           706:        }
        !           707:        if (ioReturn != IO_R_SUCCESS) {
        !           708:            /*
        !           709:             * Hmm...this is not good! We don't want to talk to this target.
        !           710:             * Perhaps it's reselecting after we have already aborted the
        !           711:             * original command request.
        !           712:            */ 
        !           713:            IOLog("%s: Unexpected reselect from target %d lun %d tag %d\n",
        !           714:                [self name],
        !           715:                gCurrentTarget,
        !           716:                gCurrentLUN,
        !           717:                queueTag
        !           718:            );
        !           719:        }
        !           720:        RESULT(ioReturn);
        !           721:        return (ioReturn);
        !           722: }
        !           723: 
        !           724: /*
        !           725:  * Determine if gActiveArray[][], maxQueue, cmdQueueEnable, and a 
        !           726:  * command's target and lun show that it's OK to start processing cmdBuf.
        !           727:  * Returns YES if this command can be started.
        !           728:  * ** ** **
        !           729:  * ** ** ** Here's where we can test for a frozen LUN queue.
        !           730:  * ** ** **
        !           731:  */
        !           732: - (Boolean) commandCanBeStarted : (CommandBuffer *) cmdBuf
        !           733: {
        !           734:        IOSCSIRequest       *scsiReq;
        !           735:        unsigned            target      = scsiReq->target;
        !           736:        unsigned            lun         = scsiReq->lun;
        !           737:        Boolean             result;
        !           738: 
        !           739:        ENTRY("Scs commandCanBeStarted");
        !           740:        ASSERT(cmdBuf != NULL && cmdBuf->scsiReq != NULL);
        !           741:        scsiReq     = cmdBuf->scsiReq;
        !           742:        target      = scsiReq->target;
        !           743:        lun         = scsiReq->lun;
        !           744:        if (gActiveArray[target][lun] == 0) {
        !           745:            /*
        !           746:             * No commands are active for this target, always ok.
        !           747:             */
        !           748:            result = TRUE;
        !           749:        }
        !           750:        else if (gOptionCmdQueueEnable == FALSE
        !           751:              || gPerTargetData[target].cmdQueueDisable) {
        !           752:            /*
        !           753:             * Command queueing is disabled for this target
        !           754:             * (or disabled globally); only one command at a time
        !           755:             * can be issued.
        !           756:             */
        !           757:            result = FALSE;
        !           758:        }
        !           759:        else {
        !           760:            if (gPerTargetData[target].maxQueue == 0
        !           761:             || gActiveArray[target][lun] < gPerTargetData[target].maxQueue) {
        !           762:                /*
        !           763:                 * If maxQueueDepth is zero, we haven't reached the
        !           764:                 * target's limit. Otherwise, we're under the limit. In
        !           765:                 * both cases, we can (presumably) start this command.
        !           766:                 * 
        !           767:                 */
        !           768:                result = TRUE;
        !           769:            }
        !           770:            else {
        !           771:                /*
        !           772:                 * We're over the target limit. Wait on this one.
        !           773:                 */
        !           774:                result = FALSE;
        !           775:            }   
        !           776:        }
        !           777:        RESULT(result);
        !           778:        return (result);
        !           779: }
        !           780: 
        !           781: /*
        !           782:  * The bus has gone free. Start up a command from gPendingCommandQueue, if any, and
        !           783:  * if allowed by cmdQueueEnable and gActiveArray[][].
        !           784:  *
        !           785:  * This is called from the interrupt routine when it is about to exit (and the
        !           786:  * bus is free and there is no active command). It may also be called from
        !           787:  * threadExecuteRequest when the selected command couldn't be started.
        !           788:  * 
        !           789:  */
        !           790: - (void) busFree
        !           791: {
        !           792:        CommandBuffer       *cmdBuf;
        !           793: 
        !           794:        ENTRY("Sbf busFree");
        !           795:        cmdBuf = [self selectNextRequest];
        !           796:        if (cmdBuf != NULL) {
        !           797:            [self threadExecuteRequest:cmdBuf];
        !           798:        }
        !           799:        EXIT();
        !           800: }
        !           801: 
        !           802: /*
        !           803:  * Scan through the pending queue for the first command that can be started.
        !           804:  * Return the command record, or NULL if there is no pending command.
        !           805:  */
        !           806: - (CommandBuffer *)    selectNextRequest
        !           807: {
        !           808:        CommandBuffer       *cmdBuf = NULL;
        !           809:        Boolean             foundRequest;
        !           810: 
        !           811:        ENTRY("Ssn selectNextRequest");
        !           812:        ASSERT(gActiveCommand == NULL);
        !           813:        foundRequest = FALSE;
        !           814:        if (queue_empty(&gPendingCommandQueue) == FALSE) {
        !           815:            /*
        !           816:             * Attempt to find a CommandBuffer in gPendingCommandQueue which we are in a position
        !           817:             * to process.
        !           818:             */
        !           819:            cmdBuf = (CommandBuffer *) queue_first(&gPendingCommandQueue);
        !           820:            while (queue_end(&gPendingCommandQueue, (queue_entry_t) cmdBuf) == FALSE) {
        !           821:                if ([self commandCanBeStarted:cmdBuf]) {
        !           822:                    queue_remove(&gPendingCommandQueue, cmdBuf, CommandBuffer *, link);
        !           823:                    ddmThread("busFree: starting pending cmd 0x%x\n", cmdBuf,
        !           824:                        2,3,4,5);
        !           825:                    foundRequest = TRUE;
        !           826:                    break;
        !           827:                    /*
        !           828:                     * Note that threadExecuteRequest may call busFree if the command
        !           829:                     * was rejected. If so, the rejected command will have been
        !           830:                     * returned (with an error status) to its client, so there is
        !           831:                     * no chance of an infinite loop here.
        !           832:                     */
        !           833:                }
        !           834:                else {
        !           835:                    cmdBuf = (CommandBuffer *) queue_next(&cmdBuf->link);
        !           836:                }
        !           837:            }
        !           838:        }
        !           839:        if (foundRequest == FALSE) {
        !           840:            cmdBuf = NULL;
        !           841:        }
        !           842:        RESULT(cmdBuf);
        !           843:        return (cmdBuf);
        !           844: }
        !           845: 
        !           846: /*
        !           847:  * Abort gActiveCommand (if any) and any disconnected I/Os (if any) and reset 
        !           848:  * the bus due to gross hardware failure.
        !           849:  *
        !           850:  * If gActiveCommand is valid, its scsiReq->driverStatus will be set to 'status'.
        !           851:  * This is called when the bus state machine detects an error that it can't
        !           852:  * recover from, such as a "gross error" in the chip. It is a very big hammer.
        !           853:  */
        !           854: - (void) killActiveCommandAndResetBus
        !           855:                        : (sc_status_t) status
        !           856:             reason     : (const char *) reason
        !           857: {
        !           858:        ENTRY("Skr killActiveCommandAndResetBus");
        !           859:        [self killActiveCommand : status];
        !           860:        [self logRegisters : TRUE reason : "Killing Active Command and Resetting Bus"];
        !           861:        [self threadResetBus : reason];
        !           862:        EXIT();
        !           863: }
        !           864: 
        !           865: - (void) killActiveCommand
        !           866:                        : (sc_status_t) status
        !           867: {
        !           868:     CommandBuffer      *activeCmd;     /* -> The currently executing command   */
        !           869: 
        !           870:        ENTRY("Ski killActiveCommand");
        !           871:        if (gActiveCommand != NULL) {
        !           872:            activeCmd = gActiveCommand;
        !           873:            [self deactivateCmd];
        !           874:            [self ioComplete
        !           875:                                : activeCmd
        !           876:                finalStatus     : status
        !           877:             ];
        !           878:        }
        !           879:        EXIT();
        !           880: }
        !           881: 
        !           882: /*
        !           883:  * Called by chip level to indicate that a command has gone out to the 
        !           884:  * hardware.
        !           885:  */
        !           886: - (void) activateCommand
        !           887:                    : (CommandBuffer *) cmdBuf
        !           888: {
        !           889:        ENTRY("Sac activateCommand");
        !           890:        ASSERT(gActiveCommand == NULL);
        !           891:        /*
        !           892:         * Start timeout timer for this I/O. The timer request is cancelled
        !           893:         * in ioComplete.
        !           894:         */
        !           895:        cmdBuf->timeoutPort = gKernelInterruptPort;
        !           896: #if LONG_TIMEOUT
        !           897:        cmdBuf->scsiReq->timeoutLength = OUR_TIMEOUT;
        !           898: #endif LONG_TIMEOUT
        !           899:        IOScheduleFunc(serviceTimeoutInterrupt, cmdBuf, cmdBuf->scsiReq->timeoutLength);
        !           900: 
        !           901:        /*
        !           902:         * This is the only place where an gActiveArray[][] counter is 
        !           903:         * incremented (and, hence, the only place where cmdBuf->active is 
        !           904:         * set). The only other place gActiveCommand is set to non-NULL is
        !           905:         * in reselectNexux... (but those methods don't increment the
        !           906:         * active command counter)
        !           907:         */
        !           908:        gActiveCommand          = cmdBuf;
        !           909:        gCurrentTarget          = cmdBuf->scsiReq->target;
        !           910:        gCurrentLUN             = cmdBuf->scsiReq->lun;
        !           911:        TAG(__tag__, (gCurrentTarget << 4) | gCurrentLUN);
        !           912:        gActiveArray[gCurrentTarget][gCurrentLUN]++;
        !           913:        gActiveCount++;
        !           914:        cmdBuf->flagActive          = TRUE;
        !           915:        /*
        !           916:         * Accumulate statistics.
        !           917:         */
        !           918:        gMaxQueueLen = MAX(gMaxQueueLen, gActiveCount);
        !           919:        gQueueLenTotal += gActiveCount;
        !           920:        gTotalCommands++;
        !           921:        ddmThread("activateCommand: cmdBuf 0x%x target %d lun %d\n",
        !           922:            cmdBuf, gCurrentTarget, gCurrentLUN,
        !           923:            4, 5
        !           924:        );
        !           925:        EXIT();
        !           926: }
        !           927: 
        !           928: /*
        !           929:  * Remove the current command from "active" status. Update activeArray,
        !           930:  * activeCount, and unschedule pending timer.
        !           931:  */
        !           932: - (void) deactivateCmd
        !           933: {
        !           934:        CommandBuffer       *cmdBuf;
        !           935:        unsigned            target, lun;
        !           936: 
        !           937:        ENTRY("Sdc deactivateCmd");
        !           938:        /*
        !           939:         * If we are pushing back a full target queue, it's possible
        !           940:         * to be called twice on the same command: once from ioComplete
        !           941:         * and once from pushbackCurrentRequest. To prevent the second
        !           942:         * call from de-referencing NULL, we exit if gActiveCommand
        !           943:         * is already NULL. Radar 2206796.
        !           944:         */
        !           945:        if (gActiveCommand != NULL) {
        !           946:            ASSERT(gActiveCommand->scsiReq != NULL);
        !           947:            TAG(__tag__,
        !           948:                (gActiveCommand->scsiReq->target << 4)
        !           949:                | gActiveCommand->scsiReq->lun
        !           950:            );
        !           951:            ddmThread("deactivate cmd 0x%x target %d lun %d activeArray %d\n",
        !           952:                gActiveCommand,
        !           953:                gActiveCommand->scsiReq->target,
        !           954:                gActiveCommand->scsiReq->lun,
        !           955:                gActiveArray[gActiveCommand->scsiReq->target]
        !           956:                        [gActiveCommand->scsiReq->lun],
        !           957:                5
        !           958:            );
        !           959:            cmdBuf              = gActiveCommand;
        !           960:            gActiveCommand      = NULL;
        !           961:            gCurrentTarget      = kInvalidTarget;
        !           962:            gCurrentLUN         = kInvalidLUN;
        !           963:            target              = cmdBuf->scsiReq->target;
        !           964:            lun                 = cmdBuf->scsiReq->lun;
        !           965:            ASSERT(gActiveArray[target][lun] > 0);
        !           966:            gActiveArray[target][lun]--;
        !           967:            ASSERT(gActiveCount > 0);
        !           968:            gActiveCount--;
        !           969:            /*
        !           970:             * Cancel pending timeout request. We don't have to do this
        !           971:             * for commands that have timed out as they won't have a
        !           972:             * timeout request in the schedular.
        !           973:             */
        !           974:            if (cmdBuf->scsiReq->driverStatus != SR_IOST_IOTO) {
        !           975:                IOUnscheduleFunc(serviceTimeoutInterrupt, cmdBuf);
        !           976:            }
        !           977:            cmdBuf->flagActive = FALSE;
        !           978:        }
        !           979:        EXIT();
        !           980: }
        !           981: 
        !           982: /**
        !           983:  * Kill everything in the indicated queue. Called after bus reset.
        !           984:  */
        !           985: - (void) killQueue  : (queue_head_t *) queuePtr
        !           986:     finalStatus : (sc_status_t) scsiStatus
        !           987: {
        !           988:        CommandBuffer           *cmdBuf;
        !           989: 
        !           990:        ENTRY("Skq killQueue");
        !           991:        while (queue_empty(queuePtr) == FALSE) {
        !           992:            cmdBuf = (CommandBuffer *) queue_first(queuePtr);
        !           993:            queue_remove(queuePtr, cmdBuf, CommandBuffer *, link);
        !           994:            cmdBuf->scsiReq->driverStatus = scsiStatus;
        !           995:            [self ioComplete
        !           996:                                : cmdBuf
        !           997:                finalStatus     : scsiStatus
        !           998:            ];
        !           999:        }
        !          1000:        EXIT();
        !          1001: }
        !          1002: 
        !          1003: @end   /* Apple96_SCSI(Private) */
        !          1004: 
        !          1005: /*
        !          1006:  *  Handle timeouts.  We just send a timeout message to the I/O thread
        !          1007:  *  so it wakes up.
        !          1008:  */
        !          1009: static void serviceTimeoutInterrupt(void *arg)
        !          1010: {
        !          1011:        CommandBuffer       *cmdBuf = arg;
        !          1012:        msg_header_t        msg = timeoutMsgTemplate;
        !          1013: 
        !          1014:        ENTRY("Sto serviceTimeoutInterrupt");
        !          1015:        ASSERT(cmdBuf != NULL && cmdBuf->scsiReq != NULL);
        !          1016:        ddmError("Apple96SCSI: timeout: cmdBuf 0x%x target %d\n",
        !          1017:            cmdBuf,
        !          1018:            cmdBuf->scsiReq->target,
        !          1019:            3,4,5
        !          1020:        );
        !          1021:        if (cmdBuf->flagActive == FALSE) {
        !          1022:            /*
        !          1023:             * Should never happen...
        !          1024:             */
        !          1025:            IOLog("Apple96SCSI: Timeout on inactive command\n");
        !          1026:        }
        !          1027:        else {
        !          1028:            msg.msg_remote_port = cmdBuf->timeoutPort;
        !          1029:            IOLog("Apple96SCSI: SCSI Timeout on target %d, lun %d\n",
        !          1030:                cmdBuf->scsiReq->target,
        !          1031:                cmdBuf->scsiReq->lun
        !          1032:            );
        !          1033:            (void) msg_send_from_kernel(&msg, MSG_OPTION_NONE, 0);
        !          1034:        }
        !          1035:        EXIT();
        !          1036: }
        !          1037: 

unix.superglobalmegacorp.com

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