Annotation of Examples/DriverKit/AMDPCSCSIDriver/AMDPCSCSIDriver_reloc.tproj/AMD_SCSI.m, revision 1.1.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.