|
|
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: * IdeCnt.m - IDE Controller class. ! 29: * ! 30: * HISTORY ! 31: * ! 32: * 1-Feb-1998 Joe Liu at Apple ! 33: * Created an initFromDeviceDescription method to do things that used to be ! 34: * done in the probe method. This allows us to call [super init...] after ! 35: * we have finished munging with our resources. ! 36: * ! 37: * 04-Sep-1996 Becky Divinski at NeXT ! 38: * Added code in probe method to handle Dual EIDE personality case. ! 39: * ! 40: * 07-Jul-1994 Rakesh Dubey at NeXT ! 41: * Created from original driver written by David Somayajulu. ! 42: */ ! 43: ! 44: #if 0 ! 45: #define KERNEL 1 ! 46: #define KERNEL_PRIVATE 1 ! 47: #define ARCH_PRIVATE 1 ! 48: #undef MACH_USER_API ! 49: #endif ! 50: ! 51: #import "IdeCnt.h" ! 52: #import "IdeCntInit.h" ! 53: #import "IdeCntCmds.h" ! 54: #import "IdePIIX.h" ! 55: #import <driverkit/i386/IOPCIDeviceDescription.h> ! 56: #import <driverkit/i386/IOPCIDirectDevice.h> ! 57: #import <driverkit/kernelDriver.h> ! 58: #import <driverkit/interruptMsg.h> ! 59: #if (IO_DRIVERKIT_VERSION != 330) ! 60: #import <machdep/machine/pmap.h> // XXX get rid of this ! 61: #endif ! 62: #import <mach/mach_interface.h> ! 63: #import <driverkit/IODevice.h> ! 64: #import <driverkit/align.h> ! 65: #import <machkit/NXLock.h> ! 66: #import <machdep/i386/io_inline.h> ! 67: #import <kernserv/i386/spl.h> ! 68: #ifdef NO_IRQ_MSG ! 69: #import <kern/sched_prim.h> ! 70: #endif NO_IRQ_MSG ! 71: #import <kern/lock.h> ! 72: #import "IdeDDM.h" ! 73: #import <bsd/stdio.h> ! 74: ! 75: // XXX get rid of this ! 76: #if (IO_DRIVERKIT_VERSION != 330) ! 77: #import <machdep/machine/pmap.h> ! 78: #endif ! 79: #import "IdeCntInline.h" ! 80: #import "DualEide.h" ! 81: ! 82: /* ! 83: * If set to non-zero some debugging messages will be prinetd in case of ! 84: * failure. ! 85: */ ! 86: __private_extern__ unsigned int _ide_debug = 0; ! 87: ! 88: /* ! 89: * Config table keys that determine our configuration. ! 90: */ ! 91: #define CONTROLLER_INSTANCE "Instance" ! 92: #define ATA_DEBUG "Debug" ! 93: ! 94: #ifdef NO_IRQ_MSG ! 95: #warning Interrupt messaging OFF ! 96: typedef struct _ideStruct { ! 97: @defs(IdeController) ! 98: } ideStruct_t; ! 99: #endif NO_IRQ_MSG ! 100: ! 101: @implementation IdeController ! 102: ! 103: /* ! 104: * Create and initialize one instance of IDE Controller. ! 105: */ ! 106: ! 107: + (BOOL)probe:(IODeviceDescription *)devDesc ! 108: { ! 109: IdeController *idec; ! 110: ! 111: idec = [self alloc]; ! 112: if (idec == nil) { ! 113: IOLog("%s: Failed to alloc instance\n", [self name]); ! 114: return NO; ! 115: } ! 116: ! 117: return ([idec initFromDeviceDescription:devDesc] != nil); ! 118: } ! 119: ! 120: - initFromDeviceDescription:(IODeviceDescription *)devDesc ! 121: { ! 122: char devName[20]; ! 123: const char *ctlType, *param; ! 124: int n, hcUnitNum; ! 125: ! 126: IOEISADeviceDescription *deviceDescription = ! 127: (IOEISADeviceDescription *)devDesc; ! 128: ! 129: if ((n = [deviceDescription numPortRanges]) != 1) { ! 130: IOLog("ATA: Invalid port ranges: %d.\n", n); ! 131: [self free]; ! 132: return nil; ! 133: } ! 134: ! 135: if ((n = [deviceDescription numInterrupts]) != 1) { ! 136: IOLog("ATA: Invalid number of interrupts: %d.\n", n); ! 137: [self free]; ! 138: return nil; ! 139: } ! 140: ! 141: ctlType = [[deviceDescription configTable] ! 142: valueForStringKey: CONTROLLER_INSTANCE]; ! 143: ! 144: hcUnitNum = (unsigned char) ctlType[0] - '0'; ! 145: ! 146: // Hack for Dual EIDE case ! 147: ! 148: if (dualEide) ! 149: { ! 150: if (instanceNum > 0) ! 151: hcUnitNum = instanceNum; ! 152: } ! 153: ! 154: if (hcUnitNum > MAX_IDE_CONTROLLERS-1) { ! 155: IOLog("ATA: Controller %d not supported.\n", hcUnitNum); ! 156: [self free]; ! 157: return nil; ! 158: } ! 159: ! 160: param = [[deviceDescription configTable] ! 161: valueForStringKey: ATA_DEBUG]; ! 162: if ((param != NULL) && (strcmp(param, "Yes") == 0)) { ! 163: _ide_debug = 1; ! 164: IOLog("ATA/ATAPI: Debug mode enabled.\n"); ! 165: } else { ! 166: _ide_debug = 0; ! 167: } ! 168: ! 169: /* ! 170: * Proceed with initialization. ! 171: */ ! 172: [self setUnit:hcUnitNum]; ! 173: sprintf(devName, "hc%d", hcUnitNum); ! 174: [self setName:devName]; ! 175: [self setDeviceKind:"IdeController"]; ! 176: ! 177: /* ! 178: * Allocate storage for the ideIdentifyInfo_t structures. ! 179: */ ! 180: for (n = 0; n < MAX_IDE_DRIVES; n++) { ! 181: _drives[n].ideIdentifyInfo = ! 182: (ideIdentifyInfo_t *)IOMalloc(sizeof(ideIdentifyInfo_t)); ! 183: if (_drives[n].ideIdentifyInfo == NULL) { ! 184: [self free]; ! 185: return nil; ! 186: } ! 187: } ! 188: ! 189: /* ! 190: * This must be called before [super init...] so that we can append ! 191: * to the portRangeList before it is registered. ! 192: */ ! 193: if ([self probePCIController:(IOPCIDeviceDescription *)devDesc] != YES) { ! 194: [self free]; ! 195: return nil; ! 196: } ! 197: ! 198: if ([super initFromDeviceDescription:deviceDescription] == nil) { ! 199: IOLog("%s: initFromDeviceDescription failed.\n", [self name]); ! 200: [self free]; ! 201: return nil; ! 202: } ! 203: ! 204: if ([self ideControllerInit:devDesc] != YES) { ! 205: [self free]; ! 206: return nil; ! 207: } ! 208: ! 209: if ([self registerDevice] == nil) { ! 210: IOLog("%s: Failed to register device.\n", [self name]); ! 211: [self free]; ! 212: return nil; ! 213: } ! 214: ! 215: return self; ! 216: } ! 217: ! 218: static int logInterrupts = 0; ! 219: static unsigned short lastCommand = 0; ! 220: ! 221: /* ! 222: * Wait for interrupt or timeout. Returns IDER_SUCCESS or IDER_TIMEOUT. ! 223: */ ! 224: - (ide_return_t)ideWaitForInterrupt:(unsigned int)command ! 225: ideStatus:(unsigned char *)status ! 226: { ! 227: #ifdef NO_IRQ_MSG ! 228: ide_return_t ret; ! 229: u_int s; ! 230: BOOL _interruptOccurred; ! 231: ! 232: s = spldevice(); ! 233: ! 234: assert_wait((void *)&waitQueue, TRUE); ! 235: thread_set_timeout(HZ * _interruptTimeOut / 1000); // value in ticks ! 236: thread_block_with_continuation((void (*)()) 0); ! 237: ! 238: _interruptOccurred = interruptOccurred; ! 239: ! 240: splx(s); ! 241: ! 242: if (_interruptOccurred == YES) { ! 243: if (status != NULL) ! 244: *status = inb(_ideRegsAddrs.status); /* acknowledge */ ! 245: else ! 246: inb(_ideRegsAddrs.status); ! 247: ! 248: logInterrupts -= 1; ! 249: lastCommand = command; ! 250: ! 251: ret = IDER_SUCCESS; ! 252: } ! 253: else { ! 254: IOLog("%s: interrupt timeout, cmd: 0x%0x\n", [self name], command); ! 255: ret = IDER_CMD_ERROR; ! 256: } ! 257: ! 258: return (ret); ! 259: ! 260: #else NO_IRQ_MSG ! 261: ! 262: msg_return_t result; ! 263: msg_header_t msg; ! 264: ! 265: msg.msg_local_port = _ideInterruptPort; ! 266: msg.msg_size = sizeof(msg); ! 267: ! 268: #ifdef undef ! 269: if (logInterrupts > 0) ! 270: IOLog("%s: waiting for interrupt for command %x\n", ! 271: [self name], command); ! 272: #endif undef ! 273: ! 274: result = msg_receive(&msg, RCV_TIMEOUT, _interruptTimeOut); ! 275: ! 276: if (result == RCV_SUCCESS || result == RCV_TOO_LARGE) { ! 277: if (status != NULL) ! 278: *status = inb(_ideRegsAddrs.status); /* acknowledge */ ! 279: else ! 280: inb(_ideRegsAddrs.status); ! 281: ! 282: #ifdef undef ! 283: if (logInterrupts > 0) ! 284: IOLog("%s: interrupt received for cmd: 0x%0x, status: 0x%0x\n", ! 285: [self name], command, (status == NULL) ? 0 : *status); ! 286: #endif undef ! 287: logInterrupts -= 1; ! 288: lastCommand = command; ! 289: ! 290: return IDER_SUCCESS; ! 291: } ! 292: ! 293: if (result == RCV_TIMED_OUT) ! 294: IOLog("%s: interrupt timeout, cmd: 0x%0x\n", [self name], command); ! 295: else ! 296: IOLog("%s: Error %d in receiving interrupt, cmd: 0x%0x\n", ! 297: [self name], result, command); ! 298: ! 299: return IDER_CMD_ERROR; ! 300: #endif NO_IRQ_MSG ! 301: } ! 302: ! 303: /* ! 304: * Remove any interrupts messages that have queued up. This will get rid of ! 305: * any spurious or duplicate interrupts. ! 306: */ ! 307: - (void)clearInterrupts ! 308: { ! 309: #ifdef NO_IRQ_MSG ! 310: return; ! 311: #else NO_IRQ_MSG ! 312: msg_return_t result; ! 313: msg_header_t msg; ! 314: int count; ! 315: ! 316: count = 0; ! 317: ! 318: while (1) { ! 319: ! 320: msg.msg_local_port = _ideInterruptPort; ! 321: msg.msg_size = sizeof(msg); ! 322: ! 323: result = msg_receive(&msg, RCV_TIMEOUT, 0); ! 324: ! 325: if (result != RCV_SUCCESS) { ! 326: if (count != 0) { ! 327: #ifdef DEBUG ! 328: IOLog("%s: %d spurious interrupts after command 0x%0x\n", ! 329: [self name], count, lastCommand); ! 330: #endif DEBUG ! 331: } ! 332: return; ! 333: } ! 334: count += 1; ! 335: } ! 336: #endif NO_IRQ_MSG ! 337: } ! 338: ! 339: - free ! 340: { ! 341: int n; ! 342: ! 343: [self resetController]; ! 344: ! 345: if ((_controllerID == PCI_ID_PIIX) || ! 346: (_controllerID == PCI_ID_PIIX3) || ! 347: (_controllerID == PCI_ID_PIIX4)) { ! 348: if (_prdTable.ptr) ! 349: IOFree(_prdTable.ptrReal, _prdTable.sizeReal); ! 350: } ! 351: ! 352: for (n = 0; n < MAX_IDE_DRIVES; n++) { ! 353: if (_drives[n].ideIdentifyInfo) ! 354: IOFree(_drives[n].ideIdentifyInfo, sizeof(ideIdentifyInfo_t)); ! 355: } ! 356: ! 357: return [super free]; ! 358: } ! 359: ! 360: - (ide_return_t)waitForNotBusy ! 361: { ! 362: int delay = MAX_BUSY_DELAY; /* microseconds */ ! 363: unsigned char status; ! 364: ! 365: #ifdef undef ! 366: IOLog("%s: waitForNotBusy\n", [self name]); ! 367: #endif undef ! 368: ! 369: delay -= 2; /* Or else will block on second try */ ! 370: while (delay > 0) { ! 371: status = inb(_ideRegsAddrs.status); ! 372: if (!(status & BUSY)) { ! 373: return IDER_SUCCESS; ! 374: } ! 375: if (delay % 1000) { ! 376: IODelay(2); ! 377: delay -= 2; ! 378: } else { ! 379: IOSleep(1); ! 380: delay -= 1000; ! 381: } ! 382: ! 383: #ifdef undef ! 384: if ((_printWaitForNotBusy) && (delay % 20000 == 0)) { ! 385: IOLog("%s: waitForNotBusy, status = %x\n", ! 386: [self name], status); ! 387: } ! 388: #endif undef ! 389: } ! 390: ! 391: return IDER_TIMEOUT; ! 392: } ! 393: ! 394: - (ide_return_t)waitForDeviceReady ! 395: { ! 396: int delay = MAX_BUSY_DELAY; ! 397: unsigned char status; ! 398: ! 399: #ifdef undef ! 400: if (_printWaitForNotBusy) ! 401: IOLog("%s: waitForDeviceReady\n", [self name]); ! 402: #endif undef ! 403: ! 404: delay -= 2; ! 405: while (delay > 0) { ! 406: status = inb(_ideRegsAddrs.status); ! 407: if ((!(status & BUSY)) && (status & READY)) { ! 408: return IDER_SUCCESS; ! 409: } ! 410: if (delay % 1000) { ! 411: IODelay(2); ! 412: delay -= 2; ! 413: } else { ! 414: IOSleep(1); ! 415: delay -= 1000; ! 416: } ! 417: ! 418: #ifdef undef ! 419: if ((_printWaitForNotBusy) && (delay % 20000 == 0)) { ! 420: IOLog("%s: waitForDeviceReady, status = %x\n", ! 421: [self name], status); ! 422: } ! 423: #endif undef ! 424: ! 425: } ! 426: return IDER_TIMEOUT; ! 427: } ! 428: ! 429: #define ATA_IDLE_BIT_MASK (BUSY | DREQUEST) ! 430: - (ide_return_t)waitForDeviceIdle ! 431: { ! 432: int delay = MAX_BUSY_DELAY; ! 433: unsigned char status; ! 434: ! 435: #ifdef undef ! 436: IOLog("%s: waitForDeviceIdle\n", [self name]); ! 437: #endif undef ! 438: ! 439: delay -= 2; ! 440: while (delay > 0) { ! 441: status = inb(_ideRegsAddrs.status); ! 442: if ((status & ATA_IDLE_BIT_MASK) == 0) ! 443: return IDER_SUCCESS; ! 444: if (delay % 1000) { ! 445: IODelay(2); ! 446: delay -= 2; ! 447: } else { ! 448: IOSleep(1); ! 449: delay -= 1000; ! 450: } ! 451: } ! 452: return IDER_TIMEOUT; ! 453: } ! 454: ! 455: - (ide_return_t)waitForDataReady ! 456: { ! 457: int delay = MAX_DATA_READY_DELAY; ! 458: unsigned char status; ! 459: ! 460: #ifdef undef ! 461: IOLog("waitForDataReady\n"); ! 462: #endif undef ! 463: ! 464: delay -= 2; ! 465: while (delay > 0) { ! 466: status = inb(_ideRegsAddrs.altStatus); ! 467: if ((!(status & BUSY)) && (status & DREQUEST)) ! 468: return (IDER_SUCCESS); ! 469: if (delay % 1000) { ! 470: IODelay(2); ! 471: delay -= 2; ! 472: } else { ! 473: IOSleep(1); ! 474: delay -= 1000; ! 475: } ! 476: } ! 477: ! 478: return IDER_TIMEOUT; ! 479: } ! 480: ! 481: ! 482: /* ! 483: * This is a private version for ideReadGetInfoCommon. It has a short delay ! 484: * time. This is the same situation as atapiIdentifyDeviceWaitForDataReady in ! 485: * AtapiCntCmds.m. The problem in both cases is that some devices pass ! 486: * identification checks even when they should not. Now the first command ! 487: * issued after can really confirm that but we don't want to wait too long. ! 488: */ ! 489: - (ide_return_t)ataIdeReadGetInfoCommonWaitForDataReady ! 490: { ! 491: int delay = MAX_DATA_READY_DELAY/25; ! 492: unsigned char status; ! 493: ! 494: #ifdef undef ! 495: IOLog("waitForDataReady\n"); ! 496: #endif undef ! 497: ! 498: delay -= 2; ! 499: while (delay > 0) { ! 500: status = inb(_ideRegsAddrs.altStatus); ! 501: if ((!(status & BUSY)) && (status & DREQUEST)) ! 502: return (IDER_SUCCESS); ! 503: if (delay % 1000) { ! 504: IODelay(2); ! 505: delay -= 2; ! 506: } else { ! 507: IOSleep(1); ! 508: delay -= 1000; ! 509: } ! 510: } ! 511: ! 512: return IDER_TIMEOUT; ! 513: } ! 514: ! 515: ! 516: - (void)enableInterrupts ! 517: { ! 518: outb(_ideRegsAddrs.deviceControl, DISK_INTERRUPT_ENABLE); ! 519: } ! 520: ! 521: - (void)disableInterrupts ! 522: { ! 523: outb(_ideRegsAddrs.deviceControl, DISK_INTERRUPT_DISABLE); ! 524: } ! 525: ! 526: - (void)setInterruptTimeOut:(unsigned int)timeOut ! 527: { ! 528: _interruptTimeOut = timeOut; ! 529: } ! 530: ! 531: - (unsigned int)interruptTimeOut ! 532: { ! 533: return _interruptTimeOut; ! 534: } ! 535: ! 536: ! 537: /* ! 538: * Return task file values, optionally print them if given a non-null string. ! 539: */ ! 540: - (void)getIdeRegisters:(ideRegsVal_t *)rvp Print:(char *)printString ! 541: { ! 542: ideRegsVal_t ideRegs; ! 543: ! 544: ideRegs.error = inb(_ideRegsAddrs.error); ! 545: ideRegs.sectCnt = inb(_ideRegsAddrs.sectCnt); ! 546: ideRegs.sectNum = inb(_ideRegsAddrs.sectNum); ! 547: ideRegs.cylLow = inb(_ideRegsAddrs.cylLow); ! 548: ideRegs.cylHigh = inb(_ideRegsAddrs.cylHigh); ! 549: ideRegs.drHead = inb(_ideRegsAddrs.drHead); ! 550: ideRegs.status = inb(_ideRegsAddrs.altStatus); /* don't ack */ ! 551: ! 552: if (rvp != NULL) ! 553: *rvp = ideRegs; ! 554: ! 555: if (printString != NULL) { ! 556: IOLog("%s: %s: error=0x%x secCnt=0x%x " ! 557: "secNum=0x%x cyl=0x%x drhd=0x%x status=0x%x\n", ! 558: [self name], printString, ! 559: ideRegs.error, ideRegs.sectCnt, ideRegs.sectNum, ! 560: ((ideRegs.cylHigh << 8) | ideRegs.cylLow), ! 561: ideRegs.drHead, ideRegs.status); ! 562: } ! 563: } ! 564: ! 565: /* ! 566: * Read maximum of one page from the sector buffer to "addr", write maximum ! 567: * of one page from "addr" into the sector buffer. Note that (length <= ! 568: * PAGE_SIZE). ! 569: */ ! 570: - (void)xferData:(caddr_t)addr read:(BOOL)read client:(struct vm_map *)client ! 571: length:(unsigned)length ! 572: { ! 573: ideXferData(addr, read, client, length, _ideRegsAddrs, _transferWidth); ! 574: } ! 575: ! 576: - (BOOL)isMultiSectorAllowed:(unsigned int)unit ! 577: { ! 578: return (_drives[unit].multiSector != 0); ! 579: } ! 580: ! 581: -(unsigned int)getMultiSectorValue:(unsigned int)unit ! 582: { ! 583: return _drives[unit].ideIdentifyInfoSupported ? ! 584: _drives[unit].multiSector : 0; ! 585: } ! 586: ! 587: - (void)ideCntrlrLock ! 588: { ! 589: [_ideCmdLock lock]; ! 590: } ! 591: ! 592: - (void)ideCntrlrUnLock ! 593: { ! 594: [_ideCmdLock unlock]; ! 595: } ! 596: ! 597: /* ! 598: * There is no need for separate ATAPI locks but we keep them for testing ! 599: * purposes. ! 600: */ ! 601: - (void)atapiCntrlrLock ! 602: { ! 603: [_ideCmdLock lock]; ! 604: } ! 605: ! 606: - (void)atapiCntrlrUnLock ! 607: { ! 608: [_ideCmdLock unlock]; ! 609: } ! 610: ! 611: /* ! 612: * The ATAPI driver (CD-ROM or Tape) will scan thorugh this list of devices ! 613: * looking for ATAPI hardware. ! 614: */ ! 615: - (unsigned int)numDevices ! 616: { ! 617: return MAX_IDE_DRIVES; ! 618: } ! 619: ! 620: - (BOOL)isAtapiDevice:(unsigned char)unit ! 621: { ! 622: if (unit >= MAX_IDE_DRIVES) ! 623: return NO; ! 624: ! 625: return _drives[unit].atapiDevice; ! 626: } ! 627: ! 628: - (BOOL)isAtapiCommandActive:(unsigned char)unit ! 629: { ! 630: return _drives[unit].atapiCommandActive; ! 631: } ! 632: ! 633: - (void)setAtapiCommandActive:(BOOL)state forUnit:(unsigned char)unit ! 634: { ! 635: _drives[unit].atapiCommandActive = state; ! 636: } ! 637: ! 638: - (BOOL) isDmaSupported:(unsigned int)unit ! 639: { ! 640: return (_drives[unit].transferType != IDE_TRANSFER_PIO); ! 641: } ! 642: ! 643: /* ! 644: * Simply forward the interrupt. ! 645: */ ! 646: static void ideInterruptHandler(void *identity, void *state, unsigned int arg) ! 647: { ! 648: #ifdef NO_IRQ_MSG ! 649: ideStruct_t *obj = (ideStruct_t *)arg; ! 650: obj->interruptOccurred = YES; ! 651: thread_wakeup_one(&obj->waitQueue); ! 652: #else NO_IRQ_MSG ! 653: IOSendInterrupt(identity, state, IO_DEVICE_INTERRUPT_MSG); ! 654: #endif NO_IRQ_MSG ! 655: } ! 656: ! 657: - (BOOL)getHandler:(IOEISAInterruptHandler *)handler ! 658: level:(unsigned int *)ipl ! 659: argument:(unsigned int *)arg ! 660: forInterrupt:(unsigned int)localInterrupt ! 661: { ! 662: *handler = ideInterruptHandler; ! 663: *ipl = IPLDEVICE; ! 664: *arg = (unsigned int)self; ! 665: return YES; ! 666: } ! 667: ! 668: /* ! 669: * Power management. ! 670: */ ! 671: - (idePowerState_t)drivePowerState ! 672: { ! 673: return _drivePowerState; ! 674: } ! 675: ! 676: - (void)setDrivePowerState:(idePowerState_t)state ! 677: { ! 678: _drivePowerState = state; ! 679: } ! 680: ! 681: - (void)putDriveToSleep ! 682: { ! 683: if ([self drivePowerState] == IDE_PM_SLEEP) ! 684: return; ! 685: ! 686: _driveSleepRequest = YES; ! 687: ddm_ide_lock("putDriveToSleep: acquiring lock, suspend\n",1,2,3,4,5); ! 688: [self ideCntrlrLock]; ! 689: ddm_ide_lock("putDriveToSleep: acquired lock, suspend\n",1,2,3,4,5); ! 690: #ifdef DEBUG ! 691: IOLog("%s: Entering suspend mode.\n", [self name]); ! 692: #endif DEBUG ! 693: [self setDrivePowerState:IDE_PM_SLEEP]; ! 694: } ! 695: ! 696: /* ! 697: * The method wakeUpDrive simply sets a flag. The drive is actually woken up ! 698: * the next time we need it. This is done by a call from ! 699: * ideExecuteCmd:ToDrive: method to the spinUpDrive:unit: method below. ! 700: */ ! 701: - (void)wakeUpDrive ! 702: { ! 703: if ([self drivePowerState] == IDE_PM_ACTIVE) ! 704: return; ! 705: ! 706: _driveSleepRequest = NO; ! 707: ddm_ide_lock("wakeUpDrive: Exiting suspend mode.\n", 1,2,3,4,5); ! 708: [self setDrivePowerState:IDE_PM_STANDBY]; ! 709: ddm_ide_lock("wakeUpDrive: releasing lock, recovered\n",1,2,3,4,5); ! 710: [self ideCntrlrUnLock]; ! 711: } ! 712: ! 713: /* ! 714: * This will get the drive to spin up. We simply try to read a single sector ! 715: * and are prepared to camp out for a very long time (>>30 secs). ! 716: */ ! 717: #define MAX_MEDIA_ACCESS_TRIES 30 ! 718: ! 719: - (BOOL)spinUpDrive:(unsigned int)unit ! 720: { ! 721: unsigned char status; ! 722: int i, j; ! 723: unsigned char dh; ! 724: ! 725: dh = _drives[unit].addressMode | (unit ? SEL_DRIVE1 : SEL_DRIVE0); ! 726: ! 727: for (i = 0; i < MAX_MEDIA_ACCESS_TRIES; i++) { ! 728: ! 729: [self ideReset]; ! 730: [self disableInterrupts]; ! 731: ! 732: /* ! 733: * Read one sector at (0,0,1). (LBA == 1). ! 734: */ ! 735: outb(_ideRegsAddrs.drHead, dh); ! 736: outb(_ideRegsAddrs.sectNum, 0x1); ! 737: outb(_ideRegsAddrs.sectCnt, 0x1); ! 738: outb(_ideRegsAddrs.cylLow, 0x0); ! 739: outb(_ideRegsAddrs.cylHigh, 0x0); ! 740: outb(_ideRegsAddrs.command, IDE_READ); ! 741: ! 742: /* ! 743: * Wait for about ten seconds for response from drive. ! 744: */ ! 745: for (j = 0; j < 5; j++) { ! 746: IOSleep(2000); ! 747: status = inb(_ideRegsAddrs.status); ! 748: if ((!(status & BUSY)) && (status & DREQUEST)) { ! 749: [self ideReset]; /* FIXME: may not be needed */ ! 750: IOLog("%s: Recovered from suspend mode.\n", [self name]); ! 751: return YES; ! 752: } ! 753: } ! 754: IOLog("%s: Retrying to recover from suspend mode.\n", [self name]); ! 755: } ! 756: ! 757: IOLog("%s: Failed to recover from suspend mode.\n", [self name]); ! 758: return NO; ! 759: } ! 760: ! 761: /* ! 762: * We need to get the ATA drives spinning before we can try to reset them. ! 763: * The situation gets complicated if the ATA and ATAPI device share the same ! 764: * cable. We basically start up all devices on this controller. ! 765: */ ! 766: - (BOOL)startUpAttachedDevices ! 767: { ! 768: int i; ! 769: BOOL status = YES; ! 770: ! 771: /* Spin up only ATA drives */ ! 772: for (i = 0; i < MAX_IDE_DRIVES; i++) { ! 773: if ((_drives[i].ideInfo.type != 0) && ([self isAtapiDevice:i] == NO)) { ! 774: status = [self spinUpDrive:i]; ! 775: } ! 776: } ! 777: ! 778: [self resetAndInit]; ! 779: [self setDrivePowerState:IDE_PM_ACTIVE]; ! 780: ! 781: return status; ! 782: } ! 783: ! 784: - (IOReturn) getPowerState:(PMPowerState *)state_p ! 785: { ! 786: return IO_R_UNSUPPORTED; ! 787: } ! 788: ! 789: - (IOReturn) setPowerState:(PMPowerState)state ! 790: { ! 791: if (state == PM_READY) { ! 792: [self wakeUpDrive]; ! 793: } else if (state == PM_SUSPENDED) { ! 794: [self putDriveToSleep]; ! 795: } else { ! 796: //IOLog("%s: unknown APM event %x\n", [self name], (unsigned int)state); ! 797: } ! 798: ! 799: return IO_R_SUCCESS; ! 800: } ! 801: ! 802: - (IOReturn) getPowerManagement:(PMPowerManagementState *)state_p ! 803: { ! 804: return IO_R_UNSUPPORTED; ! 805: } ! 806: ! 807: - (IOReturn) setPowerManagement:(PMPowerManagementState)state ! 808: { ! 809: return IO_R_UNSUPPORTED; ! 810: } ! 811: ! 812: - property_IODeviceClass:(char *)classes length:(unsigned int *)maxLen ! 813: { ! 814: strcpy( classes, IOClassIDEController); ! 815: return( self); ! 816: } ! 817: ! 818: - property_IODeviceType:(char *)types length:(unsigned int *)maxLen ! 819: { ! 820: strcat( types, " "IOTypeIDE); ! 821: return( self); ! 822: } ! 823: ! 824: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.