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

unix.superglobalmegacorp.com

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