IOBlockStorageServices.cpp [plain text]
#include <IOKit/IOLib.h>
#include <IOKit/storage/IOBlockStorageDriver.h>
#include "IOBlockStorageServices.h"
#define DEBUG 0
#define DEBUG_ASSERT_COMPONENT_NAME_STRING "SBC Services"
#if DEBUG
#define SCSI_BLOCK_SERVICES_DEBUGGING_LEVEL 0
#endif
#include "IOSCSIArchitectureModelFamilyDebugging.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 super IOBlockStorageDevice
OSDefineMetaClassAndStructors ( IOBlockStorageServices, IOBlockStorageDevice );
#define kNumberRetries 4
struct BlockServicesClientData
{
IOBlockStorageServices * owner;
IOStorageCompletion completionData;
IOMemoryDescriptor * clientBuffer;
UInt32 clientStartingBlock;
UInt32 clientRequestedBlockCount;
UInt32 clientRequestedBlockSize;
UInt32 retriesLeft;
};
typedef struct BlockServicesClientData BlockServicesClientData;
#if 0
#pragma mark -
#pragma mark ₯ Public Methods - API Exported to layers above
#pragma mark -
#endif
IOReturn
IOBlockStorageServices::message ( UInt32 type,
IOService * nub,
void * arg )
{
IOReturn status = kIOReturnSuccess;
switch ( type )
{
case kIOMessageMediaStateHasChanged:
{
IOMediaState state = ( IOMediaState ) arg;
switch ( state )
{
case kIOMediaStateOnline:
fMediaPresent = true;
break;
case kIOMediaStateOffline:
fMediaPresent = false;
break;
default:
break;
}
status = messageClients ( type, arg, 0 );
}
break;
default:
{
status = super::message ( type, nub, arg );
}
break;
}
return status;
}
IOReturn
IOBlockStorageServices::doAsyncReadWrite (
IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks,
IOStorageCompletion completion )
{
BlockServicesClientData * clientData = NULL;
IOReturn status = kIOReturnNotAttached;
UInt32 requestBlockSize = 0;
IODirection direction;
require ( isInactive ( ) == false, ErrorExit );
direction = buffer->getDirection ( );
require_action ( ( direction == kIODirectionIn ) ||
( direction == kIODirectionOut ),
ErrorExit,
status = kIOReturnBadArgument );
clientData = IONew ( BlockServicesClientData, 1 );
require_nonzero_action ( clientData, ErrorExit, status = 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 ( );
status = fProvider->AsyncReadWrite ( buffer, (UInt64) block, (UInt64) nblks, (UInt64) requestBlockSize, (void *) clientData );
require_success ( status, ReleaseClientDataAndRetain );
return status;
ReleaseClientDataAndRetain:
require_nonzero ( clientData, ErrorExit );
IODelete ( clientData, BlockServicesClientData, 1 );
clientData = NULL;
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IOBlockStorageServices::doSyncReadWrite (
IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks )
{
IOReturn status = kIOReturnNotAttached;
require ( isInactive ( ) == false, ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->SyncReadWrite ( buffer, block, nblks, fProvider->ReportMediumBlockSize ( ) );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IOBlockStorageServices::doEjectMedia ( void )
{
IOReturn status = kIOReturnNotAttached;
require ( isInactive ( ) == false, ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->EjectTheMedium ( );
if ( status == kIOReturnSuccess )
{
fMediaPresent = false;
}
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IOBlockStorageServices::doFormatMedia ( UInt64 byteCapacity )
{
IOReturn status = kIOReturnNotAttached;
require ( isInactive ( ) == false, ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->FormatMedium ( byteCapacity / ( fProvider->ReportMediumBlockSize ( ) ),
fProvider->ReportMediumBlockSize ( ) );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
UInt32
IOBlockStorageServices::doGetFormatCapacities (
UInt64 * capacities,
UInt32 capacitiesMaxCount ) const
{
IOReturn status = kIOReturnNotAttached;
require ( isInactive ( ) == false, ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->GetFormatCapacities ( capacities, capacitiesMaxCount );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IOBlockStorageServices::doLockUnlockMedia ( bool doLock )
{
IOReturn status = kIOReturnNotAttached;
require ( isInactive ( ) == false, ErrorExit );
retain ( );
fProvider->retain ( );
status = fProvider->LockUnlockMedium ( doLock );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IOBlockStorageServices::doSynchronizeCache ( void )
{
IOReturn status = kIOReturnNotAttached;
require ( isInactive ( ) == false, ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->SynchronizeCache ( );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
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 )
{
return kIOReturnUnsupported;
}
IOReturn
IOBlockStorageServices::reportMaxWriteTransfer ( UInt64 blockSize,
UInt64 * max )
{
return kIOReturnUnsupported;
}
IOReturn
IOBlockStorageServices::reportMaxValidBlock ( UInt64 * maxBlock )
{
*maxBlock = ( fProvider->ReportMediumTotalBlockCount ( ) - 1 );
return kIOReturnSuccess;
}
IOReturn
IOBlockStorageServices::reportMediaState ( bool * mediaPresent,
bool * changed )
{
*mediaPresent = fMediaPresent;
*changed = false;
return kIOReturnSuccess;
}
IOReturn
IOBlockStorageServices::reportRemovability ( bool * isRemovable )
{
*isRemovable = fProvider->ReportDeviceMediaRemovability ( );
return kIOReturnSuccess;
}
IOReturn
IOBlockStorageServices::reportWriteProtection ( bool * isWriteProtected )
{
*isWriteProtected = fProvider->ReportMediumWriteProtection ( );
return kIOReturnSuccess;
}
#if 0
#pragma mark -
#pragma mark ₯ Protected Methods
#pragma mark -
#endif
bool
IOBlockStorageServices::attach ( IOService * provider )
{
bool result = false;
require_string ( super::attach ( provider ), ErrorExit,
"Superclass didn't attach" );
fProvider = OSDynamicCast ( IOSCSIBlockCommandsDevice, provider );
require_nonzero_string ( fProvider, ErrorExit, "Incorrect provider type\n" );
setProperty ( kIOPropertyProtocolCharacteristicsKey,
fProvider->GetProtocolCharacteristicsDictionary ( ) );
setProperty ( kIOPropertyDeviceCharacteristicsKey,
fProvider->GetDeviceCharacteristicsDictionary ( ) );
result = true;
ErrorExit:
return result;
}
void
IOBlockStorageServices::detach ( IOService * provider )
{
super::detach ( provider );
}
#if 0
#pragma mark -
#pragma mark ₯ Static Methods
#pragma mark -
#endif
void
IOBlockStorageServices::AsyncReadWriteComplete (
void * clientData,
IOReturn status,
UInt64 actualByteCount )
{
IOBlockStorageServices * owner = NULL;
BlockServicesClientData * servicesData = NULL;
IOStorageCompletion returnData = { 0 };
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 = false;
}
}
if ( commandComplete == true )
{
IODelete ( clientData, BlockServicesClientData, 1 );
owner->fProvider->release ( );
owner->release ( );
IOStorage::complete ( returnData, status, actualByteCount );
}
}
#if 0
#pragma mark -
#pragma mark ₯ VTable Padding
#pragma mark -
#endif
OSMetaClassDefineReservedUnused ( IOBlockStorageServices, 1 );
OSMetaClassDefineReservedUnused ( IOBlockStorageServices, 2 );
OSMetaClassDefineReservedUnused ( IOBlockStorageServices, 3 );
OSMetaClassDefineReservedUnused ( IOBlockStorageServices, 4 );
OSMetaClassDefineReservedUnused ( IOBlockStorageServices, 5 );
OSMetaClassDefineReservedUnused ( IOBlockStorageServices, 6 );
OSMetaClassDefineReservedUnused ( IOBlockStorageServices, 7 );
OSMetaClassDefineReservedUnused ( IOBlockStorageServices, 8 );