IOBlockStorageServices.cpp [plain text]
#include <IOKit/IOLib.h>
#include <IOKit/storage/IOBlockStorageDriver.h>
#include "IOBlockStorageServices.h"
#if ( SCSI_BLOCK_SERVICES_DEBUGGING_LEVEL >= 1 )
#define PANIC_NOW(x) IOPanic x
#else
#define PANIC_NOW(x)
#endif
#if ( SCSI_BLOCK_SERVICES_DEBUGGING_LEVEL >= 2 )
#define ERROR_LOG(x) IOLog x
#else
#define ERROR_LOG(x)
#endif
#if ( SCSI_BLOCK_SERVICES_DEBUGGING_LEVEL >= 3 )
#define STATUS_LOG(x) IOLog x
#else
#define STATUS_LOG(x)
#endif
#define kNumberRetries 4
struct BlockServicesClientData
{
IOBlockStorageServices * owner;
IOStorageCompletion completionData;
IOMemoryDescriptor * clientBuffer;
UInt32 clientStartingBlock;
UInt32 clientRequestedBlockCount;
UInt32 clientRequestedBlockSize;
UInt32 retriesLeft;
};
typedef struct BlockServicesClientData BlockServicesClientData;
#define super IOBlockStorageDevice
OSDefineMetaClassAndStructors ( IOBlockStorageServices, IOBlockStorageDevice );
bool
IOBlockStorageServices::attach ( IOService * provider )
{
STATUS_LOG ( ( "IOBlockStorageServices: attach called\n" ) );
if ( !super::attach ( provider ) )
{
return false;
}
fProvider = OSDynamicCast ( IOSCSIBlockCommandsDevice, provider );
if ( fProvider == NULL )
{
ERROR_LOG ( ( "IOBlockStorageServices: attach; wrong provider type!\n" ) );
return false;
}
setProperty ( kIOPropertyProtocolCharacteristicsKey, fProvider->GetProtocolCharacteristicsDictionary ( ) );
setProperty ( kIOPropertyDeviceCharacteristicsKey, fProvider->GetDeviceCharacteristicsDictionary ( ) );
if ( fProvider->ReportDeviceMediaRemovability ( ) == true )
{
fMediaChanged = false;
fMediaPresent = false;
}
else
{
fMediaChanged = true;
fMediaPresent = true;
}
fMaxReadBlocks = fProvider->ReportDeviceMaxBlocksReadTransfer ( );
fMaxWriteBlocks = fProvider->ReportDeviceMaxBlocksWriteTransfer ( );
STATUS_LOG ( ( "IOBlockStorageServices: attach exiting\n" ) );
return true;
}
void
IOBlockStorageServices::detach ( IOService * provider )
{
STATUS_LOG ( ( "IOBlockStorageServices: detach called\n" ) );
super::detach ( provider );
STATUS_LOG ( ( "IOBlockStorageServices: detach exiting\n" ) );
}
IOReturn
IOBlockStorageServices::message ( UInt32 type,
IOService * nub,
void * arg )
{
IOReturn status = kIOReturnSuccess;
ERROR_LOG ( ( "IOBlockStorageServices::message called\n" ) );
switch ( type )
{
case kIOMessageMediaStateHasChanged:
{
ERROR_LOG ( ( "type = kIOMessageMediaStateHasChanged, nub = %p\n", nub ) );
fMediaChanged = true;
fMediaPresent = true;
status = messageClients ( type, arg, sizeof ( IOMediaState ) );
ERROR_LOG ( ( "status = %ld\n", ( UInt32 ) status ) );
}
break;
default:
{
status = super::message ( type, nub, arg );
}
break;
}
return status;
}
void
IOBlockStorageServices::AsyncReadWriteComplete ( void * clientData,
IOReturn status,
UInt64 actualByteCount )
{
IOBlockStorageServices * owner;
BlockServicesClientData * servicesData;
IOStorageCompletion returnData;
bool commandComplete = true;
servicesData = ( BlockServicesClientData * ) clientData;
returnData = servicesData->completionData;
owner = servicesData->owner;
STATUS_LOG(("IOBlockStorageServices: AsyncReadWriteComplete; command status %x\n", status ));
if ((( status != kIOReturnNotAttached ) && ( status != kIOReturnOffline ) &&
( status != kIOReturnSuccess )) && ( servicesData->retriesLeft > 0 ))
{
IOReturn requestStatus;
STATUS_LOG(("IOBlockStorageServices: AsyncReadWriteComplete; retry command\n"));
servicesData->retriesLeft--;
requestStatus = owner->fProvider->AsyncReadWrite(
servicesData->clientBuffer,
servicesData->clientStartingBlock,
servicesData->clientRequestedBlockCount,
servicesData->clientRequestedBlockSize,
clientData );
if ( requestStatus != kIOReturnSuccess )
{
commandComplete = true;
}
else
{
commandComplete = false;
}
}
if ( commandComplete == true )
{
IOFree ( clientData, sizeof ( BlockServicesClientData ) );
owner->fProvider->release();
owner->release();
IOStorage::complete ( returnData, status, actualByteCount );
}
}
IOReturn
IOBlockStorageServices::doAsyncReadWrite ( IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks,
IOStorageCompletion completion )
{
BlockServicesClientData * clientData;
IODirection direction;
IOReturn requestStatus;
UInt32 requestBlockSize;
if ( isInactive() != false )
{
return kIOReturnNotAttached;
}
direction = buffer->getDirection();
if (( direction != kIODirectionIn ) && ( direction != kIODirectionOut ))
{
return kIOReturnBadArgument;
}
clientData = (BlockServicesClientData *) IOMalloc( sizeof(BlockServicesClientData) );
if ( clientData == NULL )
{
ERROR_LOG ( ( "IOBlockStorageServices: doAsyncReadWrite; clientData malloc failed!\n" ) );
return kIOReturnNoResources;
}
retain();
fProvider->retain();
requestBlockSize = fProvider->ReportMediumBlockSize();
STATUS_LOG ( ( "IOBlockStorageServices: doAsyncReadWrite; save completion data!\n" ) );
clientData->owner = this;
clientData->completionData = completion;
clientData->clientBuffer = buffer;
clientData->clientStartingBlock = block;
clientData->clientRequestedBlockCount = nblks;
clientData->clientRequestedBlockSize = requestBlockSize;
clientData->retriesLeft = kNumberRetries;
fProvider->CheckPowerState();
requestStatus = fProvider->AsyncReadWrite ( buffer, (UInt64) block, (UInt64) nblks, (UInt64) requestBlockSize, (void *) clientData );
if ( requestStatus != kIOReturnSuccess )
{
if ( clientData != NULL )
{
IOFree ( clientData, sizeof ( BlockServicesClientData ) );
}
}
return requestStatus;
}
IOReturn
IOBlockStorageServices::doSyncReadWrite ( IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks )
{
IOReturn result;
if ( isInactive ( ) != false )
{
return kIOReturnNotAttached;
}
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
result = fProvider->SyncReadWrite ( buffer, block, nblks, fProvider->ReportMediumBlockSize ( ) );
fProvider->release ( );
release ( );
return result;
}
IOReturn
IOBlockStorageServices::doEjectMedia ( void )
{
IOReturn result;
fMediaPresent = false;
if ( isInactive ( ) != false )
{
return kIOReturnNotAttached;
}
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
result = fProvider->EjectTheMedium ( );
fProvider->release ( );
release ( );
return result;
}
IOReturn
IOBlockStorageServices::doFormatMedia ( UInt64 byteCapacity )
{
IOReturn result;
if ( isInactive ( ) != false )
{
return kIOReturnNotAttached;
}
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
result = fProvider->FormatMedium ( byteCapacity / ( fProvider->ReportMediumBlockSize ( ) ),
fProvider->ReportMediumBlockSize ( ) );
fProvider->release ( );
release ( );
return result;
}
UInt32
IOBlockStorageServices::doGetFormatCapacities ( UInt64 * capacities,
UInt32 capacitiesMaxCount ) const
{
IOReturn result;
if ( isInactive ( ) != false )
{
return kIOReturnNotAttached;
}
retain ( );
fProvider->retain ( );
result = fProvider->GetFormatCapacities ( capacities, capacitiesMaxCount );
fProvider->release ( );
release ( );
return result;
}
IOReturn
IOBlockStorageServices::doLockUnlockMedia ( bool doLock )
{
IOReturn result;
if ( isInactive ( ) != false )
{
return kIOReturnNotAttached;
}
retain ( );
fProvider->retain ( );
result = fProvider->LockUnlockMedium ( doLock );
fProvider->release ( );
release ( );
return result;
}
IOReturn
IOBlockStorageServices::doSynchronizeCache ( void )
{
IOReturn result;
if ( isInactive ( ) != false )
{
return kIOReturnNotAttached;
}
retain ( );
fProvider->retain ( );
result = fProvider->SynchronizeCache ( );
fProvider->release ( );
release ( );
return result;
}
char *
IOBlockStorageServices::getVendorString ( void )
{
return fProvider->GetVendorString ( );
}
char *
IOBlockStorageServices::getProductString ( void )
{
return fProvider->GetProductString ( );
}
char *
IOBlockStorageServices::getRevisionString ( void )
{
return fProvider->GetRevisionString ( );
}
char *
IOBlockStorageServices::getAdditionalDeviceInfoString ( void )
{
STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) );
return ( "No Additional Device Info" );
}
IOReturn
IOBlockStorageServices::reportBlockSize ( UInt64 * blockSize )
{
*blockSize = fProvider->ReportMediumBlockSize ( );
return kIOReturnSuccess;
}
IOReturn
IOBlockStorageServices::reportEjectability ( bool * isEjectable )
{
*isEjectable = fProvider->ReportDeviceMediaRemovability ( );
return kIOReturnSuccess;
}
IOReturn
IOBlockStorageServices::reportLockability ( bool * isLockable )
{
*isLockable = true;
return kIOReturnSuccess;
}
IOReturn
IOBlockStorageServices::reportPollRequirements ( bool * pollIsRequired,
bool * pollIsExpensive )
{
*pollIsRequired = false;
*pollIsExpensive = false;
return kIOReturnSuccess;
}
IOReturn
IOBlockStorageServices::reportMaxReadTransfer ( UInt64 blockSize,
UInt64 * max )
{
if ( fMaxReadBlocks == 0 )
{
*max = blockSize * 256;
}
else
{
*max = blockSize * fMaxReadBlocks;
}
return kIOReturnSuccess;
}
IOReturn
IOBlockStorageServices::reportMaxValidBlock ( UInt64 * maxBlock )
{
*maxBlock = ( fProvider->ReportMediumTotalBlockCount ( ) - 1 );
return kIOReturnSuccess;
}
IOReturn
IOBlockStorageServices::reportMaxWriteTransfer ( UInt64 blockSize,
UInt64 * max )
{
if ( fMaxWriteBlocks == 0 )
{
*max = blockSize * 256;
}
else
{
*max = blockSize * fMaxWriteBlocks;
}
return kIOReturnSuccess;
}
IOReturn
IOBlockStorageServices::reportMediaState ( bool * mediaPresent,
bool * changed )
{
STATUS_LOG ( ( "IOSCSIBlockCommandsDevice::reportMediaState.\n" ) );
*mediaPresent = fMediaPresent;
*changed = fMediaChanged;
if ( fMediaChanged )
{
fMediaChanged = !fMediaChanged;
}
return kIOReturnSuccess;
}
IOReturn
IOBlockStorageServices::reportRemovability ( bool * isRemovable )
{
*isRemovable = fProvider->ReportDeviceMediaRemovability();
return kIOReturnSuccess;
}
IOReturn
IOBlockStorageServices::reportWriteProtection ( bool * isWriteProtected )
{
*isWriteProtected = fProvider->ReportMediumWriteProtection();
return kIOReturnSuccess;
}
OSMetaClassDefineReservedUnused( IOBlockStorageServices, 1 );
OSMetaClassDefineReservedUnused( IOBlockStorageServices, 2 );
OSMetaClassDefineReservedUnused( IOBlockStorageServices, 3 );
OSMetaClassDefineReservedUnused( IOBlockStorageServices, 4 );
OSMetaClassDefineReservedUnused( IOBlockStorageServices, 5 );
OSMetaClassDefineReservedUnused( IOBlockStorageServices, 6 );
OSMetaClassDefineReservedUnused( IOBlockStorageServices, 7 );
OSMetaClassDefineReservedUnused( IOBlockStorageServices, 8 );