Annotation of driverkit/libDriver/Kernel/SCSIDiskThread.m, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: /*     Copyright (c) 1991 NeXT Computer, Inc.  All rights reserved. 
                     25:  *
                     26:  * SCSIDiskThread.m - Implementation of SCSIDisk I/O thread and its associated
                     27:  *               methods. All communication with the SCSIController object
                     28:  *               is done here. 
                     29:  *
                     30:  * HISTORY
                     31:  * 04-Mar-91    Doug Mitchell at NeXT
                     32:  *      Created.
                     33:  */
                     34: 
                     35: /*
                     36:  * Enforce clean driverkit implementation.
                     37:  */
                     38: #define MACH_USER_API  1       
                     39: #undef KERNEL_PRIVATE
                     40: 
                     41: #import <sys/types.h>
                     42: #import <kernserv/prototypes.h>
                     43: #import <driverkit/SCSIDiskPrivate.h>
                     44: #import <driverkit/SCSIDiskTypes.h>
                     45: #import <driverkit/SCSIDiskThread.h>
                     46: #import <driverkit/SCSIStructInlines.h>
                     47: #import <bsd/dev/scsireg.h>
                     48: #import <driverkit/xpr_mi.h>   
                     49: #import <driverkit/volCheck.h>
                     50: #import <driverkit/kernelDiskMethods.h>
                     51: #import <kern/assert.h>
                     52: #import <machkit/NXLock.h>
                     53: #import <driverkit/align.h>
                     54: 
                     55: static void sdThreadDequeue(SCSIDisk *sdp, 
                     56:        BOOL needs_disk);
                     57: 
                     58: @implementation SCSIDisk(Thread)
                     59: 
                     60: /*
                     61:  * Execute one I/O, as specified in sdBuf. Called out from an I/O thread.
                     62:  *
                     63:  * This is certainly the most complicated part of the SCSIDisk object; all 
                     64:  * retry logic is done here. It's kind of big. Maybe we can break this up 
                     65:  * a little bit.
                     66:  */
                     67: - (void)doSdBuf        : (sdBuf_t *)sdBuf
                     68: {
                     69:        IOSCSIRequest scsiReq;
                     70:        sc_status_t scrtn = SR_IOST_INVALID;
                     71:        IOReturn iortn;
                     72:        esense_reply_t senseReply;
                     73:        const char *name = [self name];
                     74:        
                     75:        xpr_sd("sd%d doSdBuf: sdBuf 0x%x\n", [self unit], sdBuf, 3,4,5);
                     76:        
                     77:        /*
                     78:         * Initialize retry counters.
                     79:         */
                     80:        sdBuf->busy_retry   = SD_RETRY_BUSY;
                     81:        sdBuf->norm_retry   = SD_RETRY_NORM;
                     82:        sdBuf->notRdy_retry = SD_RETRY_NOTRDY;
                     83: 
                     84:        while(sdBuf->busy_retry && sdBuf->norm_retry && sdBuf->notRdy_retry) {
                     85:        
                     86:                /*
                     87:                 * Set up a scsiReq to pass to the controller.
                     88:                 */
                     89:                scrtn = [self setupScsiReq:sdBuf scsiReq:&scsiReq];
                     90:                if(scrtn)
                     91:                        return;
                     92:                        
                     93:                
                     94:                /*
                     95:                 * Go for it.
                     96:                 */
                     97:                senseReply.er_ibvalid = 0;      // for error logging
                     98:                scrtn = [_controller executeRequest:&scsiReq
                     99:                        buffer:sdBuf->buf
                    100:                        client:sdBuf->client];
                    101:                xpr_sd("sd%d: CDB Complete: sdBuf 0x%x driverStatus "
                    102:                        "%s scsiStatus"
                    103:                        " 0x%x\n", [self unit], sdBuf, 
                    104:                        IOFindNameForValue(scsiReq.driverStatus, 
                    105:                                IOScStatusStrings),
                    106:                        scsiReq.scsiStatus, 5);
                    107:                if(scrtn == SR_IOST_GOOD) {
                    108:                        if((sdBuf->command == SDOP_READ) ||
                    109:                           (sdBuf->command == SDOP_WRITE)) {
                    110:                                /* 
                    111:                                 * Make sure the we moved the number of 
                    112:                                 * bytes we wanted to. Note we skip this
                    113:                                 * test for SDOP_CDB_xxx - that's the 
                    114:                                 * user's problem.
                    115:                                 */
                    116:                                u_int block_size = [self blockSize];
                    117:                                if((sdBuf->blockCnt * block_size) !=
                    118:                                    scsiReq.bytesTransferred) {
                    119:                                    if(--sdBuf->norm_retry <= 0) {
                    120:                                        IOLog("%s: TRANSFER COUNT ERROR; "
                    121:                                            " FATAL.\n",  name);
                    122:                                        [self logOpInfo:sdBuf 
                    123:                                                sense:&senseReply];
                    124:                                        scrtn = SR_IOST_BCOUNT;
                    125:                                        goto abort;
                    126:                                    }
                    127:                                    IOLog("%s: TRANSFER COUNT ERROR. "
                    128:                                        " Expected = %d Received %d; "
                    129:                                        "Retrying.\n", name,
                    130:                                        sdBuf->blockCnt * block_size,
                    131:                                        sdBuf->bytesXfr);
                    132:                                        [self logOpInfo:sdBuf sense:NULL];
                    133:                                        goto do_retry;
                    134:                                }
                    135:                        }       
                    136:                        
                    137:                        /*
                    138:                         * Success. Log statistics.
                    139:                         */
                    140:                        if(_isRegistered) {
                    141:                            switch(sdBuf->command) {
                    142:                                case SDOP_READ:
                    143:                                    [self addToBytesRead:
                    144:                                        scsiReq.bytesTransferred
                    145:                                            totalTime:scsiReq.totalTime
                    146:                                            latentTime:scsiReq.latentTime];
                    147:                                    break;
                    148:                                case SDOP_WRITE:
                    149:                                    [self addToBytesWritten:
                    150:                                        scsiReq.bytesTransferred
                    151:                                            totalTime:scsiReq.totalTime
                    152:                                            latentTime:scsiReq.latentTime];
                    153:                                    break;
                    154:                            }
                    155:                        }
                    156:                        
                    157:                        /*
                    158:                         * All right, we're done.
                    159:                         */
                    160:                        break;
                    161:                }
                    162:                
                    163:                if(sdBuf->retryDisable)
                    164:                        goto abort;
                    165:                        
                    166:                /*
                    167:                 * What seems to be the problem?
                    168:                 */
                    169:                switch(scrtn) {
                    170:                    case SR_IOST_SELTO:         /* selection timeout */
                    171:                    case SR_IOST_ALIGN:         /* DMA alignment */
                    172:                    case SR_IOST_BCOUNT:        /* DMA overrun */
                    173:                    case SR_IOST_CMDREJ:        /* command reject */
                    174:                    case SR_IOST_MEMALL:        /* malloc error */
                    175:                    case SR_IOST_MEMF:          /* memory failure */
                    176:                    case SR_IOST_IPCFAIL:       /* IPC failure */
                    177:                    case SR_IOST_INT:           /* internal error */
                    178:                    case SR_IOST_VOLNA:         /* volume not available */
                    179:                    case SR_IOST_INVALID:       /* our mistake */
                    180:                    case SR_IOST_WP:            /* write protect */
                    181:                    
                    182:                        /*
                    183:                         * These are not retriable.
                    184:                         */
                    185:                        IOLog("%s: %s : FATAL ERROR\n", name,
                    186:                                IOFindNameForValue(scrtn, IOScStatusStrings));
                    187:                        [self logOpInfo:sdBuf sense:&senseReply];
                    188: 
                    189:                        goto abort;
                    190:                        
                    191:                    case SR_IOST_BADST:
                    192:                    case SR_IOST_CHKSV:
                    193:                    case SR_IOST_CHKSNV:
                    194:                        /*
                    195:                         * The only weird SCSI status values we know how to
                    196:                         * deal with are "Busy" and "Check Status".
                    197:                         */
                    198:                        switch(scsiReq.scsiStatus) {
                    199:                            case STAT_BUSY:
                    200:                                if(--sdBuf->busy_retry <= 0) {
                    201:                                        IOLog("%s: BUSY STATUS; FATAL.\n",
                    202:                                                name);
                    203:                                        [self logOpInfo:sdBuf 
                    204:                                                sense:&senseReply];
                    205:                                        goto abort;
                    206:                                }
                    207:                                IOLog("%s: BUSY STATUS; Retrying.\n", name);
                    208:                                IOSleep(SD_BUSY_SLEEP * 1000);
                    209:                                break;
                    210:                                
                    211:                            case STAT_CHECK:
                    212:                                /*
                    213:                                 * Do a request sense to find out why.
                    214:                                 */
                    215:                                if(scrtn == SR_IOST_CHKSV) {
                    216:                                    /*
                    217:                                     * We already have sense data.
                    218:                                     */
                    219:                                    senseReply = scsiReq.senseData;
                    220:                                }
                    221:                                else {
                    222:                                    scrtn = [self reqSense:&senseReply];
                    223:                                    if(scrtn) {
                    224:                                            IOLog("%s: REQUEST SENSE ERROR; "
                    225:                                                " FATAL.\n", name);
                    226:                                            goto abort;
                    227:                                    }
                    228:                                }
                    229: 
                    230:                                
                    231:                                /*
                    232:                                 * OK, we have valid sense data. 
                    233:                                 */
                    234:                                switch(senseReply.er_sensekey) {
                    235:                                    case SENSE_NOTREADY:
                    236:                                        if(--sdBuf->notRdy_retry <= 0) {
                    237:                                            IOLog("%s: NOT READY; "
                    238:                                                "FATAL.\n", name);
                    239:                                            /*
                    240:                                             * FIXME - do we tell volCheck 
                    241:                                             * about this??
                    242:                                             */
                    243:                                            [self logOpInfo:sdBuf 
                    244:                                                sense:&senseReply];
                    245:                                            goto abort;
                    246:                                        }
                    247:                                        IOLog("%s: NOT READY; Retrying.\n",
                    248:                                                name);
                    249:                                        [self logOpInfo:sdBuf 
                    250:                                            sense:&senseReply];
                    251:                                        IOSleep(SD_NOTRDY_SLEEP * 1000);
                    252:                                        break;
                    253:                                        
                    254:                                    case SENSE_NOSENSE:         // I don't 
                    255:                                                                //  trust this!
                    256:                                    case SENSE_RECOVERED:       // or this
                    257:                                    case SENSE_MEDIA:
                    258:                                    case SENSE_HARDWARE:
                    259:                                        if(--sdBuf->norm_retry <= 0) {
                    260:                                            IOLog("%s: %s; FATAL.\n", name,
                    261:                                                IOFindNameForValue(senseReply.
                    262:                                                   er_sensekey,
                    263:                                                   IOSCSISenseStrings));
                    264:                                            [self logOpInfo:sdBuf 
                    265:                                                sense:&senseReply];
                    266:                                            goto abort;
                    267:                                        }
                    268:                                        IOLog("%s: %s; Retrying.\n", name,
                    269:                                                IOFindNameForValue(senseReply.
                    270:                                                   er_sensekey,
                    271:                                                   IOSCSISenseStrings));
                    272:                                        [self logOpInfo:sdBuf 
                    273:                                            sense:&senseReply];
                    274:                                        break;
                    275:                                        
                    276:                                    case SENSE_UNITATTENTION:
                    277:                                        /*
                    278:                                         * TBD - when we figure out how 
                    279:                                         * to handle removable media...
                    280:                                         */
                    281:                                        if(--sdBuf->norm_retry <= 0) {
                    282:                                            IOLog("%s: UNIT ATTENTION;"
                    283:                                                " FATAL.\n", name);
                    284:                                            [self logOpInfo:sdBuf 
                    285:                                                sense:&senseReply];
                    286:                                            goto abort;
                    287:                                        }
                    288:                                        IOLog("%s: UNIT ATTENTION; "
                    289:                                                "Retrying.\n", name);
                    290:                                        [self logOpInfo:sdBuf 
                    291:                                            sense:&senseReply];
                    292:                                        break;
                    293:                                        
                    294:                                    case SENSE_DATAPROTECT:
                    295:                                        /*
                    296:                                         * Not retryable, but at least we have 
                    297:                                         * a unique error code.
                    298:                                         */
                    299:                                        IOLog("%s: WRITE PROTECTED. FATAL"
                    300:                                                ".\n", name);
                    301:                                        [self logOpInfo:sdBuf 
                    302:                                            sense:&senseReply];
                    303:                                        scrtn = SR_IOST_WP;
                    304:                                        goto abort;
                    305:                                        
                    306:                                    default:
                    307:                                        /*
                    308:                                         * All others fatal.
                    309:                                         */
                    310:                                        IOLog("%s: %s; FATAL.\n", name,
                    311:                                                IOFindNameForValue(senseReply.
                    312:                                                   er_sensekey,
                    313:                                                   IOSCSISenseStrings));
                    314:                                        [self logOpInfo:sdBuf 
                    315:                                            sense:&senseReply];
                    316:                                        scrtn = SR_IOST_CHKSV;
                    317:                                        goto abort;                                     
                    318:                                }               /* switch sense key */                  
                    319:                                break;          /* from case STAT_CHECK */
                    320:                                
                    321:                            default:
                    322:                                /*
                    323:                                 * Sorry, no can do.
                    324:                                 */
                    325:                                IOLog("%s: BOGUS SCSI STATUS (0x%x): "
                    326:                                        "FATAL.\n", name, scsiReq.scsiStatus);
                    327:                                [self logOpInfo:sdBuf 
                    328:                                    sense:&senseReply];
                    329:                                scrtn = SR_IOST_BADST;
                    330:                                goto abort;
                    331:                                
                    332:                        }               /* switch scsiStatus */
                    333:                        break;          /* from case SR_IOST_BADST */
                    334:                        
                    335:                    default:
                    336:                        /*
                    337:                         * Well, what the hey. retry.
                    338:                         */
                    339:                        if(--sdBuf->norm_retry <= 0) {
                    340:                            IOLog("%s: %s; FATAL.\n", name,
                    341:                                IOFindNameForValue(scrtn, IOScStatusStrings));
                    342:                            [self logOpInfo:sdBuf 
                    343:                                sense:&senseReply];
                    344:                            goto abort;
                    345:                        }
                    346:                        IOLog("%s: %s; Retrying.\n", name,
                    347:                                IOFindNameForValue(scrtn, IOScStatusStrings));
                    348:                        [self logOpInfo:sdBuf 
                    349:                            sense:&senseReply];
                    350:                        break;
                    351:                } /* switch scrtn */
                    352: do_retry:
                    353:                /*
                    354:                 * Retrying. log this with IODisk.
                    355:                 */
                    356:                if(_isRegistered) {
                    357:                    switch(sdBuf->command) {
                    358:                        case SDOP_READ:
                    359:                            [self incrementReadRetries];
                    360:                            break;
                    361:                        case SDOP_WRITE:
                    362:                            [self incrementWriteRetries];
                    363:                            break;
                    364:                        default:
                    365:                            [self incrementOtherRetries];
                    366:                            break;
                    367:                    }
                    368:                }
                    369:        } /* main retry loop */
                    370:        
                    371: abort:
                    372: 
                    373:        /*
                    374:         * We've either successfuly executed the command or have given up.
                    375:         * Transfer appropriate return values to sdBuf and sdIoComplete the
                    376:         * result.
                    377:         */
                    378:        if((sdBuf->busy_retry == 0) ||
                    379:           (sdBuf->norm_retry == 0) ||
                    380:           (sdBuf->notRdy_retry == 0)) {
                    381:                iortn = IO_R_IO;
                    382:        }
                    383:        else if(scrtn) {
                    384:                iortn = [_controller returnFromScStatus:scrtn];
                    385:        }
                    386:        else {
                    387:                iortn = IO_R_SUCCESS;
                    388:        }
                    389:        if(iortn && _isRegistered) {
                    390:                /*
                    391:                 * All fatal errors must be logged with IODisk.
                    392:                 */
                    393:                switch(sdBuf->command) {
                    394:                    case SDOP_READ:
                    395:                        [self incrementReadErrors];
                    396:                        break;
                    397:                    case SDOP_WRITE:
                    398:                        [self incrementWriteErrors];
                    399:                        break;
                    400:                    default:
                    401:                        if(!sdBuf->retryDisable) {
                    402:                                [self incrementOtherErrors];
                    403:                        }
                    404:                        break;
                    405:                }
                    406:        }
                    407:        if(sdBuf->scsiReq) {
                    408:                /*
                    409:                 * This implies SDOP_CDB_{READ,WRITE}.
                    410:                 */
                    411:                sdBuf->scsiReq->driverStatus = scsiReq.driverStatus;
                    412:                sdBuf->scsiReq->scsiStatus = scsiReq.scsiStatus;
                    413:                sdBuf->scsiReq->bytesTransferred = scsiReq.bytesTransferred;
                    414: 
                    415:                /*
                    416:                 * Don't forget to copy over the sense data if the controller
                    417:                 * has provided it to us.   We do not copy sense data that we
                    418:                 * manually requested for our own purposes in SCSIDisk.
                    419:                 */
                    420:                if (scsiReq.driverStatus == SR_IOST_CHKSV)
                    421:                  sdBuf->scsiReq->senseData = scsiReq.senseData;
                    422:        }
                    423: #if    0
                    424:        else if(iortn == IO_R_SUCCESS) {
                    425:                /*
                    426:                 * We know we can read this thing.
                    427:                 */
                    428:                [self setFormattedInternal:1];
                    429:        }
                    430: #endif 0
                    431:        sdBuf->bytesXfr = scsiReq.bytesTransferred;
                    432:        sdBuf->status = iortn;
                    433:        [self sdIoComplete:sdBuf];
                    434:        return;
                    435: }
                    436: 
                    437: /*
                    438:  * Log info about current operation for retry/error reporting.
                    439:  */
                    440: - (void)logOpInfo : (sdBuf_t *)sdBuf
                    441:                    sense : (esense_reply_t *)senseReply
                    442: {
                    443:        char opString[40];
                    444:        char blockString[80];
                    445: 
                    446:        blockString[0] = '\0';
                    447:        switch(sdBuf->command) {
                    448:            case SDOP_READ:
                    449:                strcpy(opString, "Read");
                    450:                goto logBlock;
                    451:            case SDOP_WRITE:
                    452:                strcpy(opString, "Write");
                    453: logBlock:      
                    454:                if(senseReply && senseReply->er_ibvalid) {
                    455:                        /*
                    456:                         * Get block # from sense data
                    457:                         */
                    458:                        unsigned blockInErr;
                    459:                        
                    460:                        blockInErr = scsi_error_info(senseReply);
                    461:                        sprintf(blockString, "block:%d", blockInErr);
                    462:                }
                    463:                else {
                    464:                        /*
                    465:                         * Just report starting block # and length.
                    466:                         */
                    467:                        sprintf(blockString, "block:%d blockCount:%d",
                    468:                                sdBuf->block, sdBuf->blockCnt);
                    469:                }
                    470:                break;
                    471:                
                    472:            case SDOP_CDB_READ:
                    473:            case SDOP_CDB_WRITE:
                    474:                strcpy(opString, 
                    475:                        IOFindNameForValue(sdBuf->scsiReq->cdb.cdb_opcode,
                    476:                        IOSCSIOpcodeStrings));
                    477:                break;
                    478:                
                    479:            case SDOP_EJECT:
                    480:                strcpy(opString, "Eject");
                    481:                break;
                    482:                
                    483:            default:
                    484:                /*
                    485:                 * The remainder should not result in disk errors...
                    486:                 */
                    487:                panic("Bogus op in logOpInfo");
                    488:        }
                    489:        IOLog("   target:%d lun:%d op:%s %s\n", _target, _lun, 
                    490:                opString, blockString);
                    491:        return;
                    492: }
                    493: 
                    494: /*
                    495:  * generate a CDB for a read or write operation. Assumes that *cdbp has
                    496:  * already been zero'd.
                    497:  */
                    498: - (void)genRwCdb : (cdb_t *)cdbp
                    499:        readFlag : (BOOL)readFlag
                    500:        block : (u_int)block
                    501:        blockCnt : (u_int)blockCnt
                    502: {
                    503:        cdb_10_t *cdb = &cdbp->cdb_c10; 
                    504:        unsigned short blockCntS = blockCnt;
                    505:                 
                    506:        if (readFlag)
                    507:                scsi_readextended_setup(cdb, _lun, block, blockCntS);
                    508:        else
                    509:                scsi_writeextended_setup(cdb, _lun, block, blockCntS);
                    510: }
                    511: 
                    512: /*
                    513:  * Set up a scsiReq for a given sdBuf_t to pass to the controller. Only used
                    514:  * inside of I/O thread.
                    515:  */
                    516: - (sc_status_t)setupScsiReq:(sdBuf_t *)sdBuf
                    517:        scsiReq:(IOSCSIRequest *)scsiReq
                    518: { 
                    519:        u_int block_size;
                    520:        
                    521:        block_size = [self blockSize];
                    522:        bzero(scsiReq, sizeof(IOSCSIRequest));
                    523:        scsiReq->target = _target;
                    524:        scsiReq->lun = _lun;
                    525:        switch(sdBuf->command) {
                    526:            case SDOP_READ:
                    527:                scsiReq->read = YES;
                    528:                [self genRwCdb:&scsiReq->cdb
                    529:                        readFlag : YES
                    530:                        block : sdBuf->block
                    531:                        blockCnt : sdBuf->blockCnt];
                    532:                goto rw_common;
                    533:                
                    534:            case SDOP_WRITE:
                    535:                scsiReq->read = NO;
                    536:                [self genRwCdb:&scsiReq->cdb
                    537:                        readFlag : NO
                    538:                        block : sdBuf->block
                    539:                        blockCnt : sdBuf->blockCnt];
                    540: rw_common:
                    541:                sdBuf->scsiReq = NULL;
                    542:                scsiReq->maxTransfer = sdBuf->blockCnt * block_size;
                    543:                scsiReq->timeoutLength = SD_TIMEOUT_RW;
                    544:                scsiReq->disconnect = 1;
                    545:                break;
                    546:                
                    547:            case SDOP_EJECT:
                    548:            case SDOP_CDB_READ:
                    549:            case SDOP_CDB_WRITE:
                    550:                if((sdBuf->scsiReq->target != _target) ||
                    551:                    (sdBuf->scsiReq->lun != _lun)) {
                    552:                        /*
                    553:                         * Ooops, can't allow this!
                    554:                         */
                    555:                        sdBuf->scsiReq->driverStatus = SR_IOST_CMDREJ;
                    556:                        sdBuf->status = IO_R_INVALID_ARG;
                    557:                        [self sdIoComplete:sdBuf];
                    558:                        return(SR_IOST_CMDREJ);
                    559:                }
                    560:                /*
                    561:                 * Otherwise, we'll allow just about anything.
                    562:                 */
                    563:                *scsiReq = *sdBuf->scsiReq;
                    564:                break;
                    565:            default:
                    566:                ASSERT(0);
                    567:                break;  
                    568:        }
                    569:        return(SR_IOST_GOOD);
                    570: }
                    571: 
                    572: /*
                    573:  * Execute a request sense command within the I/O thread. esenseReply
                    574:  * does not have to be aligned.
                    575:  */
                    576: - (sc_status_t)reqSense : (esense_reply_t *)esenseReply
                    577: {
                    578:        IOSCSIRequest scsiReq;
                    579:        sc_status_t rtn;
                    580:        cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
                    581:        esense_reply_t *alignedReply;
                    582:        void *freep;
                    583:        int freeCnt;
                    584:        IODMAAlignment dmaAlign;
                    585:        
                    586:        xpr_sd("sd%d reqSense\n", [self unit], 2,3,4,5);
                    587: 
                    588:        /*
                    589:         * Get some well-aligned memory.
                    590:         */
                    591:        alignedReply = [_controller allocateBufferOfLength:
                    592:                                        sizeof(esense_reply_t)
                    593:                        actualStart:&freep
                    594:                        actualLength:&freeCnt];
                    595:        bzero(&scsiReq, sizeof(IOSCSIRequest));
                    596:        
                    597:        cdbp->c6_opcode = C6OP_REQSENSE;
                    598:        cdbp->c6_lun = _lun;
                    599:        cdbp->c6_len = sizeof(esense_reply_t);
                    600:        scsiReq.target = _target;
                    601:        scsiReq.lun = _lun;
                    602:        scsiReq.read = YES;
                    603: 
                    604:        /*
                    605:         * Get appropriate alignment from controller. 
                    606:         */
                    607:        [_controller getDMAAlignment:&dmaAlign];
                    608:        if(dmaAlign.readLength > 1) {
                    609:                scsiReq.maxTransfer = IOAlign(int, sizeof(esense_reply_t), 
                    610:                        dmaAlign.readLength);
                    611:        }
                    612:        else {
                    613:                scsiReq.maxTransfer = sizeof(esense_reply_t);
                    614:        }
                    615:        scsiReq.timeoutLength = SD_TIMEOUT_SIMPLE;
                    616:        scsiReq.disconnect = 1;
                    617:        rtn = [_controller executeRequest:&scsiReq
                    618:                buffer:alignedReply
                    619:                client:IOVmTaskSelf()];
                    620:        /*
                    621:         * Copy data back to caller's struct.
                    622:         */
                    623:         
                    624:        *esenseReply = *alignedReply;
                    625:        IOFree(freep, freeCnt);
                    626:        xpr_sd("sd%d reqSense: returning %d\n", [self unit], rtn, 3,4,5);
                    627:        
                    628:        return(rtn);
                    629: }
                    630: 
                    631: /*
                    632:  * Either wake up the thread which is waiting on the sdBuf, or send an 
                    633:  * ioComplete back to client. sdBuf->status must be valid.
                    634:  */
                    635: - (void)sdIoComplete : (sdBuf_t *)sdBuf
                    636: {
                    637:        xpr_sd("%s sdIoComplete: sdBuf 0x%x status %s\n", 
                    638:                [self name], sdBuf,
                    639:                [self stringFromReturn:sdBuf->status], 4,5);
                    640:        if(sdBuf->pending) {
                    641:        
                    642:                /*
                    643:                 * Async I/O complete. This will change with RO support.
                    644:                 */
                    645:                int dirRead = 0;
                    646:                
                    647:                switch(sdBuf->command) {
                    648:                    case SDOP_READ:
                    649:                    case SDOP_CDB_READ:
                    650:                        dirRead = 1;
                    651:                        break;
                    652:                    default:
                    653:                        break;
                    654:                }
                    655:                [self completeTransfer : sdBuf->pending
                    656:                        withStatus : sdBuf->status
                    657:                        actualLength : sdBuf->bytesXfr];
                    658:                [self freeSdBuf:sdBuf];
                    659:        }
                    660:        else {
                    661:                /*
                    662:                 * Sync I/O. Just wake up the waiting thread.
                    663:                 */
                    664:                [sdBuf->waitLock unlockWith:YES];
                    665:        }
                    666: }
                    667: 
                    668: /*
                    669:  * Unlock ioQLock, updating condition variable as appropriate.
                    670:  */
                    671: - (void)unlockIoQLock
                    672: {
                    673:        int queue_state;
                    674:        IODiskReadyState lastReady = [self lastReadyState];
                    675:        
                    676:        /*
                    677:         * There's still work to do when:
                    678:         *    -- ioQueueNodisk non-empty, or
                    679:         *    -- ioQueueDisk non-empty and we "really" have a disk.
                    680:         */
                    681: 
                    682:        if((!queue_empty(&_ioQueueNodisk)) ||
                    683:                ((!queue_empty(&_ioQueueDisk)) &&
                    684:                        (lastReady != IO_NoDisk) &&
                    685:                        (lastReady != IO_Ejecting) &&
                    686:                        (!_ejectPending)
                    687:                )
                    688:           ) {
                    689:                queue_state = WORK_AVAILABLE;
                    690:        }
                    691:        else    
                    692:                queue_state = NO_WORK_AVAILABLE;
                    693:        [_ioQLock unlockWith:queue_state];
                    694: 
                    695:        if (queue_state == WORK_AVAILABLE)
                    696:                (void) thread_block();
                    697: }
                    698: 
                    699: 
                    700: /*
                    701:  * I/O thread. Each one of these sits around waiting for work to do on 
                    702:  * ioQueue; when something appears, the thread grabs it, creates an
                    703:  * appropriate scsiReq, invokes the proper controller method, and
                    704:  * handles a possible error condition (including retries).
                    705:  */
                    706:  
                    707: volatile void sdIoThread(id me)
                    708: {
                    709:        SCSIDisk *sdp = (SCSIDisk *)me;
                    710:        IODiskReadyState lastReady;
                    711:        
                    712:        xpr_sd("sdIoThread unit %d: STARTING\n", [sdp unit], 2,3,4,5);
                    713:                
                    714:        while(1) {
                    715:                /*
                    716:                 * Wait for some work to do. Keep the ioQLock until we 
                    717:                 * dequeue something.
                    718:                 */
                    719:                xpr_sd("sdIoThread: waiting for work\n", 1,2,3,4,5);
                    720:                [sdp->_ioQLock lockWhen:WORK_AVAILABLE];
                    721:                
                    722:                /*
                    723:                 * Service all requests which do not need a disk.
                    724:                 */
                    725:                xpr_sd("sdIoThread: servicing q_nodisk\n", 1,2,3,4,5);
                    726:                while(!queue_empty(&sdp->_ioQueueNodisk))
                    727:                        sdThreadDequeue(sdp, NO);
                    728:                        
                    729:                /*
                    730:                 * Now service all requests which need a disk, if our disk
                    731:                 * is present. We still hold ioQLock.
                    732:                 */
                    733:                xpr_sd("sdIoThread: servicing q_disk\n", 1,2,3,4,5);
                    734:                while((!queue_empty(&sdp->_ioQueueDisk)) &&
                    735:                      ([sdp lastReadyState] != IO_NoDisk) &&
                    736:                      ([sdp lastReadyState] != IO_Ejecting) &&
                    737:                      (!sdp->_ejectPending)) { 
                    738:                        sdThreadDequeue(sdp, YES);
                    739:                }
                    740:                
                    741:                /*
                    742:                 * If we have work to do in ioQueueDisk but we don't have 
                    743:                 * a disk, ask volCheck to put up a panel. In either case, 
                    744:                 * when we unlock ioQueueLock for the last time, update its
                    745:                 * condition variable as appropriate so we and the other 
                    746:                 * I/O threads know whether or not to sleep.
                    747:                 */
                    748: 
                    749:                lastReady = [sdp lastReadyState];
                    750:                if((!queue_empty(&sdp->_ioQueueDisk)) && 
                    751:                   ((lastReady == IO_NotReady && [sdp isRemovable]) ||
                    752:                    (lastReady == IO_NoDisk) || sdp->_ejectPending)) {
                    753:                        [sdp unlockIoQLock];
                    754:                        xpr_sd("sdIoThread: volCheckRequest()\n", 1,2,3,4,5);
                    755:                        volCheckRequest(sdp, PR_DRIVE_SCSI);
                    756:                }
                    757:                else {
                    758:                        [sdp unlockIoQLock];
                    759:                }
                    760:        }       /* while 1 */
                    761:        
                    762:        /* NOT REACHED */
                    763: }
                    764: 
                    765: /*
                    766:  * Process a request at the head of one of the IOQueues.
                    767:  * ioQLock must be held on entry; it will still be held on exit.
                    768:  */
                    769: static void sdThreadDequeue(SCSIDisk *sdp, 
                    770:        BOOL needs_disk)
                    771: {
                    772:        queue_head_t *q;
                    773:        sdBuf_t *sdBuf;
                    774:        
                    775:        if(needs_disk)
                    776:                q = &sdp->_ioQueueDisk;
                    777:        else
                    778:                q = &sdp->_ioQueueNodisk;
                    779:        if(queue_empty(q)) {
                    780:                IOLog("sdThreadDequeue: Empty queue!\n");
                    781:                return;
                    782:        }
                    783:        sdBuf = (sdBuf_t *)queue_first(q);
                    784:        queue_remove(q, 
                    785:                sdBuf,
                    786:                sdBuf_t *,
                    787:                link);
                    788:        
                    789:        /*
                    790:         * In case of an eject command, we have to ensure right now - while 
                    791:         * the queue is locked - that no other threads attempt any 
                    792:         * "needs disk" type of I/Os. That's what the ejectPending flag is 
                    793:         * for; we can't rely on the volCheck thread setting our 
                    794:         * lastReadyState to RS_EJECTING for another second or so...
                    795:         *
                    796:         * The numDiskIos counter allows the thread doing an eject command
                    797:         * to wait for all other pending Disk I/Os to complete before doing
                    798:         * the eject.
                    799:         */
                    800:        if(needs_disk) {
                    801:                [sdp->_ejectLock lock];
                    802:                sdp->_numDiskIos++;
                    803:                if(sdBuf->command == SDOP_EJECT) {
                    804:                        sdp->_ejectPending = YES;
                    805:                        volCheckEjecting(sdp, PR_DRIVE_SCSI);
                    806:                }
                    807:                [sdp->_ejectLock unlockWith:sdp->_numDiskIos];
                    808:        }
                    809:        
                    810:        /*
                    811:         * Execute command specified in sdBuf. We hold _ioQLock.
                    812:         */
                    813:        
                    814:        xpr_sd("sdThreadDequeue: sdBuf 0x%x received\n", sdBuf, 2,3,4,5); 
                    815:        switch(sdBuf->command) {
                    816:            case SDOP_ABORT:
                    817:                /*
                    818:                 * Ah hah, we have to ioComplete all of the sdBufs in
                    819:                 * ioQueueDisk.
                    820:                 */
                    821:                {
                    822:                    sdBuf_t *abortBuf;
                    823:                    queue_head_t *q = &sdp->_ioQueueDisk;
                    824:                    
                    825:                    while(!queue_empty(q)) {
                    826:                            abortBuf = (sdBuf_t *)queue_first(q);
                    827:                            queue_remove(q, abortBuf, sdBuf_t *, link);
                    828:                            [sdp->_ioQLock unlock];
                    829:                            abortBuf->status = IO_R_NO_DISK;
                    830:                            if(abortBuf->scsiReq)
                    831:                                abortBuf->scsiReq->driverStatus = SR_IOST_VOLNA;
                    832:                            [sdp sdIoComplete:abortBuf];
                    833:                            [sdp->_ioQLock lock];
                    834:                    }
                    835:                    
                    836:                    /*
                    837:                     * and ioComplete the abort command itself.
                    838:                     */
                    839:                    sdBuf->status = IO_R_SUCCESS;
                    840:                    [sdp sdIoComplete:sdBuf];
                    841:                }
                    842:                break;
                    843:                
                    844:            case SDOP_PROBEDISK:
                    845:                /*
                    846:                 * If we got this far, the disk is present. ioComplete
                    847:                 * immediately. (If disk was not present, we would have
                    848:                 * disposed of this in case SDOP_ABORT.)
                    849:                 */
                    850:                sdBuf->status = IO_R_SUCCESS;
                    851:                [sdp sdIoComplete:sdBuf];
                    852:                break;
                    853:        
                    854:            case SDOP_EJECT:
                    855:                /*
                    856:                 * Wait until we're the only thread executing.
                    857:                 */
                    858:                [sdp->_ioQLock unlock];
                    859:                [sdp->_ejectLock lockWhen:1];
                    860:                [sdp->_ejectLock unlock];        
                    861:                [sdp doSdBuf:sdBuf];    
                    862:                [sdp->_ioQLock lock];
                    863:                break;
                    864:                
                    865:            case SDOP_READ:
                    866:            case SDOP_WRITE:
                    867:            case SDOP_CDB_READ:
                    868:            case SDOP_CDB_WRITE:
                    869:                /*
                    870:                 * We don't want to hold this lock while executing this
                    871:                 * command...
                    872:                 */
                    873:                [sdp->_ioQLock unlock];
                    874:                [sdp doSdBuf:sdBuf];
                    875:                [sdp->_ioQLock lock];
                    876:                break;
                    877:                
                    878:            case SDOP_ABORT_THREAD:
                    879:                /*
                    880:                 * I/O complete this before we die.
                    881:                 */
                    882:                [sdp->_ioQLock unlock];
                    883:                sdBuf->status = IO_R_SUCCESS;
                    884:                [sdp sdIoComplete:sdBuf];
                    885:                xpr_sd("%s: calling IOExitThread()\n", [sdp name],
                    886:                        2,3,4,5);
                    887:                IOExitThread();
                    888:                break;
                    889:        }
                    890:        
                    891:        if(needs_disk) {
                    892:                /*
                    893:                 * Enable possible waiting eject command.
                    894:                 */
                    895:                [sdp->_ejectLock lock];
                    896:                sdp->_numDiskIos--;
                    897:                [sdp->_ejectLock unlockWith:sdp->_numDiskIos];
                    898:        }
                    899: }      
                    900: 
                    901: @end
                    902: 
                    903: 

unix.superglobalmegacorp.com

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