|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.