/* * Copyright (c) 1998-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include "IOATABlockStorageDriver.h" #include "IOATABlockStorageDevice.h" #include #include #include #include #define ATA_BLOCK_STORAGE_DRIVER_DEBUGGING_LEVEL 0 #if ( ATA_BLOCK_STORAGE_DRIVER_DEBUGGING_LEVEL >= 1 ) #define PANIC_NOW(x) IOPanic x #else #define PANIC_NOW(x) #endif #if ( ATA_BLOCK_STORAGE_DRIVER_DEBUGGING_LEVEL >= 2 ) #define ERROR_LOG(x) IOLog x #else #define ERROR_LOG(x) #endif #if ( ATA_BLOCK_STORAGE_DRIVER_DEBUGGING_LEVEL >= 3 ) #define STATUS_LOG(x) IOLog x #else #define STATUS_LOG(x) #endif #if ( ATA_BLOCK_STORAGE_DRIVER_PM_DEBUGGING_LEVEL >= 1 ) #define SERIAL_STATUS_LOG(x) kprintf x #else #define SERIAL_STATUS_LOG(x) #endif #define super IOService OSDefineMetaClassAndStructors ( IOATABlockStorageDriver, IOService ); enum { kATAIdleDevice = 1, kATAStandbyDevice = 2, kATASleepDevice = 3 }; #pragma mark Public Methods //--------------------------------------------------------------------------- // ¥ init - Doesn't do anything, just calls superclass' init. //--------------------------------------------------------------------------- bool IOATABlockStorageDriver::init ( OSDictionary * properties ) { // Run by our superclass if ( super::init ( properties ) == false ) { return false; } return true; } //--------------------------------------------------------------------------- // ¥ start - Starts up the driver and spawn a nub. //--------------------------------------------------------------------------- bool IOATABlockStorageDriver::start ( IOService * provider ) { IOReturn theErr = kIOReturnSuccess; IOWorkLoop * workLoop = NULL; OSNumber * numCommandObjects = NULL; STATUS_LOG ( ( "IOATABlockStorageDriver::start entering.\n" ) ); fATADevice = NULL; fCommandPool = NULL; fATAUnitID = kATAInvalidDeviceID; fATADeviceType = kUnknownATADeviceType; fATASocketType = kUnknownSocket; fAPMLevel = 0xFF; // First call start() in our superclass if ( super::start ( provider ) == false ) return false; // Cache our provider fATADevice = OSDynamicCast ( IOATADevice, provider ); if ( fATADevice == NULL ) return false; // Find out if the device type is ATA if ( fATADevice->getDeviceType ( ) != reportATADeviceType ( ) ) { ERROR_LOG ( ( "IOATABlockStorageDriver::start exiting, not an ATA device.\n" ) ); return false; } reserved = ( ExpansionData * ) IOMalloc ( sizeof ( ExpansionData ) ); bzero ( reserved, sizeof ( ExpansionData ) ); STATUS_LOG ( ( "IOATABlockStorageDriver::start opening device.\n" ) ); if ( fATADevice->open ( this ) == false ) return false; // Cache the drive unit number (master/slave assignment). fATAUnitID = fATADevice->getUnitID ( ); fATADeviceType = fATADevice->getDeviceType ( ); STATUS_LOG ( ( "IOATABlockStorageDriver::start fATAUnitID = %d.\n", ( UInt8 ) fATAUnitID ) ); STATUS_LOG ( ( "IOATABlockStorageDriver::start fATADeviceType is %d\n", ( UInt8 ) fATADeviceType ) ); bzero ( fDeviceIdentifyData, 512 ); fDeviceIdentifyBuffer = IOMemoryDescriptor::withAddress ( ( void * ) fDeviceIdentifyData, 512, kIODirectionIn ); assert ( fDeviceIdentifyBuffer != NULL ); fDeviceIdentifyBuffer->prepare ( ); numCommandObjects = OSDynamicCast ( OSNumber, getProperty ( "IOCommandPoolSize" ) ); fNumCommandObjects = numCommandObjects->unsigned32BitValue ( ); STATUS_LOG ( ( "IOATABlockStorageDriver::start fNumCommandObjects = %ld\n", fNumCommandObjects ) ); // Create an IOCommandGate (for power management support) and attach // this event source to the provider's workloop fCommandGate = IOCommandGate::commandGate ( this ); assert ( fCommandGate != NULL ); workLoop = getWorkLoop ( ); assert ( workLoop != NULL ); theErr = workLoop->addEventSource ( fCommandGate ); assert ( theErr == kIOReturnSuccess ); fCommandPool = IOCommandPool::commandPool ( this, workLoop, fNumCommandObjects ); assert ( fCommandPool != NULL ); allocateATACommandObjects ( ); // Inspect the provider if ( inspectDevice ( fATADevice ) == false ) return false; fCurrentPowerState = kIOATAPowerStateActive; fProposedPowerState = kIOATAPowerStateActive; fNumCommandsOutstanding = 0; fPowerTransitionInProgress = false; fPowerManagementThread = thread_call_allocate ( ( thread_call_func_t ) IOATABlockStorageDriver::sPowerManagement, ( thread_call_param_t ) this ); if ( fPowerManagementThread == NULL ) { ERROR_LOG ( ( "thread allocation failed.\n" ) ); return false; } // A policy-maker must make these calls to join the PM tree, // and to initialize its state PMinit ( ); // initialize power management variables setIdleTimerPeriod ( k5Minutes ); // 5 minute inactivity timer provider->joinPMtree ( this ); // join power management tree makeUsable ( ); fPowerManagementInitialized = true; initForPM ( ); return ( createNub ( provider ) ); } //--------------------------------------------------------------------------- // ¥ finalize - Terminates all power management //--------------------------------------------------------------------------- bool IOATABlockStorageDriver::finalize ( IOOptionBits options ) { if ( fPowerManagementInitialized ) { while ( fPowerTransitionInProgress ) { IOSleep ( 1 ); } fCommandGate->commandWakeup ( &fCurrentPowerState, false ); PMstop ( ); if ( fPowerManagementThread != NULL ) { // If the power management thread is scheduled, unschedule it. thread_call_cancel ( fPowerManagementThread ); } fPowerManagementInitialized = false; } return super::finalize ( options ); } //--------------------------------------------------------------------------- // ¥ stop - Stop the driver //--------------------------------------------------------------------------- void IOATABlockStorageDriver::stop ( IOService * provider ) { // Call our superclass super::stop ( provider ); } #pragma mark - #pragma mark Protected Methods //--------------------------------------------------------------------------- // ¥ free - Release allocated resources. //--------------------------------------------------------------------------- void IOATABlockStorageDriver::free ( void ) { IOWorkLoop * workLoop; if ( fCommandPool != NULL ) { deallocateATACommandObjects ( ); fCommandPool->release ( ); fCommandPool = NULL; } if ( fCommandGate != NULL ) { workLoop = getWorkLoop ( ); if ( workLoop != NULL ) { workLoop->removeEventSource ( fCommandGate ); } fCommandGate->release ( ); fCommandGate = NULL; } if ( fPowerManagementThread != NULL ) { thread_call_free ( fPowerManagementThread ); } if ( reserved != NULL ) { // Release all memory/objects associated with the reserved fields. if ( fPowerDownNotifier != NULL ) { // remove() will also call release() on this object (IONotifier). // See IONotifier.h for more info. fPowerDownNotifier->remove ( ); fPowerDownNotifier = NULL; } IOFree ( reserved, sizeof ( ExpansionData ) ); reserved = NULL; } if ( fDeviceIdentifyBuffer != NULL ) { fDeviceIdentifyBuffer->complete ( ); fDeviceIdentifyBuffer->release ( ); fDeviceIdentifyBuffer = NULL; } super::free ( ); } //--------------------------------------------------------------------------- // ¥ inspectDevice - Fetch information about the ATA device nub. //--------------------------------------------------------------------------- bool IOATABlockStorageDriver::inspectDevice ( IOATADevice * ataDevice ) { OSString * string = NULL; IOReturn theErr = kIOReturnSuccess; // Fetch ATA device information from the nub. string = OSDynamicCast ( OSString, ataDevice->getProperty ( kATAVendorPropertyKey ) ); if ( string != NULL ) { strncpy ( fModel, string->getCStringNoCopy ( ), kSizeOfATAModelString ); fModel[kSizeOfATAModelString] = '\0'; } string = OSDynamicCast ( OSString, ataDevice->getProperty ( kATARevisionPropertyKey ) ); if ( string != NULL ) { strncpy ( fRevision, string->getCStringNoCopy ( ), kSizeOfATARevisionString ); fRevision[kSizeOfATARevisionString] = '\0'; } theErr = identifyAndConfigureATADevice ( ); if ( theErr != kIOReturnSuccess ) { ERROR_LOG ( ( "IOATABlockStorageDriver::inspectDevice theErr = %ld\n", ( UInt32 ) theErr ) ); return false; } // Add an OSNumber property indicating the supported features. setProperty ( kIOATASupportedFeaturesKey, fSupportedFeatures, sizeof ( fSupportedFeatures ) * 8 ); return true; } //--------------------------------------------------------------------------- // ¥ reportATADeviceType - Report the type of ATA device (ATA vs. ATAPI). //--------------------------------------------------------------------------- ataDeviceType IOATABlockStorageDriver::reportATADeviceType ( void ) const { return kATADeviceType; } //--------------------------------------------------------------------------- // ¥ getDeviceTypeName - Returns the device type. //--------------------------------------------------------------------------- const char * IOATABlockStorageDriver::getDeviceTypeName ( void ) { return kIOBlockStorageDeviceTypeGeneric; } //--------------------------------------------------------------------------- // ¥ instantiateNub - Instantiate an ATA specific subclass of // IOBlockStorageDevice //--------------------------------------------------------------------------- IOService * IOATABlockStorageDriver::instantiateNub ( void ) { STATUS_LOG ( ( "IOATABlockStorageDriver::instantiateNub entering.\n" ) ); IOService * nub = new IOATABlockStorageDevice; STATUS_LOG ( ( "IOATABlockStorageDriver::instantiateNub exiting nub = %p.\n", nub ) ); return nub; } //--------------------------------------------------------------------------- // ¥ createNub - Returns an IOATABlockStorageDeviceNub. //--------------------------------------------------------------------------- bool IOATABlockStorageDriver::createNub ( IOService * provider ) { IOService * nub = NULL; STATUS_LOG ( ( "IOATABlockStorageDriver::createNub entering.\n" ) ); // Instantiate a generic hard disk nub so a generic driver // can match above us. nub = instantiateNub ( ); if ( nub == NULL ) { ERROR_LOG ( ( "IOATABlockStorageDriver::createNub instantiateNub() failed, returning false\n" ) ); return false; } nub->init ( ); if ( !nub->attach ( this ) ) { // panic since the nub can't attach PANIC_NOW ( ( "IOATABlockStorageDriver::createNub() unable to attach nub" ) ); return false; } nub->registerService ( ); // The IORegistry retains the nub, so we can release our refcount // because we don't need it any more. nub->release ( ); STATUS_LOG ( ( "IOATABlockStorageDriver::createNub exiting true.\n" ) ); return true; } //--------------------------------------------------------------------------- // ¥ doAsyncReadWrite - Handles asynchronous read/write requests. //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::doAsyncReadWrite ( IOMemoryDescriptor * buffer, UInt32 block, UInt32 nblks, IOStorageCompletion completion ) { IOReturn ret; IOATACommand * cmd = NULL; STATUS_LOG ( ( "IOATABlockStorageDriver::doAsyncReadWrite entering.\n" ) ); cmd = ataCommandReadWrite ( buffer, block, nblks ); if ( cmd == NULL ) { return kIOReturnNoMemory; } ret = asyncExecute ( cmd, completion ); STATUS_LOG ( ( "IOATABlockStorageDriver::doAsyncReadWrite exiting ret = %ld.\n", ( UInt32 ) ret ) ); return ret; } //--------------------------------------------------------------------------- // ¥ doSyncReadWrite - Handles synchronous read/write requests. //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::doSyncReadWrite ( IOMemoryDescriptor * buffer, UInt32 block, UInt32 nblks ) { IOReturn ret; IOATACommand * cmd = NULL; STATUS_LOG ( ( "IOATABlockStorageDriver::doSyncReadWrite entering\n" ) ); cmd = ataCommandReadWrite ( buffer, block, nblks ); if ( cmd == NULL ) { return kIOReturnNoMemory; } ret = syncExecute ( cmd ); STATUS_LOG ( ( "IOATABlockStorageDriver::doSyncReadWrite exiting ret = %ld.\n", ( UInt32 ) ret ) ); return ret; } //--------------------------------------------------------------------------- // ¥ doEjectMedia - Eject the media in the drive. //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::doEjectMedia ( void ) { IOReturn status = kIOReturnSuccess; STATUS_LOG ( ( "IOATABlockStorageDriver::doEjectMedia called.\n" ) ); if ( fATASocketType == kPCCardSocket ) return status; if ( getProperty ( "Power Off" ) != NULL ) { // Spin down the media now. We use to queue up a power change but we found // that since the PM stuff happens at a deferred point, the machine might shutdown // before we finish the PM change. So, we do the spindown now, then sync with PM // so it knows the state. if ( fCurrentPowerState > kIOATAPowerStateSleep ) { // Spin down the drive issuePowerTransition ( kATAStandbyDevice ); // NB: Intentionally set to sleep since some devices don't like // being put to sleep after standby. fCurrentPowerState = kIOATAPowerStateSleep; // Give the heads a chance to park IOSleep ( 500 ); } } // Synchronize our state with power management's concept of what // our state really is. changePowerStateToPriv ( kIOATAPowerStateSleep ); return status; } //--------------------------------------------------------------------------- // ¥ doFormatMedia - Format the media in the drive. ATA devices do not // support low level formatting. //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::doFormatMedia ( UInt64 byteCapacity ) { STATUS_LOG ( ( "IOATABlockStorageDriver::doFormatMedia called.\n" ) ); return kIOReturnUnsupported; } //--------------------------------------------------------------------------- // ¥ doGetFormatCapacities - Returns disk capacity. //--------------------------------------------------------------------------- UInt32 IOATABlockStorageDriver::doGetFormatCapacities ( UInt64 * capacities, UInt32 capacitiesMaxCount ) const { if ( ( capacities != NULL ) && ( capacitiesMaxCount > 0 ) ) { if ( fUseExtendedLBA ) { UInt32 hiLBA = 0; UInt32 loLBA = 0; IOATADevConfig::sDriveExtendedLBASize ( &hiLBA, &loLBA, fDeviceIdentifyData ); *capacities = ( ( UInt64 ) hiLBA ) << 32 | loLBA; } else if ( fUseLBAAddressing ) { *capacities = ( fDeviceIdentifyData[kATAIdentifyLBACapacity + 1] << 16 ) + ( UInt32 ) fDeviceIdentifyData[kATAIdentifyLBACapacity]; } else { *capacities = fDeviceIdentifyData[kATAIdentifySectorsPerTrack] * fDeviceIdentifyData[kATAIdentifyLogicalHeadCount] * fDeviceIdentifyData[kATAIdentifyLogicalCylinderCount]; } *capacities *= kATADefaultSectorSize; return 1; } return 0; } //--------------------------------------------------------------------------- // ¥ doLockUnlockMedia - Lock the media and prevent a user-initiated eject. //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::doLockUnlockMedia ( bool doLock ) { STATUS_LOG ( ( "IOATABlockStorageDriver::doLockUnlockMedia called.\n" ) ); return kIOReturnUnsupported; // No removable ATA device support. } //--------------------------------------------------------------------------- // ¥ doSynchronizeCache - Flush the write-cache to the physical media //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::doSynchronizeCache ( void ) { IOReturn status = kIOReturnSuccess; IOATACommand * cmd = NULL; STATUS_LOG ( ( "IOATABlockStorageDriver::doSynchronizeCache called.\n" ) ); if ( fATASocketType == kPCCardSocket ) { // Device doesnÕt support flush cache. DonÕt send the command. fNumCommandsOutstanding--; status = kIOReturnSuccess; goto Exit; } cmd = ataCommandFlushCache ( ); // Do we have a valid command? if ( cmd == NULL ) { // Return no memory error. fNumCommandsOutstanding--; status = kIOReturnNoMemory; goto Exit; } // Send the command to flush the cache. status = syncExecute ( cmd, kATATimeout1Minute, 0 ); Exit: STATUS_LOG ( ( "IOATABlockStorageDriver::doSynchronizeCache returning status = %ld.\n", ( UInt32 ) status ) ); return status; } //--------------------------------------------------------------------------- // ¥ doStart - Handle a Start Unit command //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::doStart ( void ) { STATUS_LOG ( ( "IOATABlockStorageDriver::doStart called.\n" ) ); return kIOReturnSuccess; } //--------------------------------------------------------------------------- // ¥ doStop - Handle a Stop Unit command //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::doStop ( void ) { STATUS_LOG ( ( "IOATABlockStorageDriver::doStop called.\n" ) ); return kIOReturnSuccess; } //--------------------------------------------------------------------------- // ¥ getAdditionalDeviceInfoString - Return additional identification strings. //--------------------------------------------------------------------------- char * IOATABlockStorageDriver::getAdditionalDeviceInfoString ( void ) { STATUS_LOG ( ( "IOATABlockStorageDriver::getAdditionalDeviceInfoString called.\n" ) ); return ( "[ATA]" ); } //--------------------------------------------------------------------------- // ¥ getProductString - Return product identification strings. //--------------------------------------------------------------------------- char * IOATABlockStorageDriver::getProductString ( void ) { STATUS_LOG ( ( "IOATABlockStorageDriver::getProductString called.\n" ) ); return fModel; } //--------------------------------------------------------------------------- // ¥ getRevisionString - Return product revision strings. //--------------------------------------------------------------------------- char * IOATABlockStorageDriver::getRevisionString ( void ) { STATUS_LOG ( ( "IOATABlockStorageDriver::getRevisionString called.\n" ) ); return fRevision; } //--------------------------------------------------------------------------- // ¥ getVendorString - Return product vendor strings. //--------------------------------------------------------------------------- char * IOATABlockStorageDriver::getVendorString ( void ) { STATUS_LOG ( ( "IOATABlockStorageDriver::getVendorString called.\n" ) ); return NULL; } //--------------------------------------------------------------------------- // ¥ reportBlockSize - Report the device block size in bytes. This is // ALWAYS 512-bytes //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::reportBlockSize ( UInt64 * blockSize ) { STATUS_LOG ( ( "IOATABlockStorageDriver::reportBlockSize called.\n" ) ); *blockSize = kATADefaultSectorSize; return kIOReturnSuccess; } //--------------------------------------------------------------------------- // ¥ reportEjectability - Report the media in the ATA device as // non-ejectable unless it is in the PC Card socket. //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::reportEjectability ( bool * isEjectable ) { STATUS_LOG ( ( "IOATABlockStorageDriver::reportEjectability called.\n" ) ); *isEjectable = (fATASocketType == kPCCardSocket); return kIOReturnSuccess; } //--------------------------------------------------------------------------- // ¥ reportLockability - Fixed media, locking is invalid. //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::reportLockability ( bool * isLockable ) { STATUS_LOG ( ( "IOATABlockStorageDriver::reportLockability called.\n" ) ); *isLockable = false; return kIOReturnSuccess; } //--------------------------------------------------------------------------- // ¥ reportPollRequirements - Report the polling requirements for // removable media. //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::reportPollRequirements ( bool * pollRequired, bool * pollIsExpensive ) { STATUS_LOG ( ( "IOATABlockStorageDriver::reportPollRequirements called.\n" ) ); *pollIsExpensive = false; *pollRequired = false; return kIOReturnSuccess; } //--------------------------------------------------------------------------- // ¥ reportMaxReadTransfer - Report the max number of bytes transferred for // an ATA read command //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::reportMaxReadTransfer ( UInt64 blocksize, UInt64 * max ) { OSNumber * size; STATUS_LOG ( ( "IOATABlockStorageDriver::reportMaxReadTransfer called.\n" ) ); *max = blocksize * kIOATAMaximumBlockCount8Bit; size = OSDynamicCast ( OSNumber, getProperty ( kIOMaximumBlockCountReadKey ) ); if ( size != NULL ) { *max = size->unsigned64BitValue ( ) * blocksize; } STATUS_LOG ( ( "IOATABlockStorageDriver::reportMaxReadTransfer max = %ld.\n", *max ) ); return kIOReturnSuccess; } //--------------------------------------------------------------------------- // ¥ reportMaxWriteTransfer - Report the max number of bytes transferred for // an ATA write command //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::reportMaxWriteTransfer ( UInt64 blocksize, UInt64 * max ) { OSNumber * size; STATUS_LOG ( ( "IOATABlockStorageDriver::reportMaxWriteTransfer called.\n" ) ); *max = blocksize * kIOATAMaximumBlockCount8Bit; size = OSDynamicCast ( OSNumber, getProperty ( kIOMaximumBlockCountWriteKey ) ); if ( size != NULL ) { *max = size->unsigned64BitValue ( ) * blocksize; } return kIOReturnSuccess; } //--------------------------------------------------------------------------- // ¥ reportMaxValidBlock - Returns the maximum addressable sector number //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::reportMaxValidBlock ( UInt64 * maxBlock ) { UInt64 diskCapacity = 0; assert ( fATADevice && maxBlock ); STATUS_LOG ( ( "IOATABlockStorageDriver::reportMaxValidBlock called.\n" ) ); doGetFormatCapacities ( &diskCapacity, 1 ); *maxBlock = ( diskCapacity / kATADefaultSectorSize ) - 1; STATUS_LOG ( ( "IOATABlockStorageDriver::reportMaxValidBlock maxBlock = %ld.\n", *maxBlock ) ); return kIOReturnSuccess; } //--------------------------------------------------------------------------- // ¥ reportMediaState - Report whether the media is currently present, and // whether a media change has been registered since the // last reporting. //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::reportMediaState ( bool * mediaPresent, bool * changed ) { STATUS_LOG ( ( "IOATABlockStorageDriver::reportMediaState called.\n" ) ); *mediaPresent = true; *changed = true; return kIOReturnSuccess; } //--------------------------------------------------------------------------- // ¥ reportRemovability - Report whether the media is removable. //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::reportRemovability ( bool * isRemovable ) { STATUS_LOG ( ( "IOATABlockStorageDriver::reportRemovability called.\n" ) ); *isRemovable = (fATASocketType == kPCCardSocket); return kIOReturnSuccess; } //--------------------------------------------------------------------------- // ¥ reportWriteProtection - Report if the media is write-protected. //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::reportWriteProtection ( bool * isWriteProtected ) { STATUS_LOG ( ( "IOATABlockStorageDriver::reportWriteProtection called.\n" ) ); *isWriteProtected = false; return kIOReturnSuccess; } //--------------------------------------------------------------------------- // ¥ getWriteCacheState - Gets the write cache state. //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::getWriteCacheState ( bool * enabled ) { IOReturn status = kIOReturnSuccess; STATUS_LOG ( ( "IOATABlockStorageDriver::getWriteCacheState called.\n" ) ); if ( activityTickle ( kIOPMSuperclassPolicy1, ( UInt32 ) kIOATAPowerStateActive ) ) { status = identifyATADevice ( ); if ( status == kIOReturnSuccess ) { // Get write cache enabled bit. It's in word 85, bit 5 *enabled = fDeviceIdentifyData[kATAIdentifyCommandExtension2] & kATAWriteCacheEnabledMask; } } else { status = kIOReturnNotResponding; } return status; } //--------------------------------------------------------------------------- // ¥ setWriteCacheState - Report if the media is write-protected. //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::setWriteCacheState ( bool enabled ) { IOReturn status = kIOReturnSuccess; STATUS_LOG ( ( "IOATABlockStorageDriver::setWriteCacheState called.\n" ) ); if ( activityTickle ( kIOPMSuperclassPolicy1, ( UInt32 ) kIOATAPowerStateActive ) ) { status = ataCommandSetFeatures ( enabled ? kATAEnableWriteCache : kATADisableWriteCache, 0, 0, 0, 0, mATAFlagImmediate, true ); } else { status = kIOReturnNotResponding; } return status; } //-------------------------------------------------------------------------------------- // ¥ sendSMARTCommand - Sends a SMART command to the device //-------------------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::sendSMARTCommand ( IOATACommand * command ) { IOReturn status = kIOReturnSuccess; if ( activityTickle ( kIOPMSuperclassPolicy1, ( UInt32 ) kIOATAPowerStateActive ) ) { command->setUnit ( fATAUnitID ); command->setDevice_Head ( fATAUnitID << 4 ); status = fATADevice->executeCommand ( command ); if ( status == kATANoErr ) status = kIOReturnSuccess; else status = kIOReturnIOError; } else { status = kIOReturnNotResponding; } return status; } //--------------------------------------------------------------------------- // ¥ message - Handles messages from our provider. //--------------------------------------------------------------------------- IOReturn IOATABlockStorageDriver::message ( UInt32 type, IOService * provider, void * argument ) { IOReturn status = kIOReturnSuccess; STATUS_LOG ( ( "IOATABlockStorageDriver::message %p %lx\n", this, type ) ); switch ( type ) { case kATAResetEvent: // Someone gave a hard reset to the drive SERIAL_STATUS_LOG ( ( "IOATABlockStorageDriver::message reset happened\n" ) ); // Reconfig device here fWakeUpResetOccurred = true; status = reconfigureATADevice ( ); // Need to set power state to standby mode, since that is what // we are in after a reset. if ( fPowerManagementInitialized == true ) activityTickle ( kIOPMSuperclassPolicy1, ( UInt32 ) kIOATAPowerStateActive ); break; case kATANullEvent: // Just kidding -- nothing happened // media bay, PC-Card events the drive has gone away and there's nothing // that can be done about it. case kATAOnlineEvent: // An ATA device has come online case kATAOfflineEvent: // An ATA device has gone offline case kATARemovedEvent: // An ATA device has been removed from the bus // on earlier hardware, the system is able to lock the PC Card slot so we can // get a request that the driver can then refuse gracefully. case kATAOfflineRequest: // Someone requesting to offline the drive case kATAEjectRequest: // Someone requesting to eject the drive // atapi resets are not relevent to ATA devices, but soft-resets ARE relevant to ATAPI devices. case kATAPIResetEvent: // Someone gave a ATAPI reset to the drive break; case kIOMessageServiceIsRequestingClose: { STATUS_LOG ( ("%s: kIOMessageServiceIsRequestingClose Received\n", getName( ) ) ); // tell clients to to away, terminate myself terminate ( kIOServiceRequired ); fATADevice->close ( this ); status = kIOReturnSuccess; } break; default: status = super::message ( type, provider, argument ); break; } return status; } #pragma mark - #pragma mark Static Functions //-------------------------------------------------------------------------------------- // ¥ sSwapBytes16 - swaps the buffer for device identify data //-------------------------------------------------------------------------------------- void IOATABlockStorageDriver::sSwapBytes16 ( UInt8 * buffer, IOByteCount numBytesToSwap ) { IOByteCount index; UInt8 temp; UInt8 * firstBytePtr; STATUS_LOG ( ( "IOATABlockStorageDriver::swapBytes16 called.\n" ) ); for ( index = 0; index < numBytesToSwap; index += 2 ) { firstBytePtr = buffer; // save pointer temp = *buffer++; // Save Byte0, point to Byte1 *firstBytePtr = *buffer; // Byte0 = Byte1 *buffer++ = temp; // Byte1 = Byte0 } } //-------------------------------------------------------------------------------------- // ¥ sConvertHighestBitToNumber - Finds the higest bit in a number and returns //-------------------------------------------------------------------------------------- UInt8 IOATABlockStorageDriver::sConvertHighestBitToNumber ( UInt16 bitField ) { STATUS_LOG ( ( "IOATABlockStorageDriver::convertHighestBitToNumber called.\n" ) ); UInt16 index, integer; // Test all bits from left to right, terminating at the first non-zero bit for ( index = 0x0080, integer = 7; ( ( index & bitField ) == 0 && index != 0 ) ; index >>= 1, integer-- ) { ; } return integer; } // binary compatibility reserved method space OSMetaClassDefineReservedUsed ( IOATABlockStorageDriver, 1 ); /* sendSMARTCommand */ OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 2 ); OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 3 ); OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 4 ); OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 5 ); OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 6 ); OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 7 ); OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 8 ); OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 9 ); OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 10 ); OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 11 ); OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 12 ); OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 13 ); OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 14 ); OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 15 ); OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 16 ); //-------------------------------------------------------------------------------------- // End Of File //--------------------------------------------------------------------------------------