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

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: /*     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.