Annotation of kernel/bsd/dev/ppc/drvATADisk/ATADiskInternal.m, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /*
        !            26:  * Copyright 1997-1998 by Apple Computer, Inc., All rights reserved.
        !            27:  * Copyright 1994-1997 NeXT Software, Inc., All rights reserved.
        !            28:  *
        !            29:  * ATADiskInternal.m - internal IDE/ATA disk methods. 
        !            30:  *
        !            31:  * HISTORY 
        !            32:  *
        !            33:  * 04-Mar-1996  Rakesh Dubey at NeXT
        !            34:  *     Modified so that no memory is allocated at run-time.
        !            35:  *
        !            36:  * 07-Jul-1994  Rakesh Dubey at NeXT
        !            37:  *     Created from original driver written by David Somayajulu.
        !            38:  */
        !            39:  
        !            40: #import <driverkit/return.h>
        !            41: #import <driverkit/driverTypes.h>
        !            42: #import "ATADiskInternal.h"
        !            43: #import "ATADiskKernel.h"
        !            44: #import <driverkit/kernelDiskMethods.h>
        !            45: #import <driverkit/generalFuncs.h>
        !            46: #import <machkit/NXLock.h>
        !            47: #import <driverkit/align.h>
        !            48: #import <sys/systm.h>
        !            49: 
        !            50: IOReturn iderToIo(ide_return_t);
        !            51: 
        !            52: //#define DEBUG
        !            53: 
        !            54: @implementation ATADisk(Internal)
        !            55: 
        !            56: /*
        !            57:  * Print information about the disk and fill up the ideDriveName field. 
        !            58:  */
        !            59: -(void)printInfo:(ideIdentifyInfo_t *)ideIdentifyInfo unit:(unsigned int)unit
        !            60: {
        !            61:     int i;
        !            62:     char name[50];
        !            63:     char firmware[9];
        !            64: 
        !            65:     /*
        !            66:      * Print drive name with firmware revision number after doing byte swaps. 
        !            67:      */
        !            68:     for (i = 0; i < 20; i++)   {
        !            69:        name[2*i] = ideIdentifyInfo->modelNumber[2*i+1];
        !            70:        name[2*i+1] = ideIdentifyInfo->modelNumber[2*i];
        !            71:     }
        !            72:     name[40] = '\0';
        !            73:     
        !            74:     for (i = 0; i < 4; i++)    {
        !            75:        firmware[2*i] = ideIdentifyInfo->firmwareRevision[2*i+1];
        !            76:        firmware[2*i+1] = ideIdentifyInfo->firmwareRevision[2*i];
        !            77:     }
        !            78:     firmware[8] = '\0';
        !            79: 
        !            80:     for (i = 38; i >= 0; i--)  {
        !            81:        if (name[i] != ' ')
        !            82:            break;
        !            83:     }
        !            84:     strcpy(name+i+2, firmware);
        !            85: 
        !            86: 
        !            87:     IOLog("%s: %s\n", [self name], name);
        !            88: 
        !            89:     /*
        !            90:      * The drive name is limited to 32 characters and we don't want firmware
        !            91:      * version in there. 
        !            92:      */
        !            93:     name[i+1] = '\0'; name[31] = '\0';
        !            94:     strcpy(_ideDriveName, name);
        !            95:        
        !            96:     /*
        !            97:      * Other diagnostic information. All of this can also be obtained via
        !            98:      * /usr/etc/idemodes 
        !            99:      */
        !           100: #if 0
        !           101:     IOLog("%s: PIO timing cycle: %d ns (mode %d).\n", [self name],
        !           102:            ideIdentifyInfo->pioDataTransferCyleTimingMode &
        !           103:            IDE_PIO_TIMING_MODE_MASK, 
        !           104:            [_cntrlr getTransferModeFromCycleTime:ideIdentifyInfo
        !           105:                transferType:IDE_TRANSFER_PIO]);
        !           106: 
        !           107:     if (ideIdentifyInfo->capabilities & IDE_CAP_DMA_SUPPORTED) {
        !           108:         IOLog("%s: DMA timing cycle: %d ns (mode %d).\n", [self name],
        !           109:                ideIdentifyInfo->dmaDataTransferCyleTimingMode &
        !           110:                IDE_DMA_TIMING_MODE_MASK,
        !           111:                [_cntrlr getTransferModeFromCycleTime:ideIdentifyInfo
        !           112:                    transferType:IDE_TRANSFER_SW_DMA]);
        !           113:     }
        !           114:     if (ideIdentifyInfo->capabilities & IDE_CAP_LBA_SUPPORTED) {
        !           115:        IOLog("%s: LBA supported.\n", [self name]); 
        !           116:     }
        !           117:     if (ideIdentifyInfo->capabilities & IDE_CAP_IORDY_SUPPORTED)       {
        !           118:        IOLog("%s: IORDY supported.\n", [self name]); 
        !           119:     }
        !           120: 
        !           121:     if (ideIdentifyInfo->bufferType != 0)      {
        !           122:        IOLog("%s: buffer type %d of %d sectors.\n", [self name],
        !           123:                ideIdentifyInfo->bufferType, ideIdentifyInfo->bufferSize);
        !           124:     }
        !           125: #endif 
        !           126: }
        !           127: 
        !           128: /*
        !           129:  * Device-specific initialization. We just do enough here to do some I/O and
        !           130:  * to find out if the requested drive is present. This function is "reusable"
        !           131:  * for a given instance of ATADisk; initResources must have been called
        !           132:  * exactly once prior to any use of this method. Returns YES if drive is
        !           133:  * present, else NO. 
        !           134:  */
        !           135: - (BOOL)ideDiskInit:(unsigned int)diskUnit target:(unsigned int)unit
        !           136: {
        !           137:     char dev_name[10];
        !           138:     unsigned total_sectors;
        !           139:     ideIdentifyInfo_t *ideIdentifyInfo;
        !           140: #ifdef NO_ATA_RUNTIME_MEMORY_ALLOCATION
        !           141:     int i;
        !           142:     ideBuf_t *ideBuf;
        !           143: #endif NO_ATA_RUNTIME_MEMORY_ALLOCATION
        !           144: 
        !           145: 
        !           146:     queue_init(&_ioQueueDisk);
        !           147:     queue_init(&_ioQueueNodisk);
        !           148: 
        !           149: 
        !           150: #ifdef NO_ATA_RUNTIME_MEMORY_ALLOCATION
        !           151: 
        !           152:     /* Set up a queue of ideBufs */
        !           153:     queue_init(&_ideBufQueue);
        !           154:     _ideBufLock = [NXLock new];
        !           155:     [_ideBufLock lock];
        !           156: 
        !           157:    
        !           158:     for (i = 0; i < MAX_NUM_ATABUF; i++)       {
        !           159:        ideBuf = &_ideBufPool[i];
        !           160:        ideBuf->waitLock = [NXConditionLock alloc];
        !           161:        [ideBuf->waitLock initWith:NO];
        !           162:        queue_enter(&_ideBufQueue, ideBuf, ideBuf_t *, bufLink);
        !           163:     }
        !           164:     [_ideBufLock unlock];
        !           165: 
        !           166: #if 0  // XXX
        !           167:     if (_ide_debug)    {
        !           168:        IOLog("NO_ATA_RUNTIME_MEMORY_ALLOCATION\n");
        !           169:     }
        !           170: #endif
        !           171: 
        !           172: #endif NO_ATA_RUNTIME_MEMORY_ALLOCATION
        !           173: 
        !           174:     _driveNum = unit;
        !           175: 
        !           176:     /* Skip ATAPI devices. */
        !           177:     if ([_cntrlr isAtapiDevice:unit] == YES)   {
        !           178:        return NO;
        !           179:     }
        !           180: 
        !           181:     _ideInfo = *[_cntrlr getIdeDriveInfo:unit];
        !           182:     if (_ideInfo.type == 0)    {
        !           183:     //IOLog("ATADisk: Bogus info for disk %d target %d.\n", diskUnit, unit);
        !           184:        return NO;
        !           185:     }
        !           186: 
        !           187:     sprintf(dev_name, "hd%d", diskUnit);
        !           188:     [self setUnit:diskUnit];
        !           189:     [self setName:dev_name];
        !           190: 
        !           191:     ideIdentifyInfo = [_cntrlr getIdeIdentifyInfo:unit];
        !           192:     [self printInfo:ideIdentifyInfo unit:unit];
        !           193: 
        !           194:     /* 
        !           195:      * Cache optimal data transfer command.
        !           196:      */
        !           197: 
        !           198:     if ([_cntrlr getMultiSectorValue:unit] > 0) 
        !           199:     {
        !           200:         _ideReadCommandPIO  = IDE_READ_MULTIPLE;
        !           201:         _ideWriteCommandPIO = IDE_WRITE_MULTIPLE;
        !           202:     } 
        !           203:     else 
        !           204:     {
        !           205:        _ideReadCommandPIO = IDE_READ;
        !           206:        _ideWriteCommandPIO = IDE_WRITE;
        !           207:     }
        !           208: 
        !           209:     if ( [_cntrlr isDmaSupported:unit] )
        !           210:     {
        !           211:        IOLog("%s: using DMA transfers.\n", [self name]);
        !           212:         _ideReadCommand  = IDE_READ_DMA;
        !           213:         _ideWriteCommand = IDE_WRITE_DMA;
        !           214:     }
        !           215:     else
        !           216:     {
        !           217:        IOLog("%s: using PIO transfers.\n", [self name]);
        !           218:         _ideReadCommand  = _ideReadCommandPIO;
        !           219:         _ideWriteCommand = _ideWriteCommandPIO;
        !           220:     }
        !           221: 
        !           222:     _ideControllerType = [_cntrlr getControllerType];
        !           223: 
        !           224:     if ([self initIdeDrive] != IO_R_SUCCESS) {
        !           225:                return NO;
        !           226:     }
        !           227: 
        !           228:     total_sectors = _ideInfo.total_sectors;
        !           229: 
        !           230:     [self setRemovable:NO];
        !           231:     [self setBlockSize:_ideInfo.bytes_per_sector];
        !           232:     [self setDiskSize:total_sectors];
        !           233:     [self setFormattedInternal:YES];
        !           234:     [self setLastReadyState: IO_Ready];
        !           235: 
        !           236:     if (_ideDriveName[0] == '\0')      {
        !           237:                sprintf(_ideDriveName, "IDE Drive Type %d", _ideInfo.type);
        !           238:     }
        !           239:     [self setDriveName:_ideDriveName];
        !           240: 
        !           241:     [super init];
        !           242: 
        !           243:     return YES;
        !           244: }
        !           245: 
        !           246: /*
        !           247:  * One-time only initialization. We have only one thread per disk since ATA
        !           248:  * disks do not support command queueing. 
        !           249:  */
        !           250: #ifdef DEBUG
        !           251: void *ideThreadPtr;
        !           252: #endif DEBUG
        !           253: 
        !           254: - initResources        : controller
        !           255: {
        !           256:     _cntrlr = controller;
        !           257:     _ioQLock = [NXConditionLock alloc];
        !           258:     [_ioQLock initWith:NO_WORK_AVAILABLE];
        !           259: #ifdef DEBUG
        !           260:     ideThreadPtr = IOForkThread((IOThreadFunc)ideThread, self);
        !           261: #else  DEBUG
        !           262:     IOForkThread((IOThreadFunc)ideThread, self);
        !           263: #endif DEBUG
        !           264:     return self;
        !           265: }
        !           266: 
        !           267: /*
        !           268:  * Free up local resources. 
        !           269:  */
        !           270: - free
        !           271: {
        !           272:     /*
        !           273:      * First kill the I/O thread, then free alloc'd instance variables. 
        !           274:      */
        !           275:     ideBuf_t *ideBuf;
        !           276:     int i;
        !           277: 
        !           278:     ideBuf = [self allocIdeBuf:NULL];
        !           279:     ideBuf->command = IDEC_THREAD_ABORT;
        !           280:     ideBuf->buf = NULL;
        !           281:     ideBuf->needsDisk = 0;
        !           282:     ideBuf->oneWay = 0;
        !           283:     [self enqueueIdeBuf:ideBuf];
        !           284:     
        !           285:     [self freeIdeBuf:ideBuf];
        !           286:     [_ioQLock free];
        !           287:     
        !           288: #ifdef NO_ATA_RUNTIME_MEMORY_ALLOCATION
        !           289:     if (_ideBufLock)
        !           290:        [_ideBufLock free];
        !           291:     
        !           292:     for (i = 0; i < MAX_NUM_ATABUF; i++) {
        !           293:        if (_ideBufPool[i].waitLock)
        !           294:            [_ideBufPool[i].waitLock free];
        !           295:     }
        !           296: #endif NO_ATA_RUNTIME_MEMORY_ALLOCATION
        !           297: 
        !           298:     return ([super free]);
        !           299: }
        !           300: 
        !           301: /*
        !           302:  * Allocate and free IdeBuf_t's.
        !           303:  */
        !           304: 
        !           305: #ifdef NO_ATA_RUNTIME_MEMORY_ALLOCATION
        !           306: - (ideBuf_t *) allocIdeBuf:(void *)pending
        !           307: {
        !           308:     ideBuf_t *ideBuf;
        !           309:     id waitLock;
        !           310: 
        !           311:     while (1)  {
        !           312:        [_ideBufLock lock];
        !           313:        if (!queue_empty(&_ideBufQueue))
        !           314:            break;
        !           315:        [_ideBufLock unlock];
        !           316:        IOSleep(10);            // the system is overloaded
        !           317:     }
        !           318:     
        !           319:     ASSERT(queue_empty(&_ideBufQueue) != 0);
        !           320:     ideBuf = (ideBuf_t *) queue_first(&_ideBufQueue);
        !           321:     ASSERT(ideBuf != 0);
        !           322:     queue_remove(&_ideBufQueue, ideBuf, ideBuf_t *, bufLink);
        !           323: 
        !           324:     waitLock = ideBuf->waitLock;
        !           325:     bzero(ideBuf, sizeof(ideBuf_t));
        !           326:     ideBuf->waitLock = waitLock;
        !           327:     [ideBuf->waitLock initWith:NO];
        !           328:     
        !           329:     if (pending != NULL)
        !           330:        ideBuf->pending = pending;
        !           331:        
        !           332:     [_ideBufLock unlock];
        !           333:     return (ideBuf);
        !           334: }
        !           335: 
        !           336: - (void)freeIdeBuf:(ideBuf_t *) ideBuf
        !           337: {
        !           338:     [_ideBufLock lock];
        !           339:     queue_enter(&_ideBufQueue, ideBuf, ideBuf_t *, bufLink);
        !           340:     ASSERT(queue_empty(&_ideBufQueue) != 0);
        !           341:     [_ideBufLock unlock];
        !           342: }
        !           343: 
        !           344: #else NO_ATA_RUNTIME_MEMORY_ALLOCATION
        !           345: 
        !           346: - (ideBuf_t *) allocIdeBuf:(void *)pending
        !           347: {
        !           348:     ideBuf_t *ideBuf = IOMalloc(sizeof(ideBuf_t));
        !           349: 
        !           350:     bzero(ideBuf, sizeof(ideBuf_t));
        !           351:     if (pending == NULL) {
        !           352:        ideBuf->waitLock = [NXConditionLock alloc];
        !           353:        [ideBuf->waitLock initWith:NO];
        !           354:     } else
        !           355:        ideBuf->pending = pending;
        !           356:     return (ideBuf);
        !           357: }
        !           358: 
        !           359: - (void)freeIdeBuf:(ideBuf_t *) ideBuf
        !           360: {
        !           361:     if (ideBuf->waitLock) {
        !           362:        [ideBuf->waitLock free];
        !           363:     }
        !           364:     IOFree(ideBuf, sizeof(ideBuf_t));
        !           365: }
        !           366: #endif NO_ATA_RUNTIME_MEMORY_ALLOCATION
        !           367: 
        !           368: - (IOReturn) ideXfrIoReq:(ideIoReq_t *)ideIoReq
        !           369: {
        !           370:     ideBuf_t *ideBuf;
        !           371:     IOReturn rtn;
        !           372: 
        !           373:     ideBuf = [self allocIdeBuf:NULL];
        !           374:     ideBuf->command = IDEC_IOREQ;
        !           375:     ideBuf->ideIoReq = ideIoReq;
        !           376:     ideBuf->block = 0;
        !           377:     ideBuf->blockCnt = 0;
        !           378:     ideBuf->buf = 0;
        !           379:     ideBuf->client = 0;        /* it picked up from ideIoReq   */
        !           380:     ideBuf->needsDisk = 1;
        !           381:     ideBuf->bytesXfr = 0;
        !           382:     ideBuf->oneWay = 0;
        !           383:     rtn = [self enqueueIdeBuf:ideBuf];
        !           384:     [self freeIdeBuf:ideBuf];
        !           385: 
        !           386:     return (rtn);
        !           387: }
        !           388: 
        !           389: - (IOReturn) initIdeDrive
        !           390: {
        !           391:     IOReturn rtn;
        !           392:     ideBuf_t *ideBuf;
        !           393: 
        !           394:     ideBuf = [self allocIdeBuf:NULL];
        !           395:     ideBuf->command = IDEC_INIT;
        !           396:     ideBuf->block = 0;
        !           397:     ideBuf->blockCnt = 0;
        !           398:     ideBuf->buf = 0;
        !           399:     ideBuf->client = 0;
        !           400:     ideBuf->needsDisk = 1;
        !           401:     ideBuf->bytesXfr = 0;
        !           402:     ideBuf->oneWay = 0;
        !           403:     rtn  = [self enqueueIdeBuf:ideBuf];
        !           404:     [self freeIdeBuf:ideBuf];
        !           405: 
        !           406:     return(rtn);
        !           407: }
        !           408: 
        !           409: /*
        !           410:  * Common read/write routine.
        !           411:  */
        !           412: - (IOReturn) deviceRwCommon:(IdeCmd_t) command
        !           413:                    block:(u_int) deviceBlock
        !           414:                    length:(u_int) length
        !           415:                    buffer:(void *)buffer
        !           416:                    client:(vm_task_t) client
        !           417:                    pending:(void *)pending
        !           418:                    actualLength:(u_int *) actualLength
        !           419: {
        !           420:     ideBuf_t *ideBuf;
        !           421:     IOReturn rtn;
        !           422:     u_int   blocksReq;
        !           423:     u_int   block_size;
        !           424:     u_int   dev_size;
        !           425: 
        !           426:     rtn = [self isDiskReady:NO];
        !           427: 
        !           428:     switch (rtn) {
        !           429:                case IO_R_SUCCESS:
        !           430:                        break;
        !           431:                case IO_R_NO_DISK:
        !           432:                        return (rtn);
        !           433:                default:
        !           434:                        IOLog("%s deviceRwCommon: bogus return from isDiskReady (%s)\n",
        !           435:                                [self name], [self stringFromReturn:rtn]);
        !           436:                        return (rtn);
        !           437:     }
        !           438: 
        !           439:     block_size = [self blockSize];
        !           440:     dev_size = [self diskSize];
        !           441: 
        !           442:     if (length % block_size) {
        !           443:                return (IO_R_INVALID);
        !           444:     }
        !           445:     blocksReq = length / block_size;
        !           446:     if ((deviceBlock + blocksReq) > dev_size) {
        !           447:                if (deviceBlock >= dev_size) {
        !           448:                        return (IO_R_INVALID_ARG);
        !           449:                }
        !           450:                blocksReq = dev_size - deviceBlock;
        !           451:     }
        !           452:     ideBuf = [self allocIdeBuf:pending];
        !           453:     ideBuf->command = command;
        !           454:     ideBuf->block = deviceBlock;
        !           455:     ideBuf->blockCnt = blocksReq;
        !           456:     ideBuf->buf = buffer;
        !           457:     ideBuf->client = client;
        !           458:     ideBuf->needsDisk = 1;
        !           459:     ideBuf->bytesXfr = 0;
        !           460:     ideBuf->oneWay = 0;
        !           461: 
        !           462:     rtn = [self enqueueIdeBuf:ideBuf];
        !           463: 
        !           464:     if (pending == NULL) {
        !           465:                /*
        !           466:                 * Sync I/O. 
        !           467:                 */
        !           468:                *actualLength = ideBuf->bytesXfr;
        !           469:                [self freeIdeBuf:ideBuf];
        !           470:     }
        !           471:     return (rtn);
        !           472: }
        !           473: 
        !           474: /*
        !           475:  * -- Enqueue an IdeBuf_t on ioQueue<Disk,Nodisk>
        !           476:  * -- wake up the I/O thread
        !           477:  * -- wait for I/O complete (if ideBuf->pending == NULL)
        !           478:  *
        !           479:  * All I/O goes thru here; this is the last method called by exported methods
        !           480:  * before the I/O thread takes over. 
        !           481:  */
        !           482: - (IOReturn) enqueueIdeBuf:(ideBuf_t *) ideBuf
        !           483: {
        !           484:     queue_head_t *q;
        !           485: 
        !           486:     ideBuf->status = IO_R_INVALID;
        !           487:     [_ioQLock lock];
        !           488:     if (ideBuf->needsDisk)
        !           489:        q = &_ioQueueDisk;
        !           490:     else
        !           491:        q = &_ioQueueNodisk;
        !           492:     queue_enter(q, ideBuf, ideBuf_t *, link);
        !           493:     [_ioQLock unlockWith:WORK_AVAILABLE];
        !           494: 
        !           495:     if (ideBuf->pending != NULL)
        !           496:        return (IO_R_SUCCESS);
        !           497: 
        !           498:     /*
        !           499:      * Wait for I/O complete if not an async command. 
        !           500:      */
        !           501: 
        !           502:     if (ideBuf->oneWay) {
        !           503:        return IO_R_SUCCESS;
        !           504:     }
        !           505:     [ideBuf->waitLock lockWhen:YES];
        !           506:     [ideBuf->waitLock unlock];
        !           507: 
        !           508:     return (ideBuf->status);
        !           509: }
        !           510: 
        !           511: 
        !           512: /*
        !           513:  * Either wake up the thread which is waiting on the ideCmdBuf, or send an 
        !           514:  * ioComplete back to client. ideCmdBuf->status must be valid.
        !           515:  */
        !           516: - (void)ideIoComplete:(ideBuf_t *) ideBuf
        !           517: {
        !           518:     if (ideBuf->pending) {
        !           519:        [self completeTransfer:ideBuf->pending
        !           520:                    withStatus:ideBuf->status
        !           521:                    actualLength:ideBuf->bytesXfr];
        !           522:        [self freeIdeBuf:ideBuf];
        !           523:     } else {
        !           524:        /*
        !           525:         * Sync I/O. Just wake up the waiting thread. 
        !           526:         */
        !           527:        [ideBuf->waitLock lock];
        !           528:        [ideBuf->waitLock unlockWith:YES];
        !           529:     }
        !           530: 
        !           531: }
        !           532: 
        !           533: /*
        !           534:  * Main command dispatch method. 
        !           535:  */
        !           536: - (void)ideCmdDispatch:(ideBuf_t *)ideBuf
        !           537: {
        !           538:     IOReturn rtn = IO_R_SUCCESS;
        !           539:     ideBuf_t *abortBuf;
        !           540: 
        !           541:     switch (ideBuf->command) {
        !           542:     
        !           543:       case IDEC_IOREQ:
        !           544:        [_cntrlr ideExecuteCmd:ideBuf->ideIoReq ToDrive:_driveNum];
        !           545: 
        !           546:        break;
        !           547: 
        !           548:       case IDEC_READ:
        !           549:       case IDEC_WRITE:
        !           550:        rtn = [self ideRwCommon:ideBuf];
        !           551: 
        !           552:        break;
        !           553: 
        !           554:       case IDEC_ABORT:
        !           555: 
        !           556:        /*
        !           557:         * Each I/O pending in the needsDisk queue must be aborted. 
        !           558:         */
        !           559:        [_ioQLock lock];
        !           560:        while (!queue_empty(&_ioQueueDisk)) {
        !           561:            abortBuf = (ideBuf_t *) queue_first(&_ioQueueDisk);
        !           562:            queue_remove(&_ioQueueDisk,
        !           563:                         abortBuf,
        !           564:                         ideBuf_t *,
        !           565:                         link);
        !           566:            [_ioQLock unlock];
        !           567:            abortBuf->status = IO_R_NO_DISK;
        !           568:            if (abortBuf->ideIoReq)
        !           569:                abortBuf->ideIoReq->status = IDER_VOLUNAVAIL;
        !           570:            [self ideIoComplete:abortBuf];
        !           571:            [_ioQLock lock];
        !           572:        }
        !           573:        [_ioQLock unlock];
        !           574: 
        !           575:        break;
        !           576: 
        !           577:       case IDEC_THREAD_ABORT:
        !           578: 
        !           579:        /*
        !           580:         * First give I/O complete before we die. 
        !           581:         */
        !           582:        ideBuf->status = IO_R_SUCCESS;
        !           583:        [self ideIoComplete:ideBuf];
        !           584:        IOExitThread();
        !           585: 
        !           586:       case IDEC_INIT:
        !           587: #if 0
        !           588:        /* Called once during initialization.   */
        !           589:        if ([_cntrlr initIdeDriveLowLevel] == IDER_SUCCESS)
        !           590:            rtn = IO_R_SUCCESS;
        !           591:        else
        !           592:            rtn = IO_R_IO;
        !           593: #endif 0
        !           594:         rtn = IO_R_SUCCESS;
        !           595:        break;
        !           596: 
        !           597:       default:
        !           598:        IOLog("%s: Bogus ideBuf->command 0x%0x in ideCmdDispatch\n", 
        !           599:                [self name], ideBuf->command);
        !           600:        IOPanic("ideThread");
        !           601:     }
        !           602: 
        !           603:     /*
        !           604:      * I/O complete the command if appropriate. 
        !           605:      */
        !           606:     if (ideBuf->oneWay) {
        !           607: 
        !           608:        [self freeIdeBuf:ideBuf];
        !           609: 
        !           610:        return;
        !           611:     }
        !           612:     ideBuf->status = rtn;
        !           613: 
        !           614:     [self ideIoComplete:ideBuf];
        !           615:     return;
        !           616: }
        !           617: 
        !           618: /*
        !           619:  * Common r/w routine. The following ideBuf fields are required:
        !           620:  *     block
        !           621:  *     blockCnt
        !           622:  *     buf
        !           623:  *     client
        !           624:  *     pending
        !           625:  *
        !           626:  * block and blockCnt are assumed to be already adjusted for overflow.
        !           627:  */
        !           628: 
        !           629: - (IOReturn) ideRwCommon:(ideBuf_t *)ideBuf
        !           630: {
        !           631:     int     currentBlock = ideBuf->block;      /* start block, current
        !           632:                                                 * segment */
        !           633:     int        currentBlockCnt;        /* block count, current segment */
        !           634:     int        blocksToGo = ideBuf->blockCnt;
        !           635:     unsigned    ioCommand;
        !           636:     char       *currentBuf = ideBuf->buf;
        !           637:     ideIoReq_t ideIoReq;
        !           638:     IOReturn   rtn;
        !           639:     unsigned   int block_size = _ideInfo.bytes_per_sector;
        !           640:     BOOL       readFlag = (ideBuf->command == IDEC_READ) ? YES : NO;
        !           641:     int        blocksMoved;
        !           642:     ns_time_t  start_time;
        !           643: 
        !           644: 
        !           645:     IOGetTimestamp(&start_time);
        !           646: 
        !           647:     if ( (_ideControllerType == kControllerTypeCmd646X) && ((u_int)currentBuf & 1) )
        !           648:     {   
        !           649:        ioCommand = readFlag ? _ideReadCommandPIO : _ideWriteCommandPIO;
        !           650:     }
        !           651:     else
        !           652:     {
        !           653:        ioCommand = readFlag ? _ideReadCommand : _ideWriteCommand;
        !           654:     }
        !           655: 
        !           656:     while (blocksToGo) {
        !           657: 
        !           658:        /*
        !           659:         * Set up controller command block for current segment. 
        !           660:         */
        !           661:        currentBlockCnt = ((blocksToGo > MAX_BLOCKS_PER_XFER) ?
        !           662:                           MAX_BLOCKS_PER_XFER : blocksToGo);
        !           663: 
        !           664:         ideIoReq.cmd    = ioCommand;
        !           665:        ideIoReq.addr   = currentBuf;
        !           666:        ideIoReq.blkcnt = currentBlockCnt;
        !           667:        ideIoReq.block  = currentBlock;
        !           668: 
        !           669:        /*
        !           670:         * Note we're compiling MACH_USER_API, hence the cast... 
        !           671:         */
        !           672:        ideIoReq.map = (struct vm_map *) ideBuf->client;
        !           673: 
        !           674:        rtn = [_cntrlr ideExecuteCmd:&ideIoReq ToDrive:_driveNum];
        !           675: 
        !           676:        blocksMoved = ideIoReq.blocks_xfered;
        !           677:        blocksToGo -= blocksMoved;
        !           678:        currentBlock += blocksMoved;
        !           679:        currentBuf += ideIoReq.blocks_xfered * block_size;
        !           680: 
        !           681:        /*
        !           682:         * Handle errors. 
        !           683:         */
        !           684: 
        !           685:        if (rtn) {
        !           686:            /*
        !           687:             * This is a colossal error, which should never happen... 
        !           688:             */
        !           689:            ideIoReq.status = IDER_REJECT;
        !           690:        }
        !           691:        switch (ideIoReq.status) {
        !           692:          case IDER_SUCCESS:
        !           693:            break;
        !           694:          case IDER_TIMEOUT:
        !           695:          case IDER_MEMALLOC:
        !           696:          case IDER_MEMFAIL:
        !           697:          case IDER_REJECT:
        !           698:          case IDER_BADDRV:
        !           699:          case IDER_CMD_ERROR:
        !           700:          case IDER_VOLUNAVAIL:
        !           701:          case IDER_SPURIOUS:
        !           702:            goto done;
        !           703:            break;
        !           704:          default:
        !           705: 
        !           706:            /*
        !           707:             * Non-retriable errors. 
        !           708:             */
        !           709:            [self logRwErr:"FATAL" block:currentBlock status:ideIoReq.status
        !           710:                    readFlag:readFlag];
        !           711:            goto done;
        !           712:            break;
        !           713: 
        !           714:        } /* switch status */
        !           715:     } /* while blocksToGo */
        !           716: done:
        !           717: 
        !           718:     /*
        !           719:      * Finished. Update client's status and log statistics. 
        !           720:      */
        !           721:     ideBuf->bytesXfr = (ideBuf->blockCnt - blocksToGo) * block_size;
        !           722:     rtn = ideBuf->status = iderToIo(ideIoReq.status);
        !           723:     if (ideIoReq.status != IO_R_SUCCESS) {
        !           724: 
        !           725:        if (readFlag) {
        !           726:            [self incrementReadErrors];
        !           727:        } else {
        !           728:            [self incrementWriteErrors];
        !           729:        }
        !           730: 
        !           731:     } else {
        !           732:        ns_time_t end_time;
        !           733: 
        !           734:        /* no "latency" measurement...  */
        !           735:        ns_time_t delta;
        !           736: 
        !           737:        IOGetTimestamp(&end_time);
        !           738:        delta = end_time - start_time;
        !           739:        if (readFlag) {
        !           740: 
        !           741:            [self addToBytesRead:ideBuf->bytesXfr
        !           742:                    totalTime:delta
        !           743:                    latentTime:0];
        !           744:        } else {
        !           745:            [self addToBytesWritten:ideBuf->bytesXfr
        !           746:                    totalTime:delta
        !           747:                    latentTime:0];
        !           748:        }
        !           749:     }
        !           750: 
        !           751:     return (rtn);
        !           752: }
        !           753: 
        !           754: - (void)logRwErr : (const char *)errType       // e.g., "RECALIBRATING"
        !           755:                   block : (int)block
        !           756:                   status : (ide_return_t)status
        !           757:                   readFlag : (BOOL)readFlag
        !           758: {
        !           759: 
        !           760:     IOLog("%s: Sector %d cmd = %s; %s: %s\n",
        !           761:            [self name], block, readFlag ? "Read" : "Write",
        !           762:            IOFindNameForValue(status, iderValues), errType);
        !           763: 
        !           764: }
        !           765: 
        !           766: /*
        !           767:  * Unlock ioQLock, updating condition variable as appropriate.
        !           768:  */
        !           769: - (void)unlockIoQLock
        !           770: {
        !           771:     int     queue_state;
        !           772:     IODiskReadyState lastReady = [self lastReadyState];
        !           773: 
        !           774:     /*
        !           775:      * There's still work to do when: 
        !           776:      * -- ioQueueNodisk non-empty, or 
        !           777:      * -- ioQueueDisk non-empty and we have a disk. 
        !           778:      */
        !           779: 
        !           780:     if ((!queue_empty(&_ioQueueNodisk)) ||
        !           781:        ((!queue_empty(&_ioQueueDisk)) && (lastReady != IO_NoDisk))) {
        !           782:        queue_state = WORK_AVAILABLE;
        !           783:     } else
        !           784:        queue_state = NO_WORK_AVAILABLE;
        !           785:     [_ioQLock unlockWith:queue_state];
        !           786: }
        !           787: 
        !           788: 
        !           789: /*
        !           790:  * I/O thread. Each one of these sits around waiting for work to do on 
        !           791:  * ioQueue; when something appears, the thread grabs it and disptahes it.
        !           792:  */
        !           793:  
        !           794: volatile void ideThread(ATADisk *idisk)
        !           795: {
        !           796:     ideBuf_t *ideBuf;
        !           797:     queue_head_t *q;
        !           798: 
        !           799:     while (1) {
        !           800: 
        !           801:        /*
        !           802:         * Wait for some work to do. 
        !           803:         */
        !           804:        [idisk->_ioQLock lockWhen:WORK_AVAILABLE];
        !           805: 
        !           806:        /*
        !           807:         * Service all requests which do not require a disk. 
        !           808:         */
        !           809:        q = &idisk->_ioQueueNodisk;
        !           810:        while (!queue_empty(q)) {
        !           811:            ideBuf = (ideBuf_t *) queue_first(q);
        !           812:            queue_remove(q, ideBuf, ideBuf_t *, link);
        !           813:            [idisk->_ioQLock unlock];
        !           814:            ASSERT(ideBuf->needsDisk == 0);
        !           815:            [idisk ideCmdDispatch:ideBuf];
        !           816:            [idisk->_ioQLock lock];
        !           817:        }
        !           818: 
        !           819:        /*
        !           820:         * Now service all requests which require a disk, as long as we have
        !           821:         * one. 
        !           822:         */
        !           823: 
        !           824:        q = &idisk->_ioQueueDisk;
        !           825:        ASSERT([idisk lastReadyState] == IO_Ready);
        !           826:        while ((!queue_empty(q)) &&
        !           827:               ([idisk lastReadyState] == IO_Ready)) {
        !           828:            ideBuf = (ideBuf_t *) queue_first(q);
        !           829:            queue_remove(q, ideBuf, ideBuf_t *, link);
        !           830:            [idisk->_ioQLock unlock];
        !           831:            ASSERT(ideBuf->needsDisk == 1);
        !           832:            [idisk ideCmdDispatch:ideBuf];
        !           833:            [idisk->_ioQLock lock];
        !           834:        }
        !           835: 
        !           836:        [idisk unlockIoQLock];
        !           837:     }
        !           838: 
        !           839:     /* NOT REACHED */
        !           840: }
        !           841: 
        !           842: IOReturn iderToIo(ide_return_t ider)
        !           843: {
        !           844:     switch  (ider) {
        !           845:                case IDER_SUCCESS:
        !           846:                        return (IO_R_SUCCESS);
        !           847:                case IDER_TIMEOUT:
        !           848:                case IDER_CNTRL_REJECT:
        !           849:                case IDER_CMD_ERROR:
        !           850:                case IDER_SPURIOUS:
        !           851:                        return (IO_R_IO);
        !           852:                case IDER_MEMALLOC:
        !           853:                        return (IO_R_NO_MEMORY);
        !           854:                case IDER_MEMFAIL:
        !           855:                        return (IO_R_VM_FAILURE);
        !           856:                case IDER_REJECT:
        !           857:                        return (IO_R_UNSUPPORTED);
        !           858:                case IDER_BADDRV:
        !           859:                        return (IO_R_NO_DEVICE);
        !           860:                case IDER_VOLUNAVAIL:
        !           861:                        return (IO_R_NO_DISK);
        !           862:                default:
        !           863:                        return (IO_R_INTERNAL);
        !           864:     }
        !           865: }
        !           866: 
        !           867: @end
        !           868: 

unix.superglobalmegacorp.com

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