Annotation of Examples/DriverKit/AMDPCSCSIDriver/AMDPCSCSIDriver_reloc.tproj/AMD_SCSI.m, revision 1.1

1.1     ! root        1: /*
        !             2:  * AMD_SCSI.m - top-level module for AMD 53C974/79C974 PCI SCSI driver. 
        !             3:  *
        !             4:  * HISTORY
        !             5:  * 21 Oct 94    Doug Mitchell at NeXT
        !             6:  *      Created. 
        !             7:  */
        !             8: 
        !             9: #import "AMD_SCSI.h"
        !            10: #import "AMD_Private.h"
        !            11: #import "AMD_x86.h"
        !            12: #import "AMD_Chip.h"
        !            13: #import "AMD_ddm.h"
        !            14: #import "AMD_Regs.h"
        !            15: #import <mach/message.h>
        !            16: #import <driverkit/generalFuncs.h>
        !            17: #import <driverkit/interruptMsg.h>
        !            18: #import <driverkit/align.h>
        !            19: #import <driverkit/kernelDriver.h>
        !            20: #import <kernserv/prototypes.h>
        !            21: 
        !            22: static void AMDTimeout(void *arg);
        !            23: 
        !            24: /* 
        !            25:  * Template for command message sent to the I/O thread.
        !            26:  */
        !            27: static msg_header_t cmdMessageTemplate = {
        !            28:        0,                                      // msg_unused 
        !            29:        1,                                      // msg_simple 
        !            30:        sizeof(msg_header_t),                   // msg_size 
        !            31:        MSG_TYPE_NORMAL,                        // msg_type 
        !            32:        PORT_NULL,                              // msg_local_port 
        !            33:        PORT_NULL,                              // msg_remote_port - TO
        !            34:                                                // BE FILLED IN 
        !            35:        IO_COMMAND_MSG                          // msg_id 
        !            36: };
        !            37: 
        !            38: /*
        !            39:  * Template for timeout message.
        !            40:  */
        !            41: static msg_header_t timeoutMsgTemplate = {
        !            42:        0,                                      // msg_unused 
        !            43:        1,                                      // msg_simple 
        !            44:        sizeof(msg_header_t),                   // msg_size 
        !            45:        MSG_TYPE_NORMAL,                        // msg_type 
        !            46:        PORT_NULL,                              // msg_local_port 
        !            47:        PORT_NULL,                              // msg_remote_port - TO
        !            48:                                                // BE FILLED IN 
        !            49:        IO_TIMEOUT_MSG                          // msg_id 
        !            50: };
        !            51: 
        !            52: 
        !            53: @implementation AMD_SCSI
        !            54: 
        !            55: /*
        !            56:  * Create and initialize one instance of AMD_SCSI. The work is done by
        !            57:  * architecture- and chip-specific modules. 
        !            58:  */
        !            59: + (BOOL)probe:deviceDescription
        !            60: {
        !            61:        AMD_SCSI *inst = [self alloc];
        !            62: 
        !            63: 
        !            64:        if([inst archInit:deviceDescription] == nil) {
        !            65:                return NO;
        !            66:        }
        !            67:        else {
        !            68:                return YES;
        !            69:        }
        !            70: }
        !            71: 
        !            72: - free
        !            73: {
        !            74:        commandBuf cmdBuf;
        !            75:        
        !            76:        /*
        !            77:         * First kill the I/O thread if running. 
        !            78:         */
        !            79:        if(ioThreadRunning) {
        !            80:                cmdBuf.op = CO_Abort;
        !            81:                cmdBuf.scsiReq = NULL;
        !            82:                [self executeCmdBuf:&cmdBuf];
        !            83:        }
        !            84:        
        !            85:        if(commandLock) {
        !            86:                [commandLock free];
        !            87:        }
        !            88:        if(mdlFree) {
        !            89:                IOFree(mdlFree, MDL_SIZE * 2 * sizeof(vm_address_t));
        !            90:        }
        !            91:        return [super free];
        !            92: }
        !            93: 
        !            94: /*
        !            95:  * Our max DMA size is 64 K, derived from using 18 MDL entries (note the 
        !            96:  * first and last entries can refer to chunks as small as 4 bytes). 
        !            97:  */
        !            98: - (unsigned)maxDmaSize
        !            99: {
        !           100:        return AMD_DMA_PAGE_SIZE * (MDL_SIZE - 2);
        !           101: }
        !           102: 
        !           103: /*
        !           104:  * Return required DMA alignment for current architecture.
        !           105:  */
        !           106: - (void)getDMAAlignment : (IODMAAlignment *)alignment;
        !           107: {
        !           108:        alignment->readStart   = AMD_READ_START_ALIGN;
        !           109:        alignment->writeStart  = AMD_WRITE_START_ALIGN;
        !           110:        alignment->readLength  = AMD_READ_LENGTH_ALIGN;
        !           111:        alignment->writeLength = AMD_WRITE_LENGTH_ALIGN;
        !           112: }
        !           113: 
        !           114: /*
        !           115:  * Statistics support.
        !           116:  */
        !           117: - (unsigned int) numQueueSamples
        !           118: {
        !           119:        return totalCommands;
        !           120: }
        !           121: 
        !           122: 
        !           123: - (unsigned int) sumQueueLengths
        !           124: {
        !           125:        return queueLenTotal;
        !           126: }
        !           127: 
        !           128: 
        !           129: - (unsigned int) maxQueueLength
        !           130: {
        !           131:        return maxQueueLen;
        !           132: }
        !           133: 
        !           134: 
        !           135: - (void)resetStats
        !           136: {
        !           137:        totalCommands = 0;
        !           138:        queueLenTotal = 0;
        !           139:        maxQueueLen   = 0;
        !           140: }
        !           141: 
        !           142: /*
        !           143:  * Do a SCSI command, as specified by an IOSCSIRequest. All the 
        !           144:  * work is done by the I/O thread.
        !           145:  */
        !           146: - (sc_status_t) executeRequest : (IOSCSIRequest *)scsiReq 
        !           147:                    buffer : (void *)buffer 
        !           148:                    client : (vm_task_t)client
        !           149: {
        !           150:        commandBuf cmdBuf;
        !           151:        
        !           152:        ddm_exp("executeRequest: cmdBuf 0x%x maxTransfer 0x%x\n", 
        !           153:                &cmdBuf, scsiReq->maxTransfer,3,4,5);
        !           154:        
        !           155:        bzero(&cmdBuf, sizeof(commandBuf));
        !           156:        cmdBuf.op      = CO_Execute;
        !           157:        cmdBuf.scsiReq = scsiReq;
        !           158:        cmdBuf.buffer  = buffer;
        !           159:        cmdBuf.client  = client;
        !           160:        scsiReq->driverStatus = SR_IOST_INVALID;
        !           161:        
        !           162:        [self executeCmdBuf:&cmdBuf];
        !           163:        
        !           164:        ddm_exp("executeRequest: cmdBuf 0x%x complete; driverStatus %s\n", 
        !           165:                &cmdBuf, IOFindNameForValue(scsiReq->driverStatus, 
        !           166:                                        IOScStatusStrings), 3,4,5);
        !           167:        return cmdBuf.scsiReq->driverStatus;
        !           168: }
        !           169: 
        !           170: 
        !           171: /*
        !           172:  *  Reset the SCSI bus. All the work is done by the I/O thread.
        !           173:  */
        !           174: - (sc_status_t)resetSCSIBus
        !           175: {
        !           176:        commandBuf cmdBuf;
        !           177:        
        !           178:        ddm_exp("resetSCSIBus: cmdBuf 0x%x\n", &cmdBuf, 2,3,4,5);
        !           179: 
        !           180:        cmdBuf.op = CO_Reset;
        !           181:        cmdBuf.scsiReq = NULL;
        !           182:        [self executeCmdBuf:&cmdBuf];
        !           183:        ddm_exp("resetSCSIBus: cmdBuf 0x%x DONE\n", &cmdBuf, 2,3,4,5);
        !           184:        return SR_IOST_GOOD;            // can not fail
        !           185: }
        !           186: 
        !           187: /*
        !           188:  * The following 6 methods are all called from the I/O thread in 
        !           189:  * IODirectDevice. 
        !           190:  */
        !           191:  
        !           192: /*
        !           193:  * Called from the I/O thread when it receives an interrupt message.
        !           194:  * Currently all work is done by chip-specific module; maybe we should 
        !           195:  * put this method there....
        !           196:  */
        !           197: - (void)interruptOccurred
        !           198: {
        !           199:        #if     DDM_DEBUG
        !           200:        /*
        !           201:         * calculate interrupt service time if enabled.
        !           202:         */
        !           203:        ns_time_t       startTime, endTime, elapsedNs;
        !           204:        unsigned        elapsedUs = 0;
        !           205:        
        !           206:        if(IODDMMasks[AMD_DDM_INDEX] & DDM_INTR) {
        !           207:                IOGetTimestamp(&startTime);
        !           208:        }
        !           209:        ddm_thr("interruptOccurred: TOP\n", 1,2,3,4,5);
        !           210:        #endif  DDM_DEBUG
        !           211: 
        !           212:        [self hwInterrupt];
        !           213:        
        !           214:        #if     DDM_DEBUG
        !           215:        if(IODDMMasks[AMD_DDM_INDEX] & DDM_INTR) {
        !           216:                IOGetTimestamp(&endTime);
        !           217:                elapsedNs = endTime - startTime;
        !           218:                elapsedUs = (unsigned)((elapsedNs + 999ULL) / 1000ULL);
        !           219:        }
        !           220:        ddm_intr("interruptOccurred: DONE; elapsed time %d us\n", 
        !           221:                elapsedUs, 2,3,4,5);
        !           222:        #endif  DDM_DEBUG
        !           223: }
        !           224: 
        !           225: /*
        !           226:  * These three should not occur; they are here as error traps. All three are 
        !           227:  * called out from the I/O thread upon receipt of messages which it should
        !           228:  * not be seeing.
        !           229:  */
        !           230: - (void)interruptOccurredAt:(int)localNum
        !           231: {
        !           232:        IOLog("%s: interruptOccurredAt:%d\n", [self name], localNum);
        !           233: }
        !           234: 
        !           235: - (void)otherOccurred:(int)id
        !           236: {
        !           237:        IOLog("%s: otherOccurred:%d\n", [self name], id);
        !           238: }
        !           239: 
        !           240: - (void)receiveMsg
        !           241: {
        !           242:        IOLog("%s: receiveMsg\n", [self name]);
        !           243:        
        !           244:        /*
        !           245:         * We have to let IODirectDevice take care of this (i.e., dequeue the
        !           246:         * bogus message).
        !           247:         */
        !           248:        [super receiveMsg];
        !           249: }
        !           250: 
        !           251: /*
        !           252:  * Used in -timeoutOccurred to determine if specified cmdBuf has timed out.
        !           253:  * Returns YES if timeout, else NO.
        !           254:  */
        !           255: static inline BOOL
        !           256: isCmdTimedOut(commandBuf *cmdBuf, ns_time_t now)
        !           257: {
        !           258:        IOSCSIRequest   *scsiReq;
        !           259:        ns_time_t       expire;
        !           260:        
        !           261:        scsiReq = cmdBuf->scsiReq;
        !           262:        expire  = cmdBuf->startTime + 
        !           263:                (1000000000ULL * (unsigned long long)scsiReq->timeoutLength);
        !           264:        return ((now > expire) ? YES : NO);
        !           265: }
        !           266: 
        !           267: /*
        !           268:  * Called from the I/O thread when it receives a timeout
        !           269:  * message. We send these messages ourself from AMDTimeout().
        !           270:  */
        !           271: - (void)timeoutOccurred
        !           272: {
        !           273:        ns_time_t       now;
        !           274:        BOOL            cmdTimedOut = NO;
        !           275:        commandBuf      *cmdBuf;
        !           276:        commandBuf      *nextCmdBuf;
        !           277:        
        !           278:        ddm_thr("timeoutOccurred: TOP\n", 1,2,3,4,5);
        !           279:        IOGetTimestamp(&now);
        !           280: 
        !           281:        /*
        !           282:         *  Scan activeCmd and disconnectQ looking for tardy I/Os.
        !           283:         */
        !           284:        if(activeCmd) {
        !           285:                cmdBuf = activeCmd;
        !           286:                if(isCmdTimedOut(cmdBuf, now)) {
        !           287:                        ddm_thr("activeCmd TIMEOUT, cmd 0x%x\n", 
        !           288:                                cmdBuf, 2,3,4,5);
        !           289:                        activeCmd = NULL;
        !           290:                        ASSERT(cmdBuf->scsiReq != NULL);
        !           291:                        cmdBuf->scsiReq->driverStatus = SR_IOST_IOTO;
        !           292:                        [self ioComplete:cmdBuf];
        !           293:                        cmdTimedOut = YES;
        !           294:                }
        !           295:        }
        !           296: 
        !           297:        cmdBuf = (commandBuf *)queue_first(&disconnectQ);
        !           298:        while(!queue_end(&disconnectQ, (queue_entry_t)cmdBuf)) {
        !           299:                if(isCmdTimedOut(cmdBuf, now)) {
        !           300:                        ddm_thr("disconnected cmd TIMEOUT, cmd 0x%x\n", 
        !           301:                                cmdBuf, 2,3,4,5);
        !           302:                
        !           303:                        /*
        !           304:                         *  Remove cmdBuf from disconnectQ and
        !           305:                         *  complete it.
        !           306:                         */
        !           307:                        nextCmdBuf = (commandBuf *)queue_next(&cmdBuf->link);
        !           308:                        queue_remove(&disconnectQ, cmdBuf, commandBuf *, link);
        !           309:                        ASSERT(cmdBuf->scsiReq != NULL);
        !           310:                        cmdBuf->scsiReq->driverStatus = SR_IOST_IOTO;
        !           311:                        [self ioComplete:cmdBuf];
        !           312:                        cmdBuf = nextCmdBuf;
        !           313:                        cmdTimedOut = YES;
        !           314:                }
        !           315:                else {
        !           316:                        cmdBuf = (commandBuf *)queue_next(&cmdBuf->link);
        !           317:                }
        !           318:        }
        !           319: 
        !           320:        /*
        !           321:         * Reset bus. This also completes all I/Os in disconnectQ with
        !           322:         * status CS_Reset.
        !           323:         */
        !           324:        if(cmdTimedOut) {
        !           325:                [self logRegs];
        !           326:                [self threadResetBus:NULL];
        !           327:        }
        !           328:        ddm_thr("timeoutOccurred: DONE\n", 1,2,3,4,5);
        !           329: }
        !           330: 
        !           331: /*
        !           332:  * Process all commands in commandQ. At most one of these will become
        !           333:  * activeCmd. The remainder of CO_Execute commands go to pendingQ. Other
        !           334:  * types of commands are executed immediately.
        !           335:  */
        !           336: - (void)commandRequestOccurred
        !           337: {
        !           338:        commandBuf *cmdBuf;
        !           339:        commandBuf *pendCmd;
        !           340:        
        !           341:        ddm_thr("commandRequestOccurred: top\n", 1,2,3,4,5);
        !           342:        [commandLock lock];
        !           343:        while(!queue_empty(&commandQ)) {
        !           344:                cmdBuf = (commandBuf *) queue_first(&commandQ);
        !           345:                queue_remove(&commandQ, cmdBuf, commandBuf *, link);
        !           346:                [commandLock unlock];
        !           347:                
        !           348:                switch(cmdBuf->op) {
        !           349:                    case CO_Reset:
        !           350:                        /* 
        !           351:                         * Note all active and disconnected commands will
        !           352:                         * be terminted.
        !           353:                         */
        !           354:                        [self threadResetBus:"Reset Command Received"];
        !           355:                        [self ioComplete:cmdBuf];
        !           356:                        break;
        !           357:                        
        !           358:                    case CO_Abort:
        !           359:                        /*
        !           360:                         * 1. Abort all active, pending, and disconnected
        !           361:                         *    commands.
        !           362:                         * 2. Notify caller of completion.
        !           363:                         * 3. Self-terminate.
        !           364:                         */
        !           365:                        [self swAbort:SR_IOST_INT];
        !           366:                        pendCmd = (commandBuf *)queue_first(&pendingQ);
        !           367:                        while(!queue_end(&pendingQ, 
        !           368:                                        (queue_entry_t)pendCmd)) {
        !           369:                                pendCmd->scsiReq->driverStatus = SR_IOST_INT;
        !           370:                                [self ioComplete:pendCmd];
        !           371:                                pendCmd = (commandBuf *)
        !           372:                                        queue_next(&pendCmd->link);
        !           373:                        }
        !           374:                        [cmdBuf->cmdLock lock];
        !           375:                        [cmdBuf->cmdLock unlockWith:CMD_COMPLETE];
        !           376:                        IOExitThread();
        !           377:                        /* not reached */
        !           378:                        
        !           379:                    case CO_Execute:
        !           380:                        [self threadExecuteRequest:cmdBuf];
        !           381:                        break;
        !           382:                        
        !           383:                }
        !           384:                [commandLock lock];
        !           385:        }
        !           386:        [commandLock unlock];
        !           387:        ddm_thr("commandRequestOccurred: DONE\n", 1,2,3,4,5);
        !           388:        return;
        !           389: }
        !           390: 
        !           391: /*
        !           392:  * Power management methods. All we care about is power off, when we must 
        !           393:  * reset the SCSI bus due to the Compaq BIOS's lack of a SCSI reset, which
        !           394:  * causes a hang if we have set up targets for sync data transfer mode.
        !           395:  */
        !           396: - (IOReturn)getPowerState:(PMPowerState *)state_p
        !           397: {
        !           398:        ddm_exp("getPowerState called\n", 1,2,3,4,5);
        !           399:        return IO_R_UNSUPPORTED;
        !           400: }
        !           401: 
        !           402: - (IOReturn)setPowerState:(PMPowerState)state
        !           403: {
        !           404: #ifdef DEBUG
        !           405:        IOLog("%s: received setPowerState: with %x\n", [self name],
        !           406:            (unsigned)state);
        !           407: #endif DEBUG
        !           408:        if (state == PM_OFF) {
        !           409:                [self scsiReset];
        !           410:                return IO_R_SUCCESS;
        !           411:        }
        !           412:        return IO_R_UNSUPPORTED;
        !           413: }
        !           414: 
        !           415: - (IOReturn)getPowerManagement:(PMPowerManagementState *)state_p
        !           416: {
        !           417:        ddm_exp("getPowerManagement called\n", 1,2,3,4,5);
        !           418:        return IO_R_UNSUPPORTED;
        !           419: }
        !           420: 
        !           421: - (IOReturn)setPowerManagement:(PMPowerManagementState)state
        !           422: {
        !           423:        ddm_exp("setPowerManagement called\n", 1,2,3,4,5);
        !           424:        return IO_R_UNSUPPORTED;
        !           425: }
        !           426: 
        !           427: #if    AMD_ENABLE_GET_SET
        !           428: 
        !           429: - (IOReturn)setIntValues:(unsigned *)parameterArray
        !           430:        forParameter:(IOParameterName)parameterName
        !           431:        count:(unsigned int)count
        !           432: {
        !           433:        if(strcmp(parameterName, AMD_AUTOSENSE) == 0) {
        !           434:                if (count != 1) {
        !           435:                        return IO_R_INVALID_ARG;
        !           436:                }
        !           437:                autoSenseEnable = (parameterArray[0] ? 1 : 0);
        !           438:                IOLog("%s: autoSense %s\n", [self name], 
        !           439:                        (autoSenseEnable ? "Enabled" : "Disabled"));
        !           440:                return IO_R_SUCCESS;
        !           441:        }
        !           442:        else if(strcmp(parameterName, AMD_CMD_QUEUE) == 0) {
        !           443:                if (count != 1) {
        !           444:                        return IO_R_INVALID_ARG;
        !           445:                }
        !           446:                cmdQueueEnable = (parameterArray[0] ? 1 : 0);
        !           447:                IOLog("%s: cmdQueue %s\n", [self name], 
        !           448:                        (cmdQueueEnable ? "Enabled" : "Disabled"));
        !           449:                return IO_R_SUCCESS;
        !           450:        }
        !           451:        else if(strcmp(parameterName, AMD_SYNC) == 0) {
        !           452:                if (count != 1) {
        !           453:                        return IO_R_INVALID_ARG;
        !           454:                }
        !           455:                syncModeEnable = (parameterArray[0] ? 1 : 0);
        !           456:                IOLog("%s: syncMode %s\n", [self name], 
        !           457:                        (syncModeEnable ? "Enabled" : "Disabled"));
        !           458:                return IO_R_SUCCESS;
        !           459:        }
        !           460:        else if(strcmp(parameterName, AMD_FAST_SCSI) == 0) {
        !           461:                if (count != 1) {
        !           462:                        return IO_R_INVALID_ARG;
        !           463:                }
        !           464:                fastModeEnable = (parameterArray[0] ? 1 : 0);
        !           465:                IOLog("%s: fastMode %s\n", [self name], 
        !           466:                        (fastModeEnable ? "Enabled" : "Disabled"));
        !           467:                return IO_R_SUCCESS;
        !           468:        }
        !           469:        else if(strcmp(parameterName, AMD_RESET_TARGETS) == 0) {
        !           470:                int target;
        !           471:                perTargetData *perTargetPtr;
        !           472:                
        !           473:                if (count != 0) {
        !           474:                        return IO_R_INVALID_ARG;
        !           475:                }
        !           476:                
        !           477:                /*
        !           478:                 * Re-enable sync and command queueing. The
        !           479:                 * disable bits persist after a reset.
        !           480:                 */
        !           481:                for(target=0; target<SCSI_NTARGETS; target++) {
        !           482:                        perTargetPtr = &perTarget[target];
        !           483:                        perTargetPtr->cmdQueueDisable = 0;
        !           484:                        perTargetPtr->syncDisable = 0;
        !           485:                        perTargetPtr->maxQueue = 0;
        !           486:                }
        !           487:                IOLog("%s: Per Target disable flags cleared\n", [self name]);
        !           488:                return IO_R_SUCCESS;
        !           489:        }
        !           490:        else {
        !           491:                return [super setIntValues:parameterArray
        !           492:                        forParameter:parameterName
        !           493:                        count:count];
        !           494:        }
        !           495: }
        !           496: 
        !           497: - (IOReturn)getIntValues               : (unsigned *)parameterArray
        !           498:                           forParameter : (IOParameterName)parameterName
        !           499:                                  count : (unsigned *)count;    // in/out
        !           500: {      
        !           501:        if(strcmp(parameterName, AMD_AUTOSENSE) == 0) {
        !           502:                if(*count != 1) {
        !           503:                        return IO_R_INVALID_ARG;
        !           504:                }
        !           505:                parameterArray[0] = autoSenseEnable;
        !           506:                return IO_R_SUCCESS;
        !           507:        }
        !           508:        else if(strcmp(parameterName, AMD_CMD_QUEUE) == 0) {
        !           509:                if(*count != 1) {
        !           510:                        return IO_R_INVALID_ARG;
        !           511:                }
        !           512:                parameterArray[0] = cmdQueueEnable;
        !           513:                return IO_R_SUCCESS;
        !           514:        }
        !           515:        else if(strcmp(parameterName, AMD_SYNC) == 0) {
        !           516:                if(*count != 1) {
        !           517:                        return IO_R_INVALID_ARG;
        !           518:                }
        !           519:                parameterArray[0] = syncModeEnable;
        !           520:                return IO_R_SUCCESS;
        !           521:        }
        !           522:        else if(strcmp(parameterName, AMD_FAST_SCSI) == 0) {
        !           523:                if(*count != 1) {
        !           524:                        return IO_R_INVALID_ARG;
        !           525:                }
        !           526:                parameterArray[0] = fastModeEnable;
        !           527:                return IO_R_SUCCESS;
        !           528:        }
        !           529:        else {
        !           530:                return [super getIntValues : parameterArray
        !           531:                        forParameter : parameterName
        !           532:                        count : count];
        !           533: 
        !           534:        }
        !           535: }                                      
        !           536: 
        !           537: 
        !           538: #endif AMD_ENABLE_GET_SET
        !           539: 
        !           540: @end   /* AMD_SCSI */
        !           541: 
        !           542: @implementation AMD_SCSI(Private)
        !           543: 
        !           544: /*
        !           545:  * Private chip- and architecture-independent methods.
        !           546:  */
        !           547: 
        !           548: /*
        !           549:  * Pass one commandBuf to the I/O thread; wait for completion. 
        !           550:  * Normal completion status is in cmdBuf->scsiReq->driverStatus; 
        !           551:  * a non-zero return from this function indicates a Mach IPC error.
        !           552:  *
        !           553:  * This method allocates and frees cmdBuf->cmdLock.
        !           554:  */
        !           555: - (IOReturn)executeCmdBuf : (commandBuf *)cmdBuf
        !           556: {
        !           557:        msg_header_t msg = cmdMessageTemplate;
        !           558:        kern_return_t krtn;
        !           559:        IOReturn rtn = IO_R_SUCCESS;
        !           560:        
        !           561:        cmdBuf->cmdPendingSense = NULL;
        !           562:        cmdBuf->active = 0;
        !           563:        cmdBuf->cmdLock = [[NXConditionLock alloc] initWith:CMD_PENDING];
        !           564:        [commandLock lock];
        !           565:        queue_enter(&commandQ, cmdBuf, commandBuf *, link);
        !           566:        [commandLock unlock];
        !           567:        
        !           568:        /*
        !           569:         * Create a Mach message and send it in order to wake up the 
        !           570:         * I/O thread.
        !           571:         */
        !           572:        msg.msg_remote_port = interruptPortKern;
        !           573:        krtn = msg_send_from_kernel(&msg, MSG_OPTION_NONE, 0);
        !           574:        if(krtn) {
        !           575:                IOLog("%s: msg_send_from_kernel() returned %d\n", 
        !           576:                        [self name], krtn);
        !           577:                rtn = IO_R_IPC_FAILURE;
        !           578:                goto out;
        !           579:        }
        !           580:        
        !           581:        /*
        !           582:         * Wait for I/O complete.
        !           583:         */
        !           584:        ddm_exp("executeCmdBuf: waiting for completion on cmdBuf 0x%x\n",
        !           585:                cmdBuf, 2,3,4,5);
        !           586:        [cmdBuf->cmdLock lockWhen:CMD_COMPLETE];
        !           587: out:
        !           588:        [cmdBuf->cmdLock free];
        !           589:        return rtn;
        !           590: }
        !           591: 
        !           592: /*
        !           593:  * Abort all active and disconnected commands with specified status. No 
        !           594:  * hardware action. Currently used by threadResetBus and during processing
        !           595:  * of a CO_Abort command.
        !           596:  */
        !           597: - (void)swAbort : (sc_status_t)status
        !           598: {
        !           599:        commandBuf *cmdBuf;
        !           600:        commandBuf *nextCmdBuf;
        !           601:        
        !           602:        ddm_thr("swAbort\n", 1,2,3,4,5);
        !           603:        if(activeCmd) {
        !           604:                activeCmd->scsiReq->driverStatus = status;
        !           605:                [self ioComplete:activeCmd];
        !           606:                activeCmd = NULL;
        !           607:        }
        !           608:        cmdBuf = (commandBuf *)queue_first(&disconnectQ);
        !           609:        while(!queue_end(&disconnectQ, (queue_entry_t)cmdBuf)) {
        !           610:                queue_remove(&disconnectQ, cmdBuf, commandBuf *, link);
        !           611:                nextCmdBuf = (commandBuf *)
        !           612:                        queue_next(&cmdBuf->link);
        !           613:                cmdBuf->scsiReq->driverStatus = status;
        !           614:                [self ioComplete:cmdBuf];
        !           615:                cmdBuf = nextCmdBuf;
        !           616:        }
        !           617: #ifdef DEBUG
        !           618:        /*
        !           619:         * activeArray "should be" empty...if not, make sure it is for debug.
        !           620:         */
        !           621:        {
        !           622:            int target, lun;
        !           623:            int active;
        !           624:            
        !           625:            for(target=0; target<SCSI_NTARGETS; target++) {
        !           626:                for(lun=0; lun<SCSI_NLUNS; lun++) {
        !           627:                    active = activeArray[target][lun];
        !           628:                    if(active) {
        !           629:                        IOLog("swAbort: activeArray[%d][%d] = %d\n",
        !           630:                            target, lun, active);
        !           631:                        activeCount -= active;
        !           632:                        activeArray[target][lun] = 0;
        !           633:                    }
        !           634:                }
        !           635:            }
        !           636:            if(activeCount != 0) {
        !           637:                IOLog("swAbort: activeCount = %d\n", activeCount);
        !           638:                activeCount = 0;
        !           639:            }
        !           640:        }
        !           641: #endif DEBUG
        !           642: }
        !           643: 
        !           644: /*
        !           645:  * Abort all active and disconnected commands with status SR_IOST_RESET.
        !           646:  * Reset hardware and SCSI bus. If there is a command in pendingQ, start
        !           647:  * it up.
        !           648:  */
        !           649: - (void)threadResetBus : (const char *)reason
        !           650: {
        !           651:        [self swAbort:SR_IOST_RESET];
        !           652:        [self hwReset : reason];
        !           653:        [self busFree];
        !           654: }
        !           655: 
        !           656: /*
        !           657:  * Commence processing of the specified command. 
        !           658:  *
        !           659:  * If activeCmd is non-NULL or cmdBufOK says we can't process this command,
        !           660:  * we just enqueue the command on the end of pendingQ. 
        !           661:  */
        !           662: - (void)threadExecuteRequest : (commandBuf *)cmdBuf
        !           663: {
        !           664:        #if     DDM_DEBUG
        !           665:        unsigned char target = cmdBuf->scsiReq->target;
        !           666:        unsigned char lun = cmdBuf->scsiReq->lun;
        !           667:        #endif  DDM_DEBUG
        !           668:        
        !           669:        if(activeCmd != NULL) {
        !           670:                ddm_thr("threadExecuteRequest: ACTIVE; adding 0x%x to "
        !           671:                        "pendingQ\n", cmdBuf, 2,3,4,5);
        !           672:                queue_enter(&pendingQ, cmdBuf, commandBuf *, link);
        !           673:                return;
        !           674:        }       
        !           675:        else if([self cmdBufOK:cmdBuf] == NO) {
        !           676:                ddm_thr("threadExecuteRequest: !cmdBufOK; adding 0x%x to "
        !           677:                        "pendingQ\n", cmdBuf, 2,3,4,5);
        !           678:                queue_enter(&pendingQ, cmdBuf, commandBuf *, link);
        !           679:                return;
        !           680:        }
        !           681: 
        !           682:        ddm_thr("calling hwStart: cmdBuf 0x%x activeArray[%d][%d] = %d\n",
        !           683:                cmdBuf, target, lun, activeArray[target][lun], 5);
        !           684:                
        !           685:        switch([self hwStart:cmdBuf]) {
        !           686:            case HWS_OK:                // cool
        !           687:            case HWS_BUSY:              // h/w can't take cmd now
        !           688:                break;
        !           689:            case HWS_REJECT:            // hw ready for new cmd
        !           690:                ddm_thr("threadExecuteRequest: calling busFree\n", 1,2,3,4,5);
        !           691:                [self busFree];
        !           692:        }
        !           693:        
        !           694:        ddm_thr("threadExecuteRequest(0x%x): DONE\n", cmdBuf, 2,3,4,5);
        !           695: }
        !           696: 
        !           697: /*
        !           698:  * Methods called by hardware-dependent modules.
        !           699:  */
        !           700: 
        !           701: #if    TEST_QUEUE_FULL
        !           702: int    testQueueFull;
        !           703: #endif TEST_QUEUE_FULL
        !           704: 
        !           705: /*
        !           706:  * Called when a transaction associated with cmdBuf is complete. Notify 
        !           707:  * waiting thread. If cmdBuf->scsiReq exists (i.e., this is not a reset
        !           708:  * or an abort), scsiReq->driverStatus must be valid. If cmdBuf is active,
        !           709:  * caller must remove from activeCmd. We decrement activeArray[][] counter
        !           710:  * if appropriate.
        !           711:  */
        !           712: - (void)ioComplete:(commandBuf *)cmdBuf
        !           713: {
        !           714:        ns_time_t       currentTime;
        !           715:        IOSCSIRequest   *scsiReq = cmdBuf->scsiReq;
        !           716:        int             target;
        !           717:        int             lun;
        !           718:        
        !           719:        if(cmdBuf->cmdPendingSense != NULL) {
        !           720:                /*
        !           721:                 * This was an autosense request.
        !           722:                 */
        !           723:                
        !           724:                commandBuf *origCmdBuf = cmdBuf->cmdPendingSense;
        !           725:                esense_reply_t *alignedSense = cmdBuf->buffer;
        !           726:                
        !           727:                ASSERT(cmdBuf->scsiReq != NULL);
        !           728:                ddm_thr("autosense buf 0x%x complete for cmd 0x%x sense "
        !           729:                        "key 0x%x\n",
        !           730:                        cmdBuf, origCmdBuf, alignedSense->er_sensekey, 4,5);
        !           731:                if(cmdBuf->scsiReq->driverStatus == SR_IOST_GOOD) {
        !           732:                        /*
        !           733:                         * Copy aligned sense data to caller's buffer.
        !           734:                         */
        !           735:                        alignedSense = cmdBuf->buffer;
        !           736:                        origCmdBuf->scsiReq->senseData = *alignedSense;
        !           737:                        origCmdBuf->scsiReq->driverStatus = SR_IOST_CHKSV;
        !           738:                }
        !           739:                else {
        !           740:                        IOLog("AMD53C974: Autosense request for target %d"
        !           741:                                " FAILED (%s)\n",
        !           742:                                cmdBuf->scsiReq->target, 
        !           743:                                IOFindNameForValue(scsiReq->driverStatus, 
        !           744:                                    IOScStatusStrings));
        !           745:                        origCmdBuf->scsiReq->driverStatus = SR_IOST_CHKSNV;
        !           746:                }
        !           747:                
        !           748:                /*
        !           749:                 * Free all of the allocated memory associated with 
        !           750:                 * this autosense request. 
        !           751:                 */
        !           752:                [self deactivateCmd:cmdBuf];
        !           753:                IOFree(cmdBuf->scsiReq, sizeof(*cmdBuf->scsiReq));
        !           754:                IOFree(cmdBuf->unalignedSense, 
        !           755:                        sizeof(esense_reply_t) + (2 * AMD_READ_START_ALIGN));
        !           756:                IOFree(cmdBuf, sizeof(commandBuf));
        !           757:                
        !           758:                /*
        !           759:                 * Now complete the I/O for the original commandBuf.
        !           760:                 */
        !           761:                [origCmdBuf->cmdLock lock];
        !           762:                [origCmdBuf->cmdLock unlockWith:YES];
        !           763:                return;
        !           764:        }
        !           765:        if(scsiReq != NULL) {
        !           766:                IOGetTimestamp(&currentTime);
        !           767:                scsiReq->totalTime = currentTime - cmdBuf->startTime;
        !           768:                scsiReq->bytesTransferred = 
        !           769:                        scsiReq->maxTransfer - cmdBuf->currentByteCount;
        !           770:                        
        !           771:                /*
        !           772:                 * Catch bad SCSI status now.
        !           773:                 */
        !           774:                if(scsiReq->driverStatus == SR_IOST_GOOD) {
        !           775:                        #if     TEST_QUEUE_FULL
        !           776:                        if(testQueueFull && 
        !           777:                           (activeArray[scsiReq->target][scsiReq->lun] > 1)) {
        !           778:                                scsiReq->scsiStatus = STAT_QUEUE_FULL;
        !           779:                                testQueueFull = 0;
        !           780:                        }
        !           781:                        #endif  TEST_QUEUE_FULL
        !           782:                        switch(scsiReq->scsiStatus) {
        !           783:                            case STAT_GOOD:
        !           784:                                break;
        !           785:                            case STAT_CHECK:
        !           786:                                if(autoSenseEnable) {
        !           787:                                    /*
        !           788:                                     * Generate an autosense request, enqueue
        !           789:                                     * on pendingQ.
        !           790:                                     */
        !           791:                                    [self generateAutoSense:cmdBuf];
        !           792:                                    if(cmdBuf->active) {
        !           793:                                        [self deactivateCmd:cmdBuf];
        !           794:                                    }
        !           795:                                    return;
        !           796:                                }
        !           797:                                else {
        !           798:                                    scsiReq->driverStatus = SR_IOST_CHKSNV;
        !           799:                                }
        !           800:                                break;
        !           801:                                
        !           802:                            case STAT_QUEUE_FULL:
        !           803:                                /*
        !           804:                                 * Avoid notifying client of this condition;
        !           805:                                 * update perTarget.maxQueue and place this 
        !           806:                                 * request on pendingQ. We'll try this 
        !           807:                                 * again when we ioComplete at least one
        !           808:                                 * command in this target's queue.
        !           809:                                 */
        !           810:                                if(cmdBuf->queueTag == QUEUE_TAG_NONTAGGED) {
        !           811:                                    /*
        !           812:                                     * Huh? We're not doing command
        !           813:                                     * queueing...
        !           814:                                     */
        !           815:                                    scsiReq->driverStatus = SR_IOST_BADST;
        !           816:                                    break;
        !           817:                                }
        !           818:                                target = scsiReq->target;
        !           819:                                lun = scsiReq->lun;
        !           820:                                if(cmdBuf->active) {
        !           821:                                    [self deactivateCmd:cmdBuf];
        !           822:                                }
        !           823:                                perTarget[target].maxQueue = 
        !           824:                                        activeArray[target][lun];
        !           825:                                ddm_thr("Target %d QUEUE FULL, maxQueue %d\n",
        !           826:                                        target, perTarget[target].maxQueue,
        !           827:                                        3,4,5);
        !           828:                                queue_enter(&pendingQ, cmdBuf, commandBuf *,
        !           829:                                        link);
        !           830:                                return;
        !           831:                                
        !           832:                            default:
        !           833:                                scsiReq->driverStatus = SR_IOST_BADST;
        !           834:                                break;
        !           835:                        }
        !           836:                }
        !           837:        }
        !           838:        if(cmdBuf->active) {
        !           839:                /*
        !           840:                 * Note that the active flag is false for non-CO_Execute
        !           841:                 * commands and commands aborted from pendingQ.
        !           842:                 */
        !           843:                [self deactivateCmd:cmdBuf];
        !           844:        }
        !           845:        
        !           846:        #if     DDM_DEBUG
        !           847:        {
        !           848:                const char *status;
        !           849:                unsigned moved;
        !           850:                
        !           851:                if(scsiReq != NULL) {
        !           852:                    status = IOFindNameForValue(scsiReq->driverStatus, 
        !           853:                        IOScStatusStrings);
        !           854:                    moved = scsiReq->bytesTransferred;
        !           855:                }
        !           856:                else {
        !           857:                    status = "Complete";
        !           858:                    moved = 0;
        !           859:                }
        !           860:                ddm_thr("ioComplete: cmdBuf 0x%x status %s bytesXfr 0x%x\n", 
        !           861:                        cmdBuf, status, moved,4,5);
        !           862:        }
        !           863:        #endif  DDM_DEBUG
        !           864:        
        !           865:        [cmdBuf->cmdLock lock];
        !           866:        [cmdBuf->cmdLock unlockWith:YES];
        !           867: }
        !           868: 
        !           869: /*
        !           870:  * Generate autosense request for specified cmdBuf, place it 
        !           871:  * at head of pendingQ.
        !           872:  */
        !           873: - (void)generateAutoSense : (commandBuf *)cmdBuf
        !           874: {
        !           875:        IOSCSIRequest   *scsiReq = cmdBuf->scsiReq;
        !           876:        commandBuf      *senseCmdBuf;
        !           877:        IOSCSIRequest   *senseScsiReq;
        !           878:        cdb_6_t         *cdbp;
        !           879:        
        !           880:        senseCmdBuf  = IOMalloc(sizeof(commandBuf));
        !           881:        senseScsiReq = IOMalloc(sizeof(IOSCSIRequest));
        !           882:        bzero(senseCmdBuf,  sizeof(commandBuf));
        !           883:        bzero(senseScsiReq, sizeof(IOSCSIRequest));
        !           884:        
        !           885:        /*
        !           886:         * commandBuf fields....
        !           887:         */
        !           888:        senseCmdBuf->cmdPendingSense = cmdBuf;
        !           889:        senseCmdBuf->op              = CO_Execute;
        !           890:        senseCmdBuf->scsiReq         = senseScsiReq;
        !           891:        
        !           892:        /*
        !           893:         * Get aligned sense buffer.
        !           894:         */
        !           895:        senseCmdBuf->unalignedSense = IOMalloc(sizeof(esense_reply_t) + 
        !           896:                                        (2 * AMD_READ_START_ALIGN));
        !           897:        senseCmdBuf->buffer         = IOAlign(void *, 
        !           898:                                        senseCmdBuf->unalignedSense,
        !           899:                                        AMD_READ_START_ALIGN);
        !           900:        senseCmdBuf->client         = IOVmTaskSelf();
        !           901:        
        !           902:        /* 
        !           903:         * Now IOSCSIRequest fields for request sense.
        !           904:         */
        !           905:        senseScsiReq->target        = scsiReq->target;
        !           906:        senseScsiReq->lun           = scsiReq->lun;
        !           907:        senseScsiReq->read          = YES;
        !           908:        senseScsiReq->maxTransfer   = sizeof(esense_reply_t);
        !           909:        senseScsiReq->timeoutLength = 10;
        !           910:        senseScsiReq->disconnect    = 0;
        !           911:        
        !           912:        cdbp                        = &senseScsiReq->cdb.cdb_c6;
        !           913:        cdbp->c6_opcode             = C6OP_REQSENSE;
        !           914:        cdbp->c6_lun                = scsiReq->lun;
        !           915:        cdbp->c6_len                = sizeof(esense_reply_t);
        !           916:        senseScsiReq->driverStatus  = SR_IOST_INVALID;
        !           917:        
        !           918:        /*
        !           919:         * This goes at the head of pendingQ; hopefully it'll be the 
        !           920:         * next command out to the bus.
        !           921:         */
        !           922:        ddm_thr("generateAutoSense: autosense buf 0x%x enqueued for "
        !           923:                "cmdBuf 0x%x\n", senseCmdBuf, cmdBuf, 3,4,5);
        !           924:        queue_enter_first(&pendingQ, senseCmdBuf, commandBuf *, link);
        !           925: 
        !           926: }
        !           927: 
        !           928: /*
        !           929:  * I/O associated with activeCmd has disconnected. Place it on disconnectQ
        !           930:  * and enable another transaction.
        !           931:  */ 
        !           932: - (void)disconnect
        !           933: {
        !           934:        ddm_thr("DISCONNECT: cmdBuf 0x%x target %d lun %d tag %d\n",
        !           935:                activeCmd, activeCmd->scsiReq->target,
        !           936:                activeCmd->scsiReq->lun, activeCmd->queueTag, 5);
        !           937:        queue_enter(&disconnectQ,
        !           938:                activeCmd,
        !           939:                commandBuf *,
        !           940:                link);
        !           941:        #if     DDM_DEBUG
        !           942:        if((activeCmd->currentByteCount != activeCmd->scsiReq->maxTransfer) &&
        !           943:           (activeCmd->currentByteCount != 0)) {
        !           944:                ddm_thr("disconnect after partial DMA (max 0x%d curr 0x%x)\n",
        !           945:                        activeCmd->scsiReq->maxTransfer, 
        !           946:                        activeCmd->currentByteCount, 3,4,5);
        !           947:        }
        !           948:        #endif  DDM_DEBUG
        !           949:        /*
        !           950:         * Record this time so that activeCmd can be billed for
        !           951:         * disconnect latency at reselect time.
        !           952:         */
        !           953:        IOGetTimestamp(&activeCmd->disconnectTime);
        !           954:        activeCmd = NULL;
        !           955:        /* [self busFree]; NO! fsm does this at end of hwInterrupt! */
        !           956: }
        !           957: 
        !           958: /*
        !           959:  * Specified target, lun, and queueTag is trying to reselect. If we have 
        !           960:  * a commandBuf for this TLQ nexus on disconnectQ, remove it, make it the
        !           961:  * current activeCmd, and return YES. Else return NO.
        !           962:  * A value of zero for queueTag indicates a nontagged command (zero is never
        !           963:  * used as the queue tag value for a tagged command).
        !           964:  */
        !           965: - (BOOL)reselect : (unsigned char)target_id
        !           966:             lun : (unsigned char)lun
        !           967:         queueTag : (unsigned char)queueTag
        !           968: {
        !           969:        commandBuf *cmdBuf;
        !           970:        IOSCSIRequest *scsiReq;
        !           971:        ns_time_t currentTime;
        !           972:        
        !           973:        cmdBuf = (commandBuf *)queue_first(&disconnectQ);
        !           974:        while(!queue_end(&disconnectQ, (queue_t)cmdBuf)) {
        !           975:        
        !           976:                scsiReq = cmdBuf->scsiReq;
        !           977:                if((scsiReq->target == target_id) && 
        !           978:                   (scsiReq->lun == lun) &&
        !           979:                   (cmdBuf->queueTag == queueTag)) {
        !           980:                        ddm_thr("RESELECT: target %d lun %d tag %d FOUND;"
        !           981:                                "cmdBuf 0x%x\n",
        !           982:                                target_id, lun, queueTag, cmdBuf, 5);
        !           983:                        queue_remove(&disconnectQ,
        !           984:                                cmdBuf,
        !           985:                                commandBuf *,
        !           986:                                link);
        !           987:                        activeCmd = cmdBuf;
        !           988:                        
        !           989:                        /*
        !           990:                         * Bill this operation for latency time.
        !           991:                         */
        !           992:                        IOGetTimestamp(&currentTime);
        !           993:                        scsiReq->latentTime += 
        !           994:                                (currentTime - activeCmd->disconnectTime);
        !           995:                        return(YES);
        !           996:                }
        !           997:                /*
        !           998:                 * Try next element in queue.
        !           999:                 */
        !          1000:                cmdBuf = (commandBuf *)cmdBuf->link.next;
        !          1001:        }
        !          1002: 
        !          1003:        /*
        !          1004:         * Hmm...this is not good! We don't want to talk to this target.
        !          1005:         */     
        !          1006:        IOLog("%s: ILLEGAL RESELECT target %d lun %d tag %d\n",
        !          1007:                                [self name], target_id, lun, queueTag);
        !          1008:        return(NO);
        !          1009: }
        !          1010: 
        !          1011: /*
        !          1012:  * Determine if activeArray[][], maxQueue, cmdQueueEnable, and a 
        !          1013:  * command's target and lun show that it's OK to start processing cmdBuf.
        !          1014:  * Returns YES if copacetic.
        !          1015:  */
        !          1016: - (BOOL)cmdBufOK : (commandBuf *)cmdBuf
        !          1017: {
        !          1018:        IOSCSIRequest   *scsiReq = cmdBuf->scsiReq;
        !          1019:        unsigned        target   = scsiReq->target;
        !          1020:        unsigned        lun      = scsiReq->lun;
        !          1021:        unsigned char   active;
        !          1022:        unsigned char   maxQ;
        !          1023:        
        !          1024:        active = activeArray[target][lun];
        !          1025:        if(active == 0) {
        !          1026:                /*
        !          1027:                 * Trivial quiescent case, always OK.
        !          1028:                 */
        !          1029:                return YES;
        !          1030:        }
        !          1031:        if((cmdQueueEnable == 0) ||
        !          1032:           (perTarget[target].cmdQueueDisable)) {
        !          1033:                /*
        !          1034:                 * No command queueing (either globally or for this target),
        !          1035:                 * only one at a time.
        !          1036:                 */
        !          1037:                return NO;
        !          1038:        }
        !          1039:        maxQ = perTarget[target].maxQueue;
        !          1040:        if(maxQ == 0) {
        !          1041:                /*
        !          1042:                 * We don't know what the target's limit is; go for it.
        !          1043:                 */
        !          1044:                return YES;
        !          1045:        }
        !          1046:        if(active >= maxQ) {
        !          1047:                /*
        !          1048:                 * T/L's queue full; hold off.
        !          1049:                 */ 
        !          1050:                return NO;
        !          1051:        }       
        !          1052:        else {
        !          1053:                return YES;
        !          1054:        }
        !          1055: }
        !          1056: 
        !          1057: /*
        !          1058:  * The bus has gone free. Start up a command from pendingQ, if any, and
        !          1059:  * if allowed by cmdQueueEnable and activeArray[][].
        !          1060:  */
        !          1061: - (void)busFree
        !          1062: {
        !          1063:        commandBuf *cmdBuf;
        !          1064:        
        !          1065:        ASSERT(activeCmd == NULL);
        !          1066:        if(queue_empty(&pendingQ)) {
        !          1067:                ddm_thr("busFree: pendingQ empty\n", 1,2,3,4,5);
        !          1068:                return;
        !          1069:        }
        !          1070:        
        !          1071:        /*
        !          1072:         * Attempt to find a commandBuf in pendingQ which we are in a position
        !          1073:         * to process.
        !          1074:         */
        !          1075:        cmdBuf = (commandBuf *)queue_first(&pendingQ);
        !          1076:        while(!queue_end(&pendingQ, (queue_entry_t)cmdBuf)) {
        !          1077:                if([self cmdBufOK:cmdBuf]) {
        !          1078:                        queue_remove(&pendingQ, cmdBuf, commandBuf *, link);
        !          1079:                        ddm_thr("busFree: starting pending cmd 0x%x\n", cmdBuf,
        !          1080:                                2,3,4,5);
        !          1081:                        [self threadExecuteRequest:cmdBuf];
        !          1082:                        return; 
        !          1083:                }
        !          1084:                else {
        !          1085:                        cmdBuf = (commandBuf *)queue_next(&cmdBuf->link);
        !          1086:                }
        !          1087:        }
        !          1088:        ddm_thr("busFree: pendingQ non-empty, no commands available\n", 
        !          1089:                1,2,3,4,5);
        !          1090: }
        !          1091: 
        !          1092: /*
        !          1093:  * Abort activeCmd (if any) and any disconnected I/Os (if any) and reset 
        !          1094:  * the bus due to gross hardware failure.
        !          1095:  * If activeCmd is valid, its scsiReq->driverStatus will be set to 'status'.
        !          1096:  */
        !          1097: - (void)hwAbort                : (sc_status_t)status
        !          1098:                         reason : (const char *)reason
        !          1099: {
        !          1100:        if(activeCmd) {
        !          1101:                activeCmd->scsiReq->driverStatus = status;
        !          1102:                [self ioComplete:activeCmd];
        !          1103:                activeCmd = NULL;
        !          1104:        }
        !          1105:        [self logRegs];
        !          1106:        [self threadResetBus:reason];   
        !          1107: }
        !          1108: 
        !          1109: /*
        !          1110:  * Called by chip level to indicate that a command has gone out to the 
        !          1111:  * hardware.
        !          1112:  */
        !          1113: - (void)activateCommand : (commandBuf *)cmdBuf
        !          1114: {
        !          1115:        unsigned char target;
        !          1116:        unsigned char lun;
        !          1117:        
        !          1118:        /*
        !          1119:         * Start timeout timer for this I/O. The timer request is cancelled
        !          1120:         * in ioComplete.
        !          1121:         */
        !          1122:        cmdBuf->timeoutPort = interruptPortKern;
        !          1123:        #if     LONG_TIMEOUT
        !          1124:        cmdBuf->scsiReq->timeoutLength = OUR_TIMEOUT;
        !          1125:        #endif  LONG_TIMEOUT
        !          1126:        IOScheduleFunc(AMDTimeout, cmdBuf, cmdBuf->scsiReq->timeoutLength);
        !          1127:        
        !          1128:        /*
        !          1129:         * This is the only place where an activeArray[][] counter is 
        !          1130:         * incremented (and, hence, the only place where cmdBuf->active is 
        !          1131:         * set). The only other place activeCmd is set to non-NULL
        !          1132:         * is in reselect:lun:queueTag.
        !          1133:         */
        !          1134:        activeCmd = cmdBuf;
        !          1135:        target = cmdBuf->scsiReq->target;
        !          1136:        lun = cmdBuf->scsiReq->lun;
        !          1137:        activeArray[target][lun]++;
        !          1138:        activeCount++;
        !          1139:        cmdBuf->active = 1;
        !          1140: 
        !          1141:        /*
        !          1142:         * Accumulate statistics.
        !          1143:         */
        !          1144:        maxQueueLen = MAX(maxQueueLen, activeCount);
        !          1145:        queueLenTotal += activeCount;
        !          1146:        totalCommands++;
        !          1147:        ddm_thr("activateCommand: cmdBuf 0x%x target %d lun %d\n",
        !          1148:                cmdBuf, target, lun, 4,5);
        !          1149: }
        !          1150: 
        !          1151: /*
        !          1152:  * Remove specified cmdBuf from "active" status. Update activeArray,
        !          1153:  * activeCount, and unschedule pending timer.
        !          1154:  */
        !          1155: - (void)deactivateCmd : (commandBuf *)cmdBuf
        !          1156: {
        !          1157:        IOSCSIRequest *scsiReq = cmdBuf->scsiReq;
        !          1158:        int target, lun;
        !          1159:        
        !          1160:        ASSERT(scsiReq != NULL);
        !          1161:        target = scsiReq->target;
        !          1162:        lun = scsiReq->lun;
        !          1163:        ddm_thr("deactivate cmdBuf 0x%x target %d lun %d activeArray %d\n",
        !          1164:                cmdBuf, target, lun, activeArray[target][lun], 5);
        !          1165:        ASSERT(activeArray[target][lun] != 0);
        !          1166:        activeArray[target][lun]--;
        !          1167:        ASSERT(activeCount != 0);
        !          1168:        activeCount--;
        !          1169: 
        !          1170:        /*
        !          1171:         * Cancel pending timeout request. Commands which timed out don't
        !          1172:         * have a timer request pending anymore.
        !          1173:         */
        !          1174:        if(scsiReq->driverStatus != SR_IOST_IOTO) {
        !          1175:                IOUnscheduleFunc(AMDTimeout, cmdBuf);
        !          1176:        }
        !          1177:        cmdBuf->active = 0;
        !          1178: }
        !          1179: 
        !          1180: @end   /* AMD_SCSI(Private) */
        !          1181: 
        !          1182: /*
        !          1183:  *  Handle timeouts.  We just send a timeout message to the I/O thread
        !          1184:  *  so it wakes up.
        !          1185:  */
        !          1186: static void AMDTimeout(void *arg)
        !          1187: {
        !          1188:        commandBuf      *cmdBuf = arg;
        !          1189:        msg_header_t    msg = timeoutMsgTemplate;
        !          1190: 
        !          1191:        ddm_err("AMDTimeout: cmdBuf 0x%x target %d\n", cmdBuf,
        !          1192:                cmdBuf->scsiReq->target, 3,4,5);
        !          1193:        if(!cmdBuf->active) {
        !          1194:                /*
        !          1195:                 * Should never happen...
        !          1196:                 */
        !          1197:                IOLog("AMD53C974: Timeout on non-active cmdBuf\n");
        !          1198:                return;
        !          1199:        }
        !          1200:        msg.msg_remote_port = cmdBuf->timeoutPort;
        !          1201:        IOLog("AMD53C974: SCSI Timeout\n");
        !          1202:        (void) msg_send_from_kernel(&msg, MSG_OPTION_NONE, 0);
        !          1203: }
        !          1204: 

unix.superglobalmegacorp.com

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