Annotation of drvEIDE/EIDE.drvproj/EIDE.lksproj/IdeDiskInternal.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.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.