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

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