Annotation of kernel/bsd/dev/ppc/drvPPCATA/IdeCntDma.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: // Copyright 1997 by Apple Computer, Inc., all rights reserved.
                     26: /*     Copyright (c) 1991-1997 NeXT Software, Inc.  All rights reserved. 
                     27:  *
                     28:  * IdeCntDma.m - Implementation for Dma category of Ide Controller device.
                     29:  *
                     30:  */
                     31: 
                     32: #import <driverkit/generalFuncs.h>
                     33: #import <driverkit/kernelDriver.h>
                     34: #import <driverkit/ppc/IODBDMA.h>
                     35: #import <driverkit/align.h>
                     36: #import <machdep/ppc/powermac.h>
                     37: #import <sys/systm.h>
                     38: 
                     39: #import "IdeCntDma.h"
                     40: #import "io_inline.h"
                     41: 
                     42: extern         IOReturn                kmem_alloc_wired();
                     43: 
                     44: static         void                    *bitBucketAddr;
                     45: static         uint                    bitBucketPhysAddr;              
                     46: 
                     47: @implementation IdeController(Dma)
                     48: 
                     49: /*
                     50:  * Called once during initialization to figure out if the hardware 
                     51:  * supports dma
                     52:  */
                     53: 
                     54: - (ide_return_t) initIdeDma:(unsigned int)unit 
                     55: {
                     56:     ideIoReq_t                 ideIoReq;
                     57:     vm_offset_t                tempDmaBuf;
                     58:     ide_return_t               status;
                     59: 
                     60:     /*
                     61:      * The hardware claims to supports DMA. Verify that by trying to read a
                     62:      * few sectors. 
                     63:      */
                     64:     tempDmaBuf = (vm_offset_t)IOMalloc(PAGE_SIZE);
                     65:     if (tempDmaBuf == NULL)    
                     66:     {
                     67:        _dmaSupported[unit] = NO;
                     68:        return IDER_REJECT;
                     69:     }
                     70:     
                     71:     bzero((unsigned char *)&ideIoReq, sizeof(ideIoReq_t));
                     72:     ideIoReq.cmd = IDE_READ_DMA;
                     73:     ideIoReq.block = 0;
                     74:     ideIoReq.blkcnt = (PAGE_SIZE/IDE_SECTOR_SIZE);
                     75:     ideIoReq.addr = (caddr_t)tempDmaBuf;
                     76:     ideIoReq.timeout = 5000;
                     77:     ideIoReq.map = (struct vm_map *)IOVmTaskSelf();
                     78:     
                     79:     [self setTransferRate: unit UseDMA: YES];
                     80: 
                     81:     if ([self ideDmaRwCommon:(ideIoReq_t *)&ideIoReq] == IDER_SUCCESS)
                     82:     {
                     83:        status = IDER_SUCCESS;
                     84:     } 
                     85:     else 
                     86:     {
                     87:        _dmaSupported[unit] = NO;
                     88:        status = IDER_REJECT;
                     89:     }
                     90:     
                     91:     IOFree((void *)tempDmaBuf, PAGE_SIZE);
                     92:     
                     93:     return status;
                     94: }
                     95: 
                     96: - (ide_return_t) allocDmaMemory
                     97: {
                     98:     IOReturn   rc;
                     99: 
                    100:     if ( !_ideDMACommands )
                    101:     {
                    102:         rc = kmem_alloc_wired(IOVmTaskSelf(), (vm_offset_t *) &_ideDMACommands, PAGE_SIZE );
                    103: 
                    104:         if ( rc != KERN_SUCCESS  )
                    105:        {
                    106:           return IDER_REJECT;
                    107:         }
                    108:        rc = IOPhysicalFromVirtual( IOVmTaskSelf(), (vm_offset_t)_ideDMACommands, (vm_offset_t *)&_ideDMACommandsPhys );
                    109:         if ( rc != IO_R_SUCCESS )
                    110:        {
                    111:             return IDER_REJECT;
                    112:         }
                    113:     }   
                    114:     
                    115:     if ( !bitBucketAddr )
                    116:     {
                    117:         bitBucketAddr = IOMalloc(32);
                    118:         bitBucketAddr = IOAlign(void *, bitBucketAddr, 16);
                    119:         rc = IOPhysicalFromVirtual( IOVmTaskSelf(), (vm_offset_t) bitBucketAddr, (vm_offset_t *)&bitBucketPhysAddr );
                    120:         if ( rc != IO_R_SUCCESS )
                    121:        {
                    122:             return IDER_REJECT;
                    123:         }
                    124:     }
                    125: 
                    126:     return IDER_SUCCESS;
                    127: }
                    128: 
                    129: 
                    130: - (ide_return_t) ideDmaRwCommon: (ideIoReq_t *)ideIoReq
                    131: {
                    132:     vm_offset_t                startAddr = (vm_offset_t)ideIoReq->addr;
                    133:     unsigned                   blocksToGo = ideIoReq->blkcnt;
                    134:     unsigned                   startBlock = ideIoReq->block;
                    135:     ide_return_t               rc = IDER_SUCCESS;
                    136:     BOOL                       fRead = (ideIoReq->cmd == IDE_READ_DMA);
                    137: 
                    138:     /*
                    139:      * Do read or write DMA. 
                    140:      */
                    141:     ideIoReq->regValues = [self logToPhys:startBlock numOfBlocks:blocksToGo];
                    142: 
                    143:     rc = [self setupDMA: startAddr client:(vm_task_t)ideIoReq->map length:blocksToGo * IDE_SECTOR_SIZE fRead:(BOOL)fRead];
                    144:     if ( rc != IDER_SUCCESS )
                    145:     {
                    146:         return ( rc );
                    147:     }  
                    148: 
                    149:     rc = [self ideReadWriteDma: &ideIoReq->regValues fRead:fRead]; 
                    150: 
                    151:     return(rc);        
                    152: }
                    153: 
                    154: - (ide_return_t) ideReadWriteDma:(ideRegsVal_t *)ideRegs fRead:(BOOL)read
                    155: {
                    156:     ide_return_t               rtn;
                    157:     ideRegsAddrs_t             *rp = &_ideRegsAddrs;
                    158:     unsigned char              status;
                    159:     unsigned long              cfgReg;
                    160: 
                    161:     rtn = [self waitForDeviceReady];
                    162:     if (rtn != IDER_SUCCESS) 
                    163:     {
                    164:        return (rtn);
                    165:     }
                    166: 
                    167:     outb(rp->drHead,  ideRegs->drHead);
                    168:     outb(rp->sectNum, ideRegs->sectNum);
                    169:     outb(rp->sectCnt, ideRegs->sectCnt);
                    170:     outb(rp->cylLow,  ideRegs->cylLow);
                    171:     outb(rp->cylHigh, ideRegs->cylHigh);
                    172:     
                    173:     [self enableInterrupts];
                    174:     outb(rp->command, (read ? IDE_READ_DMA : IDE_WRITE_DMA));
                    175: 
                    176:     if ( _controllerType != kControllerTypeCmd646X )
                    177:     {
                    178:         IODBDMAContinue( _ideDMARegs );        
                    179:     }
                    180:     else
                    181:     {
                    182:         [[self deviceDescription] configReadLong:0x70 value: &cfgReg];
                    183:         cfgReg &= ~0x08;
                    184:         cfgReg |= 0x01 | ((read) ? 0x08 : 0x00);
                    185:         [[self deviceDescription] configWriteLong:0x70 value: cfgReg];
                    186:     }
                    187: 
                    188:     rtn = [self ideWaitForInterrupt:(read ? IDE_READ_DMA : IDE_WRITE_DMA)
                    189:                        ideStatus: &status];
                    190: 
                    191: #if 0
                    192:   {
                    193:     uint       dmaStatus;
                    194: 
                    195:     dmaStatus = IOGetDBDMAChannelStatus( _ideDMARegs );
                    196:     kprintf( "DMA Status = %04x IDE Status = %02x\n\r", dmaStatus, status );
                    197:   }
                    198: #endif
                    199: 
                    200:     if ( _controllerType != kControllerTypeCmd646X )
                    201:     {
                    202:         IODBDMAStop( _ideDMARegs );
                    203:     }
                    204:     else
                    205:     {
                    206:         [[self deviceDescription] configReadLong: 0x70 value: &cfgReg];
                    207:         cfgReg &= ~0x01;
                    208:         [[self deviceDescription] configWriteLong:0x70 value: cfgReg];
                    209:     }
                    210:         
                    211:     if ( (rtn == IDER_SUCCESS) ) 
                    212:     {
                    213:        if ((rtn = [self waitForDeviceReady]) == IDER_SUCCESS) 
                    214:         {
                    215:            if (status & (ERROR | WRITE_FAULT)) 
                    216:             {
                    217:                [self getIdeRegisters:ideRegs Print:"Read Dma error"];
                    218:                return IDER_CMD_ERROR;
                    219:            }
                    220:            
                    221:            /*
                    222:            if (status & ERROR_CORRECTED) {
                    223:                IOLog("%s: Error during data transfer (corrected).\n", 
                    224:                            [self name]);
                    225:            }
                    226:            */
                    227:        } 
                    228:         else 
                    229:         {
                    230:            return IDER_CMD_ERROR;
                    231:        }
                    232:        
                    233:     } 
                    234:     else 
                    235:     {
                    236:        [self getIdeRegisters:ideRegs Print:NULL];
                    237:        IODBDMAReset( _ideDMARegs );
                    238:        return IDER_CMD_ERROR;
                    239:     }
                    240: 
                    241:     return (rtn);
                    242: }
                    243: 
                    244: /*
                    245:  *
                    246:  *
                    247:  */
                    248: -(ide_return_t) setupDMA:(vm_offset_t) startAddr client:(vm_task_t) client length:(int)length fRead:(BOOL)fRead 
                    249: {
                    250:     ide_return_t               rc;
                    251: 
                    252:     if ( _controllerType == kControllerTypeCmd646X )
                    253:     {
                    254:         rc = [self setupDMAList: startAddr client:client length:length fRead:fRead];
                    255:     }
                    256:     else
                    257:     {
                    258:         rc = [self setupDBDMA: startAddr client:client length:length fRead:fRead];
                    259:     }
                    260:     return rc;
                    261: }
                    262: 
                    263: -(ide_return_t) setupDBDMA:(vm_offset_t) startAddr client:(vm_task_t) client length:(int)length fRead:(BOOL)fRead 
                    264: {
                    265:     uint               count;
                    266:     uint               addr;
                    267:     uint               physAddr;
                    268:     uint               len;
                    269:     uint               bytesLeft;
                    270:     uint               i;
                    271:     IOReturn           rc;
                    272:     uint                maxDescriptors;
                    273: 
                    274:     /*
                    275:      * This is for the benefit of - getTransferCount in case of a zero length transfer.
                    276:      */
                    277:     bzero( (unsigned char *)_ideDMACommands, sizeof(IODBDMADescriptor) );
                    278: 
                    279:     if ( length == 0 )
                    280:     {
                    281:        return IDER_SUCCESS;
                    282:     }  
                    283: 
                    284:     bytesLeft = length;
                    285:     count     = PAGE_SIZE - (startAddr & (PAGE_SIZE-1));
                    286:     addr      = startAddr;
                    287:  
                    288:     maxDescriptors = MAX_IDE_DESCRIPTORS - 1 - ((length & 1) ? 1 : 0);
                    289:    
                    290:     for ( i=0; i < maxDescriptors && bytesLeft; i++ )
                    291:     {
                    292:        len = ( count > bytesLeft ) ? bytesLeft : count;
                    293: 
                    294:        rc = IOPhysicalFromVirtual( client, trunc_page(addr), &physAddr );
                    295:         if ( rc != IO_R_SUCCESS )
                    296:         {
                    297:             IOLog("IDE Disk - IOPhysicalFromVirtual rc = %d\n\r", rc);
                    298:             return IDER_MEMFAIL;
                    299:         }
                    300:         physAddr = (physAddr & ~(PAGE_SIZE-1)) | (addr & (PAGE_SIZE-1));
                    301: 
                    302:         IOMakeDBDMADescriptor( &_ideDMACommands[i],
                    303:                               ((fRead) ? kdbdmaInputMore : kdbdmaOutputMore),
                    304:                               kdbdmaKeyStream0,
                    305:                               kdbdmaIntNever,
                    306:                               kdbdmaBranchNever,
                    307:                               kdbdmaWaitNever,
                    308:                               len,
                    309:                               physAddr );
                    310:         bytesLeft -= len;
                    311:         addr      += len;
                    312:         count      = PAGE_SIZE;
                    313:     }
                    314: 
                    315:     /*
                    316:      * Note: ATAPI always transfers even byte-counts. Send the extra byte to/from the bit-bucket
                    317:      *       if the requested transfer length is odd.
                    318:      */
                    319:     if ( length & 1 )
                    320:     {
                    321:         IOMakeDBDMADescriptor( &_ideDMACommands[i++],
                    322:                               ((fRead) ? kdbdmaInputMore : kdbdmaOutputMore),
                    323:                               kdbdmaKeyStream0,
                    324:                               kdbdmaIntNever,
                    325:                               kdbdmaBranchNever,
                    326:                               kdbdmaWaitNever,
                    327:                               1,
                    328:                               bitBucketPhysAddr );
                    329:     }
                    330: 
                    331: 
                    332:     if ( bytesLeft )
                    333:     {
                    334:         IOLog("IDE I/O request too large - Length = %d\n\r", length);
                    335:         return IDER_REJECT;
                    336:     }
                    337:  
                    338:     IOMakeDBDMADescriptor( &_ideDMACommands[i],
                    339:                           kdbdmaStop,
                    340:                           kdbdmaKeyStream0,
                    341:                           kdbdmaIntNever,
                    342:                           kdbdmaBranchNever,
                    343:                           kdbdmaWaitNever,
                    344:                           0,
                    345:                           0  );
                    346:  
                    347:    IOSetDBDMACommandPtr( _ideDMARegs, _ideDMACommandsPhys );
                    348:        
                    349:    return IDER_SUCCESS;
                    350: }           
                    351:  
                    352: -(ide_return_t) setupDMAList:(vm_offset_t) startAddr client:(vm_task_t) client length:(int)length fRead:(BOOL)fRead 
                    353: {
                    354:     uint               count;
                    355:     uint               addr;
                    356:     uint               physAddr;
                    357:     uint               len;
                    358:     uint               bytesLeft;
                    359:     uint               i;
                    360:     IOReturn           rc;
                    361:     uint                maxDescriptors;
                    362:     ideDMAList_t       *ideDMAList;
                    363: 
                    364:     if ( length == 0 )
                    365:     {
                    366:        return IDER_SUCCESS;
                    367:     }  
                    368: 
                    369:     bytesLeft = length;
                    370:     count     = PAGE_SIZE - (startAddr & (PAGE_SIZE-1));
                    371:     addr      = startAddr;
                    372:  
                    373:     maxDescriptors = MAX_IDE_DESCRIPTORS * 2;
                    374:    
                    375:     ideDMAList = (ideDMAList_t *) _ideDMACommands;
                    376:     for ( i=0; i < maxDescriptors && bytesLeft; i++ )
                    377:     {
                    378:        len = ( count > bytesLeft ) ? bytesLeft : count;
                    379: 
                    380:        rc = IOPhysicalFromVirtual( client, trunc_page(addr), &physAddr );
                    381:         if ( rc != IO_R_SUCCESS )
                    382:         {
                    383:             IOLog("IDE Disk - IOPhysicalFromVirtual rc = %d\n\r", rc);
                    384:             return IDER_MEMFAIL;
                    385:         }
                    386:         physAddr = (physAddr & ~(PAGE_SIZE-1)) | (addr & (PAGE_SIZE-1));
                    387: 
                    388:         ideDMAList[i].start  = EndianSwap32( physAddr );
                    389:         ideDMAList[i].length = EndianSwap32( len );
                    390: 
                    391:         bytesLeft -= len;
                    392:         addr      += len;
                    393:         count      = PAGE_SIZE; 
                    394:     }
                    395: 
                    396:     if ( bytesLeft )
                    397:     {
                    398:         IOLog("IDE I/O request too large - Length = %d\n\r", length);
                    399:         return IDER_REJECT;
                    400:     }
                    401: 
                    402:     ideDMAList[i-1].length |= EndianSwap32( 0x80000000 );
                    403: 
                    404:     [[self deviceDescription] configWriteLong:0x74 value: _ideDMACommandsPhys];
                    405:        
                    406:     return IDER_SUCCESS;
                    407: }           
                    408: 
                    409: 
                    410: /*
                    411:  * This routine makes sure the DMA channel has shutdown at the end of an 
                    412:  * I/O request and obtains tha actual byte count transferred.
                    413:  */
                    414: - (uint) stopDBDMA
                    415: {
                    416:     uint       dmaStatus;
                    417:     uint        xferCount;
                    418:  
                    419:     dmaStatus = IOGetDBDMAChannelStatus( _ideDMARegs );
                    420:     
                    421:     if ( dmaStatus & (kdbdmaDead | kdbdmaActive) )
                    422:     {
                    423:         if ( IsPowerStar() )
                    424:         {
                    425:             [self fixOHareDMACorruption_1];
                    426:         }
                    427:         else
                    428:         {
                    429:             IODBDMAReset( _ideDMARegs );
                    430:         }
                    431:     }
                    432: 
                    433:     xferCount = [self getDBDMATransferCount];
                    434:     
                    435:     if ( dmaStatus & (kdbdmaDead | kdbdmaActive) )
                    436:     {
                    437:         if ( IsPowerStar() )
                    438:         {
                    439:             [self fixOHareDMACorruption_2];
                    440:         }
                    441:     }
                    442:     return xferCount;
                    443: }
                    444: 
                    445: /*
                    446:  * The OHare DMA controller and its predecessor Grand Central have a nasty habit of 
                    447:  * clobbering bytes prior to the data buffer if the buffer is not 16-byte aligned.
                    448:  *
                    449:  * To fix this we check for a non-aligned DMA read operation and save the bytes
                    450:  * prior to the start of the data buffer, and them restore them after the DMA channel
                    451:  * is shutdown.
                    452:  */
                    453: 
                    454: - (void) fixOHareDMACorruption_1
                    455: {
                    456:     IOReturn           rc;
                    457:     uint               i;
                    458:     uint               physAddr;
                    459:     uint               virtAddr;
                    460:     unsigned char      *p;
                    461:     BOOL               resetDone = NO;
                    462:     uint               dmaOp;
                    463:     unsigned char       saveUs[16];
                    464:     uint                len;
                    465: 
                    466:     do 
                    467:     {
                    468:         dmaOp = IOGetCCOperation(&_ideDMACommands[0])  >> 28; 
                    469:         if ( dmaOp != kdbdmaInputMore )
                    470:         {
                    471:             continue;
                    472:         }
                    473: 
                    474:         physAddr = IOGetCCAddress(&_ideDMACommands[0]);
                    475:         if ( !(physAddr & 0x0000000F) )
                    476:         {
                    477:             continue;
                    478:         }
                    479: 
                    480:         rc = IOMapPhysicalIntoIOTask( (vm_offset_t)   trunc_page(physAddr),
                    481:                                                       PAGE_SIZE,
                    482:                                       (vm_offset_t *) &virtAddr );
                    483:         if ( rc != IO_R_SUCCESS )
                    484:         {
                    485:             continue;
                    486:         }
                    487: 
                    488:         p =   (unsigned char *) ( (virtAddr & ~(PAGE_SIZE-1)) | (physAddr & 0xFF0) );
                    489:         len = (physAddr & 0x00F);
                    490: 
                    491:         for ( i=0; i < len; i++ )
                    492:         {
                    493:             saveUs[i] = p[i];
                    494:         }
                    495: 
                    496:         IODBDMAReset( _ideDMARegs );
                    497:         resetDone = YES;
                    498: 
                    499:         for ( i=0; i < len; i++ )
                    500:         {
                    501:             p[i] = saveUs[i];
                    502:         }
                    503: 
                    504:         IOUnmapPhysicalFromIOTask( (vm_offset_t)   trunc_page(virtAddr),
                    505:                                                    PAGE_SIZE );
                    506:     }
                    507:     while( 0 );     
                    508:  
                    509:     if ( resetDone == NO )
                    510:     {
                    511:         IODBDMAReset( _ideDMARegs );
                    512:     }
                    513: }    
                    514: 
                    515: 
                    516: /*
                    517:  * The OHare II controller has a bug where if there is a pending DMA write operation
                    518:  * that was not accepted by the device, it 'remembers' is and inserts an spurious 
                    519:  * DMA write to the device on the next write operation. This results in the data
                    520:  * for the next write operation to be shifted foward by two bytes.
                    521:  *
                    522:  */
                    523: 
                    524: - (void) fixOHareDMACorruption_2
                    525: {
                    526:     uint               dmaOp;
                    527: 
                    528:     dmaOp = IOGetCCOperation(&_ideDMACommands[0])  >> 28; 
                    529:     if ( dmaOp == kdbdmaOutputMore )
                    530:     {
                    531:         IOPanic("Disk(ata): IDE Hardware error - unable to recover\n\r");
                    532:     }
                    533: }
                    534:      
                    535: /*
                    536:  * Calculate the actual transfer count by reading back the DMA descriptors.
                    537:  */
                    538: - (uint) getDBDMATransferCount
                    539: {
                    540:     uint       i;
                    541:     uint        ccResult;
                    542:     uint        xferCount = 0;
                    543: 
                    544:     for ( i=0; i < MAX_IDE_DESCRIPTORS; i++ )
                    545:     {
                    546:         ccResult = IOGetCCResult( &_ideDMACommands[i] );
                    547:     
                    548:         if ( !(ccResult & kdbdmaStatusRun) )
                    549:         {
                    550:             break;
                    551:         } 
                    552:         xferCount += (IOGetCCOperation( &_ideDMACommands[i] ) & kdbdmaReqCountMask) - (ccResult & kdbdmaResCountMask); 
                    553:     }
                    554:     return xferCount;
                    555: }
                    556: 
                    557: @end
                    558: 

unix.superglobalmegacorp.com

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