|
|
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: /* ! 27: * Copyright (c) 1991-1997 NeXT Software, Inc. All rights reserved. ! 28: * ! 29: * IdeCnt.m - IDE Controller class. ! 30: * ! 31: */ ! 32: ! 33: #import <sys/systm.h> ! 34: #import <driverkit/kernelDriver.h> ! 35: #import <driverkit/interruptMsg.h> ! 36: #import <mach/mach_interface.h> ! 37: #import <driverkit/IODevice.h> ! 38: #import <driverkit/ppc/IOTreeDevice.h> ! 39: #import <driverkit/align.h> ! 40: #import <machkit/NXLock.h> ! 41: #import "io_inline.h" ! 42: #import "IdeDDM.h" ! 43: ! 44: #import "IdeCnt.h" ! 45: #import "IdeCntInit.h" ! 46: #import "IdeCntCmds.h" ! 47: #import "IdeCntDma.h" ! 48: ! 49: #import "IdeCntInline.h" ! 50: ! 51: #import "Cmd646xRegs.h" ! 52: ! 53: static int hcUnitNum = 0; ! 54: ! 55: ! 56: @implementation IdeController ! 57: ! 58: /* ! 59: * For PCI ATA the driver is running attached to a different node ! 60: * than OpenFirmware - patch up the path to match. ! 61: */ ! 62: #define PCIATASUBNODE "ata-4@0" ! 63: ! 64: - getDevicePath:(char *)path maxLength:(int)maxLen useAlias:(BOOL)doAlias ! 65: { ! 66: if( [super getDevicePath:path maxLength:maxLen useAlias:doAlias]) { ! 67: ! 68: if( _controllerType == kControllerTypeCmd646X) { ! 69: ! 70: int len = maxLen - strlen( path ); ! 71: ! 72: len -= strlen( PCIATASUBNODE ); ! 73: if( len < 0) ! 74: return( nil); ! 75: strcat( path, "/" PCIATASUBNODE ); ! 76: ! 77: if( doAlias) ! 78: IOAliasPath( path); ! 79: } ! 80: return( self); ! 81: } ! 82: return( nil); ! 83: } ! 84: ! 85: - (char *) matchDevicePath:(char *)matchPath ! 86: { ! 87: char * tail; ! 88: char * skip; ! 89: ! 90: tail = [super matchDevicePath:matchPath]; ! 91: if( tail && (_controllerType == kControllerTypeCmd646X)) { ! 92: ! 93: /* skip the extra path component */ ! 94: if( (0 == strncmp( tail + 1, PCIATASUBNODE, strlen( PCIATASUBNODE ))) ! 95: && (skip = strchr( tail + 1, '/')) ) ! 96: tail = skip; ! 97: } ! 98: return( tail); ! 99: } ! 100: ! 101: /* ! 102: * Create and initialize one instance of IDE Controller. ! 103: */ ! 104: ! 105: void call_kdp(void); ! 106: ! 107: + (BOOL)probe:(IOTreeDevice *)deviceDescription ! 108: { ! 109: IdeController *idec; ! 110: char devName[20]; ! 111: int numInts, numRange; ! 112: int maxInts, maxRange; ! 113: ! 114: // call_kdp(); ! 115: ! 116: idec = [[self alloc] initFromDeviceDescription:deviceDescription]; ! 117: ! 118: if ( strcmp([deviceDescription nodeName], "pci-ata") == 0 ) ! 119: { ! 120: idec->_controllerType = kControllerTypeCmd646X; ! 121: } ! 122: ! 123: numRange = [deviceDescription numMemoryRanges]; ! 124: numInts = [deviceDescription numInterrupts]; ! 125: ! 126: if ( idec->_controllerType == kControllerTypeCmd646X ) ! 127: { ! 128: maxRange = 5; ! 129: maxInts = 1; ! 130: } ! 131: else ! 132: { ! 133: maxRange = 2; ! 134: maxInts = 2; ! 135: } ! 136: ! 137: if ( numRange != maxRange ) ! 138: { ! 139: IOLog("Disk(ata): Invalid port ranges: %d.\n", numRange); ! 140: [idec free]; ! 141: return NO; ! 142: } ! 143: ! 144: if (numInts != maxInts) ! 145: { ! 146: IOLog("Disk(ata): Invalid number of interrupts: %d.\n", numInts); ! 147: [idec free]; ! 148: return NO; ! 149: } ! 150: ! 151: if ( [idec checkMediaBayOption: deviceDescription] == NO ) ! 152: { ! 153: IOLog("Disk(ata): Non-ATA/ATAPI Media Bay option detected\n\r"); ! 154: [idec free]; ! 155: return NO; ! 156: } ! 157: ! 158: /* ! 159: * Proceed with initialization. ! 160: */ ! 161: [idec setUnit:hcUnitNum]; ! 162: sprintf(devName, "hc%d", hcUnitNum); ! 163: [idec setName:devName]; ! 164: [idec setDeviceKind:"IdeController"]; ! 165: ! 166: if ([idec ideControllerInit:deviceDescription] != YES) ! 167: { ! 168: [idec free]; ! 169: return NO; ! 170: } ! 171: ! 172: if ([idec registerDevice] == nil) ! 173: { ! 174: IOLog("Disk(ata): %s: Failed to register device.\n", [self name]); ! 175: [idec free]; ! 176: return NO; ! 177: } ! 178: ! 179: hcUnitNum++; ! 180: ! 181: return YES; ! 182: } ! 183: ! 184: /* ! 185: * Wait for interrupt or timeout. Returns IDER_SUCCESS or IDER_TIMEOUT. ! 186: */ ! 187: - (ide_return_t)ideWaitForInterrupt:(unsigned int)command ! 188: ideStatus:(unsigned char *)status ! 189: { ! 190: msg_return_t result; ! 191: msg_header_t msg; ! 192: u_int8_t cfgByte; ! 193: ! 194: msg.msg_local_port = _ideInterruptPort; ! 195: msg.msg_size = sizeof(msg); ! 196: ! 197: result = msg_receive(&msg, RCV_TIMEOUT, _interruptTimeOut); ! 198: ! 199: if (result == RCV_SUCCESS || result == RCV_TOO_LARGE) ! 200: { ! 201: if (status != NULL) ! 202: *status = inb(_ideRegsAddrs.status); /* acknowledge */ ! 203: else ! 204: inb(_ideRegsAddrs.status); ! 205: ! 206: if ( _controllerType == kControllerTypeCmd646X ) ! 207: { ! 208: u_int32_t intReg; ! 209: ! 210: intReg = (_busNum == 0) ? kCmd646xCFR : kCmd646xARTTIM23; ! 211: [self configReadByte: intReg value: &cfgByte]; ! 212: [self configWriteByte: intReg value: cfgByte]; ! 213: [self enableInterrupt:0]; ! 214: ! 215: #if 0 ! 216: [self configReadByte: intReg value: &cfgByte]; ! 217: IOLog( "Int Mask = %08x Int Levels = %08x Int Events = %08x CmdInt = %02x\n\r", ! 218: *(volatile u_int32_t *)0x80800024, *(volatile u_int32_t *)0x8080002c, ! 219: *(volatile u_int32_t *)0x80800020, cfgByte ); ! 220: #endif ! 221: } ! 222: ! 223: return IDER_SUCCESS; ! 224: } ! 225: ! 226: if (result == RCV_TIMED_OUT) ! 227: { ! 228: IOLog("Disk(ata): %s: interrupt timeout, cmd: 0x%0x\n", [self name], command); ! 229: } ! 230: else ! 231: IOLog("Disk(ata): %s: Error %d in receiving interrupt, cmd: 0x%0x\n", ! 232: [self name], result, command); ! 233: ! 234: return IDER_CMD_ERROR; ! 235: } ! 236: ! 237: /* ! 238: * Remove any interrupts messages that have queued up. This will get rid of ! 239: * any spurious or duplicate interrupts. ! 240: */ ! 241: - (void)clearInterrupts ! 242: { ! 243: msg_return_t result; ! 244: msg_header_t msg; ! 245: int count; ! 246: ! 247: count = 0; ! 248: ! 249: while (1) { ! 250: ! 251: msg.msg_local_port = _ideInterruptPort; ! 252: msg.msg_size = sizeof(msg); ! 253: ! 254: result = msg_receive(&msg, RCV_TIMEOUT, 0); ! 255: ! 256: if (result != RCV_SUCCESS) ! 257: { ! 258: return; ! 259: } ! 260: count += 1; ! 261: } ! 262: } ! 263: ! 264: - (ide_return_t)waitForNotBusy ! 265: { ! 266: int delay = MAX_BUSY_DELAY; /* microseconds */ ! 267: unsigned char status; ! 268: ! 269: delay -= 2; /* Or else will block on second try */ ! 270: while (delay > 0) { ! 271: status = inb(_ideRegsAddrs.status); ! 272: if (!(status & BUSY)) { ! 273: return IDER_SUCCESS; ! 274: } ! 275: if (delay % 1000) { ! 276: IODelay(2); ! 277: delay -= 2; ! 278: } else { ! 279: IOSleep(1); ! 280: delay -= 1000; ! 281: } ! 282: } ! 283: ! 284: return IDER_TIMEOUT; ! 285: } ! 286: ! 287: - (ide_return_t)waitForDeviceReady ! 288: { ! 289: int delay = MAX_BUSY_DELAY; ! 290: unsigned char status; ! 291: ! 292: delay -= 2; ! 293: while (delay > 0) { ! 294: status = inb(_ideRegsAddrs.status); ! 295: if ((!(status & BUSY)) && (status & READY)) { ! 296: return IDER_SUCCESS; ! 297: } ! 298: if (delay % 1000) { ! 299: IODelay(2); ! 300: delay -= 2; ! 301: } else { ! 302: IOSleep(1); ! 303: delay -= 1000; ! 304: } ! 305: } ! 306: return IDER_TIMEOUT; ! 307: } ! 308: ! 309: - (ide_return_t)waitForDataReady ! 310: { ! 311: int delay = MAX_DATA_READY_DELAY; ! 312: unsigned char status; ! 313: ! 314: delay -= 2; ! 315: while (delay > 0) { ! 316: status = inb(_ideRegsAddrs.altStatus); ! 317: if ((!(status & BUSY)) && (status & DREQUEST)) ! 318: return (IDER_SUCCESS); ! 319: if (delay % 1000) { ! 320: IODelay(2); ! 321: delay -= 2; ! 322: } else { ! 323: IOSleep(1); ! 324: delay -= 1000; ! 325: } ! 326: } ! 327: ! 328: return IDER_TIMEOUT; ! 329: } ! 330: ! 331: ! 332: /* ! 333: * This is a private version for ideReadGetInfoCommon. It has a short delay ! 334: * time. This is the same situation as atapiIdentifyDeviceWaitForDataReady in ! 335: * AtapiCntCmds.m. The problem in both cases is that some devices pass ! 336: * identification checks even when they should not. Now the first command ! 337: * issued after can really confirm that but we don't want to wait too long. ! 338: */ ! 339: - (ide_return_t)ataIdeReadGetInfoCommonWaitForDataReady ! 340: { ! 341: int delay = MAX_DATA_READY_DELAY/25; ! 342: unsigned char status; ! 343: ! 344: delay -= 2; ! 345: while (delay > 0) { ! 346: status = inb(_ideRegsAddrs.altStatus); ! 347: if ((!(status & BUSY)) && (status & DREQUEST)) ! 348: return (IDER_SUCCESS); ! 349: if (delay % 1000) { ! 350: IODelay(2); ! 351: delay -= 2; ! 352: } else { ! 353: IOSleep(1); ! 354: delay -= 1000; ! 355: } ! 356: } ! 357: ! 358: return IDER_TIMEOUT; ! 359: } ! 360: ! 361: ! 362: - (void)enableInterrupts ! 363: { ! 364: outb(_ideRegsAddrs.deviceControl, DISK_INTERRUPT_ENABLE); ! 365: [self enableInterrupt:0]; ! 366: } ! 367: ! 368: - (void)disableInterrupts ! 369: { ! 370: [self disableInterrupt: 0]; ! 371: outb(_ideRegsAddrs.deviceControl, DISK_INTERRUPT_DISABLE); ! 372: } ! 373: ! 374: - (void)setInterruptTimeOut:(unsigned int)timeOut ! 375: { ! 376: _interruptTimeOut = timeOut; ! 377: } ! 378: ! 379: - (unsigned int)interruptTimeOut ! 380: { ! 381: return _interruptTimeOut; ! 382: } ! 383: ! 384: - (IOReturn) ideExecuteCmd:(ideIoReq_t *)ideIoReq ToDrive:(unsigned char)drive ! 385: { ! 386: return [self _ideExecuteCmd:ideIoReq ToDrive:drive]; ! 387: } ! 388: ! 389: ! 390: /* ! 391: * Return task file values, optionally print them if given a non-null string. ! 392: */ ! 393: - (void)getIdeRegisters:(ideRegsVal_t *)rvp Print:(char *)printString ! 394: { ! 395: ideRegsVal_t ideRegs; ! 396: ! 397: ideRegs.error = inb(_ideRegsAddrs.error); ! 398: ideRegs.sectCnt = inb(_ideRegsAddrs.sectCnt); ! 399: ideRegs.sectNum = inb(_ideRegsAddrs.sectNum); ! 400: ideRegs.cylLow = inb(_ideRegsAddrs.cylLow); ! 401: ideRegs.cylHigh = inb(_ideRegsAddrs.cylHigh); ! 402: ideRegs.drHead = inb(_ideRegsAddrs.drHead); ! 403: ideRegs.status = inb(_ideRegsAddrs.altStatus); /* don't ack */ ! 404: ! 405: if (rvp != NULL) ! 406: *rvp = ideRegs; ! 407: ! 408: if (printString != NULL) { ! 409: IOLog("Disk(ata): %s: %s: error=0x%x secCnt=0x%x " ! 410: "secNum=0x%x cyl=0x%x drhd=0x%x status=0x%x\n", ! 411: [self name], printString, ! 412: ideRegs.error, ideRegs.sectCnt, ideRegs.sectNum, ! 413: ((ideRegs.cylHigh << 8) | ideRegs.cylLow), ! 414: ideRegs.drHead, ideRegs.status); ! 415: } ! 416: } ! 417: ! 418: /* ! 419: * Read maximum of one page from the sector buffer to "addr", write maximum ! 420: * of one page from "addr" into the sector buffer. Note that (length <= ! 421: * PAGE_SIZE). ! 422: */ ! 423: - (void)xferData:(caddr_t)addr read:(BOOL)read client:(struct vm_map *)client ! 424: length:(unsigned)length ! 425: { ! 426: ideXferData(addr, read, client, length, _ideRegsAddrs ); ! 427: } ! 428: ! 429: - (BOOL)isMultiSectorAllowed:(unsigned int)unit ! 430: { ! 431: return (_multiSector[unit] != 0); ! 432: } ! 433: ! 434: -(unsigned int)getMultiSectorValue:(unsigned int)unit ! 435: { ! 436: return _ideIdentifyInfoSupported[unit] ? _multiSector[unit] : 0; ! 437: } ! 438: ! 439: - (ideIdentifyInfo_t *) getIdeIdentifyInfo:(unsigned int)unit ! 440: { ! 441: return _ideIdentifyInfoSupported[unit] ? ! 442: &_ideIdentifyInfo[unit] : NULL; ! 443: } ! 444: ! 445: - (ideDriveInfo_t *) getIdeDriveInfo:(unsigned int)unit ! 446: { ! 447: return (&_ideInfo[unit]); ! 448: } ! 449: ! 450: - (BOOL) isDmaSupported:(unsigned int)unit ! 451: { ! 452: return (_dmaSupported[unit] == YES); ! 453: } ! 454: ! 455: - (u_int) getControllerType ! 456: { ! 457: return _controllerType; ! 458: } ! 459: ! 460: /* ! 461: * Set the IDE Channel transfer rate to indicated drive ! 462: */ ! 463: -(void) setTransferRate: (int) unit UseDMA: (BOOL) fUseDMA ! 464: { ! 465: Cmd646xRegs_t *cfgRegs; ! 466: u_int8_t cfgByte; ! 467: u_int8_t drwtimReg; ! 468: ideDMATypes_t dmaType; ! 469: ! 470: if ( _cycleTimes[unit].fChanged == NO && _cycleTimes[unit].useDMA == fUseDMA ) ! 471: { ! 472: return; ! 473: } ! 474: _cycleTimes[unit].fChanged = NO; ! 475: _cycleTimes[unit].useDMA = fUseDMA; ! 476: ! 477: if ( _controllerType == kControllerTypeCmd646X ) ! 478: { ! 479: /* ! 480: * ! 481: */ ! 482: cfgRegs = &_cycleTimes[unit].ideConfig.cmd646XConfig; ! 483: ! 484: if ( _busNum == 0 ) ! 485: { ! 486: if ( unit == 0 ) ! 487: { ! 488: [self configReadByte: kCmd646xCNTRL value:&cfgByte]; ! 489: cfgByte &= ~kCmd646xCNTRL_Drive0ReadAhead; ! 490: cfgByte |= cfgRegs->cntrlReg; ! 491: [self configWriteByte: kCmd646xCNTRL value:cfgByte]; ! 492: ! 493: [self configWriteByte: kCmd646xCMDTIM value:cfgRegs->cmdtimReg]; ! 494: ! 495: [self configWriteByte: kCmd646xARTTIM0 value:cfgRegs->arttimReg]; ! 496: ! 497: dmaType = _cycleTimes[unit].dmaType; ! 498: if ( _cycleTimes[unit].useDMA && ((dmaType != IDE_DMA_NONE) || (dmaType != IDE_DMA_ULTRA)) ) ! 499: { ! 500: drwtimReg = cfgRegs->drwtimRegDMA; ! 501: } ! 502: else ! 503: { ! 504: drwtimReg = cfgRegs->drwtimRegPIO; ! 505: } ! 506: [self configWriteByte: kCmd646xDRWTIM0 value:drwtimReg]; ! 507: ! 508: [self configReadByte: kCmd646xUDIDETCR0 value:&cfgByte]; ! 509: cfgByte &= ~(kCmd646xUDIDETCR0_Drive0UDMACycleTime | kCmd646xUDIDETCR0_Drive0UDMAEnable); ! 510: cfgByte |= cfgRegs->udidetcrReg; ! 511: [self configWriteByte: kCmd646xUDIDETCR0 value:cfgByte]; ! 512: } ! 513: else ! 514: { ! 515: [self configReadByte: kCmd646xCNTRL value:&cfgByte]; ! 516: cfgByte &= ~kCmd646xCNTRL_Drive1ReadAhead; ! 517: cfgByte |= cfgRegs->cntrlReg; ! 518: [self configWriteByte: kCmd646xCNTRL value:cfgByte]; ! 519: ! 520: [self configWriteByte: kCmd646xARTTIM1 value:cfgRegs->arttimReg]; ! 521: ! 522: dmaType = _cycleTimes[unit].dmaType; ! 523: if ( _cycleTimes[unit].useDMA && ((dmaType != IDE_DMA_NONE) || (dmaType != IDE_DMA_ULTRA)) ) ! 524: { ! 525: drwtimReg = cfgRegs->drwtimRegDMA; ! 526: } ! 527: else ! 528: { ! 529: drwtimReg = cfgRegs->drwtimRegPIO; ! 530: } ! 531: [self configWriteByte: kCmd646xDRWTIM1 value:drwtimReg]; ! 532: ! 533: [self configReadByte: kCmd646xUDIDETCR0 value:&cfgByte]; ! 534: cfgByte &= ~(kCmd646xUDIDETCR0_Drive1UDMACycleTime | kCmd646xUDIDETCR0_Drive1UDMAEnable); ! 535: cfgByte |= cfgRegs->udidetcrReg; ! 536: [self configWriteByte: kCmd646xUDIDETCR0 value:cfgByte]; ! 537: } ! 538: } ! 539: else ! 540: { ! 541: if ( unit == 0 ) ! 542: { ! 543: [self configReadByte: kCmd646xARTTIM23 value:&cfgByte]; ! 544: cfgByte &= ~(kCmd646xARTTIM23_Drive2ReadAhead | kCmd646xARTTIM23_AddrSetup); ! 545: cfgByte |= (cfgRegs->cntrlReg >> 4) | cfgRegs->arttimReg; ! 546: [self configWriteByte: kCmd646xARTTIM23 value:cfgByte]; ! 547: ! 548: [self configWriteByte: kCmd646xCMDTIM value:cfgRegs->cmdtimReg]; ! 549: ! 550: dmaType = _cycleTimes[unit].dmaType; ! 551: if ( _cycleTimes[unit].useDMA && ((dmaType != IDE_DMA_NONE) || (dmaType != IDE_DMA_ULTRA)) ) ! 552: { ! 553: drwtimReg = cfgRegs->drwtimRegDMA; ! 554: } ! 555: else ! 556: { ! 557: drwtimReg = cfgRegs->drwtimRegPIO; ! 558: } ! 559: [self configWriteByte: kCmd646xDRWTIM2 value:drwtimReg]; ! 560: ! 561: [self configReadByte: kCmd646xUDIDETCR1 value:&cfgByte]; ! 562: cfgByte &= ~(kCmd646xUDIDETCR1_Drive2UDMACycleTime | kCmd646xUDIDETCR1_Drive2UDMAEnable); ! 563: cfgByte |= cfgRegs->udidetcrReg; ! 564: [self configWriteByte: kCmd646xUDIDETCR1 value:cfgByte]; ! 565: } ! 566: else ! 567: { ! 568: [self configReadByte: kCmd646xARTTIM23 value:&cfgByte]; ! 569: cfgByte &= ~(kCmd646xARTTIM23_Drive3ReadAhead | kCmd646xARTTIM23_AddrSetup); ! 570: cfgByte |= (cfgRegs->cntrlReg >> 4) | cfgRegs->arttimReg; ! 571: [self configWriteByte: kCmd646xARTTIM23 value:cfgByte]; ! 572: ! 573: dmaType = _cycleTimes[unit].dmaType; ! 574: if ( _cycleTimes[unit].useDMA && ((dmaType != IDE_DMA_NONE) || (dmaType != IDE_DMA_ULTRA)) ) ! 575: { ! 576: drwtimReg = cfgRegs->drwtimRegDMA; ! 577: } ! 578: else ! 579: { ! 580: drwtimReg = cfgRegs->drwtimRegPIO; ! 581: } ! 582: [self configWriteByte: kCmd646xDRWTIM3 value:drwtimReg]; ! 583: ! 584: [self configReadByte: kCmd646xUDIDETCR1 value:&cfgByte]; ! 585: cfgByte &= ~(kCmd646xUDIDETCR1_Drive3UDMACycleTime | kCmd646xUDIDETCR1_Drive3UDMAEnable); ! 586: cfgByte |= cfgRegs->udidetcrReg; ! 587: [self configWriteByte: kCmd646xUDIDETCR1 value:cfgByte]; ! 588: } ! 589: ! 590: } ! 591: return; ! 592: } ! 593: else ! 594: { ! 595: *(volatile uint *)_ideRegsAddrs.channelConfig = _cycleTimes[unit].ideConfig.dbdmaConfig; ! 596: eieio(); ! 597: _cycleTimes[unit ^ 1].fChanged = YES; ! 598: } ! 599: } ! 600: ! 601: /* ! 602: * Set the data transfer rate for the specified drive. ! 603: */ ! 604: -(void) setTransferMode:(int) unit ! 605: { ! 606: int value; ! 607: ! 608: value = IDE_FEATURE_MODE_PIO | _cycleTimes[unit].pioMode; ! 609: [self ideSetDriveFeature:FEATURE_SET_TRANSFER_MODE value: value]; ! 610: ! 611: if ( _cycleTimes[unit].dmaType != IDE_DMA_NONE ) ! 612: { ! 613: value = _cycleTimes[unit].dmaMode; ! 614: switch ( _cycleTimes[unit].dmaType ) ! 615: { ! 616: case IDE_DMA_NONE: ! 617: return; ! 618: case IDE_DMA_SINGLEWORD: ! 619: value |= IDE_FEATURE_MODE_SWDMA; ! 620: break; ! 621: case IDE_DMA_MULTIWORD: ! 622: value |= IDE_FEATURE_MODE_MWDMA; ! 623: break; ! 624: case IDE_DMA_ULTRA: ! 625: value |= IDE_FEATURE_MODE_ULTRADMA; ! 626: break; ! 627: } ! 628: [self ideSetDriveFeature:FEATURE_SET_TRANSFER_MODE value: value]; ! 629: } ! 630: } ! 631: ! 632: - (void)ideCntrlrLock ! 633: { ! 634: [_ideCmdLock lock]; ! 635: } ! 636: ! 637: - (void)ideCntrlrUnLock ! 638: { ! 639: [_ideCmdLock unlock]; ! 640: } ! 641: ! 642: - (u_int) numberOfDrives ! 643: { ! 644: return (MAX_IDE_DRIVES); ! 645: } ! 646: ! 647: ! 648: /* ! 649: * There is no need for separate ATAPI locks but we keep them for testing ! 650: * purposes. ! 651: */ ! 652: - (void)atapiCntrlrLock ! 653: { ! 654: [_ideCmdLock lock]; ! 655: } ! 656: ! 657: - (void)atapiCntrlrUnLock ! 658: { ! 659: [_ideCmdLock unlock]; ! 660: } ! 661: ! 662: /* ! 663: * The ATAPI driver (CD-ROM or Tape) will scan thorugh this list of devices ! 664: * looking for ATAPI hardware. ! 665: */ ! 666: - (unsigned int)numDevices ! 667: { ! 668: return MAX_IDE_DRIVES; ! 669: } ! 670: ! 671: - (BOOL)isAtapiDevice:(unsigned char)unit ! 672: { ! 673: if (unit >= MAX_IDE_DRIVES) ! 674: return NO; ! 675: ! 676: return _atapiDevice[unit]; ! 677: } ! 678: ! 679: - (BOOL)isAtapiCommandActive:(unsigned char)unit ! 680: { ! 681: return _atapiCommandActive[unit]; ! 682: } ! 683: ! 684: - (void)setAtapiCommandActive:(BOOL)state forUnit:(unsigned char)unit ! 685: { ! 686: _atapiCommandActive[unit] = state; ! 687: } ! 688: ! 689: /* ! 690: * Power management. ! 691: */ ! 692: - (idePowerState_t)drivePowerState ! 693: { ! 694: return _drivePowerState; ! 695: } ! 696: ! 697: - (void)setDrivePowerState:(idePowerState_t)state ! 698: { ! 699: _drivePowerState = state; ! 700: } ! 701: ! 702: - (void)putDriveToSleep ! 703: { ! 704: if ([self drivePowerState] == IDE_PM_SLEEP) ! 705: return; ! 706: ! 707: _driveSleepRequest = YES; ! 708: ddm_ide_lock("putDriveToSleep: acquiring lock, suspend\n",1,2,3,4,5); ! 709: [self ideCntrlrLock]; ! 710: ddm_ide_lock("putDriveToSleep: acquired lock, suspend\n",1,2,3,4,5); ! 711: #ifdef DEBUG ! 712: IOLog("Disk(ata): %s: Entering suspend mode.\n", [self name]); ! 713: #endif DEBUG ! 714: [self setDrivePowerState:IDE_PM_SLEEP]; ! 715: } ! 716: ! 717: /* ! 718: * The method wakeUpDrive simply sets a flag. The drive is actually woken up ! 719: * the next time we need it. This is done by a call from ! 720: * ideExecuteCmd:ToDrive: method to the spinUpDrive:unit: method below. ! 721: */ ! 722: - (void)wakeUpDrive ! 723: { ! 724: if ([self drivePowerState] == IDE_PM_ACTIVE) ! 725: return; ! 726: ! 727: _driveSleepRequest = NO; ! 728: ddm_ide_lock("wakeUpDrive: Exiting suspend mode.\n", 1,2,3,4,5); ! 729: [self setDrivePowerState:IDE_PM_STANDBY]; ! 730: ddm_ide_lock("wakeUpDrive: releasing lock, recovered\n",1,2,3,4,5); ! 731: [self ideCntrlrUnLock]; ! 732: } ! 733: ! 734: /* ! 735: * This will get the drive to spin up. We simply try to read a single sector ! 736: * and are prepared to camp out for a very long time (>>30 secs). ! 737: */ ! 738: #define MAX_MEDIA_ACCESS_TRIES 30 ! 739: ! 740: - (BOOL)spinUpDrive:(unsigned int)unit ! 741: { ! 742: unsigned char status; ! 743: int i, j; ! 744: unsigned char dh; ! 745: ! 746: dh = _addressMode[unit] | (unit ? SEL_DRIVE1 : SEL_DRIVE0); ! 747: ! 748: for (i = 0; i < MAX_MEDIA_ACCESS_TRIES; i++) { ! 749: ! 750: [self ideReset]; ! 751: [self disableInterrupts]; ! 752: ! 753: /* ! 754: * Read one sector at (0,0,1). (LBA == 1). ! 755: */ ! 756: outb(_ideRegsAddrs.drHead, dh); ! 757: outb(_ideRegsAddrs.sectNum, 0x1); ! 758: outb(_ideRegsAddrs.sectCnt, 0x1); ! 759: outb(_ideRegsAddrs.cylLow, 0x0); ! 760: outb(_ideRegsAddrs.cylHigh, 0x0); ! 761: outb(_ideRegsAddrs.command, IDE_READ); ! 762: ! 763: /* ! 764: * Wait for about ten seconds for response from drive. ! 765: */ ! 766: for (j = 0; j < 5; j++) { ! 767: IOSleep(2000); ! 768: status = inb(_ideRegsAddrs.status); ! 769: if ((!(status & BUSY)) && (status & DREQUEST)) { ! 770: [self ideReset]; /* FIXME: may not be needed */ ! 771: IOLog("Disk(ata): %s: Recovered from suspend mode.\n", [self name]); ! 772: return YES; ! 773: } ! 774: } ! 775: IOLog("Disk(ata): %s: Retrying to recover from suspend mode.\n", [self name]); ! 776: } ! 777: ! 778: IOLog("Disk(ata): %s: Failed to recover from suspend mode.\n", [self name]); ! 779: return NO; ! 780: } ! 781: ! 782: /* ! 783: * We need to get the ATA drives spinning before we can try to reset them. ! 784: * The situation gets complicated if the ATA and ATAPI device share the same ! 785: * cable. We basically start up all devices on this controller. ! 786: */ ! 787: - (BOOL)startUpAttachedDevices ! 788: { ! 789: int i; ! 790: BOOL status = YES; ! 791: ! 792: /* Spin up only ATA drives */ ! 793: for (i = 0; i < MAX_IDE_DRIVES; i++) { ! 794: if ((_ideInfo[i].type != 0) && ([self isAtapiDevice:i] == NO)){ ! 795: status = [self spinUpDrive:i]; ! 796: } ! 797: } ! 798: ! 799: [self resetAndInit]; ! 800: [self setDrivePowerState:IDE_PM_ACTIVE]; ! 801: ! 802: return status; ! 803: } ! 804: ! 805: - (IOReturn) getPowerState:(PMPowerState *)state_p ! 806: { ! 807: return IO_R_UNSUPPORTED; ! 808: } ! 809: ! 810: - (IOReturn) setPowerState:(PMPowerState)state ! 811: { ! 812: if (state == PM_READY) { ! 813: [self wakeUpDrive]; ! 814: } else if (state == PM_SUSPENDED) { ! 815: [self putDriveToSleep]; ! 816: } else { ! 817: //IOLog("Disk(ata): %s: unknown APM event %x\n", [self name], (unsigned int)state); ! 818: } ! 819: ! 820: return IO_R_SUCCESS; ! 821: } ! 822: ! 823: - (IOReturn) getPowerManagement:(PMPowerManagementState *)state_p ! 824: { ! 825: return IO_R_UNSUPPORTED; ! 826: } ! 827: ! 828: - (IOReturn) setPowerManagement:(PMPowerManagementState)state ! 829: { ! 830: return IO_R_UNSUPPORTED; ! 831: } ! 832: ! 833: - property_IODeviceClass:(char *)classes length:(unsigned int *)maxLen ! 834: { ! 835: strcpy( classes, IOClassIDEController); ! 836: return( self); ! 837: } ! 838: ! 839: - property_IODeviceType:(char *)types length:(unsigned int *)maxLen ! 840: { ! 841: strcat( types, " "IOTypeIDE); ! 842: return( self); ! 843: } ! 844: ! 845: ! 846: - (void) configWriteByte: (u_int32_t)reg value: (u_int8_t)cfgByte ! 847: { ! 848: union ! 849: { ! 850: unsigned long word; ! 851: unsigned char byte[4]; ! 852: } cfgReg; ! 853: ! 854: u_int32_t regWord; ! 855: ! 856: regWord = reg & ~0x03; ! 857: ! 858: [[self deviceDescription] configReadLong: regWord value: &cfgReg.word]; ! 859: cfgReg.word = EndianSwap32(cfgReg.word); ! 860: switch (regWord) ! 861: { ! 862: case kCmd646xCFR: ! 863: cfgReg.byte[kCmd646xCFR & 0x03] &= ~kCmd646xCFR_IDEIntPRI; ! 864: break; ! 865: case kCmd646xDRWTIM0: ! 866: cfgReg.byte[kCmd646xARTTIM23 & 0x03] &= ~kCmd646xARTTIM23_IDEIntSDY; ! 867: break; ! 868: case kCmd646xBMIDECR0: ! 869: cfgReg.byte[kCmd646xMRDMODE & 0x03 ] &= ~(kCmd646xMRDMODE_IDEIntPRI | kCmd646xMRDMODE_IDEIntSDY); ! 870: cfgReg.byte[kCmd646xBMIDESR0 & 0x03] &= ~(kCmd646xBMIDESR0_DMAIntPRI | kCmd646xBMIDESR0_DMAErrorPRI); ! 871: break; ! 872: case kCmd646xBMIDECR1: ! 873: cfgReg.byte[kCmd646xBMIDESR1 & 0x03] &= ~(kCmd646xBMIDESR1_DMAIntSDY | kCmd646xBMIDESR1_DMAErrorSDY); ! 874: break; ! 875: } ! 876: cfgReg.byte[reg & 0x03] = cfgByte; ! 877: ! 878: cfgReg.word = EndianSwap32(cfgReg.word); ! 879: [[self deviceDescription] configWriteLong: regWord value: cfgReg.word]; ! 880: } ! 881: ! 882: ! 883: - (void) configReadByte: (u_int32_t)reg value: (u_int8_t *)cfgByte ! 884: { ! 885: union ! 886: { ! 887: unsigned long word; ! 888: unsigned char byte[4]; ! 889: } cfgReg; ! 890: ! 891: [[self deviceDescription] configReadLong: reg value:&cfgReg.word]; ! 892: *cfgByte = cfgReg.byte[3 - (reg & 0x03)]; ! 893: return; ! 894: } ! 895: ! 896: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.